X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=lib%2Ffdtdec.c;h=9c9c30234732f09b8162414e12145373a23b6cc6;hb=HEAD;hp=ad090ea51eb5d46d433112bb8e258b43e95bd36a;hpb=6a86f1212656d4497b8980048907535f5294fabe;p=thirdparty%2Fu-boot.git diff --git a/lib/fdtdec.c b/lib/fdtdec.c index ad090ea51eb..b2c59ab3818 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1,18 +1,25 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2011 The Chromium OS Authors. + * + * NOTE: Please do not add new devicetree-reading functionality into this file. + * Add it to the ofnode API instead, since that is compatible with livetree. */ #ifndef USE_HOSTCC -#include + +#define LOG_CATEGORY LOGC_DT + +#include #include +#include #include #include #include #include #include #include -#include +#include #include #include #include @@ -23,6 +30,8 @@ #include #include #include +#include +#include #include #include #include @@ -62,7 +71,6 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(INTEL_BAYTRAIL_FSP, "intel,baytrail-fsp"), COMPAT(INTEL_BAYTRAIL_FSP_MDP, "intel,baytrail-fsp-mdp"), COMPAT(INTEL_IVYBRIDGE_FSP, "intel,ivybridge-fsp"), - COMPAT(COMPAT_SUNXI_NAND, "allwinner,sun4i-a10-nand"), COMPAT(ALTERA_SOCFPGA_CLK, "altr,clk-mgr"), COMPAT(ALTERA_SOCFPGA_PINCTRL_SINGLE, "pinctrl-single"), COMPAT(ALTERA_SOCFPGA_H2F_BRG, "altr,socfpga-hps2fpga-bridge"), @@ -76,6 +84,20 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(ALTERA_SOCFPGA_CLK_INIT, "altr,socfpga-a10-clk-init") }; +static const char *const fdt_src_name[] = { + [FDTSRC_SEPARATE] = "separate", + [FDTSRC_FIT] = "fit", + [FDTSRC_BOARD] = "board", + [FDTSRC_EMBED] = "embed", + [FDTSRC_ENV] = "env", + [FDTSRC_BLOBLIST] = "bloblist", +}; + +const char *fdtdec_get_srcname(void) +{ + return fdt_src_name[gd->fdt_src]; +} + const char *fdtdec_get_compatible(enum fdt_compat_id id) { /* We allow reading of the 'unknown' ID for testing purposes */ @@ -238,14 +260,7 @@ int fdtdec_get_pci_bar32(const struct udevice *dev, struct fdt_pci_addr *addr, barnum = (barnum - PCI_BASE_ADDRESS_0) / 4; - /* - * There is a strange toolchain bug with nds32 which complains about - * an undefined reference here, even if fdtdec_get_pci_bar32() is never - * called. An #ifdef seems to be the only fix! - */ -#if !IS_ENABLED(CONFIG_NDS32) *bar = dm_pci_read_bar32(dev, barnum); -#endif return 0; } @@ -581,6 +596,34 @@ int fdtdec_get_chosen_node(const void *blob, const char *name) return fdt_path_offset(blob, prop); } +/** + * fdtdec_prepare_fdt() - Check we have a valid fdt available to control U-Boot + * + * @blob: Blob to check + * + * If not, a message is printed to the console if the console is ready. + * + * Return: 0 if all ok, -ENOENT if not + */ +static int fdtdec_prepare_fdt(const void *blob) +{ + if (!blob || ((uintptr_t)blob & 3) || fdt_check_header(blob)) { + if (spl_phase() <= PHASE_SPL) { + puts("Missing DTB\n"); + } else { + printf("No valid device tree binary found at %p\n", + blob); + if (_DEBUG && blob) { + printf("fdt_blob=%p\n", blob); + print_buffer((ulong)blob, blob, 4, 32, 0); + } + } + return -ENOENT; + } + + return 0; +} + int fdtdec_check_fdt(void) { /* @@ -589,34 +632,7 @@ int fdtdec_check_fdt(void) * FDT (prior to console ready) will need to make their own * arrangements and do their own checks. */ - assert(!fdtdec_prepare_fdt()); - return 0; -} - -/* - * This function is a little odd in that it accesses global data. At some - * point if the architecture board.c files merge this will make more sense. - * Even now, it is common code. - */ -int fdtdec_prepare_fdt(void) -{ - if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) || - fdt_check_header(gd->fdt_blob)) { -#ifdef CONFIG_SPL_BUILD - puts("Missing DTB\n"); -#else - printf("No valid device tree binary found at %p\n", - gd->fdt_blob); -# 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; - } + assert(!fdtdec_prepare_fdt(gd->fdt_blob)); return 0; } @@ -643,7 +659,7 @@ int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name) * @param min_len minimum property length in bytes * @param err 0 if ok, or -FDT_ERR_NOTFOUND if the property is not found, or -FDT_ERR_BADLAYOUT if not enough data - * @return pointer to cell, which is only valid if err == 0 + * 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, @@ -1054,7 +1070,7 @@ ofnode get_next_memory_node(ofnode mem) { do { mem = ofnode_by_prop_value(mem, "device_type", "memory", 7); - } while (!ofnode_is_available(mem)); + } while (!ofnode_is_enabled(mem)); return mem; } @@ -1146,11 +1162,10 @@ int fdtdec_setup_mem_size_base_lowest(void) return 0; } -#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) { +#if CONFIG_IS_ENABLED(MULTI_DTB_FIT_GZIP) ||\ + CONFIG_IS_ENABLED(MULTI_DTB_FIT_LZO) size_t sz_out = CONFIG_VAL(MULTI_DTB_FIT_UNCOMPRESS_SZ); bool gzip = 0, lzo = 0; ulong sz_in = sz_src; @@ -1175,11 +1190,11 @@ static int uncompress_blob(const void *src, ulong sz_src, void **dstp) return -ENOMEM; } } else { -# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_USER_DEFINED_AREA) +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_USER_DEFINED_AREA) dst = (void *)CONFIG_VAL(MULTI_DTB_FIT_USER_DEF_ADDR); -# else +# else return -ENOTSUPP; -# endif +# endif } if (CONFIG_IS_ENABLED(GZIP) && gzip) @@ -1197,38 +1212,61 @@ static int uncompress_blob(const void *src, ulong sz_src, void **dstp) return -EBADMSG; } *dstp = dst; - return 0; -} -# else -static int uncompress_blob(const void *src, ulong sz_src, void **dstp) -{ +#else + *dstp = (void *)src; *dstp = (void *)src; +#endif return 0; } -# 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. +/** + * fdt_find_separate() - Find a devicetree at the end of the image + * + * Return: pointer to FDT blob */ -__weak void *board_fdt_blob_setup(void) +static void *fdt_find_separate(void) { void *fdt_blob = NULL; + + if (IS_ENABLED(CONFIG_SANDBOX)) + return 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; + fdt_blob = (ulong *)_image_binary_end; else - fdt_blob = (ulong *)&__bss_end; + fdt_blob = (ulong *)__bss_end; #else /* FDT is at end of image */ - fdt_blob = (ulong *)&_end; + fdt_blob = (ulong *)_end; + + if (_DEBUG && !fdtdec_prepare_fdt(fdt_blob)) { + int stack_ptr; + const void *top = fdt_blob + fdt_totalsize(fdt_blob); + + /* + * Perform a sanity check on the memory layout. If this fails, + * it indicates that the device tree is positioned above the + * global data pointer or the stack pointer. This should not + * happen. + * + * If this fails, check that SYS_INIT_SP_ADDR has enough space + * below it for SYS_MALLOC_F_LEN and global_data, as well as the + * stack, without overwriting the device tree or U-Boot itself. + * Since the device tree is sitting at _end (the start of the + * BSS region), we need the top of the device tree to be below + * any memory allocated by board_init_f_alloc_reserve(). + */ + if (top > (void *)gd || top > (void *)&stack_ptr) { + printf("FDT %p gd %p\n", fdt_blob, gd); + panic("FDT overlap"); + } + } #endif + return fdt_blob; } -#endif int fdtdec_set_ethernet_mac_address(void *fdt, const u8 *mac, size_t size) { @@ -1586,73 +1624,109 @@ int fdtdec_set_carveout(void *blob, const char *node, const char *prop_name, return 0; } +/* TODO(sjg@chromium.org): This function should not be weak */ __weak int fdtdec_board_setup(const void *fdt_blob) { return 0; } -int fdtdec_setup(void) +/** + * setup_multi_dtb_fit() - locate the correct dtb from a FIT + * + * This supports the CONFIG_MULTI_DTB_FIT feature, looking for the dtb in a + * supplied FIT + * + * It accepts the current value of gd->fdt_blob, which points to the FIT, then + * updates that gd->fdt_blob, to point to the chosen dtb so that U-Boot uses the + * correct one + */ +static void setup_multi_dtb_fit(void) { - int ret; -#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 */ -# ifdef CONFIG_SPL_BUILD - gd->fdt_blob = __dtb_dt_spl_begin; -# else - gd->fdt_blob = __dtb_dt_begin; -# endif -# 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) - if (sandbox_read_fdt_from_file()) { - puts("Failed to read control FDT\n"); - return -1; - } -# elif defined(CONFIG_OF_PRIOR_STAGE) - gd->fdt_blob = (void *)(uintptr_t)prior_stage_fdt_address; -# endif -# ifndef CONFIG_SPL_BUILD - /* Allow the early environment to override the fdt address */ - gd->fdt_blob = map_sysmem - (env_get_ulong("fdtcontroladdr", 16, - (unsigned long)map_to_sysmem(gd->fdt_blob)), 0); -# endif + void *blob; -# 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; + if (uncompress_blob(gd->fdt_blob, 0x1000000, &blob) == 0) + gd->fdt_blob = 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->multi_dtb_fit = gd->fdt_blob; - gd->fdt_blob = fdt_blob; + blob = locate_dtb_in_fit(gd->fdt_blob); + if (blob) { + gd_set_multi_dtb_fit(gd->fdt_blob); + gd->fdt_blob = blob; + gd->fdt_src = FDTSRC_FIT; } +} -# endif -#endif +int fdtdec_setup(void) +{ + int ret = -ENOENT; + + /* If allowing a bloblist, check that first */ + if (CONFIG_IS_ENABLED(BLOBLIST)) { + ret = bloblist_maybe_init(); + if (!ret) { + gd->fdt_blob = bloblist_find(BLOBLISTT_CONTROL_FDT, 0); + if (gd->fdt_blob) { + gd->fdt_src = FDTSRC_BLOBLIST; + log_debug("Devicetree is in bloblist at %p\n", + gd->fdt_blob); + } else { + log_debug("No FDT found in bloblist\n"); + ret = -ENOENT; + } + } + } + + /* Otherwise, the devicetree is typically appended to U-Boot */ + if (ret) { + if (IS_ENABLED(CONFIG_OF_SEPARATE)) { + gd->fdt_blob = fdt_find_separate(); + gd->fdt_src = FDTSRC_SEPARATE; + } else { /* embed dtb in ELF file for testing / development */ + gd->fdt_blob = dtb_dt_embedded(); + gd->fdt_src = FDTSRC_EMBED; + } + } + + /* Allow the board to override the fdt address. */ + if (IS_ENABLED(CONFIG_OF_BOARD)) { + gd->fdt_blob = board_fdt_blob_setup(&ret); + if (!ret) + gd->fdt_src = FDTSRC_BOARD; + else if (ret != -EEXIST) + return ret; + } + + /* Allow the early environment to override the fdt address */ + if (!IS_ENABLED(CONFIG_SPL_BUILD)) { + ulong addr; - ret = fdtdec_prepare_fdt(); + addr = env_get_hex("fdtcontroladdr", 0); + if (addr) { + gd->fdt_blob = map_sysmem(addr, 0); + gd->fdt_src = FDTSRC_ENV; + } + } + + if (CONFIG_IS_ENABLED(MULTI_DTB_FIT)) + setup_multi_dtb_fit(); + + ret = fdtdec_prepare_fdt(gd->fdt_blob); if (!ret) ret = fdtdec_board_setup(gd->fdt_blob); + oftree_reset(); + return ret; } -#if CONFIG_IS_ENABLED(MULTI_DTB_FIT) int fdtdec_resetup(int *rescan) { void *fdt_blob; @@ -1663,8 +1737,8 @@ int fdtdec_resetup(int *rescan) * FIT image stillpresent there. Save the time and space * required to uncompress it again. */ - if (gd->multi_dtb_fit) { - fdt_blob = locate_dtb_in_fit(gd->multi_dtb_fit); + if (gd_multi_dtb_fit()) { + fdt_blob = locate_dtb_in_fit(gd_multi_dtb_fit()); if (fdt_blob == gd->fdt_blob) { /* @@ -1677,7 +1751,7 @@ int fdtdec_resetup(int *rescan) *rescan = 1; gd->fdt_blob = fdt_blob; - return fdtdec_prepare_fdt(); + return fdtdec_prepare_fdt(fdt_blob); } /* @@ -1688,7 +1762,6 @@ int fdtdec_resetup(int *rescan) *rescan = 0; return 0; } -#endif int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id, phys_addr_t *basep, phys_size_t *sizep,