#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;
/*
#define COMPAT(id, name) name
static const char * const compat_names[COMPAT_COUNT] = {
COMPAT(UNKNOWN, "<none>"),
- 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_TEGRA210_SDMMC, "nvidia,tegra210-sdhci"),
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(NVIDIA_TEGRA210_XUSB_PADCTL, "nvidia,tegra210-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"),
COMPAT(SAMSUNG_EXYNOS_DWMMC, "samsung,exynos-dwmmc"),
COMPAT(SAMSUNG_EXYNOS_MMC, "samsung,exynos-mmc"),
COMPAT(SAMSUNG_EXYNOS_SERIAL, "samsung,exynos4210-uart"),
- COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
+ COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686"),
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(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(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"),
+ COMPAT(AMS_AS3722, "ams,as3722"),
+ COMPAT(INTEL_ICH_SPI, "intel,ich-spi"),
+ COMPAT(INTEL_QRK_MRC, "intel,quark-mrc"),
+ COMPAT(INTEL_X86_PINCTRL, "intel,x86-pinctrl"),
+ COMPAT(SOCIONEXT_XHCI, "socionext,uniphier-xhci"),
+ COMPAT(COMPAT_INTEL_PCH, "intel,bd82x6x"),
+ COMPAT(COMPAT_INTEL_IRQ_ROUTER, "intel,irq-router"),
+ COMPAT(ALTERA_SOCFPGA_DWMAC, "altr,socfpga-stmmac"),
+ COMPAT(COMPAT_INTEL_BAYTRAIL_FSP, "intel,baytrail-fsp"),
+ COMPAT(COMPAT_INTEL_BAYTRAIL_FSP_MDP, "intel,baytrail-fsp-mdp"),
};
const char *fdtdec_get_compatible(enum fdt_compat_id id)
size = (fdt_size_t *)((char *)cell +
sizeof(fdt_addr_t));
*sizep = fdt_size_to_cpu(*size);
- debug("addr=%08lx, size=%08x\n",
- (ulong)addr, *sizep);
+ debug("addr=%08lx, size=%llx\n",
+ (ulong)addr, (u64)*sizep);
} else {
debug("%08lx\n", (ulong)addr);
}
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;
+ }
+ }
+ 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)
{
const char *prop;
const char *name;
const char *slash;
- const char *p;
- int len;
+ int len, val;
prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len);
debug(" - %s, %s\n", name, prop);
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;
- }
+ val = trailing_strtol(name);
+ if (val != -1) {
+ *seqp = val;
+ debug("Found seq %d\n", *seqp);
+ return 0;
}
}
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;
{
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");
+# ifdef DEBUG
+ if (gd->fdt_blob) {
+ printf("fdt_blob=%p\n", gd->fdt_blob);
+ print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4,
+ 32, 0);
+ }
+# endif
+#endif
return -1;
}
return 0;
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)
+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)
{
- 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;
-}
+ 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);
-int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name,
- struct fdt_gpio_state *gpio)
-{
- int err;
+ /* 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,
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;
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;
-
- 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)
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);
+ }
+
+ 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)
+{
+#if CONFIG_IS_ENABLED(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 */