ARM: 8711/1: V7M: Add support for MPU to M-class
[sfrench/cifs-2.6.git] / arch / arm / kernel / head-nommu.S
index 2e21e08de7478b5e19f1aee89521356e52d8c041..0d64b8ba7e9c8489d2ad1b7aeacb34f57fd1a8a3 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <linux/linkage.h>
 #include <linux/init.h>
+#include <linux/errno.h>
 
 #include <asm/assembler.h>
 #include <asm/ptrace.h>
@@ -110,8 +111,8 @@ ENTRY(secondary_startup)
 
 #ifdef CONFIG_ARM_MPU
        /* Use MPU region info supplied by __cpu_up */
-       ldr     r6, [r7]                        @ get secondary_data.mpu_szr
-       bl      __setup_mpu                     @ Initialize the MPU
+       ldr     r6, [r7]                        @ get secondary_data.mpu_rgn_info
+       bl      __secondary_setup_mpu           @ Initialize the MPU
 #endif
 
        badr    lr, 1f                          @ return (PIC) address
@@ -175,19 +176,33 @@ ENDPROC(__after_proc_init)
 #ifdef CONFIG_ARM_MPU
 
 
+#ifndef CONFIG_CPU_V7M
 /* Set which MPU region should be programmed */
-.macro set_region_nr tmp, rgnr
+.macro set_region_nr tmp, rgnr, unused
        mov     \tmp, \rgnr                     @ Use static region numbers
        mcr     p15, 0, \tmp, c6, c2, 0         @ Write RGNR
 .endm
 
 /* Setup a single MPU region, either D or I side (D-side for unified) */
-.macro setup_region bar, acr, sr, side = MPU_DATA_SIDE
+.macro setup_region bar, acr, sr, side = MPU_DATA_SIDE, unused
        mcr     p15, 0, \bar, c6, c1, (0 + \side)       @ I/DRBAR
        mcr     p15, 0, \acr, c6, c1, (4 + \side)       @ I/DRACR
        mcr     p15, 0, \sr, c6, c1, (2 + \side)                @ I/DRSR
 .endm
