diff options
-rw-r--r-- | arch/arm/cpu/armv7m/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/cpu/armv7m/mpu.c | 82 | ||||
-rw-r--r-- | arch/arm/include/asm/armv7m.h | 20 | ||||
-rw-r--r-- | arch/arm/include/asm/armv7m_mpu.h | 67 |
4 files changed, 150 insertions, 21 deletions
diff --git a/arch/arm/cpu/armv7m/Makefile b/arch/arm/cpu/armv7m/Makefile index 93c9085219..257fc7faf3 100644 --- a/arch/arm/cpu/armv7m/Makefile +++ b/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 diff --git a/arch/arm/cpu/armv7m/mpu.c b/arch/arm/cpu/armv7m/mpu.c new file mode 100644 index 0000000000..31a243b49a --- /dev/null +++ b/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); +} diff --git a/arch/arm/include/asm/armv7m.h b/arch/arm/include/asm/armv7m.h index 9a6224f96e..af8a97e988 100644 --- a/arch/arm/include/asm/armv7m.h +++ b/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 */ diff --git a/arch/arm/include/asm/armv7m_mpu.h b/arch/arm/include/asm/armv7m_mpu.h new file mode 100644 index 0000000000..d7e99b4d8d --- /dev/null +++ b/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); |