blob: ff0a5b5164f4a23e9ebd4e333837de0510a775c7 [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
50static oftree oftree_ensure(void *fdt)
51{
52 oftree tree;
53 int i;
54
Simon Glass722281b2023-06-01 10:22:42 -060055 if (of_live_active()) {
56 struct device_node *root;
57 int ret;
58
59 ret = unflatten_device_tree(fdt, &root);
60 if (ret) {
61 log_err("Failed to create live tree: err=%d\n", ret);
62 return oftree_null();
63 }
64 tree = oftree_from_np(root);
65
66 return tree;
67 }
68
Simon Glasscb13a1b2022-09-06 20:27:26 -060069 if (gd->flags & GD_FLG_RELOC) {
70 i = oftree_find(fdt);
71 if (i == -1) {
72 if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) {
73 log_warning("Too many registered device trees (max %d)\n",
74 CONFIG_OFNODE_MULTI_TREE_MAX);
75 return oftree_null();
76 }
77
78 /* register the new tree */
79 i = oftree_count++;
80 oftree_list[i] = fdt;
81 log_debug("oftree: registered tree %d: %p\n", i, fdt);
82 }
83 } else {
84 if (fdt != gd->fdt_blob) {
Simon Glass67f8e112023-06-01 10:22:41 -060085 log_debug("Only the control FDT can be accessed before relocation\n");
Simon Glasscb13a1b2022-09-06 20:27:26 -060086 return oftree_null();
87 }
88 }
89
90 tree.fdt = fdt;
91
92 return tree;
93}
94
Simon Glass722281b2023-06-01 10:22:42 -060095void oftree_dispose(oftree tree)
96{
97 if (of_live_active())
98 of_live_free(tree.np);
99}
100
Simon Glasscb13a1b2022-09-06 20:27:26 -0600101void *ofnode_lookup_fdt(ofnode node)
102{
103 if (gd->flags & GD_FLG_RELOC) {
104 uint i = OFTREE_TREE_ID(node.of_offset);
105
Dan Carpenter408ccac2023-07-26 09:59:52 +0300106 if (i >= oftree_count) {
Simon Glasscb13a1b2022-09-06 20:27:26 -0600107 log_debug("Invalid tree ID %x\n", i);
108 return NULL;
109 }
110
111 return oftree_list[i];
112 } else {
113 return (void *)gd->fdt_blob;
114 }
115}
116
117void *ofnode_to_fdt(ofnode node)
118{
119#ifdef OF_CHECKS
120 if (of_live_active())
121 return NULL;
122#endif
123 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && ofnode_valid(node))
124 return ofnode_lookup_fdt(node);
125
126 /* Use the control FDT by default */
127 return (void *)gd->fdt_blob;
128}
129
Simon Glass45ae59d2022-09-06 20:27:24 -0600130/**
Simon Glasscb13a1b2022-09-06 20:27:26 -0600131 * ofnode_to_offset() - convert an ofnode to a flat DT offset
132 *
133 * This cannot be called if the reference contains a node pointer.
134 *
135 * @node: Reference containing offset (possibly invalid)
136 * Return: DT offset (can be -1)
137 */
138int ofnode_to_offset(ofnode node)
139{
140#ifdef OF_CHECKS
141 if (of_live_active())
142 return -1;
143#endif
144 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && node.of_offset >= 0)
145 return OFTREE_OFFSET(node.of_offset);
146
147 return node.of_offset;
148}
149
150oftree oftree_from_fdt(void *fdt)
151{
152 oftree tree;
153
154 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
155 return oftree_ensure(fdt);
156
Simon Glass994048b2023-06-01 10:22:31 -0600157#ifdef OF_CHECKS
158 if (of_live_active())
159 return oftree_null();
160#endif
Simon Glasscb13a1b2022-09-06 20:27:26 -0600161 tree.fdt = fdt;
162
163 return tree;
164}
165
166/**
167 * noffset_to_ofnode() - convert a DT offset to an ofnode
168 *
169 * @other_node: Node in the same tree to use as a reference
170 * @of_offset: DT offset (either valid, or -1)
171 * Return: reference to the associated DT offset
172 */
173ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
174{
175 ofnode node;
176
177 if (of_live_active())
178 node.np = NULL;
179 else if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) || of_offset < 0 ||
180 !ofnode_valid(other_node))
181 node.of_offset = of_offset;
182 else
183 node.of_offset = OFTREE_MAKE_NODE(other_node.of_offset,
184 of_offset);
185
186 return node;
187}
188
189#else /* !OFNODE_MULTI_TREE */
190
191static inline int oftree_find(const void *fdt)
192{
193 return 0;
194}
195
196#endif /* OFNODE_MULTI_TREE */
197
198/**
Simon Glass45ae59d2022-09-06 20:27:24 -0600199 * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
200 *
Simon Glasscb13a1b2022-09-06 20:27:26 -0600201 * Looks up the tree and returns an ofnode with the correct of_offset (i.e.
202 * containing the tree ID).
Simon Glass45ae59d2022-09-06 20:27:24 -0600203 *
Simon Glasscb13a1b2022-09-06 20:27:26 -0600204 * If @offset is < 0 then this returns an ofnode with that offset and no tree
205 * ID.
Simon Glass45ae59d2022-09-06 20:27:24 -0600206 *
207 * @tree: tree to check
208 * @offset: offset within that tree (can be < 0)
Simon Glasscb13a1b2022-09-06 20:27:26 -0600209 * @return node for that offset, with the correct ID
Simon Glass45ae59d2022-09-06 20:27:24 -0600210 */
211static ofnode ofnode_from_tree_offset(oftree tree, int offset)
212{
213 ofnode node;
214
Simon Glasscb13a1b2022-09-06 20:27:26 -0600215 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && offset >= 0) {
216 int tree_id = oftree_find(tree.fdt);
217
218 if (tree_id == -1)
219 return ofnode_null();
220 node.of_offset = OFTREE_NODE(tree_id, offset);
221 } else {
222 node.of_offset = offset;
223 }
Simon Glass45ae59d2022-09-06 20:27:24 -0600224
225 return node;
226}
227
Kishon Vijay Abraham Id6388f22021-07-21 21:28:30 +0530228bool ofnode_name_eq(ofnode node, const char *name)
229{
230 const char *node_name;
231 size_t len;
232
233 assert(ofnode_valid(node));
234
235 node_name = ofnode_get_name(node);
236 len = strchrnul(node_name, '@') - node_name;
237
238 return (strlen(name) == len) && !strncmp(node_name, name, len);
239}
240
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200241int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
242{
243 const u8 *cell;
244 int len;
245
246 assert(ofnode_valid(node));
247 debug("%s: %s: ", __func__, propname);
248
249 if (ofnode_is_np(node))
250 return of_read_u8(ofnode_to_np(node), propname, outp);
251
252 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
253 &len);
254 if (!cell || len < sizeof(*cell)) {
255 debug("(not found)\n");
256 return -EINVAL;
257 }
258 *outp = *cell;
259 debug("%#x (%d)\n", *outp, *outp);
260
261 return 0;
262}
263
264u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
265{
266 assert(ofnode_valid(node));
267 ofnode_read_u8(node, propname, &def);
268
269 return def;
270}
271
272int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
273{
274 const fdt16_t *cell;
275 int len;
276
277 assert(ofnode_valid(node));
278 debug("%s: %s: ", __func__, propname);
279
280 if (ofnode_is_np(node))
281 return of_read_u16(ofnode_to_np(node), propname, outp);
282
283 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
284 &len);
285 if (!cell || len < sizeof(*cell)) {
286 debug("(not found)\n");
287 return -EINVAL;
288 }
289 *outp = be16_to_cpup(cell);
290 debug("%#x (%d)\n", *outp, *outp);
291
292 return 0;
293}
294
295u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def)
296{
297 assert(ofnode_valid(node));
298 ofnode_read_u16(node, propname, &def);
299
300 return def;
301}
302
Simon Glassc4fc5622017-05-18 20:08:58 -0600303int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
304{
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200305 return ofnode_read_u32_index(node, propname, 0, outp);
Simon Glassc4fc5622017-05-18 20:08:58 -0600306}
307
Trent Piepho5b775412019-05-10 17:48:20 +0000308u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
Simon Glassc4fc5622017-05-18 20:08:58 -0600309{
310 assert(ofnode_valid(node));
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200311 ofnode_read_u32_index(node, propname, 0, &def);
Simon Glassc4fc5622017-05-18 20:08:58 -0600312
313 return def;
314}
315
Dario Binacchi81d80b52020-03-29 18:04:41 +0200316int ofnode_read_u32_index(ofnode node, const char *propname, int index,
317 u32 *outp)
318{
319 const fdt32_t *cell;
320 int len;
321
322 assert(ofnode_valid(node));
323 debug("%s: %s: ", __func__, propname);
324
325 if (ofnode_is_np(node))
326 return of_read_u32_index(ofnode_to_np(node), propname, index,
327 outp);
328
Simon Glass04fa09a2022-09-06 20:27:20 -0600329 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
330 propname, &len);
Dario Binacchi81d80b52020-03-29 18:04:41 +0200331 if (!cell) {
332 debug("(not found)\n");
333 return -EINVAL;
334 }
335
336 if (len < (sizeof(int) * (index + 1))) {
337 debug("(not large enough)\n");
338 return -EOVERFLOW;
339 }
340
341 *outp = fdt32_to_cpu(cell[index]);
342 debug("%#x (%d)\n", *outp, *outp);
343
344 return 0;
345}
346
Michal Simek08a194e2023-08-25 11:37:46 +0200347int ofnode_read_u64_index(ofnode node, const char *propname, int index,
348 u64 *outp)
349{
350 const fdt64_t *cell;
351 int len;
352
353 assert(ofnode_valid(node));
354
355 if (ofnode_is_np(node))
356 return of_read_u64_index(ofnode_to_np(node), propname, index,
357 outp);
358
359 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
360 propname, &len);
361 if (!cell) {
362 debug("(not found)\n");
363 return -EINVAL;
364 }
365
366 if (len < (sizeof(u64) * (index + 1))) {
367 debug("(not large enough)\n");
368 return -EOVERFLOW;
369 }
370
371 *outp = fdt64_to_cpu(cell[index]);
372 debug("%#llx (%lld)\n", *outp, *outp);
373
374 return 0;
375}
376
Dario Binacchi81d80b52020-03-29 18:04:41 +0200377u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
378 u32 def)
379{
380 assert(ofnode_valid(node));
381 ofnode_read_u32_index(node, propname, index, &def);
382
383 return def;
384}
385
Simon Glassc4fc5622017-05-18 20:08:58 -0600386int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
387{
388 assert(ofnode_valid(node));
389 ofnode_read_u32(node, propname, (u32 *)&def);
390
391 return def;
392}
393
Simon Glass9d54a7a2018-06-11 13:07:10 -0600394int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
395{
Jean-Jacques Hiblot487f9172019-10-22 10:05:22 +0200396 const unaligned_fdt64_t *cell;
Simon Glass9d54a7a2018-06-11 13:07:10 -0600397 int len;
398
399 assert(ofnode_valid(node));
400 debug("%s: %s: ", __func__, propname);
401
402 if (ofnode_is_np(node))
403 return of_read_u64(ofnode_to_np(node), propname, outp);
404
Simon Glass04fa09a2022-09-06 20:27:20 -0600405 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
406 propname, &len);
Simon Glass9d54a7a2018-06-11 13:07:10 -0600407 if (!cell || len < sizeof(*cell)) {
408 debug("(not found)\n");
409 return -EINVAL;
410 }
411 *outp = fdt64_to_cpu(cell[0]);
412 debug("%#llx (%lld)\n", (unsigned long long)*outp,
413 (unsigned long long)*outp);
414
415 return 0;
416}
417
T Karthik Reddy478860d2019-09-02 16:34:30 +0200418u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
Simon Glass9d54a7a2018-06-11 13:07:10 -0600419{
420 assert(ofnode_valid(node));
421 ofnode_read_u64(node, propname, &def);
422
423 return def;
424}
425
Simon Glassc4fc5622017-05-18 20:08:58 -0600426bool ofnode_read_bool(ofnode node, const char *propname)
427{
Masahiro Yamada5d434452017-06-22 16:54:07 +0900428 const void *prop;
Simon Glassc4fc5622017-05-18 20:08:58 -0600429
430 assert(ofnode_valid(node));
431 debug("%s: %s: ", __func__, propname);
432
Masahiro Yamada5d434452017-06-22 16:54:07 +0900433 prop = ofnode_get_property(node, propname, NULL);
434
435 debug("%s\n", prop ? "true" : "false");
Simon Glassc4fc5622017-05-18 20:08:58 -0600436
Masahiro Yamada5d434452017-06-22 16:54:07 +0900437 return prop ? true : false;
Simon Glassc4fc5622017-05-18 20:08:58 -0600438}
439
Simon Glass0c2e9802020-01-27 08:49:44 -0700440const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600441{
Simon Glass0c2e9802020-01-27 08:49:44 -0700442 const char *val = NULL;
443 int len;
Simon Glassc4fc5622017-05-18 20:08:58 -0600444
445 assert(ofnode_valid(node));
446 debug("%s: %s: ", __func__, propname);
447
448 if (ofnode_is_np(node)) {
449 struct property *prop = of_find_property(
Simon Glass0c2e9802020-01-27 08:49:44 -0700450 ofnode_to_np(node), propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600451
452 if (prop) {
Simon Glass0c2e9802020-01-27 08:49:44 -0700453 val = prop->value;
Simon Glassc4fc5622017-05-18 20:08:58 -0600454 len = prop->length;
455 }
456 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600457 val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600458 propname, &len);
459 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700460 if (!val) {
Simon Glassc4fc5622017-05-18 20:08:58 -0600461 debug("<not found>\n");
Simon Glass0c2e9802020-01-27 08:49:44 -0700462 if (sizep)
463 *sizep = -FDT_ERR_NOTFOUND;
Simon Glassc4fc5622017-05-18 20:08:58 -0600464 return NULL;
465 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700466 if (sizep)
467 *sizep = len;
468
469 return val;
470}
471
472const char *ofnode_read_string(ofnode node, const char *propname)
473{
474 const char *str;
475 int len;
476
477 str = ofnode_read_prop(node, propname, &len);
478 if (!str)
479 return NULL;
480
Simon Glassc4fc5622017-05-18 20:08:58 -0600481 if (strnlen(str, len) >= len) {
482 debug("<invalid>\n");
483 return NULL;
484 }
485 debug("%s\n", str);
486
487 return str;
488}
489
Simon Glass81c54b32020-01-27 08:49:45 -0700490int ofnode_read_size(ofnode node, const char *propname)
491{
492 int len;
493
494 if (!ofnode_read_prop(node, propname, &len))
495 return -EINVAL;
496
497 return len;
498}
499
Simon Glassc4fc5622017-05-18 20:08:58 -0600500ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
501{
502 ofnode subnode;
503
504 assert(ofnode_valid(node));
505 debug("%s: %s: ", __func__, subnode_name);
506
507 if (ofnode_is_np(node)) {
Simon Glass9036c5c2022-09-06 20:27:04 -0600508 struct device_node *np = ofnode_to_np(node);
Simon Glassc4fc5622017-05-18 20:08:58 -0600509
510 for (np = np->child; np; np = np->sibling) {
511 if (!strcmp(subnode_name, np->name))
512 break;
513 }
514 subnode = np_to_ofnode(np);
515 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600516 int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600517 ofnode_to_offset(node), subnode_name);
Simon Glass37dcd912022-09-06 20:27:23 -0600518 subnode = noffset_to_ofnode(node, ooffset);
Simon Glassc4fc5622017-05-18 20:08:58 -0600519 }
520 debug("%s\n", ofnode_valid(subnode) ?
521 ofnode_get_name(subnode) : "<none>");
522
523 return subnode;
524}
525
526int ofnode_read_u32_array(ofnode node, const char *propname,
527 u32 *out_values, size_t sz)
528{
529 assert(ofnode_valid(node));
530 debug("%s: %s: ", __func__, propname);
531
532 if (ofnode_is_np(node)) {
533 return of_read_u32_array(ofnode_to_np(node), propname,
534 out_values, sz);
535 } else {
Simon Glasse3be5fc2022-09-06 20:27:18 -0600536 int ret;
537
Simon Glass04fa09a2022-09-06 20:27:20 -0600538 ret = fdtdec_get_int_array(ofnode_to_fdt(node),
Simon Glasse3be5fc2022-09-06 20:27:18 -0600539 ofnode_to_offset(node), propname,
540 out_values, sz);
541
542 /* get the error right, but space is more important in SPL */
543 if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
544 if (ret == -FDT_ERR_NOTFOUND)
545 return -EINVAL;
546 else if (ret == -FDT_ERR_BADLAYOUT)
547 return -EOVERFLOW;
548 }
549 return ret;
Simon Glassc4fc5622017-05-18 20:08:58 -0600550 }
551}
552
Simon Glass39f1d282020-12-16 17:25:06 -0700553#if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
Simon Glass5de5b3b2020-11-28 17:50:02 -0700554bool ofnode_is_enabled(ofnode node)
555{
556 if (ofnode_is_np(node)) {
557 return of_device_is_available(ofnode_to_np(node));
558 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600559 return fdtdec_get_is_enabled(ofnode_to_fdt(node),
Simon Glass5de5b3b2020-11-28 17:50:02 -0700560 ofnode_to_offset(node));
561 }
562}
563
Simon Glassc4fc5622017-05-18 20:08:58 -0600564ofnode ofnode_first_subnode(ofnode node)
565{
566 assert(ofnode_valid(node));
567 if (ofnode_is_np(node))
568 return np_to_ofnode(node.np->child);
569
Simon Glass37dcd912022-09-06 20:27:23 -0600570 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600571 fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600572}
573
574ofnode ofnode_next_subnode(ofnode node)
575{
576 assert(ofnode_valid(node));
577 if (ofnode_is_np(node))
578 return np_to_ofnode(node.np->sibling);
579
Simon Glass37dcd912022-09-06 20:27:23 -0600580 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600581 fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600582}
Simon Glass39f1d282020-12-16 17:25:06 -0700583#endif /* !DM_INLINE_OFNODE */
Simon Glassc4fc5622017-05-18 20:08:58 -0600584
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100585ofnode ofnode_get_parent(ofnode node)
586{
587 ofnode parent;
588
589 assert(ofnode_valid(node));
590 if (ofnode_is_np(node))
591 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
592 else
Simon Glass04fa09a2022-09-06 20:27:20 -0600593 parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100594 ofnode_to_offset(node));
595
596 return parent;
597}
598
Simon Glassc4fc5622017-05-18 20:08:58 -0600599const char *ofnode_get_name(ofnode node)
600{
Kever Yang8d7976d2019-07-19 11:23:47 +0800601 if (!ofnode_valid(node)) {
602 debug("%s node not valid\n", __func__);
603 return NULL;
604 }
605
Simon Glassc4fc5622017-05-18 20:08:58 -0600606 if (ofnode_is_np(node))
Simon Glass91d89a82022-09-06 20:27:15 -0600607 return node.np->name;
Simon Glassc4fc5622017-05-18 20:08:58 -0600608
Simon Glass04fa09a2022-09-06 20:27:20 -0600609 return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600610}
611
Marek Behúne897e3c2021-05-26 14:08:18 +0200612int ofnode_get_path(ofnode node, char *buf, int buflen)
613{
614 assert(ofnode_valid(node));
615
616 if (ofnode_is_np(node)) {
617 if (strlen(node.np->full_name) >= buflen)
618 return -ENOSPC;
619
620 strcpy(buf, node.np->full_name);
621
622 return 0;
623 } else {
624 int res;
625
Simon Glass04fa09a2022-09-06 20:27:20 -0600626 res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
Marek Behúne897e3c2021-05-26 14:08:18 +0200627 buflen);
628 if (!res)
629 return res;
630 else if (res == -FDT_ERR_NOSPACE)
631 return -ENOSPC;
632 else
633 return -EINVAL;
634 }
635}
636
Kever Yang37df0e02018-02-23 17:38:50 +0100637ofnode ofnode_get_by_phandle(uint phandle)
638{
639 ofnode node;
640
641 if (of_live_active())
Simon Glass176dd432022-09-06 20:26:57 -0600642 node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
Kever Yang37df0e02018-02-23 17:38:50 +0100643 else
644 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
645 phandle);
646
647 return node;
648}
649
Simon Glass95fd2092022-09-06 20:27:22 -0600650ofnode oftree_get_by_phandle(oftree tree, uint phandle)
651{
652 ofnode node;
653
654 if (of_live_active())
655 node = np_to_ofnode(of_find_node_by_phandle(tree.np, phandle));
656 else
Simon Glassf912a722022-09-06 20:27:27 -0600657 node = ofnode_from_tree_offset(tree,
Simon Glass95fd2092022-09-06 20:27:22 -0600658 fdt_node_offset_by_phandle(oftree_lookup_fdt(tree),
Simon Glassf912a722022-09-06 20:27:27 -0600659 phandle));
Simon Glass95fd2092022-09-06 20:27:22 -0600660
661 return node;
662}
663
Marek Behún177ab7f2021-05-26 14:08:17 +0200664static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
665 fdt_size_t *size, bool translate)
Simon Glass049ae1b2017-05-18 20:09:01 -0600666{
Keerthy34222a32018-11-19 11:44:47 +0530667 int na, ns;
Keerthy34222a32018-11-19 11:44:47 +0530668
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800669 if (size)
670 *size = FDT_SIZE_T_NONE;
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800671
Simon Glass049ae1b2017-05-18 20:09:01 -0600672 if (ofnode_is_np(node)) {
673 const __be32 *prop_val;
Simon Glass47f85de2019-09-25 08:55:50 -0600674 u64 size64;
Simon Glass049ae1b2017-05-18 20:09:01 -0600675 uint flags;
Simon Glass049ae1b2017-05-18 20:09:01 -0600676
Simon Glass47f85de2019-09-25 08:55:50 -0600677 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
678 &flags);
Simon Glass049ae1b2017-05-18 20:09:01 -0600679 if (!prop_val)
680 return FDT_ADDR_T_NONE;
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800681
Simon Glass47f85de2019-09-25 08:55:50 -0600682 if (size)
683 *size = size64;
Mario Sixd007ebc2017-12-20 09:52:12 +0100684
Mario Six35616ef2018-03-12 14:53:33 +0100685 ns = of_n_size_cells(ofnode_to_np(node));
686
Marek Behún177ab7f2021-05-26 14:08:17 +0200687 if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Sixd007ebc2017-12-20 09:52:12 +0100688 return of_translate_address(ofnode_to_np(node), prop_val);
689 } else {
690 na = of_n_addr_cells(ofnode_to_np(node));
691 return of_read_number(prop_val, na);
692 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600693 } else {
Keerthy34222a32018-11-19 11:44:47 +0530694 na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
695 ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
Simon Glass04fa09a2022-09-06 20:27:20 -0600696 return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
Keerthy34222a32018-11-19 11:44:47 +0530697 ofnode_to_offset(node), "reg",
Marek Behún177ab7f2021-05-26 14:08:17 +0200698 index, na, ns, size,
699 translate);
Simon Glass049ae1b2017-05-18 20:09:01 -0600700 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600701}
702
Marek Behún177ab7f2021-05-26 14:08:17 +0200703fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
704{
705 return __ofnode_get_addr_size_index(node, index, size, true);
706}
707
708fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
709 fdt_size_t *size)
710{
711 return __ofnode_get_addr_size_index(node, index, size, false);
712}
713
Keerthyd332e6e2019-04-24 17:19:53 +0530714fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
715{
716 fdt_size_t size;
717
718 return ofnode_get_addr_size_index(node, index, &size);
719}
720
Simon Glass049ae1b2017-05-18 20:09:01 -0600721fdt_addr_t ofnode_get_addr(ofnode node)
722{
723 return ofnode_get_addr_index(node, 0);
724}
725
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800726fdt_size_t ofnode_get_size(ofnode node)
727{
728 fdt_size_t size;
729
730 ofnode_get_addr_size_index(node, 0, &size);
731
732 return size;
733}
734
Simon Glassc4fc5622017-05-18 20:08:58 -0600735int ofnode_stringlist_search(ofnode node, const char *property,
736 const char *string)
737{
738 if (ofnode_is_np(node)) {
739 return of_property_match_string(ofnode_to_np(node),
740 property, string);
741 } else {
742 int ret;
743
Simon Glass04fa09a2022-09-06 20:27:20 -0600744 ret = fdt_stringlist_search(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600745 ofnode_to_offset(node), property,
746 string);
747 if (ret == -FDT_ERR_NOTFOUND)
748 return -ENODATA;
749 else if (ret < 0)
750 return -EINVAL;
751
752 return ret;
753 }
754}
755
756int ofnode_read_string_index(ofnode node, const char *property, int index,
757 const char **outp)
758{
759 if (ofnode_is_np(node)) {
760 return of_property_read_string_index(ofnode_to_np(node),
761 property, index, outp);
762 } else {
763 int len;
764
Simon Glass04fa09a2022-09-06 20:27:20 -0600765 *outp = fdt_stringlist_get(ofnode_to_fdt(node),
766 ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600767 property, index, &len);
768 if (len < 0)
769 return -EINVAL;
770 return 0;
771 }
772}
773
Simon Glass5fdb0052017-06-12 06:21:28 -0600774int ofnode_read_string_count(ofnode node, const char *property)
775{
776 if (ofnode_is_np(node)) {
777 return of_property_count_strings(ofnode_to_np(node), property);
778 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600779 return fdt_stringlist_count(ofnode_to_fdt(node),
Simon Glass5fdb0052017-06-12 06:21:28 -0600780 ofnode_to_offset(node), property);
781 }
782}
783
Simon Glass9580bfc2021-10-23 17:26:07 -0600784int ofnode_read_string_list(ofnode node, const char *property,
785 const char ***listp)
786{
787 const char **prop;
788 int count;
789 int i;
790
791 *listp = NULL;
792 count = ofnode_read_string_count(node, property);
793 if (count < 0)
794 return count;
795 if (!count)
796 return 0;
797
798 prop = calloc(count + 1, sizeof(char *));
799 if (!prop)
800 return -ENOMEM;
801
802 for (i = 0; i < count; i++)
803 ofnode_read_string_index(node, property, i, &prop[i]);
804 prop[count] = NULL;
805 *listp = prop;
806
807 return count;
808}
809
Simon Glassc4fc5622017-05-18 20:08:58 -0600810static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
811 struct ofnode_phandle_args *out)
812{
813 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
814 out->node = offset_to_ofnode(in->node);
815 out->args_count = in->args_count;
816 memcpy(out->args, in->args, sizeof(out->args));
817}
818
819static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
820 struct ofnode_phandle_args *out)
821{
822 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
823 out->node = np_to_ofnode(in->np);
824 out->args_count = in->args_count;
825 memcpy(out->args, in->args, sizeof(out->args));
826}
827
828int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
829 const char *cells_name, int cell_count,
830 int index,
831 struct ofnode_phandle_args *out_args)
832{
833 if (ofnode_is_np(node)) {
834 struct of_phandle_args args;
835 int ret;
836
837 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay21e3b042020-09-10 18:26:17 +0200838 list_name, cells_name,
839 cell_count, index,
Mario Sixf40d82c2018-01-15 11:07:17 +0100840 &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600841 if (ret)
842 return ret;
843 ofnode_from_of_phandle_args(&args, out_args);
844 } else {
845 struct fdtdec_phandle_args args;
846 int ret;
847
Simon Glass04fa09a2022-09-06 20:27:20 -0600848 ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Mario Sixf40d82c2018-01-15 11:07:17 +0100849 ofnode_to_offset(node),
850 list_name, cells_name,
851 cell_count, index, &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600852 if (ret)
853 return ret;
854 ofnode_from_fdtdec_phandle_args(&args, out_args);
855 }
856
857 return 0;
858}
859
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200860int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200861 const char *cells_name, int cell_count)
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200862{
863 if (ofnode_is_np(node))
864 return of_count_phandle_with_args(ofnode_to_np(node),
Patrick Delaunayd776a842020-09-25 09:41:14 +0200865 list_name, cells_name, cell_count);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200866 else
Simon Glass04fa09a2022-09-06 20:27:20 -0600867 return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200868 ofnode_to_offset(node), list_name, cells_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200869 cell_count, -1, NULL);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200870}
871
Simon Glassc4fc5622017-05-18 20:08:58 -0600872ofnode ofnode_path(const char *path)
873{
874 if (of_live_active())
875 return np_to_ofnode(of_find_node_by_path(path));
876 else
877 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
878}
879
Simon Glass45ae59d2022-09-06 20:27:24 -0600880ofnode oftree_root(oftree tree)
Simon Glassef75c592022-07-30 15:52:08 -0600881{
Simon Glass45ae59d2022-09-06 20:27:24 -0600882 if (of_live_active()) {
883 return np_to_ofnode(tree.np);
884 } else {
885 return ofnode_from_tree_offset(tree, 0);
886 }
887}
888
889ofnode oftree_path(oftree tree, const char *path)
890{
891 if (of_live_active()) {
Simon Glassef75c592022-07-30 15:52:08 -0600892 return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
893 NULL));
Simon Glass45ae59d2022-09-06 20:27:24 -0600894 } else if (*path != '/' && tree.fdt != gd->fdt_blob) {
Simon Glassef75c592022-07-30 15:52:08 -0600895 return ofnode_null(); /* Aliases only on control FDT */
Simon Glass45ae59d2022-09-06 20:27:24 -0600896 } else {
897 int offset = fdt_path_offset(tree.fdt, path);
898
899 return ofnode_from_tree_offset(tree, offset);
900 }
Simon Glassef75c592022-07-30 15:52:08 -0600901}
902
Simon Glasse09223c2020-01-27 08:49:46 -0700903const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600904{
905 ofnode chosen_node;
906
907 chosen_node = ofnode_path("/chosen");
908
Simon Glasse09223c2020-01-27 08:49:46 -0700909 return ofnode_read_prop(chosen_node, propname, sizep);
Simon Glassc4fc5622017-05-18 20:08:58 -0600910}
911
Simon Glasse09223c2020-01-27 08:49:46 -0700912const char *ofnode_read_chosen_string(const char *propname)
913{
914 return ofnode_read_chosen_prop(propname, NULL);
915}
916
Simon Glassc4fc5622017-05-18 20:08:58 -0600917ofnode ofnode_get_chosen_node(const char *name)
918{
919 const char *prop;
920
Simon Glasse09223c2020-01-27 08:49:46 -0700921 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600922 if (!prop)
923 return ofnode_null();
924
925 return ofnode_path(prop);
926}
927
Michal Simek92a88622020-07-28 12:51:08 +0200928const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
929{
930 ofnode node;
931
932 node = ofnode_path("/aliases");
933
934 return ofnode_read_prop(node, propname, sizep);
935}
936
937ofnode ofnode_get_aliases_node(const char *name)
938{
939 const char *prop;
940
941 prop = ofnode_read_aliases_prop(name, NULL);
942 if (!prop)
943 return ofnode_null();
944
945 debug("%s: node_path: %s\n", __func__, prop);
946
947 return ofnode_path(prop);
948}
949
developerd93c8b42020-05-02 11:35:09 +0200950int ofnode_get_child_count(ofnode parent)
951{
952 ofnode child;
953 int num = 0;
954
955 ofnode_for_each_subnode(child, parent)
956 num++;
957
958 return num;
959}
960
Simon Glassc4fc5622017-05-18 20:08:58 -0600961static int decode_timing_property(ofnode node, const char *name,
962 struct timing_entry *result)
963{
964 int length, ret = 0;
965
966 length = ofnode_read_size(node, name);
967 if (length < 0) {
968 debug("%s: could not find property %s\n",
969 ofnode_get_name(node), name);
970 return length;
971 }
972
973 if (length == sizeof(u32)) {
974 result->typ = ofnode_read_u32_default(node, name, 0);
975 result->min = result->typ;
976 result->max = result->typ;
977 } else {
978 ret = ofnode_read_u32_array(node, name, &result->min, 3);
979 }
980
981 return ret;
982}
983
984int ofnode_decode_display_timing(ofnode parent, int index,
985 struct display_timing *dt)
986{
987 int i;
988 ofnode timings, node;
989 u32 val = 0;
990 int ret = 0;
991
992 timings = ofnode_find_subnode(parent, "display-timings");
993 if (!ofnode_valid(timings))
994 return -EINVAL;
995
Simon Glass28529762017-08-05 15:45:54 -0600996 i = 0;
997 ofnode_for_each_subnode(node, timings) {
998 if (i++ == index)
999 break;
1000 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001001
1002 if (!ofnode_valid(node))
1003 return -EINVAL;
1004
1005 memset(dt, 0, sizeof(*dt));
1006
1007 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
1008 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
1009 ret |= decode_timing_property(node, "hactive", &dt->hactive);
1010 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
1011 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
1012 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
1013 ret |= decode_timing_property(node, "vactive", &dt->vactive);
1014 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
1015 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
1016
1017 dt->flags = 0;
1018 val = ofnode_read_u32_default(node, "vsync-active", -1);
1019 if (val != -1) {
1020 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1021 DISPLAY_FLAGS_VSYNC_LOW;
1022 }
1023 val = ofnode_read_u32_default(node, "hsync-active", -1);
1024 if (val != -1) {
1025 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1026 DISPLAY_FLAGS_HSYNC_LOW;
1027 }
1028 val = ofnode_read_u32_default(node, "de-active", -1);
1029 if (val != -1) {
1030 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1031 DISPLAY_FLAGS_DE_LOW;
1032 }
1033 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
1034 if (val != -1) {
1035 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1036 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1037 }
1038
1039 if (ofnode_read_bool(node, "interlaced"))
1040 dt->flags |= DISPLAY_FLAGS_INTERLACED;
1041 if (ofnode_read_bool(node, "doublescan"))
1042 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1043 if (ofnode_read_bool(node, "doubleclk"))
1044 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1045
1046 return ret;
1047}
1048
Nikhil M Jainff407062023-01-31 15:35:14 +05301049int ofnode_decode_panel_timing(ofnode parent,
1050 struct display_timing *dt)
1051{
1052 ofnode timings;
1053 u32 val = 0;
1054 int ret = 0;
1055
Raphael Gallais-Poua853b922023-05-11 16:36:52 +02001056 timings = ofnode_find_subnode(parent, "panel-timing");
Nikhil M Jainff407062023-01-31 15:35:14 +05301057 if (!ofnode_valid(timings))
1058 return -EINVAL;
1059 memset(dt, 0, sizeof(*dt));
1060 ret |= decode_timing_property(timings, "hback-porch", &dt->hback_porch);
1061 ret |= decode_timing_property(timings, "hfront-porch", &dt->hfront_porch);
1062 ret |= decode_timing_property(timings, "hactive", &dt->hactive);
1063 ret |= decode_timing_property(timings, "hsync-len", &dt->hsync_len);
1064 ret |= decode_timing_property(timings, "vback-porch", &dt->vback_porch);
1065 ret |= decode_timing_property(timings, "vfront-porch", &dt->vfront_porch);
1066 ret |= decode_timing_property(timings, "vactive", &dt->vactive);
1067 ret |= decode_timing_property(timings, "vsync-len", &dt->vsync_len);
1068 ret |= decode_timing_property(timings, "clock-frequency", &dt->pixelclock);
1069 dt->flags = 0;
1070 if (!ofnode_read_u32(timings, "vsync-active", &val)) {
1071 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1072 DISPLAY_FLAGS_VSYNC_LOW;
1073 }
1074 if (!ofnode_read_u32(timings, "hsync-active", &val)) {
1075 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1076 DISPLAY_FLAGS_HSYNC_LOW;
1077 }
1078 if (!ofnode_read_u32(timings, "de-active", &val)) {
1079 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1080 DISPLAY_FLAGS_DE_LOW;
1081 }
1082 if (!ofnode_read_u32(timings, "pixelclk-active", &val)) {
1083 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1084 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1085 }
1086 if (ofnode_read_bool(timings, "interlaced"))
1087 dt->flags |= DISPLAY_FLAGS_INTERLACED;
1088 if (ofnode_read_bool(timings, "doublescan"))
1089 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1090 if (ofnode_read_bool(timings, "doubleclk"))
1091 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1092
1093 return ret;
1094}
1095
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +09001096const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glassc4fc5622017-05-18 20:08:58 -06001097{
Masahiro Yamada5052f1b2017-06-22 16:54:04 +09001098 if (ofnode_is_np(node))
1099 return of_get_property(ofnode_to_np(node), propname, lenp);
1100 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001101 return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001102 propname, lenp);
Simon Glassc4fc5622017-05-18 20:08:58 -06001103}
1104
Simon Glassfec058d2022-09-06 20:27:13 -06001105int ofnode_first_property(ofnode node, struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001106{
1107 prop->node = node;
1108
1109 if (ofnode_is_np(node)) {
1110 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
1111 if (!prop->prop)
1112 return -FDT_ERR_NOTFOUND;
1113 } else {
1114 prop->offset =
Simon Glass04fa09a2022-09-06 20:27:20 -06001115 fdt_first_property_offset(ofnode_to_fdt(node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001116 ofnode_to_offset(prop->node));
1117 if (prop->offset < 0)
1118 return prop->offset;
1119 }
1120
1121 return 0;
1122}
1123
Simon Glassfec058d2022-09-06 20:27:13 -06001124int ofnode_next_property(struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001125{
1126 if (ofnode_is_np(prop->node)) {
1127 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
1128 prop->prop);
1129 if (!prop->prop)
1130 return -FDT_ERR_NOTFOUND;
1131 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001132 prop->offset =
1133 fdt_next_property_offset(ofnode_to_fdt(prop->node),
1134 prop->offset);
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001135 if (prop->offset < 0)
1136 return prop->offset;
1137 }
1138
1139 return 0;
1140}
1141
Simon Glassd0aff8b2022-09-06 20:27:14 -06001142const void *ofprop_get_property(const struct ofprop *prop,
1143 const char **propname, int *lenp)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001144{
1145 if (ofnode_is_np(prop->node))
1146 return of_get_property_by_prop(ofnode_to_np(prop->node),
1147 prop->prop, propname, lenp);
1148 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001149 return fdt_getprop_by_offset(ofnode_to_fdt(prop->node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001150 prop->offset,
1151 propname, lenp);
1152}
1153
Simon Glassc4fc5622017-05-18 20:08:58 -06001154fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
1155 fdt_size_t *sizep)
1156{
1157 if (ofnode_is_np(node)) {
1158 int na, ns;
1159 int psize;
1160 const struct device_node *np = ofnode_to_np(node);
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001161 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glassc4fc5622017-05-18 20:08:58 -06001162
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001163 if (!prop)
1164 return FDT_ADDR_T_NONE;
Simon Glassc4fc5622017-05-18 20:08:58 -06001165 na = of_n_addr_cells(np);
Marek Vasut1638c172018-10-01 12:37:19 +02001166 ns = of_n_size_cells(np);
Simon Glassa67cc632017-05-18 20:09:27 -06001167 *sizep = of_read_number(prop + na, ns);
Marek Vasuta9dac492018-10-01 12:37:20 +02001168
Dario Binacchif8fc7032021-05-01 17:05:26 +02001169 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta9dac492018-10-01 12:37:20 +02001170 return of_translate_address(np, prop);
1171 else
1172 return of_read_number(prop, na);
Simon Glassc4fc5622017-05-18 20:08:58 -06001173 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001174 return fdtdec_get_addr_size(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001175 ofnode_to_offset(node), property,
1176 sizep);
1177 }
1178}
1179
1180const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
1181 size_t sz)
1182{
1183 if (ofnode_is_np(node)) {
1184 const struct device_node *np = ofnode_to_np(node);
1185 int psize;
1186 const __be32 *prop = of_get_property(np, propname, &psize);
1187
1188 if (!prop || sz != psize)
1189 return NULL;
1190 return (uint8_t *)prop;
1191
1192 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001193 return fdtdec_locate_byte_array(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001194 ofnode_to_offset(node), propname, sz);
1195 }
1196}
1197
1198int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
1199 const char *propname, struct fdt_pci_addr *addr)
1200{
Masahiro Yamada5c5991e2017-06-22 17:57:50 +09001201 const fdt32_t *cell;
Simon Glassc4fc5622017-05-18 20:08:58 -06001202 int len;
1203 int ret = -ENOENT;
1204
1205 debug("%s: %s: ", __func__, propname);
1206
1207 /*
1208 * If we follow the pci bus bindings strictly, we should check
1209 * the value of the node's parent node's #address-cells and
1210 * #size-cells. They need to be 3 and 2 accordingly. However,
1211 * for simplicity we skip the check here.
1212 */
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +09001213 cell = ofnode_get_property(node, propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -06001214 if (!cell)
1215 goto fail;
1216
1217 if ((len % FDT_PCI_REG_SIZE) == 0) {
1218 int num = len / FDT_PCI_REG_SIZE;
1219 int i;
1220
1221 for (i = 0; i < num; i++) {
1222 debug("pci address #%d: %08lx %08lx %08lx\n", i,
1223 (ulong)fdt32_to_cpu(cell[0]),
1224 (ulong)fdt32_to_cpu(cell[1]),
1225 (ulong)fdt32_to_cpu(cell[2]));
1226 if ((fdt32_to_cpu(*cell) & type) == type) {
1227 addr->phys_hi = fdt32_to_cpu(cell[0]);
1228 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glassdfd43152019-09-25 08:55:46 -06001229 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glassc4fc5622017-05-18 20:08:58 -06001230 break;
Simon Glassc4fc5622017-05-18 20:08:58 -06001231 }
Mario Sixf40d82c2018-01-15 11:07:17 +01001232
1233 cell += (FDT_PCI_ADDR_CELLS +
1234 FDT_PCI_SIZE_CELLS);
Simon Glassc4fc5622017-05-18 20:08:58 -06001235 }
1236
1237 if (i == num) {
1238 ret = -ENXIO;
1239 goto fail;
1240 }
1241
1242 return 0;
Simon Glassc4fc5622017-05-18 20:08:58 -06001243 }
1244
Mario Sixf40d82c2018-01-15 11:07:17 +01001245 ret = -EINVAL;
1246
Simon Glassc4fc5622017-05-18 20:08:58 -06001247fail:
1248 debug("(not found)\n");
1249 return ret;
1250}
1251
Bin Mengfa157712018-08-03 01:14:35 -07001252int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
1253{
1254 const char *list, *end;
1255 int len;
1256
1257 list = ofnode_get_property(node, "compatible", &len);
1258 if (!list)
1259 return -ENOENT;
1260
1261 end = list + len;
1262 while (list < end) {
1263 len = strlen(list);
1264 if (len >= strlen("pciVVVV,DDDD")) {
1265 char *s = strstr(list, "pci");
1266
1267 /*
1268 * check if the string is something like pciVVVV,DDDD.RR
1269 * or just pciVVVV,DDDD
1270 */
1271 if (s && s[7] == ',' &&
1272 (s[12] == '.' || s[12] == 0)) {
1273 s += 3;
1274 *vendor = simple_strtol(s, NULL, 16);
1275
1276 s += 5;
1277 *device = simple_strtol(s, NULL, 16);
1278
1279 return 0;
1280 }
1281 }
1282 list += (len + 1);
1283 }
1284
1285 return -ENOENT;
1286}
1287
Michal Simeka253c3b2022-02-23 15:45:40 +01001288int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
1289{
1290 const char *list, *end;
1291 int len;
1292
1293 list = ofnode_get_property(node, "compatible", &len);
1294
1295 if (!list)
1296 return -ENOENT;
1297
1298 end = list + len;
1299 while (list < end) {
1300 len = strlen(list);
1301
Michal Simekc633cdf2022-10-31 17:08:44 -07001302 if (len >= strlen("ethernet-phy-idVVVV.DDDD")) {
Michal Simeka253c3b2022-02-23 15:45:40 +01001303 char *s = strstr(list, "ethernet-phy-id");
1304
1305 /*
1306 * check if the string is something like
Michal Simekc633cdf2022-10-31 17:08:44 -07001307 * ethernet-phy-idVVVV.DDDD
Michal Simeka253c3b2022-02-23 15:45:40 +01001308 */
1309 if (s && s[19] == '.') {
1310 s += strlen("ethernet-phy-id");
1311 *vendor = simple_strtol(s, NULL, 16);
1312 s += 5;
1313 *device = simple_strtol(s, NULL, 16);
1314
1315 return 0;
1316 }
1317 }
1318 list += (len + 1);
1319 }
1320
1321 return -ENOENT;
1322}
1323
Simon Glassc4fc5622017-05-18 20:08:58 -06001324int ofnode_read_addr_cells(ofnode node)
1325{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001326 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001327 return of_n_addr_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001328 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001329 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001330 ofnode_to_offset(node));
1331
Simon Glass04fa09a2022-09-06 20:27:20 -06001332 return fdt_address_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001333 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001334}
1335
1336int ofnode_read_size_cells(ofnode node)
1337{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001338 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001339 return of_n_size_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001340 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001341 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001342 ofnode_to_offset(node));
1343
Simon Glass04fa09a2022-09-06 20:27:20 -06001344 return fdt_size_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001345 }
Simon Glass4191dc12017-06-12 06:21:31 -06001346}
1347
1348int ofnode_read_simple_addr_cells(ofnode node)
1349{
1350 if (ofnode_is_np(node))
1351 return of_simple_addr_cells(ofnode_to_np(node));
1352 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001353 return fdt_address_cells(ofnode_to_fdt(node),
1354 ofnode_to_offset(node));
Simon Glass4191dc12017-06-12 06:21:31 -06001355}
1356
1357int ofnode_read_simple_size_cells(ofnode node)
1358{
1359 if (ofnode_is_np(node))
1360 return of_simple_size_cells(ofnode_to_np(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001361 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001362 return fdt_size_cells(ofnode_to_fdt(node),
1363 ofnode_to_offset(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001364}
1365
1366bool ofnode_pre_reloc(ofnode node)
1367{
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001368#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
1369 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
Simon Glassfc1aa352023-02-13 08:56:34 -07001370 * had property bootph-all or bootph-pre-sram/bootph-pre-ram.
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001371 * They are removed in final dtb (fdtgrep 2nd pass)
1372 */
1373 return true;
1374#else
Simon Glassfc1aa352023-02-13 08:56:34 -07001375 if (ofnode_read_bool(node, "bootph-all"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001376 return true;
Simon Glassfc1aa352023-02-13 08:56:34 -07001377 if (ofnode_read_bool(node, "bootph-some-ram"))
Simon Glass23f22842018-10-01 12:22:18 -06001378 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001379
Simon Glassc4fc5622017-05-18 20:08:58 -06001380 /*
1381 * In regular builds individual spl and tpl handling both
1382 * count as handled pre-relocation for later second init.
1383 */
Simon Glassfc1aa352023-02-13 08:56:34 -07001384 if (ofnode_read_bool(node, "bootph-pre-ram") ||
1385 ofnode_read_bool(node, "bootph-pre-sram"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001386 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001387
Simon Glassc2727e52023-02-13 08:56:32 -07001388 if (IS_ENABLED(CONFIG_OF_TAG_MIGRATE)) {
1389 /* detect and handle old tags */
1390 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc") ||
1391 ofnode_read_bool(node, "u-boot,dm-pre-proper") ||
1392 ofnode_read_bool(node, "u-boot,dm-spl") ||
1393 ofnode_read_bool(node, "u-boot,dm-tpl") ||
1394 ofnode_read_bool(node, "u-boot,dm-vpl")) {
1395 gd->flags |= GD_FLG_OF_TAG_MIGRATE;
1396 return true;
1397 }
1398 }
1399
Simon Glassc4fc5622017-05-18 20:08:58 -06001400 return false;
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001401#endif
Simon Glassc4fc5622017-05-18 20:08:58 -06001402}
Simon Glassf7bfcc42017-07-25 08:29:55 -06001403
1404int ofnode_read_resource(ofnode node, uint index, struct resource *res)
1405{
1406 if (ofnode_is_np(node)) {
1407 return of_address_to_resource(ofnode_to_np(node), index, res);
1408 } else {
1409 struct fdt_resource fres;
1410 int ret;
1411
Simon Glass04fa09a2022-09-06 20:27:20 -06001412 ret = fdt_get_resource(ofnode_to_fdt(node),
1413 ofnode_to_offset(node),
Simon Glassf7bfcc42017-07-25 08:29:55 -06001414 "reg", index, &fres);
1415 if (ret < 0)
1416 return -EINVAL;
1417 memset(res, '\0', sizeof(*res));
1418 res->start = fres.start;
1419 res->end = fres.end;
1420
1421 return 0;
1422 }
1423}
Masahiro Yamada4dada2c2017-08-26 01:12:30 +09001424
1425int ofnode_read_resource_byname(ofnode node, const char *name,
1426 struct resource *res)
1427{
1428 int index;
1429
1430 index = ofnode_stringlist_search(node, "reg-names", name);
1431 if (index < 0)
1432 return index;
1433
1434 return ofnode_read_resource(node, index, res);
1435}
Mario Sixaefac062018-01-15 11:07:19 +01001436
1437u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
1438{
1439 if (ofnode_is_np(node))
1440 return of_translate_address(ofnode_to_np(node), in_addr);
1441 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001442 return fdt_translate_address(ofnode_to_fdt(node),
1443 ofnode_to_offset(node), in_addr);
Mario Sixaefac062018-01-15 11:07:19 +01001444}
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001445
Fabien Dessenne22236e02019-05-31 15:11:30 +02001446u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
1447{
1448 if (ofnode_is_np(node))
1449 return of_translate_dma_address(ofnode_to_np(node), in_addr);
1450 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001451 return fdt_translate_dma_address(ofnode_to_fdt(node),
1452 ofnode_to_offset(node), in_addr);
Fabien Dessenne22236e02019-05-31 15:11:30 +02001453}
1454
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001455int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
1456{
1457 if (ofnode_is_np(node))
1458 return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
1459 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001460 return fdt_get_dma_range(ofnode_to_fdt(node),
1461 ofnode_to_offset(node),
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001462 cpu, bus, size);
1463}
1464
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001465int ofnode_device_is_compatible(ofnode node, const char *compat)
1466{
1467 if (ofnode_is_np(node))
1468 return of_device_is_compatible(ofnode_to_np(node), compat,
1469 NULL, NULL);
1470 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001471 return !fdt_node_check_compatible(ofnode_to_fdt(node),
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001472 ofnode_to_offset(node),
1473 compat);
1474}
Simon Glass954eeae2018-06-11 13:07:13 -06001475
1476ofnode ofnode_by_compatible(ofnode from, const char *compat)
1477{
1478 if (of_live_active()) {
1479 return np_to_ofnode(of_find_compatible_node(
1480 (struct device_node *)ofnode_to_np(from), NULL,
1481 compat));
1482 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001483 return noffset_to_ofnode(from,
1484 fdt_node_offset_by_compatible(ofnode_to_fdt(from),
Simon Glass04fa09a2022-09-06 20:27:20 -06001485 ofnode_to_offset(from), compat));
Simon Glass954eeae2018-06-11 13:07:13 -06001486 }
1487}
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001488
1489ofnode ofnode_by_prop_value(ofnode from, const char *propname,
1490 const void *propval, int proplen)
1491{
1492 if (of_live_active()) {
1493 return np_to_ofnode(of_find_node_by_prop_value(
1494 (struct device_node *)ofnode_to_np(from), propname,
1495 propval, proplen));
1496 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001497 return noffset_to_ofnode(from,
1498 fdt_node_offset_by_prop_value(ofnode_to_fdt(from),
1499 ofnode_to_offset(from), propname, propval,
1500 proplen));
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001501 }
1502}
Mario Six047dafc2018-06-26 08:46:48 +02001503
Simon Glass5e2cd5e2022-07-30 15:52:10 -06001504int ofnode_write_prop(ofnode node, const char *propname, const void *value,
Simon Glass17abed02022-09-06 20:27:32 -06001505 int len, bool copy)
Mario Six047dafc2018-06-26 08:46:48 +02001506{
Simon Glass17abed02022-09-06 20:27:32 -06001507 if (of_live_active()) {
1508 void *newval;
1509 int ret;
1510
1511 if (copy) {
1512 newval = malloc(len);
1513 if (!newval)
1514 return log_ret(-ENOMEM);
1515 memcpy(newval, value, len);
1516 value = newval;
1517 }
1518 ret = of_write_prop(ofnode_to_np(node), propname, len, value);
1519 if (ret && copy)
1520 free(newval);
1521 return ret;
1522 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001523 return fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glass3ee3d152022-07-30 15:52:13 -06001524 propname, value, len);
Simon Glass17abed02022-09-06 20:27:32 -06001525 }
Mario Six047dafc2018-06-26 08:46:48 +02001526}
1527
1528int ofnode_write_string(ofnode node, const char *propname, const char *value)
1529{
Mario Six047dafc2018-06-26 08:46:48 +02001530 assert(ofnode_valid(node));
1531
1532 debug("%s: %s = %s", __func__, propname, value);
1533
Simon Glass17abed02022-09-06 20:27:32 -06001534 return ofnode_write_prop(node, propname, value, strlen(value) + 1,
1535 false);
Mario Six047dafc2018-06-26 08:46:48 +02001536}
1537
Simon Glassd28e31e2022-07-30 15:52:14 -06001538int ofnode_write_u32(ofnode node, const char *propname, u32 value)
1539{
1540 fdt32_t *val;
1541
1542 assert(ofnode_valid(node));
1543
1544 log_debug("%s = %x", propname, value);
1545 val = malloc(sizeof(*val));
1546 if (!val)
1547 return -ENOMEM;
1548 *val = cpu_to_fdt32(value);
1549
Simon Glass17abed02022-09-06 20:27:32 -06001550 return ofnode_write_prop(node, propname, val, sizeof(value), false);
Simon Glassd28e31e2022-07-30 15:52:14 -06001551}
1552
Mario Six047dafc2018-06-26 08:46:48 +02001553int ofnode_set_enabled(ofnode node, bool value)
1554{
Mario Six047dafc2018-06-26 08:46:48 +02001555 assert(ofnode_valid(node));
1556
1557 if (value)
1558 return ofnode_write_string(node, "status", "okay");
1559 else
Bin Menga9274aa2019-07-05 09:23:17 -07001560 return ofnode_write_string(node, "status", "disabled");
Mario Six047dafc2018-06-26 08:46:48 +02001561}
Simon Glass0034d962021-08-07 07:24:01 -06001562
1563bool ofnode_conf_read_bool(const char *prop_name)
1564{
1565 ofnode node;
1566
1567 node = ofnode_path("/config");
1568 if (!ofnode_valid(node))
1569 return false;
1570
1571 return ofnode_read_bool(node, prop_name);
1572}
1573
1574int ofnode_conf_read_int(const char *prop_name, int default_val)
1575{
1576 ofnode node;
1577
1578 node = ofnode_path("/config");
1579 if (!ofnode_valid(node))
1580 return default_val;
1581
1582 return ofnode_read_u32_default(node, prop_name, default_val);
1583}
1584
1585const char *ofnode_conf_read_str(const char *prop_name)
1586{
1587 ofnode node;
1588
1589 node = ofnode_path("/config");
1590 if (!ofnode_valid(node))
1591 return NULL;
1592
1593 return ofnode_read_string(node, prop_name);
1594}
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001595
Michal Simek43c42bd2023-08-31 08:59:05 +02001596int ofnode_read_bootscript_address(u64 *bootscr_address, u64 *bootscr_offset)
1597{
1598 int ret;
1599 ofnode uboot;
1600
1601 *bootscr_address = 0;
1602 *bootscr_offset = 0;
1603
1604 uboot = ofnode_path("/options/u-boot");
1605 if (!ofnode_valid(uboot)) {
Michal Simek951ca592023-09-11 15:30:01 +02001606 debug("%s: Missing /u-boot node\n", __func__);
Michal Simek43c42bd2023-08-31 08:59:05 +02001607 return -EINVAL;
1608 }
1609
1610 ret = ofnode_read_u64(uboot, "bootscr-address", bootscr_address);
1611 if (ret) {
1612 ret = ofnode_read_u64(uboot, "bootscr-ram-offset",
1613 bootscr_offset);
1614 if (ret)
1615 return -EINVAL;
1616 }
1617
1618 return 0;
1619}
1620
Michal Simek6a7c1ce2023-08-31 09:04:27 +02001621int ofnode_read_bootscript_flash(u64 *bootscr_flash_offset,
1622 u64 *bootscr_flash_size)
1623{
1624 int ret;
1625 ofnode uboot;
1626
1627 *bootscr_flash_offset = 0;
1628 *bootscr_flash_size = 0;
1629
1630 uboot = ofnode_path("/options/u-boot");
1631 if (!ofnode_valid(uboot)) {
Michal Simek951ca592023-09-11 15:30:01 +02001632 debug("%s: Missing /u-boot node\n", __func__);
Michal Simek6a7c1ce2023-08-31 09:04:27 +02001633 return -EINVAL;
1634 }
1635
1636 ret = ofnode_read_u64(uboot, "bootscr-flash-offset",
1637 bootscr_flash_offset);
1638 if (ret)
1639 return -EINVAL;
1640
1641 ret = ofnode_read_u64(uboot, "bootscr-flash-size",
1642 bootscr_flash_size);
1643 if (ret)
1644 return -EINVAL;
1645
1646 if (!bootscr_flash_size) {
1647 debug("bootscr-flash-size is zero. Ignoring properties!\n");
1648 *bootscr_flash_offset = 0;
1649 return -EINVAL;
1650 }
1651
1652 return 0;
1653}
1654
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001655ofnode ofnode_get_phy_node(ofnode node)
1656{
1657 /* DT node properties that reference a PHY node */
1658 static const char * const phy_handle_str[] = {
1659 "phy-handle", "phy", "phy-device",
1660 };
1661 struct ofnode_phandle_args args = {
1662 .node = ofnode_null()
1663 };
1664 int i;
1665
1666 assert(ofnode_valid(node));
1667
1668 for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
1669 if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
1670 NULL, 0, 0, &args))
1671 break;
1672
1673 return args.node;
1674}
Marek Behúnbc194772022-04-07 00:33:01 +02001675
1676phy_interface_t ofnode_read_phy_mode(ofnode node)
1677{
1678 const char *mode;
1679 int i;
1680
1681 assert(ofnode_valid(node));
1682
1683 mode = ofnode_read_string(node, "phy-mode");
1684 if (!mode)
1685 mode = ofnode_read_string(node, "phy-connection-type");
1686
1687 if (!mode)
Marek Behún48631e42022-04-07 00:33:03 +02001688 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001689
Marek Behún21a18362022-04-07 00:33:02 +02001690 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
Marek Behúnbc194772022-04-07 00:33:01 +02001691 if (!strcmp(mode, phy_interface_strings[i]))
1692 return i;
1693
1694 debug("%s: Invalid PHY interface '%s'\n", __func__, mode);
1695
Marek Behún48631e42022-04-07 00:33:03 +02001696 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001697}
Simon Glass56bc3322022-09-06 20:27:02 -06001698
1699int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
1700{
1701 ofnode subnode;
1702 int ret = 0;
1703
1704 assert(ofnode_valid(node));
1705
1706 if (ofnode_is_np(node)) {
1707 struct device_node *np, *child;
1708
1709 np = (struct device_node *)ofnode_to_np(node);
1710 ret = of_add_subnode(np, name, -1, &child);
1711 if (ret && ret != -EEXIST)
1712 return ret;
1713 subnode = np_to_ofnode(child);
1714 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001715 void *fdt = ofnode_to_fdt(node);
Simon Glass56bc3322022-09-06 20:27:02 -06001716 int poffset = ofnode_to_offset(node);
1717 int offset;
1718
1719 offset = fdt_add_subnode(fdt, poffset, name);
1720 if (offset == -FDT_ERR_EXISTS) {
1721 offset = fdt_subnode_offset(fdt, poffset, name);
1722 ret = -EEXIST;
1723 }
1724 if (offset < 0)
1725 return -EINVAL;
Simon Glass37dcd912022-09-06 20:27:23 -06001726 subnode = noffset_to_ofnode(node, offset);
Simon Glass56bc3322022-09-06 20:27:02 -06001727 }
1728
1729 *subnodep = subnode;
1730
1731 return ret; /* 0 or -EEXIST */
1732}
Simon Glass7a7229a2022-09-06 20:27:33 -06001733
1734int ofnode_copy_props(ofnode src, ofnode dst)
1735{
1736 struct ofprop prop;
1737
1738 ofnode_for_each_prop(prop, src) {
1739 const char *name;
1740 const char *val;
1741 int len, ret;
1742
1743 val = ofprop_get_property(&prop, &name, &len);
1744 if (!val) {
1745 log_debug("Cannot read prop (err=%d)\n", len);
1746 return log_msg_ret("get", -EINVAL);
1747 }
1748 ret = ofnode_write_prop(dst, name, val, len, true);
1749 if (ret) {
1750 log_debug("Cannot write prop (err=%d)\n", ret);
1751 return log_msg_ret("wr", -EINVAL);
1752 }
1753 }
1754
1755 return 0;
1756}