[U-Boot] [PATCH 4/9] sunxi: introduce RMR switch to enter payloads in 64-bit mode

Philipp Tomsich philipp.tomsich at theobroma-systems.com
Thu Feb 21 13:27:17 UTC 2019


Andre,

> On 21.02.2019, at 14:06, Alexander Graf <agraf at 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 at 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 at 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.


More information about the U-Boot mailing list