ARM: 8711/1: V7M: Add support for MPU to M-class

This patch makes it possible to use MPU with v7M cores.

Tested-by: Szemző András <sza@esh.hu>
Tested-by: Alexandre TORGUE <alexandre.torgue@st.com>
Tested-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
This commit is contained in:
Vladimir Murzin 2017-10-16 12:57:48 +01:00 committed by Russell King
parent 89a6dafe13
commit 9fcb01a9f5
5 changed files with 113 additions and 20 deletions

View File

@ -52,8 +52,8 @@ config REMAP_VECTORS_TO_RAM
config ARM_MPU config ARM_MPU
bool 'Use the ARM v7 PMSA Compliant MPU' bool 'Use the ARM v7 PMSA Compliant MPU'
depends on !XIP_KERNEL && CPU_V7 depends on !XIP_KERNEL && (CPU_V7 || CPU_V7M)
default y default y if CPU_V7
help help
Some ARM systems without an MMU have instead a Memory Protection Some ARM systems without an MMU have instead a Memory Protection
Unit (MPU) that defines the type and permissions for regions of Unit (MPU) that defines the type and permissions for regions of

View File

@ -173,6 +173,11 @@ static inline unsigned int __attribute_const__ read_cpuid_cachetype(void)
return read_cpuid(CPUID_CACHETYPE); return read_cpuid(CPUID_CACHETYPE);
} }
static inline unsigned int __attribute_const__ read_cpuid_mputype(void)
{
return read_cpuid(CPUID_MPUIR);
}
#elif defined(CONFIG_CPU_V7M) #elif defined(CONFIG_CPU_V7M)
static inline unsigned int __attribute_const__ read_cpuid_id(void) static inline unsigned int __attribute_const__ read_cpuid_id(void)
@ -185,6 +190,11 @@ static inline unsigned int __attribute_const__ read_cpuid_cachetype(void)
return readl(BASEADDR_V7M_SCB + V7M_SCB_CTR); return readl(BASEADDR_V7M_SCB + V7M_SCB_CTR);
} }
static inline unsigned int __attribute_const__ read_cpuid_mputype(void)
{
return readl(BASEADDR_V7M_SCB + MPU_TYPE);
}
#else /* ifdef CONFIG_CPU_CP15 / elif defined(CONFIG_CPU_V7M) */ #else /* ifdef CONFIG_CPU_CP15 / elif defined(CONFIG_CPU_V7M) */
static inline unsigned int __attribute_const__ read_cpuid_id(void) static inline unsigned int __attribute_const__ read_cpuid_id(void)

View File

@ -57,6 +57,16 @@
#define V7M_SCB_CCSIDR 0x80 /* Cache size ID register */ #define V7M_SCB_CCSIDR 0x80 /* Cache size ID register */
#define V7M_SCB_CSSELR 0x84 /* Cache size selection register */ #define V7M_SCB_CSSELR 0x84 /* Cache size selection register */
/* Memory-mapped MPU registers for M-class */
#define MPU_TYPE 0x90
#define MPU_CTRL 0x94
#define MPU_CTRL_ENABLE 1
#define MPU_CTRL_PRIVDEFENA (1 << 2)
#define MPU_RNR 0x98
#define MPU_RBAR 0x9c
#define MPU_RASR 0xa0
/* Cache opeartions */ /* Cache opeartions */
#define V7M_SCB_ICIALLU 0x250 /* I-cache invalidate all to PoU */ #define V7M_SCB_ICIALLU 0x250 /* I-cache invalidate all to PoU */
#define V7M_SCB_ICIMVAU 0x258 /* I-cache invalidate by MVA to PoU */ #define V7M_SCB_ICIMVAU 0x258 /* I-cache invalidate by MVA to PoU */

View File

