[U-Boot] [PATCH 0/9] sunxi: Allow FEL capable SPLs with 32bit builds

At the moment we can't use the USB-OTG based Allwinner FEL booting method with mainline U-Boot on ARMv8 Allwinner SoCs. As we run the SPL in AArch64 with the MMU enabled, returning to the BootROM in AArch32 with the MMU off and matching the BootROM's expectation is not trivial.
To workaround the problem, we can compile at least the SPL in AArch32. This creates FEL-capable SPLs without further ado. A second effect is the much smaller code size, due to smaller data types on one hand, and due to the more compact Thumb2 encoding on the other. Whereas Aarch64 builds get dangerously close to the 32KB limit, the Thumb2 build is less than 21KB. This is the cornerstone for more whacky experiments like DRAM autodetection and supporting multiple SoCs in one build.
So this series adds a Kconfig symbol to toggle between AArch64 and Thumb2 builds for the 64-bit Allwinner SoCs. The latter generates pure 32-bit binaries (including U-Boot proper), though this is not too useful at the moment (would require an ATF hack, for instance). However this can be the base for further 32-bit experiments.
The first patch removes the exception vectors in the SPL build (which were accidentally disabled anyway), to keep the Aarch64 H6 SPL within the limit. Patch 02 to 05 prepare the build system and some generic sunxi code parts for proper 32-bit compilation of ARMv8 boards. Patch 06 then adds the actual new Kconfig symbol, which toggles the bitness for a build. The final three patches add defconfigs for the respective SoCs and their DRAM variants. They must be build with an ARM(32) (cross) compiler, the FEL capable SPL can be plucked from spl/sunxi-spl.bin. Short of the DRAM configuration, there is nothing really board specific in there, so one SPL defconfig can cover multiple boards.
The 32-bit SPL is flexible enough to launch 64-bit binaries as well, so it can be combined with a 64-bit U-Boot proper and ATF, and also works on SD cards, from eMMC or SPI flash. Consider it a drop-in replacement for the 64-bit SPL build, although this has to be done manually. Also FEL booting requires the firmware components to be given separately on the sunxi-fel command line at the moment.
This is tested on the Pine64, Pine64-LTS, Orangepi-PC2 and Pine H64, with FEL booting, normal AArch64 boots from an SD card and a 32-bit SPL/ 64-bit U-Boot proper combination on an SD card.
Looking forward to any comments!
Cheers, Andre.
Alexander Graf (1): armv8: Disable exception vectors in SPL by default
Andre Przywara (8): Makefile: use "arm64" architecture for U-Boot image files SPL: read and store arch property from U-Boot image sunxi: introduce RMR switch to enter payloads in 64-bit mode sunxi: allow FIT image for 32-bit builds as well sunxi: allow 32-bit builds for 64-bit SoCs sunxi: H5: add generic H5 32-bit SPL defconfig sunxi: A64: add generic A64 32-bit SPL defconfigs sunxi: H6: add generic H6 32-bit SPL defconfig
Makefile | 12 +++++-- arch/arm/cpu/armv8/Kconfig | 2 +- arch/arm/cpu/armv8/start.S | 4 +-- arch/arm/lib/spl.c | 14 ++++++++ arch/arm/mach-sunxi/Kconfig | 13 +++++-- arch/arm/mach-sunxi/Makefile | 3 ++ arch/arm/mach-sunxi/spl_switch.c | 64 +++++++++++++++++++++++++++++++++ common/spl/spl.c | 1 + common/spl/spl_fit.c | 8 +++++ configs/sun50i-a64-ddr3-spl_defconfig | 13 +++++++ configs/sun50i-a64-lpddr3-spl_defconfig | 17 +++++++++ configs/sun50i-h5-ddr3-spl_defconfig | 16 +++++++++ configs/sun50i-h6-lpddr3-spl_defconfig | 12 +++++++ include/spl.h | 3 +- 14 files changed, 172 insertions(+), 10 deletions(-) create mode 100644 arch/arm/mach-sunxi/spl_switch.c create mode 100644 configs/sun50i-a64-ddr3-spl_defconfig create mode 100644 configs/sun50i-a64-lpddr3-spl_defconfig create mode 100644 configs/sun50i-h5-ddr3-spl_defconfig create mode 100644 configs/sun50i-h6-lpddr3-spl_defconfig

From: Alexander Graf agraf@suse.de
Commit 1416e2d2253 ("armv8: make SPL exception vectors optional") had a typo in it which effectively disabled exception handling in SPL code always.
Since nobody complained, I guess we may as well disable exception handling in SPL always by default.
So fix the bug to make the config option effective, but disable exception handling in SPL by default. This gets us to the same functionality as before by default, but with much less code included in the binary.
Signed-off-by: Alexander Graf agraf@suse.de Reviewed-by: Matthias Brugger mbrugger@suse.com Reviewed-by: Andre Przywara andre.przywara@arm.com --- arch/arm/cpu/armv8/Kconfig | 2 +- arch/arm/cpu/armv8/start.S | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/cpu/armv8/Kconfig b/arch/arm/cpu/armv8/Kconfig index 1c12bbde75..fb061c8d73 100644 --- a/arch/arm/cpu/armv8/Kconfig +++ b/arch/arm/cpu/armv8/Kconfig @@ -3,7 +3,7 @@ if ARM64 config ARMV8_SPL_EXCEPTION_VECTORS bool "Install crash dump exception vectors" depends on SPL - default y + default n help The default exception vector table is only used for the crash dump, but still takes quite a lot of space in the image size. diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S index 12a78ee38b..fe52166e28 100644 --- a/arch/arm/cpu/armv8/start.S +++ b/arch/arm/cpu/armv8/start.S @@ -88,7 +88,7 @@ pie_fixup_done: bl reset_sctrl #endif
-#if defined(CONFIG_ARMV8__SPL_EXCEPTION_VECTORS) || !defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_ARMV8_SPL_EXCEPTION_VECTORS) || !defined(CONFIG_SPL_BUILD) .macro set_vbar, regname, reg msr \regname, \reg .endm @@ -354,7 +354,7 @@ ENDPROC(smp_kick_all_cpus) /*-----------------------------------------------------------------------*/
ENTRY(c_runtime_cpu_setup) -#if defined(CONFIG_ARMV8__SPL_EXCEPTION_VECTORS) || !defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_ARMV8_SPL_EXCEPTION_VECTORS) || !defined(CONFIG_SPL_BUILD) /* Relocate vBAR */ adr x0, vectors switch_el x1, 3f, 2f, 1f

At the moment we use the arch/arm directory for arm64 boards as well, so the Makefile will pick up the "arm" name for the architecture to use for tagging binaries in U-Boot image files. Differentiate between the two by looking at the CPU variable being defined to "armv8", and use the arm64 architecture name on creating the image file if that matches.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- Makefile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile index 75a5c7d171..d6e7c69f40 100644 --- a/Makefile +++ b/Makefile @@ -1167,13 +1167,19 @@ $(U_BOOT_ITS): $(U_BOOT_ITS_DEPS) FORCE endif endif
+ifeq ($(CPU),armv8) +IH_ARCH := arm64 +else +IH_ARCH := $(ARCH) +endif + ifdef CONFIG_SPL_LOAD_FIT -MKIMAGEFLAGS_u-boot.img = -f auto -A $(ARCH) -T firmware -C none -O u-boot \ +MKIMAGEFLAGS_u-boot.img = -f auto -A $(IH_ARCH) -T firmware -C none -O u-boot \ -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_UBOOT_START) \ -n "U-Boot $(UBOOTRELEASE) for $(BOARD) board" -E \ $(patsubst %,-b arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST))) else -MKIMAGEFLAGS_u-boot.img = -A $(ARCH) -T firmware -C none -O u-boot \ +MKIMAGEFLAGS_u-boot.img = -A $(IH_ARCH) -T firmware -C none -O u-boot \ -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_UBOOT_START) \ -n "U-Boot $(UBOOTRELEASE) for $(BOARD) board" MKIMAGEFLAGS_u-boot-ivt.img = -A $(ARCH) -T firmware_ivt -C none -O u-boot \

