allwinner: Find DTB in BL33 image
authorAndre Przywara <andre.przywara@arm.com>
Sun, 16 Sep 2018 01:08:06 +0000 (02:08 +0100)
committerAndre Przywara <andre.przywara@arm.com>
Sat, 20 Oct 2018 15:23:59 +0000 (16:23 +0100)
The initial PMIC setup for the Allwinner platform is quite board
specific, and used to be guarded by reading the .dtb stub *name* from the
SPL image in the legacy ATF port. This doesn't scale particularly well,
and requires constant maintainance.
Instead having the actual .dtb available would be much better, as the PMIC
setup requirements could be read from there directly.
The only available BL33 for Allwinner platforms so far is U-Boot, and
fortunately U-Boot comes with the full featured .dtb, appended to the
end of the U-Boot image.

Introduce some code that scans the beginning of the BL33 image to look
for the load address, which is followed by the image size. Adding those
two values together gives us the end of the image and thus the .dtb
address. Verify that this heuristic is valid by sanitising some values
and checking the DTB magic.

Print out the DTB address and the model name, if specified in the root
node.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
plat/allwinner/common/allwinner-common.mk
plat/allwinner/common/include/platform_def.h
plat/allwinner/common/sunxi_bl31_setup.c

index 8c772bfc2a3a2dc20f642c1f849c67713723303b..2dc058f5422ffd76268ce455b72be071a9231133 100644 (file)
@@ -13,6 +13,8 @@ PLAT_INCLUDES         :=      -Iinclude/plat/arm/common               \
                                -I${AW_PLAT}/common/include             \
                                -I${AW_PLAT}/${PLAT}/include
 
+include lib/libfdt/libfdt.mk
+
 PLAT_BL_COMMON_SOURCES :=      drivers/console/${ARCH}/console.S       \
                                drivers/ti/uart/${ARCH}/16550_console.S \
                                ${XLAT_TABLES_LIB_SRCS}                 \
index 4f9c00ed13e85565ab22731752a2b696250d6f62..08eb5cf2b91e4b8bb56aa7d605f0302d62570d7c 100644 (file)
@@ -21,7 +21,7 @@
 /* How much memory to reserve as secure for BL32, if configured */
 #define SUNXI_DRAM_SEC_SIZE            (32U << 20)
 
-/* How much DRAM to map */
+/* How much DRAM to map (to map BL33, for fetching the DTB from U-Boot) */
 #define SUNXI_DRAM_MAP_SIZE            (64U << 20)
 
 #define CACHE_WRITEBACK_SHIFT          6
index 6c47e89fc9a2f08d0ffa57d42c7e3212f4ff8667..94b123a6413a16dad7847cc6dc10a785ce816ece 100644 (file)
@@ -10,6 +10,7 @@
 #include <debug.h>
 #include <generic_delay_timer.h>
 #include <gicv2.h>
+#include <libfdt.h>
 #include <platform.h>
 #include <platform_def.h>
 #include <sunxi_def.h>
@@ -28,6 +29,47 @@ static const gicv2_driver_data_t sunxi_gic_data = {
        .gicc_base = SUNXI_GICC_BASE,
 };
 
+/*
+ * Try to find a DTB loaded in memory by previous stages.
+ *
+ * At the moment we implement a heuristic to find the DTB attached to U-Boot:
+ * U-Boot appends its DTB to the end of the image. Assuming that BL33 is
+ * U-Boot, try to find the size of the U-Boot image to learn the DTB address.
+ * The generic ARMv8 U-Boot image contains the load address and its size
+ * as u64 variables at the beginning of the image. There might be padding
+ * or other headers before that data, so scan the first 2KB after the BL33
+ * entry point to find the load address, which should be followed by the
+ * size. Adding those together gives us the address of the DTB.
+ */
+static void *sunxi_find_dtb(void)
+{
+       uint64_t *u_boot_base;
+       int i;
+
+       u_boot_base = (void *)(SUNXI_DRAM_VIRT_BASE + SUNXI_DRAM_SEC_SIZE);
+
+       for (i = 0; i < 2048 / sizeof(uint64_t); i++) {
+               uint32_t *dtb_base;
+
+               if (u_boot_base[i] != PLAT_SUNXI_NS_IMAGE_OFFSET)
+                       continue;
+
+               /* Does the suspected U-Boot size look anyhow reasonable? */
+               if (u_boot_base[i + 1] >= 256 * 1024 * 1024)
+                       continue;
+
+               /* end of the image: base address + size */
+               dtb_base = (void *)((char *)u_boot_base + u_boot_base[i + 1]);
+
+               if (fdt_check_header(dtb_base) != 0)
+                       continue;
+
+               return dtb_base;
+       }
+
+       return NULL;
+}
+
 void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
                                u_register_t arg2, u_register_t arg3)
 {
@@ -66,6 +108,7 @@ void bl31_platform_setup(void)
 {
        const char *soc_name;
        uint16_t soc_id = sunxi_read_soc_id();
+       void *fdt;
 
        switch (soc_id) {
        case SUNXI_SOC_A64:
@@ -85,6 +128,18 @@ void bl31_platform_setup(void)
 
        generic_delay_timer_init();
 
+       fdt = sunxi_find_dtb();
+       if (fdt) {
+               const char *model;
+               int length;
+
+               model = fdt_getprop(fdt, 0, "model", &length);
+               NOTICE("BL31: Found U-Boot DTB at %p, model: %s\n", fdt,
+                    model ?: "unknown");
+       } else {
+               NOTICE("BL31: No DTB found.\n");
+       }
+
        /* Configure the interrupt controller */
        gicv2_driver_init(&sunxi_gic_data);
        gicv2_distif_init();