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

Jean-Jacques Hiblot jjhiblot at ti.com
Fri Jul 7 11:44:39 UTC 2017


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 at ti.com>
---

The impact in terms of boot time is not high when using LZO but I gues it can vary
from platform to platform.
The size of the SPL binary is increased (1.5kB more code on ARM), but the compression
really flattens the DTBS. so at the end of the day, enabling this option doesn't add much.

Here are some sumbers with a DRA7 platform (numbers in bytes):
                          size  delta with ref
  MLO.reference         123450
  MLO.lzo_1_DTB         123715    +265
  MLO.lzo_4_DTB         124237    +787
  MLO.gzip_4_DTB        132006    +8556
  MLO.no_comp_4_DTB     134184    +10734

 common/spl/spl_fit.c |  2 +-
 dts/Kconfig          | 48 ++++++++++++++++++++++++++++++++++
 dts/Makefile         | 18 +++++++++++--
 include/spl.h        | 15 +++++++++++
 lib/Kconfig          | 11 ++++++++
 lib/Makefile         |  6 ++---
 lib/fdtdec.c         | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 scripts/Makefile.spl | 35 ++++++++++++++++++++++++-
 8 files changed, 201 insertions(+), 7 deletions(-)

diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 4c42a96..3479b05 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -75,7 +75,7 @@ static int spl_fit_find_config_node(const void *fdt)
  * 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,
+int spl_fit_get_image_node(const void *fit, int images,
 				  const char *type, int index)
 {
 	const char *name, *str;
diff --git a/dts/Kconfig b/dts/Kconfig
index b3009af..80f21e0 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -99,6 +99,54 @@ config OF_LIST
 	  reading a board ID value). This is a list of device tree files
 	  (without the directory or .dtb suffix) separated by <space>.
 
+
+config SPL_MULTI_DTB
+	depends on SPL_LOAD_FIT && SPL_OF_CONTROL && !SPL_OF_PLATDATA
+	bool "support embedding several DTB in the SPL"
+	default n
+
+config SPL_OF_LIST
+	string "List of device tree files to include for DT control in SPL"
+	depends on SPL_MULTI_DTB
+	default OF_LIST
+	help
+	  blablablabla
+
+choice
+	prompt "SPL OF LIST compression"
+	depends on SPL_MULTI_DTB
+	default SPL_MULTI_DTB_LZO
+
+config SPL_MULTI_DTB_LZO
+	bool "Compress the DTBs with LZO"
+	depends on SYS_MALLOC_F
+	select SPL_LZO
+	help
+	  Compres the FIT image containing the DTBs available for the SPL
+	  using LZO compression. (requires lzop on host).
+
+config SPL_MULTI_DTB_GZ
+	bool "Compress the DTBs with GZip"
+	depends on SYS_MALLOC_F
+	select SPL_GZIP
+	help
+	  Compres the FIT image containing the DTBs available for the SPL
+	  using GZIP compression. (requires gzip on host)
+
+config SPL_MULTI_DTB_NO_COMPRESSION
+	bool "do not compress the DTBs"
+	help
+	  Do not tompres 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
+
+config SPL_MULTI_DTB_GZ_SZ
+	hex "Size of mmemory allocated to uncompress the dtbs"
+	depends on SYS_MALLOC_F && (SPL_MULTI_DTB_GZ || SPL_MULTI_DTB_LZO)
+	default 0x10000
+	help
+	   blablabla
+
 config OF_SPL_REMOVE_PROPS
 	string "List of device tree properties to drop for SPL"
 	depends on SPL_OF_CONTROL
diff --git a/dts/Makefile b/dts/Makefile
index 3a93daf..5cab6bd 100644
--- a/dts/Makefile
+++ b/dts/Makefile
@@ -22,9 +22,23 @@ DTB := $(ARCH_PATH)/$(DEVICE_TREE).dtb
 dtb_depends += $(DTB:.dtb=.dts)
 endif
 
