pmsa-v8.c (6837B)
1/* 2 * Based on linux/arch/arm/pmsa-v7.c 3 * 4 * ARM PMSAv8 supporting functions. 5 */ 6 7#include <linux/memblock.h> 8#include <linux/range.h> 9 10#include <asm/cp15.h> 11#include <asm/cputype.h> 12#include <asm/mpu.h> 13 14#include <asm/memory.h> 15#include <asm/sections.h> 16 17#include "mm.h" 18 19#ifndef CONFIG_CPU_V7M 20 21#define PRSEL __ACCESS_CP15(c6, 0, c2, 1) 22#define PRBAR __ACCESS_CP15(c6, 0, c3, 0) 23#define PRLAR __ACCESS_CP15(c6, 0, c3, 1) 24 25static inline u32 prlar_read(void) 26{ 27 return read_sysreg(PRLAR); 28} 29 30static inline u32 prbar_read(void) 31{ 32 return read_sysreg(PRBAR); 33} 34 35static inline void prsel_write(u32 v) 36{ 37 write_sysreg(v, PRSEL); 38} 39 40static inline void prbar_write(u32 v) 41{ 42 write_sysreg(v, PRBAR); 43} 44 45static inline void prlar_write(u32 v) 46{ 47 write_sysreg(v, PRLAR); 48} 49#else 50 51static inline u32 prlar_read(void) 52{ 53 return readl_relaxed(BASEADDR_V7M_SCB + PMSAv8_RLAR); 54} 55 56static inline u32 prbar_read(void) 57{ 58 return readl_relaxed(BASEADDR_V7M_SCB + PMSAv8_RBAR); 59} 60 61static inline void prsel_write(u32 v) 62{ 63 writel_relaxed(v, BASEADDR_V7M_SCB + PMSAv8_RNR); 64} 65 66static inline void prbar_write(u32 v) 67{ 68 writel_relaxed(v, BASEADDR_V7M_SCB + PMSAv8_RBAR); 69} 70 71static inline void prlar_write(u32 v) 72{ 73 writel_relaxed(v, BASEADDR_V7M_SCB + PMSAv8_RLAR); 74} 75 76#endif 77 78static struct range __initdata io[MPU_MAX_REGIONS]; 79static struct range __initdata mem[MPU_MAX_REGIONS]; 80 81static unsigned int __initdata mpu_max_regions; 82 83static __init bool is_region_fixed(int number) 84{ 85 switch (number) { 86 case PMSAv8_XIP_REGION: 87 case PMSAv8_KERNEL_REGION: 88 return true; 89 default: 90 return false; 91 } 92} 93 94void __init pmsav8_adjust_lowmem_bounds(void) 95{ 96 phys_addr_t mem_end; 97 phys_addr_t reg_start, reg_end; 98 bool first = true; 99 u64 i; 100 101 for_each_mem_range(i, ®_start, ®_end) { 102 if (first) { 103 phys_addr_t phys_offset = PHYS_OFFSET; 104 105 /* 106 * Initially only use memory continuous from 107 * PHYS_OFFSET */ 108 if (reg_start != phys_offset) 109 panic("First memory bank must be contiguous from PHYS_OFFSET"); 110 mem_end = reg_end; 111 first = false; 112 } else { 113 /* 114 * memblock auto merges contiguous blocks, remove 115 * all blocks afterwards in one go (we can't remove 116 * blocks separately while iterating) 117 */ 118 pr_notice("Ignoring RAM after %pa, memory at %pa ignored\n", 119 &mem_end, ®_start); 120 memblock_remove(reg_start, 0 - reg_start); 121 break; 122 } 123 } 124} 125 126static int __init __mpu_max_regions(void) 127{ 128 static int max_regions; 129 u32 mpuir; 130 131 if (max_regions) 132 return max_regions; 133 134 mpuir = read_cpuid_mputype(); 135 136 max_regions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION; 137 138 return max_regions; 139} 140 141static int __init __pmsav8_setup_region(unsigned int number, u32 bar, u32 lar) 142{ 143 if (number > mpu_max_regions 144 || number >= MPU_MAX_REGIONS) 145 return -ENOENT; 146 147 dsb(); 148 prsel_write(number); 149 isb(); 150 prbar_write(bar); 151 prlar_write(lar); 152 153 mpu_rgn_info.rgns[number].prbar = bar; 154 mpu_rgn_info.rgns[number].prlar = lar; 155 156 mpu_rgn_info.used++; 157 158 return 0; 159} 160 161static int __init pmsav8_setup_ram(unsigned int number, phys_addr_t start,phys_addr_t end) 162{ 163 u32 bar, lar; 164 165 if (is_region_fixed(number)) 166 return -EINVAL; 167 168 bar = start; 169 lar = (end - 1) & ~(PMSAv8_MINALIGN - 1); 170 171 bar |= PMSAv8_AP_PL1RW_PL0RW | PMSAv8_RGN_SHARED; 172 lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN; 173 174 return __pmsav8_setup_region(number, bar, lar); 175} 176 177static int __init pmsav8_setup_io(unsigned int number, phys_addr_t start,phys_addr_t end) 178{ 179 u32 bar, lar; 180 181 if (is_region_fixed(number)) 182 return -EINVAL; 183 184 bar = start; 185 lar = (end - 1) & ~(PMSAv8_MINALIGN - 1); 186 187 bar |= PMSAv8_AP_PL1RW_PL0RW | PMSAv8_RGN_SHARED | PMSAv8_BAR_XN; 188 lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_DEVICE_nGnRnE) | PMSAv8_LAR_EN; 189 190 return __pmsav8_setup_region(number, bar, lar); 191} 192 193static int __init pmsav8_setup_fixed(unsigned int number, phys_addr_t start,phys_addr_t end) 194{ 195 u32 bar, lar; 196 197 if (!is_region_fixed(number)) 198 return -EINVAL; 199 200 bar = start; 201 lar = (end - 1) & ~(PMSAv8_MINALIGN - 1); 202 203 bar |= PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED; 204 lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN; 205 206 prsel_write(number); 207 isb(); 208 209 if (prbar_read() != bar || prlar_read() != lar) 210 return -EINVAL; 211 212 /* Reserved region was set up early, we just need a record for secondaries */ 213 mpu_rgn_info.rgns[number].prbar = bar; 214 mpu_rgn_info.rgns[number].prlar = lar; 215 216 mpu_rgn_info.used++; 217 218 return 0; 219} 220 221#ifndef CONFIG_CPU_V7M 222static int __init pmsav8_setup_vector(unsigned int number, phys_addr_t start,phys_addr_t end) 223{ 224 u32 bar, lar; 225 226 if (number == PMSAv8_KERNEL_REGION) 227 return -EINVAL; 228 229 bar = start; 230 lar = (end - 1) & ~(PMSAv8_MINALIGN - 1); 231 232 bar |= PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED; 233 lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN; 234 235 return __pmsav8_setup_region(number, bar, lar); 236} 237#endif 238 239void __init pmsav8_setup(void) 240{ 241 int i, err = 0; 242 int region = PMSAv8_KERNEL_REGION; 243 244 /* How many regions are supported ? */ 245 mpu_max_regions = __mpu_max_regions(); 246 247 /* RAM: single chunk of memory */ 248 add_range(mem, ARRAY_SIZE(mem), 0, memblock.memory.regions[0].base, 249 memblock.memory.regions[0].base + memblock.memory.regions[0].size); 250 251 /* IO: cover full 4G range */ 252 add_range(io, ARRAY_SIZE(io), 0, 0, 0xffffffff); 253 254 /* RAM and IO: exclude kernel */ 255 subtract_range(mem, ARRAY_SIZE(mem), __pa(KERNEL_START), __pa(KERNEL_END)); 256 subtract_range(io, ARRAY_SIZE(io), __pa(KERNEL_START), __pa(KERNEL_END)); 257 258#ifdef CONFIG_XIP_KERNEL 259 /* RAM and IO: exclude xip */ 260 subtract_range(mem, ARRAY_SIZE(mem), CONFIG_XIP_PHYS_ADDR, __pa(_exiprom)); 261 subtract_range(io, ARRAY_SIZE(io), CONFIG_XIP_PHYS_ADDR, __pa(_exiprom)); 262#endif 263 264#ifndef CONFIG_CPU_V7M 265 /* RAM and IO: exclude vectors */ 266 subtract_range(mem, ARRAY_SIZE(mem), vectors_base, vectors_base + 2 * PAGE_SIZE); 267 subtract_range(io, ARRAY_SIZE(io), vectors_base, vectors_base + 2 * PAGE_SIZE); 268#endif 269 /* IO: exclude RAM */ 270 for (i = 0; i < ARRAY_SIZE(mem); i++) 271 subtract_range(io, ARRAY_SIZE(io), mem[i].start, mem[i].end); 272 273 /* Now program MPU */ 274 275#ifdef CONFIG_XIP_KERNEL 276 /* ROM */ 277 err |= pmsav8_setup_fixed(PMSAv8_XIP_REGION, CONFIG_XIP_PHYS_ADDR, __pa(_exiprom)); 278#endif 279 /* Kernel */ 280 err |= pmsav8_setup_fixed(region++, __pa(KERNEL_START), __pa(KERNEL_END)); 281 282 283 /* IO */ 284 for (i = 0; i < ARRAY_SIZE(io); i++) { 285 if (!io[i].end) 286 continue; 287 288 err |= pmsav8_setup_io(region++, io[i].start, io[i].end); 289 } 290 291 /* RAM */ 292 for (i = 0; i < ARRAY_SIZE(mem); i++) { 293 if (!mem[i].end) 294 continue; 295 296 err |= pmsav8_setup_ram(region++, mem[i].start, mem[i].end); 297 } 298 299 /* Vectors */ 300#ifndef CONFIG_CPU_V7M 301 err |= pmsav8_setup_vector(region++, vectors_base, vectors_base + 2 * PAGE_SIZE); 302#endif 303 if (err) 304 pr_warn("MPU region initialization failure! %d", err); 305 else 306 pr_info("Using ARM PMSAv8 Compliant MPU. Used %d of %d regions\n", 307 mpu_rgn_info.used, mpu_max_regions); 308}