]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - lib/fdtdec.c
tpm: Rename Infineon TPM to slb9645tt
[karo-tx-uboot.git] / lib / fdtdec.c
index 4f66ae172fe1ec3a0db742f31fc44fb76ce1c8c6..f03b231e17ac6db08e54685d8f970f061ecb0e25 100644 (file)
@@ -9,10 +9,9 @@
 #include <serial.h>
 #include <libfdt.h>
 #include <fdtdec.h>
+#include <asm/sections.h>
 #include <linux/ctype.h>
 
-#include <asm/gpio.h>
-
 DECLARE_GLOBAL_DATA_PTR;
 
 /*
@@ -26,31 +25,28 @@ static const char * const compat_names[COMPAT_COUNT] = {
        COMPAT(NVIDIA_TEGRA20_USB, "nvidia,tegra20-ehci"),
        COMPAT(NVIDIA_TEGRA30_USB, "nvidia,tegra30-ehci"),
        COMPAT(NVIDIA_TEGRA114_USB, "nvidia,tegra114-ehci"),
-       COMPAT(NVIDIA_TEGRA114_I2C, "nvidia,tegra114-i2c"),
-       COMPAT(NVIDIA_TEGRA20_I2C, "nvidia,tegra20-i2c"),
-       COMPAT(NVIDIA_TEGRA20_DVC, "nvidia,tegra20-i2c-dvc"),
        COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"),
        COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"),
        COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"),
        COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"),
        COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"),
+       COMPAT(NVIDIA_TEGRA124_DC, "nvidia,tegra124-dc"),
+       COMPAT(NVIDIA_TEGRA124_SOR, "nvidia,tegra124-sor"),
+       COMPAT(NVIDIA_TEGRA124_PMC, "nvidia,tegra124-pmc"),
        COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"),
        COMPAT(NVIDIA_TEGRA124_SDMMC, "nvidia,tegra124-sdhci"),
        COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"),
        COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
-       COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
-       COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"),
-       COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"),
+       COMPAT(NVIDIA_TEGRA124_PCIE, "nvidia,tegra124-pcie"),
+       COMPAT(NVIDIA_TEGRA30_PCIE, "nvidia,tegra30-pcie"),
+       COMPAT(NVIDIA_TEGRA20_PCIE, "nvidia,tegra20-pcie"),
+       COMPAT(NVIDIA_TEGRA124_XUSB_PADCTL, "nvidia,tegra124-xusb-padctl"),
        COMPAT(SMSC_LAN9215, "smsc,lan9215"),
        COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"),
        COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"),
        COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"),
        COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),
-       COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"),
-       COMPAT(GOOGLE_CROS_EC, "google,cros-ec"),
        COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"),
-       COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
-       COMPAT(SAMSUNG_EXYNOS5_XHCI, "samsung,exynos5250-xhci"),
        COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
        COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"),
        COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
@@ -64,14 +60,23 @@ static const char * const compat_names[COMPAT_COUNT] = {
        COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
        COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"),
        COMPAT(INFINEON_SLB9635_TPM, "infineon,slb9635-tpm"),
-       COMPAT(INFINEON_SLB9645_TPM, "infineon,slb9645-tpm"),
+       COMPAT(INFINEON_SLB9645_TPM, "infineon,slb9645tt"),
        COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"),
-       COMPAT(SANDBOX_HOST_EMULATION, "sandbox,host-emulation"),
        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(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"),
+       COMPAT(AMS_AS3722, "ams,as3722"),
+       COMPAT(INTEL_ICH_SPI, "intel,ich-spi"),
+       COMPAT(INTEL_QRK_MRC, "intel,quark-mrc"),
+       COMPAT(SOCIONEXT_XHCI, "socionext,uniphier-xhci"),
+       COMPAT(COMPAT_INTEL_PCH, "intel,bd82x6x"),
 };
 
 const char *fdtdec_get_compatible(enum fdt_compat_id id)
@@ -115,6 +120,165 @@ fdt_addr_t fdtdec_get_addr(const void *blob, int node,
        return fdtdec_get_addr_size(blob, node, prop_name, NULL);
 }
 
+#ifdef CONFIG_PCI
+int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type,
+               const char *prop_name, struct fdt_pci_addr *addr)
+{
+       const u32 *cell;
+       int len;
+       int ret = -ENOENT;
+
+       debug("%s: %s: ", __func__, prop_name);
+
+       /*
+        * If we follow the pci bus bindings strictly, we should check
+        * the value of the node's parent node's #address-cells and
+        * #size-cells. They need to be 3 and 2 accordingly. However,
+        * for simplicity we skip the check here.
+        */
+       cell = fdt_getprop(blob, node, prop_name, &len);
+       if (!cell)
+               goto fail;
+
+       if ((len % FDT_PCI_REG_SIZE) == 0) {
+               int num = len / FDT_PCI_REG_SIZE;
+               int i;
+
+               for (i = 0; i < num; i++) {
+                       debug("pci address #%d: %08lx %08lx %08lx\n", i,
+                             (ulong)fdt_addr_to_cpu(cell[0]),
+                             (ulong)fdt_addr_to_cpu(cell[1]),
+                             (ulong)fdt_addr_to_cpu(cell[2]));
+                       if ((fdt_addr_to_cpu(*cell) & type) == type) {
+                               addr->phys_hi = fdt_addr_to_cpu(cell[0]);
+                               addr->phys_mid = fdt_addr_to_cpu(cell[1]);
+                               addr->phys_lo = fdt_addr_to_cpu(cell[2]);
+                               break;
+                       } else {
+                               cell += (FDT_PCI_ADDR_CELLS +
+                                        FDT_PCI_SIZE_CELLS);
+                       }
+               }
+
+               if (i == num) {
+                       ret = -ENXIO;
+                       goto fail;
+               }
+
+               return 0;
+       } else {
+               ret = -EINVAL;
+       }
+
+fail:
+       debug("(not found)\n");
+       return ret;
+}
+
+int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device)
+{
+       const char *list, *end;
+       int len;
+
+       list = fdt_getprop(blob, node, "compatible", &len);
+       if (!list)
+               return -ENOENT;
+
+       end = list + len;
+       while (list < end) {
+               char *s;
+
+               len = strlen(list);
+               if (len >= strlen("pciVVVV,DDDD")) {
+                       s = strstr(list, "pci");
+
+                       /*
+                        * check if the string is something like pciVVVV,DDDD.RR
+                        * or just pciVVVV,DDDD
+                        */
+                       if (s && s[7] == ',' &&
+                           (s[12] == '.' || s[12] == 0)) {
+                               s += 3;
+                               *vendor = simple_strtol(s, NULL, 16);
+
+                               s += 5;
+                               *device = simple_strtol(s, NULL, 16);
+
+                               return 0;
+                       }
+               } else {
+                       list += (len + 1);
+               }
+       }
+
+       return -ENOENT;
+}
+
+int fdtdec_get_pci_bdf(const void *blob, int node,
+               struct fdt_pci_addr *addr, pci_dev_t *bdf)
+{
+       u16 dt_vendor, dt_device, vendor, device;
+       int ret;
+
+       /* get vendor id & device id from the compatible string */
+       ret = fdtdec_get_pci_vendev(blob, node, &dt_vendor, &dt_device);
+       if (ret)
+               return ret;
+
+       /* extract the bdf from fdt_pci_addr */
+       *bdf = addr->phys_hi & 0xffff00;
+
+       /* read vendor id & device id based on bdf */
+       pci_read_config_word(*bdf, PCI_VENDOR_ID, &vendor);
+       pci_read_config_word(*bdf, PCI_DEVICE_ID, &device);
+
+       /*
+        * Note there are two places in the device tree to fully describe
+        * a pci device: one is via compatible string with a format of
+        * "pciVVVV,DDDD" and the other one is the bdf numbers encoded in
+        * the device node's reg address property. We read the vendor id
+        * and device id based on bdf and compare the values with the
+        * "VVVV,DDDD". If they are the same, then we are good to use bdf
+        * to read device's bar. But if they are different, we have to rely
+        * on the vendor id and device id extracted from the compatible
+        * string and locate the real bdf by pci_find_device(). This is
+        * because normally we may only know device's device number and
+        * function number when writing device tree. The bus number is
+        * dynamically assigned during the pci enumeration process.
+        */
+       if ((dt_vendor != vendor) || (dt_device != device)) {
+               *bdf = pci_find_device(dt_vendor, dt_device, 0);
+               if (*bdf == -1)
+                       return -ENODEV;
+       }
+
+       return 0;
+}
+
+int fdtdec_get_pci_bar32(const void *blob, int node,
+               struct fdt_pci_addr *addr, u32 *bar)
+{
+       pci_dev_t bdf;
+       int barnum;
+       int ret;
+
+       /* get pci devices's bdf */
+       ret = fdtdec_get_pci_bdf(blob, node, addr, &bdf);
+       if (ret)
+               return ret;
+
+       /* extract the bar number from fdt_pci_addr */
+       barnum = addr->phys_hi & 0xff;
+       if ((barnum < PCI_BASE_ADDRESS_0) || (barnum > PCI_CARDBUS_CIS))
+               return -EINVAL;
+
+       barnum = (barnum - PCI_BASE_ADDRESS_0) / 4;
+       *bar = pci_read_bar32(pci_bus_to_hose(PCI_BUS(bdf)), bdf, barnum);
+
+       return 0;
+}
+#endif
+
 uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
                uint64_t default_val)
 {
@@ -354,9 +518,9 @@ int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
                slash = strrchr(prop, '/');
                if (strcmp(slash + 1, find_name))
                        continue;
-               for (p = name; *p; p++) {
-                       if (isdigit(*p)) {
-                               *seqp = simple_strtoul(p, NULL, 10);
+               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;
                        }
@@ -367,21 +531,6 @@ int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
        return -ENOENT;
 }
 
-int fdtdec_get_alias_node(const void *blob, const char *name)
-{
-       const char *prop;
-       int alias_node;
-       int len;
-
-       if (!blob)
-               return -FDT_ERR_NOTFOUND;
-       alias_node = fdt_path_offset(blob, "/aliases");
-       prop = fdt_getprop(blob, alias_node, name, &len);
-       if (!prop)
-               return -FDT_ERR_NOTFOUND;
-       return fdt_path_offset(blob, prop);
-}
-
 int fdtdec_get_chosen_node(const void *blob, const char *name)
 {
        const char *prop;
@@ -418,9 +567,11 @@ int fdtdec_prepare_fdt(void)
 {
        if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||
            fdt_check_header(gd->fdt_blob)) {
-               printf("No valid FDT found - please append one to U-Boot "
-                       "binary, use u-boot-dtb.bin or define "
-                       "CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n");
+#ifdef CONFIG_SPL_BUILD
+               puts("Missing DTB\n");
+#else
+               puts("No valid device tree binary found - please append one to U-Boot binary, use u-boot-dtb.bin or define CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n");
+#endif
                return -1;
        }
        return 0;
@@ -484,6 +635,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)
 {
@@ -505,99 +676,128 @@ int fdtdec_get_bool(const void *blob, int node, const char *prop_name)
        return cell != NULL;
 }
 
-/**
- * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no
- * terminating item.
- *
- * @param blob         FDT blob to use
- * @param node         Node to look at
- * @param prop_name    Node property name
- * @param gpio         Array of gpio elements to fill from FDT. This will be
- *                     untouched if either 0 or an error is returned
- * @param max_count    Maximum number of elements allowed
- * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would
- * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing.
- */
-int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name,
-               struct fdt_gpio_state *gpio, int max_count)
-{
-       const struct fdt_property *prop;
-       const u32 *cell;
-       const char *name;
-       int len, i;
-
-       debug("%s: %s\n", __func__, prop_name);
-       assert(max_count > 0);
-       prop = fdt_get_property(blob, node, prop_name, &len);
-       if (!prop) {
-               debug("%s: property '%s' missing\n", __func__, prop_name);
-               return -FDT_ERR_NOTFOUND;
-       }
-
-       /* We will use the name to tag the GPIO */
-       name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
-       cell = (u32 *)prop->data;
-       len /= sizeof(u32) * 3;         /* 3 cells per GPIO record */
-       if (len > max_count) {
-               debug(" %s: too many GPIOs / cells for "
-                       "property '%s'\n", __func__, prop_name);
-               return -FDT_ERR_BADLAYOUT;
-       }
-
-       /* Read out the GPIO data from the cells */
-       for (i = 0; i < len; i++, cell += 3) {
-               gpio[i].gpio = fdt32_to_cpu(cell[1]);
-               gpio[i].flags = fdt32_to_cpu(cell[2]);
-               gpio[i].name = name;
-       }
-
-       return len;
-}
-
-int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name,
-               struct fdt_gpio_state *gpio)
+int fdtdec_parse_phandle_with_args(const void *blob, int src_node,
+                                  const char *list_name,
+                                  const char *cells_name,
+                                  int cell_count, int index,
+                                  struct fdtdec_phandle_args *out_args)
 {
-       int err;
+       const __be32 *list, *list_end;
+       int rc = 0, size, cur_index = 0;
+       uint32_t count = 0;
+       int node = -1;
+       int phandle;
+
+       /* Retrieve the phandle list property */
+       list = fdt_getprop(blob, src_node, list_name, &size);
+       if (!list)
+               return -ENOENT;
+       list_end = list + size / sizeof(*list);
+
+       /* Loop over the phandles until all the requested entry is found */
+       while (list < list_end) {
+               rc = -EINVAL;
+               count = 0;
 
-       debug("%s: %s\n", __func__, prop_name);
-       gpio->gpio = FDT_GPIO_NONE;
-       gpio->name = NULL;
-       err = fdtdec_decode_gpios(blob, node, prop_name, gpio, 1);
-       return err == 1 ? 0 : err;
-}
+               /*
+                * If phandle is 0, then it is an empty entry with no
+                * arguments.  Skip forward to the next entry.
+                */
+               phandle = be32_to_cpup(list++);
+               if (phandle) {
+                       /*
+                        * Find the provider node and parse the #*-cells
+                        * property to determine the argument length.
+                        *
+                        * This is not needed if the cell count is hard-coded
+                        * (i.e. cells_name not set, but cell_count is set),
+                        * except when we're going to return the found node
+                        * below.
+                        */
+                       if (cells_name || cur_index == index) {
+                               node = fdt_node_offset_by_phandle(blob,
+                                                                 phandle);
+                               if (!node) {
+                                       debug("%s: could not find phandle\n",
+                                             fdt_get_name(blob, src_node,
+                                                          NULL));
+                                       goto err;
+                               }
+                       }
 
-int fdtdec_get_gpio(struct fdt_gpio_state *gpio)
-{
-       int val;
+                       if (cells_name) {
+                               count = fdtdec_get_int(blob, node, cells_name,
+                                                      -1);
+                               if (count == -1) {
+                                       debug("%s: could not get %s for %s\n",
+                                             fdt_get_name(blob, src_node,
+                                                          NULL),
+                                             cells_name,
+                                             fdt_get_name(blob, node,
+                                                          NULL));
+                                       goto err;
+                               }
+                       } else {
+                               count = cell_count;
+                       }
 
-       if (!fdt_gpio_isvalid(gpio))
-               return -1;
+                       /*
+                        * Make sure that the arguments actually fit in the
+                        * remaining property data length
+                        */
+                       if (list + count > list_end) {
+                               debug("%s: arguments longer than property\n",
+                                     fdt_get_name(blob, src_node, NULL));
+                               goto err;
+                       }
+               }
 
-       val = gpio_get_value(gpio->gpio);
-       return gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val;
-}
+               /*
+                * All of the error cases above bail out of the loop, so at
+                * this point, the parsing is successful. If the requested
+                * index matches, then fill the out_args structure and return,
+                * or return -ENOENT for an empty entry.
+                */
+               rc = -ENOENT;
+               if (cur_index == index) {
+                       if (!phandle)
+                               goto err;
+
+                       if (out_args) {
+                               int i;
+
+                               if (count > MAX_PHANDLE_ARGS) {
+                                       debug("%s: too many arguments %d\n",
+                                             fdt_get_name(blob, src_node,
+                                                          NULL), count);
+                                       count = MAX_PHANDLE_ARGS;
+                               }
+                               out_args->node = node;
+                               out_args->args_count = count;
+                               for (i = 0; i < count; i++) {
+                                       out_args->args[i] =
+                                                       be32_to_cpup(list++);
+                               }
+                       }
 
-int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val)
-{
-       if (!fdt_gpio_isvalid(gpio))
-               return -1;
+                       /* Found it! return success */
+                       return 0;
+               }
 
-       val = gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val;
-       return gpio_set_value(gpio->gpio, val);
-}
+               node = -1;
+               list += count;
+               cur_index++;
+       }
 