On 02/21/2019 02:30 AM, Andre Przywara wrote:
At the moment we use the arch/arm directory for arm64 boards as well, so the Makefile will pick up the "arm" name for the architecture to use for tagging binaries in U-Boot image files. Differentiate between the two by looking at the CPU variable being defined to "armv8", and use the arm64 architecture name on creating the image file if that matches.
Signed-off-by: Andre Przywara andre.przywara@arm.com
Reviewed-by: Alexander Graf agraf@suse.de
Alex

On 21.02.2019, at 02:30, Andre Przywara andre.przywara@arm.com wrote:
At the moment we use the arch/arm directory for arm64 boards as well, so the Makefile will pick up the "arm" name for the architecture to use for tagging binaries in U-Boot image files. Differentiate between the two by looking at the CPU variable being defined to "armv8", and use the arm64 architecture name on creating the image file if that matches.
Signed-off-by: Andre Przywara andre.przywara@arm.com
Reviewed-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com

Read the specified "arch" value from a legacy or FIT U-Boot image and store it in our SPL data structure. This allows loaders to take the target architecture in account for custom loading procedures. Having the complete string -> arch mapping for FIT based images in the SPL would be too big, so we leave it up to architectures (or boards) to overwrite the weak function that does the actual translation, possibly covering only the required subset there.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- common/spl/spl.c | 1 + common/spl/spl_fit.c | 8 ++++++++ include/spl.h | 3 ++- 3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/common/spl/spl.c b/common/spl/spl.c index 2e2af1b28e..7d25e72bbb 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -272,6 +272,7 @@ int spl_parse_image_header(struct spl_image_info *spl_image, #endif
spl_image->os = image_get_os(header); + spl_image->arch = image_get_arch(header); spl_image->name = image_get_name(header); debug(SPL_TPL_PROMPT "payload image: %32s load addr: 0x%lx size: %d\n", diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index db436268cb..d583946571 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -340,6 +340,11 @@ static int spl_fit_image_get_os(const void *fit, int noffset, uint8_t *os) #endif }
+__weak u8 spl_genimg_get_arch_id(const char *arch_str) +{ + return IH_ARCH_DEFAULT; +} + int spl_load_simple_fit(struct spl_image_info *spl_image, struct spl_load_info *info, ulong sector, void *fit) { @@ -351,6 +356,7 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, int images, ret; int base_offset, hsize, align_len = ARCH_DMA_MINALIGN - 1; int index = 0; + const char *arch_str;
/* * For FIT with external data, figure out where the external images @@ -467,6 +473,8 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, else spl_image->os = IH_OS_U_BOOT; #endif + arch_str = fdt_getprop(fit, node, "arch", NULL); + spl_image->arch = spl_genimg_get_arch_id(arch_str);
/* * Booting a next-stage U-Boot may require us to append the FDT. diff --git a/include/spl.h b/include/spl.h index f09909e189..aac85150a7 100644 --- a/include/spl.h +++ b/include/spl.h @@ -64,7 +64,6 @@ static inline bool u_boot_first_phase(void)
struct spl_image_info { const char *name; - u8 os; uintptr_t load_addr; uintptr_t entry_point; #if CONFIG_IS_ENABLED(LOAD_FIT) @@ -79,6 +78,8 @@ struct spl_image_info { ulong dcrc_length; ulong dcrc; #endif + u8 os; + u8 arch; };
/*

On 02/21/2019 02:30 AM, Andre Przywara wrote:
Read the specified "arch" value from a legacy or FIT U-Boot image and store it in our SPL data structure. This allows loaders to take the target architecture in account for custom loading procedures. Having the complete string -> arch mapping for FIT based images in the SPL would be too big, so we leave it up to architectures (or boards) to overwrite the weak function that does the actual translation, possibly covering only the required subset there.
Signed-off-by: Andre Przywara andre.przywara@arm.com
Reviewed-by: Alexander Graf agraf@suse.de
I don't fully buy the argument that the generic mapping would be too big though. Realistically you should be able to get away with 1 or 2 branches per case, no? So that would be maybe 40 instructions?
Alex

On 21.02.2019, at 12:47, Alexander Graf agraf@suse.de wrote:
On 02/21/2019 02:30 AM, Andre Przywara wrote:
Read the specified "arch" value from a legacy or FIT U-Boot image and store it in our SPL data structure. This allows loaders to take the target architecture in account for custom loading procedures. Having the complete string -> arch mapping for FIT based images in the SPL would be too big, so we leave it up to architectures (or boards) to overwrite the weak function that does the actual translation, possibly covering only the required subset there.
Signed-off-by: Andre Przywara andre.przywara@arm.com
Reviewed-by: Alexander Graf agraf@suse.de
I don't fully buy the argument that the generic mapping would be too big though. Realistically you should be able to get away with 1 or 2 branches per case, no? So that would be maybe 40 instructions?
The question I believe is not just code size (should be minimal) but the table size for the mapping (assuming it’s a table). Do we have any data on this to understand what order-of-magnitude this “too big” is?
—Phil.

On Thu, 21 Feb 2019 12:47:04 +0100 Alexander Graf agraf@suse.de wrote:
Hi Alex,
On 02/21/2019 02:30 AM, Andre Przywara wrote:
Read the specified "arch" value from a legacy or FIT U-Boot image and store it in our SPL data structure. This allows loaders to take the target architecture in account for custom loading procedures. Having the complete string -> arch mapping for FIT based images in the SPL would be too big, so we leave it up to architectures (or boards) to overwrite the weak function that does the actual translation, possibly covering only the required subset there.
Signed-off-by: Andre Przywara andre.przywara@arm.com
Reviewed-by: Alexander Graf agraf@suse.de
Thanks for having a look!
I don't fully buy the argument that the generic mapping would be too big though. Realistically you should be able to get away with 1 or 2 branches per case, no? So that would be maybe 40 instructions?
You are apparently not in the Allwinner SPL mindset ;-) I get excited when I find a way of saving 100 bytes (see the writel_relaxed patch), so wasting 160 bytes when we will probably never need to return IH_ARCH_X86_64 doesn't sound right to me.
And Philipp is right: the canonical way would be to use uimage_arch[] from common/image.c, which is quite big.
We could have a big #ifdef cascade, something like: +#ifdef CONFIG_ARM + if (!strcmp(arch_str, "arm")) + return IH_ARCH_ARM; + + if (!strcmp(arch_str, "arm64")) + return IH_ARCH_ARM64; +#endif +#ifdef CONFIG_X86 + if (!strcmp(arch_str, "x86")) + return IH_ARCH_I386; + + if (!strcmp(arch_str, "x86_64")) + return IH_ARCH_X86_64; +#endif ....
I am just not sure it's worth to introduce this out of the blue *now*, without use cases and without proper testing.
Cheers, Andre.

On 21.02.2019, at 13:00, Andre Przywara andre.przywara@arm.com wrote:
On Thu, 21 Feb 2019 12:47:04 +0100 Alexander Graf agraf@suse.de wrote:
Hi Alex,
On 02/21/2019 02:30 AM, Andre Przywara wrote:
Read the specified "arch" value from a legacy or FIT U-Boot image and store it in our SPL data structure. This allows loaders to take the target architecture in account for custom loading procedures. Having the complete string -> arch mapping for FIT based images in the SPL would be too big, so we leave it up to architectures (or boards) to overwrite the weak function that does the actual translation, possibly covering only the required subset there.
Signed-off-by: Andre Przywara andre.przywara@arm.com
Reviewed-by: Alexander Graf agraf@suse.de
Thanks for having a look!
I don't fully buy the argument that the generic mapping would be too big though. Realistically you should be able to get away with 1 or 2 branches per case, no? So that would be maybe 40 instructions?
You are apparently not in the Allwinner SPL mindset ;-)
I am sometimes struggling against the 192KB limit on the RK3399. So while my current problems (SPL on the A31 was a different story) may sound like “luxury” to you, I do understand the pain.
I get excited when I find a way of saving 100 bytes (see the writel_relaxed patch), so wasting 160 bytes when we will probably never need to return IH_ARCH_X86_64 doesn't sound right to me.
And Philipp is right: the canonical way would be to use uimage_arch[] from common/image.c, which is quite big.
We could have a big #ifdef cascade, something like: +#ifdef CONFIG_ARM
- if (!strcmp(arch_str, "arm"))
return IH_ARCH_ARM;
- if (!strcmp(arch_str, "arm64"))
return IH_ARCH_ARM64;
+#endif +#ifdef CONFIG_X86
- if (!strcmp(arch_str, , "x86"))
return IH_ARCH_I386;
- if (!strcmp(arch_str, "x86_64"))
return IH_ARCH_X86_64;
+#endif
Could we have a preprocessor-guarded table of the form ONLY_ON(ARM)( { “arm”, IH_ARCH_ARM }, ) ONLY_ON(ARM)( { “arm64”, IH_ARCH_ARM64 }, ) for this?
Then the function would be for ( …, curr_element = …, ... ) { if (!strcmp(arch_str, curr_element.arch_str)) return curr_element.ih_value; which should be less than the hypothetical 40 instructions, I would hope.
Then again, I didn’t send this through a compiler to look at the assembly generated. And I have been surprised by code-size on AArch64 before.
I usually am in favor of cleaning up the common code paths, so my personal preference would be in figuring out a way how we can change uimage_arch[] to become useful in a space-constrained SPL context.
Phil.

On 21.02.19 14:22, Philipp Tomsich wrote:
On 21.02.2019, at 13:00, Andre Przywara andre.przywara@arm.com wrote:
On Thu, 21 Feb 2019 12:47:04 +0100 Alexander Graf agraf@suse.de wrote:
Hi Alex,
On 02/21/2019 02:30 AM, Andre Przywara wrote:
Read the specified "arch" value from a legacy or FIT U-Boot image and store it in our SPL data structure. This allows loaders to take the target architecture in account for custom loading procedures. Having the complete string -> arch mapping for FIT based images in the SPL would be too big, so we leave it up to architectures (or boards) to overwrite the weak function that does the actual translation, possibly covering only the required subset there.
Signed-off-by: Andre Przywara andre.przywara@arm.com
Reviewed-by: Alexander Graf agraf@suse.de
Thanks for having a look!
I don't fully buy the argument that the generic mapping would be too big though. Realistically you should be able to get away with 1 or 2 branches per case, no? So that would be maybe 40 instructions?
You are apparently not in the Allwinner SPL mindset ;-)
I am sometimes struggling against the 192KB limit on the RK3399. So while my current problems (SPL on the A31 was a different story) may sound like “luxury” to you, I do understand the pain.
I get excited when I find a way of saving 100 bytes (see the writel_relaxed patch), so wasting 160 bytes when we will probably never need to return IH_ARCH_X86_64 doesn't sound right to me.
And Philipp is right: the canonical way would be to use uimage_arch[] from common/image.c, which is quite big.
We could have a big #ifdef cascade, something like: +#ifdef CONFIG_ARM
- if (!strcmp(arch_str, "arm"))
return IH_ARCH_ARM;
- if (!strcmp(arch_str, "arm64"))
return IH_ARCH_ARM64;
+#endif +#ifdef CONFIG_X86
- if (!strcmp(arch_str, , "x86"))
return IH_ARCH_I386;
- if (!strcmp(arch_str, "x86_64"))
return IH_ARCH_X86_64;
+#endif
Could we have a preprocessor-guarded table of the form ONLY_ON(ARM)( { “arm”, IH_ARCH_ARM }, ) ONLY_ON(ARM)( { “arm64”, IH_ARCH_ARM64 }, ) for this?
Then the function would be for ( …, curr_element = …, ... ) { if (!strcmp(arch_str, curr_element.arch_str)) return curr_element.ih_value; which should be less than the hypothetical 40 instructions, I would hope.
Then again, I didn’t send this through a compiler to look at the assembly generated. And I have been surprised by code-size on AArch64 before.
I usually am in favor of cleaning up the common code paths, so my personal preference would be in figuring out a way how we can change uimage_arch[] to become useful in a space-constrained SPL context.
I was actually thinking more along the lines of
#ifdef CONFIG_ARM if (arch[0] == 'a') { if (arch[3] == '6') /* "arm64" */ return IH_ARCH_ARM64; else return IH_ARCH_ARM; } #endif
etc.
If you put that in a generic function that can be used across the board, you will also less likely have target specific bugs sneak in. And the resulting code should be much smaller than your strcmp.
Alex

The ARMv8 capable Allwinner A64 SoC comes out of reset in AArch32 mode. To run AArch64 code, we have to trigger a warm reset via the RMR register, which proceeds with code execution at the address stored in the RVBAR register. If the bootable payload in the FIT image is using a different architecture than the SPL has been compiled for, enter it via this said RMR switch mechanism, by writing the entry point address into the MMIO mapped, writable version of the RVBAR register. Then the warm reset is triggered via a system register write. If the payload architecture is the same as the SPL, we use the normal branch as usual.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- arch/arm/lib/spl.c | 14 +++++++++ arch/arm/mach-sunxi/Makefile | 3 ++ arch/arm/mach-sunxi/spl_switch.c | 64 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 arch/arm/mach-sunxi/spl_switch.c
diff --git a/arch/arm/lib/spl.c b/arch/arm/lib/spl.c index 33cc76ba3d..4d9370d232 100644 --- a/arch/arm/lib/spl.c +++ b/arch/arm/lib/spl.c @@ -73,3 +73,17 @@ void __noreturn jump_to_image_linux(struct spl_image_info *spl_image) } #endif /* CONFIG_ARM64 */ #endif + +u8 spl_genimg_get_arch_id(const char *arch_str) +{ + if (!arch_str) + return IH_ARCH_DEFAULT; + + if (!strcmp(arch_str, "arm")) + return IH_ARCH_ARM; + + if (!strcmp(arch_str, "arm64")) + return IH_ARCH_ARM64; + + return IH_ARCH_DEFAULT; +} diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index 43a93e3085..5a5e10a024 100644 --- a/arch/arm/mach-sunxi/Makefile +++ b/arch/arm/mach-sunxi/Makefile @@ -39,4 +39,7 @@ obj-$(CONFIG_SPL_SPI_SUNXI) += spl_spi_sunxi.o obj-$(CONFIG_SUNXI_DRAM_DW) += dram_sunxi_dw.o obj-$(CONFIG_SUNXI_DRAM_DW) += dram_timings/ obj-$(CONFIG_DRAM_SUN50I_H6) += dram_sun50i_h6.o +obj-$(CONFIG_MACH_SUN50I) += spl_switch.o +obj-$(CONFIG_MACH_SUN50I_H5) += spl_switch.o +obj-$(CONFIG_MACH_SUN50I_H6) += spl_switch.o endif diff --git a/arch/arm/mach-sunxi/spl_switch.c b/arch/arm/mach-sunxi/spl_switch.c new file mode 100644 index 0000000000..1de43c2396 --- /dev/null +++ b/arch/arm/mach-sunxi/spl_switch.c @@ -0,0 +1,64 @@ +/* + * (C) Copyright 2016 ARM Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <spl.h> + +#include <asm/io.h> +#include <asm/barriers.h> + +static void __noreturn jump_to_image_native(struct spl_image_info *spl_image) +{ + typedef void __noreturn (*image_entry_noargs_t)(void); + + image_entry_noargs_t image_entry = + (image_entry_noargs_t)spl_image->entry_point; + + image_entry(); +} + +static void __noreturn reset_rmr_switch(void) +{ +#ifdef CONFIG_ARM64 + __asm__ volatile ( "mrs x0, RMR_EL3\n\t" + "bic x0, x0, #1\n\t" /* Clear enter-in-64 bit */ + "orr x0, x0, #2\n\t" /* set reset request bit */ + "msr RMR_EL3, x0\n\t" + "isb sy\n\t" + "nop\n\t" + "wfi\n\t" + "b .\n" + ::: "x0"); +#else + __asm__ volatile ( "mrc 15, 0, r0, cr12, cr0, 2\n\t" + "orr r0, r0, #3\n\t" /* request reset in 64 bit */ + "mcr 15, 0, r0, cr12, cr0, 2\n\t" + "isb\n\t" + "nop\n\t" + "wfi\n\t" + "b .\n" + ::: "r0"); +#endif + while (1); /* to avoid a compiler warning about __noreturn */ +} + +void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) +{ + if (spl_image->arch == IH_ARCH_DEFAULT) { + debug("entering by branch\n"); + jump_to_image_native(spl_image); + } else { + debug("entering by RMR switch\n"); +#ifdef CONFIG_MACH_SUN50I_H6 + writel(spl_image->entry_point, 0x09010040); +#else + writel(spl_image->entry_point, 0x017000a0); +#endif + DSB; + ISB; + reset_rmr_switch(); + } +}

On 02/21/2019 02:30 AM, Andre Przywara wrote:
The ARMv8 capable Allwinner A64 SoC comes out of reset in AArch32 mode. To run AArch64 code, we have to trigger a warm reset via the RMR register, which proceeds with code execution at the address stored in the RVBAR register. If the bootable payload in the FIT image is using a different architecture than the SPL has been compiled for, enter it via this said RMR switch mechanism, by writing the entry point address into the MMIO mapped, writable version of the RVBAR register. Then the warm reset is triggered via a system register write. If the payload architecture is the same as the SPL, we use the normal branch as usual.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/lib/spl.c | 14 +++++++++ arch/arm/mach-sunxi/Makefile | 3 ++ arch/arm/mach-sunxi/spl_switch.c | 64 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 arch/arm/mach-sunxi/spl_switch.c
diff --git a/arch/arm/lib/spl.c b/arch/arm/lib/spl.c index 33cc76ba3d..4d9370d232 100644 --- a/arch/arm/lib/spl.c +++ b/arch/arm/lib/spl.c @@ -73,3 +73,17 @@ void __noreturn jump_to_image_linux(struct spl_image_info *spl_image) } #endif /* CONFIG_ARM64 */ #endif
+u8 spl_genimg_get_arch_id(const char *arch_str) +{
- if (!arch_str)
return IH_ARCH_DEFAULT;
- if (!strcmp(arch_str, "arm"))
return IH_ARCH_ARM;
- if (!strcmp(arch_str, "arm64"))
return IH_ARCH_ARM64;
- return IH_ARCH_DEFAULT;
+} diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index 43a93e3085..5a5e10a024 100644 --- a/arch/arm/mach-sunxi/Makefile +++ b/arch/arm/mach-sunxi/Makefile @@ -39,4 +39,7 @@ obj-$(CONFIG_SPL_SPI_SUNXI) += spl_spi_sunxi.o obj-$(CONFIG_SUNXI_DRAM_DW) += dram_sunxi_dw.o obj-$(CONFIG_SUNXI_DRAM_DW) += dram_timings/ obj-$(CONFIG_DRAM_SUN50I_H6) += dram_sun50i_h6.o +obj-$(CONFIG_MACH_SUN50I) += spl_switch.o +obj-$(CONFIG_MACH_SUN50I_H5) += spl_switch.o +obj-$(CONFIG_MACH_SUN50I_H6) += spl_switch.o endif diff --git a/arch/arm/mach-sunxi/spl_switch.c b/arch/arm/mach-sunxi/spl_switch.c new file mode 100644 index 0000000000..1de43c2396 --- /dev/null +++ b/arch/arm/mach-sunxi/spl_switch.c @@ -0,0 +1,64 @@ +/*
- (C) Copyright 2016 ARM Ltd.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <spl.h>
+#include <asm/io.h> +#include <asm/barriers.h>
+static void __noreturn jump_to_image_native(struct spl_image_info *spl_image) +{
- typedef void __noreturn (*image_entry_noargs_t)(void);
- image_entry_noargs_t image_entry =
(image_entry_noargs_t)spl_image->entry_point;
- image_entry();
+}
+static void __noreturn reset_rmr_switch(void) +{ +#ifdef CONFIG_ARM64
- __asm__ volatile ( "mrs x0, RMR_EL3\n\t"
"bic x0, x0, #1\n\t" /* Clear enter-in-64 bit */
"orr x0, x0, #2\n\t" /* set reset request bit */
"msr RMR_EL3, x0\n\t"
"isb sy\n\t"
"nop\n\t"
"wfi\n\t"
"b .\n"
::: "x0");
+#else
- __asm__ volatile ( "mrc 15, 0, r0, cr12, cr0, 2\n\t"
"orr r0, r0, #3\n\t" /* request reset in 64 bit */
"mcr 15, 0, r0, cr12, cr0, 2\n\t"
"isb\n\t"
"nop\n\t"
"wfi\n\t"
"b .\n"
::: "r0");
+#endif
- while (1); /* to avoid a compiler warning about __noreturn */
+}
+void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) +{
- if (spl_image->arch == IH_ARCH_DEFAULT) {
debug("entering by branch\n");
jump_to_image_native(spl_image);
- } else {
debug("entering by RMR switch\n");
+#ifdef CONFIG_MACH_SUN50I_H6
writel(spl_image->entry_point, 0x09010040);
+#else
writel(spl_image->entry_point, 0x017000a0);
+#endif
How does the original entry point get preserved over this? Don't you have to set the reset vector register as well?
Alex
DSB;
ISB;
reset_rmr_switch();
- }
+}

