xref: /rk3399_ARM-atf/plat/mediatek/lib/pm/armv8_2/pwr_ctrl.c (revision 84498ad163025de8e004ac224c9b5f3f9e9f2de0)
16ca2046eSEdward-JW Yang /*
26ca2046eSEdward-JW Yang  * Copyright (c) 2022, Mediatek Inc. All rights reserved.
36ca2046eSEdward-JW Yang  *
46ca2046eSEdward-JW Yang  * SPDX-License-Identifier: BSD-3-Clause
56ca2046eSEdward-JW Yang  */
66ca2046eSEdward-JW Yang 
76ca2046eSEdward-JW Yang #include <assert.h>
86ca2046eSEdward-JW Yang #include <errno.h>
96ca2046eSEdward-JW Yang 
106ca2046eSEdward-JW Yang #include <common/debug.h>
116ca2046eSEdward-JW Yang #include <drivers/arm/gicv3.h>
126ca2046eSEdward-JW Yang #include <lib/psci/psci.h>
136ca2046eSEdward-JW Yang #include <lib/utils.h>
146ca2046eSEdward-JW Yang #ifdef MTK_PUBEVENT_ENABLE
150b1186a3SRex-BC Chen #include <vendor_pubsub_events.h>
166ca2046eSEdward-JW Yang #endif
176ca2046eSEdward-JW Yang #include <plat/arm/common/plat_arm.h>
186ca2046eSEdward-JW Yang #include <plat/common/platform.h>
196ca2046eSEdward-JW Yang 
207079a942SFengquan Chen #include <dfd.h>
216ca2046eSEdward-JW Yang #include <lib/mtk_init/mtk_init.h>
226ca2046eSEdward-JW Yang #include <lib/pm/mtk_pm.h>
236ca2046eSEdward-JW Yang #include <mt_gic_v3.h>
246ca2046eSEdward-JW Yang #include <platform_def.h>
256ca2046eSEdward-JW Yang 
266ca2046eSEdward-JW Yang #define IS_AFFLV_PUBEVENT(_pstate) \
276ca2046eSEdward-JW Yang 	((_pstate & (MT_CPUPM_PWR_DOMAIN_MCUSYS | MT_CPUPM_PWR_DOMAIN_CLUSTER)) != 0)
286ca2046eSEdward-JW Yang 
296ca2046eSEdward-JW Yang #ifdef MTK_PUBEVENT_ENABLE
306ca2046eSEdward-JW Yang #define MT_CPUPM_EVENT_PWR_ON(x) ({ \
316ca2046eSEdward-JW Yang 	PUBLISH_EVENT_ARG(mt_cpupm_publish_pwr_on, (const void *)(x)); })
326ca2046eSEdward-JW Yang 
336ca2046eSEdward-JW Yang #define MT_CPUPM_EVENT_PWR_OFF(x) ({ \
346ca2046eSEdward-JW Yang 	PUBLISH_EVENT_ARG(mt_cpupm_publish_pwr_off, (const void *)(x)); })
356ca2046eSEdward-JW Yang 
366ca2046eSEdward-JW Yang #define MT_CPUPM_EVENT_AFFLV_PWR_ON(x) ({ \
376ca2046eSEdward-JW Yang 	PUBLISH_EVENT_ARG(mt_cpupm_publish_afflv_pwr_on, (const void *)(x)); })
386ca2046eSEdward-JW Yang 
396ca2046eSEdward-JW Yang #define MT_CPUPM_EVENT_AFFLV_PWR_OFF(x) ({ \
406ca2046eSEdward-JW Yang 	PUBLISH_EVENT_ARG(mt_cpupm_publish_afflv_pwr_off, (const void *)(x)); })
416ca2046eSEdward-JW Yang 
426ca2046eSEdward-JW Yang #else
436ca2046eSEdward-JW Yang #define MT_CPUPM_EVENT_PWR_ON(x) ({ (void)x; })
446ca2046eSEdward-JW Yang #define MT_CPUPM_EVENT_PWR_OFF(x) ({ (void)x; })
456ca2046eSEdward-JW Yang #define MT_CPUPM_EVENT_AFFLV_PWR_ON(x) ({ (void)x; })
466ca2046eSEdward-JW Yang #define MT_CPUPM_EVENT_AFFLV_PWR_OFF(x) ({ (void)x; })
476ca2046eSEdward-JW Yang #endif
486ca2046eSEdward-JW Yang 
496ca2046eSEdward-JW Yang /*
506ca2046eSEdward-JW Yang  * The cpu require to cluster power stattus
516ca2046eSEdward-JW Yang  * [0] : The cpu require cluster power down
526ca2046eSEdward-JW Yang  * [1] : The cpu require cluster power on
536ca2046eSEdward-JW Yang  */
546ca2046eSEdward-JW Yang #define coordinate_cluster(onoff) write_clusterpwrdn_el1(onoff)
556ca2046eSEdward-JW Yang #define coordinate_cluster_pwron() coordinate_cluster(1)
566ca2046eSEdward-JW Yang #define coordinate_cluster_pwroff() coordinate_cluster(0)
576ca2046eSEdward-JW Yang 
586ca2046eSEdward-JW Yang /* defaultly disable all functions */
596ca2046eSEdward-JW Yang #define MTK_CPUPM_FN_MASK_DEFAULT	(0)
606ca2046eSEdward-JW Yang 
616ca2046eSEdward-JW Yang struct mtk_cpu_pwr_ctrl {
626ca2046eSEdward-JW Yang 	unsigned int fn_mask;
636ca2046eSEdward-JW Yang 	struct mtk_cpu_pm_ops *ops;
646ca2046eSEdward-JW Yang 	struct mtk_cpu_smp_ops *smp;
656ca2046eSEdward-JW Yang };
666ca2046eSEdward-JW Yang 
676ca2046eSEdward-JW Yang static struct mtk_cpu_pwr_ctrl mtk_cpu_pwr = {
686ca2046eSEdward-JW Yang 	.fn_mask = MTK_CPUPM_FN_MASK_DEFAULT,
696ca2046eSEdward-JW Yang 	.ops = NULL,
706ca2046eSEdward-JW Yang };
716ca2046eSEdward-JW Yang 
726ca2046eSEdward-JW Yang #define IS_CPUIDLE_FN_ENABLE(x)	((mtk_cpu_pwr.ops != NULL) && ((mtk_cpu_pwr.fn_mask & x) != 0))
736ca2046eSEdward-JW Yang #define IS_CPUSMP_FN_ENABLE(x)	((mtk_cpu_pwr.smp != NULL) && ((mtk_cpu_pwr.fn_mask & x) != 0))
746ca2046eSEdward-JW Yang 
756ca2046eSEdward-JW Yang /* per-cpu power state */
766ca2046eSEdward-JW Yang static unsigned int armv8_2_power_state[PLATFORM_CORE_COUNT];
776ca2046eSEdward-JW Yang 
786ca2046eSEdward-JW Yang #define armv8_2_get_pwr_stateid(cpu) psci_get_pstate_id(armv8_2_power_state[cpu])
796ca2046eSEdward-JW Yang 
get_mediatek_pstate(unsigned int domain,unsigned int psci_state,struct mtk_cpupm_pwrstate * state)806ca2046eSEdward-JW Yang static unsigned int get_mediatek_pstate(unsigned int domain, unsigned int psci_state,
816ca2046eSEdward-JW Yang 					struct mtk_cpupm_pwrstate *state)
826ca2046eSEdward-JW Yang {
836ca2046eSEdward-JW Yang 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_CPUPM_GET_PWR_STATE)) {
846ca2046eSEdward-JW Yang 		return mtk_cpu_pwr.ops->get_pstate(domain, psci_state, state);
856ca2046eSEdward-JW Yang 	}
866ca2046eSEdward-JW Yang 
876ca2046eSEdward-JW Yang 	return 0;
886ca2046eSEdward-JW Yang }
896ca2046eSEdward-JW Yang 
armv8_2_get_pwr_afflv(const psci_power_state_t * state_info)906ca2046eSEdward-JW Yang unsigned int armv8_2_get_pwr_afflv(const psci_power_state_t *state_info)
916ca2046eSEdward-JW Yang {
926ca2046eSEdward-JW Yang 	int i;
936ca2046eSEdward-JW Yang 
946ca2046eSEdward-JW Yang 	for (i = (int)PLAT_MAX_PWR_LVL; i >= (int)PSCI_CPU_PWR_LVL; i--) {
956ca2046eSEdward-JW Yang 		if (is_local_state_run(state_info->pwr_domain_state[i]) == 0) {
966ca2046eSEdward-JW Yang 			return (unsigned int) i;
976ca2046eSEdward-JW Yang 		}
986ca2046eSEdward-JW Yang 	}
996ca2046eSEdward-JW Yang 
1006ca2046eSEdward-JW Yang 	return PSCI_INVALID_PWR_LVL;
1016ca2046eSEdward-JW Yang }
1026ca2046eSEdward-JW Yang 
1036ca2046eSEdward-JW Yang /* MediaTek mcusys power on control interface */
armv8_2_mcusys_pwr_on_common(const struct mtk_cpupm_pwrstate * state)1046ca2046eSEdward-JW Yang static void armv8_2_mcusys_pwr_on_common(const struct mtk_cpupm_pwrstate *state)
1056ca2046eSEdward-JW Yang {
106*210ebbb0SJames Liao 	gicv3_distif_init();
1076ca2046eSEdward-JW Yang 	mt_gic_distif_restore();
1086ca2046eSEdward-JW Yang 	gic_sgi_restore_all();
1096ca2046eSEdward-JW Yang 
1107079a942SFengquan Chen 	dfd_resume();
1117079a942SFengquan Chen 
1126ca2046eSEdward-JW Yang 	/* Add code here that behavior before system enter mcusys'on */
1136ca2046eSEdward-JW Yang 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_MCUSYS)) {
1146ca2046eSEdward-JW Yang 		mtk_cpu_pwr.ops->mcusys_resume(state);
1156ca2046eSEdward-JW Yang 	}
1166ca2046eSEdward-JW Yang }
1176ca2046eSEdward-JW Yang 
1186ca2046eSEdward-JW Yang /* MediaTek mcusys power down control interface */
armv8_2_mcusys_pwr_dwn_common(const struct mtk_cpupm_pwrstate * state)1196ca2046eSEdward-JW Yang static void armv8_2_mcusys_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state)
1206ca2046eSEdward-JW Yang {
1216ca2046eSEdward-JW Yang 	mt_gic_distif_save();
1226ca2046eSEdward-JW Yang 	gic_sgi_save_all();
1236ca2046eSEdward-JW Yang 
1246ca2046eSEdward-JW Yang 	/* Add code here that behaves before entering mcusys off */
1256ca2046eSEdward-JW Yang 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_MCUSYS)) {
1266ca2046eSEdward-JW Yang 		mtk_cpu_pwr.ops->mcusys_suspend(state);
1276ca2046eSEdward-JW Yang 	}
1286ca2046eSEdward-JW Yang }
1296ca2046eSEdward-JW Yang 
1306ca2046eSEdward-JW Yang /* MediaTek Cluster power on control interface */
armv8_2_cluster_pwr_on_common(const struct mtk_cpupm_pwrstate * state)1316ca2046eSEdward-JW Yang static void armv8_2_cluster_pwr_on_common(const struct mtk_cpupm_pwrstate *state)
1326ca2046eSEdward-JW Yang {
1336ca2046eSEdward-JW Yang 	/* Add code here that behavior before system enter cluster'on */
1346ca2046eSEdward-JW Yang #if defined(MTK_CM_MGR) && !defined(MTK_FPGA_EARLY_PORTING)
1356ca2046eSEdward-JW Yang 	/* init cpu stall counter */
1366ca2046eSEdward-JW Yang 	init_cpu_stall_counter_all();
1376ca2046eSEdward-JW Yang #endif
1386ca2046eSEdward-JW Yang 
1396ca2046eSEdward-JW Yang 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_CLUSTER)) {
1406ca2046eSEdward-JW Yang 		mtk_cpu_pwr.ops->cluster_resume(state);
1416ca2046eSEdward-JW Yang 	}
1426ca2046eSEdward-JW Yang }
1436ca2046eSEdward-JW Yang 
1446ca2046eSEdward-JW Yang /* MediaTek Cluster power down control interface */
armv8_2_cluster_pwr_dwn_common(const struct mtk_cpupm_pwrstate * state)1456ca2046eSEdward-JW Yang static void armv8_2_cluster_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state)
1466ca2046eSEdward-JW Yang {
1476ca2046eSEdward-JW Yang 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_CLUSTER)) {
1486ca2046eSEdward-JW Yang 		mtk_cpu_pwr.ops->cluster_suspend(state);
1496ca2046eSEdward-JW Yang 	}
1506ca2046eSEdward-JW Yang }
1516ca2046eSEdward-JW Yang 
1526ca2046eSEdward-JW Yang /* MediaTek CPU power on control interface */
armv8_2_cpu_pwr_on_common(const struct mtk_cpupm_pwrstate * state,unsigned int pstate)1536ca2046eSEdward-JW Yang static void armv8_2_cpu_pwr_on_common(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
1546ca2046eSEdward-JW Yang {
1556ca2046eSEdward-JW Yang 	coordinate_cluster_pwron();
1566ca2046eSEdward-JW Yang 
157*210ebbb0SJames Liao 	gicv3_rdistif_init(plat_my_core_pos());
1586ca2046eSEdward-JW Yang 	gicv3_cpuif_enable(plat_my_core_pos());
1596ca2046eSEdward-JW Yang 
1606ca2046eSEdward-JW Yang 	/* If MCUSYS has been powered down then restore GIC redistributor for all CPUs. */
1616ca2046eSEdward-JW Yang 	if (IS_PLAT_SYSTEM_RETENTION(state->pwr.afflv)) {
1626ca2046eSEdward-JW Yang 		mt_gic_rdistif_restore_all();
1636ca2046eSEdward-JW Yang 	} else {
1646ca2046eSEdward-JW Yang 		mt_gic_rdistif_restore();
1656ca2046eSEdward-JW Yang 	}
1666ca2046eSEdward-JW Yang }
1676ca2046eSEdward-JW Yang 
1686ca2046eSEdward-JW Yang /* MediaTek CPU power down control interface */
armv8_2_cpu_pwr_dwn_common(const struct mtk_cpupm_pwrstate * state,unsigned int pstate)1696ca2046eSEdward-JW Yang static void armv8_2_cpu_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
1706ca2046eSEdward-JW Yang {
1716ca2046eSEdward-JW Yang 	if ((pstate & MT_CPUPM_PWR_DOMAIN_PERCORE_DSU) != 0) {
1726ca2046eSEdward-JW Yang 		coordinate_cluster_pwroff();
1736ca2046eSEdward-JW Yang 	}
1746ca2046eSEdward-JW Yang 
1756ca2046eSEdward-JW Yang 	mt_gic_rdistif_save();
1766ca2046eSEdward-JW Yang 	gicv3_cpuif_disable(plat_my_core_pos());
1776ca2046eSEdward-JW Yang 	gicv3_rdistif_off(plat_my_core_pos());
1786ca2046eSEdward-JW Yang }
1796ca2046eSEdward-JW Yang 
armv8_2_cpu_pwr_resume(const struct mtk_cpupm_pwrstate * state,unsigned int pstate)1806ca2046eSEdward-JW Yang static void armv8_2_cpu_pwr_resume(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
1816ca2046eSEdward-JW Yang {
1826ca2046eSEdward-JW Yang 	armv8_2_cpu_pwr_on_common(state, pstate);
1836ca2046eSEdward-JW Yang 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_CORE)) {
1846ca2046eSEdward-JW Yang 		mtk_cpu_pwr.ops->cpu_resume(state);
1856ca2046eSEdward-JW Yang 	}
1866ca2046eSEdward-JW Yang }
1876ca2046eSEdward-JW Yang 
armv8_2_cpu_pwr_suspend(const struct mtk_cpupm_pwrstate * state,unsigned int pstate)1886ca2046eSEdward-JW Yang static void armv8_2_cpu_pwr_suspend(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
1896ca2046eSEdward-JW Yang {
1906ca2046eSEdward-JW Yang 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_CORE)) {
1916ca2046eSEdward-JW Yang 		mtk_cpu_pwr.ops->cpu_suspend(state);
1926ca2046eSEdward-JW Yang 	}
1936ca2046eSEdward-JW Yang 	armv8_2_cpu_pwr_dwn_common(state, pstate);
1946ca2046eSEdward-JW Yang }
1956ca2046eSEdward-JW Yang 
armv8_2_cpu_pwr_on(const struct mtk_cpupm_pwrstate * state,unsigned int pstate)1966ca2046eSEdward-JW Yang static void armv8_2_cpu_pwr_on(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
1976ca2046eSEdward-JW Yang {
1986ca2046eSEdward-JW Yang 	armv8_2_cpu_pwr_on_common(state, pstate);
1996ca2046eSEdward-JW Yang 
2006ca2046eSEdward-JW Yang 	if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_CORE_ON)) {
2016ca2046eSEdward-JW Yang 		mtk_cpu_pwr.smp->cpu_on(state);
2026ca2046eSEdward-JW Yang 	}
2036ca2046eSEdward-JW Yang }
2046ca2046eSEdward-JW Yang 
armv8_2_cpu_pwr_off(const struct mtk_cpupm_pwrstate * state,unsigned int pstate)2056ca2046eSEdward-JW Yang static void armv8_2_cpu_pwr_off(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
2066ca2046eSEdward-JW Yang {
2076ca2046eSEdward-JW Yang 	if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_CORE_OFF)) {
2086ca2046eSEdward-JW Yang 		mtk_cpu_pwr.smp->cpu_off(state);
2096ca2046eSEdward-JW Yang 	}
2106ca2046eSEdward-JW Yang 	armv8_2_cpu_pwr_dwn_common(state, pstate);
2116ca2046eSEdward-JW Yang }
2126ca2046eSEdward-JW Yang 
2136ca2046eSEdward-JW Yang /* MediaTek PSCI power domain */
armv8_2_power_domain_on(u_register_t mpidr)2146ca2046eSEdward-JW Yang static int armv8_2_power_domain_on(u_register_t mpidr)
2156ca2046eSEdward-JW Yang {
2166ca2046eSEdward-JW Yang 	int ret = PSCI_E_SUCCESS;
2176ca2046eSEdward-JW Yang 	int cpu = plat_core_pos_by_mpidr(mpidr);
2186ca2046eSEdward-JW Yang 	uintptr_t entry = plat_pm_get_warm_entry();
2196ca2046eSEdward-JW Yang 
2206ca2046eSEdward-JW Yang 	if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_PWR_ON_CORE_PREPARE)) {
2216ca2046eSEdward-JW Yang 		if (mtk_cpu_pwr.smp->cpu_pwr_on_prepare(cpu, entry) != 0) {
2226ca2046eSEdward-JW Yang 			ret = PSCI_E_DENIED;
2236ca2046eSEdward-JW Yang 		}
2246ca2046eSEdward-JW Yang 	}
2256ca2046eSEdward-JW Yang 	INFO("CPU %u power domain prepare on\n", cpu);
2266ca2046eSEdward-JW Yang 	return ret;
2276ca2046eSEdward-JW Yang }
2286ca2046eSEdward-JW Yang 
2296ca2046eSEdward-JW Yang /* MediaTek PSCI power domain */
armv8_2_power_domain_on_finish(const psci_power_state_t * state)2306ca2046eSEdward-JW Yang static void armv8_2_power_domain_on_finish(const psci_power_state_t *state)
2316ca2046eSEdward-JW Yang {
2326ca2046eSEdward-JW Yang 	struct mt_cpupm_event_data nb;
2336ca2046eSEdward-JW Yang 	unsigned int pstate = (MT_CPUPM_PWR_DOMAIN_CORE | MT_CPUPM_PWR_DOMAIN_PERCORE_DSU);
2346ca2046eSEdward-JW Yang 	struct mtk_cpupm_pwrstate pm_state = {
2356ca2046eSEdward-JW Yang 		.info = {
2366ca2046eSEdward-JW Yang 			.cpuid = plat_my_core_pos(),
2376ca2046eSEdward-JW Yang 			.mode = MTK_CPU_PM_SMP,
2386ca2046eSEdward-JW Yang 		},
2396ca2046eSEdward-JW Yang 		.pwr = {
2406ca2046eSEdward-JW Yang 			.afflv = armv8_2_get_pwr_afflv(state),
2416ca2046eSEdward-JW Yang 			.state_id = 0x0,
2426ca2046eSEdward-JW Yang 		},
2436ca2046eSEdward-JW Yang 	};
2446ca2046eSEdward-JW Yang 
2456ca2046eSEdward-JW Yang 	armv8_2_cpu_pwr_on(&pm_state, pstate);
2466ca2046eSEdward-JW Yang 
2476ca2046eSEdward-JW Yang 	nb.cpuid = pm_state.info.cpuid;
2486ca2046eSEdward-JW Yang 	nb.pwr_domain = pstate;
2496ca2046eSEdward-JW Yang 	MT_CPUPM_EVENT_PWR_ON(&nb);
2506ca2046eSEdward-JW Yang 
2516ca2046eSEdward-JW Yang 	INFO("CPU %u power domain on finished\n", pm_state.info.cpuid);
2526ca2046eSEdward-JW Yang }
2536ca2046eSEdward-JW Yang 
2546ca2046eSEdward-JW Yang /* MediaTek PSCI power domain */
armv8_2_power_domain_off(const psci_power_state_t * state)2556ca2046eSEdward-JW Yang static void armv8_2_power_domain_off(const psci_power_state_t *state)
2566ca2046eSEdward-JW Yang {
2576ca2046eSEdward-JW Yang 	struct mt_cpupm_event_data nb;
2586ca2046eSEdward-JW Yang 	unsigned int pstate = (MT_CPUPM_PWR_DOMAIN_CORE | MT_CPUPM_PWR_DOMAIN_PERCORE_DSU);
2596ca2046eSEdward-JW Yang 	struct mtk_cpupm_pwrstate pm_state = {
2606ca2046eSEdward-JW Yang 		.info = {
2616ca2046eSEdward-JW Yang 			.cpuid = plat_my_core_pos(),
2626ca2046eSEdward-JW Yang 			.mode = MTK_CPU_PM_SMP,
2636ca2046eSEdward-JW Yang 		},
2646ca2046eSEdward-JW Yang 		.pwr = {
2656ca2046eSEdward-JW Yang 			.afflv = armv8_2_get_pwr_afflv(state),
2666ca2046eSEdward-JW Yang 			.state_id = 0x0,
2676ca2046eSEdward-JW Yang 		},
2686ca2046eSEdward-JW Yang 	};
2696ca2046eSEdward-JW Yang 	armv8_2_cpu_pwr_off(&pm_state, pstate);
2706ca2046eSEdward-JW Yang 
2716ca2046eSEdward-JW Yang 	nb.cpuid = pm_state.info.cpuid;
2726ca2046eSEdward-JW Yang 	nb.pwr_domain = pstate;
2736ca2046eSEdward-JW Yang 	MT_CPUPM_EVENT_PWR_OFF(&nb);
2746ca2046eSEdward-JW Yang 
2756ca2046eSEdward-JW Yang 	INFO("CPU %u power domain off\n", pm_state.info.cpuid);
2766ca2046eSEdward-JW Yang }
2776ca2046eSEdward-JW Yang 
2786ca2046eSEdward-JW Yang /* MediaTek PSCI power domain */
armv8_2_power_domain_suspend(const psci_power_state_t * state)2796ca2046eSEdward-JW Yang static void armv8_2_power_domain_suspend(const psci_power_state_t *state)
2806ca2046eSEdward-JW Yang {
2816ca2046eSEdward-JW Yang 	unsigned int pstate = 0;
2826ca2046eSEdward-JW Yang 	struct mt_cpupm_event_data nb;
2836ca2046eSEdward-JW Yang 	struct mtk_cpupm_pwrstate pm_state = {
2846ca2046eSEdward-JW Yang 		.info = {
2856ca2046eSEdward-JW Yang 			.cpuid = plat_my_core_pos(),
2866ca2046eSEdward-JW Yang 			.mode = MTK_CPU_PM_CPUIDLE,
2876ca2046eSEdward-JW Yang 		},
2886ca2046eSEdward-JW Yang 	};
2896ca2046eSEdward-JW Yang 
2906ca2046eSEdward-JW Yang 	pm_state.pwr.state_id = armv8_2_get_pwr_stateid(pm_state.info.cpuid);
2916ca2046eSEdward-JW Yang 	pm_state.pwr.afflv = armv8_2_get_pwr_afflv(state);
2926ca2046eSEdward-JW Yang 	pm_state.pwr.raw = state;
2936ca2046eSEdward-JW Yang 
2946ca2046eSEdward-JW Yang 	pstate = get_mediatek_pstate(CPUPM_PWR_OFF,
2956ca2046eSEdward-JW Yang 				     armv8_2_power_state[pm_state.info.cpuid], &pm_state);
2966ca2046eSEdward-JW Yang 
2976ca2046eSEdward-JW Yang 	armv8_2_cpu_pwr_suspend(&pm_state, pstate);
2986ca2046eSEdward-JW Yang 
2996ca2046eSEdward-JW Yang 	if ((pstate & MT_CPUPM_PWR_DOMAIN_CLUSTER) != 0) {
3006ca2046eSEdward-JW Yang 		armv8_2_cluster_pwr_dwn_common(&pm_state);
3016ca2046eSEdward-JW Yang 	}
3026ca2046eSEdward-JW Yang 
3036ca2046eSEdward-JW Yang 	if ((pstate & MT_CPUPM_PWR_DOMAIN_MCUSYS) != 0) {
3046ca2046eSEdward-JW Yang 		armv8_2_mcusys_pwr_dwn_common(&pm_state);
3056ca2046eSEdward-JW Yang 	}
3066ca2046eSEdward-JW Yang 
3076ca2046eSEdward-JW Yang 	nb.cpuid = pm_state.info.cpuid;
3086ca2046eSEdward-JW Yang 	nb.pwr_domain = pstate;
3096ca2046eSEdward-JW Yang 	MT_CPUPM_EVENT_PWR_OFF(&nb);
3106ca2046eSEdward-JW Yang 
3116ca2046eSEdward-JW Yang 	if (IS_AFFLV_PUBEVENT(pstate)) {
3126ca2046eSEdward-JW Yang 		MT_CPUPM_EVENT_AFFLV_PWR_OFF(&nb);
3136ca2046eSEdward-JW Yang 	}
3146ca2046eSEdward-JW Yang }
3156ca2046eSEdward-JW Yang 
3166ca2046eSEdward-JW Yang /* MediaTek PSCI power domain */
armv8_2_power_domain_suspend_finish(const psci_power_state_t * state)3176ca2046eSEdward-JW Yang static void armv8_2_power_domain_suspend_finish(const psci_power_state_t *state)
3186ca2046eSEdward-JW Yang {
3196ca2046eSEdward-JW Yang 	unsigned int pstate = 0;
3206ca2046eSEdward-JW Yang 	struct mt_cpupm_event_data nb;
3216ca2046eSEdward-JW Yang 	struct mtk_cpupm_pwrstate pm_state = {
3226ca2046eSEdward-JW Yang 		.info = {
3236ca2046eSEdward-JW Yang 			.cpuid = plat_my_core_pos(),
3246ca2046eSEdward-JW Yang 			.mode = MTK_CPU_PM_CPUIDLE,
3256ca2046eSEdward-JW Yang 		},
3266ca2046eSEdward-JW Yang 	};
3276ca2046eSEdward-JW Yang 
3286ca2046eSEdward-JW Yang 	pm_state.pwr.state_id = armv8_2_get_pwr_stateid(pm_state.info.cpuid);
3296ca2046eSEdward-JW Yang 	pm_state.pwr.afflv = armv8_2_get_pwr_afflv(state);
3306ca2046eSEdward-JW Yang 	pm_state.pwr.raw = state;
3316ca2046eSEdward-JW Yang 
3326ca2046eSEdward-JW Yang 	pstate = get_mediatek_pstate(CPUPM_PWR_ON,
3336ca2046eSEdward-JW Yang 				     armv8_2_power_state[pm_state.info.cpuid], &pm_state);
3346ca2046eSEdward-JW Yang 
3356ca2046eSEdward-JW Yang 	if ((pstate & MT_CPUPM_PWR_DOMAIN_MCUSYS) != 0) {
3366ca2046eSEdward-JW Yang 		armv8_2_mcusys_pwr_on_common(&pm_state);
3376ca2046eSEdward-JW Yang 	}
3386ca2046eSEdward-JW Yang 
3396ca2046eSEdward-JW Yang 	if ((pstate & MT_CPUPM_PWR_DOMAIN_CLUSTER) != 0) {
3406ca2046eSEdward-JW Yang 		armv8_2_cluster_pwr_on_common(&pm_state);
3416ca2046eSEdward-JW Yang 	}
3426ca2046eSEdward-JW Yang 
3436ca2046eSEdward-JW Yang 	armv8_2_cpu_pwr_resume(&pm_state, pstate);
3446ca2046eSEdward-JW Yang 
3456ca2046eSEdward-JW Yang 	nb.cpuid = pm_state.info.cpuid;
3466ca2046eSEdward-JW Yang 	nb.pwr_domain = pstate;
3476ca2046eSEdward-JW Yang 	MT_CPUPM_EVENT_PWR_ON(&nb);
3486ca2046eSEdward-JW Yang 
3496ca2046eSEdward-JW Yang 	if (IS_AFFLV_PUBEVENT(pstate)) {
3506ca2046eSEdward-JW Yang 		MT_CPUPM_EVENT_AFFLV_PWR_ON(&nb);
3516ca2046eSEdward-JW Yang 	}
3526ca2046eSEdward-JW Yang }
3536ca2046eSEdward-JW Yang 
3546ca2046eSEdward-JW Yang /* MediaTek PSCI power domain */
armv8_2_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)3556ca2046eSEdward-JW Yang static int armv8_2_validate_power_state(unsigned int power_state, psci_power_state_t *req_state)
3566ca2046eSEdward-JW Yang {
3576ca2046eSEdward-JW Yang 	unsigned int i;
3586ca2046eSEdward-JW Yang 	unsigned int pstate = psci_get_pstate_type(power_state);
3596ca2046eSEdward-JW Yang 	unsigned int aff_lvl = psci_get_pstate_pwrlvl(power_state);
3606ca2046eSEdward-JW Yang 	unsigned int my_core_pos = plat_my_core_pos();
3616ca2046eSEdward-JW Yang 
3626ca2046eSEdward-JW Yang 	if (mtk_cpu_pwr.ops == NULL) {
3636ca2046eSEdward-JW Yang 		return PSCI_E_INVALID_PARAMS;
3646ca2046eSEdward-JW Yang 	}
3656ca2046eSEdward-JW Yang 
3666ca2046eSEdward-JW Yang 	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_PWR_STATE_VALID)) {
3676ca2046eSEdward-JW Yang 		if (mtk_cpu_pwr.ops->pwr_state_valid(aff_lvl, pstate) != 0) {
3686ca2046eSEdward-JW Yang 			return PSCI_E_INVALID_PARAMS;
3696ca2046eSEdward-JW Yang 		}
3706ca2046eSEdward-JW Yang 	}
3716ca2046eSEdward-JW Yang 
3726ca2046eSEdward-JW Yang 	if (pstate == PSTATE_TYPE_STANDBY) {
3736ca2046eSEdward-JW Yang 		req_state->pwr_domain_state[0] = PLAT_MAX_RET_STATE;
3746ca2046eSEdward-JW Yang 	} else {
3756ca2046eSEdward-JW Yang 		for (i = PSCI_CPU_PWR_LVL; i <= aff_lvl; i++) {
3766ca2046eSEdward-JW Yang 			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
3776ca2046eSEdward-JW Yang 		}
3786ca2046eSEdward-JW Yang 	}
3796ca2046eSEdward-JW Yang 	armv8_2_power_state[my_core_pos] = power_state;
3806ca2046eSEdward-JW Yang 
3816ca2046eSEdward-JW Yang 	return PSCI_E_SUCCESS;
3826ca2046eSEdward-JW Yang }
3836ca2046eSEdward-JW Yang 
3846ca2046eSEdward-JW Yang /* MediaTek PSCI power domain */
3856ca2046eSEdward-JW Yang #if CONFIG_MTK_SUPPORT_SYSTEM_SUSPEND
armv8_2_get_sys_suspend_power_state(psci_power_state_t * req_state)3866ca2046eSEdward-JW Yang static void armv8_2_get_sys_suspend_power_state(psci_power_state_t *req_state)
3876ca2046eSEdward-JW Yang {
3886ca2046eSEdward-JW Yang 	unsigned int i;
3896ca2046eSEdward-JW Yang 	int ret;
3906ca2046eSEdward-JW Yang 	unsigned int power_state;
3916ca2046eSEdward-JW Yang 	unsigned int my_core_pos = plat_my_core_pos();
3926ca2046eSEdward-JW Yang 
3936ca2046eSEdward-JW Yang 	ret = mtk_cpu_pwr.ops->pwr_state_valid(PLAT_MAX_PWR_LVL,
3946ca2046eSEdward-JW Yang 						PSTATE_TYPE_POWERDOWN);
3956ca2046eSEdward-JW Yang 
3966ca2046eSEdward-JW Yang 	if (ret != MTK_CPUPM_E_OK) {
3976ca2046eSEdward-JW Yang 		/* Avoid suspend due to platform is not ready. */
3986ca2046eSEdward-JW Yang 		req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] =
3996ca2046eSEdward-JW Yang 						PLAT_MAX_RET_STATE;
4006ca2046eSEdward-JW Yang 		for (i = PSCI_CPU_PWR_LVL + 1; i <= PLAT_MAX_PWR_LVL; i++) {
4016ca2046eSEdward-JW Yang 			req_state->pwr_domain_state[i] = PSCI_LOCAL_STATE_RUN;
4026ca2046eSEdward-JW Yang 		}
4036ca2046eSEdward-JW Yang 
4046ca2046eSEdward-JW Yang 		power_state = psci_make_powerstate(0, PSTATE_TYPE_STANDBY, PSCI_CPU_PWR_LVL);
4056ca2046eSEdward-JW Yang 	} else {
4066ca2046eSEdward-JW Yang 		for (i = PSCI_CPU_PWR_LVL; i <= PLAT_MAX_PWR_LVL; i++) {
4076ca2046eSEdward-JW Yang 			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
4086ca2046eSEdward-JW Yang 		}
4096ca2046eSEdward-JW Yang 
410e35f4cbfSEdward-JW Yang 		power_state = psci_make_powerstate(MT_PLAT_PWR_STATE_SUSPEND,
4116ca2046eSEdward-JW Yang 						   PSTATE_TYPE_POWERDOWN, PLAT_MAX_PWR_LVL);
4126ca2046eSEdward-JW Yang 	}
4136ca2046eSEdward-JW Yang 
4146ca2046eSEdward-JW Yang 	armv8_2_power_state[my_core_pos] = power_state;
4156ca2046eSEdward-JW Yang 	flush_dcache_range((uintptr_t)&armv8_2_power_state[my_core_pos],
4166ca2046eSEdward-JW Yang 			   sizeof(armv8_2_power_state[my_core_pos]));
4176ca2046eSEdward-JW Yang }
4186ca2046eSEdward-JW Yang #endif
armv8_2_pm_smp_init(unsigned int cpu_id,uintptr_t entry_point)4196ca2046eSEdward-JW Yang static void armv8_2_pm_smp_init(unsigned int cpu_id, uintptr_t entry_point)
4206ca2046eSEdward-JW Yang {
4216ca2046eSEdward-JW Yang 	if (entry_point == 0) {
4226ca2046eSEdward-JW Yang 		ERROR("%s, warm_entry_point is null\n", __func__);
4236ca2046eSEdward-JW Yang 		panic();
4246ca2046eSEdward-JW Yang 	}
4256ca2046eSEdward-JW Yang 	if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_INIT)) {
4266ca2046eSEdward-JW Yang 		mtk_cpu_pwr.smp->init(cpu_id, entry_point);
4276ca2046eSEdward-JW Yang 	}
4286ca2046eSEdward-JW Yang 	INFO("[%s:%d] - Initialize finished\n", __func__, __LINE__);
4296ca2046eSEdward-JW Yang }
4306ca2046eSEdward-JW Yang 
4316ca2046eSEdward-JW Yang static struct plat_pm_pwr_ctrl armv8_2_pwr_ops = {
4326ca2046eSEdward-JW Yang 	.pwr_domain_suspend = armv8_2_power_domain_suspend,
4336ca2046eSEdward-JW Yang 	.pwr_domain_suspend_finish = armv8_2_power_domain_suspend_finish,
4346ca2046eSEdward-JW Yang 	.validate_power_state = armv8_2_validate_power_state,
4356ca2046eSEdward-JW Yang #if CONFIG_MTK_SUPPORT_SYSTEM_SUSPEND
4366ca2046eSEdward-JW Yang 	.get_sys_suspend_power_state = armv8_2_get_sys_suspend_power_state,
4376ca2046eSEdward-JW Yang #endif
4386ca2046eSEdward-JW Yang };
4396ca2046eSEdward-JW Yang 
4406ca2046eSEdward-JW Yang struct plat_pm_smp_ctrl armv8_2_smp_ops = {
4416ca2046eSEdward-JW Yang 	.init = armv8_2_pm_smp_init,
4426ca2046eSEdward-JW Yang 	.pwr_domain_on = armv8_2_power_domain_on,
4436ca2046eSEdward-JW Yang 	.pwr_domain_off = armv8_2_power_domain_off,
4446ca2046eSEdward-JW Yang 	.pwr_domain_on_finish = armv8_2_power_domain_on_finish,
4456ca2046eSEdward-JW Yang };
4466ca2046eSEdward-JW Yang 
4476ca2046eSEdward-JW Yang #define ISSUE_CPU_PM_REG_FAIL(_success) ({ _success = false; assert(0); })
4486ca2046eSEdward-JW Yang 
4496ca2046eSEdward-JW Yang #define CPM_PM_FN_CHECK(_fns, _ops, _id, _func, _result, _flag) ({ \
4506ca2046eSEdward-JW Yang 	if ((_fns & _id)) { \
4516ca2046eSEdward-JW Yang 		if (_ops->_func) \
4526ca2046eSEdward-JW Yang 			_flag |= _id; \
4536ca2046eSEdward-JW Yang 		else { \
4546ca2046eSEdward-JW Yang 			ISSUE_CPU_PM_REG_FAIL(_result); \
4556ca2046eSEdward-JW Yang 		} \
4566ca2046eSEdward-JW Yang 	} })
4576ca2046eSEdward-JW Yang 
register_cpu_pm_ops(unsigned int fn_flags,struct mtk_cpu_pm_ops * ops)4586ca2046eSEdward-JW Yang int register_cpu_pm_ops(unsigned int fn_flags, struct mtk_cpu_pm_ops *ops)
4596ca2046eSEdward-JW Yang {
4606ca2046eSEdward-JW Yang 	bool success = true;
4616ca2046eSEdward-JW Yang 	unsigned int fns = 0;
4626ca2046eSEdward-JW Yang 
4636ca2046eSEdward-JW Yang 	if ((ops == NULL) || (mtk_cpu_pwr.ops != NULL)) {
4646ca2046eSEdward-JW Yang 		ERROR("[%s:%d] register cpu_pm fail !!\n", __FILE__, __LINE__);
4656ca2046eSEdward-JW Yang 		return MTK_CPUPM_E_ERR;
4666ca2046eSEdward-JW Yang 	}
4676ca2046eSEdward-JW Yang 
4686ca2046eSEdward-JW Yang 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_CORE,
4696ca2046eSEdward-JW Yang 			cpu_resume, success, fns);
4706ca2046eSEdward-JW Yang 
4716ca2046eSEdward-JW Yang 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_CORE,
4726ca2046eSEdward-JW Yang 			cpu_suspend, success, fns);
4736ca2046eSEdward-JW Yang 
4746ca2046eSEdward-JW Yang 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_CLUSTER,
4756ca2046eSEdward-JW Yang 			cluster_resume, success, fns);
4766ca2046eSEdward-JW Yang 
4776ca2046eSEdward-JW Yang 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_CLUSTER,
4786ca2046eSEdward-JW Yang 			cluster_suspend, success, fns);
4796ca2046eSEdward-JW Yang 
4806ca2046eSEdward-JW Yang 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_MCUSYS,
4816ca2046eSEdward-JW Yang 			mcusys_resume, success, fns);
4826ca2046eSEdward-JW Yang 
4836ca2046eSEdward-JW Yang 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_MCUSYS,
4846ca2046eSEdward-JW Yang 			mcusys_suspend, success, fns);
4856ca2046eSEdward-JW Yang 
4866ca2046eSEdward-JW Yang 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_CPUPM_GET_PWR_STATE,
4876ca2046eSEdward-JW Yang 			get_pstate, success, fns);
4886ca2046eSEdward-JW Yang 
4896ca2046eSEdward-JW Yang 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_PWR_STATE_VALID,
4906ca2046eSEdward-JW Yang 			pwr_state_valid, success, fns);
4916ca2046eSEdward-JW Yang 
4926ca2046eSEdward-JW Yang 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_INIT,
4936ca2046eSEdward-JW Yang 			init, success, fns);
4946ca2046eSEdward-JW Yang 
4956ca2046eSEdward-JW Yang 	if (success) {
4966ca2046eSEdward-JW Yang 		mtk_cpu_pwr.ops = ops;
4976ca2046eSEdward-JW Yang 		mtk_cpu_pwr.fn_mask |= fns;
4986ca2046eSEdward-JW Yang 		plat_pm_ops_setup_pwr(&armv8_2_pwr_ops);
4996ca2046eSEdward-JW Yang 		INFO("[%s:%d] CPU pwr ops register success, support:0x%x\n",
5006ca2046eSEdward-JW Yang 		     __func__, __LINE__, fns);
5016ca2046eSEdward-JW Yang 	} else {
5026ca2046eSEdward-JW Yang 		ERROR("[%s:%d] register cpu_pm ops fail !, fn:0x%x\n",
5036ca2046eSEdward-JW Yang 		      __func__, __LINE__, fn_flags);
5046ca2046eSEdward-JW Yang 		assert(0);
5056ca2046eSEdward-JW Yang 	}
5066ca2046eSEdward-JW Yang 	return MTK_CPUPM_E_OK;
5076ca2046eSEdward-JW Yang }
5086ca2046eSEdward-JW Yang 
register_cpu_smp_ops(unsigned int fn_flags,struct mtk_cpu_smp_ops * ops)5096ca2046eSEdward-JW Yang int register_cpu_smp_ops(unsigned int fn_flags, struct mtk_cpu_smp_ops *ops)
5106ca2046eSEdward-JW Yang {
5116ca2046eSEdward-JW Yang 	bool success = true;
5126ca2046eSEdward-JW Yang 	unsigned int fns = 0;
5136ca2046eSEdward-JW Yang 
5146ca2046eSEdward-JW Yang 	if ((ops == NULL) || (mtk_cpu_pwr.smp != NULL)) {
5156ca2046eSEdward-JW Yang 		ERROR("[%s:%d] register cpu_smp fail !!\n", __FILE__, __LINE__);
5166ca2046eSEdward-JW Yang 		return MTK_CPUPM_E_ERR;
5176ca2046eSEdward-JW Yang 	}
5186ca2046eSEdward-JW Yang 
5196ca2046eSEdward-JW Yang 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_INIT,
5206ca2046eSEdward-JW Yang 			init, success, fns);
5216ca2046eSEdward-JW Yang 
5226ca2046eSEdward-JW Yang 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_PWR_ON_CORE_PREPARE,
5236ca2046eSEdward-JW Yang 			cpu_pwr_on_prepare, success, fns);
5246ca2046eSEdward-JW Yang 
5256ca2046eSEdward-JW Yang 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_CORE_ON,
5266ca2046eSEdward-JW Yang 			cpu_on, success, fns);
5276ca2046eSEdward-JW Yang 
5286ca2046eSEdward-JW Yang 	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_CORE_OFF,
5296ca2046eSEdward-JW Yang 			cpu_off, success, fns);
5306ca2046eSEdward-JW Yang 
5316ca2046eSEdward-JW Yang 	if (success == true) {
5326ca2046eSEdward-JW Yang 		mtk_cpu_pwr.smp = ops;
5336ca2046eSEdward-JW Yang 		mtk_cpu_pwr.fn_mask |= fns;
5346ca2046eSEdward-JW Yang 		plat_pm_ops_setup_smp(&armv8_2_smp_ops);
5356ca2046eSEdward-JW Yang 		INFO("[%s:%d] CPU smp ops register success, support:0x%x\n",
5366ca2046eSEdward-JW Yang 		     __func__, __LINE__, fns);
5376ca2046eSEdward-JW Yang 	} else {
5386ca2046eSEdward-JW Yang 		ERROR("[%s:%d] register cpu_smp ops fail !, fn:0x%x\n",
5396ca2046eSEdward-JW Yang 		      __func__, __LINE__, fn_flags);
5406ca2046eSEdward-JW Yang 		assert(0);
5416ca2046eSEdward-JW Yang 	}
5426ca2046eSEdward-JW Yang 	return MTK_CPUPM_E_OK;
5436ca2046eSEdward-JW Yang }
544