blob: dee890b5527bcb4db6cacc9ec81223eb69f0902d [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
Simon Glass994048b2023-06-01 10:22:31 -060063 if (of_live_active()) {
64 log_err("Cannot register a flattree when OF_LIVE is active\n");
65 return oftree_null();
66 }
67
Simon Glasscb13a1b2022-09-06 20:27:26 -060068 /* register the new tree */
69 i = oftree_count++;
70 oftree_list[i] = fdt;
71 log_debug("oftree: registered tree %d: %p\n", i, fdt);
72 }
73 } else {
74 if (fdt != gd->fdt_blob) {
Simon Glass67f8e112023-06-01 10:22:41 -060075 log_debug("Only the control FDT can be accessed before relocation\n");
Simon Glasscb13a1b2022-09-06 20:27:26 -060076 return oftree_null();
77 }
78 }
79
80 tree.fdt = fdt;
81
82 return tree;
83}
84
85void *ofnode_lookup_fdt(ofnode node)
86{
87 if (gd->flags & GD_FLG_RELOC) {
88 uint i = OFTREE_TREE_ID(node.of_offset);
89
90 if (i > oftree_count) {
91 log_debug("Invalid tree ID %x\n", i);
92 return NULL;
93 }
94
95 return oftree_list[i];
96 } else {
97 return (void *)gd->fdt_blob;
98 }
99}
100
101void *ofnode_to_fdt(ofnode node)
102{
103#ifdef OF_CHECKS
104 if (of_live_active())
105 return NULL;
106#endif
107 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && ofnode_valid(node))
108 return ofnode_lookup_fdt(node);
109
110 /* Use the control FDT by default */
111 return (void *)gd->fdt_blob;
112}
113
Simon Glass45ae59d2022-09-06 20:27:24 -0600114/**
Simon Glasscb13a1b2022-09-06 20:27:26 -0600115 * ofnode_to_offset() - convert an ofnode to a flat DT offset
116 *
117 * This cannot be called if the reference contains a node pointer.
118 *
119 * @node: Reference containing offset (possibly invalid)
120 * Return: DT offset (can be -1)
121 */
122int ofnode_to_offset(ofnode node)
123{
124#ifdef OF_CHECKS
125 if (of_live_active())
126 return -1;
127#endif
128 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && node.of_offset >= 0)
129 return OFTREE_OFFSET(node.of_offset);
130
131 return node.of_offset;
132}
133
134oftree oftree_from_fdt(void *fdt)
135{
136 oftree tree;
137
138 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
139 return oftree_ensure(fdt);
140
Simon Glass994048b2023-06-01 10:22:31 -0600141#ifdef OF_CHECKS
142 if (of_live_active())
143 return oftree_null();
144#endif
Simon Glasscb13a1b2022-09-06 20:27:26 -0600145 tree.fdt = fdt;
146
147 return tree;
148}
149
150/**
151 * noffset_to_ofnode() - convert a DT offset to an ofnode
152 *
153 * @other_node: Node in the same tree to use as a reference
154 * @of_offset: DT offset (either valid, or -1)
155 * Return: reference to the associated DT offset
156 */
157ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
158{
159 ofnode node;
160
161 if (of_live_active())
162 node.np = NULL;
163 else if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) || of_offset < 0 ||
164 !ofnode_valid(other_node))
165 node.of_offset = of_offset;
166 else
167 node.of_offset = OFTREE_MAKE_NODE(other_node.of_offset,
168 of_offset);
169
170 return node;
171}
172
173#else /* !OFNODE_MULTI_TREE */
174
175static inline int oftree_find(const void *fdt)
176{
177 return 0;
178}
179
180#endif /* OFNODE_MULTI_TREE */
181
182/**
Simon Glass45ae59d2022-09-06 20:27:24 -0600183 * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
184 *
Simon Glasscb13a1b2022-09-06 20:27:26 -0600185 * Looks up the tree and returns an ofnode with the correct of_offset (i.e.
186 * containing the tree ID).
Simon Glass45ae59d2022-09-06 20:27:24 -0600187 *
Simon Glasscb13a1b2022-09-06 20:27:26 -0600188 * If @offset is < 0 then this returns an ofnode with that offset and no tree
189 * ID.
Simon Glass45ae59d2022-09-06 20:27:24 -0600190 *
191 * @tree: tree to check
192 * @offset: offset within that tree (can be < 0)
Simon Glasscb13a1b2022-09-06 20:27:26 -0600193 * @return node for that offset, with the correct ID
Simon Glass45ae59d2022-09-06 20:27:24 -0600194 */
195static ofnode ofnode_from_tree_offset(oftree tree, int offset)
196{
197 ofnode node;
198
Simon Glasscb13a1b2022-09-06 20:27:26 -0600199 if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && offset >= 0) {
200 int tree_id = oftree_find(tree.fdt);
201
202 if (tree_id == -1)
203 return ofnode_null();
204 node.of_offset = OFTREE_NODE(tree_id, offset);
205 } else {
206 node.of_offset = offset;
207 }
Simon Glass45ae59d2022-09-06 20:27:24 -0600208
209 return node;
210}
211
Kishon Vijay Abraham Id6388f22021-07-21 21:28:30 +0530212bool ofnode_name_eq(ofnode node, const char *name)
213{
214 const char *node_name;
215 size_t len;
216
217 assert(ofnode_valid(node));
218
219 node_name = ofnode_get_name(node);
220 len = strchrnul(node_name, '@') - node_name;
221
222 return (strlen(name) == len) && !strncmp(node_name, name, len);
223}
224
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +0200225int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
226{
227 const u8 *cell;
228 int len;
229
230 assert(ofnode_valid(node));
231 debug("%s: %s: ", __func__, propname);
232
233 if (ofnode_is_np(node))
234 return of_read_u8(ofnode_to_np(node), propname, outp);
235
236 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
237 &len);
238 if (!cell || len < sizeof(*cell)) {
239 debug("(not found)\n");
240 return -EINVAL;
241 }
242 *outp = *cell;
243 debug("%#x (%d)\n", *outp, *outp);
244
245 return 0;
246}
247
248u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
249{
250 assert(ofnode_valid(node));
251 ofnode_read_u8(node, propname, &def);
252
253 return def;
254}
255
256int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
257{
258 const fdt16_t *cell;
259 int len;
260
261 assert(ofnode_valid(node));
262 debug("%s: %s: ", __func__, propname);
263
264 if (ofnode_is_np(node))
265 return of_read_u16(ofnode_to_np(node), propname, outp);
266
267 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
268 &len);
269 if (!cell || len < sizeof(*cell)) {
270 debug("(not found)\n");
271 return -EINVAL;
272 }
273 *outp = be16_to_cpup(cell);
274 debug("%#x (%d)\n", *outp, *outp);
275
276 return 0;
277}
278
279u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def)
280{
281 assert(ofnode_valid(node));
282 ofnode_read_u16(node, propname, &def);
283
284 return def;
285}
286
Simon Glassc4fc5622017-05-18 20:08:58 -0600287int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
288{
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200289 return ofnode_read_u32_index(node, propname, 0, outp);
Simon Glassc4fc5622017-05-18 20:08:58 -0600290}
291
Trent Piepho5b775412019-05-10 17:48:20 +0000292u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
Simon Glassc4fc5622017-05-18 20:08:58 -0600293{
294 assert(ofnode_valid(node));
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200295 ofnode_read_u32_index(node, propname, 0, &def);
Simon Glassc4fc5622017-05-18 20:08:58 -0600296
297 return def;
298}
299
Dario Binacchi81d80b52020-03-29 18:04:41 +0200300int ofnode_read_u32_index(ofnode node, const char *propname, int index,
301 u32 *outp)
302{
303 const fdt32_t *cell;
304 int len;
305
306 assert(ofnode_valid(node));
307 debug("%s: %s: ", __func__, propname);
308
309 if (ofnode_is_np(node))
310 return of_read_u32_index(ofnode_to_np(node), propname, index,
311 outp);
312
Simon Glass04fa09a2022-09-06 20:27:20 -0600313 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
314 propname, &len);
Dario Binacchi81d80b52020-03-29 18:04:41 +0200315 if (!cell) {
316 debug("(not found)\n");
317 return -EINVAL;
318 }
319
320 if (len < (sizeof(int) * (index + 1))) {
321 debug("(not large enough)\n");
322 return -EOVERFLOW;
323 }
324
325 *outp = fdt32_to_cpu(cell[index]);
326 debug("%#x (%d)\n", *outp, *outp);
327
328 return 0;
329}
330
331u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
332 u32 def)
333{
334 assert(ofnode_valid(node));
335 ofnode_read_u32_index(node, propname, index, &def);
336
337 return def;
338}
339
Simon Glassc4fc5622017-05-18 20:08:58 -0600340int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
341{
342 assert(ofnode_valid(node));
343 ofnode_read_u32(node, propname, (u32 *)&def);
344
345 return def;
346}
347
Simon Glass9d54a7a2018-06-11 13:07:10 -0600348int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
349{
Jean-Jacques Hiblot487f9172019-10-22 10:05:22 +0200350 const unaligned_fdt64_t *cell;
Simon Glass9d54a7a2018-06-11 13:07:10 -0600351 int len;
352
353 assert(ofnode_valid(node));
354 debug("%s: %s: ", __func__, propname);
355
356 if (ofnode_is_np(node))
357 return of_read_u64(ofnode_to_np(node), propname, outp);
358
Simon Glass04fa09a2022-09-06 20:27:20 -0600359 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
360 propname, &len);
Simon Glass9d54a7a2018-06-11 13:07:10 -0600361 if (!cell || len < sizeof(*cell)) {
362 debug("(not found)\n");
363 return -EINVAL;
364 }
365 *outp = fdt64_to_cpu(cell[0]);
366 debug("%#llx (%lld)\n", (unsigned long long)*outp,
367 (unsigned long long)*outp);
368
369 return 0;
370}
371
T Karthik Reddy478860d2019-09-02 16:34:30 +0200372u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
Simon Glass9d54a7a2018-06-11 13:07:10 -0600373{
374 assert(ofnode_valid(node));
375 ofnode_read_u64(node, propname, &def);
376
377 return def;
378}
379
Simon Glassc4fc5622017-05-18 20:08:58 -0600380bool ofnode_read_bool(ofnode node, const char *propname)
381{
Masahiro Yamada5d434452017-06-22 16:54:07 +0900382 const void *prop;
Simon Glassc4fc5622017-05-18 20:08:58 -0600383
384 assert(ofnode_valid(node));
385 debug("%s: %s: ", __func__, propname);
386
Masahiro Yamada5d434452017-06-22 16:54:07 +0900387 prop = ofnode_get_property(node, propname, NULL);
388
389 debug("%s\n", prop ? "true" : "false");
Simon Glassc4fc5622017-05-18 20:08:58 -0600390
Masahiro Yamada5d434452017-06-22 16:54:07 +0900391 return prop ? true : false;
Simon Glassc4fc5622017-05-18 20:08:58 -0600392}
393
Simon Glass0c2e9802020-01-27 08:49:44 -0700394const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600395{
Simon Glass0c2e9802020-01-27 08:49:44 -0700396 const char *val = NULL;
397 int len;
Simon Glassc4fc5622017-05-18 20:08:58 -0600398
399 assert(ofnode_valid(node));
400 debug("%s: %s: ", __func__, propname);
401
402 if (ofnode_is_np(node)) {
403 struct property *prop = of_find_property(
Simon Glass0c2e9802020-01-27 08:49:44 -0700404 ofnode_to_np(node), propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600405
406 if (prop) {
Simon Glass0c2e9802020-01-27 08:49:44 -0700407 val = prop->value;
Simon Glassc4fc5622017-05-18 20:08:58 -0600408 len = prop->length;
409 }
410 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600411 val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600412 propname, &len);
413 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700414 if (!val) {
Simon Glassc4fc5622017-05-18 20:08:58 -0600415 debug("<not found>\n");
Simon Glass0c2e9802020-01-27 08:49:44 -0700416 if (sizep)
417 *sizep = -FDT_ERR_NOTFOUND;
Simon Glassc4fc5622017-05-18 20:08:58 -0600418 return NULL;
419 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700420 if (sizep)
421 *sizep = len;
422
423 return val;
424}
425
426const char *ofnode_read_string(ofnode node, const char *propname)
427{
428 const char *str;
429 int len;
430
431 str = ofnode_read_prop(node, propname, &len);
432 if (!str)
433 return NULL;
434
Simon Glassc4fc5622017-05-18 20:08:58 -0600435 if (strnlen(str, len) >= len) {
436 debug("<invalid>\n");
437 return NULL;
438 }
439 debug("%s\n", str);
440
441 return str;
442}
443
Simon Glass81c54b32020-01-27 08:49:45 -0700444int ofnode_read_size(ofnode node, const char *propname)
445{
446 int len;
447
448 if (!ofnode_read_prop(node, propname, &len))
449 return -EINVAL;
450
451 return len;
452}
453
Simon Glassc4fc5622017-05-18 20:08:58 -0600454ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
455{
456 ofnode subnode;
457
458 assert(ofnode_valid(node));
459 debug("%s: %s: ", __func__, subnode_name);
460
461 if (ofnode_is_np(node)) {
Simon Glass9036c5c2022-09-06 20:27:04 -0600462 struct device_node *np = ofnode_to_np(node);
Simon Glassc4fc5622017-05-18 20:08:58 -0600463
464 for (np = np->child; np; np = np->sibling) {
465 if (!strcmp(subnode_name, np->name))
466 break;
467 }
468 subnode = np_to_ofnode(np);
469 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600470 int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600471 ofnode_to_offset(node), subnode_name);
Simon Glass37dcd912022-09-06 20:27:23 -0600472 subnode = noffset_to_ofnode(node, ooffset);
Simon Glassc4fc5622017-05-18 20:08:58 -0600473 }
474 debug("%s\n", ofnode_valid(subnode) ?
475 ofnode_get_name(subnode) : "<none>");
476
477 return subnode;
478}
479
480int ofnode_read_u32_array(ofnode node, const char *propname,
481 u32 *out_values, size_t sz)
482{
483 assert(ofnode_valid(node));
484 debug("%s: %s: ", __func__, propname);
485
486 if (ofnode_is_np(node)) {
487 return of_read_u32_array(ofnode_to_np(node), propname,
488 out_values, sz);
489 } else {
Simon Glasse3be5fc2022-09-06 20:27:18 -0600490 int ret;
491
Simon Glass04fa09a2022-09-06 20:27:20 -0600492 ret = fdtdec_get_int_array(ofnode_to_fdt(node),
Simon Glasse3be5fc2022-09-06 20:27:18 -0600493 ofnode_to_offset(node), propname,
494 out_values, sz);
495
496 /* get the error right, but space is more important in SPL */
497 if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
498 if (ret == -FDT_ERR_NOTFOUND)
499 return -EINVAL;
500 else if (ret == -FDT_ERR_BADLAYOUT)
501 return -EOVERFLOW;
502 }
503 return ret;
Simon Glassc4fc5622017-05-18 20:08:58 -0600504 }
505}
506
Simon Glass39f1d282020-12-16 17:25:06 -0700507#if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
Simon Glass5de5b3b2020-11-28 17:50:02 -0700508bool ofnode_is_enabled(ofnode node)
509{
510 if (ofnode_is_np(node)) {
511 return of_device_is_available(ofnode_to_np(node));
512 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600513 return fdtdec_get_is_enabled(ofnode_to_fdt(node),
Simon Glass5de5b3b2020-11-28 17:50:02 -0700514 ofnode_to_offset(node));
515 }
516}
517
Simon Glassc4fc5622017-05-18 20:08:58 -0600518ofnode ofnode_first_subnode(ofnode node)
519{
520 assert(ofnode_valid(node));
521 if (ofnode_is_np(node))
522 return np_to_ofnode(node.np->child);
523
Simon Glass37dcd912022-09-06 20:27:23 -0600524 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600525 fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600526}
527
528ofnode ofnode_next_subnode(ofnode node)
529{
530 assert(ofnode_valid(node));
531 if (ofnode_is_np(node))
532 return np_to_ofnode(node.np->sibling);
533
Simon Glass37dcd912022-09-06 20:27:23 -0600534 return noffset_to_ofnode(node,
Simon Glass04fa09a2022-09-06 20:27:20 -0600535 fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glassc4fc5622017-05-18 20:08:58 -0600536}
Simon Glass39f1d282020-12-16 17:25:06 -0700537#endif /* !DM_INLINE_OFNODE */
Simon Glassc4fc5622017-05-18 20:08:58 -0600538
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100539ofnode ofnode_get_parent(ofnode node)
540{
541 ofnode parent;
542
543 assert(ofnode_valid(node));
544 if (ofnode_is_np(node))
545 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
546 else
Simon Glass04fa09a2022-09-06 20:27:20 -0600547 parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100548 ofnode_to_offset(node));
549
550 return parent;
551}
552
Simon Glassc4fc5622017-05-18 20:08:58 -0600553const char *ofnode_get_name(ofnode node)
554{
Kever Yang8d7976d2019-07-19 11:23:47 +0800555 if (!ofnode_valid(node)) {
556 debug("%s node not valid\n", __func__);
557 return NULL;
558 }
559
Simon Glassc4fc5622017-05-18 20:08:58 -0600560 if (ofnode_is_np(node))
Simon Glass91d89a82022-09-06 20:27:15 -0600561 return node.np->name;
Simon Glassc4fc5622017-05-18 20:08:58 -0600562
Simon Glass04fa09a2022-09-06 20:27:20 -0600563 return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600564}
565
Marek Behúne897e3c2021-05-26 14:08:18 +0200566int ofnode_get_path(ofnode node, char *buf, int buflen)
567{
568 assert(ofnode_valid(node));
569
570 if (ofnode_is_np(node)) {
571 if (strlen(node.np->full_name) >= buflen)
572 return -ENOSPC;
573
574 strcpy(buf, node.np->full_name);
575
576 return 0;
577 } else {
578 int res;
579
Simon Glass04fa09a2022-09-06 20:27:20 -0600580 res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
Marek Behúne897e3c2021-05-26 14:08:18 +0200581 buflen);
582 if (!res)
583 return res;
584 else if (res == -FDT_ERR_NOSPACE)
585 return -ENOSPC;
586 else
587 return -EINVAL;
588 }
589}
590
Kever Yang37df0e02018-02-23 17:38:50 +0100591ofnode ofnode_get_by_phandle(uint phandle)
592{
593 ofnode node;
594
595 if (of_live_active())
Simon Glass176dd432022-09-06 20:26:57 -0600596 node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
Kever Yang37df0e02018-02-23 17:38:50 +0100597 else
598 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
599 phandle);
600
601 return node;
602}
603
Simon Glass95fd2092022-09-06 20:27:22 -0600604ofnode oftree_get_by_phandle(oftree tree, uint phandle)
605{
606 ofnode node;
607
608 if (of_live_active())
609 node = np_to_ofnode(of_find_node_by_phandle(tree.np, phandle));
610 else
Simon Glassf912a722022-09-06 20:27:27 -0600611 node = ofnode_from_tree_offset(tree,
Simon Glass95fd2092022-09-06 20:27:22 -0600612 fdt_node_offset_by_phandle(oftree_lookup_fdt(tree),
Simon Glassf912a722022-09-06 20:27:27 -0600613 phandle));
Simon Glass95fd2092022-09-06 20:27:22 -0600614
615 return node;
616}
617
Marek Behún177ab7f2021-05-26 14:08:17 +0200618static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
619 fdt_size_t *size, bool translate)
Simon Glass049ae1b2017-05-18 20:09:01 -0600620{
Keerthy34222a32018-11-19 11:44:47 +0530621 int na, ns;
Keerthy34222a32018-11-19 11:44:47 +0530622
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800623 if (size)
624 *size = FDT_SIZE_T_NONE;
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800625
Simon Glass049ae1b2017-05-18 20:09:01 -0600626 if (ofnode_is_np(node)) {
627 const __be32 *prop_val;
Simon Glass47f85de2019-09-25 08:55:50 -0600628 u64 size64;
Simon Glass049ae1b2017-05-18 20:09:01 -0600629 uint flags;
Simon Glass049ae1b2017-05-18 20:09:01 -0600630
Simon Glass47f85de2019-09-25 08:55:50 -0600631 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
632 &flags);
Simon Glass049ae1b2017-05-18 20:09:01 -0600633 if (!prop_val)
634 return FDT_ADDR_T_NONE;
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800635
Simon Glass47f85de2019-09-25 08:55:50 -0600636 if (size)
637 *size = size64;
Mario Sixd007ebc2017-12-20 09:52:12 +0100638
Mario Six35616ef2018-03-12 14:53:33 +0100639 ns = of_n_size_cells(ofnode_to_np(node));
640
Marek Behún177ab7f2021-05-26 14:08:17 +0200641 if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Sixd007ebc2017-12-20 09:52:12 +0100642 return of_translate_address(ofnode_to_np(node), prop_val);
643 } else {
644 na = of_n_addr_cells(ofnode_to_np(node));
645 return of_read_number(prop_val, na);
646 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600647 } else {
Keerthy34222a32018-11-19 11:44:47 +0530648 na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
649 ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
Simon Glass04fa09a2022-09-06 20:27:20 -0600650 return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
Keerthy34222a32018-11-19 11:44:47 +0530651 ofnode_to_offset(node), "reg",
Marek Behún177ab7f2021-05-26 14:08:17 +0200652 index, na, ns, size,
653 translate);
Simon Glass049ae1b2017-05-18 20:09:01 -0600654 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600655}
656
Marek Behún177ab7f2021-05-26 14:08:17 +0200657fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
658{
659 return __ofnode_get_addr_size_index(node, index, size, true);
660}
661
662fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
663 fdt_size_t *size)
664{
665 return __ofnode_get_addr_size_index(node, index, size, false);
666}
667
Keerthyd332e6e2019-04-24 17:19:53 +0530668fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
669{
670 fdt_size_t size;
671
672 return ofnode_get_addr_size_index(node, index, &size);
673}
674
Simon Glass049ae1b2017-05-18 20:09:01 -0600675fdt_addr_t ofnode_get_addr(ofnode node)
676{
677 return ofnode_get_addr_index(node, 0);
678}
679
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800680fdt_size_t ofnode_get_size(ofnode node)
681{
682 fdt_size_t size;
683
684 ofnode_get_addr_size_index(node, 0, &size);
685
686 return size;
687}
688
Simon Glassc4fc5622017-05-18 20:08:58 -0600689int ofnode_stringlist_search(ofnode node, const char *property,
690 const char *string)
691{
692 if (ofnode_is_np(node)) {
693 return of_property_match_string(ofnode_to_np(node),
694 property, string);
695 } else {
696 int ret;
697
Simon Glass04fa09a2022-09-06 20:27:20 -0600698 ret = fdt_stringlist_search(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600699 ofnode_to_offset(node), property,
700 string);
701 if (ret == -FDT_ERR_NOTFOUND)
702 return -ENODATA;
703 else if (ret < 0)
704 return -EINVAL;
705
706 return ret;
707 }
708}
709
710int ofnode_read_string_index(ofnode node, const char *property, int index,
711 const char **outp)
712{
713 if (ofnode_is_np(node)) {
714 return of_property_read_string_index(ofnode_to_np(node),
715 property, index, outp);
716 } else {
717 int len;
718
Simon Glass04fa09a2022-09-06 20:27:20 -0600719 *outp = fdt_stringlist_get(ofnode_to_fdt(node),
720 ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600721 property, index, &len);
722 if (len < 0)
723 return -EINVAL;
724 return 0;
725 }
726}
727
Simon Glass5fdb0052017-06-12 06:21:28 -0600728int ofnode_read_string_count(ofnode node, const char *property)
729{
730 if (ofnode_is_np(node)) {
731 return of_property_count_strings(ofnode_to_np(node), property);
732 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -0600733 return fdt_stringlist_count(ofnode_to_fdt(node),
Simon Glass5fdb0052017-06-12 06:21:28 -0600734 ofnode_to_offset(node), property);
735 }
736}
737
Simon Glass9580bfc2021-10-23 17:26:07 -0600738int ofnode_read_string_list(ofnode node, const char *property,
739 const char ***listp)
740{
741 const char **prop;
742 int count;
743 int i;
744
745 *listp = NULL;
746 count = ofnode_read_string_count(node, property);
747 if (count < 0)
748 return count;
749 if (!count)
750 return 0;
751
752 prop = calloc(count + 1, sizeof(char *));
753 if (!prop)
754 return -ENOMEM;
755
756 for (i = 0; i < count; i++)
757 ofnode_read_string_index(node, property, i, &prop[i]);
758 prop[count] = NULL;
759 *listp = prop;
760
761 return count;
762}
763
Simon Glassc4fc5622017-05-18 20:08:58 -0600764static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
765 struct ofnode_phandle_args *out)
766{
767 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
768 out->node = offset_to_ofnode(in->node);
769 out->args_count = in->args_count;
770 memcpy(out->args, in->args, sizeof(out->args));
771}
772
773static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
774 struct ofnode_phandle_args *out)
775{
776 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
777 out->node = np_to_ofnode(in->np);
778 out->args_count = in->args_count;
779 memcpy(out->args, in->args, sizeof(out->args));
780}
781
782int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
783 const char *cells_name, int cell_count,
784 int index,
785 struct ofnode_phandle_args *out_args)
786{
787 if (ofnode_is_np(node)) {
788 struct of_phandle_args args;
789 int ret;
790
791 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay21e3b042020-09-10 18:26:17 +0200792 list_name, cells_name,
793 cell_count, index,
Mario Sixf40d82c2018-01-15 11:07:17 +0100794 &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600795 if (ret)
796 return ret;
797 ofnode_from_of_phandle_args(&args, out_args);
798 } else {
799 struct fdtdec_phandle_args args;
800 int ret;
801
Simon Glass04fa09a2022-09-06 20:27:20 -0600802 ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Mario Sixf40d82c2018-01-15 11:07:17 +0100803 ofnode_to_offset(node),
804 list_name, cells_name,
805 cell_count, index, &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600806 if (ret)
807 return ret;
808 ofnode_from_fdtdec_phandle_args(&args, out_args);
809 }
810
811 return 0;
812}
813
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200814int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200815 const char *cells_name, int cell_count)
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200816{
817 if (ofnode_is_np(node))
818 return of_count_phandle_with_args(ofnode_to_np(node),
Patrick Delaunayd776a842020-09-25 09:41:14 +0200819 list_name, cells_name, cell_count);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200820 else
Simon Glass04fa09a2022-09-06 20:27:20 -0600821 return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200822 ofnode_to_offset(node), list_name, cells_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200823 cell_count, -1, NULL);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200824}
825
Simon Glassc4fc5622017-05-18 20:08:58 -0600826ofnode ofnode_path(const char *path)
827{
828 if (of_live_active())
829 return np_to_ofnode(of_find_node_by_path(path));
830 else
831 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
832}
833
Simon Glass45ae59d2022-09-06 20:27:24 -0600834ofnode oftree_root(oftree tree)
Simon Glassef75c592022-07-30 15:52:08 -0600835{
Simon Glass45ae59d2022-09-06 20:27:24 -0600836 if (of_live_active()) {
837 return np_to_ofnode(tree.np);
838 } else {
839 return ofnode_from_tree_offset(tree, 0);
840 }
841}
842
843ofnode oftree_path(oftree tree, const char *path)
844{
845 if (of_live_active()) {
Simon Glassef75c592022-07-30 15:52:08 -0600846 return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
847 NULL));
Simon Glass45ae59d2022-09-06 20:27:24 -0600848 } else if (*path != '/' && tree.fdt != gd->fdt_blob) {
Simon Glassef75c592022-07-30 15:52:08 -0600849 return ofnode_null(); /* Aliases only on control FDT */
Simon Glass45ae59d2022-09-06 20:27:24 -0600850 } else {
851 int offset = fdt_path_offset(tree.fdt, path);
852
853 return ofnode_from_tree_offset(tree, offset);
854 }
Simon Glassef75c592022-07-30 15:52:08 -0600855}
856
Simon Glasse09223c2020-01-27 08:49:46 -0700857const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600858{
859 ofnode chosen_node;
860
861 chosen_node = ofnode_path("/chosen");
862
Simon Glasse09223c2020-01-27 08:49:46 -0700863 return ofnode_read_prop(chosen_node, propname, sizep);
Simon Glassc4fc5622017-05-18 20:08:58 -0600864}
865
Simon Glasse09223c2020-01-27 08:49:46 -0700866const char *ofnode_read_chosen_string(const char *propname)
867{
868 return ofnode_read_chosen_prop(propname, NULL);
869}
870
Simon Glassc4fc5622017-05-18 20:08:58 -0600871ofnode ofnode_get_chosen_node(const char *name)
872{
873 const char *prop;
874
Simon Glasse09223c2020-01-27 08:49:46 -0700875 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600876 if (!prop)
877 return ofnode_null();
878
879 return ofnode_path(prop);
880}
881
Michal Simek92a88622020-07-28 12:51:08 +0200882const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
883{
884 ofnode node;
885
886 node = ofnode_path("/aliases");
887
888 return ofnode_read_prop(node, propname, sizep);
889}
890
891ofnode ofnode_get_aliases_node(const char *name)
892{
893 const char *prop;
894
895 prop = ofnode_read_aliases_prop(name, NULL);
896 if (!prop)
897 return ofnode_null();
898
899 debug("%s: node_path: %s\n", __func__, prop);
900
901 return ofnode_path(prop);
902}
903
developerd93c8b42020-05-02 11:35:09 +0200904int ofnode_get_child_count(ofnode parent)
905{
906 ofnode child;
907 int num = 0;
908
909 ofnode_for_each_subnode(child, parent)
910 num++;
911
912 return num;
913}
914
Simon Glassc4fc5622017-05-18 20:08:58 -0600915static int decode_timing_property(ofnode node, const char *name,
916 struct timing_entry *result)
917{
918 int length, ret = 0;
919
920 length = ofnode_read_size(node, name);
921 if (length < 0) {
922 debug("%s: could not find property %s\n",
923 ofnode_get_name(node), name);
924 return length;
925 }
926
927 if (length == sizeof(u32)) {
928 result->typ = ofnode_read_u32_default(node, name, 0);
929 result->min = result->typ;
930 result->max = result->typ;
931 } else {
932 ret = ofnode_read_u32_array(node, name, &result->min, 3);
933 }
934
935 return ret;
936}
937
938int ofnode_decode_display_timing(ofnode parent, int index,
939 struct display_timing *dt)
940{
941 int i;
942 ofnode timings, node;
943 u32 val = 0;
944 int ret = 0;
945
946 timings = ofnode_find_subnode(parent, "display-timings");
947 if (!ofnode_valid(timings))
948 return -EINVAL;
949
Simon Glass28529762017-08-05 15:45:54 -0600950 i = 0;
951 ofnode_for_each_subnode(node, timings) {
952 if (i++ == index)
953 break;
954 }
Simon Glassc4fc5622017-05-18 20:08:58 -0600955
956 if (!ofnode_valid(node))
957 return -EINVAL;
958
959 memset(dt, 0, sizeof(*dt));
960
961 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
962 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
963 ret |= decode_timing_property(node, "hactive", &dt->hactive);
964 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
965 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
966 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
967 ret |= decode_timing_property(node, "vactive", &dt->vactive);
968 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
969 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
970
971 dt->flags = 0;
972 val = ofnode_read_u32_default(node, "vsync-active", -1);
973 if (val != -1) {
974 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
975 DISPLAY_FLAGS_VSYNC_LOW;
976 }
977 val = ofnode_read_u32_default(node, "hsync-active", -1);
978 if (val != -1) {
979 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
980 DISPLAY_FLAGS_HSYNC_LOW;
981 }
982 val = ofnode_read_u32_default(node, "de-active", -1);
983 if (val != -1) {
984 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
985 DISPLAY_FLAGS_DE_LOW;
986 }
987 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
988 if (val != -1) {
989 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
990 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
991 }
992
993 if (ofnode_read_bool(node, "interlaced"))
994 dt->flags |= DISPLAY_FLAGS_INTERLACED;
995 if (ofnode_read_bool(node, "doublescan"))
996 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
997 if (ofnode_read_bool(node, "doubleclk"))
998 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
999
1000 return ret;
1001}
1002
Nikhil M Jainff407062023-01-31 15:35:14 +05301003int ofnode_decode_panel_timing(ofnode parent,
1004 struct display_timing *dt)
1005{
1006 ofnode timings;
1007 u32 val = 0;
1008 int ret = 0;
1009
Raphael Gallais-Poua853b922023-05-11 16:36:52 +02001010 timings = ofnode_find_subnode(parent, "panel-timing");
Nikhil M Jainff407062023-01-31 15:35:14 +05301011 if (!ofnode_valid(timings))
1012 return -EINVAL;
1013 memset(dt, 0, sizeof(*dt));
1014 ret |= decode_timing_property(timings, "hback-porch", &dt->hback_porch);
1015 ret |= decode_timing_property(timings, "hfront-porch", &dt->hfront_porch);
1016 ret |= decode_timing_property(timings, "hactive", &dt->hactive);
1017 ret |= decode_timing_property(timings, "hsync-len", &dt->hsync_len);
1018 ret |= decode_timing_property(timings, "vback-porch", &dt->vback_porch);
1019 ret |= decode_timing_property(timings, "vfront-porch", &dt->vfront_porch);
1020 ret |= decode_timing_property(timings, "vactive", &dt->vactive);
1021 ret |= decode_timing_property(timings, "vsync-len", &dt->vsync_len);
1022 ret |= decode_timing_property(timings, "clock-frequency", &dt->pixelclock);
1023 dt->flags = 0;
1024 if (!ofnode_read_u32(timings, "vsync-active", &val)) {
1025 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1026 DISPLAY_FLAGS_VSYNC_LOW;
1027 }
1028 if (!ofnode_read_u32(timings, "hsync-active", &val)) {
1029 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1030 DISPLAY_FLAGS_HSYNC_LOW;
1031 }
1032 if (!ofnode_read_u32(timings, "de-active", &val)) {
1033 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1034 DISPLAY_FLAGS_DE_LOW;
1035 }
1036 if (!ofnode_read_u32(timings, "pixelclk-active", &val)) {
1037 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1038 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1039 }
1040 if (ofnode_read_bool(timings, "interlaced"))
1041 dt->flags |= DISPLAY_FLAGS_INTERLACED;
1042 if (ofnode_read_bool(timings, "doublescan"))
1043 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1044 if (ofnode_read_bool(timings, "doubleclk"))
1045 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1046
1047 return ret;
1048}
1049
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +09001050const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glassc4fc5622017-05-18 20:08:58 -06001051{
Masahiro Yamada5052f1b2017-06-22 16:54:04 +09001052 if (ofnode_is_np(node))
1053 return of_get_property(ofnode_to_np(node), propname, lenp);
1054 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001055 return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001056 propname, lenp);
Simon Glassc4fc5622017-05-18 20:08:58 -06001057}
1058
Simon Glassfec058d2022-09-06 20:27:13 -06001059int ofnode_first_property(ofnode node, struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001060{
1061 prop->node = node;
1062
1063 if (ofnode_is_np(node)) {
1064 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
1065 if (!prop->prop)
1066 return -FDT_ERR_NOTFOUND;
1067 } else {
1068 prop->offset =
Simon Glass04fa09a2022-09-06 20:27:20 -06001069 fdt_first_property_offset(ofnode_to_fdt(node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001070 ofnode_to_offset(prop->node));
1071 if (prop->offset < 0)
1072 return prop->offset;
1073 }
1074
1075 return 0;
1076}
1077
Simon Glassfec058d2022-09-06 20:27:13 -06001078int ofnode_next_property(struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001079{
1080 if (ofnode_is_np(prop->node)) {
1081 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
1082 prop->prop);
1083 if (!prop->prop)
1084 return -FDT_ERR_NOTFOUND;
1085 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001086 prop->offset =
1087 fdt_next_property_offset(ofnode_to_fdt(prop->node),
1088 prop->offset);
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001089 if (prop->offset < 0)
1090 return prop->offset;
1091 }
1092
1093 return 0;
1094}
1095
Simon Glassd0aff8b2022-09-06 20:27:14 -06001096const void *ofprop_get_property(const struct ofprop *prop,
1097 const char **propname, int *lenp)
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001098{
1099 if (ofnode_is_np(prop->node))
1100 return of_get_property_by_prop(ofnode_to_np(prop->node),
1101 prop->prop, propname, lenp);
1102 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001103 return fdt_getprop_by_offset(ofnode_to_fdt(prop->node),
Patrick Delaunaycaee1552020-01-13 11:34:56 +01001104 prop->offset,
1105 propname, lenp);
1106}
1107
Simon Glassc4fc5622017-05-18 20:08:58 -06001108fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
1109 fdt_size_t *sizep)
1110{
1111 if (ofnode_is_np(node)) {
1112 int na, ns;
1113 int psize;
1114 const struct device_node *np = ofnode_to_np(node);
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001115 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glassc4fc5622017-05-18 20:08:58 -06001116
Klaus Gogeraf4b0212017-09-20 13:50:41 +02001117 if (!prop)
1118 return FDT_ADDR_T_NONE;
Simon Glassc4fc5622017-05-18 20:08:58 -06001119 na = of_n_addr_cells(np);
Marek Vasut1638c172018-10-01 12:37:19 +02001120 ns = of_n_size_cells(np);
Simon Glassa67cc632017-05-18 20:09:27 -06001121 *sizep = of_read_number(prop + na, ns);
Marek Vasuta9dac492018-10-01 12:37:20 +02001122
Dario Binacchif8fc7032021-05-01 17:05:26 +02001123 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta9dac492018-10-01 12:37:20 +02001124 return of_translate_address(np, prop);
1125 else
1126 return of_read_number(prop, na);
Simon Glassc4fc5622017-05-18 20:08:58 -06001127 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001128 return fdtdec_get_addr_size(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001129 ofnode_to_offset(node), property,
1130 sizep);
1131 }
1132}
1133
1134const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
1135 size_t sz)
1136{
1137 if (ofnode_is_np(node)) {
1138 const struct device_node *np = ofnode_to_np(node);
1139 int psize;
1140 const __be32 *prop = of_get_property(np, propname, &psize);
1141
1142 if (!prop || sz != psize)
1143 return NULL;
1144 return (uint8_t *)prop;
1145
1146 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001147 return fdtdec_locate_byte_array(ofnode_to_fdt(node),
Simon Glassc4fc5622017-05-18 20:08:58 -06001148 ofnode_to_offset(node), propname, sz);
1149 }
1150}
1151
1152int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
1153 const char *propname, struct fdt_pci_addr *addr)
1154{
Masahiro Yamada5c5991e2017-06-22 17:57:50 +09001155 const fdt32_t *cell;
Simon Glassc4fc5622017-05-18 20:08:58 -06001156 int len;
1157 int ret = -ENOENT;
1158
1159 debug("%s: %s: ", __func__, propname);
1160
1161 /*
1162 * If we follow the pci bus bindings strictly, we should check
1163 * the value of the node's parent node's #address-cells and
1164 * #size-cells. They need to be 3 and 2 accordingly. However,
1165 * for simplicity we skip the check here.
1166 */
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +09001167 cell = ofnode_get_property(node, propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -06001168 if (!cell)
1169 goto fail;
1170
1171 if ((len % FDT_PCI_REG_SIZE) == 0) {
1172 int num = len / FDT_PCI_REG_SIZE;
1173 int i;
1174
1175 for (i = 0; i < num; i++) {
1176 debug("pci address #%d: %08lx %08lx %08lx\n", i,
1177 (ulong)fdt32_to_cpu(cell[0]),
1178 (ulong)fdt32_to_cpu(cell[1]),
1179 (ulong)fdt32_to_cpu(cell[2]));
1180 if ((fdt32_to_cpu(*cell) & type) == type) {
1181 addr->phys_hi = fdt32_to_cpu(cell[0]);
1182 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glassdfd43152019-09-25 08:55:46 -06001183 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glassc4fc5622017-05-18 20:08:58 -06001184 break;
Simon Glassc4fc5622017-05-18 20:08:58 -06001185 }
Mario Sixf40d82c2018-01-15 11:07:17 +01001186
1187 cell += (FDT_PCI_ADDR_CELLS +
1188 FDT_PCI_SIZE_CELLS);
Simon Glassc4fc5622017-05-18 20:08:58 -06001189 }
1190
1191 if (i == num) {
1192 ret = -ENXIO;
1193 goto fail;
1194 }
1195
1196 return 0;
Simon Glassc4fc5622017-05-18 20:08:58 -06001197 }
1198
Mario Sixf40d82c2018-01-15 11:07:17 +01001199 ret = -EINVAL;
1200
Simon Glassc4fc5622017-05-18 20:08:58 -06001201fail:
1202 debug("(not found)\n");
1203 return ret;
1204}
1205
Bin Mengfa157712018-08-03 01:14:35 -07001206int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
1207{
1208 const char *list, *end;
1209 int len;
1210
1211 list = ofnode_get_property(node, "compatible", &len);
1212 if (!list)
1213 return -ENOENT;
1214
1215 end = list + len;
1216 while (list < end) {
1217 len = strlen(list);
1218 if (len >= strlen("pciVVVV,DDDD")) {
1219 char *s = strstr(list, "pci");
1220
1221 /*
1222 * check if the string is something like pciVVVV,DDDD.RR
1223 * or just pciVVVV,DDDD
1224 */
1225 if (s && s[7] == ',' &&
1226 (s[12] == '.' || s[12] == 0)) {
1227 s += 3;
1228 *vendor = simple_strtol(s, NULL, 16);
1229
1230 s += 5;
1231 *device = simple_strtol(s, NULL, 16);
1232
1233 return 0;
1234 }
1235 }
1236 list += (len + 1);
1237 }
1238
1239 return -ENOENT;
1240}
1241
Michal Simeka253c3b2022-02-23 15:45:40 +01001242int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
1243{
1244 const char *list, *end;
1245 int len;
1246
1247 list = ofnode_get_property(node, "compatible", &len);
1248
1249 if (!list)
1250 return -ENOENT;
1251
1252 end = list + len;
1253 while (list < end) {
1254 len = strlen(list);
1255
Michal Simekc633cdf2022-10-31 17:08:44 -07001256 if (len >= strlen("ethernet-phy-idVVVV.DDDD")) {
Michal Simeka253c3b2022-02-23 15:45:40 +01001257 char *s = strstr(list, "ethernet-phy-id");
1258
1259 /*
1260 * check if the string is something like
Michal Simekc633cdf2022-10-31 17:08:44 -07001261 * ethernet-phy-idVVVV.DDDD
Michal Simeka253c3b2022-02-23 15:45:40 +01001262 */
1263 if (s && s[19] == '.') {
1264 s += strlen("ethernet-phy-id");
1265 *vendor = simple_strtol(s, NULL, 16);
1266 s += 5;
1267 *device = simple_strtol(s, NULL, 16);
1268
1269 return 0;
1270 }
1271 }
1272 list += (len + 1);
1273 }
1274
1275 return -ENOENT;
1276}
1277
Simon Glassc4fc5622017-05-18 20:08:58 -06001278int ofnode_read_addr_cells(ofnode node)
1279{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001280 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001281 return of_n_addr_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001282 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001283 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001284 ofnode_to_offset(node));
1285
Simon Glass04fa09a2022-09-06 20:27:20 -06001286 return fdt_address_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001287 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001288}
1289
1290int ofnode_read_size_cells(ofnode node)
1291{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001292 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001293 return of_n_size_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001294 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001295 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001296 ofnode_to_offset(node));
1297
Simon Glass04fa09a2022-09-06 20:27:20 -06001298 return fdt_size_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001299 }
Simon Glass4191dc12017-06-12 06:21:31 -06001300}
1301
1302int ofnode_read_simple_addr_cells(ofnode node)
1303{
1304 if (ofnode_is_np(node))
1305 return of_simple_addr_cells(ofnode_to_np(node));
1306 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001307 return fdt_address_cells(ofnode_to_fdt(node),
1308 ofnode_to_offset(node));
Simon Glass4191dc12017-06-12 06:21:31 -06001309}
1310
1311int ofnode_read_simple_size_cells(ofnode node)
1312{
1313 if (ofnode_is_np(node))
1314 return of_simple_size_cells(ofnode_to_np(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001315 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001316 return fdt_size_cells(ofnode_to_fdt(node),
1317 ofnode_to_offset(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001318}
1319
1320bool ofnode_pre_reloc(ofnode node)
1321{
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001322#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
1323 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
Simon Glassfc1aa352023-02-13 08:56:34 -07001324 * had property bootph-all or bootph-pre-sram/bootph-pre-ram.
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001325 * They are removed in final dtb (fdtgrep 2nd pass)
1326 */
1327 return true;
1328#else
Simon Glassfc1aa352023-02-13 08:56:34 -07001329 if (ofnode_read_bool(node, "bootph-all"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001330 return true;
Simon Glassfc1aa352023-02-13 08:56:34 -07001331 if (ofnode_read_bool(node, "bootph-some-ram"))
Simon Glass23f22842018-10-01 12:22:18 -06001332 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001333
Simon Glassc4fc5622017-05-18 20:08:58 -06001334 /*
1335 * In regular builds individual spl and tpl handling both
1336 * count as handled pre-relocation for later second init.
1337 */
Simon Glassfc1aa352023-02-13 08:56:34 -07001338 if (ofnode_read_bool(node, "bootph-pre-ram") ||
1339 ofnode_read_bool(node, "bootph-pre-sram"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001340 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001341
Simon Glassc2727e52023-02-13 08:56:32 -07001342 if (IS_ENABLED(CONFIG_OF_TAG_MIGRATE)) {
1343 /* detect and handle old tags */
1344 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc") ||
1345 ofnode_read_bool(node, "u-boot,dm-pre-proper") ||
1346 ofnode_read_bool(node, "u-boot,dm-spl") ||
1347 ofnode_read_bool(node, "u-boot,dm-tpl") ||
1348 ofnode_read_bool(node, "u-boot,dm-vpl")) {
1349 gd->flags |= GD_FLG_OF_TAG_MIGRATE;
1350 return true;
1351 }
1352 }
1353
Simon Glassc4fc5622017-05-18 20:08:58 -06001354 return false;
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001355#endif
Simon Glassc4fc5622017-05-18 20:08:58 -06001356}
Simon Glassf7bfcc42017-07-25 08:29:55 -06001357
1358int ofnode_read_resource(ofnode node, uint index, struct resource *res)
1359{
1360 if (ofnode_is_np(node)) {
1361 return of_address_to_resource(ofnode_to_np(node), index, res);
1362 } else {
1363 struct fdt_resource fres;
1364 int ret;
1365
Simon Glass04fa09a2022-09-06 20:27:20 -06001366 ret = fdt_get_resource(ofnode_to_fdt(node),
1367 ofnode_to_offset(node),
Simon Glassf7bfcc42017-07-25 08:29:55 -06001368 "reg", index, &fres);
1369 if (ret < 0)
1370 return -EINVAL;
1371 memset(res, '\0', sizeof(*res));
1372 res->start = fres.start;
1373 res->end = fres.end;
1374
1375 return 0;
1376 }
1377}
Masahiro Yamada4dada2c2017-08-26 01:12:30 +09001378
1379int ofnode_read_resource_byname(ofnode node, const char *name,
1380 struct resource *res)
1381{
1382 int index;
1383
1384 index = ofnode_stringlist_search(node, "reg-names", name);
1385 if (index < 0)
1386 return index;
1387
1388 return ofnode_read_resource(node, index, res);
1389}
Mario Sixaefac062018-01-15 11:07:19 +01001390
1391u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
1392{
1393 if (ofnode_is_np(node))
1394 return of_translate_address(ofnode_to_np(node), in_addr);
1395 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001396 return fdt_translate_address(ofnode_to_fdt(node),
1397 ofnode_to_offset(node), in_addr);
Mario Sixaefac062018-01-15 11:07:19 +01001398}
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001399
Fabien Dessenne22236e02019-05-31 15:11:30 +02001400u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
1401{
1402 if (ofnode_is_np(node))
1403 return of_translate_dma_address(ofnode_to_np(node), in_addr);
1404 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001405 return fdt_translate_dma_address(ofnode_to_fdt(node),
1406 ofnode_to_offset(node), in_addr);
Fabien Dessenne22236e02019-05-31 15:11:30 +02001407}
1408
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001409int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
1410{
1411 if (ofnode_is_np(node))
1412 return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
1413 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001414 return fdt_get_dma_range(ofnode_to_fdt(node),
1415 ofnode_to_offset(node),
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001416 cpu, bus, size);
1417}
1418
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001419int ofnode_device_is_compatible(ofnode node, const char *compat)
1420{
1421 if (ofnode_is_np(node))
1422 return of_device_is_compatible(ofnode_to_np(node), compat,
1423 NULL, NULL);
1424 else
Simon Glass04fa09a2022-09-06 20:27:20 -06001425 return !fdt_node_check_compatible(ofnode_to_fdt(node),
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001426 ofnode_to_offset(node),
1427 compat);
1428}
Simon Glass954eeae2018-06-11 13:07:13 -06001429
1430ofnode ofnode_by_compatible(ofnode from, const char *compat)
1431{
1432 if (of_live_active()) {
1433 return np_to_ofnode(of_find_compatible_node(
1434 (struct device_node *)ofnode_to_np(from), NULL,
1435 compat));
1436 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001437 return noffset_to_ofnode(from,
1438 fdt_node_offset_by_compatible(ofnode_to_fdt(from),
Simon Glass04fa09a2022-09-06 20:27:20 -06001439 ofnode_to_offset(from), compat));
Simon Glass954eeae2018-06-11 13:07:13 -06001440 }
1441}
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001442
1443ofnode ofnode_by_prop_value(ofnode from, const char *propname,
1444 const void *propval, int proplen)
1445{
1446 if (of_live_active()) {
1447 return np_to_ofnode(of_find_node_by_prop_value(
1448 (struct device_node *)ofnode_to_np(from), propname,
1449 propval, proplen));
1450 } else {
Simon Glass37dcd912022-09-06 20:27:23 -06001451 return noffset_to_ofnode(from,
1452 fdt_node_offset_by_prop_value(ofnode_to_fdt(from),
1453 ofnode_to_offset(from), propname, propval,
1454 proplen));
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001455 }
1456}
Mario Six047dafc2018-06-26 08:46:48 +02001457
Simon Glass5e2cd5e2022-07-30 15:52:10 -06001458int ofnode_write_prop(ofnode node, const char *propname, const void *value,
Simon Glass17abed02022-09-06 20:27:32 -06001459 int len, bool copy)
Mario Six047dafc2018-06-26 08:46:48 +02001460{
Simon Glass17abed02022-09-06 20:27:32 -06001461 if (of_live_active()) {
1462 void *newval;
1463 int ret;
1464
1465 if (copy) {
1466 newval = malloc(len);
1467 if (!newval)
1468 return log_ret(-ENOMEM);
1469 memcpy(newval, value, len);
1470 value = newval;
1471 }
1472 ret = of_write_prop(ofnode_to_np(node), propname, len, value);
1473 if (ret && copy)
1474 free(newval);
1475 return ret;
1476 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001477 return fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glass3ee3d152022-07-30 15:52:13 -06001478 propname, value, len);
Simon Glass17abed02022-09-06 20:27:32 -06001479 }
Mario Six047dafc2018-06-26 08:46:48 +02001480}
1481
1482int ofnode_write_string(ofnode node, const char *propname, const char *value)
1483{
Mario Six047dafc2018-06-26 08:46:48 +02001484 assert(ofnode_valid(node));
1485
1486 debug("%s: %s = %s", __func__, propname, value);
1487
Simon Glass17abed02022-09-06 20:27:32 -06001488 return ofnode_write_prop(node, propname, value, strlen(value) + 1,
1489 false);
Mario Six047dafc2018-06-26 08:46:48 +02001490}
1491
Simon Glassd28e31e2022-07-30 15:52:14 -06001492int ofnode_write_u32(ofnode node, const char *propname, u32 value)
1493{
1494 fdt32_t *val;
1495
1496 assert(ofnode_valid(node));
1497
1498 log_debug("%s = %x", propname, value);
1499 val = malloc(sizeof(*val));
1500 if (!val)
1501 return -ENOMEM;
1502 *val = cpu_to_fdt32(value);
1503
Simon Glass17abed02022-09-06 20:27:32 -06001504 return ofnode_write_prop(node, propname, val, sizeof(value), false);
Simon Glassd28e31e2022-07-30 15:52:14 -06001505}
1506
Mario Six047dafc2018-06-26 08:46:48 +02001507int ofnode_set_enabled(ofnode node, bool value)
1508{
Mario Six047dafc2018-06-26 08:46:48 +02001509 assert(ofnode_valid(node));
1510
1511 if (value)
1512 return ofnode_write_string(node, "status", "okay");
1513 else
Bin Menga9274aa2019-07-05 09:23:17 -07001514 return ofnode_write_string(node, "status", "disabled");
Mario Six047dafc2018-06-26 08:46:48 +02001515}
Simon Glass0034d962021-08-07 07:24:01 -06001516
1517bool ofnode_conf_read_bool(const char *prop_name)
1518{
1519 ofnode node;
1520
1521 node = ofnode_path("/config");
1522 if (!ofnode_valid(node))
1523 return false;
1524
1525 return ofnode_read_bool(node, prop_name);
1526}
1527
1528int ofnode_conf_read_int(const char *prop_name, int default_val)
1529{
1530 ofnode node;
1531
1532 node = ofnode_path("/config");
1533 if (!ofnode_valid(node))
1534 return default_val;
1535
1536 return ofnode_read_u32_default(node, prop_name, default_val);
1537}
1538
1539const char *ofnode_conf_read_str(const char *prop_name)
1540{
1541 ofnode node;
1542
1543 node = ofnode_path("/config");
1544 if (!ofnode_valid(node))
1545 return NULL;
1546
1547 return ofnode_read_string(node, prop_name);
1548}
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001549
1550ofnode ofnode_get_phy_node(ofnode node)
1551{
1552 /* DT node properties that reference a PHY node */
1553 static const char * const phy_handle_str[] = {
1554 "phy-handle", "phy", "phy-device",
1555 };
1556 struct ofnode_phandle_args args = {
1557 .node = ofnode_null()
1558 };
1559 int i;
1560
1561 assert(ofnode_valid(node));
1562
1563 for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
1564 if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
1565 NULL, 0, 0, &args))
1566 break;
1567
1568 return args.node;
1569}
Marek Behúnbc194772022-04-07 00:33:01 +02001570
1571phy_interface_t ofnode_read_phy_mode(ofnode node)
1572{
1573 const char *mode;
1574 int i;
1575
1576 assert(ofnode_valid(node));
1577
1578 mode = ofnode_read_string(node, "phy-mode");
1579 if (!mode)
1580 mode = ofnode_read_string(node, "phy-connection-type");
1581
1582 if (!mode)
Marek Behún48631e42022-04-07 00:33:03 +02001583 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001584
Marek Behún21a18362022-04-07 00:33:02 +02001585 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
Marek Behúnbc194772022-04-07 00:33:01 +02001586 if (!strcmp(mode, phy_interface_strings[i]))
1587 return i;
1588
1589 debug("%s: Invalid PHY interface '%s'\n", __func__, mode);
1590
Marek Behún48631e42022-04-07 00:33:03 +02001591 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001592}
Simon Glass56bc3322022-09-06 20:27:02 -06001593
1594int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
1595{
1596 ofnode subnode;
1597 int ret = 0;
1598
1599 assert(ofnode_valid(node));
1600
1601 if (ofnode_is_np(node)) {
1602 struct device_node *np, *child;
1603
1604 np = (struct device_node *)ofnode_to_np(node);
1605 ret = of_add_subnode(np, name, -1, &child);
1606 if (ret && ret != -EEXIST)
1607 return ret;
1608 subnode = np_to_ofnode(child);
1609 } else {
Simon Glass04fa09a2022-09-06 20:27:20 -06001610 void *fdt = ofnode_to_fdt(node);
Simon Glass56bc3322022-09-06 20:27:02 -06001611 int poffset = ofnode_to_offset(node);
1612 int offset;
1613
1614 offset = fdt_add_subnode(fdt, poffset, name);
1615 if (offset == -FDT_ERR_EXISTS) {
1616 offset = fdt_subnode_offset(fdt, poffset, name);
1617 ret = -EEXIST;
1618 }
1619 if (offset < 0)
1620 return -EINVAL;
Simon Glass37dcd912022-09-06 20:27:23 -06001621 subnode = noffset_to_ofnode(node, offset);
Simon Glass56bc3322022-09-06 20:27:02 -06001622 }
1623
1624 *subnodep = subnode;
1625
1626 return ret; /* 0 or -EEXIST */
1627}
Simon Glass7a7229a2022-09-06 20:27:33 -06001628
1629int ofnode_copy_props(ofnode src, ofnode dst)
1630{
1631 struct ofprop prop;
1632
1633 ofnode_for_each_prop(prop, src) {
1634 const char *name;
1635 const char *val;
1636 int len, ret;
1637
1638 val = ofprop_get_property(&prop, &name, &len);
1639 if (!val) {
1640 log_debug("Cannot read prop (err=%d)\n", len);
1641 return log_msg_ret("get", -EINVAL);
1642 }
1643 ret = ofnode_write_prop(dst, name, val, len, true);
1644 if (ret) {
1645 log_debug("Cannot write prop (err=%d)\n", ret);
1646 return log_msg_ret("wr", -EINVAL);
1647 }
1648 }
1649
1650 return 0;
1651}