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>
lime2-spi
Lokesh Vutla 6 years ago committed by Tom Rini
parent 4bbd6b1d94
commit f2ef204312
  1. 12
      arch/arm/Kconfig
  2. 2
      arch/arm/cpu/armv7/Makefile
  3. 108
      arch/arm/cpu/armv7/mpu_v7r.c
  4. 3
      arch/arm/cpu/armv7m/Makefile
  5. 43
      arch/arm/cpu/armv7m/mpu.c
  6. 130
      arch/arm/include/asm/armv7_mpu.h
  7. 66
      arch/arm/include/asm/armv7m_mpu.h
  8. 2
      arch/arm/mach-stm32/soc.c

@ -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

@ -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

@ -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();
}

@ -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

@ -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);

@ -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 */

@ -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);

@ -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)
{

Loading…
Cancel
Save