// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2020 MediaTek Inc. */ #include #include #include #include #include #include #include "apusys_device.h" #include "reviser_cmn.h" #include "reviser_drv.h" #include "reviser_reg.h" #include "reviser_hw.h" #include "reviser_mem.h" #include "reviser_secure.h" #include "apusys_power.h" #include "reviser_aee.h" #define FAKE_CONTEX_REG_NUM 9 //#define FAKE_REMAP_REG_NUM 13 #define FAKE_REMAP_REG_NUM VLM_REMAP_TABLE_MAX #define UNKNOWN_INT_MAX (500000) #define REG_DEBUG 0 static uint32_t g_ctx_reg[FAKE_CONTEX_REG_NUM]; static uint32_t g_remap_reg[FAKE_REMAP_REG_NUM]; static uint32_t g_mva_reg; static struct reviser_mem g_mem_sys; static uint32_t *_reviser_reg_fake_search(uint32_t offset) __attribute__((unused)); static uint32_t _reviser_ctrl_reg_read(void *drvinfo, uint32_t offset); static uint32_t _reviser_int_reg_read(void *drvinfo, uint32_t offset); static uint32_t _reviser_reg_read(void *base, uint32_t offset); static void _reviser_reg_write(void *base, uint32_t offset, uint32_t value); static void _reviser_reg_set(void *base, uint32_t offset, uint32_t value); static void _reviser_reg_clr(void *base, uint32_t offset, uint32_t value); static uint32_t _reviser_get_contex_offset(enum REVISER_DEVICE_E type, int index); static uint32_t _reviser_get_remap_offset(int index); APUSYS_ATTR_USE static void _reviser_set_contex_boundary(void *drvinfo, uint32_t offset, uint8_t boundary); APUSYS_ATTR_USE static void _reviser_set_context_ID(void *drvinfo, uint32_t offset, uint8_t ID); APUSYS_ATTR_USE static void _reviser_set_remap_table(void *drvinfo, uint32_t offset, uint8_t valid, uint8_t ID, uint8_t src_page, uint8_t dst_page); #if APUSYS_SECURE static uint32_t _reviser_get_remap_table_reg( uint8_t valid, uint8_t ID, uint8_t src_page, uint8_t dst_page); #endif APUSYS_ATTR_USE static void _reviser_set_default_iova(void *drvinfo, uint32_t iova); // Test INT for setting VPU void reviser_print_rw(void *drvinfo, void *s_file) { struct reviser_dev_info *reviser_device = NULL; struct seq_file *s = (struct seq_file *)s_file; uint32_t reg_base0, reg_base1; DEBUG_TAG; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return; } reviser_device = (struct reviser_dev_info *)drvinfo; LOG_CON(s, "=============================\n"); LOG_CON(s, " reviser driver rw\n"); LOG_CON(s, "-----------------------------\n"); reg_base0 = _reviser_ctrl_reg_read(reviser_device, VP6_CORE0_BASE_0); reg_base1 = _reviser_ctrl_reg_read(reviser_device, VP6_CORE0_BASE_1); LOG_CON(s, "reg_base0: %.8x\n", reg_base0); LOG_CON(s, "reg_base1: %.8x\n", reg_base1); LOG_CON(s, "=============================\n"); return; } void reviser_print_private(void *drvinfo) { struct reviser_dev_info *reviser_device = NULL; reviser_device = (struct reviser_dev_info *)drvinfo; DEBUG_TAG; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return; } reviser_device = (struct reviser_dev_info *)drvinfo; LOG_INFO("============================="); LOG_INFO(" reviser driver private reviser_device\n"); LOG_INFO("-----------------------------"); LOG_INFO("pctrl_top: %p\n", reviser_device->pctrl_top); LOG_INFO("============================="); } void reviser_print_dram(void *drvinfo, void *s_file) { struct reviser_dev_info *reviser_device = NULL; int index; unsigned char *data; struct seq_file *s = (struct seq_file *)s_file; DEBUG_TAG; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return; } reviser_device = (struct reviser_dev_info *)drvinfo; data = (unsigned char *)reviser_device->dram_base; reviser_mem_invalidate(reviser_device->dev, &g_mem_sys); LOG_CON(s, "=============================\n"); LOG_CON(s, " reviser dram table info\n"); LOG_CON(s, "-----------------------------\n"); LOG_CON(s, "== PAGE[NUM] == [BANK0][BANK1][BANK2][BANK3]\n"); LOG_CON(s, "-----------------------------\n"); for (index = 0; index < VLM_CTXT_CTX_ID_COUNT; index++) { LOG_CON(s, "== PAGE[%02d] == [%02x][%02x][%02x][%02x]\n", index, *(data + VLM_SIZE*index + VLM_BANK_SIZE*0), *(data + VLM_SIZE*index + VLM_BANK_SIZE*1), *(data + VLM_SIZE*index + VLM_BANK_SIZE*2), *(data + VLM_SIZE*index + VLM_BANK_SIZE*3)); } LOG_CON(s, "=============================\n"); return; } void reviser_print_tcm(void *drvinfo, void *s_file) { struct reviser_dev_info *reviser_device = NULL; uint32_t offset; uint8_t bank0[32], bank1[32], bank2[32], bank3[32]; struct seq_file *s = (struct seq_file *)s_file; DEBUG_TAG; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return; } if (VLM_TCM_BANK_MAX == 0) { LOG_ERR("invalid TCM\n"); return; } reviser_device = (struct reviser_dev_info *)drvinfo; if (!reviser_device->tcm_base) { LOG_ERR("No TCM\n"); return; } offset = 0; memcpy_fromio(bank0, reviser_device->tcm_base + VLM_BANK_SIZE*0, 32); memcpy_fromio(bank1, reviser_device->tcm_base + VLM_BANK_SIZE*1, 32); memcpy_fromio(bank2, reviser_device->tcm_base + VLM_BANK_SIZE*2, 32); memcpy_fromio(bank3, reviser_device->tcm_base + VLM_BANK_SIZE*3, 32); LOG_CON(s, "=============================\n"); LOG_CON(s, " reviser tcm table info\n"); LOG_CON(s, "-----------------------------\n"); LOG_CON(s, "== BANK[NUM] == [DATA][DATA][DATA][DATA]\n"); LOG_CON(s, "-----------------------------\n"); LOG_CON(s, "== BANK[0] == [%02x][%02x][%02x]\n", *(bank0), *(bank0 + 1), *(bank0 + 2)); LOG_CON(s, "== BANK[1] == [%02x][%02x][%02x]\n", *(bank1), *(bank1 + 1), *(bank1 + 2)); LOG_CON(s, "== BANK[2] == [%02x][%02x][%02x]\n", *(bank2), *(bank2 + 1), *(bank2 + 2)); LOG_CON(s, "== BANK[3] == [%02x][%02x][%02x]\n", *(bank3), *(bank3 + 1), *(bank3 + 2)); LOG_CON(s, "=============================\n"); return; } void reviser_print_exception(void *drvinfo, void *s_file) { struct reviser_dev_info *reviser_device = NULL; struct seq_file *s = (struct seq_file *)s_file; uint32_t reg[FAKE_CONTEX_REG_NUM]; uint32_t reg_state = 0; DEBUG_TAG; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return; } reviser_device = (struct reviser_dev_info *)drvinfo; reg[0] = _reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_MDLA_0); reg[1] = _reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_MDLA_1); reg[2] = _reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_VPU_0); reg[3] = _reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_VPU_1); reg[4] = _reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_VPU_2); reg[5] = _reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_EDMA_0); reg[6] = _reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_EDMA_1); reg_state = _reviser_int_reg_read(reviser_device, APUSYS_EXCEPT_INT); LOG_CON(s, "=============================\n"); LOG_CON(s, " reviser exception info\n"); LOG_CON(s, "-----------------------------\n"); LOG_CON(s, "MDLA0: %.8x\n", reg[0]); LOG_CON(s, "MDLA1: %.8x\n", reg[1]); LOG_CON(s, "VPU0: %.8x\n", reg[2]); LOG_CON(s, "VPU1: %.8x\n", reg[3]); LOG_CON(s, "VPU2: %.8x\n", reg[4]); LOG_CON(s, "EDMA0: %.8x\n", reg[5]); LOG_CON(s, "EDMA1: %.8x\n", reg[6]); LOG_CON(s, "reg_state: %.8x\n", reg_state); LOG_CON(s, "=============================\n"); return; } void reviser_print_error(void *drvinfo, void *s_file) { struct reviser_dev_info *reviser_device = NULL; struct seq_file *s = (struct seq_file *)s_file; unsigned long flags; int count = 0; DEBUG_TAG; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return; } reviser_device = (struct reviser_dev_info *)drvinfo; spin_lock_irqsave(&reviser_device->lock_dump, flags); count = reviser_device->dump.err_count; spin_unlock_irqrestore(&reviser_device->lock_dump, flags); LOG_CON(s, "=============================\n"); LOG_CON(s, " reviser error info\n"); LOG_CON(s, "-----------------------------\n"); LOG_CON(s, "count: %d\n", count); LOG_CON(s, "=============================\n"); } void reviser_print_boundary(void *drvinfo, void *s_file) { struct reviser_dev_info *reviser_device = NULL; uint32_t mdla[VLM_CTXT_MDLA_MAX]; uint32_t vpu[VLM_CTXT_VPU_MAX]; uint32_t edma[VLM_CTXT_EDMA_MAX]; uint32_t offset = 0; struct seq_file *s = (struct seq_file *)s_file; int i; DEBUG_TAG; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return; } reviser_device = (struct reviser_dev_info *)drvinfo; #if VLM_CTXT_MDLA_MAX for (i = 0; i < VLM_CTXT_MDLA_MAX; i++) { offset = _reviser_get_contex_offset(REVISER_DEVICE_MDLA, i); if (offset == REVISER_FAIL) goto fail_offset; mdla[i] = _reviser_ctrl_reg_read(reviser_device, offset) & VLM_CTXT_BDY_SELECT; } #endif #if VLM_CTXT_VPU_MAX for (i = 0; i < VLM_CTXT_VPU_MAX; i++) { offset = _reviser_get_contex_offset(REVISER_DEVICE_VPU, i); if (offset == REVISER_FAIL) goto fail_offset; vpu[i] = _reviser_ctrl_reg_read(reviser_device, offset) & VLM_CTXT_BDY_SELECT; } #endif #if VLM_CTXT_EDMA_MAX for (i = 0; i < VLM_CTXT_EDMA_MAX; i++) { offset = _reviser_get_contex_offset(REVISER_DEVICE_EDMA, i); if (offset == REVISER_FAIL) goto fail_offset; edma[i] = _reviser_ctrl_reg_read(reviser_device, offset) & VLM_CTXT_BDY_SELECT; } #endif LOG_CON(s, "=============================\n"); LOG_CON(s, " reviser driver boundary info\n"); LOG_CON(s, "-----------------------------\n"); for (i = 0; i < VLM_CTXT_MDLA_MAX; i++) LOG_CON(s, "MDLA%d: %.8x\n", i, mdla[i]); for (i = 0; i < VLM_CTXT_VPU_MAX; i++) LOG_CON(s, "VPU%d: %.8x\n", i, vpu[i]); for (i = 0; i < VLM_CTXT_EDMA_MAX; i++) LOG_CON(s, "EDMA%d: %.8x\n", i, edma[i]); LOG_CON(s, "=============================\n"); return; fail_offset: LOG_ERR("invalid argument\n"); } void reviser_print_context_ID(void *drvinfo, void *s_file) { struct reviser_dev_info *reviser_device = NULL; uint32_t offset = 0; struct seq_file *s = (struct seq_file *)s_file; uint32_t mdla[VLM_CTXT_MDLA_MAX]; uint32_t vpu[VLM_CTXT_VPU_MAX]; uint32_t edma[VLM_CTXT_EDMA_MAX]; int i; DEBUG_TAG; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return; } reviser_device = (struct reviser_dev_info *)drvinfo; #if VLM_CTXT_MDLA_MAX for (i = 0; i < VLM_CTXT_MDLA_MAX; i++) { offset = _reviser_get_contex_offset(REVISER_DEVICE_MDLA, i); if (offset == REVISER_FAIL) goto fail_offset; mdla[i] = (_reviser_ctrl_reg_read(reviser_device, offset) & VLM_CTXT_CTX_ID) >> VLM_CTXT_CTX_ID_OFFSET; } #endif #if VLM_CTXT_VPU_MAX for (i = 0; i < VLM_CTXT_VPU_MAX; i++) { offset = _reviser_get_contex_offset(REVISER_DEVICE_VPU, i); if (offset == REVISER_FAIL) goto fail_offset; vpu[i] = (_reviser_ctrl_reg_read(reviser_device, offset) & VLM_CTXT_CTX_ID) >> VLM_CTXT_CTX_ID_OFFSET; } #endif #if VLM_CTXT_EDMA_MAX for (i = 0; i < VLM_CTXT_EDMA_MAX; i++) { offset = _reviser_get_contex_offset(REVISER_DEVICE_EDMA, i); if (offset == REVISER_FAIL) goto fail_offset; edma[i] = (_reviser_ctrl_reg_read(reviser_device, offset) & VLM_CTXT_CTX_ID) >> VLM_CTXT_CTX_ID_OFFSET; } #endif LOG_CON(s, "=============================\n"); LOG_CON(s, " reviser driver ID info\n"); LOG_CON(s, "-----------------------------\n"); for (i = 0; i < VLM_CTXT_MDLA_MAX; i++) LOG_CON(s, "MDLA%d: %.8x\n", i, mdla[i]); for (i = 0; i < VLM_CTXT_VPU_MAX; i++) LOG_CON(s, "VPU%d: %.8x\n", i, vpu[i]); for (i = 0; i < VLM_CTXT_EDMA_MAX; i++) LOG_CON(s, "EDMA%d: %.8x\n", i, edma[i]); LOG_CON(s, "=============================\n"); return; fail_offset: LOG_ERR("invalid argument\n"); } void reviser_print_remap_table(void *drvinfo, void *s_file) { struct reviser_dev_info *reviser_device = NULL; uint32_t reg[FAKE_REMAP_REG_NUM]; uint32_t offset[FAKE_REMAP_REG_NUM]; int i = 0; uint32_t valid, ID, src, dst; struct seq_file *s = (struct seq_file *)s_file; DEBUG_TAG; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return; } reviser_device = (struct reviser_dev_info *)drvinfo; for (i = 0; i < FAKE_REMAP_REG_NUM; i++) { offset[i] = _reviser_get_remap_offset(i); if (offset[i] == REVISER_FAIL) { LOG_ERR("invalid argument\n"); goto fail_offset; } reg[i] = _reviser_ctrl_reg_read( reviser_device, offset[i]); } LOG_CON(s, "=============================\n"); LOG_CON(s, " reviser driver remap info\n"); LOG_CON(s, "-----------------------------\n"); for (i = 0; i < FAKE_REMAP_REG_NUM; i++) { valid = reg[i] >> VLM_REMAP_VALID_OFFSET; ID = (reg[i] & VLM_REMAP_CTX_ID) >> VLM_REMAP_CTX_ID_OFFSET; src = (reg[i] & VLM_REMAP_CTX_SRC) >> VLM_REMAP_CTX_SRC_OFFSET; dst = (reg[i] & VLM_REMAP_CTX_DST) >> VLM_REMAP_CTX_DST_OFFSET; LOG_CON(s, "[%02d]: valid[%d] ID[%02d] src[%02d] dst[%02d]\n", i, valid, ID, src, dst); } LOG_CON(s, "=============================\n"); return; fail_offset: LOG_ERR("invalid argument\n"); } void reviser_print_default_iova(void *drvinfo, void *s_file) { struct reviser_dev_info *reviser_device = NULL; struct seq_file *s = (struct seq_file *)s_file; uint32_t reg; DEBUG_TAG; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return; } reviser_device = (struct reviser_dev_info *)drvinfo; reg = _reviser_ctrl_reg_read(reviser_device, VLM_DEFAULT_MVA); LOG_CON(s, "=============================\n"); LOG_CON(s, " reviser driver default iova\n"); LOG_CON(s, "-----------------------------\n"); LOG_CON(s, "Default: %.8x\n", reg); LOG_CON(s, "=============================\n"); } static uint32_t *_reviser_reg_fake_search(uint32_t offset) { switch (offset) { case VLM_CTXT_MDLA_0: return &g_ctx_reg[0]; case VLM_CTXT_MDLA_1: return &g_ctx_reg[1]; case VLM_CTXT_VPU_0: return &g_ctx_reg[2]; case VLM_CTXT_VPU_1: return &g_ctx_reg[3]; case VLM_CTXT_VPU_2: return &g_ctx_reg[4]; case VLM_CTXT_EDMA_0: return &g_ctx_reg[5]; case VLM_CTXT_EDMA_1: return &g_ctx_reg[6]; case VLM_REMAP_TABLE_0: return &g_remap_reg[0]; case VLM_REMAP_TABLE_1: return &g_remap_reg[1]; case VLM_REMAP_TABLE_2: return &g_remap_reg[2]; case VLM_REMAP_TABLE_3: return &g_remap_reg[3]; case VLM_REMAP_TABLE_4: return &g_remap_reg[4]; case VLM_REMAP_TABLE_5: return &g_remap_reg[5]; case VLM_REMAP_TABLE_6: return &g_remap_reg[6]; case VLM_REMAP_TABLE_7: return &g_remap_reg[7]; case VLM_REMAP_TABLE_8: return &g_remap_reg[8]; case VLM_REMAP_TABLE_9: return &g_remap_reg[9]; case VLM_REMAP_TABLE_A: return &g_remap_reg[10]; case VLM_REMAP_TABLE_B: return &g_remap_reg[11]; case VLM_REMAP_TABLE_C: return &g_remap_reg[12]; case VLM_DEFAULT_MVA: return &g_mva_reg; default: LOG_ERR("offset invalid %.8x\n", offset); return NULL; } } static uint32_t _reviser_ctrl_reg_read(void *drvinfo, uint32_t offset) { struct reviser_dev_info *reviser_device = NULL; int ret = 0; size_t value = 0; #if APUSYS_SECURE struct arm_smccc_res res; #endif if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return ret; } reviser_device = (struct reviser_dev_info *)drvinfo; #if APUSYS_SECURE arm_smccc_smc(MTK_SIP_APUSYS_CONTROL, MTK_APUSYS_KERNEL_OP_REVISER_CHK_VALUE, offset, 0, 0, 0, 0, 0, &res); ret = res.a0; value = res.a1; if (ret) { LOG_ERR("invalid argument %.8x\n", offset); ret = 0; return ret; } #else value = _reviser_reg_read(reviser_device->pctrl_top, offset); #endif return value; } static uint32_t _reviser_int_reg_read(void *drvinfo, uint32_t offset) { struct reviser_dev_info *reviser_device = NULL; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return 0; } reviser_device = (struct reviser_dev_info *)drvinfo; return _reviser_reg_read(reviser_device->int_base, offset); } static uint32_t _reviser_reg_read(void *base, uint32_t offset) { #if REG_DEBUG uint32_t *pReg = NULL; pReg = _reviser_reg_fake_search(offset); LOG_DEBUG("offset: %p value %.8x\n", offset, *pReg); return *pReg; #else #if 0 //Print for debug uint32_t value = 0; value = ioread32(base + offset); LOG_DEBUG("offset: %p value %.8x\n", offset, value); #endif return ioread32(base + offset); #endif } static void _reviser_reg_write(void *base, uint32_t offset, uint32_t value) { #if REG_DEBUG uint32_t *pReg = NULL; LOG_DEBUG("offset: %p value: %.8x\n", offset, value); pReg = _reviser_reg_fake_search(offset); if (pReg == NULL) return; *pReg = value; #else iowrite32(value, base + offset); #endif } static void _reviser_reg_set(void *base, uint32_t offset, uint32_t value) { //DEBUG_TAG; _reviser_reg_write(base, offset, _reviser_reg_read(base, offset) | value); } static void _reviser_reg_clr(void *base, uint32_t offset, uint32_t value) { //DEBUG_TAG; _reviser_reg_write(base, offset, _reviser_reg_read(base, offset) & (~value)); } static uint32_t _reviser_get_remap_offset(int index) { return reviser_get_remap_offset(index); } static uint32_t _reviser_get_contex_offset(enum REVISER_DEVICE_E type, int index) { uint32_t offset = 0; switch (type) { case REVISER_DEVICE_MDLA: if (index >= VLM_CTXT_MDLA_MAX) { LOG_ERR("invalid argument MDLA index %d\n", index); offset = REVISER_FAIL; } else { offset = reviser_get_contex_offset_MDLA(index); } break; case REVISER_DEVICE_VPU: if (index >= VLM_CTXT_VPU_MAX) { LOG_ERR("invalid argument VPU index %d\n", index); offset = REVISER_FAIL; } else { offset = reviser_get_contex_offset_VPU(index); } break; case REVISER_DEVICE_EDMA: if (index >= VLM_CTXT_EDMA_MAX) { LOG_ERR("invalid argument EDMA index %d\n", index); offset = REVISER_FAIL; } else { offset = reviser_get_contex_offset_EDMA(index); } break; default: LOG_ERR("invalid argument type\n"); offset = REVISER_FAIL; break; } return offset; } static void _reviser_set_contex_boundary(void *drvinfo, uint32_t offset, uint8_t boundary) { struct reviser_dev_info *reviser_device = NULL; reviser_device = (struct reviser_dev_info *)drvinfo; _reviser_reg_clr(reviser_device->pctrl_top, offset, VLM_CTXT_BDY_SELECT); _reviser_reg_set(reviser_device->pctrl_top, offset, boundary & VLM_CTXT_BDY_SELECT); } static void _reviser_set_context_ID(void *drvinfo, uint32_t offset, uint8_t ID) { struct reviser_dev_info *reviser_device = NULL; DEBUG_TAG; reviser_device = (struct reviser_dev_info *)drvinfo; _reviser_reg_clr(reviser_device->pctrl_top, offset, VLM_CTXT_CTX_ID); _reviser_reg_set(reviser_device->pctrl_top, offset, (ID << VLM_CTXT_CTX_ID_OFFSET)); } static void _reviser_set_remap_table(void *drvinfo, uint32_t offset, uint8_t valid, uint8_t ID, uint8_t src_page, uint8_t dst_page) { struct reviser_dev_info *reviser_device = NULL; DEBUG_TAG; reviser_device = (struct reviser_dev_info *)drvinfo; _reviser_reg_clr(reviser_device->pctrl_top, offset, VLM_REMAP_VALID); _reviser_reg_clr(reviser_device->pctrl_top, offset, VLM_REMAP_CTX_ID); _reviser_reg_set(reviser_device->pctrl_top, offset, (ID << VLM_REMAP_CTX_ID_OFFSET)); _reviser_reg_clr(reviser_device->pctrl_top, offset, VLM_REMAP_CTX_SRC); _reviser_reg_set(reviser_device->pctrl_top, offset, (src_page << VLM_REMAP_CTX_SRC_OFFSET)); _reviser_reg_clr(reviser_device->pctrl_top, offset, VLM_REMAP_CTX_DST); _reviser_reg_set(reviser_device->pctrl_top, offset, (dst_page << VLM_REMAP_CTX_DST_OFFSET)); if (valid) _reviser_reg_set(reviser_device->pctrl_top, offset, (1 << VLM_REMAP_VALID_OFFSET)); } #if APUSYS_SECURE static uint32_t _reviser_get_remap_table_reg( uint8_t valid, uint8_t ID, uint8_t src_page, uint8_t dst_page) { uint32_t value = 0; DEBUG_TAG; //if(valid) { // value = value | (1 << VLM_REMAP_VALID_OFFSET); //} value = value | (ID << VLM_REMAP_CTX_ID_OFFSET); value = value | (src_page << VLM_REMAP_CTX_SRC_OFFSET); value = value | (dst_page << VLM_REMAP_CTX_DST_OFFSET); //LOG_INFO("value %.8x\n", value); return value; } #endif int reviser_type_convert(int type, enum REVISER_DEVICE_E *reviser_type) { int ret = 0; DEBUG_TAG; switch (type) { case APUSYS_DEVICE_MDLA: case APUSYS_DEVICE_MDLA_RT: *reviser_type = REVISER_DEVICE_MDLA; break; case APUSYS_DEVICE_VPU: case APUSYS_DEVICE_VPU_RT: *reviser_type = REVISER_DEVICE_VPU; break; case APUSYS_DEVICE_EDMA: *reviser_type = REVISER_DEVICE_EDMA; break; default: *reviser_type = REVISER_DEVICE_MAX; ret = -EINVAL; break; } return ret; } int reviser_set_remap_table(void *drvinfo, int index, uint8_t valid, uint8_t ID, uint8_t src_page, uint8_t dst_page) { uint32_t offset = 0; int ret = 0; #if APUSYS_SECURE uint32_t value = 0; struct arm_smccc_res res; #endif DEBUG_TAG; if (index > VLM_REMAP_TABLE_DST_MAX) { LOG_ERR("invalid index (out of range) %d\n", index); return -1; } if (ID >= VLM_CTXT_CTX_ID_MAX) { LOG_ERR("invalid ID (out of range) %d\n", ID); return -1; } if (src_page > VLM_REMAP_TABLE_SRC_MAX) { LOG_ERR("invalid src page (out of range) %d\n", src_page); return -1; } if (dst_page > VLM_REMAP_TABLE_DST_MAX) { LOG_ERR("invalid dst page (out of range) %d\n", dst_page); return -1; } if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return -1; } //LOG_DEBUG("index: %u valid: %u ID: %u src: %u dst: %u\n", // index, valid, ID, src_page, dst_page); offset = _reviser_get_remap_offset(index); if (offset == REVISER_FAIL) { LOG_ERR("invalid argument\n"); return -1; } #if APUSYS_SECURE value = _reviser_get_remap_table_reg(valid, ID, src_page, dst_page); arm_smccc_smc(MTK_SIP_APUSYS_CONTROL, MTK_APUSYS_KERNEL_OP_REVISER_SET_REMAP_TABLE, offset, valid, value, 0, 0, 0, &res); ret = res.a0; if (ret) { LOG_ERR("Set HW RemapTable Fail\n"); return -1; } #else _reviser_set_remap_table(drvinfo, offset, valid, ID, src_page, dst_page); #endif return ret; } int reviser_set_boundary(void *drvinfo, enum REVISER_DEVICE_E type, int index, uint8_t boundary) { APUSYS_ATTR_USE uint32_t offset; #if APUSYS_SECURE uint32_t value = 0; struct arm_smccc_res res; #endif DEBUG_TAG; if (boundary > VLM_CTXT_BDY_SELECT_MAX) { LOG_ERR("invalid boundary (out of range) %d\n", VLM_CTXT_BDY_SELECT_MAX); return -1; } if (type >= REVISER_DEVICE_MAX) { LOG_ERR("invalid type (out of range) %d\n", type); return -1; } if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return -1; } #if APUSYS_SECURE value = ((BOUNDARY_ALL_NO_CHANGE) & ~(BOUNDARY_BIT_MASK << (index*4))); value = (value | boundary << (index*4)); //LOG_DEBUG("value 0x%x\n", value); switch (type) { case REVISER_DEVICE_MDLA: arm_smccc_smc(MTK_SIP_APUSYS_CONTROL, MTK_APUSYS_KERNEL_OP_REVISER_SET_BOUNDARY, value, BOUNDARY_ALL_NO_CHANGE, BOUNDARY_ALL_NO_CHANGE, 0, 0, 0, &res); break; case REVISER_DEVICE_VPU: arm_smccc_smc(MTK_SIP_APUSYS_CONTROL, MTK_APUSYS_KERNEL_OP_REVISER_SET_BOUNDARY, BOUNDARY_ALL_NO_CHANGE, value, BOUNDARY_ALL_NO_CHANGE, 0, 0, 0, &res); break; case REVISER_DEVICE_EDMA: arm_smccc_smc(MTK_SIP_APUSYS_CONTROL, MTK_APUSYS_KERNEL_OP_REVISER_SET_BOUNDARY, BOUNDARY_ALL_NO_CHANGE, BOUNDARY_ALL_NO_CHANGE, value, 0, 0, 0, &res); break; default: LOG_ERR("invalid argument\n"); return -1; } #else offset = _reviser_get_contex_offset(type, index); if (offset == REVISER_FAIL) { LOG_ERR("invalid argument\n"); return -1; } _reviser_set_contex_boundary(drvinfo, offset, boundary); #endif return 0; } int reviser_set_context_ID(void *drvinfo, enum REVISER_DEVICE_E type, int index, uint8_t ID) { uint32_t offset = 0; int ret = 0; #if APUSYS_SECURE struct arm_smccc_res res; #endif DEBUG_TAG; if (ID >= VLM_CTXT_CTX_ID_MAX) { LOG_ERR("invalid ID (out of range %d) %d\n", VLM_CTXT_CTX_ID_MAX, ID); return -1; } if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return -1; } offset = _reviser_get_contex_offset(type, index); if (offset == REVISER_FAIL) { LOG_ERR("invalid argument\n"); return -1; } #if APUSYS_SECURE arm_smccc_smc(MTK_SIP_APUSYS_CONTROL, MTK_APUSYS_KERNEL_OP_REVISER_SET_CONTEXT_ID, offset, ID, 0, 0, 0, 0, &res); ret = res.a0; if (ret) { LOG_ERR("Set HW CtxID Fail\n"); return -1; } #else _reviser_set_context_ID(drvinfo, offset, ID); #endif return ret; } static void _reviser_set_default_iova(void *drvinfo, uint32_t iova) { struct reviser_dev_info *reviser_device = NULL; #if APUSYS_SECURE int ret = 0; struct arm_smccc_res res; #endif if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return; } reviser_device = (struct reviser_dev_info *)drvinfo; #if APUSYS_SECURE arm_smccc_smc(MTK_SIP_APUSYS_CONTROL, MTK_APUSYS_KERNEL_OP_REVISER_SET_DEFAULT_IOVA, iova, 0, 0, 0, 0, 0, &res); ret = res.a0; if (ret) { LOG_ERR("Set IOVA Fail\n"); return; } #else _reviser_reg_clr(reviser_device->pctrl_top, VLM_DEFAULT_MVA, REVISER_DEFAULT); _reviser_reg_set(reviser_device->pctrl_top, VLM_DEFAULT_MVA, iova); #endif } int reviser_get_interrupt_offset(void *drvinfo) { uint32_t offset = 0; int ret = 0; #if APUSYS_SECURE size_t reg_value; struct arm_smccc_res res; #endif struct reviser_dev_info *reviser_device = NULL; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return -EINVAL; } reviser_device = (struct reviser_dev_info *)drvinfo; if (_reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_MDLA_0)) { offset = AXI_EXCEPTION_MDLA_0; LOG_DEBUG("Interrupt from AXI_EXCEPTION_MDLA_0\n"); } else if (_reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_MDLA_1)) { offset = AXI_EXCEPTION_MDLA_1; LOG_DEBUG("Interrupt from AXI_EXCEPTION_MDLA_1\n"); } else if (_reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_VPU_0)) { offset = AXI_EXCEPTION_VPU_0; LOG_DEBUG("Interrupt from AXI_EXCEPTION_VPU_0\n"); } else if (_reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_VPU_1)) { offset = AXI_EXCEPTION_VPU_1; LOG_DEBUG("Interrupt from AXI_EXCEPTION_VPU_1\n"); } else if (_reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_VPU_2)) { offset = AXI_EXCEPTION_VPU_2; LOG_DEBUG("Interrupt from AXI_EXCEPTION_VPU_2\n"); } else if (_reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_EDMA_0)) { offset = AXI_EXCEPTION_EDMA_0; LOG_DEBUG("Interrupt from AXI_EXCEPTION_EDMA_0\n"); } else if (_reviser_ctrl_reg_read(reviser_device, AXI_EXCEPTION_EDMA_1)) { offset = AXI_EXCEPTION_EDMA_1; LOG_DEBUG("Interrupt from AXI_EXCEPTION_EDMA_1\n"); } else { //LOG_ERR("Unknown Interrupt\n"); return -EINVAL; } if (offset > 0) { #if APUSYS_SECURE arm_smccc_smc(MTK_SIP_APUSYS_CONTROL, MTK_APUSYS_KERNEL_OP_REVISER_GET_INTERRUPT_STATUS, offset, 0, 0, 0, 0, 0, &res); ret = res.a0; reg_value = res.a1; #else _reviser_reg_set(reviser_device->pctrl_top, offset, 1); #endif } return ret; } int reviser_set_default_iova(void *drvinfo) { int ret = 0; #if APUSYS_SECURE struct arm_smccc_res res; #endif if (g_mem_sys.iova == 0) { LOG_ERR("invalid iova\n"); return -1; } #if APUSYS_SECURE arm_smccc_smc(MTK_SIP_APUSYS_CONTROL, MTK_APUSYS_KERNEL_OP_REVISER_SET_DEFAULT_IOVA, g_mem_sys.iova, 0, 0, 0, 0, 0, &res); ret = res.a0; if (ret) { LOG_ERR("Set IOVA Fail\n"); return -1; } #else _reviser_set_default_iova(drvinfo, g_mem_sys.iova); #endif LOG_DEBUG("Set IOVA %x\n", g_mem_sys.iova); return ret; } int reviser_init_ip(void) { int ret = 0; #if APUSYS_SECURE struct arm_smccc_res res; #endif #if APUSYS_SECURE arm_smccc_smc(MTK_SIP_APUSYS_CONTROL, MTK_APUSYS_KERNEL_OP_REVISER_INIT_IP, 0, 0, 0, 0, 0, 0, &res); ret = res.a0; if (ret) { if (ret == -EIO) LOG_ERR("Unsupported secure monitor call\n"); else LOG_ERR("Init IP fail\n"); return -1; } #else LOG_ERR("APUSYS_SECURE is not enable\n"); return -1; #endif LOG_DEBUG("Init IP\n"); return ret; } bool reviser_is_power(void *drvinfo) { struct reviser_dev_info *reviser_device = NULL; unsigned long flags; bool is_power = false; DEBUG_TAG; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return is_power; } reviser_device = (struct reviser_dev_info *)drvinfo; spin_lock_irqsave(&reviser_device->lock_power, flags); if (reviser_device->power) { //LOG_ERR("Can Not Read when power disable\n"); is_power = true; } spin_unlock_irqrestore(&reviser_device->lock_power, flags); return is_power; } int reviser_dram_remap_init(void *drvinfo) { struct reviser_dev_info *reviser_device = NULL; DEBUG_TAG; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return -1; } reviser_device = (struct reviser_dev_info *)drvinfo; //g_mem_sys.size = REMAP_DRAM_SIZE; //Reserve memory for IP device + Preemption device g_mem_sys.size = VLM_SIZE * VLM_CTXT_CTX_ID_COUNT * 2; if (reviser_mem_alloc(reviser_device->dev, &g_mem_sys)) { LOG_ERR("alloc fail\n"); return -ENOMEM; } //_reviser_set_default_iova(drvinfo, g_mem_sys.iova); reviser_device->dram_base = (void *) g_mem_sys.kva; return 0; } int reviser_dram_remap_destroy(void *drvinfo) { struct reviser_dev_info *reviser_device = NULL; DEBUG_TAG; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return -1; } reviser_device = (struct reviser_dev_info *)drvinfo; reviser_mem_free(&g_mem_sys); reviser_device->dram_base = NULL; return 0; } int reviser_boundary_init(void *drvinfo, uint8_t boundary) { int i = 0; DEBUG_TAG; LOG_DEBUG("boundary %u\n", boundary); //Add if for coverity if (VLM_CTXT_MDLA_MAX > 0) { for (i = 0; i < VLM_CTXT_MDLA_MAX; i++) { if (reviser_set_boundary( drvinfo, REVISER_DEVICE_MDLA, i, boundary)) { return -1; } } } //Add if for coverity if (VLM_CTXT_VPU_MAX > 0) { for (i = 0; i < VLM_CTXT_VPU_MAX; i++) { if (reviser_set_boundary( drvinfo, REVISER_DEVICE_VPU, i, boundary)) { return -1; } } } //Add if for coverity if (VLM_CTXT_EDMA_MAX > 0) { for (i = 0; i < VLM_CTXT_EDMA_MAX; i++) { if (reviser_set_boundary( drvinfo, REVISER_DEVICE_EDMA, i, boundary)) { return -1; } } } return 0; } void reviser_enable_interrupt(void *drvinfo, uint8_t enable) { struct reviser_dev_info *reviser_device = NULL; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return; } reviser_device = (struct reviser_dev_info *)drvinfo; if (enable) { _reviser_reg_set(reviser_device->int_base, REVISER_INT_EN, REVISER_INT_EN_MASK); } else { _reviser_reg_clr(reviser_device->int_base, REVISER_INT_EN, REVISER_INT_EN_MASK); } } int reviser_alloc_tcm(void *drvinfo, void *usr) { struct reviser_dev_info *reviser_device = NULL; struct reviser_mem *mem; reviser_device = (struct reviser_dev_info *)drvinfo; mem = (struct reviser_mem *) usr; mem->kva = (uint64_t) reviser_device->tcm_base; mem->iova = TCM_BASE; LOG_DEBUG("kva:%llx, mva:%x,size:%x\n", mem->kva, mem->iova, mem->size); return 0; } int reviser_free_tcm(void *drvinfo, void *usr) { struct reviser_mem *mem; struct reviser_dev_info *reviser_device = NULL; reviser_device = (struct reviser_dev_info *)drvinfo; mem = (struct reviser_mem *) usr; mem->kva = 0; mem->iova = 0; LOG_DEBUG("kva:%llx, mva:%x,size:%x\n", mem->kva, mem->iova, mem->size); return 0; } int reviser_power_on(void *drvinfo) { struct reviser_dev_info *reviser_device = NULL; int ret = 0; reviser_device = (struct reviser_dev_info *)drvinfo; mutex_lock(&reviser_device->mutex_power); if (reviser_device->power_count == 0) { ret = apu_device_power_on(REVISER); if (ret < 0) LOG_ERR("PowerON Fail (%d)\n", ret); } reviser_device->power_count++; mutex_unlock(&reviser_device->mutex_power); return ret; } int reviser_power_off(void *drvinfo) { struct reviser_dev_info *reviser_device = NULL; int ret = 0; reviser_device = (struct reviser_dev_info *)drvinfo; mutex_lock(&reviser_device->mutex_power); reviser_device->power_count--; if (reviser_device->power_count < 0) { LOG_ERR("Power count invalid (%d)\n", reviser_device->power_count); ret = -EINVAL; mutex_unlock(&reviser_device->mutex_power); if (ret) reviser_aee_print("count_invalid"); return ret; } else if (reviser_device->power_count == 0) { ret = apu_device_power_off(REVISER); if (ret < 0) LOG_ERR("PowerON Fail (%d)\n", ret); } mutex_unlock(&reviser_device->mutex_power); return ret; } int reviser_check_int_valid(void *drvinfo) { struct reviser_dev_info *reviser_device = NULL; int ret = -1; uint32_t value = 0; unsigned int unknown_count = 0; unsigned long flags; reviser_device = (struct reviser_dev_info *)drvinfo; value = _reviser_int_reg_read(reviser_device, APUSYS_EXCEPT_INT); if ((value & REVISER_INT_EN_MASK) > 0) { //LOG_ERR("APUSYS_EXCEPT_INT (%x)\n", value); ret = 0; } else { //LOG_ERR("Not Reviser INT (%x)\n", value); spin_lock_irqsave(&reviser_device->lock_dump, flags); reviser_device->dump.unknown_count++; unknown_count = reviser_device->dump.unknown_count; spin_unlock_irqrestore(&reviser_device->lock_dump, flags); //Show unknown INT if (unknown_count % UNKNOWN_INT_MAX == UNKNOWN_INT_MAX - 1) { LOG_ERR("unknown INT over %u (%.8x)\n", UNKNOWN_INT_MAX, value); } ret = -1; } return ret; }