diff options
author | Vladimir Murzin <vladimir.murzin@arm.com> | 2017-10-16 07:57:48 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2017-10-23 11:59:15 -0400 |
commit | 9fcb01a9f54c28062a73a545c29137a4cc104c72 (patch) | |
tree | 7cebf0b0de05a73132ef66ae9c1671206a58be77 | |
parent | 89a6dafe136952b3409d5e4ed04cb891e806e924 (diff) |
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>
-rw-r--r-- | arch/arm/Kconfig-nommu | 4 | ||||
-rw-r--r-- | arch/arm/include/asm/cputype.h | 10 | ||||
-rw-r--r-- | arch/arm/include/asm/v7m.h | 10 | ||||
-rw-r--r-- | arch/arm/kernel/head-nommu.S | 56 | ||||
-rw-r--r-- | arch/arm/mm/pmsa-v7.c | 53 |
5 files changed, 113 insertions, 20 deletions
diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu index 6d18395da24d..930e000489a8 100644 --- a/arch/arm/Kconfig-nommu +++ b/arch/arm/Kconfig-nommu | |||
@@ -52,8 +52,8 @@ config REMAP_VECTORS_TO_RAM | |||
52 | 52 | ||
53 | config ARM_MPU | 53 | config ARM_MPU |
54 | bool 'Use the ARM v7 PMSA Compliant MPU' | 54 | bool 'Use the ARM v7 PMSA Compliant MPU' |
55 | depends on !XIP_KERNEL && CPU_V7 | 55 | depends on !XIP_KERNEL && (CPU_V7 || CPU_V7M) |
56 | default y | 56 | default y if CPU_V7 |
57 | help | 57 | help |
58 | Some ARM systems without an MMU have instead a Memory Protection | 58 | Some ARM systems without an MMU have instead a Memory Protection |
59 | Unit (MPU) that defines the type and permissions for regions of | 59 | Unit (MPU) that defines the type and permissions for regions of |
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h index b62eaeb147aa..abaac5e07b80 100644 --- a/arch/arm/include/asm/cputype.h +++ b/arch/arm/include/asm/cputype.h | |||
@@ -173,6 +173,11 @@ static inline unsigned int __attribute_const__ read_cpuid_cachetype(void) | |||
173 | return read_cpuid(CPUID_CACHETYPE); | 173 | return read_cpuid(CPUID_CACHETYPE); |
174 | } | 174 | } |
175 | 175 | ||
176 | static inline unsigned int __attribute_const__ read_cpuid_mputype(void) | ||
177 | { | ||
178 | return read_cpuid(CPUID_MPUIR); | ||
179 | } | ||
180 | |||
176 | #elif defined(CONFIG_CPU_V7M) | 181 | #elif defined(CONFIG_CPU_V7M) |
177 | 182 | ||
178 | static inline unsigned int __attribute_const__ read_cpuid_id(void) | 183 | static inline unsigned int __attribute_const__ read_cpuid_id(void) |
@@ -185,6 +190,11 @@ static inline unsigned int __attribute_const__ read_cpuid_cachetype(void) | |||
185 | return readl(BASEADDR_V7M_SCB + V7M_SCB_CTR); | 190 | return readl(BASEADDR_V7M_SCB + V7M_SCB_CTR); |
186 | } | 191 | } |
187 | 192 | ||
193 | static inline unsigned int __attribute_const__ read_cpuid_mputype(void) | ||
194 | { | ||
195 | return readl(BASEADDR_V7M_SCB + MPU_TYPE); | ||
196 | } | ||
197 | |||
188 | #else /* ifdef CONFIG_CPU_CP15 / elif defined(CONFIG_CPU_V7M) */ | 198 | #else /* ifdef CONFIG_CPU_CP15 / elif defined(CONFIG_CPU_V7M) */ |
189 | 199 | ||
190 | static inline unsigned int __attribute_const__ read_cpuid_id(void) | 200 | static inline unsigned int __attribute_const__ read_cpuid_id(void) |
diff --git a/arch/arm/include/asm/v7m.h b/arch/arm/include/asm/v7m.h index 1fd775c1bc5d..5de776c81382 100644 --- a/arch/arm/include/asm/v7m.h +++ b/arch/arm/include/asm/v7m.h | |||
@@ -57,6 +57,16 @@ | |||
57 | #define V7M_SCB_CCSIDR 0x80 /* Cache size ID register */ | 57 | #define V7M_SCB_CCSIDR 0x80 /* Cache size ID register */ |
58 | #define V7M_SCB_CSSELR 0x84 /* Cache size selection register */ | 58 | #define V7M_SCB_CSSELR 0x84 /* Cache size selection register */ |
59 | 59 | ||
60 | /* Memory-mapped MPU registers for M-class */ | ||
61 | #define MPU_TYPE 0x90 | ||
62 | #define MPU_CTRL 0x94 | ||
63 | #define MPU_CTRL_ENABLE 1 | ||
64 | #define MPU_CTRL_PRIVDEFENA (1 << 2) | ||
65 | |||
66 | #define MPU_RNR 0x98 | ||
67 | #define MPU_RBAR 0x9c | ||
68 | #define MPU_RASR 0xa0 | ||
69 | |||
60 | /* Cache opeartions */ | 70 | /* Cache opeartions */ |
61 | #define V7M_SCB_ICIALLU 0x250 /* I-cache invalidate all to PoU */ | 71 | #define V7M_SCB_ICIALLU 0x250 /* I-cache invalidate all to PoU */ |
62 | #define V7M_SCB_ICIMVAU 0x258 /* I-cache invalidate by MVA to PoU */ | 72 | #define V7M_SCB_ICIMVAU 0x258 /* I-cache invalidate by MVA to PoU */ |
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index 5f90a5fb7022..0d64b8ba7e9c 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S | |||
@@ -176,19 +176,33 @@ ENDPROC(__after_proc_init) | |||
176 | #ifdef CONFIG_ARM_MPU | 176 | #ifdef CONFIG_ARM_MPU |
177 | 177 | ||
178 | 178 | ||
179 | #ifndef CONFIG_CPU_V7M | ||
179 | /* Set which MPU region should be programmed */ | 180 | /* Set which MPU region should be programmed */ |
180 | .macro set_region_nr tmp, rgnr | 181 | .macro set_region_nr tmp, rgnr, unused |
181 | mov \tmp, \rgnr @ Use static region numbers | 182 | mov \tmp, \rgnr @ Use static region numbers |
182 | mcr p15, 0, \tmp, c6, c2, 0 @ Write RGNR | 183 | mcr p15, 0, \tmp, c6, c2, 0 @ Write RGNR |
183 | .endm | 184 | .endm |
184 | 185 | ||
185 | /* Setup a single MPU region, either D or I side (D-side for unified) */ | 186 | /* Setup a single MPU region, either D or I side (D-side for unified) */ |
186 | .macro setup_region bar, acr, sr, side = MPU_DATA_SIDE | 187 | .macro setup_region bar, acr, sr, side = MPU_DATA_SIDE, unused |
187 | mcr p15, 0, \bar, c6, c1, (0 + \side) @ I/DRBAR | 188 | mcr p15, 0, \bar, c6, c1, (0 + \side) @ I/DRBAR |
188 | mcr p15, 0, \acr, c6, c1, (4 + \side) @ I/DRACR | 189 | mcr p15, 0, \acr, c6, c1, (4 + \side) @ I/DRACR |
189 | mcr p15, 0, \sr, c6, c1, (2 + \side) @ I/DRSR | 190 | mcr p15, 0, \sr, c6, c1, (2 + \side) @ I/DRSR |
190 | .endm | 191 | .endm |
192 | #else | ||
193 | .macro set_region_nr tmp, rgnr, base | ||
194 | mov \tmp, \rgnr | ||
195 | str \tmp, [\base, #MPU_RNR] | ||
196 | .endm | ||
197 | |||
198 | .macro setup_region bar, acr, sr, unused, base | ||
199 | lsl \acr, \acr, #16 | ||
200 | orr \acr, \acr, \sr | ||
201 | str \bar, [\base, #MPU_RBAR] | ||
202 | str \acr, [\base, #MPU_RASR] | ||
203 | .endm | ||
191 | 204 | ||
205 | #endif | ||
192 | /* | 206 | /* |
193 | * Setup the MPU and initial MPU Regions. We create the following regions: | 207 | * Setup the MPU and initial MPU Regions. We create the following regions: |
194 | * Region 0: Use this for probing the MPU details, so leave disabled. | 208 | * Region 0: Use this for probing the MPU details, so leave disabled. |
@@ -202,48 +216,58 @@ ENDPROC(__after_proc_init) | |||
202 | ENTRY(__setup_mpu) | 216 | ENTRY(__setup_mpu) |
203 | 217 | ||
204 | /* Probe for v7 PMSA compliance */ | 218 | /* Probe for v7 PMSA compliance */ |
205 | mrc p15, 0, r0, c0, c1, 4 @ Read ID_MMFR0 | 219 | M_CLASS(movw r12, #:lower16:BASEADDR_V7M_SCB) |
220 | M_CLASS(movt r12, #:upper16:BASEADDR_V7M_SCB) | ||
221 | |||
222 | AR_CLASS(mrc p15, 0, r0, c0, c1, 4) @ Read ID_MMFR0 | ||
223 | M_CLASS(ldr r0, [r12, 0x50]) | ||
206 | and r0, r0, #(MMFR0_PMSA) @ PMSA field | 224 | and r0, r0, #(MMFR0_PMSA) @ PMSA field |
207 | teq r0, #(MMFR0_PMSAv7) @ PMSA v7 | 225 | teq r0, #(MMFR0_PMSAv7) @ PMSA v7 |
208 | bxne lr | 226 | bxne lr |
209 | 227 | ||
210 | /* Determine whether the D/I-side memory map is unified. We set the | 228 | /* Determine whether the D/I-side memory map is unified. We set the |
211 | * flags here and continue to use them for the rest of this function */ | 229 | * flags here and continue to use them for the rest of this function */ |
212 | mrc p15, 0, r0, c0, c0, 4 @ MPUIR | 230 | AR_CLASS(mrc p15, 0, r0, c0, c0, 4) @ MPUIR |
231 | M_CLASS(ldr r0, [r12, #MPU_TYPE]) | ||
213 | ands r5, r0, #MPUIR_DREGION_SZMASK @ 0 size d region => No MPU | 232 | ands r5, r0, #MPUIR_DREGION_SZMASK @ 0 size d region => No MPU |
214 | bxeq lr | 233 | bxeq lr |
215 | tst r0, #MPUIR_nU @ MPUIR_nU = 0 for unified | 234 | tst r0, #MPUIR_nU @ MPUIR_nU = 0 for unified |
216 | 235 | ||
217 | /* Setup second region first to free up r6 */ | 236 | /* Setup second region first to free up r6 */ |
218 | set_region_nr r0, #MPU_RAM_REGION | 237 | set_region_nr r0, #MPU_RAM_REGION, r12 |
219 | isb | 238 | isb |
220 | /* Full access from PL0, PL1, shared for CONFIG_SMP, cacheable */ | 239 | /* Full access from PL0, PL1, shared for CONFIG_SMP, cacheable */ |
221 | ldr r0, =PLAT_PHYS_OFFSET @ RAM starts at PHYS_OFFSET | 240 | ldr r0, =PLAT_PHYS_OFFSET @ RAM starts at PHYS_OFFSET |
222 | ldr r5,=(MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL) | 241 | ldr r5,=(MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL) |
223 | 242 | ||
224 | setup_region r0, r5, r6, MPU_DATA_SIDE @ PHYS_OFFSET, shared, enabled | 243 | setup_region r0, r5, r6, MPU_DATA_SIDE, r12 @ PHYS_OFFSET, shared, enabled |
225 | beq 1f @ Memory-map not unified | 244 | beq 1f @ Memory-map not unified |
226 | setup_region r0, r5, r6, MPU_INSTR_SIDE @ PHYS_OFFSET, shared, enabled | 245 | setup_region r0, r5, r6, MPU_INSTR_SIDE, r12 @ PHYS_OFFSET, shared, enabled |
227 | 1: isb | 246 | 1: isb |
228 | 247 | ||
229 | /* First/background region */ | 248 | /* First/background region */ |
230 | set_region_nr r0, #MPU_BG_REGION | 249 | set_region_nr r0, #MPU_BG_REGION, r12 |
231 | isb | 250 | isb |
232 | /* Execute Never, strongly ordered, inaccessible to PL0, rw PL1 */ | 251 | /* Execute Never, strongly ordered, inaccessible to PL0, rw PL1 */ |
233 | mov r0, #0 @ BG region starts at 0x0 | 252 | mov r0, #0 @ BG region starts at 0x0 |
234 | ldr r5,=(MPU_ACR_XN | MPU_RGN_STRONGLY_ORDERED | MPU_AP_PL1RW_PL0NA) | 253 | ldr r5,=(MPU_ACR_XN | MPU_RGN_STRONGLY_ORDERED | MPU_AP_PL1RW_PL0NA) |
235 | mov r6, #MPU_RSR_ALL_MEM @ 4GB region, enabled | 254 | mov r6, #MPU_RSR_ALL_MEM @ 4GB region, enabled |
236 | 255 | ||
237 | setup_region r0, r5, r6, MPU_DATA_SIDE @ 0x0, BG region, enabled | 256 | setup_region r0, r5, r6, MPU_DATA_SIDE, r12 @ 0x0, BG region, enabled |
238 | beq 2f @ Memory-map not unified | 257 | beq 2f @ Memory-map not unified |
239 | setup_region r0, r5, r6, MPU_INSTR_SIDE @ 0x0, BG region, enabled | 258 | setup_region r0, r5, r6, MPU_INSTR_SIDE r12 @ 0x0, BG region, enabled |
240 | 2: isb | 259 | 2: isb |
241 | 260 | ||
242 | /* Enable the MPU */ | 261 | /* Enable the MPU */ |
243 | mrc p15, 0, r0, c1, c0, 0 @ Read SCTLR | 262 | AR_CLASS(mrc p15, 0, r0, c1, c0, 0) @ Read SCTLR |
244 | bic r0, r0, #CR_BR @ Disable the 'default mem-map' | 263 | AR_CLASS(bic r0, r0, #CR_BR) @ Disable the 'default mem-map' |
245 | orr r0, r0, #CR_M @ Set SCTRL.M (MPU on) | 264 | AR_CLASS(orr r0, r0, #CR_M) @ Set SCTRL.M (MPU on) |
246 | mcr p15, 0, r0, c1, c0, 0 @ Enable MPU | 265 | AR_CLASS(mcr p15, 0, r0, c1, c0, 0) @ Enable MPU |
266 | |||
267 | M_CLASS(ldr r0, [r12, #MPU_CTRL]) | ||
268 | M_CLASS(bic r0, #MPU_CTRL_PRIVDEFENA) | ||
269 | M_CLASS(orr r0, #MPU_CTRL_ENABLE) | ||
270 | M_CLASS(str r0, [r12, #MPU_CTRL]) | ||
247 | isb | 271 | isb |
248 | 272 | ||
249 | ret lr | 273 | ret lr |
diff --git a/arch/arm/mm/pmsa-v7.c b/arch/arm/mm/pmsa-v7.c index cd798271a78d..06e2a853cab9 100644 --- a/arch/arm/mm/pmsa-v7.c +++ b/arch/arm/mm/pmsa-v7.c | |||
@@ -15,6 +15,8 @@ | |||
15 | static unsigned int __initdata mpu_min_region_order; | 15 | static unsigned int __initdata mpu_min_region_order; |
16 | static unsigned int __initdata mpu_max_regions; | 16 | static unsigned int __initdata mpu_max_regions; |
17 | 17 | ||
18 | #ifndef CONFIG_CPU_V7M | ||
19 | |||
18 | #define DRBAR __ACCESS_CP15(c6, 0, c1, 0) | 20 | #define DRBAR __ACCESS_CP15(c6, 0, c1, 0) |
19 | #define IRBAR __ACCESS_CP15(c6, 0, c1, 1) | 21 | #define IRBAR __ACCESS_CP15(c6, 0, c1, 1) |
20 | #define DRSR __ACCESS_CP15(c6, 0, c1, 2) | 22 | #define DRSR __ACCESS_CP15(c6, 0, c1, 2) |
@@ -78,6 +80,51 @@ static inline u32 irbar_read(void) | |||
78 | return read_sysreg(IRBAR); | 80 | return read_sysreg(IRBAR); |
79 | } | 81 | } |
80 | 82 | ||
83 | #else | ||
84 | |||
85 | static inline void rgnr_write(u32 v) | ||
86 | { | ||
87 | writel_relaxed(v, BASEADDR_V7M_SCB + MPU_RNR); | ||
88 | } | ||
89 | |||
90 | /* Data-side / unified region attributes */ | ||
91 | |||
92 | /* Region access control register */ | ||
93 | static inline void dracr_write(u32 v) | ||
94 | { | ||
95 | u32 rsr = readl_relaxed(BASEADDR_V7M_SCB + MPU_RASR) & GENMASK(15, 0); | ||
96 | |||
97 | writel_relaxed((v << 16) | rsr, BASEADDR_V7M_SCB + MPU_RASR); | ||
98 | } | ||
99 | |||
100 | /* Region size register */ | ||
101 | static inline void drsr_write(u32 v) | ||
102 | { | ||
103 | u32 racr = readl_relaxed(BASEADDR_V7M_SCB + MPU_RASR) & GENMASK(31, 16); | ||
104 | |||
105 | writel_relaxed(v | racr, BASEADDR_V7M_SCB + MPU_RASR); | ||
106 | } | ||
107 | |||
108 | /* Region base address register */ | ||
109 | static inline void drbar_write(u32 v) | ||
110 | { | ||
111 | writel_relaxed(v, BASEADDR_V7M_SCB + MPU_RBAR); | ||
112 | } | ||
113 | |||
114 | static inline u32 drbar_read(void) | ||
115 | { | ||
116 | return readl_relaxed(BASEADDR_V7M_SCB + MPU_RBAR); | ||
117 | } | ||
118 | |||
119 | /* ARMv7-M only supports a unified MPU, so I-side operations are nop */ | ||
120 | |||
121 | static inline void iracr_write(u32 v) {} | ||
122 | static inline void irsr_write(u32 v) {} | ||
123 | static inline void irbar_write(u32 v) {} | ||
124 | static inline unsigned long irbar_read(void) {return 0;} | ||
125 | |||
126 | #endif | ||
127 | |||
81 | static int __init mpu_present(void) | 128 | static int __init mpu_present(void) |
82 | { | 129 | { |
83 | return ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7); | 130 | return ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7); |
@@ -166,7 +213,7 @@ static int __init __mpu_max_regions(void) | |||
166 | */ | 213 | */ |
167 | u32 dregions, iregions, mpuir; | 214 | u32 dregions, iregions, mpuir; |
168 | 215 | ||
169 | mpuir = read_cpuid(CPUID_MPUIR); | 216 | mpuir = read_cpuid_mputype(); |
170 | 217 | ||
171 | dregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION; | 218 | dregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION; |
172 | 219 | ||
@@ -181,7 +228,7 @@ static int __init __mpu_max_regions(void) | |||
181 | static int __init mpu_iside_independent(void) | 228 | static int __init mpu_iside_independent(void) |
182 | { | 229 | { |
183 | /* MPUIR.nU specifies whether there is *not* a unified memory map */ | 230 | /* MPUIR.nU specifies whether there is *not* a unified memory map */ |
184 | return read_cpuid(CPUID_MPUIR) & MPUIR_nU; | 231 | return read_cpuid_mputype() & MPUIR_nU; |
185 | } | 232 | } |
186 | 233 | ||
187 | static int __init __mpu_min_region_order(void) | 234 | static int __init __mpu_min_region_order(void) |
@@ -284,9 +331,11 @@ void __init mpu_setup(void) | |||
284 | MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL); | 331 | MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL); |
285 | 332 | ||
286 | /* Vectors */ | 333 | /* Vectors */ |
334 | #ifndef CONFIG_CPU_V7M | ||
287 | err |= mpu_setup_region(region++, vectors_base, | 335 | err |= mpu_setup_region(region++, vectors_base, |
288 | ilog2(2 * PAGE_SIZE), | 336 | ilog2(2 * PAGE_SIZE), |
289 | MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL); | 337 | MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL); |
338 | #endif | ||
290 | if (err) { | 339 | if (err) { |
291 | panic("MPU region initialization failure! %d", err); | 340 | panic("MPU region initialization failure! %d", err); |
292 | } else { | 341 | } else { |