diff mbox

[U-Boot,v3] rpi: passthrough of the firmware provided FDT blob

Message ID 1478627276-23115-1-git-send-email-cschieli@gmail.com
State Accepted
Commit ade243a211d62327e9ebadce27bbbff7981e37f0
Delegated to: Tom Rini
Headers show

Commit Message

Cédric Schieli Nov. 8, 2016, 5:47 p.m. UTC
Raspberry firmware used to pass a FDT blob at a fixed address (0x100),
but this is not true anymore. The address now depends on both the
memory size and the blob size [1].

If one wants to passthrough this FDT blob to the kernel, the most
reliable way is to save its address from the r2/x0 register in the
U-Boot entry point and expose it in a environment variable for
further processing.

This patch just does this:
- save the provided address in the global variable fw_dtb_pointer
- expose it in ${fdt_addr} if it points to a a valid FDT blob

There are many different ways to use it. One can, for example, use
the following script which will extract from the tree the command
line built by the firmware, then hand over the blob to a previously
loaded kernel:

fdt addr ${fdt_addr}
fdt get value bootargs /chosen bootargs
bootz ${kernel_addr_r} - ${fdt_addr}

Alternatively, users relying on sysboot/pxe can simply omit any FDT
statement in their extlinux.conf file, U-Boot will automagically pick
${fdt_addr} and pass it to the kernel.

[1] https://www.raspberrypi.org/forums//viewtopic.php?f=107&t=134018

Signed-off-by: Cédric Schieli <cschieli@gmail.com>
---

Changes in v3:
- revert back to assembly for save_boot_params()

Changes in v2:
- merge the series in a single patch
- convert the save_boot_params() function to C code
- add a board_get_usable_ram_top() function to protect the blob
  during relocation
- remove the (obsolete) extern declaration from include/configs/rpi.h
- rename the global variable to fw_dtb_pointer
- rename the environment variable to ${fdt_addr}
- fix 64-bits compatibility issues
- document possible uses of ${fdt_addr}

 board/raspberrypi/rpi/Makefile        |  1 +
 board/raspberrypi/rpi/lowlevel_init.S | 36 +++++++++++++++++++++++++++++++++++
 board/raspberrypi/rpi/rpi.c           | 29 ++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+)
 create mode 100644 board/raspberrypi/rpi/lowlevel_init.S

Comments

Stephen Warren Nov. 11, 2016, 5:36 a.m. UTC | #1
On 11/08/2016 10:47 AM, Cédric Schieli wrote:
> Raspberry firmware used to pass a FDT blob at a fixed address (0x100),
> but this is not true anymore. The address now depends on both the
> memory size and the blob size [1].
>
> If one wants to passthrough this FDT blob to the kernel, the most
> reliable way is to save its address from the r2/x0 register in the
> U-Boot entry point and expose it in a environment variable for
> further processing.
>
> This patch just does this:
> - save the provided address in the global variable fw_dtb_pointer
> - expose it in ${fdt_addr} if it points to a a valid FDT blob
>
> There are many different ways to use it. One can, for example, use
> the following script which will extract from the tree the command
> line built by the firmware, then hand over the blob to a previously
> loaded kernel:
>
> fdt addr ${fdt_addr}
> fdt get value bootargs /chosen bootargs
> bootz ${kernel_addr_r} - ${fdt_addr}
>
> Alternatively, users relying on sysboot/pxe can simply omit any FDT
> statement in their extlinux.conf file, U-Boot will automagically pick
> ${fdt_addr} and pass it to the kernel.
>
> [1] https://www.raspberrypi.org/forums//viewtopic.php?f=107&t=134018

This looks fine for the ARMv7 and ARMv8 Pis, but I forgot to mention 
last time that it causes a build failure for the ARMv6-based original Pis:

> board/raspberrypi/rpi/built-in.o: In function `save_boot_params':
> board/raspberrypi/rpi/lowlevel_init.S:36: undefined reference to `save_boot_params_ret'

That's because arch/arm/cpu/arm1176/start.S doesn't implement the 
save_boot_params hook; you can probably solve this quite easily by 
taking commit 0e2b5350d952 "ARM: Add save_boot_params for ARMv8" and 
porting that to the ARM1176 code first.

Assuming that fix is sent and applied first e.g. in a series with this 
patch, then this patch,
Acked-by: Stephen Warren <swarren@wwwdotorg.org>
diff mbox

Patch

diff --git a/board/raspberrypi/rpi/Makefile b/board/raspberrypi/rpi/Makefile
index 4ce2c98..dcb25ac 100644
--- a/board/raspberrypi/rpi/Makefile
+++ b/board/raspberrypi/rpi/Makefile
@@ -5,3 +5,4 @@ 
 #
 
 obj-y	:= rpi.o
+obj-y	+= lowlevel_init.o
diff --git a/board/raspberrypi/rpi/lowlevel_init.S b/board/raspberrypi/rpi/lowlevel_init.S
new file mode 100644
index 0000000..cdbd8e1
--- /dev/null
+++ b/board/raspberrypi/rpi/lowlevel_init.S
@@ -0,0 +1,36 @@ 
+/*
+ * (C) Copyright 2016
+ * Cédric Schieli <cschieli@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+
+.align 8
+.global fw_dtb_pointer
+fw_dtb_pointer:
+#ifdef CONFIG_ARM64
+	.dword 0x0
+#else
+	.word 0x0
+#endif
+
+/*
+ * Routine: save_boot_params (called after reset from start.S)
+ * Description: save ATAG/FDT address provided by the firmware at boot time
+ */
+
+.global save_boot_params
+save_boot_params:
+
+	/* The firmware provided ATAG/FDT address can be found in r2/x0 */
+#ifdef CONFIG_ARM64
+	adr	x8, fw_dtb_pointer
+	str	x0, [x8]
+#else
+	str	r2, fw_dtb_pointer
+#endif
+
+	/* Returns */
+	b	save_boot_params_ret
diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c
index 6245b36..ffd6d31 100644
--- a/board/raspberrypi/rpi/rpi.c
+++ b/board/raspberrypi/rpi/rpi.c
@@ -25,6 +25,9 @@ 
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/* From lowlevel_init.S */
+extern unsigned long fw_dtb_pointer;
+
 static const struct bcm2835_gpio_platdata gpio_platdata = {
 	.base = BCM2835_GPIO_BASE,
 };
@@ -285,6 +288,31 @@  static void set_fdtfile(void)
 	setenv("fdtfile", fdtfile);
 }
 
+/*
+ * If the firmware provided a valid FDT at boot time, let's expose it in
+ * ${fdt_addr} so it may be passed unmodified to the kernel.
+ */
+static void set_fdt_addr(void)
+{
+	if (getenv("fdt_addr"))
+		return;
+
+	if (fdt_magic(fw_dtb_pointer) != FDT_MAGIC)
+		return;
+
+	setenv_hex("fdt_addr", fw_dtb_pointer);
+}
+
+/*
+ * Prevent relocation from stomping on a firmware provided FDT blob.
+ */
+unsigned long board_get_usable_ram_top(unsigned long total_size)
+{
+	if ((gd->ram_top - fw_dtb_pointer) > SZ_64M)
+		return gd->ram_top;
+	return fw_dtb_pointer & ~0xffff;
+}
+
 static void set_usbethaddr(void)
 {
 	ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_mac_address, msg, 1);
@@ -356,6 +384,7 @@  static void set_serial_number(void)
 
 int misc_init_r(void)
 {
+	set_fdt_addr();
 	set_fdtfile();
 	set_usbethaddr();
 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG