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>
This commit is contained in:
parent
f554411bea
commit
fb97b8621e
140
arch/arm/cpu/armv8/fsl-layerscape/doc/README.falcon
Normal file
140
arch/arm/cpu/armv8/fsl-layerscape/doc/README.falcon
Normal file
@ -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.
|
@ -117,4 +117,29 @@ void board_init_f(ulong dummy)
|
||||
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 */
|
||||
|
@ -215,8 +215,8 @@ void __asm_switch_ttbr(u64 new_ttbr);
|
||||
* @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
|
||||
*
|
||||
|
@ -7,6 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <spl.h>
|
||||
@ -47,6 +48,15 @@ void __weak board_init_f(ulong dummy)
|
||||
* 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 @@ void __noreturn jump_to_image_linux(struct spl_image_info *spl_image)
|
||||
cleanup_before_linux();
|
||||
image_entry(0, machid, spl_image->arg);
|
||||
}
|
||||
#endif /* CONFIG_ARM64 */
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user