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 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 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 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 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 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 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 69 static void apummu_enable(void) 70 { 71 mmio_setbits_32(APUMMU_CMU_TOP_BASE, 0x1); 72 } 73 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 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 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 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 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 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 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 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 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 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 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