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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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