Message ID | 1506613337-19467-6-git-send-email-york.sun@nxp.com |
---|---|
State | Accepted |
Delegated to: | York Sun |
Headers | show |
Series | Enable falcon boot for LS1043ARDB | expand |
Hi York, > 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> > > --- > > Changes in v3: > Fix typo in subject and other cosmetic fix. > > Changes in v2: > Relace getenv_f() with env_get_f() after rebasing to latet master. > > .../arm/cpu/armv8/fsl-layerscape/doc/README.falcon | 140 +++++++++++++++++++++ > arch/arm/cpu/armv8/fsl-layerscape/spl.c | 29 +++++ > arch/arm/include/asm/system.h | 4 +- > arch/arm/lib/spl.c | 11 ++ > 4 files changed, 182 insertions(+), 2 deletions(-) > create mode 100644 arch/arm/cpu/armv8/fsl-layerscape/doc/README.falcon > > 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..282b19f > --- /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 desitinations. If FIT image is ^^^^^ - destinations > +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 abscent to favor the stored sectors. It is easier to deploy the FIT ^^^^^^ absent > +image with embedded static device tree to multiple boards. I would also add: "The decision if CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR loaded DTB is override is based on presence of "loadables" property in fitImage. If present the 'static' dtb from fitImage takes precedence. > + > +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, respectivelly. After the validation, the header ^^^^ respectively > +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, repectivelly ^^^^ respectively > + > +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 "as well as allows overriding the "falcon mode" created and loaded DTB". > + > +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..bbb9ab1 100644 > --- a/arch/arm/cpu/armv8/fsl-layerscape/spl.c > +++ b/arch/arm/cpu/armv8/fsl-layerscape/spl.c > @@ -117,4 +117,33 @@ 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) > +{ > + char s[8]; > + > + env_init(); > + env_get_f("boot_os", s, sizeof(s)); You may consider using env_get_yesno("boot_os") instead. > + if (s && (*s != '0' && *s != 'n' && *s != 'N' && > + *s != 'f' && *s != 'F')) > + 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 @@ 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 > * > 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 @@ 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 > I can confirm that your changes already available in master branch work. I'm able to boot fitImage from SPL, with using falcon boot mode. Reviewed-by: Łukasz Majewski <lukma@denx.de> Tested-by: Łukasz Majewski <lukma@denx.de>
On 09/29/2017 01:02 AM, Łukasz Majewski wrote: > Hi York, > >> 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> >> >> --- >> >> Changes in v3: >> Fix typo in subject and other cosmetic fix. >> >> Changes in v2: >> Relace getenv_f() with env_get_f() after rebasing to latet master. >> >> .../arm/cpu/armv8/fsl-layerscape/doc/README.falcon | 140 +++++++++++++++++++++ >> arch/arm/cpu/armv8/fsl-layerscape/spl.c | 29 +++++ >> arch/arm/include/asm/system.h | 4 +- >> arch/arm/lib/spl.c | 11 ++ >> 4 files changed, 182 insertions(+), 2 deletions(-) >> create mode 100644 arch/arm/cpu/armv8/fsl-layerscape/doc/README.falcon >> >> 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..282b19f >> --- /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 desitinations. If FIT image is > ^^^^^ - destinations Thanks for catching them. I will fix them with another spin, or when applying it. I need to setup the spelling check. York
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..282b19f --- /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 desitinations. 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 abscent 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, respectivelly. 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, repectivelly + +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..bbb9ab1 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/spl.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/spl.c @@ -117,4 +117,33 @@ 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) +{ + char s[8]; + + env_init(); + env_get_f("boot_os", s, sizeof(s)); + if (s && (*s != '0' && *s != 'n' && *s != 'N' && + *s != 'f' && *s != 'F')) + 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 @@ 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 * 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 @@ 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