xref: /rk3399_ARM-atf/plat/mediatek/drivers/spm/mt8189/mt_spm.c (revision af0370f25a6663a0d737bbfb3985df4232eaaa55)
1*5f748b3cSKun Lu /*
2*5f748b3cSKun Lu  * Copyright (c) 2025, Mediatek Inc. All rights reserved.
3*5f748b3cSKun Lu  *
4*5f748b3cSKun Lu  * SPDX-License-Identifier: BSD-3-Clause
5*5f748b3cSKun Lu  */
6*5f748b3cSKun Lu 
7*5f748b3cSKun Lu #include <assert.h>
8*5f748b3cSKun Lu #include <stddef.h>
9*5f748b3cSKun Lu #include <stdio.h>
10*5f748b3cSKun Lu #include <string.h>
11*5f748b3cSKun Lu 
12*5f748b3cSKun Lu #include <arch.h>
13*5f748b3cSKun Lu #include <common/debug.h>
14*5f748b3cSKun Lu #include <drivers/console.h>
15*5f748b3cSKun Lu #include <lib/bakery_lock.h>
16*5f748b3cSKun Lu #include <lib/mmio.h>
17*5f748b3cSKun Lu #include <lib/utils_def.h>
18*5f748b3cSKun Lu 
19*5f748b3cSKun Lu #include <constraints/mt_spm_rc_api.h>
20*5f748b3cSKun Lu #include <constraints/mt_spm_rc_internal.h>
21*5f748b3cSKun Lu #include <drivers/spm/mt_spm_resource_req.h>
22*5f748b3cSKun Lu #include <lib/mtk_init/mtk_init.h>
23*5f748b3cSKun Lu #include <lib/pm/mtk_pm.h>
24*5f748b3cSKun Lu #include <lpm_v2/mt_lp_rm.h>
25*5f748b3cSKun Lu #include <lpm_v2/mt_lp_rqm.h>
26*5f748b3cSKun Lu #include <lpm_v2/mt_lpm_smc.h>
27*5f748b3cSKun Lu #include <mt_cirq.h>
28*5f748b3cSKun Lu #include <mt_gic_v3.h>
29*5f748b3cSKun Lu #include <mt_plat_spm_setting.h>
30*5f748b3cSKun Lu #include <mt_spm.h>
31*5f748b3cSKun Lu #include <mt_spm_common.h>
32*5f748b3cSKun Lu #include <mt_spm_conservation.h>
33*5f748b3cSKun Lu #include <mt_spm_constraint.h>
34*5f748b3cSKun Lu #include <mt_spm_dispatcher.h>
35*5f748b3cSKun Lu #include <mt_spm_hwreq.h>
36*5f748b3cSKun Lu #include <mt_spm_idle.h>
37*5f748b3cSKun Lu #include <mt_spm_internal.h>
38*5f748b3cSKun Lu #include <mt_spm_reg.h>
39*5f748b3cSKun Lu #include <mt_spm_suspend.h>
40*5f748b3cSKun Lu #include <mtk_mmap_pool.h>
41*5f748b3cSKun Lu #include <platform_def.h>
42*5f748b3cSKun Lu #include <sleep_def.h>
43*5f748b3cSKun Lu 
44*5f748b3cSKun Lu #ifdef MT_SPM_USING_BAKERY_LOCK
45*5f748b3cSKun Lu DEFINE_BAKERY_LOCK(spm_lock);
46*5f748b3cSKun Lu #define plat_spm_lock_init() bakery_lock_init(&spm_lock)
47*5f748b3cSKun Lu #else
48*5f748b3cSKun Lu spinlock_t spm_lock;
49*5f748b3cSKun Lu #define plat_spm_lock_init()
50*5f748b3cSKun Lu #endif
51*5f748b3cSKun Lu 
52*5f748b3cSKun Lu static uint32_t spm_irq_num;
53*5f748b3cSKun Lu 
spm_set_sysclk_settle(void)54*5f748b3cSKun Lu void spm_set_sysclk_settle(void)
55*5f748b3cSKun Lu {
56*5f748b3cSKun Lu 	uint32_t settle;
57*5f748b3cSKun Lu 
58*5f748b3cSKun Lu 	mmio_write_32(SPM_CLK_SETTLE, SPM_SYSCLK_SETTLE);
59*5f748b3cSKun Lu 	settle = mmio_read_32(SPM_CLK_SETTLE);
60*5f748b3cSKun Lu 
61*5f748b3cSKun Lu 	INFO("md_settle = %u, settle = %u\n", SPM_SYSCLK_SETTLE, settle);
62*5f748b3cSKun Lu }
63*5f748b3cSKun Lu 
spm_set_irq_num(uint32_t num)64*5f748b3cSKun Lu void spm_set_irq_num(uint32_t num)
65*5f748b3cSKun Lu {
66*5f748b3cSKun Lu 	spm_irq_num = num;
67*5f748b3cSKun Lu }
68*5f748b3cSKun Lu 
spm_irq0_handler(uint64_t x1,uint64_t x2)69*5f748b3cSKun Lu void spm_irq0_handler(uint64_t x1, uint64_t x2)
70*5f748b3cSKun Lu {
71*5f748b3cSKun Lu 	if (x2 == 0) {
72*5f748b3cSKun Lu 		mmio_setbits_32(SPM_IRQ_MASK, ISRM_ALL_EXC_TWAM);
73*5f748b3cSKun Lu 		mmio_write_32(SPM_IRQ_STA, x1);
74*5f748b3cSKun Lu 		mmio_write_32(SPM_SWINT_CLR, PCM_SW_INT0);
75*5f748b3cSKun Lu 	}
76*5f748b3cSKun Lu }
77*5f748b3cSKun Lu 
spm_ap_mdsrc_ack(void)78*5f748b3cSKun Lu static int spm_ap_mdsrc_ack(void)
79*5f748b3cSKun Lu {
80*5f748b3cSKun Lu 	int ack, md_state = 0;
81*5f748b3cSKun Lu 
82*5f748b3cSKun Lu 	/* Check ap_mdsrc_ack = 1'b1, for md internal resource on ack */
83*5f748b3cSKun Lu 	ack = !!(mmio_read_32(AP_MDSRC_REQ) & AP_MDSMSRC_ACK_LSB);
84*5f748b3cSKun Lu 
85*5f748b3cSKun Lu 	if (!ack) {
86*5f748b3cSKun Lu 		/* Check md_apsrc_req = 1'b0, for md state 0:sleep, 1:wakeup */
87*5f748b3cSKun Lu 		md_state = !!(mmio_read_32(SPM_REQ_STA_9) & MD_APSRC_REQ_LSB);
88*5f748b3cSKun Lu 
89*5f748b3cSKun Lu 		ERROR("[SPM] error: md_sleep = %d\n", md_state);
90*5f748b3cSKun Lu 		ERROR("%s can not get AP_MDSRC_ACK\n", __func__);
91*5f748b3cSKun Lu 		return -1;
92*5f748b3cSKun Lu 	}
93*5f748b3cSKun Lu 	return 0;
94*5f748b3cSKun Lu }
95*5f748b3cSKun Lu 
spm_ap_mdsrc_req(int set)96*5f748b3cSKun Lu static void spm_ap_mdsrc_req(int set)
97*5f748b3cSKun Lu {
98*5f748b3cSKun Lu 	spm_lock_get();
99*5f748b3cSKun Lu 
100*5f748b3cSKun Lu 	if (set)
101*5f748b3cSKun Lu 		mmio_setbits_32(AP_MDSRC_REQ, AP_MDSMSRC_REQ_LSB);
102*5f748b3cSKun Lu 	else
103*5f748b3cSKun Lu 		mmio_clrbits_32(AP_MDSRC_REQ, AP_MDSMSRC_REQ_LSB);
104*5f748b3cSKun Lu 
105*5f748b3cSKun Lu 	spm_lock_release();
106*5f748b3cSKun Lu }
107*5f748b3cSKun Lu 
spm_is_md_sleep(void * priv)108*5f748b3cSKun Lu static int spm_is_md_sleep(void *priv)
109*5f748b3cSKun Lu {
110*5f748b3cSKun Lu 	int md_state = 0;
111*5f748b3cSKun Lu 	int *sleep = (int *)priv;
112*5f748b3cSKun Lu 
113*5f748b3cSKun Lu 	if (!priv)
114*5f748b3cSKun Lu 		return -1;
115*5f748b3cSKun Lu 
116*5f748b3cSKun Lu 	/* Check md_apsrc_req = 1'b0, for md state 0:sleep, 1:wakeup */
117*5f748b3cSKun Lu 	md_state = !!(mmio_read_32(SPM_REQ_STA_9) & MD_APSRC_REQ_LSB);
118*5f748b3cSKun Lu 
119*5f748b3cSKun Lu 	if (md_state == 0)
120*5f748b3cSKun Lu 		*sleep = 1;
121*5f748b3cSKun Lu 	else
122*5f748b3cSKun Lu 		*sleep = 0;
123*5f748b3cSKun Lu 
124*5f748b3cSKun Lu 	return 0;
125*5f748b3cSKun Lu }
126*5f748b3cSKun Lu 
spm_ap_gpueb_pll_control(int set)127*5f748b3cSKun Lu static void spm_ap_gpueb_pll_control(int set)
128*5f748b3cSKun Lu {
129*5f748b3cSKun Lu 	spm_lock_get();
130*5f748b3cSKun Lu 
131*5f748b3cSKun Lu 	if (set)
132*5f748b3cSKun Lu 		mmio_setbits_32(SPM2GPUPM_CON, SC_MFG_PLL_EN_LSB);
133*5f748b3cSKun Lu 	else
134*5f748b3cSKun Lu 		mmio_clrbits_32(SPM2GPUPM_CON, SC_MFG_PLL_EN_LSB);
135*5f748b3cSKun Lu 
136*5f748b3cSKun Lu 	spm_lock_release();
137*5f748b3cSKun Lu }
138*5f748b3cSKun Lu 
spm_ap_gpueb_get_pwr_status(void)139*5f748b3cSKun Lu static uint32_t spm_ap_gpueb_get_pwr_status(void)
140*5f748b3cSKun Lu {
141*5f748b3cSKun Lu 	uint32_t ret;
142*5f748b3cSKun Lu 
143*5f748b3cSKun Lu 	ret = mmio_read_32(XPU_PWR_STATUS);
144*5f748b3cSKun Lu 
145*5f748b3cSKun Lu 	return ret;
146*5f748b3cSKun Lu }
147*5f748b3cSKun Lu 
spm_ap_gpueb_get_mfg0_pwr_con(void)148*5f748b3cSKun Lu static uint32_t spm_ap_gpueb_get_mfg0_pwr_con(void)
149*5f748b3cSKun Lu {
150*5f748b3cSKun Lu 	uint32_t ret;
151*5f748b3cSKun Lu 
152*5f748b3cSKun Lu 	ret = mmio_read_32(MFG0_PWR_CON);
153*5f748b3cSKun Lu 
154*5f748b3cSKun Lu 	return ret;
155*5f748b3cSKun Lu }
156*5f748b3cSKun Lu 
157*5f748b3cSKun Lu #ifndef MTK_PLAT_SPM_UNSUPPORT
158*5f748b3cSKun Lu struct mt_lp_res_req rq_xo_fpm = {
159*5f748b3cSKun Lu 	.res_id = MT_LP_RQ_XO_FPM,
160*5f748b3cSKun Lu 	.res_rq = MT_SPM_XO_FPM,
161*5f748b3cSKun Lu 	.res_usage = 0,
162*5f748b3cSKun Lu };
163*5f748b3cSKun Lu 
164*5f748b3cSKun Lu struct mt_lp_res_req rq_26m = {
165*5f748b3cSKun Lu 	.res_id = MT_LP_RQ_26M,
166*5f748b3cSKun Lu 	.res_rq = MT_SPM_26M,
167*5f748b3cSKun Lu 	.res_usage = 0,
168*5f748b3cSKun Lu };
169*5f748b3cSKun Lu 
170*5f748b3cSKun Lu struct mt_lp_res_req rq_infra = {
171*5f748b3cSKun Lu 	.res_id = MT_LP_RQ_INFRA,
172*5f748b3cSKun Lu 	.res_rq = MT_SPM_INFRA,
173*5f748b3cSKun Lu 	.res_usage = 0,
174*5f748b3cSKun Lu };
175*5f748b3cSKun Lu 
176*5f748b3cSKun Lu struct mt_lp_res_req rq_syspll = {
177*5f748b3cSKun Lu 	.res_id = MT_LP_RQ_SYSPLL,
178*5f748b3cSKun Lu 	.res_rq = MT_SPM_SYSPLL,
179*5f748b3cSKun Lu 	.res_usage = 0,
180*5f748b3cSKun Lu };
181*5f748b3cSKun Lu 
182*5f748b3cSKun Lu struct mt_lp_res_req rq_dram_s0 = {
183*5f748b3cSKun Lu 	.res_id = MT_LP_RQ_DRAM,
184*5f748b3cSKun Lu 	.res_rq = MT_SPM_DRAM_S0,
185*5f748b3cSKun Lu 	.res_usage = 0,
186*5f748b3cSKun Lu };
187*5f748b3cSKun Lu 
188*5f748b3cSKun Lu struct mt_lp_res_req rq_dram_s1 = {
189*5f748b3cSKun Lu 	.res_id = MT_LP_RQ_DRAM,
190*5f748b3cSKun Lu 	.res_rq = MT_SPM_DRAM_S1,
191*5f748b3cSKun Lu 	.res_usage = 0,
192*5f748b3cSKun Lu };
193*5f748b3cSKun Lu 
194*5f748b3cSKun Lu struct mt_lp_res_req rq_vcore = {
195*5f748b3cSKun Lu 	.res_id = MT_LP_RQ_VCORE,
196*5f748b3cSKun Lu 	.res_rq = MT_SPM_VCORE,
197*5f748b3cSKun Lu 	.res_usage = 0,
198*5f748b3cSKun Lu };
199*5f748b3cSKun Lu 
200*5f748b3cSKun Lu struct mt_lp_res_req rq_emi = {
201*5f748b3cSKun Lu 	.res_id = MT_LP_RQ_EMI,
202*5f748b3cSKun Lu 	.res_rq = MT_SPM_EMI,
203*5f748b3cSKun Lu 	.res_usage = 0,
204*5f748b3cSKun Lu };
205*5f748b3cSKun Lu 
206*5f748b3cSKun Lu struct mt_lp_res_req rq_pmic = {
207*5f748b3cSKun Lu 	.res_id = MT_LP_RQ_PMIC,
208*5f748b3cSKun Lu 	.res_rq = MT_SPM_PMIC,
209*5f748b3cSKun Lu 	.res_usage = 0,
210*5f748b3cSKun Lu };
211*5f748b3cSKun Lu 
212*5f748b3cSKun Lu struct mt_lp_res_req *spm_resources[] = {
213*5f748b3cSKun Lu 	&rq_xo_fpm,  &rq_26m,	&rq_infra, &rq_syspll, &rq_dram_s0,
214*5f748b3cSKun Lu 	&rq_dram_s1, &rq_vcore, &rq_emi,   &rq_pmic,   NULL,
215*5f748b3cSKun Lu };
216*5f748b3cSKun Lu 
217*5f748b3cSKun Lu struct mt_resource_req_manager plat_mt8189_rq = {
218*5f748b3cSKun Lu 	.res = spm_resources,
219*5f748b3cSKun Lu };
220*5f748b3cSKun Lu 
221*5f748b3cSKun Lu struct mt_resource_constraint plat_constraint_vcore = {
222*5f748b3cSKun Lu 	.is_valid = spm_is_valid_rc_vcore,
223*5f748b3cSKun Lu 	.update = spm_update_rc_vcore,
224*5f748b3cSKun Lu 	.allow = spm_allow_rc_vcore,
225*5f748b3cSKun Lu 	.run = spm_run_rc_vcore,
226*5f748b3cSKun Lu 	.reset = spm_reset_rc_vcore,
227*5f748b3cSKun Lu 	.get_status = spm_get_status_rc_vcore,
228*5f748b3cSKun Lu };
229*5f748b3cSKun Lu 
230*5f748b3cSKun Lu struct mt_resource_constraint plat_constraint_bus26m = {
231*5f748b3cSKun Lu 	.is_valid = spm_is_valid_rc_bus26m,
232*5f748b3cSKun Lu 	.update = spm_update_rc_bus26m,
233*5f748b3cSKun Lu 	.allow = spm_allow_rc_bus26m,
234*5f748b3cSKun Lu 	.run = spm_run_rc_bus26m,
235*5f748b3cSKun Lu 	.reset = spm_reset_rc_bus26m,
236*5f748b3cSKun Lu 	.get_status = spm_get_status_rc_bus26m,
237*5f748b3cSKun Lu };
238*5f748b3cSKun Lu struct mt_resource_constraint plat_constraint_syspll = {
239*5f748b3cSKun Lu 	.is_valid = spm_is_valid_rc_syspll,
240*5f748b3cSKun Lu 	.update = spm_update_rc_syspll,
241*5f748b3cSKun Lu 	.allow = spm_allow_rc_syspll,
242*5f748b3cSKun Lu 	.run = spm_run_rc_syspll,
243*5f748b3cSKun Lu 	.reset = spm_reset_rc_syspll,
244*5f748b3cSKun Lu 	.get_status = spm_get_status_rc_syspll,
245*5f748b3cSKun Lu };
246*5f748b3cSKun Lu 
247*5f748b3cSKun Lu struct mt_resource_constraint *plat_constraints[] = {
248*5f748b3cSKun Lu 	&plat_constraint_vcore,
249*5f748b3cSKun Lu 	&plat_constraint_bus26m,
250*5f748b3cSKun Lu 	&plat_constraint_syspll,
251*5f748b3cSKun Lu 	NULL,
252*5f748b3cSKun Lu };
253*5f748b3cSKun Lu #endif
254*5f748b3cSKun Lu 
mt_spm_hwctrl(uint32_t type,int set,void * priv)255*5f748b3cSKun Lu int mt_spm_hwctrl(uint32_t type, int set, void *priv)
256*5f748b3cSKun Lu {
257*5f748b3cSKun Lu 	int ret = 0;
258*5f748b3cSKun Lu 
259*5f748b3cSKun Lu 	switch (type) {
260*5f748b3cSKun Lu 	case PLAT_AP_MDSRC_REQ:
261*5f748b3cSKun Lu 		spm_ap_mdsrc_req(set);
262*5f748b3cSKun Lu 		break;
263*5f748b3cSKun Lu 	case PLAT_AP_MDSRC_ACK:
264*5f748b3cSKun Lu 		ret = spm_ap_mdsrc_ack();
265*5f748b3cSKun Lu 		break;
266*5f748b3cSKun Lu 	case PLAT_AP_IS_MD_SLEEP:
267*5f748b3cSKun Lu 		ret = spm_is_md_sleep(priv);
268*5f748b3cSKun Lu 		break;
269*5f748b3cSKun Lu 	case PLAT_AP_MDSRC_SETTLE:
270*5f748b3cSKun Lu 		if (!priv)
271*5f748b3cSKun Lu 			return -1;
272*5f748b3cSKun Lu 		*(int *)priv = AP_MDSRC_REQ_MD_26M_SETTLE;
273*5f748b3cSKun Lu 		break;
274*5f748b3cSKun Lu 	case PLAT_AP_GPUEB_PLL_CONTROL:
275*5f748b3cSKun Lu 		spm_ap_gpueb_pll_control(set);
276*5f748b3cSKun Lu 		break;
277*5f748b3cSKun Lu 	case PLAT_AP_GPUEB_PWR_STATUS:
278*5f748b3cSKun Lu 		if (!priv)
279*5f748b3cSKun Lu 			return -1;
280*5f748b3cSKun Lu 		*(uint32_t *)priv = spm_ap_gpueb_get_pwr_status();
281*5f748b3cSKun Lu 		break;
282*5f748b3cSKun Lu 	case PLAT_AP_GPUEB_MFG0_PWR_CON:
283*5f748b3cSKun Lu 		if (!priv)
284*5f748b3cSKun Lu 			return -1;
285*5f748b3cSKun Lu 		*(uint32_t *)priv = spm_ap_gpueb_get_mfg0_pwr_con();
286*5f748b3cSKun Lu 		break;
287*5f748b3cSKun Lu 	case PLAT_AP_ASSERT_SPM_IRQ:
288*5f748b3cSKun Lu 		mt_irq_set_pending(spm_irq_num);
289*5f748b3cSKun Lu 		break;
290*5f748b3cSKun Lu 	case PLAT_AP_SPM_RESOURCE_REQUEST_UPDATE:
291*5f748b3cSKun Lu 		struct spm_lp_scen *spmlp;
292*5f748b3cSKun Lu 
293*5f748b3cSKun Lu #if defined(MT_SPM_FEATURE_SUPPORT)
294*5f748b3cSKun Lu 		mt_spm_idle_generic_get_spm_lp(&spmlp);
295*5f748b3cSKun Lu #endif
296*5f748b3cSKun Lu 		if (!spmlp)
297*5f748b3cSKun Lu 			return -1;
298*5f748b3cSKun Lu 		__spm_set_power_control(spmlp->pwrctrl, *(uint32_t *)priv);
299*5f748b3cSKun Lu 		ret = __spm_wait_spm_request_ack(*(uint32_t *)priv, SPM_ACK_TIMEOUT_US);
300*5f748b3cSKun Lu 		break;
301*5f748b3cSKun Lu 	default:
302*5f748b3cSKun Lu 		/* not supported type */
303*5f748b3cSKun Lu 		ret = -1;
304*5f748b3cSKun Lu 		break;
305*5f748b3cSKun Lu 	}
306*5f748b3cSKun Lu 
307*5f748b3cSKun Lu 	return ret;
308*5f748b3cSKun Lu }
309*5f748b3cSKun Lu 
310*5f748b3cSKun Lu #ifndef MTK_PLAT_SPM_UNSUPPORT
311*5f748b3cSKun Lu struct mt_resource_manager plat_mt8189_rm = {
312*5f748b3cSKun Lu 	.update = NULL,
313*5f748b3cSKun Lu 	.hwctrl = mt_spm_hwctrl,
314*5f748b3cSKun Lu 	.consts = plat_constraints,
315*5f748b3cSKun Lu };
316*5f748b3cSKun Lu #else
317*5f748b3cSKun Lu struct mt_resource_manager plat_mt8189_rm = {
318*5f748b3cSKun Lu 	.hwctrl = mt_spm_hwctrl,
319*5f748b3cSKun Lu };
320*5f748b3cSKun Lu #endif
321*5f748b3cSKun Lu 
322*5f748b3cSKun Lu /* Determine for spm sw resource user */
323*5f748b3cSKun Lu static struct mt_lp_resource_user spm_res_user;
324*5f748b3cSKun Lu 
get_spm_res_user(void)325*5f748b3cSKun Lu struct mt_lp_resource_user *get_spm_res_user(void)
326*5f748b3cSKun Lu {
327*5f748b3cSKun Lu 	return &spm_res_user;
328*5f748b3cSKun Lu }
329*5f748b3cSKun Lu 
spm_boot_init(void)330*5f748b3cSKun Lu int spm_boot_init(void)
331*5f748b3cSKun Lu {
332*5f748b3cSKun Lu 	plat_spm_lock_init();
333*5f748b3cSKun Lu 
334*5f748b3cSKun Lu #if defined(MT_SPM_FEATURE_SUPPORT)
335*5f748b3cSKun Lu 	plat_spm_pmic_wrap_init();
336*5f748b3cSKun Lu #endif
337*5f748b3cSKun Lu 	plat_spm_cond_init();
338*5f748b3cSKun Lu 
339*5f748b3cSKun Lu 	mt_lp_rm_register(&plat_mt8189_rm);
340*5f748b3cSKun Lu 
341*5f748b3cSKun Lu /* If spm service won't run when spm not ready */
342*5f748b3cSKun Lu #ifndef MTK_PLAT_SPM_UNSUPPORT
343*5f748b3cSKun Lu 	mt_lp_resource_request_manager_register(&plat_mt8189_rq);
344*5f748b3cSKun Lu 	mt_lp_resource_user_register("SPM", &spm_res_user);
345*5f748b3cSKun Lu 	mt_spm_dispatcher_init();
346*5f748b3cSKun Lu #endif
347*5f748b3cSKun Lu #if defined(MT_SPM_FEATURE_SUPPORT)
348*5f748b3cSKun Lu 	spm_hwreq_init();
349*5f748b3cSKun Lu #endif
350*5f748b3cSKun Lu 
351*5f748b3cSKun Lu 	INFO("[%s:%d] - spm finished\n", __func__, __LINE__);
352*5f748b3cSKun Lu 	return 0;
353*5f748b3cSKun Lu }
354*5f748b3cSKun Lu MTK_ARCH_INIT(spm_boot_init);
355