On Thu, 21 Feb 2019 12:52:50 +0100 Alexander Graf agraf@suse.de wrote:
On 02/21/2019 02:30 AM, Andre Przywara wrote:
The ARMv8 capable Allwinner A64 SoC comes out of reset in AArch32 mode. To run AArch64 code, we have to trigger a warm reset via the RMR register, which proceeds with code execution at the address stored in the RVBAR register. If the bootable payload in the FIT image is using a different architecture than the SPL has been compiled for, enter it via this said RMR switch mechanism, by writing the entry point address into the MMIO mapped, writable version of the RVBAR register. Then the warm reset is triggered via a system register write. If the payload architecture is the same as the SPL, we use the normal branch as usual.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/lib/spl.c | 14 +++++++++ arch/arm/mach-sunxi/Makefile | 3 ++ arch/arm/mach-sunxi/spl_switch.c | 64 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 arch/arm/mach-sunxi/spl_switch.c
diff --git a/arch/arm/lib/spl.c b/arch/arm/lib/spl.c index 33cc76ba3d..4d9370d232 100644 --- a/arch/arm/lib/spl.c +++ b/arch/arm/lib/spl.c @@ -73,3 +73,17 @@ void __noreturn jump_to_image_linux(struct spl_image_info *spl_image) } #endif /* CONFIG_ARM64 */ #endif
+u8 spl_genimg_get_arch_id(const char *arch_str) +{
- if (!arch_str)
return IH_ARCH_DEFAULT;
- if (!strcmp(arch_str, "arm"))
return IH_ARCH_ARM;
- if (!strcmp(arch_str, "arm64"))
return IH_ARCH_ARM64;
- return IH_ARCH_DEFAULT;
+} diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index 43a93e3085..5a5e10a024 100644 --- a/arch/arm/mach-sunxi/Makefile +++ b/arch/arm/mach-sunxi/Makefile @@ -39,4 +39,7 @@ obj-$(CONFIG_SPL_SPI_SUNXI) += spl_spi_sunxi.o obj-$(CONFIG_SUNXI_DRAM_DW) += dram_sunxi_dw.o obj-$(CONFIG_SUNXI_DRAM_DW) += dram_timings/ obj-$(CONFIG_DRAM_SUN50I_H6) += dram_sun50i_h6.o +obj-$(CONFIG_MACH_SUN50I) += spl_switch.o +obj-$(CONFIG_MACH_SUN50I_H5) += spl_switch.o +obj-$(CONFIG_MACH_SUN50I_H6) += spl_switch.o endif diff --git a/arch/arm/mach-sunxi/spl_switch.c b/arch/arm/mach-sunxi/spl_switch.c new file mode 100644 index 0000000000..1de43c2396 --- /dev/null +++ b/arch/arm/mach-sunxi/spl_switch.c @@ -0,0 +1,64 @@ +/*
- (C) Copyright 2016 ARM Ltd.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <spl.h>
+#include <asm/io.h> +#include <asm/barriers.h>
+static void __noreturn jump_to_image_native(struct spl_image_info *spl_image) +{
- typedef void __noreturn (*image_entry_noargs_t)(void);
- image_entry_noargs_t image_entry =
(image_entry_noargs_t)spl_image->entry_point;
- image_entry();
+}
+static void __noreturn reset_rmr_switch(void) +{ +#ifdef CONFIG_ARM64
- __asm__ volatile ( "mrs x0, RMR_EL3\n\t"
"bic x0, x0, #1\n\t" /* Clear enter-in-64 bit */
"orr x0, x0, #2\n\t" /* set reset request bit */
"msr RMR_EL3, x0\n\t"
"isb sy\n\t"
"nop\n\t"
"wfi\n\t"
"b .\n"
::: "x0");
+#else
- __asm__ volatile ( "mrc 15, 0, r0, cr12, cr0, 2\n\t"
"orr r0, r0, #3\n\t" /* request reset in 64 bit */
"mcr 15, 0, r0, cr12, cr0, 2\n\t"
"isb\n\t"
"nop\n\t"
"wfi\n\t"
"b .\n"
::: "r0");
+#endif
- while (1); /* to avoid a compiler warning about __noreturn */
+}
+void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) +{
- if (spl_image->arch == IH_ARCH_DEFAULT) {
debug("entering by branch\n");
jump_to_image_native(spl_image);
- } else {
debug("entering by RMR switch\n");
+#ifdef CONFIG_MACH_SUN50I_H6
writel(spl_image->entry_point, 0x09010040);
+#else
writel(spl_image->entry_point, 0x017000a0);
+#endif
How does the original entry point get preserved over this? Don't you have to set the reset vector register as well?
The RVBAR_ELx (Reset Vector Base Address Register) registers are architecturally read only. Fortunately Allwinner decided to have an MMIO mapped writable alias, which we exploit here. I *believe* this gets reset on a hard reset (external signal, for instance via the watchdog) to the initial 0x0 value.
Anyway we use this method already in the AArch64 SPL today [1], and it happens to work ;-)
Cheers, Andre.
[1] http://git.denx.de/?p=u-boot.git;a=blob;f=arch/arm/include/asm/arch-sunxi/bo...
DSB;
ISB;
reset_rmr_switch();
- }
+}

