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

Jean-Jacques Hiblot jjhiblot at ti.com
Fri Aug 4 17:01:03 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>
---

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 $< > $@
-- 
1.9.1



More information about the U-Boot mailing list