diff options
Diffstat (limited to 'common/spl/spl_fit.c')
-rw-r--r-- | common/spl/spl_fit.c | 151 |
1 files changed, 141 insertions, 10 deletions
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index cbc00a4e7c..ac69d8312e 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -6,14 +6,20 @@ #include <common.h> #include <errno.h> +#include <board.h> #include <fpga.h> #include <gzip.h> #include <image.h> -#include <linux/libfdt.h> +#include <malloc.h> #include <spl.h> +#include <linux/libfdt.h> DECLARE_GLOBAL_DATA_PTR; +#ifndef CONFIG_SPL_LOAD_FIT_APPLY_OVERLAY_BUF_SZ +#define CONFIG_SPL_LOAD_FIT_APPLY_OVERLAY_BUF_SZ (64 * 1024) +#endif + #ifndef CONFIG_SYS_BOOTM_LEN #define CONFIG_SYS_BOOTM_LEN (64 << 20) #endif @@ -27,6 +33,29 @@ __weak ulong board_spl_fit_size_align(ulong size) return size; } +static int find_node_from_desc(const void *fit, int node, const char *str) +{ + int child; + + if (node < 0) + return -EINVAL; + + /* iterate the FIT nodes and find a matching description */ + for (child = fdt_first_subnode(fit, node); child >= 0; + child = fdt_next_subnode(fit, child)) { + int len; + const char *desc = fdt_getprop(fit, child, "description", &len); + + if (!desc) + continue; + + if (!strcmp(desc, str)) + return child; + } + + return -ENOENT; +} + /** * spl_fit_get_image_name(): By using the matching configuration subnode, * retrieve the name of an image, specified by a property name and an index @@ -41,12 +70,14 @@ __weak ulong board_spl_fit_size_align(ulong size) */ static int spl_fit_get_image_name(const void *fit, int images, const char *type, int index, - char **outname) + const char **outname) { + struct udevice *board; const char *name, *str; __maybe_unused int node; int conf_node; int len, i; + bool found = true; conf_node = fit_find_config_node(fit); if (conf_node < 0) { @@ -72,12 +103,45 @@ static int spl_fit_get_image_name(const void *fit, int images, for (i = 0; i < index; i++) { str = strchr(str, '\0') + 1; if (!str || (str - name >= len)) { - debug("no string for index %d\n", index); - return -E2BIG; + found = false; + break; } } - *outname = (char *)str; + if (!found && !board_get(&board)) { + int rc; + /* + * no string in the property for this index. Check if the board + * level code can supply one. + */ + rc = board_get_fit_loadable(board, index - i - 1, type, &str); + if (rc && rc != -ENOENT) + return rc; + + if (!rc) { + /* + * The board provided a name for a loadable. + * Try to match it against the description properties + * first. If no matching node is found, use it as a + * node name. + */ + int node; + int images = fdt_path_offset(fit, FIT_IMAGES_PATH); + + node = find_node_from_desc(fit, images, str); + if (node > 0) + str = fdt_get_name(fit, node, NULL); + + found = true; + } + } + + if (!found) { + debug("no string for index %d\n", index); + return -E2BIG; + } + + *outname = str; return 0; } @@ -96,7 +160,7 @@ static int spl_fit_get_image_name(const void *fit, int images, static int spl_fit_get_image_node(const void *fit, int images, const char *type, int index) { - char *str; + const char *str; int err; int node; @@ -108,7 +172,7 @@ static int spl_fit_get_image_node(const void *fit, int images, node = fdt_subnode_offset(fit, images, str); if (node < 0) { - debug("cannot find image node '%s': %d\n", str, node); + pr_err("cannot find image node '%s': %d\n", str, node); return -EINVAL; } @@ -281,7 +345,7 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image, void *fit, int images, ulong base_offset) { struct spl_image_info image_info; - int node, ret = 0; + int node, ret = 0, index = 0; /* * Use the address following the image as target address for the @@ -290,7 +354,7 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image, image_info.load_addr = spl_image->load_addr + spl_image->size; /* Figure out which device tree the board wants to use */ - node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, 0); + node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, index++); if (node < 0) { debug("%s: cannot find FDT node\n", __func__); @@ -313,8 +377,65 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image, /* Make the load-address of the FDT available for the SPL framework */ spl_image->fdt_addr = (void *)image_info.load_addr; #if !CONFIG_IS_ENABLED(FIT_IMAGE_TINY) + if (CONFIG_IS_ENABLED(LOAD_FIT_APPLY_OVERLAY)) { + void *tmpbuffer = NULL; + + for (; ; index++) { + node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, + index); + if (node == -E2BIG) { + debug("%s: No additional FDT node\n", __func__); + break; + } else if (node < 0) { + debug("%s: unable to find FDT node %d\n", + __func__, index); + continue; + } + + if (!tmpbuffer) { + /* + * allocate memory to store the DT overlay + * before it is applied. It may not be used + * depending on how the overlay is stored, so + * don't fail yet if the allocation failed. + */ + tmpbuffer = malloc(CONFIG_SPL_LOAD_FIT_APPLY_OVERLAY_BUF_SZ); + if (!tmpbuffer) + debug("%s: unable to allocate space for overlays\n", + __func__); + } + image_info.load_addr = (ulong)tmpbuffer; + ret = spl_load_fit_image(info, sector, fit, base_offset, + node, &image_info); + if (ret < 0) + break; + + /* Make room in FDT for changes from the overlay */ + ret = fdt_increase_size(spl_image->fdt_addr, + image_info.size); + if (ret < 0) + break; + + ret = fdt_overlay_apply_verbose(spl_image->fdt_addr, + (void *)image_info.load_addr); + if (ret) { + pr_err("failed to apply DT overlay %s\n", + fit_get_name(fit, node, NULL)); + break; + } + + debug("%s: DT overlay %s applied\n", __func__, + fit_get_name(fit, node, NULL)); + } + if (tmpbuffer) + free(tmpbuffer); + if (ret) + return ret; + } /* Try to make space, so we can inject details on the loadables */ ret = fdt_shrink_to_minimum(spl_image->fdt_addr, 8192); + if (ret < 0) + return ret; #endif return ret; @@ -325,7 +446,7 @@ static int spl_fit_record_loadable(const void *fit, int images, int index, { int ret = 0; #if !CONFIG_IS_ENABLED(FIT_IMAGE_TINY) - char *name; + const char *name; int node; ret = spl_fit_get_image_name(fit, images, "loadables", @@ -373,6 +494,7 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, int images, ret; int base_offset, hsize, align_len = ARCH_DMA_MINALIGN - 1; int index = 0; + int firmware_node; /* * For FIT with external data, figure out where the external images @@ -502,6 +624,7 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, spl_fit_append_fdt(spl_image, info, sector, fit, images, base_offset); + firmware_node = node; /* Now check if there are more images for us to load */ for (; ; index++) { uint8_t os_type = IH_OS_INVALID; @@ -510,6 +633,14 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, if (node < 0) break; + /* + * if the firmware is also a loadable, skip it because + * it already has been loaded. This is typically the case with + * u-boot.img generated by mkimage. + */ + if (firmware_node == node) + continue; + ret = spl_load_fit_image(info, sector, fit, base_offset, node, &image_info); if (ret < 0) |