blob: b1ba8c5ab4c7553b1df7a6f15104f9dc2111e9af [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
Kishon Vijay Abraham I77cbaf82021-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 Herbrechtsmeierb471bdc2022-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 Glass9e512042017-05-18 20:08:58 -060096int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
97{
Dario Binacchi59006602020-03-29 18:04:42 +020098 return ofnode_read_u32_index(node, propname, 0, outp);
Simon Glass9e512042017-05-18 20:08:58 -060099}
100
Trent Piephob061ef32019-05-10 17:48:20 +0000101u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
Simon Glass9e512042017-05-18 20:08:58 -0600102{
103 assert(ofnode_valid(node));
Dario Binacchi59006602020-03-29 18:04:42 +0200104 ofnode_read_u32_index(node, propname, 0, &def);
Simon Glass9e512042017-05-18 20:08:58 -0600105
106 return def;
107}
108
Dario Binacchi4bb70752020-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
Simon Glassa3f50d02022-09-06 20:27:20 -0600122 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
123 propname, &len);
Dario Binacchi4bb70752020-03-29 18:04:41 +0200124 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 Glass9e512042017-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 Glass7e5196c2018-06-11 13:07:10 -0600157int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
158{
Jean-Jacques Hiblotd60ae4c2019-10-22 10:05:22 +0200159 const unaligned_fdt64_t *cell;
Simon Glass7e5196c2018-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
Simon Glassa3f50d02022-09-06 20:27:20 -0600168 cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
169 propname, &len);
Simon Glass7e5196c2018-06-11 13:07:10 -0600170 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 Reddy3f3d7712019-09-02 16:34:30 +0200181u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
Simon Glass7e5196c2018-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 Glass9e512042017-05-18 20:08:58 -0600189bool ofnode_read_bool(ofnode node, const char *propname)
190{
Masahiro Yamadab2ec7ea2017-06-22 16:54:07 +0900191 const void *prop;
Simon Glass9e512042017-05-18 20:08:58 -0600192
193 assert(ofnode_valid(node));
194 debug("%s: %s: ", __func__, propname);
195
Masahiro Yamadab2ec7ea2017-06-22 16:54:07 +0900196 prop = ofnode_get_property(node, propname, NULL);
Simon Glass9e512042017-05-18 20:08:58 -0600197
Masahiro Yamadab2ec7ea2017-06-22 16:54:07 +0900198 debug("%s\n", prop ? "true" : "false");
199
200 return prop ? true : false;
Simon Glass9e512042017-05-18 20:08:58 -0600201}
202
Simon Glassa8167d82020-01-27 08:49:44 -0700203const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
Simon Glass9e512042017-05-18 20:08:58 -0600204{
Simon Glassa8167d82020-01-27 08:49:44 -0700205 const char *val = NULL;
206 int len;
Simon Glass9e512042017-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 Glassa8167d82020-01-27 08:49:44 -0700213 ofnode_to_np(node), propname, &len);
Simon Glass9e512042017-05-18 20:08:58 -0600214
215 if (prop) {
Simon Glassa8167d82020-01-27 08:49:44 -0700216 val = prop->value;
Simon Glass9e512042017-05-18 20:08:58 -0600217 len = prop->length;
218 }
219 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -0600220 val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glass9e512042017-05-18 20:08:58 -0600221 propname, &len);
222 }
Simon Glassa8167d82020-01-27 08:49:44 -0700223 if (!val) {
Simon Glass9e512042017-05-18 20:08:58 -0600224 debug("<not found>\n");
Simon Glassa8167d82020-01-27 08:49:44 -0700225 if (sizep)
226 *sizep = -FDT_ERR_NOTFOUND;
Simon Glass9e512042017-05-18 20:08:58 -0600227 return NULL;
228 }
Simon Glassa8167d82020-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 Glass9e512042017-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 Glass1aada632020-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 Glass9e512042017-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 Glass98306982022-09-06 20:27:04 -0600271 struct device_node *np = ofnode_to_np(node);
Simon Glass9e512042017-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 {
Simon Glassa3f50d02022-09-06 20:27:20 -0600279 int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
Simon Glass9e512042017-05-18 20:08:58 -0600280 ofnode_to_offset(node), subnode_name);
Simon Glass2187cb72022-09-06 20:27:23 -0600281 subnode = noffset_to_ofnode(node, ooffset);
Simon Glass9e512042017-05-18 20:08:58 -0600282 }
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 Glass66d0d0c2022-09-06 20:27:18 -0600299 int ret;
300
Simon Glassa3f50d02022-09-06 20:27:20 -0600301 ret = fdtdec_get_int_array(ofnode_to_fdt(node),
Simon Glass66d0d0c2022-09-06 20:27:18 -0600302 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 Glass9e512042017-05-18 20:08:58 -0600313 }
314}
315
Simon Glassec1add12020-12-16 17:25:06 -0700316#if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
Simon Glass0de1b072020-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 {
Simon Glassa3f50d02022-09-06 20:27:20 -0600322 return fdtdec_get_is_enabled(ofnode_to_fdt(node),
Simon Glass0de1b072020-11-28 17:50:02 -0700323 ofnode_to_offset(node));
324 }
325}
326
Simon Glass9e512042017-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
Simon Glass2187cb72022-09-06 20:27:23 -0600333 return noffset_to_ofnode(node,
Simon Glassa3f50d02022-09-06 20:27:20 -0600334 fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glass9e512042017-05-18 20:08:58 -0600335}
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
Simon Glass2187cb72022-09-06 20:27:23 -0600343 return noffset_to_ofnode(node,
Simon Glassa3f50d02022-09-06 20:27:20 -0600344 fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
Simon Glass9e512042017-05-18 20:08:58 -0600345}
Simon Glassec1add12020-12-16 17:25:06 -0700346#endif /* !DM_INLINE_OFNODE */
Simon Glass9e512042017-05-18 20:08:58 -0600347
Philipp Tomsiche2d59972018-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
Simon Glassa3f50d02022-09-06 20:27:20 -0600356 parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
Philipp Tomsiche2d59972018-02-23 17:38:49 +0100357 ofnode_to_offset(node));
358
359 return parent;
360}
361
Simon Glass9e512042017-05-18 20:08:58 -0600362const char *ofnode_get_name(ofnode node)
363{
Kever Yang8f0a70e2019-07-19 11:23:47 +0800364 if (!ofnode_valid(node)) {
365 debug("%s node not valid\n", __func__);
366 return NULL;
367 }
368
Simon Glass9e512042017-05-18 20:08:58 -0600369 if (ofnode_is_np(node))
Simon Glassf46ec932022-09-06 20:27:15 -0600370 return node.np->name;
Simon Glass9e512042017-05-18 20:08:58 -0600371
Simon Glassa3f50d02022-09-06 20:27:20 -0600372 return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
Simon Glass9e512042017-05-18 20:08:58 -0600373}
374
Marek Behún0e116be2021-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
Simon Glassa3f50d02022-09-06 20:27:20 -0600389 res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
Marek Behún0e116be2021-05-26 14:08:18 +0200390 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 Yangb4f20762018-02-23 17:38:50 +0100400ofnode ofnode_get_by_phandle(uint phandle)
401{
402 ofnode node;
403
404 if (of_live_active())
Simon Glass829d5122022-09-06 20:26:57 -0600405 node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
Kever Yangb4f20762018-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
Simon Glass928d2672022-09-06 20:27:22 -0600413ofnode oftree_get_by_phandle(oftree tree, uint phandle)
414{
415 ofnode node;
416
417 if (of_live_active())
418 node = np_to_ofnode(of_find_node_by_phandle(tree.np, phandle));
419 else
420 node.of_offset =
421 fdt_node_offset_by_phandle(oftree_lookup_fdt(tree),
422 phandle);
423
424 return node;
425}
426
Marek Behún31a7b712021-05-26 14:08:17 +0200427static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
428 fdt_size_t *size, bool translate)
Simon Glassbed77492017-05-18 20:09:01 -0600429{
Keerthy16787542018-11-19 11:44:47 +0530430 int na, ns;
Keerthy16787542018-11-19 11:44:47 +0530431
Chen Guanqiao1b098b32021-07-12 15:40:20 +0800432 if (size)
433 *size = FDT_SIZE_T_NONE;
Chen Guanqiaoaa351a12021-04-12 14:51:11 +0800434
Simon Glassbed77492017-05-18 20:09:01 -0600435 if (ofnode_is_np(node)) {
436 const __be32 *prop_val;
Simon Glasse18c41f2019-09-25 08:55:50 -0600437 u64 size64;
Simon Glassbed77492017-05-18 20:09:01 -0600438 uint flags;
Simon Glassbed77492017-05-18 20:09:01 -0600439
Simon Glasse18c41f2019-09-25 08:55:50 -0600440 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
441 &flags);
Simon Glassbed77492017-05-18 20:09:01 -0600442 if (!prop_val)
443 return FDT_ADDR_T_NONE;
Chen Guanqiao1b098b32021-07-12 15:40:20 +0800444
Simon Glasse18c41f2019-09-25 08:55:50 -0600445 if (size)
446 *size = size64;
Mario Six286ede62017-12-20 09:52:12 +0100447
Mario Sixe8d52912018-03-12 14:53:33 +0100448 ns = of_n_size_cells(ofnode_to_np(node));
449
Marek Behún31a7b712021-05-26 14:08:17 +0200450 if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Six286ede62017-12-20 09:52:12 +0100451 return of_translate_address(ofnode_to_np(node), prop_val);
452 } else {
453 na = of_n_addr_cells(ofnode_to_np(node));
454 return of_read_number(prop_val, na);
455 }
Simon Glassbed77492017-05-18 20:09:01 -0600456 } else {
Keerthy16787542018-11-19 11:44:47 +0530457 na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
458 ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
Simon Glassa3f50d02022-09-06 20:27:20 -0600459 return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
Keerthy16787542018-11-19 11:44:47 +0530460 ofnode_to_offset(node), "reg",
Marek Behún31a7b712021-05-26 14:08:17 +0200461 index, na, ns, size,
462 translate);
Simon Glassbed77492017-05-18 20:09:01 -0600463 }
Simon Glassbed77492017-05-18 20:09:01 -0600464}
465
Marek Behún31a7b712021-05-26 14:08:17 +0200466fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
467{
468 return __ofnode_get_addr_size_index(node, index, size, true);
469}
470
471fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
472 fdt_size_t *size)
473{
474 return __ofnode_get_addr_size_index(node, index, size, false);
475}
476
Keerthye679d032019-04-24 17:19:53 +0530477fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
478{
479 fdt_size_t size;
480
481 return ofnode_get_addr_size_index(node, index, &size);
482}
483
Simon Glassbed77492017-05-18 20:09:01 -0600484fdt_addr_t ofnode_get_addr(ofnode node)
485{
486 return ofnode_get_addr_index(node, 0);
487}
488
Chen Guanqiaoaa351a12021-04-12 14:51:11 +0800489fdt_size_t ofnode_get_size(ofnode node)
490{
491 fdt_size_t size;
492
493 ofnode_get_addr_size_index(node, 0, &size);
494
495 return size;
496}
497
Simon Glass9e512042017-05-18 20:08:58 -0600498int ofnode_stringlist_search(ofnode node, const char *property,
499 const char *string)
500{
501 if (ofnode_is_np(node)) {
502 return of_property_match_string(ofnode_to_np(node),
503 property, string);
504 } else {
505 int ret;
506
Simon Glassa3f50d02022-09-06 20:27:20 -0600507 ret = fdt_stringlist_search(ofnode_to_fdt(node),
Simon Glass9e512042017-05-18 20:08:58 -0600508 ofnode_to_offset(node), property,
509 string);
510 if (ret == -FDT_ERR_NOTFOUND)
511 return -ENODATA;
512 else if (ret < 0)
513 return -EINVAL;
514
515 return ret;
516 }
517}
518
519int ofnode_read_string_index(ofnode node, const char *property, int index,
520 const char **outp)
521{
522 if (ofnode_is_np(node)) {
523 return of_property_read_string_index(ofnode_to_np(node),
524 property, index, outp);
525 } else {
526 int len;
527
Simon Glassa3f50d02022-09-06 20:27:20 -0600528 *outp = fdt_stringlist_get(ofnode_to_fdt(node),
529 ofnode_to_offset(node),
Simon Glass9e512042017-05-18 20:08:58 -0600530 property, index, &len);
531 if (len < 0)
532 return -EINVAL;
533 return 0;
534 }
535}
536
Simon Glass8c293d62017-06-12 06:21:28 -0600537int ofnode_read_string_count(ofnode node, const char *property)
538{
539 if (ofnode_is_np(node)) {
540 return of_property_count_strings(ofnode_to_np(node), property);
541 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -0600542 return fdt_stringlist_count(ofnode_to_fdt(node),
Simon Glass8c293d62017-06-12 06:21:28 -0600543 ofnode_to_offset(node), property);
544 }
545}
546
Simon Glass075bfc92021-10-23 17:26:07 -0600547int ofnode_read_string_list(ofnode node, const char *property,
548 const char ***listp)
549{
550 const char **prop;
551 int count;
552 int i;
553
554 *listp = NULL;
555 count = ofnode_read_string_count(node, property);
556 if (count < 0)
557 return count;
558 if (!count)
559 return 0;
560
561 prop = calloc(count + 1, sizeof(char *));
562 if (!prop)
563 return -ENOMEM;
564
565 for (i = 0; i < count; i++)
566 ofnode_read_string_index(node, property, i, &prop[i]);
567 prop[count] = NULL;
568 *listp = prop;
569
570 return count;
571}
572
Simon Glass9e512042017-05-18 20:08:58 -0600573static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
574 struct ofnode_phandle_args *out)
575{
576 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
577 out->node = offset_to_ofnode(in->node);
578 out->args_count = in->args_count;
579 memcpy(out->args, in->args, sizeof(out->args));
580}
581
582static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
583 struct ofnode_phandle_args *out)
584{
585 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
586 out->node = np_to_ofnode(in->np);
587 out->args_count = in->args_count;
588 memcpy(out->args, in->args, sizeof(out->args));
589}
590
591int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
592 const char *cells_name, int cell_count,
593 int index,
594 struct ofnode_phandle_args *out_args)
595{
596 if (ofnode_is_np(node)) {
597 struct of_phandle_args args;
598 int ret;
599
600 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay01d89e32020-09-10 18:26:17 +0200601 list_name, cells_name,
602 cell_count, index,
Mario Six51db2872018-01-15 11:07:17 +0100603 &args);
Simon Glass9e512042017-05-18 20:08:58 -0600604 if (ret)
605 return ret;
606 ofnode_from_of_phandle_args(&args, out_args);
607 } else {
608 struct fdtdec_phandle_args args;
609 int ret;
610
Simon Glassa3f50d02022-09-06 20:27:20 -0600611 ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Mario Six51db2872018-01-15 11:07:17 +0100612 ofnode_to_offset(node),
613 list_name, cells_name,
614 cell_count, index, &args);
Simon Glass9e512042017-05-18 20:08:58 -0600615 if (ret)
616 return ret;
617 ofnode_from_fdtdec_phandle_args(&args, out_args);
618 }
619
620 return 0;
621}
622
Patrice Chotard642346a2017-07-18 11:57:08 +0200623int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
Patrick Delaunay89f68302020-09-25 09:41:14 +0200624 const char *cells_name, int cell_count)
Patrice Chotard642346a2017-07-18 11:57:08 +0200625{
626 if (ofnode_is_np(node))
627 return of_count_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay89f68302020-09-25 09:41:14 +0200628 list_name, cells_name, cell_count);
Patrice Chotard642346a2017-07-18 11:57:08 +0200629 else
Simon Glassa3f50d02022-09-06 20:27:20 -0600630 return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
Patrice Chotard642346a2017-07-18 11:57:08 +0200631 ofnode_to_offset(node), list_name, cells_name,
Patrick Delaunay89f68302020-09-25 09:41:14 +0200632 cell_count, -1, NULL);
Patrice Chotard642346a2017-07-18 11:57:08 +0200633}
634
Simon Glass9e512042017-05-18 20:08:58 -0600635ofnode ofnode_path(const char *path)
636{
637 if (of_live_active())
638 return np_to_ofnode(of_find_node_by_path(path));
639 else
640 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
641}
642
Simon Glass33104842022-07-30 15:52:08 -0600643ofnode ofnode_path_root(oftree tree, const char *path)
644{
645 if (of_live_active())
646 return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
647 NULL));
648 else if (*path != '/' && tree.fdt != gd->fdt_blob)
649 return ofnode_null(); /* Aliases only on control FDT */
650 else
651 return offset_to_ofnode(fdt_path_offset(tree.fdt, path));
652}
653
Simon Glassbd933bf2020-01-27 08:49:46 -0700654const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glass9e512042017-05-18 20:08:58 -0600655{
656 ofnode chosen_node;
657
658 chosen_node = ofnode_path("/chosen");
659
Simon Glassbd933bf2020-01-27 08:49:46 -0700660 return ofnode_read_prop(chosen_node, propname, sizep);
661}
662
663const char *ofnode_read_chosen_string(const char *propname)
664{
665 return ofnode_read_chosen_prop(propname, NULL);
Simon Glass9e512042017-05-18 20:08:58 -0600666}
667
668ofnode ofnode_get_chosen_node(const char *name)
669{
670 const char *prop;
671
Simon Glassbd933bf2020-01-27 08:49:46 -0700672 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glass9e512042017-05-18 20:08:58 -0600673 if (!prop)
674 return ofnode_null();
675
676 return ofnode_path(prop);
677}
678
Michal Simek305d3182020-07-28 12:51:08 +0200679const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
680{
681 ofnode node;
682
683 node = ofnode_path("/aliases");
684
685 return ofnode_read_prop(node, propname, sizep);
686}
687
688ofnode ofnode_get_aliases_node(const char *name)
689{
690 const char *prop;
691
692 prop = ofnode_read_aliases_prop(name, NULL);
693 if (!prop)
694 return ofnode_null();
695
696 debug("%s: node_path: %s\n", __func__, prop);
697
698 return ofnode_path(prop);
699}
700
Chunfeng Yun89b84b82020-05-02 11:35:09 +0200701int ofnode_get_child_count(ofnode parent)
702{
703 ofnode child;
704 int num = 0;
705
706 ofnode_for_each_subnode(child, parent)
707 num++;
708
709 return num;
710}
711
Simon Glass9e512042017-05-18 20:08:58 -0600712static int decode_timing_property(ofnode node, const char *name,
713 struct timing_entry *result)
714{
715 int length, ret = 0;
716
717 length = ofnode_read_size(node, name);
718 if (length < 0) {
719 debug("%s: could not find property %s\n",
720 ofnode_get_name(node), name);
721 return length;
722 }
723
724 if (length == sizeof(u32)) {
725 result->typ = ofnode_read_u32_default(node, name, 0);
726 result->min = result->typ;
727 result->max = result->typ;
728 } else {
729 ret = ofnode_read_u32_array(node, name, &result->min, 3);
730 }
731
732 return ret;
733}
734
735int ofnode_decode_display_timing(ofnode parent, int index,
736 struct display_timing *dt)
737{
738 int i;
739 ofnode timings, node;
740 u32 val = 0;
741 int ret = 0;
742
743 timings = ofnode_find_subnode(parent, "display-timings");
744 if (!ofnode_valid(timings))
745 return -EINVAL;
746
Simon Glass3991f422017-08-05 15:45:54 -0600747 i = 0;
748 ofnode_for_each_subnode(node, timings) {
749 if (i++ == index)
750 break;
751 }
Simon Glass9e512042017-05-18 20:08:58 -0600752
753 if (!ofnode_valid(node))
754 return -EINVAL;
755
756 memset(dt, 0, sizeof(*dt));
757
758 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
759 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
760 ret |= decode_timing_property(node, "hactive", &dt->hactive);
761 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
762 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
763 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
764 ret |= decode_timing_property(node, "vactive", &dt->vactive);
765 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
766 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
767
768 dt->flags = 0;
769 val = ofnode_read_u32_default(node, "vsync-active", -1);
770 if (val != -1) {
771 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
772 DISPLAY_FLAGS_VSYNC_LOW;
773 }
774 val = ofnode_read_u32_default(node, "hsync-active", -1);
775 if (val != -1) {
776 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
777 DISPLAY_FLAGS_HSYNC_LOW;
778 }
779 val = ofnode_read_u32_default(node, "de-active", -1);
780 if (val != -1) {
781 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
782 DISPLAY_FLAGS_DE_LOW;
783 }
784 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
785 if (val != -1) {
786 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
787 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
788 }
789
790 if (ofnode_read_bool(node, "interlaced"))
791 dt->flags |= DISPLAY_FLAGS_INTERLACED;
792 if (ofnode_read_bool(node, "doublescan"))
793 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
794 if (ofnode_read_bool(node, "doubleclk"))
795 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
796
797 return ret;
798}
799
Masahiro Yamada61e51ba2017-06-22 16:54:05 +0900800const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glass9e512042017-05-18 20:08:58 -0600801{
Masahiro Yamadacb7dbe12017-06-22 16:54:04 +0900802 if (ofnode_is_np(node))
803 return of_get_property(ofnode_to_np(node), propname, lenp);
804 else
Simon Glassa3f50d02022-09-06 20:27:20 -0600805 return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glass9e512042017-05-18 20:08:58 -0600806 propname, lenp);
Simon Glass9e512042017-05-18 20:08:58 -0600807}
808
Simon Glass4b1f5712022-09-06 20:27:13 -0600809int ofnode_first_property(ofnode node, struct ofprop *prop)
Patrick Delaunayce891fca2020-01-13 11:34:56 +0100810{
811 prop->node = node;
812
813 if (ofnode_is_np(node)) {
814 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
815 if (!prop->prop)
816 return -FDT_ERR_NOTFOUND;
817 } else {
818 prop->offset =
Simon Glassa3f50d02022-09-06 20:27:20 -0600819 fdt_first_property_offset(ofnode_to_fdt(node),
Patrick Delaunayce891fca2020-01-13 11:34:56 +0100820 ofnode_to_offset(prop->node));
821 if (prop->offset < 0)
822 return prop->offset;
823 }
824
825 return 0;
826}
827
Simon Glass4b1f5712022-09-06 20:27:13 -0600828int ofnode_next_property(struct ofprop *prop)
Patrick Delaunayce891fca2020-01-13 11:34:56 +0100829{
830 if (ofnode_is_np(prop->node)) {
831 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
832 prop->prop);
833 if (!prop->prop)
834 return -FDT_ERR_NOTFOUND;
835 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -0600836 prop->offset =
837 fdt_next_property_offset(ofnode_to_fdt(prop->node),
838 prop->offset);
Patrick Delaunayce891fca2020-01-13 11:34:56 +0100839 if (prop->offset < 0)
840 return prop->offset;
841 }
842
843 return 0;
844}
845
Simon Glass92432242022-09-06 20:27:14 -0600846const void *ofprop_get_property(const struct ofprop *prop,
847 const char **propname, int *lenp)
Patrick Delaunayce891fca2020-01-13 11:34:56 +0100848{
849 if (ofnode_is_np(prop->node))
850 return of_get_property_by_prop(ofnode_to_np(prop->node),
851 prop->prop, propname, lenp);
852 else
Simon Glassa3f50d02022-09-06 20:27:20 -0600853 return fdt_getprop_by_offset(ofnode_to_fdt(prop->node),
Patrick Delaunayce891fca2020-01-13 11:34:56 +0100854 prop->offset,
855 propname, lenp);
856}
857
Simon Glass9e512042017-05-18 20:08:58 -0600858fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
859 fdt_size_t *sizep)
860{
861 if (ofnode_is_np(node)) {
862 int na, ns;
863 int psize;
864 const struct device_node *np = ofnode_to_np(node);
Klaus Goger68a34522017-09-20 13:50:41 +0200865 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glass9e512042017-05-18 20:08:58 -0600866
Klaus Goger68a34522017-09-20 13:50:41 +0200867 if (!prop)
868 return FDT_ADDR_T_NONE;
Simon Glass9e512042017-05-18 20:08:58 -0600869 na = of_n_addr_cells(np);
Marek Vasut51cb9272018-10-01 12:37:19 +0200870 ns = of_n_size_cells(np);
Simon Glassa4b8e372017-05-18 20:09:27 -0600871 *sizep = of_read_number(prop + na, ns);
Marek Vasuta6a45cd2018-10-01 12:37:20 +0200872
Dario Binacchia47abd72021-05-01 17:05:26 +0200873 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta6a45cd2018-10-01 12:37:20 +0200874 return of_translate_address(np, prop);
875 else
876 return of_read_number(prop, na);
Simon Glass9e512042017-05-18 20:08:58 -0600877 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -0600878 return fdtdec_get_addr_size(ofnode_to_fdt(node),
Simon Glass9e512042017-05-18 20:08:58 -0600879 ofnode_to_offset(node), property,
880 sizep);
881 }
882}
883
884const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
885 size_t sz)
886{
887 if (ofnode_is_np(node)) {
888 const struct device_node *np = ofnode_to_np(node);
889 int psize;
890 const __be32 *prop = of_get_property(np, propname, &psize);
891
892 if (!prop || sz != psize)
893 return NULL;
894 return (uint8_t *)prop;
895
896 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -0600897 return fdtdec_locate_byte_array(ofnode_to_fdt(node),
Simon Glass9e512042017-05-18 20:08:58 -0600898 ofnode_to_offset(node), propname, sz);
899 }
900}
901
902int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
903 const char *propname, struct fdt_pci_addr *addr)
904{
Masahiro Yamada8c9eaad2017-06-22 17:57:50 +0900905 const fdt32_t *cell;
Simon Glass9e512042017-05-18 20:08:58 -0600906 int len;
907 int ret = -ENOENT;
908
909 debug("%s: %s: ", __func__, propname);
910
911 /*
912 * If we follow the pci bus bindings strictly, we should check
913 * the value of the node's parent node's #address-cells and
914 * #size-cells. They need to be 3 and 2 accordingly. However,
915 * for simplicity we skip the check here.
916 */
Masahiro Yamada61e51ba2017-06-22 16:54:05 +0900917 cell = ofnode_get_property(node, propname, &len);
Simon Glass9e512042017-05-18 20:08:58 -0600918 if (!cell)
919 goto fail;
920
921 if ((len % FDT_PCI_REG_SIZE) == 0) {
922 int num = len / FDT_PCI_REG_SIZE;
923 int i;
924
925 for (i = 0; i < num; i++) {
926 debug("pci address #%d: %08lx %08lx %08lx\n", i,
927 (ulong)fdt32_to_cpu(cell[0]),
928 (ulong)fdt32_to_cpu(cell[1]),
929 (ulong)fdt32_to_cpu(cell[2]));
930 if ((fdt32_to_cpu(*cell) & type) == type) {
931 addr->phys_hi = fdt32_to_cpu(cell[0]);
932 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glasse5878862019-09-25 08:55:46 -0600933 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glass9e512042017-05-18 20:08:58 -0600934 break;
Simon Glass9e512042017-05-18 20:08:58 -0600935 }
Mario Six51db2872018-01-15 11:07:17 +0100936
937 cell += (FDT_PCI_ADDR_CELLS +
938 FDT_PCI_SIZE_CELLS);
Simon Glass9e512042017-05-18 20:08:58 -0600939 }
940
941 if (i == num) {
942 ret = -ENXIO;
943 goto fail;
944 }
945
946 return 0;
Simon Glass9e512042017-05-18 20:08:58 -0600947 }
948
Mario Six51db2872018-01-15 11:07:17 +0100949 ret = -EINVAL;
950
Simon Glass9e512042017-05-18 20:08:58 -0600951fail:
952 debug("(not found)\n");
953 return ret;
954}
955
Bin Meng7b9cbad2018-08-03 01:14:35 -0700956int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
957{
958 const char *list, *end;
959 int len;
960
961 list = ofnode_get_property(node, "compatible", &len);
962 if (!list)
963 return -ENOENT;
964
965 end = list + len;
966 while (list < end) {
967 len = strlen(list);
968 if (len >= strlen("pciVVVV,DDDD")) {
969 char *s = strstr(list, "pci");
970
971 /*
972 * check if the string is something like pciVVVV,DDDD.RR
973 * or just pciVVVV,DDDD
974 */
975 if (s && s[7] == ',' &&
976 (s[12] == '.' || s[12] == 0)) {
977 s += 3;
978 *vendor = simple_strtol(s, NULL, 16);
979
980 s += 5;
981 *device = simple_strtol(s, NULL, 16);
982
983 return 0;
984 }
985 }
986 list += (len + 1);
987 }
988
989 return -ENOENT;
990}
991
Michal Simekdb681d42022-02-23 15:45:40 +0100992int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
993{
994 const char *list, *end;
995 int len;
996
997 list = ofnode_get_property(node, "compatible", &len);
998
999 if (!list)
1000 return -ENOENT;
1001
1002 end = list + len;
1003 while (list < end) {
1004 len = strlen(list);
1005
1006 if (len >= strlen("ethernet-phy-idVVVV,DDDD")) {
1007 char *s = strstr(list, "ethernet-phy-id");
1008
1009 /*
1010 * check if the string is something like
1011 * ethernet-phy-idVVVV,DDDD
1012 */
1013 if (s && s[19] == '.') {
1014 s += strlen("ethernet-phy-id");
1015 *vendor = simple_strtol(s, NULL, 16);
1016 s += 5;
1017 *device = simple_strtol(s, NULL, 16);
1018
1019 return 0;
1020 }
1021 }
1022 list += (len + 1);
1023 }
1024
1025 return -ENOENT;
1026}
1027
Simon Glass9e512042017-05-18 20:08:58 -06001028int ofnode_read_addr_cells(ofnode node)
1029{
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001030 if (ofnode_is_np(node)) {
Simon Glass9e512042017-05-18 20:08:58 -06001031 return of_n_addr_cells(ofnode_to_np(node));
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001032 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -06001033 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001034 ofnode_to_offset(node));
1035
Simon Glassa3f50d02022-09-06 20:27:20 -06001036 return fdt_address_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001037 }
Simon Glass9e512042017-05-18 20:08:58 -06001038}
1039
1040int ofnode_read_size_cells(ofnode node)
1041{
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001042 if (ofnode_is_np(node)) {
Simon Glass9e512042017-05-18 20:08:58 -06001043 return of_n_size_cells(ofnode_to_np(node));
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001044 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -06001045 int parent = fdt_parent_offset(ofnode_to_fdt(node),
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001046 ofnode_to_offset(node));
1047
Simon Glassa3f50d02022-09-06 20:27:20 -06001048 return fdt_size_cells(ofnode_to_fdt(node), parent);
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +02001049 }
Simon Glass878d68c2017-06-12 06:21:31 -06001050}
1051
1052int ofnode_read_simple_addr_cells(ofnode node)
1053{
1054 if (ofnode_is_np(node))
1055 return of_simple_addr_cells(ofnode_to_np(node));
1056 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001057 return fdt_address_cells(ofnode_to_fdt(node),
1058 ofnode_to_offset(node));
Simon Glass878d68c2017-06-12 06:21:31 -06001059}
1060
1061int ofnode_read_simple_size_cells(ofnode node)
1062{
1063 if (ofnode_is_np(node))
1064 return of_simple_size_cells(ofnode_to_np(node));
Simon Glass9e512042017-05-18 20:08:58 -06001065 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001066 return fdt_size_cells(ofnode_to_fdt(node),
1067 ofnode_to_offset(node));
Simon Glass9e512042017-05-18 20:08:58 -06001068}
1069
1070bool ofnode_pre_reloc(ofnode node)
1071{
Patrick Delaunayc7a88da2019-02-11 12:49:57 +01001072#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
1073 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
1074 * had property dm-pre-reloc or u-boot,dm-spl/tpl.
1075 * They are removed in final dtb (fdtgrep 2nd pass)
1076 */
1077 return true;
1078#else
Masahiro Yamada252510a2017-06-22 16:54:03 +09001079 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
Simon Glass9e512042017-05-18 20:08:58 -06001080 return true;
Simon Glass06f94462018-10-01 12:22:18 -06001081 if (ofnode_read_bool(node, "u-boot,dm-pre-proper"))
1082 return true;
Simon Glass9e512042017-05-18 20:08:58 -06001083
Simon Glass9e512042017-05-18 20:08:58 -06001084 /*
1085 * In regular builds individual spl and tpl handling both
1086 * count as handled pre-relocation for later second init.
1087 */
Masahiro Yamada252510a2017-06-22 16:54:03 +09001088 if (ofnode_read_bool(node, "u-boot,dm-spl") ||
1089 ofnode_read_bool(node, "u-boot,dm-tpl"))
Simon Glass9e512042017-05-18 20:08:58 -06001090 return true;
Simon Glass9e512042017-05-18 20:08:58 -06001091
1092 return false;
Patrick Delaunayc7a88da2019-02-11 12:49:57 +01001093#endif
Simon Glass9e512042017-05-18 20:08:58 -06001094}
Simon Glassdcf98852017-07-25 08:29:55 -06001095
1096int ofnode_read_resource(ofnode node, uint index, struct resource *res)
1097{
1098 if (ofnode_is_np(node)) {
1099 return of_address_to_resource(ofnode_to_np(node), index, res);
1100 } else {
1101 struct fdt_resource fres;
1102 int ret;
1103
Simon Glassa3f50d02022-09-06 20:27:20 -06001104 ret = fdt_get_resource(ofnode_to_fdt(node),
1105 ofnode_to_offset(node),
Simon Glassdcf98852017-07-25 08:29:55 -06001106 "reg", index, &fres);
1107 if (ret < 0)
1108 return -EINVAL;
1109 memset(res, '\0', sizeof(*res));
1110 res->start = fres.start;
1111 res->end = fres.end;
1112
1113 return 0;
1114 }
1115}
Masahiro Yamada7b8b47b2017-08-26 01:12:30 +09001116
1117int ofnode_read_resource_byname(ofnode node, const char *name,
1118 struct resource *res)
1119{
1120 int index;
1121
1122 index = ofnode_stringlist_search(node, "reg-names", name);
1123 if (index < 0)
1124 return index;
1125
1126 return ofnode_read_resource(node, index, res);
1127}
Mario Six147c6072018-01-15 11:07:19 +01001128
1129u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
1130{
1131 if (ofnode_is_np(node))
1132 return of_translate_address(ofnode_to_np(node), in_addr);
1133 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001134 return fdt_translate_address(ofnode_to_fdt(node),
1135 ofnode_to_offset(node), in_addr);
Mario Six147c6072018-01-15 11:07:19 +01001136}
Masahiro Yamada5ccc2c22018-04-19 12:14:02 +09001137
Fabien Dessenne641067f2019-05-31 15:11:30 +02001138u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
1139{
1140 if (ofnode_is_np(node))
1141 return of_translate_dma_address(ofnode_to_np(node), in_addr);
1142 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001143 return fdt_translate_dma_address(ofnode_to_fdt(node),
1144 ofnode_to_offset(node), in_addr);
Fabien Dessenne641067f2019-05-31 15:11:30 +02001145}
1146
Nicolas Saenz Julienne51bdb502021-01-12 13:55:22 +01001147int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
1148{
1149 if (ofnode_is_np(node))
1150 return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
1151 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001152 return fdt_get_dma_range(ofnode_to_fdt(node),
1153 ofnode_to_offset(node),
Nicolas Saenz Julienne51bdb502021-01-12 13:55:22 +01001154 cpu, bus, size);
1155}
1156
Masahiro Yamada5ccc2c22018-04-19 12:14:02 +09001157int ofnode_device_is_compatible(ofnode node, const char *compat)
1158{
1159 if (ofnode_is_np(node))
1160 return of_device_is_compatible(ofnode_to_np(node), compat,
1161 NULL, NULL);
1162 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001163 return !fdt_node_check_compatible(ofnode_to_fdt(node),
Masahiro Yamada5ccc2c22018-04-19 12:14:02 +09001164 ofnode_to_offset(node),
1165 compat);
1166}
Simon Glassc60f6712018-06-11 13:07:13 -06001167
1168ofnode ofnode_by_compatible(ofnode from, const char *compat)
1169{
1170 if (of_live_active()) {
1171 return np_to_ofnode(of_find_compatible_node(
1172 (struct device_node *)ofnode_to_np(from), NULL,
1173 compat));
1174 } else {
Simon Glass2187cb72022-09-06 20:27:23 -06001175 return noffset_to_ofnode(from,
1176 fdt_node_offset_by_compatible(ofnode_to_fdt(from),
Simon Glassa3f50d02022-09-06 20:27:20 -06001177 ofnode_to_offset(from), compat));
Simon Glassc60f6712018-06-11 13:07:13 -06001178 }
1179}
Jens Wiklander61fba0f2018-08-20 11:09:58 +02001180
1181ofnode ofnode_by_prop_value(ofnode from, const char *propname,
1182 const void *propval, int proplen)
1183{
1184 if (of_live_active()) {
1185 return np_to_ofnode(of_find_node_by_prop_value(
1186 (struct device_node *)ofnode_to_np(from), propname,
1187 propval, proplen));
1188 } else {
Simon Glass2187cb72022-09-06 20:27:23 -06001189 return noffset_to_ofnode(from,
1190 fdt_node_offset_by_prop_value(ofnode_to_fdt(from),
1191 ofnode_to_offset(from), propname, propval,
1192 proplen));
Jens Wiklander61fba0f2018-08-20 11:09:58 +02001193 }
1194}
Mario Sixe369e582018-06-26 08:46:48 +02001195
Simon Glassbe0789a2022-07-30 15:52:10 -06001196int ofnode_write_prop(ofnode node, const char *propname, const void *value,
1197 int len)
Mario Sixe369e582018-06-26 08:46:48 +02001198{
Simon Glass39e42be2022-07-30 15:52:13 -06001199 if (of_live_active())
Simon Glass98306982022-09-06 20:27:04 -06001200 return of_write_prop(ofnode_to_np(node), propname, len, value);
Simon Glass39e42be2022-07-30 15:52:13 -06001201 else
Simon Glassa3f50d02022-09-06 20:27:20 -06001202 return fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
Simon Glass39e42be2022-07-30 15:52:13 -06001203 propname, value, len);
Mario Sixe369e582018-06-26 08:46:48 +02001204
1205 return 0;
1206}
1207
1208int ofnode_write_string(ofnode node, const char *propname, const char *value)
1209{
Mario Sixe369e582018-06-26 08:46:48 +02001210 assert(ofnode_valid(node));
1211
1212 debug("%s: %s = %s", __func__, propname, value);
1213
Simon Glassbe0789a2022-07-30 15:52:10 -06001214 return ofnode_write_prop(node, propname, value, strlen(value) + 1);
Mario Sixe369e582018-06-26 08:46:48 +02001215}
1216
Simon Glass55f79902022-07-30 15:52:14 -06001217int ofnode_write_u32(ofnode node, const char *propname, u32 value)
1218{
1219 fdt32_t *val;
1220
1221 assert(ofnode_valid(node));
1222
1223 log_debug("%s = %x", propname, value);
1224 val = malloc(sizeof(*val));
1225 if (!val)
1226 return -ENOMEM;
1227 *val = cpu_to_fdt32(value);
1228
1229 return ofnode_write_prop(node, propname, val, sizeof(value));
1230}
1231
Mario Sixe369e582018-06-26 08:46:48 +02001232int ofnode_set_enabled(ofnode node, bool value)
1233{
Mario Sixe369e582018-06-26 08:46:48 +02001234 assert(ofnode_valid(node));
1235
1236 if (value)
1237 return ofnode_write_string(node, "status", "okay");
1238 else
Bin Meng16351212019-07-05 09:23:17 -07001239 return ofnode_write_string(node, "status", "disabled");
Mario Sixe369e582018-06-26 08:46:48 +02001240}
Simon Glass7de8bd02021-08-07 07:24:01 -06001241
1242bool ofnode_conf_read_bool(const char *prop_name)
1243{
1244 ofnode node;
1245
1246 node = ofnode_path("/config");
1247 if (!ofnode_valid(node))
1248 return false;
1249
1250 return ofnode_read_bool(node, prop_name);
1251}
1252
1253int ofnode_conf_read_int(const char *prop_name, int default_val)
1254{
1255 ofnode node;
1256
1257 node = ofnode_path("/config");
1258 if (!ofnode_valid(node))
1259 return default_val;
1260
1261 return ofnode_read_u32_default(node, prop_name, default_val);
1262}
1263
1264const char *ofnode_conf_read_str(const char *prop_name)
1265{
1266 ofnode node;
1267
1268 node = ofnode_path("/config");
1269 if (!ofnode_valid(node))
1270 return NULL;
1271
1272 return ofnode_read_string(node, prop_name);
1273}
Marek Behúnf3dd2132022-04-07 00:32:57 +02001274
1275ofnode ofnode_get_phy_node(ofnode node)
1276{
1277 /* DT node properties that reference a PHY node */
1278 static const char * const phy_handle_str[] = {
1279 "phy-handle", "phy", "phy-device",
1280 };
1281 struct ofnode_phandle_args args = {
1282 .node = ofnode_null()
1283 };
1284 int i;
1285
1286 assert(ofnode_valid(node));
1287
1288 for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
1289 if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
1290 NULL, 0, 0, &args))
1291 break;
1292
1293 return args.node;
1294}
Marek Behún123ca112022-04-07 00:33:01 +02001295
1296phy_interface_t ofnode_read_phy_mode(ofnode node)
1297{
1298 const char *mode;
1299 int i;
1300
1301 assert(ofnode_valid(node));
1302
1303 mode = ofnode_read_string(node, "phy-mode");
1304 if (!mode)
1305 mode = ofnode_read_string(node, "phy-connection-type");
1306
1307 if (!mode)
Marek Behúnffb0f6f2022-04-07 00:33:03 +02001308 return PHY_INTERFACE_MODE_NA;
Marek Behún123ca112022-04-07 00:33:01 +02001309
Marek Behún6706d7d2022-04-07 00:33:02 +02001310 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
Marek Behún123ca112022-04-07 00:33:01 +02001311 if (!strcmp(mode, phy_interface_strings[i]))
1312 return i;
1313
1314 debug("%s: Invalid PHY interface '%s'\n", __func__, mode);
1315
Marek Behúnffb0f6f2022-04-07 00:33:03 +02001316 return PHY_INTERFACE_MODE_NA;
Marek Behún123ca112022-04-07 00:33:01 +02001317}
Simon Glassffe90392022-09-06 20:27:02 -06001318
1319int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
1320{
1321 ofnode subnode;
1322 int ret = 0;
1323
1324 assert(ofnode_valid(node));
1325
1326 if (ofnode_is_np(node)) {
1327 struct device_node *np, *child;
1328
1329 np = (struct device_node *)ofnode_to_np(node);
1330 ret = of_add_subnode(np, name, -1, &child);
1331 if (ret && ret != -EEXIST)
1332 return ret;
1333 subnode = np_to_ofnode(child);
1334 } else {
Simon Glassa3f50d02022-09-06 20:27:20 -06001335 void *fdt = ofnode_to_fdt(node);
Simon Glassffe90392022-09-06 20:27:02 -06001336 int poffset = ofnode_to_offset(node);
1337 int offset;
1338
1339 offset = fdt_add_subnode(fdt, poffset, name);
1340 if (offset == -FDT_ERR_EXISTS) {
1341 offset = fdt_subnode_offset(fdt, poffset, name);
1342 ret = -EEXIST;
1343 }
1344 if (offset < 0)
1345 return -EINVAL;
Simon Glass2187cb72022-09-06 20:27:23 -06001346 subnode = noffset_to_ofnode(node, offset);
Simon Glassffe90392022-09-06 20:27:02 -06001347 }
1348
1349 *subnodep = subnode;
1350
1351 return ret; /* 0 or -EEXIST */
1352}