blob: 373c7840eefc3ac13831f427df3f9267cce39350 [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
Simon Glass9d300ce2025-01-10 17:00:28 -0700312bool ofnode_name_eq_unit(ofnode node, const char *name)
313{
314 const char *node_name, *p;
315 int len;
316
317 assert(ofnode_valid(node));
318
319 node_name = ofnode_get_name(node);
320
321 /* check the whole name */
322 if (!strcmp(node_name, name))
323 return true;
324
325 /* if @name has no unit address, try the node name without it */
326 len = strlen(name);
327 p = strchr(node_name, '@');
328 if (p && !strchr(name, '@') && len == p - node_name &&
329 !strncmp(node_name, name, len))
330 return true;
331
332 return false;
333}
334
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200335int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
336{
337 const u8 *cell;
338 int len;
339
340 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200341 log_debug("%s: %s: ", __func__, propname);
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200342
343 if (ofnode_is_np(node))
344 return of_read_u8(ofnode_to_np(node), propname, outp);
345
346 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
347 &len);
348 if (!cell || len < sizeof(*cell)) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200349 log_debug("(not found)\n");
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200350 return -EINVAL;
351 }
352 *outp = *cell;
Quentin Schulze2d4d262024-10-15 16:32:14 +0200353 log_debug("%#x (%u)\n", *outp, *outp);
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200354
355 return 0;
356}
357
358u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
359{
360 assert(ofnode_valid(node));
361 ofnode_read_u8(node, propname, &def);
362
363 return def;
364}
365
366int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
367{
368 const fdt16_t *cell;
369 int len;
370
371 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200372 log_debug("%s: %s: ", __func__, propname);
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200373
374 if (ofnode_is_np(node))
375 return of_read_u16(ofnode_to_np(node), propname, outp);
376
377 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
378 &len);
379 if (!cell || len < sizeof(*cell)) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200380 log_debug("(not found)\n");
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200381 return -EINVAL;
382 }
383 *outp = be16_to_cpup(cell);
Quentin Schulze2d4d262024-10-15 16:32:14 +0200384 log_debug("%#x (%u)\n", *outp, *outp);
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200385
386 return 0;
387}
388
389u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def)
390{
391 assert(ofnode_valid(node));
392 ofnode_read_u16(node, propname, &def);
393
394 return def;
395}
396
Simon Glassc4fc5622017-05-18 20:08:58 -0600397int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
398{
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200399 return ofnode_read_u32_index(node, propname, 0, outp);
Simon Glassc4fc5622017-05-18 20:08:58 -0600400}
401
Trent Piepho5b775412019-05-10 17:48:20 +0000402u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
Simon Glassc4fc5622017-05-18 20:08:58 -0600403{
404 assert(ofnode_valid(node));
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200405 ofnode_read_u32_index(node, propname, 0, &def);
Simon Glassc4fc5622017-05-18 20:08:58 -0600406
407 return def;
408}
409
Dario Binacchi81d80b52020-03-29 18:04:41 +0200410int ofnode_read_u32_index(ofnode node, const char *propname, int index,
411 u32 *outp)
412{
413 const fdt32_t *cell;
414 int len;
415
416 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200417 log_debug("%s: %s: ", __func__, propname);
Dario Binacchi81d80b52020-03-29 18:04:41 +0200418
419 if (ofnode_is_np(node))
420 return of_read_u32_index(ofnode_to_np(node), propname, index,
421 outp);
422
Simon Glass04fa09a2022-09-06 20:27:20 -0600423 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
424 propname, &len);
Dario Binacchi81d80b52020-03-29 18:04:41 +0200425 if (!cell) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200426 log_debug("(not found)\n");
Dario Binacchi81d80b52020-03-29 18:04:41 +0200427 return -EINVAL;
428 }
429
430 if (len < (sizeof(int) * (index + 1))) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200431 log_debug("(not large enough)\n");
Dario Binacchi81d80b52020-03-29 18:04:41 +0200432 return -EOVERFLOW;
433 }
434
435 *outp = fdt32_to_cpu(cell[index]);
Quentin Schulze2d4d262024-10-15 16:32:14 +0200436 log_debug("%#x (%u)\n", *outp, *outp);
Dario Binacchi81d80b52020-03-29 18:04:41 +0200437
438 return 0;
439}
440
Michal Simek08a194e2023-08-25 11:37:46 +0200441int ofnode_read_u64_index(ofnode node, const char *propname, int index,
442 u64 *outp)
443{
444 const fdt64_t *cell;
445 int len;
446
447 assert(ofnode_valid(node));
448
449 if (ofnode_is_np(node))
450 return of_read_u64_index(ofnode_to_np(node), propname, index,
451 outp);
452
453 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
454 propname, &len);
455 if (!cell) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200456 log_debug("(not found)\n");
Michal Simek08a194e2023-08-25 11:37:46 +0200457 return -EINVAL;
458 }
459
460 if (len < (sizeof(u64) * (index + 1))) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200461 log_debug("(not large enough)\n");
Michal Simek08a194e2023-08-25 11:37:46 +0200462 return -EOVERFLOW;
463 }
464
465 *outp = fdt64_to_cpu(cell[index]);
Quentin Schulze2d4d262024-10-15 16:32:14 +0200466 log_debug("%#llx (%llu)\n", *outp, *outp);
Michal Simek08a194e2023-08-25 11:37:46 +0200467
468 return 0;
469}
470
Dario Binacchi81d80b52020-03-29 18:04:41 +0200471u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
472 u32 def)
473{
474 assert(ofnode_valid(node));
475 ofnode_read_u32_index(node, propname, index, &def);
476
477 return def;
478}
479
Simon Glassc4fc5622017-05-18 20:08:58 -0600480int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
481{
482 assert(ofnode_valid(node));
483 ofnode_read_u32(node, propname, (u32 *)&def);
484
485 return def;
486}
487
Simon Glass9d54a7a2018-06-11 13:07:10 -0600488int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
489{
Jean-Jacques Hiblot487f9172019-10-22 10:05:22 +0200490 const unaligned_fdt64_t *cell;
Simon Glass9d54a7a2018-06-11 13:07:10 -0600491 int len;
492
493 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200494 log_debug("%s: %s: ", __func__, propname);
Simon Glass9d54a7a2018-06-11 13:07:10 -0600495
496 if (ofnode_is_np(node))
497 return of_read_u64(ofnode_to_np(node), propname, outp);
498
Simon Glass04fa09a2022-09-06 20:27:20 -0600499 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
500 propname, &len);
Simon Glass9d54a7a2018-06-11 13:07:10 -0600501 if (!cell || len < sizeof(*cell)) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200502 log_debug("(not found)\n");
Simon Glass9d54a7a2018-06-11 13:07:10 -0600503 return -EINVAL;
504 }
505 *outp = fdt64_to_cpu(cell[0]);
Quentin Schulze2d4d262024-10-15 16:32:14 +0200506 log_debug("%#llx (%llu)\n", (unsigned long long)*outp,
507 (unsigned long long)*outp);
Simon Glass9d54a7a2018-06-11 13:07:10 -0600508
509 return 0;
510}
511
T Karthik Reddy478860d2019-09-02 16:34:30 +0200512u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
Simon Glass9d54a7a2018-06-11 13:07:10 -0600513{
514 assert(ofnode_valid(node));
515 ofnode_read_u64(node, propname, &def);
516
517 return def;
518}
519
Simon Glassc4fc5622017-05-18 20:08:58 -0600520bool ofnode_read_bool(ofnode node, const char *propname)
521{
Simon Glass86ef3992023-09-26 08:14:44 -0600522 bool prop;
Simon Glassc4fc5622017-05-18 20:08:58 -0600523
524 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200525 log_debug("%s: %s: ", __func__, propname);
Simon Glassc4fc5622017-05-18 20:08:58 -0600526
Simon Glass86ef3992023-09-26 08:14:44 -0600527 prop = ofnode_has_property(node, propname);
Masahiro Yamada5d434452017-06-22 16:54:07 +0900528
Quentin Schulze2d4d262024-10-15 16:32:14 +0200529 log_debug("%s\n", prop ? "true" : "false");
Simon Glassc4fc5622017-05-18 20:08:58 -0600530
Masahiro Yamada5d434452017-06-22 16:54:07 +0900531 return prop ? true : false;
Simon Glassc4fc5622017-05-18 20:08:58 -0600532}
533
Simon Glass0c2e9802020-01-27 08:49:44 -0700534const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600535{
Simon Glass0c2e9802020-01-27 08:49:44 -0700536 const char *val = NULL;
537 int len;
Simon Glassc4fc5622017-05-18 20:08:58 -0600538
539 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200540 log_debug("%s: %s: ", __func__, propname);
Simon Glassc4fc5622017-05-18 20:08:58 -0600541
542 if (ofnode_is_np(node)) {
543 struct property *prop = of_find_property(
Simon Glass0c2e9802020-01-27 08:49:44 -0700544 ofnode_to_np(node), propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600545
546 if (prop) {
Simon Glass0c2e9802020-01-27 08:49:44 -0700547 val = prop->value;
Simon Glassc4fc5622017-05-18 20:08:58 -0600548 len = prop->length;
549 }
550 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600551 val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600552 propname, &len);
553 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700554 if (!val) {
Quentin Schulze2d4d262024-10-15 16:32:14 +0200555 log_debug("<not found>\n");
Simon Glass0c2e9802020-01-27 08:49:44 -0700556 if (sizep)
557 *sizep = -FDT_ERR_NOTFOUND;
Simon Glassc4fc5622017-05-18 20:08:58 -0600558 return NULL;
559 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700560 if (sizep)
561 *sizep = len;
562
563 return val;
564}
565
566const char *ofnode_read_string(ofnode node, const char *propname)
567{
568 const char *str;
569 int len;
570
571 str = ofnode_read_prop(node, propname, &len);
572 if (!str)
573 return NULL;
574
Simon Glassc4fc5622017-05-18 20:08:58 -0600575 if (strnlen(str, len) >= len) {
Quentin Schulz95a5a2b2024-06-11 15:04:26 +0200576 dm_warn("<invalid>\n");
Simon Glassc4fc5622017-05-18 20:08:58 -0600577 return NULL;
578 }
Quentin Schulze2d4d262024-10-15 16:32:14 +0200579 log_debug("%s\n", str);
Simon Glassc4fc5622017-05-18 20:08:58 -0600580
581 return str;
582}
583
Simon Glass81c54b32020-01-27 08:49:45 -0700584int ofnode_read_size(ofnode node, const char *propname)
585{
586 int len;
587
588 if (!ofnode_read_prop(node, propname, &len))
589 return -EINVAL;
590
591 return len;
592}
593
Simon Glassc4fc5622017-05-18 20:08:58 -0600594ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
595{
596 ofnode subnode;
597
598 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200599 log_debug("%s: %s: ", __func__, subnode_name);
Simon Glassc4fc5622017-05-18 20:08:58 -0600600
601 if (ofnode_is_np(node)) {
Simon Glass9036c5c2022-09-06 20:27:04 -0600602 struct device_node *np = ofnode_to_np(node);
Simon Glassc4fc5622017-05-18 20:08:58 -0600603
604 for (np = np->child; np; np = np->sibling) {
605 if (!strcmp(subnode_name, np->name))
606 break;
607 }
608 subnode = np_to_ofnode(np);
609 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600610 int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600611 ofnode_to_offset(node), subnode_name);
Simon Glass37dcd912022-09-06 20:27:23 -0600612 subnode = noffset_to_ofnode(node, ooffset);
Simon Glassc4fc5622017-05-18 20:08:58 -0600613 }
Quentin Schulze2d4d262024-10-15 16:32:14 +0200614 log_debug("%s\n", ofnode_valid(subnode) ?
615 ofnode_get_name(subnode) : "<none>");
Simon Glassc4fc5622017-05-18 20:08:58 -0600616
617 return subnode;
618}
619
620int ofnode_read_u32_array(ofnode node, const char *propname,
621 u32 *out_values, size_t sz)
622{
623 assert(ofnode_valid(node));
Quentin Schulze2d4d262024-10-15 16:32:14 +0200624 log_debug("%s: %s: ", __func__, propname);
Simon Glassc4fc5622017-05-18 20:08:58 -0600625
626 if (ofnode_is_np(node)) {
627 return of_read_u32_array(ofnode_to_np(node), propname,
628 out_values, sz);
629 } else {
Simon Glasse3be5fc2022-09-06 20:27:18 -0600630 int ret;
631
Simon Glass04fa09a2022-09-06 20:27:20 -0600632 ret = fdtdec_get_int_array(ofnode_to_fdt(node),
Simon Glasse3be5fc2022-09-06 20:27:18 -0600633 ofnode_to_offset(node), propname,
634 out_values, sz);
635
636 /* get the error right, but space is more important in SPL */
Simon Glass7ec24132024-09-29 19:49:48 -0600637 if (!IS_ENABLED(CONFIG_XPL_BUILD)) {
Simon Glasse3be5fc2022-09-06 20:27:18 -0600638 if (ret == -FDT_ERR_NOTFOUND)
639 return -EINVAL;
640 else if (ret == -FDT_ERR_BADLAYOUT)
641 return -EOVERFLOW;
642 }
643 return ret;
Simon Glassc4fc5622017-05-18 20:08:58 -0600644 }
645}
646
Simon Glass39f1d282020-12-16 17:25:06 -0700647#if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
Simon Glass5de5b3b2020-11-28 17:50:02 -0700648bool ofnode_is_enabled(ofnode node)
649{
650 if (ofnode_is_np(node)) {
651 return of_device_is_available(ofnode_to_np(node));
652 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600653 return fdtdec_get_is_enabled(ofnode_to_fdt(node),
Simon Glass5de5b3b2020-11-28 17:50:02 -0700654 ofnode_to_offset(node));
655 }
656}
657
Simon Glassc4fc5622017-05-18 20:08:58 -0600658ofnode ofnode_first_subnode(ofnode node)
659{
660 assert(ofnode_valid(node));
661 if (ofnode_is_np(node))
662 return np_to_ofnode(node.np->child);
663
Simon Glass37dcd912022-09-06 20:27:23 -0600664 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600665 fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600666}
667
668ofnode ofnode_next_subnode(ofnode node)
669{
670 assert(ofnode_valid(node));
671 if (ofnode_is_np(node))
672 return np_to_ofnode(node.np->sibling);
673
Simon Glass37dcd912022-09-06 20:27:23 -0600674 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600675 fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600676}
Simon Glass39f1d282020-12-16 17:25:06 -0700677#endif /* !DM_INLINE_OFNODE */
Simon Glassc4fc5622017-05-18 20:08:58 -0600678
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100679ofnode ofnode_get_parent(ofnode node)
680{
681 ofnode parent;
682
683 assert(ofnode_valid(node));
684 if (ofnode_is_np(node))
685 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
686 else
Simon Glass04fa09a2022-09-06 20:27:20 -0600687 parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100688 ofnode_to_offset(node));
689
690 return parent;
691}
692
Simon Glassc4fc5622017-05-18 20:08:58 -0600693const char *ofnode_get_name(ofnode node)
694{
Kever Yang8d7976d2019-07-19 11:23:47 +0800695 if (!ofnode_valid(node)) {
Quentin Schulz95a5a2b2024-06-11 15:04:26 +0200696 dm_warn("%s node not valid\n", __func__);
Kever Yang8d7976d2019-07-19 11:23:47 +0800697 return NULL;
698 }
699
Simon Glassc4fc5622017-05-18 20:08:58 -0600700 if (ofnode_is_np(node))
Simon Glass91d89a82022-09-06 20:27:15 -0600701 return node.np->name;
Simon Glassc4fc5622017-05-18 20:08:58 -0600702
Simon Glass04fa09a2022-09-06 20:27:20 -0600703 return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600704}
705
Marek Behúne897e3c2021-05-26 14:08:18 +0200706int ofnode_get_path(ofnode node, char *buf, int buflen)
707{
708 assert(ofnode_valid(node));
709
710 if (ofnode_is_np(node)) {
711 if (strlen(node.np->full_name) >= buflen)
712 return -ENOSPC;
713
714 strcpy(buf, node.np->full_name);
715
716 return 0;
717 } else {
718 int res;
719
Simon Glass04fa09a2022-09-06 20:27:20 -0600720 res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
Marek Behúne897e3c2021-05-26 14:08:18 +0200721 buflen);
722 if (!res)
723 return res;
724 else if (res == -FDT_ERR_NOSPACE)
725 return -ENOSPC;
726 else
727 return -EINVAL;
728 }
729}
730
Kever Yang37df0e02018-02-23 17:38:50 +0100731ofnode ofnode_get_by_phandle(uint phandle)
732{
733 ofnode node;
734
735 if (of_live_active())
Simon Glass176dd432022-09-06 20:26:57 -0600736 node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
Kever Yang37df0e02018-02-23 17:38:50 +0100737 else
738 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
739 phandle);
740
741 return node;
742}
743
Simon Glass95fd2092022-09-06 20:27:22 -0600744ofnode oftree_get_by_phandle(oftree tree, uint phandle)
745{
746 ofnode node;
747
748 if (of_live_active())
749 node = np_to_ofnode(of_find_node_by_phandle(tree.np, phandle));
750 else
Simon Glassf912a722022-09-06 20:27:27 -0600751 node = ofnode_from_tree_offset(tree,
Simon Glass95fd2092022-09-06 20:27:22 -0600752 fdt_node_offset_by_phandle(oftree_lookup_fdt(tree),
Simon Glassf912a722022-09-06 20:27:27 -0600753 phandle));
Simon Glass95fd2092022-09-06 20:27:22 -0600754
755 return node;
756}
757
Marek Behún177ab7f2021-05-26 14:08:17 +0200758static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
759 fdt_size_t *size, bool translate)
Simon Glass049ae1b2017-05-18 20:09:01 -0600760{
Keerthy34222a32018-11-19 11:44:47 +0530761 int na, ns;
Keerthy34222a32018-11-19 11:44:47 +0530762
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800763 if (size)
764 *size = FDT_SIZE_T_NONE;
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800765
Simon Glass049ae1b2017-05-18 20:09:01 -0600766 if (ofnode_is_np(node)) {
767 const __be32 *prop_val;
Simon Glass47f85de2019-09-25 08:55:50 -0600768 u64 size64;
Simon Glass049ae1b2017-05-18 20:09:01 -0600769 uint flags;
Simon Glass049ae1b2017-05-18 20:09:01 -0600770
Simon Glass47f85de2019-09-25 08:55:50 -0600771 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
772 &flags);
Simon Glass049ae1b2017-05-18 20:09:01 -0600773 if (!prop_val)
774 return FDT_ADDR_T_NONE;
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800775
Simon Glass47f85de2019-09-25 08:55:50 -0600776 if (size)
777 *size = size64;
Mario Sixd007ebc2017-12-20 09:52:12 +0100778
Mario Six35616ef2018-03-12 14:53:33 +0100779 ns = of_n_size_cells(ofnode_to_np(node));
780
Marek Behún177ab7f2021-05-26 14:08:17 +0200781 if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Sixd007ebc2017-12-20 09:52:12 +0100782 return of_translate_address(ofnode_to_np(node), prop_val);
783 } else {
784 na = of_n_addr_cells(ofnode_to_np(node));
785 return of_read_number(prop_val, na);
786 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600787 } else {
Jonas Karlman641e1182024-08-04 15:05:50 +0000788 ofnode parent = ofnode_get_parent(node);
789 na = ofnode_read_simple_addr_cells(parent);
790 ns = ofnode_read_simple_size_cells(parent);
Simon Glass04fa09a2022-09-06 20:27:20 -0600791 return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
Keerthy34222a32018-11-19 11:44:47 +0530792 ofnode_to_offset(node), "reg",
Marek Behún177ab7f2021-05-26 14:08:17 +0200793 index, na, ns, size,
794 translate);
Simon Glass049ae1b2017-05-18 20:09:01 -0600795 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600796}
797
Marek Behún177ab7f2021-05-26 14:08:17 +0200798fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
799{
800 return __ofnode_get_addr_size_index(node, index, size, true);
801}
802
803fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
804 fdt_size_t *size)
805{
806 return __ofnode_get_addr_size_index(node, index, size, false);
807}
808
Keerthyd332e6e2019-04-24 17:19:53 +0530809fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
810{
811 fdt_size_t size;
812
813 return ofnode_get_addr_size_index(node, index, &size);
814}
815
Simon Glass049ae1b2017-05-18 20:09:01 -0600816fdt_addr_t ofnode_get_addr(ofnode node)
817{
818 return ofnode_get_addr_index(node, 0);
819}
820
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800821fdt_size_t ofnode_get_size(ofnode node)
822{
823 fdt_size_t size;
824
825 ofnode_get_addr_size_index(node, 0, &size);
826
827 return size;
828}
829
Simon Glassc4fc5622017-05-18 20:08:58 -0600830int ofnode_stringlist_search(ofnode node, const char *property,
831 const char *string)
832{
833 if (ofnode_is_np(node)) {
834 return of_property_match_string(ofnode_to_np(node),
835 property, string);
836 } else {
837 int ret;
838
Simon Glass04fa09a2022-09-06 20:27:20 -0600839 ret = fdt_stringlist_search(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600840 ofnode_to_offset(node), property,
841 string);
842 if (ret == -FDT_ERR_NOTFOUND)
843 return -ENODATA;
844 else if (ret < 0)
845 return -EINVAL;
846
847 return ret;
848 }
849}
850
851int ofnode_read_string_index(ofnode node, const char *property, int index,
852 const char **outp)
853{
854 if (ofnode_is_np(node)) {
855 return of_property_read_string_index(ofnode_to_np(node),
856 property, index, outp);
857 } else {
858 int len;
859
Simon Glass04fa09a2022-09-06 20:27:20 -0600860 *outp = fdt_stringlist_get(ofnode_to_fdt(node),
861 ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600862 property, index, &len);
863 if (len < 0)
864 return -EINVAL;
865 return 0;
866 }
867}
868
Simon Glass5fdb0052017-06-12 06:21:28 -0600869int ofnode_read_string_count(ofnode node, const char *property)
870{
871 if (ofnode_is_np(node)) {
872 return of_property_count_strings(ofnode_to_np(node), property);
873 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600874 return fdt_stringlist_count(ofnode_to_fdt(node),
Simon Glass5fdb0052017-06-12 06:21:28 -0600875 ofnode_to_offset(node), property);
876 }
877}
878
Simon Glass9580bfc2021-10-23 17:26:07 -0600879int ofnode_read_string_list(ofnode node, const char *property,
880 const char ***listp)
881{
882 const char **prop;
883 int count;
884 int i;
885
886 *listp = NULL;
887 count = ofnode_read_string_count(node, property);
888 if (count < 0)
889 return count;
890 if (!count)
891 return 0;
892
893 prop = calloc(count + 1, sizeof(char *));
894 if (!prop)
895 return -ENOMEM;
896
897 for (i = 0; i < count; i++)
898 ofnode_read_string_index(node, property, i, &prop[i]);
899 prop[count] = NULL;
900 *listp = prop;
901
902 return count;
903}
904
Christian Marangie810bcd2024-11-10 12:50:22 +0100905ofnode ofnode_parse_phandle(ofnode node, const char *phandle_name,
906 int index)
907{
908 ofnode phandle;
909
910 if (ofnode_is_np(node)) {
911 struct device_node *np;
912
913 np = of_parse_phandle(ofnode_to_np(node), phandle_name,
914 index);
915 if (!np)
916 return ofnode_null();
917
918 phandle = np_to_ofnode(np);
919 } else {
920 struct fdtdec_phandle_args args;
921
922 if (fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
923 ofnode_to_offset(node),
924 phandle_name, NULL,
925 0, index, &args))
926 return ofnode_null();
927
928 phandle = offset_to_ofnode(args.node);
929 }
930
931 return phandle;
932}
933
934ofnode oftree_parse_phandle(oftree tree, ofnode node, const char *phandle_name,
935 int index)
936{
937 ofnode phandle;
938
939 if (ofnode_is_np(node)) {
940 struct device_node *np;
941
942 np = of_root_parse_phandle(tree.np, ofnode_to_np(node),
943 phandle_name, index);
944 if (!np)
945 return ofnode_null();
946
947 phandle = np_to_ofnode(np);
948 } else {
949 struct fdtdec_phandle_args args;
950
951 if (fdtdec_parse_phandle_with_args(tree.fdt,
952 ofnode_to_offset(node),
953 phandle_name, NULL,
954 0, index, &args))
955 return ofnode_null();
956
957 phandle = noffset_to_ofnode(node, args.node);
958 }
959
960 return phandle;
961}
962
Christian Marangi98715ac2024-11-10 12:50:20 +0100963static void ofnode_from_fdtdec_phandle_args(ofnode node, struct fdtdec_phandle_args *in,
Simon Glassc4fc5622017-05-18 20:08:58 -0600964 struct ofnode_phandle_args *out)
965{
966 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
Christian Marangi98715ac2024-11-10 12:50:20 +0100967 out->node = noffset_to_ofnode(node, in->node);
Simon Glassc4fc5622017-05-18 20:08:58 -0600968 out->args_count = in->args_count;
969 memcpy(out->args, in->args, sizeof(out->args));
970}
971
972static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
973 struct ofnode_phandle_args *out)
974{
975 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
976 out->node = np_to_ofnode(in->np);
977 out->args_count = in->args_count;
978 memcpy(out->args, in->args, sizeof(out->args));
979}
980
981int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
982 const char *cells_name, int cell_count,
983 int index,
984 struct ofnode_phandle_args *out_args)
985{
986 if (ofnode_is_np(node)) {
987 struct of_phandle_args args;
988 int ret;
989
990 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay21e3b042020-09-10 18:26:17 +0200991 list_name, cells_name,
992 cell_count, index,
Mario Sixf40d82c2018-01-15 11:07:17 +0100993 &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600994 if (ret)
995 return ret;
996 ofnode_from_of_phandle_args(&args, out_args);
997 } else {
998 struct fdtdec_phandle_args args;
999 int ret;
1000
Simon Glass04fa09a2022-09-06 20:27:20 -06001001 ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Mario Sixf40d82c2018-01-15 11:07:17 +01001002 ofnode_to_offset(node),
1003 list_name, cells_name,
1004 cell_count, index, &args);
Simon Glassc4fc5622017-05-18 20:08:58 -06001005 if (ret)
1006 return ret;
Christian Marangi98715ac2024-11-10 12:50:20 +01001007 ofnode_from_fdtdec_phandle_args(node, &args, out_args);
Simon Glassc4fc5622017-05-18 20:08:58 -06001008 }
1009
1010 return 0;
1011}
1012
Christian Marangi98715ac2024-11-10 12:50:20 +01001013int oftree_parse_phandle_with_args(oftree tree, ofnode node, const char *list_name,
1014 const char *cells_name, int cell_count,
1015 int index,
1016 struct ofnode_phandle_args *out_args)
1017{
1018 if (ofnode_is_np(node)) {
1019 struct of_phandle_args args;
1020 int ret;
1021
1022 ret = of_root_parse_phandle_with_args(tree.np,
1023 ofnode_to_np(node),
1024 list_name, cells_name,
1025 cell_count, index,
1026 &args);
1027 if (ret)
1028 return ret;
1029 ofnode_from_of_phandle_args(&args, out_args);
1030 } else {
1031 struct fdtdec_phandle_args args;
1032 int ret;
1033
1034 ret = fdtdec_parse_phandle_with_args(tree.fdt,
1035 ofnode_to_offset(node),
1036 list_name, cells_name,
1037 cell_count, index, &args);
1038 if (ret)
1039 return ret;
1040 ofnode_from_fdtdec_phandle_args(node, &args, out_args);
1041 }
1042
1043 return 0;
1044}
1045
Patrice Chotardbe7dd602017-07-18 11:57:08 +02001046int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +02001047 const char *cells_name, int cell_count)
Patrice Chotardbe7dd602017-07-18 11:57:08 +02001048{
1049 if (ofnode_is_np(node))
1050 return of_count_phandle_with_args(ofnode_to_np(node),
Patrick Delaunayd776a842020-09-25 09:41:14 +02001051 list_name, cells_name, cell_count);
Patrice Chotardbe7dd602017-07-18 11:57:08 +02001052 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001053 return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Patrice Chotardbe7dd602017-07-18 11:57:08 +02001054 ofnode_to_offset(node), list_name, cells_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +02001055 cell_count, -1, NULL);
Patrice Chotardbe7dd602017-07-18 11:57:08 +02001056}
1057
Christian Marangi98715ac2024-11-10 12:50:20 +01001058int oftree_count_phandle_with_args(oftree tree, ofnode node, const char *list_name,
1059 const char *cells_name, int cell_count)
1060{
1061 if (ofnode_is_np(node))
1062 return of_root_count_phandle_with_args(tree.np, ofnode_to_np(node),
1063 list_name, cells_name, cell_count);
1064 else
1065 return fdtdec_parse_phandle_with_args(tree.fdt,
1066 ofnode_to_offset(node), list_name, cells_name,
1067 cell_count, -1, NULL);
1068}
1069
Simon Glassc4fc5622017-05-18 20:08:58 -06001070ofnode ofnode_path(const char *path)
1071{
1072 if (of_live_active())
1073 return np_to_ofnode(of_find_node_by_path(path));
1074 else
1075 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
1076}
1077
Simon Glass45ae59d2022-09-06 20:27:24 -06001078ofnode oftree_root(oftree tree)
Simon Glassef75c592022-07-30 15:52:08 -06001079{
Simon Glass45ae59d2022-09-06 20:27:24 -06001080 if (of_live_active()) {
1081 return np_to_ofnode(tree.np);
1082 } else {
1083 return ofnode_from_tree_offset(tree, 0);
1084 }
1085}
1086
1087ofnode oftree_path(oftree tree, const char *path)
1088{
1089 if (of_live_active()) {
Simon Glassef75c592022-07-30 15:52:08 -06001090 return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
1091 NULL));
Simon Glass45ae59d2022-09-06 20:27:24 -06001092 } else if (*path != '/' && tree.fdt != gd->fdt_blob) {
Simon Glassef75c592022-07-30 15:52:08 -06001093 return ofnode_null(); /* Aliases only on control FDT */
Simon Glass45ae59d2022-09-06 20:27:24 -06001094 } else {
1095 int offset = fdt_path_offset(tree.fdt, path);
1096
1097 return ofnode_from_tree_offset(tree, offset);
1098 }
Simon Glassef75c592022-07-30 15:52:08 -06001099}
1100
Simon Glasse09223c2020-01-27 08:49:46 -07001101const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -06001102{
1103 ofnode chosen_node;
1104
1105 chosen_node = ofnode_path("/chosen");
1106
Simon Glasse09223c2020-01-27 08:49:46 -07001107 return ofnode_read_prop(chosen_node, propname, sizep);
Simon Glassc4fc5622017-05-18 20:08:58 -06001108}
1109
Simon Glasse09223c2020-01-27 08:49:46 -07001110const char *ofnode_read_chosen_string(const char *propname)
1111{
1112 return ofnode_read_chosen_prop(propname, NULL);
1113}
1114
Simon Glassc4fc5622017-05-18 20:08:58 -06001115ofnode ofnode_get_chosen_node(const char *name)
1116{
1117 const char *prop;
1118
Simon Glasse09223c2020-01-27 08:49:46 -07001119 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -06001120 if (!prop)
1121 return ofnode_null();
1122
1123 return ofnode_path(prop);
1124}
1125
Algapally Santosh Sagardf178992023-09-21 16:50:43 +05301126int ofnode_read_baud(void)
1127{
1128 const char *str, *p;
1129 u32 baud;
1130
1131 str = ofnode_read_chosen_string("stdout-path");
1132 if (!str)
1133 return -EINVAL;
1134
1135 /* Parse string serial0:115200n8 */
1136 p = strchr(str, ':');
1137 if (!p)
1138 return -EINVAL;
1139
1140 baud = dectoul(p + 1, NULL);
1141 return baud;
1142}
1143
Michal Simek92a88622020-07-28 12:51:08 +02001144const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
1145{
1146 ofnode node;
1147
1148 node = ofnode_path("/aliases");
1149
1150 return ofnode_read_prop(node, propname, sizep);
1151}
1152
1153ofnode ofnode_get_aliases_node(const char *name)
1154{
1155 const char *prop;
1156
1157 prop = ofnode_read_aliases_prop(name, NULL);
1158 if (!prop)
1159 return ofnode_null();
1160
Quentin Schulze2d4d262024-10-15 16:32:14 +02001161 log_debug("%s: node_path: %s\n", __func__, prop);
Michal Simek92a88622020-07-28 12:51:08 +02001162
1163 return ofnode_path(prop);
1164}
1165
developerd93c8b42020-05-02 11:35:09 +02001166int ofnode_get_child_count(ofnode parent)
1167{
1168 ofnode child;
1169 int num = 0;
1170
1171 ofnode_for_each_subnode(child, parent)
1172 num++;
1173
1174 return num;
1175}
1176
Simon Glassc4fc5622017-05-18 20:08:58 -06001177static int decode_timing_property(ofnode node, const char *name,
1178 struct timing_entry *result)
1179{
1180 int length, ret = 0;
1181
1182 length = ofnode_read_size(node, name);
1183 if (length < 0) {
Quentin Schulz95a5a2b2024-06-11 15:04:26 +02001184 dm_warn("%s: could not find property %s\n",
1185 ofnode_get_name(node), name);
Simon Glassc4fc5622017-05-18 20:08:58 -06001186 return length;
1187 }
1188
1189 if (length == sizeof(u32)) {
1190 result->typ = ofnode_read_u32_default(node, name, 0);
1191 result->min = result->typ;
1192 result->max = result->typ;
1193 } else {
1194 ret = ofnode_read_u32_array(node, name, &result->min, 3);
1195 }
1196
1197 return ret;
1198}
1199
1200int ofnode_decode_display_timing(ofnode parent, int index,
1201 struct display_timing *dt)
1202{
1203 int i;
1204 ofnode timings, node;
1205 u32 val = 0;
1206 int ret = 0;
1207
1208 timings = ofnode_find_subnode(parent, "display-timings");
1209 if (!ofnode_valid(timings))
1210 return -EINVAL;
1211
Simon Glass28529762017-08-05 15:45:54 -06001212 i = 0;
1213 ofnode_for_each_subnode(node, timings) {
1214 if (i++ == index)
1215 break;
1216 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001217
1218 if (!ofnode_valid(node))
1219 return -EINVAL;
1220
1221 memset(dt, 0, sizeof(*dt));
1222
1223 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
1224 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
1225 ret |= decode_timing_property(node, "hactive", &dt->hactive);
1226 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
1227 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
1228 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
1229 ret |= decode_timing_property(node, "vactive", &dt->vactive);
1230 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
1231 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
1232
1233 dt->flags = 0;
1234 val = ofnode_read_u32_default(node, "vsync-active", -1);
1235 if (val != -1) {
1236 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1237 DISPLAY_FLAGS_VSYNC_LOW;
1238 }
1239 val = ofnode_read_u32_default(node, "hsync-active", -1);
1240 if (val != -1) {
1241 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1242 DISPLAY_FLAGS_HSYNC_LOW;
1243 }
1244 val = ofnode_read_u32_default(node, "de-active", -1);
1245 if (val != -1) {
1246 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1247 DISPLAY_FLAGS_DE_LOW;
1248 }
1249 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
1250 if (val != -1) {
1251 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1252 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1253 }
1254
1255 if (ofnode_read_bool(node, "interlaced"))
1256 dt->flags |= DISPLAY_FLAGS_INTERLACED;
1257 if (ofnode_read_bool(node, "doublescan"))
1258 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1259 if (ofnode_read_bool(node, "doubleclk"))
1260 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1261
1262 return ret;
1263}
1264
Nikhil M Jainff407062023-01-31 15:35:14 +05301265int ofnode_decode_panel_timing(ofnode parent,
1266 struct display_timing *dt)
1267{
1268 ofnode timings;
1269 u32 val = 0;
1270 int ret = 0;
1271
Raphael Gallais-Poua853b922023-05-11 16:36:52 +02001272 timings = ofnode_find_subnode(parent, "panel-timing");
Nikhil M Jainff407062023-01-31 15:35:14 +05301273 if (!ofnode_valid(timings))
1274 return -EINVAL;
1275 memset(dt, 0, sizeof(*dt));
1276 ret |= decode_timing_property(timings, "hback-porch", &dt->hback_porch);
1277 ret |= decode_timing_property(timings, "hfront-porch", &dt->hfront_porch);
1278 ret |= decode_timing_property(timings, "hactive", &dt->hactive);
1279 ret |= decode_timing_property(timings, "hsync-len", &dt->hsync_len);
1280 ret |= decode_timing_property(timings, "vback-porch", &dt->vback_porch);
1281 ret |= decode_timing_property(timings, "vfront-porch", &dt->vfront_porch);
1282 ret |= decode_timing_property(timings, "vactive", &dt->vactive);
1283 ret |= decode_timing_property(timings, "vsync-len", &dt->vsync_len);
1284 ret |= decode_timing_property(timings, "clock-frequency", &dt->pixelclock);
1285 dt->flags = 0;
1286 if (!ofnode_read_u32(timings, "vsync-active", &val)) {
1287 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1288 DISPLAY_FLAGS_VSYNC_LOW;
1289 }
1290 if (!ofnode_read_u32(timings, "hsync-active", &val)) {
1291 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1292 DISPLAY_FLAGS_HSYNC_LOW;
1293 }
1294 if (!ofnode_read_u32(timings, "de-active", &val)) {
1295 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1296 DISPLAY_FLAGS_DE_LOW;
1297 }
1298 if (!ofnode_read_u32(timings, "pixelclk-active", &val)) {
1299 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1300 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1301 }
1302 if (ofnode_read_bool(timings, "interlaced"))
1303 dt->flags |= DISPLAY_FLAGS_INTERLACED;
1304 if (ofnode_read_bool(timings, "doublescan"))
1305 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1306 if (ofnode_read_bool(timings, "doubleclk"))
1307 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1308
1309 return ret;
1310}
1311
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +09001312const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glassc4fc5622017-05-18 20:08:58 -06001313{
Masahiro Yamada5052f1b2017-06-22 16:54:04 +09001314 if (ofnode_is_np(node))
1315 return of_get_property(ofnode_to_np(node), propname, lenp);
1316 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001317 return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001318 propname, lenp);
Simon Glassc4fc5622017-05-18 20:08:58 -06001319}
1320
Simon Glass86ef3992023-09-26 08:14:44 -06001321bool ofnode_has_property(ofnode node, const char *propname)
1322{
1323 if (ofnode_is_np(node))
1324 return of_find_property(ofnode_to_np(node), propname, NULL);
1325 else
1326 return ofnode_get_property(node, propname, NULL);
1327}
1328
Simon Glassfec058d2022-09-06 20:27:13 -06001329int ofnode_first_property(ofnode node, struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001330{
1331 prop->node = node;
1332
1333 if (ofnode_is_np(node)) {
1334 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
1335 if (!prop->prop)
1336 return -FDT_ERR_NOTFOUND;
1337 } else {
1338 prop->offset =
Simon Glass04fa09a2022-09-06 20:27:20 -06001339 fdt_first_property_offset(ofnode_to_fdt(node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001340 ofnode_to_offset(prop->node));
1341 if (prop->offset < 0)
1342 return prop->offset;
1343 }
1344
1345 return 0;
1346}
1347
Simon Glassfec058d2022-09-06 20:27:13 -06001348int ofnode_next_property(struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001349{
1350 if (ofnode_is_np(prop->node)) {
1351 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
1352 prop->prop);
1353 if (!prop->prop)
1354 return -FDT_ERR_NOTFOUND;
1355 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001356 prop->offset =
1357 fdt_next_property_offset(ofnode_to_fdt(prop->node),
1358 prop->offset);
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001359 if (prop->offset < 0)
1360 return prop->offset;
1361 }
1362
1363 return 0;
1364}
1365
Simon Glassd0aff8b2022-09-06 20:27:14 -06001366const void *ofprop_get_property(const struct ofprop *prop,
1367 const char **propname, int *lenp)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001368{
1369 if (ofnode_is_np(prop->node))
1370 return of_get_property_by_prop(ofnode_to_np(prop->node),
1371 prop->prop, propname, lenp);
1372 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001373 return fdt_getprop_by_offset(ofnode_to_fdt(prop->node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001374 prop->offset,
1375 propname, lenp);
1376}
1377
Simon Glassc4fc5622017-05-18 20:08:58 -06001378fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
1379 fdt_size_t *sizep)
1380{
1381 if (ofnode_is_np(node)) {
1382 int na, ns;
1383 int psize;
1384 const struct device_node *np = ofnode_to_np(node);
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001385 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glassc4fc5622017-05-18 20:08:58 -06001386
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001387 if (!prop)
1388 return FDT_ADDR_T_NONE;
Simon Glassc4fc5622017-05-18 20:08:58 -06001389 na = of_n_addr_cells(np);
Marek Vasut1638c172018-10-01 12:37:19 +02001390 ns = of_n_size_cells(np);
Simon Glassa67cc632017-05-18 20:09:27 -06001391 *sizep = of_read_number(prop + na, ns);
Marek Vasuta9dac492018-10-01 12:37:20 +02001392
Dario Binacchif8fc7032021-05-01 17:05:26 +02001393 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta9dac492018-10-01 12:37:20 +02001394 return of_translate_address(np, prop);
1395 else
1396 return of_read_number(prop, na);
Simon Glassc4fc5622017-05-18 20:08:58 -06001397 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001398 return fdtdec_get_addr_size(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001399 ofnode_to_offset(node), property,
1400 sizep);
1401 }
1402}
1403
1404const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
1405 size_t sz)
1406{
1407 if (ofnode_is_np(node)) {
1408 const struct device_node *np = ofnode_to_np(node);
1409 int psize;
1410 const __be32 *prop = of_get_property(np, propname, &psize);
1411
1412 if (!prop || sz != psize)
1413 return NULL;
1414 return (uint8_t *)prop;
1415
1416 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001417 return fdtdec_locate_byte_array(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001418 ofnode_to_offset(node), propname, sz);
1419 }
1420}
1421
1422int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
Simon Glass4289c262023-09-26 08:14:58 -06001423 const char *propname, struct fdt_pci_addr *addr,
1424 fdt_size_t *size)
Simon Glassc4fc5622017-05-18 20:08:58 -06001425{
Masahiro Yamada5c5991e2017-06-22 17:57:50 +09001426 const fdt32_t *cell;
Simon Glassc4fc5622017-05-18 20:08:58 -06001427 int len;
1428 int ret = -ENOENT;
1429
Quentin Schulze2d4d262024-10-15 16:32:14 +02001430 log_debug("%s: %s: ", __func__, propname);
Simon Glassc4fc5622017-05-18 20:08:58 -06001431
1432 /*
1433 * If we follow the pci bus bindings strictly, we should check
1434 * the value of the node's parent node's #address-cells and
1435 * #size-cells. They need to be 3 and 2 accordingly. However,
1436 * for simplicity we skip the check here.
1437 */
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +09001438 cell = ofnode_get_property(node, propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -06001439 if (!cell)
1440 goto fail;
1441
1442 if ((len % FDT_PCI_REG_SIZE) == 0) {
1443 int num = len / FDT_PCI_REG_SIZE;
1444 int i;
1445
1446 for (i = 0; i < num; i++) {
Quentin Schulze2d4d262024-10-15 16:32:14 +02001447 log_debug("pci address #%d: %08lx %08lx %08lx\n", i,
1448 (ulong)fdt32_to_cpu(cell[0]),
1449 (ulong)fdt32_to_cpu(cell[1]),
1450 (ulong)fdt32_to_cpu(cell[2]));
Simon Glassc4fc5622017-05-18 20:08:58 -06001451 if ((fdt32_to_cpu(*cell) & type) == type) {
Simon Glass4289c262023-09-26 08:14:58 -06001452 const unaligned_fdt64_t *ptr;
1453
Simon Glassc4fc5622017-05-18 20:08:58 -06001454 addr->phys_hi = fdt32_to_cpu(cell[0]);
1455 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glassdfd43152019-09-25 08:55:46 -06001456 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glass4289c262023-09-26 08:14:58 -06001457 ptr = (const unaligned_fdt64_t *)(cell + 3);
1458 if (size)
1459 *size = fdt64_to_cpu(*ptr);
Simon Glassc4fc5622017-05-18 20:08:58 -06001460 break;
Simon Glassc4fc5622017-05-18 20:08:58 -06001461 }
Mario Sixf40d82c2018-01-15 11:07:17 +01001462
Simon Glass4289c262023-09-26 08:14:58 -06001463 cell += FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS;
Simon Glassc4fc5622017-05-18 20:08:58 -06001464 }
1465
1466 if (i == num) {
1467 ret = -ENXIO;
1468 goto fail;
1469 }
1470
1471 return 0;
Simon Glassc4fc5622017-05-18 20:08:58 -06001472 }
1473
Mario Sixf40d82c2018-01-15 11:07:17 +01001474 ret = -EINVAL;
1475
Simon Glassc4fc5622017-05-18 20:08:58 -06001476fail:
Quentin Schulze2d4d262024-10-15 16:32:14 +02001477 log_debug("(not found)\n");
Simon Glassc4fc5622017-05-18 20:08:58 -06001478 return ret;
1479}
1480
Bin Mengfa157712018-08-03 01:14:35 -07001481int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
1482{
1483 const char *list, *end;
1484 int len;
1485
1486 list = ofnode_get_property(node, "compatible", &len);
1487 if (!list)
1488 return -ENOENT;
1489
1490 end = list + len;
1491 while (list < end) {
1492 len = strlen(list);
1493 if (len >= strlen("pciVVVV,DDDD")) {
1494 char *s = strstr(list, "pci");
1495
1496 /*
1497 * check if the string is something like pciVVVV,DDDD.RR
1498 * or just pciVVVV,DDDD
1499 */
1500 if (s && s[7] == ',' &&
1501 (s[12] == '.' || s[12] == 0)) {
1502 s += 3;
1503 *vendor = simple_strtol(s, NULL, 16);
1504
1505 s += 5;
1506 *device = simple_strtol(s, NULL, 16);
1507
1508 return 0;
1509 }
1510 }
1511 list += (len + 1);
1512 }
1513
1514 return -ENOENT;
1515}
1516
Michal Simeka253c3b2022-02-23 15:45:40 +01001517int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
1518{
1519 const char *list, *end;
1520 int len;
1521
1522 list = ofnode_get_property(node, "compatible", &len);
1523
1524 if (!list)
1525 return -ENOENT;
1526
1527 end = list + len;
1528 while (list < end) {
1529 len = strlen(list);
1530
Michal Simekc633cdf2022-10-31 17:08:44 -07001531 if (len >= strlen("ethernet-phy-idVVVV.DDDD")) {
Michal Simeka253c3b2022-02-23 15:45:40 +01001532 char *s = strstr(list, "ethernet-phy-id");
1533
1534 /*
1535 * check if the string is something like
Michal Simekc633cdf2022-10-31 17:08:44 -07001536 * ethernet-phy-idVVVV.DDDD
Michal Simeka253c3b2022-02-23 15:45:40 +01001537 */
1538 if (s && s[19] == '.') {
1539 s += strlen("ethernet-phy-id");
1540 *vendor = simple_strtol(s, NULL, 16);
1541 s += 5;
1542 *device = simple_strtol(s, NULL, 16);
1543
1544 return 0;
1545 }
1546 }
1547 list += (len + 1);
1548 }
1549
1550 return -ENOENT;
1551}
1552
Simon Glassc4fc5622017-05-18 20:08:58 -06001553int ofnode_read_addr_cells(ofnode node)
1554{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001555 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001556 return of_n_addr_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001557 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001558 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001559 ofnode_to_offset(node));
1560
Simon Glass04fa09a2022-09-06 20:27:20 -06001561 return fdt_address_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001562 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001563}
1564
1565int ofnode_read_size_cells(ofnode node)
1566{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001567 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001568 return of_n_size_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001569 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001570 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001571 ofnode_to_offset(node));
1572
Simon Glass04fa09a2022-09-06 20:27:20 -06001573 return fdt_size_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001574 }
Simon Glass4191dc12017-06-12 06:21:31 -06001575}
1576
1577int ofnode_read_simple_addr_cells(ofnode node)
1578{
1579 if (ofnode_is_np(node))
1580 return of_simple_addr_cells(ofnode_to_np(node));
1581 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001582 return fdt_address_cells(ofnode_to_fdt(node),
1583 ofnode_to_offset(node));
Simon Glass4191dc12017-06-12 06:21:31 -06001584}
1585
1586int ofnode_read_simple_size_cells(ofnode node)
1587{
1588 if (ofnode_is_np(node))
1589 return of_simple_size_cells(ofnode_to_np(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001590 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001591 return fdt_size_cells(ofnode_to_fdt(node),
1592 ofnode_to_offset(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001593}
1594
1595bool ofnode_pre_reloc(ofnode node)
1596{
Simon Glass7ec24132024-09-29 19:49:48 -06001597#if defined(CONFIG_XPL_BUILD) || defined(CONFIG_TPL_BUILD)
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001598 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
Simon Glassfc1aa352023-02-13 08:56:34 -07001599 * had property bootph-all or bootph-pre-sram/bootph-pre-ram.
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001600 * They are removed in final dtb (fdtgrep 2nd pass)
1601 */
1602 return true;
1603#else
Simon Glassfc1aa352023-02-13 08:56:34 -07001604 if (ofnode_read_bool(node, "bootph-all"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001605 return true;
Simon Glassfc1aa352023-02-13 08:56:34 -07001606 if (ofnode_read_bool(node, "bootph-some-ram"))
Simon Glass23f22842018-10-01 12:22:18 -06001607 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001608
Simon Glassc4fc5622017-05-18 20:08:58 -06001609 /*
1610 * In regular builds individual spl and tpl handling both
1611 * count as handled pre-relocation for later second init.
1612 */
Simon Glassfc1aa352023-02-13 08:56:34 -07001613 if (ofnode_read_bool(node, "bootph-pre-ram") ||
1614 ofnode_read_bool(node, "bootph-pre-sram"))
Jonas Karlmanc43411b2023-08-20 22:03:18 +00001615 return gd->flags & GD_FLG_RELOC;
Simon Glassc4fc5622017-05-18 20:08:58 -06001616
Simon Glassc2727e52023-02-13 08:56:32 -07001617 if (IS_ENABLED(CONFIG_OF_TAG_MIGRATE)) {
1618 /* detect and handle old tags */
1619 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc") ||
1620 ofnode_read_bool(node, "u-boot,dm-pre-proper") ||
1621 ofnode_read_bool(node, "u-boot,dm-spl") ||
1622 ofnode_read_bool(node, "u-boot,dm-tpl") ||
1623 ofnode_read_bool(node, "u-boot,dm-vpl")) {
1624 gd->flags |= GD_FLG_OF_TAG_MIGRATE;
1625 return true;
1626 }
1627 }
1628
Simon Glassc4fc5622017-05-18 20:08:58 -06001629 return false;
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001630#endif
Simon Glassc4fc5622017-05-18 20:08:58 -06001631}
Simon Glassf7bfcc42017-07-25 08:29:55 -06001632
1633int ofnode_read_resource(ofnode node, uint index, struct resource *res)
1634{
1635 if (ofnode_is_np(node)) {
1636 return of_address_to_resource(ofnode_to_np(node), index, res);
1637 } else {
1638 struct fdt_resource fres;
1639 int ret;
1640
Simon Glass04fa09a2022-09-06 20:27:20 -06001641 ret = fdt_get_resource(ofnode_to_fdt(node),
1642 ofnode_to_offset(node),
Simon Glassf7bfcc42017-07-25 08:29:55 -06001643 "reg", index, &fres);
1644 if (ret < 0)
1645 return -EINVAL;
1646 memset(res, '\0', sizeof(*res));
1647 res->start = fres.start;
1648 res->end = fres.end;
1649
1650 return 0;
1651 }
1652}
Masahiro Yamada4dada2c2017-08-26 01:12:30 +09001653
1654int ofnode_read_resource_byname(ofnode node, const char *name,
1655 struct resource *res)
1656{
1657 int index;
1658
1659 index = ofnode_stringlist_search(node, "reg-names", name);
1660 if (index < 0)
1661 return index;
1662
1663 return ofnode_read_resource(node, index, res);
1664}
Mario Sixaefac062018-01-15 11:07:19 +01001665
1666u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
1667{
1668 if (ofnode_is_np(node))
1669 return of_translate_address(ofnode_to_np(node), in_addr);
1670 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001671 return fdt_translate_address(ofnode_to_fdt(node),
1672 ofnode_to_offset(node), in_addr);
Mario Sixaefac062018-01-15 11:07:19 +01001673}
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001674
Fabien Dessenne22236e02019-05-31 15:11:30 +02001675u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
1676{
1677 if (ofnode_is_np(node))
1678 return of_translate_dma_address(ofnode_to_np(node), in_addr);
1679 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001680 return fdt_translate_dma_address(ofnode_to_fdt(node),
1681 ofnode_to_offset(node), in_addr);
Fabien Dessenne22236e02019-05-31 15:11:30 +02001682}
1683
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001684int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
1685{
1686 if (ofnode_is_np(node))
1687 return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
1688 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001689 return fdt_get_dma_range(ofnode_to_fdt(node),
1690 ofnode_to_offset(node),
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001691 cpu, bus, size);
1692}
1693
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001694int ofnode_device_is_compatible(ofnode node, const char *compat)
1695{
1696 if (ofnode_is_np(node))
1697 return of_device_is_compatible(ofnode_to_np(node), compat,
1698 NULL, NULL);
1699 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001700 return !fdt_node_check_compatible(ofnode_to_fdt(node),
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001701 ofnode_to_offset(node),
1702 compat);
1703}
Simon Glass954eeae2018-06-11 13:07:13 -06001704
1705ofnode ofnode_by_compatible(ofnode from, const char *compat)
1706{
1707 if (of_live_active()) {
1708 return np_to_ofnode(of_find_compatible_node(
1709 (struct device_node *)ofnode_to_np(from), NULL,
1710 compat));
1711 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001712 return noffset_to_ofnode(from,
1713 fdt_node_offset_by_compatible(ofnode_to_fdt(from),
Simon Glass04fa09a2022-09-06 20:27:20 -06001714 ofnode_to_offset(from), compat));
Simon Glass954eeae2018-06-11 13:07:13 -06001715 }
1716}
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001717
1718ofnode ofnode_by_prop_value(ofnode from, const char *propname,
1719 const void *propval, int proplen)
1720{
1721 if (of_live_active()) {
1722 return np_to_ofnode(of_find_node_by_prop_value(
1723 (struct device_node *)ofnode_to_np(from), propname,
1724 propval, proplen));
1725 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001726 return noffset_to_ofnode(from,
1727 fdt_node_offset_by_prop_value(ofnode_to_fdt(from),
1728 ofnode_to_offset(from), propname, propval,
1729 proplen));
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001730 }
1731}
Mario Six047dafc2018-06-26 08:46:48 +02001732
Simon Glass5e2cd5e2022-07-30 15:52:10 -06001733int ofnode_write_prop(ofnode node, const char *propname, const void *value,
Simon Glass17abed02022-09-06 20:27:32 -06001734 int len, bool copy)
Mario Six047dafc2018-06-26 08:46:48 +02001735{
Simon Glass004f5bd2025-01-10 17:00:10 -07001736 int ret;
1737
Simon Glass17abed02022-09-06 20:27:32 -06001738 if (of_live_active()) {
1739 void *newval;
Simon Glass17abed02022-09-06 20:27:32 -06001740
1741 if (copy) {
1742 newval = malloc(len);
1743 if (!newval)
1744 return log_ret(-ENOMEM);
1745 memcpy(newval, value, len);
1746 value = newval;
1747 }
1748 ret = of_write_prop(ofnode_to_np(node), propname, len, value);
1749 if (ret && copy)
1750 free(newval);
1751 return ret;
1752 } else {
Simon Glass004f5bd2025-01-10 17:00:10 -07001753 ret = fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
1754 propname, value, len);
1755 if (ret)
1756 return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EINVAL;
1757
1758 return 0;
Simon Glass17abed02022-09-06 20:27:32 -06001759 }
Mario Six047dafc2018-06-26 08:46:48 +02001760}
1761
1762int ofnode_write_string(ofnode node, const char *propname, const char *value)
1763{
Mario Six047dafc2018-06-26 08:46:48 +02001764 assert(ofnode_valid(node));
1765
Quentin Schulze2d4d262024-10-15 16:32:14 +02001766 log_debug("%s: %s = %s", __func__, propname, value);
Mario Six047dafc2018-06-26 08:46:48 +02001767
Simon Glass17abed02022-09-06 20:27:32 -06001768 return ofnode_write_prop(node, propname, value, strlen(value) + 1,
1769 false);
Mario Six047dafc2018-06-26 08:46:48 +02001770}
1771
Simon Glassd28e31e2022-07-30 15:52:14 -06001772int ofnode_write_u32(ofnode node, const char *propname, u32 value)
1773{
1774 fdt32_t *val;
1775
1776 assert(ofnode_valid(node));
1777
1778 log_debug("%s = %x", propname, value);
1779 val = malloc(sizeof(*val));
1780 if (!val)
1781 return -ENOMEM;
1782 *val = cpu_to_fdt32(value);
1783
Simon Glassc681e092023-09-26 08:14:45 -06001784 return ofnode_write_prop(node, propname, val, sizeof(value), true);
1785}
1786
1787int ofnode_write_u64(ofnode node, const char *propname, u64 value)
1788{
1789 fdt64_t *val;
1790
1791 assert(ofnode_valid(node));
1792
1793 log_debug("%s = %llx", propname, (unsigned long long)value);
1794 val = malloc(sizeof(*val));
1795 if (!val)
1796 return -ENOMEM;
1797 *val = cpu_to_fdt64(value);
1798
1799 return ofnode_write_prop(node, propname, val, sizeof(value), true);
Simon Glassd28e31e2022-07-30 15:52:14 -06001800}
1801
Simon Glass86ef3992023-09-26 08:14:44 -06001802int ofnode_write_bool(ofnode node, const char *propname, bool value)
1803{
1804 if (value)
1805 return ofnode_write_prop(node, propname, NULL, 0, false);
1806 else
1807 return ofnode_delete_prop(node, propname);
1808}
1809
1810int ofnode_delete_prop(ofnode node, const char *propname)
1811{
1812 if (ofnode_is_np(node)) {
1813 struct property *prop;
1814 int len;
1815
1816 prop = of_find_property(ofnode_to_np(node), propname, &len);
1817 if (prop)
1818 return of_remove_property(ofnode_to_np(node), prop);
1819 return 0;
1820 } else {
1821 return fdt_delprop(ofnode_to_fdt(node), ofnode_to_offset(node),
1822 propname);
1823 }
1824}
1825
Mario Six047dafc2018-06-26 08:46:48 +02001826int ofnode_set_enabled(ofnode node, bool value)
1827{
Mario Six047dafc2018-06-26 08:46:48 +02001828 assert(ofnode_valid(node));
1829
1830 if (value)
1831 return ofnode_write_string(node, "status", "okay");
1832 else
Bin Menga9274aa2019-07-05 09:23:17 -07001833 return ofnode_write_string(node, "status", "disabled");
Mario Six047dafc2018-06-26 08:46:48 +02001834}
Simon Glass0034d962021-08-07 07:24:01 -06001835
1836bool ofnode_conf_read_bool(const char *prop_name)
1837{
1838 ofnode node;
1839
1840 node = ofnode_path("/config");
1841 if (!ofnode_valid(node))
1842 return false;
1843
1844 return ofnode_read_bool(node, prop_name);
1845}
1846
1847int ofnode_conf_read_int(const char *prop_name, int default_val)
1848{
1849 ofnode node;
1850
1851 node = ofnode_path("/config");
1852 if (!ofnode_valid(node))
1853 return default_val;
1854
1855 return ofnode_read_u32_default(node, prop_name, default_val);
1856}
1857
1858const char *ofnode_conf_read_str(const char *prop_name)
1859{
1860 ofnode node;
1861
1862 node = ofnode_path("/config");
1863 if (!ofnode_valid(node))
1864 return NULL;
1865
1866 return ofnode_read_string(node, prop_name);
1867}
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001868
Christian Marangi72544732024-10-01 14:24:35 +02001869bool ofnode_options_read_bool(const char *prop_name)
1870{
1871 ofnode uboot;
1872
1873 uboot = ofnode_path("/options/u-boot");
1874 if (!ofnode_valid(uboot))
1875 return false;
1876
1877 return ofnode_read_bool(uboot, prop_name);
1878}
1879
1880int ofnode_options_read_int(const char *prop_name, int default_val)
1881{
1882 ofnode uboot;
1883
1884 uboot = ofnode_path("/options/u-boot");
1885 if (!ofnode_valid(uboot))
1886 return default_val;
1887
1888 return ofnode_read_u32_default(uboot, prop_name, default_val);
1889}
1890
1891const char *ofnode_options_read_str(const char *prop_name)
1892{
1893 ofnode uboot;
1894
1895 uboot = ofnode_path("/options/u-boot");
1896 if (!ofnode_valid(uboot))
1897 return NULL;
1898
1899 return ofnode_read_string(uboot, prop_name);
1900}
1901
Christian Marangicdaa9952024-11-10 12:50:24 +01001902int ofnode_options_get_by_phandle(const char *prop_name, ofnode *nodep)
1903{
1904 ofnode uboot;
1905
1906 uboot = ofnode_path("/options/u-boot");
1907 if (!ofnode_valid(uboot))
1908 return -EINVAL;
1909
1910 *nodep = ofnode_parse_phandle(uboot, prop_name, 0);
1911 if (!ofnode_valid(*nodep))
1912 return -EINVAL;
1913
1914 return 0;
1915}
1916
Michal Simek43c42bd2023-08-31 08:59:05 +02001917int ofnode_read_bootscript_address(u64 *bootscr_address, u64 *bootscr_offset)
1918{
1919 int ret;
1920 ofnode uboot;
1921
1922 *bootscr_address = 0;
1923 *bootscr_offset = 0;
1924
1925 uboot = ofnode_path("/options/u-boot");
1926 if (!ofnode_valid(uboot)) {
Quentin Schulz95a5a2b2024-06-11 15:04:26 +02001927 dm_warn("%s: Missing /u-boot node\n", __func__);
Michal Simek43c42bd2023-08-31 08:59:05 +02001928 return -EINVAL;
1929 }
1930
1931 ret = ofnode_read_u64(uboot, "bootscr-address", bootscr_address);
1932 if (ret) {
1933 ret = ofnode_read_u64(uboot, "bootscr-ram-offset",
1934 bootscr_offset);
1935 if (ret)
1936 return -EINVAL;
1937 }
1938
1939 return 0;
1940}
1941
Michal Simek6a7c1ce2023-08-31 09:04:27 +02001942int ofnode_read_bootscript_flash(u64 *bootscr_flash_offset,
1943 u64 *bootscr_flash_size)
1944{
1945 int ret;
1946 ofnode uboot;
1947
1948 *bootscr_flash_offset = 0;
1949 *bootscr_flash_size = 0;
1950
1951 uboot = ofnode_path("/options/u-boot");
1952 if (!ofnode_valid(uboot)) {
Quentin Schulz95a5a2b2024-06-11 15:04:26 +02001953 dm_warn("%s: Missing /u-boot node\n", __func__);
Michal Simek6a7c1ce2023-08-31 09:04:27 +02001954 return -EINVAL;
1955 }
1956
1957 ret = ofnode_read_u64(uboot, "bootscr-flash-offset",
1958 bootscr_flash_offset);
1959 if (ret)
1960 return -EINVAL;
1961
1962 ret = ofnode_read_u64(uboot, "bootscr-flash-size",
1963 bootscr_flash_size);
1964 if (ret)
1965 return -EINVAL;
1966
1967 if (!bootscr_flash_size) {
Quentin Schulz95a5a2b2024-06-11 15:04:26 +02001968 dm_warn("bootscr-flash-size is zero. Ignoring properties!\n");
Michal Simek6a7c1ce2023-08-31 09:04:27 +02001969 *bootscr_flash_offset = 0;
1970 return -EINVAL;
1971 }
1972
1973 return 0;
1974}
1975
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001976ofnode ofnode_get_phy_node(ofnode node)
1977{
1978 /* DT node properties that reference a PHY node */
1979 static const char * const phy_handle_str[] = {
1980 "phy-handle", "phy", "phy-device",
1981 };
1982 struct ofnode_phandle_args args = {
1983 .node = ofnode_null()
1984 };
1985 int i;
1986
1987 assert(ofnode_valid(node));
1988
1989 for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
1990 if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
1991 NULL, 0, 0, &args))
1992 break;
1993
1994 return args.node;
1995}
Marek Behúnbc194772022-04-07 00:33:01 +02001996
1997phy_interface_t ofnode_read_phy_mode(ofnode node)
1998{
1999 const char *mode;
2000 int i;
2001
2002 assert(ofnode_valid(node));
2003
2004 mode = ofnode_read_string(node, "phy-mode");
2005 if (!mode)
2006 mode = ofnode_read_string(node, "phy-connection-type");
2007
2008 if (!mode)
Marek Behún48631e42022-04-07 00:33:03 +02002009 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02002010
Marek Behún21a18362022-04-07 00:33:02 +02002011 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
Marek Behúnbc194772022-04-07 00:33:01 +02002012 if (!strcmp(mode, phy_interface_strings[i]))
2013 return i;
2014
Quentin Schulz95a5a2b2024-06-11 15:04:26 +02002015 dm_warn("%s: Invalid PHY interface '%s'\n", __func__, mode);
Marek Behúnbc194772022-04-07 00:33:01 +02002016
Marek Behún48631e42022-04-07 00:33:03 +02002017 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02002018}
Simon Glass56bc3322022-09-06 20:27:02 -06002019
2020int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
2021{
2022 ofnode subnode;
2023 int ret = 0;
2024
2025 assert(ofnode_valid(node));
2026
2027 if (ofnode_is_np(node)) {
2028 struct device_node *np, *child;
2029
2030 np = (struct device_node *)ofnode_to_np(node);
2031 ret = of_add_subnode(np, name, -1, &child);
2032 if (ret && ret != -EEXIST)
2033 return ret;
2034 subnode = np_to_ofnode(child);
2035 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06002036 void *fdt = ofnode_to_fdt(node);
Simon Glass56bc3322022-09-06 20:27:02 -06002037 int poffset = ofnode_to_offset(node);
2038 int offset;
2039
2040 offset = fdt_add_subnode(fdt, poffset, name);
2041 if (offset == -FDT_ERR_EXISTS) {
2042 offset = fdt_subnode_offset(fdt, poffset, name);
2043 ret = -EEXIST;
2044 }
2045 if (offset < 0)
Simon Glass004f5bd2025-01-10 17:00:10 -07002046 return offset == -FDT_ERR_NOSPACE ? -ENOSPC : -EINVAL;
Simon Glass37dcd912022-09-06 20:27:23 -06002047 subnode = noffset_to_ofnode(node, offset);
Simon Glass56bc3322022-09-06 20:27:02 -06002048 }
2049
2050 *subnodep = subnode;
2051
2052 return ret; /* 0 or -EEXIST */
2053}
Simon Glass7a7229a2022-09-06 20:27:33 -06002054
Simon Glass45448772023-09-26 08:14:42 -06002055int ofnode_delete(ofnode *nodep)
2056{
2057 ofnode node = *nodep;
2058 int ret;
2059
2060 assert(ofnode_valid(node));
2061 if (ofnode_is_np(node)) {
2062 ret = of_remove_node(ofnode_to_np(node));
2063 } else {
2064 void *fdt = ofnode_to_fdt(node);
2065 int offset = ofnode_to_offset(node);
2066
2067 ret = fdt_del_node(fdt, offset);
2068 if (ret)
2069 ret = -EFAULT;
2070 }
2071 if (ret)
2072 return ret;
2073 *nodep = ofnode_null();
2074
2075 return 0;
2076}
2077
Simon Glass68164892023-09-26 08:14:37 -06002078int ofnode_copy_props(ofnode dst, ofnode src)
Simon Glass7a7229a2022-09-06 20:27:33 -06002079{
2080 struct ofprop prop;
2081
2082 ofnode_for_each_prop(prop, src) {
2083 const char *name;
2084 const char *val;
2085 int len, ret;
2086
2087 val = ofprop_get_property(&prop, &name, &len);
2088 if (!val) {
2089 log_debug("Cannot read prop (err=%d)\n", len);
2090 return log_msg_ret("get", -EINVAL);
2091 }
2092 ret = ofnode_write_prop(dst, name, val, len, true);
2093 if (ret) {
2094 log_debug("Cannot write prop (err=%d)\n", ret);
2095 return log_msg_ret("wr", -EINVAL);
2096 }
2097 }
2098
2099 return 0;
2100}
Simon Glass7c33c962023-09-26 08:14:41 -06002101
2102int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src,
2103 ofnode *nodep)
2104{
2105 ofnode node;
2106 int ret;
2107
2108 ret = ofnode_add_subnode(dst_parent, name, &node);
2109 if (ret) {
2110 if (ret == -EEXIST)
2111 *nodep = node;
2112 return log_msg_ret("add", ret);
2113 }
2114 ret = ofnode_copy_props(node, src);
2115 if (ret)
2116 return log_msg_ret("cpy", ret);
2117 *nodep = node;
2118
2119 return 0;
2120}