From e895a4b06f9062f052d438df7f4766b3decdb3d4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 23 Oct 2014 18:58:47 -0600 Subject: fdt: Allow ft_board_setup() to report failure This function can fail if the device tree runs out of space. Rather than silently booting with an incomplete device tree, allow the failure to be detected. Unfortunately this involves changing a lot of places in the code. I have not changed behvaiour to return an error where one is not currently returned, to avoid unexpected breakage. Eventually it would be nice to allow boards to register functions to be called to update the device tree. This would avoid all the many functions to do this. However it's not clear yet if this should be done using driver model or with a linker list. This work is left for later. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin --- include/fdt_support.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/fdt_support.h b/include/fdt_support.h index 55cef94358b..2e0adf3284c 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -64,7 +64,17 @@ static inline void fdt_fixup_crypto_node(void *blob, int sec_rev) {} int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose); #endif -void ft_board_setup(void *blob, bd_t *bd); +/** + * Add board-specific data to the FDT before booting the OS. + * + * Use CONFIG_SYS_FDT_PAD to ensure there is sufficient space. + * + * @param blob FDT blob to update + * @param bd_t Pointer to board data + * @return 0 if ok, or -FDT_ERR_... on error + */ +int ft_board_setup(void *blob, bd_t *bd); + /* * The keystone2 SOC requires all 32 bit aliased addresses to be converted * to their 36 physical format. This has to happen after all fdt nodes -- cgit v1.3.1 From a9e8e29101adcb0bfa1c39baba5fce6b9848678d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 23 Oct 2014 18:58:49 -0600 Subject: fdt: Export the fdt_find_or_add_subnode() function This function is useful for ensuring that a node exists. Export it so it can be used more widely. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Reviewed-by: Tom Rini --- common/fdt_support.c | 6 +++--- include/fdt_support.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/common/fdt_support.c b/common/fdt_support.c index 3f641566b97..46a15e72a0c 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -113,7 +113,8 @@ int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, } /** - * fdt_find_or_add_subnode - find or possibly add a subnode of a given node + * fdt_find_or_add_subnode() - find or possibly add a subnode of a given node + * * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate @@ -121,8 +122,7 @@ int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, * fdt_subnode_offset() finds a subnode of the node with a given name. * If the subnode does not exist, it will be created. */ -static int fdt_find_or_add_subnode(void *fdt, int parentoffset, - const char *name) +int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name) { int offset; diff --git a/include/fdt_support.h b/include/fdt_support.h index 2e0adf3284c..9ada2e49bda 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -64,6 +64,8 @@ static inline void fdt_fixup_crypto_node(void *blob, int sec_rev) {} int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose); #endif +int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name); + /** * Add board-specific data to the FDT before booting the OS. * -- cgit v1.3.1 From 76489832b28d158dd341b8992006576584cd204b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 23 Oct 2014 18:58:51 -0600 Subject: fdt: Use the correct return types for fdtdec_decode_region() Use the correct FDT data types for this function. Also add more debugging. Acked-by: Anatolij Gustschin Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- include/fdtdec.h | 10 +++++----- lib/fdtdec.c | 19 ++++++++++++------- 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/fdtdec.h b/include/fdtdec.h index 4ae77be9ba7..099930e7eef 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -595,12 +595,12 @@ const u8 *fdtdec_locate_byte_array(const void *blob, int node, * @param blob FDT blob * @param node node to examine * @param prop_name name of property to find - * @param ptrp returns pointer to region, or NULL if no address - * @param size returns size of region - * @return 0 if ok, -1 on error (propery not found) + * @param basep Returns base address of region + * @param size Returns size of region + * @return 0 if ok, -1 on error (property not found) */ -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); /* A flash map entry, containing an offset and length */ struct fmap_entry { diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 9714620ab3e..749f66ecc25 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -669,20 +669,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; } -- cgit v1.3.1 From f3cc44f9849fa7682d759621a74fb189a994e3b2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 23 Oct 2014 18:58:52 -0600 Subject: fdt: Enhance flashmap function to deal with region properties Flash regions can optionally be compressed or hashed. Add the ability to read this information from the flashmap. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Reviewed-by: Tom Rini --- include/fdtdec.h | 16 ++++++++++++++++ lib/fdtdec.c | 8 ++++++++ 2 files changed, 24 insertions(+) (limited to 'include') diff --git a/include/fdtdec.h b/include/fdtdec.h index 099930e7eef..1a931e84599 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -602,10 +602,26 @@ const u8 *fdtdec_locate_byte_array(const void *blob, int node, int fdtdec_decode_region(const void *blob, int node, const char *prop_name, fdt_addr_t *basep, fdt_size_t *sizep); +enum fmap_compress_t { + FMAP_COMPRESS_NONE, + FMAP_COMPRESS_LZO, +}; + +enum fmap_hash_t { + FMAP_HASH_NONE, + FMAP_HASH_SHA1, + FMAP_HASH_SHA256, +}; + /* A flash map entry, containing an offset and length */ struct fmap_entry { uint32_t offset; uint32_t length; + uint32_t used; /* Number of bytes used in region */ + enum fmap_compress_t compress_algo; /* Compression type */ + enum fmap_hash_t hash_algo; /* Hash algorithm */ + const uint8_t *hash; /* Hash value */ + int hash_size; /* Hash size */ }; /** diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 749f66ecc25..4dbd6aee853 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -703,6 +703,7 @@ int fdtdec_decode_region(const void *blob, int node, const char *prop_name, 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)) { @@ -711,6 +712,13 @@ 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; } -- cgit v1.3.1 From 6f4dbc21e47c5c1dd191cbd2f0fb7252340e0dcb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 23 Oct 2014 18:58:53 -0600 Subject: fdt: Tidy up error handling in image_setup_libfdt() The message about needing to reset should be printed no matter what error is printed. Also, an error should always be printed. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Reviewed-by: Tom Rini --- common/image-fdt.c | 30 ++++++++++++++++++++---------- include/fdt_support.h | 1 + 2 files changed, 21 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/common/image-fdt.c b/common/image-fdt.c index a39ae1b4cce..b95b6786c6f 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c @@ -460,19 +460,25 @@ int image_setup_libfdt(bootm_headers_t *images, void *blob, { ulong *initrd_start = &images->initrd_start; ulong *initrd_end = &images->initrd_end; - int ret; + int ret = -EPERM; + int fdt_ret; if (fdt_chosen(blob) < 0) { - puts("ERROR: /chosen node create failed"); - puts(" - must RESET the board to recover.\n"); - return -1; + printf("ERROR: /chosen node create failed\n"); + goto err; } if (arch_fixup_fdt(blob) < 0) { - puts("ERROR: arch specific fdt fixup failed"); - return -1; + printf("ERROR: arch-specific fdt fixup failed\n"); + goto err; + } + if (IMAGE_OF_BOARD_SETUP) { + fdt_ret = ft_board_setup(blob, gd->bd); + if (fdt_ret) { + printf("ERROR: board-specific fdt fixup failed: %s\n", + fdt_strerror(fdt_ret)); + goto err; + } } - if (IMAGE_OF_BOARD_SETUP) - ft_board_setup(blob, gd->bd); fdt_fixup_ethernet(blob); /* Delete the old LMB reservation */ @@ -481,7 +487,7 @@ int image_setup_libfdt(bootm_headers_t *images, void *blob, ret = fdt_shrink_to_minimum(blob); if (ret < 0) - return ret; + goto err; of_size = ret; if (*initrd_start && *initrd_end) { @@ -493,7 +499,7 @@ int image_setup_libfdt(bootm_headers_t *images, void *blob, fdt_initrd(blob, *initrd_start, *initrd_end); if (!ft_verify_fdt(blob)) - return -1; + goto err; #if defined(CONFIG_SOC_KEYSTONE) if (IMAGE_OF_BOARD_SETUP) @@ -501,4 +507,8 @@ int image_setup_libfdt(bootm_headers_t *images, void *blob, #endif return 0; +err: + printf(" - must RESET the board to recover.\n\n"); + + return ret; } diff --git a/include/fdt_support.h b/include/fdt_support.h index 9ada2e49bda..a101306cffa 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -70,6 +70,7 @@ int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name); * Add board-specific data to the FDT before booting the OS. * * Use CONFIG_SYS_FDT_PAD to ensure there is sufficient space. + * This function is called if CONFIG_OF_BOARD_SETUP is defined * * @param blob FDT blob to update * @param bd_t Pointer to board data -- cgit v1.3.1 From c654b5172a65faba2b541ee1fda1738534d47241 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 23 Oct 2014 18:58:54 -0600 Subject: fdt: Add ft_system_setup() function for system device tree additions Add an additional function for adding information to the device tree before booting. This permits additions which are not board-specific. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Reviewed-by: Tom Rini --- README | 9 ++++++++- common/cmd_fdt.c | 15 +++++++++++++++ common/image-fdt.c | 7 +++++++ include/fdt_support.h | 12 ++++++++++++ include/image.h | 6 ++++++ 5 files changed, 48 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/README b/README index 837dca0c931..bf3ec67b8ea 100644 --- a/README +++ b/README @@ -669,6 +669,13 @@ The following options need to be configured: Board code has addition modification that it wants to make to the flat device tree before handing it off to the kernel + CONFIG_OF_SYSTEM_SETUP + + Other code has addition modification that it wants to make + to the flat device tree before handing it off to the kernel. + This causes ft_system_setup() to be called before booting + the kernel. + CONFIG_OF_BOOT_CPU This define fills in the correct boot CPU in the boot @@ -3407,7 +3414,7 @@ FIT uImage format: to 128 or 256, although it does not have to be power of 2). default: 4096 - + CONFIG_MTD_UBI_BEB_LIMIT This option specifies the maximum bad physical eraseblocks UBI expects on the MTD device (per 1024 eraseblocks). If the diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c index 6f7ea086c1b..25b4675744f 100644 --- a/common/cmd_fdt.c +++ b/common/cmd_fdt.c @@ -575,6 +575,18 @@ static int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_FAILURE; } } +#endif +#ifdef CONFIG_OF_SYSTEM_SETUP + /* Call the board-specific fixup routine */ + else if (strncmp(argv[1], "sys", 3) == 0) { + int err = ft_system_setup(working_fdt, gd->bd); + + if (err) { + printf("Failed to add system information to FDT: %s\n", + fdt_strerror(err)); + return CMD_RET_FAILURE; + } + } #endif /* Create a chosen node */ else if (strncmp(argv[1], "cho", 3) == 0) { @@ -1014,6 +1026,9 @@ static char fdt_help_text[] = "addr [-c] [] - Set the [control] fdt location to \n" #ifdef CONFIG_OF_BOARD_SETUP "fdt boardsetup - Do board-specific set up\n" +#endif +#ifdef CONFIG_OF_SYSTEM_SETUP + "fdt systemsetup - Do system-specific set up\n" #endif "fdt move - Copy the fdt to and make it active\n" "fdt resize - Resize fdt to size + padding to 4k addr\n" diff --git a/common/image-fdt.c b/common/image-fdt.c index b95b6786c6f..1d76bd60da8 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c @@ -479,6 +479,13 @@ int image_setup_libfdt(bootm_headers_t *images, void *blob, goto err; } } + if (IMAGE_OF_SYSTEM_SETUP) { + if (ft_system_setup(blob, gd->bd)) { + printf("ERROR: system-specific fdt fixup failed: %s\n", + fdt_strerror(fdt_ret)); + goto err; + } + } fdt_fixup_ethernet(blob); /* Delete the old LMB reservation */ diff --git a/include/fdt_support.h b/include/fdt_support.h index a101306cffa..0fbc9bdd671 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -88,6 +88,18 @@ void ft_board_setup_ex(void *blob, bd_t *bd); void ft_cpu_setup(void *blob, bd_t *bd); void ft_pci_setup(void *blob, bd_t *bd); +/** + * Add system-specific data to the FDT before booting the OS. + * + * Use CONFIG_SYS_FDT_PAD to ensure there is sufficient space. + * This function is called if CONFIG_OF_SYSTEM_SETUP is defined + * + * @param blob FDT blob to update + * @param bd_t Pointer to board data + * @return 0 if ok, or -FDT_ERR_... on error + */ +int ft_system_setup(void *blob, bd_t *bd); + void set_working_fdt_addr(void *addr); int fdt_shrink_to_minimum(void *blob); int fdt_increase_size(void *fdt, int add_len); diff --git a/include/image.h b/include/image.h index 07e9aed16d9..af30d601585 100644 --- a/include/image.h +++ b/include/image.h @@ -119,6 +119,12 @@ struct lmb; # define IMAGE_OF_BOARD_SETUP 0 #endif +#ifdef CONFIG_OF_SYSTEM_SETUP +# define IMAGE_OF_SYSTEM_SETUP 1 +#else +# define IMAGE_OF_SYSTEM_SETUP 0 +#endif + /* * Operating System Codes */ -- cgit v1.3.1 From 2640387148ad5e0197a8ac80c24f3473dee42a65 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 23 Oct 2014 18:58:56 -0600 Subject: fdt: Add a function to decode a named memory region Permit decoding of a named memory region from the device tree. This allows easy run-time configuration of the address of on-chip SRAM, SDRAM, etc. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- include/fdtdec.h | 27 +++++++++++++++++++++++++ lib/fdtdec.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) (limited to 'include') diff --git a/include/fdtdec.h b/include/fdtdec.h index 1a931e84599..a7655dc1939 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -677,4 +677,31 @@ int fdt_get_named_resource(const void *fdt, int node, const char *property, */ int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf); +/** + * Decode a named region within a memory bank of a given type. + * + * This function handles selection of a memory region. The region is + * specified as an offset/size within a particular type of memory. + * + * The properties used are: + * + * -memory for the name of the memory bank + * -offset for the offset in that bank + * + * The property value must have an offset and a size. The function checks + * that the region is entirely within the memory bank.5 + * + * @param blob FDT blob + * @param node Node containing the properties (-1 for /config) + * @param mem_type Type of memory to use, which is a name, such as + * "u-boot" or "kernel". + * @param suffix String to append to the memory/offset + * property names + * @param basep Returns base of region + * @param sizep Returns size of region + * @return 0 if OK, -ive on error + */ +int fdtdec_decode_memory_region(const void *blob, int node, + const char *mem_type, const char *suffix, + fdt_addr_t *basep, fdt_size_t *sizep); #endif diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 4dbd6aee853..9c332ad903e 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -793,4 +793,65 @@ int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf) 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; + } + + 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; +} #endif -- cgit v1.3.1