diff mbox series

sunxi: Add arm64 FEL support

Message ID 20201119105442.24711-1-andre.przywara@arm.com
State New
Delegated to: Jagannadha Sutradharudu Teki
Headers show
Series sunxi: Add arm64 FEL support | expand

Commit Message

André Przywara Nov. 19, 2020, 10:54 a.m. UTC
So far we did not support the BootROM based FEL USB debug mode on the
64-bit builds for Allwinner SoCs: The BootROM is using AArch32, but the
SPL runs in AArch64.
Returning back to AArch32 was not working as expected, since the RMR
reset into 32-bit mode always starts execution in the BootROM, but not
in the FEL routine.

After some debug and research and with help via IRC, the CPU hotplug
mechanism emerged as a solution: If a certain R_CPUCFG register contains
some magic, the BootROM will immediately branch to an address stored in
some other register. This works well for our purposes.

Enable the FEL feature by providing early AArch32 code to first save the
FEL state, *before* initially entering AArch64.
If we eventually determine that we should return to FEL, we reset back
into AArch32, and use the CPU hotplug mechanism to run some small
AArch32 code snippet that restores the initially saved FEL state.

That allows the normal AArch64 SPL build to be loaded via the sunxi-fel
tool, with it returning into FEL mode, so that other payloads can be
transferred via FEL as well.

Tested on A64, H5 and H6.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arch/arm/cpu/armv8/Makefile             |  2 +
 arch/arm/cpu/armv8/fel_utils.S          | 78 +++++++++++++++++++++++++
 arch/arm/include/asm/arch-sunxi/boot0.h | 14 +++++
 include/configs/sunxi-common.h          |  2 -
 4 files changed, 94 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/cpu/armv8/fel_utils.S

Comments

Priit Laes Nov. 19, 2020, 7:59 p.m. UTC | #1
On Thu, Nov 19, 2020 at 10:54:42AM +0000, Andre Przywara wrote:
> So far we did not support the BootROM based FEL USB debug mode on the
> 64-bit builds for Allwinner SoCs: The BootROM is using AArch32, but the
> SPL runs in AArch64.
> Returning back to AArch32 was not working as expected, since the RMR
> reset into 32-bit mode always starts execution in the BootROM, but not
> in the FEL routine.
> 
> After some debug and research and with help via IRC, the CPU hotplug
> mechanism emerged as a solution: If a certain R_CPUCFG register contains
> some magic, the BootROM will immediately branch to an address stored in
> some other register. This works well for our purposes.
> 
> Enable the FEL feature by providing early AArch32 code to first save the
> FEL state, *before* initially entering AArch64.
> If we eventually determine that we should return to FEL, we reset back
> into AArch32, and use the CPU hotplug mechanism to run some small
> AArch32 code snippet that restores the initially saved FEL state.
> 
> That allows the normal AArch64 SPL build to be loaded via the sunxi-fel
> tool, with it returning into FEL mode, so that other payloads can be
> transferred via FEL as well.
> 
> Tested on A64, H5 and H6.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  arch/arm/cpu/armv8/Makefile             |  2 +
>  arch/arm/cpu/armv8/fel_utils.S          | 78 +++++++++++++++++++++++++
>  arch/arm/include/asm/arch-sunxi/boot0.h | 14 +++++
>  include/configs/sunxi-common.h          |  2 -
>  4 files changed, 94 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm/cpu/armv8/fel_utils.S

Don't you want to also update board/sunxi/README.sunxi64 ?

