On Thu, 21 Feb 2019 12:52:50 +0100 Alexander Graf <ag...@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.przyw...@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/boot0.h;hb=HEAD > > + DSB; > > + ISB; > > + reset_rmr_switch(); > > + } > > +} > > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot