arm: v7R: Add support for MPU
authorLokesh Vutla <lokeshvutla@ti.com>
Thu, 26 Apr 2018 12:51:30 +0000 (18:21 +0530)
committerTom Rini <trini@konsulko.com>
Mon, 7 May 2018 19:53:29 +0000 (15:53 -0400)
The Memory Protection Unit(MPU) allows to partition memory into regions
and set individual protection attributes for each region. In absence
of MPU a default map[1] will take effect. Add support for configuring
MPU on Cortex-R, by reusing the existing support for Cortex-M processor.

[1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0460d/I1002400.html

Tested-by: Michal Simek <michal.simek@xilinx.com>
Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
arch/arm/Kconfig
arch/arm/cpu/armv7/Makefile
arch/arm/cpu/armv7/mpu_v7r.c [new file with mode: 0644]
arch/arm/cpu/armv7m/Makefile
arch/arm/cpu/armv7m/mpu.c
arch/arm/include/asm/armv7_mpu.h [new file with mode: 0644]
arch/arm/include/asm/armv7m_mpu.h [deleted file]
arch/arm/mach-stm32/soc.c

index f056e03c3f23f3bd7df62495930d126c0eb76b47..2bbb86c462dd50e58f40eaa665b70105737a0ff4 100644 (file)
@@ -87,6 +87,15 @@ config SYS_ARM_MMU
          Select if you want MMU-based virtualised addressing space
          support by paged memory management.
 
+config SYS_ARM_MPU
+       bool 'Use the ARM v7 PMSA Compliant MPU'
+       help
+         Some ARM systems without an MMU have instead a Memory Protection
+         Unit (MPU) that defines the type and permissions for regions of
+         memory.
+         If your CPU has an MPU then you should choose 'y' here unless you
+         know that you do not want to use the MPU.
+
 # If set, the workarounds for these ARM errata are applied early during U-Boot
 # startup. Note that in general these options force the workarounds to be
 # applied; no CPU-type/version detection exists, unlike the similar options in
@@ -211,11 +220,14 @@ config CPU_V7M
        select HAS_THUMB2
        select THUMB2_KERNEL
        select SYS_CACHE_SHIFT_5
+       select SYS_ARM_MPU
 
 config CPU_V7R
        bool
        select HAS_THUMB2
        select SYS_CACHE_SHIFT_6
+       select SYS_ARM_MPU
+       select SYS_ARM_CACHE_CP15
 
 config CPU_PXA
        bool
index 97065c3a5f5bf323fefd486f3865fc8f1cc8c906..26056647df01f1db645bb9ee67c453df43b57dcc 100644 (file)
@@ -10,6 +10,8 @@ obj-y += cache_v7.o cache_v7_asm.o
 obj-y  += cpu.o cp15.o
 obj-y  += syslib.o
 
+obj-$(CONFIG_SYS_ARM_MPU) += mpu_v7r.o
+
 ifneq ($(CONFIG_SKIP_LOWLEVEL_INIT),y)
 obj-y  += lowlevel_init.o
 endif
diff --git a/arch/arm/cpu/armv7/mpu_v7r.c b/arch/arm/cpu/armv7/mpu_v7r.c
new file mode 100644 (file)
index 0000000..567d913
--- /dev/null
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Cortex-R Memory Protection Unit specific code
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *     Lokesh Vutla <lokeshvutla@ti.com>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/armv7.h>
+#include <asm/system.h>
+#include <asm/barriers.h>
+#include <linux/compiler.h>
+
+#include <asm/armv7_mpu.h>
+
+/* MPU Type register definitions */
+#define MPUIR_S_SHIFT          0
+#define MPUIR_S_MASK           BIT(MPUIR_S_SHIFT)
+#define MPUIR_DREGION_SHIFT    8
+#define MPUIR_DREGION_MASK     (0xff << 8)
+
+/**
+ * Note:
+ * The Memory Protection Unit(MPU) allows to partition memory into regions
+ * and set individual protection attributes for each region. In absence
+ * of MPU a default map[1] will take effect. make sure to run this code
+ * from a region which has execution permissions by default.
+ * [1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0460d/I1002400.html
+ */
+
+void disable_mpu(void)
+{
+       u32 reg;
+
+       reg = get_cr();
+       reg &= ~CR_M;
+       dsb();
+       set_cr(reg);
+       isb();
+}
+
+void enable_mpu(void)
+{
+       u32 reg;
+
+       reg = get_cr();
+       reg |= CR_M;
+       dsb();
+       set_cr(reg);
+       isb();
+}
+
+int mpu_enabled(void)
+{
+       return get_cr() & CR_M;
+}
+
+void mpu_config(struct mpu_region_config *rgn)
+{
+       u32 attr, val;
+
+       attr = get_attr_encoding(rgn->mr_attr);
+
+       /* MPU Region Number Register */
+       asm volatile ("mcr p15, 0, %0, c6, c2, 0" : : "r" (rgn->region_no));
+
+       /* MPU Region Base Address Register */
+       asm volatile ("mcr p15, 0, %0, c6, c1, 0" : : "r" (rgn->start_addr));
+
+       /* MPU Region Size and Enable Register */
+       if (rgn->reg_size)
+               val = (rgn->reg_size << REGION_SIZE_SHIFT) | ENABLE_REGION;
+       else
+               val = DISABLE_REGION;
+       asm volatile ("mcr p15, 0, %0, c6, c1, 2" : : "r" (val));
+
+       /* MPU Region Access Control Register */
+       val = rgn->xn << XN_SHIFT | rgn->ap << AP_SHIFT | attr;
+       asm volatile ("mcr p15, 0, %0, c6, c1, 4" : : "r" (val));
+}
+
+void setup_mpu_regions(struct mpu_region_config *rgns, u32 num_rgns)
+{
+       u32 num, i;
+
+       asm volatile ("mrc p15, 0, %0, c0, c0, 4" : "=r" (num));
+       num = (num & MPUIR_DREGION_MASK) >> MPUIR_DREGION_SHIFT;
+       /* Regions to be configured cannot be greater than available regions */
+       if (num < num_rgns)
+               num_rgns = num;
+       /**
+        * Assuming dcache might not be enabled at this point, disabling
+        * and invalidating only icache.
+        */
+       icache_disable();
+       invalidate_icache_all();
+
+       disable_mpu();
+
+       for (i = 0; i < num_rgns; i++)
+               mpu_config(&rgns[i]);
+
+       enable_mpu();
+
+       icache_enable();
+}
index 6c78d29ac494599e222f86c3e7823bdfdde60d07..baeac9343d9bdc9ce86585c6cb04c871811142fd 100644 (file)
@@ -4,5 +4,6 @@
 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 
 extra-y := start.o
-obj-y += cpu.o cache.o mpu.o
+obj-y += cpu.o cache.o
+obj-$(CONFIG_SYS_ARM_MPU) += mpu.o
 obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o
index d89d9f2f399575212a64db61d3d0c88d35892d52..81e7492f1c866e908bb0bf05e9dfedb87ef35f4f 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <linux/bitops.h>
 #include <asm/armv7m.h>
-#include <asm/armv7m_mpu.h>
+#include <asm/armv7_mpu.h>
 #include <asm/io.h>
 
 #define V7M_MPU_CTRL_ENABLE            BIT(0)
 #define V7M_MPU_CTRL_PRIVDEFENA                BIT(2)
 #define VALID_REGION                   BIT(4)
 
-#define ENABLE_REGION                  BIT(0)
-
-#define AP_SHIFT                       24
-#define XN_SHIFT                       28
-#define TEX_SHIFT                      19
-#define S_SHIFT                                18
-#define C_SHIFT                                17
-#define B_SHIFT                                16
-#define REGION_SIZE_SHIFT              1
-
-#define CACHEABLE                      (1 << C_SHIFT)
-#define BUFFERABLE                     (1 << B_SHIFT)
-#define SHAREABLE                      (1 << S_SHIFT)
-
 void disable_mpu(void)
 {
        writel(0, &V7M_MPU->ctrl);
@@ -47,32 +33,7 @@ void mpu_config(struct mpu_region_config *reg_config)
 {
        uint32_t attr;
 
-       switch (reg_config->mr_attr) {
-       case STRONG_ORDER:
-               attr = SHAREABLE;
-               break;
-       case SHARED_WRITE_BUFFERED:
-               attr = BUFFERABLE;
-               break;
-       case O_I_WT_NO_WR_ALLOC:
-               attr = CACHEABLE;
-               break;
-       case O_I_WB_NO_WR_ALLOC:
-               attr = CACHEABLE | BUFFERABLE;
-               break;
-       case O_I_NON_CACHEABLE:
-               attr = 1 << TEX_SHIFT;
-               break;
-       case O_I_WB_RD_WR_ALLOC:
-               attr = (1 << TEX_SHIFT) | CACHEABLE | BUFFERABLE;
-               break;
-       case DEVICE_NON_SHARED:
-               attr = (2 << TEX_SHIFT) | BUFFERABLE;
-               break;
-       default:
-               attr = 0; /* strongly ordered */
-               break;
-       };
+       attr = get_attr_encoding(reg_config->mr_attr);
 
        writel(reg_config->start_addr | VALID_REGION | reg_config->region_no,
               &V7M_MPU->rbar);
diff --git a/arch/arm/include/asm/armv7_mpu.h b/arch/arm/include/asm/armv7_mpu.h
new file mode 100644 (file)
index 0000000..8f77ec4
--- /dev/null
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics.
+ */
+
+#ifndef _ASM_ARMV7_MPU_H
+#define _ASM_ARMV7_MPU_H
+
+#ifdef CONFIG_CPU_V7M
+#define AP_SHIFT                       24
+#define XN_SHIFT                       28
+#define TEX_SHIFT                      19
+#define S_SHIFT                                18
+#define C_SHIFT                                17
+#define B_SHIFT                                16
+#else /* CONFIG_CPU_V7R */
+#define XN_SHIFT                       12
+#define AP_SHIFT                       8
+#define TEX_SHIFT                      3
+#define S_SHIFT                                2
+#define C_SHIFT                                1
+#define B_SHIFT                                0
+#endif /* CONFIG_CPU_V7R */
+
+#define CACHEABLE                      BIT(C_SHIFT)
+#define BUFFERABLE                     BIT(B_SHIFT)
+#define SHAREABLE                      BIT(S_SHIFT)
+#define REGION_SIZE_SHIFT              1
+#define ENABLE_REGION                  BIT(0)
+#define DISABLE_REGION                 0
+
+enum region_number {
+       REGION_0 = 0,
+       REGION_1,
+       REGION_2,
+       REGION_3,
+       REGION_4,
+       REGION_5,
+       REGION_6,
+       REGION_7,
+};
+
+enum ap {
+       NO_ACCESS = 0,
+       PRIV_RW_USR_NO,
+       PRIV_RW_USR_RO,
+       PRIV_RW_USR_RW,
+       UNPREDICTABLE,
+       PRIV_RO_USR_NO,
+       PRIV_RO_USR_RO,
+};
+
+enum mr_attr {
+       STRONG_ORDER = 0,
+       SHARED_WRITE_BUFFERED,
+       O_I_WT_NO_WR_ALLOC,
+       O_I_WB_NO_WR_ALLOC,
+       O_I_NON_CACHEABLE,
+       O_I_WB_RD_WR_ALLOC,
+       DEVICE_NON_SHARED,
+};
+enum size {
+       REGION_8MB = 22,
+       REGION_16MB,
+       REGION_32MB,
+       REGION_64MB,
+       REGION_128MB,
+       REGION_256MB,
+       REGION_512MB,
+       REGION_1GB,
+       REGION_2GB,
+       REGION_4GB,
+};
+
+enum xn {
+       XN_DIS = 0,
+       XN_EN,
+};
+
+struct mpu_region_config {
+       uint32_t start_addr;
+       enum region_number region_no;
+       enum xn xn;
+       enum ap ap;
+       enum mr_attr mr_attr;
+       enum size reg_size;
+};
+
+void disable_mpu(void);
+void enable_mpu(void);
+int mpu_enabled(void);
+void mpu_config(struct mpu_region_config *reg_config);
+void setup_mpu_regions(struct mpu_region_config *rgns, u32 num_rgns);
+
+static inline u32 get_attr_encoding(u32 mr_attr)
+{
+       u32 attr;
+
+       switch (mr_attr) {
+       case STRONG_ORDER:
+               attr = SHAREABLE;
+               break;
+       case SHARED_WRITE_BUFFERED:
+               attr = BUFFERABLE;
+               break;
+       case O_I_WT_NO_WR_ALLOC:
+               attr = CACHEABLE;
+               break;
+       case O_I_WB_NO_WR_ALLOC:
+               attr = CACHEABLE | BUFFERABLE;
+               break;
+       case O_I_NON_CACHEABLE:
+               attr = 1 << TEX_SHIFT;
+               break;
+       case O_I_WB_RD_WR_ALLOC:
+               attr = (1 << TEX_SHIFT) | CACHEABLE | BUFFERABLE;
+               break;
+       case DEVICE_NON_SHARED:
+               attr = (2 << TEX_SHIFT) | BUFFERABLE;
+               break;
+       default:
+               attr = 0; /* strongly ordered */
+               break;
+       };
+
+       return attr;
+}
+
+#endif /* _ASM_ARMV7_MPU_H */
diff --git a/arch/arm/include/asm/armv7m_mpu.h b/arch/arm/include/asm/armv7m_mpu.h
deleted file mode 100644 (file)
index 51d482a..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
- * Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics.
- */
-
-enum region_number {
-       REGION_0 = 0,
-       REGION_1,
-       REGION_2,
-       REGION_3,
-       REGION_4,
-       REGION_5,
-       REGION_6,
-       REGION_7,
-};
-
-enum ap {
-       NO_ACCESS = 0,
-       PRIV_RW_USR_NO,
-       PRIV_RW_USR_RO,
-       PRIV_RW_USR_RW,
-       UNPREDICTABLE,
-       PRIV_RO_USR_NO,
-       PRIV_RO_USR_RO,
-};
-
-enum mr_attr {
-       STRONG_ORDER = 0,
-       SHARED_WRITE_BUFFERED,
-       O_I_WT_NO_WR_ALLOC,
-       O_I_WB_NO_WR_ALLOC,
-       O_I_NON_CACHEABLE,
-       O_I_WB_RD_WR_ALLOC,
-       DEVICE_NON_SHARED,
-};
-enum size {
-       REGION_8MB = 22,
-       REGION_16MB,
-       REGION_32MB,
-       REGION_64MB,
-       REGION_128MB,
-       REGION_256MB,
-       REGION_512MB,
-       REGION_1GB,
-       REGION_2GB,
-       REGION_4GB,
-};
-
-enum xn {
-       XN_DIS = 0,
-       XN_EN,
-};
-
-struct mpu_region_config {
-       uint32_t start_addr;
-       enum region_number region_no;
-       enum xn xn;
-       enum ap ap;
-       enum mr_attr mr_attr;
-       enum size reg_size;
-};
-
-void disable_mpu(void);
-void enable_mpu(void);
-void mpu_config(struct mpu_region_config *reg_config);
index 02592684b946f8f722fabec428429baae7e5c06a..2b528545306fa403021fdf6dc368f8827f371eeb 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <common.h>
 #include <asm/io.h>
-#include <asm/armv7m_mpu.h>
+#include <asm/armv7_mpu.h>
 
 int arch_cpu_init(void)
 {