1*a1763ae9SXiangzhi Tang /* 2*a1763ae9SXiangzhi Tang * Copyright (c) 2024, MediaTek Inc. All rights reserved. 3*a1763ae9SXiangzhi Tang * 4*a1763ae9SXiangzhi Tang * SPDX-License-Identifier: BSD-3-Clause 5*a1763ae9SXiangzhi Tang */ 6*a1763ae9SXiangzhi Tang 7*a1763ae9SXiangzhi Tang #include <errno.h> 8*a1763ae9SXiangzhi Tang #include <inttypes.h> 9*a1763ae9SXiangzhi Tang #include <stdint.h> 10*a1763ae9SXiangzhi Tang #include <stdio.h> 11*a1763ae9SXiangzhi Tang 12*a1763ae9SXiangzhi Tang #include <arch_helpers.h> 13*a1763ae9SXiangzhi Tang #include <common/debug.h> 14*a1763ae9SXiangzhi Tang #include <lib/mmio.h> 15*a1763ae9SXiangzhi Tang #include <lib/xlat_tables/xlat_tables_v2.h> 16*a1763ae9SXiangzhi Tang #include <smccc_helpers.h> 17*a1763ae9SXiangzhi Tang 18*a1763ae9SXiangzhi Tang #include "mmup_common.h" 19*a1763ae9SXiangzhi Tang #include <mtk_mmap_pool.h> 20*a1763ae9SXiangzhi Tang #include <mtk_sip_svc.h> 21*a1763ae9SXiangzhi Tang #include "vcp_helper.h" 22*a1763ae9SXiangzhi Tang #include "vcp_reg.h" 23*a1763ae9SXiangzhi Tang 24*a1763ae9SXiangzhi Tang #define MODULE_TAG "[VCP]" 25*a1763ae9SXiangzhi Tang 26*a1763ae9SXiangzhi Tang static const mmap_region_t vcp_mmap[] MTK_MMAP_SECTION = { 27*a1763ae9SXiangzhi Tang MAP_REGION_FLAT(VCP_R_CFGREG, MTK_VCP_REG_BANK_SIZE, 28*a1763ae9SXiangzhi Tang MT_DEVICE | MT_RW | MT_SECURE), 29*a1763ae9SXiangzhi Tang MAP_REGION_FLAT(VCP_R_CFGREG_CORE0, MTK_VCP_REG_BANK_SIZE, 30*a1763ae9SXiangzhi Tang MT_DEVICE | MT_RW | MT_SECURE), 31*a1763ae9SXiangzhi Tang MAP_REGION_FLAT(VCP_R_CFGREG_CORE1, MTK_VCP_REG_BANK_SIZE, 32*a1763ae9SXiangzhi Tang MT_DEVICE | MT_RW | MT_SECURE), 33*a1763ae9SXiangzhi Tang MAP_REGION_FLAT(VCP_R_SEC_CTRL, MTK_VCP_REG_BANK_SIZE, 34*a1763ae9SXiangzhi Tang MT_DEVICE | MT_RW | MT_SECURE), 35*a1763ae9SXiangzhi Tang {0} 36*a1763ae9SXiangzhi Tang }; 37*a1763ae9SXiangzhi Tang DECLARE_MTK_MMAP_REGIONS(vcp_mmap); 38*a1763ae9SXiangzhi Tang 39*a1763ae9SXiangzhi Tang /* vcp-mmup l2tcm memory offset */ 40*a1763ae9SXiangzhi Tang static uint64_t g_l2tcm_offset; 41*a1763ae9SXiangzhi Tang static uint32_t g_mmup_fw_size; 42*a1763ae9SXiangzhi Tang 43*a1763ae9SXiangzhi Tang static bool get_vcp_pwr_status(void) 44*a1763ae9SXiangzhi Tang { 45*a1763ae9SXiangzhi Tang #if defined(SPM_BASE) 46*a1763ae9SXiangzhi Tang uint32_t spm_pwr_sta = mmio_read_32(SPM_BASE + VCP_POWER_STATUS); 47*a1763ae9SXiangzhi Tang 48*a1763ae9SXiangzhi Tang if (!(spm_pwr_sta & (MMUP_PWR_STA_EN << MMUP_PWR_STA_BIT))) { 49*a1763ae9SXiangzhi Tang ERROR("%s: pwr_sta:%x, bit:%d disable\n", MODULE_TAG, 50*a1763ae9SXiangzhi Tang spm_pwr_sta, MMUP_PWR_STA_BIT); 51*a1763ae9SXiangzhi Tang return false; 52*a1763ae9SXiangzhi Tang } 53*a1763ae9SXiangzhi Tang #endif 54*a1763ae9SXiangzhi Tang return true; 55*a1763ae9SXiangzhi Tang } 56*a1763ae9SXiangzhi Tang 57*a1763ae9SXiangzhi Tang uint32_t get_mmup_fw_size(void) 58*a1763ae9SXiangzhi Tang { 59*a1763ae9SXiangzhi Tang return g_mmup_fw_size; 60*a1763ae9SXiangzhi Tang } 61*a1763ae9SXiangzhi Tang 62*a1763ae9SXiangzhi Tang uint64_t get_mmup_l2tcm_offset(void) 63*a1763ae9SXiangzhi Tang { 64*a1763ae9SXiangzhi Tang return g_l2tcm_offset; 65*a1763ae9SXiangzhi Tang } 66*a1763ae9SXiangzhi Tang 67*a1763ae9SXiangzhi Tang static bool vcp_cold_boot_reset(void) 68*a1763ae9SXiangzhi Tang { 69*a1763ae9SXiangzhi Tang mmio_write_32(VCP_GPR2_CFGREG_SEC, 0); 70*a1763ae9SXiangzhi Tang mmio_write_32(VCP_GPR3_CFGREG_SEC, 0); 71*a1763ae9SXiangzhi Tang 72*a1763ae9SXiangzhi Tang return true; 73*a1763ae9SXiangzhi Tang } 74*a1763ae9SXiangzhi Tang 75*a1763ae9SXiangzhi Tang static bool mmup_cold_boot_reset(void) 76*a1763ae9SXiangzhi Tang { 77*a1763ae9SXiangzhi Tang mmio_write_32(VCP_GPR0_CFGREG_SEC, 0); 78*a1763ae9SXiangzhi Tang mmio_write_32(VCP_GPR1_CFGREG_SEC, 0); 79*a1763ae9SXiangzhi Tang 80*a1763ae9SXiangzhi Tang return true; 81*a1763ae9SXiangzhi Tang } 82*a1763ae9SXiangzhi Tang 83*a1763ae9SXiangzhi Tang static bool vcp_set_mmup_l2tcm_offset(uint64_t l2tcm_offset) 84*a1763ae9SXiangzhi Tang { 85*a1763ae9SXiangzhi Tang g_l2tcm_offset = l2tcm_offset; 86*a1763ae9SXiangzhi Tang 87*a1763ae9SXiangzhi Tang if (g_l2tcm_offset > MTK_VCP_SRAM_SIZE) { 88*a1763ae9SXiangzhi Tang g_l2tcm_offset = 0; 89*a1763ae9SXiangzhi Tang return false; 90*a1763ae9SXiangzhi Tang } 91*a1763ae9SXiangzhi Tang 92*a1763ae9SXiangzhi Tang return true; 93*a1763ae9SXiangzhi Tang } 94*a1763ae9SXiangzhi Tang 95*a1763ae9SXiangzhi Tang static bool vcp_set_mmup_fw_size(uint64_t fw_size) 96*a1763ae9SXiangzhi Tang { 97*a1763ae9SXiangzhi Tang g_mmup_fw_size = fw_size; 98*a1763ae9SXiangzhi Tang 99*a1763ae9SXiangzhi Tang if (g_mmup_fw_size > MTK_VCP_SRAM_SIZE - g_l2tcm_offset) { 100*a1763ae9SXiangzhi Tang g_mmup_fw_size = 0; 101*a1763ae9SXiangzhi Tang return false; 102*a1763ae9SXiangzhi Tang } 103*a1763ae9SXiangzhi Tang 104*a1763ae9SXiangzhi Tang return true; 105*a1763ae9SXiangzhi Tang } 106*a1763ae9SXiangzhi Tang 107*a1763ae9SXiangzhi Tang static bool vcp_smc_rstn_set(bool boot_ok) 108*a1763ae9SXiangzhi Tang { 109*a1763ae9SXiangzhi Tang if (mmio_read_32(VCP_GPR_C0_H0_REBOOT) != 0 && 110*a1763ae9SXiangzhi Tang mmio_read_32(VCP_R_CORE0_STATUS) != 0 && 111*a1763ae9SXiangzhi Tang (mmio_read_32(VCP_R_GIPC_IN_SET) & B_GIPC3_SETCLR_1) == 0 && 112*a1763ae9SXiangzhi Tang (mmio_read_32(VCP_R_GIPC_IN_CLR) & B_GIPC3_SETCLR_1) == 0 && 113*a1763ae9SXiangzhi Tang mmio_read_32(VCP_GPR_C0_H0_REBOOT) != VCP_CORE_RDY_TO_REBOOT && 114*a1763ae9SXiangzhi Tang mmio_read_32(VCP_GPR_C0_H1_REBOOT) != VCP_CORE_RDY_TO_REBOOT) { 115*a1763ae9SXiangzhi Tang ERROR("%s: [%s] mmup reset set fail!GIPC 0x%x 0x%x REBOOT 0x%x 0x%x\n", 116*a1763ae9SXiangzhi Tang MODULE_TAG, __func__, mmio_read_32(VCP_R_GIPC_IN_SET), 117*a1763ae9SXiangzhi Tang mmio_read_32(VCP_R_GIPC_IN_CLR), 118*a1763ae9SXiangzhi Tang mmio_read_32(VCP_GPR_C0_H0_REBOOT), 119*a1763ae9SXiangzhi Tang mmio_read_32(VCP_GPR_C0_H1_REBOOT)); 120*a1763ae9SXiangzhi Tang return false; 121*a1763ae9SXiangzhi Tang } 122*a1763ae9SXiangzhi Tang 123*a1763ae9SXiangzhi Tang mmio_write_32(VCP_R_CORE0_SW_RSTN_SET, BIT(0)); 124*a1763ae9SXiangzhi Tang 125*a1763ae9SXiangzhi Tang /* reset sec control */ 126*a1763ae9SXiangzhi Tang mmio_write_32(VCP_R_SEC_CTRL_2, 0); 127*a1763ae9SXiangzhi Tang 128*a1763ae9SXiangzhi Tang /* reset domain setting */ 129*a1763ae9SXiangzhi Tang mmio_write_32(VCP_R_S_DOM_EN0_31, 0x0); 130*a1763ae9SXiangzhi Tang mmio_write_32(VCP_R_S_DOM_EN32_63, 0x0); 131*a1763ae9SXiangzhi Tang mmio_write_32(VCP_R_NS_DOM_EN0_31, 0x0); 132*a1763ae9SXiangzhi Tang mmio_write_32(VCP_R_NS_DOM_EN32_63, 0x0); 133*a1763ae9SXiangzhi Tang 134*a1763ae9SXiangzhi Tang /* reset sec setting */ 135*a1763ae9SXiangzhi Tang mmio_clrbits_32(VCP_R_DYN_SECURE, 136*a1763ae9SXiangzhi Tang RESET_NS_SECURE_B_REGION << VCP_NS_SECURE_B_REGION_ENABLE); 137*a1763ae9SXiangzhi Tang 138*a1763ae9SXiangzhi Tang if (boot_ok) { 139*a1763ae9SXiangzhi Tang mmio_write_32(VCP_GPR_C0_H0_REBOOT, VCP_CORE_REBOOT_OK); 140*a1763ae9SXiangzhi Tang mmio_write_32(VCP_GPR_C0_H1_REBOOT, VCP_CORE_REBOOT_OK); 141*a1763ae9SXiangzhi Tang } 142*a1763ae9SXiangzhi Tang 143*a1763ae9SXiangzhi Tang dsbsy(); 144*a1763ae9SXiangzhi Tang return true; 145*a1763ae9SXiangzhi Tang } 146*a1763ae9SXiangzhi Tang 147*a1763ae9SXiangzhi Tang static bool vcp_smc_rstn_clr(void) 148*a1763ae9SXiangzhi Tang { 149*a1763ae9SXiangzhi Tang if ((mmio_read_32(VCP_R_CORE0_SW_RSTN_SET) & BIT(0)) == 1) { 150*a1763ae9SXiangzhi Tang ERROR("%s: [%s] mmup not reset set !\n", MODULE_TAG, __func__); 151*a1763ae9SXiangzhi Tang return false; 152*a1763ae9SXiangzhi Tang } 153*a1763ae9SXiangzhi Tang 154*a1763ae9SXiangzhi Tang mmio_clrsetbits_32(VCP_R_SEC_DOMAIN, 155*a1763ae9SXiangzhi Tang ~(VCP_DOMAIN_MASK << VCP_HWCCF_DOMAIN), VCP_DOMAIN_SET); 156*a1763ae9SXiangzhi Tang 157*a1763ae9SXiangzhi Tang /* enable IOVA Mode */ 158*a1763ae9SXiangzhi Tang mmio_write_32(VCP_R_AXIOMMUEN_DEV_APC, BIT(0)); 159*a1763ae9SXiangzhi Tang 160*a1763ae9SXiangzhi Tang /* reset secure setting */ 161*a1763ae9SXiangzhi Tang mmio_setbits_32(VCP_R_SEC_CTRL_2, CORE0_SEC_BIT_SEL); 162*a1763ae9SXiangzhi Tang mmio_clrbits_32(VCP_R_DYN_SECURE, VCP_NS_I0 | VCP_NS_D0); 163*a1763ae9SXiangzhi Tang mmio_clrbits_32(VCP_R_DYN_SECURE_TH1, VCP_NS_I1 | VCP_NS_D1); 164*a1763ae9SXiangzhi Tang 165*a1763ae9SXiangzhi Tang /* start vcp */ 166*a1763ae9SXiangzhi Tang mmio_write_32(VCP_R_CORE0_SW_RSTN_CLR, BIT(0)); 167*a1763ae9SXiangzhi Tang dsbsy(); 168*a1763ae9SXiangzhi Tang return true; 169*a1763ae9SXiangzhi Tang } 170*a1763ae9SXiangzhi Tang 171*a1763ae9SXiangzhi Tang static u_register_t tinysys_vcp_kernel_control(u_register_t arg0, 172*a1763ae9SXiangzhi Tang u_register_t arg1, 173*a1763ae9SXiangzhi Tang u_register_t arg2, 174*a1763ae9SXiangzhi Tang u_register_t arg3, 175*a1763ae9SXiangzhi Tang void *handle, 176*a1763ae9SXiangzhi Tang struct smccc_res *smccc_ret) 177*a1763ae9SXiangzhi Tang { 178*a1763ae9SXiangzhi Tang uint32_t request_ops; 179*a1763ae9SXiangzhi Tang uint64_t ret = MTK_SIP_E_SUCCESS; 180*a1763ae9SXiangzhi Tang 181*a1763ae9SXiangzhi Tang if (!get_vcp_pwr_status()) 182*a1763ae9SXiangzhi Tang return MTK_SIP_E_NOT_SUPPORTED; 183*a1763ae9SXiangzhi Tang 184*a1763ae9SXiangzhi Tang request_ops = (uint32_t)arg0; 185*a1763ae9SXiangzhi Tang 186*a1763ae9SXiangzhi Tang switch (request_ops) { 187*a1763ae9SXiangzhi Tang case MTK_TINYSYS_VCP_KERNEL_OP_RESET_SET: 188*a1763ae9SXiangzhi Tang ret = vcp_smc_rstn_set((bool)!!arg1); 189*a1763ae9SXiangzhi Tang break; 190*a1763ae9SXiangzhi Tang case MTK_TINYSYS_VCP_KERNEL_OP_RESET_RELEASE: 191*a1763ae9SXiangzhi Tang ret = vcp_smc_rstn_clr(); 192*a1763ae9SXiangzhi Tang break; 193*a1763ae9SXiangzhi Tang case MTK_TINYSYS_VCP_KERNEL_OP_COLD_BOOT_VCP: 194*a1763ae9SXiangzhi Tang ret = vcp_cold_boot_reset(); 195*a1763ae9SXiangzhi Tang break; 196*a1763ae9SXiangzhi Tang case MTK_TINYSYS_MMUP_KERNEL_OP_RESET_SET: 197*a1763ae9SXiangzhi Tang ret = mmup_smc_rstn_set((bool)!!arg1); 198*a1763ae9SXiangzhi Tang break; 199*a1763ae9SXiangzhi Tang case MTK_TINYSYS_MMUP_KERNEL_OP_RESET_RELEASE: 200*a1763ae9SXiangzhi Tang ret = mmup_smc_rstn_clr(); 201*a1763ae9SXiangzhi Tang break; 202*a1763ae9SXiangzhi Tang case MTK_TINYSYS_MMUP_KERNEL_OP_SET_L2TCM_OFFSET: 203*a1763ae9SXiangzhi Tang ret = vcp_set_mmup_l2tcm_offset(arg1); 204*a1763ae9SXiangzhi Tang break; 205*a1763ae9SXiangzhi Tang case MTK_TINYSYS_MMUP_KERNEL_OP_SET_FW_SIZE: 206*a1763ae9SXiangzhi Tang ret = vcp_set_mmup_fw_size(arg1); 207*a1763ae9SXiangzhi Tang break; 208*a1763ae9SXiangzhi Tang case MTK_TINYSYS_MMUP_KERNEL_OP_COLD_BOOT_MMUP: 209*a1763ae9SXiangzhi Tang ret = mmup_cold_boot_reset(); 210*a1763ae9SXiangzhi Tang break; 211*a1763ae9SXiangzhi Tang default: 212*a1763ae9SXiangzhi Tang ERROR("%s: %s, unknown request_ops = %x\n", MODULE_TAG, __func__, request_ops); 213*a1763ae9SXiangzhi Tang ret = MTK_SIP_E_INVALID_PARAM; 214*a1763ae9SXiangzhi Tang break; 215*a1763ae9SXiangzhi Tang } 216*a1763ae9SXiangzhi Tang 217*a1763ae9SXiangzhi Tang return ret; 218*a1763ae9SXiangzhi Tang } 219*a1763ae9SXiangzhi Tang 220*a1763ae9SXiangzhi Tang /* Register SiP SMC service */ 221*a1763ae9SXiangzhi Tang DECLARE_SMC_HANDLER(MTK_SIP_KERNEL_VCP_CONTROL, tinysys_vcp_kernel_control); 222