blob: 7d1b89514c7d81047e8e7f70b4f3b2146aa7651e [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassc4fc5622017-05-18 20:08:58 -06002/*
3 * Copyright (c) 2017 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glassc4fc5622017-05-18 20:08:58 -06005 */
6
7#include <common.h>
8#include <dm.h>
9#include <fdtdec.h>
10#include <fdt_support.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070012#include <malloc.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090013#include <linux/libfdt.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060014#include <dm/of_access.h>
Simon Glass049ae1b2017-05-18 20:09:01 -060015#include <dm/of_addr.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060016#include <dm/ofnode.h>
17#include <linux/err.h>
Simon Glassf7bfcc42017-07-25 08:29:55 -060018#include <linux/ioport.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060019
20int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
21{
Dario Binacchib3f1cdd2020-03-29 18:04:42 +020022 return ofnode_read_u32_index(node, propname, 0, outp);
Simon Glassc4fc5622017-05-18 20:08:58 -060023}
24
Trent Piepho5b775412019-05-10 17:48:20 +000025u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
Simon Glassc4fc5622017-05-18 20:08:58 -060026{
27 assert(ofnode_valid(node));
Dario Binacchib3f1cdd2020-03-29 18:04:42 +020028 ofnode_read_u32_index(node, propname, 0, &def);
Simon Glassc4fc5622017-05-18 20:08:58 -060029
30 return def;
31}
32
Dario Binacchi81d80b52020-03-29 18:04:41 +020033int ofnode_read_u32_index(ofnode node, const char *propname, int index,
34 u32 *outp)
35{
36 const fdt32_t *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_u32_index(ofnode_to_np(node), propname, index,
44 outp);
45
46 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
47 &len);
48 if (!cell) {
49 debug("(not found)\n");
50 return -EINVAL;
51 }
52
53 if (len < (sizeof(int) * (index + 1))) {
54 debug("(not large enough)\n");
55 return -EOVERFLOW;
56 }
57
58 *outp = fdt32_to_cpu(cell[index]);
59 debug("%#x (%d)\n", *outp, *outp);
60
61 return 0;
62}
63
64u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
65 u32 def)
66{
67 assert(ofnode_valid(node));
68 ofnode_read_u32_index(node, propname, index, &def);
69
70 return def;
71}
72
Simon Glassc4fc5622017-05-18 20:08:58 -060073int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
74{
75 assert(ofnode_valid(node));
76 ofnode_read_u32(node, propname, (u32 *)&def);
77
78 return def;
79}
80
Simon Glass9d54a7a2018-06-11 13:07:10 -060081int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
82{
Jean-Jacques Hiblot487f9172019-10-22 10:05:22 +020083 const unaligned_fdt64_t *cell;
Simon Glass9d54a7a2018-06-11 13:07:10 -060084 int len;
85
86 assert(ofnode_valid(node));
87 debug("%s: %s: ", __func__, propname);
88
89 if (ofnode_is_np(node))
90 return of_read_u64(ofnode_to_np(node), propname, outp);
91
92 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
93 &len);
94 if (!cell || len < sizeof(*cell)) {
95 debug("(not found)\n");
96 return -EINVAL;
97 }
98 *outp = fdt64_to_cpu(cell[0]);
99 debug("%#llx (%lld)\n", (unsigned long long)*outp,
100 (unsigned long long)*outp);
101
102 return 0;
103}
104
T Karthik Reddy478860d2019-09-02 16:34:30 +0200105u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
Simon Glass9d54a7a2018-06-11 13:07:10 -0600106{
107 assert(ofnode_valid(node));
108 ofnode_read_u64(node, propname, &def);
109
110 return def;
111}
112
Simon Glassc4fc5622017-05-18 20:08:58 -0600113bool ofnode_read_bool(ofnode node, const char *propname)
114{
Masahiro Yamada5d434452017-06-22 16:54:07 +0900115 const void *prop;
Simon Glassc4fc5622017-05-18 20:08:58 -0600116
117 assert(ofnode_valid(node));
118 debug("%s: %s: ", __func__, propname);
119
Masahiro Yamada5d434452017-06-22 16:54:07 +0900120 prop = ofnode_get_property(node, propname, NULL);
121
122 debug("%s\n", prop ? "true" : "false");
Simon Glassc4fc5622017-05-18 20:08:58 -0600123
Masahiro Yamada5d434452017-06-22 16:54:07 +0900124 return prop ? true : false;
Simon Glassc4fc5622017-05-18 20:08:58 -0600125}
126
Simon Glass0c2e9802020-01-27 08:49:44 -0700127const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600128{
Simon Glass0c2e9802020-01-27 08:49:44 -0700129 const char *val = NULL;
130 int len;
Simon Glassc4fc5622017-05-18 20:08:58 -0600131
132 assert(ofnode_valid(node));
133 debug("%s: %s: ", __func__, propname);
134
135 if (ofnode_is_np(node)) {
136 struct property *prop = of_find_property(
Simon Glass0c2e9802020-01-27 08:49:44 -0700137 ofnode_to_np(node), propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600138
139 if (prop) {
Simon Glass0c2e9802020-01-27 08:49:44 -0700140 val = prop->value;
Simon Glassc4fc5622017-05-18 20:08:58 -0600141 len = prop->length;
142 }
143 } else {
Simon Glass0c2e9802020-01-27 08:49:44 -0700144 val = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600145 propname, &len);
146 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700147 if (!val) {
Simon Glassc4fc5622017-05-18 20:08:58 -0600148 debug("<not found>\n");
Simon Glass0c2e9802020-01-27 08:49:44 -0700149 if (sizep)
150 *sizep = -FDT_ERR_NOTFOUND;
Simon Glassc4fc5622017-05-18 20:08:58 -0600151 return NULL;
152 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700153 if (sizep)
154 *sizep = len;
155
156 return val;
157}
158
159const char *ofnode_read_string(ofnode node, const char *propname)
160{
161 const char *str;
162 int len;
163
164 str = ofnode_read_prop(node, propname, &len);
165 if (!str)
166 return NULL;
167
Simon Glassc4fc5622017-05-18 20:08:58 -0600168 if (strnlen(str, len) >= len) {
169 debug("<invalid>\n");
170 return NULL;
171 }
172 debug("%s\n", str);
173
174 return str;
175}
176
Simon Glass81c54b32020-01-27 08:49:45 -0700177int ofnode_read_size(ofnode node, const char *propname)
178{
179 int len;
180
181 if (!ofnode_read_prop(node, propname, &len))
182 return -EINVAL;
183
184 return len;
185}
186
Simon Glassc4fc5622017-05-18 20:08:58 -0600187ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
188{
189 ofnode subnode;
190
191 assert(ofnode_valid(node));
192 debug("%s: %s: ", __func__, subnode_name);
193
194 if (ofnode_is_np(node)) {
195 const struct device_node *np = ofnode_to_np(node);
196
197 for (np = np->child; np; np = np->sibling) {
198 if (!strcmp(subnode_name, np->name))
199 break;
200 }
201 subnode = np_to_ofnode(np);
202 } else {
203 int ooffset = fdt_subnode_offset(gd->fdt_blob,
204 ofnode_to_offset(node), subnode_name);
205 subnode = offset_to_ofnode(ooffset);
206 }
207 debug("%s\n", ofnode_valid(subnode) ?
208 ofnode_get_name(subnode) : "<none>");
209
210 return subnode;
211}
212
213int ofnode_read_u32_array(ofnode node, const char *propname,
214 u32 *out_values, size_t sz)
215{
216 assert(ofnode_valid(node));
217 debug("%s: %s: ", __func__, propname);
218
219 if (ofnode_is_np(node)) {
220 return of_read_u32_array(ofnode_to_np(node), propname,
221 out_values, sz);
222 } else {
223 return fdtdec_get_int_array(gd->fdt_blob,
224 ofnode_to_offset(node), propname,
225 out_values, sz);
226 }
227}
228
229ofnode ofnode_first_subnode(ofnode node)
230{
231 assert(ofnode_valid(node));
232 if (ofnode_is_np(node))
233 return np_to_ofnode(node.np->child);
234
235 return offset_to_ofnode(
236 fdt_first_subnode(gd->fdt_blob, ofnode_to_offset(node)));
237}
238
239ofnode ofnode_next_subnode(ofnode node)
240{
241 assert(ofnode_valid(node));
242 if (ofnode_is_np(node))
243 return np_to_ofnode(node.np->sibling);
244
245 return offset_to_ofnode(
246 fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node)));
247}
248
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100249ofnode ofnode_get_parent(ofnode node)
250{
251 ofnode parent;
252
253 assert(ofnode_valid(node));
254 if (ofnode_is_np(node))
255 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
256 else
257 parent.of_offset = fdt_parent_offset(gd->fdt_blob,
258 ofnode_to_offset(node));
259
260 return parent;
261}
262
Simon Glassc4fc5622017-05-18 20:08:58 -0600263const char *ofnode_get_name(ofnode node)
264{
Kever Yang8d7976d2019-07-19 11:23:47 +0800265 if (!ofnode_valid(node)) {
266 debug("%s node not valid\n", __func__);
267 return NULL;
268 }
269
Simon Glassc4fc5622017-05-18 20:08:58 -0600270 if (ofnode_is_np(node))
271 return strrchr(node.np->full_name, '/') + 1;
272
273 return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL);
274}
275
Kever Yang37df0e02018-02-23 17:38:50 +0100276ofnode ofnode_get_by_phandle(uint phandle)
277{
278 ofnode node;
279
280 if (of_live_active())
281 node = np_to_ofnode(of_find_node_by_phandle(phandle));
282 else
283 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
284 phandle);
285
286 return node;
287}
288
Keerthyd332e6e2019-04-24 17:19:53 +0530289fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
Simon Glass049ae1b2017-05-18 20:09:01 -0600290{
Keerthy34222a32018-11-19 11:44:47 +0530291 int na, ns;
Keerthy34222a32018-11-19 11:44:47 +0530292
Simon Glass049ae1b2017-05-18 20:09:01 -0600293 if (ofnode_is_np(node)) {
294 const __be32 *prop_val;
Simon Glass47f85de2019-09-25 08:55:50 -0600295 u64 size64;
Simon Glass049ae1b2017-05-18 20:09:01 -0600296 uint flags;
Simon Glass049ae1b2017-05-18 20:09:01 -0600297
Simon Glass47f85de2019-09-25 08:55:50 -0600298 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
299 &flags);
Simon Glass049ae1b2017-05-18 20:09:01 -0600300 if (!prop_val)
301 return FDT_ADDR_T_NONE;
Simon Glass47f85de2019-09-25 08:55:50 -0600302 if (size)
303 *size = size64;
Mario Sixd007ebc2017-12-20 09:52:12 +0100304
Mario Six35616ef2018-03-12 14:53:33 +0100305 ns = of_n_size_cells(ofnode_to_np(node));
306
307 if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Sixd007ebc2017-12-20 09:52:12 +0100308 return of_translate_address(ofnode_to_np(node), prop_val);
309 } else {
310 na = of_n_addr_cells(ofnode_to_np(node));
311 return of_read_number(prop_val, na);
312 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600313 } else {
Keerthy34222a32018-11-19 11:44:47 +0530314 na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
315 ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
316 return fdtdec_get_addr_size_fixed(gd->fdt_blob,
317 ofnode_to_offset(node), "reg",
Keerthyd332e6e2019-04-24 17:19:53 +0530318 index, na, ns, size, true);
Simon Glass049ae1b2017-05-18 20:09:01 -0600319 }
320
321 return FDT_ADDR_T_NONE;
322}
323
Keerthyd332e6e2019-04-24 17:19:53 +0530324fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
325{
326 fdt_size_t size;
327
328 return ofnode_get_addr_size_index(node, index, &size);
329}
330
Simon Glass049ae1b2017-05-18 20:09:01 -0600331fdt_addr_t ofnode_get_addr(ofnode node)
332{
333 return ofnode_get_addr_index(node, 0);
334}
335
Simon Glassc4fc5622017-05-18 20:08:58 -0600336int ofnode_stringlist_search(ofnode node, const char *property,
337 const char *string)
338{
339 if (ofnode_is_np(node)) {
340 return of_property_match_string(ofnode_to_np(node),
341 property, string);
342 } else {
343 int ret;
344
345 ret = fdt_stringlist_search(gd->fdt_blob,
346 ofnode_to_offset(node), property,
347 string);
348 if (ret == -FDT_ERR_NOTFOUND)
349 return -ENODATA;
350 else if (ret < 0)
351 return -EINVAL;
352
353 return ret;
354 }
355}
356
357int ofnode_read_string_index(ofnode node, const char *property, int index,
358 const char **outp)
359{
360 if (ofnode_is_np(node)) {
361 return of_property_read_string_index(ofnode_to_np(node),
362 property, index, outp);
363 } else {
364 int len;
365
366 *outp = fdt_stringlist_get(gd->fdt_blob, ofnode_to_offset(node),
367 property, index, &len);
368 if (len < 0)
369 return -EINVAL;
370 return 0;
371 }
372}
373
Simon Glass5fdb0052017-06-12 06:21:28 -0600374int ofnode_read_string_count(ofnode node, const char *property)
375{
376 if (ofnode_is_np(node)) {
377 return of_property_count_strings(ofnode_to_np(node), property);
378 } else {
379 return fdt_stringlist_count(gd->fdt_blob,
380 ofnode_to_offset(node), property);
381 }
382}
383
Simon Glassc4fc5622017-05-18 20:08:58 -0600384static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
385 struct ofnode_phandle_args *out)
386{
387 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
388 out->node = offset_to_ofnode(in->node);
389 out->args_count = in->args_count;
390 memcpy(out->args, in->args, sizeof(out->args));
391}
392
393static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
394 struct ofnode_phandle_args *out)
395{
396 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
397 out->node = np_to_ofnode(in->np);
398 out->args_count = in->args_count;
399 memcpy(out->args, in->args, sizeof(out->args));
400}
401
402int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
403 const char *cells_name, int cell_count,
404 int index,
405 struct ofnode_phandle_args *out_args)
406{
407 if (ofnode_is_np(node)) {
408 struct of_phandle_args args;
409 int ret;
410
411 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay21e3b042020-09-10 18:26:17 +0200412 list_name, cells_name,
413 cell_count, index,
Mario Sixf40d82c2018-01-15 11:07:17 +0100414 &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600415 if (ret)
416 return ret;
417 ofnode_from_of_phandle_args(&args, out_args);
418 } else {
419 struct fdtdec_phandle_args args;
420 int ret;
421
422 ret = fdtdec_parse_phandle_with_args(gd->fdt_blob,
Mario Sixf40d82c2018-01-15 11:07:17 +0100423 ofnode_to_offset(node),
424 list_name, cells_name,
425 cell_count, index, &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600426 if (ret)
427 return ret;
428 ofnode_from_fdtdec_phandle_args(&args, out_args);
429 }
430
431 return 0;
432}
433
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200434int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200435 const char *cells_name, int cell_count)
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200436{
437 if (ofnode_is_np(node))
438 return of_count_phandle_with_args(ofnode_to_np(node),
Patrick Delaunayd776a842020-09-25 09:41:14 +0200439 list_name, cells_name, cell_count);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200440 else
441 return fdtdec_parse_phandle_with_args(gd->fdt_blob,
442 ofnode_to_offset(node), list_name, cells_name,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200443 cell_count, -1, NULL);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200444}
445
Simon Glassc4fc5622017-05-18 20:08:58 -0600446ofnode ofnode_path(const char *path)
447{
448 if (of_live_active())
449 return np_to_ofnode(of_find_node_by_path(path));
450 else
451 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
452}
453
Simon Glasse09223c2020-01-27 08:49:46 -0700454const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600455{
456 ofnode chosen_node;
457
458 chosen_node = ofnode_path("/chosen");
459
Simon Glasse09223c2020-01-27 08:49:46 -0700460 return ofnode_read_prop(chosen_node, propname, sizep);
Simon Glassc4fc5622017-05-18 20:08:58 -0600461}
462
Simon Glasse09223c2020-01-27 08:49:46 -0700463const char *ofnode_read_chosen_string(const char *propname)
464{
465 return ofnode_read_chosen_prop(propname, NULL);
466}
467
Simon Glassc4fc5622017-05-18 20:08:58 -0600468ofnode ofnode_get_chosen_node(const char *name)
469{
470 const char *prop;
471
Simon Glasse09223c2020-01-27 08:49:46 -0700472 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600473 if (!prop)
474 return ofnode_null();
475
476 return ofnode_path(prop);
477}
478
developerd93c8b42020-05-02 11:35:09 +0200479int ofnode_get_child_count(ofnode parent)
480{
481 ofnode child;
482 int num = 0;
483
484 ofnode_for_each_subnode(child, parent)
485 num++;
486
487 return num;
488}
489
Simon Glassc4fc5622017-05-18 20:08:58 -0600490static int decode_timing_property(ofnode node, const char *name,
491 struct timing_entry *result)
492{
493 int length, ret = 0;
494
495 length = ofnode_read_size(node, name);
496 if (length < 0) {
497 debug("%s: could not find property %s\n",
498 ofnode_get_name(node), name);
499 return length;
500 }
501
502 if (length == sizeof(u32)) {
503 result->typ = ofnode_read_u32_default(node, name, 0);
504 result->min = result->typ;
505 result->max = result->typ;
506 } else {
507 ret = ofnode_read_u32_array(node, name, &result->min, 3);
508 }
509
510 return ret;
511}
512
513int ofnode_decode_display_timing(ofnode parent, int index,
514 struct display_timing *dt)
515{
516 int i;
517 ofnode timings, node;
518 u32 val = 0;
519 int ret = 0;
520
521 timings = ofnode_find_subnode(parent, "display-timings");
522 if (!ofnode_valid(timings))
523 return -EINVAL;
524
Simon Glass28529762017-08-05 15:45:54 -0600525 i = 0;
526 ofnode_for_each_subnode(node, timings) {
527 if (i++ == index)
528 break;
529 }
Simon Glassc4fc5622017-05-18 20:08:58 -0600530
531 if (!ofnode_valid(node))
532 return -EINVAL;
533
534 memset(dt, 0, sizeof(*dt));
535
536 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
537 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
538 ret |= decode_timing_property(node, "hactive", &dt->hactive);
539 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
540 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
541 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
542 ret |= decode_timing_property(node, "vactive", &dt->vactive);
543 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
544 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
545
546 dt->flags = 0;
547 val = ofnode_read_u32_default(node, "vsync-active", -1);
548 if (val != -1) {
549 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
550 DISPLAY_FLAGS_VSYNC_LOW;
551 }
552 val = ofnode_read_u32_default(node, "hsync-active", -1);
553 if (val != -1) {
554 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
555 DISPLAY_FLAGS_HSYNC_LOW;
556 }
557 val = ofnode_read_u32_default(node, "de-active", -1);
558 if (val != -1) {
559 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
560 DISPLAY_FLAGS_DE_LOW;
561 }
562 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
563 if (val != -1) {
564 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
565 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
566 }
567
568 if (ofnode_read_bool(node, "interlaced"))
569 dt->flags |= DISPLAY_FLAGS_INTERLACED;
570 if (ofnode_read_bool(node, "doublescan"))
571 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
572 if (ofnode_read_bool(node, "doubleclk"))
573 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
574
575 return ret;
576}
577
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +0900578const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glassc4fc5622017-05-18 20:08:58 -0600579{
Masahiro Yamada5052f1b2017-06-22 16:54:04 +0900580 if (ofnode_is_np(node))
581 return of_get_property(ofnode_to_np(node), propname, lenp);
582 else
Simon Glassc4fc5622017-05-18 20:08:58 -0600583 return fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
584 propname, lenp);
Simon Glassc4fc5622017-05-18 20:08:58 -0600585}
586
Patrick Delaunaycaee1552020-01-13 11:34:56 +0100587int ofnode_get_first_property(ofnode node, struct ofprop *prop)
588{
589 prop->node = node;
590
591 if (ofnode_is_np(node)) {
592 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
593 if (!prop->prop)
594 return -FDT_ERR_NOTFOUND;
595 } else {
596 prop->offset =
597 fdt_first_property_offset(gd->fdt_blob,
598 ofnode_to_offset(prop->node));
599 if (prop->offset < 0)
600 return prop->offset;
601 }
602
603 return 0;
604}
605
606int ofnode_get_next_property(struct ofprop *prop)
607{
608 if (ofnode_is_np(prop->node)) {
609 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
610 prop->prop);
611 if (!prop->prop)
612 return -FDT_ERR_NOTFOUND;
613 } else {
614 prop->offset = fdt_next_property_offset(gd->fdt_blob,
615 prop->offset);
616 if (prop->offset < 0)
617 return prop->offset;
618 }
619
620 return 0;
621}
622
623const void *ofnode_get_property_by_prop(const struct ofprop *prop,
624 const char **propname, int *lenp)
625{
626 if (ofnode_is_np(prop->node))
627 return of_get_property_by_prop(ofnode_to_np(prop->node),
628 prop->prop, propname, lenp);
629 else
630 return fdt_getprop_by_offset(gd->fdt_blob,
631 prop->offset,
632 propname, lenp);
633}
634
Simon Glassc4fc5622017-05-18 20:08:58 -0600635bool ofnode_is_available(ofnode node)
636{
637 if (ofnode_is_np(node))
638 return of_device_is_available(ofnode_to_np(node));
639 else
640 return fdtdec_get_is_enabled(gd->fdt_blob,
641 ofnode_to_offset(node));
642}
643
644fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
645 fdt_size_t *sizep)
646{
647 if (ofnode_is_np(node)) {
648 int na, ns;
649 int psize;
650 const struct device_node *np = ofnode_to_np(node);
Klaus Gogeraf4b0212017-09-20 13:50:41 +0200651 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glassc4fc5622017-05-18 20:08:58 -0600652
Klaus Gogeraf4b0212017-09-20 13:50:41 +0200653 if (!prop)
654 return FDT_ADDR_T_NONE;
Simon Glassc4fc5622017-05-18 20:08:58 -0600655 na = of_n_addr_cells(np);
Marek Vasut1638c172018-10-01 12:37:19 +0200656 ns = of_n_size_cells(np);
Simon Glassa67cc632017-05-18 20:09:27 -0600657 *sizep = of_read_number(prop + na, ns);
Marek Vasuta9dac492018-10-01 12:37:20 +0200658
Simon Glass019f9562019-04-25 21:58:36 -0600659 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta9dac492018-10-01 12:37:20 +0200660 return of_translate_address(np, prop);
661 else
662 return of_read_number(prop, na);
Simon Glassc4fc5622017-05-18 20:08:58 -0600663 } else {
664 return fdtdec_get_addr_size(gd->fdt_blob,
665 ofnode_to_offset(node), property,
666 sizep);
667 }
668}
669
670const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
671 size_t sz)
672{
673 if (ofnode_is_np(node)) {
674 const struct device_node *np = ofnode_to_np(node);
675 int psize;
676 const __be32 *prop = of_get_property(np, propname, &psize);
677
678 if (!prop || sz != psize)
679 return NULL;
680 return (uint8_t *)prop;
681
682 } else {
683 return fdtdec_locate_byte_array(gd->fdt_blob,
684 ofnode_to_offset(node), propname, sz);
685 }
686}
687
688int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
689 const char *propname, struct fdt_pci_addr *addr)
690{
Masahiro Yamada5c5991e2017-06-22 17:57:50 +0900691 const fdt32_t *cell;
Simon Glassc4fc5622017-05-18 20:08:58 -0600692 int len;
693 int ret = -ENOENT;
694
695 debug("%s: %s: ", __func__, propname);
696
697 /*
698 * If we follow the pci bus bindings strictly, we should check
699 * the value of the node's parent node's #address-cells and
700 * #size-cells. They need to be 3 and 2 accordingly. However,
701 * for simplicity we skip the check here.
702 */
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +0900703 cell = ofnode_get_property(node, propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600704 if (!cell)
705 goto fail;
706
707 if ((len % FDT_PCI_REG_SIZE) == 0) {
708 int num = len / FDT_PCI_REG_SIZE;
709 int i;
710
711 for (i = 0; i < num; i++) {
712 debug("pci address #%d: %08lx %08lx %08lx\n", i,
713 (ulong)fdt32_to_cpu(cell[0]),
714 (ulong)fdt32_to_cpu(cell[1]),
715 (ulong)fdt32_to_cpu(cell[2]));
716 if ((fdt32_to_cpu(*cell) & type) == type) {
717 addr->phys_hi = fdt32_to_cpu(cell[0]);
718 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glassdfd43152019-09-25 08:55:46 -0600719 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glassc4fc5622017-05-18 20:08:58 -0600720 break;
Simon Glassc4fc5622017-05-18 20:08:58 -0600721 }
Mario Sixf40d82c2018-01-15 11:07:17 +0100722
723 cell += (FDT_PCI_ADDR_CELLS +
724 FDT_PCI_SIZE_CELLS);
Simon Glassc4fc5622017-05-18 20:08:58 -0600725 }
726
727 if (i == num) {
728 ret = -ENXIO;
729 goto fail;
730 }
731
732 return 0;
Simon Glassc4fc5622017-05-18 20:08:58 -0600733 }
734
Mario Sixf40d82c2018-01-15 11:07:17 +0100735 ret = -EINVAL;
736
Simon Glassc4fc5622017-05-18 20:08:58 -0600737fail:
738 debug("(not found)\n");
739 return ret;
740}
741
Bin Mengfa157712018-08-03 01:14:35 -0700742int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
743{
744 const char *list, *end;
745 int len;
746
747 list = ofnode_get_property(node, "compatible", &len);
748 if (!list)
749 return -ENOENT;
750
751 end = list + len;
752 while (list < end) {
753 len = strlen(list);
754 if (len >= strlen("pciVVVV,DDDD")) {
755 char *s = strstr(list, "pci");
756
757 /*
758 * check if the string is something like pciVVVV,DDDD.RR
759 * or just pciVVVV,DDDD
760 */
761 if (s && s[7] == ',' &&
762 (s[12] == '.' || s[12] == 0)) {
763 s += 3;
764 *vendor = simple_strtol(s, NULL, 16);
765
766 s += 5;
767 *device = simple_strtol(s, NULL, 16);
768
769 return 0;
770 }
771 }
772 list += (len + 1);
773 }
774
775 return -ENOENT;
776}
777
Simon Glassc4fc5622017-05-18 20:08:58 -0600778int ofnode_read_addr_cells(ofnode node)
779{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +0200780 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -0600781 return of_n_addr_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +0200782 } else {
783 int parent = fdt_parent_offset(gd->fdt_blob,
784 ofnode_to_offset(node));
785
786 return fdt_address_cells(gd->fdt_blob, parent);
787 }
Simon Glassc4fc5622017-05-18 20:08:58 -0600788}
789
790int ofnode_read_size_cells(ofnode node)
791{
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +0200792 if (ofnode_is_np(node)) {
Simon Glassc4fc5622017-05-18 20:08:58 -0600793 return of_n_size_cells(ofnode_to_np(node));
Heinrich Schuchardt60a84af2020-07-25 21:38:49 +0200794 } else {
795 int parent = fdt_parent_offset(gd->fdt_blob,
796 ofnode_to_offset(node));
797
798 return fdt_size_cells(gd->fdt_blob, parent);
799 }
Simon Glass4191dc12017-06-12 06:21:31 -0600800}
801
802int ofnode_read_simple_addr_cells(ofnode node)
803{
804 if (ofnode_is_np(node))
805 return of_simple_addr_cells(ofnode_to_np(node));
806 else
807 return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node));
808}
809
810int ofnode_read_simple_size_cells(ofnode node)
811{
812 if (ofnode_is_np(node))
813 return of_simple_size_cells(ofnode_to_np(node));
Simon Glassc4fc5622017-05-18 20:08:58 -0600814 else
815 return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node));
816}
817
818bool ofnode_pre_reloc(ofnode node)
819{
Patrick Delaunay0b025b82019-02-11 12:49:57 +0100820#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
821 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
822 * had property dm-pre-reloc or u-boot,dm-spl/tpl.
823 * They are removed in final dtb (fdtgrep 2nd pass)
824 */
825 return true;
826#else
Masahiro Yamada6a61dd92017-06-22 16:54:03 +0900827 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
Simon Glassc4fc5622017-05-18 20:08:58 -0600828 return true;
Simon Glass23f22842018-10-01 12:22:18 -0600829 if (ofnode_read_bool(node, "u-boot,dm-pre-proper"))
830 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -0600831
Simon Glassc4fc5622017-05-18 20:08:58 -0600832 /*
833 * In regular builds individual spl and tpl handling both
834 * count as handled pre-relocation for later second init.
835 */
Masahiro Yamada6a61dd92017-06-22 16:54:03 +0900836 if (ofnode_read_bool(node, "u-boot,dm-spl") ||
837 ofnode_read_bool(node, "u-boot,dm-tpl"))
Simon Glassc4fc5622017-05-18 20:08:58 -0600838 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -0600839
840 return false;
Patrick Delaunay0b025b82019-02-11 12:49:57 +0100841#endif
Simon Glassc4fc5622017-05-18 20:08:58 -0600842}
Simon Glassf7bfcc42017-07-25 08:29:55 -0600843
844int ofnode_read_resource(ofnode node, uint index, struct resource *res)
845{
846 if (ofnode_is_np(node)) {
847 return of_address_to_resource(ofnode_to_np(node), index, res);
848 } else {
849 struct fdt_resource fres;
850 int ret;
851
852 ret = fdt_get_resource(gd->fdt_blob, ofnode_to_offset(node),
853 "reg", index, &fres);
854 if (ret < 0)
855 return -EINVAL;
856 memset(res, '\0', sizeof(*res));
857 res->start = fres.start;
858 res->end = fres.end;
859
860 return 0;
861 }
862}
Masahiro Yamada4dada2c2017-08-26 01:12:30 +0900863
864int ofnode_read_resource_byname(ofnode node, const char *name,
865 struct resource *res)
866{
867 int index;
868
869 index = ofnode_stringlist_search(node, "reg-names", name);
870 if (index < 0)
871 return index;
872
873 return ofnode_read_resource(node, index, res);
874}
Mario Sixaefac062018-01-15 11:07:19 +0100875
876u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
877{
878 if (ofnode_is_np(node))
879 return of_translate_address(ofnode_to_np(node), in_addr);
880 else
881 return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
882}
Masahiro Yamada9349bcc2018-04-19 12:14:02 +0900883
Fabien Dessenne22236e02019-05-31 15:11:30 +0200884u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
885{
886 if (ofnode_is_np(node))
887 return of_translate_dma_address(ofnode_to_np(node), in_addr);
888 else
889 return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
890}
891
Masahiro Yamada9349bcc2018-04-19 12:14:02 +0900892int ofnode_device_is_compatible(ofnode node, const char *compat)
893{
894 if (ofnode_is_np(node))
895 return of_device_is_compatible(ofnode_to_np(node), compat,
896 NULL, NULL);
897 else
898 return !fdt_node_check_compatible(gd->fdt_blob,
899 ofnode_to_offset(node),
900 compat);
901}
Simon Glass954eeae2018-06-11 13:07:13 -0600902
903ofnode ofnode_by_compatible(ofnode from, const char *compat)
904{
905 if (of_live_active()) {
906 return np_to_ofnode(of_find_compatible_node(
907 (struct device_node *)ofnode_to_np(from), NULL,
908 compat));
909 } else {
910 return offset_to_ofnode(fdt_node_offset_by_compatible(
911 gd->fdt_blob, ofnode_to_offset(from), compat));
912 }
913}
Jens Wiklander7b68dad2018-08-20 11:09:58 +0200914
915ofnode ofnode_by_prop_value(ofnode from, const char *propname,
916 const void *propval, int proplen)
917{
918 if (of_live_active()) {
919 return np_to_ofnode(of_find_node_by_prop_value(
920 (struct device_node *)ofnode_to_np(from), propname,
921 propval, proplen));
922 } else {
923 return offset_to_ofnode(fdt_node_offset_by_prop_value(
924 gd->fdt_blob, ofnode_to_offset(from),
925 propname, propval, proplen));
926 }
927}
Mario Six047dafc2018-06-26 08:46:48 +0200928
929int ofnode_write_prop(ofnode node, const char *propname, int len,
930 const void *value)
931{
932 const struct device_node *np = ofnode_to_np(node);
933 struct property *pp;
934 struct property *pp_last = NULL;
935 struct property *new;
936
937 if (!of_live_active())
938 return -ENOSYS;
939
940 if (!np)
941 return -EINVAL;
942
943 for (pp = np->properties; pp; pp = pp->next) {
944 if (strcmp(pp->name, propname) == 0) {
945 /* Property exists -> change value */
946 pp->value = (void *)value;
947 pp->length = len;
948 return 0;
949 }
950 pp_last = pp;
951 }
952
953 if (!pp_last)
954 return -ENOENT;
955
956 /* Property does not exist -> append new property */
957 new = malloc(sizeof(struct property));
958 if (!new)
959 return -ENOMEM;
960
961 new->name = strdup(propname);
Mario Six95e885d2018-10-04 09:22:24 +0200962 if (!new->name) {
963 free(new);
Mario Six047dafc2018-06-26 08:46:48 +0200964 return -ENOMEM;
Mario Six95e885d2018-10-04 09:22:24 +0200965 }
Mario Six047dafc2018-06-26 08:46:48 +0200966
967 new->value = (void *)value;
968 new->length = len;
969 new->next = NULL;
970
971 pp_last->next = new;
972
973 return 0;
974}
975
976int ofnode_write_string(ofnode node, const char *propname, const char *value)
977{
978 if (!of_live_active())
979 return -ENOSYS;
980
981 assert(ofnode_valid(node));
982
983 debug("%s: %s = %s", __func__, propname, value);
984
985 return ofnode_write_prop(node, propname, strlen(value) + 1, value);
986}
987
988int ofnode_set_enabled(ofnode node, bool value)
989{
990 if (!of_live_active())
991 return -ENOSYS;
992
993 assert(ofnode_valid(node));
994
995 if (value)
996 return ofnode_write_string(node, "status", "okay");
997 else
Bin Menga9274aa2019-07-05 09:23:17 -0700998 return ofnode_write_string(node, "status", "disabled");
Mario Six047dafc2018-06-26 08:46:48 +0200999}