xref: /rk3399_ARM-atf/plat/mediatek/mt8183/plat_pm.c (revision 3c25ba440750d4b58599aca907a479627ef62551)
13fa9dec4Skenny liang /*
27352f329Skenny liang  * Copyright (c) 2019, MediaTek Inc. All rights reserved.
33fa9dec4Skenny liang  *
43fa9dec4Skenny liang  * SPDX-License-Identifier: BSD-3-Clause
53fa9dec4Skenny liang  */
63fa9dec4Skenny liang 
73fa9dec4Skenny liang /* common headers */
83fa9dec4Skenny liang #include <arch_helpers.h>
93fa9dec4Skenny liang #include <assert.h>
103fa9dec4Skenny liang #include <common/debug.h>
113fa9dec4Skenny liang #include <lib/mmio.h>
123fa9dec4Skenny liang #include <lib/psci/psci.h>
133fa9dec4Skenny liang #include <errno.h>
143fa9dec4Skenny liang 
153fa9dec4Skenny liang /* mediatek platform specific headers */
163fa9dec4Skenny liang #include <platform_def.h>
173fa9dec4Skenny liang #include <scu.h>
187352f329Skenny liang #include <mt_gic_v3.h>
193fa9dec4Skenny liang #include <mtk_plat_common.h>
203d91c9c3Skenny liang #include <mtgpio.h>
217352f329Skenny liang #include <mtspmc.h>
227352f329Skenny liang #include <plat_dcm.h>
237352f329Skenny liang #include <plat_debug.h>
243d91c9c3Skenny liang #include <plat_params.h>
253fa9dec4Skenny liang #include <plat_private.h>
263d91c9c3Skenny liang #include <power_tracer.h>
27e977b4dbSkenny liang #include <pmic.h>
28*3c25ba44Skenny liang #include <spm.h>
29*3c25ba44Skenny liang #include <spm_suspend.h>
30e977b4dbSkenny liang #include <rtc.h>
313fa9dec4Skenny liang 
327352f329Skenny liang #define MTK_LOCAL_STATE_OFF     2
337352f329Skenny liang 
347352f329Skenny liang static uintptr_t secure_entrypoint;
357352f329Skenny liang 
367352f329Skenny liang static void mp1_L2_desel_config(void)
377352f329Skenny liang {
387352f329Skenny liang 	mmio_write_64(MCUCFG_BASE + 0x2200, 0x2092c820);
397352f329Skenny liang 
407352f329Skenny liang 	dsb();
417352f329Skenny liang }
427352f329Skenny liang 
437352f329Skenny liang static int plat_mtk_power_domain_on(unsigned long mpidr)
447352f329Skenny liang {
457352f329Skenny liang 	int cpu = MPIDR_AFFLVL0_VAL(mpidr);
467352f329Skenny liang 	int cluster = MPIDR_AFFLVL1_VAL(mpidr);
477352f329Skenny liang 
487352f329Skenny liang 	INFO("%s():%d: mpidr: %lx, c.c: %d.%d\n",
497352f329Skenny liang 		__func__, __LINE__, mpidr, cluster, cpu);
507352f329Skenny liang 
517352f329Skenny liang 	/* power on cluster */
527352f329Skenny liang 	if (!spm_get_cluster_powerstate(cluster)) {
537352f329Skenny liang 		spm_poweron_cluster(cluster);
547352f329Skenny liang 		if (cluster == 1) {
557352f329Skenny liang 			l2c_parity_check_setup();
567352f329Skenny liang 			circular_buffer_setup();
577352f329Skenny liang 			mp1_L2_desel_config();
587352f329Skenny liang 			mt_gic_sync_dcm_disable();
597352f329Skenny liang 		}
607352f329Skenny liang 	}
617352f329Skenny liang 
627352f329Skenny liang 	/* init cpu reset arch as AARCH64 */
637352f329Skenny liang 	mcucfg_init_archstate(cluster, cpu, 1);
647352f329Skenny liang 	mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
657352f329Skenny liang 
667352f329Skenny liang 	spm_poweron_cpu(cluster, cpu);
677352f329Skenny liang 
687352f329Skenny liang 	return PSCI_E_SUCCESS;
697352f329Skenny liang }
707352f329Skenny liang 
717352f329Skenny liang static void plat_mtk_power_domain_off(const psci_power_state_t *state)
727352f329Skenny liang {
737352f329Skenny liang 	uint64_t mpidr = read_mpidr();
747352f329Skenny liang 	int cpu = MPIDR_AFFLVL0_VAL(mpidr);
757352f329Skenny liang 	int cluster = MPIDR_AFFLVL1_VAL(mpidr);
767352f329Skenny liang 
777352f329Skenny liang 	INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu);
787352f329Skenny liang 
797352f329Skenny liang 	/* Prevent interrupts from spuriously waking up this cpu */
807352f329Skenny liang 	mt_gic_cpuif_disable();
817352f329Skenny liang 
827352f329Skenny liang 	spm_enable_cpu_auto_off(cluster, cpu);
837352f329Skenny liang 
847352f329Skenny liang 	if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) {
857352f329Skenny liang 		if (cluster == 1)
867352f329Skenny liang 			mt_gic_sync_dcm_enable();
877352f329Skenny liang 
887352f329Skenny liang 		plat_mtk_cci_disable();
897352f329Skenny liang 		spm_enable_cluster_auto_off(cluster);
907352f329Skenny liang 	}
917352f329Skenny liang 
927352f329Skenny liang 	spm_set_cpu_power_off(cluster, cpu);
937352f329Skenny liang }
947352f329Skenny liang 
957352f329Skenny liang static void plat_mtk_power_domain_on_finish(const psci_power_state_t *state)
967352f329Skenny liang {
977352f329Skenny liang 	uint64_t mpidr = read_mpidr();
987352f329Skenny liang 	int cpu = MPIDR_AFFLVL0_VAL(mpidr);
997352f329Skenny liang 	int cluster = MPIDR_AFFLVL1_VAL(mpidr);
1007352f329Skenny liang 
1017352f329Skenny liang 	INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu);
1027352f329Skenny liang 
1037352f329Skenny liang 	assert(state->pwr_domain_state[MPIDR_AFFLVL0] == MTK_LOCAL_STATE_OFF);
1047352f329Skenny liang 
1057352f329Skenny liang 	if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) {
1067352f329Skenny liang 		enable_scu(mpidr);
1077352f329Skenny liang 
1087352f329Skenny liang 		/* Enable coherency if this cluster was off */
1097352f329Skenny liang 		plat_mtk_cci_enable();
1107352f329Skenny liang 		/* Enable big core dcm if this cluster was on */
1117352f329Skenny liang 		plat_dcm_restore_cluster_on(mpidr);
1127352f329Skenny liang 		/* Enable rgu dcm if this cluster was off */
1137352f329Skenny liang 		plat_dcm_rgu_enable();
1147352f329Skenny liang 	}
1157352f329Skenny liang 
1167352f329Skenny liang 	spm_disable_cpu_auto_off(cluster, cpu);
1177352f329Skenny liang 
1187352f329Skenny liang 	/* Enable the gic cpu interface */
1197352f329Skenny liang 	mt_gic_pcpu_init();
1207352f329Skenny liang 	mt_gic_cpuif_enable();
1217352f329Skenny liang }
1227352f329Skenny liang 
1233fa9dec4Skenny liang /*******************************************************************************
124e977b4dbSkenny liang  * MTK handlers to shutdown/reboot the system
125e977b4dbSkenny liang  ******************************************************************************/
126e977b4dbSkenny liang static void __dead2 plat_mtk_system_off(void)
127e977b4dbSkenny liang {
128e977b4dbSkenny liang 	INFO("MTK System Off\n");
129e977b4dbSkenny liang 
130e977b4dbSkenny liang 	rtc_power_off_sequence();
131e977b4dbSkenny liang 	wk_pmic_enable_sdn_delay();
132e977b4dbSkenny liang 	pmic_power_off();
133e977b4dbSkenny liang 
134e977b4dbSkenny liang 	wfi();
135e977b4dbSkenny liang 	ERROR("MTK System Off: operation not handled.\n");
136e977b4dbSkenny liang 	panic();
137e977b4dbSkenny liang }
138e977b4dbSkenny liang 
1393d91c9c3Skenny liang static void __dead2 plat_mtk_system_reset(void)
1403d91c9c3Skenny liang {
1413d91c9c3Skenny liang 	struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset();
1423d91c9c3Skenny liang 
1433d91c9c3Skenny liang 	INFO("MTK System Reset\n");
1443d91c9c3Skenny liang 
1453d91c9c3Skenny liang 	mt_set_gpio_out(gpio_reset->index, gpio_reset->polarity);
1463d91c9c3Skenny liang 
1473d91c9c3Skenny liang 	wfi();
1483d91c9c3Skenny liang 	ERROR("MTK System Reset: operation not handled.\n");
1493d91c9c3Skenny liang 	panic();
1503d91c9c3Skenny liang }
1513d91c9c3Skenny liang 
152*3c25ba44Skenny liang static void plat_mtk_power_domain_suspend(const psci_power_state_t *state)
153*3c25ba44Skenny liang {
154*3c25ba44Skenny liang 	uint64_t mpidr = read_mpidr();
155*3c25ba44Skenny liang 	int cpu = MPIDR_AFFLVL0_VAL(mpidr);
156*3c25ba44Skenny liang 	int cluster = MPIDR_AFFLVL1_VAL(mpidr);
157*3c25ba44Skenny liang 
158*3c25ba44Skenny liang 	spm_system_suspend();
159*3c25ba44Skenny liang 
160*3c25ba44Skenny liang 	/* init cpu reset arch as AARCH64 */
161*3c25ba44Skenny liang 	mcucfg_init_archstate(cluster, cpu, 1);
162*3c25ba44Skenny liang 	mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
163*3c25ba44Skenny liang 	spm_set_bootaddr(secure_entrypoint);
164*3c25ba44Skenny liang 
165*3c25ba44Skenny liang 	/* Prevent interrupts from spuriously waking up this cpu */
166*3c25ba44Skenny liang 	mt_gic_cpuif_disable();
167*3c25ba44Skenny liang 	mt_gic_irq_save();
168*3c25ba44Skenny liang 
169*3c25ba44Skenny liang 	if (state->pwr_domain_state[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF) {
170*3c25ba44Skenny liang 		plat_mtk_cci_disable();
171*3c25ba44Skenny liang 		disable_scu(mpidr);
172*3c25ba44Skenny liang 	}
173*3c25ba44Skenny liang }
174*3c25ba44Skenny liang 
175*3c25ba44Skenny liang static void plat_mtk_power_domain_suspend_finish(const psci_power_state_t *state)
176*3c25ba44Skenny liang {
177*3c25ba44Skenny liang 	uint64_t mpidr = read_mpidr();
178*3c25ba44Skenny liang 
179*3c25ba44Skenny liang 	mt_gic_init();
180*3c25ba44Skenny liang 	mt_gic_irq_restore();
181*3c25ba44Skenny liang 
182*3c25ba44Skenny liang 	if (state->pwr_domain_state[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF) {
183*3c25ba44Skenny liang 		enable_scu(mpidr);
184*3c25ba44Skenny liang 		plat_mtk_cci_enable();
185*3c25ba44Skenny liang 		plat_dcm_restore_cluster_on(mpidr);
186*3c25ba44Skenny liang 	}
187*3c25ba44Skenny liang 
188*3c25ba44Skenny liang 	mmio_write_32(EMI_WFIFO, 0xf);
189*3c25ba44Skenny liang 	spm_system_suspend_finish();
190*3c25ba44Skenny liang }
191*3c25ba44Skenny liang 
192*3c25ba44Skenny liang static void plat_mtk_get_sys_suspend_power_state(psci_power_state_t *req_state)
193*3c25ba44Skenny liang {
194*3c25ba44Skenny liang 	assert(PLAT_MAX_PWR_LVL >= 2);
195*3c25ba44Skenny liang 
196*3c25ba44Skenny liang 	for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
197*3c25ba44Skenny liang 		req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF;
198*3c25ba44Skenny liang }
199*3c25ba44Skenny liang 
200e977b4dbSkenny liang /*******************************************************************************
2013fa9dec4Skenny liang  * MTK_platform handler called when an affinity instance is about to be turned
2023fa9dec4Skenny liang  * on. The level and mpidr determine the affinity instance.
2033fa9dec4Skenny liang  ******************************************************************************/
2043fa9dec4Skenny liang static const plat_psci_ops_t plat_plat_pm_ops = {
2053fa9dec4Skenny liang 	.cpu_standby			= NULL,
2067352f329Skenny liang 	.pwr_domain_on			= plat_mtk_power_domain_on,
2077352f329Skenny liang 	.pwr_domain_on_finish		= plat_mtk_power_domain_on_finish,
2087352f329Skenny liang 	.pwr_domain_off			= plat_mtk_power_domain_off,
209*3c25ba44Skenny liang 	.pwr_domain_suspend		= plat_mtk_power_domain_suspend,
210*3c25ba44Skenny liang 	.pwr_domain_suspend_finish	= plat_mtk_power_domain_suspend_finish,
211e977b4dbSkenny liang 	.system_off			= plat_mtk_system_off,
2123d91c9c3Skenny liang 	.system_reset			= plat_mtk_system_reset,
2133fa9dec4Skenny liang 	.validate_power_state		= NULL,
214*3c25ba44Skenny liang 	.get_sys_suspend_power_state	= plat_mtk_get_sys_suspend_power_state,
2153fa9dec4Skenny liang };
2163fa9dec4Skenny liang 
2173fa9dec4Skenny liang int plat_setup_psci_ops(uintptr_t sec_entrypoint,
2183fa9dec4Skenny liang 			const plat_psci_ops_t **psci_ops)
2193fa9dec4Skenny liang {
2203fa9dec4Skenny liang 	*psci_ops = &plat_plat_pm_ops;
2213fa9dec4Skenny liang 	secure_entrypoint = sec_entrypoint;
2223fa9dec4Skenny liang 	return 0;
2233fa9dec4Skenny liang }
224