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 <drivers/delay_timer.h>
16 #include <drivers/gpio.h>
17 #include <lib/bakery_lock.h>
18 #include <lib/mmio.h>
19 #include <lib/utils_def.h>
20 #include <platform_def.h>
21
22 #include <constraints/mt_spm_rc_api.h>
23 #include <constraints/mt_spm_rc_internal.h>
24 #include <drivers/spm/mt_spm_resource_req.h>
25 #include <lib/mtk_init/mtk_init.h>
26 #include <lib/pm/mtk_pm.h>
27 #include <lpm_v2/mt_lp_rm.h>
28 #include <lpm_v2/mt_lp_rqm.h>
29 #include <lpm_v2/mt_lpm_smc.h>
30 #include <mt_plat_spm_setting.h>
31 #include <mt_spm.h>
32 #include <mt_spm_common.h>
33 #include <mt_spm_conservation.h>
34 #include <mt_spm_constraint.h>
35 #include <mt_spm_dispatcher.h>
36 #include <mt_spm_hwreq.h>
37 #include <mt_spm_idle.h>
38 #include <mt_spm_internal.h>
39 #include <mt_spm_reg.h>
40 #include <mt_spm_suspend.h>
41 #include <mtk_mmap_pool.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() \
47 bakery_lock_init(&spm_lock)
48 #else
49 spinlock_t spm_lock;
50 #define plat_spm_lock_init()
51 #endif
52
53 static uint32_t spm_irq_num;
54
spm_set_sysclk_settle(void)55 void spm_set_sysclk_settle(void)
56 {
57 uint32_t settle;
58
59 mmio_write_32(SPM_CLK_SETTLE, SPM_SYSCLK_SETTLE);
60 settle = mmio_read_32(SPM_CLK_SETTLE);
61
62 INFO("md_settle = %u, settle = %u\n", SPM_SYSCLK_SETTLE, settle);
63 }
64
spm_set_irq_num(uint32_t num)65 void spm_set_irq_num(uint32_t num)
66 {
67 spm_irq_num = num;
68 }
69
spm_irq0_handler(uint64_t x1,uint64_t x2)70 void spm_irq0_handler(uint64_t x1, uint64_t x2)
71 {
72 if (x2 == 0) {
73 mmio_setbits_32(SPM_IRQ_MASK, ISRM_ALL_EXC_TWAM);
74 mmio_write_32(SPM_IRQ_STA, x1);
75 mmio_write_32(SPM_SWINT_CLR, PCM_SW_INT0);
76 }
77 }
78
spm_ap_mdsrc_ack(void)79 static int spm_ap_mdsrc_ack(void)
80 {
81 int ack, md_state = 0;
82
83 /* Check ap_mdsrc_ack = 1'b1, for md internal resource on ack */
84 ack = !!(mmio_read_32(AP_MDSRC_REQ) & AP_MDSMSRC_ACK_LSB);
85
86 if (!ack) {
87 /* Check md_apsrc_req = 1'b0, for md state 0:sleep, 1:wakeup */
88 md_state = !!(mmio_read_32(SPM_REQ_STA_10)
89 & MD_APSRC_REQ_LSB);
90
91 ERROR("[SPM] error: md_sleep = %d\n", md_state);
92 ERROR("%s can not get AP_MDSRC_ACK\n", __func__);
93 return -1;
94 }
95 return 0;
96 }
97
spm_ap_mdsrc_req(int set)98 static void spm_ap_mdsrc_req(int set)
99 {
100 spm_lock_get();
101
102 if (set)
103 mmio_setbits_32(AP_MDSRC_REQ, AP_MDSMSRC_REQ_LSB);
104 else
105 mmio_clrbits_32(AP_MDSRC_REQ, AP_MDSMSRC_REQ_LSB);
106
107 spm_lock_release();
108 }
109
spm_is_md_sleep(void * priv)110 static int spm_is_md_sleep(void *priv)
111 {
112 int md_state = 0;
113 int *sleep = (int *)priv;
114
115 if (!priv)
116 return -1;
117
118 /* Check md_apsrc_req = 1'b0, for md state 0:sleep, 1:wakeup */
119 md_state = !!(mmio_read_32(SPM_REQ_STA_10)
120 & MD_APSRC_REQ_LSB);
121
122 if (md_state == 0)
123 *sleep = 1;
124 else
125 *sleep = 0;
126
127 return 0;
128 }
129
spm_ap_gpueb_pll_control(int set)130 static void spm_ap_gpueb_pll_control(int set)
131 {
132 spm_lock_get();
133
134 if (set)
135 mmio_setbits_32(SPM2GPUPM_CON, SC_MFG_PLL_EN_LSB);
136 else
137 mmio_clrbits_32(SPM2GPUPM_CON, SC_MFG_PLL_EN_LSB);
138
139 spm_lock_release();
140 }
141
spm_ap_gpueb_get_pwr_status(void)142 static uint32_t spm_ap_gpueb_get_pwr_status(void)
143 {
144 uint32_t ret;
145
146 ret = mmio_read_32(XPU_PWR_STATUS);
147
148 return ret;
149 }
150
spm_ap_gpueb_get_mfg0_pwr_con(void)151 static uint32_t spm_ap_gpueb_get_mfg0_pwr_con(void)
152 {
153 uint32_t ret;
154
155 ret = mmio_read_32(MFG0_PWR_CON);
156
157 return ret;
158 }
159
160 #ifndef MTK_PLAT_SPM_UNSUPPORT
161 struct mt_lp_res_req rq_xo_fpm = {
162 .res_id = MT_LP_RQ_XO_FPM,
163 .res_rq = MT_SPM_XO_FPM,
164 .res_usage = 0,
165 };
166
167 struct mt_lp_res_req rq_26m = {
168 .res_id = MT_LP_RQ_26M,
169 .res_rq = MT_SPM_26M,
170 .res_usage = 0,
171 };
172
173 struct mt_lp_res_req rq_infra = {
174 .res_id = MT_LP_RQ_INFRA,
175 .res_rq = MT_SPM_INFRA,
176 .res_usage = 0,
177 };
178
179 struct mt_lp_res_req rq_syspll = {
180 .res_id = MT_LP_RQ_SYSPLL,
181 .res_rq = MT_SPM_SYSPLL,
182 .res_usage = 0,
183 };
184
185 struct mt_lp_res_req rq_dram_s0 = {
186 .res_id = MT_LP_RQ_DRAM,
187 .res_rq = MT_SPM_DRAM_S0,
188 .res_usage = 0,
189 };
190
191 struct mt_lp_res_req rq_dram_s1 = {
192 .res_id = MT_LP_RQ_DRAM,
193 .res_rq = MT_SPM_DRAM_S1,
194 .res_usage = 0,
195 };
196
197 struct mt_lp_res_req rq_vcore = {
198 .res_id = MT_LP_RQ_VCORE,
199 .res_rq = MT_SPM_VCORE,
200 .res_usage = 0,
201 };
202
203 struct mt_lp_res_req rq_emi = {
204 .res_id = MT_LP_RQ_EMI,
205 .res_rq = MT_SPM_EMI,
206 .res_usage = 0,
207 };
208
209 struct mt_lp_res_req rq_pmic = {
210 .res_id = MT_LP_RQ_PMIC,
211 .res_rq = MT_SPM_PMIC,
212 .res_usage = 0,
213 };
214
215 struct mt_lp_res_req *spm_resources[] = {
216 &rq_xo_fpm,
217 &rq_26m,
218 &rq_infra,
219 &rq_syspll,
220 &rq_dram_s0,
221 &rq_dram_s1,
222 &rq_vcore,
223 &rq_emi,
224 &rq_pmic,
225 NULL,
226 };
227
228 struct mt_resource_req_manager plat_mt8196_rq = {
229 .res = spm_resources,
230 };
231
232 struct mt_resource_constraint plat_constraint_vcore = {
233 .is_valid = spm_is_valid_rc_vcore,
234 .update = spm_update_rc_vcore,
235 .allow = spm_allow_rc_vcore,
236 .run = spm_run_rc_vcore,
237 .reset = spm_reset_rc_vcore,
238 .get_status = spm_get_status_rc_vcore,
239 };
240
241 struct mt_resource_constraint plat_constraint_bus26m = {
242 .is_valid = spm_is_valid_rc_bus26m,
243 .update = spm_update_rc_bus26m,
244 .allow = spm_allow_rc_bus26m,
245 .run = spm_run_rc_bus26m,
246 .reset = spm_reset_rc_bus26m,
247 .get_status = spm_get_status_rc_bus26m,
248 };
249
250 struct mt_resource_constraint plat_constraint_syspll = {
251 .is_valid = spm_is_valid_rc_syspll,
252 .update = spm_update_rc_syspll,
253 .allow = spm_allow_rc_syspll,
254 .run = spm_run_rc_syspll,
255 .reset = spm_reset_rc_syspll,
256 .get_status = spm_get_status_rc_syspll,
257 };
258
259 struct mt_resource_constraint *plat_constraints[] = {
260 &plat_constraint_vcore,
261 &plat_constraint_bus26m,
262 &plat_constraint_syspll,
263 NULL,
264 };
265 #endif
266
mt_spm_hwctrl(uint32_t type,int set,void * priv)267 int mt_spm_hwctrl(uint32_t type, int set, void *priv)
268 {
269 int ret = 0;
270
271 if (type == PLAT_AP_MDSRC_REQ) {
272 spm_ap_mdsrc_req(set);
273 } else if (type == PLAT_AP_MDSRC_ACK) {
274 ret = spm_ap_mdsrc_ack();
275 } else if (type == PLAT_AP_IS_MD_SLEEP) {
276 ret = spm_is_md_sleep(priv);
277 } else if (type == PLAT_AP_MDSRC_SETTLE) {
278 if (!priv)
279 return -1;
280 *(int *)priv = AP_MDSRC_REQ_MD_26M_SETTLE;
281 } else if (type == PLAT_AP_GPUEB_PLL_CONTROL) {
282 spm_ap_gpueb_pll_control(set);
283 } else if (type == PLAT_AP_GPUEB_PWR_STATUS) {
284 if (!priv)
285 return -1;
286 *(uint32_t *)priv = spm_ap_gpueb_get_pwr_status();
287 } else if (type == PLAT_AP_GPUEB_MFG0_PWR_CON) {
288 if (!priv)
289 return -1;
290 *(uint32_t *)priv = spm_ap_gpueb_get_mfg0_pwr_con();
291 } else if (type == PLAT_AP_SPM_RESOURCE_REQUEST_UPDATE) {
292 struct spm_lp_scen *spmlp = NULL;
293
294 #ifdef MT_SPM_COMMON_SODI_SUPPORT
295 mt_spm_common_sodi_get_spm_lp(&spmlp);
296 #else
297 #if defined(MT_SPM_FEATURE_SUPPORT)
298 mt_spm_idle_generic_get_spm_lp(&spmlp);
299 #endif
300 #endif
301 if (!spmlp)
302 return -1;
303 __spm_set_power_control(spmlp->pwrctrl, *(uint32_t *)priv);
304 ret = __spm_wait_spm_request_ack(*(uint32_t *)priv,
305 SPM_ACK_TIMEOUT_US);
306 } else if (type == PLAT_AP_SPM_WDT_TRIGGER) {
307 mmio_write_32(PCM_WDT_VAL, 0x1);
308 mmio_setbits_32(PCM_CON1, SPM_REGWR_CFG_KEY |
309 REG_PCM_WDT_EN_LSB | REG_PCM_WDT_WAKE_LSB);
310 } else {
311 /* Not supported type */
312 return -1;
313 }
314
315 return ret;
316 }
317
318 #ifndef MTK_PLAT_SPM_UNSUPPORT
319 struct mt_resource_manager plat_mt8196_rm = {
320 .update = NULL,
321 .hwctrl = mt_spm_hwctrl,
322 .consts = plat_constraints,
323 };
324 #else
325 struct mt_resource_manager plat_mt8196_rm = {
326 .hwctrl = mt_spm_hwctrl,
327 };
328 #endif
329
330 /* Determine for spm sw resource user */
331 static struct mt_lp_resource_user spm_res_user;
332
get_spm_res_user(void)333 struct mt_lp_resource_user *get_spm_res_user(void)
334 {
335 return &spm_res_user;
336 }
337
338 #ifdef MT_SPM_COMMON_SODI_SUPPORT
mt_spm_common_sodi_get_spm_pcm_flag(uint32_t * lp,uint32_t idx)339 int mt_spm_common_sodi_get_spm_pcm_flag(uint32_t *lp, uint32_t idx)
340 {
341 struct spm_lp_scen *spmlp;
342 struct pwr_ctrl *pwrctrl;
343
344 mt_spm_common_sodi_get_spm_lp(&spmlp);
345
346 pwrctrl = spmlp->pwrctrl;
347
348 if (!lp || idx > 1)
349 return -1;
350
351 switch (idx) {
352 case 0:
353 *lp = pwrctrl->pcm_flags;
354 break;
355 case 1:
356 *lp = pwrctrl->pcm_flags;
357 break;
358 default:
359 return -1;
360 }
361 return 0;
362 }
363
mt_spm_common_sodi_en(bool en)364 void mt_spm_common_sodi_en(bool en)
365 {
366 struct spm_lp_scen *spmlp;
367 struct pwr_ctrl *pwrctrl;
368
369 mt_spm_common_sodi_get_spm_lp(&spmlp);
370 pwrctrl = spmlp->pwrctrl;
371 #if defined(CONFIG_MTK_VCOREDVFS_SUPPORT)
372 __spm_sync_vcore_dvfs_pcm_flags(&pwrctrl->pcm_flags,
373 &__spm_vcorefs.pwrctrl->pcm_flags);
374 #endif
375 if (en)
376 pwrctrl->pcm_flags |= SPM_FLAG_ENABLE_COMMON_SODI5;
377 else
378 pwrctrl->pcm_flags &= (~SPM_FLAG_ENABLE_COMMON_SODI5);
379
380 /* Set PCM flags */
381 __spm_set_pcm_flags(pwrctrl);
382
383 __spm_send_cpu_wakeup_event();
384 }
385
mt_spm_common_sodi_get_spm_lp(struct spm_lp_scen ** lp)386 int mt_spm_common_sodi_get_spm_lp(struct spm_lp_scen **lp)
387 {
388 if (!lp)
389 return -1;
390
391 *lp = &__spm_common_sodi;
392 return 0;
393 }
394
mt_spm_set_common_sodi_pwrctr(void)395 void mt_spm_set_common_sodi_pwrctr(void)
396 {
397 struct resource_req_status common_sodi_spm_resource_req = {
398 .id = MT_LP_RQ_ID_ALL_USAGE,
399 .val = 0,
400 };
401 struct spm_lp_scen *spmlp;
402
403 mt_lp_rq_get_status(PLAT_RQ_REQ_USAGE,
404 &common_sodi_spm_resource_req);
405 mt_spm_common_sodi_get_spm_lp(&spmlp);
406
407 __spm_set_power_control(spmlp->pwrctrl,
408 common_sodi_spm_resource_req.val);
409 }
410
mt_spm_set_common_sodi_pcm_flags(void)411 void mt_spm_set_common_sodi_pcm_flags(void)
412 {
413 struct spm_lp_scen *spmlp;
414 struct pwr_ctrl *pwrctrl;
415
416 mt_spm_common_sodi_get_spm_lp(&spmlp);
417 pwrctrl = spmlp->pwrctrl;
418 #if defined(CONFIG_MTK_VCOREDVFS_SUPPORT)
419 /* Set PCM flags */
420 __spm_sync_vcore_dvfs_pcm_flags(&pwrctrl->pcm_flags,
421 &__spm_vcorefs.pwrctrl->pcm_flags);
422 #endif
423 __spm_set_pcm_flags(pwrctrl);
424
425 __spm_send_cpu_wakeup_event();
426
427 }
428 #endif
429
spm_boot_init(void)430 int spm_boot_init(void)
431 {
432 plat_spm_lock_init();
433
434 #if defined(MT_SPM_FEATURE_SUPPORT)
435 plat_spm_pmic_wrap_init();
436 #endif
437 mt_lp_rm_register(&plat_mt8196_rm);
438
439 #ifndef MTK_PLAT_SPM_UNSUPPORT
440 mt_lp_resource_request_manager_register(&plat_mt8196_rq);
441 mt_lp_resource_user_register("SPM", &spm_res_user);
442 mt_spm_dispatcher_init();
443 #endif
444 #if defined(MT_SPM_FEATURE_SUPPORT)
445 spm_hwreq_init();
446 #endif
447 spm_irq_num = 0xFFFFFFFF;
448
449 INFO("[%s], PC = 0x%x\n", __func__, mmio_read_32(MD32PCM_PC));
450 return 0;
451 }
452 MTK_PLAT_SETUP_1_INIT(spm_boot_init);
453