[U-Boot] [PATCH v2 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 | 2 | 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 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 +- dts/Kconfig | 103 +++++++++++++++++++++++++++++++++++- include/boot_fit.h | 4 +- include/common.h | 1 + include/linux/lzo.h | 3 ++ lib/Kconfig | 11 ++++ lib/Makefile | 6 +-- lib/fdtdec.c | 85 +++++++++++++++++++++++++---- lib/gunzip.c | 15 ++++-- lib/lzo/lzo1x_decompress.c | 21 ++++++-- scripts/Makefile.spl | 35 +++++++++++- 24 files changed, 297 insertions(+), 53 deletions(-)

Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com ---
v1 -> v2 : no change
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 +- dts/Kconfig | 20 +++++++++++++++++++- lib/fdtdec.c | 2 +- 13 files changed, 30 insertions(+), 28 deletions(-)
diff --git a/Makefile b/Makefile index 4525964..dcf6a28 100644 --- a/Makefile +++ b/Makefile @@ -873,7 +873,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 361346b..f33244a 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -437,22 +437,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 17a92ea..cbf7e78 100644 --- a/common/Makefile +++ b/common/Makefile @@ -146,7 +146,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 dccaa09..6275234 100644 --- a/configs/k2e_evm_defconfig +++ b/configs/k2e_evm_defconfig @@ -44,5 +44,5 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y CONFIG_DTB_RESELECT=y -CONFIG_FIT_EMBED=y +CONFIG_MULTI_DTB_FIT=y CONFIG_OF_LIST="keystone-k2e-evm" diff --git a/configs/k2g_evm_defconfig b/configs/k2g_evm_defconfig index a43d7fc..7df397d 100644 --- a/configs/k2g_evm_defconfig +++ b/configs/k2g_evm_defconfig @@ -46,5 +46,5 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y CONFIG_DTB_RESELECT=y -CONFIG_FIT_EMBED=y +CONFIG_MULTI_DTB_FIT=y CONFIG_OF_LIST="keystone-k2g-generic keystone-k2g-evm keystone-k2g-ice" diff --git a/configs/k2hk_evm_defconfig b/configs/k2hk_evm_defconfig index e0c266a..f5f5d1f 100644 --- a/configs/k2hk_evm_defconfig +++ b/configs/k2hk_evm_defconfig @@ -44,5 +44,5 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y CONFIG_DTB_RESELECT=y -CONFIG_FIT_EMBED=y +CONFIG_MULTI_DTB_FIT=y CONFIG_OF_LIST="keystone-k2hk-evm" diff --git a/configs/k2l_evm_defconfig b/configs/k2l_evm_defconfig index 568e8dd..b61b9a1 100644 --- a/configs/k2l_evm_defconfig +++ b/configs/k2l_evm_defconfig @@ -44,5 +44,5 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y CONFIG_DTB_RESELECT=y -CONFIG_FIT_EMBED=y +CONFIG_MULTI_DTB_FIT=y CONFIG_OF_LIST="keystone-k2l-evm" 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 fbb48bf..175cfbd 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1223,7 +1223,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 --- v1 -> v2 : no change
common/boot_fit.c | 4 ++-- include/boot_fit.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/common/boot_fit.c b/common/boot_fit.c index 51440a6..6fdf019 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) +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..3d6996a 100644 --- a/include/boot_fit.h +++ b/include/boot_fit.h @@ -5,5 +5,5 @@ * SPDX-License-Identifier: GPL-2.0+ */
-int fdt_offset(void *fit); -void *locate_dtb_in_fit(void *fit); +int fdt_offset(const void *fit); +void *locate_dtb_in_fit(const void *fit);

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 ---
v1 -> v2 : no change
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 6fdf019..76f35fa 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;

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 --- v1 -> v2 : no change
common/common_fit.c | 20 ++++++++++++++++++++ 1 file changed, 20 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; }

Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com Reviewed-by: Tom Rini trini@konsulko.com ---
v1 -> v2 : no change
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 --- v1 -> v2 : no change
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 751665f..bff841f 100644 --- a/include/common.h +++ b/include/common.h @@ -567,6 +567,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 ---
v1 -> v2 : no change
lib/Kconfig | 11 +++++++++++ lib/Makefile | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/lib/Kconfig b/lib/Kconfig index 09670f0..434bf23 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -158,6 +158,17 @@ config LZMA
config LZO bool + +config SPL_LZO + bool + +config SPL_GZIP + bool + select SPL_ZLIB + +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

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 ---
v1 -> v2 : improved help in Kconfig for the SPL_MULTI_DTB_FIT option
dts/Kconfig | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/fdtdec.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++------ scripts/Makefile.spl | 35 +++++++++++++++++++++- 3 files changed, 193 insertions(+), 10 deletions(-)
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 175cfbd..eb4cd42 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> @@ -1209,9 +1211,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; @@ -1222,15 +1280,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; @@ -1249,7 +1298,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 $< > $@

On Tue, Jul 25, 2017 at 04:05:20PM +0200, Jean-Jacques Hiblot wrote:
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
Reviewed-by: Tom Rini trini@konsulko.com

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 ---
v1 -> v2 : no change
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
-
Tom Rini