Hi Simon, On 28/01/2016 17:39, Simon Glass wrote: > This provides a way to load a FIT containing U-Boot and a selection of device > tree files. The board can select the correct device tree by probing the > hardware. Then U-Boot is started with the selected device tree. > > Signed-off-by: Simon Glass <s...@chromium.org> > --- > > Kconfig | 11 +++ > common/spl/Makefile | 1 + > common/spl/spl_fit.c | 192 > +++++++++++++++++++++++++++++++++++++++++++++++++++ > include/spl.h | 18 +++++ > 4 files changed, 222 insertions(+) > create mode 100644 common/spl/spl_fit.c > > diff --git a/Kconfig b/Kconfig > index 3ce5ba1..f32c6c7 100644 > --- a/Kconfig > +++ b/Kconfig > @@ -215,6 +215,17 @@ config SYS_TEXT_BASE > help > TODO: Move CONFIG_SYS_TEXT_BASE for all the architecture > > +config SPL_LOAD_FIT > + bool "Enable SPL loading U-Boot as a FIT" > + depends on FIT > + help > + Normally with the SPL framework a legacy image is generated as part > + of the build. This contains U-Boot along with information as to > + where it should be loaded. This option instead enables generation > + of a FIT (Flat Image Tree) which provides more flexibility. In > + particular it can handle selecting from multiple device tree > + and passing the correct one to U-Boot. > + > config SYS_CLK_FREQ > depends on ARC || ARCH_SUNXI > int "CPU clock frequency" > diff --git a/common/spl/Makefile b/common/spl/Makefile > index 10a4589..2e0f695 100644 > --- a/common/spl/Makefile > +++ b/common/spl/Makefile > @@ -10,6 +10,7 @@ > > ifdef CONFIG_SPL_BUILD > obj-$(CONFIG_SPL_FRAMEWORK) += spl.o > +obj-$(CONFIG_SPL_LOAD_FIT) += spl_fit.o > obj-$(CONFIG_SPL_NOR_SUPPORT) += spl_nor.o > obj-$(CONFIG_SPL_YMODEM_SUPPORT) += spl_ymodem.o > obj-$(CONFIG_SPL_NAND_SUPPORT) += spl_nand.o > diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c > new file mode 100644 > index 0000000..f225f64 > --- /dev/null > +++ b/common/spl/spl_fit.c > @@ -0,0 +1,192 @@ > +/* > + * Copyright (C) 2016 Google, Inc > + * Written by Simon Glass <s...@chromium.org> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <errno.h> > +#include <spl.h> > +
I would like to test your patchset, I am trying with a i.MX6 (I want to build wandboard). It looks like that image.h is missing here. common/spl/spl_fit.c: In function 'fdt_getprop_u32': common/spl/spl_fit.c:20:2: warning: implicit declaration of function 'fdt_getprop' [-Wimplicit-function-declaration] However, in image.h it looks like that IMAGE_USE_FIT is not correctly set. I am looking why, I have just added these to wandboard_defconfig: +CONFIG_FIT=y +CONFIG_SPL_OF_LIBFDT=y +CONFIG_SPL_LOAD_FIT=y +CONFIG_OF_LIST="wandboard" Best regards, Stefano > +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; > + return fdt32_to_cpu(*cell); > +} > + > +static int spl_fit_select_fdt(const void *fdt, int images, int *fdt_offsetp) > +{ > + const char *name, *fdt_name; > + int conf, node, fdt_node; > + int len; > + > + *fdt_offsetp = 0; > + conf = fdt_path_offset(fdt, FIT_CONFS_PATH); > + if (conf < 0) { > + debug("%s: Cannot find /configurations node: %d\n", __func__, > + conf); > + return -EINVAL; > + } > + for (node = fdt_first_subnode(fdt, conf); > + node >= 0; > + node = fdt_next_subnode(fdt, node)) { > + name = fdt_getprop(fdt, node, "description", &len); > + if (!name) > + return -EINVAL; > + if (board_fit_config_name_match(name)) > + 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; > + } > + > + *fdt_offsetp = fdt_getprop_u32(fdt, fdt_node, "data-offset"); > + len = fdt_getprop_u32(fdt, fdt_node, "data-size"); > +#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT > + printf("FIT: Selected '%s'\n", name); > +#endif > + > + return len; > + } > + > +#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, "name", &len); > + printf(" %s\n", name); > + } > +#endif > + > + return -ENOENT; > +} > + > +int spl_load_simple_fit(struct spl_load_info *info, ulong sector, void *fit) > +{ > + int sectors; > + ulong size, load; > + unsigned long count; > + int node, images; > + void *load_ptr; > + int fdt_offset, fdt_len; > + int data_offset, data_size; > + int base_offset; > + int src_sector; > + void *dst; > + > + /* > + * Figure out where the external images start. This is the base for the > + * data-offset properties in each image. > + */ > + size = fdt_totalsize(fit); > + size = (size + 3) & ~3; > + base_offset = (size + 3) & ~3; > + > + /* > + * So far we only have one block of data from the FIT. Read the entire > + * thing, including that first block, placing it so it finishes before > + * where we will load the image. > + * > + * Note that we will load the image such that its first byte will be > + * at the load address. Since that byte may be part-way through a > + * block, we may load the image up to one block before the load > + * address. So take account of that here by subtracting an addition > + * block length from the FIT start position. > + * > + * In fact the FIT has its own load address, but we assume it cannot > + * be before CONFIG_SYS_TEXT_BASE. > + */ > + fit = (void *)(CONFIG_SYS_TEXT_BASE - size - info->bl_len); > + sectors = (size + info->bl_len - 1) / info->bl_len; > + count = info->read(info, sector, sectors, fit); > + debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu\n", > + sector, sectors, fit, count); > + if (count == 0) > + return -EIO; > + > + /* find the firmware image to load */ > + 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); > + if (node < 0) { > + debug("%s: Cannot find first 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. > + */ > + sectors = (data_size + info->bl_len - 1) / info->bl_len; > + data_offset += base_offset; > + load_ptr = (void *)load; > + debug("U-Boot size %x, data %p\n", data_size, load_ptr); > + dst = load_ptr - (data_offset % info->bl_len); > + > + /* Read the image */ > + src_sector = sector + data_offset / info->bl_len; > + debug("image: data_offset=%x, dst=%p, src_sector=%x, sectors=%x\n", > + data_offset, dst, src_sector, sectors); > + count = info->read(info, src_sector, sectors, dst); > + if (count != sectors) > + return -EIO; > + > + /* 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; > + > + /* > + * 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. > + */ > + dst = load_ptr + data_size; > + fdt_offset += base_offset; > + count = info->read(info, sector + fdt_offset / info->bl_len, sectors, > + dst); > + debug("fit read %x sectors to %x, dst %p, data_offset %x\n", > + sectors, spl_image.load_addr, dst, fdt_offset); > + if (count != sectors) > + return -EIO; > + > + /* > + * 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. > + */ > + memcpy(dst, dst + fdt_offset % info->bl_len, fdt_len); > + > + return 0; > +} > diff --git a/include/spl.h b/include/spl.h > index 92cdc04..16f2f6a 100644 > --- a/include/spl.h > +++ b/include/spl.h > @@ -29,6 +29,24 @@ struct spl_image_info { > u32 flags; > }; > > +/* > + * Information required to load data from a device > + * > + * @dev: Pointer to the device, e.g. struct mmc * > + * @priv: Private data for the device > + * @bl_len: Block length for reading in bytes > + * @read: Function to call to read from the device > + */ > +struct spl_load_info { > + void *dev; > + void *priv; > + int bl_len; > + ulong (*read)(struct spl_load_info *load, ulong sector, ulong count, > + void *buf); > +}; > + > +int spl_load_simple_fit(struct spl_load_info *info, ulong sector, void *fdt); > + > #define SPL_COPY_PAYLOAD_ONLY 1 > > extern struct spl_image_info spl_image; > -- ===================================================================== DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sba...@denx.de ===================================================================== _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot