1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2017 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
5 */
6
7 #define LOG_CATEGORY LOGC_DT
8
9 #include <common.h>
10 #include <dm.h>
11 #include <fdtdec.h>
12 #include <fdt_support.h>
13 #include <log.h>
14 #include <malloc.h>
15 #include <linux/libfdt.h>
16 #include <dm/of_access.h>
17 #include <dm/of_addr.h>
18 #include <dm/ofnode.h>
19 #include <linux/err.h>
20 #include <linux/ioport.h>
21 #include <asm/global_data.h>
22
23 DECLARE_GLOBAL_DATA_PTR;
24
25 #if CONFIG_IS_ENABLED(OFNODE_MULTI_TREE)
26 static void *oftree_list[CONFIG_OFNODE_MULTI_TREE_MAX];
27 static int oftree_count;
28
oftree_reset(void)29 void oftree_reset(void)
30 {
31 if (gd->flags & GD_FLG_RELOC) {
32 oftree_count = 0;
33 oftree_list[oftree_count++] = (void *)gd->fdt_blob;
34 }
35 }
36
oftree_find(const void * fdt)37 static int oftree_find(const void *fdt)
38 {
39 int i;
40
41 for (i = 0; i < oftree_count; i++) {
42 if (fdt == oftree_list[i])
43 return i;
44 }
45
46 return -1;
47 }
48
oftree_ensure(void * fdt)49 static oftree oftree_ensure(void *fdt)
50 {
51 oftree tree;
52 int i;
53
54 if (gd->flags & GD_FLG_RELOC) {
55 i = oftree_find(fdt);
56 if (i == -1) {
57 if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) {
58 log_warning("Too many registered device trees (max %d)\n",
59 CONFIG_OFNODE_MULTI_TREE_MAX);
60 return oftree_null();
61 }
62
63 /* register the new tree */
64 i = oftree_count++;
65 oftree_list[i] = fdt;
66 log_debug("oftree: registered tree %d: %p\n", i, fdt);
67 }
68 } else {
69 if (fdt != gd->fdt_blob) {
70 log_debug("Cannot only access control FDT before relocation\n");
71 return oftree_null();
72 }
73 }
74
75 tree.fdt = fdt;
76
77 return tree;
78 }
79
ofnode_lookup_fdt(ofnode node)80 void *ofnode_lookup_fdt(ofnode node)
81 {
82 if (gd->flags & GD_FLG_RELOC) {
83 uint i = OFTREE_TREE_ID(node.of_offset);
84
85 if (i > oftree_count) {
86 log_debug("Invalid tree ID %x\n", i);
87 return NULL;
88 }
89
90 return oftree_list[i];
91 } else {
92 return (void *)gd->fdt_blob;
93 }
94 }
95
ofnode_to_fdt(ofnode node)96 void *ofnode_to_fdt(ofnode node)
97 {
98 #ifdef OF_CHECKS
99 if (of_live_active())
100 return NULL;
101 #endif
102 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && ofnode_valid(node))
103 return ofnode_lookup_fdt(node);
104
105 /* Use the control FDT by default */
106 return (void *)gd->fdt_blob;
107 }
108
109 /**
110 * ofnode_to_offset() - convert an ofnode to a flat DT offset
111 *
112 * This cannot be called if the reference contains a node pointer.
113 *
114 * @node: Reference containing offset (possibly invalid)
115 * Return: DT offset (can be -1)
116 */
ofnode_to_offset(ofnode node)117 int ofnode_to_offset(ofnode node)
118 {
119 #ifdef OF_CHECKS
120 if (of_live_active())
121 return -1;
122 #endif
123 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && node.of_offset >= 0)
124 return OFTREE_OFFSET(node.of_offset);
125
126 return node.of_offset;
127 }
128
oftree_from_fdt(void * fdt)129 oftree oftree_from_fdt(void *fdt)
130 {
131 oftree tree;
132
133 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
134 return oftree_ensure(fdt);
135
136 tree.fdt = fdt;
137
138 return tree;
139 }
140
141 /**
142 * noffset_to_ofnode() - convert a DT offset to an ofnode
143 *
144 * @other_node: Node in the same tree to use as a reference
145 * @of_offset: DT offset (either valid, or -1)
146 * Return: reference to the associated DT offset
147 */
noffset_to_ofnode(ofnode other_node,int of_offset)148 ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
149 {
150 ofnode node;
151
152 if (of_live_active())
153 node.np = NULL;
154 else if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) || of_offset < 0 ||
155 !ofnode_valid(other_node))
156 node.of_offset = of_offset;
157 else
158 node.of_offset = OFTREE_MAKE_NODE(other_node.of_offset,
159 of_offset);
160
161 return node;
162 }
163
164 #else /* !OFNODE_MULTI_TREE */
165
oftree_find(const void * fdt)166 static inline int oftree_find(const void *fdt)
167 {
168 return 0;
169 }
170
171 #endif /* OFNODE_MULTI_TREE */
172
173 /**
174 * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
175 *
176 * Looks up the tree and returns an ofnode with the correct of_offset (i.e.
177 * containing the tree ID).
178 *
179 * If @offset is < 0 then this returns an ofnode with that offset and no tree
180 * ID.
181 *
182 * @tree: tree to check
183 * @offset: offset within that tree (can be < 0)
184 * @return node for that offset, with the correct ID
185 */
ofnode_from_tree_offset(oftree tree,int offset)186 static ofnode ofnode_from_tree_offset(oftree tree, int offset)
187 {
188 ofnode node;
189
190 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && offset >= 0) {
191 int tree_id = oftree_find(tree.fdt);
192
193 if (tree_id == -1)
194 return ofnode_null();
195 node.of_offset = OFTREE_NODE(tree_id, offset);
196 } else {
197 node.of_offset = offset;
198 }
199
200 return node;
201 }
202
ofnode_name_eq(ofnode node,const char * name)203 bool ofnode_name_eq(ofnode node, const char *name)
204 {
205 const char *node_name;
206 size_t len;
207
208 assert(ofnode_valid(node));
209
210 node_name = ofnode_get_name(node);
211 len = strchrnul(node_name, '@') - node_name;
212
213 return (strlen(name) == len) && !strncmp(node_name, name, len);
214 }
215
ofnode_read_u8(ofnode node,const char * propname,u8 * outp)216 int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
217 {
218 const u8 *cell;
219 int len;
220
221 assert(ofnode_valid(node));
222 debug("%s: %s: ", __func__, propname);
223
224 if (ofnode_is_np(node))
225 return of_read_u8(ofnode_to_np(node), propname, outp);
226
227 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
228 &len);
229 if (!cell || len < sizeof(*cell)) {
230 debug("(not found)\n");
231 return -EINVAL;
232 }
233 *outp = *cell;
234 debug("%#x (%d)\n", *outp, *outp);
235
236 return 0;
237 }
238
ofnode_read_u8_default(ofnode node,const char * propname,u8 def)239 u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
240 {
241 assert(ofnode_valid(node));
242 ofnode_read_u8(node, propname, &def);
243
244 return def;
245 }
246
ofnode_read_u16(ofnode node,const char * propname,u16 * outp)247 int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
248 {
249 const fdt16_t *cell;
250 int len;
251
252 assert(ofnode_valid(node));
253 debug("%s: %s: ", __func__, propname);
254
255 if (ofnode_is_np(node))
256 return of_read_u16(ofnode_to_np(node), propname, outp);
257
258 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
259 &len);
260 if (!cell || len < sizeof(*cell)) {
261 debug("(not found)\n");
262 return -EINVAL;
263 }
264 *outp = be16_to_cpup(cell);
265 debug("%#x (%d)\n", *outp, *outp);
266
267 return 0;
268 }
269
ofnode_read_u16_default(ofnode node,const char * propname,u16 def)270 u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def)
271 {
272 assert(ofnode_valid(node));
273 ofnode_read_u16(node, propname, &def);
274
275 return def;
276 }
277
ofnode_read_u32(ofnode node,const char * propname,u32 * outp)278 int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
279 {
280 return ofnode_read_u32_index(node, propname, 0, outp);
281 }
282
ofnode_read_u32_default(ofnode node,const char * propname,u32 def)283 u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
284 {
285 assert(ofnode_valid(node));
286 ofnode_read_u32_index(node, propname, 0, &def);
287
288 return def;
289 }
290
ofnode_read_u32_index(ofnode node,const char * propname,int index,u32 * outp)291 int ofnode_read_u32_index(ofnode node, const char *propname, int index,
292 u32 *outp)
293 {
294 const fdt32_t *cell;
295 int len;
296
297 assert(ofnode_valid(node));
298 debug("%s: %s: ", __func__, propname);
299
300 if (ofnode_is_np(node))
301 return of_read_u32_index(ofnode_to_np(node), propname, index,
302 outp);
303
304 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
305 propname, &len);
306 if (!cell) {
307 debug("(not found)\n");
308 return -EINVAL;
309 }
310
311 if (len < (sizeof(int) * (index + 1))) {
312 debug("(not large enough)\n");
313 return -EOVERFLOW;
314 }
315
316 *outp = fdt32_to_cpu(cell[index]);
317 debug("%#x (%d)\n", *outp, *outp);
318
319 return 0;
320 }
321
ofnode_read_u32_index_default(ofnode node,const char * propname,int index,u32 def)322 u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
323 u32 def)
324 {
325 assert(ofnode_valid(node));
326 ofnode_read_u32_index(node, propname, index, &def);
327
328 return def;
329 }
330
ofnode_read_s32_default(ofnode node,const char * propname,s32 def)331 int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
332 {
333 assert(ofnode_valid(node));
334 ofnode_read_u32(node, propname, (u32 *)&def);
335
336 return def;
337 }
338
ofnode_read_u64(ofnode node,const char * propname,u64 * outp)339 int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
340 {
341 const unaligned_fdt64_t *cell;
342 int len;
343
344 assert(ofnode_valid(node));
345 debug("%s: %s: ", __func__, propname);
346
347 if (ofnode_is_np(node))
348 return of_read_u64(ofnode_to_np(node), propname, outp);
349
350 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
351 propname, &len);
352 if (!cell || len < sizeof(*cell)) {
353 debug("(not found)\n");
354 return -EINVAL;
355 }
356 *outp = fdt64_to_cpu(cell[0]);
357 debug("%#llx (%lld)\n", (unsigned long long)*outp,
358 (unsigned long long)*outp);
359
360 return 0;
361 }
362
ofnode_read_u64_default(ofnode node,const char * propname,u64 def)363 u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
364 {
365 assert(ofnode_valid(node));
366 ofnode_read_u64(node, propname, &def);
367
368 return def;
369 }
370
ofnode_read_bool(ofnode node,const char * propname)371 bool ofnode_read_bool(ofnode node, const char *propname)
372 {
373 const void *prop;
374
375 assert(ofnode_valid(node));
376 debug("%s: %s: ", __func__, propname);
377
378 prop = ofnode_get_property(node, propname, NULL);
379
380 debug("%s\n", prop ? "true" : "false");
381
382 return prop ? true : false;
383 }
384
ofnode_read_prop(ofnode node,const char * propname,int * sizep)385 const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
386 {
387 const char *val = NULL;
388 int len;
389
390 assert(ofnode_valid(node));
391 debug("%s: %s: ", __func__, propname);
392
393 if (ofnode_is_np(node)) {
394 struct property *prop = of_find_property(
395 ofnode_to_np(node), propname, &len);
396
397 if (prop) {
398 val = prop->value;
399 len = prop->length;
400 }
401 } else {
402 val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
403 propname, &len);
404 }
405 if (!val) {
406 debug("<not found>\n");
407 if (sizep)
408 *sizep = -FDT_ERR_NOTFOUND;
409 return NULL;
410 }
411 if (sizep)
412 *sizep = len;
413
414 return val;
415 }
416
ofnode_read_string(ofnode node,const char * propname)417 const char *ofnode_read_string(ofnode node, const char *propname)
418 {
419 const char *str;
420 int len;
421
422 str = ofnode_read_prop(node, propname, &len);
423 if (!str)
424 return NULL;
425
426 if (strnlen(str, len) >= len) {
427 debug("<invalid>\n");
428 return NULL;
429 }
430 debug("%s\n", str);
431
432 return str;
433 }
434
ofnode_read_size(ofnode node,const char * propname)435 int ofnode_read_size(ofnode node, const char *propname)
436 {
437 int len;
438
439 if (!ofnode_read_prop(node, propname, &len))
440 return -EINVAL;
441
442 return len;
443 }
444
ofnode_find_subnode(ofnode node,const char * subnode_name)445 ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
446 {
447 ofnode subnode;
448
449 assert(ofnode_valid(node));
450 debug("%s: %s: ", __func__, subnode_name);
451
452 if (ofnode_is_np(node)) {
453 struct device_node *np = ofnode_to_np(node);
454
455 for (np = np->child; np; np = np->sibling) {
456 if (!strcmp(subnode_name, np->name))
457 break;
458 }
459 subnode = np_to_ofnode(np);
460 } else {
461 int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
462 ofnode_to_offset(node), subnode_name);
463 subnode = noffset_to_ofnode(node, ooffset);
464 }
465 debug("%s\n", ofnode_valid(subnode) ?
466 ofnode_get_name(subnode) : "<none>");
467
468 return subnode;
469 }
470
ofnode_read_u32_array(ofnode node,const char * propname,u32 * out_values,size_t sz)471 int ofnode_read_u32_array(ofnode node, const char *propname,
472 u32 *out_values, size_t sz)
473 {
474 assert(ofnode_valid(node));
475 debug("%s: %s: ", __func__, propname);
476
477 if (ofnode_is_np(node)) {
478 return of_read_u32_array(ofnode_to_np(node), propname,
479 out_values, sz);
480 } else {
481 int ret;
482
483 ret = fdtdec_get_int_array(ofnode_to_fdt(node),
484 ofnode_to_offset(node), propname,
485 out_values, sz);
486
487 /* get the error right, but space is more important in SPL */
488 if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
489 if (ret == -FDT_ERR_NOTFOUND)
490 return -EINVAL;
491 else if (ret == -FDT_ERR_BADLAYOUT)
492 return -EOVERFLOW;
493 }
494 return ret;
495 }
496 }
497
498 #if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
ofnode_is_enabled(ofnode node)499 bool ofnode_is_enabled(ofnode node)
500 {
501 if (ofnode_is_np(node)) {
502 return of_device_is_available(ofnode_to_np(node));
503 } else {
504 return fdtdec_get_is_enabled(ofnode_to_fdt(node),
505 ofnode_to_offset(node));
506 }
507 }
508
ofnode_first_subnode(ofnode node)509 ofnode ofnode_first_subnode(ofnode node)
510 {
511 assert(ofnode_valid(node));
512 if (ofnode_is_np(node))
513 return np_to_ofnode(node.np->child);
514
515 return noffset_to_ofnode(node,
516 fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
517 }
518
ofnode_next_subnode(ofnode node)519 ofnode ofnode_next_subnode(ofnode node)
520 {
521 assert(ofnode_valid(node));
522 if (ofnode_is_np(node))
523 return np_to_ofnode(node.np->sibling);
524
525 return noffset_to_ofnode(node,
526 fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
527 }
528 #endif /* !DM_INLINE_OFNODE */
529
ofnode_get_parent(ofnode node)530 ofnode ofnode_get_parent(ofnode node)
531 {
532 ofnode parent;
533
534 assert(ofnode_valid(node));
535 if (ofnode_is_np(node))
536 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
537 else
538 parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
539 ofnode_to_offset(node));
540
541 return parent;
542 }
543
ofnode_get_name(ofnode node)544 const char *ofnode_get_name(ofnode node)
545 {
546 if (!ofnode_valid(node)) {
547 debug("%s node not valid\n", __func__);
548 return NULL;
549 }
550
551 if (ofnode_is_np(node))
552 return node.np->name;
553
554 return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
555 }
556
ofnode_get_path(ofnode node,char * buf,int buflen)557 int ofnode_get_path(ofnode node, char *buf, int buflen)
558 {
559 assert(ofnode_valid(node));
560
561 if (ofnode_is_np(node)) {
562 if (strlen(node.np->full_name) >= buflen)
563 return -ENOSPC;
564
565 strcpy(buf, node.np->full_name);
566
567 return 0;
568 } else {
569 int res;
570
571 res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
572 buflen);
573 if (!res)
574 return res;
575 else if (res == -FDT_ERR_NOSPACE)
576 return -ENOSPC;
577 else
578 return -EINVAL;
579 }
580 }
581
ofnode_get_by_phandle(uint phandle)582 ofnode ofnode_get_by_phandle(uint phandle)
583 {
584 ofnode node;
585
586 if (of_live_active())
587 node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
588 else
589 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
590 phandle);
591
592 return node;
593 }
594
oftree_get_by_phandle(oftree tree,uint phandle)595 ofnode oftree_get_by_phandle(oftree tree, uint phandle)
596 {
597 ofnode node;
598
599 if (of_live_active())
600 node = np_to_ofnode(of_find_node_by_phandle(tree.np, phandle));
601 else
602 node = ofnode_from_tree_offset(tree,
603 fdt_node_offset_by_phandle(oftree_lookup_fdt(tree),
604 phandle));
605
606 return node;
607 }
608
__ofnode_get_addr_size_index(ofnode node,int index,fdt_size_t * size,bool translate)609 static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
610 fdt_size_t *size, bool translate)
611 {
612 int na, ns;
613
614 if (size)
615 *size = FDT_SIZE_T_NONE;
616
617 if (ofnode_is_np(node)) {
618 const __be32 *prop_val;
619 u64 size64;
620 uint flags;
621
622 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
623 &flags);
624 if (!prop_val)
625 return FDT_ADDR_T_NONE;
626
627 if (size)
628 *size = size64;
629
630 ns = of_n_size_cells(ofnode_to_np(node));
631
632 if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
633 return of_translate_address(ofnode_to_np(node), prop_val);
634 } else {
635 na = of_n_addr_cells(ofnode_to_np(node));
636 return of_read_number(prop_val, na);
637 }
638 } else {
639 na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
640 ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
641 return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
642 ofnode_to_offset(node), "reg",
643 index, na, ns, size,
644 translate);
645 }
646 }
647
ofnode_get_addr_size_index(ofnode node,int index,fdt_size_t * size)648 fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
649 {
650 return __ofnode_get_addr_size_index(node, index, size, true);
651 }
652
ofnode_get_addr_size_index_notrans(ofnode node,int index,fdt_size_t * size)653 fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
654 fdt_size_t *size)
655 {
656 return __ofnode_get_addr_size_index(node, index, size, false);
657 }
658
ofnode_get_addr_index(ofnode node,int index)659 fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
660 {
661 fdt_size_t size;
662
663 return ofnode_get_addr_size_index(node, index, &size);
664 }
665
ofnode_get_addr(ofnode node)666 fdt_addr_t ofnode_get_addr(ofnode node)
667 {
668 return ofnode_get_addr_index(node, 0);
669 }
670
ofnode_get_size(ofnode node)671 fdt_size_t ofnode_get_size(ofnode node)
672 {
673 fdt_size_t size;
674
675 ofnode_get_addr_size_index(node, 0, &size);
676
677 return size;
678 }
679
ofnode_stringlist_search(ofnode node,const char * property,const char * string)680 int ofnode_stringlist_search(ofnode node, const char *property,
681 const char *string)
682 {
683 if (ofnode_is_np(node)) {
684 return of_property_match_string(ofnode_to_np(node),
685 property, string);
686 } else {
687 int ret;
688
689 ret = fdt_stringlist_search(ofnode_to_fdt(node),
690 ofnode_to_offset(node), property,
691 string);
692 if (ret == -FDT_ERR_NOTFOUND)
693 return -ENODATA;
694 else if (ret < 0)
695 return -EINVAL;
696
697 return ret;
698 }
699 }
700
ofnode_read_string_index(ofnode node,const char * property,int index,const char ** outp)701 int ofnode_read_string_index(ofnode node, const char *property, int index,
702 const char **outp)
703 {
704 if (ofnode_is_np(node)) {
705 return of_property_read_string_index(ofnode_to_np(node),
706 property, index, outp);
707 } else {
708 int len;
709
710 *outp = fdt_stringlist_get(ofnode_to_fdt(node),
711 ofnode_to_offset(node),
712 property, index, &len);
713 if (len < 0)
714 return -EINVAL;
715 return 0;
716 }
717 }
718
ofnode_read_string_count(ofnode node,const char * property)719 int ofnode_read_string_count(ofnode node, const char *property)
720 {
721 if (ofnode_is_np(node)) {
722 return of_property_count_strings(ofnode_to_np(node), property);
723 } else {
724 return fdt_stringlist_count(ofnode_to_fdt(node),
725 ofnode_to_offset(node), property);
726 }
727 }
728
ofnode_read_string_list(ofnode node,const char * property,const char *** listp)729 int ofnode_read_string_list(ofnode node, const char *property,
730 const char ***listp)
731 {
732 const char **prop;
733 int count;
734 int i;
735
736 *listp = NULL;
737 count = ofnode_read_string_count(node, property);
738 if (count < 0)
739 return count;
740 if (!count)
741 return 0;
742
743 prop = calloc(count + 1, sizeof(char *));
744 if (!prop)
745 return -ENOMEM;
746
747 for (i = 0; i < count; i++)
748 ofnode_read_string_index(node, property, i, &prop[i]);
749 prop[count] = NULL;
750 *listp = prop;
751
752 return count;
753 }
754
ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args * in,struct ofnode_phandle_args * out)755 static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
756 struct ofnode_phandle_args *out)
757 {
758 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
759 out->node = offset_to_ofnode(in->node);
760 out->args_count = in->args_count;
761 memcpy(out->args, in->args, sizeof(out->args));
762 }
763
ofnode_from_of_phandle_args(struct of_phandle_args * in,struct ofnode_phandle_args * out)764 static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
765 struct ofnode_phandle_args *out)
766 {
767 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
768 out->node = np_to_ofnode(in->np);
769 out->args_count = in->args_count;
770 memcpy(out->args, in->args, sizeof(out->args));
771 }
772
ofnode_parse_phandle_with_args(ofnode node,const char * list_name,const char * cells_name,int cell_count,int index,struct ofnode_phandle_args * out_args)773 int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
774 const char *cells_name, int cell_count,
775 int index,
776 struct ofnode_phandle_args *out_args)
777 {
778 if (ofnode_is_np(node)) {
779 struct of_phandle_args args;
780 int ret;
781
782 ret = of_parse_phandle_with_args(ofnode_to_np(node),
783 list_name, cells_name,
784 cell_count, index,
785 &args);
786 if (ret)
787 return ret;
788 ofnode_from_of_phandle_args(&args, out_args);
789 } else {
790 struct fdtdec_phandle_args args;
791 int ret;
792
793 ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
794 ofnode_to_offset(node),
795 list_name, cells_name,
796 cell_count, index, &args);
797 if (ret)
798 return ret;
799 ofnode_from_fdtdec_phandle_args(&args, out_args);
800 }
801
802 return 0;
803 }
804
ofnode_count_phandle_with_args(ofnode node,const char * list_name,const char * cells_name,int cell_count)805 int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
806 const char *cells_name, int cell_count)
807 {
808 if (ofnode_is_np(node))
809 return of_count_phandle_with_args(ofnode_to_np(node),
810 list_name, cells_name, cell_count);
811 else
812 return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
813 ofnode_to_offset(node), list_name, cells_name,
814 cell_count, -1, NULL);
815 }
816
ofnode_path(const char * path)817 ofnode ofnode_path(const char *path)
818 {
819 if (of_live_active())
820 return np_to_ofnode(of_find_node_by_path(path));
821 else
822 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
823 }
824
oftree_root(oftree tree)825 ofnode oftree_root(oftree tree)
826 {
827 if (of_live_active()) {
828 return np_to_ofnode(tree.np);
829 } else {
830 return ofnode_from_tree_offset(tree, 0);
831 }
832 }
833
oftree_path(oftree tree,const char * path)834 ofnode oftree_path(oftree tree, const char *path)
835 {
836 if (of_live_active()) {
837 return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
838 NULL));
839 } else if (*path != '/' && tree.fdt != gd->fdt_blob) {
840 return ofnode_null(); /* Aliases only on control FDT */
841 } else {
842 int offset = fdt_path_offset(tree.fdt, path);
843
844 return ofnode_from_tree_offset(tree, offset);
845 }
846 }
847
ofnode_read_chosen_prop(const char * propname,int * sizep)848 const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
849 {
850 ofnode chosen_node;
851
852 chosen_node = ofnode_path("/chosen");
853
854 return ofnode_read_prop(chosen_node, propname, sizep);
855 }
856
ofnode_read_chosen_string(const char * propname)857 const char *ofnode_read_chosen_string(const char *propname)
858 {
859 return ofnode_read_chosen_prop(propname, NULL);
860 }
861
ofnode_get_chosen_node(const char * name)862 ofnode ofnode_get_chosen_node(const char *name)
863 {
864 const char *prop;
865
866 prop = ofnode_read_chosen_prop(name, NULL);
867 if (!prop)
868 return ofnode_null();
869
870 return ofnode_path(prop);
871 }
872
ofnode_read_aliases_prop(const char * propname,int * sizep)873 const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
874 {
875 ofnode node;
876
877 node = ofnode_path("/aliases");
878
879 return ofnode_read_prop(node, propname, sizep);
880 }
881
ofnode_get_aliases_node(const char * name)882 ofnode ofnode_get_aliases_node(const char *name)
883 {
884 const char *prop;
885
886 prop = ofnode_read_aliases_prop(name, NULL);
887 if (!prop)
888 return ofnode_null();
889
890 debug("%s: node_path: %s\n", __func__, prop);
891
892 return ofnode_path(prop);
893 }
894
ofnode_get_child_count(ofnode parent)895 int ofnode_get_child_count(ofnode parent)
896 {
897 ofnode child;
898 int num = 0;
899
900 ofnode_for_each_subnode(child, parent)
901 num++;
902
903 return num;
904 }
905
decode_timing_property(ofnode node,const char * name,struct timing_entry * result)906 static int decode_timing_property(ofnode node, const char *name,
907 struct timing_entry *result)
908 {
909 int length, ret = 0;
910
911 length = ofnode_read_size(node, name);
912 if (length < 0) {
913 debug("%s: could not find property %s\n",
914 ofnode_get_name(node), name);
915 return length;
916 }
917
918 if (length == sizeof(u32)) {
919 result->typ = ofnode_read_u32_default(node, name, 0);
920 result->min = result->typ;
921 result->max = result->typ;
922 } else {
923 ret = ofnode_read_u32_array(node, name, &result->min, 3);
924 }
925
926 return ret;
927 }
928
ofnode_decode_display_timing(ofnode parent,int index,struct display_timing * dt)929 int ofnode_decode_display_timing(ofnode parent, int index,
930 struct display_timing *dt)
931 {
932 int i;
933 ofnode timings, node;
934 u32 val = 0;
935 int ret = 0;
936
937 timings = ofnode_find_subnode(parent, "display-timings");
938 if (!ofnode_valid(timings))
939 return -EINVAL;
940
941 i = 0;
942 ofnode_for_each_subnode(node, timings) {
943 if (i++ == index)
944 break;
945 }
946
947 if (!ofnode_valid(node))
948 return -EINVAL;
949
950 memset(dt, 0, sizeof(*dt));
951
952 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
953 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
954 ret |= decode_timing_property(node, "hactive", &dt->hactive);
955 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
956 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
957 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
958 ret |= decode_timing_property(node, "vactive", &dt->vactive);
959 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
960 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
961
962 dt->flags = 0;
963 val = ofnode_read_u32_default(node, "vsync-active", -1);
964 if (val != -1) {
965 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
966 DISPLAY_FLAGS_VSYNC_LOW;
967 }
968 val = ofnode_read_u32_default(node, "hsync-active", -1);
969 if (val != -1) {
970 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
971 DISPLAY_FLAGS_HSYNC_LOW;
972 }
973 val = ofnode_read_u32_default(node, "de-active", -1);
974 if (val != -1) {
975 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
976 DISPLAY_FLAGS_DE_LOW;
977 }
978 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
979 if (val != -1) {
980 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
981 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
982 }
983
984 if (ofnode_read_bool(node, "interlaced"))
985 dt->flags |= DISPLAY_FLAGS_INTERLACED;
986 if (ofnode_read_bool(node, "doublescan"))
987 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
988 if (ofnode_read_bool(node, "doubleclk"))
989 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
990
991 return ret;
992 }
993
ofnode_decode_panel_timing(ofnode parent,struct display_timing * dt)994 int ofnode_decode_panel_timing(ofnode parent,
995 struct display_timing *dt)
996 {
997 ofnode timings;
998 u32 val = 0;
999 int ret = 0;
1000
1001 timings = ofnode_find_subnode(parent, "panel-timing");
1002 if (!ofnode_valid(timings))
1003 return -EINVAL;
1004 memset(dt, 0, sizeof(*dt));
1005 ret |= decode_timing_property(timings, "hback-porch", &dt->hback_porch);
1006 ret |= decode_timing_property(timings, "hfront-porch", &dt->hfront_porch);
1007 ret |= decode_timing_property(timings, "hactive", &dt->hactive);
1008 ret |= decode_timing_property(timings, "hsync-len", &dt->hsync_len);
1009 ret |= decode_timing_property(timings, "vback-porch", &dt->vback_porch);
1010 ret |= decode_timing_property(timings, "vfront-porch", &dt->vfront_porch);
1011 ret |= decode_timing_property(timings, "vactive", &dt->vactive);
1012 ret |= decode_timing_property(timings, "vsync-len", &dt->vsync_len);
1013 ret |= decode_timing_property(timings, "clock-frequency", &dt->pixelclock);
1014 dt->flags = 0;
1015 if (!ofnode_read_u32(timings, "vsync-active", &val)) {
1016 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1017 DISPLAY_FLAGS_VSYNC_LOW;
1018 }
1019 if (!ofnode_read_u32(timings, "hsync-active", &val)) {
1020 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1021 DISPLAY_FLAGS_HSYNC_LOW;
1022 }
1023 if (!ofnode_read_u32(timings, "de-active", &val)) {
1024 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1025 DISPLAY_FLAGS_DE_LOW;
1026 }
1027 if (!ofnode_read_u32(timings, "pixelclk-active", &val)) {
1028 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1029 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1030 }
1031 if (ofnode_read_bool(timings, "interlaced"))
1032 dt->flags |= DISPLAY_FLAGS_INTERLACED;
1033 if (ofnode_read_bool(timings, "doublescan"))
1034 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1035 if (ofnode_read_bool(timings, "doubleclk"))
1036 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1037
1038 return ret;
1039 }
1040
ofnode_get_property(ofnode node,const char * propname,int * lenp)1041 const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
1042 {
1043 if (ofnode_is_np(node))
1044 return of_get_property(ofnode_to_np(node), propname, lenp);
1045 else
1046 return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
1047 propname, lenp);
1048 }
1049
ofnode_first_property(ofnode node,struct ofprop * prop)1050 int ofnode_first_property(ofnode node, struct ofprop *prop)
1051 {
1052 prop->node = node;
1053
1054 if (ofnode_is_np(node)) {
1055 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
1056 if (!prop->prop)
1057 return -FDT_ERR_NOTFOUND;
1058 } else {
1059 prop->offset =
1060 fdt_first_property_offset(ofnode_to_fdt(node),
1061 ofnode_to_offset(prop->node));
1062 if (prop->offset < 0)
1063 return prop->offset;
1064 }
1065
1066 return 0;
1067 }
1068
ofnode_next_property(struct ofprop * prop)1069 int ofnode_next_property(struct ofprop *prop)
1070 {
1071 if (ofnode_is_np(prop->node)) {
1072 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
1073 prop->prop);
1074 if (!prop->prop)
1075 return -FDT_ERR_NOTFOUND;
1076 } else {
1077 prop->offset =
1078 fdt_next_property_offset(ofnode_to_fdt(prop->node),
1079 prop->offset);
1080 if (prop->offset < 0)
1081 return prop->offset;
1082 }
1083
1084 return 0;
1085 }
1086
ofprop_get_property(const struct ofprop * prop,const char ** propname,int * lenp)1087 const void *ofprop_get_property(const struct ofprop *prop,
1088 const char **propname, int *lenp)
1089 {
1090 if (ofnode_is_np(prop->node))
1091 return of_get_property_by_prop(ofnode_to_np(prop->node),
1092 prop->prop, propname, lenp);
1093 else
1094 return fdt_getprop_by_offset(ofnode_to_fdt(prop->node),
1095 prop->offset,
1096 propname, lenp);
1097 }
1098
ofnode_get_addr_size(ofnode node,const char * property,fdt_size_t * sizep)1099 fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
1100 fdt_size_t *sizep)
1101 {
1102 if (ofnode_is_np(node)) {
1103 int na, ns;
1104 int psize;
1105 const struct device_node *np = ofnode_to_np(node);
1106 const __be32 *prop = of_get_property(np, property, &psize);
1107
1108 if (!prop)
1109 return FDT_ADDR_T_NONE;
1110 na = of_n_addr_cells(np);
1111 ns = of_n_size_cells(np);
1112 *sizep = of_read_number(prop + na, ns);
1113
1114 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
1115 return of_translate_address(np, prop);
1116 else
1117 return of_read_number(prop, na);
1118 } else {
1119 return fdtdec_get_addr_size(ofnode_to_fdt(node),
1120 ofnode_to_offset(node), property,
1121 sizep);
1122 }
1123 }
1124
ofnode_read_u8_array_ptr(ofnode node,const char * propname,size_t sz)1125 const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
1126 size_t sz)
1127 {
1128 if (ofnode_is_np(node)) {
1129 const struct device_node *np = ofnode_to_np(node);
1130 int psize;
1131 const __be32 *prop = of_get_property(np, propname, &psize);
1132
1133 if (!prop || sz != psize)
1134 return NULL;
1135 return (uint8_t *)prop;
1136
1137 } else {
1138 return fdtdec_locate_byte_array(ofnode_to_fdt(node),
1139 ofnode_to_offset(node), propname, sz);
1140 }
1141 }
1142
ofnode_read_pci_addr(ofnode node,enum fdt_pci_space type,const char * propname,struct fdt_pci_addr * addr)1143 int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
1144 const char *propname, struct fdt_pci_addr *addr)
1145 {
1146 const fdt32_t *cell;
1147 int len;
1148 int ret = -ENOENT;
1149
1150 debug("%s: %s: ", __func__, propname);
1151
1152 /*
1153 * If we follow the pci bus bindings strictly, we should check
1154 * the value of the node's parent node's #address-cells and
1155 * #size-cells. They need to be 3 and 2 accordingly. However,
1156 * for simplicity we skip the check here.
1157 */
1158 cell = ofnode_get_property(node, propname, &len);
1159 if (!cell)
1160 goto fail;
1161
1162 if ((len % FDT_PCI_REG_SIZE) == 0) {
1163 int num = len / FDT_PCI_REG_SIZE;
1164 int i;
1165
1166 for (i = 0; i < num; i++) {
1167 debug("pci address #%d: %08lx %08lx %08lx\n", i,
1168 (ulong)fdt32_to_cpu(cell[0]),
1169 (ulong)fdt32_to_cpu(cell[1]),
1170 (ulong)fdt32_to_cpu(cell[2]));
1171 if ((fdt32_to_cpu(*cell) & type) == type) {
1172 addr->phys_hi = fdt32_to_cpu(cell[0]);
1173 addr->phys_mid = fdt32_to_cpu(cell[1]);
1174 addr->phys_lo = fdt32_to_cpu(cell[2]);
1175 break;
1176 }
1177
1178 cell += (FDT_PCI_ADDR_CELLS +
1179 FDT_PCI_SIZE_CELLS);
1180 }
1181
1182 if (i == num) {
1183 ret = -ENXIO;
1184 goto fail;
1185 }
1186
1187 return 0;
1188 }
1189
1190 ret = -EINVAL;
1191
1192 fail:
1193 debug("(not found)\n");
1194 return ret;
1195 }
1196
ofnode_read_pci_vendev(ofnode node,u16 * vendor,u16 * device)1197 int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
1198 {
1199 const char *list, *end;
1200 int len;
1201
1202 list = ofnode_get_property(node, "compatible", &len);
1203 if (!list)
1204 return -ENOENT;
1205
1206 end = list + len;
1207 while (list < end) {
1208 len = strlen(list);
1209 if (len >= strlen("pciVVVV,DDDD")) {
1210 char *s = strstr(list, "pci");
1211
1212 /*
1213 * check if the string is something like pciVVVV,DDDD.RR
1214 * or just pciVVVV,DDDD
1215 */
1216 if (s && s[7] == ',' &&
1217 (s[12] == '.' || s[12] == 0)) {
1218 s += 3;
1219 *vendor = simple_strtol(s, NULL, 16);
1220
1221 s += 5;
1222 *device = simple_strtol(s, NULL, 16);
1223
1224 return 0;
1225 }
1226 }
1227 list += (len + 1);
1228 }
1229
1230 return -ENOENT;
1231 }
1232
ofnode_read_eth_phy_id(ofnode node,u16 * vendor,u16 * device)1233 int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
1234 {
1235 const char *list, *end;
1236 int len;
1237
1238 list = ofnode_get_property(node, "compatible", &len);
1239
1240 if (!list)
1241 return -ENOENT;
1242
1243 end = list + len;
1244 while (list < end) {
1245 len = strlen(list);
1246
1247 if (len >= strlen("ethernet-phy-idVVVV.DDDD")) {
1248 char *s = strstr(list, "ethernet-phy-id");
1249
1250 /*
1251 * check if the string is something like
1252 * ethernet-phy-idVVVV.DDDD
1253 */
1254 if (s && s[19] == '.') {
1255 s += strlen("ethernet-phy-id");
1256 *vendor = simple_strtol(s, NULL, 16);
1257 s += 5;
1258 *device = simple_strtol(s, NULL, 16);
1259
1260 return 0;
1261 }
1262 }
1263 list += (len + 1);
1264 }
1265
1266 return -ENOENT;
1267 }
1268
ofnode_read_addr_cells(ofnode node)1269 int ofnode_read_addr_cells(ofnode node)
1270 {
1271 if (ofnode_is_np(node)) {
1272 return of_n_addr_cells(ofnode_to_np(node));
1273 } else {
1274 int parent = fdt_parent_offset(ofnode_to_fdt(node),
1275 ofnode_to_offset(node));
1276
1277 return fdt_address_cells(ofnode_to_fdt(node), parent);
1278 }
1279 }
1280
ofnode_read_size_cells(ofnode node)1281 int ofnode_read_size_cells(ofnode node)
1282 {
1283 if (ofnode_is_np(node)) {
1284 return of_n_size_cells(ofnode_to_np(node));
1285 } else {
1286 int parent = fdt_parent_offset(ofnode_to_fdt(node),
1287 ofnode_to_offset(node));
1288
1289 return fdt_size_cells(ofnode_to_fdt(node), parent);
1290 }
1291 }
1292
ofnode_read_simple_addr_cells(ofnode node)1293 int ofnode_read_simple_addr_cells(ofnode node)
1294 {
1295 if (ofnode_is_np(node))
1296 return of_simple_addr_cells(ofnode_to_np(node));
1297 else
1298 return fdt_address_cells(ofnode_to_fdt(node),
1299 ofnode_to_offset(node));
1300 }
1301
ofnode_read_simple_size_cells(ofnode node)1302 int ofnode_read_simple_size_cells(ofnode node)
1303 {
1304 if (ofnode_is_np(node))
1305 return of_simple_size_cells(ofnode_to_np(node));
1306 else
1307 return fdt_size_cells(ofnode_to_fdt(node),
1308 ofnode_to_offset(node));
1309 }
1310
ofnode_pre_reloc(ofnode node)1311 bool ofnode_pre_reloc(ofnode node)
1312 {
1313 #if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
1314 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
1315 * had property bootph-all or bootph-pre-sram/bootph-pre-ram.
1316 * They are removed in final dtb (fdtgrep 2nd pass)
1317 */
1318 return true;
1319 #else
1320 if (ofnode_read_bool(node, "bootph-all"))
1321 return true;
1322 if (ofnode_read_bool(node, "bootph-some-ram"))
1323 return true;
1324
1325 /*
1326 * In regular builds individual spl and tpl handling both
1327 * count as handled pre-relocation for later second init.
1328 */
1329 if (ofnode_read_bool(node, "bootph-pre-ram") ||
1330 ofnode_read_bool(node, "bootph-pre-sram"))
1331 return true;
1332
1333 if (IS_ENABLED(CONFIG_OF_TAG_MIGRATE)) {
1334 /* detect and handle old tags */
1335 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc") ||
1336 ofnode_read_bool(node, "u-boot,dm-pre-proper") ||
1337 ofnode_read_bool(node, "u-boot,dm-spl") ||
1338 ofnode_read_bool(node, "u-boot,dm-tpl") ||
1339 ofnode_read_bool(node, "u-boot,dm-vpl")) {
1340 gd->flags |= GD_FLG_OF_TAG_MIGRATE;
1341 return true;
1342 }
1343 }
1344
1345 return false;
1346 #endif
1347 }
1348
ofnode_read_resource(ofnode node,uint index,struct resource * res)1349 int ofnode_read_resource(ofnode node, uint index, struct resource *res)
1350 {
1351 if (ofnode_is_np(node)) {
1352 return of_address_to_resource(ofnode_to_np(node), index, res);
1353 } else {
1354 struct fdt_resource fres;
1355 int ret;
1356
1357 ret = fdt_get_resource(ofnode_to_fdt(node),
1358 ofnode_to_offset(node),
1359 "reg", index, &fres);
1360 if (ret < 0)
1361 return -EINVAL;
1362 memset(res, '\0', sizeof(*res));
1363 res->start = fres.start;
1364 res->end = fres.end;
1365
1366 return 0;
1367 }
1368 }
1369
ofnode_read_resource_byname(ofnode node,const char * name,struct resource * res)1370 int ofnode_read_resource_byname(ofnode node, const char *name,
1371 struct resource *res)
1372 {
1373 int index;
1374
1375 index = ofnode_stringlist_search(node, "reg-names", name);
1376 if (index < 0)
1377 return index;
1378
1379 return ofnode_read_resource(node, index, res);
1380 }
1381
ofnode_translate_address(ofnode node,const fdt32_t * in_addr)1382 u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
1383 {
1384 if (ofnode_is_np(node))
1385 return of_translate_address(ofnode_to_np(node), in_addr);
1386 else
1387 return fdt_translate_address(ofnode_to_fdt(node),
1388 ofnode_to_offset(node), in_addr);
1389 }
1390
ofnode_translate_dma_address(ofnode node,const fdt32_t * in_addr)1391 u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
1392 {
1393 if (ofnode_is_np(node))
1394 return of_translate_dma_address(ofnode_to_np(node), in_addr);
1395 else
1396 return fdt_translate_dma_address(ofnode_to_fdt(node),
1397 ofnode_to_offset(node), in_addr);
1398 }
1399
ofnode_get_dma_range(ofnode node,phys_addr_t * cpu,dma_addr_t * bus,u64 * size)1400 int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
1401 {
1402 if (ofnode_is_np(node))
1403 return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
1404 else
1405 return fdt_get_dma_range(ofnode_to_fdt(node),
1406 ofnode_to_offset(node),
1407 cpu, bus, size);
1408 }
1409
ofnode_device_is_compatible(ofnode node,const char * compat)1410 int ofnode_device_is_compatible(ofnode node, const char *compat)
1411 {
1412 if (ofnode_is_np(node))
1413 return of_device_is_compatible(ofnode_to_np(node), compat,
1414 NULL, NULL);
1415 else
1416 return !fdt_node_check_compatible(ofnode_to_fdt(node),
1417 ofnode_to_offset(node),
1418 compat);
1419 }
1420
ofnode_by_compatible(ofnode from,const char * compat)1421 ofnode ofnode_by_compatible(ofnode from, const char *compat)
1422 {
1423 if (of_live_active()) {
1424 return np_to_ofnode(of_find_compatible_node(
1425 (struct device_node *)ofnode_to_np(from), NULL,
1426 compat));
1427 } else {
1428 return noffset_to_ofnode(from,
1429 fdt_node_offset_by_compatible(ofnode_to_fdt(from),
1430 ofnode_to_offset(from), compat));
1431 }
1432 }
1433
ofnode_by_prop_value(ofnode from,const char * propname,const void * propval,int proplen)1434 ofnode ofnode_by_prop_value(ofnode from, const char *propname,
1435 const void *propval, int proplen)
1436 {
1437 if (of_live_active()) {
1438 return np_to_ofnode(of_find_node_by_prop_value(
1439 (struct device_node *)ofnode_to_np(from), propname,
1440 propval, proplen));
1441 } else {
1442 return noffset_to_ofnode(from,
1443 fdt_node_offset_by_prop_value(ofnode_to_fdt(from),
1444 ofnode_to_offset(from), propname, propval,
1445 proplen));
1446 }
1447 }
1448
ofnode_write_prop(ofnode node,const char * propname,const void * value,int len,bool copy)1449 int ofnode_write_prop(ofnode node, const char *propname, const void *value,
1450 int len, bool copy)
1451 {
1452 if (of_live_active()) {
1453 void *newval;
1454 int ret;
1455
1456 if (copy) {
1457 newval = malloc(len);
1458 if (!newval)
1459 return log_ret(-ENOMEM);
1460 memcpy(newval, value, len);
1461 value = newval;
1462 }
1463 ret = of_write_prop(ofnode_to_np(node), propname, len, value);
1464 if (ret && copy)
1465 free(newval);
1466 return ret;
1467 } else {
1468 return fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
1469 propname, value, len);
1470 }
1471 }
1472
ofnode_write_string(ofnode node,const char * propname,const char * value)1473 int ofnode_write_string(ofnode node, const char *propname, const char *value)
1474 {
1475 assert(ofnode_valid(node));
1476
1477 debug("%s: %s = %s", __func__, propname, value);
1478
1479 return ofnode_write_prop(node, propname, value, strlen(value) + 1,
1480 false);
1481 }
1482
ofnode_write_u32(ofnode node,const char * propname,u32 value)1483 int ofnode_write_u32(ofnode node, const char *propname, u32 value)
1484 {
1485 fdt32_t *val;
1486
1487 assert(ofnode_valid(node));
1488
1489 log_debug("%s = %x", propname, value);
1490 val = malloc(sizeof(*val));
1491 if (!val)
1492 return -ENOMEM;
1493 *val = cpu_to_fdt32(value);
1494
1495 return ofnode_write_prop(node, propname, val, sizeof(value), false);
1496 }
1497
ofnode_set_enabled(ofnode node,bool value)1498 int ofnode_set_enabled(ofnode node, bool value)
1499 {
1500 assert(ofnode_valid(node));
1501
1502 if (value)
1503 return ofnode_write_string(node, "status", "okay");
1504 else
1505 return ofnode_write_string(node, "status", "disabled");
1506 }
1507
ofnode_conf_read_bool(const char * prop_name)1508 bool ofnode_conf_read_bool(const char *prop_name)
1509 {
1510 ofnode node;
1511
1512 node = ofnode_path("/config");
1513 if (!ofnode_valid(node))
1514 return false;
1515
1516 return ofnode_read_bool(node, prop_name);
1517 }
1518
ofnode_conf_read_int(const char * prop_name,int default_val)1519 int ofnode_conf_read_int(const char *prop_name, int default_val)
1520 {
1521 ofnode node;
1522
1523 node = ofnode_path("/config");
1524 if (!ofnode_valid(node))
1525 return default_val;
1526
1527 return ofnode_read_u32_default(node, prop_name, default_val);
1528 }
1529
ofnode_conf_read_str(const char * prop_name)1530 const char *ofnode_conf_read_str(const char *prop_name)
1531 {
1532 ofnode node;
1533
1534 node = ofnode_path("/config");
1535 if (!ofnode_valid(node))
1536 return NULL;
1537
1538 return ofnode_read_string(node, prop_name);
1539 }
1540
ofnode_get_phy_node(ofnode node)1541 ofnode ofnode_get_phy_node(ofnode node)
1542 {
1543 /* DT node properties that reference a PHY node */
1544 static const char * const phy_handle_str[] = {
1545 "phy-handle", "phy", "phy-device",
1546 };
1547 struct ofnode_phandle_args args = {
1548 .node = ofnode_null()
1549 };
1550 int i;
1551
1552 assert(ofnode_valid(node));
1553
1554 for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
1555 if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
1556 NULL, 0, 0, &args))
1557 break;
1558
1559 return args.node;
1560 }
1561
ofnode_read_phy_mode(ofnode node)1562 phy_interface_t ofnode_read_phy_mode(ofnode node)
1563 {
1564 const char *mode;
1565 int i;
1566
1567 assert(ofnode_valid(node));
1568
1569 mode = ofnode_read_string(node, "phy-mode");
1570 if (!mode)
1571 mode = ofnode_read_string(node, "phy-connection-type");
1572
1573 if (!mode)
1574 return PHY_INTERFACE_MODE_NA;
1575
1576 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
1577 if (!strcmp(mode, phy_interface_strings[i]))
1578 return i;
1579
1580 debug("%s: Invalid PHY interface '%s'\n", __func__, mode);
1581
1582 return PHY_INTERFACE_MODE_NA;
1583 }
1584
ofnode_add_subnode(ofnode node,const char * name,ofnode * subnodep)1585 int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
1586 {
1587 ofnode subnode;
1588 int ret = 0;
1589
1590 assert(ofnode_valid(node));
1591
1592 if (ofnode_is_np(node)) {
1593 struct device_node *np, *child;
1594
1595 np = (struct device_node *)ofnode_to_np(node);
1596 ret = of_add_subnode(np, name, -1, &child);
1597 if (ret && ret != -EEXIST)
1598 return ret;
1599 subnode = np_to_ofnode(child);
1600 } else {
1601 void *fdt = ofnode_to_fdt(node);
1602 int poffset = ofnode_to_offset(node);
1603 int offset;
1604
1605 offset = fdt_add_subnode(fdt, poffset, name);
1606 if (offset == -FDT_ERR_EXISTS) {
1607 offset = fdt_subnode_offset(fdt, poffset, name);
1608 ret = -EEXIST;
1609 }
1610 if (offset < 0)
1611 return -EINVAL;
1612 subnode = noffset_to_ofnode(node, offset);
1613 }
1614
1615 *subnodep = subnode;
1616
1617 return ret; /* 0 or -EEXIST */
1618 }
1619
ofnode_copy_props(ofnode src,ofnode dst)1620 int ofnode_copy_props(ofnode src, ofnode dst)
1621 {
1622 struct ofprop prop;
1623
1624 ofnode_for_each_prop(prop, src) {
1625 const char *name;
1626 const char *val;
1627 int len, ret;
1628
1629 val = ofprop_get_property(&prop, &name, &len);
1630 if (!val) {
1631 log_debug("Cannot read prop (err=%d)\n", len);
1632 return log_msg_ret("get", -EINVAL);
1633 }
1634 ret = ofnode_write_prop(dst, name, val, len, true);
1635 if (ret) {
1636 log_debug("Cannot write prop (err=%d)\n", ret);
1637 return log_msg_ret("wr", -EINVAL);
1638 }
1639 }
1640
1641 return 0;
1642 }
1643