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