blob: f72ea416cf143661aea328e84e6b383892cb3955 [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 <common.h>
10#include <dm.h>
11#include <fdtdec.h>
12#include <fdt_support.h>
Simon Glass0f2af882020-05-10 11:40:05 -060013#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070014#include <malloc.h>
Simon Glass722281b2023-06-01 10:22:42 -060015#include <of_live.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090016#include <linux/libfdt.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060017#include <dm/of_access.h>
Simon Glass049ae1b2017-05-18 20:09:01 -060018#include <dm/of_addr.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060019#include <dm/ofnode.h>
20#include <linux/err.h>
Simon Glassf7bfcc42017-07-25 08:29:55 -060021#include <linux/ioport.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060022#include <asm/global_data.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060023
Simon Glasscb13a1b2022-09-06 20:27:26 -060024DECLARE_GLOBAL_DATA_PTR;
25
26#if CONFIG_IS_ENABLED(OFNODE_MULTI_TREE)
27static void *oftree_list[CONFIG_OFNODE_MULTI_TREE_MAX];
28static int oftree_count;
29
30void oftree_reset(void)
31{
32 if (gd->flags & GD_FLG_RELOC) {
33 oftree_count = 0;
34 oftree_list[oftree_count++] = (void *)gd->fdt_blob;
35 }
36}
37
38static int oftree_find(const void *fdt)
39{
40 int i;
41
42 for (i = 0; i < oftree_count; i++) {
43 if (fdt == oftree_list[i])
44 return i;
45 }
46
47 return -1;
48}
49
Simon Glassa869a1b2023-09-26 08:14:40 -060050static int check_tree_count(void)
51{
52 if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) {
53 log_warning("Too many registered device trees (max %d)\n",
54 CONFIG_OFNODE_MULTI_TREE_MAX);
55 return -E2BIG;
56 }
57
58 return 0;
59}
60
Simon Glasscb13a1b2022-09-06 20:27:26 -060061static oftree oftree_ensure(void *fdt)
62{
63 oftree tree;
64 int i;
65
Simon Glass722281b2023-06-01 10:22:42 -060066 if (of_live_active()) {
67 struct device_node *root;
68 int ret;
69
70 ret = unflatten_device_tree(fdt, &root);
71 if (ret) {
72 log_err("Failed to create live tree: err=%d\n", ret);
73 return oftree_null();
74 }
75 tree = oftree_from_np(root);
76
77 return tree;
78 }
79
Simon Glasscb13a1b2022-09-06 20:27:26 -060080 if (gd->flags & GD_FLG_RELOC) {
81 i = oftree_find(fdt);
82 if (i == -1) {
Simon Glassa869a1b2023-09-26 08:14:40 -060083 if (check_tree_count())
Simon Glasscb13a1b2022-09-06 20:27:26 -060084 return oftree_null();
Simon Glasscb13a1b2022-09-06 20:27:26 -060085
86 /* register the new tree */
87 i = oftree_count++;
88 oftree_list[i] = fdt;
89 log_debug("oftree: registered tree %d: %p\n", i, fdt);
90 }
91 } else {
92 if (fdt != gd->fdt_blob) {
Simon Glass67f8e112023-06-01 10:22:41 -060093 log_debug("Only the control FDT can be accessed before relocation\n");
Simon Glasscb13a1b2022-09-06 20:27:26 -060094 return oftree_null();
95 }
96 }
97
98 tree.fdt = fdt;
99
100 return tree;
101}
102
Simon Glassa869a1b2023-09-26 08:14:40 -0600103int oftree_new(oftree *treep)
104{
105 oftree tree = oftree_null();
106 int ret;
107
108 if (of_live_active()) {
109 struct device_node *root;
110
111 ret = of_live_create_empty(&root);
112 if (ret)
113 return log_msg_ret("liv", ret);
114 tree = oftree_from_np(root);
115 } else {
116 const int size = 1024;
117 void *fdt;
118
119 ret = check_tree_count();
120 if (ret)
121 return log_msg_ret("fla", ret);
122
123 /* register the new tree with a small size */
124 fdt = malloc(size);
125 if (!fdt)
126 return log_msg_ret("fla", -ENOMEM);
127 ret = fdt_create_empty_tree(fdt, size);
128 if (ret)
129 return log_msg_ret("fla", -EINVAL);
130 oftree_list[oftree_count++] = fdt;
131 tree.fdt = fdt;
132 }
133 *treep = tree;
134
135 return 0;
136}
137
Simon Glass722281b2023-06-01 10:22:42 -0600138void oftree_dispose(oftree tree)
139{
140 if (of_live_active())
141 of_live_free(tree.np);
142}
143
Simon Glasscb13a1b2022-09-06 20:27:26 -0600144void *ofnode_lookup_fdt(ofnode node)
145{
146 if (gd->flags & GD_FLG_RELOC) {
147 uint i = OFTREE_TREE_ID(node.of_offset);
148
Dan Carpenter408ccac2023-07-26 09:59:52 +0300149 if (i >= oftree_count) {
Simon Glasscb13a1b2022-09-06 20:27:26 -0600150 log_debug("Invalid tree ID %x\n", i);
151 return NULL;
152 }
153
154 return oftree_list[i];
155 } else {
156 return (void *)gd->fdt_blob;
157 }
158}
159
160void *ofnode_to_fdt(ofnode node)
161{
162#ifdef OF_CHECKS
163 if (of_live_active())
164 return NULL;
165#endif
166 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && ofnode_valid(node))
167 return ofnode_lookup_fdt(node);
168
169 /* Use the control FDT by default */
170 return (void *)gd->fdt_blob;
171}
172
Simon Glass45ae59d2022-09-06 20:27:24 -0600173/**
Simon Glasscb13a1b2022-09-06 20:27:26 -0600174 * ofnode_to_offset() - convert an ofnode to a flat DT offset
175 *
176 * This cannot be called if the reference contains a node pointer.
177 *
178 * @node: Reference containing offset (possibly invalid)
179 * Return: DT offset (can be -1)
180 */
181int ofnode_to_offset(ofnode node)
182{
183#ifdef OF_CHECKS
184 if (of_live_active())
185 return -1;
186#endif
187 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && node.of_offset >= 0)
188 return OFTREE_OFFSET(node.of_offset);
189
190 return node.of_offset;
191}
192
193oftree oftree_from_fdt(void *fdt)
194{
195 oftree tree;
196
197 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
198 return oftree_ensure(fdt);
199
Simon Glass994048b2023-06-01 10:22:31 -0600200#ifdef OF_CHECKS
201 if (of_live_active())
202 return oftree_null();
203#endif
Simon Glasscb13a1b2022-09-06 20:27:26 -0600204 tree.fdt = fdt;
205
206 return tree;
207}
208
209/**
210 * noffset_to_ofnode() - convert a DT offset to an ofnode
211 *
212 * @other_node: Node in the same tree to use as a reference
213 * @of_offset: DT offset (either valid, or -1)
214 * Return: reference to the associated DT offset
215 */
216ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
217{
218 ofnode node;
219
220 if (of_live_active())
221 node.np = NULL;
222 else if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) || of_offset < 0 ||
223 !ofnode_valid(other_node))
224 node.of_offset = of_offset;
225 else
226 node.of_offset = OFTREE_MAKE_NODE(other_node.of_offset,
227 of_offset);
228
229 return node;
230}
231
232#else /* !OFNODE_MULTI_TREE */
233
234static inline int oftree_find(const void *fdt)
235{
236 return 0;
237}
238
Simon Glassa869a1b2023-09-26 08:14:40 -0600239int oftree_new(oftree *treep)
240{
241 return -ENOSYS;
242}
243
Simon Glasscb13a1b2022-09-06 20:27:26 -0600244#endif /* OFNODE_MULTI_TREE */
245
Simon Glassebbe90b2023-09-26 08:14:43 -0600246int oftree_to_fdt(oftree tree, struct abuf *buf)
247{
248 int ret;
249
250 if (of_live_active()) {
251 ret = of_live_flatten(ofnode_to_np(oftree_root(tree)), buf);
252 if (ret)
253 return log_msg_ret("flt", ret);
254 } else {
255 void *fdt = oftree_lookup_fdt(tree);
256
257 abuf_init(buf);
258 abuf_set(buf, fdt, fdt_totalsize(fdt));
259 }
260
261 return 0;
262}
263
Simon Glasscb13a1b2022-09-06 20:27:26 -0600264/**
Simon Glass45ae59d2022-09-06 20:27:24 -0600265 * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
266 *
Simon Glasscb13a1b2022-09-06 20:27:26 -0600267 * Looks up the tree and returns an ofnode with the correct of_offset (i.e.
268 * containing the tree ID).
Simon Glass45ae59d2022-09-06 20:27:24 -0600269 *
Simon Glasscb13a1b2022-09-06 20:27:26 -0600270 * If @offset is < 0 then this returns an ofnode with that offset and no tree
271 * ID.
Simon Glass45ae59d2022-09-06 20:27:24 -0600272 *
273 * @tree: tree to check
274 * @offset: offset within that tree (can be < 0)
Simon Glasscb13a1b2022-09-06 20:27:26 -0600275 * @return node for that offset, with the correct ID
Simon Glass45ae59d2022-09-06 20:27:24 -0600276 */
277static ofnode ofnode_from_tree_offset(oftree tree, int offset)
278{
279 ofnode node;
280
Simon Glasscb13a1b2022-09-06 20:27:26 -0600281 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && offset >= 0) {
282 int tree_id = oftree_find(tree.fdt);
283
284 if (tree_id == -1)
285 return ofnode_null();
286 node.of_offset = OFTREE_NODE(tree_id, offset);
287 } else {
288 node.of_offset = offset;
289 }
Simon Glass45ae59d2022-09-06 20:27:24 -0600290
291 return node;
292}
293
Kishon Vijay Abraham Id6388f22021-07-21 21:28:30 +0530294bool ofnode_name_eq(ofnode node, const char *name)
295{
296 const char *node_name;
297 size_t len;
298
299 assert(ofnode_valid(node));
300
301 node_name = ofnode_get_name(node);
302 len = strchrnul(node_name, '@') - node_name;
303
304 return (strlen(name) == len) && !strncmp(node_name, name, len);
305}
306
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200307int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
308{
309 const u8 *cell;
310 int len;
311
312 assert(ofnode_valid(node));
313 debug("%s: %s: ", __func__, propname);
314
315 if (ofnode_is_np(node))
316 return of_read_u8(ofnode_to_np(node), propname, outp);
317
318 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
319 &len);
320 if (!cell || len < sizeof(*cell)) {
321 debug("(not found)\n");
322 return -EINVAL;
323 }
324 *outp = *cell;
325 debug("%#x (%d)\n", *outp, *outp);
326
327 return 0;
328}
329
330u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
331{
332 assert(ofnode_valid(node));
333 ofnode_read_u8(node, propname, &def);
334
335 return def;
336}
337
338int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
339{
340 const fdt16_t *cell;
341 int len;
342
343 assert(ofnode_valid(node));
344 debug("%s: %s: ", __func__, propname);
345
346 if (ofnode_is_np(node))
347 return of_read_u16(ofnode_to_np(node), propname, outp);
348
349 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
350 &len);
351 if (!cell || len < sizeof(*cell)) {
352 debug("(not found)\n");
353 return -EINVAL;
354 }
355 *outp = be16_to_cpup(cell);
356 debug("%#x (%d)\n", *outp, *outp);
357
358 return 0;
359}
360
361u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def)
362{
363 assert(ofnode_valid(node));
364 ofnode_read_u16(node, propname, &def);
365
366 return def;
367}
368
Simon Glassc4fc5622017-05-18 20:08:58 -0600369int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
370{
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200371 return ofnode_read_u32_index(node, propname, 0, outp);
Simon Glassc4fc5622017-05-18 20:08:58 -0600372}
373
Trent Piepho5b775412019-05-10 17:48:20 +0000374u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
Simon Glassc4fc5622017-05-18 20:08:58 -0600375{
376 assert(ofnode_valid(node));
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200377 ofnode_read_u32_index(node, propname, 0, &def);
Simon Glassc4fc5622017-05-18 20:08:58 -0600378
379 return def;
380}
381
Dario Binacchi81d80b52020-03-29 18:04:41 +0200382int ofnode_read_u32_index(ofnode node, const char *propname, int index,
383 u32 *outp)
384{
385 const fdt32_t *cell;
386 int len;
387
388 assert(ofnode_valid(node));
389 debug("%s: %s: ", __func__, propname);
390
391 if (ofnode_is_np(node))
392 return of_read_u32_index(ofnode_to_np(node), propname, index,
393 outp);
394
Simon Glass04fa09a2022-09-06 20:27:20 -0600395 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
396 propname, &len);
Dario Binacchi81d80b52020-03-29 18:04:41 +0200397 if (!cell) {
398 debug("(not found)\n");
399 return -EINVAL;
400 }
401
402 if (len < (sizeof(int) * (index + 1))) {
403 debug("(not large enough)\n");
404 return -EOVERFLOW;
405 }
406
407 *outp = fdt32_to_cpu(cell[index]);
408 debug("%#x (%d)\n", *outp, *outp);
409
410 return 0;
411}
412
Michal Simek08a194e2023-08-25 11:37:46 +0200413int ofnode_read_u64_index(ofnode node, const char *propname, int index,
414 u64 *outp)
415{
416 const fdt64_t *cell;
417 int len;
418
419 assert(ofnode_valid(node));
420
421 if (ofnode_is_np(node))
422 return of_read_u64_index(ofnode_to_np(node), propname, index,
423 outp);
424
425 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
426 propname, &len);
427 if (!cell) {
428 debug("(not found)\n");
429 return -EINVAL;
430 }
431
432 if (len < (sizeof(u64) * (index + 1))) {
433 debug("(not large enough)\n");
434 return -EOVERFLOW;
435 }
436
437 *outp = fdt64_to_cpu(cell[index]);
438 debug("%#llx (%lld)\n", *outp, *outp);
439
440 return 0;
441}
442
Dario Binacchi81d80b52020-03-29 18:04:41 +0200443u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
444 u32 def)
445{
446 assert(ofnode_valid(node));
447 ofnode_read_u32_index(node, propname, index, &def);
448
449 return def;
450}
451
Simon Glassc4fc5622017-05-18 20:08:58 -0600452int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
453{
454 assert(ofnode_valid(node));
455 ofnode_read_u32(node, propname, (u32 *)&def);
456
457 return def;
458}
459
Simon Glass9d54a7a2018-06-11 13:07:10 -0600460int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
461{
Jean-Jacques Hiblot487f9172019-10-22 10:05:22 +0200462 const unaligned_fdt64_t *cell;
Simon Glass9d54a7a2018-06-11 13:07:10 -0600463 int len;
464
465 assert(ofnode_valid(node));
466 debug("%s: %s: ", __func__, propname);
467
468 if (ofnode_is_np(node))
469 return of_read_u64(ofnode_to_np(node), propname, outp);
470
Simon Glass04fa09a2022-09-06 20:27:20 -0600471 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
472 propname, &len);
Simon Glass9d54a7a2018-06-11 13:07:10 -0600473 if (!cell || len < sizeof(*cell)) {
474 debug("(not found)\n");
475 return -EINVAL;
476 }
477 *outp = fdt64_to_cpu(cell[0]);
478 debug("%#llx (%lld)\n", (unsigned long long)*outp,
479 (unsigned long long)*outp);
480
481 return 0;
482}
483
T Karthik Reddy478860d2019-09-02 16:34:30 +0200484u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
Simon Glass9d54a7a2018-06-11 13:07:10 -0600485{
486 assert(ofnode_valid(node));
487 ofnode_read_u64(node, propname, &def);
488
489 return def;
490}
491
Simon Glassc4fc5622017-05-18 20:08:58 -0600492bool ofnode_read_bool(ofnode node, const char *propname)
493{
Simon Glass86ef3992023-09-26 08:14:44 -0600494 bool prop;
Simon Glassc4fc5622017-05-18 20:08:58 -0600495
496 assert(ofnode_valid(node));
497 debug("%s: %s: ", __func__, propname);
498
Simon Glass86ef3992023-09-26 08:14:44 -0600499 prop = ofnode_has_property(node, propname);
Masahiro Yamada5d434452017-06-22 16:54:07 +0900500
501 debug("%s\n", prop ? "true" : "false");
Simon Glassc4fc5622017-05-18 20:08:58 -0600502
Masahiro Yamada5d434452017-06-22 16:54:07 +0900503 return prop ? true : false;
Simon Glassc4fc5622017-05-18 20:08:58 -0600504}
505
Simon Glass0c2e9802020-01-27 08:49:44 -0700506const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600507{
Simon Glass0c2e9802020-01-27 08:49:44 -0700508 const char *val = NULL;
509 int len;
Simon Glassc4fc5622017-05-18 20:08:58 -0600510
511 assert(ofnode_valid(node));
512 debug("%s: %s: ", __func__, propname);
513
514 if (ofnode_is_np(node)) {
515 struct property *prop = of_find_property(
Simon Glass0c2e9802020-01-27 08:49:44 -0700516 ofnode_to_np(node), propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600517
518 if (prop) {
Simon Glass0c2e9802020-01-27 08:49:44 -0700519 val = prop->value;
Simon Glassc4fc5622017-05-18 20:08:58 -0600520 len = prop->length;
521 }
522 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600523 val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600524 propname, &len);
525 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700526 if (!val) {
Simon Glassc4fc5622017-05-18 20:08:58 -0600527 debug("<not found>\n");
Simon Glass0c2e9802020-01-27 08:49:44 -0700528 if (sizep)
529 *sizep = -FDT_ERR_NOTFOUND;
Simon Glassc4fc5622017-05-18 20:08:58 -0600530 return NULL;
531 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700532 if (sizep)
533 *sizep = len;
534
535 return val;
536}
537
538const char *ofnode_read_string(ofnode node, const char *propname)
539{
540 const char *str;
541 int len;
542
543 str = ofnode_read_prop(node, propname, &len);
544 if (!str)
545 return NULL;
546
Simon Glassc4fc5622017-05-18 20:08:58 -0600547 if (strnlen(str, len) >= len) {
548 debug("<invalid>\n");
549 return NULL;
550 }
551 debug("%s\n", str);
552
553 return str;
554}
555
Simon Glass81c54b32020-01-27 08:49:45 -0700556int ofnode_read_size(ofnode node, const char *propname)
557{
558 int len;
559
560 if (!ofnode_read_prop(node, propname, &len))
561 return -EINVAL;
562
563 return len;
564}
565
Simon Glassc4fc5622017-05-18 20:08:58 -0600566ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
567{
568 ofnode subnode;
569
570 assert(ofnode_valid(node));
571 debug("%s: %s: ", __func__, subnode_name);
572
573 if (ofnode_is_np(node)) {
Simon Glass9036c5c2022-09-06 20:27:04 -0600574 struct device_node *np = ofnode_to_np(node);
Simon Glassc4fc5622017-05-18 20:08:58 -0600575
576 for (np = np->child; np; np = np->sibling) {
577 if (!strcmp(subnode_name, np->name))
578 break;
579 }
580 subnode = np_to_ofnode(np);
581 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600582 int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600583 ofnode_to_offset(node), subnode_name);
Simon Glass37dcd912022-09-06 20:27:23 -0600584 subnode = noffset_to_ofnode(node, ooffset);
Simon Glassc4fc5622017-05-18 20:08:58 -0600585 }
586 debug("%s\n", ofnode_valid(subnode) ?
587 ofnode_get_name(subnode) : "<none>");
588
589 return subnode;
590}
591
592int ofnode_read_u32_array(ofnode node, const char *propname,
593 u32 *out_values, size_t sz)
594{
595 assert(ofnode_valid(node));
596 debug("%s: %s: ", __func__, propname);
597
598 if (ofnode_is_np(node)) {
599 return of_read_u32_array(ofnode_to_np(node), propname,
600 out_values, sz);
601 } else {
Simon Glasse3be5fc2022-09-06 20:27:18 -0600602 int ret;
603
Simon Glass04fa09a2022-09-06 20:27:20 -0600604 ret = fdtdec_get_int_array(ofnode_to_fdt(node),
Simon Glasse3be5fc2022-09-06 20:27:18 -0600605 ofnode_to_offset(node), propname,
606 out_values, sz);
607
608 /* get the error right, but space is more important in SPL */
609 if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
610 if (ret == -FDT_ERR_NOTFOUND)
611 return -EINVAL;
612 else if (ret == -FDT_ERR_BADLAYOUT)
613 return -EOVERFLOW;
614 }
615 return ret;
Simon Glassc4fc5622017-05-18 20:08:58 -0600616 }
617}
618
Simon Glass39f1d282020-12-16 17:25:06 -0700619#if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
Simon Glass5de5b3b2020-11-28 17:50:02 -0700620bool ofnode_is_enabled(ofnode node)
621{
622 if (ofnode_is_np(node)) {
623 return of_device_is_available(ofnode_to_np(node));
624 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600625 return fdtdec_get_is_enabled(ofnode_to_fdt(node),
Simon Glass5de5b3b2020-11-28 17:50:02 -0700626 ofnode_to_offset(node));
627 }
628}
629
Simon Glassc4fc5622017-05-18 20:08:58 -0600630ofnode ofnode_first_subnode(ofnode node)
631{
632 assert(ofnode_valid(node));
633 if (ofnode_is_np(node))
634 return np_to_ofnode(node.np->child);
635
Simon Glass37dcd912022-09-06 20:27:23 -0600636 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600637 fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600638}
639
640ofnode ofnode_next_subnode(ofnode node)
641{
642 assert(ofnode_valid(node));
643 if (ofnode_is_np(node))
644 return np_to_ofnode(node.np->sibling);
645
Simon Glass37dcd912022-09-06 20:27:23 -0600646 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600647 fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600648}
Simon Glass39f1d282020-12-16 17:25:06 -0700649#endif /* !DM_INLINE_OFNODE */
Simon Glassc4fc5622017-05-18 20:08:58 -0600650
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100651ofnode ofnode_get_parent(ofnode node)
652{
653 ofnode parent;
654
655 assert(ofnode_valid(node));
656 if (ofnode_is_np(node))
657 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
658 else
Simon Glass04fa09a2022-09-06 20:27:20 -0600659 parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100660 ofnode_to_offset(node));
661
662 return parent;
663}
664
Simon Glassc4fc5622017-05-18 20:08:58 -0600665const char *ofnode_get_name(ofnode node)
666{
Kever Yang8d7976d2019-07-19 11:23:47 +0800667 if (!ofnode_valid(node)) {
668 debug("%s node not valid\n", __func__);
669 return NULL;
670 }
671
Simon Glassc4fc5622017-05-18 20:08:58 -0600672 if (ofnode_is_np(node))
Simon Glass91d89a82022-09-06 20:27:15 -0600673 return node.np->name;
Simon Glassc4fc5622017-05-18 20:08:58 -0600674
Simon Glass04fa09a2022-09-06 20:27:20 -0600675 return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600676}
677
Marek Behúne897e3c2021-05-26 14:08:18 +0200678int ofnode_get_path(ofnode node, char *buf, int buflen)
679{
680 assert(ofnode_valid(node));
681
682 if (ofnode_is_np(node)) {
683 if (strlen(node.np->full_name) >= buflen)
684 return -ENOSPC;
685
686 strcpy(buf, node.np->full_name);
687
688 return 0;
689 } else {
690 int res;
691
Simon Glass04fa09a2022-09-06 20:27:20 -0600692 res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
Marek Behúne897e3c2021-05-26 14:08:18 +0200693 buflen);
694 if (!res)
695 return res;
696 else if (res == -FDT_ERR_NOSPACE)
697 return -ENOSPC;
698 else
699 return -EINVAL;
700 }
701}
702
Kever Yang37df0e02018-02-23 17:38:50 +0100703ofnode ofnode_get_by_phandle(uint phandle)
704{
705 ofnode node;
706
707 if (of_live_active())
Simon Glass176dd432022-09-06 20:26:57 -0600708 node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
Kever Yang37df0e02018-02-23 17:38:50 +0100709 else
710 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
711 phandle);
712
713 return node;
714}
715
Simon Glass95fd2092022-09-06 20:27:22 -0600716ofnode oftree_get_by_phandle(oftree tree, uint phandle)
717{
718 ofnode node;
719
720 if (of_live_active())
721 node = np_to_ofnode(of_find_node_by_phandle(tree.np, phandle));
722 else
Simon Glassf912a722022-09-06 20:27:27 -0600723 node = ofnode_from_tree_offset(tree,
Simon Glass95fd2092022-09-06 20:27:22 -0600724 fdt_node_offset_by_phandle(oftree_lookup_fdt(tree),
Simon Glassf912a722022-09-06 20:27:27 -0600725 phandle));
Simon Glass95fd2092022-09-06 20:27:22 -0600726
727 return node;
728}
729
Marek Behún177ab7f2021-05-26 14:08:17 +0200730static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
731 fdt_size_t *size, bool translate)
Simon Glass049ae1b2017-05-18 20:09:01 -0600732{
Keerthy34222a32018-11-19 11:44:47 +0530733 int na, ns;
Keerthy34222a32018-11-19 11:44:47 +0530734
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800735 if (size)
736 *size = FDT_SIZE_T_NONE;
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800737
Simon Glass049ae1b2017-05-18 20:09:01 -0600738 if (ofnode_is_np(node)) {
739 const __be32 *prop_val;
Simon Glass47f85de2019-09-25 08:55:50 -0600740 u64 size64;
Simon Glass049ae1b2017-05-18 20:09:01 -0600741 uint flags;
Simon Glass049ae1b2017-05-18 20:09:01 -0600742
Simon Glass47f85de2019-09-25 08:55:50 -0600743 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
744 &flags);
Simon Glass049ae1b2017-05-18 20:09:01 -0600745 if (!prop_val)
746 return FDT_ADDR_T_NONE;
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800747
Simon Glass47f85de2019-09-25 08:55:50 -0600748 if (size)
749 *size = size64;
Mario Sixd007ebc2017-12-20 09:52:12 +0100750
Mario Six35616ef2018-03-12 14:53:33 +0100751 ns = of_n_size_cells(ofnode_to_np(node));
752
Marek Behún177ab7f2021-05-26 14:08:17 +0200753 if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Sixd007ebc2017-12-20 09:52:12 +0100754 return of_translate_address(ofnode_to_np(node), prop_val);
755 } else {
756 na = of_n_addr_cells(ofnode_to_np(node));
757 return of_read_number(prop_val, na);
758 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600759 } else {
Keerthy34222a32018-11-19 11:44:47 +0530760 na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
761 ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
Simon Glass04fa09a2022-09-06 20:27:20 -0600762 return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
Keerthy34222a32018-11-19 11:44:47 +0530763 ofnode_to_offset(node), "reg",
Marek Behún177ab7f2021-05-26 14:08:17 +0200764 index, na, ns, size,
765 translate);
Simon Glass049ae1b2017-05-18 20:09:01 -0600766 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600767}
768
Marek Behún177ab7f2021-05-26 14:08:17 +0200769fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
770{
771 return __ofnode_get_addr_size_index(node, index, size, true);
772}
773
774fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
775 fdt_size_t *size)
776{
777 return __ofnode_get_addr_size_index(node, index, size, false);
778}
779
Keerthyd332e6e2019-04-24 17:19:53 +0530780fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
781{
782 fdt_size_t size;
783
784 return ofnode_get_addr_size_index(node, index, &size);
785}
786
Simon Glass049ae1b2017-05-18 20:09:01 -0600787fdt_addr_t ofnode_get_addr(ofnode node)
788{
789 return ofnode_get_addr_index(node, 0);
790}
791
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800792fdt_size_t ofnode_get_size(ofnode node)
793{
794 fdt_size_t size;
795
796 ofnode_get_addr_size_index(node, 0, &size);
797
798 return size;
799}
800
Simon Glassc4fc5622017-05-18 20:08:58 -0600801int ofnode_stringlist_search(ofnode node, const char *property,
802 const char *string)
803{
804 if (ofnode_is_np(node)) {
805 return of_property_match_string(ofnode_to_np(node),
806 property, string);
807 } else {
808 int ret;
809
Simon Glass04fa09a2022-09-06 20:27:20 -0600810 ret = fdt_stringlist_search(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600811 ofnode_to_offset(node), property,
812 string);
813 if (ret == -FDT_ERR_NOTFOUND)
814 return -ENODATA;
815 else if (ret < 0)
816 return -EINVAL;
817
818 return ret;
819 }
820}
821
822int ofnode_read_string_index(ofnode node, const char *property, int index,
823 const char **outp)
824{
825 if (ofnode_is_np(node)) {
826 return of_property_read_string_index(ofnode_to_np(node),
827 property, index, outp);
828 } else {
829 int len;
830
Simon Glass04fa09a2022-09-06 20:27:20 -0600831 *outp = fdt_stringlist_get(ofnode_to_fdt(node),
832 ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600833 property, index, &len);
834 if (len < 0)
835 return -EINVAL;
836 return 0;
837 }
838}
839
Simon Glass5fdb0052017-06-12 06:21:28 -0600840int ofnode_read_string_count(ofnode node, const char *property)
841{
842 if (ofnode_is_np(node)) {
843 return of_property_count_strings(ofnode_to_np(node), property);
844 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600845 return fdt_stringlist_count(ofnode_to_fdt(node),
Simon Glass5fdb0052017-06-12 06:21:28 -0600846 ofnode_to_offset(node), property);
847 }
848}
849
Simon Glass9580bfc2021-10-23 17:26:07 -0600850int ofnode_read_string_list(ofnode node, const char *property,
851 const char ***listp)
852{
853 const char **prop;
854 int count;
855 int i;
856
857 *listp = NULL;
858 count = ofnode_read_string_count(node, property);
859 if (count < 0)
860 return count;
861 if (!count)
862 return 0;
863
864 prop = calloc(count + 1, sizeof(char *));
865 if (!prop)
866 return -ENOMEM;
867
868 for (i = 0; i < count; i++)
869 ofnode_read_string_index(node, property, i, &prop[i]);
870 prop[count] = NULL;
871 *listp = prop;
872
873 return count;
874}
875
Simon Glassc4fc5622017-05-18 20:08:58 -0600876static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
877 struct ofnode_phandle_args *out)
878{
879 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
880 out->node = offset_to_ofnode(in->node);
881 out->args_count = in->args_count;
882 memcpy(out->args, in->args, sizeof(out->args));
883}
884
885static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
886 struct ofnode_phandle_args *out)
887{
888 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
889 out->node = np_to_ofnode(in->np);
890 out->args_count = in->args_count;
891 memcpy(out->args, in->args, sizeof(out->args));
892}
893
894int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
895 const char *cells_name, int cell_count,
896 int index,
897 struct ofnode_phandle_args *out_args)
898{
899 if (ofnode_is_np(node)) {
900 struct of_phandle_args args;
901 int ret;
902
903 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay21e3b042020-09-10 18:26:17 +0200904 list_name, cells_name,
905 cell_count, index,
Mario Sixf40d82c2018-01-15 11:07:17 +0100906 &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600907 if (ret)
908 return ret;
909 ofnode_from_of_phandle_args(&args, out_args);
910 } else {
911 struct fdtdec_phandle_args args;
912 int ret;
913
Simon Glass04fa09a2022-09-06 20:27:20 -0600914 ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Mario Sixf40d82c2018-01-15 11:07:17 +0100915 ofnode_to_offset(node),
916 list_name, cells_name,
917 cell_count, index, &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600918 if (ret)
919 return ret;
920 ofnode_from_fdtdec_phandle_args(&args, out_args);
921 }
922
923 return 0;
924}
925
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200926int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200927 const char *cells_name, int cell_count)
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200928{
929 if (ofnode_is_np(node))
930 return of_count_phandle_with_args(ofnode_to_np(node),
Patrick Delaunayd776a842020-09-25 09:41:14 +0200931 list_name, cells_name, cell_count);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200932 else
Simon Glass04fa09a2022-09-06 20:27:20 -0600933 return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200934 ofnode_to_offset(node), list_name, cells_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200935 cell_count, -1, NULL);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200936}
937
Simon Glassc4fc5622017-05-18 20:08:58 -0600938ofnode ofnode_path(const char *path)
939{
940 if (of_live_active())
941 return np_to_ofnode(of_find_node_by_path(path));
942 else
943 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
944}
945
Simon Glass45ae59d2022-09-06 20:27:24 -0600946ofnode oftree_root(oftree tree)
Simon Glassef75c592022-07-30 15:52:08 -0600947{
Simon Glass45ae59d2022-09-06 20:27:24 -0600948 if (of_live_active()) {
949 return np_to_ofnode(tree.np);
950 } else {
951 return ofnode_from_tree_offset(tree, 0);
952 }
953}
954
955ofnode oftree_path(oftree tree, const char *path)
956{
957 if (of_live_active()) {
Simon Glassef75c592022-07-30 15:52:08 -0600958 return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
959 NULL));
Simon Glass45ae59d2022-09-06 20:27:24 -0600960 } else if (*path != '/' && tree.fdt != gd->fdt_blob) {
Simon Glassef75c592022-07-30 15:52:08 -0600961 return ofnode_null(); /* Aliases only on control FDT */
Simon Glass45ae59d2022-09-06 20:27:24 -0600962 } else {
963 int offset = fdt_path_offset(tree.fdt, path);
964
965 return ofnode_from_tree_offset(tree, offset);
966 }
Simon Glassef75c592022-07-30 15:52:08 -0600967}
968
Simon Glasse09223c2020-01-27 08:49:46 -0700969const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600970{
971 ofnode chosen_node;
972
973 chosen_node = ofnode_path("/chosen");
974
Simon Glasse09223c2020-01-27 08:49:46 -0700975 return ofnode_read_prop(chosen_node, propname, sizep);
Simon Glassc4fc5622017-05-18 20:08:58 -0600976}
977
Simon Glasse09223c2020-01-27 08:49:46 -0700978const char *ofnode_read_chosen_string(const char *propname)
979{
980 return ofnode_read_chosen_prop(propname, NULL);
981}
982
Simon Glassc4fc5622017-05-18 20:08:58 -0600983ofnode ofnode_get_chosen_node(const char *name)
984{
985 const char *prop;
986
Simon Glasse09223c2020-01-27 08:49:46 -0700987 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600988 if (!prop)
989 return ofnode_null();
990
991 return ofnode_path(prop);
992}
993
Algapally Santosh Sagardf178992023-09-21 16:50:43 +0530994int ofnode_read_baud(void)
995{
996 const char *str, *p;
997 u32 baud;
998
999 str = ofnode_read_chosen_string("stdout-path");
1000 if (!str)
1001 return -EINVAL;
1002
1003 /* Parse string serial0:115200n8 */
1004 p = strchr(str, ':');
1005 if (!p)
1006 return -EINVAL;
1007
1008 baud = dectoul(p + 1, NULL);
1009 return baud;
1010}
1011
Michal Simek92a88622020-07-28 12:51:08 +02001012const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
1013{
1014 ofnode node;
1015
1016 node = ofnode_path("/aliases");
1017
1018 return ofnode_read_prop(node, propname, sizep);
1019}
1020
1021ofnode ofnode_get_aliases_node(const char *name)
1022{
1023 const char *prop;
1024
1025 prop = ofnode_read_aliases_prop(name, NULL);
1026 if (!prop)
1027 return ofnode_null();
1028
1029 debug("%s: node_path: %s\n", __func__, prop);
1030
1031 return ofnode_path(prop);
1032}
1033
developerd93c8b42020-05-02 11:35:09 +02001034int ofnode_get_child_count(ofnode parent)
1035{
1036 ofnode child;
1037 int num = 0;
1038
1039 ofnode_for_each_subnode(child, parent)
1040 num++;
1041
1042 return num;
1043}
1044
Simon Glassc4fc5622017-05-18 20:08:58 -06001045static int decode_timing_property(ofnode node, const char *name,
1046 struct timing_entry *result)
1047{
1048 int length, ret = 0;
1049
1050 length = ofnode_read_size(node, name);
1051 if (length < 0) {
1052 debug("%s: could not find property %s\n",
1053 ofnode_get_name(node), name);
1054 return length;
1055 }
1056
1057 if (length == sizeof(u32)) {
1058 result->typ = ofnode_read_u32_default(node, name, 0);
1059 result->min = result->typ;
1060 result->max = result->typ;
1061 } else {
1062 ret = ofnode_read_u32_array(node, name, &result->min, 3);
1063 }
1064
1065 return ret;
1066}
1067
1068int ofnode_decode_display_timing(ofnode parent, int index,
1069 struct display_timing *dt)
1070{
1071 int i;
1072 ofnode timings, node;
1073 u32 val = 0;
1074 int ret = 0;
1075
1076 timings = ofnode_find_subnode(parent, "display-timings");
1077 if (!ofnode_valid(timings))
1078 return -EINVAL;
1079
Simon Glass28529762017-08-05 15:45:54 -06001080 i = 0;
1081 ofnode_for_each_subnode(node, timings) {
1082 if (i++ == index)
1083 break;
1084 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001085
1086 if (!ofnode_valid(node))
1087 return -EINVAL;
1088
1089 memset(dt, 0, sizeof(*dt));
1090
1091 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
1092 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
1093 ret |= decode_timing_property(node, "hactive", &dt->hactive);
1094 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
1095 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
1096 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
1097 ret |= decode_timing_property(node, "vactive", &dt->vactive);
1098 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
1099 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
1100
1101 dt->flags = 0;
1102 val = ofnode_read_u32_default(node, "vsync-active", -1);
1103 if (val != -1) {
1104 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1105 DISPLAY_FLAGS_VSYNC_LOW;
1106 }
1107 val = ofnode_read_u32_default(node, "hsync-active", -1);
1108 if (val != -1) {
1109 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1110 DISPLAY_FLAGS_HSYNC_LOW;
1111 }
1112 val = ofnode_read_u32_default(node, "de-active", -1);
1113 if (val != -1) {
1114 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1115 DISPLAY_FLAGS_DE_LOW;
1116 }
1117 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
1118 if (val != -1) {
1119 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1120 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1121 }
1122
1123 if (ofnode_read_bool(node, "interlaced"))
1124 dt->flags |= DISPLAY_FLAGS_INTERLACED;
1125 if (ofnode_read_bool(node, "doublescan"))
1126 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1127 if (ofnode_read_bool(node, "doubleclk"))
1128 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1129
1130 return ret;
1131}
1132
Nikhil M Jainff407062023-01-31 15:35:14 +05301133int ofnode_decode_panel_timing(ofnode parent,
1134 struct display_timing *dt)
1135{
1136 ofnode timings;
1137 u32 val = 0;
1138 int ret = 0;
1139
Raphael Gallais-Poua853b922023-05-11 16:36:52 +02001140 timings = ofnode_find_subnode(parent, "panel-timing");
Nikhil M Jainff407062023-01-31 15:35:14 +05301141 if (!ofnode_valid(timings))
1142 return -EINVAL;
1143 memset(dt, 0, sizeof(*dt));
1144 ret |= decode_timing_property(timings, "hback-porch", &dt->hback_porch);
1145 ret |= decode_timing_property(timings, "hfront-porch", &dt->hfront_porch);
1146 ret |= decode_timing_property(timings, "hactive", &dt->hactive);
1147 ret |= decode_timing_property(timings, "hsync-len", &dt->hsync_len);
1148 ret |= decode_timing_property(timings, "vback-porch", &dt->vback_porch);
1149 ret |= decode_timing_property(timings, "vfront-porch", &dt->vfront_porch);
1150 ret |= decode_timing_property(timings, "vactive", &dt->vactive);
1151 ret |= decode_timing_property(timings, "vsync-len", &dt->vsync_len);
1152 ret |= decode_timing_property(timings, "clock-frequency", &dt->pixelclock);
1153 dt->flags = 0;
1154 if (!ofnode_read_u32(timings, "vsync-active", &val)) {
1155 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1156 DISPLAY_FLAGS_VSYNC_LOW;
1157 }
1158 if (!ofnode_read_u32(timings, "hsync-active", &val)) {
1159 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1160 DISPLAY_FLAGS_HSYNC_LOW;
1161 }
1162 if (!ofnode_read_u32(timings, "de-active", &val)) {
1163 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1164 DISPLAY_FLAGS_DE_LOW;
1165 }
1166 if (!ofnode_read_u32(timings, "pixelclk-active", &val)) {
1167 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1168 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1169 }
1170 if (ofnode_read_bool(timings, "interlaced"))
1171 dt->flags |= DISPLAY_FLAGS_INTERLACED;
1172 if (ofnode_read_bool(timings, "doublescan"))
1173 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1174 if (ofnode_read_bool(timings, "doubleclk"))
1175 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1176
1177 return ret;
1178}
1179
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +09001180const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glassc4fc5622017-05-18 20:08:58 -06001181{
Masahiro Yamada5052f1b2017-06-22 16:54:04 +09001182 if (ofnode_is_np(node))
1183 return of_get_property(ofnode_to_np(node), propname, lenp);
1184 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001185 return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001186 propname, lenp);
Simon Glassc4fc5622017-05-18 20:08:58 -06001187}
1188
Simon Glass86ef3992023-09-26 08:14:44 -06001189bool ofnode_has_property(ofnode node, const char *propname)
1190{
1191 if (ofnode_is_np(node))
1192 return of_find_property(ofnode_to_np(node), propname, NULL);
1193 else
1194 return ofnode_get_property(node, propname, NULL);
1195}
1196
Simon Glassfec058d2022-09-06 20:27:13 -06001197int ofnode_first_property(ofnode node, struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001198{
1199 prop->node = node;
1200
1201 if (ofnode_is_np(node)) {
1202 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
1203 if (!prop->prop)
1204 return -FDT_ERR_NOTFOUND;
1205 } else {
1206 prop->offset =
Simon Glass04fa09a2022-09-06 20:27:20 -06001207 fdt_first_property_offset(ofnode_to_fdt(node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001208 ofnode_to_offset(prop->node));
1209 if (prop->offset < 0)
1210 return prop->offset;
1211 }
1212
1213 return 0;
1214}
1215
Simon Glassfec058d2022-09-06 20:27:13 -06001216int ofnode_next_property(struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001217{
1218 if (ofnode_is_np(prop->node)) {
1219 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
1220 prop->prop);
1221 if (!prop->prop)
1222 return -FDT_ERR_NOTFOUND;
1223 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001224 prop->offset =
1225 fdt_next_property_offset(ofnode_to_fdt(prop->node),
1226 prop->offset);
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001227 if (prop->offset < 0)
1228 return prop->offset;
1229 }
1230
1231 return 0;
1232}
1233
Simon Glassd0aff8b2022-09-06 20:27:14 -06001234const void *ofprop_get_property(const struct ofprop *prop,
1235 const char **propname, int *lenp)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001236{
1237 if (ofnode_is_np(prop->node))
1238 return of_get_property_by_prop(ofnode_to_np(prop->node),
1239 prop->prop, propname, lenp);
1240 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001241 return fdt_getprop_by_offset(ofnode_to_fdt(prop->node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001242 prop->offset,
1243 propname, lenp);
1244}
1245
Simon Glassc4fc5622017-05-18 20:08:58 -06001246fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
1247 fdt_size_t *sizep)
1248{
1249 if (ofnode_is_np(node)) {
1250 int na, ns;
1251 int psize;
1252 const struct device_node *np = ofnode_to_np(node);
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001253 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glassc4fc5622017-05-18 20:08:58 -06001254
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001255 if (!prop)
1256 return FDT_ADDR_T_NONE;
Simon Glassc4fc5622017-05-18 20:08:58 -06001257 na = of_n_addr_cells(np);
Marek Vasut1638c172018-10-01 12:37:19 +02001258 ns = of_n_size_cells(np);
Simon Glassa67cc632017-05-18 20:09:27 -06001259 *sizep = of_read_number(prop + na, ns);
Marek Vasuta9dac492018-10-01 12:37:20 +02001260
Dario Binacchif8fc7032021-05-01 17:05:26 +02001261 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta9dac492018-10-01 12:37:20 +02001262 return of_translate_address(np, prop);
1263 else
1264 return of_read_number(prop, na);
Simon Glassc4fc5622017-05-18 20:08:58 -06001265 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001266 return fdtdec_get_addr_size(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001267 ofnode_to_offset(node), property,
1268 sizep);
1269 }
1270}
1271
1272const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
1273 size_t sz)
1274{
1275 if (ofnode_is_np(node)) {
1276 const struct device_node *np = ofnode_to_np(node);
1277 int psize;
1278 const __be32 *prop = of_get_property(np, propname, &psize);
1279
1280 if (!prop || sz != psize)
1281 return NULL;
1282 return (uint8_t *)prop;
1283
1284 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001285 return fdtdec_locate_byte_array(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001286 ofnode_to_offset(node), propname, sz);
1287 }
1288}
1289
1290int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
Simon Glass4289c262023-09-26 08:14:58 -06001291 const char *propname, struct fdt_pci_addr *addr,
1292 fdt_size_t *size)
Simon Glassc4fc5622017-05-18 20:08:58 -06001293{
Masahiro Yamada5c5991e2017-06-22 17:57:50 +09001294 const fdt32_t *cell;
Simon Glassc4fc5622017-05-18 20:08:58 -06001295 int len;
1296 int ret = -ENOENT;
1297
1298 debug("%s: %s: ", __func__, propname);
1299
1300 /*
1301 * If we follow the pci bus bindings strictly, we should check
1302 * the value of the node's parent node's #address-cells and
1303 * #size-cells. They need to be 3 and 2 accordingly. However,
1304 * for simplicity we skip the check here.
1305 */
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +09001306 cell = ofnode_get_property(node, propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -06001307 if (!cell)
1308 goto fail;
1309
1310 if ((len % FDT_PCI_REG_SIZE) == 0) {
1311 int num = len / FDT_PCI_REG_SIZE;
1312 int i;
1313
1314 for (i = 0; i < num; i++) {
1315 debug("pci address #%d: %08lx %08lx %08lx\n", i,
1316 (ulong)fdt32_to_cpu(cell[0]),
1317 (ulong)fdt32_to_cpu(cell[1]),
1318 (ulong)fdt32_to_cpu(cell[2]));
1319 if ((fdt32_to_cpu(*cell) & type) == type) {
Simon Glass4289c262023-09-26 08:14:58 -06001320 const unaligned_fdt64_t *ptr;
1321
Simon Glassc4fc5622017-05-18 20:08:58 -06001322 addr->phys_hi = fdt32_to_cpu(cell[0]);
1323 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glassdfd43152019-09-25 08:55:46 -06001324 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glass4289c262023-09-26 08:14:58 -06001325 ptr = (const unaligned_fdt64_t *)(cell + 3);
1326 if (size)
1327 *size = fdt64_to_cpu(*ptr);
Simon Glassc4fc5622017-05-18 20:08:58 -06001328 break;
Simon Glassc4fc5622017-05-18 20:08:58 -06001329 }
Mario Sixf40d82c2018-01-15 11:07:17 +01001330
Simon Glass4289c262023-09-26 08:14:58 -06001331 cell += FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS;
Simon Glassc4fc5622017-05-18 20:08:58 -06001332 }
1333
1334 if (i == num) {
1335 ret = -ENXIO;
1336 goto fail;
1337 }
1338
1339 return 0;
Simon Glassc4fc5622017-05-18 20:08:58 -06001340 }
1341
Mario Sixf40d82c2018-01-15 11:07:17 +01001342 ret = -EINVAL;
1343
Simon Glassc4fc5622017-05-18 20:08:58 -06001344fail:
1345 debug("(not found)\n");
1346 return ret;
1347}
1348
Bin Mengfa157712018-08-03 01:14:35 -07001349int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
1350{
1351 const char *list, *end;
1352 int len;
1353
1354 list = ofnode_get_property(node, "compatible", &len);
1355 if (!list)
1356 return -ENOENT;
1357
1358 end = list + len;
1359 while (list < end) {
1360 len = strlen(list);
1361 if (len >= strlen("pciVVVV,DDDD")) {
1362 char *s = strstr(list, "pci");
1363
1364 /*
1365 * check if the string is something like pciVVVV,DDDD.RR
1366 * or just pciVVVV,DDDD
1367 */
1368 if (s && s[7] == ',' &&
1369 (s[12] == '.' || s[12] == 0)) {
1370 s += 3;
1371 *vendor = simple_strtol(s, NULL, 16);
1372
1373 s += 5;
1374 *device = simple_strtol(s, NULL, 16);
1375
1376 return 0;
1377 }
1378 }
1379 list += (len + 1);
1380 }
1381
1382 return -ENOENT;
1383}
1384
Michal Simeka253c3b2022-02-23 15:45:40 +01001385int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
1386{
1387 const char *list, *end;
1388 int len;
1389
1390 list = ofnode_get_property(node, "compatible", &len);
1391
1392 if (!list)
1393 return -ENOENT;
1394
1395 end = list + len;
1396 while (list < end) {
1397 len = strlen(list);
1398
Michal Simekc633cdf2022-10-31 17:08:44 -07001399 if (len >= strlen("ethernet-phy-idVVVV.DDDD")) {
Michal Simeka253c3b2022-02-23 15:45:40 +01001400 char *s = strstr(list, "ethernet-phy-id");
1401
1402 /*
1403 * check if the string is something like
Michal Simekc633cdf2022-10-31 17:08:44 -07001404 * ethernet-phy-idVVVV.DDDD
Michal Simeka253c3b2022-02-23 15:45:40 +01001405 */
1406 if (s && s[19] == '.') {
1407 s += strlen("ethernet-phy-id");
1408 *vendor = simple_strtol(s, NULL, 16);
1409 s += 5;
1410 *device = simple_strtol(s, NULL, 16);
1411
1412 return 0;
1413 }
1414 }
1415 list += (len + 1);
1416 }
1417
1418 return -ENOENT;
1419}
1420
Simon Glassc4fc5622017-05-18 20:08:58 -06001421int ofnode_read_addr_cells(ofnode node)
1422{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001423 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001424 return of_n_addr_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001425 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001426 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001427 ofnode_to_offset(node));
1428
Simon Glass04fa09a2022-09-06 20:27:20 -06001429 return fdt_address_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001430 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001431}
1432
1433int ofnode_read_size_cells(ofnode node)
1434{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001435 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001436 return of_n_size_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001437 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001438 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001439 ofnode_to_offset(node));
1440
Simon Glass04fa09a2022-09-06 20:27:20 -06001441 return fdt_size_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001442 }
Simon Glass4191dc12017-06-12 06:21:31 -06001443}
1444
1445int ofnode_read_simple_addr_cells(ofnode node)
1446{
1447 if (ofnode_is_np(node))
1448 return of_simple_addr_cells(ofnode_to_np(node));
1449 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001450 return fdt_address_cells(ofnode_to_fdt(node),
1451 ofnode_to_offset(node));
Simon Glass4191dc12017-06-12 06:21:31 -06001452}
1453
1454int ofnode_read_simple_size_cells(ofnode node)
1455{
1456 if (ofnode_is_np(node))
1457 return of_simple_size_cells(ofnode_to_np(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001458 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001459 return fdt_size_cells(ofnode_to_fdt(node),
1460 ofnode_to_offset(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001461}
1462
1463bool ofnode_pre_reloc(ofnode node)
1464{
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001465#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
1466 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
Simon Glassfc1aa352023-02-13 08:56:34 -07001467 * had property bootph-all or bootph-pre-sram/bootph-pre-ram.
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001468 * They are removed in final dtb (fdtgrep 2nd pass)
1469 */
1470 return true;
1471#else
Simon Glassfc1aa352023-02-13 08:56:34 -07001472 if (ofnode_read_bool(node, "bootph-all"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001473 return true;
Simon Glassfc1aa352023-02-13 08:56:34 -07001474 if (ofnode_read_bool(node, "bootph-some-ram"))
Simon Glass23f22842018-10-01 12:22:18 -06001475 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001476
Simon Glassc4fc5622017-05-18 20:08:58 -06001477 /*
1478 * In regular builds individual spl and tpl handling both
1479 * count as handled pre-relocation for later second init.
1480 */
Simon Glassfc1aa352023-02-13 08:56:34 -07001481 if (ofnode_read_bool(node, "bootph-pre-ram") ||
1482 ofnode_read_bool(node, "bootph-pre-sram"))
Jonas Karlmanc43411b2023-08-20 22:03:18 +00001483 return gd->flags & GD_FLG_RELOC;
Simon Glassc4fc5622017-05-18 20:08:58 -06001484
Simon Glassc2727e52023-02-13 08:56:32 -07001485 if (IS_ENABLED(CONFIG_OF_TAG_MIGRATE)) {
1486 /* detect and handle old tags */
1487 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc") ||
1488 ofnode_read_bool(node, "u-boot,dm-pre-proper") ||
1489 ofnode_read_bool(node, "u-boot,dm-spl") ||
1490 ofnode_read_bool(node, "u-boot,dm-tpl") ||
1491 ofnode_read_bool(node, "u-boot,dm-vpl")) {
1492 gd->flags |= GD_FLG_OF_TAG_MIGRATE;
1493 return true;
1494 }
1495 }
1496
Simon Glassc4fc5622017-05-18 20:08:58 -06001497 return false;
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001498#endif
Simon Glassc4fc5622017-05-18 20:08:58 -06001499}
Simon Glassf7bfcc42017-07-25 08:29:55 -06001500
1501int ofnode_read_resource(ofnode node, uint index, struct resource *res)
1502{
1503 if (ofnode_is_np(node)) {
1504 return of_address_to_resource(ofnode_to_np(node), index, res);
1505 } else {
1506 struct fdt_resource fres;
1507 int ret;
1508
Simon Glass04fa09a2022-09-06 20:27:20 -06001509 ret = fdt_get_resource(ofnode_to_fdt(node),
1510 ofnode_to_offset(node),
Simon Glassf7bfcc42017-07-25 08:29:55 -06001511 "reg", index, &fres);
1512 if (ret < 0)
1513 return -EINVAL;
1514 memset(res, '\0', sizeof(*res));
1515 res->start = fres.start;
1516 res->end = fres.end;
1517
1518 return 0;
1519 }
1520}
Masahiro Yamada4dada2c2017-08-26 01:12:30 +09001521
1522int ofnode_read_resource_byname(ofnode node, const char *name,
1523 struct resource *res)
1524{
1525 int index;
1526
1527 index = ofnode_stringlist_search(node, "reg-names", name);
1528 if (index < 0)
1529 return index;
1530
1531 return ofnode_read_resource(node, index, res);
1532}
Mario Sixaefac062018-01-15 11:07:19 +01001533
1534u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
1535{
1536 if (ofnode_is_np(node))
1537 return of_translate_address(ofnode_to_np(node), in_addr);
1538 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001539 return fdt_translate_address(ofnode_to_fdt(node),
1540 ofnode_to_offset(node), in_addr);
Mario Sixaefac062018-01-15 11:07:19 +01001541}
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001542
Fabien Dessenne22236e02019-05-31 15:11:30 +02001543u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
1544{
1545 if (ofnode_is_np(node))
1546 return of_translate_dma_address(ofnode_to_np(node), in_addr);
1547 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001548 return fdt_translate_dma_address(ofnode_to_fdt(node),
1549 ofnode_to_offset(node), in_addr);
Fabien Dessenne22236e02019-05-31 15:11:30 +02001550}
1551
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001552int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
1553{
1554 if (ofnode_is_np(node))
1555 return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
1556 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001557 return fdt_get_dma_range(ofnode_to_fdt(node),
1558 ofnode_to_offset(node),
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001559 cpu, bus, size);
1560}
1561
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001562int ofnode_device_is_compatible(ofnode node, const char *compat)
1563{
1564 if (ofnode_is_np(node))
1565 return of_device_is_compatible(ofnode_to_np(node), compat,
1566 NULL, NULL);
1567 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001568 return !fdt_node_check_compatible(ofnode_to_fdt(node),
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001569 ofnode_to_offset(node),
1570 compat);
1571}
Simon Glass954eeae2018-06-11 13:07:13 -06001572
1573ofnode ofnode_by_compatible(ofnode from, const char *compat)
1574{
1575 if (of_live_active()) {
1576 return np_to_ofnode(of_find_compatible_node(
1577 (struct device_node *)ofnode_to_np(from), NULL,
1578 compat));
1579 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001580 return noffset_to_ofnode(from,
1581 fdt_node_offset_by_compatible(ofnode_to_fdt(from),
Simon Glass04fa09a2022-09-06 20:27:20 -06001582 ofnode_to_offset(from), compat));
Simon Glass954eeae2018-06-11 13:07:13 -06001583 }
1584}
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001585
1586ofnode ofnode_by_prop_value(ofnode from, const char *propname,
1587 const void *propval, int proplen)
1588{
1589 if (of_live_active()) {
1590 return np_to_ofnode(of_find_node_by_prop_value(
1591 (struct device_node *)ofnode_to_np(from), propname,
1592 propval, proplen));
1593 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001594 return noffset_to_ofnode(from,
1595 fdt_node_offset_by_prop_value(ofnode_to_fdt(from),
1596 ofnode_to_offset(from), propname, propval,
1597 proplen));
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001598 }
1599}
Mario Six047dafc2018-06-26 08:46:48 +02001600
Simon Glass5e2cd5e2022-07-30 15:52:10 -06001601int ofnode_write_prop(ofnode node, const char *propname, const void *value,
Simon Glass17abed02022-09-06 20:27:32 -06001602 int len, bool copy)
Mario Six047dafc2018-06-26 08:46:48 +02001603{
Simon Glass17abed02022-09-06 20:27:32 -06001604 if (of_live_active()) {
1605 void *newval;
1606 int ret;
1607
1608 if (copy) {
1609 newval = malloc(len);
1610 if (!newval)
1611 return log_ret(-ENOMEM);
1612 memcpy(newval, value, len);
1613 value = newval;
1614 }
1615 ret = of_write_prop(ofnode_to_np(node), propname, len, value);
1616 if (ret && copy)
1617 free(newval);
1618 return ret;
1619 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001620 return fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glass3ee3d152022-07-30 15:52:13 -06001621 propname, value, len);
Simon Glass17abed02022-09-06 20:27:32 -06001622 }
Mario Six047dafc2018-06-26 08:46:48 +02001623}
1624
1625int ofnode_write_string(ofnode node, const char *propname, const char *value)
1626{
Mario Six047dafc2018-06-26 08:46:48 +02001627 assert(ofnode_valid(node));
1628
1629 debug("%s: %s = %s", __func__, propname, value);
1630
Simon Glass17abed02022-09-06 20:27:32 -06001631 return ofnode_write_prop(node, propname, value, strlen(value) + 1,
1632 false);
Mario Six047dafc2018-06-26 08:46:48 +02001633}
1634
Simon Glassd28e31e2022-07-30 15:52:14 -06001635int ofnode_write_u32(ofnode node, const char *propname, u32 value)
1636{
1637 fdt32_t *val;
1638
1639 assert(ofnode_valid(node));
1640
1641 log_debug("%s = %x", propname, value);
1642 val = malloc(sizeof(*val));
1643 if (!val)
1644 return -ENOMEM;
1645 *val = cpu_to_fdt32(value);
1646
Simon Glassc681e092023-09-26 08:14:45 -06001647 return ofnode_write_prop(node, propname, val, sizeof(value), true);
1648}
1649
1650int ofnode_write_u64(ofnode node, const char *propname, u64 value)
1651{
1652 fdt64_t *val;
1653
1654 assert(ofnode_valid(node));
1655
1656 log_debug("%s = %llx", propname, (unsigned long long)value);
1657 val = malloc(sizeof(*val));
1658 if (!val)
1659 return -ENOMEM;
1660 *val = cpu_to_fdt64(value);
1661
1662 return ofnode_write_prop(node, propname, val, sizeof(value), true);
Simon Glassd28e31e2022-07-30 15:52:14 -06001663}
1664
Simon Glass86ef3992023-09-26 08:14:44 -06001665int ofnode_write_bool(ofnode node, const char *propname, bool value)
1666{
1667 if (value)
1668 return ofnode_write_prop(node, propname, NULL, 0, false);
1669 else
1670 return ofnode_delete_prop(node, propname);
1671}
1672
1673int ofnode_delete_prop(ofnode node, const char *propname)
1674{
1675 if (ofnode_is_np(node)) {
1676 struct property *prop;
1677 int len;
1678
1679 prop = of_find_property(ofnode_to_np(node), propname, &len);
1680 if (prop)
1681 return of_remove_property(ofnode_to_np(node), prop);
1682 return 0;
1683 } else {
1684 return fdt_delprop(ofnode_to_fdt(node), ofnode_to_offset(node),
1685 propname);
1686 }
1687}
1688
Mario Six047dafc2018-06-26 08:46:48 +02001689int ofnode_set_enabled(ofnode node, bool value)
1690{
Mario Six047dafc2018-06-26 08:46:48 +02001691 assert(ofnode_valid(node));
1692
1693 if (value)
1694 return ofnode_write_string(node, "status", "okay");
1695 else
Bin Menga9274aa2019-07-05 09:23:17 -07001696 return ofnode_write_string(node, "status", "disabled");
Mario Six047dafc2018-06-26 08:46:48 +02001697}
Simon Glass0034d962021-08-07 07:24:01 -06001698
1699bool ofnode_conf_read_bool(const char *prop_name)
1700{
1701 ofnode node;
1702
1703 node = ofnode_path("/config");
1704 if (!ofnode_valid(node))
1705 return false;
1706
1707 return ofnode_read_bool(node, prop_name);
1708}
1709
1710int ofnode_conf_read_int(const char *prop_name, int default_val)
1711{
1712 ofnode node;
1713
1714 node = ofnode_path("/config");
1715 if (!ofnode_valid(node))
1716 return default_val;
1717
1718 return ofnode_read_u32_default(node, prop_name, default_val);
1719}
1720
1721const char *ofnode_conf_read_str(const char *prop_name)
1722{
1723 ofnode node;
1724
1725 node = ofnode_path("/config");
1726 if (!ofnode_valid(node))
1727 return NULL;
1728
1729 return ofnode_read_string(node, prop_name);
1730}
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001731
Michal Simek43c42bd2023-08-31 08:59:05 +02001732int ofnode_read_bootscript_address(u64 *bootscr_address, u64 *bootscr_offset)
1733{
1734 int ret;
1735 ofnode uboot;
1736
1737 *bootscr_address = 0;
1738 *bootscr_offset = 0;
1739
1740 uboot = ofnode_path("/options/u-boot");
1741 if (!ofnode_valid(uboot)) {
Michal Simek951ca592023-09-11 15:30:01 +02001742 debug("%s: Missing /u-boot node\n", __func__);
Michal Simek43c42bd2023-08-31 08:59:05 +02001743 return -EINVAL;
1744 }
1745
1746 ret = ofnode_read_u64(uboot, "bootscr-address", bootscr_address);
1747 if (ret) {
1748 ret = ofnode_read_u64(uboot, "bootscr-ram-offset",
1749 bootscr_offset);
1750 if (ret)
1751 return -EINVAL;
1752 }
1753
1754 return 0;
1755}
1756
Michal Simek6a7c1ce2023-08-31 09:04:27 +02001757int ofnode_read_bootscript_flash(u64 *bootscr_flash_offset,
1758 u64 *bootscr_flash_size)
1759{
1760 int ret;
1761 ofnode uboot;
1762
1763 *bootscr_flash_offset = 0;
1764 *bootscr_flash_size = 0;
1765
1766 uboot = ofnode_path("/options/u-boot");
1767 if (!ofnode_valid(uboot)) {
Michal Simek951ca592023-09-11 15:30:01 +02001768 debug("%s: Missing /u-boot node\n", __func__);
Michal Simek6a7c1ce2023-08-31 09:04:27 +02001769 return -EINVAL;
1770 }
1771
1772 ret = ofnode_read_u64(uboot, "bootscr-flash-offset",
1773 bootscr_flash_offset);
1774 if (ret)
1775 return -EINVAL;
1776
1777 ret = ofnode_read_u64(uboot, "bootscr-flash-size",
1778 bootscr_flash_size);
1779 if (ret)
1780 return -EINVAL;
1781
1782 if (!bootscr_flash_size) {
1783 debug("bootscr-flash-size is zero. Ignoring properties!\n");
1784 *bootscr_flash_offset = 0;
1785 return -EINVAL;
1786 }
1787
1788 return 0;
1789}
1790
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001791ofnode ofnode_get_phy_node(ofnode node)
1792{
1793 /* DT node properties that reference a PHY node */
1794 static const char * const phy_handle_str[] = {
1795 "phy-handle", "phy", "phy-device",
1796 };
1797 struct ofnode_phandle_args args = {
1798 .node = ofnode_null()
1799 };
1800 int i;
1801
1802 assert(ofnode_valid(node));
1803
1804 for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
1805 if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
1806 NULL, 0, 0, &args))
1807 break;
1808
1809 return args.node;
1810}
Marek Behúnbc194772022-04-07 00:33:01 +02001811
1812phy_interface_t ofnode_read_phy_mode(ofnode node)
1813{
1814 const char *mode;
1815 int i;
1816
1817 assert(ofnode_valid(node));
1818
1819 mode = ofnode_read_string(node, "phy-mode");
1820 if (!mode)
1821 mode = ofnode_read_string(node, "phy-connection-type");
1822
1823 if (!mode)
Marek Behún48631e42022-04-07 00:33:03 +02001824 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001825
Marek Behún21a18362022-04-07 00:33:02 +02001826 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
Marek Behúnbc194772022-04-07 00:33:01 +02001827 if (!strcmp(mode, phy_interface_strings[i]))
1828 return i;
1829
1830 debug("%s: Invalid PHY interface '%s'\n", __func__, mode);
1831
Marek Behún48631e42022-04-07 00:33:03 +02001832 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001833}
Simon Glass56bc3322022-09-06 20:27:02 -06001834
1835int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
1836{
1837 ofnode subnode;
1838 int ret = 0;
1839
1840 assert(ofnode_valid(node));
1841
1842 if (ofnode_is_np(node)) {
1843 struct device_node *np, *child;
1844
1845 np = (struct device_node *)ofnode_to_np(node);
1846 ret = of_add_subnode(np, name, -1, &child);
1847 if (ret && ret != -EEXIST)
1848 return ret;
1849 subnode = np_to_ofnode(child);
1850 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001851 void *fdt = ofnode_to_fdt(node);
Simon Glass56bc3322022-09-06 20:27:02 -06001852 int poffset = ofnode_to_offset(node);
1853 int offset;
1854
1855 offset = fdt_add_subnode(fdt, poffset, name);
1856 if (offset == -FDT_ERR_EXISTS) {
1857 offset = fdt_subnode_offset(fdt, poffset, name);
1858 ret = -EEXIST;
1859 }
1860 if (offset < 0)
1861 return -EINVAL;
Simon Glass37dcd912022-09-06 20:27:23 -06001862 subnode = noffset_to_ofnode(node, offset);
Simon Glass56bc3322022-09-06 20:27:02 -06001863 }
1864
1865 *subnodep = subnode;
1866
1867 return ret; /* 0 or -EEXIST */
1868}
Simon Glass7a7229a2022-09-06 20:27:33 -06001869
Simon Glass45448772023-09-26 08:14:42 -06001870int ofnode_delete(ofnode *nodep)
1871{
1872 ofnode node = *nodep;
1873 int ret;
1874
1875 assert(ofnode_valid(node));
1876 if (ofnode_is_np(node)) {
1877 ret = of_remove_node(ofnode_to_np(node));
1878 } else {
1879 void *fdt = ofnode_to_fdt(node);
1880 int offset = ofnode_to_offset(node);
1881
1882 ret = fdt_del_node(fdt, offset);
1883 if (ret)
1884 ret = -EFAULT;
1885 }
1886 if (ret)
1887 return ret;
1888 *nodep = ofnode_null();
1889
1890 return 0;
1891}
1892
Simon Glass68164892023-09-26 08:14:37 -06001893int ofnode_copy_props(ofnode dst, ofnode src)
Simon Glass7a7229a2022-09-06 20:27:33 -06001894{
1895 struct ofprop prop;
1896
1897 ofnode_for_each_prop(prop, src) {
1898 const char *name;
1899 const char *val;
1900 int len, ret;
1901
1902 val = ofprop_get_property(&prop, &name, &len);
1903 if (!val) {
1904 log_debug("Cannot read prop (err=%d)\n", len);
1905 return log_msg_ret("get", -EINVAL);
1906 }
1907 ret = ofnode_write_prop(dst, name, val, len, true);
1908 if (ret) {
1909 log_debug("Cannot write prop (err=%d)\n", ret);
1910 return log_msg_ret("wr", -EINVAL);
1911 }
1912 }
1913
1914 return 0;
1915}
Simon Glass7c33c962023-09-26 08:14:41 -06001916
1917int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src,
1918 ofnode *nodep)
1919{
1920 ofnode node;
1921 int ret;
1922
1923 ret = ofnode_add_subnode(dst_parent, name, &node);
1924 if (ret) {
1925 if (ret == -EEXIST)
1926 *nodep = node;
1927 return log_msg_ret("add", ret);
1928 }
1929 ret = ofnode_copy_props(node, src);
1930 if (ret)
1931 return log_msg_ret("cpy", ret);
1932 *nodep = node;
1933
1934 return 0;
1935}