mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 08:14:15 +08:00
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:
parent
89a6dafe13
commit
9fcb01a9f5
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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 */
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user