Merge branch 'master' of git://git.denx.de/u-boot-rockchip
[platform/kernel/u-boot.git] / 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 static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
264                                             struct ofnode_phandle_args *out)
265 {
266         assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
267         out->node = offset_to_ofnode(in->node);
268         out->args_count = in->args_count;
269         memcpy(out->args, in->args, sizeof(out->args));
270 }
271
272 static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
273                                         struct ofnode_phandle_args *out)
274 {
275         assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
276         out->node = np_to_ofnode(in->np);
277         out->args_count = in->args_count;
278         memcpy(out->args, in->args, sizeof(out->args));
279 }
280
281 int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
282                                    const char *cells_name, int cell_count,
283                                    int index,
284                                    struct ofnode_phandle_args *out_args)
285 {
286         if (ofnode_is_np(node)) {
287                 struct of_phandle_args args;
288                 int ret;
289
290                 ret = of_parse_phandle_with_args(ofnode_to_np(node),
291                                 list_name, cells_name, index, &args);
292                 if (ret)
293                         return ret;
294                 ofnode_from_of_phandle_args(&args, out_args);
295         } else {
296                 struct fdtdec_phandle_args args;
297                 int ret;
298
299                 ret = fdtdec_parse_phandle_with_args(gd->fdt_blob,
300                                 ofnode_to_offset(node), list_name, cells_name,
301                                 cell_count, index, &args);
302                 if (ret)
303                         return ret;
304                 ofnode_from_fdtdec_phandle_args(&args, out_args);
305         }
306
307         return 0;
308 }
309
310 ofnode ofnode_path(const char *path)
311 {
312         if (of_live_active())
313                 return np_to_ofnode(of_find_node_by_path(path));
314         else
315                 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
316 }
317
318 const char *ofnode_get_chosen_prop(const char *name)
319 {
320         ofnode chosen_node;
321
322         chosen_node = ofnode_path("/chosen");
323
324         return ofnode_read_string(chosen_node, name);
325 }
326
327 ofnode ofnode_get_chosen_node(const char *name)
328 {
329         const char *prop;
330
331         prop = ofnode_get_chosen_prop(name);
332         if (!prop)
333                 return ofnode_null();
334
335         return ofnode_path(prop);
336 }
337
338 static int decode_timing_property(ofnode node, const char *name,
339                                   struct timing_entry *result)
340 {
341         int length, ret = 0;
342
343         length = ofnode_read_size(node, name);
344         if (length < 0) {
345                 debug("%s: could not find property %s\n",
346                       ofnode_get_name(node), name);
347                 return length;
348         }
349
350         if (length == sizeof(u32)) {
351                 result->typ = ofnode_read_u32_default(node, name, 0);
352                 result->min = result->typ;
353                 result->max = result->typ;
354         } else {
355                 ret = ofnode_read_u32_array(node, name, &result->min, 3);
356         }
357
358         return ret;
359 }
360
361 int ofnode_decode_display_timing(ofnode parent, int index,
362                                  struct display_timing *dt)
363 {
364         int i;
365         ofnode timings, node;
366         u32 val = 0;
367         int ret = 0;
368
369         timings = ofnode_find_subnode(parent, "display-timings");
370         if (!ofnode_valid(timings))
371                 return -EINVAL;
372
373         for (i = 0, node = ofnode_first_subnode(timings);
374              ofnode_valid(node) && i != index;
375              node = ofnode_first_subnode(node))
376                 i++;
377
378         if (!ofnode_valid(node))
379                 return -EINVAL;
380
381         memset(dt, 0, sizeof(*dt));
382
383         ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
384         ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
385         ret |= decode_timing_property(node, "hactive", &dt->hactive);
386         ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
387         ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
388         ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
389         ret |= decode_timing_property(node, "vactive", &dt->vactive);
390         ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
391         ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
392
393         dt->flags = 0;
394         val = ofnode_read_u32_default(node, "vsync-active", -1);
395         if (val != -1) {
396                 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
397                                 DISPLAY_FLAGS_VSYNC_LOW;
398         }
399         val = ofnode_read_u32_default(node, "hsync-active", -1);
400         if (val != -1) {
401                 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
402                                 DISPLAY_FLAGS_HSYNC_LOW;
403         }
404         val = ofnode_read_u32_default(node, "de-active", -1);
405         if (val != -1) {
406                 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
407                                 DISPLAY_FLAGS_DE_LOW;
408         }
409         val = ofnode_read_u32_default(node, "pixelclk-active", -1);
410         if (val != -1) {
411                 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
412                                 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
413         }
414
415         if (ofnode_read_bool(node, "interlaced"))
416                 dt->flags |= DISPLAY_FLAGS_INTERLACED;
417         if (ofnode_read_bool(node, "doublescan"))
418                 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
419         if (ofnode_read_bool(node, "doubleclk"))
420                 dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
421
422         return ret;
423 }
424
425 const u32 *ofnode_read_prop(ofnode node, const char *propname, int *lenp)
426 {
427         if (ofnode_is_np(node)) {
428                 struct property *prop;
429
430                 prop = of_find_property(ofnode_to_np(node), propname, lenp);
431                 if (!prop)
432                         return NULL;
433                 return prop->value;
434         } else {
435                 return fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
436                                    propname, lenp);
437         }
438 }
439
440 bool ofnode_is_available(ofnode node)
441 {
442         if (ofnode_is_np(node))
443                 return of_device_is_available(ofnode_to_np(node));
444         else
445                 return fdtdec_get_is_enabled(gd->fdt_blob,
446                                              ofnode_to_offset(node));
447 }
448
449 fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
450                                 fdt_size_t *sizep)
451 {
452         if (ofnode_is_np(node)) {
453                 int na, ns;
454                 int psize;
455                 const struct device_node *np = ofnode_to_np(node);
456                 const __be32 *prop = of_get_property(np, "reg", &psize);
457
458                 na = of_n_addr_cells(np);
459                 ns = of_n_addr_cells(np);
460                 *sizep = of_read_number(prop + na, ns);
461                 return of_read_number(prop, na);
462         } else {
463                 return fdtdec_get_addr_size(gd->fdt_blob,
464                                             ofnode_to_offset(node), property,
465                                             sizep);
466         }
467 }
468
469 const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
470                                         size_t sz)
471 {
472         if (ofnode_is_np(node)) {
473                 const struct device_node *np = ofnode_to_np(node);
474                 int psize;
475                 const __be32 *prop = of_get_property(np, propname, &psize);
476
477                 if (!prop || sz != psize)
478                         return NULL;
479                 return (uint8_t *)prop;
480
481         } else {
482                 return fdtdec_locate_byte_array(gd->fdt_blob,
483                                 ofnode_to_offset(node), propname, sz);
484         }
485 }
486
487 int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
488                          const char *propname, struct fdt_pci_addr *addr)
489 {
490         const u32 *cell;
491         int len;
492         int ret = -ENOENT;
493
494         debug("%s: %s: ", __func__, propname);
495
496         /*
497          * If we follow the pci bus bindings strictly, we should check
498          * the value of the node's parent node's #address-cells and
499          * #size-cells. They need to be 3 and 2 accordingly. However,
500          * for simplicity we skip the check here.
501          */
502         cell = ofnode_read_prop(node, propname, &len);
503         if (!cell)
504                 goto fail;
505
506         if ((len % FDT_PCI_REG_SIZE) == 0) {
507                 int num = len / FDT_PCI_REG_SIZE;
508                 int i;
509
510                 for (i = 0; i < num; i++) {
511                         debug("pci address #%d: %08lx %08lx %08lx\n", i,
512                               (ulong)fdt32_to_cpu(cell[0]),
513                               (ulong)fdt32_to_cpu(cell[1]),
514                               (ulong)fdt32_to_cpu(cell[2]));
515                         if ((fdt32_to_cpu(*cell) & type) == type) {
516                                 addr->phys_hi = fdt32_to_cpu(cell[0]);
517                                 addr->phys_mid = fdt32_to_cpu(cell[1]);
518                                 addr->phys_lo = fdt32_to_cpu(cell[1]);
519                                 break;
520                         } else {
521                                 cell += (FDT_PCI_ADDR_CELLS +
522                                          FDT_PCI_SIZE_CELLS);
523                         }
524                 }
525
526                 if (i == num) {
527                         ret = -ENXIO;
528                         goto fail;
529                 }
530
531                 return 0;
532         } else {
533                 ret = -EINVAL;
534         }
535
536 fail:
537         debug("(not found)\n");
538         return ret;
539 }
540
541 int ofnode_read_addr_cells(ofnode node)
542 {
543         if (ofnode_is_np(node))
544                 return of_n_addr_cells(ofnode_to_np(node));
545         else
546                 return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node));
547 }
548
549 int ofnode_read_size_cells(ofnode node)
550 {
551         if (ofnode_is_np(node))
552                 return of_n_size_cells(ofnode_to_np(node));
553         else
554                 return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node));
555 }
556
557 bool ofnode_pre_reloc(ofnode node)
558 {
559         if (ofnode_read_prop(node, "u-boot,dm-pre-reloc", NULL))
560                 return true;
561
562 #ifdef CONFIG_TPL_BUILD
563         if (ofnode_read_prop(node, "u-boot,dm-tpl", NULL))
564                 return true;
565 #elif defined(CONFIG_SPL_BUILD)
566         if (ofnode_read_prop(node, "u-boot,dm-spl", NULL))
567                 return true;
568 #else
569         /*
570          * In regular builds individual spl and tpl handling both
571          * count as handled pre-relocation for later second init.
572          */
573         if (ofnode_read_prop(node, "u-boot,dm-spl", NULL) ||
574             ofnode_read_prop(node, "u-boot,dm-tpl", NULL))
575                 return true;
576 #endif
577
578         return false;
579 }