summaryrefslogtreecommitdiff
path: root/plat/allwinner
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@arm.com>2018-09-16 02:08:06 +0100
committerAndre Przywara <andre.przywara@arm.com>2018-10-20 16:23:59 +0100
commit41538930555182e4c36f44677e5df2b97d266350 (patch)
treebb5d0afe3daa706c2514931a1710e43bd1feb4cb /plat/allwinner
parenteae5fe79558c0c2744f74ca88970b16ce45450b1 (diff)
allwinner: Find DTB in BL33 image
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>
Diffstat (limited to 'plat/allwinner')
-rw-r--r--plat/allwinner/common/allwinner-common.mk2
-rw-r--r--plat/allwinner/common/include/platform_def.h2
-rw-r--r--plat/allwinner/common/sunxi_bl31_setup.c55
3 files changed, 58 insertions, 1 deletions
diff --git a/plat/allwinner/common/allwinner-common.mk b/plat/allwinner/common/allwinner-common.mk
index 8c772bfc..2dc058f5 100644
--- a/plat/allwinner/common/allwinner-common.mk
+++ b/plat/allwinner/common/allwinner-common.mk
@@ -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} \
diff --git a/plat/allwinner/common/include/platform_def.h b/plat/allwinner/common/include/platform_def.h
index 4f9c00ed..08eb5cf2 100644
--- a/plat/allwinner/common/include/platform_def.h
+++ b/plat/allwinner/common/include/platform_def.h
@@ -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
diff --git a/plat/allwinner/common/sunxi_bl31_setup.c b/plat/allwinner/common/sunxi_bl31_setup.c
index 6c47e89f..94b123a6 100644
--- a/plat/allwinner/common/sunxi_bl31_setup.c
+++ b/plat/allwinner/common/sunxi_bl31_setup.c
@@ -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();