xref: /rk3399_ARM-atf/plat/mediatek/drivers/spm/mt8196/mt_spm.c (revision e7be9243d071b37d13d826824ec4bb8c8b39caa2)
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 uint32_t mt_spm_version;
54 
55 static uint32_t spm_irq_num;
56 
57 void 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 
67 void spm_set_irq_num(uint32_t num)
68 {
69 	spm_irq_num = num;
70 }
71 
72 void 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 
81 static 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 
100 static 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 
112 static 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 
132 static 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 
144 static 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 
153 static 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
163 struct 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 
169 struct 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 
175 struct 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 
181 struct 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 
187 struct 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 
193 struct 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 
199 struct 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 
205 struct 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 
211 struct 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 
217 struct 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 
230 struct mt_resource_req_manager plat_mt8196_rq = {
231 	.res = spm_resources,
232 };
233 
234 struct 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 
243 struct 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 
252 struct 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 
261 struct mt_resource_constraint *plat_constraints[] = {
262 	&plat_constraint_vcore,
263 	&plat_constraint_bus26m,
264 	&plat_constraint_syspll,
265 	NULL,
266 };
267 #endif
268 
269 int 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
321 struct mt_resource_manager plat_mt8196_rm = {
322 	.update = NULL,
323 	.hwctrl = mt_spm_hwctrl,
324 	.consts = plat_constraints,
325 };
326 #else
327 struct mt_resource_manager plat_mt8196_rm = {
328 	.hwctrl = mt_spm_hwctrl,
329 };
330 #endif
331 
332 /* Determine for spm sw resource user */
333 static struct mt_lp_resource_user spm_res_user;
334 
335 struct mt_lp_resource_user *get_spm_res_user(void)
336 {
337 	return &spm_res_user;
338 }
339 
340 #ifdef MT_SPM_COMMON_SODI_SUPPORT
341 int 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 
366 void 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 
388 int 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 
397 void 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 
413 void 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 
432 static 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 
438 int 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 }
464 MTK_PLAT_SETUP_1_INIT(spm_boot_init);
465