blob: 5bc3b02996ebf972d2575804830b5829f9a8af61 [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 Glass9bc15642020-02-03 07:36:16 -070011#include <malloc.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090012#include <linux/libfdt.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060013#include <dm/of_access.h>
Simon Glass049ae1b2017-05-18 20:09:01 -060014#include <dm/of_addr.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060015#include <dm/ofnode.h>
16#include <linux/err.h>
Simon Glassf7bfcc42017-07-25 08:29:55 -060017#include <linux/ioport.h>
Simon Glassc4fc5622017-05-18 20:08:58 -060018
19int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
20{
21 assert(ofnode_valid(node));
22 debug("%s: %s: ", __func__, propname);
23
24 if (ofnode_is_np(node)) {
25 return of_read_u32(ofnode_to_np(node), propname, outp);
26 } else {
Masahiro Yamada5c5991e2017-06-22 17:57:50 +090027 const fdt32_t *cell;
Simon Glassc4fc5622017-05-18 20:08:58 -060028 int len;
29
30 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
31 propname, &len);
32 if (!cell || len < sizeof(int)) {
33 debug("(not found)\n");
34 return -EINVAL;
35 }
36 *outp = fdt32_to_cpu(cell[0]);
37 }
38 debug("%#x (%d)\n", *outp, *outp);
39
40 return 0;
41}
42
Trent Piepho5b775412019-05-10 17:48:20 +000043u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
Simon Glassc4fc5622017-05-18 20:08:58 -060044{
45 assert(ofnode_valid(node));
46 ofnode_read_u32(node, propname, &def);
47
48 return def;
49}
50
Dario Binacchi81d80b52020-03-29 18:04:41 +020051int ofnode_read_u32_index(ofnode node, const char *propname, int index,
52 u32 *outp)
53{
54 const fdt32_t *cell;
55 int len;
56
57 assert(ofnode_valid(node));
58 debug("%s: %s: ", __func__, propname);
59
60 if (ofnode_is_np(node))
61 return of_read_u32_index(ofnode_to_np(node), propname, index,
62 outp);
63
64 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
65 &len);
66 if (!cell) {
67 debug("(not found)\n");
68 return -EINVAL;
69 }
70
71 if (len < (sizeof(int) * (index + 1))) {
72 debug("(not large enough)\n");
73 return -EOVERFLOW;
74 }
75
76 *outp = fdt32_to_cpu(cell[index]);
77 debug("%#x (%d)\n", *outp, *outp);
78
79 return 0;
80}
81
82u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
83 u32 def)
84{
85 assert(ofnode_valid(node));
86 ofnode_read_u32_index(node, propname, index, &def);
87
88 return def;
89}
90
Simon Glassc4fc5622017-05-18 20:08:58 -060091int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
92{
93 assert(ofnode_valid(node));
94 ofnode_read_u32(node, propname, (u32 *)&def);
95
96 return def;
97}
98
Simon Glass9d54a7a2018-06-11 13:07:10 -060099int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
100{
Jean-Jacques Hiblot487f9172019-10-22 10:05:22 +0200101 const unaligned_fdt64_t *cell;
Simon Glass9d54a7a2018-06-11 13:07:10 -0600102 int len;
103
104 assert(ofnode_valid(node));
105 debug("%s: %s: ", __func__, propname);
106
107 if (ofnode_is_np(node))
108 return of_read_u64(ofnode_to_np(node), propname, outp);
109
110 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
111 &len);
112 if (!cell || len < sizeof(*cell)) {
113 debug("(not found)\n");
114 return -EINVAL;
115 }
116 *outp = fdt64_to_cpu(cell[0]);
117 debug("%#llx (%lld)\n", (unsigned long long)*outp,
118 (unsigned long long)*outp);
119
120 return 0;
121}
122
T Karthik Reddy478860d2019-09-02 16:34:30 +0200123u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
Simon Glass9d54a7a2018-06-11 13:07:10 -0600124{
125 assert(ofnode_valid(node));
126 ofnode_read_u64(node, propname, &def);
127
128 return def;
129}
130
Simon Glassc4fc5622017-05-18 20:08:58 -0600131bool ofnode_read_bool(ofnode node, const char *propname)
132{
Masahiro Yamada5d434452017-06-22 16:54:07 +0900133 const void *prop;
Simon Glassc4fc5622017-05-18 20:08:58 -0600134
135 assert(ofnode_valid(node));
136 debug("%s: %s: ", __func__, propname);
137
Masahiro Yamada5d434452017-06-22 16:54:07 +0900138 prop = ofnode_get_property(node, propname, NULL);
139
140 debug("%s\n", prop ? "true" : "false");
Simon Glassc4fc5622017-05-18 20:08:58 -0600141
Masahiro Yamada5d434452017-06-22 16:54:07 +0900142 return prop ? true : false;
Simon Glassc4fc5622017-05-18 20:08:58 -0600143}
144
Simon Glass0c2e9802020-01-27 08:49:44 -0700145const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600146{
Simon Glass0c2e9802020-01-27 08:49:44 -0700147 const char *val = NULL;
148 int len;
Simon Glassc4fc5622017-05-18 20:08:58 -0600149
150 assert(ofnode_valid(node));
151 debug("%s: %s: ", __func__, propname);
152
153 if (ofnode_is_np(node)) {
154 struct property *prop = of_find_property(
Simon Glass0c2e9802020-01-27 08:49:44 -0700155 ofnode_to_np(node), propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600156
157 if (prop) {
Simon Glass0c2e9802020-01-27 08:49:44 -0700158 val = prop->value;
Simon Glassc4fc5622017-05-18 20:08:58 -0600159 len = prop->length;
160 }
161 } else {
Simon Glass0c2e9802020-01-27 08:49:44 -0700162 val = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
Simon Glassc4fc5622017-05-18 20:08:58 -0600163 propname, &len);
164 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700165 if (!val) {
Simon Glassc4fc5622017-05-18 20:08:58 -0600166 debug("<not found>\n");
Simon Glass0c2e9802020-01-27 08:49:44 -0700167 if (sizep)
168 *sizep = -FDT_ERR_NOTFOUND;
Simon Glassc4fc5622017-05-18 20:08:58 -0600169 return NULL;
170 }
Simon Glass0c2e9802020-01-27 08:49:44 -0700171 if (sizep)
172 *sizep = len;
173
174 return val;
175}
176
177const char *ofnode_read_string(ofnode node, const char *propname)
178{
179 const char *str;
180 int len;
181
182 str = ofnode_read_prop(node, propname, &len);
183 if (!str)
184 return NULL;
185
Simon Glassc4fc5622017-05-18 20:08:58 -0600186 if (strnlen(str, len) >= len) {
187 debug("<invalid>\n");
188 return NULL;
189 }
190 debug("%s\n", str);
191
192 return str;
193}
194
Simon Glass81c54b32020-01-27 08:49:45 -0700195int ofnode_read_size(ofnode node, const char *propname)
196{
197 int len;
198
199 if (!ofnode_read_prop(node, propname, &len))
200 return -EINVAL;
201
202 return len;
203}
204
Simon Glassc4fc5622017-05-18 20:08:58 -0600205ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
206{
207 ofnode subnode;
208
209 assert(ofnode_valid(node));
210 debug("%s: %s: ", __func__, subnode_name);
211
212 if (ofnode_is_np(node)) {
213 const struct device_node *np = ofnode_to_np(node);
214
215 for (np = np->child; np; np = np->sibling) {
216 if (!strcmp(subnode_name, np->name))
217 break;
218 }
219 subnode = np_to_ofnode(np);
220 } else {
221 int ooffset = fdt_subnode_offset(gd->fdt_blob,
222 ofnode_to_offset(node), subnode_name);
223 subnode = offset_to_ofnode(ooffset);
224 }
225 debug("%s\n", ofnode_valid(subnode) ?
226 ofnode_get_name(subnode) : "<none>");
227
228 return subnode;
229}
230
231int ofnode_read_u32_array(ofnode node, const char *propname,
232 u32 *out_values, size_t sz)
233{
234 assert(ofnode_valid(node));
235 debug("%s: %s: ", __func__, propname);
236
237 if (ofnode_is_np(node)) {
238 return of_read_u32_array(ofnode_to_np(node), propname,
239 out_values, sz);
240 } else {
241 return fdtdec_get_int_array(gd->fdt_blob,
242 ofnode_to_offset(node), propname,
243 out_values, sz);
244 }
245}
246
247ofnode ofnode_first_subnode(ofnode node)
248{
249 assert(ofnode_valid(node));
250 if (ofnode_is_np(node))
251 return np_to_ofnode(node.np->child);
252
253 return offset_to_ofnode(
254 fdt_first_subnode(gd->fdt_blob, ofnode_to_offset(node)));
255}
256
257ofnode ofnode_next_subnode(ofnode node)
258{
259 assert(ofnode_valid(node));
260 if (ofnode_is_np(node))
261 return np_to_ofnode(node.np->sibling);
262
263 return offset_to_ofnode(
264 fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node)));
265}
266
Philipp Tomsich6fce1dd2018-02-23 17:38:49 +0100267ofnode ofnode_get_parent(ofnode node)
268{
269 ofnode parent;
270
271 assert(ofnode_valid(node));
272 if (ofnode_is_np(node))
273 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
274 else
275 parent.of_offset = fdt_parent_offset(gd->fdt_blob,
276 ofnode_to_offset(node));
277
278 return parent;
279}
280
Simon Glassc4fc5622017-05-18 20:08:58 -0600281const char *ofnode_get_name(ofnode node)
282{
Kever Yang8d7976d2019-07-19 11:23:47 +0800283 if (!ofnode_valid(node)) {
284 debug("%s node not valid\n", __func__);
285 return NULL;
286 }
287
Simon Glassc4fc5622017-05-18 20:08:58 -0600288 if (ofnode_is_np(node))
289 return strrchr(node.np->full_name, '/') + 1;
290
291 return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL);
292}
293
Kever Yang37df0e02018-02-23 17:38:50 +0100294ofnode ofnode_get_by_phandle(uint phandle)
295{
296 ofnode node;
297
298 if (of_live_active())
299 node = np_to_ofnode(of_find_node_by_phandle(phandle));
300 else
301 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
302 phandle);
303
304 return node;
305}
306
Keerthyd332e6e2019-04-24 17:19:53 +0530307fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
Simon Glass049ae1b2017-05-18 20:09:01 -0600308{
Keerthy34222a32018-11-19 11:44:47 +0530309 int na, ns;
Keerthy34222a32018-11-19 11:44:47 +0530310
Simon Glass049ae1b2017-05-18 20:09:01 -0600311 if (ofnode_is_np(node)) {
312 const __be32 *prop_val;
Simon Glass47f85de2019-09-25 08:55:50 -0600313 u64 size64;
Simon Glass049ae1b2017-05-18 20:09:01 -0600314 uint flags;
Simon Glass049ae1b2017-05-18 20:09:01 -0600315
Simon Glass47f85de2019-09-25 08:55:50 -0600316 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
317 &flags);
Simon Glass049ae1b2017-05-18 20:09:01 -0600318 if (!prop_val)
319 return FDT_ADDR_T_NONE;
Simon Glass47f85de2019-09-25 08:55:50 -0600320 if (size)
321 *size = size64;
Mario Sixd007ebc2017-12-20 09:52:12 +0100322
Mario Six35616ef2018-03-12 14:53:33 +0100323 ns = of_n_size_cells(ofnode_to_np(node));
324
325 if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Sixd007ebc2017-12-20 09:52:12 +0100326 return of_translate_address(ofnode_to_np(node), prop_val);
327 } else {
328 na = of_n_addr_cells(ofnode_to_np(node));
329 return of_read_number(prop_val, na);
330 }
Simon Glass049ae1b2017-05-18 20:09:01 -0600331 } else {
Keerthy34222a32018-11-19 11:44:47 +0530332 na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
333 ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
334 return fdtdec_get_addr_size_fixed(gd->fdt_blob,
335 ofnode_to_offset(node), "reg",
Keerthyd332e6e2019-04-24 17:19:53 +0530336 index, na, ns, size, true);
Simon Glass049ae1b2017-05-18 20:09:01 -0600337 }
338
339 return FDT_ADDR_T_NONE;
340}
341
Keerthyd332e6e2019-04-24 17:19:53 +0530342fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
343{
344 fdt_size_t size;
345
346 return ofnode_get_addr_size_index(node, index, &size);
347}
348
Simon Glass049ae1b2017-05-18 20:09:01 -0600349fdt_addr_t ofnode_get_addr(ofnode node)
350{
351 return ofnode_get_addr_index(node, 0);
352}
353
Simon Glassc4fc5622017-05-18 20:08:58 -0600354int ofnode_stringlist_search(ofnode node, const char *property,
355 const char *string)
356{
357 if (ofnode_is_np(node)) {
358 return of_property_match_string(ofnode_to_np(node),
359 property, string);
360 } else {
361 int ret;
362
363 ret = fdt_stringlist_search(gd->fdt_blob,
364 ofnode_to_offset(node), property,
365 string);
366 if (ret == -FDT_ERR_NOTFOUND)
367 return -ENODATA;
368 else if (ret < 0)
369 return -EINVAL;
370
371 return ret;
372 }
373}
374
375int ofnode_read_string_index(ofnode node, const char *property, int index,
376 const char **outp)
377{
378 if (ofnode_is_np(node)) {
379 return of_property_read_string_index(ofnode_to_np(node),
380 property, index, outp);
381 } else {
382 int len;
383
384 *outp = fdt_stringlist_get(gd->fdt_blob, ofnode_to_offset(node),
385 property, index, &len);
386 if (len < 0)
387 return -EINVAL;
388 return 0;
389 }
390}
391
Simon Glass5fdb0052017-06-12 06:21:28 -0600392int ofnode_read_string_count(ofnode node, const char *property)
393{
394 if (ofnode_is_np(node)) {
395 return of_property_count_strings(ofnode_to_np(node), property);
396 } else {
397 return fdt_stringlist_count(gd->fdt_blob,
398 ofnode_to_offset(node), property);
399 }
400}
401
Simon Glassc4fc5622017-05-18 20:08:58 -0600402static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
403 struct ofnode_phandle_args *out)
404{
405 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
406 out->node = offset_to_ofnode(in->node);
407 out->args_count = in->args_count;
408 memcpy(out->args, in->args, sizeof(out->args));
409}
410
411static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
412 struct ofnode_phandle_args *out)
413{
414 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
415 out->node = np_to_ofnode(in->np);
416 out->args_count = in->args_count;
417 memcpy(out->args, in->args, sizeof(out->args));
418}
419
420int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
421 const char *cells_name, int cell_count,
422 int index,
423 struct ofnode_phandle_args *out_args)
424{
425 if (ofnode_is_np(node)) {
426 struct of_phandle_args args;
427 int ret;
428
429 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Mario Sixf40d82c2018-01-15 11:07:17 +0100430 list_name, cells_name, index,
431 &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600432 if (ret)
433 return ret;
434 ofnode_from_of_phandle_args(&args, out_args);
435 } else {
436 struct fdtdec_phandle_args args;
437 int ret;
438
439 ret = fdtdec_parse_phandle_with_args(gd->fdt_blob,
Mario Sixf40d82c2018-01-15 11:07:17 +0100440 ofnode_to_offset(node),
441 list_name, cells_name,
442 cell_count, index, &args);
Simon Glassc4fc5622017-05-18 20:08:58 -0600443 if (ret)
444 return ret;
445 ofnode_from_fdtdec_phandle_args(&args, out_args);
446 }
447
448 return 0;
449}
450
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200451int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
452 const char *cells_name)
453{
454 if (ofnode_is_np(node))
455 return of_count_phandle_with_args(ofnode_to_np(node),
456 list_name, cells_name);
457 else
458 return fdtdec_parse_phandle_with_args(gd->fdt_blob,
459 ofnode_to_offset(node), list_name, cells_name,
460 0, -1, NULL);
461}
462
Simon Glassc4fc5622017-05-18 20:08:58 -0600463ofnode ofnode_path(const char *path)
464{
465 if (of_live_active())
466 return np_to_ofnode(of_find_node_by_path(path));
467 else
468 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
469}
470
Simon Glasse09223c2020-01-27 08:49:46 -0700471const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glassc4fc5622017-05-18 20:08:58 -0600472{
473 ofnode chosen_node;
474
475 chosen_node = ofnode_path("/chosen");
476
Simon Glasse09223c2020-01-27 08:49:46 -0700477 return ofnode_read_prop(chosen_node, propname, sizep);
Simon Glassc4fc5622017-05-18 20:08:58 -0600478}
479
Simon Glasse09223c2020-01-27 08:49:46 -0700480const char *ofnode_read_chosen_string(const char *propname)
481{
482 return ofnode_read_chosen_prop(propname, NULL);
483}
484
Simon Glassc4fc5622017-05-18 20:08:58 -0600485ofnode ofnode_get_chosen_node(const char *name)
486{
487 const char *prop;
488
Simon Glasse09223c2020-01-27 08:49:46 -0700489 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glassc4fc5622017-05-18 20:08:58 -0600490 if (!prop)
491 return ofnode_null();
492
493 return ofnode_path(prop);
494}
495
496static int decode_timing_property(ofnode node, const char *name,
497 struct timing_entry *result)
498{
499 int length, ret = 0;
500
501 length = ofnode_read_size(node, name);
502 if (length < 0) {
503 debug("%s: could not find property %s\n",
504 ofnode_get_name(node), name);
505 return length;
506 }
507
508 if (length == sizeof(u32)) {
509 result->typ = ofnode_read_u32_default(node, name, 0);
510 result->min = result->typ;
511 result->max = result->typ;
512 } else {
513 ret = ofnode_read_u32_array(node, name, &result->min, 3);
514 }
515
516 return ret;
517}
518
519int ofnode_decode_display_timing(ofnode parent, int index,
520 struct display_timing *dt)
521{
522 int i;
523 ofnode timings, node;
524 u32 val = 0;
525 int ret = 0;
526
527 timings = ofnode_find_subnode(parent, "display-timings");
528 if (!ofnode_valid(timings))
529 return -EINVAL;
530
Simon Glass28529762017-08-05 15:45:54 -0600531 i = 0;
532 ofnode_for_each_subnode(node, timings) {
533 if (i++ == index)
534 break;
535 }
Simon Glassc4fc5622017-05-18 20:08:58 -0600536
537 if (!ofnode_valid(node))
538 return -EINVAL;
539
540 memset(dt, 0, sizeof(*dt));
541
542 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
543 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
544 ret |= decode_timing_property(node, "hactive", &dt->hactive);
545 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
546 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
547 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
548 ret |= decode_timing_property(node, "vactive", &dt->vactive);
549 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
550 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
551
552 dt->flags = 0;
553 val = ofnode_read_u32_default(node, "vsync-active", -1);
554 if (val != -1) {
555 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
556 DISPLAY_FLAGS_VSYNC_LOW;
557 }
558 val = ofnode_read_u32_default(node, "hsync-active", -1);
559 if (val != -1) {
560 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
561 DISPLAY_FLAGS_HSYNC_LOW;
562 }
563 val = ofnode_read_u32_default(node, "de-active", -1);
564 if (val != -1) {
565 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
566 DISPLAY_FLAGS_DE_LOW;
567 }
568 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
569 if (val != -1) {
570 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
571 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
572 }
573
574 if (ofnode_read_bool(node, "interlaced"))
575 dt->flags |= DISPLAY_FLAGS_INTERLACED;
576 if (ofnode_read_bool(node, "doublescan"))
577 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
578 if (ofnode_read_bool(node, "doubleclk"))
579 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
580
581 return ret;
582}
583
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +0900584const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glassc4fc5622017-05-18 20:08:58 -0600585{
Masahiro Yamada5052f1b2017-06-22 16:54:04 +0900586 if (ofnode_is_np(node))
587 return of_get_property(ofnode_to_np(node), propname, lenp);
588 else
Simon Glassc4fc5622017-05-18 20:08:58 -0600589 return fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
590 propname, lenp);
Simon Glassc4fc5622017-05-18 20:08:58 -0600591}
592
593bool ofnode_is_available(ofnode node)
594{
595 if (ofnode_is_np(node))
596 return of_device_is_available(ofnode_to_np(node));
597 else
598 return fdtdec_get_is_enabled(gd->fdt_blob,
599 ofnode_to_offset(node));
600}
601
602fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
603 fdt_size_t *sizep)
604{
605 if (ofnode_is_np(node)) {
606 int na, ns;
607 int psize;
608 const struct device_node *np = ofnode_to_np(node);
Klaus Gogeraf4b0212017-09-20 13:50:41 +0200609 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glassc4fc5622017-05-18 20:08:58 -0600610
Klaus Gogeraf4b0212017-09-20 13:50:41 +0200611 if (!prop)
612 return FDT_ADDR_T_NONE;
Simon Glassc4fc5622017-05-18 20:08:58 -0600613 na = of_n_addr_cells(np);
Marek Vasut1638c172018-10-01 12:37:19 +0200614 ns = of_n_size_cells(np);
Simon Glassa67cc632017-05-18 20:09:27 -0600615 *sizep = of_read_number(prop + na, ns);
Marek Vasuta9dac492018-10-01 12:37:20 +0200616
Simon Glass019f9562019-04-25 21:58:36 -0600617 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta9dac492018-10-01 12:37:20 +0200618 return of_translate_address(np, prop);
619 else
620 return of_read_number(prop, na);
Simon Glassc4fc5622017-05-18 20:08:58 -0600621 } else {
622 return fdtdec_get_addr_size(gd->fdt_blob,
623 ofnode_to_offset(node), property,
624 sizep);
625 }
626}
627
628const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
629 size_t sz)
630{
631 if (ofnode_is_np(node)) {
632 const struct device_node *np = ofnode_to_np(node);
633 int psize;
634 const __be32 *prop = of_get_property(np, propname, &psize);
635
636 if (!prop || sz != psize)
637 return NULL;
638 return (uint8_t *)prop;
639
640 } else {
641 return fdtdec_locate_byte_array(gd->fdt_blob,
642 ofnode_to_offset(node), propname, sz);
643 }
644}
645
646int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
647 const char *propname, struct fdt_pci_addr *addr)
648{
Masahiro Yamada5c5991e2017-06-22 17:57:50 +0900649 const fdt32_t *cell;
Simon Glassc4fc5622017-05-18 20:08:58 -0600650 int len;
651 int ret = -ENOENT;
652
653 debug("%s: %s: ", __func__, propname);
654
655 /*
656 * If we follow the pci bus bindings strictly, we should check
657 * the value of the node's parent node's #address-cells and
658 * #size-cells. They need to be 3 and 2 accordingly. However,
659 * for simplicity we skip the check here.
660 */
Masahiro Yamada9cf85cb2017-06-22 16:54:05 +0900661 cell = ofnode_get_property(node, propname, &len);
Simon Glassc4fc5622017-05-18 20:08:58 -0600662 if (!cell)
663 goto fail;
664
665 if ((len % FDT_PCI_REG_SIZE) == 0) {
666 int num = len / FDT_PCI_REG_SIZE;
667 int i;
668
669 for (i = 0; i < num; i++) {
670 debug("pci address #%d: %08lx %08lx %08lx\n", i,
671 (ulong)fdt32_to_cpu(cell[0]),
672 (ulong)fdt32_to_cpu(cell[1]),
673 (ulong)fdt32_to_cpu(cell[2]));
674 if ((fdt32_to_cpu(*cell) & type) == type) {
675 addr->phys_hi = fdt32_to_cpu(cell[0]);
676 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glassdfd43152019-09-25 08:55:46 -0600677 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glassc4fc5622017-05-18 20:08:58 -0600678 break;
Simon Glassc4fc5622017-05-18 20:08:58 -0600679 }
Mario Sixf40d82c2018-01-15 11:07:17 +0100680
681 cell += (FDT_PCI_ADDR_CELLS +
682 FDT_PCI_SIZE_CELLS);
Simon Glassc4fc5622017-05-18 20:08:58 -0600683 }
684
685 if (i == num) {
686 ret = -ENXIO;
687 goto fail;
688 }
689
690 return 0;
Simon Glassc4fc5622017-05-18 20:08:58 -0600691 }
692
Mario Sixf40d82c2018-01-15 11:07:17 +0100693 ret = -EINVAL;
694
Simon Glassc4fc5622017-05-18 20:08:58 -0600695fail:
696 debug("(not found)\n");
697 return ret;
698}
699
Bin Mengfa157712018-08-03 01:14:35 -0700700int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
701{
702 const char *list, *end;
703 int len;
704
705 list = ofnode_get_property(node, "compatible", &len);
706 if (!list)
707 return -ENOENT;
708
709 end = list + len;
710 while (list < end) {
711 len = strlen(list);
712 if (len >= strlen("pciVVVV,DDDD")) {
713 char *s = strstr(list, "pci");
714
715 /*
716 * check if the string is something like pciVVVV,DDDD.RR
717 * or just pciVVVV,DDDD
718 */
719 if (s && s[7] == ',' &&
720 (s[12] == '.' || s[12] == 0)) {
721 s += 3;
722 *vendor = simple_strtol(s, NULL, 16);
723
724 s += 5;
725 *device = simple_strtol(s, NULL, 16);
726
727 return 0;
728 }
729 }
730 list += (len + 1);
731 }
732
733 return -ENOENT;
734}
735
Simon Glassc4fc5622017-05-18 20:08:58 -0600736int ofnode_read_addr_cells(ofnode node)
737{
738 if (ofnode_is_np(node))
739 return of_n_addr_cells(ofnode_to_np(node));
Simon Glass4191dc12017-06-12 06:21:31 -0600740 else /* NOTE: this call should walk up the parent stack */
Simon Glassc4fc5622017-05-18 20:08:58 -0600741 return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node));
742}
743
744int ofnode_read_size_cells(ofnode node)
745{
746 if (ofnode_is_np(node))
747 return of_n_size_cells(ofnode_to_np(node));
Simon Glass4191dc12017-06-12 06:21:31 -0600748 else /* NOTE: this call should walk up the parent stack */
749 return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node));
750}
751
752int ofnode_read_simple_addr_cells(ofnode node)
753{
754 if (ofnode_is_np(node))
755 return of_simple_addr_cells(ofnode_to_np(node));
756 else
757 return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node));
758}
759
760int ofnode_read_simple_size_cells(ofnode node)
761{
762 if (ofnode_is_np(node))
763 return of_simple_size_cells(ofnode_to_np(node));
Simon Glassc4fc5622017-05-18 20:08:58 -0600764 else
765 return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node));
766}
767
768bool ofnode_pre_reloc(ofnode node)
769{
Patrick Delaunay0b025b82019-02-11 12:49:57 +0100770#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
771 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
772 * had property dm-pre-reloc or u-boot,dm-spl/tpl.
773 * They are removed in final dtb (fdtgrep 2nd pass)
774 */
775 return true;
776#else
Masahiro Yamada6a61dd92017-06-22 16:54:03 +0900777 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
Simon Glassc4fc5622017-05-18 20:08:58 -0600778 return true;
Simon Glass23f22842018-10-01 12:22:18 -0600779 if (ofnode_read_bool(node, "u-boot,dm-pre-proper"))
780 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -0600781
Simon Glassc4fc5622017-05-18 20:08:58 -0600782 /*
783 * In regular builds individual spl and tpl handling both
784 * count as handled pre-relocation for later second init.
785 */
Masahiro Yamada6a61dd92017-06-22 16:54:03 +0900786 if (ofnode_read_bool(node, "u-boot,dm-spl") ||
787 ofnode_read_bool(node, "u-boot,dm-tpl"))
Simon Glassc4fc5622017-05-18 20:08:58 -0600788 return true;
Simon Glassc4fc5622017-05-18 20:08:58 -0600789
790 return false;
Patrick Delaunay0b025b82019-02-11 12:49:57 +0100791#endif
Simon Glassc4fc5622017-05-18 20:08:58 -0600792}
Simon Glassf7bfcc42017-07-25 08:29:55 -0600793
794int ofnode_read_resource(ofnode node, uint index, struct resource *res)
795{
796 if (ofnode_is_np(node)) {
797 return of_address_to_resource(ofnode_to_np(node), index, res);
798 } else {
799 struct fdt_resource fres;
800 int ret;
801
802 ret = fdt_get_resource(gd->fdt_blob, ofnode_to_offset(node),
803 "reg", index, &fres);
804 if (ret < 0)
805 return -EINVAL;
806 memset(res, '\0', sizeof(*res));
807 res->start = fres.start;
808 res->end = fres.end;
809
810 return 0;
811 }
812}
Masahiro Yamada4dada2c2017-08-26 01:12:30 +0900813
814int ofnode_read_resource_byname(ofnode node, const char *name,
815 struct resource *res)
816{
817 int index;
818
819 index = ofnode_stringlist_search(node, "reg-names", name);
820 if (index < 0)
821 return index;
822
823 return ofnode_read_resource(node, index, res);
824}
Mario Sixaefac062018-01-15 11:07:19 +0100825
826u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
827{
828 if (ofnode_is_np(node))
829 return of_translate_address(ofnode_to_np(node), in_addr);
830 else
831 return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
832}
Masahiro Yamada9349bcc2018-04-19 12:14:02 +0900833
Fabien Dessenne22236e02019-05-31 15:11:30 +0200834u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
835{
836 if (ofnode_is_np(node))
837 return of_translate_dma_address(ofnode_to_np(node), in_addr);
838 else
839 return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
840}
841
Masahiro Yamada9349bcc2018-04-19 12:14:02 +0900842int ofnode_device_is_compatible(ofnode node, const char *compat)
843{
844 if (ofnode_is_np(node))
845 return of_device_is_compatible(ofnode_to_np(node), compat,
846 NULL, NULL);
847 else
848 return !fdt_node_check_compatible(gd->fdt_blob,
849 ofnode_to_offset(node),
850 compat);
851}
Simon Glass954eeae2018-06-11 13:07:13 -0600852
853ofnode ofnode_by_compatible(ofnode from, const char *compat)
854{
855 if (of_live_active()) {
856 return np_to_ofnode(of_find_compatible_node(
857 (struct device_node *)ofnode_to_np(from), NULL,
858 compat));
859 } else {
860 return offset_to_ofnode(fdt_node_offset_by_compatible(
861 gd->fdt_blob, ofnode_to_offset(from), compat));
862 }
863}
Jens Wiklander7b68dad2018-08-20 11:09:58 +0200864
865ofnode ofnode_by_prop_value(ofnode from, const char *propname,
866 const void *propval, int proplen)
867{
868 if (of_live_active()) {
869 return np_to_ofnode(of_find_node_by_prop_value(
870 (struct device_node *)ofnode_to_np(from), propname,
871 propval, proplen));
872 } else {
873 return offset_to_ofnode(fdt_node_offset_by_prop_value(
874 gd->fdt_blob, ofnode_to_offset(from),
875 propname, propval, proplen));
876 }
877}
Mario Six047dafc2018-06-26 08:46:48 +0200878
879int ofnode_write_prop(ofnode node, const char *propname, int len,
880 const void *value)
881{
882 const struct device_node *np = ofnode_to_np(node);
883 struct property *pp;
884 struct property *pp_last = NULL;
885 struct property *new;
886
887 if (!of_live_active())
888 return -ENOSYS;
889
890 if (!np)
891 return -EINVAL;
892
893 for (pp = np->properties; pp; pp = pp->next) {
894 if (strcmp(pp->name, propname) == 0) {
895 /* Property exists -> change value */
896 pp->value = (void *)value;
897 pp->length = len;
898 return 0;
899 }
900 pp_last = pp;
901 }
902
903 if (!pp_last)
904 return -ENOENT;
905
906 /* Property does not exist -> append new property */
907 new = malloc(sizeof(struct property));
908 if (!new)
909 return -ENOMEM;
910
911 new->name = strdup(propname);
Mario Six95e885d2018-10-04 09:22:24 +0200912 if (!new->name) {
913 free(new);
Mario Six047dafc2018-06-26 08:46:48 +0200914 return -ENOMEM;
Mario Six95e885d2018-10-04 09:22:24 +0200915 }
Mario Six047dafc2018-06-26 08:46:48 +0200916
917 new->value = (void *)value;
918 new->length = len;
919 new->next = NULL;
920
921 pp_last->next = new;
922
923 return 0;
924}
925
926int ofnode_write_string(ofnode node, const char *propname, const char *value)
927{
928 if (!of_live_active())
929 return -ENOSYS;
930
931 assert(ofnode_valid(node));
932
933 debug("%s: %s = %s", __func__, propname, value);
934
935 return ofnode_write_prop(node, propname, strlen(value) + 1, value);
936}
937
938int ofnode_set_enabled(ofnode node, bool value)
939{
940 if (!of_live_active())
941 return -ENOSYS;
942
943 assert(ofnode_valid(node));
944
945 if (value)
946 return ofnode_write_string(node, "status", "okay");
947 else
Bin Menga9274aa2019-07-05 09:23:17 -0700948 return ofnode_write_string(node, "status", "disabled");
Mario Six047dafc2018-06-26 08:46:48 +0200949}