X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=lib%2Ffdtdec.c;h=f4e8dbf699a88cebd7793e87066c319b23b037c3;hb=0c1562e7ee5698a8951a22ab2fe6368402051a0a;hp=d2dbd0f122ea1b358306586ea3613ae263dc0c3c;hpb=19d1f1a2f3ccfbf85125150f7876ce22714b38bd;p=u-boot diff --git a/lib/fdtdec.c b/lib/fdtdec.c index d2dbd0f122..f4e8dbf699 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1,20 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2011 The Chromium OS Authors. - * SPDX-License-Identifier: GPL-2.0+ */ #ifndef USE_HOSTCC -#include #include +#include #include +#include #include -#include -#include -#include #include +#include +#include +#include #include -#include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -47,7 +48,6 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SAMSUNG_EXYNOS_MIPI_DSI, "samsung,exynos-mipi-dsi"), COMPAT(SAMSUNG_EXYNOS_DWMMC, "samsung,exynos-dwmmc"), COMPAT(SAMSUNG_EXYNOS_MMC, "samsung,exynos-mmc"), - COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686"), COMPAT(GENERIC_SPI_FLASH, "spi-flash"), COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"), COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"), @@ -70,6 +70,9 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(ALTERA_SOCFPGA_F2SDR0, "altr,socfpga-fpga2sdram0-bridge"), COMPAT(ALTERA_SOCFPGA_F2SDR1, "altr,socfpga-fpga2sdram1-bridge"), COMPAT(ALTERA_SOCFPGA_F2SDR2, "altr,socfpga-fpga2sdram2-bridge"), + COMPAT(ALTERA_SOCFPGA_FPGA0, "altr,socfpga-a10-fpga-mgr"), + COMPAT(ALTERA_SOCFPGA_NOC, "altr,socfpga-a10-noc"), + COMPAT(ALTERA_SOCFPGA_CLK_INIT, "altr,socfpga-a10-clk-init") }; const char *fdtdec_get_compatible(enum fdt_compat_id id) @@ -80,8 +83,9 @@ const char *fdtdec_get_compatible(enum fdt_compat_id id) } fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node, - const char *prop_name, int index, int na, int ns, - fdt_size_t *sizep, bool translate) + const char *prop_name, int index, int na, + int ns, fdt_size_t *sizep, + bool translate) { const fdt32_t *prop, *prop_end; const fdt32_t *prop_addr, *prop_size, *prop_after_size; @@ -135,8 +139,9 @@ fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node, } fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent, - int node, const char *prop_name, int index, fdt_size_t *sizep, - bool translate) + int node, const char *prop_name, + int index, fdt_size_t *sizep, + bool translate) { int na, ns; @@ -161,8 +166,9 @@ fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent, } fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node, - const char *prop_name, int index, fdt_size_t *sizep, - bool translate) + const char *prop_name, int index, + fdt_size_t *sizep, + bool translate) { int parent; @@ -179,7 +185,7 @@ fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node, } fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, - const char *prop_name, fdt_size_t *sizep) + const char *prop_name, fdt_size_t *sizep) { int ns = sizep ? (sizeof(fdt_size_t) / sizeof(fdt32_t)) : 0; @@ -188,15 +194,14 @@ fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, ns, sizep, false); } -fdt_addr_t fdtdec_get_addr(const void *blob, int node, - const char *prop_name) +fdt_addr_t fdtdec_get_addr(const void *blob, int node, const char *prop_name) { return fdtdec_get_addr_size(blob, node, prop_name, NULL); } #if defined(CONFIG_PCI) && defined(CONFIG_DM_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 char *prop_name, struct fdt_pci_addr *addr) { const u32 *cell; int len; @@ -228,10 +233,10 @@ int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type, addr->phys_mid = fdt32_to_cpu(cell[1]); addr->phys_lo = fdt32_to_cpu(cell[1]); break; - } else { - cell += (FDT_PCI_ADDR_CELLS + - FDT_PCI_SIZE_CELLS); } + + cell += (FDT_PCI_ADDR_CELLS + + FDT_PCI_SIZE_CELLS); } if (i == num) { @@ -240,10 +245,10 @@ int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type, } return 0; - } else { - ret = -EINVAL; } + ret = -EINVAL; + fail: debug("(not found)\n"); return ret; @@ -260,11 +265,9 @@ int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device) end = list + len; while (list < end) { - char *s; - len = strlen(list); if (len >= strlen("pciVVVV,DDDD")) { - s = strstr(list, "pci"); + char *s = strstr(list, "pci"); /* * check if the string is something like pciVVVV,DDDD.RR @@ -294,7 +297,7 @@ int fdtdec_get_pci_bar32(struct udevice *dev, struct fdt_pci_addr *addr, /* extract the bar number from fdt_pci_addr */ barnum = addr->phys_hi & 0xff; - if ((barnum < PCI_BASE_ADDRESS_0) || (barnum > PCI_CARDBUS_CIS)) + if (barnum < PCI_BASE_ADDRESS_0 || barnum > PCI_CARDBUS_CIS) return -EINVAL; barnum = (barnum - PCI_BASE_ADDRESS_0) / 4; @@ -305,7 +308,7 @@ int fdtdec_get_pci_bar32(struct udevice *dev, struct fdt_pci_addr *addr, #endif uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, - uint64_t default_val) + uint64_t default_val) { const uint64_t *cell64; int length; @@ -330,7 +333,7 @@ int fdtdec_get_is_enabled(const void *blob, int node) */ cell = fdt_getprop(blob, node, "status", NULL); if (cell) - return 0 == strcmp(cell, "okay"); + return strcmp(cell, "okay") == 0; return 1; } @@ -340,20 +343,19 @@ enum fdt_compat_id fdtdec_lookup(const void *blob, int node) /* Search our drivers */ for (id = COMPAT_UNKNOWN; id < COMPAT_COUNT; id++) - if (0 == fdt_node_check_compatible(blob, node, - compat_names[id])) + if (fdt_node_check_compatible(blob, node, + compat_names[id]) == 0) return id; return COMPAT_UNKNOWN; } -int fdtdec_next_compatible(const void *blob, int node, - enum fdt_compat_id id) +int fdtdec_next_compatible(const void *blob, int node, enum fdt_compat_id id) { return fdt_node_offset_by_compatible(blob, node, compat_names[id]); } int fdtdec_next_compatible_subnode(const void *blob, int node, - enum fdt_compat_id id, int *depthp) + enum fdt_compat_id id, int *depthp) { do { node = fdt_next_node(blob, node, depthp); @@ -367,8 +369,8 @@ int fdtdec_next_compatible_subnode(const void *blob, int node, return -FDT_ERR_NOTFOUND; } -int fdtdec_next_alias(const void *blob, const char *name, - enum fdt_compat_id id, int *upto) +int fdtdec_next_alias(const void *blob, const char *name, enum fdt_compat_id id, + int *upto) { #define MAX_STR_LEN 20 char str[MAX_STR_LEN + 20]; @@ -390,7 +392,8 @@ int fdtdec_next_alias(const void *blob, const char *name, } int fdtdec_find_aliases_for_id(const void *blob, const char *name, - enum fdt_compat_id id, int *node_list, int maxcount) + enum fdt_compat_id id, int *node_list, + int maxcount) { memset(node_list, '\0', sizeof(*node_list) * maxcount); @@ -399,7 +402,8 @@ int fdtdec_find_aliases_for_id(const void *blob, const char *name, /* TODO: Can we tighten this code up a little? */ int fdtdec_add_aliases_for_id(const void *blob, const char *name, - enum fdt_compat_id id, int *node_list, int maxcount) + enum fdt_compat_id id, int *node_list, + int maxcount) { int name_len = strlen(name); int nodes[maxcount]; @@ -426,7 +430,7 @@ int fdtdec_add_aliases_for_id(const void *blob, const char *name, } if (node >= 0) debug("%s: warning: maxcount exceeded with alias '%s'\n", - __func__, name); + __func__, name); /* Now find all the aliases */ for (offset = fdt_first_property_offset(blob, alias_node); @@ -449,7 +453,7 @@ int fdtdec_add_aliases_for_id(const void *blob, const char *name, number = simple_strtoul(path + name_len, NULL, 10); if (number < 0 || number >= maxcount) { debug("%s: warning: alias '%s' is out of range\n", - __func__, path); + __func__, path); continue; } @@ -495,7 +499,7 @@ int fdtdec_add_aliases_for_id(const void *blob, const char *name, if (!node_list[i]) { for (; j < maxcount; j++) if (nodes[j] && - fdtdec_get_is_enabled(blob, nodes[j])) + fdtdec_get_is_enabled(blob, nodes[j])) break; /* Have we run out of nodes to add? */ @@ -638,7 +642,8 @@ int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name) * @return pointer to cell, which is only valid if err == 0 */ static const void *get_prop_check_min_len(const void *blob, int node, - const char *prop_name, int min_len, int *err) + const char *prop_name, int min_len, + int *err) { const void *cell; int len; @@ -655,15 +660,17 @@ static const void *get_prop_check_min_len(const void *blob, int node, } int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, - u32 *array, int count) + u32 *array, int count) { const u32 *cell; - int i, err = 0; + int err = 0; debug("%s: %s\n", __func__, prop_name); cell = get_prop_check_min_len(blob, node, prop_name, sizeof(u32) * count, &err); if (!err) { + int i; + for (i = 0; i < count; i++) array[i] = fdt32_to_cpu(cell[i]); } @@ -847,7 +854,7 @@ int fdtdec_get_child_count(const void *blob, int node) } int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name, - u8 *array, int count) + u8 *array, int count) { const u8 *cell; int err; @@ -859,7 +866,7 @@ int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name, } const u8 *fdtdec_locate_byte_array(const void *blob, int node, - const char *prop_name, int count) + const char *prop_name, int count) { const u8 *cell; int err; @@ -871,7 +878,7 @@ const u8 *fdtdec_locate_byte_array(const void *blob, int node, } int fdtdec_get_config_int(const void *blob, const char *prop_name, - int default_val) + int default_val) { int config_node; @@ -968,7 +975,8 @@ int fdt_get_resource(const void *fdt, int node, const char *property, while (ptr + na + ns <= end) { if (i == index) { - res->start = res->end = fdtdec_get_number(ptr, na); + res->start = fdtdec_get_number(ptr, na); + res->end = res->start; res->end += fdtdec_get_number(&ptr[na], ns) - 1; return 0; } @@ -1173,21 +1181,33 @@ int fdtdec_setup_memory_size(void) #if defined(CONFIG_NR_DRAM_BANKS) int fdtdec_setup_memory_banksize(void) { - int bank, ret, mem; + int bank, ret, mem, reg = 0; struct fdt_resource res; - mem = fdt_path_offset(gd->fdt_blob, "/memory"); + mem = fdt_node_offset_by_prop_value(gd->fdt_blob, -1, "device_type", + "memory", 7); if (mem < 0) { debug("%s: Missing /memory node\n", __func__); return -EINVAL; } for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { - ret = fdt_get_resource(gd->fdt_blob, mem, "reg", bank, &res); - if (ret == -FDT_ERR_NOTFOUND) - break; - if (ret != 0) + ret = fdt_get_resource(gd->fdt_blob, mem, "reg", reg++, &res); + if (ret == -FDT_ERR_NOTFOUND) { + reg = 0; + mem = fdt_node_offset_by_prop_value(gd->fdt_blob, mem, + "device_type", + "memory", 7); + if (mem == -FDT_ERR_NOTFOUND) + break; + + ret = fdt_get_resource(gd->fdt_blob, mem, "reg", reg++, &res); + if (ret == -FDT_ERR_NOTFOUND) + break; + } + if (ret != 0) { return -EINVAL; + } gd->bd->bi_dram[bank].start = (phys_addr_t)res.start; gd->bd->bi_dram[bank].size = @@ -1203,33 +1223,96 @@ int fdtdec_setup_memory_banksize(void) } #endif +#if CONFIG_IS_ENABLED(MULTI_DTB_FIT) +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_GZIP) ||\ + CONFIG_IS_ENABLED(MULTI_DTB_FIT_LZO) +static int uncompress_blob(const void *src, ulong sz_src, void **dstp) +{ + size_t sz_out = CONFIG_SPL_MULTI_DTB_FIT_UNCOMPRESS_SZ; + ulong sz_in = sz_src; + void *dst; + int rc; + + if (CONFIG_IS_ENABLED(GZIP)) + if (gzip_parse_header(src, sz_in) < 0) + return -1; + if (CONFIG_IS_ENABLED(LZO)) + if (!lzop_is_valid_header(src)) + return -EBADMSG; + + if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC)) { + dst = malloc(sz_out); + if (!dst) { + puts("uncompress_blob: Unable to allocate memory\n"); + return -ENOMEM; + } + } else { +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_USER_DEFINED_AREA) + dst = (void *)CONFIG_VAL(MULTI_DTB_FIT_USER_DEF_ADDR); +# else + return -ENOTSUPP; +# endif + } + + if (CONFIG_IS_ENABLED(GZIP)) + rc = gunzip(dst, sz_out, (u8 *)src, &sz_in); + else if (CONFIG_IS_ENABLED(LZO)) + rc = lzop_decompress(src, sz_in, dst, &sz_out); + + if (rc < 0) { + /* not a valid compressed blob */ + puts("uncompress_blob: Unable to uncompress\n"); + if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC)) + free(dst); + return -EBADMSG; + } + *dstp = dst; + return 0; +} +# else +static int uncompress_blob(const void *src, ulong sz_src, void **dstp) +{ + return -ENOTSUPP; +} +# endif +#endif + +#if defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE) +/* + * For CONFIG_OF_SEPARATE, the board may optionally implement this to + * provide and/or fixup the fdt. + */ +__weak void *board_fdt_blob_setup(void) +{ + void *fdt_blob = NULL; +#ifdef CONFIG_SPL_BUILD + /* FDT is at end of BSS unless it is in a different memory region */ + if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS)) + fdt_blob = (ulong *)&_image_binary_end; + else + fdt_blob = (ulong *)&__bss_end; +#else + /* FDT is at end of image */ + fdt_blob = (ulong *)&_end; +#endif + return fdt_blob; +} +#endif + int fdtdec_setup(void) { #if CONFIG_IS_ENABLED(OF_CONTROL) +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT) + void *fdt_blob; +# endif # 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 unless it is in a different memory region */ - if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS)) - gd->fdt_blob = (ulong *)&_image_binary_end; - else - gd->fdt_blob = (ulong *)&__bss_end; - -# elif defined CONFIG_FIT_EMBED - gd->fdt_blob = locate_dtb_in_fit(&_end); - - if (gd->fdt_blob == NULL || gd->fdt_blob <= ((void *)&_end)) { - puts("Failed to find proper dtb in embedded FIT Image\n"); - return -1; - } - + gd->fdt_blob = __dtb_dt_spl_begin; # else - /* FDT is at end of image */ - gd->fdt_blob = (ulong *)&_end; + gd->fdt_blob = __dtb_dt_begin; # endif -# elif defined(CONFIG_OF_BOARD) +# elif defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE) /* Allow the board to override the fdt address. */ gd->fdt_blob = board_fdt_blob_setup(); # elif defined(CONFIG_OF_HOSTFILE) @@ -1240,10 +1323,30 @@ int fdtdec_setup(void) # endif # ifndef CONFIG_SPL_BUILD /* Allow the early environment to override the fdt address */ - gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, + gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob); # endif + +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT) + /* + * Try and uncompress the blob. + * Unfortunately there is no way to know how big the input blob really + * is. So let us set the maximum input size arbitrarily high. 16MB + * ought to be more than enough for packed DTBs. + */ + if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0) + gd->fdt_blob = fdt_blob; + + /* + * Check if blob is a FIT images containings DTBs. + * If so, pick the most relevant + */ + fdt_blob = locate_dtb_in_fit(gd->fdt_blob); + if (fdt_blob) + gd->fdt_blob = fdt_blob; +# endif #endif + return fdtdec_prepare_fdt(); }