+
+ARCH_SPL_DTB := $(patsubst %,$(ARCH_PATH)/%.dtb,$(subst ",,$(CONFIG_SPL_OF_LIST)))
+LOCAL_SPL_DTBS := $(patsubst %,$(obj)/%.dtb,$(subst ",,$(CONFIG_SPL_OF_LIST)))
+
+.PHONY: arch-dtbs
+
 $(obj)/dt.dtb: $(DTB) FORCE
 	$(call if_changed,shipped)
 
+ARCH_SPL_DTB_EXECPT_ONE := $(filter-out $(DTB),$(ARCH_SPL_DTB))
+$(ARCH_SPL_DTB_EXECPT_ONE): arch-dtbs
+	@
+
+.SECONDEXPANSION:
+$(LOCAL_SPL_DTBS): $$(patsubst $(TARGETDIR)/%, %, arch/$(ARCH)/$$@)
+	$(shell cp $< $@)
+
 targets += dt.dtb
 
 $(DTB): $(dtb_depends)
@@ -46,10 +60,10 @@ arch-dtbs:
 
 obj-$(CONFIG_OF_EMBED) := dt.dtb.o
 
-dtbs: $(obj)/dt.dtb
+dtbs: $(obj)/dt.dtb $(LOCAL_SPL_DTBS)
 	@:
 
-clean-files := dt.dtb.S
+clean-files := dt.dtb.S *.dtb
 
 # Let clean descend into dts directories
 subdir- += ../arch/arm/dts ../arch/microblaze/dts ../arch/mips/dts ../arch/sandbox/dts ../arch/x86/dts
diff --git a/include/spl.h b/include/spl.h
index ffadce9..8ff96c3 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -49,6 +49,21 @@ struct spl_load_info {
 };
 
 /**
+ * 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.
+ */
+int spl_fit_get_image_node(const void *fit, int images,
+				  const char *type, int index);
+
+/**
  * spl_load_simple_fit() - Loads a fit image from a device.
  * @spl_image:	Image description to set up
  * @info:	Structure containing the information required to load data.
diff --git a/lib/Kconfig b/lib/Kconfig
index 09670f0..6865325 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -158,6 +158,17 @@ config LZMA
 
 config LZO
 	bool
+
+config SPL_LZO
+	bool
+
+config SPL_GZIP
+	bool
+	depends on SPL_ZLIB
+
+config SPL_ZLIB
+	bool
+
 endmenu
 
 config ERRNO_STR
diff --git a/lib/Makefile b/lib/Makefile
index eacc7d6..82b2de0 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
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 91503b8..68322d8 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -7,6 +7,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>
@@ -1208,6 +1210,65 @@ int fdtdec_setup_memory_banksize(void)
 }
 #endif
 
+#if defined(CONFIG_SPL_MULTI_DTB) && defined(CONFIG_SPL_BUILD)
+const void *get_dtb_blob_from_fit(const void *fit)
+{
+	int node, images;
+	ulong fit_size, offset;
+
+#if defined(CONFIG_SPL_MULTI_DTB_GZ) || defined(CONFIG_SPL_MULTI_DTB_LZO)
+	if (image_get_magic(fit) != FDT_MAGIC) {
+		/* not a valid FIT, maybe it is a compressed fit */
+		void *dst = malloc(CONFIG_SPL_MULTI_DTB_GZ_SZ);
+		size_t sz_out = CONFIG_SPL_MULTI_DTB_GZ_SZ;
+		ulong sz_in = 1024*1024; /* not more than 1MB */
+		if (!dst) {
+			puts("Unable to allocate memory to uncompress the DTBs\n");
+			return NULL;
+		}
+#ifdef CONFIG_SPL_MULTI_DTB_GZ
+		int rc = gunzip(dst, sz_out,
+				(u8 *)fit, &sz_in);
+#elif defined CONFIG_SPL_MULTI_DTB_LZO
+		int rc = lzop_decompress(fit, sz_in, dst, &sz_out);
+#endif
+		if (rc < 0) {
+			/* not a valid compressed blob */
+			free(dst);
+			return NULL;
+		}
+		fit = dst;
+	}
+#endif
+
+	if (image_get_magic(fit) != FDT_MAGIC) {
+		debug("not a FIT image\n");
+		return NULL;
+	}
+
+	fit_size = fdt_totalsize(fit);
+	fit_size = (fit_size + 3) & ~3; /* align on 32bit upper boundary */
+
+	/* find the node holding the images information */
+	images = fdt_path_offset(fit, FIT_IMAGES_PATH);
+	if (images < 0) {
+		debug("could not find the '/images' node\n");
+		return NULL;
+	}
+
+	/* 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)
+		return NULL;
+
+	offset = fdtdec_get_int(fit, node, "data-offset", -1);
+	if (offset < 0)
+		return NULL;
+
+	return fit + fit_size + offset;
+}
+#endif
+
 int fdtdec_setup(void)
 {
 #if CONFIG_IS_ENABLED(OF_CONTROL)
@@ -1239,6 +1300,18 @@ int fdtdec_setup(void)
 	gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
 						(uintptr_t)gd->fdt_blob);
 # endif
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_MULTI_DTB)
+	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) {
+		const void *fdt_blob;
+		fdt_blob = get_dtb_blob_from_fit(gd->fdt_blob);
+		if (fdt_blob) {
+			debug("found FIT containg several DTBs\n");
+			gd->fdt_blob = fdt_blob;
+		} else {
+			debug("legacy DTB file\n");
+		}
+	}
+#endif
 #endif
 	return fdtdec_prepare_fdt();
 }
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index ac3c2c7..39aa939 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),y)
+FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).dtb
+else ifeq ($(CONFIG_SPL_MULTI_DTB_LZO),y)
+FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit.lzo
+else ifeq ($(CONFIG_SPL_MULTI_DTB_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) JJH" -E \
+	$(patsubst %,-b $(obj)/dts/%.dtb,$(subst ",,$(CONFIG_SPL_OF_LIST)))
+
+$(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 $< > $@
\ No newline at end of file
-- 
1.9.1



More information about the U-Boot mailing list