14ba679daSKai Liang /*
24ba679daSKai Liang * Copyright (c) 2025, Mediatek Inc. All rights reserved.
34ba679daSKai Liang *
44ba679daSKai Liang * SPDX-License-Identifier: BSD-3-Clause
54ba679daSKai Liang */
64ba679daSKai Liang
74ba679daSKai Liang #include <assert.h>
84ba679daSKai Liang #include <errno.h>
94ba679daSKai Liang
104ba679daSKai Liang #ifdef CONFIG_MTK_BOOKER
114ba679daSKai Liang #include <drivers/booker.h>
124ba679daSKai Liang #endif
134ba679daSKai Liang
144ba679daSKai Liang #include <common/debug.h>
154ba679daSKai Liang #include <drivers/arm/gicv3.h>
164ba679daSKai Liang #include <drivers/console.h>
174ba679daSKai Liang #include <lib/psci/psci.h>
184ba679daSKai Liang #include <lib/utils.h>
19*0d8c101cSGavin Liu #include <mt_gic_v3.h>
204ba679daSKai Liang #include <plat/arm/common/plat_arm.h>
214ba679daSKai Liang #include <plat/common/platform.h>
224ba679daSKai Liang #include <platform_def.h>
234ba679daSKai Liang
244ba679daSKai Liang #include <lib/mtk_init/mtk_init.h>
254ba679daSKai Liang #include <lib/pm/mtk_pm.h>
264ba679daSKai Liang #ifdef MTK_PUBEVENT_ENABLE
274ba679daSKai Liang #include <vendor_pubsub_events.h>
284ba679daSKai Liang #endif
294ba679daSKai Liang
304ba679daSKai Liang #define IS_AFFLV_PUBEVENT(_pstate) \
314ba679daSKai Liang (_pstate & (MT_CPUPM_PWR_DOMAIN_MCUSYS | \
324ba679daSKai Liang MT_CPUPM_PWR_DOMAIN_CLUSTER))
334ba679daSKai Liang
344ba679daSKai Liang #ifdef MTK_PUBEVENT_ENABLE
354ba679daSKai Liang #define MT_CPUPM_EVENT_PWR_ON(x) ({ \
364ba679daSKai Liang PUBLISH_EVENT_ARG(mt_cpupm_publish_pwr_on, \
374ba679daSKai Liang (const void *)(x)); })
384ba679daSKai Liang
394ba679daSKai Liang #define MT_CPUPM_EVENT_PWR_OFF(x) ({ \
404ba679daSKai Liang PUBLISH_EVENT_ARG(mt_cpupm_publish_pwr_off, \
414ba679daSKai Liang (const void *)(x)); })
424ba679daSKai Liang
434ba679daSKai Liang #define MT_CPUPM_EVENT_AFFLV_PWR_ON(x) ({ \
444ba679daSKai Liang PUBLISH_EVENT_ARG(mt_cpupm_publish_afflv_pwr_on, \
454ba679daSKai Liang (const void *)(x)); })
464ba679daSKai Liang
474ba679daSKai Liang #define MT_CPUPM_EVENT_AFFLV_PWR_OFF(x) ({ \
484ba679daSKai Liang PUBLISH_EVENT_ARG(mt_cpupm_publish_afflv_pwr_off, \
494ba679daSKai Liang (const void *)(x)); })
504ba679daSKai Liang
514ba679daSKai Liang #else
524ba679daSKai Liang #define MT_CPUPM_EVENT_PWR_ON(x) ({ (void)x; })
534ba679daSKai Liang #define MT_CPUPM_EVENT_PWR_OFF(x) ({ (void)x; })
544ba679daSKai Liang #define MT_CPUPM_EVENT_AFFLV_PWR_ON(x) ({ (void)x; })
554ba679daSKai Liang #define MT_CPUPM_EVENT_AFFLV_PWR_OFF(x) ({ (void)x; })
564ba679daSKai Liang #endif
574ba679daSKai Liang
584ba679daSKai Liang /*
594ba679daSKai Liang * The cpu require to cluster power stattus
604ba679daSKai Liang * [0] : The cpu require cluster power down
614ba679daSKai Liang * [1] : The cpu require cluster power on
624ba679daSKai Liang */
634ba679daSKai Liang #define coordinate_cluster(onoff) \
644ba679daSKai Liang write_clusterpwrdn_el1(onoff)
654ba679daSKai Liang #define coordinate_cluster_pwron() \
664ba679daSKai Liang coordinate_cluster(1)
674ba679daSKai Liang #define coordinate_cluster_pwroff() \
684ba679daSKai Liang coordinate_cluster(0)
694ba679daSKai Liang
704ba679daSKai Liang /* default enable all function */
714ba679daSKai Liang #define MTK_CPU_PWR_FN_MASK_DEFAULT (0)
724ba679daSKai Liang
734ba679daSKai Liang struct mtk_cpu_pwr_ctrl {
744ba679daSKai Liang unsigned int fn_mask;
754ba679daSKai Liang struct mtk_cpu_pm_ops *ops;
764ba679daSKai Liang struct mtk_cpu_smp_ops *smp;
774ba679daSKai Liang };
784ba679daSKai Liang
794ba679daSKai Liang static struct mtk_cpu_pwr_ctrl imtk_cpu_pwr = {
804ba679daSKai Liang .fn_mask = MTK_CPU_PWR_FN_MASK_DEFAULT,
814ba679daSKai Liang .ops = NULL,
824ba679daSKai Liang };
834ba679daSKai Liang
844ba679daSKai Liang #define IS_CPUIDLE_FN_ENABLE(x) (imtk_cpu_pwr.ops && (imtk_cpu_pwr.fn_mask & (x)))
854ba679daSKai Liang #define IS_CPUSMP_FN_ENABLE(x) (imtk_cpu_pwr.smp && (imtk_cpu_pwr.fn_mask & (x)))
864ba679daSKai Liang
874ba679daSKai Liang /* per-cpu power state */
884ba679daSKai Liang static unsigned int cpu_power_state[PLATFORM_CORE_COUNT];
894ba679daSKai Liang
904ba679daSKai Liang #define get_pwr_stateid(cpu) \
914ba679daSKai Liang psci_get_pstate_id(cpu_power_state[cpu])
924ba679daSKai Liang
934ba679daSKai Liang #define GET_MEDIATEK_PSTATE(_domain, _psci_state, _state) ({ \
944ba679daSKai Liang int mret = 0; \
954ba679daSKai Liang if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_CPUPM_GET_PWR_STATE)) \
964ba679daSKai Liang mret = imtk_cpu_pwr.ops->get_pstate( \
974ba679daSKai Liang _domain, _psci_state, _state); \
984ba679daSKai Liang mret; })
994ba679daSKai Liang
get_pwr_afflv(const psci_power_state_t * state)1004ba679daSKai Liang static inline unsigned int get_pwr_afflv(const psci_power_state_t *state)
1014ba679daSKai Liang {
1024ba679daSKai Liang for (int i = PLAT_MAX_PWR_LVL; i >= PSCI_CPU_PWR_LVL; i--) {
1034ba679daSKai Liang if (is_local_state_run(state->pwr_domain_state[i]) == 0)
1044ba679daSKai Liang return (unsigned int) i;
1054ba679daSKai Liang }
1064ba679daSKai Liang
1074ba679daSKai Liang return PSCI_INVALID_PWR_LVL;
1084ba679daSKai Liang }
1094ba679daSKai Liang
mcusys_pwr_on_common(const struct mtk_cpupm_pwrstate * state)1104ba679daSKai Liang static void mcusys_pwr_on_common(const struct mtk_cpupm_pwrstate *state)
1114ba679daSKai Liang {
112*0d8c101cSGavin Liu mt_gic_distif_restore();
113*0d8c101cSGavin Liu mt_gic_rdistif_restore();
114*0d8c101cSGavin Liu
1154ba679daSKai Liang if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_MCUSYS))
1164ba679daSKai Liang imtk_cpu_pwr.ops->mcusys_resume(state);
1174ba679daSKai Liang }
1184ba679daSKai Liang
mcusys_pwr_dwn_common(const struct mtk_cpupm_pwrstate * state)1194ba679daSKai Liang static void mcusys_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state)
1204ba679daSKai Liang {
1214ba679daSKai Liang #ifdef CONFIG_MTK_BOOKER
1224ba679daSKai Liang booker_flush();
1234ba679daSKai Liang #endif
1244ba679daSKai Liang
1254ba679daSKai Liang if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_MCUSYS))
1264ba679daSKai Liang imtk_cpu_pwr.ops->mcusys_suspend(state);
1274ba679daSKai Liang
128*0d8c101cSGavin Liu mt_gic_rdistif_save();
129*0d8c101cSGavin Liu /* save gic context after cirq enable */
130*0d8c101cSGavin Liu mt_gic_distif_save();
1314ba679daSKai Liang }
1324ba679daSKai Liang
cluster_pwr_on_common(const struct mtk_cpupm_pwrstate * state)1334ba679daSKai Liang static void cluster_pwr_on_common(const struct mtk_cpupm_pwrstate *state)
1344ba679daSKai Liang {
1354ba679daSKai Liang if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_CLUSTER))
1364ba679daSKai Liang imtk_cpu_pwr.ops->cluster_resume(state);
1374ba679daSKai Liang }
1384ba679daSKai Liang
cluster_pwr_dwn_common(const struct mtk_cpupm_pwrstate * state)1394ba679daSKai Liang static void cluster_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state)
1404ba679daSKai Liang {
1414ba679daSKai Liang if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_CLUSTER))
1424ba679daSKai Liang imtk_cpu_pwr.ops->cluster_suspend(state);
1434ba679daSKai Liang }
1444ba679daSKai Liang
cpu_pwr_on_common(const struct mtk_cpupm_pwrstate * state,unsigned int pstate)1454ba679daSKai Liang static void cpu_pwr_on_common(const struct mtk_cpupm_pwrstate *state,
1464ba679daSKai Liang unsigned int pstate)
1474ba679daSKai Liang {
1484ba679daSKai Liang coordinate_cluster_pwron();
1494ba679daSKai Liang
150*0d8c101cSGavin Liu mt_gic_cpuif_enable();
1514ba679daSKai Liang }
1524ba679daSKai Liang
cpu_pwr_dwn_common(const struct mtk_cpupm_pwrstate * state,unsigned int pstate)1534ba679daSKai Liang static void cpu_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state,
1544ba679daSKai Liang unsigned int pstate)
1554ba679daSKai Liang {
1564ba679daSKai Liang if (pstate & MT_CPUPM_PWR_DOMAIN_PERCORE_DSU)
1574ba679daSKai Liang coordinate_cluster_pwroff();
158*0d8c101cSGavin Liu
159*0d8c101cSGavin Liu mt_gic_cpuif_disable();
1604ba679daSKai Liang }
1614ba679daSKai Liang
cpu_pwr_resume(const struct mtk_cpupm_pwrstate * state,unsigned int pstate)1624ba679daSKai Liang static void cpu_pwr_resume(const struct mtk_cpupm_pwrstate *state,
1634ba679daSKai Liang unsigned int pstate)
1644ba679daSKai Liang {
1654ba679daSKai Liang cpu_pwr_on_common(state, pstate);
1664ba679daSKai Liang if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_CORE))
1674ba679daSKai Liang imtk_cpu_pwr.ops->cpu_resume(state);
1684ba679daSKai Liang }
1694ba679daSKai Liang
cpu_pwr_suspend(const struct mtk_cpupm_pwrstate * state,unsigned int pstate)1704ba679daSKai Liang static void cpu_pwr_suspend(const struct mtk_cpupm_pwrstate *state,
1714ba679daSKai Liang unsigned int pstate)
1724ba679daSKai Liang {
1734ba679daSKai Liang if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_CORE))
1744ba679daSKai Liang imtk_cpu_pwr.ops->cpu_suspend(state);
1754ba679daSKai Liang cpu_pwr_dwn_common(state, pstate);
1764ba679daSKai Liang }
1774ba679daSKai Liang
cpu_pwr_on(const struct mtk_cpupm_pwrstate * state,unsigned int pstate)1784ba679daSKai Liang static void cpu_pwr_on(const struct mtk_cpupm_pwrstate *state,
1794ba679daSKai Liang unsigned int pstate)
1804ba679daSKai Liang {
1814ba679daSKai Liang cpu_pwr_on_common(state, pstate);
1824ba679daSKai Liang if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_CORE_ON))
1834ba679daSKai Liang imtk_cpu_pwr.smp->cpu_on(state);
1844ba679daSKai Liang }
1854ba679daSKai Liang
cpu_pwr_off(const struct mtk_cpupm_pwrstate * state,unsigned int pstate)1864ba679daSKai Liang static void cpu_pwr_off(const struct mtk_cpupm_pwrstate *state,
1874ba679daSKai Liang unsigned int pstate)
1884ba679daSKai Liang {
1894ba679daSKai Liang if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_CORE_OFF))
1904ba679daSKai Liang imtk_cpu_pwr.smp->cpu_off(state);
1914ba679daSKai Liang cpu_pwr_dwn_common(state, pstate);
1924ba679daSKai Liang }
1934ba679daSKai Liang
power_domain_on(u_register_t mpidr)1944ba679daSKai Liang static int power_domain_on(u_register_t mpidr)
1954ba679daSKai Liang {
1964ba679daSKai Liang int ret = PSCI_E_SUCCESS;
1974ba679daSKai Liang int cpu = plat_core_pos_by_mpidr(mpidr);
1984ba679daSKai Liang uintptr_t entry = plat_pm_get_warm_entry();
1994ba679daSKai Liang
2004ba679daSKai Liang if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_PWR_ON_CORE_PREPARE)) {
2014ba679daSKai Liang int b_ret = MTK_CPUPM_E_FAIL;
2024ba679daSKai Liang
2034ba679daSKai Liang b_ret = imtk_cpu_pwr.smp->cpu_pwr_on_prepare(cpu, entry);
2044ba679daSKai Liang
2054ba679daSKai Liang if (b_ret)
2064ba679daSKai Liang ret = PSCI_E_DENIED;
2074ba679daSKai Liang }
2084ba679daSKai Liang INFO("CPU %u power domain prepare on\n", cpu);
2094ba679daSKai Liang return ret;
2104ba679daSKai Liang }
2114ba679daSKai Liang
power_domain_on_finish(const psci_power_state_t * state)2124ba679daSKai Liang static void power_domain_on_finish(const psci_power_state_t *state)
2134ba679daSKai Liang {
2144ba679daSKai Liang struct mt_cpupm_event_data nb;
2154ba679daSKai Liang unsigned int pstate = (MT_CPUPM_PWR_DOMAIN_CORE |
2164ba679daSKai Liang MT_CPUPM_PWR_DOMAIN_PERCORE_DSU);
2174ba679daSKai Liang struct mtk_cpupm_pwrstate pm_state = {
2184ba679daSKai Liang .info = {
2194ba679daSKai Liang .cpuid = plat_my_core_pos(),
2204ba679daSKai Liang .mode = MTK_CPU_PM_SMP,
2214ba679daSKai Liang },
2224ba679daSKai Liang .pwr = {
2234ba679daSKai Liang .afflv = get_pwr_afflv(state),
2244ba679daSKai Liang .state_id = 0x0,
2254ba679daSKai Liang },
2264ba679daSKai Liang };
2274ba679daSKai Liang
228*0d8c101cSGavin Liu mt_gic_pcpu_init();
229*0d8c101cSGavin Liu
2304ba679daSKai Liang cpu_pwr_on(&pm_state, pstate);
2314ba679daSKai Liang
2324ba679daSKai Liang nb.cpuid = pm_state.info.cpuid;
2334ba679daSKai Liang nb.pwr_domain = pstate;
2344ba679daSKai Liang MT_CPUPM_EVENT_PWR_ON(&nb);
2354ba679daSKai Liang INFO("CPU %u power domain on finished\n", pm_state.info.cpuid);
2364ba679daSKai Liang }
2374ba679daSKai Liang
power_domain_off(const psci_power_state_t * state)2384ba679daSKai Liang static void power_domain_off(const psci_power_state_t *state)
2394ba679daSKai Liang {
2404ba679daSKai Liang struct mt_cpupm_event_data nb;
2414ba679daSKai Liang unsigned int pstate = (MT_CPUPM_PWR_DOMAIN_CORE |
2424ba679daSKai Liang MT_CPUPM_PWR_DOMAIN_PERCORE_DSU);
2434ba679daSKai Liang struct mtk_cpupm_pwrstate pm_state = {
2444ba679daSKai Liang .info = {
2454ba679daSKai Liang .cpuid = plat_my_core_pos(),
2464ba679daSKai Liang .mode = MTK_CPU_PM_SMP,
2474ba679daSKai Liang },
2484ba679daSKai Liang .pwr = {
2494ba679daSKai Liang .afflv = get_pwr_afflv(state),
2504ba679daSKai Liang .state_id = 0x0,
2514ba679daSKai Liang },
2524ba679daSKai Liang };
2534ba679daSKai Liang
2544ba679daSKai Liang cpu_pwr_off(&pm_state, pstate);
2554ba679daSKai Liang
256*0d8c101cSGavin Liu mt_gic_redistif_off();
2574ba679daSKai Liang
2584ba679daSKai Liang nb.cpuid = pm_state.info.cpuid;
2594ba679daSKai Liang nb.pwr_domain = pstate;
2604ba679daSKai Liang MT_CPUPM_EVENT_PWR_OFF(&nb);
2614ba679daSKai Liang
2624ba679daSKai Liang INFO("CPU %u power domain off\n", pm_state.info.cpuid);
2634ba679daSKai Liang }
2644ba679daSKai Liang
power_domain_suspend(const psci_power_state_t * state)2654ba679daSKai Liang static void power_domain_suspend(const psci_power_state_t *state)
2664ba679daSKai Liang {
2674ba679daSKai Liang unsigned int pstate = 0;
2684ba679daSKai Liang struct mt_cpupm_event_data nb;
2694ba679daSKai Liang struct mtk_cpupm_pwrstate pm_state = {
2704ba679daSKai Liang .info = {
2714ba679daSKai Liang .cpuid = plat_my_core_pos(),
2724ba679daSKai Liang .mode = MTK_CPU_PM_CPUIDLE,
2734ba679daSKai Liang },
2744ba679daSKai Liang };
2754ba679daSKai Liang
2764ba679daSKai Liang pm_state.pwr.state_id = get_pwr_stateid(pm_state.info.cpuid);
2774ba679daSKai Liang pm_state.pwr.afflv = get_pwr_afflv(state);
2784ba679daSKai Liang pm_state.pwr.raw = state;
2794ba679daSKai Liang
2804ba679daSKai Liang pstate = GET_MEDIATEK_PSTATE(CPUPM_PWR_OFF,
2814ba679daSKai Liang cpu_power_state[pm_state.info.cpuid], &pm_state);
2824ba679daSKai Liang
2834ba679daSKai Liang cpu_pwr_suspend(&pm_state, pstate);
2844ba679daSKai Liang
2854ba679daSKai Liang if (pstate & MT_CPUPM_PWR_DOMAIN_CLUSTER)
2864ba679daSKai Liang cluster_pwr_dwn_common(&pm_state);
2874ba679daSKai Liang
2884ba679daSKai Liang if (pstate & MT_CPUPM_PWR_DOMAIN_MCUSYS)
2894ba679daSKai Liang mcusys_pwr_dwn_common(&pm_state);
2904ba679daSKai Liang
2914ba679daSKai Liang nb.cpuid = pm_state.info.cpuid;
2924ba679daSKai Liang nb.pwr_domain = pstate;
2934ba679daSKai Liang MT_CPUPM_EVENT_PWR_OFF(&nb);
2944ba679daSKai Liang
2954ba679daSKai Liang if (IS_AFFLV_PUBEVENT(pstate))
2964ba679daSKai Liang MT_CPUPM_EVENT_AFFLV_PWR_OFF(&nb);
2974ba679daSKai Liang }
2984ba679daSKai Liang
power_domain_suspend_finish(const psci_power_state_t * state)2994ba679daSKai Liang static void power_domain_suspend_finish(const psci_power_state_t *state)
3004ba679daSKai Liang {
3014ba679daSKai Liang unsigned int pstate = 0;
3024ba679daSKai Liang struct mt_cpupm_event_data nb;
3034ba679daSKai Liang struct mtk_cpupm_pwrstate pm_state = {
3044ba679daSKai Liang .info = {
3054ba679daSKai Liang .cpuid = plat_my_core_pos(),
3064ba679daSKai Liang .mode = MTK_CPU_PM_CPUIDLE,
3074ba679daSKai Liang },
3084ba679daSKai Liang };
3094ba679daSKai Liang
3104ba679daSKai Liang pm_state.pwr.state_id = get_pwr_stateid(pm_state.info.cpuid);
3114ba679daSKai Liang pm_state.pwr.afflv = get_pwr_afflv(state);
3124ba679daSKai Liang pm_state.pwr.raw = state;
3134ba679daSKai Liang
3144ba679daSKai Liang pstate = GET_MEDIATEK_PSTATE(CPUPM_PWR_ON,
3154ba679daSKai Liang cpu_power_state[pm_state.info.cpuid], &pm_state);
3164ba679daSKai Liang
3174ba679daSKai Liang if (pstate & MT_CPUPM_PWR_DOMAIN_MCUSYS)
3184ba679daSKai Liang mcusys_pwr_on_common(&pm_state);
3194ba679daSKai Liang
3204ba679daSKai Liang if (pstate & MT_CPUPM_PWR_DOMAIN_CLUSTER)
3214ba679daSKai Liang cluster_pwr_on_common(&pm_state);
3224ba679daSKai Liang
3234ba679daSKai Liang cpu_pwr_resume(&pm_state, pstate);
3244ba679daSKai Liang
3254ba679daSKai Liang nb.cpuid = pm_state.info.cpuid;
3264ba679daSKai Liang nb.pwr_domain = pstate;
3274ba679daSKai Liang MT_CPUPM_EVENT_PWR_ON(&nb);
3284ba679daSKai Liang
3294ba679daSKai Liang if (IS_AFFLV_PUBEVENT(pstate))
3304ba679daSKai Liang MT_CPUPM_EVENT_AFFLV_PWR_ON(&nb);
3314ba679daSKai Liang }
3324ba679daSKai Liang
validate_power_state(unsigned int power_state,psci_power_state_t * req_state)3334ba679daSKai Liang static int validate_power_state(unsigned int power_state,
3344ba679daSKai Liang psci_power_state_t *req_state)
3354ba679daSKai Liang {
3364ba679daSKai Liang int i;
3374ba679daSKai Liang unsigned int pstate = psci_get_pstate_type(power_state);
3384ba679daSKai Liang int aff_lvl = psci_get_pstate_pwrlvl(power_state);
3394ba679daSKai Liang unsigned int my_core_pos = plat_my_core_pos();
3404ba679daSKai Liang
3414ba679daSKai Liang if (!imtk_cpu_pwr.ops)
3424ba679daSKai Liang return PSCI_E_INVALID_PARAMS;
3434ba679daSKai Liang
3444ba679daSKai Liang if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_PWR_STATE_VALID)) {
3454ba679daSKai Liang int ret = MTK_CPUPM_E_FAIL;
3464ba679daSKai Liang
3474ba679daSKai Liang ret = imtk_cpu_pwr.ops->pwr_state_valid(aff_lvl, pstate);
3484ba679daSKai Liang if (ret)
3494ba679daSKai Liang return PSCI_E_INVALID_PARAMS;
3504ba679daSKai Liang }
3514ba679daSKai Liang
3524ba679daSKai Liang if (pstate == PSTATE_TYPE_STANDBY)
3534ba679daSKai Liang req_state->pwr_domain_state[0] = PLAT_MAX_RET_STATE;
3544ba679daSKai Liang else {
3554ba679daSKai Liang for (i = PSCI_CPU_PWR_LVL; i <= aff_lvl; i++)
3564ba679daSKai Liang req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
3574ba679daSKai Liang }
3584ba679daSKai Liang cpu_power_state[my_core_pos] = power_state;
3594ba679daSKai Liang return PSCI_E_SUCCESS;
3604ba679daSKai Liang }
3614ba679daSKai Liang
3624ba679daSKai Liang #if CONFIG_MTK_SUPPORT_SYSTEM_SUSPEND
3634ba679daSKai Liang /* Mediatek PSCI power domain */
get_sys_suspend_power_state(psci_power_state_t * req_state)3644ba679daSKai Liang static void get_sys_suspend_power_state(psci_power_state_t *req_state)
3654ba679daSKai Liang {
3664ba679daSKai Liang int lv = 0;
3674ba679daSKai Liang unsigned int my_core_pos = plat_my_core_pos();
3684ba679daSKai Liang
3694ba679daSKai Liang for (lv = PSCI_CPU_PWR_LVL; lv <= PLAT_MAX_PWR_LVL; lv++)
3704ba679daSKai Liang req_state->pwr_domain_state[lv] = PLAT_MAX_OFF_STATE;
3714ba679daSKai Liang
3724ba679daSKai Liang cpu_power_state[my_core_pos] = psci_make_powerstate(
3734ba679daSKai Liang MT_PLAT_PWR_STATE_SUSPEND,
3744ba679daSKai Liang PSTATE_TYPE_POWERDOWN,
3754ba679daSKai Liang PLAT_MT_SYSTEM_SUSPEND);
3764ba679daSKai Liang
3774ba679daSKai Liang flush_dcache_range((uintptr_t)&cpu_power_state[my_core_pos],
3784ba679daSKai Liang sizeof(cpu_power_state[my_core_pos]));
3794ba679daSKai Liang }
3804ba679daSKai Liang #endif
3814ba679daSKai Liang
pwr_domain_pwr_down_wfi(const psci_power_state_t * req_state)3822bd3b397SBoyan Karatotev static void pwr_domain_pwr_down_wfi(const psci_power_state_t *req_state)
3835cb0bc07SKai Liang {
3845cb0bc07SKai Liang unsigned int cpu = plat_my_core_pos();
3855cb0bc07SKai Liang int ret = MTK_CPUPM_E_NOT_SUPPORT;
3865cb0bc07SKai Liang
3875cb0bc07SKai Liang if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_PWR_DOMAIN_POWER_DOWN_WFI))
3885cb0bc07SKai Liang ret = imtk_cpu_pwr.ops->pwr_domain_pwr_down_wfi(cpu);
3895cb0bc07SKai Liang if (ret == MTK_CPUPM_E_OK)
3905cb0bc07SKai Liang plat_panic_handler();
3915cb0bc07SKai Liang }
3925cb0bc07SKai Liang
pm_smp_init(unsigned int cpu_id,uintptr_t entry_point)3934ba679daSKai Liang static void pm_smp_init(unsigned int cpu_id, uintptr_t entry_point)
3944ba679daSKai Liang {
3954ba679daSKai Liang if (entry_point == 0) {
3964ba679daSKai Liang ERROR("%s, warm_entry_point is null\n", __func__);
3974ba679daSKai Liang panic();
3984ba679daSKai Liang }
3994ba679daSKai Liang if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_INIT))
4004ba679daSKai Liang imtk_cpu_pwr.smp->init(cpu_id, entry_point);
4014ba679daSKai Liang INFO("[%s:%d] - Initialize finished\n", __func__, __LINE__);
4024ba679daSKai Liang }
4034ba679daSKai Liang
4045cb0bc07SKai Liang static struct plat_pm_pwr_ctrl armv9_0_pwr_ops = {
4055cb0bc07SKai Liang .pwr_domain_suspend = power_domain_suspend,
4065cb0bc07SKai Liang .pwr_domain_suspend_finish = power_domain_suspend_finish,
4075cb0bc07SKai Liang .validate_power_state = validate_power_state,
4085cb0bc07SKai Liang #if CONFIG_MTK_SUPPORT_SYSTEM_SUSPEND
4095cb0bc07SKai Liang .get_sys_suspend_power_state = get_sys_suspend_power_state,
4105cb0bc07SKai Liang #endif
4115cb0bc07SKai Liang .pwr_domain_pwr_down_wfi = pwr_domain_pwr_down_wfi,
4125cb0bc07SKai Liang };
4135cb0bc07SKai Liang
4144ba679daSKai Liang struct plat_pm_smp_ctrl armv9_0_smp_ops = {
4154ba679daSKai Liang .init = pm_smp_init,
4164ba679daSKai Liang .pwr_domain_on = power_domain_on,
4174ba679daSKai Liang .pwr_domain_off = power_domain_off,
4184ba679daSKai Liang .pwr_domain_on_finish = power_domain_on_finish,
4194ba679daSKai Liang };
4204ba679daSKai Liang
4214ba679daSKai Liang #define ISSUE_CPU_PM_REG_FAIL(_success) ({ \
4224ba679daSKai Liang _success = 0; assert(0); })
4234ba679daSKai Liang
4244ba679daSKai Liang #define CPM_PM_FN_CHECK(_fns, _ops, _id, _func, _cond_ex, _result, _flag) ({ \
4254ba679daSKai Liang if ((_fns & _id)) { \
4264ba679daSKai Liang if (_ops->_func && _cond_ex) \
4274ba679daSKai Liang _flag |= _id; \
4284ba679daSKai Liang else { \
4294ba679daSKai Liang ISSUE_CPU_PM_REG_FAIL(_result); \
4304ba679daSKai Liang } \
4314ba679daSKai Liang } }) \
4324ba679daSKai Liang
plat_pm_invoke_func(enum mtk_cpu_pm_mode mode,unsigned int id,void * priv)4334ba679daSKai Liang int plat_pm_invoke_func(enum mtk_cpu_pm_mode mode, unsigned int id, void *priv)
4344ba679daSKai Liang {
4354ba679daSKai Liang int ret = MTK_CPUPM_E_ERR;
4364ba679daSKai Liang
4374ba679daSKai Liang if ((mode == MTK_CPU_PM_CPUIDLE) && imtk_cpu_pwr.ops &&
4384ba679daSKai Liang imtk_cpu_pwr.ops->invoke)
4394ba679daSKai Liang ret = imtk_cpu_pwr.ops->invoke(id, priv);
4404ba679daSKai Liang else if ((mode == MTK_CPU_PM_SMP) &&
4414ba679daSKai Liang imtk_cpu_pwr.smp &&
4424ba679daSKai Liang imtk_cpu_pwr.smp->invoke)
4434ba679daSKai Liang ret = imtk_cpu_pwr.smp->invoke(id, priv);
4444ba679daSKai Liang
4454ba679daSKai Liang return ret;
4464ba679daSKai Liang }
4474ba679daSKai Liang
register_cpu_pm_ops(unsigned int fn_flags,struct mtk_cpu_pm_ops * ops)4485cb0bc07SKai Liang int register_cpu_pm_ops(unsigned int fn_flags, struct mtk_cpu_pm_ops *ops)
4495cb0bc07SKai Liang {
4505cb0bc07SKai Liang int success = 1;
4515cb0bc07SKai Liang unsigned int fns = 0;
4525cb0bc07SKai Liang
4535cb0bc07SKai Liang if (!ops || imtk_cpu_pwr.ops) {
4545cb0bc07SKai Liang ERROR("[%s:%d] register cpu_pm fail !!\n", __FILE__, __LINE__);
4555cb0bc07SKai Liang return MTK_CPUPM_E_ERR;
4565cb0bc07SKai Liang }
4575cb0bc07SKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_CORE,
4585cb0bc07SKai Liang cpu_resume, 1, success, fns);
4595cb0bc07SKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_CORE,
4605cb0bc07SKai Liang cpu_suspend, 1, success, fns);
4615cb0bc07SKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_CLUSTER,
4625cb0bc07SKai Liang cluster_resume, 1, success, fns);
4635cb0bc07SKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_CLUSTER,
4645cb0bc07SKai Liang cluster_suspend, 1, success, fns);
4655cb0bc07SKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_MCUSYS,
4665cb0bc07SKai Liang mcusys_resume, 1,
4675cb0bc07SKai Liang success, fns);
4685cb0bc07SKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_MCUSYS,
4695cb0bc07SKai Liang mcusys_suspend, 1, success, fns);
4705cb0bc07SKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_CPUPM_GET_PWR_STATE,
4715cb0bc07SKai Liang get_pstate, 1, success, fns);
4725cb0bc07SKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_PWR_STATE_VALID,
4735cb0bc07SKai Liang pwr_state_valid, 1, success, fns);
4745cb0bc07SKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_INIT,
4755cb0bc07SKai Liang init, 1, success, fns);
4765cb0bc07SKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_PWR_DOMAIN_POWER_DOWN_WFI,
4775cb0bc07SKai Liang pwr_domain_pwr_down_wfi, 1, success, fns);
4785cb0bc07SKai Liang if (success) {
4795cb0bc07SKai Liang imtk_cpu_pwr.ops = ops;
4805cb0bc07SKai Liang imtk_cpu_pwr.fn_mask |= fns;
4815cb0bc07SKai Liang plat_pm_ops_setup_pwr(&armv9_0_pwr_ops);
4825cb0bc07SKai Liang INFO("[%s:%d] CPU pwr ops register success, support:0x%x\n",
4835cb0bc07SKai Liang __func__, __LINE__, fns);
4845cb0bc07SKai Liang } else {
4855cb0bc07SKai Liang ERROR("[%s:%d] register cpu_pm ops fail !, fn:0x%x\n",
4865cb0bc07SKai Liang __func__, __LINE__, fn_flags);
4875cb0bc07SKai Liang assert(0);
4885cb0bc07SKai Liang }
4895cb0bc07SKai Liang return MTK_CPUPM_E_OK;
4905cb0bc07SKai Liang }
4915cb0bc07SKai Liang
register_cpu_smp_ops(unsigned int fn_flags,struct mtk_cpu_smp_ops * ops)4924ba679daSKai Liang int register_cpu_smp_ops(unsigned int fn_flags, struct mtk_cpu_smp_ops *ops)
4934ba679daSKai Liang {
4944ba679daSKai Liang int success = 1;
4954ba679daSKai Liang unsigned int fns = 0;
4964ba679daSKai Liang
4974ba679daSKai Liang if (!ops || imtk_cpu_pwr.smp) {
4984ba679daSKai Liang ERROR("[%s:%d] register cpu_smp fail !!\n", __FILE__, __LINE__);
4994ba679daSKai Liang return MTK_CPUPM_E_ERR;
5004ba679daSKai Liang }
5014ba679daSKai Liang
5024ba679daSKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_INIT,
5034ba679daSKai Liang init, 1, success, fns);
5044ba679daSKai Liang
5054ba679daSKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_PWR_ON_CORE_PREPARE,
5064ba679daSKai Liang cpu_pwr_on_prepare, 1, success, fns);
5074ba679daSKai Liang
5084ba679daSKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_CORE_ON,
5094ba679daSKai Liang cpu_on, 1, success, fns);
5104ba679daSKai Liang
5114ba679daSKai Liang CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_CORE_OFF,
5124ba679daSKai Liang cpu_off, 1, success, fns);
5134ba679daSKai Liang
5144ba679daSKai Liang if (success) {
5154ba679daSKai Liang imtk_cpu_pwr.smp = ops;
5164ba679daSKai Liang imtk_cpu_pwr.fn_mask |= fns;
5174ba679daSKai Liang plat_pm_ops_setup_smp(&armv9_0_smp_ops);
5184ba679daSKai Liang INFO("[%s:%d] CPU smp ops register success, support:0x%x\n",
5194ba679daSKai Liang __func__, __LINE__, fns);
5204ba679daSKai Liang } else {
5214ba679daSKai Liang ERROR("[%s:%d] register cpu_smp ops fail !, fn:0x%x\n",
5224ba679daSKai Liang __func__, __LINE__, fn_flags);
5234ba679daSKai Liang assert(0);
5244ba679daSKai Liang }
5254ba679daSKai Liang return MTK_CPUPM_E_OK;
5264ba679daSKai Liang }
527