> 
> diff --git a/arch/arm/cpu/armv8/Makefile b/arch/arm/cpu/armv8/Makefile
> index 93d26f98568..f7b4a5ee46c 100644
> --- a/arch/arm/cpu/armv8/Makefile
> +++ b/arch/arm/cpu/armv8/Makefile
> @@ -27,6 +27,8 @@ obj-$(CONFIG_ARM_SMCCC)		+= smccc-call.o
>  
>  ifndef CONFIG_SPL_BUILD
>  obj-$(CONFIG_ARMV8_SPIN_TABLE) += spin_table.o spin_table_v8.o
> +else
> +obj-$(CONFIG_ARCH_SUNXI) += fel_utils.o
>  endif
>  obj-$(CONFIG_$(SPL_)ARMV8_SEC_FIRMWARE_SUPPORT) += sec_firmware.o sec_firmware_asm.o
>  
> diff --git a/arch/arm/cpu/armv8/fel_utils.S b/arch/arm/cpu/armv8/fel_utils.S
> new file mode 100644
> index 00000000000..334fdef7fa0
> --- /dev/null
> +++ b/arch/arm/cpu/armv8/fel_utils.S
> @@ -0,0 +1,78 @@
> +/*
> + * Utility functions for FEL mode, when running SPL in AArch64.
> + *
> + * Copyright (c) 2017 Arm Ltd.
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <asm-offsets.h>
> +#include <config.h>
> +#include <asm/system.h>
> +#include <linux/linkage.h>
> +
> +/*
> + * We don't overwrite save_boot_params() here, to save the FEL state upon
> + * entry, since this would run *after* the RMR reset, which clobbers that
> + * state.
> + * Instead we store the state _very_ early in the boot0 hook, *before*
> + * resetting to AArch64.
> + */
> +
> +/*
> + * The FEL routines in BROM run in AArch32.
> + * Reset back into 32-bit mode here and restore the saved FEL state
> + * afterwards.
> + * Resetting back into AArch32/EL3 using the RMR always enters the BROM,
> + * but we can use the CPU hotplug mechanism to branch back to our code
> + * immediately.
> + */
> +ENTRY(return_to_fel)
> +	/*
> +	 * the RMR reset will clear all registers, so save the arguments
> +	 * (LR and SP) in the fel_stash structure, which we read anyways later
> +	 */
> +	adr	x2, fel_stash
> +	str	w0, [x2]
> +	str	w1, [x2, #4]
> +
> +	adr	x1, fel_stash_addr	// to find the fel_stash address in AA32
> +	str	w2, [x1]
> +
> +	ldr	x0, =0xfa50392f		// CPU hotplug magic
> +#ifndef CONFIG_MACH_SUN50I_H6
> +	ldr	x2, =(SUNXI_CPUCFG_BASE + 0x1a4) // offset for CPU hotplug base
> +	str	w0, [x2, #0x8]
> +#else
> +	ldr	x2, =(SUNXI_RTC_BASE + 0x1b8)	// BOOT_CPU_HP_FLAG_REG
> +	str	w0, [x2], #0x4
> +#endif
> +	adr	x0, back_in_32
> +	str	w0, [x2]
> +
> +	dsb	sy
> +	isb	sy
> +	mov	x0, #2			// RMR reset into AArch32
> +	dsb	sy
> +	msr	RMR_EL3, x0
> +	isb	sy
> +1:	wfi
> +	b	1b
> +
> +/* AArch32 code to restore the state from fel_stash and return back to FEL. */
> +back_in_32:
> +	.word	0xe59f0028 	// ldr	r0, [pc, #40]	; load fel_stash address
> +	.word	0xe5901008 	// ldr	r1, [r0, #8]
> +	.word	0xe129f001 	// msr	CPSR_fc, r1
> +	.word	0xf57ff06f	// isb
> +	.word	0xe590d000 	// ldr	sp, [r0]
> +	.word	0xe590e004 	// ldr	lr, [r0, #4]
> +	.word	0xe5901010 	// ldr	r1, [r0, #16]
> +	.word	0xee0c1f10 	// mcr	15, 0, r1, cr12, cr0, {0} ; VBAR
> +	.word	0xe590100c 	// ldr	r1, [r0, #12]
> +	.word	0xee011f10 	// mcr	15, 0, r1, cr1, cr0, {0}  ; SCTLR
> +	.word	0xf57ff06f	// isb
> +	.word	0xe12fff1e 	// bx	lr		; return to FEL
> +fel_stash_addr:
> +	.word   0x00000000	// receives fel_stash addr, by AA64 code above
> +ENDPROC(return_to_fel)
> diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h b/arch/arm/include/asm/arch-sunxi/boot0.h
> index 54c144afd8c..46d0f0666c2 100644
> --- a/arch/arm/include/asm/arch-sunxi/boot0.h
> +++ b/arch/arm/include/asm/arch-sunxi/boot0.h
> @@ -15,6 +15,19 @@
>  	tst     x0, x0                  // this is "b #0x84" in ARM
>  	b       reset
>  	.space  0x7c
> +
> +	.word	0xe28f0058	// add     r0, pc, #88
> +	.word	0xe59f1054	// ldr     r1, [pc, #84]
> +	.word	0xe0800001	// add     r0, r0, r1
> +	.word	0xe580d000	// str     sp, [r0]
> +	.word	0xe580e004	// str     lr, [r0, #4]
> +	.word	0xe10fe000	// mrs     lr, CPSR
> +	.word	0xe580e008	// str     lr, [r0, #8]
> +	.word	0xee11ef10	// mrc     15, 0, lr, cr1, cr0, {0}
> +	.word	0xe580e00c	// str     lr, [r0, #12]
> +	.word	0xee1cef10	// mrc     15, 0, lr, cr12, cr0, {0}
> +	.word	0xe580e010	// str     lr, [r0, #16]
> +
>  	.word	0xe59f1024	// ldr     r1, [pc, #36] ; 0x170000a0
>  	.word	0xe59f0024	// ldr     r0, [pc, #36] ; CONFIG_*_TEXT_BASE
>  	.word	0xe5810000	// str     r0, [r1]
> @@ -36,6 +49,7 @@
>  #else
>  	.word   CONFIG_SYS_TEXT_BASE
>  #endif
> +	.word	fel_stash - .
>  #else
>  /* normal execution */
>  	b	reset
> diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
> index a6a4879523a..203cb10fbab 100644
> --- a/include/configs/sunxi-common.h
> +++ b/include/configs/sunxi-common.h
> @@ -163,9 +163,7 @@
>  
>  #define CONFIG_SYS_MONITOR_LEN		(768 << 10)	/* 768 KiB */
>  
> -#ifndef CONFIG_ARM64		/* AArch64 FEL support is not ready yet */
>  #define CONFIG_SPL_BOARD_LOAD_IMAGE
> -#endif
>  
>  /*
>   * We cannot use expressions here, because expressions won't be evaluated in
> -- 
> 2.17.5
> 
> -- 
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
> To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20201119105442.24711-1-andre.przywara%40arm.com.
André Przywara Nov. 20, 2020, 9:42 a.m. UTC | #2
On 19/11/2020 19:59, Priit Laes wrote:
> On Thu, Nov 19, 2020 at 10:54:42AM +0000, Andre Przywara wrote:
>> So far we did not support the BootROM based FEL USB debug mode on the
>> 64-bit builds for Allwinner SoCs: The BootROM is using AArch32, but the
>> SPL runs in AArch64.
>> Returning back to AArch32 was not working as expected, since the RMR
>> reset into 32-bit mode always starts execution in the BootROM, but not
>> in the FEL routine.
>>
>> After some debug and research and with help via IRC, the CPU hotplug
>> mechanism emerged as a solution: If a certain R_CPUCFG register contains
>> some magic, the BootROM will immediately branch to an address stored in
>> some other register. This works well for our purposes.
>>
>> Enable the FEL feature by providing early AArch32 code to first save the
>> FEL state, *before* initially entering AArch64.
>> If we eventually determine that we should return to FEL, we reset back
>> into AArch32, and use the CPU hotplug mechanism to run some small
>> AArch32 code snippet that restores the initially saved FEL state.
>>
>> That allows the normal AArch64 SPL build to be loaded via the sunxi-fel
>> tool, with it returning into FEL mode, so that other payloads can be
>> transferred via FEL as well.
>>
>> Tested on A64, H5 and H6.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  arch/arm/cpu/armv8/Makefile             |  2 +
>>  arch/arm/cpu/armv8/fel_utils.S          | 78 +++++++++++++++++++++++++
>>  arch/arm/include/asm/arch-sunxi/boot0.h | 14 +++++
>>  include/configs/sunxi-common.h          |  2 -
>>  4 files changed, 94 insertions(+), 2 deletions(-)
>>  create mode 100644 arch/arm/cpu/armv8/fel_utils.S
> 
> Don't you want to also update board/sunxi/README.sunxi64 ?

Yes, but I am in the process of rewriting this anyway, since some parts
apply to 32-bit SoCs as well (SD card, SPI flash), and there is
currently no documentation about them. So bear with me, I will post a
documentation update ASAP, just didn't want to hold back this patch.

Thanks!
Andre.

>>
>> diff --git a/arch/arm/cpu/armv8/Makefile b/arch/arm/cpu/armv8/Makefile
>> index 93d26f98568..f7b4a5ee46c 100644
>> --- a/arch/arm/cpu/armv8/Makefile
>> +++ b/arch/arm/cpu/armv8/Makefile
>> @@ -27,6 +27,8 @@ obj-$(CONFIG_ARM_SMCCC)		+= smccc-call.o
>>  
>>  ifndef CONFIG_SPL_BUILD
>>  obj-$(CONFIG_ARMV8_SPIN_TABLE) += spin_table.o spin_table_v8.o
>> +else
>> +obj-$(CONFIG_ARCH_SUNXI) += fel_utils.o
>>  endif
>>  obj-$(CONFIG_$(SPL_)ARMV8_SEC_FIRMWARE_SUPPORT) += sec_firmware.o sec_firmware_asm.o
>>  
>> diff --git a/arch/arm/cpu/armv8/fel_utils.S b/arch/arm/cpu/armv8/fel_utils.S
>> new file mode 100644
>> index 00000000000..334fdef7fa0
>> --- /dev/null
>> +++ b/arch/arm/cpu/armv8/fel_utils.S
>> @@ -0,0 +1,78 @@
>> +/*
>> + * Utility functions for FEL mode, when running SPL in AArch64.
>> + *
>> + * Copyright (c) 2017 Arm Ltd.
>> + *
>> + * SPDX-License-Identifier:	GPL-2.0+
>> + */
>> +
>> +#include <asm-offsets.h>
>> +#include <config.h>
>> +#include <asm/system.h>
>> +#include <linux/linkage.h>
>> +
>> +/*
>> + * We don't overwrite save_boot_params() here, to save the FEL state upon
>> + * entry, since this would run *after* the RMR reset, which clobbers that
>> + * state.
>> + * Instead we store the state _very_ early in the boot0 hook, *before*
>> + * resetting to AArch64.
>> + */
>> +
>> +/*
>> + * The FEL routines in BROM run in AArch32.
>> + * Reset back into 32-bit mode here and restore the saved FEL state
>> + * afterwards.
>> + * Resetting back into AArch32/EL3 using the RMR always enters the BROM,
>> + * but we can use the CPU hotplug mechanism to branch back to our code
>> + * immediately.
>> + */
>> +ENTRY(return_to_fel)
>> +	/*
>> +	 * the RMR reset will clear all registers, so save the arguments
>> +	 * (LR and SP) in the fel_stash structure, which we read anyways later
>> +	 */
>> +	adr	x2, fel_stash
>> +	str	w0, [x2]
>> +	str	w1, [x2, #4]
>> +
>> +	adr	x1, fel_stash_addr	// to find the fel_stash address in AA32
>> +	str	w2, [x1]
>> +
>> +	ldr	x0, =0xfa50392f		// CPU hotplug magic
>> +#ifndef CONFIG_MACH_SUN50I_H6
>> +	ldr	x2, =(SUNXI_CPUCFG_BASE + 0x1a4) // offset for CPU hotplug base
>> +	str	w0, [x2, #0x8]
>> +#else
>> +	ldr	x2, =(SUNXI_RTC_BASE + 0x1b8)	// BOOT_CPU_HP_FLAG_REG
>> +	str	w0, [x2], #0x4
>> +#endif
>> +	adr	x0, back_in_32
>> +	str	w0, [x2]
>> +
>> +	dsb	sy
>> +	isb	sy
>> +	mov	x0, #2			// RMR reset into AArch32
>> +	dsb	sy
>> +	msr	RMR_EL3, x0
>> +	isb	sy
>> +1:	wfi
>> +	b	1b
>> +
>> +/* AArch32 code to restore the state from fel_stash and return back to FEL. */
>> +back_in_32:
>> +	.word	0xe59f0028 	// ldr	r0, [pc, #40]	; load fel_stash address
>> +	.word	0xe5901008 	// ldr	r1, [r0, #8]
>> +	.word	0xe129f001 	// msr	CPSR_fc, r1
>> +	.word	0xf57ff06f	// isb
>> +	.word	0xe590d000 	// ldr	sp, [r0]
>> +	.word	0xe590e004 	// ldr	lr, [r0, #4]
>> +	.word	0xe5901010 	// ldr	r1, [r0, #16]
>> +	.word	0xee0c1f10 	// mcr	15, 0, r1, cr12, cr0, {0} ; VBAR
>> +	.word	0xe590100c 	// ldr	r1, [r0, #12]
>> +	.word	0xee011f10 	// mcr	15, 0, r1, cr1, cr0, {0}  ; SCTLR
>> +	.word	0xf57ff06f	// isb
>> +	.word	0xe12fff1e 	// bx	lr		; return to FEL
>> +fel_stash_addr:
>> +	.word   0x00000000	// receives fel_stash addr, by AA64 code above
>> +ENDPROC(return_to_fel)
>> diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h b/arch/arm/include/asm/arch-sunxi/boot0.h
>> index 54c144afd8c..46d0f0666c2 100644
>> --- a/arch/arm/include/asm/arch-sunxi/boot0.h
>> +++ b/arch/arm/include/asm/arch-sunxi/boot0.h
>> @@ -15,6 +15,19 @@
>>  	tst     x0, x0                  // this is "b #0x84" in ARM
>>  	b       reset
>>  	.space  0x7c
>> +
>> +	.word	0xe28f0058	// add     r0, pc, #88
>> +	.word	0xe59f1054	// ldr     r1, [pc, #84]
>> +	.word	0xe0800001	// add     r0, r0, r1
>> +	.word	0xe580d000	// str     sp, [r0]
>> +	.word	0xe580e004	// str     lr, [r0, #4]
>> +	.word	0xe10fe000	// mrs     lr, CPSR
>> +	.word	0xe580e008	// str     lr, [r0, #8]
>> +	.word	0xee11ef10	// mrc     15, 0, lr, cr1, cr0, {0}
>> +	.word	0xe580e00c	// str     lr, [r0, #12]
>> +	.word	0xee1cef10	// mrc     15, 0, lr, cr12, cr0, {0}
>> +	.word	0xe580e010	// str     lr, [r0, #16]
>> +
>>  	.word	0xe59f1024	// ldr     r1, [pc, #36] ; 0x170000a0
>>  	.word	0xe59f0024	// ldr     r0, [pc, #36] ; CONFIG_*_TEXT_BASE
>>  	.word	0xe5810000	// str     r0, [r1]
>> @@ -36,6 +49,7 @@
>>  #else
>>  	.word   CONFIG_SYS_TEXT_BASE
>>  #endif
>> +	.word	fel_stash - .
>>  #else
>>  /* normal execution */
>>  	b	reset
>> diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
>> index a6a4879523a..203cb10fbab 100644
>> --- a/include/configs/sunxi-common.h
>> +++ b/include/configs/sunxi-common.h
>> @@ -163,9 +163,7 @@
>>  
>>  #define CONFIG_SYS_MONITOR_LEN		(768 << 10)	/* 768 KiB */
>>  
>> -#ifndef CONFIG_ARM64		/* AArch64 FEL support is not ready yet */
>>  #define CONFIG_SPL_BOARD_LOAD_IMAGE
>> -#endif
>>  
>>  /*
>>   * We cannot use expressions here, because expressions won't be evaluated in
>> -- 
>> 2.17.5
>>
>> -- 
>> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
>> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
>> To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20201119105442.24711-1-andre.przywara%40arm.com.
Jernej Škrabec Nov. 21, 2020, 7:05 a.m. UTC | #3
Hi Andre,

thanks for working on this!

Dne petek, 20. november 2020 ob 10:42:15 CET je André Przywara napisal(a):
> On 19/11/2020 19:59, Priit Laes wrote:
> > On Thu, Nov 19, 2020 at 10:54:42AM +0000, Andre Przywara wrote:
> >> So far we did not support the BootROM based FEL USB debug mode on the
> >> 64-bit builds for Allwinner SoCs: The BootROM is using AArch32, but the
> >> SPL runs in AArch64.
> >> Returning back to AArch32 was not working as expected, since the RMR
> >> reset into 32-bit mode always starts execution in the BootROM, but not
> >> in the FEL routine.
> >>
> >> After some debug and research and with help via IRC, the CPU hotplug
> >> mechanism emerged as a solution: If a certain R_CPUCFG register contains
> >> some magic, the BootROM will immediately branch to an address stored in
> >> some other register. This works well for our purposes.
> >>
> >> Enable the FEL feature by providing early AArch32 code to first save the
> >> FEL state, *before* initially entering AArch64.
> >> If we eventually determine that we should return to FEL, we reset back
> >> into AArch32, and use the CPU hotplug mechanism to run some small
> >> AArch32 code snippet that restores the initially saved FEL state.
> >>
> >> That allows the normal AArch64 SPL build to be loaded via the sunxi-fel
> >> tool, with it returning into FEL mode, so that other payloads can be
> >> transferred via FEL as well.
> >>
> >> Tested on A64, H5 and H6.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  arch/arm/cpu/armv8/Makefile             |  2 +
> >>  arch/arm/cpu/armv8/fel_utils.S          | 78 +++++++++++++++++++++++++
> >>  arch/arm/include/asm/arch-sunxi/boot0.h | 14 +++++
> >>  include/configs/sunxi-common.h          |  2 -
> >>  4 files changed, 94 insertions(+), 2 deletions(-)
> >>  create mode 100644 arch/arm/cpu/armv8/fel_utils.S
> > 
> > Don't you want to also update board/sunxi/README.sunxi64 ?
> 
> Yes, but I am in the process of rewriting this anyway, since some parts
> apply to 32-bit SoCs as well (SD card, SPI flash), and there is
> currently no documentation about them. So bear with me, I will post a
> documentation update ASAP, just didn't want to hold back this patch.
> 
> Thanks!
> Andre.
> 
> >>
> >> diff --git a/arch/arm/cpu/armv8/Makefile b/arch/arm/cpu/armv8/Makefile
> >> index 93d26f98568..f7b4a5ee46c 100644
> >> --- a/arch/arm/cpu/armv8/Makefile
> >> +++ b/arch/arm/cpu/armv8/Makefile
> >> @@ -27,6 +27,8 @@ obj-$(CONFIG_ARM_SMCCC)		+= smccc-
call.o
> >>  
> >>  ifndef CONFIG_SPL_BUILD
> >>  obj-$(CONFIG_ARMV8_SPIN_TABLE) += spin_table.o spin_table_v8.o
> >> +else
> >> +obj-$(CONFIG_ARCH_SUNXI) += fel_utils.o
> >>  endif
> >>  obj-$(CONFIG_$(SPL_)ARMV8_SEC_FIRMWARE_SUPPORT) += sec_firmware.o 
sec_firmware_asm.o
> >>  
> >> diff --git a/arch/arm/cpu/armv8/fel_utils.S b/arch/arm/cpu/armv8/
fel_utils.S
> >> new file mode 100644
> >> index 00000000000..334fdef7fa0
> >> --- /dev/null
> >> +++ b/arch/arm/cpu/armv8/fel_utils.S
> >> @@ -0,0 +1,78 @@
> >> +/*
> >> + * Utility functions for FEL mode, when running SPL in AArch64.
> >> + *
> >> + * Copyright (c) 2017 Arm Ltd.
> >> + *
> >> + * SPDX-License-Identifier:	GPL-2.0+
> >> + */
> >> +
> >> +#include <asm-offsets.h>
> >> +#include <config.h>
> >> +#include <asm/system.h>
> >> +#include <linux/linkage.h>
> >> +
> >> +/*
> >> + * We don't overwrite save_boot_params() here, to save the FEL state 
upon
> >> + * entry, since this would run *after* the RMR reset, which clobbers 
that
> >> + * state.
> >> + * Instead we store the state _very_ early in the boot0 hook, *before*
> >> + * resetting to AArch64.
> >> + */
> >> +
> >> +/*
> >> + * The FEL routines in BROM run in AArch32.
> >> + * Reset back into 32-bit mode here and restore the saved FEL state
> >> + * afterwards.
> >> + * Resetting back into AArch32/EL3 using the RMR always enters the BROM,
> >> + * but we can use the CPU hotplug mechanism to branch back to our code
> >> + * immediately.
> >> + */
> >> +ENTRY(return_to_fel)
> >> +	/*
> >> +	 * the RMR reset will clear all registers, so save the arguments
> >> +	 * (LR and SP) in the fel_stash structure, which we read anyways 
later
> >> +	 */
> >> +	adr	x2, fel_stash
> >> +	str	w0, [x2]
> >> +	str	w1, [x2, #4]
> >> +
> >> +	adr	x1, fel_stash_addr	// to find the fel_stash 
address in AA32
> >> +	str	w2, [x1]
> >> +
> >> +	ldr	x0, =0xfa50392f		// CPU hotplug magic
> >> +#ifndef CONFIG_MACH_SUN50I_H6
> >> +	ldr	x2, =(SUNXI_CPUCFG_BASE + 0x1a4) // offset for CPU 
hotplug base
> >> +	str	w0, [x2, #0x8]
> >> +#else
> >> +	ldr	x2, =(SUNXI_RTC_BASE + 0x1b8)	// 
BOOT_CPU_HP_FLAG_REG
> >> +	str	w0, [x2], #0x4
> >> +#endif

I suggest to turn around those ifdefs, e.g. put specific one first and general 
last. That way it will be much more readable when new exception will be added. 
For example, H616 has it's own address.

Best regards,
Jernej

> >> +	adr	x0, back_in_32
> >> +	str	w0, [x2]
> >> +
> >> +	dsb	sy
> >> +	isb	sy
> >> +	mov	x0, #2			// RMR reset into 
AArch32
> >> +	dsb	sy
> >> +	msr	RMR_EL3, x0
> >> +	isb	sy
> >> +1:	wfi
> >> +	b	1b
> >> +
> >> +/* AArch32 code to restore the state from fel_stash and return back to 
FEL. */
> >> +back_in_32:
> >> +	.word	0xe59f0028 	// ldr	r0, [pc, #40]	; load fel_stash 
address
> >> +	.word	0xe5901008 	// ldr	r1, [r0, #8]
> >> +	.word	0xe129f001 	// msr	CPSR_fc, r1
> >> +	.word	0xf57ff06f	// isb
> >> +	.word	0xe590d000 	// ldr	sp, [r0]
> >> +	.word	0xe590e004 	// ldr	lr, [r0, #4]
> >> +	.word	0xe5901010 	// ldr	r1, [r0, #16]
> >> +	.word	0xee0c1f10 	// mcr	15, 0, r1, cr12, cr0, {0} ; 
VBAR
> >> +	.word	0xe590100c 	// ldr	r1, [r0, #12]
> >> +	.word	0xee011f10 	// mcr	15, 0, r1, cr1, cr0, {0}  ; 
SCTLR
> >> +	.word	0xf57ff06f	// isb
> >> +	.word	0xe12fff1e 	// bx	lr		; return 
to FEL
> >> +fel_stash_addr:
> >> +	.word   0x00000000	// receives fel_stash addr, by AA64 code 
above
> >> +ENDPROC(return_to_fel)
> >> diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h b/arch/arm/include/
asm/arch-sunxi/boot0.h
> >> index 54c144afd8c..46d0f0666c2 100644
> >> --- a/arch/arm/include/asm/arch-sunxi/boot0.h
> >> +++ b/arch/arm/include/asm/arch-sunxi/boot0.h
> >> @@ -15,6 +15,19 @@
> >>  	tst     x0, x0                  // this is "b #0x84" in ARM
> >>  	b       reset
> >>  	.space  0x7c
> >> +
> >> +	.word	0xe28f0058	// add     r0, pc, #88
> >> +	.word	0xe59f1054	// ldr     r1, [pc, #84]
> >> +	.word	0xe0800001	// add     r0, r0, r1
> >> +	.word	0xe580d000	// str     sp, [r0]
> >> +	.word	0xe580e004	// str     lr, [r0, #4]
> >> +	.word	0xe10fe000	// mrs     lr, CPSR
> >> +	.word	0xe580e008	// str     lr, [r0, #8]
> >> +	.word	0xee11ef10	// mrc     15, 0, lr, cr1, cr0, {0}
> >> +	.word	0xe580e00c	// str     lr, [r0, #12]
> >> +	.word	0xee1cef10	// mrc     15, 0, lr, cr12, cr0, {0}
> >> +	.word	0xe580e010	// str     lr, [r0, #16]
> >> +
> >>  	.word	0xe59f1024	// ldr     r1, [pc, #36] ; 0x170000a0
> >>  	.word	0xe59f0024	// ldr     r0, [pc, #36] ; 
CONFIG_*_TEXT_BASE
> >>  	.word	0xe5810000	// str     r0, [r1]
> >> @@ -36,6 +49,7 @@
> >>  #else
> >>  	.word   CONFIG_SYS_TEXT_BASE
> >>  #endif
> >> +	.word	fel_stash - .
> >>  #else
> >>  /* normal execution */
> >>  	b	reset
> >> diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
> >> index a6a4879523a..203cb10fbab 100644
> >> --- a/include/configs/sunxi-common.h
> >> +++ b/include/configs/sunxi-common.h
> >> @@ -163,9 +163,7 @@
> >>  
> >>  #define CONFIG_SYS_MONITOR_LEN		(768 << 10)	/* 768 KiB 
*/
> >>  
> >> -#ifndef CONFIG_ARM64		/* AArch64 FEL support is not 
ready yet */
> >>  #define CONFIG_SPL_BOARD_LOAD_IMAGE
> >> -#endif
> >>  
> >>  /*
> >>   * We cannot use expressions here, because expressions won't be 
evaluated in
> >> -- 
> >> 2.17.5
> >>
> >> -- 
> >> You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
> >> To unsubscribe from this group and stop receiving emails from it, send an 
email to linux-sunxi+unsubscribe@googlegroups.com.
> >> To view this discussion on the web, visit https://groups.google.com/d/
msgid/linux-sunxi/20201119105442.24711-1-andre.przywara%40arm.com.
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
email to linux-sunxi+unsubscribe@googlegroups.com.
> To view this discussion on the web, visit https://groups.google.com/d/msgid/
linux-sunxi/0fd3cbb4-a2c9-85d5-5fbd-057bb654863d%40arm.com.
>
Icenowy Zheng Nov. 28, 2020, 11:30 a.m. UTC | #4
在 2020-11-19星期四的 10:54 +0000,Andre Przywara写道:
> So far we did not support the BootROM based FEL USB debug mode on the
> 64-bit builds for Allwinner SoCs: The BootROM is using AArch32, but
> the
> SPL runs in AArch64.
> Returning back to AArch32 was not working as expected, since the RMR
> reset into 32-bit mode always starts execution in the BootROM, but
> not
> in the FEL routine.
> 
> After some debug and research and with help via IRC, the CPU hotplug
> mechanism emerged as a solution: If a certain R_CPUCFG register
> contains
> some magic, the BootROM will immediately branch to an address stored
> in
> some other register. This works well for our purposes.
> 
> Enable the FEL feature by providing early AArch32 code to first save
> the
> FEL state, *before* initially entering AArch64.
> If we eventually determine that we should return to FEL, we reset
> back
> into AArch32, and use the CPU hotplug mechanism to run some small
> AArch32 code snippet that restores the initially saved FEL state.
> 
> That allows the normal AArch64 SPL build to be loaded via the sunxi-
> fel
> tool, with it returning into FEL mode, so that other payloads can be
> transferred via FEL as well.
> 
> Tested on A64, H5 and H6.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Tested-by: Icenowy Zheng <icenowy@aosc.io>

> ---
>  arch/arm/cpu/armv8/Makefile             |  2 +
>  arch/arm/cpu/armv8/fel_utils.S          | 78
> +++++++++++++++++++++++++
>  arch/arm/include/asm/arch-sunxi/boot0.h | 14 +++++
>  include/configs/sunxi-common.h          |  2 -
>  4 files changed, 94 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm/cpu/armv8/fel_utils.S
> 
> diff --git a/arch/arm/cpu/armv8/Makefile
> b/arch/arm/cpu/armv8/Makefile
> index 93d26f98568..f7b4a5ee46c 100644
> --- a/arch/arm/cpu/armv8/Makefile
> +++ b/arch/arm/cpu/armv8/Makefile
> @@ -27,6 +27,8 @@ obj-$(CONFIG_ARM_SMCCC)		+= smccc-call.o
>  
>  ifndef CONFIG_SPL_BUILD
>  obj-$(CONFIG_ARMV8_SPIN_TABLE) += spin_table.o spin_table_v8.o
> +else
> +obj-$(CONFIG_ARCH_SUNXI) += fel_utils.o
>  endif
>  obj-$(CONFIG_$(SPL_)ARMV8_SEC_FIRMWARE_SUPPORT) += sec_firmware.o
> sec_firmware_asm.o
>  
> diff --git a/arch/arm/cpu/armv8/fel_utils.S
> b/arch/arm/cpu/armv8/fel_utils.S
> new file mode 100644
> index 00000000000..334fdef7fa0
> --- /dev/null
> +++ b/arch/arm/cpu/armv8/fel_utils.S
> @@ -0,0 +1,78 @@
> +/*
> + * Utility functions for FEL mode, when running SPL in AArch64.
> + *
> + * Copyright (c) 2017 Arm Ltd.
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <asm-offsets.h>
> +#include <config.h>
> +#include <asm/system.h>
> +#include <linux/linkage.h>
> +
> +/*
> + * We don't overwrite save_boot_params() here, to save the FEL state
> upon
> + * entry, since this would run *after* the RMR reset, which clobbers
> that
> + * state.
> + * Instead we store the state _very_ early in the boot0 hook,
> *before*
> + * resetting to AArch64.
> + */
> +
> +/*
> + * The FEL routines in BROM run in AArch32.
> + * Reset back into 32-bit mode here and restore the saved FEL state
> + * afterwards.
> + * Resetting back into AArch32/EL3 using the RMR always enters the
> BROM,
> + * but we can use the CPU hotplug mechanism to branch back to our
> code
> + * immediately.
> + */
> +ENTRY(return_to_fel)
> +	/*
> +	 * the RMR reset will clear all registers, so save the
> arguments
> +	 * (LR and SP) in the fel_stash structure, which we read
> anyways later
> +	 */
> +	adr	x2, fel_stash
> +	str	w0, [x2]
> +	str	w1, [x2, #4]
> +
> +	adr	x1, fel_stash_addr	// to find the fel_stash
> address in AA32
> +	str	w2, [x1]
> +
> +	ldr	x0, =0xfa50392f		// CPU hotplug magic
> +#ifndef CONFIG_MACH_SUN50I_H6
> +	ldr	x2, =(SUNXI_CPUCFG_BASE + 0x1a4) // offset for CPU
> hotplug base
> +	str	w0, [x2, #0x8]
> +#else
> +	ldr	x2, =(SUNXI_RTC_BASE + 0x1b8)	//
> BOOT_CPU_HP_FLAG_REG
> +	str	w0, [x2], #0x4
> +#endif
> +	adr	x0, back_in_32
> +	str	w0, [x2]
> +
> +	dsb	sy
> +	isb	sy
> +	mov	x0, #2			// RMR reset into AArch32
> +	dsb	sy
> +	msr	RMR_EL3, x0
> +	isb	sy
> +1:	wfi
> +	b	1b
> +
> +/* AArch32 code to restore the state from fel_stash and return back
> to FEL. */
> +back_in_32:
> +	.word	0xe59f0028 	// ldr	r0, [pc, #40]	; load
> fel_stash address
> +	.word	0xe5901008 	// ldr	r1, [r0, #8]
> +	.word	0xe129f001 	// msr	CPSR_fc, r1
> +	.word	0xf57ff06f	// isb
> +	.word	0xe590d000 	// ldr	sp, [r0]
> +	.word	0xe590e004 	// ldr	lr, [r0, #4]
> +	.word	0xe5901010 	// ldr	r1, [r0, #16]
> +	.word	0xee0c1f10 	// mcr	15, 0, r1, cr12, cr0, {0} ;
> VBAR
> +	.word	0xe590100c 	// ldr	r1, [r0, #12]
> +	.word	0xee011f10 	// mcr	15, 0, r1, cr1, cr0, {0}  ;
> SCTLR
> +	.word	0xf57ff06f	// isb
> +	.word	0xe12fff1e 	// bx	lr		; return to
> FEL
> +fel_stash_addr:
> +	.word   0x00000000	// receives fel_stash addr, by AA64
> code above
> +ENDPROC(return_to_fel)
> diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h
> b/arch/arm/include/asm/arch-sunxi/boot0.h
> index 54c144afd8c..46d0f0666c2 100644
> --- a/arch/arm/include/asm/arch-sunxi/boot0.h
> +++ b/arch/arm/include/asm/arch-sunxi/boot0.h
> @@ -15,6 +15,19 @@
>  	tst     x0, x0                  // this is "b #0x84" in ARM
>  	b       reset
>  	.space  0x7c
> +
> +	.word	0xe28f0058	// add     r0, pc, #88
> +	.word	0xe59f1054	// ldr     r1, [pc, #84]
> +	.word	0xe0800001	// add     r0, r0, r1
> +	.word	0xe580d000	// str     sp, [r0]
> +	.word	0xe580e004	// str     lr, [r0, #4]
> +	.word	0xe10fe000	// mrs     lr, CPSR
> +	.word	0xe580e008	// str     lr, [r0, #8]
> +	.word	0xee11ef10	// mrc     15, 0, lr, cr1, cr0, {0}
> +	.word	0xe580e00c	// str     lr, [r0, #12]
> +	.word	0xee1cef10	// mrc     15, 0, lr, cr12, cr0, {0}
> +	.word	0xe580e010	// str     lr, [r0, #16]
> +
>  	.word	0xe59f1024	// ldr     r1, [pc, #36] ; 0x170000a0
>  	.word	0xe59f0024	// ldr     r0, [pc, #36] ;
> CONFIG_*_TEXT_BASE
>  	.word	0xe5810000	// str     r0, [r1]
> @@ -36,6 +49,7 @@
>  #else
>  	.word   CONFIG_SYS_TEXT_BASE
>  #endif
> +	.word	fel_stash - .
>  #else
>  /* normal execution */
>  	b	reset
> diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-
> common.h
> index a6a4879523a..203cb10fbab 100644
> --- a/include/configs/sunxi-common.h
> +++ b/include/configs/sunxi-common.h
> @@ -163,9 +163,7 @@
>  
>  #define CONFIG_SYS_MONITOR_LEN		(768 << 10)	/*
> 768 KiB */
>  
> -#ifndef CONFIG_ARM64		/* AArch64 FEL support is not ready yet
> */
>  #define CONFIG_SPL_BOARD_LOAD_IMAGE
> -#endif
>  
>  /*
>   * We cannot use expressions here, because expressions won't be
> evaluated in
> -- 
> 2.17.5
>
Jagan Teki Dec. 7, 2020, 5:50 p.m. UTC | #5
On Thu, Nov 19, 2020 at 4:24 PM Andre Przywara <andre.przywara@arm.com> wrote:
>
> So far we did not support the BootROM based FEL USB debug mode on the
> 64-bit builds for Allwinner SoCs: The BootROM is using AArch32, but the
> SPL runs in AArch64.
> Returning back to AArch32 was not working as expected, since the RMR
> reset into 32-bit mode always starts execution in the BootROM, but not
> in the FEL routine.
>
> After some debug and research and with help via IRC, the CPU hotplug
> mechanism emerged as a solution: If a certain R_CPUCFG register contains
> some magic, the BootROM will immediately branch to an address stored in
> some other register. This works well for our purposes.
>
> Enable the FEL feature by providing early AArch32 code to first save the
> FEL state, *before* initially entering AArch64.
> If we eventually determine that we should return to FEL, we reset back
> into AArch32, and use the CPU hotplug mechanism to run some small
> AArch32 code snippet that restores the initially saved FEL state.
>
> That allows the normal AArch64 SPL build to be loaded via the sunxi-fel
> tool, with it returning into FEL mode, so that other payloads can be
> transferred via FEL as well.
>
> Tested on A64, H5 and H6.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---

Acked-by: Jagan Teki <jagan@amarulasolutions.com>
Priit Laes Dec. 21, 2020, 2:48 p.m. UTC | #6
On Thu, Nov 19, 2020 at 10:54:42AM +0000, Andre Przywara wrote:
> So far we did not support the BootROM based FEL USB debug mode on the
> 64-bit builds for Allwinner SoCs: The BootROM is using AArch32, but the
> SPL runs in AArch64.
> Returning back to AArch32 was not working as expected, since the RMR
> reset into 32-bit mode always starts execution in the BootROM, but not
> in the FEL routine.
> 
> After some debug and research and with help via IRC, the CPU hotplug
> mechanism emerged as a solution: If a certain R_CPUCFG register contains
> some magic, the BootROM will immediately branch to an address stored in
> some other register. This works well for our purposes.
> 
> Enable the FEL feature by providing early AArch32 code to first save the
> FEL state, *before* initially entering AArch64.
> If we eventually determine that we should return to FEL, we reset back
> into AArch32, and use the CPU hotplug mechanism to run some small
> AArch32 code snippet that restores the initially saved FEL state.
> 
> That allows the normal AArch64 SPL build to be loaded via the sunxi-fel
> tool, with it returning into FEL mode, so that other payloads can be
> transferred via FEL as well.
> 
> Tested on A64, H5 and H6.

For A64 (on Olimex A64-Olinuxino):
Tested-by: Priit Laes <plaes@plaes.org>

Also writing down the command to run as it was not that obvious:

$ sunxi-fel spl sunxi-spl.bin \
	write 0x4a000000 u-boot.bin \
	write 0x44000 bl31.bin \
	write 0x50000 scp.bin \
	reset64 0x44000

> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  arch/arm/cpu/armv8/Makefile             |  2 +
>  arch/arm/cpu/armv8/fel_utils.S          | 78 +++++++++++++++++++++++++
>  arch/arm/include/asm/arch-sunxi/boot0.h | 14 +++++
>  include/configs/sunxi-common.h          |  2 -
>  4 files changed, 94 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm/cpu/armv8/fel_utils.S
> 
> diff --git a/arch/arm/cpu/armv8/Makefile b/arch/arm/cpu/armv8/Makefile
> index 93d26f98568..f7b4a5ee46c 100644
> --- a/arch/arm/cpu/armv8/Makefile
> +++ b/arch/arm/cpu/armv8/Makefile
> @@ -27,6 +27,8 @@ obj-$(CONFIG_ARM_SMCCC)		+= smccc-call.o
>  
>  ifndef CONFIG_SPL_BUILD
>  obj-$(CONFIG_ARMV8_SPIN_TABLE) += spin_table.o spin_table_v8.o
> +else
> +obj-$(CONFIG_ARCH_SUNXI) += fel_utils.o
>  endif
>  obj-$(CONFIG_$(SPL_)ARMV8_SEC_FIRMWARE_SUPPORT) += sec_firmware.o sec_firmware_asm.o
>  
> diff --git a/arch/arm/cpu/armv8/fel_utils.S b/arch/arm/cpu/armv8/fel_utils.S
> new file mode 100644
> index 00000000000..334fdef7fa0
> --- /dev/null
> +++ b/arch/arm/cpu/armv8/fel_utils.S
> @@ -0,0 +1,78 @@
> +/*
> + * Utility functions for FEL mode, when running SPL in AArch64.
> + *
> + * Copyright (c) 2017 Arm Ltd.
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <asm-offsets.h>
> +#include <config.h>
> +#include <asm/system.h>
> +#include <linux/linkage.h>
> +
> +/*
> + * We don't overwrite save_boot_params() here, to save the FEL state upon
> + * entry, since this would run *after* the RMR reset, which clobbers that
> + * state.
> + * Instead we store the state _very_ early in the boot0 hook, *before*
> + * resetting to AArch64.
> + */
> +
> +/*
> + * The FEL routines in BROM run in AArch32.
> + * Reset back into 32-bit mode here and restore the saved FEL state
> + * afterwards.
> + * Resetting back into AArch32/EL3 using the RMR always enters the BROM,
> + * but we can use the CPU hotplug mechanism to branch back to our code
> + * immediately.
> + */
> +ENTRY(return_to_fel)
> +	/*
> +	 * the RMR reset will clear all registers, so save the arguments
> +	 * (LR and SP) in the fel_stash structure, which we read anyways later
> +	 */
> +	adr	x2, fel_stash
> +	str	w0, [x2]
> +	str	w1, [x2, #4]
> +
> +	adr	x1, fel_stash_addr	// to find the fel_stash address in AA32
> +	str	w2, [x1]
> +
> +	ldr	x0, =0xfa50392f		// CPU hotplug magic
> +#ifndef CONFIG_MACH_SUN50I_H6
> +	ldr	x2, =(SUNXI_CPUCFG_BASE + 0x1a4) // offset for CPU hotplug base
> +	str	w0, [x2, #0x8]
> +#else
> +	ldr	x2, =(SUNXI_RTC_BASE + 0x1b8)	// BOOT_CPU_HP_FLAG_REG
> +	str	w0, [x2], #0x4
> +#endif
> +	adr	x0, back_in_32
> +	str	w0, [x2]
> +
> +	dsb	sy
> +	isb	sy
> +	mov	x0, #2			// RMR reset into AArch32
> +	dsb	sy
> +	msr	RMR_EL3, x0
> +	isb	sy
> +1:	wfi
> +	b	1b
> +
> +/* AArch32 code to restore the state from fel_stash and return back to FEL. */
> +back_in_32:
> +	.word	0xe59f0028 	// ldr	r0, [pc, #40]	; load fel_stash address
> +	.word	0xe5901008 	// ldr	r1, [r0, #8]
> +	.word	0xe129f001 	// msr	CPSR_fc, r1
> +	.word	0xf57ff06f	// isb
> +	.word	0xe590d000 	// ldr	sp, [r0]
> +	.word	0xe590e004 	// ldr	lr, [r0, #4]
> +	.word	0xe5901010 	// ldr	r1, [r0, #16]
> +	.word	0xee0c1f10 	// mcr	15, 0, r1, cr12, cr0, {0} ; VBAR
> +	.word	0xe590100c 	// ldr	r1, [r0, #12]
> +	.word	0xee011f10 	// mcr	15, 0, r1, cr1, cr0, {0}  ; SCTLR
> +	.word	0xf57ff06f	// isb
> +	.word	0xe12fff1e 	// bx	lr		; return to FEL
> +fel_stash_addr:
> +	.word   0x00000000	// receives fel_stash addr, by AA64 code above
> +ENDPROC(return_to_fel)
> diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h b/arch/arm/include/asm/arch-sunxi/boot0.h
> index 54c144afd8c..46d0f0666c2 100644
> --- a/arch/arm/include/asm/arch-sunxi/boot0.h
> +++ b/arch/arm/include/asm/arch-sunxi/boot0.h
> @@ -15,6 +15,19 @@
>  	tst     x0, x0                  // this is "b #0x84" in ARM
>  	b       reset
>  	.space  0x7c
> +
> +	.word	0xe28f0058	// add     r0, pc, #88
> +	.word	0xe59f1054	// ldr     r1, [pc, #84]
> +	.word	0xe0800001	// add     r0, r0, r1
> +	.word	0xe580d000	// str     sp, [r0]
> +	.word	0xe580e004	// str     lr, [r0, #4]
> +	.word	0xe10fe000	// mrs     lr, CPSR
> +	.word	0xe580e008	// str     lr, [r0, #8]
> +	.word	0xee11ef10	// mrc     15, 0, lr, cr1, cr0, {0}
> +	.word	0xe580e00c	// str     lr, [r0, #12]
> +	.word	0xee1cef10	// mrc     15, 0, lr, cr12, cr0, {0}
> +	.word	0xe580e010	// str     lr, [r0, #16]
> +
>  	.word	0xe59f1024	// ldr     r1, [pc, #36] ; 0x170000a0
>  	.word	0xe59f0024	// ldr     r0, [pc, #36] ; CONFIG_*_TEXT_BASE
>  	.word	0xe5810000	// str     r0, [r1]
> @@ -36,6 +49,7 @@
>  #else
>  	.word   CONFIG_SYS_TEXT_BASE
>  #endif
> +	.word	fel_stash - .
>  #else
>  /* normal execution */
>  	b	reset
> diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
> index a6a4879523a..203cb10fbab 100644
> --- a/include/configs/sunxi-common.h
> +++ b/include/configs/sunxi-common.h
> @@ -163,9 +163,7 @@
>  
>  #define CONFIG_SYS_MONITOR_LEN		(768 << 10)	/* 768 KiB */
>  
> -#ifndef CONFIG_ARM64		/* AArch64 FEL support is not ready yet */
>  #define CONFIG_SPL_BOARD_LOAD_IMAGE
> -#endif
>  
>  /*
>   * We cannot use expressions here, because expressions won't be evaluated in
> -- 
> 2.17.5
> 
> -- 
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
> To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20201119105442.24711-1-andre.przywara%40arm.com.
diff mbox series

Patch

diff --git a/arch/arm/cpu/armv8/Makefile b/arch/arm/cpu/armv8/Makefile
index 93d26f98568..f7b4a5ee46c 100644
--- a/arch/arm/cpu/armv8/Makefile
+++ b/arch/arm/cpu/armv8/Makefile
@@ -27,6 +27,8 @@  obj-$(CONFIG_ARM_SMCCC)		+= smccc-call.o
 
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_ARMV8_SPIN_TABLE) += spin_table.o spin_table_v8.o
+else
+obj-$(CONFIG_ARCH_SUNXI) += fel_utils.o
 endif
 obj-$(CONFIG_$(SPL_)ARMV8_SEC_FIRMWARE_SUPPORT) += sec_firmware.o sec_firmware_asm.o
 
diff --git a/arch/arm/cpu/armv8/fel_utils.S b/arch/arm/cpu/armv8/fel_utils.S
new file mode 100644
index 00000000000..334fdef7fa0
--- /dev/null
+++ b/arch/arm/cpu/armv8/fel_utils.S
@@ -0,0 +1,78 @@ 
+/*
+ * Utility functions for FEL mode, when running SPL in AArch64.
+ *
+ * Copyright (c) 2017 Arm Ltd.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <asm/system.h>
+#include <linux/linkage.h>
+
+/*
+ * We don't overwrite save_boot_params() here, to save the FEL state upon
+ * entry, since this would run *after* the RMR reset, which clobbers that
+ * state.
+ * Instead we store the state _very_ early in the boot0 hook, *before*
+ * resetting to AArch64.
+ */
+
+/*
+ * The FEL routines in BROM run in AArch32.
+ * Reset back into 32-bit mode here and restore the saved FEL state
+ * afterwards.
+ * Resetting back into AArch32/EL3 using the RMR always enters the BROM,
+ * but we can use the CPU hotplug mechanism to branch back to our code
+ * immediately.
+ */
+ENTRY(return_to_fel)
+	/*
+	 * the RMR reset will clear all registers, so save the arguments
+	 * (LR and SP) in the fel_stash structure, which we read anyways later
+	 */
+	adr	x2, fel_stash
+	str	w0, [x2]
+	str	w1, [x2, #4]
+
+	adr	x1, fel_stash_addr	// to find the fel_stash address in AA32
+	str	w2, [x1]
+
+	ldr	x0, =0xfa50392f		// CPU hotplug magic
+#ifndef CONFIG_MACH_SUN50I_H6
+	ldr	x2, =(SUNXI_CPUCFG_BASE + 0x1a4) // offset for CPU hotplug base
+	str	w0, [x2, #0x8]
+#else
+	ldr	x2, =(SUNXI_RTC_BASE + 0x1b8)	// BOOT_CPU_HP_FLAG_REG
+	str	w0, [x2], #0x4
+#endif
+	adr	x0, back_in_32
+	str	w0, [x2]
+
+	dsb	sy
+	isb	sy
+	mov	x0, #2			// RMR reset into AArch32
+	dsb	sy
+	msr	RMR_EL3, x0
+	isb	sy
+1:	wfi
+	b	1b
+
+/* AArch32 code to restore the state from fel_stash and return back to FEL. */
+back_in_32:
+	.word	0xe59f0028 	// ldr	r0, [pc, #40]	; load fel_stash address
+	.word	0xe5901008 	// ldr	r1, [r0, #8]
+	.word	0xe129f001 	// msr	CPSR_fc, r1
+	.word	0xf57ff06f	// isb
+	.word	0xe590d000 	// ldr	sp, [r0]
+	.word	0xe590e004 	// ldr	lr, [r0, #4]
+	.word	0xe5901010 	// ldr	r1, [r0, #16]
+	.word	0xee0c1f10 	// mcr	15, 0, r1, cr12, cr0, {0} ; VBAR
+	.word	0xe590100c 	// ldr	r1, [r0, #12]
+	.word	0xee011f10 	// mcr	15, 0, r1, cr1, cr0, {0}  ; SCTLR
+	.word	0xf57ff06f	// isb
+	.word	0xe12fff1e 	// bx	lr		; return to FEL
+fel_stash_addr:
+	.word   0x00000000	// receives fel_stash addr, by AA64 code above
+ENDPROC(return_to_fel)
diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h b/arch/arm/include/asm/arch-sunxi/boot0.h
index 54c144afd8c..46d0f0666c2 100644
--- a/arch/arm/include/asm/arch-sunxi/boot0.h
+++ b/arch/arm/include/asm/arch-sunxi/boot0.h
@@ -15,6 +15,19 @@ 
 	tst     x0, x0                  // this is "b #0x84" in ARM
 	b       reset
 	.space  0x7c
+
+	.word	0xe28f0058	// add     r0, pc, #88
+	.word	0xe59f1054	// ldr     r1, [pc, #84]
+	.word	0xe0800001	// add     r0, r0, r1
+	.word	0xe580d000	// str     sp, [r0]
+	.word	0xe580e004	// str     lr, [r0, #4]
+	.word	0xe10fe000	// mrs     lr, CPSR
+	.word	0xe580e008	// str     lr, [r0, #8]
+	.word	0xee11ef10	// mrc     15, 0, lr, cr1, cr0, {0}
+	.word	0xe580e00c	// str     lr, [r0, #12]
+	.word	0xee1cef10	// mrc     15, 0, lr, cr12, cr0, {0}
+	.word	0xe580e010	// str     lr, [r0, #16]
+
 	.word	0xe59f1024	// ldr     r1, [pc, #36] ; 0x170000a0
 	.word	0xe59f0024	// ldr     r0, [pc, #36] ; CONFIG_*_TEXT_BASE
 	.word	0xe5810000	// str     r0, [r1]
@@ -36,6 +49,7 @@ 
 #else
 	.word   CONFIG_SYS_TEXT_BASE
 #endif
+	.word	fel_stash - .
 #else
 /* normal execution */
 	b	reset
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index a6a4879523a..203cb10fbab 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -163,9 +163,7 @@ 
 
 #define CONFIG_SYS_MONITOR_LEN		(768 << 10)	/* 768 KiB */
 
-#ifndef CONFIG_ARM64		/* AArch64 FEL support is not ready yet */
 #define CONFIG_SPL_BOARD_LOAD_IMAGE
-#endif
 
 /*
  * We cannot use expressions here, because expressions won't be evaluated in