blob: e4b4b352e460aa942071c2d2dc5c70616ea5b3f9 [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
7#include <common.h>
8#include <dm.h>
9#include <fdtdec.h>
10#include <fdt_support.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070012#include <malloc.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090013#include <linux/libfdt.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060014#include <dm/of_access.h>
Simon Glass049ae1b2017-05-18 20:09:01 -060015#include <dm/of_addr.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060016#include <dm/ofnode.h>
17#include <linux/err.h>
Simon Glassf7bfcc42017-07-25 08:29:55 -060018#include <linux/ioport.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060019#include <asm/global_data.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060020
Kishon Vijay Abraham Id6388f22021-07-21 21:28:30 +053021bool ofnode_name_eq(ofnode node, const char *name)
22{
23 const char *node_name;
24 size_t len;
25
26 assert(ofnode_valid(node));
27
28 node_name = ofnode_get_name(node);
29 len = strchrnul(node_name, '@') - node_name;
30
31 return (strlen(name) == len) && !strncmp(node_name, name, len);
32}
33
Stefan Herbrechtsmeier1b090e62022-06-14 15:21:30 +020034int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
35{
36 const u8 *cell;
37 int len;
38
39 assert(ofnode_valid(node));
40 debug("%s: %s: ", __func__, propname);
41
42 if (ofnode_is_np(node))
43 return of_read_u8(ofnode_to_np(node), propname, outp);
44
45 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
46 &len);
47 if (!cell || len < sizeof(*cell)) {
48 debug("(not found)\n");
49 return -EINVAL;
50 }
51 *outp = *cell;
52 debug("%#x (%d)\n", *outp, *outp);
53
54 return 0;
55}
56
57u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
58{
59 assert(ofnode_valid(node));
60 ofnode_read_u8(node, propname, &def);
61
62 return def;
63}
64
65int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
66{
67 const fdt16_t *cell;
68 int len;
69
70 assert(ofnode_valid(node));
71 debug("%s: %s: ", __func__, propname);
72
73 if (ofnode_is_np(node))
74 return of_read_u16(ofnode_to_np(node), propname, outp);
75
76 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
77 &len);
78 if (!cell || len < sizeof(*cell)) {
79 debug("(not found)\n");
80 return -EINVAL;
81 }
82 *outp = be16_to_cpup(cell);
83 debug("%#x (%d)\n", *outp, *outp);
84
85 return 0;
86}
87
88u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def)
89{
90 assert(ofnode_valid(node));
91 ofnode_read_u16(node, propname, &def);
92
93 return def;
94}
95
Simon Glassc4fc5622017-05-18 20:08:58 -060096int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
97{
Dario Binacchib3f1cdd2020-03-29 18:04:42 +020098 return ofnode_read_u32_index(node, propname, 0, outp);
Simon Glassc4fc5622017-05-18 20:08:58 -060099}
100
Trent Piepho5b775412019-05-10 17:48:20 +0000101u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
Simon Glassc4fc5622017-05-18 20:08:58 -0600102{
103 assert(ofnode_valid(node));
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200104 ofnode_read_u32_index(node, propname, 0, &def);
Simon Glassc4fc5622017-05-18 20:08:58 -0600105
106 return def;
107}
108
Dario Binacchi81d80b52020-03-29 18:04:41 +0200109int ofnode_read_u32_index(ofnode node, const char *propname, int index,
110 u32 *outp)
111{
112 const fdt32_t *cell;
113 int len;
114
115 assert(ofnode_valid(node));
116 debug("%s: %s: ", __func__, propname);
117
118 if (ofnode_is_np(node))
119 return of_read_u32_index(ofnode_to_np(node), propname, index,
120 outp);
121
122 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
123 &len);
124 if (!cell) {
125 debug("(not found)\n");
126 return -EINVAL;
127 }
128
129 if (len < (sizeof(int) * (index + 1))) {
130 debug("(not large enough)\n");
131 return -EOVERFLOW;
132 }
133
134 *outp = fdt32_to_cpu(cell[index]);
135 debug("%#x (%d)\n", *outp, *outp);
136
137 return 0;
138}
139
140u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
141 u32 def)
142{
143 assert(ofnode_valid(node));
144 ofnode_read_u32_index(node, propname, index, &def);
145
146 return def;
147}
148
Simon Glassc4fc5622017-05-18 20:08:58 -0600149int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
150{
151 assert(ofnode_valid(node));
152 ofnode_read_u32(node, propname, (u32 *)&def);
153
154 return def;
155}
156
Simon Glass9d54a7a2018-06-11 13:07:10 -0600157int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
158{
Jean-Jacques Hiblot487f9172019-10-22 10:05:22 +0200159 const unaligned_fdt64_t *cell;
Simon Glass9d54a7a2018-06-11 13:07:10 -0600160 int len;
161
162 assert(ofnode_valid(node));
163 debug("%s: %s: ", __func__, propname);
164
165 if (ofnode_is_np(node))
166 return of_read_u64(ofnode_to_np(node), propname, outp);
167
168 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
169 &len);
170 if (!cell || len < sizeof(*cell)) {
171 debug("(not found)\n");
172 return -EINVAL;
173 }
174 *outp = fdt64_to_cpu(cell[0]);
175 debug("%#llx (%lld)\n", (unsigned long long)*outp,
176 (unsigned long long)*outp);
177
178 return 0;
179}
180
T Karthik Reddy478860d2019-09-02 16:34:30 +0200181u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
Simon Glass9d54a7a2018-06-11 13:07:10 -0600182{
183 assert(ofnode_valid(node));
184 ofnode_read_u64(node, propname, &def);
185
186 return def;
187}
188
Simon Glassc4fc5622017-05-18 20:08:58 -0600189bool ofnode_read_bool(ofnode node, const char *propname)
190{
Masahiro Yamada5d434452017-06-22 16:54:07 +0900191 const void *prop;
Simon Glassc4fc5622017-05-18 20:08:58 -0600192
193 assert(ofnode_valid(node));
194 debug("%s: %s: ", __func__, propname);
195
Masahiro Yamada5d434452017-06-22 16:54:07 +0900196 prop = ofnode_get_property(node, propname, NULL);
197
198 debug("%s\n", prop ? "true" : "false");
Simon Glassc4fc5622017-05-18 20:08:58 -0600199
Masahiro Yamada5d434452017-06-22 16:54:07 +0900200 return prop ? true : false;
Simon Glassc4fc5622017-05-18 20:08:58 -0600201}
202
Simon Glass0c2e9802020-01-27 08:49:44 -0700203const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600204{
Simon Glass0c2e9802020-01-27 08:49:44 -0700205 const char *val = NULL;
206 int len;
Simon Glassc4fc5622017-05-18 20:08:58 -0600207
208 assert(ofnode_valid(node));
209 debug("%s: %s: ", __func__, propname);
210
211 if (ofnode_is_np(node)) {
212 struct property *prop = of_find_property(
Simon Glass0c2e9802020-01-27 08:49:44 -0700213 ofnode_to_np(node), propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600214
215 if (prop) {
Simon Glass0c2e9802020-01-27 08:49:44 -0700216 val = prop->value;
Simon Glassc4fc5622017-05-18 20:08:58 -0600217 len = prop->length;
218 }
219 } else {
Simon Glass0c2e9802020-01-27 08:49:44 -0700220 val = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600221 propname, &len);
222 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700223 if (!val) {
Simon Glassc4fc5622017-05-18 20:08:58 -0600224 debug("<not found>\n");
Simon Glass0c2e9802020-01-27 08:49:44 -0700225 if (sizep)
226 *sizep = -FDT_ERR_NOTFOUND;
Simon Glassc4fc5622017-05-18 20:08:58 -0600227 return NULL;
228 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700229 if (sizep)
230 *sizep = len;
231
232 return val;
233}
234
235const char *ofnode_read_string(ofnode node, const char *propname)
236{
237 const char *str;
238 int len;
239
240 str = ofnode_read_prop(node, propname, &len);
241 if (!str)
242 return NULL;
243
Simon Glassc4fc5622017-05-18 20:08:58 -0600244 if (strnlen(str, len) >= len) {
245 debug("<invalid>\n");
246 return NULL;
247 }
248 debug("%s\n", str);
249
250 return str;
251}
252
Simon Glass81c54b32020-01-27 08:49:45 -0700253int ofnode_read_size(ofnode node, const char *propname)
254{
255 int len;
256
257 if (!ofnode_read_prop(node, propname, &len))
258 return -EINVAL;
259
260 return len;
261}
262
Simon Glassc4fc5622017-05-18 20:08:58 -0600263ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
264{
265 ofnode subnode;
266
267 assert(ofnode_valid(node));
268 debug("%s: %s: ", __func__, subnode_name);
269
270 if (ofnode_is_np(node)) {
Simon Glass9036c5c2022-09-06 20:27:04 -0600271 struct device_node *np = ofnode_to_np(node);
Simon Glassc4fc5622017-05-18 20:08:58 -0600272
273 for (np = np->child; np; np = np->sibling) {
274 if (!strcmp(subnode_name, np->name))
275 break;
276 }
277 subnode = np_to_ofnode(np);
278 } else {
279 int ooffset = fdt_subnode_offset(gd->fdt_blob,
280 ofnode_to_offset(node), subnode_name);
281 subnode = offset_to_ofnode(ooffset);
282 }
283 debug("%s\n", ofnode_valid(subnode) ?
284 ofnode_get_name(subnode) : "<none>");
285
286 return subnode;
287}
288
289int ofnode_read_u32_array(ofnode node, const char *propname,
290 u32 *out_values, size_t sz)
291{
292 assert(ofnode_valid(node));
293 debug("%s: %s: ", __func__, propname);
294
295 if (ofnode_is_np(node)) {
296 return of_read_u32_array(ofnode_to_np(node), propname,
297 out_values, sz);
298 } else {
Simon Glasse3be5fc2022-09-06 20:27:18 -0600299 int ret;
300
301 ret = fdtdec_get_int_array(gd->fdt_blob,
302 ofnode_to_offset(node), propname,
303 out_values, sz);
304
305 /* get the error right, but space is more important in SPL */
306 if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
307 if (ret == -FDT_ERR_NOTFOUND)
308 return -EINVAL;
309 else if (ret == -FDT_ERR_BADLAYOUT)
310 return -EOVERFLOW;
311 }
312 return ret;
Simon Glassc4fc5622017-05-18 20:08:58 -0600313 }
314}
315
Simon Glass39f1d282020-12-16 17:25:06 -0700316#if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
Simon Glass5de5b3b2020-11-28 17:50:02 -0700317bool ofnode_is_enabled(ofnode node)
318{
319 if (ofnode_is_np(node)) {
320 return of_device_is_available(ofnode_to_np(node));
321 } else {
322 return fdtdec_get_is_enabled(gd->fdt_blob,
323 ofnode_to_offset(node));
324 }
325}
326
Simon Glassc4fc5622017-05-18 20:08:58 -0600327ofnode ofnode_first_subnode(ofnode node)
328{
329 assert(ofnode_valid(node));
330 if (ofnode_is_np(node))
331 return np_to_ofnode(node.np->child);
332
333 return offset_to_ofnode(
334 fdt_first_subnode(gd->fdt_blob, ofnode_to_offset(node)));
335}
336
337ofnode ofnode_next_subnode(ofnode node)
338{
339 assert(ofnode_valid(node));
340 if (ofnode_is_np(node))
341 return np_to_ofnode(node.np->sibling);
342
343 return offset_to_ofnode(
344 fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node)));
345}
Simon Glass39f1d282020-12-16 17:25:06 -0700346#endif /* !DM_INLINE_OFNODE */
Simon Glassc4fc5622017-05-18 20:08:58 -0600347
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100348ofnode ofnode_get_parent(ofnode node)
349{
350 ofnode parent;
351
352 assert(ofnode_valid(node));
353 if (ofnode_is_np(node))
354 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
355 else
356 parent.of_offset = fdt_parent_offset(gd->fdt_blob,
357 ofnode_to_offset(node));
358
359 return parent;
360}
361
Simon Glassc4fc5622017-05-18 20:08:58 -0600362const char *ofnode_get_name(ofnode node)
363{
Kever Yang8d7976d2019-07-19 11:23:47 +0800364 if (!ofnode_valid(node)) {
365 debug("%s node not valid\n", __func__);
366 return NULL;
367 }
368
Simon Glassc4fc5622017-05-18 20:08:58 -0600369 if (ofnode_is_np(node))
Simon Glass91d89a82022-09-06 20:27:15 -0600370 return node.np->name;
Simon Glassc4fc5622017-05-18 20:08:58 -0600371
372 return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL);
373}
374
Marek Behúne897e3c2021-05-26 14:08:18 +0200375int ofnode_get_path(ofnode node, char *buf, int buflen)
376{
377 assert(ofnode_valid(node));
378
379 if (ofnode_is_np(node)) {
380 if (strlen(node.np->full_name) >= buflen)
381 return -ENOSPC;
382
383 strcpy(buf, node.np->full_name);
384
385 return 0;
386 } else {
387 int res;
388
389 res = fdt_get_path(gd->fdt_blob, ofnode_to_offset(node), buf,
390 buflen);
391 if (!res)
392 return res;
393 else if (res == -FDT_ERR_NOSPACE)
394 return -ENOSPC;
395 else
396 return -EINVAL;
397 }
398}
399
Kever Yang37df0e02018-02-23 17:38:50 +0100400ofnode ofnode_get_by_phandle(uint phandle)
401{
402 ofnode node;
403
404 if (of_live_active())
Simon Glass176dd432022-09-06 20:26:57 -0600405 node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
Kever Yang37df0e02018-02-23 17:38:50 +0100406 else
407 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
408 phandle);
409
410 return node;
411}
412
Marek Behún177ab7f2021-05-26 14:08:17 +0200413static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
414 fdt_size_t *size, bool translate)
Simon Glass049ae1b2017-05-18 20:09:01 -0600415{
Keerthy34222a32018-11-19 11:44:47 +0530416 int na, ns;
Keerthy34222a32018-11-19 11:44:47 +0530417
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800418 if (size)
419 *size = FDT_SIZE_T_NONE;
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800420
Simon Glass049ae1b2017-05-18 20:09:01 -0600421 if (ofnode_is_np(node)) {
422 const __be32 *prop_val;
Simon Glass47f85de2019-09-25 08:55:50 -0600423 u64 size64;
Simon Glass049ae1b2017-05-18 20:09:01 -0600424 uint flags;
Simon Glass049ae1b2017-05-18 20:09:01 -0600425
Simon Glass47f85de2019-09-25 08:55:50 -0600426 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
427 &flags);
Simon Glass049ae1b2017-05-18 20:09:01 -0600428 if (!prop_val)
429 return FDT_ADDR_T_NONE;
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800430
Simon Glass47f85de2019-09-25 08:55:50 -0600431 if (size)
432 *size = size64;
Mario Sixd007ebc2017-12-20 09:52:12 +0100433
Mario Six35616ef2018-03-12 14:53:33 +0100434 ns = of_n_size_cells(ofnode_to_np(node));
435
Marek Behún177ab7f2021-05-26 14:08:17 +0200436 if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Sixd007ebc2017-12-20 09:52:12 +0100437 return of_translate_address(ofnode_to_np(node), prop_val);
438 } else {
439 na = of_n_addr_cells(ofnode_to_np(node));
440 return of_read_number(prop_val, na);
441 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600442 } else {
Keerthy34222a32018-11-19 11:44:47 +0530443 na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
444 ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
445 return fdtdec_get_addr_size_fixed(gd->fdt_blob,
446 ofnode_to_offset(node), "reg",
Marek Behún177ab7f2021-05-26 14:08:17 +0200447 index, na, ns, size,
448 translate);
Simon Glass049ae1b2017-05-18 20:09:01 -0600449 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600450}
451
Marek Behún177ab7f2021-05-26 14:08:17 +0200452fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
453{
454 return __ofnode_get_addr_size_index(node, index, size, true);
455}
456
457fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
458 fdt_size_t *size)
459{
460 return __ofnode_get_addr_size_index(node, index, size, false);
461}
462
Keerthyd332e6e2019-04-24 17:19:53 +0530463fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
464{
465 fdt_size_t size;
466
467 return ofnode_get_addr_size_index(node, index, &size);
468}
469
Simon Glass049ae1b2017-05-18 20:09:01 -0600470fdt_addr_t ofnode_get_addr(ofnode node)
471{
472 return ofnode_get_addr_index(node, 0);
473}
474
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800475fdt_size_t ofnode_get_size(ofnode node)
476{
477 fdt_size_t size;
478
479 ofnode_get_addr_size_index(node, 0, &size);
480
481 return size;
482}
483
Simon Glassc4fc5622017-05-18 20:08:58 -0600484int ofnode_stringlist_search(ofnode node, const char *property,
485 const char *string)
486{
487 if (ofnode_is_np(node)) {
488 return of_property_match_string(ofnode_to_np(node),
489 property, string);
490 } else {
491 int ret;
492
493 ret = fdt_stringlist_search(gd->fdt_blob,
494 ofnode_to_offset(node), property,
495 string);
496 if (ret == -FDT_ERR_NOTFOUND)
497 return -ENODATA;
498 else if (ret < 0)
499 return -EINVAL;
500
501 return ret;
502 }
503}
504
505int ofnode_read_string_index(ofnode node, const char *property, int index,
506 const char **outp)
507{
508 if (ofnode_is_np(node)) {
509 return of_property_read_string_index(ofnode_to_np(node),
510 property, index, outp);
511 } else {
512 int len;
513
514 *outp = fdt_stringlist_get(gd->fdt_blob, ofnode_to_offset(node),
515 property, index, &len);
516 if (len < 0)
517 return -EINVAL;
518 return 0;
519 }
520}
521
Simon Glass5fdb0052017-06-12 06:21:28 -0600522int ofnode_read_string_count(ofnode node, const char *property)
523{
524 if (ofnode_is_np(node)) {
525 return of_property_count_strings(ofnode_to_np(node), property);
526 } else {
527 return fdt_stringlist_count(gd->fdt_blob,
528 ofnode_to_offset(node), property);
529 }
530}
531
Simon Glass9580bfc2021-10-23 17:26:07 -0600532int ofnode_read_string_list(ofnode node, const char *property,
533 const char ***listp)
534{
535 const char **prop;
536 int count;
537 int i;
538
539 *listp = NULL;
540 count = ofnode_read_string_count(node, property);
541 if (count < 0)
542 return count;
543 if (!count)
544 return 0;
545
546 prop = calloc(count + 1, sizeof(char *));
547 if (!prop)
548 return -ENOMEM;
549
550 for (i = 0; i < count; i++)
551 ofnode_read_string_index(node, property, i, &prop[i]);
552 prop[count] = NULL;
553 *listp = prop;
554
555 return count;
556}
557
Simon Glassc4fc5622017-05-18 20:08:58 -0600558static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
559 struct ofnode_phandle_args *out)
560{
561 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
562 out->node = offset_to_ofnode(in->node);
563 out->args_count = in->args_count;
564 memcpy(out->args, in->args, sizeof(out->args));
565}
566
567static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
568 struct ofnode_phandle_args *out)
569{
570 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
571 out->node = np_to_ofnode(in->np);
572 out->args_count = in->args_count;
573 memcpy(out->args, in->args, sizeof(out->args));
574}
575
576int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
577 const char *cells_name, int cell_count,
578 int index,
579 struct ofnode_phandle_args *out_args)
580{
581 if (ofnode_is_np(node)) {
582 struct of_phandle_args args;
583 int ret;
584
585 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay21e3b042020-09-10 18:26:17 +0200586 list_name, cells_name,
587 cell_count, index,
Mario Sixf40d82c2018-01-15 11:07:17 +0100588 &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600589 if (ret)
590 return ret;
591 ofnode_from_of_phandle_args(&args, out_args);
592 } else {
593 struct fdtdec_phandle_args args;
594 int ret;
595
596 ret = fdtdec_parse_phandle_with_args(gd->fdt_blob,
Mario Sixf40d82c2018-01-15 11:07:17 +0100597 ofnode_to_offset(node),
598 list_name, cells_name,
599 cell_count, index, &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600600 if (ret)
601 return ret;
602 ofnode_from_fdtdec_phandle_args(&args, out_args);
603 }
604
605 return 0;
606}
607
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200608int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200609 const char *cells_name, int cell_count)
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200610{
611 if (ofnode_is_np(node))
612 return of_count_phandle_with_args(ofnode_to_np(node),
Patrick Delaunayd776a842020-09-25 09:41:14 +0200613 list_name, cells_name, cell_count);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200614 else
615 return fdtdec_parse_phandle_with_args(gd->fdt_blob,
616 ofnode_to_offset(node), list_name, cells_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200617 cell_count, -1, NULL);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200618}
619
Simon Glassc4fc5622017-05-18 20:08:58 -0600620ofnode ofnode_path(const char *path)
621{
622 if (of_live_active())
623 return np_to_ofnode(of_find_node_by_path(path));
624 else
625 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
626}
627
Simon Glassef75c592022-07-30 15:52:08 -0600628ofnode ofnode_path_root(oftree tree, const char *path)
629{
630 if (of_live_active())
631 return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
632 NULL));
633 else if (*path != '/' && tree.fdt != gd->fdt_blob)
634 return ofnode_null(); /* Aliases only on control FDT */
635 else
636 return offset_to_ofnode(fdt_path_offset(tree.fdt, path));
637}
638
Simon Glasse09223c2020-01-27 08:49:46 -0700639const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600640{
641 ofnode chosen_node;
642
643 chosen_node = ofnode_path("/chosen");
644
Simon Glasse09223c2020-01-27 08:49:46 -0700645 return ofnode_read_prop(chosen_node, propname, sizep);
Simon Glassc4fc5622017-05-18 20:08:58 -0600646}
647
Simon Glasse09223c2020-01-27 08:49:46 -0700648const char *ofnode_read_chosen_string(const char *propname)
649{
650 return ofnode_read_chosen_prop(propname, NULL);
651}
652
Simon Glassc4fc5622017-05-18 20:08:58 -0600653ofnode ofnode_get_chosen_node(const char *name)
654{
655 const char *prop;
656
Simon Glasse09223c2020-01-27 08:49:46 -0700657 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600658 if (!prop)
659 return ofnode_null();
660
661 return ofnode_path(prop);
662}
663
Michal Simek92a88622020-07-28 12:51:08 +0200664const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
665{
666 ofnode node;
667
668 node = ofnode_path("/aliases");
669
670 return ofnode_read_prop(node, propname, sizep);
671}
672
673ofnode ofnode_get_aliases_node(const char *name)
674{
675 const char *prop;
676
677 prop = ofnode_read_aliases_prop(name, NULL);
678 if (!prop)
679 return ofnode_null();
680
681 debug("%s: node_path: %s\n", __func__, prop);
682
683 return ofnode_path(prop);
684}
685
developerd93c8b42020-05-02 11:35:09 +0200686int ofnode_get_child_count(ofnode parent)
687{
688 ofnode child;
689 int num = 0;
690
691 ofnode_for_each_subnode(child, parent)
692 num++;
693
694 return num;
695}
696
Simon Glassc4fc5622017-05-18 20:08:58 -0600697static int decode_timing_property(ofnode node, const char *name,
698 struct timing_entry *result)
699{
700 int length, ret = 0;
701
702 length = ofnode_read_size(node, name);
703 if (length < 0) {
704 debug("%s: could not find property %s\n",
705 ofnode_get_name(node), name);
706 return length;
707 }
708
709 if (length == sizeof(u32)) {
710 result->typ = ofnode_read_u32_default(node, name, 0);
711 result->min = result->typ;
712 result->max = result->typ;
713 } else {
714 ret = ofnode_read_u32_array(node, name, &result->min, 3);
715 }
716
717 return ret;
718}
719
720int ofnode_decode_display_timing(ofnode parent, int index,
721 struct display_timing *dt)
722{
723 int i;
724 ofnode timings, node;
725 u32 val = 0;
726 int ret = 0;
727
728 timings = ofnode_find_subnode(parent, "display-timings");
729 if (!ofnode_valid(timings))
730 return -EINVAL;
731
Simon Glass28529762017-08-05 15:45:54 -0600732 i = 0;
733 ofnode_for_each_subnode(node, timings) {
734 if (i++ == index)
735 break;
736 }
Simon Glassc4fc5622017-05-18 20:08:58 -0600737
738 if (!ofnode_valid(node))
739 return -EINVAL;
740
741 memset(dt, 0, sizeof(*dt));
742
743 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
744 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
745 ret |= decode_timing_property(node, "hactive", &dt->hactive);
746 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
747 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
748 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
749 ret |= decode_timing_property(node, "vactive", &dt->vactive);
750 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
751 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
752
753 dt->flags = 0;
754 val = ofnode_read_u32_default(node, "vsync-active", -1);
755 if (val != -1) {
756 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
757 DISPLAY_FLAGS_VSYNC_LOW;
758 }
759 val = ofnode_read_u32_default(node, "hsync-active", -1);
760 if (val != -1) {
761 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
762 DISPLAY_FLAGS_HSYNC_LOW;
763 }
764 val = ofnode_read_u32_default(node, "de-active", -1);
765 if (val != -1) {
766 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
767 DISPLAY_FLAGS_DE_LOW;
768 }
769 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
770 if (val != -1) {
771 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
772 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
773 }
774
775 if (ofnode_read_bool(node, "interlaced"))
776 dt->flags |= DISPLAY_FLAGS_INTERLACED;
777 if (ofnode_read_bool(node, "doublescan"))
778 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
779 if (ofnode_read_bool(node, "doubleclk"))
780 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
781
782 return ret;
783}
784
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +0900785const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glassc4fc5622017-05-18 20:08:58 -0600786{
Masahiro Yamada5052f1b2017-06-22 16:54:04 +0900787 if (ofnode_is_np(node))
788 return of_get_property(ofnode_to_np(node), propname, lenp);
789 else
Simon Glassc4fc5622017-05-18 20:08:58 -0600790 return fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
791 propname, lenp);
Simon Glassc4fc5622017-05-18 20:08:58 -0600792}
793
Simon Glassfec058d2022-09-06 20:27:13 -0600794int ofnode_first_property(ofnode node, struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +0100795{
796 prop->node = node;
797
798 if (ofnode_is_np(node)) {
799 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
800 if (!prop->prop)
801 return -FDT_ERR_NOTFOUND;
802 } else {
803 prop->offset =
804 fdt_first_property_offset(gd->fdt_blob,
805 ofnode_to_offset(prop->node));
806 if (prop->offset < 0)
807 return prop->offset;
808 }
809
810 return 0;
811}
812
Simon Glassfec058d2022-09-06 20:27:13 -0600813int ofnode_next_property(struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +0100814{
815 if (ofnode_is_np(prop->node)) {
816 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
817 prop->prop);
818 if (!prop->prop)
819 return -FDT_ERR_NOTFOUND;
820 } else {
821 prop->offset = fdt_next_property_offset(gd->fdt_blob,
822 prop->offset);
823 if (prop->offset < 0)
824 return prop->offset;
825 }
826
827 return 0;
828}
829
Simon Glassd0aff8b2022-09-06 20:27:14 -0600830const void *ofprop_get_property(const struct ofprop *prop,
831 const char **propname, int *lenp)
Patrick Delaunaycaee1552020-01-13 11:34:56 +0100832{
833 if (ofnode_is_np(prop->node))
834 return of_get_property_by_prop(ofnode_to_np(prop->node),
835 prop->prop, propname, lenp);
836 else
837 return fdt_getprop_by_offset(gd->fdt_blob,
838 prop->offset,
839 propname, lenp);
840}
841
Simon Glassc4fc5622017-05-18 20:08:58 -0600842fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
843 fdt_size_t *sizep)
844{
845 if (ofnode_is_np(node)) {
846 int na, ns;
847 int psize;
848 const struct device_node *np = ofnode_to_np(node);
Klaus Gogeraf4b0212017-09-20 13:50:41 +0200849 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glassc4fc5622017-05-18 20:08:58 -0600850
Klaus Gogeraf4b0212017-09-20 13:50:41 +0200851 if (!prop)
852 return FDT_ADDR_T_NONE;
Simon Glassc4fc5622017-05-18 20:08:58 -0600853 na = of_n_addr_cells(np);
Marek Vasut1638c172018-10-01 12:37:19 +0200854 ns = of_n_size_cells(np);
Simon Glassa67cc632017-05-18 20:09:27 -0600855 *sizep = of_read_number(prop + na, ns);
Marek Vasuta9dac492018-10-01 12:37:20 +0200856
Dario Binacchif8fc7032021-05-01 17:05:26 +0200857 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta9dac492018-10-01 12:37:20 +0200858 return of_translate_address(np, prop);
859 else
860 return of_read_number(prop, na);
Simon Glassc4fc5622017-05-18 20:08:58 -0600861 } else {
862 return fdtdec_get_addr_size(gd->fdt_blob,
863 ofnode_to_offset(node), property,
864 sizep);
865 }
866}
867
868const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
869 size_t sz)
870{
871 if (ofnode_is_np(node)) {
872 const struct device_node *np = ofnode_to_np(node);
873 int psize;
874 const __be32 *prop = of_get_property(np, propname, &psize);
875
876 if (!prop || sz != psize)
877 return NULL;
878 return (uint8_t *)prop;
879
880 } else {
881 return fdtdec_locate_byte_array(gd->fdt_blob,
882 ofnode_to_offset(node), propname, sz);
883 }
884}
885
886int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
887 const char *propname, struct fdt_pci_addr *addr)
888{
Masahiro Yamada5c5991e2017-06-22 17:57:50 +0900889 const fdt32_t *cell;
Simon Glassc4fc5622017-05-18 20:08:58 -0600890 int len;
891 int ret = -ENOENT;
892
893 debug("%s: %s: ", __func__, propname);
894
895 /*
896 * If we follow the pci bus bindings strictly, we should check
897 * the value of the node's parent node's #address-cells and
898 * #size-cells. They need to be 3 and 2 accordingly. However,
899 * for simplicity we skip the check here.
900 */
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +0900901 cell = ofnode_get_property(node, propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600902 if (!cell)
903 goto fail;
904
905 if ((len % FDT_PCI_REG_SIZE) == 0) {
906 int num = len / FDT_PCI_REG_SIZE;
907 int i;
908
909 for (i = 0; i < num; i++) {
910 debug("pci address #%d: %08lx %08lx %08lx\n", i,
911 (ulong)fdt32_to_cpu(cell[0]),
912 (ulong)fdt32_to_cpu(cell[1]),
913 (ulong)fdt32_to_cpu(cell[2]));
914 if ((fdt32_to_cpu(*cell) & type) == type) {
915 addr->phys_hi = fdt32_to_cpu(cell[0]);
916 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glassdfd43152019-09-25 08:55:46 -0600917 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glassc4fc5622017-05-18 20:08:58 -0600918 break;
Simon Glassc4fc5622017-05-18 20:08:58 -0600919 }
Mario Sixf40d82c2018-01-15 11:07:17 +0100920
921 cell += (FDT_PCI_ADDR_CELLS +
922 FDT_PCI_SIZE_CELLS);
Simon Glassc4fc5622017-05-18 20:08:58 -0600923 }
924
925 if (i == num) {
926 ret = -ENXIO;
927 goto fail;
928 }
929
930 return 0;
Simon Glassc4fc5622017-05-18 20:08:58 -0600931 }
932
Mario Sixf40d82c2018-01-15 11:07:17 +0100933 ret = -EINVAL;
934
Simon Glassc4fc5622017-05-18 20:08:58 -0600935fail:
936 debug("(not found)\n");
937 return ret;
938}
939
Bin Mengfa157712018-08-03 01:14:35 -0700940int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
941{
942 const char *list, *end;
943 int len;
944
945 list = ofnode_get_property(node, "compatible", &len);
946 if (!list)
947 return -ENOENT;
948
949 end = list + len;
950 while (list < end) {
951 len = strlen(list);
952 if (len >= strlen("pciVVVV,DDDD")) {
953 char *s = strstr(list, "pci");
954
955 /*
956 * check if the string is something like pciVVVV,DDDD.RR
957 * or just pciVVVV,DDDD
958 */
959 if (s && s[7] == ',' &&
960 (s[12] == '.' || s[12] == 0)) {
961 s += 3;
962 *vendor = simple_strtol(s, NULL, 16);
963
964 s += 5;
965 *device = simple_strtol(s, NULL, 16);
966
967 return 0;
968 }
969 }
970 list += (len + 1);
971 }
972
973 return -ENOENT;
974}
975
Michal Simeka253c3b2022-02-23 15:45:40 +0100976int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
977{
978 const char *list, *end;
979 int len;
980
981 list = ofnode_get_property(node, "compatible", &len);
982
983 if (!list)
984 return -ENOENT;
985
986 end = list + len;
987 while (list < end) {
988 len = strlen(list);
989
990 if (len >= strlen("ethernet-phy-idVVVV,DDDD")) {
991 char *s = strstr(list, "ethernet-phy-id");
992
993 /*
994 * check if the string is something like
995 * ethernet-phy-idVVVV,DDDD
996 */
997 if (s && s[19] == '.') {
998 s += strlen("ethernet-phy-id");
999 *vendor = simple_strtol(s, NULL, 16);
1000 s += 5;
1001 *device = simple_strtol(s, NULL, 16);
1002
1003 return 0;
1004 }
1005 }
1006 list += (len + 1);
1007 }
1008
1009 return -ENOENT;
1010}
1011
Simon Glassc4fc5622017-05-18 20:08:58 -06001012int ofnode_read_addr_cells(ofnode node)
1013{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001014 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001015 return of_n_addr_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001016 } else {
1017 int parent = fdt_parent_offset(gd->fdt_blob,
1018 ofnode_to_offset(node));
1019
1020 return fdt_address_cells(gd->fdt_blob, parent);
1021 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001022}
1023
1024int ofnode_read_size_cells(ofnode node)
1025{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001026 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001027 return of_n_size_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001028 } else {
1029 int parent = fdt_parent_offset(gd->fdt_blob,
1030 ofnode_to_offset(node));
1031
1032 return fdt_size_cells(gd->fdt_blob, parent);
1033 }
Simon Glass4191dc12017-06-12 06:21:31 -06001034}
1035
1036int ofnode_read_simple_addr_cells(ofnode node)
1037{
1038 if (ofnode_is_np(node))
1039 return of_simple_addr_cells(ofnode_to_np(node));
1040 else
1041 return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node));
1042}
1043
1044int ofnode_read_simple_size_cells(ofnode node)
1045{
1046 if (ofnode_is_np(node))
1047 return of_simple_size_cells(ofnode_to_np(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001048 else
1049 return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node));
1050}
1051
1052bool ofnode_pre_reloc(ofnode node)
1053{
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001054#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
1055 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
1056 * had property dm-pre-reloc or u-boot,dm-spl/tpl.
1057 * They are removed in final dtb (fdtgrep 2nd pass)
1058 */
1059 return true;
1060#else
Masahiro Yamada6a61dd92017-06-22 16:54:03 +09001061 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001062 return true;
Simon Glass23f22842018-10-01 12:22:18 -06001063 if (ofnode_read_bool(node, "u-boot,dm-pre-proper"))
1064 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001065
Simon Glassc4fc5622017-05-18 20:08:58 -06001066 /*
1067 * In regular builds individual spl and tpl handling both
1068 * count as handled pre-relocation for later second init.
1069 */
Masahiro Yamada6a61dd92017-06-22 16:54:03 +09001070 if (ofnode_read_bool(node, "u-boot,dm-spl") ||
1071 ofnode_read_bool(node, "u-boot,dm-tpl"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001072 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001073
1074 return false;
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001075#endif
Simon Glassc4fc5622017-05-18 20:08:58 -06001076}
Simon Glassf7bfcc42017-07-25 08:29:55 -06001077
1078int ofnode_read_resource(ofnode node, uint index, struct resource *res)
1079{
1080 if (ofnode_is_np(node)) {
1081 return of_address_to_resource(ofnode_to_np(node), index, res);
1082 } else {
1083 struct fdt_resource fres;
1084 int ret;
1085
1086 ret = fdt_get_resource(gd->fdt_blob, ofnode_to_offset(node),
1087 "reg", index, &fres);
1088 if (ret < 0)
1089 return -EINVAL;
1090 memset(res, '\0', sizeof(*res));
1091 res->start = fres.start;
1092 res->end = fres.end;
1093
1094 return 0;
1095 }
1096}
Masahiro Yamada4dada2c2017-08-26 01:12:30 +09001097
1098int ofnode_read_resource_byname(ofnode node, const char *name,
1099 struct resource *res)
1100{
1101 int index;
1102
1103 index = ofnode_stringlist_search(node, "reg-names", name);
1104 if (index < 0)
1105 return index;
1106
1107 return ofnode_read_resource(node, index, res);
1108}
Mario Sixaefac062018-01-15 11:07:19 +01001109
1110u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
1111{
1112 if (ofnode_is_np(node))
1113 return of_translate_address(ofnode_to_np(node), in_addr);
1114 else
1115 return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
1116}
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001117
Fabien Dessenne22236e02019-05-31 15:11:30 +02001118u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
1119{
1120 if (ofnode_is_np(node))
1121 return of_translate_dma_address(ofnode_to_np(node), in_addr);
1122 else
1123 return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
1124}
1125
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001126int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
1127{
1128 if (ofnode_is_np(node))
1129 return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
1130 else
1131 return fdt_get_dma_range(gd->fdt_blob, ofnode_to_offset(node),
1132 cpu, bus, size);
1133}
1134
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001135int ofnode_device_is_compatible(ofnode node, const char *compat)
1136{
1137 if (ofnode_is_np(node))
1138 return of_device_is_compatible(ofnode_to_np(node), compat,
1139 NULL, NULL);
1140 else
1141 return !fdt_node_check_compatible(gd->fdt_blob,
1142 ofnode_to_offset(node),
1143 compat);
1144}
Simon Glass954eeae2018-06-11 13:07:13 -06001145
1146ofnode ofnode_by_compatible(ofnode from, const char *compat)
1147{
1148 if (of_live_active()) {
1149 return np_to_ofnode(of_find_compatible_node(
1150 (struct device_node *)ofnode_to_np(from), NULL,
1151 compat));
1152 } else {
1153 return offset_to_ofnode(fdt_node_offset_by_compatible(
1154 gd->fdt_blob, ofnode_to_offset(from), compat));
1155 }
1156}
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001157
1158ofnode ofnode_by_prop_value(ofnode from, const char *propname,
1159 const void *propval, int proplen)
1160{
1161 if (of_live_active()) {
1162 return np_to_ofnode(of_find_node_by_prop_value(
1163 (struct device_node *)ofnode_to_np(from), propname,
1164 propval, proplen));
1165 } else {
1166 return offset_to_ofnode(fdt_node_offset_by_prop_value(
1167 gd->fdt_blob, ofnode_to_offset(from),
1168 propname, propval, proplen));
1169 }
1170}
Mario Six047dafc2018-06-26 08:46:48 +02001171
Simon Glass5e2cd5e2022-07-30 15:52:10 -06001172int ofnode_write_prop(ofnode node, const char *propname, const void *value,
1173 int len)
Mario Six047dafc2018-06-26 08:46:48 +02001174{
Simon Glass3ee3d152022-07-30 15:52:13 -06001175 if (of_live_active())
Simon Glass9036c5c2022-09-06 20:27:04 -06001176 return of_write_prop(ofnode_to_np(node), propname, len, value);
Simon Glass3ee3d152022-07-30 15:52:13 -06001177 else
1178 return fdt_setprop((void *)gd->fdt_blob, ofnode_to_offset(node),
1179 propname, value, len);
Mario Six047dafc2018-06-26 08:46:48 +02001180
1181 return 0;
1182}
1183
1184int ofnode_write_string(ofnode node, const char *propname, const char *value)
1185{
Mario Six047dafc2018-06-26 08:46:48 +02001186 assert(ofnode_valid(node));
1187
1188 debug("%s: %s = %s", __func__, propname, value);
1189
Simon Glass5e2cd5e2022-07-30 15:52:10 -06001190 return ofnode_write_prop(node, propname, value, strlen(value) + 1);
Mario Six047dafc2018-06-26 08:46:48 +02001191}
1192
Simon Glassd28e31e2022-07-30 15:52:14 -06001193int ofnode_write_u32(ofnode node, const char *propname, u32 value)
1194{
1195 fdt32_t *val;
1196
1197 assert(ofnode_valid(node));
1198
1199 log_debug("%s = %x", propname, value);
1200 val = malloc(sizeof(*val));
1201 if (!val)
1202 return -ENOMEM;
1203 *val = cpu_to_fdt32(value);
1204
1205 return ofnode_write_prop(node, propname, val, sizeof(value));
1206}
1207
Mario Six047dafc2018-06-26 08:46:48 +02001208int ofnode_set_enabled(ofnode node, bool value)
1209{
Mario Six047dafc2018-06-26 08:46:48 +02001210 assert(ofnode_valid(node));
1211
1212 if (value)
1213 return ofnode_write_string(node, "status", "okay");
1214 else
Bin Menga9274aa2019-07-05 09:23:17 -07001215 return ofnode_write_string(node, "status", "disabled");
Mario Six047dafc2018-06-26 08:46:48 +02001216}
Simon Glass0034d962021-08-07 07:24:01 -06001217
1218bool ofnode_conf_read_bool(const char *prop_name)
1219{
1220 ofnode node;
1221
1222 node = ofnode_path("/config");
1223 if (!ofnode_valid(node))
1224 return false;
1225
1226 return ofnode_read_bool(node, prop_name);
1227}
1228
1229int ofnode_conf_read_int(const char *prop_name, int default_val)
1230{
1231 ofnode node;
1232
1233 node = ofnode_path("/config");
1234 if (!ofnode_valid(node))
1235 return default_val;
1236
1237 return ofnode_read_u32_default(node, prop_name, default_val);
1238}
1239
1240const char *ofnode_conf_read_str(const char *prop_name)
1241{
1242 ofnode node;
1243
1244 node = ofnode_path("/config");
1245 if (!ofnode_valid(node))
1246 return NULL;
1247
1248 return ofnode_read_string(node, prop_name);
1249}
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001250
1251ofnode ofnode_get_phy_node(ofnode node)
1252{
1253 /* DT node properties that reference a PHY node */
1254 static const char * const phy_handle_str[] = {
1255 "phy-handle", "phy", "phy-device",
1256 };
1257 struct ofnode_phandle_args args = {
1258 .node = ofnode_null()
1259 };
1260 int i;
1261
1262 assert(ofnode_valid(node));
1263
1264 for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
1265 if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
1266 NULL, 0, 0, &args))
1267 break;
1268
1269 return args.node;
1270}
Marek Behúnbc194772022-04-07 00:33:01 +02001271
1272phy_interface_t ofnode_read_phy_mode(ofnode node)
1273{
1274 const char *mode;
1275 int i;
1276
1277 assert(ofnode_valid(node));
1278
1279 mode = ofnode_read_string(node, "phy-mode");
1280 if (!mode)
1281 mode = ofnode_read_string(node, "phy-connection-type");
1282
1283 if (!mode)
Marek Behún48631e42022-04-07 00:33:03 +02001284 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001285
Marek Behún21a18362022-04-07 00:33:02 +02001286 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
Marek Behúnbc194772022-04-07 00:33:01 +02001287 if (!strcmp(mode, phy_interface_strings[i]))
1288 return i;
1289
1290 debug("%s: Invalid PHY interface '%s'\n", __func__, mode);
1291
Marek Behún48631e42022-04-07 00:33:03 +02001292 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001293}
Simon Glass56bc3322022-09-06 20:27:02 -06001294
1295int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
1296{
1297 ofnode subnode;
1298 int ret = 0;
1299
1300 assert(ofnode_valid(node));
1301
1302 if (ofnode_is_np(node)) {
1303 struct device_node *np, *child;
1304
1305 np = (struct device_node *)ofnode_to_np(node);
1306 ret = of_add_subnode(np, name, -1, &child);
1307 if (ret && ret != -EEXIST)
1308 return ret;
1309 subnode = np_to_ofnode(child);
1310 } else {
1311 void *fdt = (void *)gd->fdt_blob;
1312 int poffset = ofnode_to_offset(node);
1313 int offset;
1314
1315 offset = fdt_add_subnode(fdt, poffset, name);
1316 if (offset == -FDT_ERR_EXISTS) {
1317 offset = fdt_subnode_offset(fdt, poffset, name);
1318 ret = -EEXIST;
1319 }
1320 if (offset < 0)
1321 return -EINVAL;
1322 subnode = offset_to_ofnode(offset);
1323 }
1324
1325 *subnodep = subnode;
1326
1327 return ret; /* 0 or -EEXIST */
1328}