]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - lib/fdtdec.c
Merge branch 'master' of git://www.denx.de/git/u-boot-imx
[karo-tx-uboot.git] / lib / fdtdec.c
index 13d3d2f522f177fc994e7be91d859858d32e3d9c..9d86dba32944ccdca97d35cfa02305f1de2508c3 100644 (file)
@@ -5,9 +5,11 @@
 
 #ifndef USE_HOSTCC
 #include <common.h>
+#include <errno.h>
 #include <serial.h>
 #include <libfdt.h>
 #include <fdtdec.h>
+#include <linux/ctype.h>
 
 #include <asm/gpio.h>
 
@@ -68,6 +70,14 @@ static const char * const compat_names[COMPAT_COUNT] = {
        COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"),
        COMPAT(TI_TPS65090, "ti,tps65090"),
        COMPAT(COMPAT_NXP_PTN3460, "nxp,ptn3460"),
+       COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"),
+       COMPAT(PARADE_PS8625, "parade,ps8625"),
+       COMPAT(COMPAT_INTEL_LPC, "intel,lpc"),
+       COMPAT(INTEL_MICROCODE, "intel,microcode"),
+       COMPAT(MEMORY_SPD, "memory-spd"),
+       COMPAT(INTEL_PANTHERPOINT_AHCI, "intel,pantherpoint-ahci"),
+       COMPAT(INTEL_MODEL_206AX, "intel,model-206ax"),
+       COMPAT(INTEL_GMA, "intel,gma"),
 };
 
 const char *fdtdec_get_compatible(enum fdt_compat_id id)
@@ -111,24 +121,6 @@ fdt_addr_t fdtdec_get_addr(const void *blob, int node,
        return fdtdec_get_addr_size(blob, node, prop_name, NULL);
 }
 
