xref: /openbmc/linux/arch/arm/mm/pmsa-v7.c (revision e8b47e12d6c72f26a8ce85974f98a4050ac7ca24)
1 /*
2  * Based on linux/arch/arm/mm/nommu.c
3  *
4  * ARM PMSAv7 supporting functions.
5  */
6 
7 #include <linux/memblock.h>
8 
9 #include <asm/cp15.h>
10 #include <asm/cputype.h>
11 #include <asm/mpu.h>
12 
13 #include "mm.h"
14 
15 #define DRBAR	__ACCESS_CP15(c6, 0, c1, 0)
16 #define IRBAR	__ACCESS_CP15(c6, 0, c1, 1)
17 #define DRSR	__ACCESS_CP15(c6, 0, c1, 2)
18 #define IRSR	__ACCESS_CP15(c6, 0, c1, 3)
19 #define DRACR	__ACCESS_CP15(c6, 0, c1, 4)
20 #define IRACR	__ACCESS_CP15(c6, 0, c1, 5)
21 #define RNGNR	__ACCESS_CP15(c6, 0, c2, 0)
22 
23 /* Region number */
24 static inline void rgnr_write(u32 v)
25 {
26 	write_sysreg(v, RNGNR);
27 }
28 
29 /* Data-side / unified region attributes */
30 
31 /* Region access control register */
32 static inline void dracr_write(u32 v)
33 {
34 	write_sysreg(v, DRACR);
35 }
36 
37 /* Region size register */
38 static inline void drsr_write(u32 v)
39 {
40 	write_sysreg(v, DRSR);
41 }
42 
43 /* Region base address register */
44 static inline void drbar_write(u32 v)
45 {
46 	write_sysreg(v, DRBAR);
47 }
48 
49 static inline u32 drbar_read(void)
50 {
51 	return read_sysreg(DRBAR);
52 }
53 /* Optional instruction-side region attributes */
54 
55 /* I-side Region access control register */
56 static inline void iracr_write(u32 v)
57 {
58 	write_sysreg(v, IRACR);
59 }
60 
61 /* I-side Region size register */
62 static inline void irsr_write(u32 v)
63 {
64 	write_sysreg(v, IRSR);
65 }
66 
67 /* I-side Region base address register */
68 static inline void irbar_write(u32 v)
69 {
70 	write_sysreg(v, IRBAR);
71 }
72 
73 static inline u32 irbar_read(void)
74 {
75 	return read_sysreg(IRBAR);
76 }
77 
78 /* MPU initialisation functions */
79 void __init adjust_lowmem_bounds_mpu(void)
80 {
81 	phys_addr_t phys_offset = PHYS_OFFSET;
82 	phys_addr_t aligned_region_size, specified_mem_size, rounded_mem_size;
83 	struct memblock_region *reg;
84 	bool first = true;
85 	phys_addr_t mem_start;
86 	phys_addr_t mem_end;
87 
88 	for_each_memblock(memory, reg) {
89 		if (first) {
90 			/*
91 			 * Initially only use memory continuous from
92 			 * PHYS_OFFSET */
93 			if (reg->base != phys_offset)
94 				panic("First memory bank must be contiguous from PHYS_OFFSET");
95 
96 			mem_start = reg->base;
97 			mem_end = reg->base + reg->size;
98 			specified_mem_size = reg->size;
99 			first = false;
100 		} else {
101 			/*
102 			 * memblock auto merges contiguous blocks, remove
103 			 * all blocks afterwards in one go (we can't remove
104 			 * blocks separately while iterating)
105 			 */
106 			pr_notice("Ignoring RAM after %pa, memory at %pa ignored\n",
107 				  &mem_end, &reg->base);
108 			memblock_remove(reg->base, 0 - reg->base);
109 			break;
110 		}
111 	}
112 
113 	/*
114 	 * MPU has curious alignment requirements: Size must be power of 2, and
115 	 * region start must be aligned to the region size
116 	 */
117 	if (phys_offset != 0)
118 		pr_info("PHYS_OFFSET != 0 => MPU Region size constrained by alignment requirements\n");
119 
120 	/*
121 	 * Maximum aligned region might overflow phys_addr_t if phys_offset is
122 	 * 0. Hence we keep everything below 4G until we take the smaller of
123 	 * the aligned_region_size and rounded_mem_size, one of which is
124 	 * guaranteed to be smaller than the maximum physical address.
125 	 */
126 	aligned_region_size = (phys_offset - 1) ^ (phys_offset);
127 	/* Find the max power-of-two sized region that fits inside our bank */
128 	rounded_mem_size = (1 <<  __fls(specified_mem_size)) - 1;
129 
130 	/* The actual region size is the smaller of the two */
131 	aligned_region_size = aligned_region_size < rounded_mem_size
132 				? aligned_region_size + 1
133 				: rounded_mem_size + 1;
134 
135 	if (aligned_region_size != specified_mem_size) {
136 		pr_warn("Truncating memory from %pa to %pa (MPU region constraints)",
137 				&specified_mem_size, &aligned_region_size);
138 		memblock_remove(mem_start + aligned_region_size,
139 				specified_mem_size - aligned_region_size);
140 
141 		mem_end = mem_start + aligned_region_size;
142 	}
143 
144 	pr_debug("MPU Region from %pa size %pa (end %pa))\n",
145 		&phys_offset, &aligned_region_size, &mem_end);
146 
147 }
148 
149 static int mpu_present(void)
150 {
151 	return ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7);
152 }
153 
154 static int mpu_max_regions(void)
155 {
156 	/*
157 	 * We don't support a different number of I/D side regions so if we
158 	 * have separate instruction and data memory maps then return
159 	 * whichever side has a smaller number of supported regions.
160 	 */
161 	u32 dregions, iregions, mpuir;
162 	mpuir = read_cpuid(CPUID_MPUIR);
163 
164 	dregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION;
165 
166 	/* Check for separate d-side and i-side memory maps */
167 	if (mpuir & MPUIR_nU)
168 		iregions = (mpuir & MPUIR_IREGION_SZMASK) >> MPUIR_IREGION;
169 
170 	/* Use the smallest of the two maxima */
171 	return min(dregions, iregions);
172 }
173 
174 static int mpu_iside_independent(void)
175 {
176 	/* MPUIR.nU specifies whether there is *not* a unified memory map */
177 	return read_cpuid(CPUID_MPUIR) & MPUIR_nU;
178 }
179 
180 static int mpu_min_region_order(void)
181 {
182 	u32 drbar_result, irbar_result;
183 	/* We've kept a region free for this probing */
184 	rgnr_write(MPU_PROBE_REGION);
185 	isb();
186 	/*
187 	 * As per ARM ARM, write 0xFFFFFFFC to DRBAR to find the minimum
188 	 * region order
189 	*/
190 	drbar_write(0xFFFFFFFC);
191 	drbar_result = irbar_result = drbar_read();
192 	drbar_write(0x0);
193 	/* If the MPU is non-unified, we use the larger of the two minima*/
194 	if (mpu_iside_independent()) {
195 		irbar_write(0xFFFFFFFC);
196 		irbar_result = irbar_read();
197 		irbar_write(0x0);
198 	}
199 	isb(); /* Ensure that MPU region operations have completed */
200 	/* Return whichever result is larger */
201 	return __ffs(max(drbar_result, irbar_result));
202 }
203 
204 static int mpu_setup_region(unsigned int number, phys_addr_t start,
205 			unsigned int size_order, unsigned int properties)
206 {
207 	u32 size_data;
208 
209 	/* We kept a region free for probing resolution of MPU regions*/
210 	if (number > mpu_max_regions() || number == MPU_PROBE_REGION)
211 		return -ENOENT;
212 
213 	if (size_order > 32)
214 		return -ENOMEM;
215 
216 	if (size_order < mpu_min_region_order())
217 		return -ENOMEM;
218 
219 	/* Writing N to bits 5:1 (RSR_SZ)  specifies region size 2^N+1 */
220 	size_data = ((size_order - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN;
221 
222 	dsb(); /* Ensure all previous data accesses occur with old mappings */
223 	rgnr_write(number);
224 	isb();
225 	drbar_write(start);
226 	dracr_write(properties);
227 	isb(); /* Propagate properties before enabling region */
228 	drsr_write(size_data);
229 
230 	/* Check for independent I-side registers */
231 	if (mpu_iside_independent()) {
232 		irbar_write(start);
233 		iracr_write(properties);
234 		isb();
235 		irsr_write(size_data);
236 	}
237 	isb();
238 
239 	/* Store region info (we treat i/d side the same, so only store d) */
240 	mpu_rgn_info.rgns[number].dracr = properties;
241 	mpu_rgn_info.rgns[number].drbar = start;
242 	mpu_rgn_info.rgns[number].drsr = size_data;
243 	return 0;
244 }
245 
246 /*
247 * Set up default MPU regions, doing nothing if there is no MPU
248 */
249 void __init mpu_setup(void)
250 {
251 	int region_err;
252 	if (!mpu_present())
253 		return;
254 
255 	region_err = mpu_setup_region(MPU_RAM_REGION, PHYS_OFFSET,
256 					ilog2(memblock.memory.regions[0].size),
257 					MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL);
258 	if (region_err) {
259 		panic("MPU region initialization failure! %d", region_err);
260 	} else {
261 		pr_info("Using ARMv7 PMSA Compliant MPU. "
262 			 "Region independence: %s, Max regions: %d\n",
263 			mpu_iside_independent() ? "Yes" : "No",
264 			mpu_max_regions());
265 	}
266 }
267