1 /*
2 * Copyright (c) 2022-2023, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <string.h>
8 #include <common/debug.h>
9 #include <lib/mmio.h>
10 #include <smccc_helpers.h>
11
12 #include <emi_mpu.h>
13 #include <lib/mtk_init/mtk_init.h>
14 #include <mtk_sip_svc.h>
15
16 #if ENABLE_EMI_MPU_SW_LOCK
17 static unsigned char region_lock_state[EMI_MPU_REGION_NUM];
18 #endif
19
20 #define EMI_MPU_START_MASK (0x00FFFFFF)
21 #define EMI_MPU_END_MASK (0x00FFFFFF)
22 #define EMI_MPU_APC_SW_LOCK_MASK (0x00FFFFFF)
23 #define EMI_MPU_APC_HW_LOCK_MASK (0x80FFFFFF)
24
_emi_mpu_set_protection(unsigned int start,unsigned int end,unsigned int apc)25 static int _emi_mpu_set_protection(unsigned int start, unsigned int end,
26 unsigned int apc)
27 {
28 unsigned int dgroup;
29 unsigned int region;
30
31 region = (start >> 24) & 0xFF;
32 start &= EMI_MPU_START_MASK;
33 dgroup = (end >> 24) & 0xFF;
34 end &= EMI_MPU_END_MASK;
35
36 if ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) {
37 WARN("invalid region, domain\n");
38 return -1;
39 }
40
41 #if ENABLE_EMI_MPU_SW_LOCK
42 if (region_lock_state[region] == LOCK) {
43 WARN("invalid region\n");
44 return -1;
45 }
46
47 if ((dgroup == 0) && ((apc >> 31) & 0x1)) {
48 region_lock_state[region] = LOCK;
49 }
50
51 apc &= EMI_MPU_APC_SW_LOCK_MASK;
52 #else
53 apc &= EMI_MPU_APC_HW_LOCK_MASK;
54 #endif
55
56 if ((start >= DRAM_OFFSET) && (end >= start)) {
57 start -= DRAM_OFFSET;
58 end -= DRAM_OFFSET;
59 } else {
60 WARN("invalid range\n");
61 return -1;
62 }
63
64 mmio_write_32(EMI_MPU_SA(region), start);
65 mmio_write_32(EMI_MPU_EA(region), end);
66 mmio_write_32(EMI_MPU_APC(region, dgroup), apc);
67
68 #if defined(SUB_EMI_MPU_BASE)
69 mmio_write_32(SUB_EMI_MPU_SA(region), start);
70 mmio_write_32(SUB_EMI_MPU_EA(region), end);
71 mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), apc);
72 #endif
73 return 0;
74 }
75
emi_mpu_clear_protection(unsigned int region)76 int emi_mpu_clear_protection(unsigned int region)
77 {
78 unsigned int dgroup;
79
80 if (region >= EMI_MPU_REGION_NUM) {
81 WARN("invalid region number\n");
82 return -1;
83 }
84
85 #if ENABLE_EMI_MPU_SW_LOCK
86 if (region_lock_state[region] == LOCK) {
87 WARN("SW:region is locked\n");
88 return -1;
89 }
90 #endif
91 if (mmio_read_32(EMI_MPU_APC(region, 0)) & (LOCK << 31UL)) {
92 WARN("HW:EMI-MPU region is locked\n");
93 return -1;
94 }
95
96 #if defined(SUB_EMI_MPU_BASE)
97 if (mmio_read_32(SUB_EMI_MPU_APC(region, 0)) & (LOCK << 31UL)) {
98 WARN("HW:SUB EMI-MPU region is locked\n");
99 return -1;
100 }
101 #endif
102
103 for (dgroup = 0; dgroup < EMI_MPU_DGROUP_NUM; dgroup++)
104 mmio_write_32(EMI_MPU_APC(region, dgroup), 0x0);
105
106 mmio_write_32(EMI_MPU_SA(region), 0x0);
107 mmio_write_32(EMI_MPU_EA(region), 0x0);
108
109 #if defined(SUB_EMI_MPU_BASE)
110 for (dgroup = 0; dgroup < EMI_MPU_DGROUP_NUM; dgroup++)
111 mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), 0x0);
112
113 mmio_write_32(SUB_EMI_MPU_SA(region), 0);
114 mmio_write_32(SUB_EMI_MPU_EA(region), 0);
115 #endif
116 return 0;
117 }
118
119
dump_emi_mpu_regions(void)120 static void dump_emi_mpu_regions(void)
121 {
122 int region, i;
123
124 /* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */
125 for (region = 0; region < 8; ++region) {
126 INFO("region %d:\n", region);
127 INFO("\tsa: 0x%x, ea: 0x%x\n",
128 mmio_read_32(EMI_MPU_SA(region)), mmio_read_32(EMI_MPU_EA(region)));
129
130 for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i) {
131 INFO("\tapc%d: 0x%x\n", i, mmio_read_32(EMI_MPU_APC(region, i)));
132 }
133 }
134 }
135
emi_mpu_set_protection(struct emi_region_info_t * region_info)136 int emi_mpu_set_protection(struct emi_region_info_t *region_info)
137 {
138 unsigned int start, end;
139 int i;
140
141 if (region_info->region >= EMI_MPU_REGION_NUM) {
142 WARN("invalid region\n");
143 return -1;
144 }
145
146 start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) |
147 (region_info->region << 24);
148
149 for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) {
150 end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) | (i << 24);
151
152 if (_emi_mpu_set_protection(start, end, region_info->apc[i]) < 0) {
153 WARN("Failed to set emi mpu protection(%d, %d, %d)\n",
154 start, end, region_info->apc[i]);
155 }
156 }
157
158 return 0;
159 }
160
mtk_emi_mpu_sip_handler(u_register_t x1,u_register_t x2,u_register_t x3,u_register_t x4,void * handle,struct smccc_res * smccc_ret)161 u_register_t mtk_emi_mpu_sip_handler(u_register_t x1, u_register_t x2,
162 u_register_t x3, u_register_t x4,
163 void *handle, struct smccc_res *smccc_ret)
164 {
165 return (u_register_t) emi_mpu_optee_handler(x1, x2, x3);
166 }
167 DECLARE_SMC_HANDLER(MTK_SIP_TEE_MPU_PERM_SET, mtk_emi_mpu_sip_handler);
168
emi_mpu_init(void)169 int emi_mpu_init(void)
170 {
171 INFO("[%s] emi mpu initialization\n", __func__);
172
173 set_emi_mpu_regions();
174 dump_emi_mpu_regions();
175
176 return 0;
177 }
178 MTK_PLAT_SETUP_0_INIT(emi_mpu_init);
179