xref: /arm-trusted-firmware/plat/mediatek/lib/pm/armv8_2/pwr_ctrl.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2022, Mediatek Inc. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <common/debug.h>
11*91f16700Schasinglulu #include <drivers/arm/gicv3.h>
12*91f16700Schasinglulu #include <lib/psci/psci.h>
13*91f16700Schasinglulu #include <lib/utils.h>
14*91f16700Schasinglulu #ifdef MTK_PUBEVENT_ENABLE
15*91f16700Schasinglulu #include <vendor_pubsub_events.h>
16*91f16700Schasinglulu #endif
17*91f16700Schasinglulu #include <plat/arm/common/plat_arm.h>
18*91f16700Schasinglulu #include <plat/common/platform.h>
19*91f16700Schasinglulu 
20*91f16700Schasinglulu #include <dfd.h>
21*91f16700Schasinglulu #include <lib/mtk_init/mtk_init.h>
22*91f16700Schasinglulu #include <lib/pm/mtk_pm.h>
23*91f16700Schasinglulu #include <mt_gic_v3.h>
24*91f16700Schasinglulu #include <platform_def.h>
25*91f16700Schasinglulu 
26*91f16700Schasinglulu #define IS_AFFLV_PUBEVENT(_pstate) \
27*91f16700Schasinglulu 	((_pstate & (MT_CPUPM_PWR_DOMAIN_MCUSYS | MT_CPUPM_PWR_DOMAIN_CLUSTER)) != 0)
28*91f16700Schasinglulu 
29*91f16700Schasinglulu #ifdef MTK_PUBEVENT_ENABLE
30*91f16700Schasinglulu #define MT_CPUPM_EVENT_PWR_ON(x) ({ \
31*91f16700Schasinglulu 	PUBLISH_EVENT_ARG(mt_cpupm_publish_pwr_on, (const void *)(x)); })
32*91f16700Schasinglulu 
33*91f16700Schasinglulu #define MT_CPUPM_EVENT_PWR_OFF(x) ({ \
34*91f16700Schasinglulu 	PUBLISH_EVENT_ARG(mt_cpupm_publish_pwr_off, (const void *)(x)); })
35*91f16700Schasinglulu 
36*91f16700Schasinglulu #define MT_CPUPM_EVENT_AFFLV_PWR_ON(x) ({ \
37*91f16700Schasinglulu 	PUBLISH_EVENT_ARG(mt_cpupm_publish_afflv_pwr_on, (const void *)(x)); })
38*91f16700Schasinglulu 
39*91f16700Schasinglulu #define MT_CPUPM_EVENT_AFFLV_PWR_OFF(x) ({ \
40*91f16700Schasinglulu 	PUBLISH_EVENT_ARG(mt_cpupm_publish_afflv_pwr_off, (const void *)(x)); })
41*91f16700Schasinglulu 
42*91f16700Schasinglulu #else
43*91f16700Schasinglulu #define MT_CPUPM_EVENT_PWR_ON(x) ({ (void)x; })
44*91f16700Schasinglulu #define MT_CPUPM_EVENT_PWR_OFF(x) ({ (void)x; })
45*91f16700Schasinglulu #define MT_CPUPM_EVENT_AFFLV_PWR_ON(x) ({ (void)x; })
46*91f16700Schasinglulu #define MT_CPUPM_EVENT_AFFLV_PWR_OFF(x) ({ (void)x; })
47*91f16700Schasinglulu #endif
48*91f16700Schasinglulu 
49*91f16700Schasinglulu /*
50*91f16700Schasinglulu  * The cpu require to cluster power stattus
51*91f16700Schasinglulu  * [0] : The cpu require cluster power down
52*91f16700Schasinglulu  * [1] : The cpu require cluster power on
53*91f16700Schasinglulu  */
54*91f16700Schasinglulu #define coordinate_cluster(onoff) write_clusterpwrdn_el1(onoff)
55*91f16700Schasinglulu #define coordinate_cluster_pwron() coordinate_cluster(1)
56*91f16700Schasinglulu #define coordinate_cluster_pwroff() coordinate_cluster(0)
57*91f16700Schasinglulu 
58*91f16700Schasinglulu /* defaultly disable all functions */
59*91f16700Schasinglulu #define MTK_CPUPM_FN_MASK_DEFAULT	(0)
60*91f16700Schasinglulu 
61*91f16700Schasinglulu struct mtk_cpu_pwr_ctrl {
62*91f16700Schasinglulu 	unsigned int fn_mask;
63*91f16700Schasinglulu 	struct mtk_cpu_pm_ops *ops;
64*91f16700Schasinglulu 	struct mtk_cpu_smp_ops *smp;
65*91f16700Schasinglulu };
66*91f16700Schasinglulu 
67*91f16700Schasinglulu static struct mtk_cpu_pwr_ctrl mtk_cpu_pwr = {
68*91f16700Schasinglulu 	.fn_mask = MTK_CPUPM_FN_MASK_DEFAULT,
69*91f16700Schasinglulu 	.ops = NULL,
70*91f16700Schasinglulu };
71*91f16700Schasinglulu 
72*91f16700Schasinglulu #define IS_CPUIDLE_FN_ENABLE(x)	((mtk_cpu_pwr.ops != NULL) && ((mtk_cpu_pwr.fn_mask & x) != 0))
73*91f16700Schasinglulu #define IS_CPUSMP_FN_ENABLE(x)	((mtk_cpu_pwr.smp != NULL) && ((mtk_cpu_pwr.fn_mask & x) != 0))
74*91f16700Schasinglulu 
75*91f16700Schasinglulu /* per-cpu power state */
76*91f16700Schasinglulu static unsigned int armv8_2_power_state[PLATFORM_CORE_COUNT];
77*91f16700Schasinglulu 
78*91f16700Schasinglulu #define armv8_2_get_pwr_stateid(cpu) psci_get_pstate_id(armv8_2_power_state[cpu])
79*91f16700Schasinglulu 
80*91f16700Schasinglulu static unsigned int get_mediatek_pstate(unsigned int domain, unsigned int psci_state,
81*91f16700Schasinglulu 					struct mtk_cpupm_pwrstate *state)
82*91f16700Schasinglulu {
83*91f16700Schasinglulu 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_CPUPM_GET_PWR_STATE)) {
84*91f16700Schasinglulu 		return mtk_cpu_pwr.ops->get_pstate(domain, psci_state, state);
85*91f16700Schasinglulu 	}
86*91f16700Schasinglulu 
87*91f16700Schasinglulu 	return 0;
88*91f16700Schasinglulu }
89*91f16700Schasinglulu 
90*91f16700Schasinglulu unsigned int armv8_2_get_pwr_afflv(const psci_power_state_t *state_info)
91*91f16700Schasinglulu {
92*91f16700Schasinglulu 	int i;
93*91f16700Schasinglulu 
94*91f16700Schasinglulu 	for (i = (int)PLAT_MAX_PWR_LVL; i >= (int)PSCI_CPU_PWR_LVL; i--) {
95*91f16700Schasinglulu 		if (is_local_state_run(state_info->pwr_domain_state[i]) == 0) {
96*91f16700Schasinglulu 			return (unsigned int) i;
97*91f16700Schasinglulu 		}
98*91f16700Schasinglulu 	}
99*91f16700Schasinglulu 
100*91f16700Schasinglulu 	return PSCI_INVALID_PWR_LVL;
101*91f16700Schasinglulu }
102*91f16700Schasinglulu 
103*91f16700Schasinglulu /* MediaTek mcusys power on control interface */
104*91f16700Schasinglulu static void armv8_2_mcusys_pwr_on_common(const struct mtk_cpupm_pwrstate *state)
105*91f16700Schasinglulu {
106*91f16700Schasinglulu 	gicv3_distif_init();
107*91f16700Schasinglulu 	mt_gic_distif_restore();
108*91f16700Schasinglulu 	gic_sgi_restore_all();
109*91f16700Schasinglulu 
110*91f16700Schasinglulu 	dfd_resume();
111*91f16700Schasinglulu 
112*91f16700Schasinglulu 	/* Add code here that behavior before system enter mcusys'on */
113*91f16700Schasinglulu 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_MCUSYS)) {
114*91f16700Schasinglulu 		mtk_cpu_pwr.ops->mcusys_resume(state);
115*91f16700Schasinglulu 	}
116*91f16700Schasinglulu }
117*91f16700Schasinglulu 
118*91f16700Schasinglulu /* MediaTek mcusys power down control interface */
119*91f16700Schasinglulu static void armv8_2_mcusys_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state)
120*91f16700Schasinglulu {
121*91f16700Schasinglulu 	mt_gic_distif_save();
122*91f16700Schasinglulu 	gic_sgi_save_all();
123*91f16700Schasinglulu 
124*91f16700Schasinglulu 	/* Add code here that behaves before entering mcusys off */
125*91f16700Schasinglulu 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_MCUSYS)) {
126*91f16700Schasinglulu 		mtk_cpu_pwr.ops->mcusys_suspend(state);
127*91f16700Schasinglulu 	}
128*91f16700Schasinglulu }
129*91f16700Schasinglulu 
130*91f16700Schasinglulu /* MediaTek Cluster power on control interface */
131*91f16700Schasinglulu static void armv8_2_cluster_pwr_on_common(const struct mtk_cpupm_pwrstate *state)
132*91f16700Schasinglulu {
133*91f16700Schasinglulu 	/* Add code here that behavior before system enter cluster'on */
134*91f16700Schasinglulu #if defined(MTK_CM_MGR) && !defined(MTK_FPGA_EARLY_PORTING)
135*91f16700Schasinglulu 	/* init cpu stall counter */
136*91f16700Schasinglulu 	init_cpu_stall_counter_all();
137*91f16700Schasinglulu #endif
138*91f16700Schasinglulu 
139*91f16700Schasinglulu 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_CLUSTER)) {
140*91f16700Schasinglulu 		mtk_cpu_pwr.ops->cluster_resume(state);
141*91f16700Schasinglulu 	}
142*91f16700Schasinglulu }
143*91f16700Schasinglulu 
144*91f16700Schasinglulu /* MediaTek Cluster power down control interface */
145*91f16700Schasinglulu static void armv8_2_cluster_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state)
146*91f16700Schasinglulu {
147*91f16700Schasinglulu 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_CLUSTER)) {
148*91f16700Schasinglulu 		mtk_cpu_pwr.ops->cluster_suspend(state);
149*91f16700Schasinglulu 	}
150*91f16700Schasinglulu }
151*91f16700Schasinglulu 
152*91f16700Schasinglulu /* MediaTek CPU power on control interface */
153*91f16700Schasinglulu static void armv8_2_cpu_pwr_on_common(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
154*91f16700Schasinglulu {
155*91f16700Schasinglulu 	coordinate_cluster_pwron();
156*91f16700Schasinglulu 
157*91f16700Schasinglulu 	gicv3_rdistif_init(plat_my_core_pos());
158*91f16700Schasinglulu 	gicv3_cpuif_enable(plat_my_core_pos());
159*91f16700Schasinglulu 
160*91f16700Schasinglulu 	/* If MCUSYS has been powered down then restore GIC redistributor for all CPUs. */
161*91f16700Schasinglulu 	if (IS_PLAT_SYSTEM_RETENTION(state->pwr.afflv)) {
162*91f16700Schasinglulu 		mt_gic_rdistif_restore_all();
163*91f16700Schasinglulu 	} else {
164*91f16700Schasinglulu 		mt_gic_rdistif_restore();
165*91f16700Schasinglulu 	}
166*91f16700Schasinglulu }
167*91f16700Schasinglulu 
168*91f16700Schasinglulu /* MediaTek CPU power down control interface */
169*91f16700Schasinglulu static void armv8_2_cpu_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
170*91f16700Schasinglulu {
171*91f16700Schasinglulu 	if ((pstate & MT_CPUPM_PWR_DOMAIN_PERCORE_DSU) != 0) {
172*91f16700Schasinglulu 		coordinate_cluster_pwroff();
173*91f16700Schasinglulu 	}
174*91f16700Schasinglulu 
175*91f16700Schasinglulu 	mt_gic_rdistif_save();
176*91f16700Schasinglulu 	gicv3_cpuif_disable(plat_my_core_pos());
177*91f16700Schasinglulu 	gicv3_rdistif_off(plat_my_core_pos());
178*91f16700Schasinglulu }
179*91f16700Schasinglulu 
180*91f16700Schasinglulu static void armv8_2_cpu_pwr_resume(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
181*91f16700Schasinglulu {
182*91f16700Schasinglulu 	armv8_2_cpu_pwr_on_common(state, pstate);
183*91f16700Schasinglulu 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_CORE)) {
184*91f16700Schasinglulu 		mtk_cpu_pwr.ops->cpu_resume(state);
185*91f16700Schasinglulu 	}
186*91f16700Schasinglulu }
187*91f16700Schasinglulu 
188*91f16700Schasinglulu static void armv8_2_cpu_pwr_suspend(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
189*91f16700Schasinglulu {
190*91f16700Schasinglulu 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_CORE)) {
191*91f16700Schasinglulu 		mtk_cpu_pwr.ops->cpu_suspend(state);
192*91f16700Schasinglulu 	}
193*91f16700Schasinglulu 	armv8_2_cpu_pwr_dwn_common(state, pstate);
194*91f16700Schasinglulu }
195*91f16700Schasinglulu 
196*91f16700Schasinglulu static void armv8_2_cpu_pwr_on(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
197*91f16700Schasinglulu {
198*91f16700Schasinglulu 	armv8_2_cpu_pwr_on_common(state, pstate);
199*91f16700Schasinglulu 
200*91f16700Schasinglulu 	if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_CORE_ON)) {
201*91f16700Schasinglulu 		mtk_cpu_pwr.smp->cpu_on(state);
202*91f16700Schasinglulu 	}
203*91f16700Schasinglulu }
204*91f16700Schasinglulu 
205*91f16700Schasinglulu static void armv8_2_cpu_pwr_off(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
206*91f16700Schasinglulu {
207*91f16700Schasinglulu 	if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_CORE_OFF)) {
208*91f16700Schasinglulu 		mtk_cpu_pwr.smp->cpu_off(state);
209*91f16700Schasinglulu 	}
210*91f16700Schasinglulu 	armv8_2_cpu_pwr_dwn_common(state, pstate);
211*91f16700Schasinglulu }
212*91f16700Schasinglulu 
213*91f16700Schasinglulu /* MediaTek PSCI power domain */
214*91f16700Schasinglulu static int armv8_2_power_domain_on(u_register_t mpidr)
215*91f16700Schasinglulu {
216*91f16700Schasinglulu 	int ret = PSCI_E_SUCCESS;
217*91f16700Schasinglulu 	int cpu = plat_core_pos_by_mpidr(mpidr);
218*91f16700Schasinglulu 	uintptr_t entry = plat_pm_get_warm_entry();
219*91f16700Schasinglulu 
220*91f16700Schasinglulu 	if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_PWR_ON_CORE_PREPARE)) {
221*91f16700Schasinglulu 		if (mtk_cpu_pwr.smp->cpu_pwr_on_prepare(cpu, entry) != 0) {
222*91f16700Schasinglulu 			ret = PSCI_E_DENIED;
223*91f16700Schasinglulu 		}
224*91f16700Schasinglulu 	}
225*91f16700Schasinglulu 	INFO("CPU %u power domain prepare on\n", cpu);
226*91f16700Schasinglulu 	return ret;
227*91f16700Schasinglulu }
228*91f16700Schasinglulu 
229*91f16700Schasinglulu /* MediaTek PSCI power domain */
230*91f16700Schasinglulu static void armv8_2_power_domain_on_finish(const psci_power_state_t *state)
231*91f16700Schasinglulu {
232*91f16700Schasinglulu 	struct mt_cpupm_event_data nb;
233*91f16700Schasinglulu 	unsigned int pstate = (MT_CPUPM_PWR_DOMAIN_CORE | MT_CPUPM_PWR_DOMAIN_PERCORE_DSU);
234*91f16700Schasinglulu 	struct mtk_cpupm_pwrstate pm_state = {
235*91f16700Schasinglulu 		.info = {
236*91f16700Schasinglulu 			.cpuid = plat_my_core_pos(),
237*91f16700Schasinglulu 			.mode = MTK_CPU_PM_SMP,
238*91f16700Schasinglulu 		},
239*91f16700Schasinglulu 		.pwr = {
240*91f16700Schasinglulu 			.afflv = armv8_2_get_pwr_afflv(state),
241*91f16700Schasinglulu 			.state_id = 0x0,
242*91f16700Schasinglulu 		},
243*91f16700Schasinglulu 	};
244*91f16700Schasinglulu 
245*91f16700Schasinglulu 	armv8_2_cpu_pwr_on(&pm_state, pstate);
246*91f16700Schasinglulu 
247*91f16700Schasinglulu 	nb.cpuid = pm_state.info.cpuid;
248*91f16700Schasinglulu 	nb.pwr_domain = pstate;
249*91f16700Schasinglulu 	MT_CPUPM_EVENT_PWR_ON(&nb);
250*91f16700Schasinglulu 
251*91f16700Schasinglulu 	INFO("CPU %u power domain on finished\n", pm_state.info.cpuid);
252*91f16700Schasinglulu }
253*91f16700Schasinglulu 
254*91f16700Schasinglulu /* MediaTek PSCI power domain */
255*91f16700Schasinglulu static void armv8_2_power_domain_off(const psci_power_state_t *state)
256*91f16700Schasinglulu {
257*91f16700Schasinglulu 	struct mt_cpupm_event_data nb;
258*91f16700Schasinglulu 	unsigned int pstate = (MT_CPUPM_PWR_DOMAIN_CORE | MT_CPUPM_PWR_DOMAIN_PERCORE_DSU);
259*91f16700Schasinglulu 	struct mtk_cpupm_pwrstate pm_state = {
260*91f16700Schasinglulu 		.info = {
261*91f16700Schasinglulu 			.cpuid = plat_my_core_pos(),
262*91f16700Schasinglulu 			.mode = MTK_CPU_PM_SMP,
263*91f16700Schasinglulu 		},
264*91f16700Schasinglulu 		.pwr = {
265*91f16700Schasinglulu 			.afflv = armv8_2_get_pwr_afflv(state),
266*91f16700Schasinglulu 			.state_id = 0x0,
267*91f16700Schasinglulu 		},
268*91f16700Schasinglulu 	};
269*91f16700Schasinglulu 	armv8_2_cpu_pwr_off(&pm_state, pstate);
270*91f16700Schasinglulu 
271*91f16700Schasinglulu 	nb.cpuid = pm_state.info.cpuid;
272*91f16700Schasinglulu 	nb.pwr_domain = pstate;
273*91f16700Schasinglulu 	MT_CPUPM_EVENT_PWR_OFF(&nb);
274*91f16700Schasinglulu 
275*91f16700Schasinglulu 	INFO("CPU %u power domain off\n", pm_state.info.cpuid);
276*91f16700Schasinglulu }
277*91f16700Schasinglulu 
278*91f16700Schasinglulu /* MediaTek PSCI power domain */
279*91f16700Schasinglulu static void armv8_2_power_domain_suspend(const psci_power_state_t *state)
280*91f16700Schasinglulu {
281*91f16700Schasinglulu 	unsigned int pstate = 0;
282*91f16700Schasinglulu 	struct mt_cpupm_event_data nb;
283*91f16700Schasinglulu 	struct mtk_cpupm_pwrstate pm_state = {
284*91f16700Schasinglulu 		.info = {
285*91f16700Schasinglulu 			.cpuid = plat_my_core_pos(),
286*91f16700Schasinglulu 			.mode = MTK_CPU_PM_CPUIDLE,
287*91f16700Schasinglulu 		},
288*91f16700Schasinglulu 	};
289*91f16700Schasinglulu 
290*91f16700Schasinglulu 	pm_state.pwr.state_id = armv8_2_get_pwr_stateid(pm_state.info.cpuid);
291*91f16700Schasinglulu 	pm_state.pwr.afflv = armv8_2_get_pwr_afflv(state);
292*91f16700Schasinglulu 	pm_state.pwr.raw = state;
293*91f16700Schasinglulu 
294*91f16700Schasinglulu 	pstate = get_mediatek_pstate(CPUPM_PWR_OFF,
295*91f16700Schasinglulu 				     armv8_2_power_state[pm_state.info.cpuid], &pm_state);
296*91f16700Schasinglulu 
297*91f16700Schasinglulu 	armv8_2_cpu_pwr_suspend(&pm_state, pstate);
298*91f16700Schasinglulu 
299*91f16700Schasinglulu 	if ((pstate & MT_CPUPM_PWR_DOMAIN_CLUSTER) != 0) {
300*91f16700Schasinglulu 		armv8_2_cluster_pwr_dwn_common(&pm_state);
301*91f16700Schasinglulu 	}
302*91f16700Schasinglulu 
303*91f16700Schasinglulu 	if ((pstate & MT_CPUPM_PWR_DOMAIN_MCUSYS) != 0) {
304*91f16700Schasinglulu 		armv8_2_mcusys_pwr_dwn_common(&pm_state);
305*91f16700Schasinglulu 	}
306*91f16700Schasinglulu 
307*91f16700Schasinglulu 	nb.cpuid = pm_state.info.cpuid;
308*91f16700Schasinglulu 	nb.pwr_domain = pstate;
309*91f16700Schasinglulu 	MT_CPUPM_EVENT_PWR_OFF(&nb);
310*91f16700Schasinglulu 
311*91f16700Schasinglulu 	if (IS_AFFLV_PUBEVENT(pstate)) {
312*91f16700Schasinglulu 		MT_CPUPM_EVENT_AFFLV_PWR_OFF(&nb);
313*91f16700Schasinglulu 	}
314*91f16700Schasinglulu }
315*91f16700Schasinglulu 
316*91f16700Schasinglulu /* MediaTek PSCI power domain */
317*91f16700Schasinglulu static void armv8_2_power_domain_suspend_finish(const psci_power_state_t *state)
318*91f16700Schasinglulu {
319*91f16700Schasinglulu 	unsigned int pstate = 0;
320*91f16700Schasinglulu 	struct mt_cpupm_event_data nb;
321*91f16700Schasinglulu 	struct mtk_cpupm_pwrstate pm_state = {
322*91f16700Schasinglulu 		.info = {
323*91f16700Schasinglulu 			.cpuid = plat_my_core_pos(),
324*91f16700Schasinglulu 			.mode = MTK_CPU_PM_CPUIDLE,
325*91f16700Schasinglulu 		},
326*91f16700Schasinglulu 	};
327*91f16700Schasinglulu 
328*91f16700Schasinglulu 	pm_state.pwr.state_id = armv8_2_get_pwr_stateid(pm_state.info.cpuid);
329*91f16700Schasinglulu 	pm_state.pwr.afflv = armv8_2_get_pwr_afflv(state);
330*91f16700Schasinglulu 	pm_state.pwr.raw = state;
331*91f16700Schasinglulu 
332*91f16700Schasinglulu 	pstate = get_mediatek_pstate(CPUPM_PWR_ON,
333*91f16700Schasinglulu 				     armv8_2_power_state[pm_state.info.cpuid], &pm_state);
334*91f16700Schasinglulu 
335*91f16700Schasinglulu 	if ((pstate & MT_CPUPM_PWR_DOMAIN_MCUSYS) != 0) {
336*91f16700Schasinglulu 		armv8_2_mcusys_pwr_on_common(&pm_state);
337*91f16700Schasinglulu 	}
338*91f16700Schasinglulu 
339*91f16700Schasinglulu 	if ((pstate & MT_CPUPM_PWR_DOMAIN_CLUSTER) != 0) {
340*91f16700Schasinglulu 		armv8_2_cluster_pwr_on_common(&pm_state);
341*91f16700Schasinglulu 	}
342*91f16700Schasinglulu 
343*91f16700Schasinglulu 	armv8_2_cpu_pwr_resume(&pm_state, pstate);
344*91f16700Schasinglulu 
345*91f16700Schasinglulu 	nb.cpuid = pm_state.info.cpuid;
346*91f16700Schasinglulu 	nb.pwr_domain = pstate;
347*91f16700Schasinglulu 	MT_CPUPM_EVENT_PWR_ON(&nb);
348*91f16700Schasinglulu 
349*91f16700Schasinglulu 	if (IS_AFFLV_PUBEVENT(pstate)) {
350*91f16700Schasinglulu 		MT_CPUPM_EVENT_AFFLV_PWR_ON(&nb);
351*91f16700Schasinglulu 	}
352*91f16700Schasinglulu }
353*91f16700Schasinglulu 
354*91f16700Schasinglulu /* MediaTek PSCI power domain */
355*91f16700Schasinglulu static int armv8_2_validate_power_state(unsigned int power_state, psci_power_state_t *req_state)
356*91f16700Schasinglulu {
357*91f16700Schasinglulu 	unsigned int i;
358*91f16700Schasinglulu 	unsigned int pstate = psci_get_pstate_type(power_state);
359*91f16700Schasinglulu 	unsigned int aff_lvl = psci_get_pstate_pwrlvl(power_state);
360*91f16700Schasinglulu 	unsigned int my_core_pos = plat_my_core_pos();
361*91f16700Schasinglulu 
362*91f16700Schasinglulu 	if (mtk_cpu_pwr.ops == NULL) {
363*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
364*91f16700Schasinglulu 	}
365*91f16700Schasinglulu 
366*91f16700Schasinglulu 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_PWR_STATE_VALID)) {
367*91f16700Schasinglulu 		if (mtk_cpu_pwr.ops->pwr_state_valid(aff_lvl, pstate) != 0) {
368*91f16700Schasinglulu 			return PSCI_E_INVALID_PARAMS;
369*91f16700Schasinglulu 		}
370*91f16700Schasinglulu 	}
371*91f16700Schasinglulu 
372*91f16700Schasinglulu 	if (pstate == PSTATE_TYPE_STANDBY) {
373*91f16700Schasinglulu 		req_state->pwr_domain_state[0] = PLAT_MAX_RET_STATE;
374*91f16700Schasinglulu 	} else {
375*91f16700Schasinglulu 		for (i = PSCI_CPU_PWR_LVL; i <= aff_lvl; i++) {
376*91f16700Schasinglulu 			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
377*91f16700Schasinglulu 		}
378*91f16700Schasinglulu 	}
379*91f16700Schasinglulu 	armv8_2_power_state[my_core_pos] = power_state;
380*91f16700Schasinglulu 
381*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
382*91f16700Schasinglulu }
383*91f16700Schasinglulu 
384*91f16700Schasinglulu /* MediaTek PSCI power domain */
385*91f16700Schasinglulu #if CONFIG_MTK_SUPPORT_SYSTEM_SUSPEND
386*91f16700Schasinglulu static void armv8_2_get_sys_suspend_power_state(psci_power_state_t *req_state)
387*91f16700Schasinglulu {
388*91f16700Schasinglulu 	unsigned int i;
389*91f16700Schasinglulu 	int ret;
390*91f16700Schasinglulu 	unsigned int power_state;
391*91f16700Schasinglulu 	unsigned int my_core_pos = plat_my_core_pos();
392*91f16700Schasinglulu 
393*91f16700Schasinglulu 	ret = mtk_cpu_pwr.ops->pwr_state_valid(PLAT_MAX_PWR_LVL,
394*91f16700Schasinglulu 						PSTATE_TYPE_POWERDOWN);
395*91f16700Schasinglulu 
396*91f16700Schasinglulu 	if (ret != MTK_CPUPM_E_OK) {
397*91f16700Schasinglulu 		/* Avoid suspend due to platform is not ready. */
398*91f16700Schasinglulu 		req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] =
399*91f16700Schasinglulu 						PLAT_MAX_RET_STATE;
400*91f16700Schasinglulu 		for (i = PSCI_CPU_PWR_LVL + 1; i <= PLAT_MAX_PWR_LVL; i++) {
401*91f16700Schasinglulu 			req_state->pwr_domain_state[i] = PSCI_LOCAL_STATE_RUN;
402*91f16700Schasinglulu 		}
403*91f16700Schasinglulu 
404*91f16700Schasinglulu 		power_state = psci_make_powerstate(0, PSTATE_TYPE_STANDBY, PSCI_CPU_PWR_LVL);
405*91f16700Schasinglulu 	} else {
406*91f16700Schasinglulu 		for (i = PSCI_CPU_PWR_LVL; i <= PLAT_MAX_PWR_LVL; i++) {
407*91f16700Schasinglulu 			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
408*91f16700Schasinglulu 		}
409*91f16700Schasinglulu 
410*91f16700Schasinglulu 		power_state = psci_make_powerstate(MT_PLAT_PWR_STATE_SUSPEND,
411*91f16700Schasinglulu 						   PSTATE_TYPE_POWERDOWN, PLAT_MAX_PWR_LVL);
412*91f16700Schasinglulu 	}
413*91f16700Schasinglulu 
414*91f16700Schasinglulu 	armv8_2_power_state[my_core_pos] = power_state;
415*91f16700Schasinglulu 	flush_dcache_range((uintptr_t)&armv8_2_power_state[my_core_pos],
416*91f16700Schasinglulu 			   sizeof(armv8_2_power_state[my_core_pos]));
417*91f16700Schasinglulu }
418*91f16700Schasinglulu #endif
419*91f16700Schasinglulu static void armv8_2_pm_smp_init(unsigned int cpu_id, uintptr_t entry_point)
420*91f16700Schasinglulu {
421*91f16700Schasinglulu 	if (entry_point == 0) {
422*91f16700Schasinglulu 		ERROR("%s, warm_entry_point is null\n", __func__);
423*91f16700Schasinglulu 		panic();
424*91f16700Schasinglulu 	}
425*91f16700Schasinglulu 	if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_INIT)) {
426*91f16700Schasinglulu 		mtk_cpu_pwr.smp->init(cpu_id, entry_point);
427*91f16700Schasinglulu 	}
428*91f16700Schasinglulu 	INFO("[%s:%d] - Initialize finished\n", __func__, __LINE__);
429*91f16700Schasinglulu }
430*91f16700Schasinglulu 
431*91f16700Schasinglulu static struct plat_pm_pwr_ctrl armv8_2_pwr_ops = {
432*91f16700Schasinglulu 	.pwr_domain_suspend = armv8_2_power_domain_suspend,
433*91f16700Schasinglulu 	.pwr_domain_suspend_finish = armv8_2_power_domain_suspend_finish,
434*91f16700Schasinglulu 	.validate_power_state = armv8_2_validate_power_state,
435*91f16700Schasinglulu #if CONFIG_MTK_SUPPORT_SYSTEM_SUSPEND
436*91f16700Schasinglulu 	.get_sys_suspend_power_state = armv8_2_get_sys_suspend_power_state,
437*91f16700Schasinglulu #endif
438*91f16700Schasinglulu };
439*91f16700Schasinglulu 
440*91f16700Schasinglulu struct plat_pm_smp_ctrl armv8_2_smp_ops = {
441*91f16700Schasinglulu 	.init = armv8_2_pm_smp_init,
442*91f16700Schasinglulu 	.pwr_domain_on = armv8_2_power_domain_on,
443*91f16700Schasinglulu 	.pwr_domain_off = armv8_2_power_domain_off,
444*91f16700Schasinglulu 	.pwr_domain_on_finish = armv8_2_power_domain_on_finish,
445*91f16700Schasinglulu };
446*91f16700Schasinglulu 
447*91f16700Schasinglulu #define ISSUE_CPU_PM_REG_FAIL(_success) ({ _success = false; assert(0); })
448*91f16700Schasinglulu 
449*91f16700Schasinglulu #define CPM_PM_FN_CHECK(_fns, _ops, _id, _func, _result, _flag) ({ \
450*91f16700Schasinglulu 	if ((_fns & _id)) { \
451*91f16700Schasinglulu 		if (_ops->_func) \
452*91f16700Schasinglulu 			_flag |= _id; \
453*91f16700Schasinglulu 		else { \
454*91f16700Schasinglulu 			ISSUE_CPU_PM_REG_FAIL(_result); \
455*91f16700Schasinglulu 		} \
456*91f16700Schasinglulu 	} })
457*91f16700Schasinglulu 
458*91f16700Schasinglulu int register_cpu_pm_ops(unsigned int fn_flags, struct mtk_cpu_pm_ops *ops)
459*91f16700Schasinglulu {
460*91f16700Schasinglulu 	bool success = true;
461*91f16700Schasinglulu 	unsigned int fns = 0;
462*91f16700Schasinglulu 
463*91f16700Schasinglulu 	if ((ops == NULL) || (mtk_cpu_pwr.ops != NULL)) {
464*91f16700Schasinglulu 		ERROR("[%s:%d] register cpu_pm fail !!\n", __FILE__, __LINE__);
465*91f16700Schasinglulu 		return MTK_CPUPM_E_ERR;
466*91f16700Schasinglulu 	}
467*91f16700Schasinglulu 
468*91f16700Schasinglulu 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_CORE,
469*91f16700Schasinglulu 			cpu_resume, success, fns);
470*91f16700Schasinglulu 
471*91f16700Schasinglulu 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_CORE,
472*91f16700Schasinglulu 			cpu_suspend, success, fns);
473*91f16700Schasinglulu 
474*91f16700Schasinglulu 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_CLUSTER,
475*91f16700Schasinglulu 			cluster_resume, success, fns);
476*91f16700Schasinglulu 
477*91f16700Schasinglulu 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_CLUSTER,
478*91f16700Schasinglulu 			cluster_suspend, success, fns);
479*91f16700Schasinglulu 
480*91f16700Schasinglulu 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_MCUSYS,
481*91f16700Schasinglulu 			mcusys_resume, success, fns);
482*91f16700Schasinglulu 
483*91f16700Schasinglulu 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_MCUSYS,
484*91f16700Schasinglulu 			mcusys_suspend, success, fns);
485*91f16700Schasinglulu 
486*91f16700Schasinglulu 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_CPUPM_GET_PWR_STATE,
487*91f16700Schasinglulu 			get_pstate, success, fns);
488*91f16700Schasinglulu 
489*91f16700Schasinglulu 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_PWR_STATE_VALID,
490*91f16700Schasinglulu 			pwr_state_valid, success, fns);
491*91f16700Schasinglulu 
492*91f16700Schasinglulu 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_INIT,
493*91f16700Schasinglulu 			init, success, fns);
494*91f16700Schasinglulu 
495*91f16700Schasinglulu 	if (success) {
496*91f16700Schasinglulu 		mtk_cpu_pwr.ops = ops;
497*91f16700Schasinglulu 		mtk_cpu_pwr.fn_mask |= fns;
498*91f16700Schasinglulu 		plat_pm_ops_setup_pwr(&armv8_2_pwr_ops);
499*91f16700Schasinglulu 		INFO("[%s:%d] CPU pwr ops register success, support:0x%x\n",
500*91f16700Schasinglulu 		     __func__, __LINE__, fns);
501*91f16700Schasinglulu 	} else {
502*91f16700Schasinglulu 		ERROR("[%s:%d] register cpu_pm ops fail !, fn:0x%x\n",
503*91f16700Schasinglulu 		      __func__, __LINE__, fn_flags);
504*91f16700Schasinglulu 		assert(0);
505*91f16700Schasinglulu 	}
506*91f16700Schasinglulu 	return MTK_CPUPM_E_OK;
507*91f16700Schasinglulu }
508*91f16700Schasinglulu 
509*91f16700Schasinglulu int register_cpu_smp_ops(unsigned int fn_flags, struct mtk_cpu_smp_ops *ops)
510*91f16700Schasinglulu {
511*91f16700Schasinglulu 	bool success = true;
512*91f16700Schasinglulu 	unsigned int fns = 0;
513*91f16700Schasinglulu 
514*91f16700Schasinglulu 	if ((ops == NULL) || (mtk_cpu_pwr.smp != NULL)) {
515*91f16700Schasinglulu 		ERROR("[%s:%d] register cpu_smp fail !!\n", __FILE__, __LINE__);
516*91f16700Schasinglulu 		return MTK_CPUPM_E_ERR;
517*91f16700Schasinglulu 	}
518*91f16700Schasinglulu 
519*91f16700Schasinglulu 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_INIT,
520*91f16700Schasinglulu 			init, success, fns);
521*91f16700Schasinglulu 
522*91f16700Schasinglulu 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_PWR_ON_CORE_PREPARE,
523*91f16700Schasinglulu 			cpu_pwr_on_prepare, success, fns);
524*91f16700Schasinglulu 
525*91f16700Schasinglulu 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_CORE_ON,
526*91f16700Schasinglulu 			cpu_on, success, fns);
527*91f16700Schasinglulu 
528*91f16700Schasinglulu 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_CORE_OFF,
529*91f16700Schasinglulu 			cpu_off, success, fns);
530*91f16700Schasinglulu 
531*91f16700Schasinglulu 	if (success == true) {
532*91f16700Schasinglulu 		mtk_cpu_pwr.smp = ops;
533*91f16700Schasinglulu 		mtk_cpu_pwr.fn_mask |= fns;
534*91f16700Schasinglulu 		plat_pm_ops_setup_smp(&armv8_2_smp_ops);
535*91f16700Schasinglulu 		INFO("[%s:%d] CPU smp ops register success, support:0x%x\n",
536*91f16700Schasinglulu 		     __func__, __LINE__, fns);
537*91f16700Schasinglulu 	} else {
538*91f16700Schasinglulu 		ERROR("[%s:%d] register cpu_smp ops fail !, fn:0x%x\n",
539*91f16700Schasinglulu 		      __func__, __LINE__, fn_flags);
540*91f16700Schasinglulu 		assert(0);
541*91f16700Schasinglulu 	}
542*91f16700Schasinglulu 	return MTK_CPUPM_E_OK;
543*91f16700Schasinglulu }
544