]> git.sur5r.net Git - u-boot/blob - drivers/core/ofnode.c
79c80df7f4a03cf6d845f25b38ae648aa232e21a
[u-boot] / drivers / core / ofnode.c
1 /*
2  * Copyright (c) 2017 Google, Inc
3  * Written by Simon Glass <sjg@chromium.org>
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <dm.h>
10 #include <fdtdec.h>
11 #include <fdt_support.h>
12 #include <libfdt.h>
13 #include <dm/of_access.h>
14 #include <dm/of_addr.h>
15 #include <dm/ofnode.h>
16 #include <linux/err.h>
17
18 int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
19 {
20         assert(ofnode_valid(node));
21         debug("%s: %s: ", __func__, propname);
22
23         if (ofnode_is_np(node)) {
24                 return of_read_u32(ofnode_to_np(node), propname, outp);
25         } else {
26                 const int *cell;
27                 int len;
28
29                 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
30                                    propname, &len);
31                 if (!cell || len < sizeof(int)) {
32                         debug("(not found)\n");
33                         return -EINVAL;
34                 }
35                 *outp = fdt32_to_cpu(cell[0]);
36         }
37         debug("%#x (%d)\n", *outp, *outp);
38
39         return 0;
40 }
41
42 int ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
43 {
44         assert(ofnode_valid(node));
45         ofnode_read_u32(node, propname, &def);
46
47         return def;
48 }
49
50 int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
51 {
52         assert(ofnode_valid(node));
53         ofnode_read_u32(node, propname, (u32 *)&def);
54
55         return def;
56 }
57
58 bool ofnode_read_bool(ofnode node, const char *propname)
59 {
60         bool val;
61
62         assert(ofnode_valid(node));
63         debug("%s: %s: ", __func__, propname);
64
65         if (ofnode_is_np(node)) {
66                 val = !!of_find_property(ofnode_to_np(node), propname, NULL);
67         } else {
68                 val = !!fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
69                                     propname, NULL);
70         }
71         debug("%s\n", val ? "true" : "false");
72
73         return val;
74 }
75
76 const char *ofnode_read_string(ofnode node, const char *propname)
77 {
78         const char *str = NULL;
79         int len = -1;
80
81         assert(ofnode_valid(node));
82         debug("%s: %s: ", __func__, propname);
83
84         if (ofnode_is_np(node)) {
85                 struct property *prop = of_find_property(
86                                 ofnode_to_np(node), propname, NULL);
87
88                 if (prop) {
89                         str = prop->value;
90                         len = prop->length;
91                 }
92         } else {
93                 str = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
94                                   propname, &len);
95         }
96         if (!str) {
97                 debug("<not found>\n");
98                 return NULL;
99         }
100         if (strnlen(str, len) >= len) {
101                 debug("<invalid>\n");
102                 return NULL;
103         }
104         debug("%s\n", str);
105
106         return str;
107 }
108
109 ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
110 {
111         ofnode subnode;
112
113         assert(ofnode_valid(node));
114         debug("%s: %s: ", __func__, subnode_name);
115
116         if (ofnode_is_np(node)) {
117                 const struct device_node *np = ofnode_to_np(node);
118
119                 for (np = np->child; np; np = np->sibling) {
120                         if (!strcmp(subnode_name, np->name))
121                                 break;
122                 }
123                 subnode = np_to_ofnode(np);
124         } else {
125                 int ooffset = fdt_subnode_offset(gd->fdt_blob,
126                                 ofnode_to_offset(node), subnode_name);
127                 subnode = offset_to_ofnode(ooffset);
128         }
129         debug("%s\n", ofnode_valid(subnode) ?
130               ofnode_get_name(subnode) : "<none>");
131
132         return subnode;
133 }
134
135 int ofnode_read_u32_array(ofnode node, const char *propname,
136                           u32 *out_values, size_t sz)
137 {
138         assert(ofnode_valid(node));
139         debug("%s: %s: ", __func__, propname);
140
141         if (ofnode_is_np(node)) {
142                 return of_read_u32_array(ofnode_to_np(node), propname,
143                                          out_values, sz);
144         } else {
145                 return fdtdec_get_int_array(gd->fdt_blob,
146                                             ofnode_to_offset(node), propname,
147                                             out_values, sz);
148         }
149 }
150
151 ofnode ofnode_first_subnode(ofnode node)
152 {
153         assert(ofnode_valid(node));
154         if (ofnode_is_np(node))
155                 return np_to_ofnode(node.np->child);
156
157         return offset_to_ofnode(
158                 fdt_first_subnode(gd->fdt_blob, ofnode_to_offset(node)));
159 }
160
161 ofnode ofnode_next_subnode(ofnode node)
162 {
163         assert(ofnode_valid(node));
164         if (ofnode_is_np(node))
165                 return np_to_ofnode(node.np->sibling);
166
167         return offset_to_ofnode(
168                 fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node)));
169 }
170
171 const char *ofnode_get_name(ofnode node)
172 {
173         assert(ofnode_valid(node));
174         if (ofnode_is_np(node))
175                 return strrchr(node.np->full_name, '/') + 1;
176
177         return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL);
178 }
179
180 int ofnode_read_size(ofnode node, const char *propname)
181 {
182         int len;
183
184         if (ofnode_is_np(node)) {
185                 struct property *prop = of_find_property(
186                                 ofnode_to_np(node), propname, NULL);
187
188                 if (prop)
189                         return prop->length;
190         } else {
191                 if (fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
192                                 &len))
193                         return len;
194         }
195
196         return -EINVAL;
197 }
198
199 fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
200 {
201         if (ofnode_is_np(node)) {
202                 const __be32 *prop_val;
203                 uint flags;
204                 u64 size;
205
206                 prop_val = of_get_address(
207                         (struct device_node *)ofnode_to_np(node), index,
208                         &size, &flags);
209                 if (!prop_val)
210                         return FDT_ADDR_T_NONE;
211                 return  be32_to_cpup(prop_val);
212         } else {
213                 return fdt_get_base_address(gd->fdt_blob,
214                                             ofnode_to_offset(node));
215         }
216
217         return FDT_ADDR_T_NONE;
218 }
219
220 fdt_addr_t ofnode_get_addr(ofnode node)
221 {
222         return ofnode_get_addr_index(node, 0);
223 }
224
225 int ofnode_stringlist_search(ofnode node, const char *property,
226                              const char *string)
227 {
228         if (ofnode_is_np(node)) {
229                 return of_property_match_string(ofnode_to_np(node),
230                                                 property, string);
231         } else {
232                 int ret;
233
234                 ret = fdt_stringlist_search(gd->fdt_blob,
235                                             ofnode_to_offset(node), property,
236                                             string);
237                 if (ret == -FDT_ERR_NOTFOUND)
238                         return -ENODATA;
239                 else if (ret < 0)
240                         return -EINVAL;
241
242                 return ret;
243         }
244 }
245
246 int ofnode_read_string_index(ofnode node, const char *property, int index,
247                              const char **outp)
248 {
249         if (ofnode_is_np(node)) {
250                 return of_property_read_string_index(ofnode_to_np(node),
251                                                      property, index, outp);
252         } else {
253                 int len;
254
255                 *outp = fdt_stringlist_get(gd->fdt_blob, ofnode_to_offset(node),
256                                            property, index, &len);
257                 if (len < 0)
258                         return -EINVAL;
259                 return 0;
260         }
261 }
262
263 int ofnode_read_string_count(ofnode node, const char *property)
264 {
265         if (ofnode_is_np(node)) {
266                 return of_property_count_strings(ofnode_to_np(node), property);
267         } else {
268                 return fdt_stringlist_count(gd->fdt_blob,
269                                             ofnode_to_offset(node), property);
270         }
271 }
272
273 static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
274                                             struct ofnode_phandle_args *out)
275 {
276         assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
277         out->node = offset_to_ofnode(in->node);
278         out->args_count = in->args_count;
279         memcpy(out->args, in->args, sizeof(out->args));
280 }
281
282 static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
283                                         struct ofnode_phandle_args *out)
284 {
285         assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
286         out->node = np_to_ofnode(in->np);
287         out->args_count = in->args_count;
288         memcpy(out->args, in->args, sizeof(out->args));
289 }
290
291 int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
292                                    const char *cells_name, int cell_count,
293                                    int index,
294                                    struct ofnode_phandle_args *out_args)
295 {
296         if (ofnode_is_np(node)) {
297                 struct of_phandle_args args;
298                 int ret;
299
300                 ret = of_parse_phandle_with_args(ofnode_to_np(node),
301                                 list_name, cells_name, index, &args);
302                 if (ret)
303                         return ret;
304                 ofnode_from_of_phandle_args(&args, out_args);
305         } else {
306                 struct fdtdec_phandle_args args;
307                 int ret;
308
309                 ret = fdtdec_parse_phandle_with_args(gd->fdt_blob,
310                                 ofnode_to_offset(node), list_name, cells_name,
311                                 cell_count, index, &args);
312                 if (ret)
313                         return ret;
314                 ofnode_from_fdtdec_phandle_args(&args, out_args);
315         }
316
317         return 0;
318 }
319
320 ofnode ofnode_path(const char *path)
321 {
322         if (of_live_active())
323                 return np_to_ofnode(of_find_node_by_path(path));
324         else
325                 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
326 }
327
328 const char *ofnode_get_chosen_prop(const char *name)
329 {
330         ofnode chosen_node;
331
332         chosen_node = ofnode_path("/chosen");
333
334         return ofnode_read_string(chosen_node, name);
335 }
336
337 ofnode ofnode_get_chosen_node(const char *name)
338 {
339         const char *prop;
340
341         prop = ofnode_get_chosen_prop(name);
342         if (!prop)
343                 return ofnode_null();
344
345         return ofnode_path(prop);
346 }
347
348 static int decode_timing_property(ofnode node, const char *name,
349                                   struct timing_entry *result)
350 {
351         int length, ret = 0;
352
353         length = ofnode_read_size(node, name);
354         if (length < 0) {
355                 debug("%s: could not find property %s\n",
356                       ofnode_get_name(node), name);
357                 return length;
358         }
359
360         if (length == sizeof(u32)) {
361                 result->typ = ofnode_read_u32_default(node, name, 0);
362                 result->min = result->typ;
363                 result->max = result->typ;
364         } else {
365                 ret = ofnode_read_u32_array(node, name, &result->min, 3);
366         }
367
368         return ret;
369 }
370
371 int ofnode_decode_display_timing(ofnode parent, int index,
372                                  struct display_timing *dt)
373 {
374         int i;
375         ofnode timings, node;
376         u32 val = 0;
377         int ret = 0;
378
379         timings = ofnode_find_subnode(parent, "display-timings");
380         if (!ofnode_valid(timings))
381                 return -EINVAL;
382
383         for (i = 0, node = ofnode_first_subnode(timings);
384              ofnode_valid(node) && i != index;
385              node = ofnode_first_subnode(node))
386                 i++;
387
388         if (!ofnode_valid(node))
389                 return -EINVAL;
390
391         memset(dt, 0, sizeof(*dt));
392
393         ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
394         ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
395         ret |= decode_timing_property(node, "hactive", &dt->hactive);
396         ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
397         ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
398         ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
399         ret |= decode_timing_property(node, "vactive", &dt->vactive);
400         ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
401         ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
402
403         dt->flags = 0;
404         val = ofnode_read_u32_default(node, "vsync-active", -1);
405         if (val != -1) {
406                 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
407                                 DISPLAY_FLAGS_VSYNC_LOW;
408         }
409         val = ofnode_read_u32_default(node, "hsync-active", -1);
410         if (val != -1) {
411                 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
412                                 DISPLAY_FLAGS_HSYNC_LOW;
413         }
414         val = ofnode_read_u32_default(node, "de-active", -1);
415         if (val != -1) {
416                 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
417                                 DISPLAY_FLAGS_DE_LOW;
418         }
419         val = ofnode_read_u32_default(node, "pixelclk-active", -1);
420         if (val != -1) {
421                 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
422                                 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
423         }
424
425         if (ofnode_read_bool(node, "interlaced"))
426                 dt->flags |= DISPLAY_FLAGS_INTERLACED;
427         if (ofnode_read_bool(node, "doublescan"))
428                 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
429         if (ofnode_read_bool(node, "doubleclk"))
430                 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
431
432         return ret;
433 }
434
435 const u32 *ofnode_read_prop(ofnode node, const char *propname, int *lenp)
436 {
437         if (ofnode_is_np(node)) {
438                 struct property *prop;
439
440                 prop = of_find_property(ofnode_to_np(node), propname, lenp);
441                 if (!prop)
442                         return NULL;
443                 return prop->value;
444         } else {
445                 return fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
446                                    propname, lenp);
447         }
448 }
449
450 bool ofnode_is_available(ofnode node)
451 {
452         if (ofnode_is_np(node))
453                 return of_device_is_available(ofnode_to_np(node));
454         else
455                 return fdtdec_get_is_enabled(gd->fdt_blob,
456                                              ofnode_to_offset(node));
457 }
458
459 fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
460                                 fdt_size_t *sizep)
461 {
462         if (ofnode_is_np(node)) {
463                 int na, ns;
464                 int psize;
465                 const struct device_node *np = ofnode_to_np(node);
466                 const __be32 *prop = of_get_property(np, "reg", &psize);
467
468                 na = of_n_addr_cells(np);
469                 ns = of_n_addr_cells(np);
470                 *sizep = of_read_number(prop + na, ns);
471                 return of_read_number(prop, na);
472         } else {
473                 return fdtdec_get_addr_size(gd->fdt_blob,
474                                             ofnode_to_offset(node), property,
475                                             sizep);
476         }
477 }
478
479 const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
480                                         size_t sz)
481 {
482         if (ofnode_is_np(node)) {
483                 const struct device_node *np = ofnode_to_np(node);
484                 int psize;
485                 const __be32 *prop = of_get_property(np, propname, &psize);
486
487                 if (!prop || sz != psize)
488                         return NULL;
489                 return (uint8_t *)prop;
490
491         } else {
492                 return fdtdec_locate_byte_array(gd->fdt_blob,
493                                 ofnode_to_offset(node), propname, sz);
494         }
495 }
496
497 int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
498                          const char *propname, struct fdt_pci_addr *addr)
499 {
500         const u32 *cell;
501         int len;
502         int ret = -ENOENT;
503
504         debug("%s: %s: ", __func__, propname);
505
506         /*
507          * If we follow the pci bus bindings strictly, we should check
508          * the value of the node's parent node's #address-cells and
509          * #size-cells. They need to be 3 and 2 accordingly. However,
510          * for simplicity we skip the check here.
511          */
512         cell = ofnode_read_prop(node, propname, &len);
513         if (!cell)
514                 goto fail;
515
516         if ((len % FDT_PCI_REG_SIZE) == 0) {
517                 int num = len / FDT_PCI_REG_SIZE;
518                 int i;
519
520                 for (i = 0; i < num; i++) {
521                         debug("pci address #%d: %08lx %08lx %08lx\n", i,
522                               (ulong)fdt32_to_cpu(cell[0]),
523                               (ulong)fdt32_to_cpu(cell[1]),
524                               (ulong)fdt32_to_cpu(cell[2]));
525                         if ((fdt32_to_cpu(*cell) & type) == type) {
526                                 addr->phys_hi = fdt32_to_cpu(cell[0]);
527                                 addr->phys_mid = fdt32_to_cpu(cell[1]);
528                                 addr->phys_lo = fdt32_to_cpu(cell[1]);
529                                 break;
530                         } else {
531                                 cell += (FDT_PCI_ADDR_CELLS +
532                                          FDT_PCI_SIZE_CELLS);
533                         }
534                 }
535
536                 if (i == num) {
537                         ret = -ENXIO;
538                         goto fail;
539                 }
540
541                 return 0;
542         } else {
543                 ret = -EINVAL;
544         }
545
546 fail:
547         debug("(not found)\n");
548         return ret;
549 }
550
551 int ofnode_read_addr_cells(ofnode node)
552 {
553         if (ofnode_is_np(node))
554                 return of_n_addr_cells(ofnode_to_np(node));
555         else
556                 return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node));
557 }
558
559 int ofnode_read_size_cells(ofnode node)
560 {
561         if (ofnode_is_np(node))
562                 return of_n_size_cells(ofnode_to_np(node));
563         else
564                 return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node));
565 }
566
567 bool ofnode_pre_reloc(ofnode node)
568 {
569         if (ofnode_read_prop(node, "u-boot,dm-pre-reloc", NULL))
570                 return true;
571
572 #ifdef CONFIG_TPL_BUILD
573         if (ofnode_read_prop(node, "u-boot,dm-tpl", NULL))
574                 return true;
575 #elif defined(CONFIG_SPL_BUILD)
576         if (ofnode_read_prop(node, "u-boot,dm-spl", NULL))
577                 return true;
578 #else
579         /*
580          * In regular builds individual spl and tpl handling both
581          * count as handled pre-relocation for later second init.
582          */
583         if (ofnode_read_prop(node, "u-boot,dm-spl", NULL) ||
584             ofnode_read_prop(node, "u-boot,dm-tpl", NULL))
585                 return true;
586 #endif
587
588         return false;
589 }