xref: /rk3399_ARM-atf/plat/mediatek/mt8183/plat_pm.c (revision 9fc34bbd8d804b5a89472b714a55ccfe7931f2ae)
1 /*
2  * Copyright (c) 2019, MediaTek Inc. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /* common headers */
8 #include <arch_helpers.h>
9 #include <assert.h>
10 #include <common/debug.h>
11 #include <lib/mmio.h>
12 #include <lib/psci/psci.h>
13 #include <errno.h>
14 
15 /* mediatek platform specific headers */
16 #include <platform_def.h>
17 #include <scu.h>
18 #include <mt_gic_v3.h>
19 #include <mtk_plat_common.h>
20 #include <mtgpio.h>
21 #include <mtspmc.h>
22 #include <plat_dcm.h>
23 #include <plat_debug.h>
24 #include <plat_params.h>
25 #include <plat_private.h>
26 #include <power_tracer.h>
27 #include <pmic.h>
28 #include <spm.h>
29 #include <spm_suspend.h>
30 #include <rtc.h>
31 
32 #define MTK_LOCAL_STATE_OFF     2
33 
34 static uintptr_t secure_entrypoint;
35 
36 static void mp1_L2_desel_config(void)
37 {
38 	mmio_write_64(MCUCFG_BASE + 0x2200, 0x2092c820);
39 
40 	dsb();
41 }
42 
43 static int plat_mtk_power_domain_on(unsigned long mpidr)
44 {
45 	int cpu = MPIDR_AFFLVL0_VAL(mpidr);
46 	int cluster = MPIDR_AFFLVL1_VAL(mpidr);
47 
48 	INFO("%s():%d: mpidr: %lx, c.c: %d.%d\n",
49 		__func__, __LINE__, mpidr, cluster, cpu);
50 
51 	/* power on cluster */
52 	if (!spm_get_cluster_powerstate(cluster)) {
53 		spm_poweron_cluster(cluster);
54 		if (cluster == 1) {
55 			l2c_parity_check_setup();
56 			circular_buffer_setup();
57 			mp1_L2_desel_config();
58 			mt_gic_sync_dcm_disable();
59 		}
60 	}
61 
62 	/* init cpu reset arch as AARCH64 */
63 	mcucfg_init_archstate(cluster, cpu, 1);
64 	mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
65 
66 	spm_poweron_cpu(cluster, cpu);
67 
68 	return PSCI_E_SUCCESS;
69 }
70 
71 static void plat_mtk_power_domain_off(const psci_power_state_t *state)
72 {
73 	uint64_t mpidr = read_mpidr();
74 	int cpu = MPIDR_AFFLVL0_VAL(mpidr);
75 	int cluster = MPIDR_AFFLVL1_VAL(mpidr);
76 
77 	INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu);
78 
79 	/* Prevent interrupts from spuriously waking up this cpu */
80 	mt_gic_cpuif_disable();
81 
82 	spm_enable_cpu_auto_off(cluster, cpu);
83 
84 	if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) {
85 		if (cluster == 1)
86 			mt_gic_sync_dcm_enable();
87 
88 		plat_mtk_cci_disable();
89 		spm_enable_cluster_auto_off(cluster);
90 	}
91 
92 	spm_set_cpu_power_off(cluster, cpu);
93 }
94 
95 static void plat_mtk_power_domain_on_finish(const psci_power_state_t *state)
96 {
97 	uint64_t mpidr = read_mpidr();
98 	int cpu = MPIDR_AFFLVL0_VAL(mpidr);
99 	int cluster = MPIDR_AFFLVL1_VAL(mpidr);
100 
101 	INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu);
102 
103 	assert(state->pwr_domain_state[MPIDR_AFFLVL0] == MTK_LOCAL_STATE_OFF);
104 
105 	if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) {
106 		enable_scu(mpidr);
107 
108 		/* Enable coherency if this cluster was off */
109 		plat_mtk_cci_enable();
110 		/* Enable big core dcm if this cluster was on */
111 		plat_dcm_restore_cluster_on(mpidr);
112 		/* Enable rgu dcm if this cluster was off */
113 		plat_dcm_rgu_enable();
114 	}
115 
116 	spm_disable_cpu_auto_off(cluster, cpu);
117 
118 	/* Enable the gic cpu interface */
119 	mt_gic_pcpu_init();
120 	mt_gic_cpuif_enable();
121 }
122 
123 /*******************************************************************************
124  * MTK handlers to shutdown/reboot the system
125  ******************************************************************************/
126 static void __dead2 plat_mtk_system_off(void)
127 {
128 	INFO("MTK System Off\n");
129 
130 	rtc_power_off_sequence();
131 	wk_pmic_enable_sdn_delay();
132 	pmic_power_off();
133 
134 	wfi();
135 	ERROR("MTK System Off: operation not handled.\n");
136 	panic();
137 }
138 
139 static void __dead2 plat_mtk_system_reset(void)
140 {
141 	struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset();
142 
143 	INFO("MTK System Reset\n");
144 
145 	mt_set_gpio_out(gpio_reset->index, gpio_reset->polarity);
146 
147 	wfi();
148 	ERROR("MTK System Reset: operation not handled.\n");
149 	panic();
150 }
151 
152 static void plat_mtk_power_domain_suspend(const psci_power_state_t *state)
153 {
154 	uint64_t mpidr = read_mpidr();
155 	int cpu = MPIDR_AFFLVL0_VAL(mpidr);
156 	int cluster = MPIDR_AFFLVL1_VAL(mpidr);
157 
158 	spm_system_suspend();
159 
160 	/* init cpu reset arch as AARCH64 */
161 	mcucfg_init_archstate(cluster, cpu, 1);
162 	mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
163 	spm_set_bootaddr(secure_entrypoint);
164 
165 	/* Prevent interrupts from spuriously waking up this cpu */
166 	mt_gic_cpuif_disable();
167 	mt_gic_irq_save();
168 
169 	if (state->pwr_domain_state[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF) {
170 		plat_mtk_cci_disable();
171 		disable_scu(mpidr);
172 	}
173 }
174 
175 static void plat_mtk_power_domain_suspend_finish(const psci_power_state_t *state)
176 {
177 	uint64_t mpidr = read_mpidr();
178 
179 	mt_gic_init();
180 	mt_gic_irq_restore();
181 
182 	if (state->pwr_domain_state[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF) {
183 		enable_scu(mpidr);
184 		plat_mtk_cci_enable();
185 		plat_dcm_restore_cluster_on(mpidr);
186 	}
187 
188 	mmio_write_32(EMI_WFIFO, 0xf);
189 	spm_system_suspend_finish();
190 }
191 
192 static void plat_mtk_get_sys_suspend_power_state(psci_power_state_t *req_state)
193 {
194 	assert(PLAT_MAX_PWR_LVL >= 2);
195 
196 	for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
197 		req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF;
198 }
199 
200 /*******************************************************************************
201  * MTK_platform handler called when an affinity instance is about to be turned
202  * on. The level and mpidr determine the affinity instance.
203  ******************************************************************************/
204 static const plat_psci_ops_t plat_plat_pm_ops = {
205 	.cpu_standby			= NULL,
206 	.pwr_domain_on			= plat_mtk_power_domain_on,
207 	.pwr_domain_on_finish		= plat_mtk_power_domain_on_finish,
208 	.pwr_domain_off			= plat_mtk_power_domain_off,
209 	.pwr_domain_suspend		= plat_mtk_power_domain_suspend,
210 	.pwr_domain_suspend_finish	= plat_mtk_power_domain_suspend_finish,
211 	.system_off			= plat_mtk_system_off,
212 	.system_reset			= plat_mtk_system_reset,
213 	.validate_power_state		= NULL,
214 	.get_sys_suspend_power_state	= plat_mtk_get_sys_suspend_power_state,
215 };
216 
217 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
218 			const plat_psci_ops_t **psci_ops)
219 {
220 	*psci_ops = &plat_plat_pm_ops;
221 	secure_entrypoint = sec_entrypoint;
222 	return 0;
223 }
224