+#else
+.macro set_region_nr tmp, rgnr, base
+       mov     \tmp, \rgnr
+       str     \tmp, [\base, #MPU_RNR]
+.endm
 
+.macro setup_region bar, acr, sr, unused, base
+       lsl     \acr, \acr, #16
+       orr     \acr, \acr, \sr
+       str     \bar, [\base, #MPU_RBAR]
+       str     \acr, [\base, #MPU_RASR]
+.endm
+
+#endif
 /*
  * Setup the MPU and initial MPU Regions. We create the following regions:
  * Region 0: Use this for probing the MPU details, so leave disabled.
@@ -201,64 +216,117 @@ ENDPROC(__after_proc_init)
 ENTRY(__setup_mpu)
 
        /* Probe for v7 PMSA compliance */
-       mrc     p15, 0, r0, c0, c1, 4           @ Read ID_MMFR0
+M_CLASS(movw   r12, #:lower16:BASEADDR_V7M_SCB)
+M_CLASS(movt   r12, #:upper16:BASEADDR_V7M_SCB)
+
+AR_CLASS(mrc   p15, 0, r0, c0, c1, 4)          @ Read ID_MMFR0
+M_CLASS(ldr    r0, [r12, 0x50])
        and     r0, r0, #(MMFR0_PMSA)           @ PMSA field
        teq     r0, #(MMFR0_PMSAv7)             @ PMSA v7
-       bne     __error_p                       @ Fail: ARM_MPU on NOT v7 PMSA
+       bxne    lr
 
        /* Determine whether the D/I-side memory map is unified. We set the
         * flags here and continue to use them for the rest of this function */
-       mrc     p15, 0, r0, c0, c0, 4           @ MPUIR
+AR_CLASS(mrc   p15, 0, r0, c0, c0, 4)          @ MPUIR
+M_CLASS(ldr    r0, [r12, #MPU_TYPE])
        ands    r5, r0, #MPUIR_DREGION_SZMASK   @ 0 size d region => No MPU
-       beq     __error_p                       @ Fail: ARM_MPU and no MPU
+       bxeq    lr
        tst     r0, #MPUIR_nU                   @ MPUIR_nU = 0 for unified
 
        /* Setup second region first to free up r6 */
-       set_region_nr r0, #MPU_RAM_REGION
+       set_region_nr r0, #MPU_RAM_REGION, r12
        isb
        /* Full access from PL0, PL1, shared for CONFIG_SMP, cacheable */
        ldr     r0, =PLAT_PHYS_OFFSET           @ RAM starts at PHYS_OFFSET
        ldr     r5,=(MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL)
 
-       setup_region r0, r5, r6, MPU_DATA_SIDE  @ PHYS_OFFSET, shared, enabled
-       beq     1f                              @ Memory-map not unified
-       setup_region r0, r5, r6, MPU_INSTR_SIDE @ PHYS_OFFSET, shared, enabled
+       setup_region r0, r5, r6, MPU_DATA_SIDE, r12     @ PHYS_OFFSET, shared, enabled
+       beq     1f                                      @ Memory-map not unified
+       setup_region r0, r5, r6, MPU_INSTR_SIDE, r12    @ PHYS_OFFSET, shared, enabled
 1:     isb
 
        /* First/background region */
-       set_region_nr r0, #MPU_BG_REGION
+       set_region_nr r0, #MPU_BG_REGION, r12
        isb
        /* Execute Never,  strongly ordered, inaccessible to PL0, rw PL1  */
        mov     r0, #0                          @ BG region starts at 0x0
        ldr     r5,=(MPU_ACR_XN | MPU_RGN_STRONGLY_ORDERED | MPU_AP_PL1RW_PL0NA)
        mov     r6, #MPU_RSR_ALL_MEM            @ 4GB region, enabled
 
-       setup_region r0, r5, r6, MPU_DATA_SIDE  @ 0x0, BG region, enabled
-       beq     2f                              @ Memory-map not unified
-       setup_region r0, r5, r6, MPU_INSTR_SIDE @ 0x0, BG region, enabled
+       setup_region r0, r5, r6, MPU_DATA_SIDE, r12     @ 0x0, BG region, enabled
+       beq     2f                                      @ Memory-map not unified
+       setup_region r0, r5, r6, MPU_INSTR_SIDE r12     @ 0x0, BG region, enabled
 2:     isb
 
-       /* Vectors region */
-       set_region_nr r0, #MPU_VECTORS_REGION
+       /* Enable the MPU */
+AR_CLASS(mrc   p15, 0, r0, c1, c0, 0)          @ Read SCTLR
+AR_CLASS(bic   r0, r0, #CR_BR)                 @ Disable the 'default mem-map'
+AR_CLASS(orr   r0, r0, #CR_M)                  @ Set SCTRL.M (MPU on)
+AR_CLASS(mcr   p15, 0, r0, c1, c0, 0)          @ Enable MPU
+
+M_CLASS(ldr    r0, [r12, #MPU_CTRL])
+M_CLASS(bic    r0, #MPU_CTRL_PRIVDEFENA)
+M_CLASS(orr    r0, #MPU_CTRL_ENABLE)
+M_CLASS(str    r0, [r12, #MPU_CTRL])
+       isb
+
+       ret     lr
+ENDPROC(__setup_mpu)
+
+#ifdef CONFIG_SMP
+/*
+ * r6: pointer at mpu_rgn_info
+ */
+
+ENTRY(__secondary_setup_mpu)
+       /* Probe for v7 PMSA compliance */
+       mrc     p15, 0, r0, c0, c1, 4           @ Read ID_MMFR0
+       and     r0, r0, #(MMFR0_PMSA)           @ PMSA field
+       teq     r0, #(MMFR0_PMSAv7)             @ PMSA v7
+       bne     __error_p
+
+       /* Determine whether the D/I-side memory map is unified. We set the
+        * flags here and continue to use them for the rest of this function */
+       mrc     p15, 0, r0, c0, c0, 4           @ MPUIR
+       ands    r5, r0, #MPUIR_DREGION_SZMASK   @ 0 size d region => No MPU
+       beq     __error_p
+
+       ldr     r4, [r6, #MPU_RNG_INFO_USED]
+       mov     r5, #MPU_RNG_SIZE
+       add     r3, r6, #MPU_RNG_INFO_RNGS
+       mla     r3, r4, r5, r3
+
+1:
+       tst     r0, #MPUIR_nU                   @ MPUIR_nU = 0 for unified
+       sub     r3, r3, #MPU_RNG_SIZE
+       sub     r4, r4, #1
+
+       set_region_nr r0, r4
        isb
-       /* Shared, inaccessible to PL0, rw PL1 */
-       mov     r0, #CONFIG_VECTORS_BASE        @ Cover from VECTORS_BASE
-       ldr     r5,=(MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL)
-       /* Writing N to bits 5:1 (RSR_SZ) --> region size 2^N+1 */
-       mov     r6, #(((2 * PAGE_SHIFT - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN)
 
-       setup_region r0, r5, r6, MPU_DATA_SIDE  @ VECTORS_BASE, PL0 NA, enabled
-       beq     3f                              @ Memory-map not unified
-       setup_region r0, r5, r6, MPU_INSTR_SIDE @ VECTORS_BASE, PL0 NA, enabled
-3:     isb
+       ldr     r0, [r3, #MPU_RGN_DRBAR]
+       ldr     r6, [r3, #MPU_RGN_DRSR]
+       ldr     r5, [r3, #MPU_RGN_DRACR]
+
+       setup_region r0, r5, r6, MPU_DATA_SIDE
+       beq     2f
+       setup_region r0, r5, r6, MPU_INSTR_SIDE
+2:     isb
+
+       mrc     p15, 0, r0, c0, c0, 4           @ Reevaluate the MPUIR
+       cmp     r4, #0
+       bgt     1b
 
        /* Enable the MPU */
        mrc     p15, 0, r0, c1, c0, 0           @ Read SCTLR
-       bic     r0, r0, #CR_BR                  @ Disable the 'default mem-map'
+       bic     r0, r0, #CR_BR                  @ Disable the 'default mem-map'
        orr     r0, r0, #CR_M                   @ Set SCTRL.M (MPU on)
        mcr     p15, 0, r0, c1, c0, 0           @ Enable MPU
        isb
+
        ret     lr
-ENDPROC(__setup_mpu)
-#endif
+ENDPROC(__secondary_setup_mpu)
+
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_ARM_MPU */
 #include "head-common.S"