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