1 /*
2  * Copyright (c) 2021, MediaTek Inc. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <stdint.h>
9 
10 #include <arch_helpers.h>
11 #include <lib/psci/psci.h>
12 #include <lib/spinlock.h>
13 
14 #include <mt_cpu_pm_cpc.h>
15 #include <mt_lp_irqremain.h>
16 #include <mt_lp_rm.h>
17 #include <mt_mcdi.h>
18 #include <plat_mtk_lpm.h>
19 #include <plat_pm.h>
20 
21 DEFINE_SYSREG_RW_FUNCS(dbgprcr_el1);
22 
23 static int plat_mt_lp_cpu_rc;
24 
pwr_state_prompt(unsigned int cpu,const psci_power_state_t * state)25 static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state)
26 {
27 	return 0;
28 }
29 
pwr_state_reflect(unsigned int cpu,const psci_power_state_t * state)30 static int pwr_state_reflect(unsigned int cpu, const psci_power_state_t *state)
31 {
32 	mtk_cpc_core_on_hint_clr(cpu);
33 
34 	if (IS_SYSTEM_SUSPEND_STATE(state)) {
35 		mtk_cpc_time_sync();
36 	}
37 
38 	return 0;
39 }
40 
pwr_cpu_pwron(unsigned int cpu,const psci_power_state_t * state)41 static int pwr_cpu_pwron(unsigned int cpu, const psci_power_state_t *state)
42 {
43 	return 0;
44 }
45 
pwr_cpu_pwrdwn(unsigned int cpu,const psci_power_state_t * state)46 static int pwr_cpu_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
47 {
48 	/* clear DBGPRCR.CORENPDRQ to allow CPU power down  */
49 	write_dbgprcr_el1(0ULL);
50 
51 	return 0;
52 }
53 
pwr_cluster_pwron(unsigned int cpu,const psci_power_state_t * state)54 static int pwr_cluster_pwron(unsigned int cpu, const psci_power_state_t *state)
55 {
56 	return 0;
57 }
58 
pwr_cluster_pwrdwn(unsigned int cpu,const psci_power_state_t * state)59 static int pwr_cluster_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
60 {
61 	return 0;
62 }
63 
pwr_mcusys_pwron(unsigned int cpu,const psci_power_state_t * state)64 static int pwr_mcusys_pwron(unsigned int cpu, const psci_power_state_t *state)
65 {
66 	if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
67 		return -1;
68 	}
69 
70 	mtk_cpc_mcusys_off_reflect();
71 
72 	return 0;
73 }
74 
pwr_mcusys_pwron_finished(unsigned int cpu,const psci_power_state_t * state)75 static int pwr_mcusys_pwron_finished(unsigned int cpu,
76 					const psci_power_state_t *state)
77 {
78 	int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];
79 
80 	if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
81 		return -1;
82 	}
83 
84 	mt_lp_rm_reset_constraint(plat_mt_lp_cpu_rc, cpu, state_id);
85 	mt_lp_irqremain_release();
86 
87 	return 0;
88 }
89 
pwr_mcusys_pwrdwn(unsigned int cpu,const psci_power_state_t * state)90 static int pwr_mcusys_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
91 {
92 	int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];
93 
94 	if (!IS_MCUSYS_OFF_STATE(state)) {
95 		goto mt_pwr_mcusysoff_break;
96 	}
97 
98 	if (mcdi_try_init() != 0) { /* not ready to process mcusys-off */
99 		goto mt_pwr_mcusysoff_break;
100 	}
101 
102 	if (mtk_cpc_mcusys_off_prepare() != CPC_SUCCESS) {
103 		goto mt_pwr_mcusysoff_break;
104 	}
105 
106 	plat_mt_lp_cpu_rc =
107 		mt_lp_rm_find_and_run_constraint(0, cpu, state_id, NULL);
108 
109 	if (plat_mt_lp_cpu_rc < 0) {
110 		goto mt_pwr_mcusysoff_reflect;
111 	}
112 
113 	mt_lp_irqremain_aquire();
114 
115 	return 0;
116 
117 mt_pwr_mcusysoff_reflect:
118 	mtk_cpc_mcusys_off_reflect();
119 
120 mt_pwr_mcusysoff_break:
121 	plat_mt_lp_cpu_rc = -1;
122 
123 	return -1;
124 }
125 
126 static const struct mt_lpm_tz plat_pm = {
127 	.pwr_prompt			= pwr_state_prompt,
128 	.pwr_reflect			= pwr_state_reflect,
129 	.pwr_cpu_on			= pwr_cpu_pwron,
130 	.pwr_cpu_dwn			= pwr_cpu_pwrdwn,
131 	.pwr_cluster_on			= pwr_cluster_pwron,
132 	.pwr_cluster_dwn		= pwr_cluster_pwrdwn,
133 	.pwr_mcusys_dwn			= pwr_mcusys_pwrdwn,
134 	.pwr_mcusys_on			= pwr_mcusys_pwron,
135 	.pwr_mcusys_on_finished		= pwr_mcusys_pwron_finished
136 };
137 
mt_plat_cpu_pm_init(void)138 const struct mt_lpm_tz *mt_plat_cpu_pm_init(void)
139 {
140 	mtk_cpc_init();
141 
142 	if (mcdi_try_init() == 0) {
143 		INFO("MCDI init done.\n");
144 	}
145 
146 	mt_lp_irqremain_init();
147 
148 	return &plat_pm;
149 }
150