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