spl: LOAD_FIT_FULL: Relocate FDT for u-boot payloads
authorAlexandru Gagniuc <mr.nuke.me@gmail.com>
Thu, 1 Apr 2021 18:25:28 +0000 (13:25 -0500)
committerTom Rini <trini@konsulko.com>
Wed, 14 Apr 2021 20:02:43 +0000 (16:02 -0400)
U-Boot expects the FDT to be located right after the _end
linker symbol (see fdtdec.c: board_fdt_blob_setup())

The "basic" LOAD_FIT path is aware of this limitation, and relocates
the FDT at the expected location. Guessing the expected location
probably only works reliably on 32-bit arm, and it feels like a hack.
One proposal would be to pass the FDT address to u-boot
(e.g. using 'r2' on arm platforms).

The variable is named "fdt_hack" to remind future contributors that,
"hey! we should fix the underlying problem". However, that is beyond
the scope of this patch.

Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
common/spl/spl.c

index 85fccb5..8941cbf 100644 (file)
@@ -202,6 +202,7 @@ static int spl_load_fit_image(struct spl_image_info *spl_image,
 {
        bootm_headers_t images;
        const char *fit_uname_config = NULL;
+       uintptr_t fdt_hack;
        const char *uname;
        ulong fw_data = 0, dt_data = 0, img_data = 0;
        ulong fw_len = 0, dt_len = 0, img_len = 0;
@@ -234,9 +235,18 @@ static int spl_load_fit_image(struct spl_image_info *spl_image,
        ret = fit_image_load(&images, (ulong)header, NULL, &fit_uname_config,
                       IH_ARCH_DEFAULT, IH_TYPE_FLATDT, -1,
                       FIT_LOAD_OPTIONAL, &dt_data, &dt_len);
-       if (ret >= 0)
+       if (ret >= 0) {
                spl_image->fdt_addr = (void *)dt_data;
 
+               if (spl_image->os == IH_OS_U_BOOT) {
+                       /* HACK: U-boot expects FDT at a specific address */
+                       fdt_hack = spl_image->load_addr + spl_image->size;
+                       fdt_hack = (fdt_hack + 3) & ~3;
+                       debug("Relocating FDT to %p\n", spl_image->fdt_addr);
+                       memcpy((void *)fdt_hack, spl_image->fdt_addr, dt_len);
+               }
+       }
+
        conf_noffset = fit_conf_get_node((const void *)header,
                                         fit_uname_config);
        if (conf_noffset <= 0)