* 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>
#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);
}
}
+ *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);
* @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.
*/
int align_len = ARCH_DMA_MINALIGN - 1;
uint8_t image_comp = -1, type = -1;
const void *data;
+ bool external_data = false;
if (IS_ENABLED(CONFIG_SPL_OS_BOOT) && IS_ENABLED(CONFIG_SPL_GZIP)) {
if (fit_image_get_comp(fit, node, &image_comp))
if (fit_image_get_load(fit, node, &load_addr))
load_addr = image_info->load_addr;
- if (!fit_image_get_data_offset(fit, node, &offset)) {
- /* External data */
+ if (!fit_image_get_data_position(fit, node, &offset)) {
+ external_data = true;
+ } else if (!fit_image_get_data_offset(fit, node, &offset)) {
offset += base_offset;
+ external_data = true;
+ }
+
+ if (external_data) {
+ /* External data */
if (fit_image_get_data_size(fit, node, &len))
return -ENOENT;
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)
{
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;
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);
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;
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.
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);
}
/*