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.si...@xilinx.com>
Signed-off-by: Lokesh Vutla <lokeshvu...@ti.com>
---
 arch/arm/Kconfig                  |  12 +++
 arch/arm/cpu/armv7/Makefile       |   2 +
 arch/arm/cpu/armv7/mpu_v7r.c      | 109 +++++++++++++++++++++++++
 arch/arm/cpu/armv7m/Makefile      |   3 +-
 arch/arm/cpu/armv7m/mpu.c         |  43 +---------
 arch/arm/include/asm/armv7_mpu.h  | 131 ++++++++++++++++++++++++++++++
 arch/arm/include/asm/armv7m_mpu.h |  67 ---------------
 arch/arm/mach-stm32/soc.c         |   2 +-
 8 files changed, 259 insertions(+), 110 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/mpu_v7r.c
 create mode 100644 arch/arm/include/asm/armv7_mpu.h
 delete mode 100644 arch/arm/include/asm/armv7m_mpu.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index fcdbded22a..99fb11435b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -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
diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile
index b14ee54519..d085b3be93 100644
--- a/arch/arm/cpu/armv7/Makefile
+++ b/arch/arm/cpu/armv7/Makefile
@@ -12,6 +12,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
index 0000000000..1576511ec5
--- /dev/null
+++ b/arch/arm/cpu/armv7/mpu_v7r.c
@@ -0,0 +1,109 @@
+/*
+ * Cortex-R Memory Protection Unit specific code
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *     Lokesh Vutla <lokeshvu...@ti.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#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();
+}
diff --git a/arch/arm/cpu/armv7m/Makefile b/arch/arm/cpu/armv7m/Makefile
index 257fc7faf3..c1742cb967 100644
--- a/arch/arm/cpu/armv7m/Makefile
+++ b/arch/arm/cpu/armv7m/Makefile
@@ -6,5 +6,6 @@
 #
 
 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
diff --git a/arch/arm/cpu/armv7m/mpu.c b/arch/arm/cpu/armv7m/mpu.c
index e4d090e5de..6c419e07f5 100644
--- a/arch/arm/cpu/armv7m/mpu.c
+++ b/arch/arm/cpu/armv7m/mpu.c
@@ -7,7 +7,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)
@@ -16,20 +16,6 @@
 #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);
@@ -48,32 +34,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
index 0000000000..72d576d823
--- /dev/null
+++ b/arch/arm/include/asm/armv7_mpu.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Author(s): Vikas Manocha, <vikas.mano...@st.com> for STMicroelectronics.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#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
index 0f73cf1dc0..0000000000
--- a/arch/arm/include/asm/armv7m_mpu.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
- * Author(s): Vikas Manocha, <vikas.mano...@st.com> for STMicroelectronics.
- *
- * SPDX-License-Identifier:    GPL-2.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);
-void mpu_config(struct mpu_region_config *reg_config);
diff --git a/arch/arm/mach-stm32/soc.c b/arch/arm/mach-stm32/soc.c
index f6fd0b2e23..f4c5bb16ff 100644
--- a/arch/arm/mach-stm32/soc.c
+++ b/arch/arm/mach-stm32/soc.c
@@ -7,7 +7,7 @@
 
 #include <common.h>
 #include <asm/io.h>
-#include <asm/armv7m_mpu.h>
+#include <asm/armv7_mpu.h>
 
 int arch_cpu_init(void)
 {
-- 
2.17.0

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to