armv8: layerscape: Enable falcon boot
Add jump_to_image_linux() for arm64. Add "noreturn" flag to
armv8_switch_to_el2(). Add hooks to fsl-layerscape to enable falcon
boot.
Signed-off-by: York Sun <york.sun@nxp.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Łukasz Majewski <lukma@denx.de>
Tested-by: Łukasz Majewski <lukma@denx.de>
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/doc/README.falcon b/arch/arm/cpu/armv8/fsl-layerscape/doc/README.falcon
new file mode 100644
index 0000000..2505f40
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-layerscape/doc/README.falcon
@@ -0,0 +1,140 @@
+Falcon boot option
+------------------
+Falcon boot is a short cut boot method for SD/eMMC targets. It skips loading the
+RAM version U-Boot. Instead, it loads FIT image and boot directly to Linux.
+CONFIG_SPL_OS_BOOT enables falcon boot. CONFIG_SPL_LOAD_FIT enables the FIT
+image support (also need CONFIG_SPL_OF_LIBFDT, CONFIG_SPL_FIT and optionally
+CONFIG_SPL_GZIP).
+
+To enable falcon boot, a hook function spl_start_uboot() returns 0 to indicate
+booting U-Boot is not the first choice. The kernel FIT image needs to be put
+at CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR. SPL mmc driver reads the header to
+determine if this is a FIT image. If true, FIT image components are parsed and
+copied or decompressed (if applicable) to their destinations. If FIT image is
+not found, normal U-Boot flow will follow.
+
+An important part of falcon boot is to prepare the device tree. A normal U-Boot
+does FDT fixups when booting Linux. For falcon boot, Linux boots directly from
+SPL, skipping the normal U-Boot. The device tree has to be prepared in advance.
+A command "spl export" should be called under the normal RAM version U-Boot.
+It is equivalent to go through "bootm" step-by-step until device tree fixup is
+done. The device tree in memory is the one needed for falcon boot. Falcon boot
+flow suggests to save this image to SD/eMMC at the location pointed by macro
+CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, with maximum size specified by macro
+CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS. However, when FIT image is used for
+Linux, the device tree stored in FIT image overwrites the memory loaded by spl
+driver from these sectors. We could change this loading order to favor the
+stored sectors. But when secure boot is enabled, these sectors are used for
+signature header and needs to be loaded before the FIT image. So it is important
+to understand the device tree in FIT image should be the one actually used, or
+leave it absent to favor the stored sectors. It is easier to deploy the FIT
+image with embedded static device tree to multiple boards.
+
+Macro CONFIG_SYS_SPL_ARGS_ADDR serves two purposes. One is the pointer to load
+the stored sectors to. Normally this is the static device tree. The second
+purpose is the memory location of signature header for secure boot. After the
+FIT image is loaded into memory, it is validated against the signature header
+before individual components are extracted (and optionally decompressed) into
+their final memory locations, respectively. After the validation, the header
+is no longer used. The static device tree is copied into this location. So
+this macro is passed as the location of device tree when booting Linux.
+
+Steps to prepare static device tree
+-----------------------------------
+To prepare the static device tree for Layerscape boards, it is important to
+understand the fixups in U-Boot. Memory size and location, as well as reserved
+memory blocks are added/updated. Ethernet MAC addressed are updated. FMan
+microcode (if used) is embedded in the device tree. Kernel command line and
+initrd information are embedded. Others including CPU status, boot method,
+Ethernet port status, etc. are also updated.
+
+Following normal booting process, all variables are set, all images are loaded
+before "bootm" command would be issued to boot, run command
+
+spl export fdt <address>
+
+where the address is the location of FIT image. U-Boot goes through the booting
+process as if "bootm start", "bootm loados", "bootm ramdisk"... commands but
+stops before "bootm go". There we have the fixed-up device tree in memory.
+We can check the device tree header by these commands
+
+fdt addr <fdt address>
+fdt header
+
+Where the fdt address is the device tree in memory. It is printed by U-Boot.
+It is useful to know the exact size. One way to extract this static device
+tree is to save it to eMMC/SD using command in U-Boot, and extract under Linux
+with these commands, repectively
+
+mmc write <address> <sector> <sectors>
+dd if=/dev/mmcblk0 of=<filename> bs=512 skip=<sector> count=<sectors>
+
+Note, U-Boot takes values as hexadecimals while Linux takes them as decimals by
+default. If using NAND or other storage, the commands are slightly different.
+When we have the static device tree image, we can re-make the FIT image with
+it. It is important to specify the load addresses in FIT image for every
+components. Otherwise U-Boot cannot load them correctly.
+
+Generate FIT image with static device tree
+------------------------------------------
+Example:
+
+/dts-v1/;
+
+/ {
+ description = "Image file for the LS1043A Linux Kernel";
+ #address-cells = <1>;
+
+ images {
+ kernel@1 {
+ description = "ARM64 Linux kernel";
+ data = /incbin/("./arch/arm64/boot/Image.gz");
+ type = "kernel";
+ arch = "arm64";
+ os = "linux";
+ compression = "gzip";
+ load = <0x80080000>;
+ entry = <0x80080000>;
+ };
+ fdt@1 {
+ description = "Flattened Device Tree blob";
+ data = /incbin/("./fsl-ls1043ardb-static.dtb");
+ type = "flat_dt";
+ arch = "arm64";
+ compression = "none";
+ load = <0x90000000>;
+ };
+ ramdisk@1 {
+ description = "LS1043 Ramdisk";
+ data = /incbin/("./rootfs.cpio.gz");
+ type = "ramdisk";
+ arch = "arm64";
+ os = "linux";
+ compression = "gzip";
+ load = <0xa0000000>;
+ };
+ };
+
+ configurations {
+ default = "config@1";
+ config@1 {
+ description = "Boot Linux kernel";
+ kernel = "kernel@1";
+ fdt = "fdt@1";
+ ramdisk = "ramdisk@1";
+ loadables = "fdt", "ramdisk";
+ };
+ };
+};
+
+The "loadables" is not optional. It tells SPL which images to load into memory.
+
+Other things to consider
+-----------------------
+Falcon boot skips a lot of initialization in U-Boot. If Linux expects the
+hardware to be initialized by U-Boot, the related code should be ported to SPL
+build. For example, if Linux expect Ethernet PHY to be initialized in U-Boot
+(which is not a common case), the PHY initialization has to be included in
+falcon boot. This increases the SPL image size and should be handled carefully.
+If Linux has PHY driver enabled, it still depends on the correct MDIO bus setup
+in U-Boot. Normal U-Boot sets the MDC ratio to generate a proper clock signal.
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/spl.c b/arch/arm/cpu/armv8/fsl-layerscape/spl.c
index 2534b4b..1c694e7 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/spl.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/spl.c
@@ -117,4 +117,29 @@
gd->arch.tlb_allocated = gd->arch.tlb_addr;
#endif /* CONFIG_SPL_FSL_LS_PPA */
}
+
+#ifdef CONFIG_SPL_OS_BOOT
+/*
+ * Return
+ * 0 if booting into OS is selected
+ * 1 if booting into U-Boot is selected
+ */
+int spl_start_uboot(void)
+{
+ env_init();
+ if (env_get_yesno("boot_os") != 0)
+ return 0;
+
+ return 1;
+}
+#endif /* CONFIG_SPL_OS_BOOT */
+#ifdef CONFIG_SPL_LOAD_FIT
+int board_fit_config_name_match(const char *name)
+{
+ /* Just empty function now - can't decide what to choose */
+ debug("%s: %s\n", __func__, name);
+
+ return 0;
+}
+#endif
#endif /* CONFIG_SPL_BUILD */
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 79bd19a..1d7d4f3 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -215,8 +215,8 @@
* @entry_point: kernel entry point
* @es_flag: execution state flag, ES_TO_AARCH64 or ES_TO_AARCH32
*/
-void armv8_switch_to_el2(u64 args, u64 mach_nr, u64 fdt_addr,
- u64 arg4, u64 entry_point, u64 es_flag);
+void __noreturn armv8_switch_to_el2(u64 args, u64 mach_nr, u64 fdt_addr,
+ u64 arg4, u64 entry_point, u64 es_flag);
/*
* Switch from EL2 to EL1 for ARMv8
*
diff --git a/arch/arm/lib/spl.c b/arch/arm/lib/spl.c
index 27d6682..ab5d227 100644
--- a/arch/arm/lib/spl.c
+++ b/arch/arm/lib/spl.c
@@ -7,6 +7,7 @@
*
* SPDX-License-Identifier: GPL-2.0+
*/
+
#include <common.h>
#include <config.h>
#include <spl.h>
@@ -47,6 +48,15 @@
* image.
*/
#ifdef CONFIG_SPL_OS_BOOT
+#ifdef CONFIG_ARM64
+void __noreturn jump_to_image_linux(struct spl_image_info *spl_image)
+{
+ debug("Entering kernel arg pointer: 0x%p\n", spl_image->arg);
+ cleanup_before_linux();
+ armv8_switch_to_el2((u64)spl_image->arg, 0, 0, 0,
+ spl_image->entry_point, ES_TO_AARCH64);
+}
+#else
void __noreturn jump_to_image_linux(struct spl_image_info *spl_image)
{
unsigned long machid = 0xffffffff;
@@ -62,4 +72,5 @@
cleanup_before_linux();
image_entry(0, machid, spl_image->arg);
}
+#endif /* CONFIG_ARM64 */
#endif