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