瀏覽代碼

armv7m: add MPU configuration support

Cortex-M archs support option memory protection unit (MPU). MPU is used
to set the memory types, attributes, access permissions for different regions,
cache policies of the device.

e.g. using MPU it is possible to configure memory region as device memory
or strongly ordered, memory attributes like execute never, cache policies
like write-back or write-through.

Signed-off-by: Vikas Manocha <vikas.manocha@st.com>
Vikas Manocha 8 年之前
父節點
當前提交
96b61ab15c
共有 4 個文件被更改,包括 150 次插入21 次删除
  1. 1 1
      arch/arm/cpu/armv7m/Makefile
  2. 82 0
      arch/arm/cpu/armv7m/mpu.c
  3. 0 20
      arch/arm/include/asm/armv7m.h
  4. 67 0
      arch/arm/include/asm/armv7m_mpu.h

+ 1 - 1
arch/arm/cpu/armv7m/Makefile

@@ -6,5 +6,5 @@
 #
 
 extra-y := start.o
-obj-y += cpu.o cache.o
+obj-y += cpu.o cache.o mpu.o
 obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o

+ 82 - 0
arch/arm/cpu/armv7m/mpu.c

@@ -0,0 +1,82 @@
+/*
+ * (C) Copyright 2017
+ * Vikas Manocha, ST Micoelectronics, vikas.manocha@st.com.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <linux/bitops.h>
+#include <asm/armv7m.h>
+#include <asm/armv7m_mpu.h>
+#include <asm/io.h>
+
+#define V7M_MPU_CTRL_ENABLE		(1 << 0)
+#define V7M_MPU_CTRL_DISABLE		(0 << 0)
+#define V7M_MPU_CTRL_HFNMIENA		(1 << 1)
+#define VALID_REGION			(1 << 4)
+
+#define ENABLE_REGION			(1 << 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);
+}
+
+void enable_mpu(void)
+{
+	writel(V7M_MPU_CTRL_ENABLE | V7M_MPU_CTRL_HFNMIENA, &V7M_MPU->ctrl);
+
+	/* Make sure new mpu config is effective for next memory access */
+	dsb();
+	isb();	/* Make sure instruction stream sees it */
+}
+
+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;
+	default:
+		attr = 0; /* strongly ordered */
+		break;
+	};
+
+	writel(reg_config->start_addr | VALID_REGION | reg_config->region_no,
+	       &V7M_MPU->rbar);
+
+	writel(reg_config->xn << XN_SHIFT | reg_config->ap << AP_SHIFT | attr
+		| reg_config->reg_size << REGION_SIZE_SHIFT | ENABLE_REGION
+	       , &V7M_MPU->rasr);
+}

+ 0 - 20
arch/arm/include/asm/armv7m.h

@@ -70,25 +70,5 @@ struct v7m_mpu {
 };
 #define V7M_MPU				((struct v7m_mpu *)V7M_MPU_BASE)
 
-#define V7M_MPU_CTRL_ENABLE		(1 << 0)
-#define V7M_MPU_CTRL_HFNMIENA		(1 << 1)
-
-#define V7M_MPU_CTRL_ENABLE		(1 << 0)
-#define V7M_MPU_CTRL_DISABLE		(0 << 0)
-#define V7M_MPU_CTRL_HFNMIENA		(1 << 1)
-
-#define V7M_MPU_RASR_EN			(1 << 0)
-#define V7M_MPU_RASR_SIZE_BITS		1
-#define V7M_MPU_RASR_SIZE_4GB		(31 << V7M_MPU_RASR_SIZE_BITS)
-#define V7M_MPU_RASR_SIZE_8MB		(22 << V7M_MPU_RASR_SIZE_BITS)
-
-#define V7M_MPU_RASR_TEX_SHIFT	19
-#define V7M_MPU_RASR_S_SHIFT		18
-#define V7M_MPU_RASR_C_SHIFT		17
-#define V7M_MPU_RASR_B_SHIFT		16
-#define V7M_MPU_RASR_AP_RW_RW		(3 << 24)
-#define V7M_MPU_RASR_XN_ENABLE	(0 << 28)
-#define V7M_MPU_RASR_XN_DISABLE (1 << 28)
-
 #endif /* !defined(__ASSEMBLY__) */
 #endif /* ARMV7M_H */

+ 67 - 0
arch/arm/include/asm/armv7m_mpu.h

@@ -0,0 +1,67 @@
+/*
+ * (C) Copyright 2017
+ * Vikas Manocha, ST Micoelectronics, vikas.manocha@st.com.
+ *
+ * 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);