On 02/21/2019 01:07 PM, Andre Przywara wrote:
On Thu, 21 Feb 2019 12:52:50 +0100 Alexander Graf agraf@suse.de wrote:
On 02/21/2019 02:30 AM, Andre Przywara wrote:
The ARMv8 capable Allwinner A64 SoC comes out of reset in AArch32 mode. To run AArch64 code, we have to trigger a warm reset via the RMR register, which proceeds with code execution at the address stored in the RVBAR register. If the bootable payload in the FIT image is using a different architecture than the SPL has been compiled for, enter it via this said RMR switch mechanism, by writing the entry point address into the MMIO mapped, writable version of the RVBAR register. Then the warm reset is triggered via a system register write. If the payload architecture is the same as the SPL, we use the normal branch as usual.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/lib/spl.c | 14 +++++++++ arch/arm/mach-sunxi/Makefile | 3 ++ arch/arm/mach-sunxi/spl_switch.c | 64 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 arch/arm/mach-sunxi/spl_switch.c
diff --git a/arch/arm/lib/spl.c b/arch/arm/lib/spl.c index 33cc76ba3d..4d9370d232 100644 --- a/arch/arm/lib/spl.c +++ b/arch/arm/lib/spl.c @@ -73,3 +73,17 @@ void __noreturn jump_to_image_linux(struct spl_image_info *spl_image) } #endif /* CONFIG_ARM64 */ #endif
+u8 spl_genimg_get_arch_id(const char *arch_str) +{
- if (!arch_str)
return IH_ARCH_DEFAULT;
- if (!strcmp(arch_str, "arm"))
return IH_ARCH_ARM;
- if (!strcmp(arch_str, "arm64"))
return IH_ARCH_ARM64;
- return IH_ARCH_DEFAULT;
+} diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index 43a93e3085..5a5e10a024 100644 --- a/arch/arm/mach-sunxi/Makefile +++ b/arch/arm/mach-sunxi/Makefile @@ -39,4 +39,7 @@ obj-$(CONFIG_SPL_SPI_SUNXI) += spl_spi_sunxi.o obj-$(CONFIG_SUNXI_DRAM_DW) += dram_sunxi_dw.o obj-$(CONFIG_SUNXI_DRAM_DW) += dram_timings/ obj-$(CONFIG_DRAM_SUN50I_H6) += dram_sun50i_h6.o +obj-$(CONFIG_MACH_SUN50I) += spl_switch.o +obj-$(CONFIG_MACH_SUN50I_H5) += spl_switch.o +obj-$(CONFIG_MACH_SUN50I_H6) += spl_switch.o endif diff --git a/arch/arm/mach-sunxi/spl_switch.c b/arch/arm/mach-sunxi/spl_switch.c new file mode 100644 index 0000000000..1de43c2396 --- /dev/null +++ b/arch/arm/mach-sunxi/spl_switch.c @@ -0,0 +1,64 @@ +/*
- (C) Copyright 2016 ARM Ltd.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <spl.h>
+#include <asm/io.h> +#include <asm/barriers.h>
+static void __noreturn jump_to_image_native(struct spl_image_info *spl_image) +{
- typedef void __noreturn (*image_entry_noargs_t)(void);
- image_entry_noargs_t image_entry =
(image_entry_noargs_t)spl_image->entry_point;
- image_entry();
+}
+static void __noreturn reset_rmr_switch(void) +{ +#ifdef CONFIG_ARM64
- __asm__ volatile ( "mrs x0, RMR_EL3\n\t"
"bic x0, x0, #1\n\t" /* Clear enter-in-64 bit */
"orr x0, x0, #2\n\t" /* set reset request bit */
"msr RMR_EL3, x0\n\t"
"isb sy\n\t"
"nop\n\t"
"wfi\n\t"
"b .\n"
::: "x0");
+#else
- __asm__ volatile ( "mrc 15, 0, r0, cr12, cr0, 2\n\t"
"orr r0, r0, #3\n\t" /* request reset in 64 bit */
"mcr 15, 0, r0, cr12, cr0, 2\n\t"
"isb\n\t"
"nop\n\t"
"wfi\n\t"
"b .\n"
::: "r0");
+#endif
- while (1); /* to avoid a compiler warning about __noreturn */
+}
+void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) +{
- if (spl_image->arch == IH_ARCH_DEFAULT) {
debug("entering by branch\n");
jump_to_image_native(spl_image);
- } else {
debug("entering by RMR switch\n");
+#ifdef CONFIG_MACH_SUN50I_H6
writel(spl_image->entry_point, 0x09010040);
+#else
writel(spl_image->entry_point, 0x017000a0);
+#endif
How does the original entry point get preserved over this? Don't you have to set the reset vector register as well?
The RVBAR_ELx (Reset Vector Base Address Register) registers are architecturally read only. Fortunately Allwinner decided to have an MMIO mapped writable alias, which we exploit here. I *believe* this gets reset on a hard reset (external signal, for instance via the watchdog) to the initial 0x0 value.
Anyway we use this method already in the AArch64 SPL today [1], and it happens to work ;-)
Ugh, I read writel() the wrong way around. Do you think you can give the constant a nice #define that makes it fully obvious what's going on here?
Thanks!
Alex

Andre,
On 21.02.2019, at 14:06, Alexander Graf agraf@suse.de wrote:
On 02/21/2019 01:07 PM, Andre Przywara wrote:
On Thu, 21 Feb 2019 12:52:50 +0100 Alexander Graf agraf@suse.de wrote:
On 02/21/2019 02:30 AM, Andre Przywara wrote:
The ARMv8 capable Allwinner A64 SoC comes out of reset in AArch32 mode. To run AArch64 code, we have to trigger a warm reset via the RMR register, which proceeds with code execution at the address stored in the RVBAR register. If the bootable payload in the FIT image is using a different architecture than the SPL has been compiled for, enter it via this said RMR switch mechanism, by writing the entry point address into the MMIO mapped, writable version of the RVBAR register. Then the warm reset is triggered via a system register write. If the payload architecture is the same as the SPL, we use the normal branch as usual.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/lib/spl.c | 14 +++++++++ arch/arm/mach-sunxi/Makefile | 3 ++ arch/arm/mach-sunxi/spl_switch.c | 64 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 arch/arm/mach-sunxi/spl_switch.c
diff --git a/arch/arm/lib/spl.c b/arch/arm/lib/spl.c index 33cc76ba3d..4d9370d232 100644 --- a/arch/arm/lib/spl.c +++ b/arch/arm/lib/spl.c @@ -73,3 +73,17 @@ void __noreturn jump_to_image_linux(struct spl_image_info *spl_image) } #endif /* CONFIG_ARM64 */ #endif
+u8 spl_genimg_get_arch_id(const char *arch_str) +{
- if (!arch_str)
return IH_ARCH_DEFAULT;
- if (!strcmp(arch_str, "arm"))
return IH_ARCH_ARM;
- if (!strcmp(arch_str, "arm64"))
return IH_ARCH_ARM64;
- return IH_ARCH_DEFAULT;
+} diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index 43a93e3085..5a5e10a024 100644 --- a/arch/arm/mach-sunxi/Makefile +++ b/arch/arm/mach-sunxi/Makefile @@ -39,4 +39,7 @@ obj-$(CONFIG_SPL_SPI_SUNXI) += spl_spi_sunxi.o obj-$(CONFIG_SUNXI_DRAM_DW) += dram_sunxi_dw.o obj-$(CONFIG_SUNXI_DRAM_DW) += dram_timings/ obj-$(CONFIG_DRAM_SUN50I_H6) += dram_sun50i_h6.o +obj-$(CONFIG_MACH_SUN50I) += spl_switch.o +obj-$(CONFIG_MACH_SUN50I_H5) += spl_switch.o +obj-$(CONFIG_MACH_SUN50I_H6) += spl_switch.o endif diff --git a/arch/arm/mach-sunxi/spl_switch.c b/arch/arm/mach-sunxi/spl_switch.c new file mode 100644 index 0000000000..1de43c2396 --- /dev/null +++ b/arch/arm/mach-sunxi/spl_switch.c @@ -0,0 +1,64 @@ +/*
- (C) Copyright 2016 ARM Ltd.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <spl.h>
+#include <asm/io.h> +#include <asm/barriers.h>
+static void __noreturn jump_to_image_native(struct spl_image_info *spl_image) +{
- typedef void __noreturn (*image_entry_noargs_t)(void);
- image_entry_noargs_t image_entry =
(image_entry_noargs_t)spl_image->entry_point;
- image_entry();
+}
+static void __noreturn reset_rmr_switch(void) +{ +#ifdef CONFIG_ARM64
- __asm__ volatile ( "mrs x0, RMR_EL3\n\t"
"bic x0, x0, #1\n\t" /* Clear enter-in-64 bit */
"orr x0, x0, #2\n\t" /* set reset request bit */
"msr RMR_EL3, x0\n\t"
"isb sy\n\t"
"nop\n\t"
"wfi\n\t"
"b .\n"
::: "x0");
+#else
- __asm__ volatile ( "mrc 15, 0, r0, cr12, cr0, 2\n\t"
"orr r0, r0, #3\n\t" /* request reset in 64 bit */
"mcr 15, 0, r0, cr12, cr0, 2\n\t"
"isb\n\t"
"nop\n\t"
"wfi\n\t"
"b .\n"
::: "r0");
+#endif
- while (1); /* to avoid a compiler warning about __noreturn */
+}
+void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) +{
- if (spl_image->arch == IH_ARCH_DEFAULT) {
debug("entering by branch\n");
jump_to_image_native(spl_image);
- } else {
debug("entering by RMR switch\n");
+#ifdef CONFIG_MACH_SUN50I_H6
writel(spl_image->entry_point, 0x09010040);
+#else
writel(spl_image->entry_point, 0x017000a0);
+#endif
How does the original entry point get preserved over this? Don't you have to set the reset vector register as well?
The RVBAR_ELx (Reset Vector Base Address Register) registers are architecturally read only. Fortunately Allwinner decided to have an MMIO mapped writable alias, which we exploit here. I *believe* this gets reset on a hard reset (external signal, for instance via the watchdog) to the initial 0x0 value.
Anyway we use this method already in the AArch64 SPL today [1], and it happens to work ;-)
Ugh, I read writel() the wrong way around. Do you think you can give the constant a nice #define that makes it fully obvious what's going on here?
I have been preaching this for rockchip-changes: please use a “u32 * const” instead of a define... The compiler has a typesystem, so let’s provide the necessary info to fully use it ;-)
Cheers, Philipp.

