diff options
Diffstat (limited to 'common/spl/spl_fit.c')
-rw-r--r-- | common/spl/spl_fit.c | 193 |
1 files changed, 150 insertions, 43 deletions
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 32d9ee59012..72ae8f4c503 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -2,7 +2,7 @@ * Copyright (C) 2016 Google, Inc * Written by Simon Glass <sjg@chromium.org> * - * SPDX-License-Identifier: GPL-2.0+ + * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> @@ -16,22 +16,24 @@ #endif /** - * spl_fit_get_image_node(): By using the matching configuration subnode, + * 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 * 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. + * @outname: Name of the image * - * Return: the node offset of the respective image node or a negative - * error number. + * Return: 0 on success, or a negative error number */ -static int spl_fit_get_image_node(const void *fit, int images, - const char *type, int index) +static int spl_fit_get_image_name(const void *fit, int images, + const char *type, int index, + char **outname) { const char *name, *str; - int node, conf_node; + __maybe_unused int node; + int conf_node; int len, i; conf_node = fit_find_config_node(fit); @@ -63,7 +65,35 @@ static int spl_fit_get_image_node(const void *fit, int images, } } + *outname = (char *)str; + return 0; +} + +/** + * 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) +{ + char *str; + int err; + int node; + + err = spl_fit_get_image_name(fit, images, type, index, &str); + if (err) + return err; + 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); @@ -116,15 +146,15 @@ static int get_aligned_image_size(struct spl_load_info *info, int data_size, * @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 + * 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) + * 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. + * 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. */ @@ -218,6 +248,73 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector, return 0; } +static int spl_fit_append_fdt(struct spl_image_info *spl_image, + struct spl_load_info *info, ulong sector, + void *fit, int images, ulong base_offset) +{ + struct spl_image_info image_info; + int node, ret; + + /* Figure out which device tree the board wants to use */ + 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. + * Align the destination address to ARCH_DMA_MINALIGN. + */ + 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; + + /* 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) + /* Try to make space, so we can inject details on the loadables */ + ret = fdt_shrink_to_minimum(spl_image->fdt_addr, 8192); +#endif + + return ret; +} + +static int spl_fit_record_loadable(const void *fit, int images, int index, + void *blob, struct spl_image_info *image) +{ + int ret = 0; +#if !CONFIG_IS_ENABLED(FIT_IMAGE_TINY) + char *name; + int node; + + ret = spl_fit_get_image_name(fit, images, "loadables", + index, &name); + if (ret < 0) + return ret; + + node = spl_fit_get_image_node(fit, images, "loadables", index); + + ret = fdt_record_loadable(blob, index, name, image->load_addr, + image->size, image->entry_point, + fdt_getprop(fit, node, "type", NULL), + fdt_getprop(fit, node, "os", NULL)); +#endif + return ret; +} + +static int spl_fit_image_get_os(const void *fit, int noffset, uint8_t *os) +{ +#if CONFIG_IS_ENABLED(FIT_IMAGE_TINY) + return -ENOTSUPP; +#else + return fit_image_get_os(fit, noffset, os); +#endif +} + int spl_load_simple_fit(struct spl_image_info *spl_image, struct spl_load_info *info, ulong sector, void *fit) { @@ -225,7 +322,6 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, ulong size; unsigned long count; struct spl_image_info image_info; - bool boot_os = false; int node = -1; int images, ret; int base_offset, align_len = ARCH_DMA_MINALIGN - 1; @@ -273,17 +369,18 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, return -1; } + /* + * Find the U-Boot image using the following search order: + * - start at 'firmware' (e.g. an ARM Trusted Firmware) + * - fall back 'kernel' (e.g. a Falcon-mode OS boot + * - fall back to using the first 'loadables' entry + */ + if (node < 0) + node = spl_fit_get_image_node(fit, images, "firmware", 0); #ifdef CONFIG_SPL_OS_BOOT - /* Find OS image first */ - node = spl_fit_get_image_node(fit, images, FIT_KERNEL_PROP, 0); if (node < 0) - debug("No kernel image.\n"); - else - boot_os = true; + node = spl_fit_get_image_node(fit, images, FIT_KERNEL_PROP, 0); #endif - /* find the U-Boot image */ - if (node < 0) - 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); @@ -305,34 +402,29 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, if (ret) return ret; -#ifdef CONFIG_SPL_OS_BOOT - if (!fit_image_get_os(fit, node, &spl_image->os)) + /* + * For backward compatibility, we treat the first node that is + * as a U-Boot image, if no OS-type has been declared. + */ + if (!spl_fit_image_get_os(fit, node, &spl_image->os)) debug("Image OS is %s\n", genimg_get_os_name(spl_image->os)); -#else - spl_image->os = IH_OS_U_BOOT; +#if !defined(CONFIG_SPL_OS_BOOT) + else + spl_image->os = IH_OS_U_BOOT; #endif - if (!boot_os) { - /* Figure out which device tree the board wants to use */ - 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. - * Align the destination address to ARCH_DMA_MINALIGN. - */ - 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; - } + /* + * Booting a next-stage U-Boot may require us to append the FDT. + * We allow this to fail, as the U-Boot image might embed its FDT. + */ + if (spl_image->os == IH_OS_U_BOOT) + spl_fit_append_fdt(spl_image, info, sector, fit, + images, base_offset); /* Now check if there are more images for us to load */ for (; ; index++) { + uint8_t os_type = IH_OS_INVALID; + node = spl_fit_get_image_node(fit, images, "loadables", index); if (node < 0) break; @@ -342,6 +434,15 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, if (ret < 0) continue; + if (!spl_fit_image_get_os(fit, node, &os_type)) + debug("Loadable is %s\n", genimg_get_os_name(os_type)); + + if (os_type == IH_OS_U_BOOT) { + spl_fit_append_fdt(&image_info, info, sector, + fit, images, base_offset); + spl_image->fdt_addr = image_info.fdt_addr; + } + /* * If the "firmware" image did not provide an entry point, * use the first valid entry point from the loadables. @@ -349,6 +450,12 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, if (spl_image->entry_point == FDT_ERROR && image_info.entry_point != FDT_ERROR) spl_image->entry_point = image_info.entry_point; + + /* Record our loadables into the FDT */ + if (spl_image->fdt_addr) + spl_fit_record_loadable(fit, images, index, + spl_image->fdt_addr, + &image_info); } /* |