Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Based on linux/arch/arm/pmsa-v7.c
0003  *
0004  * ARM PMSAv8 supporting functions.
0005  */
0006 
0007 #include <linux/memblock.h>
0008 #include <linux/range.h>
0009 
0010 #include <asm/cp15.h>
0011 #include <asm/cputype.h>
0012 #include <asm/mpu.h>
0013 
0014 #include <asm/memory.h>
0015 #include <asm/sections.h>
0016 
0017 #include "mm.h"
0018 
0019 #ifndef CONFIG_CPU_V7M
0020 
0021 #define PRSEL   __ACCESS_CP15(c6, 0, c2, 1)
0022 #define PRBAR   __ACCESS_CP15(c6, 0, c3, 0)
0023 #define PRLAR   __ACCESS_CP15(c6, 0, c3, 1)
0024 
0025 static inline u32 prlar_read(void)
0026 {
0027     return read_sysreg(PRLAR);
0028 }
0029 
0030 static inline u32 prbar_read(void)
0031 {
0032     return read_sysreg(PRBAR);
0033 }
0034 
0035 static inline void prsel_write(u32 v)
0036 {
0037     write_sysreg(v, PRSEL);
0038 }
0039 
0040 static inline void prbar_write(u32 v)
0041 {
0042     write_sysreg(v, PRBAR);
0043 }
0044 
0045 static inline void prlar_write(u32 v)
0046 {
0047     write_sysreg(v, PRLAR);
0048 }
0049 #else
0050 
0051 static inline u32 prlar_read(void)
0052 {
0053     return readl_relaxed(BASEADDR_V7M_SCB + PMSAv8_RLAR);
0054 }
0055 
0056 static inline u32 prbar_read(void)
0057 {
0058     return readl_relaxed(BASEADDR_V7M_SCB + PMSAv8_RBAR);
0059 }
0060 
0061 static inline void prsel_write(u32 v)
0062 {
0063     writel_relaxed(v, BASEADDR_V7M_SCB + PMSAv8_RNR);
0064 }
0065 
0066 static inline void prbar_write(u32 v)
0067 {
0068     writel_relaxed(v, BASEADDR_V7M_SCB + PMSAv8_RBAR);
0069 }
0070 
0071 static inline void prlar_write(u32 v)
0072 {
0073     writel_relaxed(v, BASEADDR_V7M_SCB + PMSAv8_RLAR);
0074 }
0075 
0076 #endif
0077 
0078 static struct range __initdata io[MPU_MAX_REGIONS];
0079 static struct range __initdata mem[MPU_MAX_REGIONS];
0080 
0081 static unsigned int __initdata mpu_max_regions;
0082 
0083 static __init bool is_region_fixed(int number)
0084 {
0085     switch (number) {
0086     case PMSAv8_XIP_REGION:
0087     case PMSAv8_KERNEL_REGION:
0088         return true;
0089     default:
0090         return false;
0091     }
0092 }
0093 
0094 void __init pmsav8_adjust_lowmem_bounds(void)
0095 {
0096     phys_addr_t mem_end;
0097     phys_addr_t reg_start, reg_end;
0098     bool first = true;
0099     u64 i;
0100 
0101     for_each_mem_range(i, &reg_start, &reg_end) {
0102         if (first) {
0103             phys_addr_t phys_offset = PHYS_OFFSET;
0104 
0105             /*
0106              * Initially only use memory continuous from
0107              * PHYS_OFFSET */
0108             if (reg_start != phys_offset)
0109                 panic("First memory bank must be contiguous from PHYS_OFFSET");
0110             mem_end = reg_end;
0111             first = false;
0112         } else {
0113             /*
0114              * memblock auto merges contiguous blocks, remove
0115              * all blocks afterwards in one go (we can't remove
0116              * blocks separately while iterating)
0117              */
0118             pr_notice("Ignoring RAM after %pa, memory at %pa ignored\n",
0119                   &mem_end, &reg_start);
0120             memblock_remove(reg_start, 0 - reg_start);
0121             break;
0122         }
0123     }
0124 }
0125 
0126 static int __init __mpu_max_regions(void)
0127 {
0128     static int max_regions;
0129     u32 mpuir;
0130 
0131     if (max_regions)
0132         return max_regions;
0133 
0134     mpuir = read_cpuid_mputype();
0135 
0136     max_regions  = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION;
0137 
0138     return max_regions;
0139 }
0140 
0141 static int __init __pmsav8_setup_region(unsigned int number, u32 bar, u32 lar)
0142 {
0143     if (number > mpu_max_regions
0144         || number >= MPU_MAX_REGIONS)
0145         return -ENOENT;
0146 
0147     dsb();
0148     prsel_write(number);
0149     isb();
0150     prbar_write(bar);
0151     prlar_write(lar);
0152 
0153     mpu_rgn_info.rgns[number].prbar = bar;
0154     mpu_rgn_info.rgns[number].prlar = lar;
0155 
0156     mpu_rgn_info.used++;
0157 
0158     return 0;
0159 }
0160 
0161 static int __init pmsav8_setup_ram(unsigned int number, phys_addr_t start,phys_addr_t end)
0162 {
0163     u32 bar, lar;
0164 
0165     if (is_region_fixed(number))
0166         return -EINVAL;
0167 
0168     bar = start;
0169     lar = (end - 1) & ~(PMSAv8_MINALIGN - 1);
0170 
0171     bar |= PMSAv8_AP_PL1RW_PL0RW | PMSAv8_RGN_SHARED;
0172     lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN;
0173 
0174     return __pmsav8_setup_region(number, bar, lar);
0175 }
0176 
0177 static int __init pmsav8_setup_io(unsigned int number, phys_addr_t start,phys_addr_t end)
0178 {
0179     u32 bar, lar;
0180 
0181     if (is_region_fixed(number))
0182         return -EINVAL;
0183 
0184     bar = start;
0185     lar = (end - 1) & ~(PMSAv8_MINALIGN - 1);
0186 
0187     bar |= PMSAv8_AP_PL1RW_PL0RW | PMSAv8_RGN_SHARED | PMSAv8_BAR_XN;
0188     lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_DEVICE_nGnRnE) | PMSAv8_LAR_EN;
0189 
0190     return __pmsav8_setup_region(number, bar, lar);
0191 }
0192 
0193 static int __init pmsav8_setup_fixed(unsigned int number, phys_addr_t start,phys_addr_t end)
0194 {
0195     u32 bar, lar;
0196 
0197     if (!is_region_fixed(number))
0198         return -EINVAL;
0199 
0200     bar = start;
0201     lar = (end - 1) & ~(PMSAv8_MINALIGN - 1);
0202 
0203     bar |= PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED;
0204     lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN;
0205 
0206     prsel_write(number);
0207     isb();
0208 
0209     if (prbar_read() != bar || prlar_read() != lar)
0210         return -EINVAL;
0211 
0212     /* Reserved region was set up early, we just need a record for secondaries */
0213     mpu_rgn_info.rgns[number].prbar = bar;
0214     mpu_rgn_info.rgns[number].prlar = lar;
0215 
0216     mpu_rgn_info.used++;
0217 
0218     return 0;
0219 }
0220 
0221 #ifndef CONFIG_CPU_V7M
0222 static int __init pmsav8_setup_vector(unsigned int number, phys_addr_t start,phys_addr_t end)
0223 {
0224     u32 bar, lar;
0225 
0226     if (number == PMSAv8_KERNEL_REGION)
0227         return -EINVAL;
0228 
0229     bar = start;
0230     lar = (end - 1) & ~(PMSAv8_MINALIGN - 1);
0231 
0232     bar |= PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED;
0233     lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN;
0234 
0235     return __pmsav8_setup_region(number, bar, lar);
0236 }
0237 #endif
0238 
0239 void __init pmsav8_setup(void)
0240 {
0241     int i, err = 0;
0242     int region = PMSAv8_KERNEL_REGION;
0243 
0244     /* How many regions are supported ? */
0245     mpu_max_regions = __mpu_max_regions();
0246 
0247     /* RAM: single chunk of memory */
0248     add_range(mem,  ARRAY_SIZE(mem), 0,  memblock.memory.regions[0].base,
0249           memblock.memory.regions[0].base + memblock.memory.regions[0].size);
0250 
0251     /* IO: cover full 4G range */
0252     add_range(io, ARRAY_SIZE(io), 0, 0, 0xffffffff);
0253 
0254     /* RAM and IO: exclude kernel */
0255     subtract_range(mem, ARRAY_SIZE(mem), __pa(KERNEL_START), __pa(KERNEL_END));
0256     subtract_range(io, ARRAY_SIZE(io),  __pa(KERNEL_START), __pa(KERNEL_END));
0257 
0258 #ifdef CONFIG_XIP_KERNEL
0259     /* RAM and IO: exclude xip */
0260     subtract_range(mem, ARRAY_SIZE(mem), CONFIG_XIP_PHYS_ADDR, __pa(_exiprom));
0261     subtract_range(io, ARRAY_SIZE(io), CONFIG_XIP_PHYS_ADDR, __pa(_exiprom));
0262 #endif
0263 
0264 #ifndef CONFIG_CPU_V7M
0265     /* RAM and IO: exclude vectors */
0266     subtract_range(mem, ARRAY_SIZE(mem),  vectors_base, vectors_base + 2 * PAGE_SIZE);
0267     subtract_range(io, ARRAY_SIZE(io),  vectors_base, vectors_base + 2 * PAGE_SIZE);
0268 #endif
0269     /* IO: exclude RAM */
0270     for (i = 0; i < ARRAY_SIZE(mem); i++)
0271         subtract_range(io, ARRAY_SIZE(io), mem[i].start, mem[i].end);
0272 
0273     /* Now program MPU */
0274 
0275 #ifdef CONFIG_XIP_KERNEL
0276     /* ROM */
0277     err |= pmsav8_setup_fixed(PMSAv8_XIP_REGION, CONFIG_XIP_PHYS_ADDR, __pa(_exiprom));
0278 #endif
0279     /* Kernel */
0280     err |= pmsav8_setup_fixed(region++, __pa(KERNEL_START), __pa(KERNEL_END));
0281 
0282 
0283     /* IO */
0284     for (i = 0; i < ARRAY_SIZE(io); i++) {
0285         if (!io[i].end)
0286             continue;
0287 
0288         err |= pmsav8_setup_io(region++, io[i].start, io[i].end);
0289     }
0290 
0291     /* RAM */
0292     for (i = 0; i < ARRAY_SIZE(mem); i++) {
0293         if (!mem[i].end)
0294             continue;
0295 
0296         err |= pmsav8_setup_ram(region++, mem[i].start, mem[i].end);
0297     }
0298 
0299     /* Vectors */
0300 #ifndef CONFIG_CPU_V7M
0301     err |= pmsav8_setup_vector(region++, vectors_base, vectors_base + 2 * PAGE_SIZE);
0302 #endif
0303     if (err)
0304         pr_warn("MPU region initialization failure! %d", err);
0305     else
0306         pr_info("Using ARM PMSAv8 Compliant MPU. Used %d of %d regions\n",
0307             mpu_rgn_info.used, mpu_max_regions);
0308 }