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