[U-Boot] [PATCH v3 0/9] spl: dm: Make it possible for the SPL to pick its own DTB from a FIT

Following the RFC, here is the series implementing the mechanism in a cleaner way. The idea is that the SPL may take advantage of selecting its DTB from a pool of available DTBs. To do that several DTBs are embedded in a compressed FIT image appended at the end of the SPL. The patch is done in such way that this mechanism can easily be extended to other ways of loading the DTBs.
Here are some numbers: +----------------------------------------+ | Size |delta |boot-time| delta | | (bytes) |(bytes) |(ms) | (ms) | +---------------------------------------------------------------+ | reference | 120185 | | 1331 | | +---------------------------------------------------------------+ | feature | | | | | | deactiVated | 120185 | 0 | 1330 | -1 | +---------------------------------------------------------------+ | 1 DTB LZO | 120208 | 23 | 1331 | 0 | +---------------------------------------------------------------+ | 4 DTB LZO | 120810 | 625 | 1336 | 5 | +---------------------------------------------------------------+ | 4 DTB LZO | | | | | | no malloc | 120746 | 561 | 1343 | 12 | +---------------------------------------------------------------+ | 4 DTB GZIP | 128552 | 8367 | 1353 | 22 | +---------------------------------------------------------------+ | 4 DTB No comp | 132352 | 12167 | 1351 | 20 | +----------------------+----------+----------+---------+--------+
changes since v2: - rebased on u-boot/master - improved help in Kconfig for the compression options in SPL - improved commit message for patch #1 - Added some comments to describe locate_dtb_in_fit() and fit_find_config_node() - Added a description of the mecanism in a README
changes since v1: - improved help in Kconfig for the SPL_MULTI_DTB_FIT option - Added "reviewed-by" tags
changes since RFC: - split the RFC patch in several patches. - leverage work from Cooper Jr., Franklin (CONFIG_FIT_EMBED) as a big part of the code is similar. Rename CONFIG_FIT_EMBED as CONFIG_MULTI_DTB_FIT to prevent confusion with CONFIG_OF_EMBED. - use the default configuration if no match is provided by board_fit_config_name_match(). note that this is generic not just for this feature. - provide an option to not use dynamic memory allocation. - added a patch related to board detection on omap that's required to take advantage of this feature.
Jean-Jacques Hiblot (9): dts: renamed FIT_EMBED to MULTI_DTB_FIT and moved it to the dts Kconfig fit: use 'const' for the input of fdt_offset() and locate_dtb_in_fit() fit: fixed bug in locate_dtb_in_fit() fit: If no matching config is found in fit_find_config_node(), use the default one lzo: add a function to check the validity of the header gzip: add a function to parse the header lib: allow building lzo and gunzip for the SPL spl: dm: Make it possible for the SPL to pick its own DTB from a FIT omap: detect board before spl_early_init()
Makefile | 2 +- arch/arm/mach-omap2/hwinit-common.c | 4 +- board/ti/ks2_evm/board_k2e.c | 2 +- board/ti/ks2_evm/board_k2g.c | 2 +- board/ti/ks2_evm/board_k2hk.c | 2 +- board/ti/ks2_evm/board_k2l.c | 2 +- common/Kconfig | 16 ------ common/Makefile | 2 +- common/boot_fit.c | 6 +-- common/common_fit.c | 20 +++++++ configs/k2e_evm_defconfig | 2 +- configs/k2g_evm_defconfig | 2 +- configs/k2hk_evm_defconfig | 2 +- configs/k2l_evm_defconfig | 2 +- doc/README.multi-dtb-fit | 49 +++++++++++++++++ dts/Kconfig | 103 +++++++++++++++++++++++++++++++++++- include/boot_fit.h | 9 +++- include/common.h | 1 + include/image.h | 13 +++++ include/linux/lzo.h | 3 ++ lib/Kconfig | 17 +++++- lib/Makefile | 6 +-- lib/fdtdec.c | 85 +++++++++++++++++++++++++---- lib/gunzip.c | 15 ++++-- lib/lzo/lzo1x_decompress.c | 21 ++++++-- scripts/Makefile.spl | 35 +++++++++++- 26 files changed, 369 insertions(+), 54 deletions(-) create mode 100644 doc/README.multi-dtb-fit

