aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJean-Jacques Hiblot <jjhiblot@ti.com>2017-09-15 12:57:32 +0200
committerTom Rini <trini@konsulko.com>2017-10-06 11:26:41 -0400
commit2f57c95100f231de0f4e0301237cbe477e09084b (patch)
tree0dbc74c6a5dc820ba5fc85875fce28bc6668ff2b /lib
parent035d64025c3e32a2f372981f86fc69255feeb2b2 (diff)
downloadu-boot-2f57c95100f231de0f4e0301237cbe477e09084b.zip
u-boot-2f57c95100f231de0f4e0301237cbe477e09084b.tar.gz
u-boot-2f57c95100f231de0f4e0301237cbe477e09084b.tar.bz2
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>
Diffstat (limited to 'lib')
-rw-r--r--lib/fdtdec.c87
1 files changed, 78 insertions, 9 deletions
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index f26d2eb..45f3fe7 100644
--- a/lib/fdtdec.c
+++ b/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();
}