Even though we introduced FIT image support for the SPL to cover the 64-bit SoCs, there is no technical limitation to those parts.
Change the Makefile stanza to always create a FIT image if the particular config either provided a script or an .its file.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile index d6e7c69f40..3a560e29bf 100644 --- a/Makefile +++ b/Makefile @@ -1350,7 +1350,7 @@ u-boot-x86-16bit.bin: u-boot FORCE endif
ifneq ($(CONFIG_ARCH_SUNXI),) -ifeq ($(CONFIG_ARM64),) +ifeq ($(CONFIG_SPL_FIT_SOURCE)$(CONFIG_SPL_FIT_GENERATOR),) u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img u-boot.dtb FORCE $(call if_changed,binman) else

On 21.02.19 02:30, Andre Przywara wrote:
Even though we introduced FIT image support for the SPL to cover the 64-bit SoCs, there is no technical limitation to those parts.
Change the Makefile stanza to always create a FIT image if the particular config either provided a script or an .its file.
Signed-off-by: Andre Przywara andre.przywara@arm.com
Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile index d6e7c69f40..3a560e29bf 100644 --- a/Makefile +++ b/Makefile @@ -1350,7 +1350,7 @@ u-boot-x86-16bit.bin: u-boot FORCE endif
ifneq ($(CONFIG_ARCH_SUNXI),) -ifeq ($(CONFIG_ARM64),) +ifeq ($(CONFIG_SPL_FIT_SOURCE)$(CONFIG_SPL_FIT_GENERATOR),)
The commit message sounds as if this should be an "ifneq"?
Alex
u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img u-boot.dtb FORCE $(call if_changed,binman) else