CONFIG_FIT_EMBED might be confused with CONFIG_OF_EMBED, rename it MULTI_DTB_FIT as it is able to get a DTB from a FIT image containing multiple DTBs. Also move the option to the Kconfig dedicated to the DTS options and create a README for this feature.
Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com Reviewed-by: Simon Glass sjg@chromium.org ---
changes since v2: Added a READ file to explain the feature
Makefile | 2 +- board/ti/ks2_evm/board_k2e.c | 2 +- board/ti/ks2_evm/board_k2g.c | 2 +- board/ti/ks2_evm/board_k2hk.c | 2 +- board/ti/ks2_evm/board_k2l.c | 2 +- common/Kconfig | 16 ---------------- common/Makefile | 2 +- configs/k2e_evm_defconfig | 2 +- configs/k2g_evm_defconfig | 2 +- configs/k2hk_evm_defconfig | 2 +- configs/k2l_evm_defconfig | 2 +- doc/README.multi-dtb-fit | 9 +++++++++ dts/Kconfig | 20 +++++++++++++++++++- lib/fdtdec.c | 2 +- 14 files changed, 39 insertions(+), 28 deletions(-) create mode 100644 doc/README.multi-dtb-fit
diff --git a/Makefile b/Makefile index 50a002e..d5869e1 100644 --- a/Makefile +++ b/Makefile @@ -876,7 +876,7 @@ dts/dt.dtb: checkdtc u-boot quiet_cmd_copy = COPY $@ cmd_copy = cp $< $@
-ifeq ($(CONFIG_FIT_EMBED),y) +ifeq ($(CONFIG_MULTI_DTB_FIT),y)
fit-dtb.blob: dts/dt.dtb FORCE $(call if_changed,mkimage) diff --git a/board/ti/ks2_evm/board_k2e.c b/board/ti/ks2_evm/board_k2e.c index 266a66b..6c77d91 100644 --- a/board/ti/ks2_evm/board_k2e.c +++ b/board/ti/ks2_evm/board_k2e.c @@ -166,7 +166,7 @@ int get_num_eth_ports(void) } #endif
-#if defined(CONFIG_FIT_EMBED) +#if defined(CONFIG_MULTI_DTB_FIT) int board_fit_config_name_match(const char *name) { if (!strcmp(name, "keystone-k2e-evm")) diff --git a/board/ti/ks2_evm/board_k2g.c b/board/ti/ks2_evm/board_k2g.c index 2160576..b1dd606 100644 --- a/board/ti/ks2_evm/board_k2g.c +++ b/board/ti/ks2_evm/board_k2g.c @@ -216,7 +216,7 @@ int board_mmc_init(bd_t *bis) } #endif
-#if defined(CONFIG_FIT_EMBED) +#if defined(CONFIG_MULTI_DTB_FIT) int board_fit_config_name_match(const char *name) { bool eeprom_read = board_ti_was_eeprom_read(); diff --git a/board/ti/ks2_evm/board_k2hk.c b/board/ti/ks2_evm/board_k2hk.c index c733099..e99e635 100644 --- a/board/ti/ks2_evm/board_k2hk.c +++ b/board/ti/ks2_evm/board_k2hk.c @@ -150,7 +150,7 @@ int board_early_init_f(void) } #endif
-#if defined(CONFIG_FIT_EMBED) +#if defined(CONFIG_MULTI_DTB_FIT) int board_fit_config_name_match(const char *name) { if (!strcmp(name, "keystone-k2hk-evm")) diff --git a/board/ti/ks2_evm/board_k2l.c b/board/ti/ks2_evm/board_k2l.c index 166367b..c65f331 100644 --- a/board/ti/ks2_evm/board_k2l.c +++ b/board/ti/ks2_evm/board_k2l.c @@ -138,7 +138,7 @@ int board_early_init_f(void) } #endif
-#if defined(CONFIG_FIT_EMBED) +#if defined(CONFIG_MULTI_DTB_FIT) int board_fit_config_name_match(const char *name) { if (!strcmp(name, "keystone-k2l-evm")) diff --git a/common/Kconfig b/common/Kconfig index 0983891..3c7e3a2 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -810,22 +810,6 @@ config SYS_STDIO_DEREGISTER
endmenu
-config DTB_RESELECT - bool "Support swapping dtbs at a later point in boot" - depends on FIT_EMBED - help - It is possible during initial boot you may need to use a generic - dtb until you can fully determine the board your running on. This - config allows boards to implement a function at a later point - during boot to switch to the "correct" dtb. - -config FIT_EMBED - bool "Support a FIT image embedded in the U-boot image" - help - This option provides hooks to allow U-boot to parse an - appended FIT image and enable board specific code to then select - the correct DTB to be used. - config DEFAULT_FDT_FILE string "Default fdt file" help diff --git a/common/Makefile b/common/Makefile index 60681c8..3bff64f 100644 --- a/common/Makefile +++ b/common/Makefile @@ -148,7 +148,7 @@ obj-y += image.o obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o obj-$(CONFIG_$(SPL_)OF_LIBFDT) += image-fdt.o obj-$(CONFIG_$(SPL_)FIT) += image-fit.o -obj-$(CONFIG_FIT_EMBED) += boot_fit.o common_fit.o +obj-$(CONFIG_$(SPL_)MULTI_DTB_FIT) += boot_fit.o common_fit.o obj-$(CONFIG_$(SPL_)FIT_SIGNATURE) += image-sig.o obj-$(CONFIG_IO_TRACE) += iotrace.o obj-y += memsize.o diff --git a/configs/k2e_evm_defconfig b/configs/k2e_evm_defconfig index b3763e4..291b377 100644 --- a/configs/k2e_evm_defconfig +++ b/configs/k2e_evm_defconfig @@ -13,7 +13,7 @@ CONFIG_OF_BOARD_SETUP=y CONFIG_ENV_IS_IN_NAND=y CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_DTB_RESELECT=y -CONFIG_FIT_EMBED=y +CONFIG_MULTI_DTB_FIT=y CONFIG_VERSION_VARIABLE=y CONFIG_BOARD_EARLY_INIT_F=y CONFIG_SPL=y diff --git a/configs/k2g_evm_defconfig b/configs/k2g_evm_defconfig index 1eed605..3ac5905 100644 --- a/configs/k2g_evm_defconfig +++ b/configs/k2g_evm_defconfig @@ -12,7 +12,7 @@ CONFIG_DEFAULT_DEVICE_TREE="keystone-k2g-evm" CONFIG_OF_BOARD_SETUP=y CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_DTB_RESELECT=y -CONFIG_FIT_EMBED=y +CONFIG_MULTI_DTB_FIT=y CONFIG_VERSION_VARIABLE=y CONFIG_BOARD_EARLY_INIT_F=y CONFIG_SPL=y diff --git a/configs/k2hk_evm_defconfig b/configs/k2hk_evm_defconfig index 59cd9ef..d0eef23 100644 --- a/configs/k2hk_evm_defconfig +++ b/configs/k2hk_evm_defconfig @@ -13,7 +13,7 @@ CONFIG_OF_BOARD_SETUP=y CONFIG_ENV_IS_IN_NAND=y CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_DTB_RESELECT=y -CONFIG_FIT_EMBED=y +CONFIG_MULTI_DTB_FIT=y CONFIG_VERSION_VARIABLE=y CONFIG_BOARD_EARLY_INIT_F=y CONFIG_SPL=y diff --git a/configs/k2l_evm_defconfig b/configs/k2l_evm_defconfig index db45fe1..e87c4ce 100644 --- a/configs/k2l_evm_defconfig +++ b/configs/k2l_evm_defconfig @@ -13,7 +13,7 @@ CONFIG_OF_BOARD_SETUP=y CONFIG_ENV_IS_IN_NAND=y CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_DTB_RESELECT=y -CONFIG_FIT_EMBED=y +CONFIG_MULTI_DTB_FIT=y CONFIG_VERSION_VARIABLE=y CONFIG_BOARD_EARLY_INIT_F=y CONFIG_SPL=y diff --git a/doc/README.multi-dtb-fit b/doc/README.multi-dtb-fit new file mode 100644 index 0000000..d182d4e --- /dev/null +++ b/doc/README.multi-dtb-fit @@ -0,0 +1,9 @@ +MULTI DTB FIT + +The purpose of this feature is to enable u-boot to select its DTB from a FIT +image appended at the end of the binary. + +Usually the DTB is selected by the SPL and passed down to u-boot. But some +platforms don't use the SPL. In this case MULTI_DTB_FIT can used to provide +u-boot with a choice of DTBs. The FIT image is automatically image at the end +of the compilation and appended to u-boot.bin diff --git a/dts/Kconfig b/dts/Kconfig index 1bc9656..c78438a 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -90,7 +90,7 @@ config DEFAULT_DEVICE_TREE
config OF_LIST string "List of device tree files to include for DT control" - depends on SPL_LOAD_FIT || FIT_EMBED + depends on SPL_LOAD_FIT || MULTI_DTB_FIT default DEFAULT_DEVICE_TREE help This option specifies a list of device tree files to use for DT @@ -100,6 +100,24 @@ config OF_LIST device tree files (without the directory or .dtb suffix) separated by <space>.
+ +config DTB_RESELECT + bool "Support swapping dtbs at a later point in boot" + depends on MULTI_DTB_FIT + help + It is possible during initial boot you may need to use a generic + dtb until you can fully determine the board your running on. This + config allows boards to implement a function at a later point + during boot to switch to the "correct" dtb. + +config MULTI_DTB_FIT + bool "support embedding several DTBs in a FIT image for u-boot" + help + This option provides hooks to allow U-boot to parse an + appended FIT image and enable board specific code to then select + the correct DTB to be used. Use this if you need to support + multiple DTBs but don't use the SPL. + config OF_SPL_REMOVE_PROPS string "List of device tree properties to drop for SPL" depends on SPL_OF_CONTROL diff --git a/lib/fdtdec.c b/lib/fdtdec.c index d2dbd0f..0374f21 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1217,7 +1217,7 @@ int fdtdec_setup(void) else gd->fdt_blob = (ulong *)&__bss_end;
-# elif defined CONFIG_FIT_EMBED +# elif defined CONFIG_MULTI_DTB_FIT gd->fdt_blob = locate_dtb_in_fit(&_end);
if (gd->fdt_blob == NULL || gd->fdt_blob <= ((void *)&_end)) {

Those 2 functions don't modify their input, we can mark it const. This prevents compilation warnings when they are provided const input.
Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com --- changes since v2: Added a comment describing the function locate_dtb_in_fit()
common/boot_fit.c | 4 ++-- include/boot_fit.h | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/common/boot_fit.c b/common/boot_fit.c index 51440a6..3767c63 100644 --- a/common/boot_fit.c +++ b/common/boot_fit.c @@ -13,7 +13,7 @@ #include <image.h> #include <libfdt.h>
-int fdt_offset(void *fit) +static int fdt_offset(const void *fit) { int images, node, fdt_len, fdt_node, fdt_offset; const char *fdt_name; @@ -55,7 +55,7 @@ int fdt_offset(void *fit) return fdt_offset; }
-void *locate_dtb_in_fit(void *fit) +void *locate_dtb_in_fit(const void *fit) { struct image_header *header; int size; diff --git a/include/boot_fit.h b/include/boot_fit.h index b7d2462..ac9590d 100644 --- a/include/boot_fit.h +++ b/include/boot_fit.h @@ -5,5 +5,10 @@ * SPDX-License-Identifier: GPL-2.0+ */
-int fdt_offset(void *fit); -void *locate_dtb_in_fit(void *fit); +/** + * locate_dtb_in_fit - Find a DTB matching the board in a FIT image + * @fit: pointer to the FIT image + * + * @Return a pointer to a matching DTB blob + */ +void *locate_dtb_in_fit(const void *fit);

On 4 August 2017 at 11:00, Jean-Jacques Hiblot jjhiblot@ti.com wrote:
Those 2 functions don't modify their input, we can mark it const. This prevents compilation warnings when they are provided const input.
Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com
changes since v2: Added a comment describing the function locate_dtb_in_fit()
common/boot_fit.c | 4 ++-- include/boot_fit.h | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
nit: @return (lower case)
Also, what does it return if there is no matching blob?

If the dtb is the first data of the FIT, the its offset is 0x0. Change the test to '<' instead of '<='
Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com ---
no change since v2
common/boot_fit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/boot_fit.c b/common/boot_fit.c index 3767c63..8e81745 100644 --- a/common/boot_fit.c +++ b/common/boot_fit.c @@ -73,7 +73,7 @@ void *locate_dtb_in_fit(const void *fit)
ret = fdt_offset(fit);
- if (ret <= 0) + if (ret < 0) return NULL; else return (void *)fit+size+ret;

On 4 August 2017 at 11:00, Jean-Jacques Hiblot jjhiblot@ti.com wrote:
If the dtb is the first data of the FIT, the its offset is 0x0. Change the test to '<' instead of '<='
Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com
no change since v2
common/boot_fit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org

If board_fit_config_name_match() doesn't match any configuration node, then use the default one (if provided).
Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com --- changes since v2: Added a comment describing the function fit_find_config_node()
common/common_fit.c | 20 ++++++++++++++++++++ include/image.h | 13 +++++++++++++ 2 files changed, 33 insertions(+)
diff --git a/common/common_fit.c b/common/common_fit.c index 5f5f3f9..85b33d8 100644 --- a/common/common_fit.c +++ b/common/common_fit.c @@ -32,6 +32,9 @@ int fit_find_config_node(const void *fdt) { const char *name; int conf, node, len; + const char *dflt_conf_name; + const char *dflt_conf_desc = NULL; + int dflt_conf_node = -ENOENT;
conf = fdt_path_offset(fdt, FIT_CONFS_PATH); if (conf < 0) { @@ -39,6 +42,9 @@ int fit_find_config_node(const void *fdt) conf); return -EINVAL; } + + dflt_conf_name = fdt_getprop(fdt, conf, "default", &len); + for (node = fdt_first_subnode(fdt, conf); node >= 0; node = fdt_next_subnode(fdt, node)) { @@ -50,6 +56,15 @@ int fit_find_config_node(const void *fdt) #endif return -EINVAL; } + + if (dflt_conf_name) { + const char *node_name = fdt_get_name(fdt, node, NULL); + if (strcmp(dflt_conf_name, node_name) == 0) { + dflt_conf_node = node; + dflt_conf_desc = name; + } + } + if (board_fit_config_name_match(name)) continue;
@@ -58,5 +73,10 @@ int fit_find_config_node(const void *fdt) return node; }
+ if (dflt_conf_node != -ENOENT) { + debug("Selecting default config '%s'", dflt_conf_desc); + return dflt_conf_node; + } + return -ENOENT; } diff --git a/include/image.h b/include/image.h index c6f1513..c981600 100644 --- a/include/image.h +++ b/include/image.h @@ -1273,6 +1273,19 @@ void board_fit_image_post_process(void **p_image, size_t *p_size); #define FDT_ERROR ((ulong)(-1))
ulong fdt_getprop_u32(const void *fdt, int node, const char *prop); + +/** + * fit_find_config_node() - Find the node for the best DTB in a FIT image + * + * A FIT image contains one or more DTBs. This functions parses the + * configurations described in the FIT images and returns the node of + * the first matching DTB. To check if a DTB matches a board, this function + * calls board_fit_config_name_match(). If no matching DTB is found, it returns + * the node described by the default configuration if it exits. + * + * @fdt: pointer to flat device tree + * @return the node if found, -ev otherwise + */ int fit_find_config_node(const void *fdt);
/**

On 4 August 2017 at 11:00, Jean-Jacques Hiblot jjhiblot@ti.com wrote:
If board_fit_config_name_match() doesn't match any configuration node, then use the default one (if provided).
Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com
changes since v2: Added a comment describing the function fit_find_config_node()
common/common_fit.c | 20 ++++++++++++++++++++ include/image.h | 13 +++++++++++++ 2 files changed, 33 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
See below
diff --git a/common/common_fit.c b/common/common_fit.c index 5f5f3f9..85b33d8 100644 --- a/common/common_fit.c +++ b/common/common_fit.c @@ -32,6 +32,9 @@ int fit_find_config_node(const void *fdt) { const char *name; int conf, node, len;
const char *dflt_conf_name;
const char *dflt_conf_desc = NULL;
int dflt_conf_node = -ENOENT; conf = fdt_path_offset(fdt, FIT_CONFS_PATH); if (conf < 0) {
@@ -39,6 +42,9 @@ int fit_find_config_node(const void *fdt) conf); return -EINVAL; }
dflt_conf_name = fdt_getprop(fdt, conf, "default", &len);
for (node = fdt_first_subnode(fdt, conf); node >= 0; node = fdt_next_subnode(fdt, node)) {
@@ -50,6 +56,15 @@ int fit_find_config_node(const void *fdt) #endif return -EINVAL; }
if (dflt_conf_name) {
const char *node_name = fdt_get_name(fdt, node, NULL);
if (strcmp(dflt_conf_name, node_name) == 0) {
dflt_conf_node = node;
dflt_conf_desc = name;
}
}
if (board_fit_config_name_match(name)) continue;
@@ -58,5 +73,10 @@ int fit_find_config_node(const void *fdt) return node; }
if (dflt_conf_node != -ENOENT) {
debug("Selecting default config '%s'", dflt_conf_desc);
return dflt_conf_node;
}
return -ENOENT;
} diff --git a/include/image.h b/include/image.h index c6f1513..c981600 100644 --- a/include/image.h +++ b/include/image.h @@ -1273,6 +1273,19 @@ void board_fit_image_post_process(void **p_image, size_t *p_size); #define FDT_ERROR ((ulong)(-1))
ulong fdt_getprop_u32(const void *fdt, int node, const char *prop);
+/**
- fit_find_config_node() - Find the node for the best DTB in a FIT image
- A FIT image contains one or more DTBs. This functions parses the
function
- configurations described in the FIT images and returns the node of
- the first matching DTB. To check if a DTB matches a board, this function
- calls board_fit_config_name_match(). If no matching DTB is found, it returns
- the node described by the default configuration if it exits.
exists
- @fdt: pointer to flat device tree
- @return the node if found, -ev otherwise
-ve
- */
int fit_find_config_node(const void *fdt);
/**
1.9.1

Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com Reviewed-by: Simon Glass sjg@chromium.org ---
no change since v2
include/linux/lzo.h | 3 +++ lib/lzo/lzo1x_decompress.c | 21 +++++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/include/linux/lzo.h b/include/linux/lzo.h index 88687fa..8981d04 100644 --- a/include/linux/lzo.h +++ b/include/linux/lzo.h @@ -31,6 +31,9 @@ int lzo1x_decompress_safe(const unsigned char *src, size_t src_len, int lzop_decompress(const unsigned char *src, size_t src_len, unsigned char *dst, size_t *dst_len);
+/* check if the header is valid (based on magic numbers) */ +bool lzop_is_valid_header(const unsigned char *src); + /* * Return values (< 0 = Error) */ diff --git a/lib/lzo/lzo1x_decompress.c b/lib/lzo/lzo1x_decompress.c index ccc90b8..65fef0b 100644 --- a/lib/lzo/lzo1x_decompress.c +++ b/lib/lzo/lzo1x_decompress.c @@ -30,16 +30,29 @@ static const unsigned char lzop_magic[] = {
#define HEADER_HAS_FILTER 0x00000800L
-static inline const unsigned char *parse_header(const unsigned char *src) + +bool lzop_is_valid_header(const unsigned char *src) { - u16 version; int i; - /* read magic: 9 first bytes */ for (i = 0; i < ARRAY_SIZE(lzop_magic); i++) { if (*src++ != lzop_magic[i]) - return NULL; + return false; } + return true; +} + +static inline const unsigned char *parse_header(const unsigned char *src) +{ + u16 version; + int i; + + if (!lzop_is_valid_header(src)) + return NULL; + + /* skip header */ + src += 9; + /* get version (2bytes), skip library version (2), * 'need to be extracted' version (2) and * method (1) */

Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com Reviewed-by: Simon Glass sjg@chromium.org ---
no change since v2
include/common.h | 1 + lib/gunzip.c | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/include/common.h b/include/common.h index c8fb277..8678275 100644 --- a/include/common.h +++ b/include/common.h @@ -568,6 +568,7 @@ ulong usec2ticks (unsigned long usec); ulong ticks2usec (unsigned long ticks);
/* lib/gunzip.c */ +int gzip_parse_header(const unsigned char *src, unsigned long len); int gunzip(void *, int, unsigned char *, unsigned long *); int zunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp, int stoponerr, int offset); diff --git a/lib/gunzip.c b/lib/gunzip.c index 832b306..adb86c7 100644 --- a/lib/gunzip.c +++ b/lib/gunzip.c @@ -42,7 +42,7 @@ void gzfree(void *x, void *addr, unsigned nb) free (addr); }
-int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp) +int gzip_parse_header(const unsigned char *src, unsigned long len) { int i, flags;
@@ -63,12 +63,21 @@ int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp) ; if ((flags & HEAD_CRC) != 0) i += 2; - if (i >= *lenp) { + if (i >= len) { puts ("Error: gunzip out of data in header\n"); return (-1); } + return i; +} + +int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp) +{ + int offset = gzip_parse_header(src, *lenp); + + if (offset < 0) + return offset;
- return zunzip(dst, dstlen, src, lenp, 1, i); + return zunzip(dst, dstlen, src, lenp, 1, offset); }
#ifdef CONFIG_CMD_UNZIP

Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com ---
changes since v2 : Add some help for the options. except for SPL_ZLIB which is automatically selected by SPL_GZIP
lib/Kconfig | 17 ++++++++++++++++- lib/Makefile | 6 +++--- 2 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/lib/Kconfig b/lib/Kconfig index 2f5a210..5b90a91 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -159,7 +159,22 @@ config LZMA config LZO bool "Enable LZO decompression support" help - This enables support for LZO compression algorithm.r + This enables support for LZO compression algorithm. + +config SPL_LZO + bool "Enable LZO decompression support in SPL" + help + This enables support for LZO compression algorithm in the SPL. + +config SPL_GZIP + bool "Enable GZIP decompression support in SPL" + select SPL_ZLIB + help + This enables support for GZIP compression algorithm in the SPL. + +config SPL_ZLIB + bool + endmenu
config ERRNO_STR diff --git a/lib/Makefile b/lib/Makefile index eacc7d6..21cd4e2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -4,14 +4,15 @@ # # SPDX-License-Identifier: GPL-2.0+ # +obj-$(CONFIG_$(SPL_)ZLIB) += zlib/ +obj-$(CONFIG_$(SPL_)GZIP) += gunzip.o +obj-$(CONFIG_$(SPL_)LZO) += lzo/
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_EFI) += efi/ obj-$(CONFIG_EFI_LOADER) += efi_loader/ obj-$(CONFIG_LZMA) += lzma/ -obj-$(CONFIG_LZO) += lzo/ -obj-$(CONFIG_ZLIB) += zlib/ obj-$(CONFIG_BZIP2) += bzip2/ obj-$(CONFIG_TIZEN) += tizen/ obj-$(CONFIG_FIT) += libfdt/ @@ -26,7 +27,6 @@ obj-y += crc16.o obj-$(CONFIG_ERRNO_STR) += errno_str.o obj-$(CONFIG_FIT) += fdtdec_common.o obj-$(CONFIG_TEST_FDTDEC) += fdtdec_test.o -obj-$(CONFIG_GZIP) += gunzip.o obj-$(CONFIG_GZIP_COMPRESSED) += gzip.o obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += smbios.o obj-y += initcall.o

