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