blob: 4d56b1a7675d75eefce208ba229590aac3d17bd3 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassc4fc5622017-05-18 20:08:58 -06002/*
3 * Copyright (c) 2017 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glassc4fc5622017-05-18 20:08:58 -06005 */
6
Simon Glasscb13a1b2022-09-06 20:27:26 -06007#define LOG_CATEGORY LOGC_DT
8
Simon Glassc4fc5622017-05-18 20:08:58 -06009#include <common.h>
10#include <dm.h>
11#include <fdtdec.h>
12#include <fdt_support.h>
Simon Glass0f2af882020-05-10 11:40:05 -060013#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070014#include <malloc.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090015#include <linux/libfdt.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060016#include <dm/of_access.h>
Simon Glass049ae1b2017-05-18 20:09:01 -060017#include <dm/of_addr.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060018#include <dm/ofnode.h>
19#include <linux/err.h>
Simon Glassf7bfcc42017-07-25 08:29:55 -060020#include <linux/ioport.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060021#include <asm/global_data.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060022
Simon Glasscb13a1b2022-09-06 20:27:26 -060023DECLARE_GLOBAL_DATA_PTR;
24
25#if CONFIG_IS_ENABLED(OFNODE_MULTI_TREE)
26static void *oftree_list[CONFIG_OFNODE_MULTI_TREE_MAX];
27static int oftree_count;
28
29void oftree_reset(void)
30{
31 if (gd->flags & GD_FLG_RELOC) {
32 oftree_count = 0;
33 oftree_list[oftree_count++] = (void *)gd->fdt_blob;
34 }
35}
36
37static int oftree_find(const void *fdt)
38{
39 int i;
40
41 for (i = 0; i < oftree_count; i++) {
42 if (fdt == oftree_list[i])
43 return i;
44 }
45
46 return -1;
47}
48
49static oftree oftree_ensure(void *fdt)
50{
51 oftree tree;
52 int i;
53
54 if (gd->flags & GD_FLG_RELOC) {
55 i = oftree_find(fdt);
56 if (i == -1) {
57 if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) {
58 log_warning("Too many registered device trees (max %d)\n",
59 CONFIG_OFNODE_MULTI_TREE_MAX);
60 return oftree_null();
61 }
62
63 /* register the new tree */
64 i = oftree_count++;
65 oftree_list[i] = fdt;
66 log_debug("oftree: registered tree %d: %p\n", i, fdt);
67 }
68 } else {
69 if (fdt != gd->fdt_blob) {
70 log_debug("Cannot only access control FDT before relocation\n");
71 return oftree_null();
72 }
73 }
74
75 tree.fdt = fdt;
76
77 return tree;
78}
79
80void *ofnode_lookup_fdt(ofnode node)
81{
82 if (gd->flags & GD_FLG_RELOC) {
83 uint i = OFTREE_TREE_ID(node.of_offset);
84
85 if (i > oftree_count) {
86 log_debug("Invalid tree ID %x\n", i);
87 return NULL;
88 }
89
90 return oftree_list[i];
91 } else {
92 return (void *)gd->fdt_blob;
93 }
94}
95
96void *ofnode_to_fdt(ofnode node)
97{
98#ifdef OF_CHECKS
99 if (of_live_active())
100 return NULL;
101#endif
102 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && ofnode_valid(node))
103 return ofnode_lookup_fdt(node);
104
105 /* Use the control FDT by default */
106 return (void *)gd->fdt_blob;
107}
108
Simon Glass45ae59d2022-09-06 20:27:24 -0600109/**
Simon Glasscb13a1b2022-09-06 20:27:26 -0600110 * ofnode_to_offset() - convert an ofnode to a flat DT offset
111 *
112 * This cannot be called if the reference contains a node pointer.
113 *
114 * @node: Reference containing offset (possibly invalid)
115 * Return: DT offset (can be -1)
116 */
117int ofnode_to_offset(ofnode node)
118{
119#ifdef OF_CHECKS
120 if (of_live_active())
121 return -1;
122#endif
123 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && node.of_offset >= 0)
124 return OFTREE_OFFSET(node.of_offset);
125
126 return node.of_offset;
127}
128
129oftree oftree_from_fdt(void *fdt)
130{
131 oftree tree;
132
133 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
134 return oftree_ensure(fdt);
135
136 tree.fdt = fdt;
137
138 return tree;
139}
140
141/**
142 * noffset_to_ofnode() - convert a DT offset to an ofnode
143 *
144 * @other_node: Node in the same tree to use as a reference
145 * @of_offset: DT offset (either valid, or -1)
146 * Return: reference to the associated DT offset
147 */
148ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
149{
150 ofnode node;
151
152 if (of_live_active())
153 node.np = NULL;
154 else if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) || of_offset < 0 ||
155 !ofnode_valid(other_node))
156 node.of_offset = of_offset;
157 else
158 node.of_offset = OFTREE_MAKE_NODE(other_node.of_offset,
159 of_offset);
160
161 return node;
162}
163
164#else /* !OFNODE_MULTI_TREE */
165
166static inline int oftree_find(const void *fdt)
167{
168 return 0;
169}
170
171#endif /* OFNODE_MULTI_TREE */
172
173/**
Simon Glass45ae59d2022-09-06 20:27:24 -0600174 * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
175 *
Simon Glasscb13a1b2022-09-06 20:27:26 -0600176 * Looks up the tree and returns an ofnode with the correct of_offset (i.e.
177 * containing the tree ID).
Simon Glass45ae59d2022-09-06 20:27:24 -0600178 *
Simon Glasscb13a1b2022-09-06 20:27:26 -0600179 * If @offset is < 0 then this returns an ofnode with that offset and no tree
180 * ID.
Simon Glass45ae59d2022-09-06 20:27:24 -0600181 *
182 * @tree: tree to check
183 * @offset: offset within that tree (can be < 0)
Simon Glasscb13a1b2022-09-06 20:27:26 -0600184 * @return node for that offset, with the correct ID
Simon Glass45ae59d2022-09-06 20:27:24 -0600185 */
186static ofnode ofnode_from_tree_offset(oftree tree, int offset)
187{
188 ofnode node;
189
Simon Glasscb13a1b2022-09-06 20:27:26 -0600190 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && offset >= 0) {
191 int tree_id = oftree_find(tree.fdt);
192
193 if (tree_id == -1)
194 return ofnode_null();
195 node.of_offset = OFTREE_NODE(tree_id, offset);
196 } else {
197 node.of_offset = offset;
198 }
Simon Glass45ae59d2022-09-06 20:27:24 -0600199
200 return node;
201}
202
Kishon Vijay Abraham Id6388f22021-07-21 21:28:30 +0530203bool ofnode_name_eq(ofnode node, const char *name)
204{
205 const char *node_name;
206 size_t len;
207
208 assert(ofnode_valid(node));
209
210 node_name = ofnode_get_name(node);
211 len = strchrnul(node_name, '@') - node_name;
212
213 return (strlen(name) == len) && !strncmp(node_name, name, len);
214}
215
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200216int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
217{
218 const u8 *cell;
219 int len;
220
221 assert(ofnode_valid(node));
222 debug("%s: %s: ", __func__, propname);
223
224 if (ofnode_is_np(node))
225 return of_read_u8(ofnode_to_np(node), propname, outp);
226
227 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
228 &len);
229 if (!cell || len < sizeof(*cell)) {
230 debug("(not found)\n");
231 return -EINVAL;
232 }
233 *outp = *cell;
234 debug("%#x (%d)\n", *outp, *outp);
235
236 return 0;
237}
238
239u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
240{
241 assert(ofnode_valid(node));
242 ofnode_read_u8(node, propname, &def);
243
244 return def;
245}
246
247int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
248{
249 const fdt16_t *cell;
250 int len;
251
252 assert(ofnode_valid(node));
253 debug("%s: %s: ", __func__, propname);
254
255 if (ofnode_is_np(node))
256 return of_read_u16(ofnode_to_np(node), propname, outp);
257
258 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
259 &len);
260 if (!cell || len < sizeof(*cell)) {
261 debug("(not found)\n");
262 return -EINVAL;
263 }
264 *outp = be16_to_cpup(cell);
265 debug("%#x (%d)\n", *outp, *outp);
266
267 return 0;
268}
269
270u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def)
271{
272 assert(ofnode_valid(node));
273 ofnode_read_u16(node, propname, &def);
274
275 return def;
276}
277
Simon Glassc4fc5622017-05-18 20:08:58 -0600278int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
279{
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200280 return ofnode_read_u32_index(node, propname, 0, outp);
Simon Glassc4fc5622017-05-18 20:08:58 -0600281}
282
Trent Piepho5b775412019-05-10 17:48:20 +0000283u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
Simon Glassc4fc5622017-05-18 20:08:58 -0600284{
285 assert(ofnode_valid(node));
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200286 ofnode_read_u32_index(node, propname, 0, &def);
Simon Glassc4fc5622017-05-18 20:08:58 -0600287
288 return def;
289}
290
Dario Binacchi81d80b52020-03-29 18:04:41 +0200291int ofnode_read_u32_index(ofnode node, const char *propname, int index,
292 u32 *outp)
293{
294 const fdt32_t *cell;
295 int len;
296
297 assert(ofnode_valid(node));
298 debug("%s: %s: ", __func__, propname);
299
300 if (ofnode_is_np(node))
301 return of_read_u32_index(ofnode_to_np(node), propname, index,
302 outp);
303
Simon Glass04fa09a2022-09-06 20:27:20 -0600304 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
305 propname, &len);
Dario Binacchi81d80b52020-03-29 18:04:41 +0200306 if (!cell) {
307 debug("(not found)\n");
308 return -EINVAL;
309 }
310
311 if (len < (sizeof(int) * (index + 1))) {
312 debug("(not large enough)\n");
313 return -EOVERFLOW;
314 }
315
316 *outp = fdt32_to_cpu(cell[index]);
317 debug("%#x (%d)\n", *outp, *outp);
318
319 return 0;
320}
321
322u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
323 u32 def)
324{
325 assert(ofnode_valid(node));
326 ofnode_read_u32_index(node, propname, index, &def);
327
328 return def;
329}
330
Simon Glassc4fc5622017-05-18 20:08:58 -0600331int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
332{
333 assert(ofnode_valid(node));
334 ofnode_read_u32(node, propname, (u32 *)&def);
335
336 return def;
337}
338
Simon Glass9d54a7a2018-06-11 13:07:10 -0600339int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
340{
Jean-Jacques Hiblot487f9172019-10-22 10:05:22 +0200341 const unaligned_fdt64_t *cell;
Simon Glass9d54a7a2018-06-11 13:07:10 -0600342 int len;
343
344 assert(ofnode_valid(node));
345 debug("%s: %s: ", __func__, propname);
346
347 if (ofnode_is_np(node))
348 return of_read_u64(ofnode_to_np(node), propname, outp);
349
Simon Glass04fa09a2022-09-06 20:27:20 -0600350 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
351 propname, &len);
Simon Glass9d54a7a2018-06-11 13:07:10 -0600352 if (!cell || len < sizeof(*cell)) {
353 debug("(not found)\n");
354 return -EINVAL;
355 }
356 *outp = fdt64_to_cpu(cell[0]);
357 debug("%#llx (%lld)\n", (unsigned long long)*outp,
358 (unsigned long long)*outp);
359
360 return 0;
361}
362
T Karthik Reddy478860d2019-09-02 16:34:30 +0200363u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
Simon Glass9d54a7a2018-06-11 13:07:10 -0600364{
365 assert(ofnode_valid(node));
366 ofnode_read_u64(node, propname, &def);
367
368 return def;
369}
370
Simon Glassc4fc5622017-05-18 20:08:58 -0600371bool ofnode_read_bool(ofnode node, const char *propname)
372{
Masahiro Yamada5d434452017-06-22 16:54:07 +0900373 const void *prop;
Simon Glassc4fc5622017-05-18 20:08:58 -0600374
375 assert(ofnode_valid(node));
376 debug("%s: %s: ", __func__, propname);
377
Masahiro Yamada5d434452017-06-22 16:54:07 +0900378 prop = ofnode_get_property(node, propname, NULL);
379
380 debug("%s\n", prop ? "true" : "false");
Simon Glassc4fc5622017-05-18 20:08:58 -0600381
Masahiro Yamada5d434452017-06-22 16:54:07 +0900382 return prop ? true : false;
Simon Glassc4fc5622017-05-18 20:08:58 -0600383}
384
Simon Glass0c2e9802020-01-27 08:49:44 -0700385const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600386{
Simon Glass0c2e9802020-01-27 08:49:44 -0700387 const char *val = NULL;
388 int len;
Simon Glassc4fc5622017-05-18 20:08:58 -0600389
390 assert(ofnode_valid(node));
391 debug("%s: %s: ", __func__, propname);
392
393 if (ofnode_is_np(node)) {
394 struct property *prop = of_find_property(
Simon Glass0c2e9802020-01-27 08:49:44 -0700395 ofnode_to_np(node), propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600396
397 if (prop) {
Simon Glass0c2e9802020-01-27 08:49:44 -0700398 val = prop->value;
Simon Glassc4fc5622017-05-18 20:08:58 -0600399 len = prop->length;
400 }
401 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600402 val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600403 propname, &len);
404 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700405 if (!val) {
Simon Glassc4fc5622017-05-18 20:08:58 -0600406 debug("<not found>\n");
Simon Glass0c2e9802020-01-27 08:49:44 -0700407 if (sizep)
408 *sizep = -FDT_ERR_NOTFOUND;
Simon Glassc4fc5622017-05-18 20:08:58 -0600409 return NULL;
410 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700411 if (sizep)
412 *sizep = len;
413
414 return val;
415}
416
417const char *ofnode_read_string(ofnode node, const char *propname)
418{
419 const char *str;
420 int len;
421
422 str = ofnode_read_prop(node, propname, &len);
423 if (!str)
424 return NULL;
425
Simon Glassc4fc5622017-05-18 20:08:58 -0600426 if (strnlen(str, len) >= len) {
427 debug("<invalid>\n");
428 return NULL;
429 }
430 debug("%s\n", str);
431
432 return str;
433}
434
Simon Glass81c54b32020-01-27 08:49:45 -0700435int ofnode_read_size(ofnode node, const char *propname)
436{
437 int len;
438
439 if (!ofnode_read_prop(node, propname, &len))
440 return -EINVAL;
441
442 return len;
443}
444
Simon Glassc4fc5622017-05-18 20:08:58 -0600445ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
446{
447 ofnode subnode;
448
449 assert(ofnode_valid(node));
450 debug("%s: %s: ", __func__, subnode_name);
451
452 if (ofnode_is_np(node)) {
Simon Glass9036c5c2022-09-06 20:27:04 -0600453 struct device_node *np = ofnode_to_np(node);
Simon Glassc4fc5622017-05-18 20:08:58 -0600454
455 for (np = np->child; np; np = np->sibling) {
456 if (!strcmp(subnode_name, np->name))
457 break;
458 }
459 subnode = np_to_ofnode(np);
460 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600461 int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600462 ofnode_to_offset(node), subnode_name);
Simon Glass37dcd912022-09-06 20:27:23 -0600463 subnode = noffset_to_ofnode(node, ooffset);
Simon Glassc4fc5622017-05-18 20:08:58 -0600464 }
465 debug("%s\n", ofnode_valid(subnode) ?
466 ofnode_get_name(subnode) : "<none>");
467
468 return subnode;
469}
470
471int ofnode_read_u32_array(ofnode node, const char *propname,
472 u32 *out_values, size_t sz)
473{
474 assert(ofnode_valid(node));
475 debug("%s: %s: ", __func__, propname);
476
477 if (ofnode_is_np(node)) {
478 return of_read_u32_array(ofnode_to_np(node), propname,
479 out_values, sz);
480 } else {
Simon Glasse3be5fc2022-09-06 20:27:18 -0600481 int ret;
482
Simon Glass04fa09a2022-09-06 20:27:20 -0600483 ret = fdtdec_get_int_array(ofnode_to_fdt(node),
Simon Glasse3be5fc2022-09-06 20:27:18 -0600484 ofnode_to_offset(node), propname,
485 out_values, sz);
486
487 /* get the error right, but space is more important in SPL */
488 if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
489 if (ret == -FDT_ERR_NOTFOUND)
490 return -EINVAL;
491 else if (ret == -FDT_ERR_BADLAYOUT)
492 return -EOVERFLOW;
493 }
494 return ret;
Simon Glassc4fc5622017-05-18 20:08:58 -0600495 }
496}
497
Simon Glass39f1d282020-12-16 17:25:06 -0700498#if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
Simon Glass5de5b3b2020-11-28 17:50:02 -0700499bool ofnode_is_enabled(ofnode node)
500{
501 if (ofnode_is_np(node)) {
502 return of_device_is_available(ofnode_to_np(node));
503 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600504 return fdtdec_get_is_enabled(ofnode_to_fdt(node),
Simon Glass5de5b3b2020-11-28 17:50:02 -0700505 ofnode_to_offset(node));
506 }
507}
508
Simon Glassc4fc5622017-05-18 20:08:58 -0600509ofnode ofnode_first_subnode(ofnode node)
510{
511 assert(ofnode_valid(node));
512 if (ofnode_is_np(node))
513 return np_to_ofnode(node.np->child);
514
Simon Glass37dcd912022-09-06 20:27:23 -0600515 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600516 fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600517}
518
519ofnode ofnode_next_subnode(ofnode node)
520{
521 assert(ofnode_valid(node));
522 if (ofnode_is_np(node))
523 return np_to_ofnode(node.np->sibling);
524
Simon Glass37dcd912022-09-06 20:27:23 -0600525 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600526 fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600527}
Simon Glass39f1d282020-12-16 17:25:06 -0700528#endif /* !DM_INLINE_OFNODE */
Simon Glassc4fc5622017-05-18 20:08:58 -0600529
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100530ofnode ofnode_get_parent(ofnode node)
531{
532 ofnode parent;
533
534 assert(ofnode_valid(node));
535 if (ofnode_is_np(node))
536 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
537 else
Simon Glass04fa09a2022-09-06 20:27:20 -0600538 parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100539 ofnode_to_offset(node));
540
541 return parent;
542}
543
Simon Glassc4fc5622017-05-18 20:08:58 -0600544const char *ofnode_get_name(ofnode node)
545{
Kever Yang8d7976d2019-07-19 11:23:47 +0800546 if (!ofnode_valid(node)) {
547 debug("%s node not valid\n", __func__);
548 return NULL;
549 }
550
Simon Glassc4fc5622017-05-18 20:08:58 -0600551 if (ofnode_is_np(node))
Simon Glass91d89a82022-09-06 20:27:15 -0600552 return node.np->name;
Simon Glassc4fc5622017-05-18 20:08:58 -0600553
Simon Glass04fa09a2022-09-06 20:27:20 -0600554 return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600555}
556
Marek Behúne897e3c2021-05-26 14:08:18 +0200557int ofnode_get_path(ofnode node, char *buf, int buflen)
558{
559 assert(ofnode_valid(node));
560
561 if (ofnode_is_np(node)) {
562 if (strlen(node.np->full_name) >= buflen)
563 return -ENOSPC;
564
565 strcpy(buf, node.np->full_name);
566
567 return 0;
568 } else {
569 int res;
570
Simon Glass04fa09a2022-09-06 20:27:20 -0600571 res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
Marek Behúne897e3c2021-05-26 14:08:18 +0200572 buflen);
573 if (!res)
574 return res;
575 else if (res == -FDT_ERR_NOSPACE)
576 return -ENOSPC;
577 else
578 return -EINVAL;
579 }
580}
581
Kever Yang37df0e02018-02-23 17:38:50 +0100582ofnode ofnode_get_by_phandle(uint phandle)
583{
584 ofnode node;
585
586 if (of_live_active())
Simon Glass176dd432022-09-06 20:26:57 -0600587 node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
Kever Yang37df0e02018-02-23 17:38:50 +0100588 else
589 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
590 phandle);
591
592 return node;
593}
594
Simon Glass95fd2092022-09-06 20:27:22 -0600595ofnode oftree_get_by_phandle(oftree tree, uint phandle)
596{
597 ofnode node;
598
599 if (of_live_active())
600 node = np_to_ofnode(of_find_node_by_phandle(tree.np, phandle));
601 else
Simon Glassf912a722022-09-06 20:27:27 -0600602 node = ofnode_from_tree_offset(tree,
Simon Glass95fd2092022-09-06 20:27:22 -0600603 fdt_node_offset_by_phandle(oftree_lookup_fdt(tree),
Simon Glassf912a722022-09-06 20:27:27 -0600604 phandle));
Simon Glass95fd2092022-09-06 20:27:22 -0600605
606 return node;
607}
608
Marek Behún177ab7f2021-05-26 14:08:17 +0200609static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
610 fdt_size_t *size, bool translate)
Simon Glass049ae1b2017-05-18 20:09:01 -0600611{
Keerthy34222a32018-11-19 11:44:47 +0530612 int na, ns;
Keerthy34222a32018-11-19 11:44:47 +0530613
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800614 if (size)
615 *size = FDT_SIZE_T_NONE;
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800616
Simon Glass049ae1b2017-05-18 20:09:01 -0600617 if (ofnode_is_np(node)) {
618 const __be32 *prop_val;
Simon Glass47f85de2019-09-25 08:55:50 -0600619 u64 size64;
Simon Glass049ae1b2017-05-18 20:09:01 -0600620 uint flags;
Simon Glass049ae1b2017-05-18 20:09:01 -0600621
Simon Glass47f85de2019-09-25 08:55:50 -0600622 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
623 &flags);
Simon Glass049ae1b2017-05-18 20:09:01 -0600624 if (!prop_val)
625 return FDT_ADDR_T_NONE;
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800626
Simon Glass47f85de2019-09-25 08:55:50 -0600627 if (size)
628 *size = size64;
Mario Sixd007ebc2017-12-20 09:52:12 +0100629
Mario Six35616ef2018-03-12 14:53:33 +0100630 ns = of_n_size_cells(ofnode_to_np(node));
631
Marek Behún177ab7f2021-05-26 14:08:17 +0200632 if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Sixd007ebc2017-12-20 09:52:12 +0100633 return of_translate_address(ofnode_to_np(node), prop_val);
634 } else {
635 na = of_n_addr_cells(ofnode_to_np(node));
636 return of_read_number(prop_val, na);
637 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600638 } else {
Keerthy34222a32018-11-19 11:44:47 +0530639 na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
640 ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
Simon Glass04fa09a2022-09-06 20:27:20 -0600641 return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
Keerthy34222a32018-11-19 11:44:47 +0530642 ofnode_to_offset(node), "reg",
Marek Behún177ab7f2021-05-26 14:08:17 +0200643 index, na, ns, size,
644 translate);
Simon Glass049ae1b2017-05-18 20:09:01 -0600645 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600646}
647
Marek Behún177ab7f2021-05-26 14:08:17 +0200648fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
649{
650 return __ofnode_get_addr_size_index(node, index, size, true);
651}
652
653fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
654 fdt_size_t *size)
655{
656 return __ofnode_get_addr_size_index(node, index, size, false);
657}
658
Keerthyd332e6e2019-04-24 17:19:53 +0530659fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
660{
661 fdt_size_t size;
662
663 return ofnode_get_addr_size_index(node, index, &size);
664}
665
Simon Glass049ae1b2017-05-18 20:09:01 -0600666fdt_addr_t ofnode_get_addr(ofnode node)
667{
668 return ofnode_get_addr_index(node, 0);
669}
670
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800671fdt_size_t ofnode_get_size(ofnode node)
672{
673 fdt_size_t size;
674
675 ofnode_get_addr_size_index(node, 0, &size);
676
677 return size;
678}
679
Simon Glassc4fc5622017-05-18 20:08:58 -0600680int ofnode_stringlist_search(ofnode node, const char *property,
681 const char *string)
682{
683 if (ofnode_is_np(node)) {
684 return of_property_match_string(ofnode_to_np(node),
685 property, string);
686 } else {
687 int ret;
688
Simon Glass04fa09a2022-09-06 20:27:20 -0600689 ret = fdt_stringlist_search(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600690 ofnode_to_offset(node), property,
691 string);
692 if (ret == -FDT_ERR_NOTFOUND)
693 return -ENODATA;
694 else if (ret < 0)
695 return -EINVAL;
696
697 return ret;
698 }
699}
700
701int ofnode_read_string_index(ofnode node, const char *property, int index,
702 const char **outp)
703{
704 if (ofnode_is_np(node)) {
705 return of_property_read_string_index(ofnode_to_np(node),
706 property, index, outp);
707 } else {
708 int len;
709
Simon Glass04fa09a2022-09-06 20:27:20 -0600710 *outp = fdt_stringlist_get(ofnode_to_fdt(node),
711 ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600712 property, index, &len);
713 if (len < 0)
714 return -EINVAL;
715 return 0;
716 }
717}
718
Simon Glass5fdb0052017-06-12 06:21:28 -0600719int ofnode_read_string_count(ofnode node, const char *property)
720{
721 if (ofnode_is_np(node)) {
722 return of_property_count_strings(ofnode_to_np(node), property);
723 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600724 return fdt_stringlist_count(ofnode_to_fdt(node),
Simon Glass5fdb0052017-06-12 06:21:28 -0600725 ofnode_to_offset(node), property);
726 }
727}
728
Simon Glass9580bfc2021-10-23 17:26:07 -0600729int ofnode_read_string_list(ofnode node, const char *property,
730 const char ***listp)
731{
732 const char **prop;
733 int count;
734 int i;
735
736 *listp = NULL;
737 count = ofnode_read_string_count(node, property);
738 if (count < 0)
739 return count;
740 if (!count)
741 return 0;
742
743 prop = calloc(count + 1, sizeof(char *));
744 if (!prop)
745 return -ENOMEM;
746
747 for (i = 0; i < count; i++)
748 ofnode_read_string_index(node, property, i, &prop[i]);
749 prop[count] = NULL;
750 *listp = prop;
751
752 return count;
753}
754
Simon Glassc4fc5622017-05-18 20:08:58 -0600755static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
756 struct ofnode_phandle_args *out)
757{
758 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
759 out->node = offset_to_ofnode(in->node);
760 out->args_count = in->args_count;
761 memcpy(out->args, in->args, sizeof(out->args));
762}
763
764static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
765 struct ofnode_phandle_args *out)
766{
767 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
768 out->node = np_to_ofnode(in->np);
769 out->args_count = in->args_count;
770 memcpy(out->args, in->args, sizeof(out->args));
771}
772
773int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
774 const char *cells_name, int cell_count,
775 int index,
776 struct ofnode_phandle_args *out_args)
777{
778 if (ofnode_is_np(node)) {
779 struct of_phandle_args args;
780 int ret;
781
782 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay21e3b042020-09-10 18:26:17 +0200783 list_name, cells_name,
784 cell_count, index,
Mario Sixf40d82c2018-01-15 11:07:17 +0100785 &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600786 if (ret)
787 return ret;
788 ofnode_from_of_phandle_args(&args, out_args);
789 } else {
790 struct fdtdec_phandle_args args;
791 int ret;
792
Simon Glass04fa09a2022-09-06 20:27:20 -0600793 ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Mario Sixf40d82c2018-01-15 11:07:17 +0100794 ofnode_to_offset(node),
795 list_name, cells_name,
796 cell_count, index, &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600797 if (ret)
798 return ret;
799 ofnode_from_fdtdec_phandle_args(&args, out_args);
800 }
801
802 return 0;
803}
804
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200805int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200806 const char *cells_name, int cell_count)
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200807{
808 if (ofnode_is_np(node))
809 return of_count_phandle_with_args(ofnode_to_np(node),
Patrick Delaunayd776a842020-09-25 09:41:14 +0200810 list_name, cells_name, cell_count);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200811 else
Simon Glass04fa09a2022-09-06 20:27:20 -0600812 return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200813 ofnode_to_offset(node), list_name, cells_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200814 cell_count, -1, NULL);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200815}
816
Simon Glassc4fc5622017-05-18 20:08:58 -0600817ofnode ofnode_path(const char *path)
818{
819 if (of_live_active())
820 return np_to_ofnode(of_find_node_by_path(path));
821 else
822 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
823}
824
Simon Glass45ae59d2022-09-06 20:27:24 -0600825ofnode oftree_root(oftree tree)
Simon Glassef75c592022-07-30 15:52:08 -0600826{
Simon Glass45ae59d2022-09-06 20:27:24 -0600827 if (of_live_active()) {
828 return np_to_ofnode(tree.np);
829 } else {
830 return ofnode_from_tree_offset(tree, 0);
831 }
832}
833
834ofnode oftree_path(oftree tree, const char *path)
835{
836 if (of_live_active()) {
Simon Glassef75c592022-07-30 15:52:08 -0600837 return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
838 NULL));
Simon Glass45ae59d2022-09-06 20:27:24 -0600839 } else if (*path != '/' && tree.fdt != gd->fdt_blob) {
Simon Glassef75c592022-07-30 15:52:08 -0600840 return ofnode_null(); /* Aliases only on control FDT */
Simon Glass45ae59d2022-09-06 20:27:24 -0600841 } else {
842 int offset = fdt_path_offset(tree.fdt, path);
843
844 return ofnode_from_tree_offset(tree, offset);
845 }
Simon Glassef75c592022-07-30 15:52:08 -0600846}
847
Simon Glasse09223c2020-01-27 08:49:46 -0700848const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600849{
850 ofnode chosen_node;
851
852 chosen_node = ofnode_path("/chosen");
853
Simon Glasse09223c2020-01-27 08:49:46 -0700854 return ofnode_read_prop(chosen_node, propname, sizep);
Simon Glassc4fc5622017-05-18 20:08:58 -0600855}
856
Simon Glasse09223c2020-01-27 08:49:46 -0700857const char *ofnode_read_chosen_string(const char *propname)
858{
859 return ofnode_read_chosen_prop(propname, NULL);
860}
861
Simon Glassc4fc5622017-05-18 20:08:58 -0600862ofnode ofnode_get_chosen_node(const char *name)
863{
864 const char *prop;
865
Simon Glasse09223c2020-01-27 08:49:46 -0700866 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600867 if (!prop)
868 return ofnode_null();
869
870 return ofnode_path(prop);
871}
872
Michal Simek92a88622020-07-28 12:51:08 +0200873const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
874{
875 ofnode node;
876
877 node = ofnode_path("/aliases");
878
879 return ofnode_read_prop(node, propname, sizep);
880}
881
882ofnode ofnode_get_aliases_node(const char *name)
883{
884 const char *prop;
885
886 prop = ofnode_read_aliases_prop(name, NULL);
887 if (!prop)
888 return ofnode_null();
889
890 debug("%s: node_path: %s\n", __func__, prop);
891
892 return ofnode_path(prop);
893}
894
developerd93c8b42020-05-02 11:35:09 +0200895int ofnode_get_child_count(ofnode parent)
896{
897 ofnode child;
898 int num = 0;
899
900 ofnode_for_each_subnode(child, parent)
901 num++;
902
903 return num;
904}
905
Simon Glassc4fc5622017-05-18 20:08:58 -0600906static int decode_timing_property(ofnode node, const char *name,
907 struct timing_entry *result)
908{
909 int length, ret = 0;
910
911 length = ofnode_read_size(node, name);
912 if (length < 0) {
913 debug("%s: could not find property %s\n",
914 ofnode_get_name(node), name);
915 return length;
916 }
917
918 if (length == sizeof(u32)) {
919 result->typ = ofnode_read_u32_default(node, name, 0);
920 result->min = result->typ;
921 result->max = result->typ;
922 } else {
923 ret = ofnode_read_u32_array(node, name, &result->min, 3);
924 }
925
926 return ret;
927}
928
929int ofnode_decode_display_timing(ofnode parent, int index,
930 struct display_timing *dt)
931{
932 int i;
933 ofnode timings, node;
934 u32 val = 0;
935 int ret = 0;
936
937 timings = ofnode_find_subnode(parent, "display-timings");
938 if (!ofnode_valid(timings))
939 return -EINVAL;
940
Simon Glass28529762017-08-05 15:45:54 -0600941 i = 0;
942 ofnode_for_each_subnode(node, timings) {
943 if (i++ == index)
944 break;
945 }
Simon Glassc4fc5622017-05-18 20:08:58 -0600946
947 if (!ofnode_valid(node))
948 return -EINVAL;
949
950 memset(dt, 0, sizeof(*dt));
951
952 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
953 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
954 ret |= decode_timing_property(node, "hactive", &dt->hactive);
955 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
956 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
957 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
958 ret |= decode_timing_property(node, "vactive", &dt->vactive);
959 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
960 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
961
962 dt->flags = 0;
963 val = ofnode_read_u32_default(node, "vsync-active", -1);
964 if (val != -1) {
965 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
966 DISPLAY_FLAGS_VSYNC_LOW;
967 }
968 val = ofnode_read_u32_default(node, "hsync-active", -1);
969 if (val != -1) {
970 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
971 DISPLAY_FLAGS_HSYNC_LOW;
972 }
973 val = ofnode_read_u32_default(node, "de-active", -1);
974 if (val != -1) {
975 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
976 DISPLAY_FLAGS_DE_LOW;
977 }
978 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
979 if (val != -1) {
980 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
981 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
982 }
983
984 if (ofnode_read_bool(node, "interlaced"))
985 dt->flags |= DISPLAY_FLAGS_INTERLACED;
986 if (ofnode_read_bool(node, "doublescan"))
987 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
988 if (ofnode_read_bool(node, "doubleclk"))
989 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
990
991 return ret;
992}
993
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +0900994const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glassc4fc5622017-05-18 20:08:58 -0600995{
Masahiro Yamada5052f1b2017-06-22 16:54:04 +0900996 if (ofnode_is_np(node))
997 return of_get_property(ofnode_to_np(node), propname, lenp);
998 else
Simon Glass04fa09a2022-09-06 20:27:20 -0600999 return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001000 propname, lenp);
Simon Glassc4fc5622017-05-18 20:08:58 -06001001}
1002
Simon Glassfec058d2022-09-06 20:27:13 -06001003int ofnode_first_property(ofnode node, struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001004{
1005 prop->node = node;
1006
1007 if (ofnode_is_np(node)) {
1008 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
1009 if (!prop->prop)
1010 return -FDT_ERR_NOTFOUND;
1011 } else {
1012 prop->offset =
Simon Glass04fa09a2022-09-06 20:27:20 -06001013 fdt_first_property_offset(ofnode_to_fdt(node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001014 ofnode_to_offset(prop->node));
1015 if (prop->offset < 0)
1016 return prop->offset;
1017 }
1018
1019 return 0;
1020}
1021
Simon Glassfec058d2022-09-06 20:27:13 -06001022int ofnode_next_property(struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001023{
1024 if (ofnode_is_np(prop->node)) {
1025 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
1026 prop->prop);
1027 if (!prop->prop)
1028 return -FDT_ERR_NOTFOUND;
1029 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001030 prop->offset =
1031 fdt_next_property_offset(ofnode_to_fdt(prop->node),
1032 prop->offset);
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001033 if (prop->offset < 0)
1034 return prop->offset;
1035 }
1036
1037 return 0;
1038}
1039
Simon Glassd0aff8b2022-09-06 20:27:14 -06001040const void *ofprop_get_property(const struct ofprop *prop,
1041 const char **propname, int *lenp)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001042{
1043 if (ofnode_is_np(prop->node))
1044 return of_get_property_by_prop(ofnode_to_np(prop->node),
1045 prop->prop, propname, lenp);
1046 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001047 return fdt_getprop_by_offset(ofnode_to_fdt(prop->node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001048 prop->offset,
1049 propname, lenp);
1050}
1051
Simon Glassc4fc5622017-05-18 20:08:58 -06001052fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
1053 fdt_size_t *sizep)
1054{
1055 if (ofnode_is_np(node)) {
1056 int na, ns;
1057 int psize;
1058 const struct device_node *np = ofnode_to_np(node);
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001059 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glassc4fc5622017-05-18 20:08:58 -06001060
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001061 if (!prop)
1062 return FDT_ADDR_T_NONE;
Simon Glassc4fc5622017-05-18 20:08:58 -06001063 na = of_n_addr_cells(np);
Marek Vasut1638c172018-10-01 12:37:19 +02001064 ns = of_n_size_cells(np);
Simon Glassa67cc632017-05-18 20:09:27 -06001065 *sizep = of_read_number(prop + na, ns);
Marek Vasuta9dac492018-10-01 12:37:20 +02001066
Dario Binacchif8fc7032021-05-01 17:05:26 +02001067 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta9dac492018-10-01 12:37:20 +02001068 return of_translate_address(np, prop);
1069 else
1070 return of_read_number(prop, na);
Simon Glassc4fc5622017-05-18 20:08:58 -06001071 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001072 return fdtdec_get_addr_size(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001073 ofnode_to_offset(node), property,
1074 sizep);
1075 }
1076}
1077
1078const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
1079 size_t sz)
1080{
1081 if (ofnode_is_np(node)) {
1082 const struct device_node *np = ofnode_to_np(node);
1083 int psize;
1084 const __be32 *prop = of_get_property(np, propname, &psize);
1085
1086 if (!prop || sz != psize)
1087 return NULL;
1088 return (uint8_t *)prop;
1089
1090 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001091 return fdtdec_locate_byte_array(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001092 ofnode_to_offset(node), propname, sz);
1093 }
1094}
1095
1096int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
1097 const char *propname, struct fdt_pci_addr *addr)
1098{
Masahiro Yamada5c5991e2017-06-22 17:57:50 +09001099 const fdt32_t *cell;
Simon Glassc4fc5622017-05-18 20:08:58 -06001100 int len;
1101 int ret = -ENOENT;
1102
1103 debug("%s: %s: ", __func__, propname);
1104
1105 /*
1106 * If we follow the pci bus bindings strictly, we should check
1107 * the value of the node's parent node's #address-cells and
1108 * #size-cells. They need to be 3 and 2 accordingly. However,
1109 * for simplicity we skip the check here.
1110 */
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +09001111 cell = ofnode_get_property(node, propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -06001112 if (!cell)
1113 goto fail;
1114
1115 if ((len % FDT_PCI_REG_SIZE) == 0) {
1116 int num = len / FDT_PCI_REG_SIZE;
1117 int i;
1118
1119 for (i = 0; i < num; i++) {
1120 debug("pci address #%d: %08lx %08lx %08lx\n", i,
1121 (ulong)fdt32_to_cpu(cell[0]),
1122 (ulong)fdt32_to_cpu(cell[1]),
1123 (ulong)fdt32_to_cpu(cell[2]));
1124 if ((fdt32_to_cpu(*cell) & type) == type) {
1125 addr->phys_hi = fdt32_to_cpu(cell[0]);
1126 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glassdfd43152019-09-25 08:55:46 -06001127 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glassc4fc5622017-05-18 20:08:58 -06001128 break;
Simon Glassc4fc5622017-05-18 20:08:58 -06001129 }
Mario Sixf40d82c2018-01-15 11:07:17 +01001130
1131 cell += (FDT_PCI_ADDR_CELLS +
1132 FDT_PCI_SIZE_CELLS);
Simon Glassc4fc5622017-05-18 20:08:58 -06001133 }
1134
1135 if (i == num) {
1136 ret = -ENXIO;
1137 goto fail;
1138 }
1139
1140 return 0;
Simon Glassc4fc5622017-05-18 20:08:58 -06001141 }
1142
Mario Sixf40d82c2018-01-15 11:07:17 +01001143 ret = -EINVAL;
1144
Simon Glassc4fc5622017-05-18 20:08:58 -06001145fail:
1146 debug("(not found)\n");
1147 return ret;
1148}
1149
Bin Mengfa157712018-08-03 01:14:35 -07001150int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
1151{
1152 const char *list, *end;
1153 int len;
1154
1155 list = ofnode_get_property(node, "compatible", &len);
1156 if (!list)
1157 return -ENOENT;
1158
1159 end = list + len;
1160 while (list < end) {
1161 len = strlen(list);
1162 if (len >= strlen("pciVVVV,DDDD")) {
1163 char *s = strstr(list, "pci");
1164
1165 /*
1166 * check if the string is something like pciVVVV,DDDD.RR
1167 * or just pciVVVV,DDDD
1168 */
1169 if (s && s[7] == ',' &&
1170 (s[12] == '.' || s[12] == 0)) {
1171 s += 3;
1172 *vendor = simple_strtol(s, NULL, 16);
1173
1174 s += 5;
1175 *device = simple_strtol(s, NULL, 16);
1176
1177 return 0;
1178 }
1179 }
1180 list += (len + 1);
1181 }
1182
1183 return -ENOENT;
1184}
1185
Michal Simeka253c3b2022-02-23 15:45:40 +01001186int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
1187{
1188 const char *list, *end;
1189 int len;
1190
1191 list = ofnode_get_property(node, "compatible", &len);
1192
1193 if (!list)
1194 return -ENOENT;
1195
1196 end = list + len;
1197 while (list < end) {
1198 len = strlen(list);
1199
Michal Simekc633cdf2022-10-31 17:08:44 -07001200 if (len >= strlen("ethernet-phy-idVVVV.DDDD")) {
Michal Simeka253c3b2022-02-23 15:45:40 +01001201 char *s = strstr(list, "ethernet-phy-id");
1202
1203 /*
1204 * check if the string is something like
Michal Simekc633cdf2022-10-31 17:08:44 -07001205 * ethernet-phy-idVVVV.DDDD
Michal Simeka253c3b2022-02-23 15:45:40 +01001206 */
1207 if (s && s[19] == '.') {
1208 s += strlen("ethernet-phy-id");
1209 *vendor = simple_strtol(s, NULL, 16);
1210 s += 5;
1211 *device = simple_strtol(s, NULL, 16);
1212
1213 return 0;
1214 }
1215 }
1216 list += (len + 1);
1217 }
1218
1219 return -ENOENT;
1220}
1221
Simon Glassc4fc5622017-05-18 20:08:58 -06001222int ofnode_read_addr_cells(ofnode node)
1223{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001224 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001225 return of_n_addr_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001226 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001227 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001228 ofnode_to_offset(node));
1229
Simon Glass04fa09a2022-09-06 20:27:20 -06001230 return fdt_address_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001231 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001232}
1233
1234int ofnode_read_size_cells(ofnode node)
1235{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001236 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001237 return of_n_size_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001238 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001239 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001240 ofnode_to_offset(node));
1241
Simon Glass04fa09a2022-09-06 20:27:20 -06001242 return fdt_size_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001243 }
Simon Glass4191dc12017-06-12 06:21:31 -06001244}
1245
1246int ofnode_read_simple_addr_cells(ofnode node)
1247{
1248 if (ofnode_is_np(node))
1249 return of_simple_addr_cells(ofnode_to_np(node));
1250 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001251 return fdt_address_cells(ofnode_to_fdt(node),
1252 ofnode_to_offset(node));
Simon Glass4191dc12017-06-12 06:21:31 -06001253}
1254
1255int ofnode_read_simple_size_cells(ofnode node)
1256{
1257 if (ofnode_is_np(node))
1258 return of_simple_size_cells(ofnode_to_np(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001259 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001260 return fdt_size_cells(ofnode_to_fdt(node),
1261 ofnode_to_offset(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001262}
1263
1264bool ofnode_pre_reloc(ofnode node)
1265{
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001266#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
1267 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
1268 * had property dm-pre-reloc or u-boot,dm-spl/tpl.
1269 * They are removed in final dtb (fdtgrep 2nd pass)
1270 */
1271 return true;
1272#else
Masahiro Yamada6a61dd92017-06-22 16:54:03 +09001273 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001274 return true;
Simon Glass23f22842018-10-01 12:22:18 -06001275 if (ofnode_read_bool(node, "u-boot,dm-pre-proper"))
1276 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001277
Simon Glassc4fc5622017-05-18 20:08:58 -06001278 /*
1279 * In regular builds individual spl and tpl handling both
1280 * count as handled pre-relocation for later second init.
1281 */
Masahiro Yamada6a61dd92017-06-22 16:54:03 +09001282 if (ofnode_read_bool(node, "u-boot,dm-spl") ||
1283 ofnode_read_bool(node, "u-boot,dm-tpl"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001284 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001285
1286 return false;
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001287#endif
Simon Glassc4fc5622017-05-18 20:08:58 -06001288}
Simon Glassf7bfcc42017-07-25 08:29:55 -06001289
1290int ofnode_read_resource(ofnode node, uint index, struct resource *res)
1291{
1292 if (ofnode_is_np(node)) {
1293 return of_address_to_resource(ofnode_to_np(node), index, res);
1294 } else {
1295 struct fdt_resource fres;
1296 int ret;
1297
Simon Glass04fa09a2022-09-06 20:27:20 -06001298 ret = fdt_get_resource(ofnode_to_fdt(node),
1299 ofnode_to_offset(node),
Simon Glassf7bfcc42017-07-25 08:29:55 -06001300 "reg", index, &fres);
1301 if (ret < 0)
1302 return -EINVAL;
1303 memset(res, '\0', sizeof(*res));
1304 res->start = fres.start;
1305 res->end = fres.end;
1306
1307 return 0;
1308 }
1309}
Masahiro Yamada4dada2c2017-08-26 01:12:30 +09001310
1311int ofnode_read_resource_byname(ofnode node, const char *name,
1312 struct resource *res)
1313{
1314 int index;
1315
1316 index = ofnode_stringlist_search(node, "reg-names", name);
1317 if (index < 0)
1318 return index;
1319
1320 return ofnode_read_resource(node, index, res);
1321}
Mario Sixaefac062018-01-15 11:07:19 +01001322
1323u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
1324{
1325 if (ofnode_is_np(node))
1326 return of_translate_address(ofnode_to_np(node), in_addr);
1327 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001328 return fdt_translate_address(ofnode_to_fdt(node),
1329 ofnode_to_offset(node), in_addr);
Mario Sixaefac062018-01-15 11:07:19 +01001330}
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001331
Fabien Dessenne22236e02019-05-31 15:11:30 +02001332u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
1333{
1334 if (ofnode_is_np(node))
1335 return of_translate_dma_address(ofnode_to_np(node), in_addr);
1336 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001337 return fdt_translate_dma_address(ofnode_to_fdt(node),
1338 ofnode_to_offset(node), in_addr);
Fabien Dessenne22236e02019-05-31 15:11:30 +02001339}
1340
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001341int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
1342{
1343 if (ofnode_is_np(node))
1344 return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
1345 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001346 return fdt_get_dma_range(ofnode_to_fdt(node),
1347 ofnode_to_offset(node),
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001348 cpu, bus, size);
1349}
1350
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001351int ofnode_device_is_compatible(ofnode node, const char *compat)
1352{
1353 if (ofnode_is_np(node))
1354 return of_device_is_compatible(ofnode_to_np(node), compat,
1355 NULL, NULL);
1356 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001357 return !fdt_node_check_compatible(ofnode_to_fdt(node),
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001358 ofnode_to_offset(node),
1359 compat);
1360}
Simon Glass954eeae2018-06-11 13:07:13 -06001361
1362ofnode ofnode_by_compatible(ofnode from, const char *compat)
1363{
1364 if (of_live_active()) {
1365 return np_to_ofnode(of_find_compatible_node(
1366 (struct device_node *)ofnode_to_np(from), NULL,
1367 compat));
1368 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001369 return noffset_to_ofnode(from,
1370 fdt_node_offset_by_compatible(ofnode_to_fdt(from),
Simon Glass04fa09a2022-09-06 20:27:20 -06001371 ofnode_to_offset(from), compat));
Simon Glass954eeae2018-06-11 13:07:13 -06001372 }
1373}
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001374
1375ofnode ofnode_by_prop_value(ofnode from, const char *propname,
1376 const void *propval, int proplen)
1377{
1378 if (of_live_active()) {
1379 return np_to_ofnode(of_find_node_by_prop_value(
1380 (struct device_node *)ofnode_to_np(from), propname,
1381 propval, proplen));
1382 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001383 return noffset_to_ofnode(from,
1384 fdt_node_offset_by_prop_value(ofnode_to_fdt(from),
1385 ofnode_to_offset(from), propname, propval,
1386 proplen));
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001387 }
1388}
Mario Six047dafc2018-06-26 08:46:48 +02001389
Simon Glass5e2cd5e2022-07-30 15:52:10 -06001390int ofnode_write_prop(ofnode node, const char *propname, const void *value,
Simon Glass17abed02022-09-06 20:27:32 -06001391 int len, bool copy)
Mario Six047dafc2018-06-26 08:46:48 +02001392{
Simon Glass17abed02022-09-06 20:27:32 -06001393 if (of_live_active()) {
1394 void *newval;
1395 int ret;
1396
1397 if (copy) {
1398 newval = malloc(len);
1399 if (!newval)
1400 return log_ret(-ENOMEM);
1401 memcpy(newval, value, len);
1402 value = newval;
1403 }
1404 ret = of_write_prop(ofnode_to_np(node), propname, len, value);
1405 if (ret && copy)
1406 free(newval);
1407 return ret;
1408 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001409 return fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glass3ee3d152022-07-30 15:52:13 -06001410 propname, value, len);
Simon Glass17abed02022-09-06 20:27:32 -06001411 }
Mario Six047dafc2018-06-26 08:46:48 +02001412}
1413
1414int ofnode_write_string(ofnode node, const char *propname, const char *value)
1415{
Mario Six047dafc2018-06-26 08:46:48 +02001416 assert(ofnode_valid(node));
1417
1418 debug("%s: %s = %s", __func__, propname, value);
1419
Simon Glass17abed02022-09-06 20:27:32 -06001420 return ofnode_write_prop(node, propname, value, strlen(value) + 1,
1421 false);
Mario Six047dafc2018-06-26 08:46:48 +02001422}
1423
Simon Glassd28e31e2022-07-30 15:52:14 -06001424int ofnode_write_u32(ofnode node, const char *propname, u32 value)
1425{
1426 fdt32_t *val;
1427
1428 assert(ofnode_valid(node));
1429
1430 log_debug("%s = %x", propname, value);
1431 val = malloc(sizeof(*val));
1432 if (!val)
1433 return -ENOMEM;
1434 *val = cpu_to_fdt32(value);
1435
Simon Glass17abed02022-09-06 20:27:32 -06001436 return ofnode_write_prop(node, propname, val, sizeof(value), false);
Simon Glassd28e31e2022-07-30 15:52:14 -06001437}
1438
Mario Six047dafc2018-06-26 08:46:48 +02001439int ofnode_set_enabled(ofnode node, bool value)
1440{
Mario Six047dafc2018-06-26 08:46:48 +02001441 assert(ofnode_valid(node));
1442
1443 if (value)
1444 return ofnode_write_string(node, "status", "okay");
1445 else
Bin Menga9274aa2019-07-05 09:23:17 -07001446 return ofnode_write_string(node, "status", "disabled");
Mario Six047dafc2018-06-26 08:46:48 +02001447}
Simon Glass0034d962021-08-07 07:24:01 -06001448
1449bool ofnode_conf_read_bool(const char *prop_name)
1450{
1451 ofnode node;
1452
1453 node = ofnode_path("/config");
1454 if (!ofnode_valid(node))
1455 return false;
1456
1457 return ofnode_read_bool(node, prop_name);
1458}
1459
1460int ofnode_conf_read_int(const char *prop_name, int default_val)
1461{
1462 ofnode node;
1463
1464 node = ofnode_path("/config");
1465 if (!ofnode_valid(node))
1466 return default_val;
1467
1468 return ofnode_read_u32_default(node, prop_name, default_val);
1469}
1470
1471const char *ofnode_conf_read_str(const char *prop_name)
1472{
1473 ofnode node;
1474
1475 node = ofnode_path("/config");
1476 if (!ofnode_valid(node))
1477 return NULL;
1478
1479 return ofnode_read_string(node, prop_name);
1480}
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001481
1482ofnode ofnode_get_phy_node(ofnode node)
1483{
1484 /* DT node properties that reference a PHY node */
1485 static const char * const phy_handle_str[] = {
1486 "phy-handle", "phy", "phy-device",
1487 };
1488 struct ofnode_phandle_args args = {
1489 .node = ofnode_null()
1490 };
1491 int i;
1492
1493 assert(ofnode_valid(node));
1494
1495 for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
1496 if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
1497 NULL, 0, 0, &args))
1498 break;
1499
1500 return args.node;
1501}
Marek Behúnbc194772022-04-07 00:33:01 +02001502
1503phy_interface_t ofnode_read_phy_mode(ofnode node)
1504{
1505 const char *mode;
1506 int i;
1507
1508 assert(ofnode_valid(node));
1509
1510 mode = ofnode_read_string(node, "phy-mode");
1511 if (!mode)
1512 mode = ofnode_read_string(node, "phy-connection-type");
1513
1514 if (!mode)
Marek Behún48631e42022-04-07 00:33:03 +02001515 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001516
Marek Behún21a18362022-04-07 00:33:02 +02001517 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
Marek Behúnbc194772022-04-07 00:33:01 +02001518 if (!strcmp(mode, phy_interface_strings[i]))
1519 return i;
1520
1521 debug("%s: Invalid PHY interface '%s'\n", __func__, mode);
1522
Marek Behún48631e42022-04-07 00:33:03 +02001523 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001524}
Simon Glass56bc3322022-09-06 20:27:02 -06001525
1526int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
1527{
1528 ofnode subnode;
1529 int ret = 0;
1530
1531 assert(ofnode_valid(node));
1532
1533 if (ofnode_is_np(node)) {
1534 struct device_node *np, *child;
1535
1536 np = (struct device_node *)ofnode_to_np(node);
1537 ret = of_add_subnode(np, name, -1, &child);
1538 if (ret && ret != -EEXIST)
1539 return ret;
1540 subnode = np_to_ofnode(child);
1541 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001542 void *fdt = ofnode_to_fdt(node);
Simon Glass56bc3322022-09-06 20:27:02 -06001543 int poffset = ofnode_to_offset(node);
1544 int offset;
1545
1546 offset = fdt_add_subnode(fdt, poffset, name);
1547 if (offset == -FDT_ERR_EXISTS) {
1548 offset = fdt_subnode_offset(fdt, poffset, name);
1549 ret = -EEXIST;
1550 }
1551 if (offset < 0)
1552 return -EINVAL;
Simon Glass37dcd912022-09-06 20:27:23 -06001553 subnode = noffset_to_ofnode(node, offset);
Simon Glass56bc3322022-09-06 20:27:02 -06001554 }
1555
1556 *subnodep = subnode;
1557
1558 return ret; /* 0 or -EEXIST */
1559}
Simon Glass7a7229a2022-09-06 20:27:33 -06001560
1561int ofnode_copy_props(ofnode src, ofnode dst)
1562{
1563 struct ofprop prop;
1564
1565 ofnode_for_each_prop(prop, src) {
1566 const char *name;
1567 const char *val;
1568 int len, ret;
1569
1570 val = ofprop_get_property(&prop, &name, &len);
1571 if (!val) {
1572 log_debug("Cannot read prop (err=%d)\n", len);
1573 return log_msg_ret("get", -EINVAL);
1574 }
1575 ret = ofnode_write_prop(dst, name, val, len, true);
1576 if (ret) {
1577 log_debug("Cannot write prop (err=%d)\n", ret);
1578 return log_msg_ret("wr", -EINVAL);
1579 }
1580 }
1581
1582 return 0;
1583}