blob: 7f6c47f0c0775f531ff15478cf1e38492765c776 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass9e512042017-05-18 20:08:58 -06002/*
3 * Copyright (c) 2017 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glass9e512042017-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 Glassf7ae49f2020-05-10 11:40:05 -060011#include <log.h>
Simon Glass336d4612020-02-03 07:36:16 -070012#include <malloc.h>
Masahiro Yamadab08c8c42018-03-05 01:20:11 +090013#include <linux/libfdt.h>
Simon Glass9e512042017-05-18 20:08:58 -060014#include <dm/of_access.h>
Simon Glassbed77492017-05-18 20:09:01 -060015#include <dm/of_addr.h>
Simon Glass9e512042017-05-18 20:08:58 -060016#include <dm/ofnode.h>
17#include <linux/err.h>
Simon Glassdcf98852017-07-25 08:29:55 -060018#include <linux/ioport.h>
Simon Glass401d1c42020-10-30 21:38:53 -060019#include <asm/global_data.h>
Simon Glass9e512042017-05-18 20:08:58 -060020
Simon Glassb7bd94f2022-09-06 20:27:24 -060021/**
22 * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
23 *
24 * Looks up the tree and returns an ofnode with the correct of_offset
25 *
26 * If @offset is < 0 then this returns an ofnode with that offset
27 *
28 * @tree: tree to check
29 * @offset: offset within that tree (can be < 0)
30 * @return node for that offset
31 */
32static ofnode ofnode_from_tree_offset(oftree tree, int offset)
33{
34 ofnode node;
35
36 node.of_offset = offset;
37
38 return node;
39}
40
Kishon Vijay Abraham I77cbaf82021-07-21 21:28:30 +053041bool ofnode_name_eq(ofnode node, const char *name)
42{
43 const char *node_name;
44 size_t len;
45
46 assert(ofnode_valid(node));
47
48 node_name = ofnode_get_name(node);
49 len = strchrnul(node_name, '@') - node_name;
50
51 return (strlen(name) == len) && !strncmp(node_name, name, len);
52}
53
Stefan Herbrechtsmeierb471bdc2022-06-14 15:21:30 +020054int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
55{
56 const u8 *cell;
57 int len;
58
59 assert(ofnode_valid(node));
60 debug("%s: %s: ", __func__, propname);
61
62 if (ofnode_is_np(node))
63 return of_read_u8(ofnode_to_np(node), propname, outp);
64
65 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
66 &len);
67 if (!cell || len < sizeof(*cell)) {
68 debug("(not found)\n");
69 return -EINVAL;
70 }
71 *outp = *cell;
72 debug("%#x (%d)\n", *outp, *outp);
73
74 return 0;
75}
76
77u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
78{
79 assert(ofnode_valid(node));
80 ofnode_read_u8(node, propname, &def);
81
82 return def;
83}
84
85int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
86{
87 const fdt16_t *cell;
88 int len;
89
90 assert(ofnode_valid(node));
91 debug("%s: %s: ", __func__, propname);
92
93 if (ofnode_is_np(node))
94 return of_read_u16(ofnode_to_np(node), propname, outp);
95
96 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
97 &len);
98 if (!cell || len < sizeof(*cell)) {
99 debug("(not found)\n");
100 return -EINVAL;
101 }
102 *outp = be16_to_cpup(cell);
103 debug("%#x (%d)\n", *outp, *outp);
104
105 return 0;
106}
107
108u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def)
109{
110 assert(ofnode_valid(node));
111 ofnode_read_u16(node, propname, &def);
112
113 return def;
114}
115
Simon Glass9e512042017-05-18 20:08:58 -0600116int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
117{
Dario Binacchi59006602020-03-29 18:04:42 +0200118 return ofnode_read_u32_index(node, propname, 0, outp);
Simon Glass9e512042017-05-18 20:08:58 -0600119}
120
Trent Piephob061ef32019-05-10 17:48:20 +0000121u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
Simon Glass9e512042017-05-18 20:08:58 -0600122{
123 assert(ofnode_valid(node));
Dario Binacchi59006602020-03-29 18:04:42 +0200124 ofnode_read_u32_index(node, propname, 0, &def);
Simon Glass9e512042017-05-18 20:08:58 -0600125
126 return def;
127}
128
Dario Binacchi4bb70752020-03-29 18:04:41 +0200129int ofnode_read_u32_index(ofnode node, const char *propname, int index,
130 u32 *outp)
131{
132 const fdt32_t *cell;
133 int len;
134
135 assert(ofnode_valid(node));
136 debug("%s: %s: ", __func__, propname);
137
138 if (ofnode_is_np(node))
139 return of_read_u32_index(ofnode_to_np(node), propname, index,
140 outp);
141
Simon Glassa3f50d02022-09-06 20:27:20 -0600142 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
143 propname, &len);
Dario Binacchi4bb70752020-03-29 18:04:41 +0200144 if (!cell) {
145 debug("(not found)\n");
146 return -EINVAL;
147 }
148
149 if (len < (sizeof(int) * (index + 1))) {
150 debug("(not large enough)\n");
151 return -EOVERFLOW;
152 }
153
154 *outp = fdt32_to_cpu(cell[index]);
155 debug("%#x (%d)\n", *outp, *outp);
156
157 return 0;
158}
159
160u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
161 u32 def)
162{
163 assert(ofnode_valid(node));
164 ofnode_read_u32_index(node, propname, index, &def);
165
166 return def;
167}
168
Simon Glass9e512042017-05-18 20:08:58 -0600169int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
170{
171 assert(ofnode_valid(node));
172 ofnode_read_u32(node, propname, (u32 *)&def);
173
174 return def;
175}
176
Simon Glass7e5196c2018-06-11 13:07:10 -0600177int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
178{
Jean-Jacques Hiblotd60ae4c2019-10-22 10:05:22 +0200179 const unaligned_fdt64_t *cell;
Simon Glass7e5196c2018-06-11 13:07:10 -0600180 int len;
181
182 assert(ofnode_valid(node));
183 debug("%s: %s: ", __func__, propname);
184
185 if (ofnode_is_np(node))
186 return of_read_u64(ofnode_to_np(node), propname, outp);
187
Simon Glassa3f50d02022-09-06 20:27:20 -0600188 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
189 propname, &len);
Simon Glass7e5196c2018-06-11 13:07:10 -0600190 if (!cell || len < sizeof(*cell)) {
191 debug("(not found)\n");
192 return -EINVAL;
193 }
194 *outp = fdt64_to_cpu(cell[0]);
195 debug("%#llx (%lld)\n", (unsigned long long)*outp,
196 (unsigned long long)*outp);
197
198 return 0;
199}
200
T Karthik Reddy3f3d7712019-09-02 16:34:30 +0200201u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
Simon Glass7e5196c2018-06-11 13:07:10 -0600202{
203 assert(ofnode_valid(node));
204 ofnode_read_u64(node, propname, &def);
205
206 return def;
207}
208
Simon Glass9e512042017-05-18 20:08:58 -0600209bool ofnode_read_bool(ofnode node, const char *propname)
210{
Masahiro Yamadab2ec7ea2017-06-22 16:54:07 +0900211 const void *prop;
Simon Glass9e512042017-05-18 20:08:58 -0600212
213 assert(ofnode_valid(node));
214 debug("%s: %s: ", __func__, propname);
215
Masahiro Yamadab2ec7ea2017-06-22 16:54:07 +0900216 prop = ofnode_get_property(node, propname, NULL);
Simon Glass9e512042017-05-18 20:08:58 -0600217
Masahiro Yamadab2ec7ea2017-06-22 16:54:07 +0900218 debug("%s\n", prop ? "true" : "false");
219
220 return prop ? true : false;
Simon Glass9e512042017-05-18 20:08:58 -0600221}
222
Simon Glassa8167d82020-01-27 08:49:44 -0700223const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
Simon Glass9e512042017-05-18 20:08:58 -0600224{
Simon Glassa8167d82020-01-27 08:49:44 -0700225 const char *val = NULL;
226 int len;
Simon Glass9e512042017-05-18 20:08:58 -0600227
228 assert(ofnode_valid(node));
229 debug("%s: %s: ", __func__, propname);
230
231 if (ofnode_is_np(node)) {
232 struct property *prop = of_find_property(
Simon Glassa8167d82020-01-27 08:49:44 -0700233 ofnode_to_np(node), propname, &len);
Simon Glass9e512042017-05-18 20:08:58 -0600234
235 if (prop) {
Simon Glassa8167d82020-01-27 08:49:44 -0700236 val = prop->value;
Simon Glass9e512042017-05-18 20:08:58 -0600237 len = prop->length;
238 }
239 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -0600240 val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glass9e512042017-05-18 20:08:58 -0600241 propname, &len);
242 }
Simon Glassa8167d82020-01-27 08:49:44 -0700243 if (!val) {
Simon Glass9e512042017-05-18 20:08:58 -0600244 debug("<not found>\n");
Simon Glassa8167d82020-01-27 08:49:44 -0700245 if (sizep)
246 *sizep = -FDT_ERR_NOTFOUND;
Simon Glass9e512042017-05-18 20:08:58 -0600247 return NULL;
248 }
Simon Glassa8167d82020-01-27 08:49:44 -0700249 if (sizep)
250 *sizep = len;
251
252 return val;
253}
254
255const char *ofnode_read_string(ofnode node, const char *propname)
256{
257 const char *str;
258 int len;
259
260 str = ofnode_read_prop(node, propname, &len);
261 if (!str)
262 return NULL;
263
Simon Glass9e512042017-05-18 20:08:58 -0600264 if (strnlen(str, len) >= len) {
265 debug("<invalid>\n");
266 return NULL;
267 }
268 debug("%s\n", str);
269
270 return str;
271}
272
Simon Glass1aada632020-01-27 08:49:45 -0700273int ofnode_read_size(ofnode node, const char *propname)
274{
275 int len;
276
277 if (!ofnode_read_prop(node, propname, &len))
278 return -EINVAL;
279
280 return len;
281}
282
Simon Glass9e512042017-05-18 20:08:58 -0600283ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
284{
285 ofnode subnode;
286
287 assert(ofnode_valid(node));
288 debug("%s: %s: ", __func__, subnode_name);
289
290 if (ofnode_is_np(node)) {
Simon Glass98306982022-09-06 20:27:04 -0600291 struct device_node *np = ofnode_to_np(node);
Simon Glass9e512042017-05-18 20:08:58 -0600292
293 for (np = np->child; np; np = np->sibling) {
294 if (!strcmp(subnode_name, np->name))
295 break;
296 }
297 subnode = np_to_ofnode(np);
298 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -0600299 int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
Simon Glass9e512042017-05-18 20:08:58 -0600300 ofnode_to_offset(node), subnode_name);
Simon Glass2187cb72022-09-06 20:27:23 -0600301 subnode = noffset_to_ofnode(node, ooffset);
Simon Glass9e512042017-05-18 20:08:58 -0600302 }
303 debug("%s\n", ofnode_valid(subnode) ?
304 ofnode_get_name(subnode) : "<none>");
305
306 return subnode;
307}
308
309int ofnode_read_u32_array(ofnode node, const char *propname,
310 u32 *out_values, size_t sz)
311{
312 assert(ofnode_valid(node));
313 debug("%s: %s: ", __func__, propname);
314
315 if (ofnode_is_np(node)) {
316 return of_read_u32_array(ofnode_to_np(node), propname,
317 out_values, sz);
318 } else {
Simon Glass66d0d0c2022-09-06 20:27:18 -0600319 int ret;
320
Simon Glassa3f50d02022-09-06 20:27:20 -0600321 ret = fdtdec_get_int_array(ofnode_to_fdt(node),
Simon Glass66d0d0c2022-09-06 20:27:18 -0600322 ofnode_to_offset(node), propname,
323 out_values, sz);
324
325 /* get the error right, but space is more important in SPL */
326 if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
327 if (ret == -FDT_ERR_NOTFOUND)
328 return -EINVAL;
329 else if (ret == -FDT_ERR_BADLAYOUT)
330 return -EOVERFLOW;
331 }
332 return ret;
Simon Glass9e512042017-05-18 20:08:58 -0600333 }
334}
335
Simon Glassec1add12020-12-16 17:25:06 -0700336#if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
Simon Glass0de1b072020-11-28 17:50:02 -0700337bool ofnode_is_enabled(ofnode node)
338{
339 if (ofnode_is_np(node)) {
340 return of_device_is_available(ofnode_to_np(node));
341 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -0600342 return fdtdec_get_is_enabled(ofnode_to_fdt(node),
Simon Glass0de1b072020-11-28 17:50:02 -0700343 ofnode_to_offset(node));
344 }
345}
346
Simon Glass9e512042017-05-18 20:08:58 -0600347ofnode ofnode_first_subnode(ofnode node)
348{
349 assert(ofnode_valid(node));
350 if (ofnode_is_np(node))
351 return np_to_ofnode(node.np->child);
352
Simon Glass2187cb72022-09-06 20:27:23 -0600353 return noffset_to_ofnode(node,
Simon Glassa3f50d02022-09-06 20:27:20 -0600354 fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glass9e512042017-05-18 20:08:58 -0600355}
356
357ofnode ofnode_next_subnode(ofnode node)
358{
359 assert(ofnode_valid(node));
360 if (ofnode_is_np(node))
361 return np_to_ofnode(node.np->sibling);
362
Simon Glass2187cb72022-09-06 20:27:23 -0600363 return noffset_to_ofnode(node,
Simon Glassa3f50d02022-09-06 20:27:20 -0600364 fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glass9e512042017-05-18 20:08:58 -0600365}
Simon Glassec1add12020-12-16 17:25:06 -0700366#endif /* !DM_INLINE_OFNODE */
Simon Glass9e512042017-05-18 20:08:58 -0600367
Philipp Tomsiche2d59972018-02-23 17:38:49 +0100368ofnode ofnode_get_parent(ofnode node)
369{
370 ofnode parent;
371
372 assert(ofnode_valid(node));
373 if (ofnode_is_np(node))
374 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
375 else
Simon Glassa3f50d02022-09-06 20:27:20 -0600376 parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
Philipp Tomsiche2d59972018-02-23 17:38:49 +0100377 ofnode_to_offset(node));
378
379 return parent;
380}
381
Simon Glass9e512042017-05-18 20:08:58 -0600382const char *ofnode_get_name(ofnode node)
383{
Kever Yang8f0a70e2019-07-19 11:23:47 +0800384 if (!ofnode_valid(node)) {
385 debug("%s node not valid\n", __func__);
386 return NULL;
387 }
388
Simon Glass9e512042017-05-18 20:08:58 -0600389 if (ofnode_is_np(node))
Simon Glassf46ec932022-09-06 20:27:15 -0600390 return node.np->name;
Simon Glass9e512042017-05-18 20:08:58 -0600391
Simon Glassa3f50d02022-09-06 20:27:20 -0600392 return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
Simon Glass9e512042017-05-18 20:08:58 -0600393}
394
Marek Behún0e116be2021-05-26 14:08:18 +0200395int ofnode_get_path(ofnode node, char *buf, int buflen)
396{
397 assert(ofnode_valid(node));
398
399 if (ofnode_is_np(node)) {
400 if (strlen(node.np->full_name) >= buflen)
401 return -ENOSPC;
402
403 strcpy(buf, node.np->full_name);
404
405 return 0;
406 } else {
407 int res;
408
Simon Glassa3f50d02022-09-06 20:27:20 -0600409 res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
Marek Behún0e116be2021-05-26 14:08:18 +0200410 buflen);
411 if (!res)
412 return res;
413 else if (res == -FDT_ERR_NOSPACE)
414 return -ENOSPC;
415 else
416 return -EINVAL;
417 }
418}
419
Kever Yangb4f20762018-02-23 17:38:50 +0100420ofnode ofnode_get_by_phandle(uint phandle)
421{
422 ofnode node;
423
424 if (of_live_active())
Simon Glass829d5122022-09-06 20:26:57 -0600425 node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
Kever Yangb4f20762018-02-23 17:38:50 +0100426 else
427 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
428 phandle);
429
430 return node;
431}
432
Simon Glass928d2672022-09-06 20:27:22 -0600433ofnode oftree_get_by_phandle(oftree tree, uint phandle)
434{
435 ofnode node;
436
437 if (of_live_active())
438 node = np_to_ofnode(of_find_node_by_phandle(tree.np, phandle));
439 else
440 node.of_offset =
441 fdt_node_offset_by_phandle(oftree_lookup_fdt(tree),
442 phandle);
443
444 return node;
445}
446
Marek Behún31a7b712021-05-26 14:08:17 +0200447static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
448 fdt_size_t *size, bool translate)
Simon Glassbed77492017-05-18 20:09:01 -0600449{
Keerthy16787542018-11-19 11:44:47 +0530450 int na, ns;
Keerthy16787542018-11-19 11:44:47 +0530451
Chen Guanqiao1b098b32021-07-12 15:40:20 +0800452 if (size)
453 *size = FDT_SIZE_T_NONE;
Chen Guanqiaoaa351a12021-04-12 14:51:11 +0800454
Simon Glassbed77492017-05-18 20:09:01 -0600455 if (ofnode_is_np(node)) {
456 const __be32 *prop_val;
Simon Glasse18c41f2019-09-25 08:55:50 -0600457 u64 size64;
Simon Glassbed77492017-05-18 20:09:01 -0600458 uint flags;
Simon Glassbed77492017-05-18 20:09:01 -0600459
Simon Glasse18c41f2019-09-25 08:55:50 -0600460 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
461 &flags);
Simon Glassbed77492017-05-18 20:09:01 -0600462 if (!prop_val)
463 return FDT_ADDR_T_NONE;
Chen Guanqiao1b098b32021-07-12 15:40:20 +0800464
Simon Glasse18c41f2019-09-25 08:55:50 -0600465 if (size)
466 *size = size64;
Mario Six286ede62017-12-20 09:52:12 +0100467
Mario Sixe8d52912018-03-12 14:53:33 +0100468 ns = of_n_size_cells(ofnode_to_np(node));
469
Marek Behún31a7b712021-05-26 14:08:17 +0200470 if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Six286ede62017-12-20 09:52:12 +0100471 return of_translate_address(ofnode_to_np(node), prop_val);
472 } else {
473 na = of_n_addr_cells(ofnode_to_np(node));
474 return of_read_number(prop_val, na);
475 }
Simon Glassbed77492017-05-18 20:09:01 -0600476 } else {
Keerthy16787542018-11-19 11:44:47 +0530477 na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
478 ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
Simon Glassa3f50d02022-09-06 20:27:20 -0600479 return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
Keerthy16787542018-11-19 11:44:47 +0530480 ofnode_to_offset(node), "reg",
Marek Behún31a7b712021-05-26 14:08:17 +0200481 index, na, ns, size,
482 translate);
Simon Glassbed77492017-05-18 20:09:01 -0600483 }
Simon Glassbed77492017-05-18 20:09:01 -0600484}
485
Marek Behún31a7b712021-05-26 14:08:17 +0200486fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
487{
488 return __ofnode_get_addr_size_index(node, index, size, true);
489}
490
491fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
492 fdt_size_t *size)
493{
494 return __ofnode_get_addr_size_index(node, index, size, false);
495}
496
Keerthye679d032019-04-24 17:19:53 +0530497fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
498{
499 fdt_size_t size;
500
501 return ofnode_get_addr_size_index(node, index, &size);
502}
503
Simon Glassbed77492017-05-18 20:09:01 -0600504fdt_addr_t ofnode_get_addr(ofnode node)
505{
506 return ofnode_get_addr_index(node, 0);
507}
508
Chen Guanqiaoaa351a12021-04-12 14:51:11 +0800509fdt_size_t ofnode_get_size(ofnode node)
510{
511 fdt_size_t size;
512
513 ofnode_get_addr_size_index(node, 0, &size);
514
515 return size;
516}
517
Simon Glass9e512042017-05-18 20:08:58 -0600518int ofnode_stringlist_search(ofnode node, const char *property,
519 const char *string)
520{
521 if (ofnode_is_np(node)) {
522 return of_property_match_string(ofnode_to_np(node),
523 property, string);
524 } else {
525 int ret;
526
Simon Glassa3f50d02022-09-06 20:27:20 -0600527 ret = fdt_stringlist_search(ofnode_to_fdt(node),
Simon Glass9e512042017-05-18 20:08:58 -0600528 ofnode_to_offset(node), property,
529 string);
530 if (ret == -FDT_ERR_NOTFOUND)
531 return -ENODATA;
532 else if (ret < 0)
533 return -EINVAL;
534
535 return ret;
536 }
537}
538
539int ofnode_read_string_index(ofnode node, const char *property, int index,
540 const char **outp)
541{
542 if (ofnode_is_np(node)) {
543 return of_property_read_string_index(ofnode_to_np(node),
544 property, index, outp);
545 } else {
546 int len;
547
Simon Glassa3f50d02022-09-06 20:27:20 -0600548 *outp = fdt_stringlist_get(ofnode_to_fdt(node),
549 ofnode_to_offset(node),
Simon Glass9e512042017-05-18 20:08:58 -0600550 property, index, &len);
551 if (len < 0)
552 return -EINVAL;
553 return 0;
554 }
555}
556
Simon Glass8c293d62017-06-12 06:21:28 -0600557int ofnode_read_string_count(ofnode node, const char *property)
558{
559 if (ofnode_is_np(node)) {
560 return of_property_count_strings(ofnode_to_np(node), property);
561 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -0600562 return fdt_stringlist_count(ofnode_to_fdt(node),
Simon Glass8c293d62017-06-12 06:21:28 -0600563 ofnode_to_offset(node), property);
564 }
565}
566
Simon Glass075bfc92021-10-23 17:26:07 -0600567int ofnode_read_string_list(ofnode node, const char *property,
568 const char ***listp)
569{
570 const char **prop;
571 int count;
572 int i;
573
574 *listp = NULL;
575 count = ofnode_read_string_count(node, property);
576 if (count < 0)
577 return count;
578 if (!count)
579 return 0;
580
581 prop = calloc(count + 1, sizeof(char *));
582 if (!prop)
583 return -ENOMEM;
584
585 for (i = 0; i < count; i++)
586 ofnode_read_string_index(node, property, i, &prop[i]);
587 prop[count] = NULL;
588 *listp = prop;
589
590 return count;
591}
592
Simon Glass9e512042017-05-18 20:08:58 -0600593static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
594 struct ofnode_phandle_args *out)
595{
596 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
597 out->node = offset_to_ofnode(in->node);
598 out->args_count = in->args_count;
599 memcpy(out->args, in->args, sizeof(out->args));
600}
601
602static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
603 struct ofnode_phandle_args *out)
604{
605 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
606 out->node = np_to_ofnode(in->np);
607 out->args_count = in->args_count;
608 memcpy(out->args, in->args, sizeof(out->args));
609}
610
611int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
612 const char *cells_name, int cell_count,
613 int index,
614 struct ofnode_phandle_args *out_args)
615{
616 if (ofnode_is_np(node)) {
617 struct of_phandle_args args;
618 int ret;
619
620 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay01d89e32020-09-10 18:26:17 +0200621 list_name, cells_name,
622 cell_count, index,
Mario Six51db2872018-01-15 11:07:17 +0100623 &args);
Simon Glass9e512042017-05-18 20:08:58 -0600624 if (ret)
625 return ret;
626 ofnode_from_of_phandle_args(&args, out_args);
627 } else {
628 struct fdtdec_phandle_args args;
629 int ret;
630
Simon Glassa3f50d02022-09-06 20:27:20 -0600631 ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Mario Six51db2872018-01-15 11:07:17 +0100632 ofnode_to_offset(node),
633 list_name, cells_name,
634 cell_count, index, &args);
Simon Glass9e512042017-05-18 20:08:58 -0600635 if (ret)
636 return ret;
637 ofnode_from_fdtdec_phandle_args(&args, out_args);
638 }
639
640 return 0;
641}
642
Patrice Chotard642346a2017-07-18 11:57:08 +0200643int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
Patrick Delaunay89f68302020-09-25 09:41:14 +0200644 const char *cells_name, int cell_count)
Patrice Chotard642346a2017-07-18 11:57:08 +0200645{
646 if (ofnode_is_np(node))
647 return of_count_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay89f68302020-09-25 09:41:14 +0200648 list_name, cells_name, cell_count);
Patrice Chotard642346a2017-07-18 11:57:08 +0200649 else
Simon Glassa3f50d02022-09-06 20:27:20 -0600650 return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Patrice Chotard642346a2017-07-18 11:57:08 +0200651 ofnode_to_offset(node), list_name, cells_name,
Patrick Delaunay89f68302020-09-25 09:41:14 +0200652 cell_count, -1, NULL);
Patrice Chotard642346a2017-07-18 11:57:08 +0200653}
654
Simon Glass9e512042017-05-18 20:08:58 -0600655ofnode ofnode_path(const char *path)
656{
657 if (of_live_active())
658 return np_to_ofnode(of_find_node_by_path(path));
659 else
660 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
661}
662
Simon Glassb7bd94f2022-09-06 20:27:24 -0600663ofnode oftree_root(oftree tree)
Simon Glass33104842022-07-30 15:52:08 -0600664{
Simon Glassb7bd94f2022-09-06 20:27:24 -0600665 if (of_live_active()) {
666 return np_to_ofnode(tree.np);
667 } else {
668 return ofnode_from_tree_offset(tree, 0);
669 }
670}
671
672ofnode oftree_path(oftree tree, const char *path)
673{
674 if (of_live_active()) {
Simon Glass33104842022-07-30 15:52:08 -0600675 return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
676 NULL));
Simon Glassb7bd94f2022-09-06 20:27:24 -0600677 } else if (*path != '/' && tree.fdt != gd->fdt_blob) {
Simon Glass33104842022-07-30 15:52:08 -0600678 return ofnode_null(); /* Aliases only on control FDT */
Simon Glassb7bd94f2022-09-06 20:27:24 -0600679 } else {
680 int offset = fdt_path_offset(tree.fdt, path);
681
682 return ofnode_from_tree_offset(tree, offset);
683 }
Simon Glass33104842022-07-30 15:52:08 -0600684}
685
Simon Glassbd933bf2020-01-27 08:49:46 -0700686const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glass9e512042017-05-18 20:08:58 -0600687{
688 ofnode chosen_node;
689
690 chosen_node = ofnode_path("/chosen");
691
Simon Glassbd933bf2020-01-27 08:49:46 -0700692 return ofnode_read_prop(chosen_node, propname, sizep);
693}
694
695const char *ofnode_read_chosen_string(const char *propname)
696{
697 return ofnode_read_chosen_prop(propname, NULL);
Simon Glass9e512042017-05-18 20:08:58 -0600698}
699
700ofnode ofnode_get_chosen_node(const char *name)
701{
702 const char *prop;
703
Simon Glassbd933bf2020-01-27 08:49:46 -0700704 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glass9e512042017-05-18 20:08:58 -0600705 if (!prop)
706 return ofnode_null();
707
708 return ofnode_path(prop);
709}
710
Michal Simek305d3182020-07-28 12:51:08 +0200711const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
712{
713 ofnode node;
714
715 node = ofnode_path("/aliases");
716
717 return ofnode_read_prop(node, propname, sizep);
718}
719
720ofnode ofnode_get_aliases_node(const char *name)
721{
722 const char *prop;
723
724 prop = ofnode_read_aliases_prop(name, NULL);
725 if (!prop)
726 return ofnode_null();
727
728 debug("%s: node_path: %s\n", __func__, prop);
729
730 return ofnode_path(prop);
731}
732
Chunfeng Yun89b84b82020-05-02 11:35:09 +0200733int ofnode_get_child_count(ofnode parent)
734{
735 ofnode child;
736 int num = 0;
737
738 ofnode_for_each_subnode(child, parent)
739 num++;
740
741 return num;
742}
743
Simon Glass9e512042017-05-18 20:08:58 -0600744static int decode_timing_property(ofnode node, const char *name,
745 struct timing_entry *result)
746{
747 int length, ret = 0;
748
749 length = ofnode_read_size(node, name);
750 if (length < 0) {
751 debug("%s: could not find property %s\n",
752 ofnode_get_name(node), name);
753 return length;
754 }
755
756 if (length == sizeof(u32)) {
757 result->typ = ofnode_read_u32_default(node, name, 0);
758 result->min = result->typ;
759 result->max = result->typ;
760 } else {
761 ret = ofnode_read_u32_array(node, name, &result->min, 3);
762 }
763
764 return ret;
765}
766
767int ofnode_decode_display_timing(ofnode parent, int index,
768 struct display_timing *dt)
769{
770 int i;
771 ofnode timings, node;
772 u32 val = 0;
773 int ret = 0;
774
775 timings = ofnode_find_subnode(parent, "display-timings");
776 if (!ofnode_valid(timings))
777 return -EINVAL;
778
Simon Glass3991f422017-08-05 15:45:54 -0600779 i = 0;
780 ofnode_for_each_subnode(node, timings) {
781 if (i++ == index)
782 break;
783 }
Simon Glass9e512042017-05-18 20:08:58 -0600784
785 if (!ofnode_valid(node))
786 return -EINVAL;
787
788 memset(dt, 0, sizeof(*dt));
789
790 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
791 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
792 ret |= decode_timing_property(node, "hactive", &dt->hactive);
793 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
794 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
795 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
796 ret |= decode_timing_property(node, "vactive", &dt->vactive);
797 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
798 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
799
800 dt->flags = 0;
801 val = ofnode_read_u32_default(node, "vsync-active", -1);
802 if (val != -1) {
803 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
804 DISPLAY_FLAGS_VSYNC_LOW;
805 }
806 val = ofnode_read_u32_default(node, "hsync-active", -1);
807 if (val != -1) {
808 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
809 DISPLAY_FLAGS_HSYNC_LOW;
810 }
811 val = ofnode_read_u32_default(node, "de-active", -1);
812 if (val != -1) {
813 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
814 DISPLAY_FLAGS_DE_LOW;
815 }
816 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
817 if (val != -1) {
818 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
819 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
820 }
821
822 if (ofnode_read_bool(node, "interlaced"))
823 dt->flags |= DISPLAY_FLAGS_INTERLACED;
824 if (ofnode_read_bool(node, "doublescan"))
825 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
826 if (ofnode_read_bool(node, "doubleclk"))
827 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
828
829 return ret;
830}
831
Masahiro Yamada61e51ba2017-06-22 16:54:05 +0900832const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glass9e512042017-05-18 20:08:58 -0600833{
Masahiro Yamadacb7dbe12017-06-22 16:54:04 +0900834 if (ofnode_is_np(node))
835 return of_get_property(ofnode_to_np(node), propname, lenp);
836 else
Simon Glassa3f50d02022-09-06 20:27:20 -0600837 return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glass9e512042017-05-18 20:08:58 -0600838 propname, lenp);
Simon Glass9e512042017-05-18 20:08:58 -0600839}
840
Simon Glass4b1f5712022-09-06 20:27:13 -0600841int ofnode_first_property(ofnode node, struct ofprop *prop)
Patrick Delaunayce891fca2020-01-13 11:34:56 +0100842{
843 prop->node = node;
844
845 if (ofnode_is_np(node)) {
846 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
847 if (!prop->prop)
848 return -FDT_ERR_NOTFOUND;
849 } else {
850 prop->offset =
Simon Glassa3f50d02022-09-06 20:27:20 -0600851 fdt_first_property_offset(ofnode_to_fdt(node),
Patrick Delaunayce891fca2020-01-13 11:34:56 +0100852 ofnode_to_offset(prop->node));
853 if (prop->offset < 0)
854 return prop->offset;
855 }
856
857 return 0;
858}
859
Simon Glass4b1f5712022-09-06 20:27:13 -0600860int ofnode_next_property(struct ofprop *prop)
Patrick Delaunayce891fca2020-01-13 11:34:56 +0100861{
862 if (ofnode_is_np(prop->node)) {
863 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
864 prop->prop);
865 if (!prop->prop)
866 return -FDT_ERR_NOTFOUND;
867 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -0600868 prop->offset =
869 fdt_next_property_offset(ofnode_to_fdt(prop->node),
870 prop->offset);
Patrick Delaunayce891fca2020-01-13 11:34:56 +0100871 if (prop->offset < 0)
872 return prop->offset;
873 }
874
875 return 0;
876}
877
Simon Glass92432242022-09-06 20:27:14 -0600878const void *ofprop_get_property(const struct ofprop *prop,
879 const char **propname, int *lenp)
Patrick Delaunayce891fca2020-01-13 11:34:56 +0100880{
881 if (ofnode_is_np(prop->node))
882 return of_get_property_by_prop(ofnode_to_np(prop->node),
883 prop->prop, propname, lenp);
884 else
Simon Glassa3f50d02022-09-06 20:27:20 -0600885 return fdt_getprop_by_offset(ofnode_to_fdt(prop->node),
Patrick Delaunayce891fca2020-01-13 11:34:56 +0100886 prop->offset,
887 propname, lenp);
888}
889
Simon Glass9e512042017-05-18 20:08:58 -0600890fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
891 fdt_size_t *sizep)
892{
893 if (ofnode_is_np(node)) {
894 int na, ns;
895 int psize;
896 const struct device_node *np = ofnode_to_np(node);
Klaus Goger68a34522017-09-20 13:50:41 +0200897 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glass9e512042017-05-18 20:08:58 -0600898
Klaus Goger68a34522017-09-20 13:50:41 +0200899 if (!prop)
900 return FDT_ADDR_T_NONE;
Simon Glass9e512042017-05-18 20:08:58 -0600901 na = of_n_addr_cells(np);
Marek Vasut51cb9272018-10-01 12:37:19 +0200902 ns = of_n_size_cells(np);
Simon Glassa4b8e372017-05-18 20:09:27 -0600903 *sizep = of_read_number(prop + na, ns);
Marek Vasuta6a45cd2018-10-01 12:37:20 +0200904
Dario Binacchia47abd72021-05-01 17:05:26 +0200905 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta6a45cd2018-10-01 12:37:20 +0200906 return of_translate_address(np, prop);
907 else
908 return of_read_number(prop, na);
Simon Glass9e512042017-05-18 20:08:58 -0600909 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -0600910 return fdtdec_get_addr_size(ofnode_to_fdt(node),
Simon Glass9e512042017-05-18 20:08:58 -0600911 ofnode_to_offset(node), property,
912 sizep);
913 }
914}
915
916const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
917 size_t sz)
918{
919 if (ofnode_is_np(node)) {
920 const struct device_node *np = ofnode_to_np(node);
921 int psize;
922 const __be32 *prop = of_get_property(np, propname, &psize);
923
924 if (!prop || sz != psize)
925 return NULL;
926 return (uint8_t *)prop;
927
928 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -0600929 return fdtdec_locate_byte_array(ofnode_to_fdt(node),
Simon Glass9e512042017-05-18 20:08:58 -0600930 ofnode_to_offset(node), propname, sz);
931 }
932}
933
934int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
935 const char *propname, struct fdt_pci_addr *addr)
936{
Masahiro Yamada8c9eaad2017-06-22 17:57:50 +0900937 const fdt32_t *cell;
Simon Glass9e512042017-05-18 20:08:58 -0600938 int len;
939 int ret = -ENOENT;
940
941 debug("%s: %s: ", __func__, propname);
942
943 /*
944 * If we follow the pci bus bindings strictly, we should check
945 * the value of the node's parent node's #address-cells and
946 * #size-cells. They need to be 3 and 2 accordingly. However,
947 * for simplicity we skip the check here.
948 */
Masahiro Yamada61e51ba2017-06-22 16:54:05 +0900949 cell = ofnode_get_property(node, propname, &len);
Simon Glass9e512042017-05-18 20:08:58 -0600950 if (!cell)
951 goto fail;
952
953 if ((len % FDT_PCI_REG_SIZE) == 0) {
954 int num = len / FDT_PCI_REG_SIZE;
955 int i;
956
957 for (i = 0; i < num; i++) {
958 debug("pci address #%d: %08lx %08lx %08lx\n", i,
959 (ulong)fdt32_to_cpu(cell[0]),
960 (ulong)fdt32_to_cpu(cell[1]),
961 (ulong)fdt32_to_cpu(cell[2]));
962 if ((fdt32_to_cpu(*cell) & type) == type) {
963 addr->phys_hi = fdt32_to_cpu(cell[0]);
964 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glasse5878862019-09-25 08:55:46 -0600965 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glass9e512042017-05-18 20:08:58 -0600966 break;
Simon Glass9e512042017-05-18 20:08:58 -0600967 }
Mario Six51db2872018-01-15 11:07:17 +0100968
969 cell += (FDT_PCI_ADDR_CELLS +
970 FDT_PCI_SIZE_CELLS);
Simon Glass9e512042017-05-18 20:08:58 -0600971 }
972
973 if (i == num) {
974 ret = -ENXIO;
975 goto fail;
976 }
977
978 return 0;
Simon Glass9e512042017-05-18 20:08:58 -0600979 }
980
Mario Six51db2872018-01-15 11:07:17 +0100981 ret = -EINVAL;
982
Simon Glass9e512042017-05-18 20:08:58 -0600983fail:
984 debug("(not found)\n");
985 return ret;
986}
987
Bin Meng7b9cbad2018-08-03 01:14:35 -0700988int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
989{
990 const char *list, *end;
991 int len;
992
993 list = ofnode_get_property(node, "compatible", &len);
994 if (!list)
995 return -ENOENT;
996
997 end = list + len;
998 while (list < end) {
999 len = strlen(list);
1000 if (len >= strlen("pciVVVV,DDDD")) {
1001 char *s = strstr(list, "pci");
1002
1003 /*
1004 * check if the string is something like pciVVVV,DDDD.RR
1005 * or just pciVVVV,DDDD
1006 */
1007 if (s && s[7] == ',' &&
1008 (s[12] == '.' || s[12] == 0)) {
1009 s += 3;
1010 *vendor = simple_strtol(s, NULL, 16);
1011
1012 s += 5;
1013 *device = simple_strtol(s, NULL, 16);
1014
1015 return 0;
1016 }
1017 }
1018 list += (len + 1);
1019 }
1020
1021 return -ENOENT;
1022}
1023
Michal Simekdb681d42022-02-23 15:45:40 +01001024int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
1025{
1026 const char *list, *end;
1027 int len;
1028
1029 list = ofnode_get_property(node, "compatible", &len);
1030
1031 if (!list)
1032 return -ENOENT;
1033
1034 end = list + len;
1035 while (list < end) {
1036 len = strlen(list);
1037
1038 if (len >= strlen("ethernet-phy-idVVVV,DDDD")) {
1039 char *s = strstr(list, "ethernet-phy-id");
1040
1041 /*
1042 * check if the string is something like
1043 * ethernet-phy-idVVVV,DDDD
1044 */
1045 if (s && s[19] == '.') {
1046 s += strlen("ethernet-phy-id");
1047 *vendor = simple_strtol(s, NULL, 16);
1048 s += 5;
1049 *device = simple_strtol(s, NULL, 16);
1050
1051 return 0;
1052 }
1053 }
1054 list += (len + 1);
1055 }
1056
1057 return -ENOENT;
1058}
1059
Simon Glass9e512042017-05-18 20:08:58 -06001060int ofnode_read_addr_cells(ofnode node)
1061{
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001062 if (ofnode_is_np(node)) {
Simon Glass9e512042017-05-18 20:08:58 -06001063 return of_n_addr_cells(ofnode_to_np(node));
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001064 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -06001065 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001066 ofnode_to_offset(node));
1067
Simon Glassa3f50d02022-09-06 20:27:20 -06001068 return fdt_address_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001069 }
Simon Glass9e512042017-05-18 20:08:58 -06001070}
1071
1072int ofnode_read_size_cells(ofnode node)
1073{
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001074 if (ofnode_is_np(node)) {
Simon Glass9e512042017-05-18 20:08:58 -06001075 return of_n_size_cells(ofnode_to_np(node));
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001076 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -06001077 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001078 ofnode_to_offset(node));
1079
Simon Glassa3f50d02022-09-06 20:27:20 -06001080 return fdt_size_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001081 }
Simon Glass878d68c2017-06-12 06:21:31 -06001082}
1083
1084int ofnode_read_simple_addr_cells(ofnode node)
1085{
1086 if (ofnode_is_np(node))
1087 return of_simple_addr_cells(ofnode_to_np(node));
1088 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001089 return fdt_address_cells(ofnode_to_fdt(node),
1090 ofnode_to_offset(node));
Simon Glass878d68c2017-06-12 06:21:31 -06001091}
1092
1093int ofnode_read_simple_size_cells(ofnode node)
1094{
1095 if (ofnode_is_np(node))
1096 return of_simple_size_cells(ofnode_to_np(node));
Simon Glass9e512042017-05-18 20:08:58 -06001097 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001098 return fdt_size_cells(ofnode_to_fdt(node),
1099 ofnode_to_offset(node));
Simon Glass9e512042017-05-18 20:08:58 -06001100}
1101
1102bool ofnode_pre_reloc(ofnode node)
1103{
Patrick Delaunayc7a88da2019-02-11 12:49:57 +01001104#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
1105 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
1106 * had property dm-pre-reloc or u-boot,dm-spl/tpl.
1107 * They are removed in final dtb (fdtgrep 2nd pass)
1108 */
1109 return true;
1110#else
Masahiro Yamada252510a2017-06-22 16:54:03 +09001111 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
Simon Glass9e512042017-05-18 20:08:58 -06001112 return true;
Simon Glass06f94462018-10-01 12:22:18 -06001113 if (ofnode_read_bool(node, "u-boot,dm-pre-proper"))
1114 return true;
Simon Glass9e512042017-05-18 20:08:58 -06001115
Simon Glass9e512042017-05-18 20:08:58 -06001116 /*
1117 * In regular builds individual spl and tpl handling both
1118 * count as handled pre-relocation for later second init.
1119 */
Masahiro Yamada252510a2017-06-22 16:54:03 +09001120 if (ofnode_read_bool(node, "u-boot,dm-spl") ||
1121 ofnode_read_bool(node, "u-boot,dm-tpl"))
Simon Glass9e512042017-05-18 20:08:58 -06001122 return true;
Simon Glass9e512042017-05-18 20:08:58 -06001123
1124 return false;
Patrick Delaunayc7a88da2019-02-11 12:49:57 +01001125#endif
Simon Glass9e512042017-05-18 20:08:58 -06001126}
Simon Glassdcf98852017-07-25 08:29:55 -06001127
1128int ofnode_read_resource(ofnode node, uint index, struct resource *res)
1129{
1130 if (ofnode_is_np(node)) {
1131 return of_address_to_resource(ofnode_to_np(node), index, res);
1132 } else {
1133 struct fdt_resource fres;
1134 int ret;
1135
Simon Glassa3f50d02022-09-06 20:27:20 -06001136 ret = fdt_get_resource(ofnode_to_fdt(node),
1137 ofnode_to_offset(node),
Simon Glassdcf98852017-07-25 08:29:55 -06001138 "reg", index, &fres);
1139 if (ret < 0)
1140 return -EINVAL;
1141 memset(res, '\0', sizeof(*res));
1142 res->start = fres.start;
1143 res->end = fres.end;
1144
1145 return 0;
1146 }
1147}
Masahiro Yamada7b8b47b2017-08-26 01:12:30 +09001148
1149int ofnode_read_resource_byname(ofnode node, const char *name,
1150 struct resource *res)
1151{
1152 int index;
1153
1154 index = ofnode_stringlist_search(node, "reg-names", name);
1155 if (index < 0)
1156 return index;
1157
1158 return ofnode_read_resource(node, index, res);
1159}
Mario Six147c6072018-01-15 11:07:19 +01001160
1161u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
1162{
1163 if (ofnode_is_np(node))
1164 return of_translate_address(ofnode_to_np(node), in_addr);
1165 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001166 return fdt_translate_address(ofnode_to_fdt(node),
1167 ofnode_to_offset(node), in_addr);
Mario Six147c6072018-01-15 11:07:19 +01001168}
Masahiro Yamada5ccc2c22018-04-19 12:14:02 +09001169
Fabien Dessenne641067f2019-05-31 15:11:30 +02001170u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
1171{
1172 if (ofnode_is_np(node))
1173 return of_translate_dma_address(ofnode_to_np(node), in_addr);
1174 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001175 return fdt_translate_dma_address(ofnode_to_fdt(node),
1176 ofnode_to_offset(node), in_addr);
Fabien Dessenne641067f2019-05-31 15:11:30 +02001177}
1178
Nicolas Saenz Julienne51bdb502021-01-12 13:55:22 +01001179int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
1180{
1181 if (ofnode_is_np(node))
1182 return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
1183 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001184 return fdt_get_dma_range(ofnode_to_fdt(node),
1185 ofnode_to_offset(node),
Nicolas Saenz Julienne51bdb502021-01-12 13:55:22 +01001186 cpu, bus, size);
1187}
1188
Masahiro Yamada5ccc2c22018-04-19 12:14:02 +09001189int ofnode_device_is_compatible(ofnode node, const char *compat)
1190{
1191 if (ofnode_is_np(node))
1192 return of_device_is_compatible(ofnode_to_np(node), compat,
1193 NULL, NULL);
1194 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001195 return !fdt_node_check_compatible(ofnode_to_fdt(node),
Masahiro Yamada5ccc2c22018-04-19 12:14:02 +09001196 ofnode_to_offset(node),
1197 compat);
1198}
Simon Glassc60f6712018-06-11 13:07:13 -06001199
1200ofnode ofnode_by_compatible(ofnode from, const char *compat)
1201{
1202 if (of_live_active()) {
1203 return np_to_ofnode(of_find_compatible_node(
1204 (struct device_node *)ofnode_to_np(from), NULL,
1205 compat));
1206 } else {
Simon Glass2187cb72022-09-06 20:27:23 -06001207 return noffset_to_ofnode(from,
1208 fdt_node_offset_by_compatible(ofnode_to_fdt(from),
Simon Glassa3f50d02022-09-06 20:27:20 -06001209 ofnode_to_offset(from), compat));
Simon Glassc60f6712018-06-11 13:07:13 -06001210 }
1211}
Jens Wiklander61fba0f2018-08-20 11:09:58 +02001212
1213ofnode ofnode_by_prop_value(ofnode from, const char *propname,
1214 const void *propval, int proplen)
1215{
1216 if (of_live_active()) {
1217 return np_to_ofnode(of_find_node_by_prop_value(
1218 (struct device_node *)ofnode_to_np(from), propname,
1219 propval, proplen));
1220 } else {
Simon Glass2187cb72022-09-06 20:27:23 -06001221 return noffset_to_ofnode(from,
1222 fdt_node_offset_by_prop_value(ofnode_to_fdt(from),
1223 ofnode_to_offset(from), propname, propval,
1224 proplen));
Jens Wiklander61fba0f2018-08-20 11:09:58 +02001225 }
1226}
Mario Sixe369e582018-06-26 08:46:48 +02001227
Simon Glassbe0789a2022-07-30 15:52:10 -06001228int ofnode_write_prop(ofnode node, const char *propname, const void *value,
1229 int len)
Mario Sixe369e582018-06-26 08:46:48 +02001230{
Simon Glass39e42be2022-07-30 15:52:13 -06001231 if (of_live_active())
Simon Glass98306982022-09-06 20:27:04 -06001232 return of_write_prop(ofnode_to_np(node), propname, len, value);
Simon Glass39e42be2022-07-30 15:52:13 -06001233 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001234 return fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glass39e42be2022-07-30 15:52:13 -06001235 propname, value, len);
Mario Sixe369e582018-06-26 08:46:48 +02001236
1237 return 0;
1238}
1239
1240int ofnode_write_string(ofnode node, const char *propname, const char *value)
1241{
Mario Sixe369e582018-06-26 08:46:48 +02001242 assert(ofnode_valid(node));
1243
1244 debug("%s: %s = %s", __func__, propname, value);
1245
Simon Glassbe0789a2022-07-30 15:52:10 -06001246 return ofnode_write_prop(node, propname, value, strlen(value) + 1);
Mario Sixe369e582018-06-26 08:46:48 +02001247}
1248
Simon Glass55f79902022-07-30 15:52:14 -06001249int ofnode_write_u32(ofnode node, const char *propname, u32 value)
1250{
1251 fdt32_t *val;
1252
1253 assert(ofnode_valid(node));
1254
1255 log_debug("%s = %x", propname, value);
1256 val = malloc(sizeof(*val));
1257 if (!val)
1258 return -ENOMEM;
1259 *val = cpu_to_fdt32(value);
1260
1261 return ofnode_write_prop(node, propname, val, sizeof(value));
1262}
1263
Mario Sixe369e582018-06-26 08:46:48 +02001264int ofnode_set_enabled(ofnode node, bool value)
1265{
Mario Sixe369e582018-06-26 08:46:48 +02001266 assert(ofnode_valid(node));
1267
1268 if (value)
1269 return ofnode_write_string(node, "status", "okay");
1270 else
Bin Meng16351212019-07-05 09:23:17 -07001271 return ofnode_write_string(node, "status", "disabled");
Mario Sixe369e582018-06-26 08:46:48 +02001272}
Simon Glass7de8bd02021-08-07 07:24:01 -06001273
1274bool ofnode_conf_read_bool(const char *prop_name)
1275{
1276 ofnode node;
1277
1278 node = ofnode_path("/config");
1279 if (!ofnode_valid(node))
1280 return false;
1281
1282 return ofnode_read_bool(node, prop_name);
1283}
1284
1285int ofnode_conf_read_int(const char *prop_name, int default_val)
1286{
1287 ofnode node;
1288
1289 node = ofnode_path("/config");
1290 if (!ofnode_valid(node))
1291 return default_val;
1292
1293 return ofnode_read_u32_default(node, prop_name, default_val);
1294}
1295
1296const char *ofnode_conf_read_str(const char *prop_name)
1297{
1298 ofnode node;
1299
1300 node = ofnode_path("/config");
1301 if (!ofnode_valid(node))
1302 return NULL;
1303
1304 return ofnode_read_string(node, prop_name);
1305}
Marek Behúnf3dd2132022-04-07 00:32:57 +02001306
1307ofnode ofnode_get_phy_node(ofnode node)
1308{
1309 /* DT node properties that reference a PHY node */
1310 static const char * const phy_handle_str[] = {
1311 "phy-handle", "phy", "phy-device",
1312 };
1313 struct ofnode_phandle_args args = {
1314 .node = ofnode_null()
1315 };
1316 int i;
1317
1318 assert(ofnode_valid(node));
1319
1320 for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
1321 if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
1322 NULL, 0, 0, &args))
1323 break;
1324
1325 return args.node;
1326}
Marek Behún123ca112022-04-07 00:33:01 +02001327
1328phy_interface_t ofnode_read_phy_mode(ofnode node)
1329{
1330 const char *mode;
1331 int i;
1332
1333 assert(ofnode_valid(node));
1334
1335 mode = ofnode_read_string(node, "phy-mode");
1336 if (!mode)
1337 mode = ofnode_read_string(node, "phy-connection-type");
1338
1339 if (!mode)
Marek Behúnffb0f6f2022-04-07 00:33:03 +02001340 return PHY_INTERFACE_MODE_NA;
Marek Behún123ca112022-04-07 00:33:01 +02001341
Marek Behún6706d7d2022-04-07 00:33:02 +02001342 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
Marek Behún123ca112022-04-07 00:33:01 +02001343 if (!strcmp(mode, phy_interface_strings[i]))
1344 return i;
1345
1346 debug("%s: Invalid PHY interface '%s'\n", __func__, mode);
1347
Marek Behúnffb0f6f2022-04-07 00:33:03 +02001348 return PHY_INTERFACE_MODE_NA;
Marek Behún123ca112022-04-07 00:33:01 +02001349}
Simon Glassffe90392022-09-06 20:27:02 -06001350
1351int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
1352{
1353 ofnode subnode;
1354 int ret = 0;
1355
1356 assert(ofnode_valid(node));
1357
1358 if (ofnode_is_np(node)) {
1359 struct device_node *np, *child;
1360
1361 np = (struct device_node *)ofnode_to_np(node);
1362 ret = of_add_subnode(np, name, -1, &child);
1363 if (ret && ret != -EEXIST)
1364 return ret;
1365 subnode = np_to_ofnode(child);
1366 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -06001367 void *fdt = ofnode_to_fdt(node);
Simon Glassffe90392022-09-06 20:27:02 -06001368 int poffset = ofnode_to_offset(node);
1369 int offset;
1370
1371 offset = fdt_add_subnode(fdt, poffset, name);
1372 if (offset == -FDT_ERR_EXISTS) {
1373 offset = fdt_subnode_offset(fdt, poffset, name);
1374 ret = -EEXIST;
1375 }
1376 if (offset < 0)
1377 return -EINVAL;
Simon Glass2187cb72022-09-06 20:27:23 -06001378 subnode = noffset_to_ofnode(node, offset);
Simon Glassffe90392022-09-06 20:27:02 -06001379 }
1380
1381 *subnodep = subnode;
1382
1383 return ret; /* 0 or -EEXIST */
1384}