[U-Boot] [PATCH v2 6/7] arm: v7R: Add support for MPU

Lokesh Vutla lokeshvutla at ti.com
Thu Apr 26 12:51:30 UTC 2018


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 at xilinx.com>
Signed-off-by: Lokesh Vutla <lokeshvutla at 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 <lokeshvutla at 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.manocha at 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.manocha at 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



More information about the U-Boot mailing list