summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLokesh Vutla <lokeshvutla@ti.com>2018-04-26 18:21:30 +0530
committerTom Rini <trini@konsulko.com>2018-05-07 15:53:29 -0400
commitf2ef204312480bfba7700f47c8ce9fb975c26557 (patch)
tree3fd338e772be2cbec3c1a6b4a847d7d6ae673eae
parent4bbd6b1d946ab6165bff8aeae6f252faa07ce85a (diff)
arm: v7R: Add support for MPU
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>
-rw-r--r--arch/arm/Kconfig12
-rw-r--r--arch/arm/cpu/armv7/Makefile2
-rw-r--r--arch/arm/cpu/armv7/mpu_v7r.c108
-rw-r--r--arch/arm/cpu/armv7m/Makefile3
-rw-r--r--arch/arm/cpu/armv7m/mpu.c43
-rw-r--r--arch/arm/include/asm/armv7_mpu.h130
-rw-r--r--arch/arm/include/asm/armv7m_mpu.h66
-rw-r--r--arch/arm/mach-stm32/soc.c2
8 files changed, 257 insertions, 109 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index f056e03c3f..2bbb86c462 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 97065c3a5f..26056647df 100644
--- a/arch/arm/cpu/armv7/Makefile
+++ b/arch/arm/cpu/armv7/Makefile
@@ -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
index 0000000000..567d913414
--- /dev/null
+++ b/arch/arm/cpu/armv7/mpu_v7r.c
@@ -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();
+}
diff --git a/arch/arm/cpu/armv7m/Makefile b/arch/arm/cpu/armv7m/Makefile
index 6c78d29ac4..baeac9343d 100644
--- a/arch/arm/cpu/armv7m/Makefile
+++ b/arch/arm/cpu/armv7m/Makefile
@@ -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
diff --git a/arch/arm/cpu/armv7m/mpu.c b/arch/arm/cpu/armv7m/mpu.c
index d89d9f2f39..81e7492f1c 100644
--- a/arch/arm/cpu/armv7m/mpu.c
+++ b/arch/arm/cpu/armv7m/mpu.c
@@ -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)
@@ -15,20 +15,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);
@@ -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
index 0000000000..8f77ec42a6
--- /dev/null
+++ b/arch/arm/include/asm/armv7_mpu.h
@@ -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
index 51d482a5cd..0000000000
--- a/arch/arm/include/asm/armv7m_mpu.h
+++ /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);
diff --git a/arch/arm/mach-stm32/soc.c b/arch/arm/mach-stm32/soc.c
index 02592684b9..2b52854530 100644
--- a/arch/arm/mach-stm32/soc.c
+++ b/arch/arm/mach-stm32/soc.c
@@ -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)
{