1 /*
2 * Copyright (c) 2024, MediaTek Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6 #include <errno.h>
7
8 #include <common/debug.h>
9 #include <lib/mmio.h>
10 #include <lib/utils_def.h>
11
12 #include "apusys_ammu.h"
13 #include <apusys_security_ctrl_perm.h>
14 #include <mtk_mmap_pool.h>
15
apummu_set_segment_offset0(uint32_t vsid_idx,uint8_t seg_idx,uint32_t input_adr,uint8_t res_bits,uint8_t page_sel,uint8_t page_len)16 static void apummu_set_segment_offset0(uint32_t vsid_idx, uint8_t seg_idx, uint32_t input_adr,
17 uint8_t res_bits, uint8_t page_sel, uint8_t page_len)
18 {
19 mmio_write_32(APUMMU_VSID_SEGMENT_BASE(vsid_idx, seg_idx, APUMMU_SEG_OFFSET_0),
20 APUMMU_BUILD_SEGMENT_OFFSET0(input_adr, res_bits, page_sel, page_len));
21 }
22
apummu_set_segment_offset1(uint32_t vsid_idx,uint8_t seg_idx,uint32_t output_adr,uint8_t res0,uint8_t iommu_en,uint8_t res1)23 static void apummu_set_segment_offset1(uint32_t vsid_idx, uint8_t seg_idx, uint32_t output_adr,
24 uint8_t res0, uint8_t iommu_en, uint8_t res1)
25 {
26 mmio_write_32(APUMMU_VSID_SEGMENT_BASE(vsid_idx, seg_idx, APUMMU_SEG_OFFSET_1),
27 APUMMU_BUILD_SEGMENT_OFFSET1(output_adr, res0, iommu_en, res1));
28 }
29
apummu_set_segment_offset2(uint32_t vsid_idx,uint8_t seg_idx,uint8_t resv,uint8_t domain,uint8_t acp_en,uint8_t aw_clr,uint8_t aw_invalid,uint8_t ar_exclu,uint8_t ar_sepcu,uint8_t aw_cache_allocate,uint8_t aw_slc_en,uint8_t aw_slb_en,uint8_t ar_cache_allocate,uint8_t ar_slc_en,uint8_t ar_slb_en,uint8_t ro,uint8_t ns)30 static void apummu_set_segment_offset2(uint32_t vsid_idx, uint8_t seg_idx, uint8_t resv,
31 uint8_t domain, uint8_t acp_en, uint8_t aw_clr,
32 uint8_t aw_invalid, uint8_t ar_exclu, uint8_t ar_sepcu,
33 uint8_t aw_cache_allocate, uint8_t aw_slc_en,
34 uint8_t aw_slb_en, uint8_t ar_cache_allocate,
35 uint8_t ar_slc_en, uint8_t ar_slb_en, uint8_t ro,
36 uint8_t ns)
37 {
38 mmio_write_32(APUMMU_VSID_SEGMENT_BASE(vsid_idx, seg_idx, APUMMU_SEG_OFFSET_2),
39 APUMMU_BUILD_SEGMENT_OFFSET2(resv, domain, acp_en, aw_clr, aw_invalid,
40 ar_exclu, ar_sepcu, aw_cache_allocate,
41 aw_slc_en, aw_slb_en, ar_cache_allocate,
42 ar_slc_en, ar_slb_en, ro, ns));
43 }
44
apummu_vsid_segment_enable_init(uint8_t vsid_idx)45 static void apummu_vsid_segment_enable_init(uint8_t vsid_idx)
46 {
47 mmio_write_32(APUMMU_VSID_SEGMENT_ENABLE(vsid_idx), 0);
48 }
49
apummu_set_single_segment(uint8_t vsid_idx,uint8_t seg_idx)50 static void apummu_set_single_segment(uint8_t vsid_idx, uint8_t seg_idx)
51 {
52 mmio_setbits_32(APUMMU_VSID_SEGMENT_ENABLE(vsid_idx), BIT(seg_idx));
53 }
54
apummu_enable_vsid(uint32_t vsid_idx)55 static int apummu_enable_vsid(uint32_t vsid_idx)
56 {
57 if (vsid_idx > (APUMMU_VSID_ACTIVE - 1) &&
58 vsid_idx < (APUMMU_RSV_VSID_IDX_END - APUMMU_VSID_RSV + 1)) {
59 ERROR("invalid vsid index %d\n", vsid_idx);
60 return -1;
61 }
62
63 mmio_write_32(APUMMU_VSID_ENABLE_BASE(vsid_idx), BIT(vsid_idx & APUMMU_VSID_EN_MASK));
64 mmio_write_32(APUMMU_VSID_VALID_BASE(vsid_idx), BIT(vsid_idx & APUMMU_VSID_EN_MASK));
65
66 return 0;
67 }
68
apummu_enable(void)69 static void apummu_enable(void)
70 {
71 mmio_setbits_32(APUMMU_CMU_TOP_BASE, 0x1);
72 }
73
apummu_vsid_sram_config(void)74 static void apummu_vsid_sram_config(void)
75 {
76 uint32_t idx;
77 uint32_t base = (APUMMU_VSID_SRAM_TOTAL - APUMMU_VSID_RSV);
78
79 for (idx = 0; idx < APUMMU_VSID_RSV; idx++) {
80 mmio_write_32(APUMMU_VSID(APUMMU_RSV_VSID_IDX_START + idx),
81 APUMMU_VSID_DESC(base + idx));
82 apummu_vsid_segment_enable_init(base + idx);
83 }
84 }
85
apummu_bind_vsid(uint32_t tcu_base,uint32_t vsid_idx,uint8_t cor_id,uint8_t hw_thread,uint8_t cor_valid,uint8_t vsid_valid)86 static void apummu_bind_vsid(uint32_t tcu_base, uint32_t vsid_idx, uint8_t cor_id,
87 uint8_t hw_thread, uint8_t cor_valid, uint8_t vsid_valid)
88 {
89 mmio_write_32((tcu_base + hw_thread * VSID_THREAD_SZ),
90 (((cor_id & VSID_CORID_MASK) << VSID_CORID_OFF) |
91 ((vsid_idx & VSID_IDX_MASK) << VSID_IDX_OFF) |
92 ((cor_valid & VSID_VALID_MASK) << VSID_COR_VALID_OFF) |
93 ((vsid_valid & VSID_VALID_MASK) << VSID_VALID_OFF)));
94 }
95
apummu_rv_bind_vsid(uint8_t hw_thread)96 static int apummu_rv_bind_vsid(uint8_t hw_thread)
97 {
98 uint8_t cor_id = 0, cor_valid = 0, vsid_valid = 1;
99
100 if (hw_thread > APUMMU_HW_THREAD_MAX) {
101 ERROR("%s: the hw thread id (%d) is not valid for rv/logger\n", __func__,
102 hw_thread);
103 return -EINVAL;
104 }
105
106 apummu_bind_vsid(APUMMU_RCX_UPRV_TCU_BASE, APUMMU_UPRV_RSV_VSID, cor_id, hw_thread,
107 cor_valid, vsid_valid);
108
109 return 0;
110 }
111
apummu_apmcu_bind_vsid(uint8_t hw_thread)112 static int apummu_apmcu_bind_vsid(uint8_t hw_thread)
113 {
114 uint8_t cor_id = 0, cor_valid = 0, vsid_valid = 1;
115
116 if (hw_thread > APUMMU_HW_THREAD_MAX) {
117 ERROR("%s: the hw thread id (%d) is not valid for apmcu\n", __func__, hw_thread);
118 return -EINVAL;
119 }
120
121 apummu_bind_vsid(APUMMU_RCX_EXTM_TCU_BASE, APUMMU_APMCU_RSV_VSID, cor_id, hw_thread,
122 cor_valid, vsid_valid);
123
124 return 0;
125 }
126
apummu_add_map(uint32_t vsid_idx,uint8_t seg_idx,uint64_t input_adr,uint64_t output_adr,uint8_t page_sel,uint8_t page_len,uint8_t domain,uint8_t ns)127 static int apummu_add_map(uint32_t vsid_idx, uint8_t seg_idx, uint64_t input_adr,
128 uint64_t output_adr, uint8_t page_sel, uint8_t page_len,
129 uint8_t domain, uint8_t ns)
130 {
131 uint8_t smmu_sid;
132 bool smmu_sec_id;
133
134 if (seg_idx > APUMMU_SEG_MAX) {
135 ERROR("seg_idx is illegal (0x%x)\n", seg_idx);
136 return -EINVAL;
137 }
138
139 smmu_sec_id = false;
140 if (ns == 0)
141 smmu_sid = SMMU_NORMAL_1_4G_SID;
142 else
143 smmu_sid = (output_adr > 0xFFFFFFFF) ? SMMU_NORMAL_4_16G_SID
144 : SMMU_NORMAL_1_4G_SID;
145
146 /* fill segment */
147 apummu_set_segment_offset0(vsid_idx, seg_idx, (input_adr >> APUMMU_ADDR_SHIFT), 0,
148 page_sel, page_len);
149 apummu_set_segment_offset1(vsid_idx, seg_idx, (output_adr >> APUMMU_ADDR_SHIFT),
150 smmu_sid, 0, smmu_sec_id);
151 apummu_set_segment_offset2(vsid_idx, seg_idx, 0, domain,
152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ns);
153 apummu_set_single_segment(vsid_idx, seg_idx);
154
155 return 0;
156 }
157
apummu_get_dns(enum apusys_dev_type engine_type,enum apusys_sec_level sec_level,uint8_t * domain,uint8_t * ns)158 static int apummu_get_dns(enum apusys_dev_type engine_type, enum apusys_sec_level sec_level,
159 uint8_t *domain, uint8_t *ns)
160 {
161 int ret = 0;
162
163 if (engine_type != APUSYS_DEVICE_NUM) {
164 ret = sec_get_dns(engine_type, sec_level, domain, ns);
165 if (ret)
166 ERROR("engine:%d, sec: %d\n", engine_type, sec_level);
167 } else {
168 *domain = 7;
169 *ns = 1;
170 }
171
172 return ret;
173 }
174
apummu_init(void)175 static void apummu_init(void)
176 {
177 apummu_vsid_sram_config();
178 mmio_write_32((APU_VCORE_CONFIG_BASE + APUMMU_SSID_SID_WIDTH_CTRL),
179 CSR_SMMU_AXMMUSID_WIDTH);
180 apummu_enable();
181 }
182
virtual_engine_thread(void)183 static void virtual_engine_thread(void)
184 {
185 mmio_write_32((APUMMU_RCX_EXTM_TCU_BASE + APUMMU_INT_D2T_TBL0_OFS), APUMMU_THD_ID_TEE);
186 }
187
apummu_add_apmcu_map(uint32_t seg0_input,uint32_t seg0_output,enum apummu_page_size page_size)188 static int apummu_add_apmcu_map(uint32_t seg0_input, uint32_t seg0_output,
189 enum apummu_page_size page_size)
190 {
191 int i, ret;
192 uint8_t domain, ns, seg;
193
194 ret = apummu_get_dns(APUSYS_DEVICE_NUM, SEC_LEVEL_SECURE, &domain, &ns);
195 if (ret) {
196 return ret;
197 }
198
199 seg = 0;
200 ret = apummu_add_map(APUMMU_APMCU_RSV_DESC_IDX, seg, seg0_input, seg0_output, 0,
201 page_size, domain, ns);
202 seg += 1;
203 if (ret)
204 return ret;
205
206 for (i = 0; i < 4; i++) {
207 ret = apummu_add_map(APUMMU_APMCU_RSV_DESC_IDX, seg,
208 APUSYS_TCM + (i * APUMMU_1M_SIZE),
209 APUSYS_TCM + (i * APUMMU_1M_SIZE),
210 0, APUMMU_PAGE_LEN_1MB, domain, ns);
211 seg += 1;
212 if (ret)
213 return ret;
214 }
215
216 ret = apummu_enable_vsid(APUMMU_APMCU_RSV_VSID);
217
218 return ret;
219 }
220
apummu_add_rv_boot_map(uint32_t seg0_output,uint32_t seg1_output,uint32_t seg2_output)221 static int apummu_add_rv_boot_map(uint32_t seg0_output, uint32_t seg1_output, uint32_t seg2_output)
222 {
223 int ret;
224 uint8_t domain, ns;
225
226 ret = apummu_get_dns(APUSYS_DEVICE_UP, SEC_LEVEL_SECURE, &domain, &ns);
227 if (ret) {
228 ERROR("sec get dns fail %d\n", ret);
229 return ret;
230 }
231
232 /* must be in order */
233 ret |= apummu_add_map(APUMMU_RSV_VSID_DESC_IDX_END, 0, 0, seg0_output, 0,
234 APUMMU_PAGE_LEN_1MB, domain, ns);
235 ret |= apummu_add_map(APUMMU_RSV_VSID_DESC_IDX_END, 1, 0, seg1_output, 0,
236 APUMMU_PAGE_LEN_512MB, domain, ns);
237
238 ret |= apummu_get_dns(APUSYS_DEVICE_UP, SEC_LEVEL_NORMAL, &domain, &ns);
239 if (ret) {
240 return ret;
241 }
242
243 ret |= apummu_add_map(APUMMU_RSV_VSID_DESC_IDX_END, 2,
244 0, seg2_output, 0, APUMMU_PAGE_LEN_4GB,
245 domain, ns);
246 if (ret) {
247 ERROR("sec add map fail %d\n", ret);
248 return ret;
249 }
250
251 ret = apummu_enable_vsid(APUMMU_UPRV_RSV_VSID);
252
253 return ret;
254 }
255
rv_boot(uint32_t uP_seg_output,uint8_t uP_hw_thread,enum apummu_page_size logger_page_size,uint32_t XPU_seg_output,enum apummu_page_size XPU_page_size)256 int rv_boot(uint32_t uP_seg_output, uint8_t uP_hw_thread,
257 enum apummu_page_size logger_page_size,
258 uint32_t XPU_seg_output, enum apummu_page_size XPU_page_size)
259 {
260 int ret = 0;
261
262 apummu_init();
263
264 ret = apummu_add_rv_boot_map(uP_seg_output, 0, 0);
265 if (ret) {
266 return ret;
267 }
268
269 ret = apummu_rv_bind_vsid(uP_hw_thread);
270 if (ret)
271 return ret;
272
273 ret = apummu_rv_bind_vsid(uP_hw_thread + 1);
274 if (ret)
275 return ret;
276
277 virtual_engine_thread();
278
279 ret = apummu_add_apmcu_map(XPU_seg_output, XPU_seg_output,
280 XPU_page_size);
281 if (ret)
282 return ret;
283
284 ret = apummu_apmcu_bind_vsid(APUMMU_THD_ID_TEE);
285
286 return ret;
287 }
288