mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
spl: dm: Make it possible for the SPL to pick its own DTB from a FIT
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> [trini: Move default y of SPL_MULTI_DTB_FIT_DYN_ALLOC to it being the default choice if SYS_MALLOC_F, drop spl.h include from lib/fdtdec.c it's unused.] Signed-off-by Tom Rini <trini@konsulko.com>
This commit is contained in:
parent
035d64025c
commit
2f57c95100
4 changed files with 248 additions and 13 deletions
|
@ -1,8 +1,11 @@
|
|||
MULTI DTB FIT
|
||||
MULTI DTB FIT and SPL_MULTI_DTB_FIT
|
||||
|
||||
The purpose of this feature is to enable u-boot to select its DTB from a FIT
|
||||
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 appended at the end of the binary.
|
||||
It comes in two flavors: 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.
|
||||
|
@ -13,3 +16,50 @@ the FIT.
|
|||
The selection is done using board_fit_config_name_match() (same as what the SPL
|
||||
uses to select the DTB for U-Boot). The selection happens during fdtdec_setup()
|
||||
which is called during before relocation by board_init_f().
|
||||
|
||||
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 some 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 relevant DTBs are packed into a FIT. This FIT is automatically generated
|
||||
at the end of the compilation, compressed and appended to u-boot-spl.bin, so
|
||||
that SPL can locate it and select the correct DTB from inside the FIT.
|
||||
CONFIG_SPL__OF_LIST is used to list the relevant DTBs.
|
||||
The compression stage is optional but reduces the impact on the size of the
|
||||
SPL. LZO and GZIP compressions are supported. By default, the area where the
|
||||
FIT is uncompressed is dynamicaly allocated but this behaviour can be changed
|
||||
for platforms that don't provide a HEAP big enough to contain the uncompressed
|
||||
FIT.
|
||||
The SPL uses board_fit_config_name_match() to find the correct DTB within the
|
||||
FIT (same as what the SPL uses to select the DTB for U-Boot).
|
||||
Uncompression and selection stages happen in fdtdec_setup() which is called
|
||||
during the early initialization stage of the SPL (spl_early_init() or
|
||||
spl_init())
|
||||
|
||||
Impacts and performances (SPL flavor):
|
||||
The impact of this option is relatively small. Here are some numbers measured
|
||||
for a TI DRA72 platform:
|
||||
|
||||
+----------+------------+-----------+------------+
|
||||
| size | size delta | SPL boot | boot time |
|
||||
| (bytes) | (bytes) | time (s) | delta (s) |
|
||||
+---------------------------+----------+------------+-----------+------------+
|
||||
| 1 DTB | | | | |
|
||||
+---------------------------+----------+------------+-----------+------------+
|
||||
| reference | 125305 | 0 | 1.389 | 0 |
|
||||
| LZO (dynamic allocation) | 125391 | 86 | 1.381 | -0.008 |
|
||||
+---------------------------+----------+------------+-----------+------------+
|
||||
| 4 DTBs (DRA7, DRA71, | | | | |
|
||||
| DRA72, DRA72 revC) | | | | |
|
||||
+---------------------------+----------+------------+-----------+------------+
|
||||
| LZO (dynamic allocation) | 125991 | 686 | 1.39 | 0.001 |
|
||||
| LZO (user defined area) | 125927 | 622 | 1.403 | 0.014 |
|
||||
| GZIP (user defined area) | 133880 | 8575 | 1.421 | 0.032 |
|
||||
| No compression (in place) | 137472 | 12167 | 1.412 | 0.023 |
|
||||
+---------------------------+----------+------------+-----------+------------+
|
||||
|
||||
Note: SPL boot time is the time elapsed between the 'reset' command is entered
|
||||
and the time when the first U-Boot (not SPL) version string is displayed.
|
||||
|
|
83
dts/Kconfig
83
dts/Kconfig
|
@ -130,6 +130,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_GZIP
|
||||
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_GZIP || SPL_MULTI_DTB_FIT_LZO)
|
||||
default SPL_MULTI_DTB_FIT_DYN_ALLOC if SYS_MALLOC_F
|
||||
|
||||
config SPL_MULTI_DTB_FIT_DYN_ALLOC
|
||||
bool "Dynamically allocate the memory"
|
||||
depends on SYS_MALLOC_F
|
||||
|
||||
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_GZIP || SPL_MULTI_DTB_FIT_LZO)
|
||||
default 0x8000
|
||||
help
|
||||
This is the size of this area where the DTBs are uncompressed.
|
||||
If this area is dynamically allocated, make sure that
|
||||
SPL_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
|
||||
|
|
87
lib/fdtdec.c
87
lib/fdtdec.c
|
@ -15,6 +15,7 @@
|
|||
#include <serial.h>
|
||||
#include <asm/sections.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/lzo.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
|
@ -1203,9 +1204,66 @@ int fdtdec_setup_memory_banksize(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
|
||||
# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_GZIP) ||\
|
||||
CONFIG_IS_ENABLED(MULTI_DTB_FIT_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;
|
||||
if (CONFIG_IS_ENABLED(LZO))
|
||||
if (!lzop_is_valid_header(src))
|
||||
return -EBADMSG;
|
||||
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
# if 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);
|
||||
else if (CONFIG_IS_ENABLED(LZO))
|
||||
rc = lzop_decompress(src, sz_in, dst, &sz_out);
|
||||
|
||||
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);
|
||||
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,27 @@ int fdtdec_setup(void)
|
|||
gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16,
|
||||
(uintptr_t)gd->fdt_blob);
|
||||
# endif
|
||||
|
||||
# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
|
||||
/*
|
||||
* Try and uncompress the blob.
|
||||
* Unfortunately there is no way to know how big the input blob really
|
||||
* is. So let us set the maximum input size arbitrarily high. 16MB
|
||||
* ought to be more than enough for packed DTBs.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -209,10 +209,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_GZIP),y)
|
||||
FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit.gz
|
||||
else
|
||||
FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(CONFIG_$(SPL_TPL_)OF_CONTROL)$(CONFIG_OF_SEPARATE)$(CONFIG_$(SPL_TPL_)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
|
||||
|
@ -383,6 +394,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 $< > $@
|
||||
|
|
Loading…
Reference in a new issue