xref: /openbmc/u-boot/arch/arm/cpu/armv7/mpu_v7r.c (revision e8f80a5a)
1f2ef2043SLokesh Vutla // SPDX-License-Identifier: GPL-2.0+
2f2ef2043SLokesh Vutla /*
3f2ef2043SLokesh Vutla  * Cortex-R Memory Protection Unit specific code
4f2ef2043SLokesh Vutla  *
5f2ef2043SLokesh Vutla  * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
6f2ef2043SLokesh Vutla  *	Lokesh Vutla <lokeshvutla@ti.com>
7f2ef2043SLokesh Vutla  */
8f2ef2043SLokesh Vutla 
9f2ef2043SLokesh Vutla #include <common.h>
10f2ef2043SLokesh Vutla #include <command.h>
11f2ef2043SLokesh Vutla #include <asm/armv7.h>
12f2ef2043SLokesh Vutla #include <asm/system.h>
13f2ef2043SLokesh Vutla #include <asm/barriers.h>
14f2ef2043SLokesh Vutla #include <linux/compiler.h>
15f2ef2043SLokesh Vutla 
16f2ef2043SLokesh Vutla #include <asm/armv7_mpu.h>
17f2ef2043SLokesh Vutla 
18f2ef2043SLokesh Vutla /* MPU Type register definitions */
19f2ef2043SLokesh Vutla #define MPUIR_S_SHIFT		0
20f2ef2043SLokesh Vutla #define MPUIR_S_MASK		BIT(MPUIR_S_SHIFT)
21f2ef2043SLokesh Vutla #define MPUIR_DREGION_SHIFT	8
22f2ef2043SLokesh Vutla #define MPUIR_DREGION_MASK	(0xff << 8)
23f2ef2043SLokesh Vutla 
24f2ef2043SLokesh Vutla /**
25f2ef2043SLokesh Vutla  * Note:
26f2ef2043SLokesh Vutla  * The Memory Protection Unit(MPU) allows to partition memory into regions
27f2ef2043SLokesh Vutla  * and set individual protection attributes for each region. In absence
28f2ef2043SLokesh Vutla  * of MPU a default map[1] will take effect. make sure to run this code
29f2ef2043SLokesh Vutla  * from a region which has execution permissions by default.
30f2ef2043SLokesh Vutla  * [1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0460d/I1002400.html
31f2ef2043SLokesh Vutla  */
32f2ef2043SLokesh Vutla 
disable_mpu(void)33f2ef2043SLokesh Vutla void disable_mpu(void)
34f2ef2043SLokesh Vutla {
35f2ef2043SLokesh Vutla 	u32 reg;
36f2ef2043SLokesh Vutla 
37f2ef2043SLokesh Vutla 	reg = get_cr();
38f2ef2043SLokesh Vutla 	reg &= ~CR_M;
39f2ef2043SLokesh Vutla 	dsb();
40f2ef2043SLokesh Vutla 	set_cr(reg);
41f2ef2043SLokesh Vutla 	isb();
42f2ef2043SLokesh Vutla }
43f2ef2043SLokesh Vutla 
enable_mpu(void)44f2ef2043SLokesh Vutla void enable_mpu(void)
45f2ef2043SLokesh Vutla {
46f2ef2043SLokesh Vutla 	u32 reg;
47f2ef2043SLokesh Vutla 
48f2ef2043SLokesh Vutla 	reg = get_cr();
49f2ef2043SLokesh Vutla 	reg |= CR_M;
50f2ef2043SLokesh Vutla 	dsb();
51f2ef2043SLokesh Vutla 	set_cr(reg);
52f2ef2043SLokesh Vutla 	isb();
53f2ef2043SLokesh Vutla }
54f2ef2043SLokesh Vutla 
mpu_enabled(void)55f2ef2043SLokesh Vutla int mpu_enabled(void)
56f2ef2043SLokesh Vutla {
57f2ef2043SLokesh Vutla 	return get_cr() & CR_M;
58f2ef2043SLokesh Vutla }
59f2ef2043SLokesh Vutla 
mpu_config(struct mpu_region_config * rgn)60f2ef2043SLokesh Vutla void mpu_config(struct mpu_region_config *rgn)
61f2ef2043SLokesh Vutla {
62f2ef2043SLokesh Vutla 	u32 attr, val;
63f2ef2043SLokesh Vutla 
64f2ef2043SLokesh Vutla 	attr = get_attr_encoding(rgn->mr_attr);
65f2ef2043SLokesh Vutla 
66f2ef2043SLokesh Vutla 	/* MPU Region Number Register */
67f2ef2043SLokesh Vutla 	asm volatile ("mcr p15, 0, %0, c6, c2, 0" : : "r" (rgn->region_no));
68f2ef2043SLokesh Vutla 
69f2ef2043SLokesh Vutla 	/* MPU Region Base Address Register */
70f2ef2043SLokesh Vutla 	asm volatile ("mcr p15, 0, %0, c6, c1, 0" : : "r" (rgn->start_addr));
71f2ef2043SLokesh Vutla 
72f2ef2043SLokesh Vutla 	/* MPU Region Size and Enable Register */
73f2ef2043SLokesh Vutla 	if (rgn->reg_size)
74f2ef2043SLokesh Vutla 		val = (rgn->reg_size << REGION_SIZE_SHIFT) | ENABLE_REGION;
75f2ef2043SLokesh Vutla 	else
76f2ef2043SLokesh Vutla 		val = DISABLE_REGION;
77f2ef2043SLokesh Vutla 	asm volatile ("mcr p15, 0, %0, c6, c1, 2" : : "r" (val));
78f2ef2043SLokesh Vutla 
79f2ef2043SLokesh Vutla 	/* MPU Region Access Control Register */
80f2ef2043SLokesh Vutla 	val = rgn->xn << XN_SHIFT | rgn->ap << AP_SHIFT | attr;
81f2ef2043SLokesh Vutla 	asm volatile ("mcr p15, 0, %0, c6, c1, 4" : : "r" (val));
82f2ef2043SLokesh Vutla }
83f2ef2043SLokesh Vutla 
setup_mpu_regions(struct mpu_region_config * rgns,u32 num_rgns)84f2ef2043SLokesh Vutla void setup_mpu_regions(struct mpu_region_config *rgns, u32 num_rgns)
85f2ef2043SLokesh Vutla {
86f2ef2043SLokesh Vutla 	u32 num, i;
87f2ef2043SLokesh Vutla 
88f2ef2043SLokesh Vutla 	asm volatile ("mrc p15, 0, %0, c0, c0, 4" : "=r" (num));
89f2ef2043SLokesh Vutla 	num = (num & MPUIR_DREGION_MASK) >> MPUIR_DREGION_SHIFT;
90f2ef2043SLokesh Vutla 	/* Regions to be configured cannot be greater than available regions */
91f2ef2043SLokesh Vutla 	if (num < num_rgns)
92f2ef2043SLokesh Vutla 		num_rgns = num;
93f2ef2043SLokesh Vutla 	/**
94f2ef2043SLokesh Vutla 	 * Assuming dcache might not be enabled at this point, disabling
95f2ef2043SLokesh Vutla 	 * and invalidating only icache.
96f2ef2043SLokesh Vutla 	 */
97f2ef2043SLokesh Vutla 	icache_disable();
98f2ef2043SLokesh Vutla 	invalidate_icache_all();
99f2ef2043SLokesh Vutla 
100f2ef2043SLokesh Vutla 	disable_mpu();
101f2ef2043SLokesh Vutla 
102f2ef2043SLokesh Vutla 	for (i = 0; i < num_rgns; i++)
103f2ef2043SLokesh Vutla 		mpu_config(&rgns[i]);
104f2ef2043SLokesh Vutla 
105f2ef2043SLokesh Vutla 	enable_mpu();
106f2ef2043SLokesh Vutla 
107f2ef2043SLokesh Vutla 	icache_enable();
108f2ef2043SLokesh Vutla }
109*a43d46a7SLokesh Vutla 
enable_caches(void)110*a43d46a7SLokesh Vutla void enable_caches(void)
111*a43d46a7SLokesh Vutla {
112*a43d46a7SLokesh Vutla 	/*
113*a43d46a7SLokesh Vutla 	 * setup_mpu_regions() might have enabled Icache. So add a check
114*a43d46a7SLokesh Vutla 	 * before enabling Icache
115*a43d46a7SLokesh Vutla 	 */
116*a43d46a7SLokesh Vutla 	if (!icache_status())
117*a43d46a7SLokesh Vutla 		icache_enable();
118*a43d46a7SLokesh Vutla 	dcache_enable();
119*a43d46a7SLokesh Vutla }
120