xref: /arm-trusted-firmware/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2022-2023, 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 <stdint.h>
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <lib/spinlock.h>
11*91f16700Schasinglulu 
12*91f16700Schasinglulu #include <lib/mtk_init/mtk_init.h>
13*91f16700Schasinglulu #include <lib/pm/mtk_pm.h>
14*91f16700Schasinglulu #include <lpm/mt_lp_rm.h>
15*91f16700Schasinglulu #include "mt_cpu_pm.h"
16*91f16700Schasinglulu #include "mt_cpu_pm_cpc.h"
17*91f16700Schasinglulu #include "mt_cpu_pm_mbox.h"
18*91f16700Schasinglulu #include "mt_smp.h"
19*91f16700Schasinglulu #include <mtk_mmap_pool.h>
20*91f16700Schasinglulu #include <platform_def.h>
21*91f16700Schasinglulu 
22*91f16700Schasinglulu /*
23*91f16700Schasinglulu  * The locker must use the bakery locker when cache turns off.
24*91f16700Schasinglulu  * Using spin_lock will gain better performance.
25*91f16700Schasinglulu  */
26*91f16700Schasinglulu #ifdef MT_CPU_PM_USING_BAKERY_LOCK
27*91f16700Schasinglulu DEFINE_BAKERY_LOCK(mt_cpu_pm_lock);
28*91f16700Schasinglulu #define plat_cpu_pm_lock_init()	bakery_lock_init(&mt_cpu_pm_lock)
29*91f16700Schasinglulu #define plat_cpu_pm_lock()	bakery_lock_get(&mt_cpu_pm_lock)
30*91f16700Schasinglulu #define plat_cpu_pm_unlock()	bakery_lock_release(&mt_cpu_pm_lock)
31*91f16700Schasinglulu #else
32*91f16700Schasinglulu spinlock_t mt_cpu_pm_lock;
33*91f16700Schasinglulu #define plat_cpu_pm_lock_init()
34*91f16700Schasinglulu #define plat_cpu_pm_lock()	spin_lock(&mt_cpu_pm_lock)
35*91f16700Schasinglulu #define plat_cpu_pm_unlock()	spin_unlock(&mt_cpu_pm_lock)
36*91f16700Schasinglulu #endif
37*91f16700Schasinglulu 
38*91f16700Schasinglulu enum mt_pwr_node {
39*91f16700Schasinglulu 	MT_PWR_NONMCUSYS = 0,
40*91f16700Schasinglulu 	MT_PWR_MCUSYS_PDN,
41*91f16700Schasinglulu 	MT_PWR_SUSPEND,
42*91f16700Schasinglulu 	MT_PWR_SYSTEM_MEM,
43*91f16700Schasinglulu 	MT_PWR_SYSTEM_PLL,
44*91f16700Schasinglulu 	MT_PWR_SYSTEM_BUS,
45*91f16700Schasinglulu 	MT_PWR_MAX,
46*91f16700Schasinglulu };
47*91f16700Schasinglulu 
48*91f16700Schasinglulu #define CPU_PM_DEPD_INIT	BIT(0)
49*91f16700Schasinglulu #define CPU_PM_DEPD_READY	BIT(1)
50*91f16700Schasinglulu #define CPU_PM_PLAT_READY	BIT(2)
51*91f16700Schasinglulu 
52*91f16700Schasinglulu #ifdef CPU_PM_TINYSYS_SUPPORT
53*91f16700Schasinglulu #define CPU_PM_INIT_READY	(CPU_PM_DEPD_INIT | CPU_PM_DEPD_READY)
54*91f16700Schasinglulu #define CPU_PM_LP_READY		(CPU_PM_INIT_READY | CPU_PM_PLAT_READY)
55*91f16700Schasinglulu #else
56*91f16700Schasinglulu #define CPU_PM_LP_READY		(CPU_PM_PLAT_READY)
57*91f16700Schasinglulu #endif
58*91f16700Schasinglulu 
59*91f16700Schasinglulu #if CONFIG_MTK_PM_SUPPORT
60*91f16700Schasinglulu 
61*91f16700Schasinglulu #if CONFIG_MTK_CPU_SUSPEND_EN || CONFIG_MTK_SMP_EN
62*91f16700Schasinglulu static void cpupm_cpu_resume_common(const struct mtk_cpupm_pwrstate *state)
63*91f16700Schasinglulu {
64*91f16700Schasinglulu 	CPU_PM_ASSERT(state != NULL);
65*91f16700Schasinglulu 	mtk_cpc_core_on_hint_clr(state->info.cpuid);
66*91f16700Schasinglulu }
67*91f16700Schasinglulu #endif
68*91f16700Schasinglulu 
69*91f16700Schasinglulu #if CONFIG_MTK_SMP_EN
70*91f16700Schasinglulu static int cpupm_cpu_pwr_on_prepare(unsigned int cpu, uintptr_t entry)
71*91f16700Schasinglulu {
72*91f16700Schasinglulu 	struct cpu_pwr_ctrl pwr_ctrl;
73*91f16700Schasinglulu 
74*91f16700Schasinglulu 	PER_CPU_PWR_CTRL(pwr_ctrl, cpu);
75*91f16700Schasinglulu 	mt_smp_core_bootup_address_set(&pwr_ctrl, entry);
76*91f16700Schasinglulu 	mt_smp_core_init_arch(0, cpu, 1, &pwr_ctrl);
77*91f16700Schasinglulu 
78*91f16700Schasinglulu 	return mt_smp_power_core_on(cpu, &pwr_ctrl);
79*91f16700Schasinglulu }
80*91f16700Schasinglulu 
81*91f16700Schasinglulu static void cpupm_cpu_resume_smp(const struct mtk_cpupm_pwrstate *state)
82*91f16700Schasinglulu {
83*91f16700Schasinglulu 	CPU_PM_ASSERT(state != NULL);
84*91f16700Schasinglulu 
85*91f16700Schasinglulu 	plat_cpu_pm_lock();
86*91f16700Schasinglulu 	mmio_clrbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
87*91f16700Schasinglulu 			GIC_WAKEUP_IGNORE(state->info.cpuid));
88*91f16700Schasinglulu 	plat_cpu_pm_unlock();
89*91f16700Schasinglulu 	cpupm_cpu_resume_common(state);
90*91f16700Schasinglulu }
91*91f16700Schasinglulu 
92*91f16700Schasinglulu static void cpupm_cpu_suspend_smp(const struct mtk_cpupm_pwrstate *state)
93*91f16700Schasinglulu {
94*91f16700Schasinglulu 	struct cpu_pwr_ctrl pwr_ctrl;
95*91f16700Schasinglulu 
96*91f16700Schasinglulu 	CPU_PM_ASSERT(state != NULL);
97*91f16700Schasinglulu 
98*91f16700Schasinglulu 	PER_CPU_PWR_CTRL(pwr_ctrl, state->info.cpuid);
99*91f16700Schasinglulu 	mt_smp_power_core_off(&pwr_ctrl);
100*91f16700Schasinglulu 	mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
101*91f16700Schasinglulu 			GIC_WAKEUP_IGNORE(state->info.cpuid));
102*91f16700Schasinglulu }
103*91f16700Schasinglulu 
104*91f16700Schasinglulu static void cpupm_smp_init(unsigned int cpu, uintptr_t sec_entrypoint)
105*91f16700Schasinglulu {
106*91f16700Schasinglulu 	unsigned int reg;
107*91f16700Schasinglulu 	struct mtk_cpupm_pwrstate state = {
108*91f16700Schasinglulu 		.info = {
109*91f16700Schasinglulu 			.cpuid = cpu,
110*91f16700Schasinglulu 			.mode = MTK_CPU_PM_SMP,
111*91f16700Schasinglulu 		},
112*91f16700Schasinglulu 		.pwr = {
113*91f16700Schasinglulu 			.afflv = 0,
114*91f16700Schasinglulu 			.state_id = 0,
115*91f16700Schasinglulu 		},
116*91f16700Schasinglulu 	};
117*91f16700Schasinglulu 
118*91f16700Schasinglulu 	reg = mmio_read_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG);
119*91f16700Schasinglulu 	if ((reg & CPC_MCUSYS_CPC_RESET_PWR_ON_EN) != 0) {
120*91f16700Schasinglulu 		INFO("[%s:%d][CPU_PM] reset pwr on is enabled then clear it!\n",
121*91f16700Schasinglulu 		     __func__, __LINE__);
122*91f16700Schasinglulu 		mmio_clrbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, CPC_MCUSYS_CPC_RESET_PWR_ON_EN);
123*91f16700Schasinglulu 	}
124*91f16700Schasinglulu 
125*91f16700Schasinglulu 	cpupm_cpu_pwr_on_prepare(cpu, sec_entrypoint);
126*91f16700Schasinglulu 	cpupm_cpu_resume_smp(&state);
127*91f16700Schasinglulu }
128*91f16700Schasinglulu 
129*91f16700Schasinglulu static struct mtk_cpu_smp_ops cpcv3_2_cpu_smp = {
130*91f16700Schasinglulu 	.init = cpupm_smp_init,
131*91f16700Schasinglulu 	.cpu_pwr_on_prepare = cpupm_cpu_pwr_on_prepare,
132*91f16700Schasinglulu 	.cpu_on = cpupm_cpu_resume_smp,
133*91f16700Schasinglulu 	.cpu_off = cpupm_cpu_suspend_smp,
134*91f16700Schasinglulu };
135*91f16700Schasinglulu 
136*91f16700Schasinglulu #endif /* CONFIG_MTK_SMP_EN */
137*91f16700Schasinglulu 
138*91f16700Schasinglulu #if CONFIG_MTK_CPU_SUSPEND_EN
139*91f16700Schasinglulu #define CPUPM_READY_MS		(40000)
140*91f16700Schasinglulu #define CPUPM_ARCH_TIME_MS(ms)	(ms * 1000 * SYS_COUNTER_FREQ_IN_MHZ)
141*91f16700Schasinglulu #define CPUPM_BOOTUP_TIME_THR	CPUPM_ARCH_TIME_MS(CPUPM_READY_MS)
142*91f16700Schasinglulu 
143*91f16700Schasinglulu static int mt_pwr_nodes[MT_PWR_MAX];
144*91f16700Schasinglulu static int plat_mt_lp_cpu_rc;
145*91f16700Schasinglulu static unsigned int cpu_pm_status;
146*91f16700Schasinglulu static unsigned int plat_prev_stateid;
147*91f16700Schasinglulu 
148*91f16700Schasinglulu static int mcusys_prepare_suspend(const struct mtk_cpupm_pwrstate *state)
149*91f16700Schasinglulu {
150*91f16700Schasinglulu 	unsigned int stateid = state->pwr.state_id;
151*91f16700Schasinglulu 
152*91f16700Schasinglulu 	if (mtk_cpc_mcusys_off_prepare() != CPC_SUCCESS) {
153*91f16700Schasinglulu 		goto mt_pwr_mcusysoff_break;
154*91f16700Schasinglulu 	}
155*91f16700Schasinglulu 
156*91f16700Schasinglulu 	if (!IS_PLAT_SUSPEND_ID(stateid)) {
157*91f16700Schasinglulu 		if (mt_pwr_nodes[MT_PWR_SYSTEM_MEM] != 0) {
158*91f16700Schasinglulu 			stateid = MT_PLAT_PWR_STATE_SYSTEM_MEM;
159*91f16700Schasinglulu 		} else if (mt_pwr_nodes[MT_PWR_SYSTEM_PLL] != 0) {
160*91f16700Schasinglulu 			stateid = MT_PLAT_PWR_STATE_SYSTEM_PLL;
161*91f16700Schasinglulu 		} else if (mt_pwr_nodes[MT_PWR_SYSTEM_BUS] != 0) {
162*91f16700Schasinglulu 			stateid = MT_PLAT_PWR_STATE_SYSTEM_BUS;
163*91f16700Schasinglulu 		} else if (mt_pwr_nodes[MT_PWR_SUSPEND] != 0) {
164*91f16700Schasinglulu 			stateid = MT_PLAT_PWR_STATE_SUSPEND;
165*91f16700Schasinglulu 		} else {
166*91f16700Schasinglulu 			stateid = MT_PLAT_PWR_STATE_MCUSYS;
167*91f16700Schasinglulu 		}
168*91f16700Schasinglulu 	}
169*91f16700Schasinglulu 
170*91f16700Schasinglulu 	plat_prev_stateid = stateid;
171*91f16700Schasinglulu 	plat_mt_lp_cpu_rc = mt_lp_rm_find_and_run_constraint(0, state->info.cpuid, stateid, NULL);
172*91f16700Schasinglulu 
173*91f16700Schasinglulu 	if (plat_mt_lp_cpu_rc < 0) {
174*91f16700Schasinglulu 		goto mt_pwr_mcusysoff_reflect;
175*91f16700Schasinglulu 	}
176*91f16700Schasinglulu 
177*91f16700Schasinglulu #ifdef CPU_PM_TINYSYS_SUPPORT
178*91f16700Schasinglulu 	mtk_set_cpu_pm_preffered_cpu(state->info.cpuid);
179*91f16700Schasinglulu #endif
180*91f16700Schasinglulu 	return MTK_CPUPM_E_OK;
181*91f16700Schasinglulu 
182*91f16700Schasinglulu mt_pwr_mcusysoff_reflect:
183*91f16700Schasinglulu 	mtk_cpc_mcusys_off_reflect();
184*91f16700Schasinglulu mt_pwr_mcusysoff_break:
185*91f16700Schasinglulu 	plat_mt_lp_cpu_rc = -1;
186*91f16700Schasinglulu 
187*91f16700Schasinglulu 	return MTK_CPUPM_E_FAIL;
188*91f16700Schasinglulu }
189*91f16700Schasinglulu 
190*91f16700Schasinglulu static int mcusys_prepare_resume(const struct mtk_cpupm_pwrstate *state)
191*91f16700Schasinglulu {
192*91f16700Schasinglulu 	if (plat_mt_lp_cpu_rc < 0) {
193*91f16700Schasinglulu 		return MTK_CPUPM_E_FAIL;
194*91f16700Schasinglulu 	}
195*91f16700Schasinglulu 
196*91f16700Schasinglulu 	mt_lp_rm_reset_constraint(plat_mt_lp_cpu_rc, state->info.cpuid, plat_prev_stateid);
197*91f16700Schasinglulu 	mtk_cpc_mcusys_off_reflect();
198*91f16700Schasinglulu 	return MTK_CPUPM_E_OK;
199*91f16700Schasinglulu }
200*91f16700Schasinglulu 
201*91f16700Schasinglulu static unsigned int cpupm_do_pstate_off(const mtk_pstate_type psci_state,
202*91f16700Schasinglulu 					const struct mtk_cpupm_pwrstate *state)
203*91f16700Schasinglulu {
204*91f16700Schasinglulu 	unsigned int pstate = MT_CPUPM_PWR_DOMAIN_CORE;
205*91f16700Schasinglulu 
206*91f16700Schasinglulu 	if (!state || (state->pwr.afflv > PLAT_MAX_PWR_LVL)) {
207*91f16700Schasinglulu 		CPU_PM_ASSERT(0);
208*91f16700Schasinglulu 	}
209*91f16700Schasinglulu 
210*91f16700Schasinglulu 	switch (state->pwr.state_id) {
211*91f16700Schasinglulu 	case MT_PLAT_PWR_STATE_SYSTEM_MEM:
212*91f16700Schasinglulu 		mt_pwr_nodes[MT_PWR_SYSTEM_MEM] += 1;
213*91f16700Schasinglulu 		break;
214*91f16700Schasinglulu 	case MT_PLAT_PWR_STATE_SYSTEM_PLL:
215*91f16700Schasinglulu 		mt_pwr_nodes[MT_PWR_SYSTEM_PLL] += 1;
216*91f16700Schasinglulu 		break;
217*91f16700Schasinglulu 	case MT_PLAT_PWR_STATE_SYSTEM_BUS:
218*91f16700Schasinglulu 		mt_pwr_nodes[MT_PWR_SYSTEM_BUS] += 1;
219*91f16700Schasinglulu 		break;
220*91f16700Schasinglulu 	case MT_PLAT_PWR_STATE_SUSPEND:
221*91f16700Schasinglulu 		mt_pwr_nodes[MT_PWR_SUSPEND] += 1;
222*91f16700Schasinglulu 		break;
223*91f16700Schasinglulu 	default:
224*91f16700Schasinglulu 		if (!IS_MT_PLAT_PWR_STATE_MCUSYS(state->pwr.state_id) &&
225*91f16700Schasinglulu 		    !IS_PLAT_SYSTEM_SUSPEND(state->pwr.afflv)) {
226*91f16700Schasinglulu 			plat_cpu_pm_lock();
227*91f16700Schasinglulu 			mt_pwr_nodes[MT_PWR_NONMCUSYS] += 1;
228*91f16700Schasinglulu 			flush_dcache_range((uintptr_t)&mt_pwr_nodes[MT_PWR_NONMCUSYS],
229*91f16700Schasinglulu 					   sizeof(mt_pwr_nodes[MT_PWR_NONMCUSYS]));
230*91f16700Schasinglulu 			plat_cpu_pm_unlock();
231*91f16700Schasinglulu 		}
232*91f16700Schasinglulu 		break;
233*91f16700Schasinglulu 	}
234*91f16700Schasinglulu 
235*91f16700Schasinglulu 	if ((mt_pwr_nodes[MT_PWR_NONMCUSYS] == 0) && IS_PLAT_MCUSYSOFF_AFFLV(state->pwr.afflv)) {
236*91f16700Schasinglulu 		/* Prepare to power down mcusys */
237*91f16700Schasinglulu 		if (mcusys_prepare_suspend(state) == MTK_CPUPM_E_OK) {
238*91f16700Schasinglulu 			mt_pwr_nodes[MT_PWR_MCUSYS_PDN] += 1;
239*91f16700Schasinglulu 			flush_dcache_range((uintptr_t)&mt_pwr_nodes[MT_PWR_MCUSYS_PDN],
240*91f16700Schasinglulu 					   sizeof(mt_pwr_nodes[MT_PWR_MCUSYS_PDN]));
241*91f16700Schasinglulu 			pstate |= (MT_CPUPM_PWR_DOMAIN_MCUSYS | MT_CPUPM_PWR_DOMAIN_CLUSTER);
242*91f16700Schasinglulu 		}
243*91f16700Schasinglulu 	}
244*91f16700Schasinglulu 
245*91f16700Schasinglulu 	if (state->pwr.afflv >= PLAT_MT_CPU_SUSPEND_CLUSTER) {
246*91f16700Schasinglulu 		pstate |= MT_CPUPM_PWR_DOMAIN_CLUSTER;
247*91f16700Schasinglulu 	}
248*91f16700Schasinglulu 
249*91f16700Schasinglulu 	if (psci_get_pstate_pwrlvl(psci_state) >= PLAT_MT_CPU_SUSPEND_CLUSTER) {
250*91f16700Schasinglulu 		pstate |= MT_CPUPM_PWR_DOMAIN_PERCORE_DSU;
251*91f16700Schasinglulu 	}
252*91f16700Schasinglulu 
253*91f16700Schasinglulu 	return pstate;
254*91f16700Schasinglulu }
255*91f16700Schasinglulu 
256*91f16700Schasinglulu static unsigned int cpupm_do_pstate_on(const mtk_pstate_type psci_state,
257*91f16700Schasinglulu 				       const struct mtk_cpupm_pwrstate *state)
258*91f16700Schasinglulu {
259*91f16700Schasinglulu 	unsigned int pstate = MT_CPUPM_PWR_DOMAIN_CORE;
260*91f16700Schasinglulu 
261*91f16700Schasinglulu 	CPU_PM_ASSERT(state != NULL);
262*91f16700Schasinglulu 
263*91f16700Schasinglulu 	if (state->pwr.afflv > PLAT_MAX_PWR_LVL) {
264*91f16700Schasinglulu 		CPU_PM_ASSERT(0);
265*91f16700Schasinglulu 	}
266*91f16700Schasinglulu 
267*91f16700Schasinglulu 	if (mt_pwr_nodes[MT_PWR_MCUSYS_PDN] != 0) {
268*91f16700Schasinglulu 		mt_pwr_nodes[MT_PWR_MCUSYS_PDN] = 0;
269*91f16700Schasinglulu 		flush_dcache_range((uintptr_t)&mt_pwr_nodes[MT_PWR_MCUSYS_PDN],
270*91f16700Schasinglulu 				   sizeof(mt_pwr_nodes[MT_PWR_MCUSYS_PDN]));
271*91f16700Schasinglulu 		pstate |= (MT_CPUPM_PWR_DOMAIN_MCUSYS | MT_CPUPM_PWR_DOMAIN_CLUSTER);
272*91f16700Schasinglulu 		mcusys_prepare_resume(state);
273*91f16700Schasinglulu 	}
274*91f16700Schasinglulu 
275*91f16700Schasinglulu 	if (state->pwr.afflv >= PLAT_MT_CPU_SUSPEND_CLUSTER) {
276*91f16700Schasinglulu 		pstate |= MT_CPUPM_PWR_DOMAIN_CLUSTER;
277*91f16700Schasinglulu 	}
278*91f16700Schasinglulu 
279*91f16700Schasinglulu 	switch (state->pwr.state_id) {
280*91f16700Schasinglulu 	case MT_PLAT_PWR_STATE_SYSTEM_MEM:
281*91f16700Schasinglulu 		mt_pwr_nodes[MT_PWR_SYSTEM_MEM] -= 1;
282*91f16700Schasinglulu 		CPU_PM_ASSERT(mt_pwr_nodes[MT_PWR_SYSTEM_MEM] >= 0);
283*91f16700Schasinglulu 		break;
284*91f16700Schasinglulu 	case MT_PLAT_PWR_STATE_SYSTEM_PLL:
285*91f16700Schasinglulu 		mt_pwr_nodes[MT_PWR_SYSTEM_PLL] -= 1;
286*91f16700Schasinglulu 		CPU_PM_ASSERT(mt_pwr_nodes[MT_PWR_SYSTEM_PLL] >= 0);
287*91f16700Schasinglulu 		break;
288*91f16700Schasinglulu 	case MT_PLAT_PWR_STATE_SYSTEM_BUS:
289*91f16700Schasinglulu 		mt_pwr_nodes[MT_PWR_SYSTEM_BUS] -= 1;
290*91f16700Schasinglulu 		CPU_PM_ASSERT(mt_pwr_nodes[MT_PWR_SYSTEM_BUS] >= 0);
291*91f16700Schasinglulu 		break;
292*91f16700Schasinglulu 	case MT_PLAT_PWR_STATE_SUSPEND:
293*91f16700Schasinglulu 		mt_pwr_nodes[MT_PWR_SUSPEND] -= 1;
294*91f16700Schasinglulu 		CPU_PM_ASSERT(mt_pwr_nodes[MT_PWR_SUSPEND] >= 0);
295*91f16700Schasinglulu 		break;
296*91f16700Schasinglulu 	default:
297*91f16700Schasinglulu 		if (!IS_MT_PLAT_PWR_STATE_MCUSYS(state->pwr.state_id) &&
298*91f16700Schasinglulu 		    !IS_PLAT_SYSTEM_SUSPEND(state->pwr.afflv)) {
299*91f16700Schasinglulu 			plat_cpu_pm_lock();
300*91f16700Schasinglulu 			mt_pwr_nodes[MT_PWR_NONMCUSYS] -= 1;
301*91f16700Schasinglulu 			flush_dcache_range((uintptr_t)&mt_pwr_nodes[MT_PWR_NONMCUSYS],
302*91f16700Schasinglulu 					   sizeof(mt_pwr_nodes[MT_PWR_NONMCUSYS]));
303*91f16700Schasinglulu 			plat_cpu_pm_unlock();
304*91f16700Schasinglulu 		}
305*91f16700Schasinglulu 		break;
306*91f16700Schasinglulu 	}
307*91f16700Schasinglulu 
308*91f16700Schasinglulu 	if (IS_PLAT_SYSTEM_SUSPEND(state->pwr.afflv) ||
309*91f16700Schasinglulu 	    (IS_PLAT_SYSTEM_RETENTION(state->pwr.afflv) && (mt_pwr_nodes[MT_PWR_SUSPEND] > 0))) {
310*91f16700Schasinglulu 		mtk_cpc_time_sync();
311*91f16700Schasinglulu 	}
312*91f16700Schasinglulu 
313*91f16700Schasinglulu 	if (mt_pwr_nodes[MT_PWR_NONMCUSYS] < 0) {
314*91f16700Schasinglulu 		CPU_PM_ASSERT(0);
315*91f16700Schasinglulu 	}
316*91f16700Schasinglulu 
317*91f16700Schasinglulu 	pstate |= MT_CPUPM_PWR_DOMAIN_PERCORE_DSU;
318*91f16700Schasinglulu 
319*91f16700Schasinglulu 	return pstate;
320*91f16700Schasinglulu }
321*91f16700Schasinglulu 
322*91f16700Schasinglulu static void cpupm_cpu_resume(const struct mtk_cpupm_pwrstate *state)
323*91f16700Schasinglulu {
324*91f16700Schasinglulu 	cpupm_cpu_resume_common(state);
325*91f16700Schasinglulu }
326*91f16700Schasinglulu 
327*91f16700Schasinglulu static void cpupm_mcusys_resume(const struct mtk_cpupm_pwrstate *state)
328*91f16700Schasinglulu {
329*91f16700Schasinglulu 	assert(state != NULL);
330*91f16700Schasinglulu }
331*91f16700Schasinglulu 
332*91f16700Schasinglulu static void cpupm_mcusys_suspend(const struct mtk_cpupm_pwrstate *state)
333*91f16700Schasinglulu {
334*91f16700Schasinglulu 	assert(state != NULL);
335*91f16700Schasinglulu }
336*91f16700Schasinglulu 
337*91f16700Schasinglulu static unsigned int cpupm_get_pstate(enum mt_cpupm_pwr_domain domain,
338*91f16700Schasinglulu 				     const mtk_pstate_type psci_state,
339*91f16700Schasinglulu 				     const struct mtk_cpupm_pwrstate *state)
340*91f16700Schasinglulu {
341*91f16700Schasinglulu 	unsigned int pstate = 0;
342*91f16700Schasinglulu 
343*91f16700Schasinglulu 	if (state == NULL) {
344*91f16700Schasinglulu 		return 0;
345*91f16700Schasinglulu 	}
346*91f16700Schasinglulu 
347*91f16700Schasinglulu 	if (state->info.mode == MTK_CPU_PM_SMP) {
348*91f16700Schasinglulu 		pstate = MT_CPUPM_PWR_DOMAIN_CORE;
349*91f16700Schasinglulu 	} else {
350*91f16700Schasinglulu 		if (domain == CPUPM_PWR_OFF) {
351*91f16700Schasinglulu 			pstate = cpupm_do_pstate_off(psci_state, state);
352*91f16700Schasinglulu 		} else if (domain == CPUPM_PWR_ON) {
353*91f16700Schasinglulu 			pstate = cpupm_do_pstate_on(psci_state, state);
354*91f16700Schasinglulu 		} else {
355*91f16700Schasinglulu 			INFO("[%s:%d][CPU_PM] unknown pwr domain :%d\n",
356*91f16700Schasinglulu 			     __func__, __LINE__, domain);
357*91f16700Schasinglulu 			assert(0);
358*91f16700Schasinglulu 		}
359*91f16700Schasinglulu 	}
360*91f16700Schasinglulu 	return pstate;
361*91f16700Schasinglulu }
362*91f16700Schasinglulu 
363*91f16700Schasinglulu static int cpupm_init(void)
364*91f16700Schasinglulu {
365*91f16700Schasinglulu 	int ret = MTK_CPUPM_E_OK;
366*91f16700Schasinglulu 
367*91f16700Schasinglulu #ifdef CPU_PM_TINYSYS_SUPPORT
368*91f16700Schasinglulu 	int status;
369*91f16700Schasinglulu 
370*91f16700Schasinglulu 	if ((cpu_pm_status & CPU_PM_INIT_READY) == CPU_PM_INIT_READY) {
371*91f16700Schasinglulu 		return MTK_CPUPM_E_OK;
372*91f16700Schasinglulu 	}
373*91f16700Schasinglulu 
374*91f16700Schasinglulu 	if (!(cpu_pm_status & CPU_PM_DEPD_INIT)) {
375*91f16700Schasinglulu 		status = mtk_lp_depd_condition(CPUPM_MBOX_WAIT_DEV_INIT);
376*91f16700Schasinglulu 		if (status == 0) {
377*91f16700Schasinglulu 			plat_cpu_pm_lock();
378*91f16700Schasinglulu 			cpu_pm_status |= CPU_PM_DEPD_INIT;
379*91f16700Schasinglulu 			plat_cpu_pm_unlock();
380*91f16700Schasinglulu 		}
381*91f16700Schasinglulu 	}
382*91f16700Schasinglulu 
383*91f16700Schasinglulu 	if ((cpu_pm_status & CPU_PM_DEPD_INIT) && !(cpu_pm_status & CPU_PM_DEPD_READY)) {
384*91f16700Schasinglulu 		status = mtk_lp_depd_condition(CPUPM_MBOX_WAIT_TASK_READY);
385*91f16700Schasinglulu 		if (status == 0) {
386*91f16700Schasinglulu 			plat_cpu_pm_lock();
387*91f16700Schasinglulu 			cpu_pm_status |= CPU_PM_DEPD_READY;
388*91f16700Schasinglulu 			plat_cpu_pm_unlock();
389*91f16700Schasinglulu 		}
390*91f16700Schasinglulu 	}
391*91f16700Schasinglulu 
392*91f16700Schasinglulu 	ret = ((cpu_pm_status & CPU_PM_INIT_READY) == CPU_PM_INIT_READY) ?
393*91f16700Schasinglulu 	      MTK_CPUPM_E_OK : MTK_CPUPM_E_FAIL;
394*91f16700Schasinglulu #endif
395*91f16700Schasinglulu 	return ret;
396*91f16700Schasinglulu }
397*91f16700Schasinglulu 
398*91f16700Schasinglulu static int cpupm_pwr_state_valid(unsigned int afflv, unsigned int state)
399*91f16700Schasinglulu {
400*91f16700Schasinglulu 	if (cpu_pm_status == CPU_PM_LP_READY) {
401*91f16700Schasinglulu 		return MTK_CPUPM_E_OK;
402*91f16700Schasinglulu 	}
403*91f16700Schasinglulu 
404*91f16700Schasinglulu 	if (cpupm_init() != MTK_CPUPM_E_OK) {
405*91f16700Schasinglulu 		return MTK_CPUPM_E_FAIL;
406*91f16700Schasinglulu 	}
407*91f16700Schasinglulu 
408*91f16700Schasinglulu 	if (read_cntpct_el0() >= (uint64_t)CPUPM_BOOTUP_TIME_THR) {
409*91f16700Schasinglulu 		plat_cpu_pm_lock();
410*91f16700Schasinglulu 		cpu_pm_status |= CPU_PM_PLAT_READY;
411*91f16700Schasinglulu 		plat_cpu_pm_unlock();
412*91f16700Schasinglulu 	}
413*91f16700Schasinglulu 
414*91f16700Schasinglulu 	if (!IS_PLAT_SYSTEM_SUSPEND(afflv) && (cpu_pm_status & CPU_PM_PLAT_READY) == 0) {
415*91f16700Schasinglulu 		return MTK_CPUPM_E_FAIL;
416*91f16700Schasinglulu 	}
417*91f16700Schasinglulu 
418*91f16700Schasinglulu 	return MTK_CPUPM_E_OK;
419*91f16700Schasinglulu }
420*91f16700Schasinglulu 
421*91f16700Schasinglulu static struct mtk_cpu_pm_ops cpcv3_2_mcdi = {
422*91f16700Schasinglulu 	.get_pstate = cpupm_get_pstate,
423*91f16700Schasinglulu 	.pwr_state_valid = cpupm_pwr_state_valid,
424*91f16700Schasinglulu 	.cpu_resume = cpupm_cpu_resume,
425*91f16700Schasinglulu 	.mcusys_suspend = cpupm_mcusys_suspend,
426*91f16700Schasinglulu 	.mcusys_resume = cpupm_mcusys_resume,
427*91f16700Schasinglulu };
428*91f16700Schasinglulu #endif /* CONFIG_MTK_CPU_SUSPEND_EN */
429*91f16700Schasinglulu 
430*91f16700Schasinglulu #endif /* CONFIG_MTK_PM_SUPPORT */
431*91f16700Schasinglulu 
432*91f16700Schasinglulu /*
433*91f16700Schasinglulu  * Depend on mtk pm methodology, the psci op init must
434*91f16700Schasinglulu  * be invoked after cpu pm to avoid initialization fail.
435*91f16700Schasinglulu  */
436*91f16700Schasinglulu int mt_plat_cpu_pm_init(void)
437*91f16700Schasinglulu {
438*91f16700Schasinglulu 	plat_cpu_pm_lock_init();
439*91f16700Schasinglulu 
440*91f16700Schasinglulu 	mtk_cpc_init();
441*91f16700Schasinglulu #if CONFIG_MTK_PM_SUPPORT
442*91f16700Schasinglulu 
443*91f16700Schasinglulu #if CONFIG_MTK_CPU_SUSPEND_EN
444*91f16700Schasinglulu 	register_cpu_pm_ops(CPU_PM_FN, &cpcv3_2_mcdi);
445*91f16700Schasinglulu #endif /* CONFIG_MTK_CPU_SUSPEND_EN */
446*91f16700Schasinglulu 
447*91f16700Schasinglulu #if CONFIG_MTK_SMP_EN
448*91f16700Schasinglulu 	register_cpu_smp_ops(CPU_PM_FN, &cpcv3_2_cpu_smp);
449*91f16700Schasinglulu #endif /* CONFIG_MTK_SMP_EN */
450*91f16700Schasinglulu 
451*91f16700Schasinglulu #endif /* CONFIG_MTK_PM_SUPPORT */
452*91f16700Schasinglulu 
453*91f16700Schasinglulu 	INFO("[%s:%d] - CPU PM INIT finished\n", __func__, __LINE__);
454*91f16700Schasinglulu 	return 0;
455*91f16700Schasinglulu }
456*91f16700Schasinglulu MTK_ARCH_INIT(mt_plat_cpu_pm_init);
457*91f16700Schasinglulu 
458*91f16700Schasinglulu static const mmap_region_t cpu_pm_mmap[] MTK_MMAP_SECTION = {
459*91f16700Schasinglulu #ifdef CPU_PM_TINYSYS_SUPPORT
460*91f16700Schasinglulu #if CONFIG_MTK_PM_SUPPORT && CONFIG_MTK_CPU_SUSPEND_EN
461*91f16700Schasinglulu 	MAP_REGION_FLAT(CPU_EB_TCM_BASE, CPU_EB_TCM_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
462*91f16700Schasinglulu #endif
463*91f16700Schasinglulu #endif
464*91f16700Schasinglulu 	{0}
465*91f16700Schasinglulu };
466*91f16700Schasinglulu DECLARE_MTK_MMAP_REGIONS(cpu_pm_mmap);
467