[U-Boot] [RFC PATCH 4/5] arm: v7R: Add support for MPU

Lokesh Vutla lokeshvutla at ti.com
Tue Apr 24 12:54:47 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

Signed-off-by: Lokesh Vutla <lokeshvutla at ti.com>
---
 arch/arm/Kconfig                  |  11 +++
 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         |  41 +----------
 arch/arm/include/asm/armv7m_mpu.h |  69 +++++++++++++++++++
 6 files changed, 194 insertions(+), 41 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/mpu_v7r.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index fe5bff097d..2bbfb08578 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -80,6 +80,15 @@ config MMU
 	  Select if you want MMU-based virtualised addressing space
 	  support by paged memory management.
 
+config 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
@@ -204,11 +213,13 @@ config CPU_V7M
 	select HAS_THUMB2
 	select THUMB2_KERNEL
 	select SYS_CACHE_SHIFT_5
+	select ARM_MPU
 
 config CPU_V7R
 	bool
         select HAS_THUMB2
 	select SYS_CACHE_SHIFT_6
+	select ARM_MPU
 
 config CPU_PXA
 	bool
diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile
index b14ee54519..1c8a5ca868 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_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..703f744b31
--- /dev/null
+++ b/arch/arm/cpu/armv7/mpu_v7r.c
@@ -0,0 +1,109 @@
+/*
+ * Cortex-R Memory Protection Unit specific code
+ *
+ * Copyright (C) 2017 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/armv7m_mpu.h>
+
+/* MPU Type register definitions */
+#define MPUIR_S_SHIFT		0
+#define MPUIR_S_MASK		(1 << 0)
+#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)
+{
+	uint32_t reg;
+
+	reg = get_cr();
+	reg &= ~CR_M;
+	dsb();
+	set_cr(reg);
+	isb();
+}
+
+void enable_mpu(void)
+{
+	uint32_t 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)
+{
+	uint32_t 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..3096fa34d3 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_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..08c02a2d5a 100644
--- a/arch/arm/cpu/armv7m/mpu.c
+++ b/arch/arm/cpu/armv7m/mpu.c
@@ -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/armv7m_mpu.h b/arch/arm/include/asm/armv7m_mpu.h
index 0f73cf1dc0..2f08c641cb 100644
--- a/arch/arm/include/asm/armv7m_mpu.h
+++ b/arch/arm/include/asm/armv7m_mpu.h
@@ -5,6 +5,37 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
+#ifndef _ASM_ARMV7M_MPU_H
+#define _ASM_ARMV7M_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
+
+#endif /* CONFIG_CPU_V7M */
+
+#ifdef 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			(1 << C_SHIFT)
+#define BUFFERABLE			(1 << B_SHIFT)
+#define SHAREABLE			(1 << S_SHIFT)
+#define REGION_SIZE_SHIFT		1
+#define ENABLE_REGION			BIT(0)
+#define DISABLE_REGION			0
+
 enum region_number {
 	REGION_0 = 0,
 	REGION_1,
@@ -64,4 +95,42 @@ struct mpu_region_config {
 
 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 uint32_t get_attr_encoding(uint32_t mr_attr)
+{
+	uint32_t 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_ARMV7M_MPU_H */
-- 
2.17.0



More information about the U-Boot mailing list