xref: /rk3399_ARM-atf/plat/mediatek/drivers/spm/mt8196/mt_spm.c (revision 10ecd58093a34e95e2dfad65b1180610f29397cc)
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 
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 
65 void spm_set_irq_num(uint32_t num)
66 {
67 	spm_irq_num = num;
68 }
69 
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 
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 
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 
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 
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 
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 
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 
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 
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
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 
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 
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 
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 
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 
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