1*a24b53e0SWenzhen Yu /*
2*a24b53e0SWenzhen Yu * Copyright (c) 2025, Mediatek Inc. All rights reserved.
3*a24b53e0SWenzhen Yu *
4*a24b53e0SWenzhen Yu * SPDX-License-Identifier: BSD-3-Clause
5*a24b53e0SWenzhen Yu */
6*a24b53e0SWenzhen Yu
7*a24b53e0SWenzhen Yu #include <assert.h>
8*a24b53e0SWenzhen Yu #include <inttypes.h>
9*a24b53e0SWenzhen Yu #include <stddef.h>
10*a24b53e0SWenzhen Yu #include <stdint.h>
11*a24b53e0SWenzhen Yu #include <stdio.h>
12*a24b53e0SWenzhen Yu #include <string.h>
13*a24b53e0SWenzhen Yu
14*a24b53e0SWenzhen Yu #include <common/debug.h>
15*a24b53e0SWenzhen Yu #include <lib/mmio.h>
16*a24b53e0SWenzhen Yu #include <plat/common/platform.h>
17*a24b53e0SWenzhen Yu #include <platform_def.h>
18*a24b53e0SWenzhen Yu
19*a24b53e0SWenzhen Yu #include <lib/pm/mtk_pm.h>
20*a24b53e0SWenzhen Yu #include <lpm_v2/mt_lp_rqm.h>
21*a24b53e0SWenzhen Yu #include <mt_spm.h>
22*a24b53e0SWenzhen Yu #include <mt_spm_common.h>
23*a24b53e0SWenzhen Yu #include <mt_spm_conservation.h>
24*a24b53e0SWenzhen Yu #include <mt_spm_reg.h>
25*a24b53e0SWenzhen Yu #include <mt_spm_vcorefs.h>
26*a24b53e0SWenzhen Yu
27*a24b53e0SWenzhen Yu #define MT_RESUMETIME_THRESHOLD_MAX 5
28*a24b53e0SWenzhen Yu #define IS_RESUME_OVERTIME(delta) \
29*a24b53e0SWenzhen Yu (delta > MT_RESUMETIME_THRESHOLD_MAX)
30*a24b53e0SWenzhen Yu
31*a24b53e0SWenzhen Yu static struct wake_status spm_wakesta; /* Record last wakesta */
32*a24b53e0SWenzhen Yu static wake_reason_t spm_wake_reason = WR_NONE;
33*a24b53e0SWenzhen Yu static struct resource_req_status generic_spm_resource_req = {
34*a24b53e0SWenzhen Yu .id = MT_LP_RQ_ID_ALL_USAGE,
35*a24b53e0SWenzhen Yu .val = 0,
36*a24b53e0SWenzhen Yu };
37*a24b53e0SWenzhen Yu
38*a24b53e0SWenzhen Yu #define do_spm_init(pwrctrl) ({ int local_ret = 0; local_ret; })
39*a24b53e0SWenzhen Yu #define do_spm_run(pwrctrl) __spm_send_cpu_wakeup_event()
40*a24b53e0SWenzhen Yu
go_to_spm_before_wfi(int state_id,uint32_t ext_opand,struct spm_lp_scen * spm_lp,uint32_t resource_req)41*a24b53e0SWenzhen Yu static int go_to_spm_before_wfi(int state_id, uint32_t ext_opand,
42*a24b53e0SWenzhen Yu struct spm_lp_scen *spm_lp,
43*a24b53e0SWenzhen Yu uint32_t resource_req)
44*a24b53e0SWenzhen Yu {
45*a24b53e0SWenzhen Yu int ret = 0;
46*a24b53e0SWenzhen Yu struct pwr_ctrl *pwrctrl;
47*a24b53e0SWenzhen Yu
48*a24b53e0SWenzhen Yu pwrctrl = spm_lp->pwrctrl;
49*a24b53e0SWenzhen Yu
50*a24b53e0SWenzhen Yu #if SPM_FW_NO_RESUME == 0
51*a24b53e0SWenzhen Yu ret = do_spm_init(pwrctrl);
52*a24b53e0SWenzhen Yu
53*a24b53e0SWenzhen Yu if (ret)
54*a24b53e0SWenzhen Yu return ret;
55*a24b53e0SWenzhen Yu #endif
56*a24b53e0SWenzhen Yu __spm_set_power_control(pwrctrl, resource_req);
57*a24b53e0SWenzhen Yu __spm_set_wakeup_event(pwrctrl);
58*a24b53e0SWenzhen Yu #if defined(CONFIG_MTK_VCOREDVFS_SUPPORT)
59*a24b53e0SWenzhen Yu __spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcorefs.pwrctrl);
60*a24b53e0SWenzhen Yu #endif
61*a24b53e0SWenzhen Yu
62*a24b53e0SWenzhen Yu #ifdef MTK_SPM_IVI_SUPPORT
63*a24b53e0SWenzhen Yu pwrctrl->pcm_flags |= SPM_FLAG_ENABLE_MT8196_IVI;
64*a24b53e0SWenzhen Yu #endif
65*a24b53e0SWenzhen Yu __spm_set_pcm_flags(pwrctrl);
66*a24b53e0SWenzhen Yu
67*a24b53e0SWenzhen Yu #ifdef HW_S1_DETECT
68*a24b53e0SWenzhen Yu if (ext_opand & MT_SPM_EX_OP_HW_S1_DETECT)
69*a24b53e0SWenzhen Yu spm_hw_s1_state_monitor_resume();
70*a24b53e0SWenzhen Yu #endif
71*a24b53e0SWenzhen Yu do_spm_run(pwrctrl);
72*a24b53e0SWenzhen Yu return ret;
73*a24b53e0SWenzhen Yu }
74*a24b53e0SWenzhen Yu
go_to_spm_after_wfi(int state_id,uint32_t ext_opand,struct spm_lp_scen * spm_lp,struct wake_status ** status)75*a24b53e0SWenzhen Yu static void go_to_spm_after_wfi(int state_id, uint32_t ext_opand,
76*a24b53e0SWenzhen Yu struct spm_lp_scen *spm_lp,
77*a24b53e0SWenzhen Yu struct wake_status **status)
78*a24b53e0SWenzhen Yu {
79*a24b53e0SWenzhen Yu uint32_t ext_status = 0;
80*a24b53e0SWenzhen Yu
81*a24b53e0SWenzhen Yu spm_wakesta.tr.comm.resumetime = 0;
82*a24b53e0SWenzhen Yu spm_wakesta.tr.comm.times_h = spm_wakesta.tr.comm.times_l = 0;
83*a24b53e0SWenzhen Yu
84*a24b53e0SWenzhen Yu if (ext_opand & MT_SPM_EX_OP_HW_S1_DETECT)
85*a24b53e0SWenzhen Yu spm_hw_s1_state_monitor_pause(&ext_status);
86*a24b53e0SWenzhen Yu
87*a24b53e0SWenzhen Yu __spm_ext_int_wakeup_req_clr();
88*a24b53e0SWenzhen Yu
89*a24b53e0SWenzhen Yu __spm_get_wakeup_status(&spm_wakesta, ext_status);
90*a24b53e0SWenzhen Yu
91*a24b53e0SWenzhen Yu if (status)
92*a24b53e0SWenzhen Yu *status = &spm_wakesta;
93*a24b53e0SWenzhen Yu
94*a24b53e0SWenzhen Yu #ifndef MT_SPM_COMMON_SODI_SUPPORT
95*a24b53e0SWenzhen Yu __spm_clean_after_wakeup();
96*a24b53e0SWenzhen Yu #endif
97*a24b53e0SWenzhen Yu spm_wake_reason = __spm_output_wake_reason(&spm_wakesta);
98*a24b53e0SWenzhen Yu }
99*a24b53e0SWenzhen Yu
spm_conservation(int state_id,uint32_t ext_opand,struct spm_lp_scen * spm_lp,uint32_t resource_req)100*a24b53e0SWenzhen Yu int spm_conservation(int state_id, uint32_t ext_opand,
101*a24b53e0SWenzhen Yu struct spm_lp_scen *spm_lp, uint32_t resource_req)
102*a24b53e0SWenzhen Yu {
103*a24b53e0SWenzhen Yu uint32_t rc_state = resource_req;
104*a24b53e0SWenzhen Yu
105*a24b53e0SWenzhen Yu if (!spm_lp)
106*a24b53e0SWenzhen Yu return -1;
107*a24b53e0SWenzhen Yu
108*a24b53e0SWenzhen Yu spm_lock_get();
109*a24b53e0SWenzhen Yu
110*a24b53e0SWenzhen Yu /* Uart bk/rs is needed if infra off for legacy project
111*a24b53e0SWenzhen Yu * leave code here for reference.
112*a24b53e0SWenzhen Yu */
113*a24b53e0SWenzhen Yu if (ext_opand & MT_SPM_EX_OP_NOTIFY_INFRA_OFF) {
114*a24b53e0SWenzhen Yu #ifndef MTK_PLAT_SPM_UART_UNSUPPORT
115*a24b53e0SWenzhen Yu /* Notify UART to sleep */
116*a24b53e0SWenzhen Yu mt_uart_save();
117*a24b53e0SWenzhen Yu #endif
118*a24b53e0SWenzhen Yu }
119*a24b53e0SWenzhen Yu
120*a24b53e0SWenzhen Yu if (!(ext_opand & MT_SPM_EX_OP_NON_GENERIC_RESOURCE_REQ)) {
121*a24b53e0SWenzhen Yu /* Resource request */
122*a24b53e0SWenzhen Yu mt_lp_rq_get_status(PLAT_RQ_REQ_USAGE,
123*a24b53e0SWenzhen Yu &generic_spm_resource_req);
124*a24b53e0SWenzhen Yu rc_state |= generic_spm_resource_req.val;
125*a24b53e0SWenzhen Yu }
126*a24b53e0SWenzhen Yu go_to_spm_before_wfi(state_id, ext_opand, spm_lp, rc_state);
127*a24b53e0SWenzhen Yu
128*a24b53e0SWenzhen Yu spm_lock_release();
129*a24b53e0SWenzhen Yu
130*a24b53e0SWenzhen Yu return 0;
131*a24b53e0SWenzhen Yu }
132*a24b53e0SWenzhen Yu
spm_conservation_finish(int state_id,uint32_t ext_opand,struct spm_lp_scen * spm_lp,struct wake_status ** status)133*a24b53e0SWenzhen Yu void spm_conservation_finish(int state_id, uint32_t ext_opand,
134*a24b53e0SWenzhen Yu struct spm_lp_scen *spm_lp,
135*a24b53e0SWenzhen Yu struct wake_status **status)
136*a24b53e0SWenzhen Yu {
137*a24b53e0SWenzhen Yu /* Uart bk/rs is needed if infra off for legacy project
138*a24b53e0SWenzhen Yu * leave code here for reference.
139*a24b53e0SWenzhen Yu */
140*a24b53e0SWenzhen Yu if (ext_opand & MT_SPM_EX_OP_NOTIFY_INFRA_OFF) {
141*a24b53e0SWenzhen Yu #ifndef MTK_PLAT_SPM_UART_UNSUPPORT
142*a24b53e0SWenzhen Yu /* Notify UART to wakeup */
143*a24b53e0SWenzhen Yu mt_uart_restore();
144*a24b53e0SWenzhen Yu #endif
145*a24b53e0SWenzhen Yu }
146*a24b53e0SWenzhen Yu
147*a24b53e0SWenzhen Yu spm_lock_get();
148*a24b53e0SWenzhen Yu go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status);
149*a24b53e0SWenzhen Yu #ifdef MT_SPM_COMMON_SODI_SUPPORT
150*a24b53e0SWenzhen Yu /* Restore common sodi mask and resource req setting */
151*a24b53e0SWenzhen Yu mt_spm_set_common_sodi_pwrctr();
152*a24b53e0SWenzhen Yu mt_spm_set_common_sodi_pcm_flags();
153*a24b53e0SWenzhen Yu #endif
154*a24b53e0SWenzhen Yu spm_lock_release();
155*a24b53e0SWenzhen Yu }
156*a24b53e0SWenzhen Yu
spm_conservation_get_result(struct wake_status ** res)157*a24b53e0SWenzhen Yu int spm_conservation_get_result(struct wake_status **res)
158*a24b53e0SWenzhen Yu {
159*a24b53e0SWenzhen Yu if (!res)
160*a24b53e0SWenzhen Yu return -1;
161*a24b53e0SWenzhen Yu *res = &spm_wakesta;
162*a24b53e0SWenzhen Yu return 0;
163*a24b53e0SWenzhen Yu }
164