1 /* 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/page.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 54 } 55 56 static inline u32 prbar_read(void) 57 { 58 return readl_relaxed(BASEADDR_V7M_SCB 59 } 60 61 static inline void prsel_write(u32 v) 62 { 63 writel_relaxed(v, BASEADDR_V7M_SCB + P 64 } 65 66 static inline void prbar_write(u32 v) 67 { 68 writel_relaxed(v, BASEADDR_V7M_SCB + P 69 } 70 71 static inline void prlar_write(u32 v) 72 { 73 writel_relaxed(v, BASEADDR_V7M_SCB + P 74 } 75 76 #endif 77 78 static struct range __initdata io[MPU_MAX_REGI 79 static struct range __initdata mem[MPU_MAX_REG 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 phys_addr_t reg_start, reg_end; 98 bool first = true; 99 u64 i; 100 101 for_each_mem_range(i, ®_start, ® 102 if (first) { 103 phys_addr_t phys_offse 104 105 /* 106 * Initially only use 107 * PHYS_OFFSET */ 108 if (reg_start != phys_ 109 panic("First m 110 mem_end = reg_end; 111 first = false; 112 } else { 113 /* 114 * memblock auto merge 115 * all blocks afterwar 116 * blocks separately w 117 */ 118 pr_notice("Ignoring RA 119 &mem_end, &r 120 memblock_remove(reg_st 121 break; 122 } 123 } 124 } 125 126 static 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_ 137 138 return max_regions; 139 } 140 141 static int __init __pmsav8_setup_region(unsign 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 161 static int __init pmsav8_setup_ram(unsigned in 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 - 170 171 bar |= PMSAv8_AP_PL1RW_PL0RW | PMSAv8_ 172 lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_NORMA 173 174 return __pmsav8_setup_region(number, b 175 } 176 177 static int __init pmsav8_setup_io(unsigned int 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 - 186 187 bar |= PMSAv8_AP_PL1RW_PL0RW | PMSAv8_ 188 lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_DEVIC 189 190 return __pmsav8_setup_region(number, b 191 } 192 193 static int __init pmsav8_setup_fixed(unsigned 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 - 202 203 bar |= PMSAv8_AP_PL1RW_PL0NA | PMSAv8_ 204 lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_NORMA 205 206 prsel_write(number); 207 isb(); 208 209 if (prbar_read() != bar || prlar_read( 210 return -EINVAL; 211 212 /* Reserved region was set up early, w 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 222 static int __init pmsav8_setup_vector(unsigned 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 - 231 232 bar |= PMSAv8_AP_PL1RW_PL0NA | PMSAv8_ 233 lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_NORMA 234 235 return __pmsav8_setup_region(number, b 236 } 237 #endif 238 239 void __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, m 249 memblock.memory.regions[0].b 250 251 /* IO: cover full 4G range */ 252 add_range(io, ARRAY_SIZE(io), 0, 0, 0x 253 254 /* RAM and IO: exclude kernel */ 255 subtract_range(mem, ARRAY_SIZE(mem), _ 256 subtract_range(io, ARRAY_SIZE(io), __ 257 258 #ifdef CONFIG_XIP_KERNEL 259 /* RAM and IO: exclude xip */ 260 subtract_range(mem, ARRAY_SIZE(mem), C 261 subtract_range(io, ARRAY_SIZE(io), CON 262 #endif 263 264 #ifndef CONFIG_CPU_V7M 265 /* RAM and IO: exclude vectors */ 266 subtract_range(mem, ARRAY_SIZE(mem), 267 subtract_range(io, ARRAY_SIZE(io), ve 268 #endif 269 /* IO: exclude RAM */ 270 for (i = 0; i < ARRAY_SIZE(mem); i++) 271 subtract_range(io, ARRAY_SIZE( 272 273 /* Now program MPU */ 274 275 #ifdef CONFIG_XIP_KERNEL 276 /* ROM */ 277 err |= pmsav8_setup_fixed(PMSAv8_XIP_R 278 #endif 279 /* Kernel */ 280 err |= pmsav8_setup_fixed(region++, __ 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+ 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 297 } 298 299 /* Vectors */ 300 #ifndef CONFIG_CPU_V7M 301 err |= pmsav8_setup_vector(region++, v 302 #endif 303 if (err) 304 pr_warn("MPU region initializa 305 else 306 pr_info("Using ARM PMSAv8 Comp 307 mpu_rgn_info.used, mpu 308 } 309
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.