On 22/02/2019 08:06, Alexander Graf wrote:
On 21.02.19 02:30, Andre Przywara wrote:
Even though we introduced FIT image support for the SPL to cover the 64-bit SoCs, there is no technical limitation to those parts.
Change the Makefile stanza to always create a FIT image if the particular config either provided a script or an .its file.
Signed-off-by: Andre Przywara andre.przywara@arm.com
Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile index d6e7c69f40..3a560e29bf 100644 --- a/Makefile +++ b/Makefile @@ -1350,7 +1350,7 @@ u-boot-x86-16bit.bin: u-boot FORCE endif
ifneq ($(CONFIG_ARCH_SUNXI),) -ifeq ($(CONFIG_ARM64),) +ifeq ($(CONFIG_SPL_FIT_SOURCE)$(CONFIG_SPL_FIT_GENERATOR),)
The commit message sounds as if this should be an "ifneq"?
If find those ifeq(something,) constructs always confusing, but I think it's right here: The line in the if-clause creates the *legacy* U-Boot image, so the two strings must be both empty for it to match and to execute those commands. If only one of them is "y", the comparison with the empty string will fail and the else clause will be called, which creates the FIT image.
Or did I trick myself?
Cheers, Andre.
u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img u-boot.dtb FORCE $(call if_changed,binman) else

