blob: 2feca567a880a14dc0fcfb9ef68a1cf17cf8418a [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 {
299 return fdtdec_get_int_array(gd->fdt_blob,
300 ofnode_to_offset(node), propname,
301 out_values, sz);
302 }
303}
304
Simon Glass39f1d282020-12-16 17:25:06 -0700305#if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
Simon Glass5de5b3b2020-11-28 17:50:02 -0700306bool ofnode_is_enabled(ofnode node)
307{
308 if (ofnode_is_np(node)) {
309 return of_device_is_available(ofnode_to_np(node));
310 } else {
311 return fdtdec_get_is_enabled(gd->fdt_blob,
312 ofnode_to_offset(node));
313 }
314}
315
Simon Glassc4fc5622017-05-18 20:08:58 -0600316ofnode ofnode_first_subnode(ofnode node)
317{
318 assert(ofnode_valid(node));
319 if (ofnode_is_np(node))
320 return np_to_ofnode(node.np->child);
321
322 return offset_to_ofnode(
323 fdt_first_subnode(gd->fdt_blob, ofnode_to_offset(node)));
324}
325
326ofnode ofnode_next_subnode(ofnode node)
327{
328 assert(ofnode_valid(node));
329 if (ofnode_is_np(node))
330 return np_to_ofnode(node.np->sibling);
331
332 return offset_to_ofnode(
333 fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node)));
334}
Simon Glass39f1d282020-12-16 17:25:06 -0700335#endif /* !DM_INLINE_OFNODE */
Simon Glassc4fc5622017-05-18 20:08:58 -0600336
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100337ofnode ofnode_get_parent(ofnode node)
338{
339 ofnode parent;
340
341 assert(ofnode_valid(node));
342 if (ofnode_is_np(node))
343 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
344 else
345 parent.of_offset = fdt_parent_offset(gd->fdt_blob,
346 ofnode_to_offset(node));
347
348 return parent;
349}
350
Simon Glassc4fc5622017-05-18 20:08:58 -0600351const char *ofnode_get_name(ofnode node)
352{
Kever Yang8d7976d2019-07-19 11:23:47 +0800353 if (!ofnode_valid(node)) {
354 debug("%s node not valid\n", __func__);
355 return NULL;
356 }
357
Simon Glassc4fc5622017-05-18 20:08:58 -0600358 if (ofnode_is_np(node))
359 return strrchr(node.np->full_name, '/') + 1;
360
361 return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL);
362}
363
Marek Behúne897e3c2021-05-26 14:08:18 +0200364int ofnode_get_path(ofnode node, char *buf, int buflen)
365{
366 assert(ofnode_valid(node));
367
368 if (ofnode_is_np(node)) {
369 if (strlen(node.np->full_name) >= buflen)
370 return -ENOSPC;
371
372 strcpy(buf, node.np->full_name);
373
374 return 0;
375 } else {
376 int res;
377
378 res = fdt_get_path(gd->fdt_blob, ofnode_to_offset(node), buf,
379 buflen);
380 if (!res)
381 return res;
382 else if (res == -FDT_ERR_NOSPACE)
383 return -ENOSPC;
384 else
385 return -EINVAL;
386 }
387}
388
Kever Yang37df0e02018-02-23 17:38:50 +0100389ofnode ofnode_get_by_phandle(uint phandle)
390{
391 ofnode node;
392
393 if (of_live_active())
Simon Glass176dd432022-09-06 20:26:57 -0600394 node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
Kever Yang37df0e02018-02-23 17:38:50 +0100395 else
396 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
397 phandle);
398
399 return node;
400}
401
Marek Behún177ab7f2021-05-26 14:08:17 +0200402static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
403 fdt_size_t *size, bool translate)
Simon Glass049ae1b2017-05-18 20:09:01 -0600404{
Keerthy34222a32018-11-19 11:44:47 +0530405 int na, ns;
Keerthy34222a32018-11-19 11:44:47 +0530406
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800407 if (size)
408 *size = FDT_SIZE_T_NONE;
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800409
Simon Glass049ae1b2017-05-18 20:09:01 -0600410 if (ofnode_is_np(node)) {
411 const __be32 *prop_val;
Simon Glass47f85de2019-09-25 08:55:50 -0600412 u64 size64;
Simon Glass049ae1b2017-05-18 20:09:01 -0600413 uint flags;
Simon Glass049ae1b2017-05-18 20:09:01 -0600414
Simon Glass47f85de2019-09-25 08:55:50 -0600415 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
416 &flags);
Simon Glass049ae1b2017-05-18 20:09:01 -0600417 if (!prop_val)
418 return FDT_ADDR_T_NONE;
Chen Guanqiao2d1034b2021-07-12 15:40:20 +0800419
Simon Glass47f85de2019-09-25 08:55:50 -0600420 if (size)
421 *size = size64;
Mario Sixd007ebc2017-12-20 09:52:12 +0100422
Mario Six35616ef2018-03-12 14:53:33 +0100423 ns = of_n_size_cells(ofnode_to_np(node));
424
Marek Behún177ab7f2021-05-26 14:08:17 +0200425 if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Sixd007ebc2017-12-20 09:52:12 +0100426 return of_translate_address(ofnode_to_np(node), prop_val);
427 } else {
428 na = of_n_addr_cells(ofnode_to_np(node));
429 return of_read_number(prop_val, na);
430 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600431 } else {
Keerthy34222a32018-11-19 11:44:47 +0530432 na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
433 ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
434 return fdtdec_get_addr_size_fixed(gd->fdt_blob,
435 ofnode_to_offset(node), "reg",
Marek Behún177ab7f2021-05-26 14:08:17 +0200436 index, na, ns, size,
437 translate);
Simon Glass049ae1b2017-05-18 20:09:01 -0600438 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600439}
440
Marek Behún177ab7f2021-05-26 14:08:17 +0200441fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
442{
443 return __ofnode_get_addr_size_index(node, index, size, true);
444}
445
446fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
447 fdt_size_t *size)
448{
449 return __ofnode_get_addr_size_index(node, index, size, false);
450}
451
Keerthyd332e6e2019-04-24 17:19:53 +0530452fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
453{
454 fdt_size_t size;
455
456 return ofnode_get_addr_size_index(node, index, &size);
457}
458
Simon Glass049ae1b2017-05-18 20:09:01 -0600459fdt_addr_t ofnode_get_addr(ofnode node)
460{
461 return ofnode_get_addr_index(node, 0);
462}
463
Chen Guanqiao223f17d2021-04-12 14:51:11 +0800464fdt_size_t ofnode_get_size(ofnode node)
465{
466 fdt_size_t size;
467
468 ofnode_get_addr_size_index(node, 0, &size);
469
470 return size;
471}
472
Simon Glassc4fc5622017-05-18 20:08:58 -0600473int ofnode_stringlist_search(ofnode node, const char *property,
474 const char *string)
475{
476 if (ofnode_is_np(node)) {
477 return of_property_match_string(ofnode_to_np(node),
478 property, string);
479 } else {
480 int ret;
481
482 ret = fdt_stringlist_search(gd->fdt_blob,
483 ofnode_to_offset(node), property,
484 string);
485 if (ret == -FDT_ERR_NOTFOUND)
486 return -ENODATA;
487 else if (ret < 0)
488 return -EINVAL;
489
490 return ret;
491 }
492}
493
494int ofnode_read_string_index(ofnode node, const char *property, int index,
495 const char **outp)
496{
497 if (ofnode_is_np(node)) {
498 return of_property_read_string_index(ofnode_to_np(node),
499 property, index, outp);
500 } else {
501 int len;
502
503 *outp = fdt_stringlist_get(gd->fdt_blob, ofnode_to_offset(node),
504 property, index, &len);
505 if (len < 0)
506 return -EINVAL;
507 return 0;
508 }
509}
510
Simon Glass5fdb0052017-06-12 06:21:28 -0600511int ofnode_read_string_count(ofnode node, const char *property)
512{
513 if (ofnode_is_np(node)) {
514 return of_property_count_strings(ofnode_to_np(node), property);
515 } else {
516 return fdt_stringlist_count(gd->fdt_blob,
517 ofnode_to_offset(node), property);
518 }
519}
520
Simon Glass9580bfc2021-10-23 17:26:07 -0600521int ofnode_read_string_list(ofnode node, const char *property,
522 const char ***listp)
523{
524 const char **prop;
525 int count;
526 int i;
527
528 *listp = NULL;
529 count = ofnode_read_string_count(node, property);
530 if (count < 0)
531 return count;
532 if (!count)
533 return 0;
534
535 prop = calloc(count + 1, sizeof(char *));
536 if (!prop)
537 return -ENOMEM;
538
539 for (i = 0; i < count; i++)
540 ofnode_read_string_index(node, property, i, &prop[i]);
541 prop[count] = NULL;
542 *listp = prop;
543
544 return count;
545}
546
Simon Glassc4fc5622017-05-18 20:08:58 -0600547static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
548 struct ofnode_phandle_args *out)
549{
550 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
551 out->node = offset_to_ofnode(in->node);
552 out->args_count = in->args_count;
553 memcpy(out->args, in->args, sizeof(out->args));
554}
555
556static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
557 struct ofnode_phandle_args *out)
558{
559 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
560 out->node = np_to_ofnode(in->np);
561 out->args_count = in->args_count;
562 memcpy(out->args, in->args, sizeof(out->args));
563}
564
565int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
566 const char *cells_name, int cell_count,
567 int index,
568 struct ofnode_phandle_args *out_args)
569{
570 if (ofnode_is_np(node)) {
571 struct of_phandle_args args;
572 int ret;
573
574 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay21e3b042020-09-10 18:26:17 +0200575 list_name, cells_name,
576 cell_count, index,
Mario Sixf40d82c2018-01-15 11:07:17 +0100577 &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600578 if (ret)
579 return ret;
580 ofnode_from_of_phandle_args(&args, out_args);
581 } else {
582 struct fdtdec_phandle_args args;
583 int ret;
584
585 ret = fdtdec_parse_phandle_with_args(gd->fdt_blob,
Mario Sixf40d82c2018-01-15 11:07:17 +0100586 ofnode_to_offset(node),
587 list_name, cells_name,
588 cell_count, index, &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600589 if (ret)
590 return ret;
591 ofnode_from_fdtdec_phandle_args(&args, out_args);
592 }
593
594 return 0;
595}
596
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200597int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200598 const char *cells_name, int cell_count)
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200599{
600 if (ofnode_is_np(node))
601 return of_count_phandle_with_args(ofnode_to_np(node),
Patrick Delaunayd776a842020-09-25 09:41:14 +0200602 list_name, cells_name, cell_count);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200603 else
604 return fdtdec_parse_phandle_with_args(gd->fdt_blob,
605 ofnode_to_offset(node), list_name, cells_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200606 cell_count, -1, NULL);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200607}
608
Simon Glassc4fc5622017-05-18 20:08:58 -0600609ofnode ofnode_path(const char *path)
610{
611 if (of_live_active())
612 return np_to_ofnode(of_find_node_by_path(path));
613 else
614 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
615}
616
Simon Glassef75c592022-07-30 15:52:08 -0600617ofnode ofnode_path_root(oftree tree, const char *path)
618{
619 if (of_live_active())
620 return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
621 NULL));
622 else if (*path != '/' && tree.fdt != gd->fdt_blob)
623 return ofnode_null(); /* Aliases only on control FDT */
624 else
625 return offset_to_ofnode(fdt_path_offset(tree.fdt, path));
626}
627
Simon Glasse09223c2020-01-27 08:49:46 -0700628const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600629{
630 ofnode chosen_node;
631
632 chosen_node = ofnode_path("/chosen");
633
Simon Glasse09223c2020-01-27 08:49:46 -0700634 return ofnode_read_prop(chosen_node, propname, sizep);
Simon Glassc4fc5622017-05-18 20:08:58 -0600635}
636
Simon Glasse09223c2020-01-27 08:49:46 -0700637const char *ofnode_read_chosen_string(const char *propname)
638{
639 return ofnode_read_chosen_prop(propname, NULL);
640}
641
Simon Glassc4fc5622017-05-18 20:08:58 -0600642ofnode ofnode_get_chosen_node(const char *name)
643{
644 const char *prop;
645
Simon Glasse09223c2020-01-27 08:49:46 -0700646 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600647 if (!prop)
648 return ofnode_null();
649
650 return ofnode_path(prop);
651}
652
Michal Simek92a88622020-07-28 12:51:08 +0200653const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
654{
655 ofnode node;
656
657 node = ofnode_path("/aliases");
658
659 return ofnode_read_prop(node, propname, sizep);
660}
661
662ofnode ofnode_get_aliases_node(const char *name)
663{
664 const char *prop;
665
666 prop = ofnode_read_aliases_prop(name, NULL);
667 if (!prop)
668 return ofnode_null();
669
670 debug("%s: node_path: %s\n", __func__, prop);
671
672 return ofnode_path(prop);
673}
674
developerd93c8b42020-05-02 11:35:09 +0200675int ofnode_get_child_count(ofnode parent)
676{
677 ofnode child;
678 int num = 0;
679
680 ofnode_for_each_subnode(child, parent)
681 num++;
682
683 return num;
684}
685
Simon Glassc4fc5622017-05-18 20:08:58 -0600686static int decode_timing_property(ofnode node, const char *name,
687 struct timing_entry *result)
688{
689 int length, ret = 0;
690
691 length = ofnode_read_size(node, name);
692 if (length < 0) {
693 debug("%s: could not find property %s\n",
694 ofnode_get_name(node), name);
695 return length;
696 }
697
698 if (length == sizeof(u32)) {
699 result->typ = ofnode_read_u32_default(node, name, 0);
700 result->min = result->typ;
701 result->max = result->typ;
702 } else {
703 ret = ofnode_read_u32_array(node, name, &result->min, 3);
704 }
705
706 return ret;
707}
708
709int ofnode_decode_display_timing(ofnode parent, int index,
710 struct display_timing *dt)
711{
712 int i;
713 ofnode timings, node;
714 u32 val = 0;
715 int ret = 0;
716
717 timings = ofnode_find_subnode(parent, "display-timings");
718 if (!ofnode_valid(timings))
719 return -EINVAL;
720
Simon Glass28529762017-08-05 15:45:54 -0600721 i = 0;
722 ofnode_for_each_subnode(node, timings) {
723 if (i++ == index)
724 break;
725 }
Simon Glassc4fc5622017-05-18 20:08:58 -0600726
727 if (!ofnode_valid(node))
728 return -EINVAL;
729
730 memset(dt, 0, sizeof(*dt));
731
732 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
733 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
734 ret |= decode_timing_property(node, "hactive", &dt->hactive);
735 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
736 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
737 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
738 ret |= decode_timing_property(node, "vactive", &dt->vactive);
739 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
740 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
741
742 dt->flags = 0;
743 val = ofnode_read_u32_default(node, "vsync-active", -1);
744 if (val != -1) {
745 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
746 DISPLAY_FLAGS_VSYNC_LOW;
747 }
748 val = ofnode_read_u32_default(node, "hsync-active", -1);
749 if (val != -1) {
750 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
751 DISPLAY_FLAGS_HSYNC_LOW;
752 }
753 val = ofnode_read_u32_default(node, "de-active", -1);
754 if (val != -1) {
755 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
756 DISPLAY_FLAGS_DE_LOW;
757 }
758 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
759 if (val != -1) {
760 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
761 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
762 }
763
764 if (ofnode_read_bool(node, "interlaced"))
765 dt->flags |= DISPLAY_FLAGS_INTERLACED;
766 if (ofnode_read_bool(node, "doublescan"))
767 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
768 if (ofnode_read_bool(node, "doubleclk"))
769 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
770
771 return ret;
772}
773
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +0900774const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glassc4fc5622017-05-18 20:08:58 -0600775{
Masahiro Yamada5052f1b2017-06-22 16:54:04 +0900776 if (ofnode_is_np(node))
777 return of_get_property(ofnode_to_np(node), propname, lenp);
778 else
Simon Glassc4fc5622017-05-18 20:08:58 -0600779 return fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
780 propname, lenp);
Simon Glassc4fc5622017-05-18 20:08:58 -0600781}
782
Simon Glassfec058d2022-09-06 20:27:13 -0600783int ofnode_first_property(ofnode node, struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +0100784{
785 prop->node = node;
786
787 if (ofnode_is_np(node)) {
788 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
789 if (!prop->prop)
790 return -FDT_ERR_NOTFOUND;
791 } else {
792 prop->offset =
793 fdt_first_property_offset(gd->fdt_blob,
794 ofnode_to_offset(prop->node));
795 if (prop->offset < 0)
796 return prop->offset;
797 }
798
799 return 0;
800}
801
Simon Glassfec058d2022-09-06 20:27:13 -0600802int ofnode_next_property(struct ofprop *prop)
Patrick Delaunaycaee1552020-01-13 11:34:56 +0100803{
804 if (ofnode_is_np(prop->node)) {
805 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
806 prop->prop);
807 if (!prop->prop)
808 return -FDT_ERR_NOTFOUND;
809 } else {
810 prop->offset = fdt_next_property_offset(gd->fdt_blob,
811 prop->offset);
812 if (prop->offset < 0)
813 return prop->offset;
814 }
815
816 return 0;
817}
818
819const void *ofnode_get_property_by_prop(const struct ofprop *prop,
820 const char **propname, int *lenp)
821{
822 if (ofnode_is_np(prop->node))
823 return of_get_property_by_prop(ofnode_to_np(prop->node),
824 prop->prop, propname, lenp);
825 else
826 return fdt_getprop_by_offset(gd->fdt_blob,
827 prop->offset,
828 propname, lenp);
829}
830
Simon Glassc4fc5622017-05-18 20:08:58 -0600831bool ofnode_is_available(ofnode node)
832{
833 if (ofnode_is_np(node))
834 return of_device_is_available(ofnode_to_np(node));
835 else
836 return fdtdec_get_is_enabled(gd->fdt_blob,
837 ofnode_to_offset(node));
838}
839
840fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
841 fdt_size_t *sizep)
842{
843 if (ofnode_is_np(node)) {
844 int na, ns;
845 int psize;
846 const struct device_node *np = ofnode_to_np(node);
Klaus Gogeraf4b0212017-09-20 13:50:41 +0200847 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glassc4fc5622017-05-18 20:08:58 -0600848
Klaus Gogeraf4b0212017-09-20 13:50:41 +0200849 if (!prop)
850 return FDT_ADDR_T_NONE;
Simon Glassc4fc5622017-05-18 20:08:58 -0600851 na = of_n_addr_cells(np);
Marek Vasut1638c172018-10-01 12:37:19 +0200852 ns = of_n_size_cells(np);
Simon Glassa67cc632017-05-18 20:09:27 -0600853 *sizep = of_read_number(prop + na, ns);
Marek Vasuta9dac492018-10-01 12:37:20 +0200854
Dario Binacchif8fc7032021-05-01 17:05:26 +0200855 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta9dac492018-10-01 12:37:20 +0200856 return of_translate_address(np, prop);
857 else
858 return of_read_number(prop, na);
Simon Glassc4fc5622017-05-18 20:08:58 -0600859 } else {
860 return fdtdec_get_addr_size(gd->fdt_blob,
861 ofnode_to_offset(node), property,
862 sizep);
863 }
864}
865
866const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
867 size_t sz)
868{
869 if (ofnode_is_np(node)) {
870 const struct device_node *np = ofnode_to_np(node);
871 int psize;
872 const __be32 *prop = of_get_property(np, propname, &psize);
873
874 if (!prop || sz != psize)
875 return NULL;
876 return (uint8_t *)prop;
877
878 } else {
879 return fdtdec_locate_byte_array(gd->fdt_blob,
880 ofnode_to_offset(node), propname, sz);
881 }
882}
883
884int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
885 const char *propname, struct fdt_pci_addr *addr)
886{
Masahiro Yamada5c5991e2017-06-22 17:57:50 +0900887 const fdt32_t *cell;
Simon Glassc4fc5622017-05-18 20:08:58 -0600888 int len;
889 int ret = -ENOENT;
890
891 debug("%s: %s: ", __func__, propname);
892
893 /*
894 * If we follow the pci bus bindings strictly, we should check
895 * the value of the node's parent node's #address-cells and
896 * #size-cells. They need to be 3 and 2 accordingly. However,
897 * for simplicity we skip the check here.
898 */
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +0900899 cell = ofnode_get_property(node, propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600900 if (!cell)
901 goto fail;
902
903 if ((len % FDT_PCI_REG_SIZE) == 0) {
904 int num = len / FDT_PCI_REG_SIZE;
905 int i;
906
907 for (i = 0; i < num; i++) {
908 debug("pci address #%d: %08lx %08lx %08lx\n", i,
909 (ulong)fdt32_to_cpu(cell[0]),
910 (ulong)fdt32_to_cpu(cell[1]),
911 (ulong)fdt32_to_cpu(cell[2]));
912 if ((fdt32_to_cpu(*cell) & type) == type) {
913 addr->phys_hi = fdt32_to_cpu(cell[0]);
914 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glassdfd43152019-09-25 08:55:46 -0600915 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glassc4fc5622017-05-18 20:08:58 -0600916 break;
Simon Glassc4fc5622017-05-18 20:08:58 -0600917 }
Mario Sixf40d82c2018-01-15 11:07:17 +0100918
919 cell += (FDT_PCI_ADDR_CELLS +
920 FDT_PCI_SIZE_CELLS);
Simon Glassc4fc5622017-05-18 20:08:58 -0600921 }
922
923 if (i == num) {
924 ret = -ENXIO;
925 goto fail;
926 }
927
928 return 0;
Simon Glassc4fc5622017-05-18 20:08:58 -0600929 }
930
Mario Sixf40d82c2018-01-15 11:07:17 +0100931 ret = -EINVAL;
932
Simon Glassc4fc5622017-05-18 20:08:58 -0600933fail:
934 debug("(not found)\n");
935 return ret;
936}
937
Bin Mengfa157712018-08-03 01:14:35 -0700938int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
939{
940 const char *list, *end;
941 int len;
942
943 list = ofnode_get_property(node, "compatible", &len);
944 if (!list)
945 return -ENOENT;
946
947 end = list + len;
948 while (list < end) {
949 len = strlen(list);
950 if (len >= strlen("pciVVVV,DDDD")) {
951 char *s = strstr(list, "pci");
952
953 /*
954 * check if the string is something like pciVVVV,DDDD.RR
955 * or just pciVVVV,DDDD
956 */
957 if (s && s[7] == ',' &&
958 (s[12] == '.' || s[12] == 0)) {
959 s += 3;
960 *vendor = simple_strtol(s, NULL, 16);
961
962 s += 5;
963 *device = simple_strtol(s, NULL, 16);
964
965 return 0;
966 }
967 }
968 list += (len + 1);
969 }
970
971 return -ENOENT;
972}
973
Michal Simeka253c3b2022-02-23 15:45:40 +0100974int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
975{
976 const char *list, *end;
977 int len;
978
979 list = ofnode_get_property(node, "compatible", &len);
980
981 if (!list)
982 return -ENOENT;
983
984 end = list + len;
985 while (list < end) {
986 len = strlen(list);
987
988 if (len >= strlen("ethernet-phy-idVVVV,DDDD")) {
989 char *s = strstr(list, "ethernet-phy-id");
990
991 /*
992 * check if the string is something like
993 * ethernet-phy-idVVVV,DDDD
994 */
995 if (s && s[19] == '.') {
996 s += strlen("ethernet-phy-id");
997 *vendor = simple_strtol(s, NULL, 16);
998 s += 5;
999 *device = simple_strtol(s, NULL, 16);
1000
1001 return 0;
1002 }
1003 }
1004 list += (len + 1);
1005 }
1006
1007 return -ENOENT;
1008}
1009
Simon Glassc4fc5622017-05-18 20:08:58 -06001010int ofnode_read_addr_cells(ofnode node)
1011{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001012 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001013 return of_n_addr_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001014 } else {
1015 int parent = fdt_parent_offset(gd->fdt_blob,
1016 ofnode_to_offset(node));
1017
1018 return fdt_address_cells(gd->fdt_blob, parent);
1019 }
Simon Glassc4fc5622017-05-18 20:08:58 -06001020}
1021
1022int ofnode_read_size_cells(ofnode node)
1023{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001024 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -06001025 return of_n_size_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +02001026 } else {
1027 int parent = fdt_parent_offset(gd->fdt_blob,
1028 ofnode_to_offset(node));
1029
1030 return fdt_size_cells(gd->fdt_blob, parent);
1031 }
Simon Glass4191dc12017-06-12 06:21:31 -06001032}
1033
1034int ofnode_read_simple_addr_cells(ofnode node)
1035{
1036 if (ofnode_is_np(node))
1037 return of_simple_addr_cells(ofnode_to_np(node));
1038 else
1039 return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node));
1040}
1041
1042int ofnode_read_simple_size_cells(ofnode node)
1043{
1044 if (ofnode_is_np(node))
1045 return of_simple_size_cells(ofnode_to_np(node));
Simon Glassc4fc5622017-05-18 20:08:58 -06001046 else
1047 return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node));
1048}
1049
1050bool ofnode_pre_reloc(ofnode node)
1051{
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001052#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
1053 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
1054 * had property dm-pre-reloc or u-boot,dm-spl/tpl.
1055 * They are removed in final dtb (fdtgrep 2nd pass)
1056 */
1057 return true;
1058#else
Masahiro Yamada6a61dd92017-06-22 16:54:03 +09001059 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001060 return true;
Simon Glass23f22842018-10-01 12:22:18 -06001061 if (ofnode_read_bool(node, "u-boot,dm-pre-proper"))
1062 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001063
Simon Glassc4fc5622017-05-18 20:08:58 -06001064 /*
1065 * In regular builds individual spl and tpl handling both
1066 * count as handled pre-relocation for later second init.
1067 */
Masahiro Yamada6a61dd92017-06-22 16:54:03 +09001068 if (ofnode_read_bool(node, "u-boot,dm-spl") ||
1069 ofnode_read_bool(node, "u-boot,dm-tpl"))
Simon Glassc4fc5622017-05-18 20:08:58 -06001070 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -06001071
1072 return false;
Patrick Delaunay0b025b82019-02-11 12:49:57 +01001073#endif
Simon Glassc4fc5622017-05-18 20:08:58 -06001074}
Simon Glassf7bfcc42017-07-25 08:29:55 -06001075
1076int ofnode_read_resource(ofnode node, uint index, struct resource *res)
1077{
1078 if (ofnode_is_np(node)) {
1079 return of_address_to_resource(ofnode_to_np(node), index, res);
1080 } else {
1081 struct fdt_resource fres;
1082 int ret;
1083
1084 ret = fdt_get_resource(gd->fdt_blob, ofnode_to_offset(node),
1085 "reg", index, &fres);
1086 if (ret < 0)
1087 return -EINVAL;
1088 memset(res, '\0', sizeof(*res));
1089 res->start = fres.start;
1090 res->end = fres.end;
1091
1092 return 0;
1093 }
1094}
Masahiro Yamada4dada2c2017-08-26 01:12:30 +09001095
1096int ofnode_read_resource_byname(ofnode node, const char *name,
1097 struct resource *res)
1098{
1099 int index;
1100
1101 index = ofnode_stringlist_search(node, "reg-names", name);
1102 if (index < 0)
1103 return index;
1104
1105 return ofnode_read_resource(node, index, res);
1106}
Mario Sixaefac062018-01-15 11:07:19 +01001107
1108u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
1109{
1110 if (ofnode_is_np(node))
1111 return of_translate_address(ofnode_to_np(node), in_addr);
1112 else
1113 return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
1114}
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001115
Fabien Dessenne22236e02019-05-31 15:11:30 +02001116u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
1117{
1118 if (ofnode_is_np(node))
1119 return of_translate_dma_address(ofnode_to_np(node), in_addr);
1120 else
1121 return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
1122}
1123
Nicolas Saenz Julienne50d2fa42021-01-12 13:55:22 +01001124int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
1125{
1126 if (ofnode_is_np(node))
1127 return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
1128 else
1129 return fdt_get_dma_range(gd->fdt_blob, ofnode_to_offset(node),
1130 cpu, bus, size);
1131}
1132
Masahiro Yamada9349bcc2018-04-19 12:14:02 +09001133int ofnode_device_is_compatible(ofnode node, const char *compat)
1134{
1135 if (ofnode_is_np(node))
1136 return of_device_is_compatible(ofnode_to_np(node), compat,
1137 NULL, NULL);
1138 else
1139 return !fdt_node_check_compatible(gd->fdt_blob,
1140 ofnode_to_offset(node),
1141 compat);
1142}
Simon Glass954eeae2018-06-11 13:07:13 -06001143
1144ofnode ofnode_by_compatible(ofnode from, const char *compat)
1145{
1146 if (of_live_active()) {
1147 return np_to_ofnode(of_find_compatible_node(
1148 (struct device_node *)ofnode_to_np(from), NULL,
1149 compat));
1150 } else {
1151 return offset_to_ofnode(fdt_node_offset_by_compatible(
1152 gd->fdt_blob, ofnode_to_offset(from), compat));
1153 }
1154}
Jens Wiklander7b68dad2018-08-20 11:09:58 +02001155
1156ofnode ofnode_by_prop_value(ofnode from, const char *propname,
1157 const void *propval, int proplen)
1158{
1159 if (of_live_active()) {
1160 return np_to_ofnode(of_find_node_by_prop_value(
1161 (struct device_node *)ofnode_to_np(from), propname,
1162 propval, proplen));
1163 } else {
1164 return offset_to_ofnode(fdt_node_offset_by_prop_value(
1165 gd->fdt_blob, ofnode_to_offset(from),
1166 propname, propval, proplen));
1167 }
1168}
Mario Six047dafc2018-06-26 08:46:48 +02001169
Simon Glass5e2cd5e2022-07-30 15:52:10 -06001170int ofnode_write_prop(ofnode node, const char *propname, const void *value,
1171 int len)
Mario Six047dafc2018-06-26 08:46:48 +02001172{
Simon Glass3ee3d152022-07-30 15:52:13 -06001173 if (of_live_active())
Simon Glass9036c5c2022-09-06 20:27:04 -06001174 return of_write_prop(ofnode_to_np(node), propname, len, value);
Simon Glass3ee3d152022-07-30 15:52:13 -06001175 else
1176 return fdt_setprop((void *)gd->fdt_blob, ofnode_to_offset(node),
1177 propname, value, len);
Mario Six047dafc2018-06-26 08:46:48 +02001178
1179 return 0;
1180}
1181
1182int ofnode_write_string(ofnode node, const char *propname, const char *value)
1183{
Mario Six047dafc2018-06-26 08:46:48 +02001184 assert(ofnode_valid(node));
1185
1186 debug("%s: %s = %s", __func__, propname, value);
1187
Simon Glass5e2cd5e2022-07-30 15:52:10 -06001188 return ofnode_write_prop(node, propname, value, strlen(value) + 1);
Mario Six047dafc2018-06-26 08:46:48 +02001189}
1190
Simon Glassd28e31e2022-07-30 15:52:14 -06001191int ofnode_write_u32(ofnode node, const char *propname, u32 value)
1192{
1193 fdt32_t *val;
1194
1195 assert(ofnode_valid(node));
1196
1197 log_debug("%s = %x", propname, value);
1198 val = malloc(sizeof(*val));
1199 if (!val)
1200 return -ENOMEM;
1201 *val = cpu_to_fdt32(value);
1202
1203 return ofnode_write_prop(node, propname, val, sizeof(value));
1204}
1205
Mario Six047dafc2018-06-26 08:46:48 +02001206int ofnode_set_enabled(ofnode node, bool value)
1207{
Mario Six047dafc2018-06-26 08:46:48 +02001208 assert(ofnode_valid(node));
1209
1210 if (value)
1211 return ofnode_write_string(node, "status", "okay");
1212 else
Bin Menga9274aa2019-07-05 09:23:17 -07001213 return ofnode_write_string(node, "status", "disabled");
Mario Six047dafc2018-06-26 08:46:48 +02001214}
Simon Glass0034d962021-08-07 07:24:01 -06001215
1216bool ofnode_conf_read_bool(const char *prop_name)
1217{
1218 ofnode node;
1219
1220 node = ofnode_path("/config");
1221 if (!ofnode_valid(node))
1222 return false;
1223
1224 return ofnode_read_bool(node, prop_name);
1225}
1226
1227int ofnode_conf_read_int(const char *prop_name, int default_val)
1228{
1229 ofnode node;
1230
1231 node = ofnode_path("/config");
1232 if (!ofnode_valid(node))
1233 return default_val;
1234
1235 return ofnode_read_u32_default(node, prop_name, default_val);
1236}
1237
1238const char *ofnode_conf_read_str(const char *prop_name)
1239{
1240 ofnode node;
1241
1242 node = ofnode_path("/config");
1243 if (!ofnode_valid(node))
1244 return NULL;
1245
1246 return ofnode_read_string(node, prop_name);
1247}
Marek Behúnf4f1ddc2022-04-07 00:32:57 +02001248
1249ofnode ofnode_get_phy_node(ofnode node)
1250{
1251 /* DT node properties that reference a PHY node */
1252 static const char * const phy_handle_str[] = {
1253 "phy-handle", "phy", "phy-device",
1254 };
1255 struct ofnode_phandle_args args = {
1256 .node = ofnode_null()
1257 };
1258 int i;
1259
1260 assert(ofnode_valid(node));
1261
1262 for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
1263 if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
1264 NULL, 0, 0, &args))
1265 break;
1266
1267 return args.node;
1268}
Marek Behúnbc194772022-04-07 00:33:01 +02001269
1270phy_interface_t ofnode_read_phy_mode(ofnode node)
1271{
1272 const char *mode;
1273 int i;
1274
1275 assert(ofnode_valid(node));
1276
1277 mode = ofnode_read_string(node, "phy-mode");
1278 if (!mode)
1279 mode = ofnode_read_string(node, "phy-connection-type");
1280
1281 if (!mode)
Marek Behún48631e42022-04-07 00:33:03 +02001282 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001283
Marek Behún21a18362022-04-07 00:33:02 +02001284 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
Marek Behúnbc194772022-04-07 00:33:01 +02001285 if (!strcmp(mode, phy_interface_strings[i]))
1286 return i;
1287
1288 debug("%s: Invalid PHY interface '%s'\n", __func__, mode);
1289
Marek Behún48631e42022-04-07 00:33:03 +02001290 return PHY_INTERFACE_MODE_NA;
Marek Behúnbc194772022-04-07 00:33:01 +02001291}
Simon Glass56bc3322022-09-06 20:27:02 -06001292
1293int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
1294{
1295 ofnode subnode;
1296 int ret = 0;
1297
1298 assert(ofnode_valid(node));
1299
1300 if (ofnode_is_np(node)) {
1301 struct device_node *np, *child;
1302
1303 np = (struct device_node *)ofnode_to_np(node);
1304 ret = of_add_subnode(np, name, -1, &child);
1305 if (ret && ret != -EEXIST)
1306 return ret;
1307 subnode = np_to_ofnode(child);
1308 } else {
1309 void *fdt = (void *)gd->fdt_blob;
1310 int poffset = ofnode_to_offset(node);
1311 int offset;
1312
1313 offset = fdt_add_subnode(fdt, poffset, name);
1314 if (offset == -FDT_ERR_EXISTS) {
1315 offset = fdt_subnode_offset(fdt, poffset, name);
1316 ret = -EEXIST;
1317 }
1318 if (offset < 0)
1319 return -EINVAL;
1320 subnode = offset_to_ofnode(offset);
1321 }
1322
1323 *subnodep = subnode;
1324
1325 return ret; /* 0 or -EEXIST */
1326}