[U-Boot] [PATCH 4/9] sunxi: introduce RMR switch to enter payloads in 64-bit mode
Alexander Graf
agraf at suse.de
Thu Feb 21 13:06:02 UTC 2019
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?
Thanks!
Alex
More information about the U-Boot
mailing list