-int fdtdec_setup_gpio(struct fdt_gpio_state *gpio)
-{
        /*
-        * Return success if there is no GPIO defined. This is used for
-        * optional GPIOs)
+        * Result will be one of:
+        * -ENOENT : index is for empty phandle
+        * -EINVAL : parsing error on data
+        * [1..n]  : Number of phandle (count mode; when index = -1)
         */
-       if (!fdt_gpio_isvalid(gpio))
-               return 0;
-
-       if (gpio_request(gpio->gpio, gpio->name))
-               return -1;
-       return 0;
+       rc = index < 0 ? cur_index : -ENOENT;
+ err:
+       return rc;
 }
 
 int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name,
@@ -668,20 +868,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;
 }
 
@@ -697,6 +902,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)) {
@@ -705,11 +911,18 @@ 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;
 }
 
-static u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells)
+u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells)
 {
        u64 number = 0;
 
@@ -766,17 +979,186 @@ int fdt_get_named_resource(const void *fdt, int node, const char *property,
        return fdt_get_resource(fdt, node, property, index, res);
 }
 
-int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf)
+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)
 {
-       const fdt32_t *prop;
-       int len;
+       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";
+       }
 
-       prop = fdt_getprop(fdt, node, "reg", &len);
-       if (!prop)
-               return len;
+       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;
+       }
+
+       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;
+       }
+
+       *basep = base + offset;
+       *sizep = offset_size;
+
+       return 0;
+}
+
+static int decode_timing_property(const void *blob, int node, const char *name,
+                                 struct timing_entry *result)
+{
+       int length, ret = 0;
+       const u32 *prop;
+
+       prop = fdt_getprop(blob, node, name, &length);
+       if (!prop) {
+               debug("%s: could not find property %s\n",
+                     fdt_get_name(blob, node, NULL), name);
+               return length;
+       }
+
+       if (length == sizeof(u32)) {
+               result->typ = fdtdec_get_int(blob, node, name, 0);
+               result->min = result->typ;
+               result->max = result->typ;
+       } else {
+               ret = fdtdec_get_int_array(blob, node, name, &result->min, 3);
+       }
 
-       *bdf = fdt32_to_cpu(*prop) & 0xffffff;
+       return ret;
+}
+
+int fdtdec_decode_display_timing(const void *blob, int parent, int index,
+                                struct display_timing *dt)
+{
+       int i, node, timings_node;
+       u32 val = 0;
+       int ret = 0;
+
+       timings_node = fdt_subnode_offset(blob, parent, "display-timings");
+       if (timings_node < 0)
+               return timings_node;
+
+       for (i = 0, node = fdt_first_subnode(blob, timings_node);
+            node > 0 && i != index;
+            node = fdt_next_subnode(blob, node))
+               i++;
+
+       if (node < 0)
+               return node;
+
+       memset(dt, 0, sizeof(*dt));
+
+       ret |= decode_timing_property(blob, node, "hback-porch",
+                                     &dt->hback_porch);
+       ret |= decode_timing_property(blob, node, "hfront-porch",
+                                     &dt->hfront_porch);
+       ret |= decode_timing_property(blob, node, "hactive", &dt->hactive);
+       ret |= decode_timing_property(blob, node, "hsync-len", &dt->hsync_len);
+       ret |= decode_timing_property(blob, node, "vback-porch",
+                                     &dt->vback_porch);
+       ret |= decode_timing_property(blob, node, "vfront-porch",
+                                     &dt->vfront_porch);
+       ret |= decode_timing_property(blob, node, "vactive", &dt->vactive);
+       ret |= decode_timing_property(blob, node, "vsync-len", &dt->vsync_len);
+       ret |= decode_timing_property(blob, node, "clock-frequency",
+                                     &dt->pixelclock);
+
+       dt->flags = 0;
+       val = fdtdec_get_int(blob, node, "vsync-active", -1);
+       if (val != -1) {
+               dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
+                               DISPLAY_FLAGS_VSYNC_LOW;
+       }
+       val = fdtdec_get_int(blob, node, "hsync-active", -1);
+       if (val != -1) {
+               dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
+                               DISPLAY_FLAGS_HSYNC_LOW;
+       }
+       val = fdtdec_get_int(blob, node, "de-active", -1);
+       if (val != -1) {
+               dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
+                               DISPLAY_FLAGS_DE_LOW;
+       }
+       val = fdtdec_get_int(blob, node, "pixelclk-active", -1);
+       if (val != -1) {
+               dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
+                               DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+       }
+
+       if (fdtdec_get_bool(blob, node, "interlaced"))
+               dt->flags |= DISPLAY_FLAGS_INTERLACED;
+       if (fdtdec_get_bool(blob, node, "doublescan"))
+               dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
+       if (fdtdec_get_bool(blob, node, "doubleclk"))
+               dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
 
        return 0;
 }
+
+int fdtdec_setup(void)
+{
+#ifdef CONFIG_OF_CONTROL
+# ifdef CONFIG_OF_EMBED
+       /* Get a pointer to the FDT */
+       gd->fdt_blob = __dtb_dt_begin;
+# elif defined CONFIG_OF_SEPARATE
+#  ifdef CONFIG_SPL_BUILD
+       /* FDT is at end of BSS */
+       gd->fdt_blob = (ulong *)&__bss_end;
+#  else
+       /* FDT is at end of image */
+       gd->fdt_blob = (ulong *)&_end;
 #endif
+# elif defined(CONFIG_OF_HOSTFILE)
+       if (sandbox_read_fdt_from_file()) {
+               puts("Failed to read control FDT\n");
+               return -1;
+       }
+# endif
+# ifndef CONFIG_SPL_BUILD
+       /* Allow the early environment to override the fdt address */
+       gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
+                                               (uintptr_t)gd->fdt_blob);
+# endif
+#endif
+       return fdtdec_prepare_fdt();
+}
+
+#endif /* !USE_HOSTCC */