On 23.02.19 02:10, André Przywara wrote:
On 22/02/2019 08:06, Alexander Graf wrote:
On 21.02.19 02:30, Andre Przywara wrote:
Even though we introduced FIT image support for the SPL to cover the 64-bit SoCs, there is no technical limitation to those parts.
Change the Makefile stanza to always create a FIT image if the particular config either provided a script or an .its file.
Signed-off-by: Andre Przywara andre.przywara@arm.com
Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile index d6e7c69f40..3a560e29bf 100644 --- a/Makefile +++ b/Makefile @@ -1350,7 +1350,7 @@ u-boot-x86-16bit.bin: u-boot FORCE endif
ifneq ($(CONFIG_ARCH_SUNXI),) -ifeq ($(CONFIG_ARM64),) +ifeq ($(CONFIG_SPL_FIT_SOURCE)$(CONFIG_SPL_FIT_GENERATOR),)
The commit message sounds as if this should be an "ifneq"?
If find those ifeq(something,) constructs always confusing, but I think it's right here: The line in the if-clause creates the *legacy* U-Boot image, so the two strings must be both empty for it to match and to execute those commands. If only one of them is "y", the comparison with the empty string will fail and the else clause will be called, which creates the FIT image.
Or did I trick myself?
No, I just got confused myself, sorry :). All good.
Reviewed-by: Alexander Graf agraf@suse.de
Alex

At the moment we build the SPL and U-Boot proper for the 64-bit AArch64 instruction set. But since the cores provide an AArch32 compatibility mode and in fact the BootROM runs in 32-bit mode, it can be useful to have at least the SPL run in AArch32 as well. This has two advantages: - As AArch32 features the compact Thumb2 instruction encoding, we can get a much smaller image size, which is a relief for our SPL. - Staying in AArch32, with the MMU turned off, allows an easy return to the BootROM and its FEL mode. This enables FEL booting on those SoCs.
Introduce a Kconfig option which toggles between CONFIG_ARM64 and CONFIG_CPU_V7A, to allow easy switching between the two modes. This can be manually selected in menuconfig, but follow-up patches will introduce a separate defconfig for that purpose.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- arch/arm/mach-sunxi/Kconfig | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 74e234cded..347d737fd0 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -146,6 +146,10 @@ config SUNXI_DRAM_MAX_SIZE default 0xC0000000 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6 default 0x80000000
+config SUNXI_ARMV8_32BIT_BUILD + bool "Build 32-bit binaries for ARMv8 SoCs" + default n + choice prompt "Sunxi SoC Variant" optional @@ -275,7 +279,8 @@ config MACH_SUN9I
config MACH_SUN50I bool "sun50i (Allwinner A64)" - select ARM64 + select ARM64 if !SUNXI_ARMV8_32BIT_BUILD + select CPU_V7A if SUNXI_ARMV8_32BIT_BUILD select DM_I2C select PHY_SUN4I_USB select SUN6I_PRCM @@ -291,14 +296,16 @@ config MACH_SUN50I
config MACH_SUN50I_H5 bool "sun50i (Allwinner H5)" - select ARM64 + select ARM64 if !SUNXI_ARMV8_32BIT_BUILD + select CPU_V7A if SUNXI_ARMV8_32BIT_BUILD select MACH_SUNXI_H3_H5 select FIT select SPL_LOAD_FIT
config MACH_SUN50I_H6 bool "sun50i (Allwinner H6)" - select ARM64 + select ARM64 if !SUNXI_ARMV8_32BIT_BUILD + select CPU_V7A if SUNXI_ARMV8_32BIT_BUILD select SUPPORT_SPL select FIT select SPL_LOAD_FIT

On 21.02.19 02:30, Andre Przywara wrote:
At the moment we build the SPL and U-Boot proper for the 64-bit AArch64 instruction set. But since the cores provide an AArch32 compatibility mode and in fact the BootROM runs in 32-bit mode, it can be useful to have at least the SPL run in AArch32 as well. This has two advantages:
- As AArch32 features the compact Thumb2 instruction encoding, we can get a much smaller image size, which is a relief for our SPL.
- Staying in AArch32, with the MMU turned off, allows an easy return to the BootROM and its FEL mode. This enables FEL booting on those SoCs.
Introduce a Kconfig option which toggles between CONFIG_ARM64 and CONFIG_CPU_V7A, to allow easy switching between the two modes. This can be manually selected in menuconfig, but follow-up patches will introduce a separate defconfig for that purpose.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/mach-sunxi/Kconfig | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 74e234cded..347d737fd0 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -146,6 +146,10 @@ config SUNXI_DRAM_MAX_SIZE default 0xC0000000 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6 default 0x80000000
+config SUNXI_ARMV8_32BIT_BUILD
- bool "Build 32-bit binaries for ARMv8 SoCs"
- default n
choice prompt "Sunxi SoC Variant" optional @@ -275,7 +279,8 @@ config MACH_SUN9I
config MACH_SUN50I bool "sun50i (Allwinner A64)"
- select ARM64
- select ARM64 if !SUNXI_ARMV8_32BIT_BUILD
Can't you make this "imply ARM64" instead and then just set ARM64=n;CPU_V7A=y in the defconfig?
Alex
- select CPU_V7A if SUNXI_ARMV8_32BIT_BUILD select DM_I2C select PHY_SUN4I_USB select SUN6I_PRCM
@@ -291,14 +296,16 @@ config MACH_SUN50I
config MACH_SUN50I_H5 bool "sun50i (Allwinner H5)"
- select ARM64
- select ARM64 if !SUNXI_ARMV8_32BIT_BUILD
- select CPU_V7A if SUNXI_ARMV8_32BIT_BUILD select MACH_SUNXI_H3_H5 select FIT select SPL_LOAD_FIT
config MACH_SUN50I_H6 bool "sun50i (Allwinner H6)"
- select ARM64
- select ARM64 if !SUNXI_ARMV8_32BIT_BUILD
- select CPU_V7A if SUNXI_ARMV8_32BIT_BUILD select SUPPORT_SPL select FIT select SPL_LOAD_FIT

Hi Alex,
On 2/22/19 2:13 AM, Alexander Graf wrote:
On 21.02.19 02:30, Andre Przywara wrote:
At the moment we build the SPL and U-Boot proper for the 64-bit AArch64 instruction set. But since the cores provide an AArch32 compatibility mode and in fact the BootROM runs in 32-bit mode, it can be useful to have at least the SPL run in AArch32 as well. This has two advantages:
- As AArch32 features the compact Thumb2 instruction encoding, we can get a much smaller image size, which is a relief for our SPL.
- Staying in AArch32, with the MMU turned off, allows an easy return to the BootROM and its FEL mode. This enables FEL booting on those SoCs.
Introduce a Kconfig option which toggles between CONFIG_ARM64 and CONFIG_CPU_V7A, to allow easy switching between the two modes. This can be manually selected in menuconfig, but follow-up patches will introduce a separate defconfig for that purpose.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/mach-sunxi/Kconfig | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 74e234cded..347d737fd0 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -146,6 +146,10 @@ config SUNXI_DRAM_MAX_SIZE default 0xC0000000 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6 default 0x80000000
+config SUNXI_ARMV8_32BIT_BUILD
- bool "Build 32-bit binaries for ARMv8 SoCs"
- default n
- choice prompt "Sunxi SoC Variant" optional
@@ -275,7 +279,8 @@ config MACH_SUN9I
config MACH_SUN50I bool "sun50i (Allwinner A64)"
- select ARM64
- select ARM64 if !SUNXI_ARMV8_32BIT_BUILD
Can't you make this "imply ARM64" instead and then just set ARM64=n;CPU_V7A=y in the defconfig?
Ha, that indeed sounds tempting, and actually I tried this before, but it doesn't work. The kernel doc says that an "imply" setting can be overwritten by a direct dependency or a visible prompt. ARM64 is not visible (empty bool), so I figured that introducing this simple symbol is the smallest pain to tackle this issue.
Cheers, Andre.
Alex
- select CPU_V7A if SUNXI_ARMV8_32BIT_BUILD select DM_I2C select PHY_SUN4I_USB select SUN6I_PRCM
@@ -291,14 +296,16 @@ config MACH_SUN50I
config MACH_SUN50I_H5 bool "sun50i (Allwinner H5)"
- select ARM64
select ARM64 if !SUNXI_ARMV8_32BIT_BUILD
select CPU_V7A if SUNXI_ARMV8_32BIT_BUILD select MACH_SUNXI_H3_H5 select FIT select SPL_LOAD_FIT
config MACH_SUN50I_H6 bool "sun50i (Allwinner H6)"
- select ARM64
- select ARM64 if !SUNXI_ARMV8_32BIT_BUILD
- select CPU_V7A if SUNXI_ARMV8_32BIT_BUILD select SUPPORT_SPL select FIT select SPL_LOAD_FIT