-s32 fdtdec_get_int(const void *blob, int node, const char *prop_name,
-               s32 default_val)
-{
-       const s32 *cell;
-       int len;
-
-       debug("%s: %s: ", __func__, prop_name);
-       cell = fdt_getprop(blob, node, prop_name, &len);
-       if (cell && len >= sizeof(s32)) {
-               s32 val = fdt32_to_cpu(cell[0]);
-
-               debug("%#x (%d)\n", val, val);
-               return val;
-       }
-       debug("(not found)\n");
-       return default_val;
-}
-
 uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
                uint64_t default_val)
 {
@@ -337,6 +329,65 @@ int fdtdec_add_aliases_for_id(const void *blob, const char *name,
        return num_found;
 }
 
+int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
+                        int *seqp)
+{
+       int base_len = strlen(base);
+       const char *find_name;
+       int find_namelen;
+       int prop_offset;
+       int aliases;
+
+       find_name = fdt_get_name(blob, offset, &find_namelen);
+       debug("Looking for '%s' at %d, name %s\n", base, offset, find_name);
+
+       aliases = fdt_path_offset(blob, "/aliases");
+       for (prop_offset = fdt_first_property_offset(blob, aliases);
+            prop_offset > 0;
+            prop_offset = fdt_next_property_offset(blob, prop_offset)) {
+               const char *prop;
+               const char *name;
+               const char *slash;
+               const char *p;
+               int len;
+
+               prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len);
+               debug("   - %s, %s\n", name, prop);
+               if (len < find_namelen || *prop != '/' || prop[len - 1] ||
+                   strncmp(name, base, base_len))
+                       continue;
+
+               slash = strrchr(prop, '/');
+               if (strcmp(slash + 1, find_name))
+                       continue;
+               for (p = name + strlen(name) - 1; p > name; p--) {
+                       if (!isdigit(*p)) {
+                               *seqp = simple_strtoul(p + 1, NULL, 10);
+                               debug("Found seq %d\n", *seqp);
+                               return 0;
+                       }
+               }
+       }
+
+       debug("Not found\n");
+       return -ENOENT;
+}
+
+int fdtdec_get_chosen_node(const void *blob, const char *name)
+{
+       const char *prop;
+       int chosen_node;
+       int len;
+
+       if (!blob)
+               return -FDT_ERR_NOTFOUND;
+       chosen_node = fdt_path_offset(blob, "/chosen");
+       prop = fdt_getprop(blob, chosen_node, name, &len);
+       if (!prop)
+               return -FDT_ERR_NOTFOUND;
+       return fdt_path_offset(blob, prop);
+}
+
 int fdtdec_check_fdt(void)
 {
        /*
@@ -424,6 +475,26 @@ int fdtdec_get_int_array(const void *blob, int node, const char *prop_name,
        return err;
 }
 
+int fdtdec_get_int_array_count(const void *blob, int node,
+                              const char *prop_name, u32 *array, int count)
+{
+       const u32 *cell;
+       int len, elems;
+       int i;
+
+       debug("%s: %s\n", __func__, prop_name);
+       cell = fdt_getprop(blob, node, prop_name, &len);
+       if (!cell)
+               return -FDT_ERR_NOTFOUND;
+       elems = len / sizeof(u32);
+       if (count > elems)
+               count = elems;
+       for (i = 0; i < count; i++)
+               array[i] = fdt32_to_cpu(cell[i]);
+
+       return count;
+}
+
 const u32 *fdtdec_locate_array(const void *blob, int node,
                               const char *prop_name, int count)
 {
@@ -608,20 +679,25 @@ char *fdtdec_get_config_string(const void *blob, const char *prop_name)
        return (char *)nodep;
 }
 
-int fdtdec_decode_region(const void *blob, int node,
-               const char *prop_name, void **ptrp, size_t *size)
+int fdtdec_decode_region(const void *blob, int node, const char *prop_name,
+                        fdt_addr_t *basep, fdt_size_t *sizep)
 {
        const fdt_addr_t *cell;
        int len;
 
-       debug("%s: %s\n", __func__, prop_name);
+       debug("%s: %s: %s\n", __func__, fdt_get_name(blob, node, NULL),
+             prop_name);
        cell = fdt_getprop(blob, node, prop_name, &len);
-       if (!cell || (len != sizeof(fdt_addr_t) * 2))
+       if (!cell || (len < sizeof(fdt_addr_t) * 2)) {
+               debug("cell=%p, len=%d\n", cell, len);
                return -1;
+       }
+
+       *basep = fdt_addr_to_cpu(*cell);
+       *sizep = fdt_size_to_cpu(cell[1]);
+       debug("%s: base=%08lx, size=%lx\n", __func__, (ulong)*basep,
+             (ulong)*sizep);
 
-       *ptrp = map_sysmem(fdt_addr_to_cpu(*cell), *size);
-       *size = fdt_size_to_cpu(cell[1]);
-       debug("%s: size=%zx\n", __func__, *size);
        return 0;
 }
 
@@ -637,6 +713,7 @@ int fdtdec_decode_region(const void *blob, int node,
 int fdtdec_read_fmap_entry(const void *blob, int node, const char *name,
                           struct fmap_entry *entry)
 {
+       const char *prop;
        u32 reg[2];
 
        if (fdtdec_get_int_array(blob, node, "reg", reg, 2)) {
@@ -645,25 +722,146 @@ int fdtdec_read_fmap_entry(const void *blob, int node, const char *name,
        }
        entry->offset = reg[0];
        entry->length = reg[1];
+       entry->used = fdtdec_get_int(blob, node, "used", entry->length);
+       prop = fdt_getprop(blob, node, "compress", NULL);
+       entry->compress_algo = prop && !strcmp(prop, "lzo") ?
+               FMAP_COMPRESS_LZO : FMAP_COMPRESS_NONE;
+       prop = fdt_getprop(blob, node, "hash", &entry->hash_size);
+       entry->hash_algo = prop ? FMAP_HASH_SHA256 : FMAP_HASH_NONE;
+       entry->hash = (uint8_t *)prop;
 
        return 0;
 }
-#else
-#include "libfdt.h"
-#include "fdt_support.h"
 
-int fdtdec_get_int(const void *blob, int node, const char *prop_name,
-               int default_val)
+static u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells)
 {
-       const int *cell;
+       u64 number = 0;
+
+       while (cells--)
+               number = (number << 32) | fdt32_to_cpu(*ptr++);
+
+       return number;
+}
+
+int fdt_get_resource(const void *fdt, int node, const char *property,
+                    unsigned int index, struct fdt_resource *res)
+{
+       const fdt32_t *ptr, *end;
+       int na, ns, len, parent;
+       unsigned int i = 0;
+
+       parent = fdt_parent_offset(fdt, node);
+       if (parent < 0)
+               return parent;
+
+       na = fdt_address_cells(fdt, parent);
+       ns = fdt_size_cells(fdt, parent);
+
+       ptr = fdt_getprop(fdt, node, property, &len);
+       if (!ptr)
+               return len;
+
+       end = ptr + len / sizeof(*ptr);
+
+       while (ptr + na + ns <= end) {
+               if (i == index) {
+                       res->start = res->end = fdtdec_get_number(ptr, na);
+                       res->end += fdtdec_get_number(&ptr[na], ns) - 1;
+                       return 0;
+               }
+
+               ptr += na + ns;
+               i++;
+       }
+
+       return -FDT_ERR_NOTFOUND;
+}
+
+int fdt_get_named_resource(const void *fdt, int node, const char *property,
+                          const char *prop_names, const char *name,
+                          struct fdt_resource *res)
+{
+       int index;
+
+       index = fdt_find_string(fdt, node, prop_names, name);
+       if (index < 0)
+               return index;
+
+       return fdt_get_resource(fdt, node, property, index, res);
+}
+
+int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf)
+{
+       const fdt32_t *prop;
        int len;
 
-       cell = fdt_getprop_w((void *)blob, node, prop_name, &len);
-       if (cell && len >= sizeof(int)) {
-               int val = fdt32_to_cpu(cell[0]);
+       prop = fdt_getprop(fdt, node, "reg", &len);
+       if (!prop)
+               return len;
+
+       *bdf = fdt32_to_cpu(*prop) & 0xffffff;
+
+       return 0;
+}
+
+int fdtdec_decode_memory_region(const void *blob, int config_node,
+                               const char *mem_type, const char *suffix,
+                               fdt_addr_t *basep, fdt_size_t *sizep)
+{
+       char prop_name[50];
+       const char *mem;
+       fdt_size_t size, offset_size;
+       fdt_addr_t base, offset;
+       int node;
+
+       if (config_node == -1) {
+               config_node = fdt_path_offset(blob, "/config");
+               if (config_node < 0) {
+                       debug("%s: Cannot find /config node\n", __func__);
+                       return -ENOENT;
+               }
+       }
+       if (!suffix)
+               suffix = "";
+
+       snprintf(prop_name, sizeof(prop_name), "%s-memory%s", mem_type,
+                suffix);
+       mem = fdt_getprop(blob, config_node, prop_name, NULL);
+       if (!mem) {
+               debug("%s: No memory type for '%s', using /memory\n", __func__,
+                     prop_name);
+               mem = "/memory";
+       }
+
+       node = fdt_path_offset(blob, mem);
+       if (node < 0) {
+               debug("%s: Failed to find node '%s': %s\n", __func__, mem,
+                     fdt_strerror(node));
+               return -ENOENT;
+       }
+
+       /*
+        * Not strictly correct - the memory may have multiple banks. We just
+        * use the first
+        */
+       if (fdtdec_decode_region(blob, node, "reg", &base, &size)) {
+               debug("%s: Failed to decode memory region %s\n", __func__,
+                     mem);
+               return -EINVAL;
+       }
 
-               return val;
+       snprintf(prop_name, sizeof(prop_name), "%s-offset%s", mem_type,
+                suffix);
+       if (fdtdec_decode_region(blob, config_node, prop_name, &offset,
+                                &offset_size)) {
+               debug("%s: Failed to decode memory region '%s'\n", __func__,
+                     prop_name);
+               return -EINVAL;
        }
-       return default_val;
+
+       *basep = base + offset;
+       *sizep = offset_size;
+
+       return 0;
 }
 #endif