diff options
| -rw-r--r-- | arch/arm/cpu/armv7/nonsec_virt.S | 87 | ||||
| -rw-r--r-- | arch/arm/include/asm/armv7.h | 21 | ||||
| -rw-r--r-- | arch/arm/include/asm/gic.h | 17 | ||||
| -rw-r--r-- | include/configs/vexpress_ca15_tc2.h | 2 | 
4 files changed, 125 insertions, 2 deletions
| diff --git a/arch/arm/cpu/armv7/nonsec_virt.S b/arch/arm/cpu/armv7/nonsec_virt.S index d11eb2dc6..3dd60b713 100644 --- a/arch/arm/cpu/armv7/nonsec_virt.S +++ b/arch/arm/cpu/armv7/nonsec_virt.S @@ -23,6 +23,11 @@   */  #include <config.h> +#include <linux/linkage.h> +#include <asm/gic.h> +#include <asm/armv7.h> + +.arch_extension sec  /* the vector table for secure state */  _monitor_vectors: @@ -51,3 +56,85 @@ _secure_monitor:  	mcr	p15, 0, r1, c1, c1, 0		@ write SCR (with NS bit set)  	movs	pc, lr				@ return to non-secure SVC + +/* + * Switch a core to non-secure state. + * + *  1. initialize the GIC per-core interface + *  2. allow coprocessor access in non-secure modes + *  3. switch the cpu mode (by calling "smc #0") + * + * Called from smp_pen by secondary cores and directly by the BSP. + * Do not assume that the stack is available and only use registers + * r0-r3 and r12. + * + * PERIPHBASE is used to get the GIC address. This could be 40 bits long, + * though, but we check this in C before calling this function. + */ +ENTRY(_nonsec_init) +#ifdef CONFIG_ARM_GIC_BASE_ADDRESS +	ldr	r2, =CONFIG_ARM_GIC_BASE_ADDRESS +#else +	mrc	p15, 4, r2, c15, c0, 0		@ read CBAR +	bfc	r2, #0, #15			@ clear reserved bits +#endif +	add	r3, r2, #GIC_DIST_OFFSET	@ GIC dist i/f offset +	mvn	r1, #0				@ all bits to 1 +	str	r1, [r3, #GICD_IGROUPRn]	@ allow private interrupts + +	mrc	p15, 0, r0, c0, c0, 0		@ read MIDR +	ldr	r1, =MIDR_PRIMARY_PART_MASK +	and	r0, r0, r1			@ mask out variant and revision + +	ldr	r1, =MIDR_CORTEX_A7_R0P0 & MIDR_PRIMARY_PART_MASK +	cmp	r0, r1				@ check for Cortex-A7 + +	ldr	r1, =MIDR_CORTEX_A15_R0P0 & MIDR_PRIMARY_PART_MASK +	cmpne	r0, r1				@ check for Cortex-A15 + +	movne	r1, #GIC_CPU_OFFSET_A9		@ GIC CPU offset for A9 +	moveq	r1, #GIC_CPU_OFFSET_A15		@ GIC CPU offset for A15/A7 +	add	r3, r2, r1			@ r3 = GIC CPU i/f addr + +	mov	r1, #1				@ set GICC_CTLR[enable] +	str	r1, [r3, #GICC_CTLR]		@ and clear all other bits +	mov	r1, #0xff +	str	r1, [r3, #GICC_PMR]		@ set priority mask register + +	movw	r1, #0x3fff +	movt	r1, #0x0006 +	mcr	p15, 0, r1, c1, c1, 2		@ NSACR = all copros to non-sec + +/* The CNTFRQ register of the generic timer needs to be + * programmed in secure state. Some primary bootloaders / firmware + * omit this, so if the frequency is provided in the configuration, + * we do this here instead. + * But first check if we have the generic timer. + */ +#ifdef CONFIG_SYS_CLK_FREQ +	mrc	p15, 0, r0, c0, c1, 1		@ read ID_PFR1 +	and	r0, r0, #CPUID_ARM_GENTIMER_MASK	@ mask arch timer bits +	cmp	r0, #(1 << CPUID_ARM_GENTIMER_SHIFT) +	ldreq	r1, =CONFIG_SYS_CLK_FREQ +	mcreq	p15, 0, r1, c14, c0, 0		@ write CNTFRQ +#endif + +	adr	r1, _monitor_vectors +	mcr	p15, 0, r1, c12, c0, 1		@ set MVBAR to secure vectors + +	mrc	p15, 0, ip, c12, c0, 0		@ save secure copy of VBAR + +	isb +	smc	#0				@ call into MONITOR mode + +	mcr	p15, 0, ip, c12, c0, 0		@ write non-secure copy of VBAR + +	mov	r1, #1 +	str	r1, [r3, #GICC_CTLR]		@ enable non-secure CPU i/f +	add	r2, r2, #GIC_DIST_OFFSET +	str	r1, [r2, #GICD_CTLR]		@ allow private interrupts + +	mov	r0, r3				@ return GICC address + +	bx	lr +ENDPROC(_nonsec_init) diff --git a/arch/arm/include/asm/armv7.h b/arch/arm/include/asm/armv7.h index 0f7cbbfc1..3dcfc8fb2 100644 --- a/arch/arm/include/asm/armv7.h +++ b/arch/arm/include/asm/armv7.h @@ -18,6 +18,22 @@  #define MIDR_CORTEX_A15_R0P0	0x410FC0F0  #define MIDR_CORTEX_A15_R2P2	0x412FC0F2 +/* Cortex-A7 revisions */ +#define MIDR_CORTEX_A7_R0P0	0x410FC070 + +#define MIDR_PRIMARY_PART_MASK	0xFF0FFFF0 + +/* ID_PFR1 feature fields */ +#define CPUID_ARM_SEC_SHIFT		4 +#define CPUID_ARM_SEC_MASK		(0xF << CPUID_ARM_SEC_SHIFT) +#define CPUID_ARM_VIRT_SHIFT		12 +#define CPUID_ARM_VIRT_MASK		(0xF << CPUID_ARM_VIRT_SHIFT) +#define CPUID_ARM_GENTIMER_SHIFT	16 +#define CPUID_ARM_GENTIMER_MASK		(0xF << CPUID_ARM_GENTIMER_SHIFT) + +/* valid bits in CBAR register / PERIPHBASE value */ +#define CBAR_MASK			0xFFFF8000 +  /* CCSIDR */  #define CCSIDR_LINE_SIZE_OFFSET		0  #define CCSIDR_LINE_SIZE_MASK		0x7 @@ -60,6 +76,11 @@ void v7_outer_cache_inval_all(void);  void v7_outer_cache_flush_range(u32 start, u32 end);  void v7_outer_cache_inval_range(u32 start, u32 end); +#ifdef CONFIG_ARMV7_NONSEC +/* defined in assembly file */ +unsigned int _nonsec_init(void); +#endif /* CONFIG_ARMV7_NONSEC */ +  #endif /* ! __ASSEMBLY__ */  #endif diff --git a/arch/arm/include/asm/gic.h b/arch/arm/include/asm/gic.h new file mode 100644 index 000000000..c2b1e2862 --- /dev/null +++ b/arch/arm/include/asm/gic.h @@ -0,0 +1,17 @@ +#ifndef __GIC_V2_H__ +#define __GIC_V2_H__ + +/* register offsets for the ARM generic interrupt controller (GIC) */ + +#define GIC_DIST_OFFSET		0x1000 +#define GICD_CTLR		0x0000 +#define GICD_TYPER		0x0004 +#define GICD_IGROUPRn		0x0080 +#define GICD_SGIR		0x0F00 + +#define GIC_CPU_OFFSET_A9	0x0100 +#define GIC_CPU_OFFSET_A15	0x2000 +#define GICC_CTLR		0x0000 +#define GICC_PMR		0x0004 + +#endif diff --git a/include/configs/vexpress_ca15_tc2.h b/include/configs/vexpress_ca15_tc2.h index d1431e5c7..89ce1c711 100644 --- a/include/configs/vexpress_ca15_tc2.h +++ b/include/configs/vexpress_ca15_tc2.h @@ -15,6 +15,4 @@  #include "vexpress_common.h"  #define CONFIG_BOOTP_VCI_STRING     "U-boot.armv7.vexpress_ca15x2_tc2" -#define CONFIG_SYS_CLK_FREQ 24000000 -  #endif |