On 26.02.19 00:32, Andre Przywara wrote:
Hi Alex,
On 2/22/19 2:13 AM, Alexander Graf wrote:
On 21.02.19 02:30, Andre Przywara wrote:
At the moment we build the SPL and U-Boot proper for the 64-bit AArch64 instruction set. But since the cores provide an AArch32 compatibility mode and in fact the BootROM runs in 32-bit mode, it can be useful to have at least the SPL run in AArch32 as well. This has two advantages:
- As AArch32 features the compact Thumb2 instruction encoding, we can
get a much smaller image size, which is a relief for our SPL.
- Staying in AArch32, with the MMU turned off, allows an easy return to
the BootROM and its FEL mode. This enables FEL booting on those SoCs.
Introduce a Kconfig option which toggles between CONFIG_ARM64 and CONFIG_CPU_V7A, to allow easy switching between the two modes. This can be manually selected in menuconfig, but follow-up patches will introduce a separate defconfig for that purpose.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/mach-sunxi/Kconfig | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 74e234cded..347d737fd0 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -146,6 +146,10 @@ config SUNXI_DRAM_MAX_SIZE default 0xC0000000 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6 default 0x80000000 +config SUNXI_ARMV8_32BIT_BUILD + bool "Build 32-bit binaries for ARMv8 SoCs" + default n
choice prompt "Sunxi SoC Variant" optional @@ -275,7 +279,8 @@ config MACH_SUN9I config MACH_SUN50I bool "sun50i (Allwinner A64)" - select ARM64 + select ARM64 if !SUNXI_ARMV8_32BIT_BUILD
Can't you make this "imply ARM64" instead and then just set ARM64=n;CPU_V7A=y in the defconfig?
Ha, that indeed sounds tempting, and actually I tried this before, but it doesn't work. The kernel doc says that an "imply" setting can be overwritten by a direct dependency or a visible prompt. ARM64 is not visible (empty bool), so I figured that introducing this simple symbol is the smallest pain to tackle this issue.
If you say you already did try imply, then I'm all happy :).
Alex

To be able to use FEL booting (Allwinner's USB-OTG protocol), we need a 32 bit SPL, to easily return into the 32 bit BootROM. Add a generic defconfig for that purpose, that should work on all boards. The resulting spl/sunxi-spl.bin can be used with the sunxi-fel tool to initialise the DRAM via FEL. This allows to load the normal versions for the rest of the firmware components (ATF, 64 bit U-Boot proper). This SPL will determine the architecture of the loaded binaries and will switch the bitness if necessary.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- configs/sun50i-h5-ddr3-spl_defconfig | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 configs/sun50i-h5-ddr3-spl_defconfig
diff --git a/configs/sun50i-h5-ddr3-spl_defconfig b/configs/sun50i-h5-ddr3-spl_defconfig new file mode 100644 index 0000000000..7b720e2fc5 --- /dev/null +++ b/configs/sun50i-h5-ddr3-spl_defconfig @@ -0,0 +1,16 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_SPL=y +CONFIG_MACH_SUN50I_H5=y +CONFIG_SUNXI_ARMV8_32BIT_BUILD=y +CONFIG_DRAM_CLK=672 +CONFIG_DRAM_ZQ=3881977 +CONFIG_SPL_SPI_SUNXI=y +CONFIG_NR_DRAM_BANKS=1 +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +# CONFIG_CMD_FLASH is not set +# CONFIG_SPL_DOS_PARTITION is not set +# CONFIG_SPL_EFI_PARTITION is not set +CONFIG_DEFAULT_DEVICE_TREE="sun50i-h5-orangepi-pc2" +CONFIG_MMC_SUNXI_SLOT_EXTRA=2 +CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE=y

To be able to use FEL booting (Allwinner's USB-OTG protocol), we need a 32 bit SPL, to easily return into the 32 bit BootROM. Add two generic defconfigs for that purpose, one for boards with DDR3 DRAM, the other for those with LPDDR3 DRAM chips. The resulting spl/sunxi-spl.bin can be used with the sunxi-fel tool to initialise the DRAM via FEL. This allows to load the normal versions for the rest of the firmware components (ATF, 64 bit U-Boot proper). This SPL will determine the architecture of the loaded binaries and will switch the bitness if necessary.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- configs/sun50i-a64-ddr3-spl_defconfig | 13 +++++++++++++ configs/sun50i-a64-lpddr3-spl_defconfig | 17 +++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 configs/sun50i-a64-ddr3-spl_defconfig create mode 100644 configs/sun50i-a64-lpddr3-spl_defconfig
diff --git a/configs/sun50i-a64-ddr3-spl_defconfig b/configs/sun50i-a64-ddr3-spl_defconfig new file mode 100644 index 0000000000..fda15e2491 --- /dev/null +++ b/configs/sun50i-a64-ddr3-spl_defconfig @@ -0,0 +1,13 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_SPL=y +CONFIG_MACH_SUN50I=y +CONFIG_SUNXI_ARMV8_32BIT_BUILD=y +CONFIG_NR_DRAM_BANKS=1 +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +# CONFIG_CMD_FLASH is not set +# CONFIG_SPL_DOS_PARTITION is not set +# CONFIG_SPL_EFI_PARTITION is not set +CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-pine64-plus" +CONFIG_SPL_SPI_SUNXI=y +CONFIG_MMC_SUNXI_SLOT_EXTRA=2 diff --git a/configs/sun50i-a64-lpddr3-spl_defconfig b/configs/sun50i-a64-lpddr3-spl_defconfig new file mode 100644 index 0000000000..20bc376cbd --- /dev/null +++ b/configs/sun50i-a64-lpddr3-spl_defconfig @@ -0,0 +1,17 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_SPL=y +CONFIG_MACH_SUN50I=y +CONFIG_SUNXI_ARMV8_32BIT_BUILD=y +CONFIG_SUNXI_DRAM_LPDDR3_STOCK=y +CONFIG_DRAM_CLK=552 +CONFIG_DRAM_ZQ=3881949 +CONFIG_NR_DRAM_BANKS=1 +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +# CONFIG_CMD_FLASH is not set +# CONFIG_SPL_DOS_PARTITION is not set +# CONFIG_SPL_EFI_PARTITION is not set +CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-pine64-lts" +CONFIG_MMC0_CD_PIN="" +CONFIG_SPL_SPI_SUNXI=y +CONFIG_MMC_SUNXI_SLOT_EXTRA=2

To be able to use FEL booting (Allwinner's USB-OTG protocol), we need a 32 bit SPL, to easily return into the 32 bit BootROM. Add a generic defconfig for that purpose, that should work on all boards. The resulting spl/sunxi-spl.bin can be used with the sunxi-fel tool to initialise the DRAM via FEL. This allows to load the normal versions for the rest of the firmware components (ATF, 64 bit U-Boot proper). This SPL will determine the architecture of the loaded binaries and will switch the bitness if necessary.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- configs/sun50i-h6-lpddr3-spl_defconfig | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 configs/sun50i-h6-lpddr3-spl_defconfig
diff --git a/configs/sun50i-h6-lpddr3-spl_defconfig b/configs/sun50i-h6-lpddr3-spl_defconfig new file mode 100644 index 0000000000..8480d027a5 --- /dev/null +++ b/configs/sun50i-h6-lpddr3-spl_defconfig @@ -0,0 +1,12 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_SPL=y +CONFIG_MACH_SUN50I_H6=y +CONFIG_SUNXI_ARMV8_32BIT_BUILD=y +CONFIG_MMC_SUNXI_SLOT_EXTRA=2 +CONFIG_NR_DRAM_BANKS=1 +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +# CONFIG_CMD_FLASH is not set +# CONFIG_SPL_DOS_PARTITION is not set +# CONFIG_SPL_EFI_PARTITION is not set +CONFIG_DEFAULT_DEVICE_TREE="sun50i-h6-pine-h64"
participants (4)
-
Alexander Graf
-
Andre Przywara
-
André Przywara
-
Philipp Tomsich