1 /*
2 * Copyright (c) 2025, Mediatek Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdint.h>
8
9 #include <common/debug.h>
10
11 #include <constraints/mt_spm_rc_api.h>
12 #include <constraints/mt_spm_rc_internal.h>
13 #include <drivers/spm/mt_spm_resource_req.h>
14 #include <lib/pm/mtk_pm.h>
15 #include <lpm_v2/mt_lp_api.h>
16 #include <lpm_v2/mt_lp_rm.h>
17 #include <mt_plat_spm_setting.h>
18 #include <mt_spm.h>
19 #include <mt_spm_conservation.h>
20 #include <mt_spm_constraint.h>
21 #include <mt_spm_idle.h>
22 #include <mt_spm_internal.h>
23 #include <mt_spm_pmic_lp.h>
24 #include <mt_spm_reg.h>
25 #include <mt_spm_suspend.h>
26 #include <notifier/inc/mt_spm_notifier.h>
27
28 #define CONSTRAINT_SYSPLL_ALLOW \
29 (MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF | \
30 MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
31 MT_RM_CONSTRAINT_ALLOW_VCORE_LP | MT_RM_CONSTRAINT_ALLOW_LVTS_STATE)
32
33 #define CONSTRAINT_SYSPLL_PCM_FLAG \
34 (SPM_FLAG_DISABLE_INFRA_PDN | SPM_FLAG_DISABLE_DPM_PDN | \
35 SPM_FLAG_DISABLE_MCUPM_PDN | SPM_FLAG_ENABLE_LVTS_WORKAROUND | \
36 SPM_FLAG_DISABLE_VCORE_DVS | SPM_FLAG_DISABLE_DDR_DFS | \
37 SPM_FLAG_DISABLE_EMI_DFS | SPM_FLAG_DISABLE_BUS_DFS | \
38 SPM_FLAG_SRAM_SLEEP_CTRL | SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
39
40 #define CONSTRAINT_SYSPLL_PCM_FLAG1 \
41 (SPM_FLAG1_DISABLE_PERI_OFF | SPM_FLAG1_ENABLE_MCU_INFRA_PARITY)
42
43 #define CONSTRAINT_SYSPLL_RESOURCE_REQ \
44 (MT_SPM_26M | MT_SPM_VCORE | MT_SPM_INFRA)
45
46 #define CHECK_VAL(val, sys_state) \
47 ((val) ? !!(*((uint32_t *)(val)) == (sys_state)) : 0)
48
49 static uint32_t cmd;
50
51 static struct constraint_status status = {
52 .id = MT_RM_CONSTRAINT_ID_SYSPL,
53 .is_valid = (MT_SPM_RC_VALID_SW | MT_SPM_RC_VALID_FW |
54 MT_SPM_RC_VALID_NOTIFY),
55 .enter_cnt = 0,
56 .residency = 0,
57 };
58
spm_syspll_conduct(int state_id,struct spm_lp_scen * spm_lp,uint32_t * resource_req)59 int spm_syspll_conduct(int state_id, struct spm_lp_scen *spm_lp,
60 uint32_t *resource_req)
61 {
62 if ((spm_lp == NULL) || (resource_req == NULL))
63 return -1;
64
65 struct pwr_ctrl *pwrctrl = spm_lp->pwrctrl;
66
67 pwrctrl->pcm_flags = CONSTRAINT_SYSPLL_PCM_FLAG;
68 pwrctrl->pcm_flags1 = CONSTRAINT_SYSPLL_PCM_FLAG1;
69
70 *resource_req |= CONSTRAINT_SYSPLL_RESOURCE_REQ;
71
72 return 0;
73 }
74
spm_is_valid_rc_syspll(uint32_t cpu,int state_id)75 bool spm_is_valid_rc_syspll(uint32_t cpu, int state_id)
76 {
77 return IS_MT_RM_RC_READY(status.is_valid);
78 }
79
spm_update_rc_syspll(int state_id,int type,const void * val)80 int spm_update_rc_syspll(int state_id, int type, const void *val)
81 {
82 int res = MT_RM_STATUS_OK;
83
84 if (type == PLAT_RC_CLKBUF_STATUS) {
85 bool is_flight = CHECK_VAL(val, FLIGHT_MODE_ON);
86
87 if (is_flight)
88 spm_rc_constraint_valid_set(MT_RM_CONSTRAINT_ID_SYSPL,
89 MT_RM_CONSTRAINT_ID_SYSPL,
90 MT_SPM_RC_VALID_FLIGHTMODE,
91 &status);
92 else
93 spm_rc_constraint_valid_clr(MT_RM_CONSTRAINT_ID_SYSPL,
94 MT_RM_CONSTRAINT_ID_SYSPL,
95 MT_SPM_RC_VALID_FLIGHTMODE,
96 &status);
97 } else if (type == PLAT_RC_UFS_STATUS) {
98 uint32_t is_ufs_h8 = CHECK_VAL(val, UFS_REF_CLK_OFF);
99
100 if (is_ufs_h8)
101 spm_rc_constraint_valid_set(MT_RM_CONSTRAINT_ID_SYSPL,
102 MT_RM_CONSTRAINT_ID_SYSPL,
103 MT_SPM_RC_VALID_UFS_H8,
104 &status);
105 else
106 spm_rc_constraint_valid_clr(MT_RM_CONSTRAINT_ID_SYSPL,
107 MT_RM_CONSTRAINT_ID_SYSPL,
108 MT_SPM_RC_VALID_UFS_H8,
109 &status);
110 } else if (type == PLAT_RC_STATUS) {
111 const struct rc_common_state *st;
112
113 st = (const struct rc_common_state *)val;
114
115 if (!st)
116 return 0;
117 if ((st->type == CONSTRAINT_UPDATE_VALID) ||
118 (st->type == CONSTRAINT_RESIDNECY))
119 spm_rc_constraint_status_set(st->id, st->type, st->act,
120 MT_RM_CONSTRAINT_ID_SYSPL,
121 st->value, &status);
122 else
123 INFO("[%s:%d] - Unknown type: 0x%x\n", __func__,
124 __LINE__, st->type);
125 }
126
127 return res;
128 }
129
spm_allow_rc_syspll(int state_id)130 uint32_t spm_allow_rc_syspll(int state_id)
131 {
132 return CONSTRAINT_SYSPLL_ALLOW;
133 }
134
spm_run_rc_syspll(uint32_t cpu,int state_id)135 int spm_run_rc_syspll(uint32_t cpu, int state_id)
136 {
137 uint32_t ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
138 uint32_t nb_type = 0;
139
140 MT_SPM_RC_TAG(cpu, state_id, MT_RM_CONSTRAINT_ID_SYSPL);
141 MT_SPM_RC_TAG_VALID(status.is_valid);
142 MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_START);
143
144 cmd = CONSTRAINT_SYSPLL_ALLOW;
145
146 if (IS_PLAT_SUSPEND_ID(state_id)) {
147 cmd |= MT_RM_CONSTRAINT_ALLOW_AP_PLAT_SUSPEND;
148 ext_op |= (MT_SPM_EX_OP_CLR_26M_RECORD | MT_SPM_EX_OP_SET_WDT |
149 MT_SPM_EX_OP_SET_SUSPEND_MODE);
150
151 nb_type = MT_SPM_NOTIFY_LP_ENTER;
152 } else {
153 if (status.is_valid & MT_SPM_RC_VALID_TRACE_TIME)
154 ext_op |= MT_SPM_EX_OP_TRACE_TIMESTAMP_EN;
155
156 nb_type = MT_SPM_NOTIFY_IDLE_ENTER;
157 }
158
159 #ifdef MTK_SPM_PMIC_LP_SUPPORT
160 if (do_spm_low_power(SPM_LP_ENTER, cmd) == PMIC_ONLV)
161 ext_op |= MT_SPM_EX_OP_DISABLE_VCORE_LP;
162 #endif
163
164 MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_NOTIFY);
165
166 if (IS_MT_SPM_RC_NOTIFY_ENABLE(status.is_valid))
167 mt_spm_sspm_notify_u32(nb_type, cmd);
168
169 MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_WAKE_SPM_BEFORE);
170
171 if (IS_PLAT_SUSPEND_ID(state_id))
172 mt_spm_suspend_enter(state_id, ext_op,
173 CONSTRAINT_SYSPLL_RESOURCE_REQ);
174 else
175 mt_spm_idle_generic_enter(state_id, ext_op, spm_syspll_conduct);
176
177 MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_WAKE_SPM_AFTER);
178 return 0;
179 }
180
spm_reset_rc_syspll(uint32_t cpu,int state_id)181 int spm_reset_rc_syspll(uint32_t cpu, int state_id)
182 {
183 uint32_t ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
184 uint32_t nb_type = 0;
185
186 MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_START);
187
188 if (IS_PLAT_SUSPEND_ID(state_id)) {
189 ext_op |=
190 (MT_SPM_EX_OP_SET_WDT | MT_SPM_EX_OP_SET_SUSPEND_MODE);
191
192 nb_type = MT_SPM_NOTIFY_LP_LEAVE;
193 } else {
194 if (status.is_valid & MT_SPM_RC_VALID_TRACE_TIME)
195 ext_op |= MT_SPM_EX_OP_TRACE_TIMESTAMP_EN;
196
197 if (spm_unlikely(status.is_valid & MT_SPM_RC_VALID_TRACE_EVENT))
198 ext_op |= MT_SPM_EX_OP_TRACE_LP;
199
200 nb_type = MT_SPM_NOTIFY_IDLE_LEAVE;
201 }
202
203 #ifdef MTK_SPM_PMIC_LP_SUPPORT
204 do_spm_low_power(SPM_LP_RESUME, cmd);
205 #endif
206
207 MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_NOTIFY);
208
209 if (IS_MT_SPM_RC_NOTIFY_ENABLE(status.is_valid))
210 mt_spm_sspm_notify_u32(nb_type, cmd);
211
212 MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_RESET_SPM_BEFORE);
213
214 if (IS_PLAT_SUSPEND_ID(state_id))
215 mt_spm_suspend_resume(state_id, ext_op, NULL);
216 else {
217 struct wake_status *waken = NULL;
218
219 mt_spm_idle_generic_resume(state_id, ext_op, &waken, NULL);
220 status.enter_cnt++;
221
222 if (spm_unlikely(status.is_valid & MT_SPM_RC_VALID_RESIDNECY))
223 status.residency += waken ? waken->tr.comm.timer_out :
224 0;
225 }
226
227 MT_SPM_RC_FP(MT_SPM_RC_FP_INIT);
228 return 0;
229 }
230
spm_get_status_rc_syspll(uint32_t type,void * priv)231 int spm_get_status_rc_syspll(uint32_t type, void *priv)
232 {
233 int ret = MT_RM_STATUS_OK;
234
235 if (type == PLAT_RC_STATUS) {
236 int res = 0;
237 struct rc_common_state *st = (struct rc_common_state *)priv;
238
239 if (!st)
240 return MT_RM_STATUS_BAD;
241
242 res = spm_rc_constraint_status_get(st->id, st->type, st->act,
243 MT_RM_CONSTRAINT_ID_SYSPL,
244 &status, st->value);
245 if (!res && (st->id != MT_RM_CONSTRAINT_ID_ALL))
246 ret = MT_RM_STATUS_STOP;
247 }
248 return ret;
249 }
250