xref: /rk3399_ARM-atf/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c (revision 723c4c2d511cb6ffa534bc879d1edc2e3a691a63)
1271d9497SJames Liao /*
2271d9497SJames Liao  * Copyright (c) 2020, MediaTek Inc. All rights reserved.
3271d9497SJames Liao  *
4271d9497SJames Liao  * SPDX-License-Identifier: BSD-3-Clause
5271d9497SJames Liao  */
6271d9497SJames Liao 
7271d9497SJames Liao #include <assert.h>
8271d9497SJames Liao #include <stdint.h>
9271d9497SJames Liao 
10271d9497SJames Liao #include <arch_helpers.h>
11271d9497SJames Liao #include <lib/psci/psci.h>
12271d9497SJames Liao #include <lib/spinlock.h>
13271d9497SJames Liao 
14271d9497SJames Liao #include <mt_cpu_pm_cpc.h>
15*df60025fSRoger Lu #include <mt_lp_irqremain.h>
16*df60025fSRoger Lu #include <mt_lp_rm.h>
17271d9497SJames Liao #include <mt_mcdi.h>
18271d9497SJames Liao #include <plat_mtk_lpm.h>
19271d9497SJames Liao #include <plat_pm.h>
20271d9497SJames Liao 
21271d9497SJames Liao static int plat_mt_lp_cpu_rc;
22271d9497SJames Liao 
pwr_state_prompt(unsigned int cpu,const psci_power_state_t * state)23271d9497SJames Liao static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state)
24271d9497SJames Liao {
25271d9497SJames Liao 	return 0;
26271d9497SJames Liao }
27271d9497SJames Liao 
pwr_state_reflect(unsigned int cpu,const psci_power_state_t * state)28271d9497SJames Liao static int pwr_state_reflect(unsigned int cpu, const psci_power_state_t *state)
29271d9497SJames Liao {
30271d9497SJames Liao 	mtk_cpc_core_on_hint_clr(cpu);
31271d9497SJames Liao 
32271d9497SJames Liao 	if (IS_SYSTEM_SUSPEND_STATE(state)) {
33271d9497SJames Liao 		mtk_cpc_time_sync();
34271d9497SJames Liao 	}
35271d9497SJames Liao 
36271d9497SJames Liao 	return 0;
37271d9497SJames Liao }
38271d9497SJames Liao 
pwr_cpu_pwron(unsigned int cpu,const psci_power_state_t * state)39271d9497SJames Liao static int pwr_cpu_pwron(unsigned int cpu, const psci_power_state_t *state)
40271d9497SJames Liao {
41271d9497SJames Liao 	return 0;
42271d9497SJames Liao }
43271d9497SJames Liao 
pwr_cpu_pwrdwn(unsigned int cpu,const psci_power_state_t * state)44271d9497SJames Liao static int pwr_cpu_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
45271d9497SJames Liao {
46271d9497SJames Liao 	/* clear DBGPRCR.CORENPDRQ to allow CPU power down  */
47271d9497SJames Liao 	write_dbgprcr_el1(0ULL);
48271d9497SJames Liao 
49271d9497SJames Liao 	return 0;
50271d9497SJames Liao }
51271d9497SJames Liao 
pwr_cluster_pwron(unsigned int cpu,const psci_power_state_t * state)52271d9497SJames Liao static int pwr_cluster_pwron(unsigned int cpu, const psci_power_state_t *state)
53271d9497SJames Liao {
54271d9497SJames Liao 	return 0;
55271d9497SJames Liao }
56271d9497SJames Liao 
pwr_cluster_pwrdwn(unsigned int cpu,const psci_power_state_t * state)57271d9497SJames Liao static int pwr_cluster_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
58271d9497SJames Liao {
59271d9497SJames Liao 	return 0;
60271d9497SJames Liao }
61271d9497SJames Liao 
pwr_mcusys_pwron(unsigned int cpu,const psci_power_state_t * state)62271d9497SJames Liao static int pwr_mcusys_pwron(unsigned int cpu, const psci_power_state_t *state)
63271d9497SJames Liao {
64271d9497SJames Liao 	if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
65271d9497SJames Liao 		return -1;
66271d9497SJames Liao 	}
67271d9497SJames Liao 
68271d9497SJames Liao 	mtk_cpc_mcusys_off_reflect();
69271d9497SJames Liao 
70271d9497SJames Liao 	return 0;
71271d9497SJames Liao }
72271d9497SJames Liao 
pwr_mcusys_pwron_finished(unsigned int cpu,const psci_power_state_t * state)73271d9497SJames Liao static int pwr_mcusys_pwron_finished(unsigned int cpu,
74271d9497SJames Liao 					const psci_power_state_t *state)
75271d9497SJames Liao {
76*df60025fSRoger Lu 	int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];
77*df60025fSRoger Lu 
78271d9497SJames Liao 	if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
79271d9497SJames Liao 		return -1;
80271d9497SJames Liao 	}
81271d9497SJames Liao 
82*df60025fSRoger Lu 	mt_lp_rm_reset_constraint(plat_mt_lp_cpu_rc, cpu, state_id);
83*df60025fSRoger Lu 	mt_lp_irqremain_release();
84*df60025fSRoger Lu 
85271d9497SJames Liao 	return 0;
86271d9497SJames Liao }
87271d9497SJames Liao 
pwr_mcusys_pwrdwn(unsigned int cpu,const psci_power_state_t * state)88271d9497SJames Liao static int pwr_mcusys_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
89271d9497SJames Liao {
90*df60025fSRoger Lu 	int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];
91*df60025fSRoger Lu 
92271d9497SJames Liao 	if (!IS_MCUSYS_OFF_STATE(state)) {
93271d9497SJames Liao 		goto mt_pwr_mcusysoff_break;
94271d9497SJames Liao 	}
95271d9497SJames Liao 
96*df60025fSRoger Lu 	if (mcdi_try_init() != 0) {
97271d9497SJames Liao 		goto mt_pwr_mcusysoff_break;
98271d9497SJames Liao 	}
99271d9497SJames Liao 
100*df60025fSRoger Lu 	if (mtk_cpc_mcusys_off_prepare() != CPC_SUCCESS) {
101*df60025fSRoger Lu 		goto mt_pwr_mcusysoff_break;
102*df60025fSRoger Lu 	}
103*df60025fSRoger Lu 
104*df60025fSRoger Lu 	plat_mt_lp_cpu_rc =
105*df60025fSRoger Lu 		mt_lp_rm_find_and_run_constraint(0, cpu, state_id, NULL);
106*df60025fSRoger Lu 
107*df60025fSRoger Lu 	if (plat_mt_lp_cpu_rc < 0) {
108*df60025fSRoger Lu 		goto mt_pwr_mcusysoff_reflect;
109*df60025fSRoger Lu 	}
110*df60025fSRoger Lu 
111*df60025fSRoger Lu 	mt_lp_irqremain_aquire();
112*df60025fSRoger Lu 
113271d9497SJames Liao 	return 0;
114271d9497SJames Liao 
115*df60025fSRoger Lu mt_pwr_mcusysoff_reflect:
116*df60025fSRoger Lu 	mtk_cpc_mcusys_off_reflect();
117271d9497SJames Liao 
118*df60025fSRoger Lu mt_pwr_mcusysoff_break:
119271d9497SJames Liao 	plat_mt_lp_cpu_rc = -1;
120271d9497SJames Liao 
121271d9497SJames Liao 	return -1;
122271d9497SJames Liao }
123271d9497SJames Liao 
124271d9497SJames Liao static const struct mt_lpm_tz plat_pm = {
125271d9497SJames Liao 	.pwr_prompt			= pwr_state_prompt,
126271d9497SJames Liao 	.pwr_reflect			= pwr_state_reflect,
127271d9497SJames Liao 	.pwr_cpu_on			= pwr_cpu_pwron,
128271d9497SJames Liao 	.pwr_cpu_dwn			= pwr_cpu_pwrdwn,
129271d9497SJames Liao 	.pwr_cluster_on			= pwr_cluster_pwron,
130271d9497SJames Liao 	.pwr_cluster_dwn		= pwr_cluster_pwrdwn,
131271d9497SJames Liao 	.pwr_mcusys_dwn			= pwr_mcusys_pwrdwn,
132271d9497SJames Liao 	.pwr_mcusys_on			= pwr_mcusys_pwron,
133271d9497SJames Liao 	.pwr_mcusys_on_finished		= pwr_mcusys_pwron_finished
134271d9497SJames Liao };
135271d9497SJames Liao 
mt_plat_cpu_pm_init(void)136271d9497SJames Liao const struct mt_lpm_tz *mt_plat_cpu_pm_init(void)
137271d9497SJames Liao {
138271d9497SJames Liao 	mtk_cpc_init();
139271d9497SJames Liao 
140271d9497SJames Liao 	if (mcdi_try_init() == 0) {
141271d9497SJames Liao 		INFO("MCDI init done.\n");
142271d9497SJames Liao 	}
143271d9497SJames Liao 
144*df60025fSRoger Lu 	mt_lp_irqremain_init();
145*df60025fSRoger Lu 
146271d9497SJames Liao 	return &plat_pm;
147271d9497SJames Liao }
148