On 4 August 2017 at 11:01, Jean-Jacques Hiblot jjhiblot@ti.com wrote:
Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com
changes since v2 : Add some help for the options. except for SPL_ZLIB which is automatically selected by SPL_GZIP
lib/Kconfig | 17 ++++++++++++++++- lib/Makefile | 6 +++--- 2 files changed, 19 insertions(+), 4 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

u-boot can be embedded within a FIT image with multiple DTBs. It then selects at run-time which one is best suited for the platform. Use the same principle here for the SPL: put the DTBs in a FIT image, compress it (LZO, GZIP, or no compression) and append it at the end of the SPL.
Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com ---
changes since v2 : Added documentation in the README for multi_dtb_fit
doc/README.multi-dtb-fit | 44 +++++++++++++++++++++++-- dts/Kconfig | 83 ++++++++++++++++++++++++++++++++++++++++++++++ lib/fdtdec.c | 85 +++++++++++++++++++++++++++++++++++++++++++----- scripts/Makefile.spl | 35 +++++++++++++++++++- 4 files changed, 235 insertions(+), 12 deletions(-)
diff --git a/doc/README.multi-dtb-fit b/doc/README.multi-dtb-fit index d182d4e..5e593c8 100644 --- a/doc/README.multi-dtb-fit +++ b/doc/README.multi-dtb-fit @@ -1,9 +1,49 @@ MULTI DTB FIT
-The purpose of this feature is to enable u-boot to select its DTB from a FIT -image appended at the end of the binary. +The purpose of this feature is to enable u-boot or the SPL to select its DTB +from a FIT image appended at the end of the binary. +It comes in two flavor: u-boot (CONFIG_MULTI_DTB_FIT) and SPL +(CONFIG_SPL_MULTI_DTB_FIT)
+u-boot flavor: Usually the DTB is selected by the SPL and passed down to u-boot. But some platforms don't use the SPL. In this case MULTI_DTB_FIT can used to provide u-boot with a choice of DTBs. The FIT image is automatically image at the end of the compilation and appended to u-boot.bin + + + +SPL flavor: +the SPL uses only a small subset of the DTB and it usually depends more +on the SOC than on the board. So it's usually fine to include a DTB in the +SPL that doesn't exactly match the board. There are howerver somes cases +where it's not possible. In the later case, in order to support multiple +boards (or board revisions) with the same SPL binary, SPL_MULTI_DTB_FIT +can be used. The list of DTB is given in CONFIG_SPL_OF_LIST which by default +is the same list as CONFIG_OF_LIST +The FIT image is automatically generated at the end of the compilation, +compressed and appended to u-boot-spl.bin + +The impact of this option is relatively small. Here are some numbers measured +for a TI DRA7 platform: + + +----------------------------------------+ + | Size |delta |boot-time| delta | + | (bytes) |(bytes) |(ms) | (ms) | ++---------------------------------------------------------------+ +| reference | 120185 | | 1331 | | ++---------------------------------------------------------------+ +| feature | | | | | +| deactiVated | 120185 | 0 | 1330 | -1 | ++---------------------------------------------------------------+ +| 1 DTB LZO | 120208 | 23 | 1331 | 0 | ++---------------------------------------------------------------+ +| 4 DTB LZO | 120810 | 625 | 1336 | 5 | ++---------------------------------------------------------------+ +| 4 DTB LZO | | | | | +| no malloc | 120746 | 561 | 1343 | 12 | ++---------------------------------------------------------------+ +| 4 DTB GZIP | 128552 | 8367 | 1353 | 22 | ++---------------------------------------------------------------+ +| 4 DTB No comp | 132352 | 12167 | 1351 | 20 | ++----------------------+----------+----------+---------+--------+ diff --git a/dts/Kconfig b/dts/Kconfig index c78438a..10a8926 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -118,6 +118,89 @@ config MULTI_DTB_FIT the correct DTB to be used. Use this if you need to support multiple DTBs but don't use the SPL.
+ +config SPL_MULTI_DTB_FIT + depends on SPL_LOAD_FIT && SPL_OF_CONTROL && !SPL_OF_PLATDATA + bool "support embedding several DTBs in a FIT image for the SPL" + help + This option provides the SPL with the ability to select its own + DTB at runtime from an appended FIT image containing several DTBs. + This allows using the same SPL binary on multiple platforms. + The primary purpose is to handle different versions of + the same platform without tweaking the platform code if the + differences can be expressed in the DTBs (common examples are: bus + capabilities, pad configurations). + +config SPL_OF_LIST + string "List of device tree files to include for DT control in SPL" + depends on SPL_MULTI_DTB_FIT + default OF_LIST + help + This option specifies a list of device tree files to use for DT + control in the SPL. These will be packaged into a FIT. At run-time, + the SPL will select the correct DT to use by examining the + hardware (e.g. reading a board ID value). This is a list of + device tree files (without the directory or .dtb suffix) + separated by <space>. + +choice + prompt "SPL OF LIST compression" + depends on SPL_MULTI_DTB_FIT + default SPL_MULTI_DTB_FIT_LZO + +config SPL_MULTI_DTB_FIT_LZO + bool "LZO" + depends on SYS_MALLOC_F + select SPL_LZO + help + Compress the FIT image containing the DTBs available for the SPL + using LZO compression. (requires lzop on host). + +config SPL_MULTI_DTB_FIT_GZ + bool "GZIP" + depends on SYS_MALLOC_F + select SPL_GZIP + help + Compress the FIT image containing the DTBs available for the SPL + using GZIP compression. (requires gzip on host) + +config SPL_MULTI_DTB_FIT_NO_COMPRESSION + bool "No compression" + help + Do not compress the FIT image containing the DTBs available for the SPL. + Use this options only if LZO is not available and the DTBs are very small. +endchoice + +choice + prompt "location of uncompressed DTBs " + depends on (SPL_MULTI_DTB_FIT_GZ || SPL_MULTI_DTB_FIT_LZO) + +config SPL_MULTI_DTB_FIT_DYN_ALLOC + bool "Dynamically allocate the memory" + depends on SYS_MALLOC_F + default y + +config SPL_MULTI_DTB_FIT_USER_DEFINED_AREA + bool "user-defined location" +endchoice + +config SPL_MULTI_DTB_FIT_UNCOMPRESS_SZ + hex "Size of memory reserved to uncompress the DTBs" + depends on (SPL_MULTI_DTB_FIT_GZ || SPL_MULTI_DTB_FIT_LZO) + default 0x10000 + help + This is the size of this area where the DTBs are uncompressed. + If this area is dynamically allocated, make sure that + FSP_SYS_MALLOC_F_LEN is big enough to contain it. + +config SPL_MULTI_DTB_FIT_USER_DEF_ADDR + hex "Address of memory where dtbs are uncompressed" + depends on SPL_MULTI_DTB_FIT_USER_DEFINED_AREA + help + the FIT image containing the DTBs is uncompressed in an area defined + at compilation time. This is the address of this area. It must be + aligned on 2-byte boundary. + config OF_SPL_REMOVE_PROPS string "List of device tree properties to drop for SPL" depends on SPL_OF_CONTROL diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 0374f21..e7a1df6 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -8,6 +8,8 @@ #include <common.h> #include <dm.h> #include <errno.h> +#include <spl.h> +#include <linux/lzo.h> #include <serial.h> #include <libfdt.h> #include <fdt_support.h> @@ -1203,9 +1205,65 @@ int fdtdec_setup_memory_banksize(void) } #endif
+#if CONFIG_IS_ENABLED(MULTI_DTB_FIT) +# if CONFIG_IS_ENABLED(GZIP) || CONFIG_IS_ENABLED(LZO) +static int uncompress_blob(const void *src, ulong sz_src, void **dstp) +{ + size_t sz_out = CONFIG_SPL_MULTI_DTB_FIT_UNCOMPRESS_SZ; + ulong sz_in = sz_src; + void *dst; + int rc; + +# if CONFIG_IS_ENABLED(GZIP) + if (gzip_parse_header(src, sz_in) < 0) + return -1; +# elif CONFIG_IS_ENABLED(LZO) + if (!lzop_is_valid_header(src)) + return -EBADMSG; +# endif + +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC) + dst = malloc(sz_out); + if (!dst) { + puts("uncompress_blob: Unable to allocate memory\n"); + return -ENOMEM; + } +# elif CONFIG_IS_ENABLED(MULTI_DTB_FIT_USER_DEFINED_AREA) + dst = (void *)CONFIG_VAL(MULTI_DTB_FIT_USER_DEF_ADDR); +# else + return -ENOTSUPP; +# endif + +# if CONFIG_IS_ENABLED(GZIP) + rc = gunzip(dst, sz_out, (u8 *)src, &sz_in); +# elif CONFIG_IS_ENABLED(LZO) + rc = lzop_decompress(src, sz_in, dst, &sz_out); +# endif + if (rc < 0) { + /* not a valid compressed blob */ + puts("uncompress_blob: Unable to uncompress\n"); +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC) + free(dst); +# endif + return -EBADMSG; + } + *dstp = dst; + return 0; +} +# else +static int uncompress_blob(const void *src, ulong sz_src, void **dstp) +{ + return -ENOTSUPP; +} +# endif +#endif + int fdtdec_setup(void) { #if CONFIG_IS_ENABLED(OF_CONTROL) +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT) + void *fdt_blob; +# endif # ifdef CONFIG_OF_EMBED /* Get a pointer to the FDT */ gd->fdt_blob = __dtb_dt_begin; @@ -1216,15 +1274,6 @@ int fdtdec_setup(void) gd->fdt_blob = (ulong *)&_image_binary_end; else gd->fdt_blob = (ulong *)&__bss_end; - -# elif defined CONFIG_MULTI_DTB_FIT - gd->fdt_blob = locate_dtb_in_fit(&_end); - - if (gd->fdt_blob == NULL || gd->fdt_blob <= ((void *)&_end)) { - puts("Failed to find proper dtb in embedded FIT Image\n"); - return -1; - } - # else /* FDT is at end of image */ gd->fdt_blob = (ulong *)&_end; @@ -1243,7 +1292,25 @@ int fdtdec_setup(void) gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob); # endif + +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT) + /* + *try and uncompress the blob. + * max input size is set arbitrarily to 16MB (should more than enough) + */ + if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0) + gd->fdt_blob = fdt_blob; + + /* + * Check if blob is a FIT images containings DTBs. + * If so, pick the most relevant + */ + fdt_blob = locate_dtb_in_fit(gd->fdt_blob); + if (fdt_blob) + gd->fdt_blob = fdt_blob; +# endif #endif + return fdtdec_prepare_fdt(); }
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index ac3c2c7..18316a9 100644 --- a/scripts/Makefile.spl +++ b/scripts/Makefile.spl @@ -202,10 +202,21 @@ cmd_cat = cat $(filter-out $(PHONY), $^) > $@ quiet_cmd_copy = COPY $@ cmd_copy = cp $< $@
+ifneq ($(CONFIG_SPL_MULTI_DTB_FIT),y) +FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).dtb +else ifeq ($(CONFIG_SPL_MULTI_DTB_FIT_LZO),y) +FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit.lzo +else ifeq ($(CONFIG_SPL_MULTI_DTB_FIT_GZ),y) +FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit.gz +else +FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit +endif + + ifeq ($(CONFIG_SPL_OF_CONTROL)$(CONFIG_OF_SEPARATE)$(CONFIG_SPL_OF_PLATDATA),yy) $(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN)-nodtb.bin \ $(if $(CONFIG_SPL_SEPARATE_BSS),,$(obj)/$(SPL_BIN)-pad.bin) \ - $(obj)/$(SPL_BIN).dtb FORCE + $(FINAL_DTB_CONTAINER) FORCE $(call if_changed,cat)
$(obj)/$(SPL_BIN).bin: $(obj)/$(SPL_BIN)-dtb.bin FORCE @@ -369,6 +380,28 @@ checkdtoc: tools PHONY += FORCE FORCE:
+PHONY += dtbs +dtbs: + $(Q)$(MAKE) $(build)=dts dtbs + # Declare the contents of the .PHONY variable as phony. We keep that # information in a variable so we can use it in if_changed and friends. .PHONY: $(PHONY) + +SHRUNK_ARCH_DTB = $(patsubst %,$(obj)/dts/%.dtb,$(subst ",,$(CONFIG_SPL_OF_LIST))) +.SECONDEXPANSION: +$(SHRUNK_ARCH_DTB): $$(patsubst $(obj)/dts/%, arch/$(ARCH)/dts/%, $$@) + $(call if_changed,fdtgrep) + +MKIMAGEFLAGS_$(SPL_BIN).multidtb.fit = -f auto -A $(ARCH) -T firmware -C none -O u-boot \ + -n "Multi DTB fit image for $(SPL_BIN)" -E \ + $(patsubst %,-b %,$(SHRUNK_ARCH_DTB)) + +$(obj)/$(SPL_BIN).multidtb.fit: /dev/null $(SHRUNK_ARCH_DTB) FORCE + $(call if_changed,mkimage) + +$(obj)/$(SPL_BIN).multidtb.fit.gz: $(obj)/$(SPL_BIN).multidtb.fit + @gzip -kf9 $< > $@ + +$(obj)/$(SPL_BIN).multidtb.fit.lzo: $(obj)/$(SPL_BIN).multidtb.fit + @lzop -f9 $< > $@

In order to be able to select the right DTB, we need to have identified the board before spl_early_init() is called.
Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com Reviewed-by: Simon Glass sjg@chromium.org ---
no change since v2
arch/arm/mach-omap2/hwinit-common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-omap2/hwinit-common.c b/arch/arm/mach-omap2/hwinit-common.c index 7324d52..56890a0 100644 --- a/arch/arm/mach-omap2/hwinit-common.c +++ b/arch/arm/mach-omap2/hwinit-common.c @@ -165,9 +165,11 @@ void early_system_init(void) * to prevent overwrites. */ save_omap_boot_params(); - spl_early_init(); #endif do_board_detect(); +#ifdef CONFIG_SPL_BUILD + spl_early_init(); +#endif vcores_init(); #ifdef CONFIG_DEBUG_UART_OMAP debug_uart_init();
participants (2)
-
Jean-Jacques Hiblot
-
Simon Glass