blob: 83c60069cb37966f1b524e4f9fccc6d528651408 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassc4fc5622017-05-18 20:08:58 -06002/*
3 * Copyright (c) 2017 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glassc4fc5622017-05-18 20:08:58 -06005 */
6
Simon Glasscb13a1b2022-09-06 20:27:26 -06007#define LOG_CATEGORY LOGC_DT
8
Simon Glassc4fc5622017-05-18 20:08:58 -06009#include <dm.h>
10#include <fdtdec.h>
11#include <fdt_support.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070013#include <malloc.h>
Simon Glass722281b2023-06-01 10:22:42 -060014#include <of_live.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090015#include <linux/libfdt.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060016#include <dm/of_access.h>
Simon Glass049ae1b2017-05-18 20:09:01 -060017#include <dm/of_addr.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060018#include <dm/ofnode.h>
Quentin Schulz95a5a2b2024-06-11 15:04:26 +020019#include <dm/util.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060020#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
Simon Glassf4c8cf22023-11-12 08:27:45 -070086 if (fdt_check_header(fdt)) {
87 log_err("Invalid device tree blob header\n");
88 return oftree_null();
89 }
90
Simon Glasscb13a1b2022-09-06 20:27:26 -060091 /* register the new tree */
92 i = oftree_count++;
93 oftree_list[i] = fdt;
94 log_debug("oftree: registered tree %d: %p\n", i, fdt);
95 }
96 } else {
97 if (fdt != gd->fdt_blob) {
Simon Glass67f8e112023-06-01 10:22:41 -060098 log_debug("Only the control FDT can be accessed before relocation\n");
Simon Glasscb13a1b2022-09-06 20:27:26 -060099 return oftree_null();
100 }
101 }
102
103 tree.fdt = fdt;
104
105 return tree;
106}
107
Simon Glassa869a1b2023-09-26 08:14:40 -0600108int oftree_new(oftree *treep)
109{
110 oftree tree = oftree_null();
111 int ret;
112
113 if (of_live_active()) {
114 struct device_node *root;
115
116 ret = of_live_create_empty(&root);
117 if (ret)
118 return log_msg_ret("liv", ret);
119 tree = oftree_from_np(root);
120 } else {
Simon Glass9479c642025-01-10 17:00:09 -0700121 const int size = 4096;
Simon Glassa869a1b2023-09-26 08:14:40 -0600122 void *fdt;
123
124 ret = check_tree_count();
125 if (ret)
126 return log_msg_ret("fla", ret);
127
128 /* register the new tree with a small size */
129 fdt = malloc(size);
130 if (!fdt)
131 return log_msg_ret("fla", -ENOMEM);
132 ret = fdt_create_empty_tree(fdt, size);
133 if (ret)
134 return log_msg_ret("fla", -EINVAL);
135 oftree_list[oftree_count++] = fdt;
136 tree.fdt = fdt;
137 }
138 *treep = tree;
139
140 return 0;
141}
142
Simon Glass722281b2023-06-01 10:22:42 -0600143void oftree_dispose(oftree tree)
144{
145 if (of_live_active())
146 of_live_free(tree.np);
147}
148
Simon Glasscb13a1b2022-09-06 20:27:26 -0600149void *ofnode_lookup_fdt(ofnode node)
150{
151 if (gd->flags & GD_FLG_RELOC) {
152 uint i = OFTREE_TREE_ID(node.of_offset);
153
Dan Carpenter408ccac2023-07-26 09:59:52 +0300154 if (i >= oftree_count) {
Simon Glasscb13a1b2022-09-06 20:27:26 -0600155 log_debug("Invalid tree ID %x\n", i);
156 return NULL;
157 }
158
159 return oftree_list[i];
160 } else {
161 return (void *)gd->fdt_blob;
162 }
163}
164
165void *ofnode_to_fdt(ofnode node)
166{
167#ifdef OF_CHECKS
168 if (of_live_active())
169 return NULL;
170#endif
171 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && ofnode_valid(node))
172 return ofnode_lookup_fdt(node);
173
174 /* Use the control FDT by default */
175 return (void *)gd->fdt_blob;
176}
177
Simon Glass45ae59d2022-09-06 20:27:24 -0600178/**
Simon Glasscb13a1b2022-09-06 20:27:26 -0600179 * ofnode_to_offset() - convert an ofnode to a flat DT offset
180 *
181 * This cannot be called if the reference contains a node pointer.
182 *
183 * @node: Reference containing offset (possibly invalid)
184 * Return: DT offset (can be -1)
185 */
186int ofnode_to_offset(ofnode node)
187{
188#ifdef OF_CHECKS
189 if (of_live_active())
190 return -1;
191#endif
192 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && node.of_offset >= 0)
193 return OFTREE_OFFSET(node.of_offset);
194
195 return node.of_offset;
196}
197
198oftree oftree_from_fdt(void *fdt)
199{
200 oftree tree;
201
202 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
203 return oftree_ensure(fdt);
204
Simon Glass994048b2023-06-01 10:22:31 -0600205#ifdef OF_CHECKS
206 if (of_live_active())
207 return oftree_null();
208#endif
Simon Glasscb13a1b2022-09-06 20:27:26 -0600209 tree.fdt = fdt;
210
211 return tree;
212}
213
214/**
215 * noffset_to_ofnode() - convert a DT offset to an ofnode
216 *
217 * @other_node: Node in the same tree to use as a reference
218 * @of_offset: DT offset (either valid, or -1)
219 * Return: reference to the associated DT offset
220 */
221ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
222{
223 ofnode node;
224
225 if (of_live_active())
226 node.np = NULL;
227 else if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) || of_offset < 0 ||
228 !ofnode_valid(other_node))
229 node.of_offset = of_offset;
230 else
231 node.of_offset = OFTREE_MAKE_NODE(other_node.of_offset,
232 of_offset);
233
234 return node;
235}
236
237#else /* !OFNODE_MULTI_TREE */
238
239static inline int oftree_find(const void *fdt)
240{
241 return 0;
242}
243
Simon Glassa869a1b2023-09-26 08:14:40 -0600244int oftree_new(oftree *treep)
245{
246 return -ENOSYS;
247}
248
Simon Glasscb13a1b2022-09-06 20:27:26 -0600249#endif /* OFNODE_MULTI_TREE */
250
Simon Glassebbe90b2023-09-26 08:14:43 -0600251int oftree_to_fdt(oftree tree, struct abuf *buf)
252{
253 int ret;
254
255 if (of_live_active()) {
256 ret = of_live_flatten(ofnode_to_np(oftree_root(tree)), buf);
257 if (ret)
258 return log_msg_ret("flt", ret);
259 } else {
260 void *fdt = oftree_lookup_fdt(tree);
261
262 abuf_init(buf);
263 abuf_set(buf, fdt, fdt_totalsize(fdt));
264 }
265
266 return 0;
267}
268
Simon Glasscb13a1b2022-09-06 20:27:26 -0600269/**
Simon Glass45ae59d2022-09-06 20:27:24 -0600270 * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
271 *
Simon Glasscb13a1b2022-09-06 20:27:26 -0600272 * Looks up the tree and returns an ofnode with the correct of_offset (i.e.
273 * containing the tree ID).
Simon Glass45ae59d2022-09-06 20:27:24 -0600274 *
Simon Glasscb13a1b2022-09-06 20:27:26 -0600275 * If @offset is < 0 then this returns an ofnode with that offset and no tree
276 * ID.
Simon Glass45ae59d2022-09-06 20:27:24 -0600277 *
278 * @tree: tree to check
279 * @offset: offset within that tree (can be < 0)
Simon Glasscb13a1b2022-09-06 20:27:26 -0600280 * @return node for that offset, with the correct ID
Simon Glass45ae59d2022-09-06 20:27:24 -0600281 */
282static ofnode ofnode_from_tree_offset(oftree tree, int offset)
283{
284 ofnode node;
285
Simon Glasscb13a1b2022-09-06 20:27:26 -0600286 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && offset >= 0) {
287 int tree_id = oftree_find(tree.fdt);
288
289 if (tree_id == -1)
290 return ofnode_null();
291 node.of_offset = OFTREE_NODE(tree_id, offset);
292 } else {
293 node.of_offset = offset;
294 }
Simon Glass45ae59d2022-09-06 20:27:24 -0600295
296 return node;
297}
298
Kishon Vijay Abraham Id6388f22021-07-21 21:28:30 +0530299bool ofnode_name_eq(ofnode node, const char *name)
300{
301 const char *node_name;
302 size_t len;
303
304 assert(ofnode_valid(node));
305
306 node_name = ofnode_get_name(node);
307 len = strchrnul(node_name, '@') - node_name;
308
309 return (strlen(name) == len) && !strncmp(node_name, name, len);
310}
311
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200312int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
313{
314 const u8 *cell;
315 int len;
316
317 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200318 log_debug("%s: %s: ", __func__, propname);
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200319
320 if (ofnode_is_np(node))
321 return of_read_u8(ofnode_to_np(node), propname, outp);
322
323 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
324 &len);
325 if (!cell || len < sizeof(*cell)) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200326 log_debug("(not found)\n");
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200327 return -EINVAL;
328 }
329 *outp = *cell;
Quentin Schulze2d4d262024-10-15 16:32:14 +0200330 log_debug("%#x (%u)\n", *outp, *outp);
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200331
332 return 0;
333}
334
335u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
336{
337 assert(ofnode_valid(node));
338 ofnode_read_u8(node, propname, &def);
339
340 return def;
341}
342
343int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
344{
345 const fdt16_t *cell;
346 int len;
347
348 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200349 log_debug("%s: %s: ", __func__, propname);
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200350
351 if (ofnode_is_np(node))
352 return of_read_u16(ofnode_to_np(node), propname, outp);
353
354 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
355 &len);
356 if (!cell || len < sizeof(*cell)) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200357 log_debug("(not found)\n");
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200358 return -EINVAL;
359 }
360 *outp = be16_to_cpup(cell);
Quentin Schulze2d4d262024-10-15 16:32:14 +0200361 log_debug("%#x (%u)\n", *outp, *outp);
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200362
363 return 0;
364}
365
366u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def)
367{
368 assert(ofnode_valid(node));
369 ofnode_read_u16(node, propname, &def);
370
371 return def;
372}
373
Simon Glassc4fc5622017-05-18 20:08:58 -0600374int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
375{
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200376 return ofnode_read_u32_index(node, propname, 0, outp);
Simon Glassc4fc5622017-05-18 20:08:58 -0600377}
378
Trent Piepho5b775412019-05-10 17:48:20 +0000379u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
Simon Glassc4fc5622017-05-18 20:08:58 -0600380{
381 assert(ofnode_valid(node));
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200382 ofnode_read_u32_index(node, propname, 0, &def);
Simon Glassc4fc5622017-05-18 20:08:58 -0600383
384 return def;
385}
386
Dario Binacchi81d80b52020-03-29 18:04:41 +0200387int ofnode_read_u32_index(ofnode node, const char *propname, int index,
388 u32 *outp)
389{
390 const fdt32_t *cell;
391 int len;
392
393 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200394 log_debug("%s: %s: ", __func__, propname);
Dario Binacchi81d80b52020-03-29 18:04:41 +0200395
396 if (ofnode_is_np(node))
397 return of_read_u32_index(ofnode_to_np(node), propname, index,
398 outp);
399
Simon Glass04fa09a2022-09-06 20:27:20 -0600400 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
401 propname, &len);
Dario Binacchi81d80b52020-03-29 18:04:41 +0200402 if (!cell) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200403 log_debug("(not found)\n");
Dario Binacchi81d80b52020-03-29 18:04:41 +0200404 return -EINVAL;
405 }
406
407 if (len < (sizeof(int) * (index + 1))) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200408 log_debug("(not large enough)\n");
Dario Binacchi81d80b52020-03-29 18:04:41 +0200409 return -EOVERFLOW;
410 }
411
412 *outp = fdt32_to_cpu(cell[index]);
Quentin Schulze2d4d262024-10-15 16:32:14 +0200413 log_debug("%#x (%u)\n", *outp, *outp);
Dario Binacchi81d80b52020-03-29 18:04:41 +0200414
415 return 0;
416}
417
Michal Simek08a194e2023-08-25 11:37:46 +0200418int ofnode_read_u64_index(ofnode node, const char *propname, int index,
419 u64 *outp)
420{
421 const fdt64_t *cell;
422 int len;
423
424 assert(ofnode_valid(node));
425
426 if (ofnode_is_np(node))
427 return of_read_u64_index(ofnode_to_np(node), propname, index,
428 outp);
429
430 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
431 propname, &len);
432 if (!cell) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200433 log_debug("(not found)\n");
Michal Simek08a194e2023-08-25 11:37:46 +0200434 return -EINVAL;
435 }
436
437 if (len < (sizeof(u64) * (index + 1))) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200438 log_debug("(not large enough)\n");
Michal Simek08a194e2023-08-25 11:37:46 +0200439 return -EOVERFLOW;
440 }
441
442 *outp = fdt64_to_cpu(cell[index]);
Quentin Schulze2d4d262024-10-15 16:32:14 +0200443 log_debug("%#llx (%llu)\n", *outp, *outp);
Michal Simek08a194e2023-08-25 11:37:46 +0200444
445 return 0;
446}
447
Dario Binacchi81d80b52020-03-29 18:04:41 +0200448u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
449 u32 def)
450{
451 assert(ofnode_valid(node));
452 ofnode_read_u32_index(node, propname, index, &def);
453
454 return def;
455}
456
Simon Glassc4fc5622017-05-18 20:08:58 -0600457int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
458{
459 assert(ofnode_valid(node));
460 ofnode_read_u32(node, propname, (u32 *)&def);
461
462 return def;
463}
464
Simon Glass9d54a7a2018-06-11 13:07:10 -0600465int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
466{
Jean-Jacques Hiblot487f9172019-10-22 10:05:22 +0200467 const unaligned_fdt64_t *cell;
Simon Glass9d54a7a2018-06-11 13:07:10 -0600468 int len;
469
470 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200471 log_debug("%s: %s: ", __func__, propname);
Simon Glass9d54a7a2018-06-11 13:07:10 -0600472
473 if (ofnode_is_np(node))
474 return of_read_u64(ofnode_to_np(node), propname, outp);
475
Simon Glass04fa09a2022-09-06 20:27:20 -0600476 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
477 propname, &len);
Simon Glass9d54a7a2018-06-11 13:07:10 -0600478 if (!cell || len < sizeof(*cell)) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200479 log_debug("(not found)\n");
Simon Glass9d54a7a2018-06-11 13:07:10 -0600480 return -EINVAL;
481 }
482 *outp = fdt64_to_cpu(cell[0]);
Quentin Schulze2d4d262024-10-15 16:32:14 +0200483 log_debug("%#llx (%llu)\n", (unsigned long long)*outp,
484 (unsigned long long)*outp);
Simon Glass9d54a7a2018-06-11 13:07:10 -0600485
486 return 0;
487}
488
T Karthik Reddy478860d2019-09-02 16:34:30 +0200489u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
Simon Glass9d54a7a2018-06-11 13:07:10 -0600490{
491 assert(ofnode_valid(node));
492 ofnode_read_u64(node, propname, &def);
493
494 return def;
495}
496
Simon Glassc4fc5622017-05-18 20:08:58 -0600497bool ofnode_read_bool(ofnode node, const char *propname)
498{
Simon Glass86ef3992023-09-26 08:14:44 -0600499 bool prop;
Simon Glassc4fc5622017-05-18 20:08:58 -0600500
501 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200502 log_debug("%s: %s: ", __func__, propname);
Simon Glassc4fc5622017-05-18 20:08:58 -0600503
Simon Glass86ef3992023-09-26 08:14:44 -0600504 prop = ofnode_has_property(node, propname);
Masahiro Yamada5d434452017-06-22 16:54:07 +0900505
Quentin Schulze2d4d262024-10-15 16:32:14 +0200506 log_debug("%s\n", prop ? "true" : "false");
Simon Glassc4fc5622017-05-18 20:08:58 -0600507
Masahiro Yamada5d434452017-06-22 16:54:07 +0900508 return prop ? true : false;
Simon Glassc4fc5622017-05-18 20:08:58 -0600509}
510
Simon Glass0c2e9802020-01-27 08:49:44 -0700511const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600512{
Simon Glass0c2e9802020-01-27 08:49:44 -0700513 const char *val = NULL;
514 int len;
Simon Glassc4fc5622017-05-18 20:08:58 -0600515
516 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200517 log_debug("%s: %s: ", __func__, propname);
Simon Glassc4fc5622017-05-18 20:08:58 -0600518
519 if (ofnode_is_np(node)) {
520 struct property *prop = of_find_property(
Simon Glass0c2e9802020-01-27 08:49:44 -0700521 ofnode_to_np(node), propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600522
523 if (prop) {
Simon Glass0c2e9802020-01-27 08:49:44 -0700524 val = prop->value;
Simon Glassc4fc5622017-05-18 20:08:58 -0600525 len = prop->length;
526 }
527 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600528 val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600529 propname, &len);
530 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700531 if (!val) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200532 log_debug("<not found>\n");
Simon Glass0c2e9802020-01-27 08:49:44 -0700533 if (sizep)
534 *sizep = -FDT_ERR_NOTFOUND;
Simon Glassc4fc5622017-05-18 20:08:58 -0600535 return NULL;
536 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700537 if (sizep)
538 *sizep = len;
539
540 return val;
541}
542
543const char *ofnode_read_string(ofnode node, const char *propname)
544{
545 const char *str;
546 int len;
547
548 str = ofnode_read_prop(node, propname, &len);
549 if (!str)
550 return NULL;
551
Simon Glassc4fc5622017-05-18 20:08:58 -0600552 if (strnlen(str, len) >= len) {
Quentin Schulz95a5a2b2024-06-11 15:04:26 +0200553 dm_warn("<invalid>\n");
Simon Glassc4fc5622017-05-18 20:08:58 -0600554 return NULL;
555 }
Quentin Schulze2d4d262024-10-15 16:32:14 +0200556 log_debug("%s\n", str);
Simon Glassc4fc5622017-05-18 20:08:58 -0600557
558 return str;
559}
560
Simon Glass81c54b32020-01-27 08:49:45 -0700561int ofnode_read_size(ofnode node, const char *propname)
562{
563 int len;
564
565 if (!ofnode_read_prop(node, propname, &len))
566 return -EINVAL;
567
568 return len;
569}
570
Simon Glassc4fc5622017-05-18 20:08:58 -0600571ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
572{
573 ofnode subnode;
574
575 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200576 log_debug("%s: %s: ", __func__, subnode_name);
Simon Glassc4fc5622017-05-18 20:08:58 -0600577
578 if (ofnode_is_np(node)) {
Simon Glass9036c5c2022-09-06 20:27:04 -0600579 struct device_node *np = ofnode_to_np(node);
Simon Glassc4fc5622017-05-18 20:08:58 -0600580
581 for (np = np->child; np; np = np->sibling) {
582 if (!strcmp(subnode_name, np->name))
583 break;
584 }
585 subnode = np_to_ofnode(np);
586 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600587 int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600588 ofnode_to_offset(node), subnode_name);
Simon Glass37dcd912022-09-06 20:27:23 -0600589 subnode = noffset_to_ofnode(node, ooffset);
Simon Glassc4fc5622017-05-18 20:08:58 -0600590 }
Quentin Schulze2d4d262024-10-15 16:32:14 +0200591 log_debug("%s\n", ofnode_valid(subnode) ?
592 ofnode_get_name(subnode) : "<none>");
Simon Glassc4fc5622017-05-18 20:08:58 -0600593
594 return subnode;
595}
596
597int ofnode_read_u32_array(ofnode node, const char *propname,
598 u32 *out_values, size_t sz)
599{
600 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200601 log_debug("%s: %s: ", __func__, propname);
Simon Glassc4fc5622017-05-18 20:08:58 -0600602
603 if (ofnode_is_np(node)) {
604 return of_read_u32_array(ofnode_to_np(node), propname,
605 out_values, sz);
606 } else {
Simon Glasse3be5fc2022-09-06 20:27:18 -0600607 int ret;
608
Simon Glass04fa09a2022-09-06 20:27:20 -0600609 ret = fdtdec_get_int_array(ofnode_to_fdt(node),
Simon Glasse3be5fc2022-09-06 20:27:18 -0600610 ofnode_to_offset(node), propname,
611 out_values, sz);
612
613 /* get the error right, but space is more important in SPL */
Simon Glass7ec24132024-09-29 19:49:48 -0600614 if (!IS_ENABLED(CONFIG_XPL_BUILD)) {
Simon Glasse3be5fc2022-09-06 20:27:18 -0600615 if (ret == -FDT_ERR_NOTFOUND)
616 return -EINVAL;
617 else if (ret == -FDT_ERR_BADLAYOUT)
618 return -EOVERFLOW;
619 }
620 return ret;
Simon Glassc4fc5622017-05-18 20:08:58 -0600621 }
622}
623
Simon Glass39f1d282020-12-16 17:25:06 -0700624#if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
Simon Glass5de5b3b2020-11-28 17:50:02 -0700625bool ofnode_is_enabled(ofnode node)
626{
627 if (ofnode_is_np(node)) {
628 return of_device_is_available(ofnode_to_np(node));
629 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600630 return fdtdec_get_is_enabled(ofnode_to_fdt(node),
Simon Glass5de5b3b2020-11-28 17:50:02 -0700631 ofnode_to_offset(node));
632 }
633}
634
Simon Glassc4fc5622017-05-18 20:08:58 -0600635ofnode ofnode_first_subnode(ofnode node)
636{
637 assert(ofnode_valid(node));
638 if (ofnode_is_np(node))
639 return np_to_ofnode(node.np->child);
640
Simon Glass37dcd912022-09-06 20:27:23 -0600641 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600642 fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600643}
644
645ofnode ofnode_next_subnode(ofnode node)
646{
647 assert(ofnode_valid(node));
648 if (ofnode_is_np(node))
649 return np_to_ofnode(node.np->sibling);
650
Simon Glass37dcd912022-09-06 20:27:23 -0600651 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600652 fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600653}
Simon Glass39f1d282020-12-16 17:25:06 -0700654#endif /* !DM_INLINE_OFNODE */
Simon Glassc4fc5622017-05-18 20:08:58 -0600655
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100656ofnode ofnode_get_parent(ofnode node)
657{
658 ofnode parent;
659
660 assert(ofnode_valid(node));
661 if (ofnode_is_np(node))
662 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
663 else
Simon Glass04fa09a2022-09-06 20:27:20 -0600664 parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100665 ofnode_to_offset(node));
666
667 return parent;
668}
669
Simon Glassc4fc5622017-05-18 20:08:58 -0600670const char *ofnode_get_name(ofnode node)
671{
Kever Yang8d7976d2019-07-19 11:23:47 +0800672 if (!ofnode_valid(node)) {
Quentin Schulz95a5a2b2024-06-11 15:04:26 +0200673 dm_warn("%s node not valid\n", __func__);
Kever Yang8d7976d2019-07-19 11:23:47 +0800674 return NULL;
675 }
676
Simon Glassc4fc5622017-05-18 20:08:58 -0600677 if (ofnode_is_np(node))
Simon Glass91d89a82022-09-06 20:27:15 -0600678 return node.np->name;
Simon Glassc4fc5622017-05-18 20:08:58 -0600679
Simon Glass04fa09a2022-09-06 20:27:20 -0600680 return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600681}
682
Marek Behúne897e3c2021-05-26 14:08:18 +0200683int ofnode_get_path(ofnode node, char *buf, int buflen)
684{
685 assert(ofnode_valid(node));
686
687 if (ofnode_is_np(node)) {
688 if (strlen(node.np->full_name) >= buflen)
689 return -ENOSPC;
690
691 strcpy(buf, node.np->full_name);
692
693 return 0;
694 } else {
695 int res;
696
Simon Glass04fa09a2022-09-06 20:27:20 -0600697 res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
Marek Behúne897e3c2021-05-26 14:08:18 +0200698 buflen);
699 if (!res)
700 return res;
701 else if (res == -FDT_ERR_NOSPACE)
702 return -ENOSPC;
703 else
704 return -EINVAL;
705 }
706}
707
Kever Yang37df0e02018-02-23 17:38:50 +0100708ofnode ofnode_get_by_phandle(uint phandle)
709{
710 ofnode node;
711
712 if (of_live_active())
Simon Glass176dd432022-09-06 20:26:57 -0600713 node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
Kever Yang37df0e02018-02-23 17:38:50 +0100714 else
715 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
716 phandle);
717
718 return node;
719}
720
Simon Glass95fd2092022-09-06 20:27:22 -0600721ofnode oftree_get_by_phandle(oftree tree, uint phandle)
722{
723 ofnode node;
724
725 if (of_live_active())
726 node = np_to_ofnode(of_find_node_by_phandle(tree.np, phandle));
727 else
Simon Glassf912a722022-09-06 20:27:27 -0600728 node = ofnode_from_tree_offset(tree,
Simon Glass95fd2092022-09-06 20:27:22 -0600729 fdt_node_offset_by_phandle(oftree_lookup_fdt(tree),
Simon Glassf912a722022-09-06 20:27:27 -0600730 phandle));
Simon Glass95fd2092022-09-06 20:27:22 -0600731
732 return node;
733}
734
Marek Behún177ab7f2021-05-26 14:08:17 +0200735static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
736 fdt_size_t *size, bool translate)
Simon Glass049ae1b2017-05-18 20:09:01 -0600737{
Keerthy34222a32018-11-19 11:44:47 +0530738 int na, ns;
Keerthy34222a32018-11-19 11:44:47 +0530739
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800740 if (size)
741 *size = FDT_SIZE_T_NONE;
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800742
Simon Glass049ae1b2017-05-18 20:09:01 -0600743 if (ofnode_is_np(node)) {
744 const __be32 *prop_val;
Simon Glass47f85de2019-09-25 08:55:50 -0600745 u64 size64;
Simon Glass049ae1b2017-05-18 20:09:01 -0600746 uint flags;
Simon Glass049ae1b2017-05-18 20:09:01 -0600747
Simon Glass47f85de2019-09-25 08:55:50 -0600748 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
749 &flags);
Simon Glass049ae1b2017-05-18 20:09:01 -0600750 if (!prop_val)
751 return FDT_ADDR_T_NONE;
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800752
Simon Glass47f85de2019-09-25 08:55:50 -0600753 if (size)
754 *size = size64;
Mario Sixd007ebc2017-12-20 09:52:12 +0100755
Mario Six35616ef2018-03-12 14:53:33 +0100756 ns = of_n_size_cells(ofnode_to_np(node));
757
Marek Behún177ab7f2021-05-26 14:08:17 +0200758 if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Sixd007ebc2017-12-20 09:52:12 +0100759 return of_translate_address(ofnode_to_np(node), prop_val);
760 } else {
761 na = of_n_addr_cells(ofnode_to_np(node));
762 return of_read_number(prop_val, na);
763 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600764 } else {
Jonas Karlman641e1182024-08-04 15:05:50 +0000765 ofnode parent = ofnode_get_parent(node);
766 na = ofnode_read_simple_addr_cells(parent);
767 ns = ofnode_read_simple_size_cells(parent);
Simon Glass04fa09a2022-09-06 20:27:20 -0600768 return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
Keerthy34222a32018-11-19 11:44:47 +0530769 ofnode_to_offset(node), "reg",
Marek Behún177ab7f2021-05-26 14:08:17 +0200770 index, na, ns, size,
771 translate);
Simon Glass049ae1b2017-05-18 20:09:01 -0600772 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600773}
774
Marek Behún177ab7f2021-05-26 14:08:17 +0200775fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
776{
777 return __ofnode_get_addr_size_index(node, index, size, true);
778}
779
780fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
781 fdt_size_t *size)
782{
783 return __ofnode_get_addr_size_index(node, index, size, false);
784}
785
Keerthyd332e6e2019-04-24 17:19:53 +0530786fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
787{
788 fdt_size_t size;
789
790 return ofnode_get_addr_size_index(node, index, &size);
791}
792
Simon Glass049ae1b2017-05-18 20:09:01 -0600793fdt_addr_t ofnode_get_addr(ofnode node)
794{
795 return ofnode_get_addr_index(node, 0);
796}
797
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800798fdt_size_t ofnode_get_size(ofnode node)
799{
800 fdt_size_t size;
801
802 ofnode_get_addr_size_index(node, 0, &size);
803
804 return size;
805}
806
Simon Glassc4fc5622017-05-18 20:08:58 -0600807int ofnode_stringlist_search(ofnode node, const char *property,
808 const char *string)
809{
810 if (ofnode_is_np(node)) {
811 return of_property_match_string(ofnode_to_np(node),
812 property, string);
813 } else {
814 int ret;
815
Simon Glass04fa09a2022-09-06 20:27:20 -0600816 ret = fdt_stringlist_search(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600817 ofnode_to_offset(node), property,
818 string);
819 if (ret == -FDT_ERR_NOTFOUND)
820 return -ENODATA;
821 else if (ret < 0)
822 return -EINVAL;
823
824 return ret;
825 }
826}
827
828int ofnode_read_string_index(ofnode node, const char *property, int index,
829 const char **outp)
830{
831 if (ofnode_is_np(node)) {
832 return of_property_read_string_index(ofnode_to_np(node),
833 property, index, outp);
834 } else {
835 int len;
836
Simon Glass04fa09a2022-09-06 20:27:20 -0600837 *outp = fdt_stringlist_get(ofnode_to_fdt(node),
838 ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600839 property, index, &len);
840 if (len < 0)
841 return -EINVAL;
842 return 0;
843 }
844}
845
Simon Glass5fdb0052017-06-12 06:21:28 -0600846int ofnode_read_string_count(ofnode node, const char *property)
847{
848 if (ofnode_is_np(node)) {
849 return of_property_count_strings(ofnode_to_np(node), property);
850 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600851 return fdt_stringlist_count(ofnode_to_fdt(node),
Simon Glass5fdb0052017-06-12 06:21:28 -0600852 ofnode_to_offset(node), property);
853 }
854}
855
Simon Glass9580bfc2021-10-23 17:26:07 -0600856int ofnode_read_string_list(ofnode node, const char *property,
857 const char ***listp)
858{
859 const char **prop;
860 int count;
861 int i;
862
863 *listp = NULL;
864 count = ofnode_read_string_count(node, property);
865 if (count < 0)
866 return count;
867 if (!count)
868 return 0;
869
870 prop = calloc(count + 1, sizeof(char *));
871 if (!prop)
872 return -ENOMEM;
873
874 for (i = 0; i < count; i++)
875 ofnode_read_string_index(node, property, i, &prop[i]);
876 prop[count] = NULL;
877 *listp = prop;
878
879 return count;
880}
881
Christian Marangie810bcd2024-11-10 12:50:22 +0100882ofnode ofnode_parse_phandle(ofnode node, const char *phandle_name,
883 int index)
884{
885 ofnode phandle;
886
887 if (ofnode_is_np(node)) {
888 struct device_node *np;
889
890 np = of_parse_phandle(ofnode_to_np(node), phandle_name,
891 index);
892 if (!np)
893 return ofnode_null();
894
895 phandle = np_to_ofnode(np);
896 } else {
897 struct fdtdec_phandle_args args;
898
899 if (fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
900 ofnode_to_offset(node),
901 phandle_name, NULL,
902 0, index, &args))
903 return ofnode_null();
904
905 phandle = offset_to_ofnode(args.node);
906 }
907
908 return phandle;
909}
910
911ofnode oftree_parse_phandle(oftree tree, ofnode node, const char *phandle_name,
912 int index)
913{
914 ofnode phandle;
915
916 if (ofnode_is_np(node)) {
917 struct device_node *np;
918
919 np = of_root_parse_phandle(tree.np, ofnode_to_np(node),
920 phandle_name, index);
921 if (!np)
922 return ofnode_null();
923
924 phandle = np_to_ofnode(np);
925 } else {
926 struct fdtdec_phandle_args args;
927
928 if (fdtdec_parse_phandle_with_args(tree.fdt,
929 ofnode_to_offset(node),
930 phandle_name, NULL,
931 0, index, &args))
932 return ofnode_null();
933
934 phandle = noffset_to_ofnode(node, args.node);
935 }
936
937 return phandle;
938}
939
Christian Marangi98715ac2024-11-10 12:50:20 +0100940static void ofnode_from_fdtdec_phandle_args(ofnode node, struct fdtdec_phandle_args *in,
Simon Glassc4fc5622017-05-18 20:08:58 -0600941 struct ofnode_phandle_args *out)
942{
943 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
Christian Marangi98715ac2024-11-10 12:50:20 +0100944 out->node = noffset_to_ofnode(node, in->node);
Simon Glassc4fc5622017-05-18 20:08:58 -0600945 out->args_count = in->args_count;
946 memcpy(out->args, in->args, sizeof(out->args));
947}
948
949static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
950 struct ofnode_phandle_args *out)
951{
952 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
953 out->node = np_to_ofnode(in->np);
954 out->args_count = in->args_count;
955 memcpy(out->args, in->args, sizeof(out->args));
956}
957
958int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
959 const char *cells_name, int cell_count,
960 int index,
961 struct ofnode_phandle_args *out_args)
962{
963 if (ofnode_is_np(node)) {
964 struct of_phandle_args args;
965 int ret;
966
967 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay21e3b042020-09-10 18:26:17 +0200968 list_name, cells_name,
969 cell_count, index,
Mario Sixf40d82c2018-01-15 11:07:17 +0100970 &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600971 if (ret)
972 return ret;
973 ofnode_from_of_phandle_args(&args, out_args);
974 } else {
975 struct fdtdec_phandle_args args;
976 int ret;
977
Simon Glass04fa09a2022-09-06 20:27:20 -0600978 ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Mario Sixf40d82c2018-01-15 11:07:17 +0100979 ofnode_to_offset(node),
980 list_name, cells_name,
981 cell_count, index, &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600982 if (ret)
983 return ret;
Christian Marangi98715ac2024-11-10 12:50:20 +0100984 ofnode_from_fdtdec_phandle_args(node, &args, out_args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600985 }
986
987 return 0;
988}
989
Christian Marangi98715ac2024-11-10 12:50:20 +0100990int oftree_parse_phandle_with_args(oftree tree, ofnode node, const char *list_name,
991 const char *cells_name, int cell_count,
992 int index,
993 struct ofnode_phandle_args *out_args)
994{
995 if (ofnode_is_np(node)) {
996 struct of_phandle_args args;
997 int ret;
998
999 ret = of_root_parse_phandle_with_args(tree.np,
1000 ofnode_to_np(node),
1001 list_name, cells_name,
1002 cell_count, index,
1003 &args);
1004 if (ret)
1005 return ret;
1006 ofnode_from_of_phandle_args(&args, out_args);
1007 } else {
1008 struct fdtdec_phandle_args args;
1009 int ret;
1010
1011 ret = fdtdec_parse_phandle_with_args(tree.fdt,
1012 ofnode_to_offset(node),
1013 list_name, cells_name,
1014 cell_count, index, &args);
1015 if (ret)
1016 return ret;
1017 ofnode_from_fdtdec_phandle_args(node, &args, out_args);
1018 }
1019
1020 return 0;
1021}
1022
Patrice Chotardbe7dd602017-07-18 11:57:08 +02001023int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +02001024 const char *cells_name, int cell_count)
Patrice Chotardbe7dd602017-07-18 11:57:08 +02001025{
1026 if (ofnode_is_np(node))
1027 return of_count_phandle_with_args(ofnode_to_np(node),
Patrick Delaunayd776a842020-09-25 09:41:14 +02001028 list_name, cells_name, cell_count);
Patrice Chotardbe7dd602017-07-18 11:57:08 +02001029 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001030 return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Patrice Chotardbe7dd602017-07-18 11:57:08 +02001031 ofnode_to_offset(node), list_name, cells_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +02001032 cell_count, -1, NULL);
Patrice Chotardbe7dd602017-07-18 11:57:08 +02001033}
1034
Christian Marangi98715ac2024-11-10 12:50:20 +01001035int oftree_count_phandle_with_args(oftree tree, ofnode node, const char *list_name,
1036 const char *cells_name, int cell_count)
1037{
1038 if (ofnode_is_np(node))
1039 return of_root_count_phandle_with_args(tree.np, ofnode_to_np(node),
1040 list_name, cells_name, cell_count);
1041 else
1042 return fdtdec_parse_phandle_with_args(tree.fdt,
1043 ofnode_to_offset(node), list_name, cells_name,
1044 cell_count, -1, NULL);
1045}
1046
Simon Glassc4fc5622017-05-18 20:08:58 -06001047ofnode ofnode_path(const char *path)
1048{
1049 if (of_live_active())
1050 return np_to_ofnode(of_find_node_by_path(path));
1051 else
1052 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
1053}
1054
Simon Glass45ae59d2022-09-06 20:27:24 -06001055ofnode oftree_root(oftree tree)
Simon Glassef75c592022-07-30 15:52:08 -06001056{
Simon Glass45ae59d2022-09-06 20:27:24 -06001057 if (of_live_active()) {
1058 return np_to_ofnode(tree.np);
1059 } else {
1060 return ofnode_from_tree_offset(tree, 0);
1061 }
1062}
1063
1064ofnode oftree_path(oftree tree, const char *path)
1065{
1066 if (of_live_active()) {
Simon Glassef75c592022-07-30 15:52:08 -06001067 return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
1068 NULL));
Simon Glass45ae59d2022-09-06 20:27:24 -06001069 } else if (*path != '/' && tree.fdt != gd->fdt_blob) {
Simon Glassef75c592022-07-30 15:52:08 -06001070 return ofnode_null(); /* Aliases only on control FDT */
Simon Glass45ae59d2022-09-06 20:27:24 -06001071 } else {
1072 int offset = fdt_path_offset(tree.fdt, path);
1073
1074 return ofnode_from_tree_offset(tree, offset);
1075 }
Simon Glassef75c592022-07-30 15:52:08 -06001076}
1077
Simon Glasse09223c2020-01-27 08:49:46 -07001078const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -06001079{
1080 ofnode chosen_node;
1081
1082 chosen_node = ofnode_path("/chosen");
1083
Simon Glasse09223c2020-01-27 08:49:46 -07001084 return ofnode_read_prop(chosen_node, propname, sizep);
Simon Glassc4fc5622017-05-18 20:08:58 -06001085}
1086
Simon Glasse09223c2020-01-27 08:49:46 -07001087const char *ofnode_read_chosen_string(const char *propname)
1088{
1089 return ofnode_read_chosen_prop(propname, NULL);
1090}
1091
Simon Glassc4fc5622017-05-18 20:08:58 -06001092ofnode ofnode_get_chosen_node(const char *name)
1093{
1094 const char *prop;
1095
Simon Glasse09223c2020-01-27 08:49:46 -07001096 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -06001097 if (!prop)
1098 return ofnode_null();
1099
1100 return ofnode_path(prop);
1101}
1102
Algapally Santosh Sagardf178992023-09-21 16:50:43 +05301103int ofnode_read_baud(void)
1104{
1105 const char *str, *p;
1106 u32 baud;
1107
1108 str = ofnode_read_chosen_string("stdout-path");
1109 if (!str)
1110 return -EINVAL;
1111
1112 /* Parse string serial0:115200n8 */
1113 p = strchr(str, ':');
1114 if (!p)
1115 return -EINVAL;
1116
1117 baud = dectoul(p + 1, NULL);
1118 return baud;
1119}
1120
Michal Simek92a88622020-07-28 12:51:08 +02001121const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
1122{
1123 ofnode node;
1124
1125 node = ofnode_path("/aliases");
1126
1127 return ofnode_read_prop(node, propname, sizep);
1128}
1129
1130ofnode ofnode_get_aliases_node(const char *name)
1131{
1132 const char *prop;
1133
1134 prop = ofnode_read_aliases_prop(name, NULL);
1135 if (!prop)
1136 return ofnode_null();
1137
Quentin Schulze2d4d262024-10-15 16:32:14 +02001138 log_debug("%s: node_path: %s\n", __func__, prop);
Michal Simek92a88622020-07-28 12:51:08 +02001139
1140 return ofnode_path(prop);
1141}
1142
developerd93c8b42020-05-02 11:35:09 +02001143int ofnode_get_child_count(ofnode parent)
1144{
1145 ofnode child;
1146 int num = 0;
1147
1148 ofnode_for_each_subnode(child, parent)
1149 num++;
1150
1151 return num;
1152}
1153
Simon Glassc4fc5622017-05-18 20:08:58 -06001154static int decode_timing_property(ofnode node, const char *name,
1155 struct timing_entry *result)
1156{
1157 int length, ret = 0;
1158
1159 length = ofnode_read_size(node, name);
1160 if (length < 0) {
Quentin Schulz95a5a2b2024-06-11 15:04:26 +02001161 dm_warn("%s: could not find property %s\n",
1162 ofnode_get_name(node), name);
Simon Glassc4fc5622017-05-18 20:08:58 -06001163 return length;
1164 }
1165
1166 if (length == sizeof(u32)) {
1167 result->typ = ofnode_read_u32_default(node, name, 0);
1168 result->min = result->typ;
1169 result->max = result->typ;
1170 } else {
1171 ret = ofnode_read_u32_array(node, name, &result->min, 3);
1172 }
1173
1174 return ret;
1175}
1176
1177int ofnode_decode_display_timing(ofnode parent, int index,
1178 struct display_timing *dt)
1179{
1180 int i;
1181 ofnode timings, node;
1182 u32 val = 0;
1183 int ret = 0;
1184
1185 timings = ofnode_find_subnode(parent, "display-timings");
1186 if (!ofnode_valid(timings))
1187 return -EINVAL;
1188
Simon Glass28529762017-08-05 15:45:54 -06001189 i = 0;
1190 ofnode_for_each_subnode(node, timings) {
1191 if (i++ == index)
1192 break;
1193 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001194
1195 if (!ofnode_valid(node))
1196 return -EINVAL;
1197
1198 memset(dt, 0, sizeof(*dt));
1199
1200 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
1201 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
1202 ret |= decode_timing_property(node, "hactive", &dt->hactive);
1203 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
1204 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
1205 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
1206 ret |= decode_timing_property(node, "vactive", &dt->vactive);
1207 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
1208 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
1209
1210 dt->flags = 0;
1211 val = ofnode_read_u32_default(node, "vsync-active", -1);
1212 if (val != -1) {
1213 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1214 DISPLAY_FLAGS_VSYNC_LOW;
1215 }
1216 val = ofnode_read_u32_default(node, "hsync-active", -1);
1217 if (val != -1) {
1218 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1219 DISPLAY_FLAGS_HSYNC_LOW;
1220 }
1221 val = ofnode_read_u32_default(node, "de-active", -1);
1222 if (val != -1) {
1223 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1224 DISPLAY_FLAGS_DE_LOW;
1225 }
1226 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
1227 if (val != -1) {
1228 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1229 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1230 }
1231
1232 if (ofnode_read_bool(node, "interlaced"))
1233 dt->flags |= DISPLAY_FLAGS_INTERLACED;
1234 if (ofnode_read_bool(node, "doublescan"))
1235 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1236 if (ofnode_read_bool(node, "doubleclk"))
1237 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1238
1239 return ret;
1240}
1241
Nikhil M Jainff407062023-01-31 15:35:14 +05301242int ofnode_decode_panel_timing(ofnode parent,
1243 struct display_timing *dt)
1244{
1245 ofnode timings;
1246 u32 val = 0;
1247 int ret = 0;
1248
Raphael Gallais-Poua853b922023-05-11 16:36:52 +02001249 timings = ofnode_find_subnode(parent, "panel-timing");
Nikhil M Jainff407062023-01-31 15:35:14 +05301250 if (!ofnode_valid(timings))
1251 return -EINVAL;
1252 memset(dt, 0, sizeof(*dt));
1253 ret |= decode_timing_property(timings, "hback-porch", &dt->hback_porch);
1254 ret |= decode_timing_property(timings, "hfront-porch", &dt->hfront_porch);
1255 ret |= decode_timing_property(timings, "hactive", &dt->hactive);
1256 ret |= decode_timing_property(timings, "hsync-len", &dt->hsync_len);
1257 ret |= decode_timing_property(timings, "vback-porch", &dt->vback_porch);
1258 ret |= decode_timing_property(timings, "vfront-porch", &dt->vfront_porch);
1259 ret |= decode_timing_property(timings, "vactive", &dt->vactive);
1260 ret |= decode_timing_property(timings, "vsync-len", &dt->vsync_len);
1261 ret |= decode_timing_property(timings, "clock-frequency", &dt->pixelclock);
1262 dt->flags = 0;
1263 if (!ofnode_read_u32(timings, "vsync-active", &val)) {
1264 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1265 DISPLAY_FLAGS_VSYNC_LOW;
1266 }
1267 if (!ofnode_read_u32(timings, "hsync-active", &val)) {
1268 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1269 DISPLAY_FLAGS_HSYNC_LOW;
1270 }
1271 if (!ofnode_read_u32(timings, "de-active", &val)) {
1272 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1273 DISPLAY_FLAGS_DE_LOW;
1274 }
1275 if (!ofnode_read_u32(timings, "pixelclk-active", &val)) {
1276 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1277 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1278 }
1279 if (ofnode_read_bool(timings, "interlaced"))
1280 dt->flags |= DISPLAY_FLAGS_INTERLACED;
1281 if (ofnode_read_bool(timings, "doublescan"))
1282 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1283 if (ofnode_read_bool(timings, "doubleclk"))
1284 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1285
1286 return ret;
1287}
1288
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +09001289const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glassc4fc5622017-05-18 20:08:58 -06001290{
Masahiro Yamada5052f1b2017-06-22 16:54:04 +09001291 if (ofnode_is_np(node))
1292 return of_get_property(ofnode_to_np(node), propname, lenp);
1293 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001294 return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001295 propname, lenp);
Simon Glassc4fc5622017-05-18 20:08:58 -06001296}
1297
Simon Glass86ef3992023-09-26 08:14:44 -06001298bool ofnode_has_property(ofnode node, const char *propname)
1299{
1300 if (ofnode_is_np(node))
1301 return of_find_property(ofnode_to_np(node), propname, NULL);
1302 else
1303 return ofnode_get_property(node, propname, NULL);
1304}
1305
Simon Glassfec058d2022-09-06 20:27:13 -06001306int ofnode_first_property(ofnode node, struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001307{
1308 prop->node = node;
1309
1310 if (ofnode_is_np(node)) {
1311 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
1312 if (!prop->prop)
1313 return -FDT_ERR_NOTFOUND;
1314 } else {
1315 prop->offset =
Simon Glass04fa09a2022-09-06 20:27:20 -06001316 fdt_first_property_offset(ofnode_to_fdt(node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001317 ofnode_to_offset(prop->node));
1318 if (prop->offset < 0)
1319 return prop->offset;
1320 }
1321
1322 return 0;
1323}
1324
Simon Glassfec058d2022-09-06 20:27:13 -06001325int ofnode_next_property(struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001326{
1327 if (ofnode_is_np(prop->node)) {
1328 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
1329 prop->prop);
1330 if (!prop->prop)
1331 return -FDT_ERR_NOTFOUND;
1332 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001333 prop->offset =
1334 fdt_next_property_offset(ofnode_to_fdt(prop->node),
1335 prop->offset);
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001336 if (prop->offset < 0)
1337 return prop->offset;
1338 }
1339
1340 return 0;
1341}
1342
Simon Glassd0aff8b2022-09-06 20:27:14 -06001343const void *ofprop_get_property(const struct ofprop *prop,
1344 const char **propname, int *lenp)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001345{
1346 if (ofnode_is_np(prop->node))
1347 return of_get_property_by_prop(ofnode_to_np(prop->node),
1348 prop->prop, propname, lenp);
1349 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001350 return fdt_getprop_by_offset(ofnode_to_fdt(prop->node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001351 prop->offset,
1352 propname, lenp);
1353}
1354
Simon Glassc4fc5622017-05-18 20:08:58 -06001355fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
1356 fdt_size_t *sizep)
1357{
1358 if (ofnode_is_np(node)) {
1359 int na, ns;
1360 int psize;
1361 const struct device_node *np = ofnode_to_np(node);
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001362 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glassc4fc5622017-05-18 20:08:58 -06001363
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001364 if (!prop)
1365 return FDT_ADDR_T_NONE;
Simon Glassc4fc5622017-05-18 20:08:58 -06001366 na = of_n_addr_cells(np);
Marek Vasut1638c172018-10-01 12:37:19 +02001367 ns = of_n_size_cells(np);
Simon Glassa67cc632017-05-18 20:09:27 -06001368 *sizep = of_read_number(prop + na, ns);
Marek Vasuta9dac492018-10-01 12:37:20 +02001369
Dario Binacchif8fc7032021-05-01 17:05:26 +02001370 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta9dac492018-10-01 12:37:20 +02001371 return of_translate_address(np, prop);
1372 else
1373 return of_read_number(prop, na);
Simon Glassc4fc5622017-05-18 20:08:58 -06001374 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001375 return fdtdec_get_addr_size(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001376 ofnode_to_offset(node), property,
1377 sizep);
1378 }
1379}
1380
1381const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
1382 size_t sz)
1383{
1384 if (ofnode_is_np(node)) {
1385 const struct device_node *np = ofnode_to_np(node);
1386 int psize;
1387 const __be32 *prop = of_get_property(np, propname, &psize);
1388
1389 if (!prop || sz != psize)
1390 return NULL;
1391 return (uint8_t *)prop;
1392
1393 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001394 return fdtdec_locate_byte_array(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001395 ofnode_to_offset(node), propname, sz);
1396 }
1397}
1398
1399int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
Simon Glass4289c262023-09-26 08:14:58 -06001400 const char *propname, struct fdt_pci_addr *addr,
1401 fdt_size_t *size)
Simon Glassc4fc5622017-05-18 20:08:58 -06001402{
Masahiro Yamada5c5991e2017-06-22 17:57:50 +09001403 const fdt32_t *cell;
Simon Glassc4fc5622017-05-18 20:08:58 -06001404 int len;
1405 int ret = -ENOENT;
1406
Quentin Schulze2d4d262024-10-15 16:32:14 +02001407 log_debug("%s: %s: ", __func__, propname);
Simon Glassc4fc5622017-05-18 20:08:58 -06001408
1409 /*
1410 * If we follow the pci bus bindings strictly, we should check
1411 * the value of the node's parent node's #address-cells and
1412 * #size-cells. They need to be 3 and 2 accordingly. However,
1413 * for simplicity we skip the check here.
1414 */
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +09001415 cell = ofnode_get_property(node, propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -06001416 if (!cell)
1417 goto fail;
1418
1419 if ((len % FDT_PCI_REG_SIZE) == 0) {
1420 int num = len / FDT_PCI_REG_SIZE;
1421 int i;
1422
1423 for (i = 0; i < num; i++) {
Quentin Schulze2d4d262024-10-15 16:32:14 +02001424 log_debug("pci address #%d: %08lx %08lx %08lx\n", i,
1425 (ulong)fdt32_to_cpu(cell[0]),
1426 (ulong)fdt32_to_cpu(cell[1]),
1427 (ulong)fdt32_to_cpu(cell[2]));
Simon Glassc4fc5622017-05-18 20:08:58 -06001428 if ((fdt32_to_cpu(*cell) & type) == type) {
Simon Glass4289c262023-09-26 08:14:58 -06001429 const unaligned_fdt64_t *ptr;
1430
Simon Glassc4fc5622017-05-18 20:08:58 -06001431 addr->phys_hi = fdt32_to_cpu(cell[0]);
1432 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glassdfd43152019-09-25 08:55:46 -06001433 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glass4289c262023-09-26 08:14:58 -06001434 ptr = (const unaligned_fdt64_t *)(cell + 3);
1435 if (size)
1436 *size = fdt64_to_cpu(*ptr);
Simon Glassc4fc5622017-05-18 20:08:58 -06001437 break;
Simon Glassc4fc5622017-05-18 20:08:58 -06001438 }
Mario Sixf40d82c2018-01-15 11:07:17 +01001439
Simon Glass4289c262023-09-26 08:14:58 -06001440 cell += FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS;
Simon Glassc4fc5622017-05-18 20:08:58 -06001441 }
1442
1443 if (i == num) {
1444 ret = -ENXIO;
1445 goto fail;
1446 }
1447
1448 return 0;
Simon Glassc4fc5622017-05-18 20:08:58 -06001449 }
1450
Mario Sixf40d82c2018-01-15 11:07:17 +01001451 ret = -EINVAL;
1452
Simon Glassc4fc5622017-05-18 20:08:58 -06001453fail:
Quentin Schulze2d4d262024-10-15 16:32:14 +02001454 log_debug("(not found)\n");
Simon Glassc4fc5622017-05-18 20:08:58 -06001455 return ret;
1456}
1457
Bin Mengfa157712018-08-03 01:14:35 -07001458int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
1459{
1460 const char *list, *end;
1461 int len;
1462
1463 list = ofnode_get_property(node, "compatible", &len);
1464 if (!list)
1465 return -ENOENT;
1466
1467 end = list + len;
1468 while (list < end) {
1469 len = strlen(list);
1470 if (len >= strlen("pciVVVV,DDDD")) {
1471 char *s = strstr(list, "pci");
1472
1473 /*
1474 * check if the string is something like pciVVVV,DDDD.RR
1475 * or just pciVVVV,DDDD
1476 */
1477 if (s && s[7] == ',' &&
1478 (s[12] == '.' || s[12] == 0)) {
1479 s += 3;
1480 *vendor = simple_strtol(s, NULL, 16);
1481
1482 s += 5;
1483 *device = simple_strtol(s, NULL, 16);
1484
1485 return 0;
1486 }
1487 }
1488 list += (len + 1);
1489 }
1490
1491 return -ENOENT;
1492}
1493
Michal Simeka253c3b2022-02-23 15:45:40 +01001494int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
1495{
1496 const char *list, *end;
1497 int len;
1498
1499 list = ofnode_get_property(node, "compatible", &len);
1500
1501 if (!list)
1502 return -ENOENT;
1503
1504 end = list + len;
1505 while (list < end) {
1506 len = strlen(list);
1507
Michal Simekc633cdf2022-10-31 17:08:44 -07001508 if (len >= strlen("ethernet-phy-idVVVV.DDDD")) {
Michal Simeka253c3b2022-02-23 15:45:40 +01001509 char *s = strstr(list, "ethernet-phy-id");
1510
1511 /*
1512 * check if the string is something like
Michal Simekc633cdf2022-10-31 17:08:44 -07001513 * ethernet-phy-idVVVV.DDDD
Michal Simeka253c3b2022-02-23 15:45:40 +01001514 */
1515 if (s && s[19] == '.') {
1516 s += strlen("ethernet-phy-id");
1517 *vendor = simple_strtol(s, NULL, 16);
1518 s += 5;
1519 *device = simple_strtol(s, NULL, 16);
1520
1521 return 0;
1522 }
1523 }
1524 list += (len + 1);
1525 }
1526
1527 return -ENOENT;
1528}
1529
Simon Glassc4fc5622017-05-18 20:08:58 -06001530int ofnode_read_addr_cells(ofnode node)
1531{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001532 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001533 return of_n_addr_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001534 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001535 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001536 ofnode_to_offset(node));
1537
Simon Glass04fa09a2022-09-06 20:27:20 -06001538 return fdt_address_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001539 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001540}
1541
1542int ofnode_read_size_cells(ofnode node)
1543{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001544 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001545 return of_n_size_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001546 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001547 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001548 ofnode_to_offset(node));
1549
Simon Glass04fa09a2022-09-06 20:27:20 -06001550 return fdt_size_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001551 }
Simon Glass4191dc12017-06-12 06:21:31 -06001552}
1553
1554int ofnode_read_simple_addr_cells(ofnode node)
1555{
1556 if (ofnode_is_np(node))
1557 return of_simple_addr_cells(ofnode_to_np(node));
1558 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001559 return fdt_address_cells(ofnode_to_fdt(node),
1560 ofnode_to_offset(node));
Simon Glass4191dc12017-06-12 06:21:31 -06001561}
1562
1563int ofnode_read_simple_size_cells(ofnode node)
1564{
1565 if (ofnode_is_np(node))
1566 return of_simple_size_cells(ofnode_to_np(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001567 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001568 return fdt_size_cells(ofnode_to_fdt(node),
1569 ofnode_to_offset(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001570}
1571
1572bool ofnode_pre_reloc(ofnode node)
1573{
Simon Glass7ec24132024-09-29 19:49:48 -06001574#if defined(CONFIG_XPL_BUILD) || defined(CONFIG_TPL_BUILD)
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001575 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
Simon Glassfc1aa352023-02-13 08:56:34 -07001576 * had property bootph-all or bootph-pre-sram/bootph-pre-ram.
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001577 * They are removed in final dtb (fdtgrep 2nd pass)
1578 */
1579 return true;
1580#else
Simon Glassfc1aa352023-02-13 08:56:34 -07001581 if (ofnode_read_bool(node, "bootph-all"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001582 return true;
Simon Glassfc1aa352023-02-13 08:56:34 -07001583 if (ofnode_read_bool(node, "bootph-some-ram"))
Simon Glass23f22842018-10-01 12:22:18 -06001584 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001585
Simon Glassc4fc5622017-05-18 20:08:58 -06001586 /*
1587 * In regular builds individual spl and tpl handling both
1588 * count as handled pre-relocation for later second init.
1589 */
Simon Glassfc1aa352023-02-13 08:56:34 -07001590 if (ofnode_read_bool(node, "bootph-pre-ram") ||
1591 ofnode_read_bool(node, "bootph-pre-sram"))
Jonas Karlmanc43411b2023-08-20 22:03:18 +00001592 return gd->flags & GD_FLG_RELOC;
Simon Glassc4fc5622017-05-18 20:08:58 -06001593
Simon Glassc2727e52023-02-13 08:56:32 -07001594 if (IS_ENABLED(CONFIG_OF_TAG_MIGRATE)) {
1595 /* detect and handle old tags */
1596 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc") ||
1597 ofnode_read_bool(node, "u-boot,dm-pre-proper") ||
1598 ofnode_read_bool(node, "u-boot,dm-spl") ||
1599 ofnode_read_bool(node, "u-boot,dm-tpl") ||
1600 ofnode_read_bool(node, "u-boot,dm-vpl")) {
1601 gd->flags |= GD_FLG_OF_TAG_MIGRATE;
1602 return true;
1603 }
1604 }
1605
Simon Glassc4fc5622017-05-18 20:08:58 -06001606 return false;
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001607#endif
Simon Glassc4fc5622017-05-18 20:08:58 -06001608}
Simon Glassf7bfcc42017-07-25 08:29:55 -06001609
1610int ofnode_read_resource(ofnode node, uint index, struct resource *res)
1611{
1612 if (ofnode_is_np(node)) {
1613 return of_address_to_resource(ofnode_to_np(node), index, res);
1614 } else {
1615 struct fdt_resource fres;
1616 int ret;
1617
Simon Glass04fa09a2022-09-06 20:27:20 -06001618 ret = fdt_get_resource(ofnode_to_fdt(node),
1619 ofnode_to_offset(node),
Simon Glassf7bfcc42017-07-25 08:29:55 -06001620 "reg", index, &fres);
1621 if (ret < 0)
1622 return -EINVAL;
1623 memset(res, '\0', sizeof(*res));
1624 res->start = fres.start;
1625 res->end = fres.end;
1626
1627 return 0;
1628 }
1629}
Masahiro Yamada4dada2c2017-08-26 01:12:30 +09001630
1631int ofnode_read_resource_byname(ofnode node, const char *name,
1632 struct resource *res)
1633{
1634 int index;
1635
1636 index = ofnode_stringlist_search(node, "reg-names", name);
1637 if (index < 0)
1638 return index;
1639
1640 return ofnode_read_resource(node, index, res);
1641}
Mario Sixaefac062018-01-15 11:07:19 +01001642
1643u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
1644{
1645 if (ofnode_is_np(node))
1646 return of_translate_address(ofnode_to_np(node), in_addr);
1647 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001648 return fdt_translate_address(ofnode_to_fdt(node),
1649 ofnode_to_offset(node), in_addr);
Mario Sixaefac062018-01-15 11:07:19 +01001650}
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001651
Fabien Dessenne22236e02019-05-31 15:11:30 +02001652u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
1653{
1654 if (ofnode_is_np(node))
1655 return of_translate_dma_address(ofnode_to_np(node), in_addr);
1656 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001657 return fdt_translate_dma_address(ofnode_to_fdt(node),
1658 ofnode_to_offset(node), in_addr);
Fabien Dessenne22236e02019-05-31 15:11:30 +02001659}
1660
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001661int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
1662{
1663 if (ofnode_is_np(node))
1664 return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
1665 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001666 return fdt_get_dma_range(ofnode_to_fdt(node),
1667 ofnode_to_offset(node),
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001668 cpu, bus, size);
1669}
1670
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001671int ofnode_device_is_compatible(ofnode node, const char *compat)
1672{
1673 if (ofnode_is_np(node))
1674 return of_device_is_compatible(ofnode_to_np(node), compat,
1675 NULL, NULL);
1676 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001677 return !fdt_node_check_compatible(ofnode_to_fdt(node),
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001678 ofnode_to_offset(node),
1679 compat);
1680}
Simon Glass954eeae2018-06-11 13:07:13 -06001681
1682ofnode ofnode_by_compatible(ofnode from, const char *compat)
1683{
1684 if (of_live_active()) {
1685 return np_to_ofnode(of_find_compatible_node(
1686 (struct device_node *)ofnode_to_np(from), NULL,
1687 compat));
1688 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001689 return noffset_to_ofnode(from,
1690 fdt_node_offset_by_compatible(ofnode_to_fdt(from),
Simon Glass04fa09a2022-09-06 20:27:20 -06001691 ofnode_to_offset(from), compat));
Simon Glass954eeae2018-06-11 13:07:13 -06001692 }
1693}
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001694
1695ofnode ofnode_by_prop_value(ofnode from, const char *propname,
1696 const void *propval, int proplen)
1697{
1698 if (of_live_active()) {
1699 return np_to_ofnode(of_find_node_by_prop_value(
1700 (struct device_node *)ofnode_to_np(from), propname,
1701 propval, proplen));
1702 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001703 return noffset_to_ofnode(from,
1704 fdt_node_offset_by_prop_value(ofnode_to_fdt(from),
1705 ofnode_to_offset(from), propname, propval,
1706 proplen));
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001707 }
1708}
Mario Six047dafc2018-06-26 08:46:48 +02001709
Simon Glass5e2cd5e2022-07-30 15:52:10 -06001710int ofnode_write_prop(ofnode node, const char *propname, const void *value,
Simon Glass17abed02022-09-06 20:27:32 -06001711 int len, bool copy)
Mario Six047dafc2018-06-26 08:46:48 +02001712{
Simon Glass004f5bd2025-01-10 17:00:10 -07001713 int ret;
1714
Simon Glass17abed02022-09-06 20:27:32 -06001715 if (of_live_active()) {
1716 void *newval;
Simon Glass17abed02022-09-06 20:27:32 -06001717
1718 if (copy) {
1719 newval = malloc(len);
1720 if (!newval)
1721 return log_ret(-ENOMEM);
1722 memcpy(newval, value, len);
1723 value = newval;
1724 }
1725 ret = of_write_prop(ofnode_to_np(node), propname, len, value);
1726 if (ret && copy)
1727 free(newval);
1728 return ret;
1729 } else {
Simon Glass004f5bd2025-01-10 17:00:10 -07001730 ret = fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
1731 propname, value, len);
1732 if (ret)
1733 return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EINVAL;
1734
1735 return 0;
Simon Glass17abed02022-09-06 20:27:32 -06001736 }
Mario Six047dafc2018-06-26 08:46:48 +02001737}
1738
1739int ofnode_write_string(ofnode node, const char *propname, const char *value)
1740{
Mario Six047dafc2018-06-26 08:46:48 +02001741 assert(ofnode_valid(node));
1742
Quentin Schulze2d4d262024-10-15 16:32:14 +02001743 log_debug("%s: %s = %s", __func__, propname, value);
Mario Six047dafc2018-06-26 08:46:48 +02001744
Simon Glass17abed02022-09-06 20:27:32 -06001745 return ofnode_write_prop(node, propname, value, strlen(value) + 1,
1746 false);
Mario Six047dafc2018-06-26 08:46:48 +02001747}
1748
Simon Glassd28e31e2022-07-30 15:52:14 -06001749int ofnode_write_u32(ofnode node, const char *propname, u32 value)
1750{
1751 fdt32_t *val;
1752
1753 assert(ofnode_valid(node));
1754
1755 log_debug("%s = %x", propname, value);
1756 val = malloc(sizeof(*val));
1757 if (!val)
1758 return -ENOMEM;
1759 *val = cpu_to_fdt32(value);
1760
Simon Glassc681e092023-09-26 08:14:45 -06001761 return ofnode_write_prop(node, propname, val, sizeof(value), true);
1762}
1763
1764int ofnode_write_u64(ofnode node, const char *propname, u64 value)
1765{
1766 fdt64_t *val;
1767
1768 assert(ofnode_valid(node));
1769
1770 log_debug("%s = %llx", propname, (unsigned long long)value);
1771 val = malloc(sizeof(*val));
1772 if (!val)
1773 return -ENOMEM;
1774 *val = cpu_to_fdt64(value);
1775
1776 return ofnode_write_prop(node, propname, val, sizeof(value), true);
Simon Glassd28e31e2022-07-30 15:52:14 -06001777}
1778
Simon Glass86ef3992023-09-26 08:14:44 -06001779int ofnode_write_bool(ofnode node, const char *propname, bool value)
1780{
1781 if (value)
1782 return ofnode_write_prop(node, propname, NULL, 0, false);
1783 else
1784 return ofnode_delete_prop(node, propname);
1785}
1786
1787int ofnode_delete_prop(ofnode node, const char *propname)
1788{
1789 if (ofnode_is_np(node)) {
1790 struct property *prop;
1791 int len;
1792
1793 prop = of_find_property(ofnode_to_np(node), propname, &len);
1794 if (prop)
1795 return of_remove_property(ofnode_to_np(node), prop);
1796 return 0;
1797 } else {
1798 return fdt_delprop(ofnode_to_fdt(node), ofnode_to_offset(node),
1799 propname);
1800 }
1801}
1802
Mario Six047dafc2018-06-26 08:46:48 +02001803int ofnode_set_enabled(ofnode node, bool value)
1804{
Mario Six047dafc2018-06-26 08:46:48 +02001805 assert(ofnode_valid(node));
1806
1807 if (value)
1808 return ofnode_write_string(node, "status", "okay");
1809 else
Bin Menga9274aa2019-07-05 09:23:17 -07001810 return ofnode_write_string(node, "status", "disabled");
Mario Six047dafc2018-06-26 08:46:48 +02001811}
Simon Glass0034d962021-08-07 07:24:01 -06001812
1813bool ofnode_conf_read_bool(const char *prop_name)
1814{
1815 ofnode node;
1816
1817 node = ofnode_path("/config");
1818 if (!ofnode_valid(node))
1819 return false;
1820
1821 return ofnode_read_bool(node, prop_name);
1822}
1823
1824int ofnode_conf_read_int(const char *prop_name, int default_val)
1825{
1826 ofnode node;
1827
1828 node = ofnode_path("/config");
1829 if (!ofnode_valid(node))
1830 return default_val;
1831
1832 return ofnode_read_u32_default(node, prop_name, default_val);
1833}
1834
1835const char *ofnode_conf_read_str(const char *prop_name)
1836{
1837 ofnode node;
1838
1839 node = ofnode_path("/config");
1840 if (!ofnode_valid(node))
1841 return NULL;
1842
1843 return ofnode_read_string(node, prop_name);
1844}
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001845
Christian Marangi72544732024-10-01 14:24:35 +02001846bool ofnode_options_read_bool(const char *prop_name)
1847{
1848 ofnode uboot;
1849
1850 uboot = ofnode_path("/options/u-boot");
1851 if (!ofnode_valid(uboot))
1852 return false;
1853
1854 return ofnode_read_bool(uboot, prop_name);
1855}
1856
1857int ofnode_options_read_int(const char *prop_name, int default_val)
1858{
1859 ofnode uboot;
1860
1861 uboot = ofnode_path("/options/u-boot");
1862 if (!ofnode_valid(uboot))
1863 return default_val;
1864
1865 return ofnode_read_u32_default(uboot, prop_name, default_val);
1866}
1867
1868const char *ofnode_options_read_str(const char *prop_name)
1869{
1870 ofnode uboot;
1871
1872 uboot = ofnode_path("/options/u-boot");
1873 if (!ofnode_valid(uboot))
1874 return NULL;
1875
1876 return ofnode_read_string(uboot, prop_name);
1877}
1878
Christian Marangicdaa9952024-11-10 12:50:24 +01001879int ofnode_options_get_by_phandle(const char *prop_name, ofnode *nodep)
1880{
1881 ofnode uboot;
1882
1883 uboot = ofnode_path("/options/u-boot");
1884 if (!ofnode_valid(uboot))
1885 return -EINVAL;
1886
1887 *nodep = ofnode_parse_phandle(uboot, prop_name, 0);
1888 if (!ofnode_valid(*nodep))
1889 return -EINVAL;
1890
1891 return 0;
1892}
1893
Michal Simek43c42bd2023-08-31 08:59:05 +02001894int ofnode_read_bootscript_address(u64 *bootscr_address, u64 *bootscr_offset)
1895{
1896 int ret;
1897 ofnode uboot;
1898
1899 *bootscr_address = 0;
1900 *bootscr_offset = 0;
1901
1902 uboot = ofnode_path("/options/u-boot");
1903 if (!ofnode_valid(uboot)) {
Quentin Schulz95a5a2b2024-06-11 15:04:26 +02001904 dm_warn("%s: Missing /u-boot node\n", __func__);
Michal Simek43c42bd2023-08-31 08:59:05 +02001905 return -EINVAL;
1906 }
1907
1908 ret = ofnode_read_u64(uboot, "bootscr-address", bootscr_address);
1909 if (ret) {
1910 ret = ofnode_read_u64(uboot, "bootscr-ram-offset",
1911 bootscr_offset);
1912 if (ret)
1913 return -EINVAL;
1914 }
1915
1916 return 0;
1917}
1918
Michal Simek6a7c1ce2023-08-31 09:04:27 +02001919int ofnode_read_bootscript_flash(u64 *bootscr_flash_offset,
1920 u64 *bootscr_flash_size)
1921{
1922 int ret;
1923 ofnode uboot;
1924
1925 *bootscr_flash_offset = 0;
1926 *bootscr_flash_size = 0;
1927
1928 uboot = ofnode_path("/options/u-boot");
1929 if (!ofnode_valid(uboot)) {
Quentin Schulz95a5a2b2024-06-11 15:04:26 +02001930 dm_warn("%s: Missing /u-boot node\n", __func__);
Michal Simek6a7c1ce2023-08-31 09:04:27 +02001931 return -EINVAL;
1932 }
1933
1934 ret = ofnode_read_u64(uboot, "bootscr-flash-offset",
1935 bootscr_flash_offset);
1936 if (ret)
1937 return -EINVAL;
1938
1939 ret = ofnode_read_u64(uboot, "bootscr-flash-size",
1940 bootscr_flash_size);
1941 if (ret)
1942 return -EINVAL;
1943
1944 if (!bootscr_flash_size) {
Quentin Schulz95a5a2b2024-06-11 15:04:26 +02001945 dm_warn("bootscr-flash-size is zero. Ignoring properties!\n");
Michal Simek6a7c1ce2023-08-31 09:04:27 +02001946 *bootscr_flash_offset = 0;
1947 return -EINVAL;
1948 }
1949
1950 return 0;
1951}
1952
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001953ofnode ofnode_get_phy_node(ofnode node)
1954{
1955 /* DT node properties that reference a PHY node */
1956 static const char * const phy_handle_str[] = {
1957 "phy-handle", "phy", "phy-device",
1958 };
1959 struct ofnode_phandle_args args = {
1960 .node = ofnode_null()
1961 };
1962 int i;
1963
1964 assert(ofnode_valid(node));
1965
1966 for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
1967 if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
1968 NULL, 0, 0, &args))
1969 break;
1970
1971 return args.node;
1972}
Marek Behúnbc194772022-04-07 00:33:01 +02001973
1974phy_interface_t ofnode_read_phy_mode(ofnode node)
1975{
1976 const char *mode;
1977 int i;
1978
1979 assert(ofnode_valid(node));
1980
1981 mode = ofnode_read_string(node, "phy-mode");
1982 if (!mode)
1983 mode = ofnode_read_string(node, "phy-connection-type");
1984
1985 if (!mode)
Marek Behún48631e42022-04-07 00:33:03 +02001986 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001987
Marek Behún21a18362022-04-07 00:33:02 +02001988 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
Marek Behúnbc194772022-04-07 00:33:01 +02001989 if (!strcmp(mode, phy_interface_strings[i]))
1990 return i;
1991
Quentin Schulz95a5a2b2024-06-11 15:04:26 +02001992 dm_warn("%s: Invalid PHY interface '%s'\n", __func__, mode);
Marek Behúnbc194772022-04-07 00:33:01 +02001993
Marek Behún48631e42022-04-07 00:33:03 +02001994 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001995}
Simon Glass56bc3322022-09-06 20:27:02 -06001996
1997int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
1998{
1999 ofnode subnode;
2000 int ret = 0;
2001
2002 assert(ofnode_valid(node));
2003
2004 if (ofnode_is_np(node)) {
2005 struct device_node *np, *child;
2006
2007 np = (struct device_node *)ofnode_to_np(node);
2008 ret = of_add_subnode(np, name, -1, &child);
2009 if (ret && ret != -EEXIST)
2010 return ret;
2011 subnode = np_to_ofnode(child);
2012 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06002013 void *fdt = ofnode_to_fdt(node);
Simon Glass56bc3322022-09-06 20:27:02 -06002014 int poffset = ofnode_to_offset(node);
2015 int offset;
2016
2017 offset = fdt_add_subnode(fdt, poffset, name);
2018 if (offset == -FDT_ERR_EXISTS) {
2019 offset = fdt_subnode_offset(fdt, poffset, name);
2020 ret = -EEXIST;
2021 }
2022 if (offset < 0)
Simon Glass004f5bd2025-01-10 17:00:10 -07002023 return offset == -FDT_ERR_NOSPACE ? -ENOSPC : -EINVAL;
Simon Glass37dcd912022-09-06 20:27:23 -06002024 subnode = noffset_to_ofnode(node, offset);
Simon Glass56bc3322022-09-06 20:27:02 -06002025 }
2026
2027 *subnodep = subnode;
2028
2029 return ret; /* 0 or -EEXIST */
2030}
Simon Glass7a7229a2022-09-06 20:27:33 -06002031
Simon Glass45448772023-09-26 08:14:42 -06002032int ofnode_delete(ofnode *nodep)
2033{
2034 ofnode node = *nodep;
2035 int ret;
2036
2037 assert(ofnode_valid(node));
2038 if (ofnode_is_np(node)) {
2039 ret = of_remove_node(ofnode_to_np(node));
2040 } else {
2041 void *fdt = ofnode_to_fdt(node);
2042 int offset = ofnode_to_offset(node);
2043
2044 ret = fdt_del_node(fdt, offset);
2045 if (ret)
2046 ret = -EFAULT;
2047 }
2048 if (ret)
2049 return ret;
2050 *nodep = ofnode_null();
2051
2052 return 0;
2053}
2054
Simon Glass68164892023-09-26 08:14:37 -06002055int ofnode_copy_props(ofnode dst, ofnode src)
Simon Glass7a7229a2022-09-06 20:27:33 -06002056{
2057 struct ofprop prop;
2058
2059 ofnode_for_each_prop(prop, src) {
2060 const char *name;
2061 const char *val;
2062 int len, ret;
2063
2064 val = ofprop_get_property(&prop, &name, &len);
2065 if (!val) {
2066 log_debug("Cannot read prop (err=%d)\n", len);
2067 return log_msg_ret("get", -EINVAL);
2068 }
2069 ret = ofnode_write_prop(dst, name, val, len, true);
2070 if (ret) {
2071 log_debug("Cannot write prop (err=%d)\n", ret);
2072 return log_msg_ret("wr", -EINVAL);
2073 }
2074 }
2075
2076 return 0;
2077}
Simon Glass7c33c962023-09-26 08:14:41 -06002078
2079int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src,
2080 ofnode *nodep)
2081{
2082 ofnode node;
2083 int ret;
2084
2085 ret = ofnode_add_subnode(dst_parent, name, &node);
2086 if (ret) {
2087 if (ret == -EEXIST)
2088 *nodep = node;
2089 return log_msg_ret("add", ret);
2090 }
2091 ret = ofnode_copy_props(node, src);
2092 if (ret)
2093 return log_msg_ret("cpy", ret);
2094 *nodep = node;
2095
2096 return 0;
2097}