diff options
author | Tom Rini <trini@konsulko.com> | 2017-05-22 14:15:16 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2017-05-22 19:20:28 +0000 |
commit | 711391131c84398d1b8256ab5a8cfa2969ad57c7 (patch) | |
tree | 0abea0dbe3971e5420557828a145275bb07bd9f9 /common | |
parent | a4b0d83b66f1cef9a93b403e4c11424b5b43b09f (diff) | |
parent | 80b51b5aa91b75d83323fd1fdd253d5f67621784 (diff) | |
download | u-boot-711391131c84398d1b8256ab5a8cfa2969ad57c7.tar.gz |
Merge git://git.denx.de/u-boot-sunxi
trini: Make Kconfig SPL_xxx entires only show if SPL, so that we don't
get Kconfig errors on platforms without SPL, ie sandbox (without SPL).
Signed-off-by: Tom Rini <trini@konsulko.com>
Diffstat (limited to 'common')
-rw-r--r-- | common/spl/spl_fit.c | 301 |
1 files changed, 196 insertions, 105 deletions
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index aae556f97d..4c42a96ca3 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -11,24 +11,30 @@ #include <libfdt.h> #include <spl.h> +#define FDT_ERROR ((ulong)(-1)) + static ulong fdt_getprop_u32(const void *fdt, int node, const char *prop) { const u32 *cell; int len; cell = fdt_getprop(fdt, node, prop, &len); - if (len != sizeof(*cell)) - return -1U; + if (!cell || len != sizeof(*cell)) + return FDT_ERROR; + return fdt32_to_cpu(*cell); } -static int spl_fit_select_fdt(const void *fdt, int images, int *fdt_offsetp) +/* + * Iterate over all /configurations subnodes and call a platform specific + * function to find the matching configuration. + * Returns the node offset or a negative error number. + */ +static int spl_fit_find_config_node(const void *fdt) { - const char *name, *fdt_name; - int conf, node, fdt_node; - int len; + const char *name; + int conf, node, len; - *fdt_offsetp = 0; conf = fdt_path_offset(fdt, FIT_CONFS_PATH); if (conf < 0) { debug("%s: Cannot find /configurations node: %d\n", __func__, @@ -50,39 +56,69 @@ static int spl_fit_select_fdt(const void *fdt, int images, int *fdt_offsetp) continue; debug("Selecting config '%s'", name); - fdt_name = fdt_getprop(fdt, node, FIT_FDT_PROP, &len); - if (!fdt_name) { - debug("%s: Cannot find fdt name property: %d\n", - __func__, len); - return -EINVAL; - } - debug(", fdt '%s'\n", fdt_name); - fdt_node = fdt_subnode_offset(fdt, images, fdt_name); - if (fdt_node < 0) { - debug("%s: Cannot find fdt node '%s': %d\n", - __func__, fdt_name, fdt_node); - return -EINVAL; + return node; + } + + return -ENOENT; +} + +/** + * spl_fit_get_image_node(): By using the matching configuration subnode, + * retrieve the name of an image, specified by a property name and an index + * into that. + * @fit: Pointer to the FDT blob. + * @images: Offset of the /images subnode. + * @type: Name of the property within the configuration subnode. + * @index: Index into the list of strings in this property. + * + * Return: the node offset of the respective image node or a negative + * error number. + */ +static int spl_fit_get_image_node(const void *fit, int images, + const char *type, int index) +{ + const char *name, *str; + int node, conf_node; + int len, i; + + conf_node = spl_fit_find_config_node(fit); + if (conf_node < 0) { +#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT + printf("No matching DT out of these options:\n"); + for (node = fdt_first_subnode(fit, conf_node); + node >= 0; + node = fdt_next_subnode(fit, node)) { + name = fdt_getprop(fit, node, "description", &len); + printf(" %s\n", name); } +#endif + return conf_node; + } - *fdt_offsetp = fdt_getprop_u32(fdt, fdt_node, "data-offset"); - len = fdt_getprop_u32(fdt, fdt_node, "data-size"); - debug("FIT: Selected '%s'\n", name); + name = fdt_getprop(fit, conf_node, type, &len); + if (!name) { + debug("cannot find property '%s': %d\n", type, len); + return -EINVAL; + } - return len; + str = name; + 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; + } } -#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT - printf("No matching DT out of these options:\n"); - for (node = fdt_first_subnode(fdt, conf); - node >= 0; - node = fdt_next_subnode(fdt, node)) { - name = fdt_getprop(fdt, node, "description", &len); - printf(" %s\n", name); + debug("%s: '%s'\n", type, str); + node = fdt_subnode_offset(fit, images, str); + if (node < 0) { + debug("cannot find image node '%s': %d\n", str, node); + return -EINVAL; } -#endif - return -ENOENT; + return node; } static int get_aligned_image_offset(struct spl_load_info *info, int offset) @@ -123,19 +159,82 @@ static int get_aligned_image_size(struct spl_load_info *info, int data_size, return (data_size + info->bl_len - 1) / info->bl_len; } +/** + * spl_load_fit_image(): load the image described in a certain FIT node + * @info: points to information about the device to load data from + * @sector: the start sector of the FIT image on the device + * @fit: points to the flattened device tree blob describing the FIT + * image + * @base_offset: the beginning of the data area containing the actual + * image data, relative to the beginning of the FIT + * @node: offset of the DT node describing the image to load (relative + * to @fit) + * @image_info: will be filled with information about the loaded image + * If the FIT node does not contain a "load" (address) property, + * the image gets loaded to the address pointed to by the + * load_addr member in this struct. + * + * Return: 0 on success or a negative error number. + */ +static int spl_load_fit_image(struct spl_load_info *info, ulong sector, + void *fit, ulong base_offset, int node, + struct spl_image_info *image_info) +{ + ulong offset; + size_t length; + ulong load_addr, load_ptr; + void *src; + ulong overhead; + int nr_sectors; + int align_len = ARCH_DMA_MINALIGN - 1; + + offset = fdt_getprop_u32(fit, node, "data-offset"); + if (offset == FDT_ERROR) + return -ENOENT; + offset += base_offset; + length = fdt_getprop_u32(fit, node, "data-size"); + if (length == FDT_ERROR) + return -ENOENT; + load_addr = fdt_getprop_u32(fit, node, "load"); + if (load_addr == FDT_ERROR && image_info) + load_addr = image_info->load_addr; + load_ptr = (load_addr + align_len) & ~align_len; + + overhead = get_aligned_image_overhead(info, offset); + nr_sectors = get_aligned_image_size(info, length, offset); + + if (info->read(info, sector + get_aligned_image_offset(info, offset), + nr_sectors, (void*)load_ptr) != nr_sectors) + return -EIO; + debug("image: dst=%lx, offset=%lx, size=%lx\n", load_ptr, offset, + (unsigned long)length); + + src = (void *)load_ptr + overhead; +#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS + board_fit_image_post_process(&src, &length); +#endif + + memcpy((void*)load_addr, src, length); + + if (image_info) { + image_info->load_addr = load_addr; + image_info->size = length; + image_info->entry_point = fdt_getprop_u32(fit, node, "entry"); + } + + return 0; +} + int spl_load_simple_fit(struct spl_image_info *spl_image, struct spl_load_info *info, ulong sector, void *fit) { int sectors; - ulong size, load; + ulong size; unsigned long count; - int node, images; - void *load_ptr; - int fdt_offset, fdt_len; - int data_offset, data_size; + struct spl_image_info image_info; + int node, images, ret; int base_offset, align_len = ARCH_DMA_MINALIGN - 1; - int src_sector; - void *dst, *src; + int index = 0; /* * Figure out where the external images start. This is the base for the @@ -168,90 +267,82 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, if (count == 0) return -EIO; - /* find the firmware image to load */ + /* find the node holding the images information */ images = fdt_path_offset(fit, FIT_IMAGES_PATH); if (images < 0) { debug("%s: Cannot find /images node: %d\n", __func__, images); return -1; } - node = fdt_first_subnode(fit, images); + + /* find the U-Boot image */ + node = spl_fit_get_image_node(fit, images, "firmware", 0); + if (node < 0) { + debug("could not find firmware image, trying loadables...\n"); + node = spl_fit_get_image_node(fit, images, "loadables", 0); + /* + * If we pick the U-Boot image from "loadables", start at + * the second image when later loading additional images. + */ + index = 1; + } if (node < 0) { - debug("%s: Cannot find first image node: %d\n", __func__, node); + debug("%s: Cannot find u-boot image node: %d\n", + __func__, node); return -1; } - /* Get its information and set up the spl_image structure */ - data_offset = fdt_getprop_u32(fit, node, "data-offset"); - data_size = fdt_getprop_u32(fit, node, "data-size"); - load = fdt_getprop_u32(fit, node, "load"); - debug("data_offset=%x, data_size=%x\n", data_offset, data_size); - spl_image->load_addr = load; - spl_image->entry_point = load; - spl_image->os = IH_OS_U_BOOT; - - /* - * Work out where to place the image. We read it so that the first - * byte will be at 'load'. This may mean we need to load it starting - * before then, since we can only read whole blocks. - */ - data_offset += base_offset; - sectors = get_aligned_image_size(info, data_size, data_offset); - load_ptr = (void *)load; - debug("U-Boot size %x, data %p\n", data_size, load_ptr); - dst = load_ptr; - - /* Read the image */ - src_sector = sector + get_aligned_image_offset(info, data_offset); - debug("Aligned image read: dst=%p, src_sector=%x, sectors=%x\n", - dst, src_sector, sectors); - count = info->read(info, src_sector, sectors, dst); - if (count != sectors) - return -EIO; - debug("image: dst=%p, data_offset=%x, size=%x\n", dst, data_offset, - data_size); - src = dst + get_aligned_image_overhead(info, data_offset); + /* Load the image and set up the spl_image structure */ + ret = spl_load_fit_image(info, sector, fit, base_offset, node, + spl_image); + if (ret) + return ret; -#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS - board_fit_image_post_process((void **)&src, (size_t *)&data_size); -#endif - - memcpy(dst, src, data_size); + spl_image->os = IH_OS_U_BOOT; /* Figure out which device tree the board wants to use */ - fdt_len = spl_fit_select_fdt(fit, images, &fdt_offset); - if (fdt_len < 0) - return fdt_len; + node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, 0); + if (node < 0) { + debug("%s: cannot find FDT node\n", __func__); + return node; + } /* - * Read the device tree and place it after the image. There may be - * some extra data before it since we can only read entire blocks. - * And also align the destination address to ARCH_DMA_MINALIGN. + * Read the device tree and place it after the image. + * Align the destination address to ARCH_DMA_MINALIGN. */ - dst = (void *)((load + data_size + align_len) & ~align_len); - fdt_offset += base_offset; - sectors = get_aligned_image_size(info, fdt_len, fdt_offset); - src_sector = sector + get_aligned_image_offset(info, fdt_offset); - count = info->read(info, src_sector, sectors, dst); - debug("Aligned fdt read: dst %p, src_sector = %x, sectors %x\n", - dst, src_sector, sectors); - if (count != sectors) - return -EIO; + image_info.load_addr = spl_image->load_addr + spl_image->size; + ret = spl_load_fit_image(info, sector, fit, base_offset, node, + &image_info); + if (ret < 0) + return ret; + + /* Now check if there are more images for us to load */ + for (; ; index++) { + node = spl_fit_get_image_node(fit, images, "loadables", index); + if (node < 0) + break; + + ret = spl_load_fit_image(info, sector, fit, base_offset, node, + &image_info); + if (ret < 0) + continue; + + /* + * If the "firmware" image did not provide an entry point, + * use the first valid entry point from the loadables. + */ + if (spl_image->entry_point == FDT_ERROR && + image_info.entry_point != FDT_ERROR) + spl_image->entry_point = image_info.entry_point; + } /* - * Copy the device tree so that it starts immediately after the image. - * After this we will have the U-Boot image and its device tree ready - * for us to start. + * If a platform does not provide CONFIG_SYS_UBOOT_START, U-Boot's + * Makefile will set it to 0 and it will end up as the entry point + * here. What it actually means is: use the load address. */ - debug("fdt: dst=%p, data_offset=%x, size=%x\n", dst, fdt_offset, - fdt_len); - src = dst + get_aligned_image_overhead(info, fdt_offset); - dst = load_ptr + data_size; - -#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS - board_fit_image_post_process((void **)&src, (size_t *)&fdt_len); -#endif - - memcpy(dst, src, fdt_len); + if (spl_image->entry_point == FDT_ERROR || spl_image->entry_point == 0) + spl_image->entry_point = spl_image->load_addr; return 0; } |