xref: /rk3399_ARM-atf/plat/mediatek/drivers/spm/mt8189/mt_spm_conservation.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 <inttypes.h>
9*5f748b3cSKun Lu #include <stddef.h>
10*5f748b3cSKun Lu #include <stdint.h>
11*5f748b3cSKun Lu #include <stdio.h>
12*5f748b3cSKun Lu #include <string.h>
13*5f748b3cSKun Lu 
14*5f748b3cSKun Lu #include <common/debug.h>
15*5f748b3cSKun Lu #include <lib/mmio.h>
16*5f748b3cSKun Lu #include <plat/common/platform.h>
17*5f748b3cSKun Lu 
18*5f748b3cSKun Lu #include <lib/pm/mtk_pm.h>
19*5f748b3cSKun Lu #include <lpm_v2/mt_lp_rqm.h>
20*5f748b3cSKun Lu #include <mt_spm.h>
21*5f748b3cSKun Lu #include <mt_spm_common.h>
22*5f748b3cSKun Lu #include <mt_spm_conservation.h>
23*5f748b3cSKun Lu #include <mt_spm_reg.h>
24*5f748b3cSKun Lu #include <mt_spm_vcorefs.h>
25*5f748b3cSKun Lu #include <platform_def.h>
26*5f748b3cSKun Lu #ifndef MTK_PLAT_SPM_UART_UNSUPPORT
27*5f748b3cSKun Lu #include <uart.h>
28*5f748b3cSKun Lu #endif
29*5f748b3cSKun Lu 
30*5f748b3cSKun Lu #define MT_RESUMETIME_THRESHOLD_MAX 5 /*ms*/
31*5f748b3cSKun Lu #define IS_RESUME_OVERTIME(delta) (delta > MT_RESUMETIME_THRESHOLD_MAX)
32*5f748b3cSKun Lu 
33*5f748b3cSKun Lu static struct wake_status spm_wakesta; /* Record last wakesta */
34*5f748b3cSKun Lu static wake_reason_t spm_wake_reason = WR_NONE;
35*5f748b3cSKun Lu static struct resource_req_status generic_spm_resource_req = {
36*5f748b3cSKun Lu 	.id = MT_LP_RQ_ID_ALL_USAGE,
37*5f748b3cSKun Lu 	.val = 0,
38*5f748b3cSKun Lu };
39*5f748b3cSKun Lu 
40*5f748b3cSKun Lu #ifdef MT_SPM_TIMESTAMP_SUPPORT
41*5f748b3cSKun Lu struct spm_con_info {
42*5f748b3cSKun Lu 	uint32_t wakeup_obs;
43*5f748b3cSKun Lu 	unsigned short entries;
44*5f748b3cSKun Lu 	unsigned short resume;
45*5f748b3cSKun Lu 	uint64_t entry_time;
46*5f748b3cSKun Lu };
47*5f748b3cSKun Lu static struct spm_con_info spm_cst_info;
48*5f748b3cSKun Lu #endif
49*5f748b3cSKun Lu 
50*5f748b3cSKun Lu #if SPM_FW_NO_RESUME
51*5f748b3cSKun Lu #define do_spm_init(pwrctrl)       \
52*5f748b3cSKun Lu 	({                         \
53*5f748b3cSKun Lu 		int local_ret = 0; \
54*5f748b3cSKun Lu 		local_ret;         \
55*5f748b3cSKun Lu 	})
56*5f748b3cSKun Lu #define do_spm_run(pwrctrl) __spm_send_cpu_wakeup_event()
57*5f748b3cSKun Lu #else
58*5f748b3cSKun Lu #define do_spm_run(pwrctrl) __spm_kick_pcm_to_run(pwrctrl)
59*5f748b3cSKun Lu #define do_spm_init(pcmdesc) __spm_conservation_fw_init(pcmdesc)
60*5f748b3cSKun Lu #endif
61*5f748b3cSKun Lu 
62*5f748b3cSKun Lu #ifndef MTK_PLAT_SPM_TRACE_UNSUPPORT
63*5f748b3cSKun Lu #define SPM_CONSERVATION_BOUND (MT_SPM_TRACE_LP_RINGBUF_MAX - 1)
64*5f748b3cSKun Lu 
65*5f748b3cSKun Lu static const uint32_t spm_conservation_trace_comm_sz =
66*5f748b3cSKun Lu 	sizeof(struct wake_status_trace_comm);
67*5f748b3cSKun Lu 
spm_conservation_trace_lp(struct wake_status_trace * trace)68*5f748b3cSKun Lu static void spm_conservation_trace_lp(struct wake_status_trace *trace)
69*5f748b3cSKun Lu {
70*5f748b3cSKun Lu 	MT_SPM_TRACE_LP_RINGBUF(&trace->comm, spm_conservation_trace_comm_sz);
71*5f748b3cSKun Lu }
72*5f748b3cSKun Lu 
spm_conservation_trace_suspend(struct wake_status_trace * trace)73*5f748b3cSKun Lu static void spm_conservation_trace_suspend(struct wake_status_trace *trace)
74*5f748b3cSKun Lu {
75*5f748b3cSKun Lu 	if (!trace) {
76*5f748b3cSKun Lu 		INFO("[%s:%d] Enter\n", __func__, __LINE__);
77*5f748b3cSKun Lu 		return;
78*5f748b3cSKun Lu 	}
79*5f748b3cSKun Lu }
80*5f748b3cSKun Lu 
81*5f748b3cSKun Lu #endif
82*5f748b3cSKun Lu 
83*5f748b3cSKun Lu #ifdef MT_SPM_TIMESTAMP_SUPPORT
spm_conservation_wakeup_obs(int is_set,int cat,uint32_t wake_src_bits)84*5f748b3cSKun Lu int spm_conservation_wakeup_obs(int is_set, int cat, uint32_t wake_src_bits)
85*5f748b3cSKun Lu {
86*5f748b3cSKun Lu 	spm_lock_get();
87*5f748b3cSKun Lu 	if (is_set)
88*5f748b3cSKun Lu 		spm_cst_info.wakeup_obs |= wake_src_bits;
89*5f748b3cSKun Lu 	else
90*5f748b3cSKun Lu 		spm_cst_info.wakeup_obs &= ~wake_src_bits;
91*5f748b3cSKun Lu 	spm_lock_release();
92*5f748b3cSKun Lu 	return 0;
93*5f748b3cSKun Lu }
94*5f748b3cSKun Lu #endif
95*5f748b3cSKun Lu 
go_to_spm_before_wfi(int state_id,uint32_t ext_opand,struct spm_lp_scen * spm_lp,uint32_t resource_req)96*5f748b3cSKun Lu static int go_to_spm_before_wfi(int state_id, uint32_t ext_opand,
97*5f748b3cSKun Lu 				struct spm_lp_scen *spm_lp,
98*5f748b3cSKun Lu 				uint32_t resource_req)
99*5f748b3cSKun Lu {
100*5f748b3cSKun Lu 	int ret = 0;
101*5f748b3cSKun Lu 	struct pwr_ctrl *pwrctrl;
102*5f748b3cSKun Lu 	uint32_t cpu = plat_my_core_pos();
103*5f748b3cSKun Lu 
104*5f748b3cSKun Lu 	pwrctrl = spm_lp->pwrctrl;
105*5f748b3cSKun Lu 
106*5f748b3cSKun Lu #if SPM_FW_NO_RESUME == 0
107*5f748b3cSKun Lu 	ret = do_spm_init(pwrctrl);
108*5f748b3cSKun Lu 
109*5f748b3cSKun Lu 	if (ret)
110*5f748b3cSKun Lu 		return ret;
111*5f748b3cSKun Lu #endif
112*5f748b3cSKun Lu 	__spm_set_cpu_status(cpu);
113*5f748b3cSKun Lu 	__spm_set_power_control(pwrctrl, resource_req);
114*5f748b3cSKun Lu 	__spm_set_wakeup_event(pwrctrl);
115*5f748b3cSKun Lu #if defined(CONFIG_MTK_VCOREDVFS_SUPPORT)
116*5f748b3cSKun Lu 	__spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcorefs.pwrctrl);
117*5f748b3cSKun Lu #endif
118*5f748b3cSKun Lu 
119*5f748b3cSKun Lu 	__spm_set_pcm_flags(pwrctrl);
120*5f748b3cSKun Lu 
121*5f748b3cSKun Lu 	if (ext_opand & MT_SPM_EX_OP_CLR_26M_RECORD)
122*5f748b3cSKun Lu 		__spm_clean_before_wfi();
123*5f748b3cSKun Lu 
124*5f748b3cSKun Lu 	if (ext_opand & MT_SPM_EX_OP_HW_S1_DETECT)
125*5f748b3cSKun Lu 		spm_hw_s1_state_monitor_resume();
126*5f748b3cSKun Lu 
127*5f748b3cSKun Lu 	do_spm_run(pwrctrl);
128*5f748b3cSKun Lu 
129*5f748b3cSKun Lu 	return ret;
130*5f748b3cSKun Lu }
131*5f748b3cSKun Lu 
go_to_spm_after_wfi(int state_id,uint32_t ext_opand,struct spm_lp_scen * spm_lp,struct wake_status ** status)132*5f748b3cSKun Lu static void go_to_spm_after_wfi(int state_id, uint32_t ext_opand,
133*5f748b3cSKun Lu 				struct spm_lp_scen *spm_lp,
134*5f748b3cSKun Lu 				struct wake_status **status)
135*5f748b3cSKun Lu {
136*5f748b3cSKun Lu #ifdef MT_SPM_TIMESTAMP_SUPPORT
137*5f748b3cSKun Lu 	uint64_t ktime = 0;
138*5f748b3cSKun Lu #endif
139*5f748b3cSKun Lu 	uint32_t ext_status = 0;
140*5f748b3cSKun Lu 
141*5f748b3cSKun Lu 	spm_wakesta.tr.comm.resumetime = 0;
142*5f748b3cSKun Lu 	spm_wakesta.tr.comm.times_h = spm_wakesta.tr.comm.times_l = 0;
143*5f748b3cSKun Lu #ifdef MT_SPM_TIMESTAMP_SUPPORT
144*5f748b3cSKun Lu 	if (ext_opand & MT_SPM_EX_OP_TRACE_TIMESTAMP_EN) {
145*5f748b3cSKun Lu 		MT_SPM_TIME_GET(ktime);
146*5f748b3cSKun Lu 		spm_wakesta.tr.comm.times_h = (ktime >> 32);
147*5f748b3cSKun Lu 		spm_wakesta.tr.comm.times_l = (ktime & (uint32_t)-1);
148*5f748b3cSKun Lu 	}
149*5f748b3cSKun Lu #endif
150*5f748b3cSKun Lu 
151*5f748b3cSKun Lu 	if (ext_opand & MT_SPM_EX_OP_HW_S1_DETECT)
152*5f748b3cSKun Lu 		spm_hw_s1_state_monitor_pause(&ext_status);
153*5f748b3cSKun Lu 
154*5f748b3cSKun Lu 	__spm_ext_int_wakeup_req_clr();
155*5f748b3cSKun Lu 
156*5f748b3cSKun Lu 	__spm_get_wakeup_status(&spm_wakesta, ext_status);
157*5f748b3cSKun Lu 
158*5f748b3cSKun Lu #ifdef MT_SPM_TIMESTAMP_SUPPORT
159*5f748b3cSKun Lu 
160*5f748b3cSKun Lu 	if (spm_wakesta.tr.comm.r12 & R12_SYS_CIRQ_IRQ_B)
161*5f748b3cSKun Lu 		INFO("[%s:%d] spm receive wakeup r12 = (0x%" PRIx32
162*5f748b3cSKun Lu 		     ") (0x%" PRIx32 "%" PRIx32 ")\n",
163*5f748b3cSKun Lu 		     __func__, __LINE__, spm_wakesta.tr.comm.r12,
164*5f748b3cSKun Lu 		     mmio_read_32(SYS_TIMER_VALUE_H),
165*5f748b3cSKun Lu 		     mmio_read_32(SYS_TIMER_VALUE_L));
166*5f748b3cSKun Lu 
167*5f748b3cSKun Lu 	if (ext_opand & MT_SPM_EX_OP_TRACE_TIMESTAMP_EN) {
168*5f748b3cSKun Lu 		if ((ext_opand & MT_SPM_EX_OP_TIME_CHECK) &&
169*5f748b3cSKun Lu 		    (spm_cst_info.entries != spm_cst_info.resume)) {
170*5f748b3cSKun Lu 			uint64_t t_resume =
171*5f748b3cSKun Lu 				(ktime - spm_cst_info.entry_time) / 1000000;
172*5f748b3cSKun Lu 			uint64_t t_spm = spm_wakesta.tr.comm.timer_out >> 5;
173*5f748b3cSKun Lu 
174*5f748b3cSKun Lu 			spm_wakesta.tr.comm.resumetime =
175*5f748b3cSKun Lu 				(t_resume > t_spm) ? (t_resume - t_spm) : 0;
176*5f748b3cSKun Lu 			if ((t_resume > t_spm) &&
177*5f748b3cSKun Lu 			    IS_RESUME_OVERTIME(
178*5f748b3cSKun Lu 				    spm_wakesta.tr.comm.resumetime)) {
179*5f748b3cSKun Lu 				INFO("[%s:%d] Overtime use %lu(ms)(%" PRIu64
180*5f748b3cSKun Lu 				     ",%" PRIu64 ")\n",
181*5f748b3cSKun Lu 				     __func__, __LINE__, (t_resume - t_spm),
182*5f748b3cSKun Lu 				     t_resume, t_spm);
183*5f748b3cSKun Lu 			}
184*5f748b3cSKun Lu 			spm_cst_info.resume = spm_cst_info.entries;
185*5f748b3cSKun Lu 		}
186*5f748b3cSKun Lu 	}
187*5f748b3cSKun Lu #endif
188*5f748b3cSKun Lu 
189*5f748b3cSKun Lu 	if (status)
190*5f748b3cSKun Lu 		*status = &spm_wakesta;
191*5f748b3cSKun Lu 
192*5f748b3cSKun Lu #ifndef MTK_PLAT_SPM_TRACE_UNSUPPORT
193*5f748b3cSKun Lu 	if (ext_opand & MT_SPM_EX_OP_TRACE_LP)
194*5f748b3cSKun Lu 		spm_conservation_trace_lp(&spm_wakesta.tr);
195*5f748b3cSKun Lu 	else if (ext_opand & MT_SPM_EX_OP_TRACE_SUSPEND)
196*5f748b3cSKun Lu 		spm_conservation_trace_suspend(&spm_wakesta.tr);
197*5f748b3cSKun Lu #endif
198*5f748b3cSKun Lu 	__spm_clean_after_wakeup();
199*5f748b3cSKun Lu 	spm_wake_reason = __spm_output_wake_reason(&spm_wakesta);
200*5f748b3cSKun Lu }
201*5f748b3cSKun Lu 
spm_conservation(int state_id,uint32_t ext_opand,struct spm_lp_scen * spm_lp,uint32_t resource_req)202*5f748b3cSKun Lu int spm_conservation(int state_id, uint32_t ext_opand,
203*5f748b3cSKun Lu 		     struct spm_lp_scen *spm_lp, uint32_t resource_req)
204*5f748b3cSKun Lu {
205*5f748b3cSKun Lu 	uint32_t rc_state = resource_req;
206*5f748b3cSKun Lu 
207*5f748b3cSKun Lu 	if (!spm_lp)
208*5f748b3cSKun Lu 		return -1;
209*5f748b3cSKun Lu 
210*5f748b3cSKun Lu 	spm_lock_get();
211*5f748b3cSKun Lu 
212*5f748b3cSKun Lu 	if (ext_opand & MT_SPM_EX_OP_DEVICES_SAVE) {
213*5f748b3cSKun Lu #ifndef MTK_PLAT_SPM_UART_UNSUPPORT
214*5f748b3cSKun Lu 
215*5f748b3cSKun Lu 		/* Notify UART to sleep */
216*5f748b3cSKun Lu 		mt_uart_save();
217*5f748b3cSKun Lu #else
218*5f748b3cSKun Lu 		INFO("[%s:%d] - uart not support will crash when infra off\n",
219*5f748b3cSKun Lu 		     __func__, __LINE__);
220*5f748b3cSKun Lu #endif
221*5f748b3cSKun Lu 	}
222*5f748b3cSKun Lu 
223*5f748b3cSKun Lu 	if (!(ext_opand & MT_SPM_EX_OP_NON_GENERIC_RESOURCE_REQ)) {
224*5f748b3cSKun Lu 		/* resource request */
225*5f748b3cSKun Lu 		mt_lp_rq_get_status(PLAT_RQ_REQ_USAGE,
226*5f748b3cSKun Lu 				    &generic_spm_resource_req);
227*5f748b3cSKun Lu 		rc_state |= generic_spm_resource_req.val;
228*5f748b3cSKun Lu 	}
229*5f748b3cSKun Lu 
230*5f748b3cSKun Lu 	if (ext_opand & MT_SPM_EX_OP_DISABLE_VCORE_LP)
231*5f748b3cSKun Lu 		spm_lp->pwrctrl->pcm_flags1 |= SPM_FLAG1_DISABLE_VCORE_LP;
232*5f748b3cSKun Lu 	else
233*5f748b3cSKun Lu 		spm_lp->pwrctrl->pcm_flags1 &= ~SPM_FLAG1_DISABLE_VCORE_LP;
234*5f748b3cSKun Lu 
235*5f748b3cSKun Lu 	go_to_spm_before_wfi(state_id, ext_opand, spm_lp, rc_state);
236*5f748b3cSKun Lu 
237*5f748b3cSKun Lu 	spm_lock_release();
238*5f748b3cSKun Lu 
239*5f748b3cSKun Lu 	return 0;
240*5f748b3cSKun Lu }
241*5f748b3cSKun Lu 
spm_conservation_finish(int state_id,uint32_t ext_opand,struct spm_lp_scen * spm_lp,struct wake_status ** status)242*5f748b3cSKun Lu void spm_conservation_finish(int state_id, uint32_t ext_opand,
243*5f748b3cSKun Lu 			     struct spm_lp_scen *spm_lp,
244*5f748b3cSKun Lu 			     struct wake_status **status)
245*5f748b3cSKun Lu {
246*5f748b3cSKun Lu 	if (ext_opand & MT_SPM_EX_OP_DEVICES_SAVE) {
247*5f748b3cSKun Lu #ifndef MTK_PLAT_SPM_UART_UNSUPPORT
248*5f748b3cSKun Lu 		/* Notify UART to wakeup */
249*5f748b3cSKun Lu 		mt_uart_restore();
250*5f748b3cSKun Lu #else
251*5f748b3cSKun Lu 		INFO("[%s:%d] - uart not support will crash when infra off\n",
252*5f748b3cSKun Lu 		     __func__, __LINE__);
253*5f748b3cSKun Lu #endif
254*5f748b3cSKun Lu 	}
255*5f748b3cSKun Lu 
256*5f748b3cSKun Lu 	spm_lock_get();
257*5f748b3cSKun Lu 	go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status);
258*5f748b3cSKun Lu 	spm_lock_release();
259*5f748b3cSKun Lu }
260*5f748b3cSKun Lu 
spm_conservation_get_result(struct wake_status ** res)261*5f748b3cSKun Lu int spm_conservation_get_result(struct wake_status **res)
262*5f748b3cSKun Lu {
263*5f748b3cSKun Lu 	if (!res)
264*5f748b3cSKun Lu 		return -1;
265*5f748b3cSKun Lu 	*res = &spm_wakesta;
266*5f748b3cSKun Lu 	return 0;
267*5f748b3cSKun Lu }
268