]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - lib/fdtdec.c
Merge branch 'u-boot-tegra/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / lib / fdtdec.c
1 /*
2  * Copyright (c) 2011 The Chromium OS Authors.
3  * See file CREDITS for list of people who contributed to this
4  * project.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19  * MA 02111-1307 USA
20  */
21
22 #include <common.h>
23 #include <serial.h>
24 #include <libfdt.h>
25 #include <fdtdec.h>
26
27 #include <asm/gpio.h>
28
29 DECLARE_GLOBAL_DATA_PTR;
30
31 /*
32  * Here are the type we know about. One day we might allow drivers to
33  * register. For now we just put them here. The COMPAT macro allows us to
34  * turn this into a sparse list later, and keeps the ID with the name.
35  */
36 #define COMPAT(id, name) name
37 static const char * const compat_names[COMPAT_COUNT] = {
38         COMPAT(UNKNOWN, "<none>"),
39         COMPAT(NVIDIA_TEGRA20_USB, "nvidia,tegra20-ehci"),
40         COMPAT(NVIDIA_TEGRA114_I2C, "nvidia,tegra114-i2c"),
41         COMPAT(NVIDIA_TEGRA20_I2C, "nvidia,tegra20-i2c"),
42         COMPAT(NVIDIA_TEGRA20_DVC, "nvidia,tegra20-i2c-dvc"),
43         COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"),
44         COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"),
45         COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"),
46         COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"),
47         COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"),
48         COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"),
49         COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"),
50         COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
51         COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
52         COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"),
53         COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"),
54         COMPAT(SMSC_LAN9215, "smsc,lan9215"),
55         COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"),
56         COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"),
57         COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"),
58         COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),
59         COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"),
60         COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
61         COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
62         COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
63         COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
64         COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"),
65 };
66
67 const char *fdtdec_get_compatible(enum fdt_compat_id id)
68 {
69         /* We allow reading of the 'unknown' ID for testing purposes */
70         assert(id >= 0 && id < COMPAT_COUNT);
71         return compat_names[id];
72 }
73
74 fdt_addr_t fdtdec_get_addr(const void *blob, int node,
75                 const char *prop_name)
76 {
77         const fdt_addr_t *cell;
78         int len;
79
80         debug("%s: %s: ", __func__, prop_name);
81         cell = fdt_getprop(blob, node, prop_name, &len);
82         if (cell && (len == sizeof(fdt_addr_t) ||
83                         len == sizeof(fdt_addr_t) * 2)) {
84                 fdt_addr_t addr = fdt_addr_to_cpu(*cell);
85
86                 debug("%p\n", (void *)addr);
87                 return addr;
88         }
89         debug("(not found)\n");
90         return FDT_ADDR_T_NONE;
91 }
92
93 s32 fdtdec_get_int(const void *blob, int node, const char *prop_name,
94                 s32 default_val)
95 {
96         const s32 *cell;
97         int len;
98
99         debug("%s: %s: ", __func__, prop_name);
100         cell = fdt_getprop(blob, node, prop_name, &len);
101         if (cell && len >= sizeof(s32)) {
102                 s32 val = fdt32_to_cpu(cell[0]);
103
104                 debug("%#x (%d)\n", val, val);
105                 return val;
106         }
107         debug("(not found)\n");
108         return default_val;
109 }
110
111 uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
112                 uint64_t default_val)
113 {
114         const uint64_t *cell64;
115         int length;
116
117         cell64 = fdt_getprop(blob, node, prop_name, &length);
118         if (!cell64 || length < sizeof(*cell64))
119                 return default_val;
120
121         return fdt64_to_cpu(*cell64);
122 }
123
124 int fdtdec_get_is_enabled(const void *blob, int node)
125 {
126         const char *cell;
127
128         /*
129          * It should say "okay", so only allow that. Some fdts use "ok" but
130          * this is a bug. Please fix your device tree source file. See here
131          * for discussion:
132          *
133          * http://www.mail-archive.com/u-boot@lists.denx.de/msg71598.html
134          */
135         cell = fdt_getprop(blob, node, "status", NULL);
136         if (cell)
137                 return 0 == strcmp(cell, "okay");
138         return 1;
139 }
140
141 enum fdt_compat_id fdtdec_lookup(const void *blob, int node)
142 {
143         enum fdt_compat_id id;
144
145         /* Search our drivers */
146         for (id = COMPAT_UNKNOWN; id < COMPAT_COUNT; id++)
147                 if (0 == fdt_node_check_compatible(blob, node,
148                                 compat_names[id]))
149                         return id;
150         return COMPAT_UNKNOWN;
151 }
152
153 int fdtdec_next_compatible(const void *blob, int node,
154                 enum fdt_compat_id id)
155 {
156         return fdt_node_offset_by_compatible(blob, node, compat_names[id]);
157 }
158
159 int fdtdec_next_compatible_subnode(const void *blob, int node,
160                 enum fdt_compat_id id, int *depthp)
161 {
162         do {
163                 node = fdt_next_node(blob, node, depthp);
164         } while (*depthp > 1);
165
166         /* If this is a direct subnode, and compatible, return it */
167         if (*depthp == 1 && 0 == fdt_node_check_compatible(
168                                                 blob, node, compat_names[id]))
169                 return node;
170
171         return -FDT_ERR_NOTFOUND;
172 }
173
174 int fdtdec_next_alias(const void *blob, const char *name,
175                 enum fdt_compat_id id, int *upto)
176 {
177 #define MAX_STR_LEN 20
178         char str[MAX_STR_LEN + 20];
179         int node, err;
180
181         /* snprintf() is not available */
182         assert(strlen(name) < MAX_STR_LEN);
183         sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto);
184         node = fdt_path_offset(blob, str);
185         if (node < 0)
186                 return node;
187         err = fdt_node_check_compatible(blob, node, compat_names[id]);
188         if (err < 0)
189                 return err;
190         if (err)
191                 return -FDT_ERR_NOTFOUND;
192         (*upto)++;
193         return node;
194 }
195
196 int fdtdec_find_aliases_for_id(const void *blob, const char *name,
197                         enum fdt_compat_id id, int *node_list, int maxcount)
198 {
199         memset(node_list, '\0', sizeof(*node_list) * maxcount);
200
201         return fdtdec_add_aliases_for_id(blob, name, id, node_list, maxcount);
202 }
203
204 /* TODO: Can we tighten this code up a little? */
205 int fdtdec_add_aliases_for_id(const void *blob, const char *name,
206                         enum fdt_compat_id id, int *node_list, int maxcount)
207 {
208         int name_len = strlen(name);
209         int nodes[maxcount];
210         int num_found = 0;
211         int offset, node;
212         int alias_node;
213         int count;
214         int i, j;
215
216         /* find the alias node if present */
217         alias_node = fdt_path_offset(blob, "/aliases");
218
219         /*
220          * start with nothing, and we can assume that the root node can't
221          * match
222          */
223         memset(nodes, '\0', sizeof(nodes));
224
225         /* First find all the compatible nodes */
226         for (node = count = 0; node >= 0 && count < maxcount;) {
227                 node = fdtdec_next_compatible(blob, node, id);
228                 if (node >= 0)
229                         nodes[count++] = node;
230         }
231         if (node >= 0)
232                 debug("%s: warning: maxcount exceeded with alias '%s'\n",
233                        __func__, name);
234
235         /* Now find all the aliases */
236         for (offset = fdt_first_property_offset(blob, alias_node);
237                         offset > 0;
238                         offset = fdt_next_property_offset(blob, offset)) {
239                 const struct fdt_property *prop;
240                 const char *path;
241                 int number;
242                 int found;
243
244                 node = 0;
245                 prop = fdt_get_property_by_offset(blob, offset, NULL);
246                 path = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
247                 if (prop->len && 0 == strncmp(path, name, name_len))
248                         node = fdt_path_offset(blob, prop->data);
249                 if (node <= 0)
250                         continue;
251
252                 /* Get the alias number */
253                 number = simple_strtoul(path + name_len, NULL, 10);
254                 if (number < 0 || number >= maxcount) {
255                         debug("%s: warning: alias '%s' is out of range\n",
256                                __func__, path);
257                         continue;
258                 }
259
260                 /* Make sure the node we found is actually in our list! */
261                 found = -1;
262                 for (j = 0; j < count; j++)
263                         if (nodes[j] == node) {
264                                 found = j;
265                                 break;
266                         }
267
268                 if (found == -1) {
269                         debug("%s: warning: alias '%s' points to a node "
270                                 "'%s' that is missing or is not compatible "
271                                 " with '%s'\n", __func__, path,
272                                 fdt_get_name(blob, node, NULL),
273                                compat_names[id]);
274                         continue;
275                 }
276
277                 /*
278                  * Add this node to our list in the right place, and mark
279                  * it as done.
280                  */
281                 if (fdtdec_get_is_enabled(blob, node)) {
282                         if (node_list[number]) {
283                                 debug("%s: warning: alias '%s' requires that "
284                                       "a node be placed in the list in a "
285                                       "position which is already filled by "
286                                       "node '%s'\n", __func__, path,
287                                       fdt_get_name(blob, node, NULL));
288                                 continue;
289                         }
290                         node_list[number] = node;
291                         if (number >= num_found)
292                                 num_found = number + 1;
293                 }
294                 nodes[found] = 0;
295         }
296
297         /* Add any nodes not mentioned by an alias */
298         for (i = j = 0; i < maxcount; i++) {
299                 if (!node_list[i]) {
300                         for (; j < maxcount; j++)
301                                 if (nodes[j] &&
302                                         fdtdec_get_is_enabled(blob, nodes[j]))
303                                         break;
304
305                         /* Have we run out of nodes to add? */
306                         if (j == maxcount)
307                                 break;
308
309                         assert(!node_list[i]);
310                         node_list[i] = nodes[j++];
311                         if (i >= num_found)
312                                 num_found = i + 1;
313                 }
314         }
315
316         return num_found;
317 }
318
319 int fdtdec_check_fdt(void)
320 {
321         /*
322          * We must have an FDT, but we cannot panic() yet since the console
323          * is not ready. So for now, just assert(). Boards which need an early
324          * FDT (prior to console ready) will need to make their own
325          * arrangements and do their own checks.
326          */
327         assert(!fdtdec_prepare_fdt());
328         return 0;
329 }
330
331 /*
332  * This function is a little odd in that it accesses global data. At some
333  * point if the architecture board.c files merge this will make more sense.
334  * Even now, it is common code.
335  */
336 int fdtdec_prepare_fdt(void)
337 {
338         if (((uintptr_t)gd->fdt_blob & 3) || fdt_check_header(gd->fdt_blob)) {
339                 printf("No valid FDT found - please append one to U-Boot "
340                         "binary, use u-boot-dtb.bin or define "
341                         "CONFIG_OF_EMBED\n");
342                 return -1;
343         }
344         return 0;
345 }
346
347 int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name)
348 {
349         const u32 *phandle;
350         int lookup;
351
352         debug("%s: %s\n", __func__, prop_name);
353         phandle = fdt_getprop(blob, node, prop_name, NULL);
354         if (!phandle)
355                 return -FDT_ERR_NOTFOUND;
356
357         lookup = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*phandle));
358         return lookup;
359 }
360
361 /**
362  * Look up a property in a node and check that it has a minimum length.
363  *
364  * @param blob          FDT blob
365  * @param node          node to examine
366  * @param prop_name     name of property to find
367  * @param min_len       minimum property length in bytes
368  * @param err           0 if ok, or -FDT_ERR_NOTFOUND if the property is not
369                         found, or -FDT_ERR_BADLAYOUT if not enough data
370  * @return pointer to cell, which is only valid if err == 0
371  */
372 static const void *get_prop_check_min_len(const void *blob, int node,
373                 const char *prop_name, int min_len, int *err)
374 {
375         const void *cell;
376         int len;
377
378         debug("%s: %s\n", __func__, prop_name);
379         cell = fdt_getprop(blob, node, prop_name, &len);
380         if (!cell)
381                 *err = -FDT_ERR_NOTFOUND;
382         else if (len < min_len)
383                 *err = -FDT_ERR_BADLAYOUT;
384         else
385                 *err = 0;
386         return cell;
387 }
388
389 int fdtdec_get_int_array(const void *blob, int node, const char *prop_name,
390                 u32 *array, int count)
391 {
392         const u32 *cell;
393         int i, err = 0;
394
395         debug("%s: %s\n", __func__, prop_name);
396         cell = get_prop_check_min_len(blob, node, prop_name,
397                                       sizeof(u32) * count, &err);
398         if (!err) {
399                 for (i = 0; i < count; i++)
400                         array[i] = fdt32_to_cpu(cell[i]);
401         }
402         return err;
403 }
404
405 const u32 *fdtdec_locate_array(const void *blob, int node,
406                                const char *prop_name, int count)
407 {
408         const u32 *cell;
409         int err;
410
411         cell = get_prop_check_min_len(blob, node, prop_name,
412                                       sizeof(u32) * count, &err);
413         return err ? NULL : cell;
414 }
415
416 int fdtdec_get_bool(const void *blob, int node, const char *prop_name)
417 {
418         const s32 *cell;
419         int len;
420
421         debug("%s: %s\n", __func__, prop_name);
422         cell = fdt_getprop(blob, node, prop_name, &len);
423         return cell != NULL;
424 }
425
426 /**
427  * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no
428  * terminating item.
429  *
430  * @param blob          FDT blob to use
431  * @param node          Node to look at
432  * @param prop_name     Node property name
433  * @param gpio          Array of gpio elements to fill from FDT. This will be
434  *                      untouched if either 0 or an error is returned
435  * @param max_count     Maximum number of elements allowed
436  * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would
437  * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing.
438  */
439 int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name,
440                 struct fdt_gpio_state *gpio, int max_count)
441 {
442         const struct fdt_property *prop;
443         const u32 *cell;
444         const char *name;
445         int len, i;
446
447         debug("%s: %s\n", __func__, prop_name);
448         assert(max_count > 0);
449         prop = fdt_get_property(blob, node, prop_name, &len);
450         if (!prop) {
451                 debug("%s: property '%s' missing\n", __func__, prop_name);
452                 return -FDT_ERR_NOTFOUND;
453         }
454
455         /* We will use the name to tag the GPIO */
456         name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
457         cell = (u32 *)prop->data;
458         len /= sizeof(u32) * 3;         /* 3 cells per GPIO record */
459         if (len > max_count) {
460                 debug(" %s: too many GPIOs / cells for "
461                         "property '%s'\n", __func__, prop_name);
462                 return -FDT_ERR_BADLAYOUT;
463         }
464
465         /* Read out the GPIO data from the cells */
466         for (i = 0; i < len; i++, cell += 3) {
467                 gpio[i].gpio = fdt32_to_cpu(cell[1]);
468                 gpio[i].flags = fdt32_to_cpu(cell[2]);
469                 gpio[i].name = name;
470         }
471
472         return len;
473 }
474
475 int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name,
476                 struct fdt_gpio_state *gpio)
477 {
478         int err;
479
480         debug("%s: %s\n", __func__, prop_name);
481         gpio->gpio = FDT_GPIO_NONE;
482         gpio->name = NULL;
483         err = fdtdec_decode_gpios(blob, node, prop_name, gpio, 1);
484         return err == 1 ? 0 : err;
485 }
486
487 int fdtdec_get_gpio(struct fdt_gpio_state *gpio)
488 {
489         int val;
490
491         if (!fdt_gpio_isvalid(gpio))
492                 return -1;
493
494         val = gpio_get_value(gpio->gpio);
495         return gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val;
496 }
497
498 int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val)
499 {
500         if (!fdt_gpio_isvalid(gpio))
501                 return -1;
502
503         val = gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val;
504         return gpio_set_value(gpio->gpio, val);
505 }
506
507 int fdtdec_setup_gpio(struct fdt_gpio_state *gpio)
508 {
509         /*
510          * Return success if there is no GPIO defined. This is used for
511          * optional GPIOs)
512          */
513         if (!fdt_gpio_isvalid(gpio))
514                 return 0;
515
516         if (gpio_request(gpio->gpio, gpio->name))
517                 return -1;
518         return 0;
519 }
520
521 int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name,
522                 u8 *array, int count)
523 {
524         const u8 *cell;
525         int err;
526
527         cell = get_prop_check_min_len(blob, node, prop_name, count, &err);
528         if (!err)
529                 memcpy(array, cell, count);
530         return err;
531 }
532
533 const u8 *fdtdec_locate_byte_array(const void *blob, int node,
534                              const char *prop_name, int count)
535 {
536         const u8 *cell;
537         int err;
538
539         cell = get_prop_check_min_len(blob, node, prop_name, count, &err);
540         if (err)
541                 return NULL;
542         return cell;
543 }
544
545 int fdtdec_get_config_int(const void *blob, const char *prop_name,
546                 int default_val)
547 {
548         int config_node;
549
550         debug("%s: %s\n", __func__, prop_name);
551         config_node = fdt_path_offset(blob, "/config");
552         if (config_node < 0)
553                 return default_val;
554         return fdtdec_get_int(blob, config_node, prop_name, default_val);
555 }
556
557 int fdtdec_get_config_bool(const void *blob, const char *prop_name)
558 {
559         int config_node;
560         const void *prop;
561
562         debug("%s: %s\n", __func__, prop_name);
563         config_node = fdt_path_offset(blob, "/config");
564         if (config_node < 0)
565                 return 0;
566         prop = fdt_get_property(blob, config_node, prop_name, NULL);
567
568         return prop != NULL;
569 }
570
571 char *fdtdec_get_config_string(const void *blob, const char *prop_name)
572 {
573         const char *nodep;
574         int nodeoffset;
575         int len;
576
577         debug("%s: %s\n", __func__, prop_name);
578         nodeoffset = fdt_path_offset(blob, "/config");
579         if (nodeoffset < 0)
580                 return NULL;
581
582         nodep = fdt_getprop(blob, nodeoffset, prop_name, &len);
583         if (!nodep)
584                 return NULL;
585
586         return (char *)nodep;
587 }
588
589 int fdtdec_decode_region(const void *blob, int node,
590                 const char *prop_name, void **ptrp, size_t *size)
591 {
592         const fdt_addr_t *cell;
593         int len;
594
595         debug("%s: %s\n", __func__, prop_name);
596         cell = fdt_getprop(blob, node, prop_name, &len);
597         if (!cell || (len != sizeof(fdt_addr_t) * 2))
598                 return -1;
599
600         *ptrp = (void *)fdt_addr_to_cpu(*cell);
601         *size = fdt_size_to_cpu(cell[1]);
602         debug("%s: size=%zx\n", __func__, *size);
603         return 0;
604 }