blob: 9a5eaaa4d1342a416990395a9289cd5c4a4f29e3 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassc4fc5622017-05-18 20:08:58 -06002/*
3 * Copyright (c) 2017 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glassc4fc5622017-05-18 20:08:58 -06005 */
6
Simon Glasscb13a1b2022-09-06 20:27:26 -06007#define LOG_CATEGORY LOGC_DT
8
Simon Glassc4fc5622017-05-18 20:08:58 -06009#include <dm.h>
10#include <fdtdec.h>
11#include <fdt_support.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070013#include <malloc.h>
Simon Glass722281b2023-06-01 10:22:42 -060014#include <of_live.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090015#include <linux/libfdt.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060016#include <dm/of_access.h>
Simon Glass049ae1b2017-05-18 20:09:01 -060017#include <dm/of_addr.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060018#include <dm/ofnode.h>
19#include <linux/err.h>
Simon Glassf7bfcc42017-07-25 08:29:55 -060020#include <linux/ioport.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060021#include <asm/global_data.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060022
Simon Glasscb13a1b2022-09-06 20:27:26 -060023DECLARE_GLOBAL_DATA_PTR;
24
25#if CONFIG_IS_ENABLED(OFNODE_MULTI_TREE)
26static void *oftree_list[CONFIG_OFNODE_MULTI_TREE_MAX];
27static int oftree_count;
28
29void 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
37static 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
Simon Glassa869a1b2023-09-26 08:14:40 -060049static int check_tree_count(void)
50{
51 if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) {
52 log_warning("Too many registered device trees (max %d)\n",
53 CONFIG_OFNODE_MULTI_TREE_MAX);
54 return -E2BIG;
55 }
56
57 return 0;
58}
59
Simon Glasscb13a1b2022-09-06 20:27:26 -060060static oftree oftree_ensure(void *fdt)
61{
62 oftree tree;
63 int i;
64
Simon Glass722281b2023-06-01 10:22:42 -060065 if (of_live_active()) {
66 struct device_node *root;
67 int ret;
68
69 ret = unflatten_device_tree(fdt, &root);
70 if (ret) {
71 log_err("Failed to create live tree: err=%d\n", ret);
72 return oftree_null();
73 }
74 tree = oftree_from_np(root);
75
76 return tree;
77 }
78
Simon Glasscb13a1b2022-09-06 20:27:26 -060079 if (gd->flags & GD_FLG_RELOC) {
80 i = oftree_find(fdt);
81 if (i == -1) {
Simon Glassa869a1b2023-09-26 08:14:40 -060082 if (check_tree_count())
Simon Glasscb13a1b2022-09-06 20:27:26 -060083 return oftree_null();
Simon Glasscb13a1b2022-09-06 20:27:26 -060084
Simon Glassf4c8cf22023-11-12 08:27:45 -070085 if (fdt_check_header(fdt)) {
86 log_err("Invalid device tree blob header\n");
87 return oftree_null();
88 }
89
Simon Glasscb13a1b2022-09-06 20:27:26 -060090 /* register the new tree */
91 i = oftree_count++;
92 oftree_list[i] = fdt;
93 log_debug("oftree: registered tree %d: %p\n", i, fdt);
94 }
95 } else {
96 if (fdt != gd->fdt_blob) {
Simon Glass67f8e112023-06-01 10:22:41 -060097 log_debug("Only the control FDT can be accessed before relocation\n");
Simon Glasscb13a1b2022-09-06 20:27:26 -060098 return oftree_null();
99 }
100 }
101
102 tree.fdt = fdt;
103
104 return tree;
105}
106
Simon Glassa869a1b2023-09-26 08:14:40 -0600107int oftree_new(oftree *treep)
108{
109 oftree tree = oftree_null();
110 int ret;
111
112 if (of_live_active()) {
113 struct device_node *root;
114
115 ret = of_live_create_empty(&root);
116 if (ret)
117 return log_msg_ret("liv", ret);
118 tree = oftree_from_np(root);
119 } else {
120 const int size = 1024;
121 void *fdt;
122
123 ret = check_tree_count();
124 if (ret)
125 return log_msg_ret("fla", ret);
126
127 /* register the new tree with a small size */
128 fdt = malloc(size);
129 if (!fdt)
130 return log_msg_ret("fla", -ENOMEM);
131 ret = fdt_create_empty_tree(fdt, size);
132 if (ret)
133 return log_msg_ret("fla", -EINVAL);
134 oftree_list[oftree_count++] = fdt;
135 tree.fdt = fdt;
136 }
137 *treep = tree;
138
139 return 0;
140}
141
Simon Glass722281b2023-06-01 10:22:42 -0600142void oftree_dispose(oftree tree)
143{
144 if (of_live_active())
145 of_live_free(tree.np);
146}
147
Simon Glasscb13a1b2022-09-06 20:27:26 -0600148void *ofnode_lookup_fdt(ofnode node)
149{
150 if (gd->flags & GD_FLG_RELOC) {
151 uint i = OFTREE_TREE_ID(node.of_offset);
152
Dan Carpenter408ccac2023-07-26 09:59:52 +0300153 if (i >= oftree_count) {
Simon Glasscb13a1b2022-09-06 20:27:26 -0600154 log_debug("Invalid tree ID %x\n", i);
155 return NULL;
156 }
157
158 return oftree_list[i];
159 } else {
160 return (void *)gd->fdt_blob;
161 }
162}
163
164void *ofnode_to_fdt(ofnode node)
165{
166#ifdef OF_CHECKS
167 if (of_live_active())
168 return NULL;
169#endif
170 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && ofnode_valid(node))
171 return ofnode_lookup_fdt(node);
172
173 /* Use the control FDT by default */
174 return (void *)gd->fdt_blob;
175}
176
Simon Glass45ae59d2022-09-06 20:27:24 -0600177/**
Simon Glasscb13a1b2022-09-06 20:27:26 -0600178 * ofnode_to_offset() - convert an ofnode to a flat DT offset
179 *
180 * This cannot be called if the reference contains a node pointer.
181 *
182 * @node: Reference containing offset (possibly invalid)
183 * Return: DT offset (can be -1)
184 */
185int ofnode_to_offset(ofnode node)
186{
187#ifdef OF_CHECKS
188 if (of_live_active())
189 return -1;
190#endif
191 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && node.of_offset >= 0)
192 return OFTREE_OFFSET(node.of_offset);
193
194 return node.of_offset;
195}
196
197oftree oftree_from_fdt(void *fdt)
198{
199 oftree tree;
200
201 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
202 return oftree_ensure(fdt);
203
Simon Glass994048b2023-06-01 10:22:31 -0600204#ifdef OF_CHECKS
205 if (of_live_active())
206 return oftree_null();
207#endif
Simon Glasscb13a1b2022-09-06 20:27:26 -0600208 tree.fdt = fdt;
209
210 return tree;
211}
212
213/**
214 * noffset_to_ofnode() - convert a DT offset to an ofnode
215 *
216 * @other_node: Node in the same tree to use as a reference
217 * @of_offset: DT offset (either valid, or -1)
218 * Return: reference to the associated DT offset
219 */
220ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
221{
222 ofnode node;
223
224 if (of_live_active())
225 node.np = NULL;
226 else if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) || of_offset < 0 ||
227 !ofnode_valid(other_node))
228 node.of_offset = of_offset;
229 else
230 node.of_offset = OFTREE_MAKE_NODE(other_node.of_offset,
231 of_offset);
232
233 return node;
234}
235
236#else /* !OFNODE_MULTI_TREE */
237
238static inline int oftree_find(const void *fdt)
239{
240 return 0;
241}
242
Simon Glassa869a1b2023-09-26 08:14:40 -0600243int oftree_new(oftree *treep)
244{
245 return -ENOSYS;
246}
247
Simon Glasscb13a1b2022-09-06 20:27:26 -0600248#endif /* OFNODE_MULTI_TREE */
249
Simon Glassebbe90b2023-09-26 08:14:43 -0600250int oftree_to_fdt(oftree tree, struct abuf *buf)
251{
252 int ret;
253
254 if (of_live_active()) {
255 ret = of_live_flatten(ofnode_to_np(oftree_root(tree)), buf);
256 if (ret)
257 return log_msg_ret("flt", ret);
258 } else {
259 void *fdt = oftree_lookup_fdt(tree);
260
261 abuf_init(buf);
262 abuf_set(buf, fdt, fdt_totalsize(fdt));
263 }
264
265 return 0;
266}
267
Simon Glasscb13a1b2022-09-06 20:27:26 -0600268/**
Simon Glass45ae59d2022-09-06 20:27:24 -0600269 * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
270 *
Simon Glasscb13a1b2022-09-06 20:27:26 -0600271 * Looks up the tree and returns an ofnode with the correct of_offset (i.e.
272 * containing the tree ID).
Simon Glass45ae59d2022-09-06 20:27:24 -0600273 *
Simon Glasscb13a1b2022-09-06 20:27:26 -0600274 * If @offset is < 0 then this returns an ofnode with that offset and no tree
275 * ID.
Simon Glass45ae59d2022-09-06 20:27:24 -0600276 *
277 * @tree: tree to check
278 * @offset: offset within that tree (can be < 0)
Simon Glasscb13a1b2022-09-06 20:27:26 -0600279 * @return node for that offset, with the correct ID
Simon Glass45ae59d2022-09-06 20:27:24 -0600280 */
281static ofnode ofnode_from_tree_offset(oftree tree, int offset)
282{
283 ofnode node;
284
Simon Glasscb13a1b2022-09-06 20:27:26 -0600285 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && offset >= 0) {
286 int tree_id = oftree_find(tree.fdt);
287
288 if (tree_id == -1)
289 return ofnode_null();
290 node.of_offset = OFTREE_NODE(tree_id, offset);
291 } else {
292 node.of_offset = offset;
293 }
Simon Glass45ae59d2022-09-06 20:27:24 -0600294
295 return node;
296}
297
Kishon Vijay Abraham Id6388f22021-07-21 21:28:30 +0530298bool ofnode_name_eq(ofnode node, const char *name)
299{
300 const char *node_name;
301 size_t len;
302
303 assert(ofnode_valid(node));
304
305 node_name = ofnode_get_name(node);
306 len = strchrnul(node_name, '@') - node_name;
307
308 return (strlen(name) == len) && !strncmp(node_name, name, len);
309}
310
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200311int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
312{
313 const u8 *cell;
314 int len;
315
316 assert(ofnode_valid(node));
317 debug("%s: %s: ", __func__, propname);
318
319 if (ofnode_is_np(node))
320 return of_read_u8(ofnode_to_np(node), propname, outp);
321
322 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
323 &len);
324 if (!cell || len < sizeof(*cell)) {
325 debug("(not found)\n");
326 return -EINVAL;
327 }
328 *outp = *cell;
329 debug("%#x (%d)\n", *outp, *outp);
330
331 return 0;
332}
333
334u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
335{
336 assert(ofnode_valid(node));
337 ofnode_read_u8(node, propname, &def);
338
339 return def;
340}
341
342int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
343{
344 const fdt16_t *cell;
345 int len;
346
347 assert(ofnode_valid(node));
348 debug("%s: %s: ", __func__, propname);
349
350 if (ofnode_is_np(node))
351 return of_read_u16(ofnode_to_np(node), propname, outp);
352
353 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
354 &len);
355 if (!cell || len < sizeof(*cell)) {
356 debug("(not found)\n");
357 return -EINVAL;
358 }
359 *outp = be16_to_cpup(cell);
360 debug("%#x (%d)\n", *outp, *outp);
361
362 return 0;
363}
364
365u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def)
366{
367 assert(ofnode_valid(node));
368 ofnode_read_u16(node, propname, &def);
369
370 return def;
371}
372
Simon Glassc4fc5622017-05-18 20:08:58 -0600373int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
374{
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200375 return ofnode_read_u32_index(node, propname, 0, outp);
Simon Glassc4fc5622017-05-18 20:08:58 -0600376}
377
Trent Piepho5b775412019-05-10 17:48:20 +0000378u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
Simon Glassc4fc5622017-05-18 20:08:58 -0600379{
380 assert(ofnode_valid(node));
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200381 ofnode_read_u32_index(node, propname, 0, &def);
Simon Glassc4fc5622017-05-18 20:08:58 -0600382
383 return def;
384}
385
Dario Binacchi81d80b52020-03-29 18:04:41 +0200386int ofnode_read_u32_index(ofnode node, const char *propname, int index,
387 u32 *outp)
388{
389 const fdt32_t *cell;
390 int len;
391
392 assert(ofnode_valid(node));
393 debug("%s: %s: ", __func__, propname);
394
395 if (ofnode_is_np(node))
396 return of_read_u32_index(ofnode_to_np(node), propname, index,
397 outp);
398
Simon Glass04fa09a2022-09-06 20:27:20 -0600399 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
400 propname, &len);
Dario Binacchi81d80b52020-03-29 18:04:41 +0200401 if (!cell) {
402 debug("(not found)\n");
403 return -EINVAL;
404 }
405
406 if (len < (sizeof(int) * (index + 1))) {
407 debug("(not large enough)\n");
408 return -EOVERFLOW;
409 }
410
411 *outp = fdt32_to_cpu(cell[index]);
412 debug("%#x (%d)\n", *outp, *outp);
413
414 return 0;
415}
416
Michal Simek08a194e2023-08-25 11:37:46 +0200417int ofnode_read_u64_index(ofnode node, const char *propname, int index,
418 u64 *outp)
419{
420 const fdt64_t *cell;
421 int len;
422
423 assert(ofnode_valid(node));
424
425 if (ofnode_is_np(node))
426 return of_read_u64_index(ofnode_to_np(node), propname, index,
427 outp);
428
429 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
430 propname, &len);
431 if (!cell) {
432 debug("(not found)\n");
433 return -EINVAL;
434 }
435
436 if (len < (sizeof(u64) * (index + 1))) {
437 debug("(not large enough)\n");
438 return -EOVERFLOW;
439 }
440
441 *outp = fdt64_to_cpu(cell[index]);
442 debug("%#llx (%lld)\n", *outp, *outp);
443
444 return 0;
445}
446
Dario Binacchi81d80b52020-03-29 18:04:41 +0200447u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
448 u32 def)
449{
450 assert(ofnode_valid(node));
451 ofnode_read_u32_index(node, propname, index, &def);
452
453 return def;
454}
455
Simon Glassc4fc5622017-05-18 20:08:58 -0600456int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
457{
458 assert(ofnode_valid(node));
459 ofnode_read_u32(node, propname, (u32 *)&def);
460
461 return def;
462}
463
Simon Glass9d54a7a2018-06-11 13:07:10 -0600464int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
465{
Jean-Jacques Hiblot487f9172019-10-22 10:05:22 +0200466 const unaligned_fdt64_t *cell;
Simon Glass9d54a7a2018-06-11 13:07:10 -0600467 int len;
468
469 assert(ofnode_valid(node));
470 debug("%s: %s: ", __func__, propname);
471
472 if (ofnode_is_np(node))
473 return of_read_u64(ofnode_to_np(node), propname, outp);
474
Simon Glass04fa09a2022-09-06 20:27:20 -0600475 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
476 propname, &len);
Simon Glass9d54a7a2018-06-11 13:07:10 -0600477 if (!cell || len < sizeof(*cell)) {
478 debug("(not found)\n");
479 return -EINVAL;
480 }
481 *outp = fdt64_to_cpu(cell[0]);
482 debug("%#llx (%lld)\n", (unsigned long long)*outp,
483 (unsigned long long)*outp);
484
485 return 0;
486}
487
T Karthik Reddy478860d2019-09-02 16:34:30 +0200488u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
Simon Glass9d54a7a2018-06-11 13:07:10 -0600489{
490 assert(ofnode_valid(node));
491 ofnode_read_u64(node, propname, &def);
492
493 return def;
494}
495
Simon Glassc4fc5622017-05-18 20:08:58 -0600496bool ofnode_read_bool(ofnode node, const char *propname)
497{
Simon Glass86ef3992023-09-26 08:14:44 -0600498 bool prop;
Simon Glassc4fc5622017-05-18 20:08:58 -0600499
500 assert(ofnode_valid(node));
501 debug("%s: %s: ", __func__, propname);
502
Simon Glass86ef3992023-09-26 08:14:44 -0600503 prop = ofnode_has_property(node, propname);
Masahiro Yamada5d434452017-06-22 16:54:07 +0900504
505 debug("%s\n", prop ? "true" : "false");
Simon Glassc4fc5622017-05-18 20:08:58 -0600506
Masahiro Yamada5d434452017-06-22 16:54:07 +0900507 return prop ? true : false;
Simon Glassc4fc5622017-05-18 20:08:58 -0600508}
509
Simon Glass0c2e9802020-01-27 08:49:44 -0700510const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600511{
Simon Glass0c2e9802020-01-27 08:49:44 -0700512 const char *val = NULL;
513 int len;
Simon Glassc4fc5622017-05-18 20:08:58 -0600514
515 assert(ofnode_valid(node));
516 debug("%s: %s: ", __func__, propname);
517
518 if (ofnode_is_np(node)) {
519 struct property *prop = of_find_property(
Simon Glass0c2e9802020-01-27 08:49:44 -0700520 ofnode_to_np(node), propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600521
522 if (prop) {
Simon Glass0c2e9802020-01-27 08:49:44 -0700523 val = prop->value;
Simon Glassc4fc5622017-05-18 20:08:58 -0600524 len = prop->length;
525 }
526 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600527 val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600528 propname, &len);
529 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700530 if (!val) {
Simon Glassc4fc5622017-05-18 20:08:58 -0600531 debug("<not found>\n");
Simon Glass0c2e9802020-01-27 08:49:44 -0700532 if (sizep)
533 *sizep = -FDT_ERR_NOTFOUND;
Simon Glassc4fc5622017-05-18 20:08:58 -0600534 return NULL;
535 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700536 if (sizep)
537 *sizep = len;
538
539 return val;
540}
541
542const char *ofnode_read_string(ofnode node, const char *propname)
543{
544 const char *str;
545 int len;
546
547 str = ofnode_read_prop(node, propname, &len);
548 if (!str)
549 return NULL;
550
Simon Glassc4fc5622017-05-18 20:08:58 -0600551 if (strnlen(str, len) >= len) {
552 debug("<invalid>\n");
553 return NULL;
554 }
555 debug("%s\n", str);
556
557 return str;
558}
559
Simon Glass81c54b32020-01-27 08:49:45 -0700560int ofnode_read_size(ofnode node, const char *propname)
561{
562 int len;
563
564 if (!ofnode_read_prop(node, propname, &len))
565 return -EINVAL;
566
567 return len;
568}
569
Simon Glassc4fc5622017-05-18 20:08:58 -0600570ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
571{
572 ofnode subnode;
573
574 assert(ofnode_valid(node));
575 debug("%s: %s: ", __func__, subnode_name);
576
577 if (ofnode_is_np(node)) {
Simon Glass9036c5c2022-09-06 20:27:04 -0600578 struct device_node *np = ofnode_to_np(node);
Simon Glassc4fc5622017-05-18 20:08:58 -0600579
580 for (np = np->child; np; np = np->sibling) {
581 if (!strcmp(subnode_name, np->name))
582 break;
583 }
584 subnode = np_to_ofnode(np);
585 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600586 int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600587 ofnode_to_offset(node), subnode_name);
Simon Glass37dcd912022-09-06 20:27:23 -0600588 subnode = noffset_to_ofnode(node, ooffset);
Simon Glassc4fc5622017-05-18 20:08:58 -0600589 }
590 debug("%s\n", ofnode_valid(subnode) ?
591 ofnode_get_name(subnode) : "<none>");
592
593 return subnode;
594}
595
596int ofnode_read_u32_array(ofnode node, const char *propname,
597 u32 *out_values, size_t sz)
598{
599 assert(ofnode_valid(node));
600 debug("%s: %s: ", __func__, propname);
601
602 if (ofnode_is_np(node)) {
603 return of_read_u32_array(ofnode_to_np(node), propname,
604 out_values, sz);
605 } else {
Simon Glasse3be5fc2022-09-06 20:27:18 -0600606 int ret;
607
Simon Glass04fa09a2022-09-06 20:27:20 -0600608 ret = fdtdec_get_int_array(ofnode_to_fdt(node),
Simon Glasse3be5fc2022-09-06 20:27:18 -0600609 ofnode_to_offset(node), propname,
610 out_values, sz);
611
612 /* get the error right, but space is more important in SPL */
613 if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
614 if (ret == -FDT_ERR_NOTFOUND)
615 return -EINVAL;
616 else if (ret == -FDT_ERR_BADLAYOUT)
617 return -EOVERFLOW;
618 }
619 return ret;
Simon Glassc4fc5622017-05-18 20:08:58 -0600620 }
621}
622
Simon Glass39f1d282020-12-16 17:25:06 -0700623#if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
Simon Glass5de5b3b2020-11-28 17:50:02 -0700624bool ofnode_is_enabled(ofnode node)
625{
626 if (ofnode_is_np(node)) {
627 return of_device_is_available(ofnode_to_np(node));
628 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600629 return fdtdec_get_is_enabled(ofnode_to_fdt(node),
Simon Glass5de5b3b2020-11-28 17:50:02 -0700630 ofnode_to_offset(node));
631 }
632}
633
Simon Glassc4fc5622017-05-18 20:08:58 -0600634ofnode ofnode_first_subnode(ofnode node)
635{
636 assert(ofnode_valid(node));
637 if (ofnode_is_np(node))
638 return np_to_ofnode(node.np->child);
639
Simon Glass37dcd912022-09-06 20:27:23 -0600640 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600641 fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600642}
643
644ofnode ofnode_next_subnode(ofnode node)
645{
646 assert(ofnode_valid(node));
647 if (ofnode_is_np(node))
648 return np_to_ofnode(node.np->sibling);
649
Simon Glass37dcd912022-09-06 20:27:23 -0600650 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600651 fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600652}
Simon Glass39f1d282020-12-16 17:25:06 -0700653#endif /* !DM_INLINE_OFNODE */
Simon Glassc4fc5622017-05-18 20:08:58 -0600654
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100655ofnode ofnode_get_parent(ofnode node)
656{
657 ofnode parent;
658
659 assert(ofnode_valid(node));
660 if (ofnode_is_np(node))
661 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
662 else
Simon Glass04fa09a2022-09-06 20:27:20 -0600663 parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100664 ofnode_to_offset(node));
665
666 return parent;
667}
668
Simon Glassc4fc5622017-05-18 20:08:58 -0600669const char *ofnode_get_name(ofnode node)
670{
Kever Yang8d7976d2019-07-19 11:23:47 +0800671 if (!ofnode_valid(node)) {
672 debug("%s node not valid\n", __func__);
673 return NULL;
674 }
675
Simon Glassc4fc5622017-05-18 20:08:58 -0600676 if (ofnode_is_np(node))
Simon Glass91d89a82022-09-06 20:27:15 -0600677 return node.np->name;
Simon Glassc4fc5622017-05-18 20:08:58 -0600678
Simon Glass04fa09a2022-09-06 20:27:20 -0600679 return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600680}
681
Marek Behúne897e3c2021-05-26 14:08:18 +0200682int ofnode_get_path(ofnode node, char *buf, int buflen)
683{
684 assert(ofnode_valid(node));
685
686 if (ofnode_is_np(node)) {
687 if (strlen(node.np->full_name) >= buflen)
688 return -ENOSPC;
689
690 strcpy(buf, node.np->full_name);
691
692 return 0;
693 } else {
694 int res;
695
Simon Glass04fa09a2022-09-06 20:27:20 -0600696 res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
Marek Behúne897e3c2021-05-26 14:08:18 +0200697 buflen);
698 if (!res)
699 return res;
700 else if (res == -FDT_ERR_NOSPACE)
701 return -ENOSPC;
702 else
703 return -EINVAL;
704 }
705}
706
Kever Yang37df0e02018-02-23 17:38:50 +0100707ofnode ofnode_get_by_phandle(uint phandle)
708{
709 ofnode node;
710
711 if (of_live_active())
Simon Glass176dd432022-09-06 20:26:57 -0600712 node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
Kever Yang37df0e02018-02-23 17:38:50 +0100713 else
714 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
715 phandle);
716
717 return node;
718}
719
Simon Glass95fd2092022-09-06 20:27:22 -0600720ofnode oftree_get_by_phandle(oftree tree, uint phandle)
721{
722 ofnode node;
723
724 if (of_live_active())
725 node = np_to_ofnode(of_find_node_by_phandle(tree.np, phandle));
726 else
Simon Glassf912a722022-09-06 20:27:27 -0600727 node = ofnode_from_tree_offset(tree,
Simon Glass95fd2092022-09-06 20:27:22 -0600728 fdt_node_offset_by_phandle(oftree_lookup_fdt(tree),
Simon Glassf912a722022-09-06 20:27:27 -0600729 phandle));
Simon Glass95fd2092022-09-06 20:27:22 -0600730
731 return node;
732}
733
Marek Behún177ab7f2021-05-26 14:08:17 +0200734static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
735 fdt_size_t *size, bool translate)
Simon Glass049ae1b2017-05-18 20:09:01 -0600736{
Keerthy34222a32018-11-19 11:44:47 +0530737 int na, ns;
Keerthy34222a32018-11-19 11:44:47 +0530738
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800739 if (size)
740 *size = FDT_SIZE_T_NONE;
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800741
Simon Glass049ae1b2017-05-18 20:09:01 -0600742 if (ofnode_is_np(node)) {
743 const __be32 *prop_val;
Simon Glass47f85de2019-09-25 08:55:50 -0600744 u64 size64;
Simon Glass049ae1b2017-05-18 20:09:01 -0600745 uint flags;
Simon Glass049ae1b2017-05-18 20:09:01 -0600746
Simon Glass47f85de2019-09-25 08:55:50 -0600747 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
748 &flags);
Simon Glass049ae1b2017-05-18 20:09:01 -0600749 if (!prop_val)
750 return FDT_ADDR_T_NONE;
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800751
Simon Glass47f85de2019-09-25 08:55:50 -0600752 if (size)
753 *size = size64;
Mario Sixd007ebc2017-12-20 09:52:12 +0100754
Mario Six35616ef2018-03-12 14:53:33 +0100755 ns = of_n_size_cells(ofnode_to_np(node));
756
Marek Behún177ab7f2021-05-26 14:08:17 +0200757 if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Sixd007ebc2017-12-20 09:52:12 +0100758 return of_translate_address(ofnode_to_np(node), prop_val);
759 } else {
760 na = of_n_addr_cells(ofnode_to_np(node));
761 return of_read_number(prop_val, na);
762 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600763 } else {
Keerthy34222a32018-11-19 11:44:47 +0530764 na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
765 ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
Simon Glass04fa09a2022-09-06 20:27:20 -0600766 return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
Keerthy34222a32018-11-19 11:44:47 +0530767 ofnode_to_offset(node), "reg",
Marek Behún177ab7f2021-05-26 14:08:17 +0200768 index, na, ns, size,
769 translate);
Simon Glass049ae1b2017-05-18 20:09:01 -0600770 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600771}
772
Marek Behún177ab7f2021-05-26 14:08:17 +0200773fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
774{
775 return __ofnode_get_addr_size_index(node, index, size, true);
776}
777
778fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
779 fdt_size_t *size)
780{
781 return __ofnode_get_addr_size_index(node, index, size, false);
782}
783
Keerthyd332e6e2019-04-24 17:19:53 +0530784fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
785{
786 fdt_size_t size;
787
788 return ofnode_get_addr_size_index(node, index, &size);
789}
790
Simon Glass049ae1b2017-05-18 20:09:01 -0600791fdt_addr_t ofnode_get_addr(ofnode node)
792{
793 return ofnode_get_addr_index(node, 0);
794}
795
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800796fdt_size_t ofnode_get_size(ofnode node)
797{
798 fdt_size_t size;
799
800 ofnode_get_addr_size_index(node, 0, &size);
801
802 return size;
803}
804
Simon Glassc4fc5622017-05-18 20:08:58 -0600805int ofnode_stringlist_search(ofnode node, const char *property,
806 const char *string)
807{
808 if (ofnode_is_np(node)) {
809 return of_property_match_string(ofnode_to_np(node),
810 property, string);
811 } else {
812 int ret;
813
Simon Glass04fa09a2022-09-06 20:27:20 -0600814 ret = fdt_stringlist_search(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600815 ofnode_to_offset(node), property,
816 string);
817 if (ret == -FDT_ERR_NOTFOUND)
818 return -ENODATA;
819 else if (ret < 0)
820 return -EINVAL;
821
822 return ret;
823 }
824}
825
826int ofnode_read_string_index(ofnode node, const char *property, int index,
827 const char **outp)
828{
829 if (ofnode_is_np(node)) {
830 return of_property_read_string_index(ofnode_to_np(node),
831 property, index, outp);
832 } else {
833 int len;
834
Simon Glass04fa09a2022-09-06 20:27:20 -0600835 *outp = fdt_stringlist_get(ofnode_to_fdt(node),
836 ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600837 property, index, &len);
838 if (len < 0)
839 return -EINVAL;
840 return 0;
841 }
842}
843
Simon Glass5fdb0052017-06-12 06:21:28 -0600844int ofnode_read_string_count(ofnode node, const char *property)
845{
846 if (ofnode_is_np(node)) {
847 return of_property_count_strings(ofnode_to_np(node), property);
848 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600849 return fdt_stringlist_count(ofnode_to_fdt(node),
Simon Glass5fdb0052017-06-12 06:21:28 -0600850 ofnode_to_offset(node), property);
851 }
852}
853
Simon Glass9580bfc2021-10-23 17:26:07 -0600854int ofnode_read_string_list(ofnode node, const char *property,
855 const char ***listp)
856{
857 const char **prop;
858 int count;
859 int i;
860
861 *listp = NULL;
862 count = ofnode_read_string_count(node, property);
863 if (count < 0)
864 return count;
865 if (!count)
866 return 0;
867
868 prop = calloc(count + 1, sizeof(char *));
869 if (!prop)
870 return -ENOMEM;
871
872 for (i = 0; i < count; i++)
873 ofnode_read_string_index(node, property, i, &prop[i]);
874 prop[count] = NULL;
875 *listp = prop;
876
877 return count;
878}
879
Simon Glassc4fc5622017-05-18 20:08:58 -0600880static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
881 struct ofnode_phandle_args *out)
882{
883 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
884 out->node = offset_to_ofnode(in->node);
885 out->args_count = in->args_count;
886 memcpy(out->args, in->args, sizeof(out->args));
887}
888
889static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
890 struct ofnode_phandle_args *out)
891{
892 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
893 out->node = np_to_ofnode(in->np);
894 out->args_count = in->args_count;
895 memcpy(out->args, in->args, sizeof(out->args));
896}
897
898int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
899 const char *cells_name, int cell_count,
900 int index,
901 struct ofnode_phandle_args *out_args)
902{
903 if (ofnode_is_np(node)) {
904 struct of_phandle_args args;
905 int ret;
906
907 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay21e3b042020-09-10 18:26:17 +0200908 list_name, cells_name,
909 cell_count, index,
Mario Sixf40d82c2018-01-15 11:07:17 +0100910 &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600911 if (ret)
912 return ret;
913 ofnode_from_of_phandle_args(&args, out_args);
914 } else {
915 struct fdtdec_phandle_args args;
916 int ret;
917
Simon Glass04fa09a2022-09-06 20:27:20 -0600918 ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Mario Sixf40d82c2018-01-15 11:07:17 +0100919 ofnode_to_offset(node),
920 list_name, cells_name,
921 cell_count, index, &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600922 if (ret)
923 return ret;
924 ofnode_from_fdtdec_phandle_args(&args, out_args);
925 }
926
927 return 0;
928}
929
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200930int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200931 const char *cells_name, int cell_count)
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200932{
933 if (ofnode_is_np(node))
934 return of_count_phandle_with_args(ofnode_to_np(node),
Patrick Delaunayd776a842020-09-25 09:41:14 +0200935 list_name, cells_name, cell_count);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200936 else
Simon Glass04fa09a2022-09-06 20:27:20 -0600937 return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200938 ofnode_to_offset(node), list_name, cells_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200939 cell_count, -1, NULL);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200940}
941
Simon Glassc4fc5622017-05-18 20:08:58 -0600942ofnode ofnode_path(const char *path)
943{
944 if (of_live_active())
945 return np_to_ofnode(of_find_node_by_path(path));
946 else
947 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
948}
949
Simon Glass45ae59d2022-09-06 20:27:24 -0600950ofnode oftree_root(oftree tree)
Simon Glassef75c592022-07-30 15:52:08 -0600951{
Simon Glass45ae59d2022-09-06 20:27:24 -0600952 if (of_live_active()) {
953 return np_to_ofnode(tree.np);
954 } else {
955 return ofnode_from_tree_offset(tree, 0);
956 }
957}
958
959ofnode oftree_path(oftree tree, const char *path)
960{
961 if (of_live_active()) {
Simon Glassef75c592022-07-30 15:52:08 -0600962 return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
963 NULL));
Simon Glass45ae59d2022-09-06 20:27:24 -0600964 } else if (*path != '/' && tree.fdt != gd->fdt_blob) {
Simon Glassef75c592022-07-30 15:52:08 -0600965 return ofnode_null(); /* Aliases only on control FDT */
Simon Glass45ae59d2022-09-06 20:27:24 -0600966 } else {
967 int offset = fdt_path_offset(tree.fdt, path);
968
969 return ofnode_from_tree_offset(tree, offset);
970 }
Simon Glassef75c592022-07-30 15:52:08 -0600971}
972
Simon Glasse09223c2020-01-27 08:49:46 -0700973const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600974{
975 ofnode chosen_node;
976
977 chosen_node = ofnode_path("/chosen");
978
Simon Glasse09223c2020-01-27 08:49:46 -0700979 return ofnode_read_prop(chosen_node, propname, sizep);
Simon Glassc4fc5622017-05-18 20:08:58 -0600980}
981
Simon Glasse09223c2020-01-27 08:49:46 -0700982const char *ofnode_read_chosen_string(const char *propname)
983{
984 return ofnode_read_chosen_prop(propname, NULL);
985}
986
Simon Glassc4fc5622017-05-18 20:08:58 -0600987ofnode ofnode_get_chosen_node(const char *name)
988{
989 const char *prop;
990
Simon Glasse09223c2020-01-27 08:49:46 -0700991 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600992 if (!prop)
993 return ofnode_null();
994
995 return ofnode_path(prop);
996}
997
Algapally Santosh Sagardf178992023-09-21 16:50:43 +0530998int ofnode_read_baud(void)
999{
1000 const char *str, *p;
1001 u32 baud;
1002
1003 str = ofnode_read_chosen_string("stdout-path");
1004 if (!str)
1005 return -EINVAL;
1006
1007 /* Parse string serial0:115200n8 */
1008 p = strchr(str, ':');
1009 if (!p)
1010 return -EINVAL;
1011
1012 baud = dectoul(p + 1, NULL);
1013 return baud;
1014}
1015
Michal Simek92a88622020-07-28 12:51:08 +02001016const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
1017{
1018 ofnode node;
1019
1020 node = ofnode_path("/aliases");
1021
1022 return ofnode_read_prop(node, propname, sizep);
1023}
1024
1025ofnode ofnode_get_aliases_node(const char *name)
1026{
1027 const char *prop;
1028
1029 prop = ofnode_read_aliases_prop(name, NULL);
1030 if (!prop)
1031 return ofnode_null();
1032
1033 debug("%s: node_path: %s\n", __func__, prop);
1034
1035 return ofnode_path(prop);
1036}
1037
developerd93c8b42020-05-02 11:35:09 +02001038int ofnode_get_child_count(ofnode parent)
1039{
1040 ofnode child;
1041 int num = 0;
1042
1043 ofnode_for_each_subnode(child, parent)
1044 num++;
1045
1046 return num;
1047}
1048
Simon Glassc4fc5622017-05-18 20:08:58 -06001049static int decode_timing_property(ofnode node, const char *name,
1050 struct timing_entry *result)
1051{
1052 int length, ret = 0;
1053
1054 length = ofnode_read_size(node, name);
1055 if (length < 0) {
1056 debug("%s: could not find property %s\n",
1057 ofnode_get_name(node), name);
1058 return length;
1059 }
1060
1061 if (length == sizeof(u32)) {
1062 result->typ = ofnode_read_u32_default(node, name, 0);
1063 result->min = result->typ;
1064 result->max = result->typ;
1065 } else {
1066 ret = ofnode_read_u32_array(node, name, &result->min, 3);
1067 }
1068
1069 return ret;
1070}
1071
1072int ofnode_decode_display_timing(ofnode parent, int index,
1073 struct display_timing *dt)
1074{
1075 int i;
1076 ofnode timings, node;
1077 u32 val = 0;
1078 int ret = 0;
1079
1080 timings = ofnode_find_subnode(parent, "display-timings");
1081 if (!ofnode_valid(timings))
1082 return -EINVAL;
1083
Simon Glass28529762017-08-05 15:45:54 -06001084 i = 0;
1085 ofnode_for_each_subnode(node, timings) {
1086 if (i++ == index)
1087 break;
1088 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001089
1090 if (!ofnode_valid(node))
1091 return -EINVAL;
1092
1093 memset(dt, 0, sizeof(*dt));
1094
1095 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
1096 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
1097 ret |= decode_timing_property(node, "hactive", &dt->hactive);
1098 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
1099 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
1100 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
1101 ret |= decode_timing_property(node, "vactive", &dt->vactive);
1102 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
1103 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
1104
1105 dt->flags = 0;
1106 val = ofnode_read_u32_default(node, "vsync-active", -1);
1107 if (val != -1) {
1108 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1109 DISPLAY_FLAGS_VSYNC_LOW;
1110 }
1111 val = ofnode_read_u32_default(node, "hsync-active", -1);
1112 if (val != -1) {
1113 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1114 DISPLAY_FLAGS_HSYNC_LOW;
1115 }
1116 val = ofnode_read_u32_default(node, "de-active", -1);
1117 if (val != -1) {
1118 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1119 DISPLAY_FLAGS_DE_LOW;
1120 }
1121 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
1122 if (val != -1) {
1123 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1124 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1125 }
1126
1127 if (ofnode_read_bool(node, "interlaced"))
1128 dt->flags |= DISPLAY_FLAGS_INTERLACED;
1129 if (ofnode_read_bool(node, "doublescan"))
1130 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1131 if (ofnode_read_bool(node, "doubleclk"))
1132 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1133
1134 return ret;
1135}
1136
Nikhil M Jainff407062023-01-31 15:35:14 +05301137int ofnode_decode_panel_timing(ofnode parent,
1138 struct display_timing *dt)
1139{
1140 ofnode timings;
1141 u32 val = 0;
1142 int ret = 0;
1143
Raphael Gallais-Poua853b922023-05-11 16:36:52 +02001144 timings = ofnode_find_subnode(parent, "panel-timing");
Nikhil M Jainff407062023-01-31 15:35:14 +05301145 if (!ofnode_valid(timings))
1146 return -EINVAL;
1147 memset(dt, 0, sizeof(*dt));
1148 ret |= decode_timing_property(timings, "hback-porch", &dt->hback_porch);
1149 ret |= decode_timing_property(timings, "hfront-porch", &dt->hfront_porch);
1150 ret |= decode_timing_property(timings, "hactive", &dt->hactive);
1151 ret |= decode_timing_property(timings, "hsync-len", &dt->hsync_len);
1152 ret |= decode_timing_property(timings, "vback-porch", &dt->vback_porch);
1153 ret |= decode_timing_property(timings, "vfront-porch", &dt->vfront_porch);
1154 ret |= decode_timing_property(timings, "vactive", &dt->vactive);
1155 ret |= decode_timing_property(timings, "vsync-len", &dt->vsync_len);
1156 ret |= decode_timing_property(timings, "clock-frequency", &dt->pixelclock);
1157 dt->flags = 0;
1158 if (!ofnode_read_u32(timings, "vsync-active", &val)) {
1159 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1160 DISPLAY_FLAGS_VSYNC_LOW;
1161 }
1162 if (!ofnode_read_u32(timings, "hsync-active", &val)) {
1163 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1164 DISPLAY_FLAGS_HSYNC_LOW;
1165 }
1166 if (!ofnode_read_u32(timings, "de-active", &val)) {
1167 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1168 DISPLAY_FLAGS_DE_LOW;
1169 }
1170 if (!ofnode_read_u32(timings, "pixelclk-active", &val)) {
1171 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1172 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1173 }
1174 if (ofnode_read_bool(timings, "interlaced"))
1175 dt->flags |= DISPLAY_FLAGS_INTERLACED;
1176 if (ofnode_read_bool(timings, "doublescan"))
1177 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1178 if (ofnode_read_bool(timings, "doubleclk"))
1179 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1180
1181 return ret;
1182}
1183
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +09001184const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glassc4fc5622017-05-18 20:08:58 -06001185{
Masahiro Yamada5052f1b2017-06-22 16:54:04 +09001186 if (ofnode_is_np(node))
1187 return of_get_property(ofnode_to_np(node), propname, lenp);
1188 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001189 return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001190 propname, lenp);
Simon Glassc4fc5622017-05-18 20:08:58 -06001191}
1192
Simon Glass86ef3992023-09-26 08:14:44 -06001193bool ofnode_has_property(ofnode node, const char *propname)
1194{
1195 if (ofnode_is_np(node))
1196 return of_find_property(ofnode_to_np(node), propname, NULL);
1197 else
1198 return ofnode_get_property(node, propname, NULL);
1199}
1200
Simon Glassfec058d2022-09-06 20:27:13 -06001201int ofnode_first_property(ofnode node, struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001202{
1203 prop->node = node;
1204
1205 if (ofnode_is_np(node)) {
1206 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
1207 if (!prop->prop)
1208 return -FDT_ERR_NOTFOUND;
1209 } else {
1210 prop->offset =
Simon Glass04fa09a2022-09-06 20:27:20 -06001211 fdt_first_property_offset(ofnode_to_fdt(node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001212 ofnode_to_offset(prop->node));
1213 if (prop->offset < 0)
1214 return prop->offset;
1215 }
1216
1217 return 0;
1218}
1219
Simon Glassfec058d2022-09-06 20:27:13 -06001220int ofnode_next_property(struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001221{
1222 if (ofnode_is_np(prop->node)) {
1223 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
1224 prop->prop);
1225 if (!prop->prop)
1226 return -FDT_ERR_NOTFOUND;
1227 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001228 prop->offset =
1229 fdt_next_property_offset(ofnode_to_fdt(prop->node),
1230 prop->offset);
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001231 if (prop->offset < 0)
1232 return prop->offset;
1233 }
1234
1235 return 0;
1236}
1237
Simon Glassd0aff8b2022-09-06 20:27:14 -06001238const void *ofprop_get_property(const struct ofprop *prop,
1239 const char **propname, int *lenp)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001240{
1241 if (ofnode_is_np(prop->node))
1242 return of_get_property_by_prop(ofnode_to_np(prop->node),
1243 prop->prop, propname, lenp);
1244 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001245 return fdt_getprop_by_offset(ofnode_to_fdt(prop->node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001246 prop->offset,
1247 propname, lenp);
1248}
1249
Simon Glassc4fc5622017-05-18 20:08:58 -06001250fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
1251 fdt_size_t *sizep)
1252{
1253 if (ofnode_is_np(node)) {
1254 int na, ns;
1255 int psize;
1256 const struct device_node *np = ofnode_to_np(node);
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001257 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glassc4fc5622017-05-18 20:08:58 -06001258
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001259 if (!prop)
1260 return FDT_ADDR_T_NONE;
Simon Glassc4fc5622017-05-18 20:08:58 -06001261 na = of_n_addr_cells(np);
Marek Vasut1638c172018-10-01 12:37:19 +02001262 ns = of_n_size_cells(np);
Simon Glassa67cc632017-05-18 20:09:27 -06001263 *sizep = of_read_number(prop + na, ns);
Marek Vasuta9dac492018-10-01 12:37:20 +02001264
Dario Binacchif8fc7032021-05-01 17:05:26 +02001265 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta9dac492018-10-01 12:37:20 +02001266 return of_translate_address(np, prop);
1267 else
1268 return of_read_number(prop, na);
Simon Glassc4fc5622017-05-18 20:08:58 -06001269 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001270 return fdtdec_get_addr_size(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001271 ofnode_to_offset(node), property,
1272 sizep);
1273 }
1274}
1275
1276const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
1277 size_t sz)
1278{
1279 if (ofnode_is_np(node)) {
1280 const struct device_node *np = ofnode_to_np(node);
1281 int psize;
1282 const __be32 *prop = of_get_property(np, propname, &psize);
1283
1284 if (!prop || sz != psize)
1285 return NULL;
1286 return (uint8_t *)prop;
1287
1288 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001289 return fdtdec_locate_byte_array(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001290 ofnode_to_offset(node), propname, sz);
1291 }
1292}
1293
1294int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
Simon Glass4289c262023-09-26 08:14:58 -06001295 const char *propname, struct fdt_pci_addr *addr,
1296 fdt_size_t *size)
Simon Glassc4fc5622017-05-18 20:08:58 -06001297{
Masahiro Yamada5c5991e2017-06-22 17:57:50 +09001298 const fdt32_t *cell;
Simon Glassc4fc5622017-05-18 20:08:58 -06001299 int len;
1300 int ret = -ENOENT;
1301
1302 debug("%s: %s: ", __func__, propname);
1303
1304 /*
1305 * If we follow the pci bus bindings strictly, we should check
1306 * the value of the node's parent node's #address-cells and
1307 * #size-cells. They need to be 3 and 2 accordingly. However,
1308 * for simplicity we skip the check here.
1309 */
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +09001310 cell = ofnode_get_property(node, propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -06001311 if (!cell)
1312 goto fail;
1313
1314 if ((len % FDT_PCI_REG_SIZE) == 0) {
1315 int num = len / FDT_PCI_REG_SIZE;
1316 int i;
1317
1318 for (i = 0; i < num; i++) {
1319 debug("pci address #%d: %08lx %08lx %08lx\n", i,
1320 (ulong)fdt32_to_cpu(cell[0]),
1321 (ulong)fdt32_to_cpu(cell[1]),
1322 (ulong)fdt32_to_cpu(cell[2]));
1323 if ((fdt32_to_cpu(*cell) & type) == type) {
Simon Glass4289c262023-09-26 08:14:58 -06001324 const unaligned_fdt64_t *ptr;
1325
Simon Glassc4fc5622017-05-18 20:08:58 -06001326 addr->phys_hi = fdt32_to_cpu(cell[0]);
1327 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glassdfd43152019-09-25 08:55:46 -06001328 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glass4289c262023-09-26 08:14:58 -06001329 ptr = (const unaligned_fdt64_t *)(cell + 3);
1330 if (size)
1331 *size = fdt64_to_cpu(*ptr);
Simon Glassc4fc5622017-05-18 20:08:58 -06001332 break;
Simon Glassc4fc5622017-05-18 20:08:58 -06001333 }
Mario Sixf40d82c2018-01-15 11:07:17 +01001334
Simon Glass4289c262023-09-26 08:14:58 -06001335 cell += FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS;
Simon Glassc4fc5622017-05-18 20:08:58 -06001336 }
1337
1338 if (i == num) {
1339 ret = -ENXIO;
1340 goto fail;
1341 }
1342
1343 return 0;
Simon Glassc4fc5622017-05-18 20:08:58 -06001344 }
1345
Mario Sixf40d82c2018-01-15 11:07:17 +01001346 ret = -EINVAL;
1347
Simon Glassc4fc5622017-05-18 20:08:58 -06001348fail:
1349 debug("(not found)\n");
1350 return ret;
1351}
1352
Bin Mengfa157712018-08-03 01:14:35 -07001353int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
1354{
1355 const char *list, *end;
1356 int len;
1357
1358 list = ofnode_get_property(node, "compatible", &len);
1359 if (!list)
1360 return -ENOENT;
1361
1362 end = list + len;
1363 while (list < end) {
1364 len = strlen(list);
1365 if (len >= strlen("pciVVVV,DDDD")) {
1366 char *s = strstr(list, "pci");
1367
1368 /*
1369 * check if the string is something like pciVVVV,DDDD.RR
1370 * or just pciVVVV,DDDD
1371 */
1372 if (s && s[7] == ',' &&
1373 (s[12] == '.' || s[12] == 0)) {
1374 s += 3;
1375 *vendor = simple_strtol(s, NULL, 16);
1376
1377 s += 5;
1378 *device = simple_strtol(s, NULL, 16);
1379
1380 return 0;
1381 }
1382 }
1383 list += (len + 1);
1384 }
1385
1386 return -ENOENT;
1387}
1388
Michal Simeka253c3b2022-02-23 15:45:40 +01001389int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
1390{
1391 const char *list, *end;
1392 int len;
1393
1394 list = ofnode_get_property(node, "compatible", &len);
1395
1396 if (!list)
1397 return -ENOENT;
1398
1399 end = list + len;
1400 while (list < end) {
1401 len = strlen(list);
1402
Michal Simekc633cdf2022-10-31 17:08:44 -07001403 if (len >= strlen("ethernet-phy-idVVVV.DDDD")) {
Michal Simeka253c3b2022-02-23 15:45:40 +01001404 char *s = strstr(list, "ethernet-phy-id");
1405
1406 /*
1407 * check if the string is something like
Michal Simekc633cdf2022-10-31 17:08:44 -07001408 * ethernet-phy-idVVVV.DDDD
Michal Simeka253c3b2022-02-23 15:45:40 +01001409 */
1410 if (s && s[19] == '.') {
1411 s += strlen("ethernet-phy-id");
1412 *vendor = simple_strtol(s, NULL, 16);
1413 s += 5;
1414 *device = simple_strtol(s, NULL, 16);
1415
1416 return 0;
1417 }
1418 }
1419 list += (len + 1);
1420 }
1421
1422 return -ENOENT;
1423}
1424
Simon Glassc4fc5622017-05-18 20:08:58 -06001425int ofnode_read_addr_cells(ofnode node)
1426{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001427 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001428 return of_n_addr_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001429 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001430 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001431 ofnode_to_offset(node));
1432
Simon Glass04fa09a2022-09-06 20:27:20 -06001433 return fdt_address_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001434 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001435}
1436
1437int ofnode_read_size_cells(ofnode node)
1438{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001439 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001440 return of_n_size_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001441 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001442 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001443 ofnode_to_offset(node));
1444
Simon Glass04fa09a2022-09-06 20:27:20 -06001445 return fdt_size_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001446 }
Simon Glass4191dc12017-06-12 06:21:31 -06001447}
1448
1449int ofnode_read_simple_addr_cells(ofnode node)
1450{
1451 if (ofnode_is_np(node))
1452 return of_simple_addr_cells(ofnode_to_np(node));
1453 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001454 return fdt_address_cells(ofnode_to_fdt(node),
1455 ofnode_to_offset(node));
Simon Glass4191dc12017-06-12 06:21:31 -06001456}
1457
1458int ofnode_read_simple_size_cells(ofnode node)
1459{
1460 if (ofnode_is_np(node))
1461 return of_simple_size_cells(ofnode_to_np(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001462 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001463 return fdt_size_cells(ofnode_to_fdt(node),
1464 ofnode_to_offset(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001465}
1466
1467bool ofnode_pre_reloc(ofnode node)
1468{
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001469#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
1470 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
Simon Glassfc1aa352023-02-13 08:56:34 -07001471 * had property bootph-all or bootph-pre-sram/bootph-pre-ram.
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001472 * They are removed in final dtb (fdtgrep 2nd pass)
1473 */
1474 return true;
1475#else
Simon Glassfc1aa352023-02-13 08:56:34 -07001476 if (ofnode_read_bool(node, "bootph-all"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001477 return true;
Simon Glassfc1aa352023-02-13 08:56:34 -07001478 if (ofnode_read_bool(node, "bootph-some-ram"))
Simon Glass23f22842018-10-01 12:22:18 -06001479 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001480
Simon Glassc4fc5622017-05-18 20:08:58 -06001481 /*
1482 * In regular builds individual spl and tpl handling both
1483 * count as handled pre-relocation for later second init.
1484 */
Simon Glassfc1aa352023-02-13 08:56:34 -07001485 if (ofnode_read_bool(node, "bootph-pre-ram") ||
1486 ofnode_read_bool(node, "bootph-pre-sram"))
Jonas Karlmanc43411b2023-08-20 22:03:18 +00001487 return gd->flags & GD_FLG_RELOC;
Simon Glassc4fc5622017-05-18 20:08:58 -06001488
Simon Glassc2727e52023-02-13 08:56:32 -07001489 if (IS_ENABLED(CONFIG_OF_TAG_MIGRATE)) {
1490 /* detect and handle old tags */
1491 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc") ||
1492 ofnode_read_bool(node, "u-boot,dm-pre-proper") ||
1493 ofnode_read_bool(node, "u-boot,dm-spl") ||
1494 ofnode_read_bool(node, "u-boot,dm-tpl") ||
1495 ofnode_read_bool(node, "u-boot,dm-vpl")) {
1496 gd->flags |= GD_FLG_OF_TAG_MIGRATE;
1497 return true;
1498 }
1499 }
1500
Simon Glassc4fc5622017-05-18 20:08:58 -06001501 return false;
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001502#endif
Simon Glassc4fc5622017-05-18 20:08:58 -06001503}
Simon Glassf7bfcc42017-07-25 08:29:55 -06001504
1505int ofnode_read_resource(ofnode node, uint index, struct resource *res)
1506{
1507 if (ofnode_is_np(node)) {
1508 return of_address_to_resource(ofnode_to_np(node), index, res);
1509 } else {
1510 struct fdt_resource fres;
1511 int ret;
1512
Simon Glass04fa09a2022-09-06 20:27:20 -06001513 ret = fdt_get_resource(ofnode_to_fdt(node),
1514 ofnode_to_offset(node),
Simon Glassf7bfcc42017-07-25 08:29:55 -06001515 "reg", index, &fres);
1516 if (ret < 0)
1517 return -EINVAL;
1518 memset(res, '\0', sizeof(*res));
1519 res->start = fres.start;
1520 res->end = fres.end;
1521
1522 return 0;
1523 }
1524}
Masahiro Yamada4dada2c2017-08-26 01:12:30 +09001525
1526int ofnode_read_resource_byname(ofnode node, const char *name,
1527 struct resource *res)
1528{
1529 int index;
1530
1531 index = ofnode_stringlist_search(node, "reg-names", name);
1532 if (index < 0)
1533 return index;
1534
1535 return ofnode_read_resource(node, index, res);
1536}
Mario Sixaefac062018-01-15 11:07:19 +01001537
1538u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
1539{
1540 if (ofnode_is_np(node))
1541 return of_translate_address(ofnode_to_np(node), in_addr);
1542 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001543 return fdt_translate_address(ofnode_to_fdt(node),
1544 ofnode_to_offset(node), in_addr);
Mario Sixaefac062018-01-15 11:07:19 +01001545}
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001546
Fabien Dessenne22236e02019-05-31 15:11:30 +02001547u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
1548{
1549 if (ofnode_is_np(node))
1550 return of_translate_dma_address(ofnode_to_np(node), in_addr);
1551 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001552 return fdt_translate_dma_address(ofnode_to_fdt(node),
1553 ofnode_to_offset(node), in_addr);
Fabien Dessenne22236e02019-05-31 15:11:30 +02001554}
1555
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001556int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
1557{
1558 if (ofnode_is_np(node))
1559 return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
1560 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001561 return fdt_get_dma_range(ofnode_to_fdt(node),
1562 ofnode_to_offset(node),
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001563 cpu, bus, size);
1564}
1565
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001566int ofnode_device_is_compatible(ofnode node, const char *compat)
1567{
1568 if (ofnode_is_np(node))
1569 return of_device_is_compatible(ofnode_to_np(node), compat,
1570 NULL, NULL);
1571 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001572 return !fdt_node_check_compatible(ofnode_to_fdt(node),
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001573 ofnode_to_offset(node),
1574 compat);
1575}
Simon Glass954eeae2018-06-11 13:07:13 -06001576
1577ofnode ofnode_by_compatible(ofnode from, const char *compat)
1578{
1579 if (of_live_active()) {
1580 return np_to_ofnode(of_find_compatible_node(
1581 (struct device_node *)ofnode_to_np(from), NULL,
1582 compat));
1583 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001584 return noffset_to_ofnode(from,
1585 fdt_node_offset_by_compatible(ofnode_to_fdt(from),
Simon Glass04fa09a2022-09-06 20:27:20 -06001586 ofnode_to_offset(from), compat));
Simon Glass954eeae2018-06-11 13:07:13 -06001587 }
1588}
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001589
1590ofnode ofnode_by_prop_value(ofnode from, const char *propname,
1591 const void *propval, int proplen)
1592{
1593 if (of_live_active()) {
1594 return np_to_ofnode(of_find_node_by_prop_value(
1595 (struct device_node *)ofnode_to_np(from), propname,
1596 propval, proplen));
1597 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001598 return noffset_to_ofnode(from,
1599 fdt_node_offset_by_prop_value(ofnode_to_fdt(from),
1600 ofnode_to_offset(from), propname, propval,
1601 proplen));
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001602 }
1603}
Mario Six047dafc2018-06-26 08:46:48 +02001604
Simon Glass5e2cd5e2022-07-30 15:52:10 -06001605int ofnode_write_prop(ofnode node, const char *propname, const void *value,
Simon Glass17abed02022-09-06 20:27:32 -06001606 int len, bool copy)
Mario Six047dafc2018-06-26 08:46:48 +02001607{
Simon Glass17abed02022-09-06 20:27:32 -06001608 if (of_live_active()) {
1609 void *newval;
1610 int ret;
1611
1612 if (copy) {
1613 newval = malloc(len);
1614 if (!newval)
1615 return log_ret(-ENOMEM);
1616 memcpy(newval, value, len);
1617 value = newval;
1618 }
1619 ret = of_write_prop(ofnode_to_np(node), propname, len, value);
1620 if (ret && copy)
1621 free(newval);
1622 return ret;
1623 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001624 return fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glass3ee3d152022-07-30 15:52:13 -06001625 propname, value, len);
Simon Glass17abed02022-09-06 20:27:32 -06001626 }
Mario Six047dafc2018-06-26 08:46:48 +02001627}
1628
1629int ofnode_write_string(ofnode node, const char *propname, const char *value)
1630{
Mario Six047dafc2018-06-26 08:46:48 +02001631 assert(ofnode_valid(node));
1632
1633 debug("%s: %s = %s", __func__, propname, value);
1634
Simon Glass17abed02022-09-06 20:27:32 -06001635 return ofnode_write_prop(node, propname, value, strlen(value) + 1,
1636 false);
Mario Six047dafc2018-06-26 08:46:48 +02001637}
1638
Simon Glassd28e31e2022-07-30 15:52:14 -06001639int ofnode_write_u32(ofnode node, const char *propname, u32 value)
1640{
1641 fdt32_t *val;
1642
1643 assert(ofnode_valid(node));
1644
1645 log_debug("%s = %x", propname, value);
1646 val = malloc(sizeof(*val));
1647 if (!val)
1648 return -ENOMEM;
1649 *val = cpu_to_fdt32(value);
1650
Simon Glassc681e092023-09-26 08:14:45 -06001651 return ofnode_write_prop(node, propname, val, sizeof(value), true);
1652}
1653
1654int ofnode_write_u64(ofnode node, const char *propname, u64 value)
1655{
1656 fdt64_t *val;
1657
1658 assert(ofnode_valid(node));
1659
1660 log_debug("%s = %llx", propname, (unsigned long long)value);
1661 val = malloc(sizeof(*val));
1662 if (!val)
1663 return -ENOMEM;
1664 *val = cpu_to_fdt64(value);
1665
1666 return ofnode_write_prop(node, propname, val, sizeof(value), true);
Simon Glassd28e31e2022-07-30 15:52:14 -06001667}
1668
Simon Glass86ef3992023-09-26 08:14:44 -06001669int ofnode_write_bool(ofnode node, const char *propname, bool value)
1670{
1671 if (value)
1672 return ofnode_write_prop(node, propname, NULL, 0, false);
1673 else
1674 return ofnode_delete_prop(node, propname);
1675}
1676
1677int ofnode_delete_prop(ofnode node, const char *propname)
1678{
1679 if (ofnode_is_np(node)) {
1680 struct property *prop;
1681 int len;
1682
1683 prop = of_find_property(ofnode_to_np(node), propname, &len);
1684 if (prop)
1685 return of_remove_property(ofnode_to_np(node), prop);
1686 return 0;
1687 } else {
1688 return fdt_delprop(ofnode_to_fdt(node), ofnode_to_offset(node),
1689 propname);
1690 }
1691}
1692
Mario Six047dafc2018-06-26 08:46:48 +02001693int ofnode_set_enabled(ofnode node, bool value)
1694{
Mario Six047dafc2018-06-26 08:46:48 +02001695 assert(ofnode_valid(node));
1696
1697 if (value)
1698 return ofnode_write_string(node, "status", "okay");
1699 else
Bin Menga9274aa2019-07-05 09:23:17 -07001700 return ofnode_write_string(node, "status", "disabled");
Mario Six047dafc2018-06-26 08:46:48 +02001701}
Simon Glass0034d962021-08-07 07:24:01 -06001702
1703bool ofnode_conf_read_bool(const char *prop_name)
1704{
1705 ofnode node;
1706
1707 node = ofnode_path("/config");
1708 if (!ofnode_valid(node))
1709 return false;
1710
1711 return ofnode_read_bool(node, prop_name);
1712}
1713
1714int ofnode_conf_read_int(const char *prop_name, int default_val)
1715{
1716 ofnode node;
1717
1718 node = ofnode_path("/config");
1719 if (!ofnode_valid(node))
1720 return default_val;
1721
1722 return ofnode_read_u32_default(node, prop_name, default_val);
1723}
1724
1725const char *ofnode_conf_read_str(const char *prop_name)
1726{
1727 ofnode node;
1728
1729 node = ofnode_path("/config");
1730 if (!ofnode_valid(node))
1731 return NULL;
1732
1733 return ofnode_read_string(node, prop_name);
1734}
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001735
Michal Simek43c42bd2023-08-31 08:59:05 +02001736int ofnode_read_bootscript_address(u64 *bootscr_address, u64 *bootscr_offset)
1737{
1738 int ret;
1739 ofnode uboot;
1740
1741 *bootscr_address = 0;
1742 *bootscr_offset = 0;
1743
1744 uboot = ofnode_path("/options/u-boot");
1745 if (!ofnode_valid(uboot)) {
Michal Simek951ca592023-09-11 15:30:01 +02001746 debug("%s: Missing /u-boot node\n", __func__);
Michal Simek43c42bd2023-08-31 08:59:05 +02001747 return -EINVAL;
1748 }
1749
1750 ret = ofnode_read_u64(uboot, "bootscr-address", bootscr_address);
1751 if (ret) {
1752 ret = ofnode_read_u64(uboot, "bootscr-ram-offset",
1753 bootscr_offset);
1754 if (ret)
1755 return -EINVAL;
1756 }
1757
1758 return 0;
1759}
1760
Michal Simek6a7c1ce2023-08-31 09:04:27 +02001761int ofnode_read_bootscript_flash(u64 *bootscr_flash_offset,
1762 u64 *bootscr_flash_size)
1763{
1764 int ret;
1765 ofnode uboot;
1766
1767 *bootscr_flash_offset = 0;
1768 *bootscr_flash_size = 0;
1769
1770 uboot = ofnode_path("/options/u-boot");
1771 if (!ofnode_valid(uboot)) {
Michal Simek951ca592023-09-11 15:30:01 +02001772 debug("%s: Missing /u-boot node\n", __func__);
Michal Simek6a7c1ce2023-08-31 09:04:27 +02001773 return -EINVAL;
1774 }
1775
1776 ret = ofnode_read_u64(uboot, "bootscr-flash-offset",
1777 bootscr_flash_offset);
1778 if (ret)
1779 return -EINVAL;
1780
1781 ret = ofnode_read_u64(uboot, "bootscr-flash-size",
1782 bootscr_flash_size);
1783 if (ret)
1784 return -EINVAL;
1785
1786 if (!bootscr_flash_size) {
1787 debug("bootscr-flash-size is zero. Ignoring properties!\n");
1788 *bootscr_flash_offset = 0;
1789 return -EINVAL;
1790 }
1791
1792 return 0;
1793}
1794
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001795ofnode ofnode_get_phy_node(ofnode node)
1796{
1797 /* DT node properties that reference a PHY node */
1798 static const char * const phy_handle_str[] = {
1799 "phy-handle", "phy", "phy-device",
1800 };
1801 struct ofnode_phandle_args args = {
1802 .node = ofnode_null()
1803 };
1804 int i;
1805
1806 assert(ofnode_valid(node));
1807
1808 for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
1809 if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
1810 NULL, 0, 0, &args))
1811 break;
1812
1813 return args.node;
1814}
Marek Behúnbc194772022-04-07 00:33:01 +02001815
1816phy_interface_t ofnode_read_phy_mode(ofnode node)
1817{
1818 const char *mode;
1819 int i;
1820
1821 assert(ofnode_valid(node));
1822
1823 mode = ofnode_read_string(node, "phy-mode");
1824 if (!mode)
1825 mode = ofnode_read_string(node, "phy-connection-type");
1826
1827 if (!mode)
Marek Behún48631e42022-04-07 00:33:03 +02001828 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001829
Marek Behún21a18362022-04-07 00:33:02 +02001830 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
Marek Behúnbc194772022-04-07 00:33:01 +02001831 if (!strcmp(mode, phy_interface_strings[i]))
1832 return i;
1833
1834 debug("%s: Invalid PHY interface '%s'\n", __func__, mode);
1835
Marek Behún48631e42022-04-07 00:33:03 +02001836 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001837}
Simon Glass56bc3322022-09-06 20:27:02 -06001838
1839int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
1840{
1841 ofnode subnode;
1842 int ret = 0;
1843
1844 assert(ofnode_valid(node));
1845
1846 if (ofnode_is_np(node)) {
1847 struct device_node *np, *child;
1848
1849 np = (struct device_node *)ofnode_to_np(node);
1850 ret = of_add_subnode(np, name, -1, &child);
1851 if (ret && ret != -EEXIST)
1852 return ret;
1853 subnode = np_to_ofnode(child);
1854 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001855 void *fdt = ofnode_to_fdt(node);
Simon Glass56bc3322022-09-06 20:27:02 -06001856 int poffset = ofnode_to_offset(node);
1857 int offset;
1858
1859 offset = fdt_add_subnode(fdt, poffset, name);
1860 if (offset == -FDT_ERR_EXISTS) {
1861 offset = fdt_subnode_offset(fdt, poffset, name);
1862 ret = -EEXIST;
1863 }
1864 if (offset < 0)
1865 return -EINVAL;
Simon Glass37dcd912022-09-06 20:27:23 -06001866 subnode = noffset_to_ofnode(node, offset);
Simon Glass56bc3322022-09-06 20:27:02 -06001867 }
1868
1869 *subnodep = subnode;
1870
1871 return ret; /* 0 or -EEXIST */
1872}
Simon Glass7a7229a2022-09-06 20:27:33 -06001873
Simon Glass45448772023-09-26 08:14:42 -06001874int ofnode_delete(ofnode *nodep)
1875{
1876 ofnode node = *nodep;
1877 int ret;
1878
1879 assert(ofnode_valid(node));
1880 if (ofnode_is_np(node)) {
1881 ret = of_remove_node(ofnode_to_np(node));
1882 } else {
1883 void *fdt = ofnode_to_fdt(node);
1884 int offset = ofnode_to_offset(node);
1885
1886 ret = fdt_del_node(fdt, offset);
1887 if (ret)
1888 ret = -EFAULT;
1889 }
1890 if (ret)
1891 return ret;
1892 *nodep = ofnode_null();
1893
1894 return 0;
1895}
1896
Simon Glass68164892023-09-26 08:14:37 -06001897int ofnode_copy_props(ofnode dst, ofnode src)
Simon Glass7a7229a2022-09-06 20:27:33 -06001898{
1899 struct ofprop prop;
1900
1901 ofnode_for_each_prop(prop, src) {
1902 const char *name;
1903 const char *val;
1904 int len, ret;
1905
1906 val = ofprop_get_property(&prop, &name, &len);
1907 if (!val) {
1908 log_debug("Cannot read prop (err=%d)\n", len);
1909 return log_msg_ret("get", -EINVAL);
1910 }
1911 ret = ofnode_write_prop(dst, name, val, len, true);
1912 if (ret) {
1913 log_debug("Cannot write prop (err=%d)\n", ret);
1914 return log_msg_ret("wr", -EINVAL);
1915 }
1916 }
1917
1918 return 0;
1919}
Simon Glass7c33c962023-09-26 08:14:41 -06001920
1921int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src,
1922 ofnode *nodep)
1923{
1924 ofnode node;
1925 int ret;
1926
1927 ret = ofnode_add_subnode(dst_parent, name, &node);
1928 if (ret) {
1929 if (ret == -EEXIST)
1930 *nodep = node;
1931 return log_msg_ret("add", ret);
1932 }
1933 ret = ofnode_copy_props(node, src);
1934 if (ret)
1935 return log_msg_ret("cpy", ret);
1936 *nodep = node;
1937
1938 return 0;
1939}