blob: 87072094f32dcaff82385c1196e5bdfca2f4b80e [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 Glass9e512042017-05-18 20:08:58 -060019
20int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
21{
Dario Binacchi59006602020-03-29 18:04:42 +020022 return ofnode_read_u32_index(node, propname, 0, outp);
Simon Glass9e512042017-05-18 20:08:58 -060023}
24
Trent Piephob061ef32019-05-10 17:48:20 +000025u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
Simon Glass9e512042017-05-18 20:08:58 -060026{
27 assert(ofnode_valid(node));
Dario Binacchi59006602020-03-29 18:04:42 +020028 ofnode_read_u32_index(node, propname, 0, &def);
Simon Glass9e512042017-05-18 20:08:58 -060029
30 return def;
31}
32
Dario Binacchi4bb70752020-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 Glass9e512042017-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 Glass7e5196c2018-06-11 13:07:10 -060081int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
82{
Jean-Jacques Hiblotd60ae4c2019-10-22 10:05:22 +020083 const unaligned_fdt64_t *cell;
Simon Glass7e5196c2018-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 Reddy3f3d7712019-09-02 16:34:30 +0200105u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
Simon Glass7e5196c2018-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 Glass9e512042017-05-18 20:08:58 -0600113bool ofnode_read_bool(ofnode node, const char *propname)
114{
Masahiro Yamadab2ec7ea2017-06-22 16:54:07 +0900115 const void *prop;
Simon Glass9e512042017-05-18 20:08:58 -0600116
117 assert(ofnode_valid(node));
118 debug("%s: %s: ", __func__, propname);
119
Masahiro Yamadab2ec7ea2017-06-22 16:54:07 +0900120 prop = ofnode_get_property(node, propname, NULL);
Simon Glass9e512042017-05-18 20:08:58 -0600121
Masahiro Yamadab2ec7ea2017-06-22 16:54:07 +0900122 debug("%s\n", prop ? "true" : "false");
123
124 return prop ? true : false;
Simon Glass9e512042017-05-18 20:08:58 -0600125}
126
Simon Glassa8167d82020-01-27 08:49:44 -0700127const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
Simon Glass9e512042017-05-18 20:08:58 -0600128{
Simon Glassa8167d82020-01-27 08:49:44 -0700129 const char *val = NULL;
130 int len;
Simon Glass9e512042017-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 Glassa8167d82020-01-27 08:49:44 -0700137 ofnode_to_np(node), propname, &len);
Simon Glass9e512042017-05-18 20:08:58 -0600138
139 if (prop) {
Simon Glassa8167d82020-01-27 08:49:44 -0700140 val = prop->value;
Simon Glass9e512042017-05-18 20:08:58 -0600141 len = prop->length;
142 }
143 } else {
Simon Glassa8167d82020-01-27 08:49:44 -0700144 val = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
Simon Glass9e512042017-05-18 20:08:58 -0600145 propname, &len);
146 }
Simon Glassa8167d82020-01-27 08:49:44 -0700147 if (!val) {
Simon Glass9e512042017-05-18 20:08:58 -0600148 debug("<not found>\n");
Simon Glassa8167d82020-01-27 08:49:44 -0700149 if (sizep)
150 *sizep = -FDT_ERR_NOTFOUND;
Simon Glass9e512042017-05-18 20:08:58 -0600151 return NULL;
152 }
Simon Glassa8167d82020-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 Glass9e512042017-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 Glass1aada632020-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 Glass9e512042017-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
Simon Glass0de1b072020-11-28 17:50:02 -0700229bool ofnode_is_enabled(ofnode node)
230{
231 if (ofnode_is_np(node)) {
232 return of_device_is_available(ofnode_to_np(node));
233 } else {
234 return fdtdec_get_is_enabled(gd->fdt_blob,
235 ofnode_to_offset(node));
236 }
237}
238
Simon Glass9e512042017-05-18 20:08:58 -0600239ofnode ofnode_first_subnode(ofnode node)
240{
241 assert(ofnode_valid(node));
242 if (ofnode_is_np(node))
243 return np_to_ofnode(node.np->child);
244
245 return offset_to_ofnode(
246 fdt_first_subnode(gd->fdt_blob, ofnode_to_offset(node)));
247}
248
249ofnode ofnode_next_subnode(ofnode node)
250{
251 assert(ofnode_valid(node));
252 if (ofnode_is_np(node))
253 return np_to_ofnode(node.np->sibling);
254
255 return offset_to_ofnode(
256 fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node)));
257}
258
Philipp Tomsiche2d59972018-02-23 17:38:49 +0100259ofnode ofnode_get_parent(ofnode node)
260{
261 ofnode parent;
262
263 assert(ofnode_valid(node));
264 if (ofnode_is_np(node))
265 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
266 else
267 parent.of_offset = fdt_parent_offset(gd->fdt_blob,
268 ofnode_to_offset(node));
269
270 return parent;
271}
272
Simon Glass9e512042017-05-18 20:08:58 -0600273const char *ofnode_get_name(ofnode node)
274{
Kever Yang8f0a70e2019-07-19 11:23:47 +0800275 if (!ofnode_valid(node)) {
276 debug("%s node not valid\n", __func__);
277 return NULL;
278 }
279
Simon Glass9e512042017-05-18 20:08:58 -0600280 if (ofnode_is_np(node))
281 return strrchr(node.np->full_name, '/') + 1;
282
283 return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL);
284}
285
Kever Yangb4f20762018-02-23 17:38:50 +0100286ofnode ofnode_get_by_phandle(uint phandle)
287{
288 ofnode node;
289
290 if (of_live_active())
291 node = np_to_ofnode(of_find_node_by_phandle(phandle));
292 else
293 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
294 phandle);
295
296 return node;
297}
298
Keerthye679d032019-04-24 17:19:53 +0530299fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
Simon Glassbed77492017-05-18 20:09:01 -0600300{
Keerthy16787542018-11-19 11:44:47 +0530301 int na, ns;
Keerthy16787542018-11-19 11:44:47 +0530302
Simon Glassbed77492017-05-18 20:09:01 -0600303 if (ofnode_is_np(node)) {
304 const __be32 *prop_val;
Simon Glasse18c41f2019-09-25 08:55:50 -0600305 u64 size64;
Simon Glassbed77492017-05-18 20:09:01 -0600306 uint flags;
Simon Glassbed77492017-05-18 20:09:01 -0600307
Simon Glasse18c41f2019-09-25 08:55:50 -0600308 prop_val = of_get_address(ofnode_to_np(node), index, &size64,
309 &flags);
Simon Glassbed77492017-05-18 20:09:01 -0600310 if (!prop_val)
311 return FDT_ADDR_T_NONE;
Simon Glasse18c41f2019-09-25 08:55:50 -0600312 if (size)
313 *size = size64;
Mario Six286ede62017-12-20 09:52:12 +0100314
Mario Sixe8d52912018-03-12 14:53:33 +0100315 ns = of_n_size_cells(ofnode_to_np(node));
316
317 if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
Mario Six286ede62017-12-20 09:52:12 +0100318 return of_translate_address(ofnode_to_np(node), prop_val);
319 } else {
320 na = of_n_addr_cells(ofnode_to_np(node));
321 return of_read_number(prop_val, na);
322 }
Simon Glassbed77492017-05-18 20:09:01 -0600323 } else {
Keerthy16787542018-11-19 11:44:47 +0530324 na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
325 ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
326 return fdtdec_get_addr_size_fixed(gd->fdt_blob,
327 ofnode_to_offset(node), "reg",
Keerthye679d032019-04-24 17:19:53 +0530328 index, na, ns, size, true);
Simon Glassbed77492017-05-18 20:09:01 -0600329 }
330
331 return FDT_ADDR_T_NONE;
332}
333
Keerthye679d032019-04-24 17:19:53 +0530334fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
335{
336 fdt_size_t size;
337
338 return ofnode_get_addr_size_index(node, index, &size);
339}
340
Simon Glassbed77492017-05-18 20:09:01 -0600341fdt_addr_t ofnode_get_addr(ofnode node)
342{
343 return ofnode_get_addr_index(node, 0);
344}
345
Simon Glass9e512042017-05-18 20:08:58 -0600346int ofnode_stringlist_search(ofnode node, const char *property,
347 const char *string)
348{
349 if (ofnode_is_np(node)) {
350 return of_property_match_string(ofnode_to_np(node),
351 property, string);
352 } else {
353 int ret;
354
355 ret = fdt_stringlist_search(gd->fdt_blob,
356 ofnode_to_offset(node), property,
357 string);
358 if (ret == -FDT_ERR_NOTFOUND)
359 return -ENODATA;
360 else if (ret < 0)
361 return -EINVAL;
362
363 return ret;
364 }
365}
366
367int ofnode_read_string_index(ofnode node, const char *property, int index,
368 const char **outp)
369{
370 if (ofnode_is_np(node)) {
371 return of_property_read_string_index(ofnode_to_np(node),
372 property, index, outp);
373 } else {
374 int len;
375
376 *outp = fdt_stringlist_get(gd->fdt_blob, ofnode_to_offset(node),
377 property, index, &len);
378 if (len < 0)
379 return -EINVAL;
380 return 0;
381 }
382}
383
Simon Glass8c293d62017-06-12 06:21:28 -0600384int ofnode_read_string_count(ofnode node, const char *property)
385{
386 if (ofnode_is_np(node)) {
387 return of_property_count_strings(ofnode_to_np(node), property);
388 } else {
389 return fdt_stringlist_count(gd->fdt_blob,
390 ofnode_to_offset(node), property);
391 }
392}
393
Simon Glass9e512042017-05-18 20:08:58 -0600394static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
395 struct ofnode_phandle_args *out)
396{
397 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
398 out->node = offset_to_ofnode(in->node);
399 out->args_count = in->args_count;
400 memcpy(out->args, in->args, sizeof(out->args));
401}
402
403static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
404 struct ofnode_phandle_args *out)
405{
406 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
407 out->node = np_to_ofnode(in->np);
408 out->args_count = in->args_count;
409 memcpy(out->args, in->args, sizeof(out->args));
410}
411
412int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
413 const char *cells_name, int cell_count,
414 int index,
415 struct ofnode_phandle_args *out_args)
416{
417 if (ofnode_is_np(node)) {
418 struct of_phandle_args args;
419 int ret;
420
421 ret = of_parse_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay01d89e32020-09-10 18:26:17 +0200422 list_name, cells_name,
423 cell_count, index,
Mario Six51db2872018-01-15 11:07:17 +0100424 &args);
Simon Glass9e512042017-05-18 20:08:58 -0600425 if (ret)
426 return ret;
427 ofnode_from_of_phandle_args(&args, out_args);
428 } else {
429 struct fdtdec_phandle_args args;
430 int ret;
431
432 ret = fdtdec_parse_phandle_with_args(gd->fdt_blob,
Mario Six51db2872018-01-15 11:07:17 +0100433 ofnode_to_offset(node),
434 list_name, cells_name,
435 cell_count, index, &args);
Simon Glass9e512042017-05-18 20:08:58 -0600436 if (ret)
437 return ret;
438 ofnode_from_fdtdec_phandle_args(&args, out_args);
439 }
440
441 return 0;
442}
443
Patrice Chotard642346a2017-07-18 11:57:08 +0200444int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
Patrick Delaunay89f68302020-09-25 09:41:14 +0200445 const char *cells_name, int cell_count)
Patrice Chotard642346a2017-07-18 11:57:08 +0200446{
447 if (ofnode_is_np(node))
448 return of_count_phandle_with_args(ofnode_to_np(node),
Patrick Delaunay89f68302020-09-25 09:41:14 +0200449 list_name, cells_name, cell_count);
Patrice Chotard642346a2017-07-18 11:57:08 +0200450 else
451 return fdtdec_parse_phandle_with_args(gd->fdt_blob,
452 ofnode_to_offset(node), list_name, cells_name,
Patrick Delaunay89f68302020-09-25 09:41:14 +0200453 cell_count, -1, NULL);
Patrice Chotard642346a2017-07-18 11:57:08 +0200454}
455
Simon Glass9e512042017-05-18 20:08:58 -0600456ofnode ofnode_path(const char *path)
457{
458 if (of_live_active())
459 return np_to_ofnode(of_find_node_by_path(path));
460 else
461 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
462}
463
Simon Glassbd933bf2020-01-27 08:49:46 -0700464const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
Simon Glass9e512042017-05-18 20:08:58 -0600465{
466 ofnode chosen_node;
467
468 chosen_node = ofnode_path("/chosen");
469
Simon Glassbd933bf2020-01-27 08:49:46 -0700470 return ofnode_read_prop(chosen_node, propname, sizep);
471}
472
473const char *ofnode_read_chosen_string(const char *propname)
474{
475 return ofnode_read_chosen_prop(propname, NULL);
Simon Glass9e512042017-05-18 20:08:58 -0600476}
477
478ofnode ofnode_get_chosen_node(const char *name)
479{
480 const char *prop;
481
Simon Glassbd933bf2020-01-27 08:49:46 -0700482 prop = ofnode_read_chosen_prop(name, NULL);
Simon Glass9e512042017-05-18 20:08:58 -0600483 if (!prop)
484 return ofnode_null();
485
486 return ofnode_path(prop);
487}
488
Michal Simek305d3182020-07-28 12:51:08 +0200489const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
490{
491 ofnode node;
492
493 node = ofnode_path("/aliases");
494
495 return ofnode_read_prop(node, propname, sizep);
496}
497
498ofnode ofnode_get_aliases_node(const char *name)
499{
500 const char *prop;
501
502 prop = ofnode_read_aliases_prop(name, NULL);
503 if (!prop)
504 return ofnode_null();
505
506 debug("%s: node_path: %s\n", __func__, prop);
507
508 return ofnode_path(prop);
509}
510
Chunfeng Yun89b84b82020-05-02 11:35:09 +0200511int ofnode_get_child_count(ofnode parent)
512{
513 ofnode child;
514 int num = 0;
515
516 ofnode_for_each_subnode(child, parent)
517 num++;
518
519 return num;
520}
521
Simon Glass9e512042017-05-18 20:08:58 -0600522static int decode_timing_property(ofnode node, const char *name,
523 struct timing_entry *result)
524{
525 int length, ret = 0;
526
527 length = ofnode_read_size(node, name);
528 if (length < 0) {
529 debug("%s: could not find property %s\n",
530 ofnode_get_name(node), name);
531 return length;
532 }
533
534 if (length == sizeof(u32)) {
535 result->typ = ofnode_read_u32_default(node, name, 0);
536 result->min = result->typ;
537 result->max = result->typ;
538 } else {
539 ret = ofnode_read_u32_array(node, name, &result->min, 3);
540 }
541
542 return ret;
543}
544
545int ofnode_decode_display_timing(ofnode parent, int index,
546 struct display_timing *dt)
547{
548 int i;
549 ofnode timings, node;
550 u32 val = 0;
551 int ret = 0;
552
553 timings = ofnode_find_subnode(parent, "display-timings");
554 if (!ofnode_valid(timings))
555 return -EINVAL;
556
Simon Glass3991f422017-08-05 15:45:54 -0600557 i = 0;
558 ofnode_for_each_subnode(node, timings) {
559 if (i++ == index)
560 break;
561 }
Simon Glass9e512042017-05-18 20:08:58 -0600562
563 if (!ofnode_valid(node))
564 return -EINVAL;
565
566 memset(dt, 0, sizeof(*dt));
567
568 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
569 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
570 ret |= decode_timing_property(node, "hactive", &dt->hactive);
571 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
572 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
573 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
574 ret |= decode_timing_property(node, "vactive", &dt->vactive);
575 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
576 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
577
578 dt->flags = 0;
579 val = ofnode_read_u32_default(node, "vsync-active", -1);
580 if (val != -1) {
581 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
582 DISPLAY_FLAGS_VSYNC_LOW;
583 }
584 val = ofnode_read_u32_default(node, "hsync-active", -1);
585 if (val != -1) {
586 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
587 DISPLAY_FLAGS_HSYNC_LOW;
588 }
589 val = ofnode_read_u32_default(node, "de-active", -1);
590 if (val != -1) {
591 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
592 DISPLAY_FLAGS_DE_LOW;
593 }
594 val = ofnode_read_u32_default(node, "pixelclk-active", -1);
595 if (val != -1) {
596 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
597 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
598 }
599
600 if (ofnode_read_bool(node, "interlaced"))
601 dt->flags |= DISPLAY_FLAGS_INTERLACED;
602 if (ofnode_read_bool(node, "doublescan"))
603 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
604 if (ofnode_read_bool(node, "doubleclk"))
605 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
606
607 return ret;
608}
609
Masahiro Yamada61e51ba2017-06-22 16:54:05 +0900610const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
Simon Glass9e512042017-05-18 20:08:58 -0600611{
Masahiro Yamadacb7dbe12017-06-22 16:54:04 +0900612 if (ofnode_is_np(node))
613 return of_get_property(ofnode_to_np(node), propname, lenp);
614 else
Simon Glass9e512042017-05-18 20:08:58 -0600615 return fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
616 propname, lenp);
Simon Glass9e512042017-05-18 20:08:58 -0600617}
618
Patrick Delaunayce891fca2020-01-13 11:34:56 +0100619int ofnode_get_first_property(ofnode node, struct ofprop *prop)
620{
621 prop->node = node;
622
623 if (ofnode_is_np(node)) {
624 prop->prop = of_get_first_property(ofnode_to_np(prop->node));
625 if (!prop->prop)
626 return -FDT_ERR_NOTFOUND;
627 } else {
628 prop->offset =
629 fdt_first_property_offset(gd->fdt_blob,
630 ofnode_to_offset(prop->node));
631 if (prop->offset < 0)
632 return prop->offset;
633 }
634
635 return 0;
636}
637
638int ofnode_get_next_property(struct ofprop *prop)
639{
640 if (ofnode_is_np(prop->node)) {
641 prop->prop = of_get_next_property(ofnode_to_np(prop->node),
642 prop->prop);
643 if (!prop->prop)
644 return -FDT_ERR_NOTFOUND;
645 } else {
646 prop->offset = fdt_next_property_offset(gd->fdt_blob,
647 prop->offset);
648 if (prop->offset < 0)
649 return prop->offset;
650 }
651
652 return 0;
653}
654
655const void *ofnode_get_property_by_prop(const struct ofprop *prop,
656 const char **propname, int *lenp)
657{
658 if (ofnode_is_np(prop->node))
659 return of_get_property_by_prop(ofnode_to_np(prop->node),
660 prop->prop, propname, lenp);
661 else
662 return fdt_getprop_by_offset(gd->fdt_blob,
663 prop->offset,
664 propname, lenp);
665}
666
Simon Glass9e512042017-05-18 20:08:58 -0600667bool ofnode_is_available(ofnode node)
668{
669 if (ofnode_is_np(node))
670 return of_device_is_available(ofnode_to_np(node));
671 else
672 return fdtdec_get_is_enabled(gd->fdt_blob,
673 ofnode_to_offset(node));
674}
675
676fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
677 fdt_size_t *sizep)
678{
679 if (ofnode_is_np(node)) {
680 int na, ns;
681 int psize;
682 const struct device_node *np = ofnode_to_np(node);
Klaus Goger68a34522017-09-20 13:50:41 +0200683 const __be32 *prop = of_get_property(np, property, &psize);
Simon Glass9e512042017-05-18 20:08:58 -0600684
Klaus Goger68a34522017-09-20 13:50:41 +0200685 if (!prop)
686 return FDT_ADDR_T_NONE;
Simon Glass9e512042017-05-18 20:08:58 -0600687 na = of_n_addr_cells(np);
Marek Vasut51cb9272018-10-01 12:37:19 +0200688 ns = of_n_size_cells(np);
Simon Glassa4b8e372017-05-18 20:09:27 -0600689 *sizep = of_read_number(prop + na, ns);
Marek Vasuta6a45cd2018-10-01 12:37:20 +0200690
Simon Glass00333182019-04-25 21:58:36 -0600691 if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
Marek Vasuta6a45cd2018-10-01 12:37:20 +0200692 return of_translate_address(np, prop);
693 else
694 return of_read_number(prop, na);
Simon Glass9e512042017-05-18 20:08:58 -0600695 } else {
696 return fdtdec_get_addr_size(gd->fdt_blob,
697 ofnode_to_offset(node), property,
698 sizep);
699 }
700}
701
702const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
703 size_t sz)
704{
705 if (ofnode_is_np(node)) {
706 const struct device_node *np = ofnode_to_np(node);
707 int psize;
708 const __be32 *prop = of_get_property(np, propname, &psize);
709
710 if (!prop || sz != psize)
711 return NULL;
712 return (uint8_t *)prop;
713
714 } else {
715 return fdtdec_locate_byte_array(gd->fdt_blob,
716 ofnode_to_offset(node), propname, sz);
717 }
718}
719
720int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
721 const char *propname, struct fdt_pci_addr *addr)
722{
Masahiro Yamada8c9eaad2017-06-22 17:57:50 +0900723 const fdt32_t *cell;
Simon Glass9e512042017-05-18 20:08:58 -0600724 int len;
725 int ret = -ENOENT;
726
727 debug("%s: %s: ", __func__, propname);
728
729 /*
730 * If we follow the pci bus bindings strictly, we should check
731 * the value of the node's parent node's #address-cells and
732 * #size-cells. They need to be 3 and 2 accordingly. However,
733 * for simplicity we skip the check here.
734 */
Masahiro Yamada61e51ba2017-06-22 16:54:05 +0900735 cell = ofnode_get_property(node, propname, &len);
Simon Glass9e512042017-05-18 20:08:58 -0600736 if (!cell)
737 goto fail;
738
739 if ((len % FDT_PCI_REG_SIZE) == 0) {
740 int num = len / FDT_PCI_REG_SIZE;
741 int i;
742
743 for (i = 0; i < num; i++) {
744 debug("pci address #%d: %08lx %08lx %08lx\n", i,
745 (ulong)fdt32_to_cpu(cell[0]),
746 (ulong)fdt32_to_cpu(cell[1]),
747 (ulong)fdt32_to_cpu(cell[2]));
748 if ((fdt32_to_cpu(*cell) & type) == type) {
749 addr->phys_hi = fdt32_to_cpu(cell[0]);
750 addr->phys_mid = fdt32_to_cpu(cell[1]);
Simon Glasse5878862019-09-25 08:55:46 -0600751 addr->phys_lo = fdt32_to_cpu(cell[2]);
Simon Glass9e512042017-05-18 20:08:58 -0600752 break;
Simon Glass9e512042017-05-18 20:08:58 -0600753 }
Mario Six51db2872018-01-15 11:07:17 +0100754
755 cell += (FDT_PCI_ADDR_CELLS +
756 FDT_PCI_SIZE_CELLS);
Simon Glass9e512042017-05-18 20:08:58 -0600757 }
758
759 if (i == num) {
760 ret = -ENXIO;
761 goto fail;
762 }
763
764 return 0;
Simon Glass9e512042017-05-18 20:08:58 -0600765 }
766
Mario Six51db2872018-01-15 11:07:17 +0100767 ret = -EINVAL;
768
Simon Glass9e512042017-05-18 20:08:58 -0600769fail:
770 debug("(not found)\n");
771 return ret;
772}
773
Bin Meng7b9cbad2018-08-03 01:14:35 -0700774int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
775{
776 const char *list, *end;
777 int len;
778
779 list = ofnode_get_property(node, "compatible", &len);
780 if (!list)
781 return -ENOENT;
782
783 end = list + len;
784 while (list < end) {
785 len = strlen(list);
786 if (len >= strlen("pciVVVV,DDDD")) {
787 char *s = strstr(list, "pci");
788
789 /*
790 * check if the string is something like pciVVVV,DDDD.RR
791 * or just pciVVVV,DDDD
792 */
793 if (s && s[7] == ',' &&
794 (s[12] == '.' || s[12] == 0)) {
795 s += 3;
796 *vendor = simple_strtol(s, NULL, 16);
797
798 s += 5;
799 *device = simple_strtol(s, NULL, 16);
800
801 return 0;
802 }
803 }
804 list += (len + 1);
805 }
806
807 return -ENOENT;
808}
809
Simon Glass9e512042017-05-18 20:08:58 -0600810int ofnode_read_addr_cells(ofnode node)
811{
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +0200812 if (ofnode_is_np(node)) {
Simon Glass9e512042017-05-18 20:08:58 -0600813 return of_n_addr_cells(ofnode_to_np(node));
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +0200814 } else {
815 int parent = fdt_parent_offset(gd->fdt_blob,
816 ofnode_to_offset(node));
817
818 return fdt_address_cells(gd->fdt_blob, parent);
819 }
Simon Glass9e512042017-05-18 20:08:58 -0600820}
821
822int ofnode_read_size_cells(ofnode node)
823{
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +0200824 if (ofnode_is_np(node)) {
Simon Glass9e512042017-05-18 20:08:58 -0600825 return of_n_size_cells(ofnode_to_np(node));
Heinrich Schuchardtae6b33d2020-07-25 21:38:49 +0200826 } else {
827 int parent = fdt_parent_offset(gd->fdt_blob,
828 ofnode_to_offset(node));
829
830 return fdt_size_cells(gd->fdt_blob, parent);
831 }
Simon Glass878d68c2017-06-12 06:21:31 -0600832}
833
834int ofnode_read_simple_addr_cells(ofnode node)
835{
836 if (ofnode_is_np(node))
837 return of_simple_addr_cells(ofnode_to_np(node));
838 else
839 return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node));
840}
841
842int ofnode_read_simple_size_cells(ofnode node)
843{
844 if (ofnode_is_np(node))
845 return of_simple_size_cells(ofnode_to_np(node));
Simon Glass9e512042017-05-18 20:08:58 -0600846 else
847 return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node));
848}
849
850bool ofnode_pre_reloc(ofnode node)
851{
Patrick Delaunayc7a88da2019-02-11 12:49:57 +0100852#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
853 /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
854 * had property dm-pre-reloc or u-boot,dm-spl/tpl.
855 * They are removed in final dtb (fdtgrep 2nd pass)
856 */
857 return true;
858#else
Masahiro Yamada252510a2017-06-22 16:54:03 +0900859 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
Simon Glass9e512042017-05-18 20:08:58 -0600860 return true;
Simon Glass06f94462018-10-01 12:22:18 -0600861 if (ofnode_read_bool(node, "u-boot,dm-pre-proper"))
862 return true;
Simon Glass9e512042017-05-18 20:08:58 -0600863
Simon Glass9e512042017-05-18 20:08:58 -0600864 /*
865 * In regular builds individual spl and tpl handling both
866 * count as handled pre-relocation for later second init.
867 */
Masahiro Yamada252510a2017-06-22 16:54:03 +0900868 if (ofnode_read_bool(node, "u-boot,dm-spl") ||
869 ofnode_read_bool(node, "u-boot,dm-tpl"))
Simon Glass9e512042017-05-18 20:08:58 -0600870 return true;
Simon Glass9e512042017-05-18 20:08:58 -0600871
872 return false;
Patrick Delaunayc7a88da2019-02-11 12:49:57 +0100873#endif
Simon Glass9e512042017-05-18 20:08:58 -0600874}
Simon Glassdcf98852017-07-25 08:29:55 -0600875
876int ofnode_read_resource(ofnode node, uint index, struct resource *res)
877{
878 if (ofnode_is_np(node)) {
879 return of_address_to_resource(ofnode_to_np(node), index, res);
880 } else {
881 struct fdt_resource fres;
882 int ret;
883
884 ret = fdt_get_resource(gd->fdt_blob, ofnode_to_offset(node),
885 "reg", index, &fres);
886 if (ret < 0)
887 return -EINVAL;
888 memset(res, '\0', sizeof(*res));
889 res->start = fres.start;
890 res->end = fres.end;
891
892 return 0;
893 }
894}
Masahiro Yamada7b8b47b2017-08-26 01:12:30 +0900895
896int ofnode_read_resource_byname(ofnode node, const char *name,
897 struct resource *res)
898{
899 int index;
900
901 index = ofnode_stringlist_search(node, "reg-names", name);
902 if (index < 0)
903 return index;
904
905 return ofnode_read_resource(node, index, res);
906}
Mario Six147c6072018-01-15 11:07:19 +0100907
908u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
909{
910 if (ofnode_is_np(node))
911 return of_translate_address(ofnode_to_np(node), in_addr);
912 else
913 return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
914}
Masahiro Yamada5ccc2c22018-04-19 12:14:02 +0900915
Fabien Dessenne641067f2019-05-31 15:11:30 +0200916u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
917{
918 if (ofnode_is_np(node))
919 return of_translate_dma_address(ofnode_to_np(node), in_addr);
920 else
921 return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
922}
923
Masahiro Yamada5ccc2c22018-04-19 12:14:02 +0900924int ofnode_device_is_compatible(ofnode node, const char *compat)
925{
926 if (ofnode_is_np(node))
927 return of_device_is_compatible(ofnode_to_np(node), compat,
928 NULL, NULL);
929 else
930 return !fdt_node_check_compatible(gd->fdt_blob,
931 ofnode_to_offset(node),
932 compat);
933}
Simon Glassc60f6712018-06-11 13:07:13 -0600934
935ofnode ofnode_by_compatible(ofnode from, const char *compat)
936{
937 if (of_live_active()) {
938 return np_to_ofnode(of_find_compatible_node(
939 (struct device_node *)ofnode_to_np(from), NULL,
940 compat));
941 } else {
942 return offset_to_ofnode(fdt_node_offset_by_compatible(
943 gd->fdt_blob, ofnode_to_offset(from), compat));
944 }
945}
Jens Wiklander61fba0f2018-08-20 11:09:58 +0200946
947ofnode ofnode_by_prop_value(ofnode from, const char *propname,
948 const void *propval, int proplen)
949{
950 if (of_live_active()) {
951 return np_to_ofnode(of_find_node_by_prop_value(
952 (struct device_node *)ofnode_to_np(from), propname,
953 propval, proplen));
954 } else {
955 return offset_to_ofnode(fdt_node_offset_by_prop_value(
956 gd->fdt_blob, ofnode_to_offset(from),
957 propname, propval, proplen));
958 }
959}
Mario Sixe369e582018-06-26 08:46:48 +0200960
961int ofnode_write_prop(ofnode node, const char *propname, int len,
962 const void *value)
963{
964 const struct device_node *np = ofnode_to_np(node);
965 struct property *pp;
966 struct property *pp_last = NULL;
967 struct property *new;
968
969 if (!of_live_active())
970 return -ENOSYS;
971
972 if (!np)
973 return -EINVAL;
974
975 for (pp = np->properties; pp; pp = pp->next) {
976 if (strcmp(pp->name, propname) == 0) {
977 /* Property exists -> change value */
978 pp->value = (void *)value;
979 pp->length = len;
980 return 0;
981 }
982 pp_last = pp;
983 }
984
985 if (!pp_last)
986 return -ENOENT;
987
988 /* Property does not exist -> append new property */
989 new = malloc(sizeof(struct property));
990 if (!new)
991 return -ENOMEM;
992
993 new->name = strdup(propname);
Mario Six205dd5a2018-10-04 09:22:24 +0200994 if (!new->name) {
995 free(new);
Mario Sixe369e582018-06-26 08:46:48 +0200996 return -ENOMEM;
Mario Six205dd5a2018-10-04 09:22:24 +0200997 }
Mario Sixe369e582018-06-26 08:46:48 +0200998
999 new->value = (void *)value;
1000 new->length = len;
1001 new->next = NULL;
1002
1003 pp_last->next = new;
1004
1005 return 0;
1006}
1007
1008int ofnode_write_string(ofnode node, const char *propname, const char *value)
1009{
1010 if (!of_live_active())
1011 return -ENOSYS;
1012
1013 assert(ofnode_valid(node));
1014
1015 debug("%s: %s = %s", __func__, propname, value);
1016
1017 return ofnode_write_prop(node, propname, strlen(value) + 1, value);
1018}
1019
1020int ofnode_set_enabled(ofnode node, bool value)
1021{
1022 if (!of_live_active())
1023 return -ENOSYS;
1024
1025 assert(ofnode_valid(node));
1026
1027 if (value)
1028 return ofnode_write_string(node, "status", "okay");
1029 else
Bin Meng16351212019-07-05 09:23:17 -07001030 return ofnode_write_string(node, "status", "disabled");
Mario Sixe369e582018-06-26 08:46:48 +02001031}