@ -176,19 +176,33 @@ ENDPROC(__after_proc_init)
#ifdef CONFIG_ARM_MPU #ifdef CONFIG_ARM_MPU
#ifndef CONFIG_CPU_V7M
/* Set which MPU region should be programmed */ /* Set which MPU region should be programmed */
.macro set_region_nr tmp, rgnr .macro set_region_nr tmp, rgnr, unused
mov \tmp, \rgnr @ Use static region numbers mov \tmp, \rgnr @ Use static region numbers
mcr p15, 0, \tmp, c6, c2, 0 @ Write RGNR mcr p15, 0, \tmp, c6, c2, 0 @ Write RGNR
.endm .endm
/* Setup a single MPU region, either D or I side (D-side for unified) */ /* Setup a single MPU region, either D or I side (D-side for unified) */
.macro setup_region bar, acr, sr, side = MPU_DATA_SIDE .macro setup_region bar, acr, sr, side = MPU_DATA_SIDE, unused
mcr p15, 0, \bar, c6, c1, (0 + \side) @ I/DRBAR mcr p15, 0, \bar, c6, c1, (0 + \side) @ I/DRBAR
mcr p15, 0, \acr, c6, c1, (4 + \side) @ I/DRACR mcr p15, 0, \acr, c6, c1, (4 + \side) @ I/DRACR
mcr p15, 0, \sr, c6, c1, (2 + \side) @ I/DRSR mcr p15, 0, \sr, c6, c1, (2 + \side) @ I/DRSR
.endm .endm
#else
.macro set_region_nr tmp, rgnr, base
mov \tmp, \rgnr
str \tmp, [\base, #MPU_RNR]
.endm
.macro setup_region bar, acr, sr, unused, base
lsl \acr, \acr, #16
orr \acr, \acr, \sr
str \bar, [\base, #MPU_RBAR]
str \acr, [\base, #MPU_RASR]
.endm
#endif
/* /*
* Setup the MPU and initial MPU Regions. We create the following regions: * Setup the MPU and initial MPU Regions. We create the following regions:
* Region 0: Use this for probing the MPU details, so leave disabled. * Region 0: Use this for probing the MPU details, so leave disabled.
@ -202,48 +216,58 @@ ENDPROC(__after_proc_init)
ENTRY(__setup_mpu) ENTRY(__setup_mpu)
/* Probe for v7 PMSA compliance */ /* Probe for v7 PMSA compliance */
mrc p15, 0, r0, c0, c1, 4 @ Read ID_MMFR0 M_CLASS(movw r12, #:lower16:BASEADDR_V7M_SCB)
M_CLASS(movt r12, #:upper16:BASEADDR_V7M_SCB)
AR_CLASS(mrc p15, 0, r0, c0, c1, 4) @ Read ID_MMFR0
M_CLASS(ldr r0, [r12, 0x50])
and r0, r0, #(MMFR0_PMSA) @ PMSA field and r0, r0, #(MMFR0_PMSA) @ PMSA field
teq r0, #(MMFR0_PMSAv7) @ PMSA v7 teq r0, #(MMFR0_PMSAv7) @ PMSA v7
bxne lr bxne lr
/* Determine whether the D/I-side memory map is unified. We set the /* Determine whether the D/I-side memory map is unified. We set the
* flags here and continue to use them for the rest of this function */ * flags here and continue to use them for the rest of this function */
mrc p15, 0, r0, c0, c0, 4 @ MPUIR AR_CLASS(mrc p15, 0, r0, c0, c0, 4) @ MPUIR
M_CLASS(ldr r0, [r12, #MPU_TYPE])
ands r5, r0, #MPUIR_DREGION_SZMASK @ 0 size d region => No MPU ands r5, r0, #MPUIR_DREGION_SZMASK @ 0 size d region => No MPU
bxeq lr bxeq lr
tst r0, #MPUIR_nU @ MPUIR_nU = 0 for unified tst r0, #MPUIR_nU @ MPUIR_nU = 0 for unified
/* Setup second region first to free up r6 */ /* Setup second region first to free up r6 */
set_region_nr r0, #MPU_RAM_REGION set_region_nr r0, #MPU_RAM_REGION, r12
isb isb
/* Full access from PL0, PL1, shared for CONFIG_SMP, cacheable */ /* Full access from PL0, PL1, shared for CONFIG_SMP, cacheable */
ldr r0, =PLAT_PHYS_OFFSET @ RAM starts at PHYS_OFFSET ldr r0, =PLAT_PHYS_OFFSET @ RAM starts at PHYS_OFFSET
ldr r5,=(MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL) ldr r5,=(MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL)
setup_region r0, r5, r6, MPU_DATA_SIDE @ PHYS_OFFSET, shared, enabled setup_region r0, r5, r6, MPU_DATA_SIDE, r12 @ PHYS_OFFSET, shared, enabled
beq 1f @ Memory-map not unified beq 1f @ Memory-map not unified
setup_region r0, r5, r6, MPU_INSTR_SIDE @ PHYS_OFFSET, shared, enabled setup_region r0, r5, r6, MPU_INSTR_SIDE, r12 @ PHYS_OFFSET, shared, enabled
1: isb 1: isb
/* First/background region */ /* First/background region */
set_region_nr r0, #MPU_BG_REGION set_region_nr r0, #MPU_BG_REGION, r12
isb isb
/* Execute Never, strongly ordered, inaccessible to PL0, rw PL1 */ /* Execute Never, strongly ordered, inaccessible to PL0, rw PL1 */
mov r0, #0 @ BG region starts at 0x0 mov r0, #0 @ BG region starts at 0x0
ldr r5,=(MPU_ACR_XN | MPU_RGN_STRONGLY_ORDERED | MPU_AP_PL1RW_PL0NA) ldr r5,=(MPU_ACR_XN | MPU_RGN_STRONGLY_ORDERED | MPU_AP_PL1RW_PL0NA)
mov r6, #MPU_RSR_ALL_MEM @ 4GB region, enabled mov r6, #MPU_RSR_ALL_MEM @ 4GB region, enabled
setup_region r0, r5, r6, MPU_DATA_SIDE @ 0x0, BG region, enabled setup_region r0, r5, r6, MPU_DATA_SIDE, r12 @ 0x0, BG region, enabled
beq 2f @ Memory-map not unified beq 2f @ Memory-map not unified
setup_region r0, r5, r6, MPU_INSTR_SIDE @ 0x0, BG region, enabled setup_region r0, r5, r6, MPU_INSTR_SIDE r12 @ 0x0, BG region, enabled
2: isb 2: isb
/* Enable the MPU */ /* Enable the MPU */
mrc p15, 0, r0, c1, c0, 0 @ Read SCTLR AR_CLASS(mrc p15, 0, r0, c1, c0, 0) @ Read SCTLR
bic r0, r0, #CR_BR @ Disable the 'default mem-map' AR_CLASS(bic r0, r0, #CR_BR) @ Disable the 'default mem-map'
orr r0, r0, #CR_M @ Set SCTRL.M (MPU on) AR_CLASS(orr r0, r0, #CR_M) @ Set SCTRL.M (MPU on)
mcr p15, 0, r0, c1, c0, 0 @ Enable MPU AR_CLASS(mcr p15, 0, r0, c1, c0, 0) @ Enable MPU
M_CLASS(ldr r0, [r12, #MPU_CTRL])
M_CLASS(bic r0, #MPU_CTRL_PRIVDEFENA)
M_CLASS(orr r0, #MPU_CTRL_ENABLE)
M_CLASS(str r0, [r12, #MPU_CTRL])
isb isb
ret lr ret lr

View File

@ -15,6 +15,8 @@
static unsigned int __initdata mpu_min_region_order; static unsigned int __initdata mpu_min_region_order;
static unsigned int __initdata mpu_max_regions; static unsigned int __initdata mpu_max_regions;
#ifndef CONFIG_CPU_V7M
#define DRBAR __ACCESS_CP15(c6, 0, c1, 0) #define DRBAR __ACCESS_CP15(c6, 0, c1, 0)
#define IRBAR __ACCESS_CP15(c6, 0, c1, 1) #define IRBAR __ACCESS_CP15(c6, 0, c1, 1)
#define DRSR __ACCESS_CP15(c6, 0, c1, 2) #define DRSR __ACCESS_CP15(c6, 0, c1, 2)
@ -78,6 +80,51 @@ static inline u32 irbar_read(void)
return read_sysreg(IRBAR); return read_sysreg(IRBAR);
} }
#else
static inline void rgnr_write(u32 v)
{
writel_relaxed(v, BASEADDR_V7M_SCB + MPU_RNR);
}
/* Data-side / unified region attributes */
/* Region access control register */
static inline void dracr_write(u32 v)
{
u32 rsr = readl_relaxed(BASEADDR_V7M_SCB + MPU_RASR) & GENMASK(15, 0);
writel_relaxed((v << 16) | rsr, BASEADDR_V7M_SCB + MPU_RASR);
}
/* Region size register */
static inline void drsr_write(u32 v)
{
u32 racr = readl_relaxed(BASEADDR_V7M_SCB + MPU_RASR) & GENMASK(31, 16);
writel_relaxed(v | racr, BASEADDR_V7M_SCB + MPU_RASR);
}
/* Region base address register */
static inline void drbar_write(u32 v)
{
writel_relaxed(v, BASEADDR_V7M_SCB + MPU_RBAR);
}
static inline u32 drbar_read(void)
{
return readl_relaxed(BASEADDR_V7M_SCB + MPU_RBAR);
}
/* ARMv7-M only supports a unified MPU, so I-side operations are nop */
static inline void iracr_write(u32 v) {}
static inline void irsr_write(u32 v) {}
static inline void irbar_write(u32 v) {}
static inline unsigned long irbar_read(void) {return 0;}
#endif
static int __init mpu_present(void) static int __init mpu_present(void)
{ {
return ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7); return ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7);
@ -166,7 +213,7 @@ static int __init __mpu_max_regions(void)
*/ */
u32 dregions, iregions, mpuir; u32 dregions, iregions, mpuir;
mpuir = read_cpuid(CPUID_MPUIR); mpuir = read_cpuid_mputype();
dregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION; dregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION;
@ -181,7 +228,7 @@ static int __init __mpu_max_regions(void)
static int __init mpu_iside_independent(void) static int __init mpu_iside_independent(void)
{ {
/* MPUIR.nU specifies whether there is *not* a unified memory map */ /* MPUIR.nU specifies whether there is *not* a unified memory map */
return read_cpuid(CPUID_MPUIR) & MPUIR_nU; return read_cpuid_mputype() & MPUIR_nU;
} }
static int __init __mpu_min_region_order(void) static int __init __mpu_min_region_order(void)
@ -284,9 +331,11 @@ void __init mpu_setup(void)
MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL); MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL);
/* Vectors */ /* Vectors */
#ifndef CONFIG_CPU_V7M
err |= mpu_setup_region(region++, vectors_base, err |= mpu_setup_region(region++, vectors_base,
ilog2(2 * PAGE_SIZE), ilog2(2 * PAGE_SIZE),
MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL); MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL);
#endif
if (err) { if (err) {
panic("MPU region initialization failure! %d", err); panic("MPU region initialization failure! %d", err);
} else { } else {