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
get_vcp_pwr_status(void)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
get_mmup_fw_size(void)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
get_mmup_l2tcm_offset(void)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
vcp_cold_boot_reset(void)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
mmup_cold_boot_reset(void)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
vcp_set_mmup_l2tcm_offset(uint64_t l2tcm_offset)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
vcp_set_mmup_fw_size(uint64_t fw_size)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
vcp_smc_rstn_set(bool boot_ok)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
vcp_smc_rstn_clr(void)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
tinysys_vcp_kernel_control(u_register_t arg0,u_register_t arg1,u_register_t arg2,u_register_t arg3,void * handle,struct smccc_res * smccc_ret)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