xref: /rk3399_rockchip-uboot/arch/arm/cpu/armv7/nonsec_virt.S (revision 64fd44dcae0daafb011f98d4b2d4e1f28036b99e)
145b940d6SAndre Przywara/*
2d4296887SAndre Przywara * code for switching cores into non-secure state and into HYP mode
345b940d6SAndre Przywara *
445b940d6SAndre Przywara * Copyright (c) 2013	Andre Przywara <andre.przywara@linaro.org>
545b940d6SAndre Przywara *
6f833e790SAndre Przywara * SPDX-License-Identifier:	GPL-2.0+
745b940d6SAndre Przywara */
845b940d6SAndre Przywara
945b940d6SAndre Przywara#include <config.h>
1016212b59SAndre Przywara#include <linux/linkage.h>
1116212b59SAndre Przywara#include <asm/gic.h>
1216212b59SAndre Przywara#include <asm/armv7.h>
1316212b59SAndre Przywara
1416212b59SAndre Przywara.arch_extension sec
15d4296887SAndre Przywara.arch_extension virt
1645b940d6SAndre Przywara
173064d599SMasahiro Yamada	.align	5
18d4296887SAndre Przywara/* the vector table for secure state and HYP mode */
1945b940d6SAndre Przywara_monitor_vectors:
2045b940d6SAndre Przywara	.word 0	/* reset */
2145b940d6SAndre Przywara	.word 0 /* undef */
2245b940d6SAndre Przywara	adr pc, _secure_monitor
2345b940d6SAndre Przywara	.word 0
2445b940d6SAndre Przywara	.word 0
25d4296887SAndre Przywara	adr pc, _hyp_trap
2645b940d6SAndre Przywara	.word 0
2745b940d6SAndre Przywara	.word 0
2845b940d6SAndre Przywara
2945b940d6SAndre Przywara/*
3045b940d6SAndre Przywara * secure monitor handler
3145b940d6SAndre Przywara * U-boot calls this "software interrupt" in start.S
3245b940d6SAndre Przywara * This is executed on a "smc" instruction, we use a "smc #0" to switch
3345b940d6SAndre Przywara * to non-secure state.
3445b940d6SAndre Przywara * We use only r0 and r1 here, due to constraints in the caller.
3545b940d6SAndre Przywara */
3645b940d6SAndre Przywara_secure_monitor:
3745b940d6SAndre Przywara	mrc	p15, 0, r1, c1, c1, 0		@ read SCR
3845b940d6SAndre Przywara	bic	r1, r1, #0x4e			@ clear IRQ, FIQ, EA, nET bits
3945b940d6SAndre Przywara	orr	r1, r1, #0x31			@ enable NS, AW, FW bits
4045b940d6SAndre Przywara
41d4296887SAndre Przywara	mrc	p15, 0, r0, c0, c1, 1		@ read ID_PFR1
42d4296887SAndre Przywara	and	r0, r0, #CPUID_ARM_VIRT_MASK	@ mask virtualization bits
43d4296887SAndre Przywara	cmp	r0, #(1 << CPUID_ARM_VIRT_SHIFT)
44*64fd44dcSMarc Zyngier#ifdef CONFIG_ARMV7_VIRT
45d4296887SAndre Przywara	orreq	r1, r1, #0x100			@ allow HVC instruction
46d4296887SAndre Przywara#endif
47d4296887SAndre Przywara
4845b940d6SAndre Przywara	mcr	p15, 0, r1, c1, c1, 0		@ write SCR (with NS bit set)
49800c8352SMarc Zyngier	isb
5045b940d6SAndre Przywara
51d4296887SAndre Przywara#ifdef CONFIG_ARMV7_VIRT
52d4296887SAndre Przywara	mrceq	p15, 0, r0, c12, c0, 1		@ get MVBAR value
53d4296887SAndre Przywara	mcreq	p15, 4, r0, c12, c0, 0		@ write HVBAR
54d4296887SAndre Przywara#endif
55*64fd44dcSMarc Zyngier	bne	1f
56d4296887SAndre Przywara
57*64fd44dcSMarc Zyngier	@ Reset CNTVOFF to 0 before leaving monitor mode
58*64fd44dcSMarc Zyngier	mrc	p15, 0, r0, c0, c1, 1		@ read ID_PFR1
59*64fd44dcSMarc Zyngier	ands	r0, r0, #CPUID_ARM_GENTIMER_MASK	@ test arch timer bits
60*64fd44dcSMarc Zyngier	movne	r0, #0
61*64fd44dcSMarc Zyngier	mcrrne	p15, 4, r0, r0, c14		@ Reset CNTVOFF to zero
62*64fd44dcSMarc Zyngier1:
6345b940d6SAndre Przywara	movs	pc, lr				@ return to non-secure SVC
6416212b59SAndre Przywara
65d4296887SAndre Przywara_hyp_trap:
66d4296887SAndre Przywara	mrs	lr, elr_hyp	@ for older asm: .byte 0x00, 0xe3, 0x0e, 0xe1
67d4296887SAndre Przywara	mov pc, lr				@ do no switch modes, but
68d4296887SAndre Przywara						@ return to caller
69d4296887SAndre Przywara
7016212b59SAndre Przywara/*
71ba6a1698SAndre Przywara * Secondary CPUs start here and call the code for the core specific parts
72ba6a1698SAndre Przywara * of the non-secure and HYP mode transition. The GIC distributor specific
73ba6a1698SAndre Przywara * code has already been executed by a C function before.
74ba6a1698SAndre Przywara * Then they go back to wfi and wait to be woken up by the kernel again.
75ba6a1698SAndre Przywara */
76ba6a1698SAndre PrzywaraENTRY(_smp_pen)
77ba6a1698SAndre Przywara	mrs	r0, cpsr
78ba6a1698SAndre Przywara	orr	r0, r0, #0xc0
79ba6a1698SAndre Przywara	msr	cpsr, r0			@ disable interrupts
80ba6a1698SAndre Przywara	ldr	r1, =_start
81ba6a1698SAndre Przywara	mcr	p15, 0, r1, c12, c0, 0		@ set VBAR
82ba6a1698SAndre Przywara
83ba6a1698SAndre Przywara	bl	_nonsec_init
84d4296887SAndre Przywara	mov	r12, r0				@ save GICC address
85d4296887SAndre Przywara#ifdef CONFIG_ARMV7_VIRT
86d4296887SAndre Przywara	bl	_switch_to_hyp
87d4296887SAndre Przywara#endif
88ba6a1698SAndre Przywara
89d4296887SAndre Przywara	ldr	r1, [r12, #GICC_IAR]		@ acknowledge IPI
90d4296887SAndre Przywara	str	r1, [r12, #GICC_EOIR]		@ signal end of interrupt
91ba6a1698SAndre Przywara
92ba6a1698SAndre Przywara	adr	r0, _smp_pen			@ do not use this address again
93ba6a1698SAndre Przywara	b	smp_waitloop			@ wait for IPIs, board specific
94ba6a1698SAndre PrzywaraENDPROC(_smp_pen)
95ba6a1698SAndre Przywara
96ba6a1698SAndre Przywara/*
9716212b59SAndre Przywara * Switch a core to non-secure state.
9816212b59SAndre Przywara *
9916212b59SAndre Przywara *  1. initialize the GIC per-core interface
10016212b59SAndre Przywara *  2. allow coprocessor access in non-secure modes
10116212b59SAndre Przywara *  3. switch the cpu mode (by calling "smc #0")
10216212b59SAndre Przywara *
10316212b59SAndre Przywara * Called from smp_pen by secondary cores and directly by the BSP.
10416212b59SAndre Przywara * Do not assume that the stack is available and only use registers
10516212b59SAndre Przywara * r0-r3 and r12.
10616212b59SAndre Przywara *
10716212b59SAndre Przywara * PERIPHBASE is used to get the GIC address. This could be 40 bits long,
10816212b59SAndre Przywara * though, but we check this in C before calling this function.
10916212b59SAndre Przywara */
11016212b59SAndre PrzywaraENTRY(_nonsec_init)
11116212b59SAndre Przywara#ifdef CONFIG_ARM_GIC_BASE_ADDRESS
11216212b59SAndre Przywara	ldr	r2, =CONFIG_ARM_GIC_BASE_ADDRESS
11316212b59SAndre Przywara#else
11416212b59SAndre Przywara	mrc	p15, 4, r2, c15, c0, 0		@ read CBAR
11516212b59SAndre Przywara	bfc	r2, #0, #15			@ clear reserved bits
11616212b59SAndre Przywara#endif
11716212b59SAndre Przywara	add	r3, r2, #GIC_DIST_OFFSET	@ GIC dist i/f offset
11816212b59SAndre Przywara	mvn	r1, #0				@ all bits to 1
11916212b59SAndre Przywara	str	r1, [r3, #GICD_IGROUPRn]	@ allow private interrupts
12016212b59SAndre Przywara
12116212b59SAndre Przywara	mrc	p15, 0, r0, c0, c0, 0		@ read MIDR
12216212b59SAndre Przywara	ldr	r1, =MIDR_PRIMARY_PART_MASK
12316212b59SAndre Przywara	and	r0, r0, r1			@ mask out variant and revision
12416212b59SAndre Przywara
12516212b59SAndre Przywara	ldr	r1, =MIDR_CORTEX_A7_R0P0 & MIDR_PRIMARY_PART_MASK
12616212b59SAndre Przywara	cmp	r0, r1				@ check for Cortex-A7
12716212b59SAndre Przywara
12816212b59SAndre Przywara	ldr	r1, =MIDR_CORTEX_A15_R0P0 & MIDR_PRIMARY_PART_MASK
12916212b59SAndre Przywara	cmpne	r0, r1				@ check for Cortex-A15
13016212b59SAndre Przywara
13116212b59SAndre Przywara	movne	r1, #GIC_CPU_OFFSET_A9		@ GIC CPU offset for A9
13216212b59SAndre Przywara	moveq	r1, #GIC_CPU_OFFSET_A15		@ GIC CPU offset for A15/A7
13316212b59SAndre Przywara	add	r3, r2, r1			@ r3 = GIC CPU i/f addr
13416212b59SAndre Przywara
13516212b59SAndre Przywara	mov	r1, #1				@ set GICC_CTLR[enable]
13616212b59SAndre Przywara	str	r1, [r3, #GICC_CTLR]		@ and clear all other bits
13716212b59SAndre Przywara	mov	r1, #0xff
13816212b59SAndre Przywara	str	r1, [r3, #GICC_PMR]		@ set priority mask register
13916212b59SAndre Przywara
14016212b59SAndre Przywara	movw	r1, #0x3fff
14116212b59SAndre Przywara	movt	r1, #0x0006
14216212b59SAndre Przywara	mcr	p15, 0, r1, c1, c1, 2		@ NSACR = all copros to non-sec
14316212b59SAndre Przywara
14416212b59SAndre Przywara/* The CNTFRQ register of the generic timer needs to be
14516212b59SAndre Przywara * programmed in secure state. Some primary bootloaders / firmware
14616212b59SAndre Przywara * omit this, so if the frequency is provided in the configuration,
14716212b59SAndre Przywara * we do this here instead.
14816212b59SAndre Przywara * But first check if we have the generic timer.
14916212b59SAndre Przywara */
15016212b59SAndre Przywara#ifdef CONFIG_SYS_CLK_FREQ
15116212b59SAndre Przywara	mrc	p15, 0, r0, c0, c1, 1		@ read ID_PFR1
15216212b59SAndre Przywara	and	r0, r0, #CPUID_ARM_GENTIMER_MASK	@ mask arch timer bits
15316212b59SAndre Przywara	cmp	r0, #(1 << CPUID_ARM_GENTIMER_SHIFT)
15416212b59SAndre Przywara	ldreq	r1, =CONFIG_SYS_CLK_FREQ
15516212b59SAndre Przywara	mcreq	p15, 0, r1, c14, c0, 0		@ write CNTFRQ
15616212b59SAndre Przywara#endif
15716212b59SAndre Przywara
15816212b59SAndre Przywara	adr	r1, _monitor_vectors
15916212b59SAndre Przywara	mcr	p15, 0, r1, c12, c0, 1		@ set MVBAR to secure vectors
16016212b59SAndre Przywara
16116212b59SAndre Przywara	mrc	p15, 0, ip, c12, c0, 0		@ save secure copy of VBAR
16216212b59SAndre Przywara
16316212b59SAndre Przywara	isb
16416212b59SAndre Przywara	smc	#0				@ call into MONITOR mode
16516212b59SAndre Przywara
16616212b59SAndre Przywara	mcr	p15, 0, ip, c12, c0, 0		@ write non-secure copy of VBAR
16716212b59SAndre Przywara
16816212b59SAndre Przywara	mov	r1, #1
16916212b59SAndre Przywara	str	r1, [r3, #GICC_CTLR]		@ enable non-secure CPU i/f
17016212b59SAndre Przywara	add	r2, r2, #GIC_DIST_OFFSET
17116212b59SAndre Przywara	str	r1, [r2, #GICD_CTLR]		@ allow private interrupts
17216212b59SAndre Przywara
17316212b59SAndre Przywara	mov	r0, r3				@ return GICC address
17416212b59SAndre Przywara
17516212b59SAndre Przywara	bx	lr
17616212b59SAndre PrzywaraENDPROC(_nonsec_init)
177ba6a1698SAndre Przywara
178ba6a1698SAndre Przywara#ifdef CONFIG_SMP_PEN_ADDR
179ba6a1698SAndre Przywara/* void __weak smp_waitloop(unsigned previous_address); */
180ba6a1698SAndre PrzywaraENTRY(smp_waitloop)
181ba6a1698SAndre Przywara	wfi
182ba6a1698SAndre Przywara	ldr	r1, =CONFIG_SMP_PEN_ADDR	@ load start address
183ba6a1698SAndre Przywara	ldr	r1, [r1]
184ba6a1698SAndre Przywara	cmp	r0, r1			@ make sure we dont execute this code
185ba6a1698SAndre Przywara	beq	smp_waitloop		@ again (due to a spurious wakeup)
186ba6a1698SAndre Przywara	mov	pc, r1
187ba6a1698SAndre PrzywaraENDPROC(smp_waitloop)
188ba6a1698SAndre Przywara.weak smp_waitloop
189ba6a1698SAndre Przywara#endif
190d4296887SAndre Przywara
191d4296887SAndre PrzywaraENTRY(_switch_to_hyp)
192d4296887SAndre Przywara	mov	r0, lr
193d4296887SAndre Przywara	mov	r1, sp				@ save SVC copy of LR and SP
194d4296887SAndre Przywara	isb
195d4296887SAndre Przywara	hvc #0			 @ for older asm: .byte 0x70, 0x00, 0x40, 0xe1
196d4296887SAndre Przywara	mov	sp, r1
197d4296887SAndre Przywara	mov	lr, r0				@ restore SVC copy of LR and SP
198d4296887SAndre Przywara
199d4296887SAndre Przywara	bx	lr
200d4296887SAndre PrzywaraENDPROC(_switch_to_hyp)
201