xref: /rk3399_ARM-atf/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c (revision 51faada71a219a8b94cd8d8e423f0f22e9da4d8f)
1 /*
2  * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of ARM nor the names of its contributors may be used
15  * to endorse or promote products derived from this software without specific
16  * prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <arch.h>
32 #include <arch_helpers.h>
33 #include <assert.h>
34 #include <bl_common.h>
35 #include <context.h>
36 #include <context_mgmt.h>
37 #include <debug.h>
38 #include <denver.h>
39 #include <mce.h>
40 #include <psci.h>
41 #include <smmu.h>
42 #include <t18x_ari.h>
43 #include <tegra_private.h>
44 
45 extern void prepare_cpu_pwr_dwn(void);
46 
47 /* state id mask */
48 #define TEGRA186_STATE_ID_MASK		0xF
49 /* constants to get power state's wake time */
50 #define TEGRA186_WAKE_TIME_MASK		0xFFFFFF
51 #define TEGRA186_WAKE_TIME_SHIFT	4
52 /* context size to save during system suspend */
53 #define TEGRA186_SE_CONTEXT_SIZE		3
54 
55 static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE];
56 static unsigned int wake_time[PLATFORM_CORE_COUNT];
57 
58 /* System power down state */
59 uint32_t tegra186_system_powerdn_state = TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF;
60 
61 int32_t tegra_soc_validate_power_state(unsigned int power_state,
62 					psci_power_state_t *req_state)
63 {
64 	int state_id = psci_get_pstate_id(power_state) & TEGRA186_STATE_ID_MASK;
65 	int cpu = read_mpidr() & MPIDR_CPU_MASK;
66 	int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
67 
68 	if (impl == DENVER_IMPL)
69 		cpu |= 0x4;
70 
71 	wake_time[cpu] = (power_state  >> TEGRA186_WAKE_TIME_SHIFT) &
72 			 TEGRA186_WAKE_TIME_MASK;
73 
74 	/* Sanity check the requested state id */
75 	switch (state_id) {
76 	case PSTATE_ID_CORE_IDLE:
77 	case PSTATE_ID_CORE_POWERDN:
78 		/*
79 		 * Core powerdown request only for afflvl 0
80 		 */
81 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id;
82 
83 		break;
84 
85 	default:
86 		ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
87 		return PSCI_E_INVALID_PARAMS;
88 	}
89 
90 	return PSCI_E_SUCCESS;
91 }
92 
93 int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
94 {
95 	const plat_local_state_t *pwr_domain_state;
96 	unsigned int stateid_afflvl0, stateid_afflvl2;
97 	int cpu = read_mpidr() & MPIDR_CPU_MASK;
98 	int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
99 	cpu_context_t *ctx = cm_get_context(NON_SECURE);
100 	gp_regs_t *gp_regs = get_gpregs_ctx(ctx);
101 	uint32_t val;
102 
103 	assert(ctx);
104 	assert(gp_regs);
105 
106 	if (impl == DENVER_IMPL)
107 		cpu |= 0x4;
108 
109 	/* get the state ID */
110 	pwr_domain_state = target_state->pwr_domain_state;
111 	stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] &
112 		TEGRA186_STATE_ID_MASK;
113 	stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
114 		TEGRA186_STATE_ID_MASK;
115 
116 	if (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) {
117 
118 		/* Prepare for cpu idle */
119 		(void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
120 			TEGRA_ARI_CORE_C6, wake_time[cpu], 0);
121 
122 	} else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {
123 
124 		/* Prepare for cpu powerdn */
125 		(void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
126 			TEGRA_ARI_CORE_C7, wake_time[cpu], 0);
127 
128 	} else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
129 
130 		/* loop until SC7 is allowed */
131 		do {
132 			val = mce_command_handler(MCE_CMD_IS_SC7_ALLOWED,
133 					TEGRA_ARI_CORE_C7,
134 					MCE_CORE_SLEEP_TIME_INFINITE,
135 					0);
136 		} while (val == 0);
137 
138 		/* save SE registers */
139 		se_regs[0] = mmio_read_32(TEGRA_SE0_BASE +
140 				SE_MUTEX_WATCHDOG_NS_LIMIT);
141 		se_regs[1] = mmio_read_32(TEGRA_RNG1_BASE +
142 				RNG_MUTEX_WATCHDOG_NS_LIMIT);
143 		se_regs[2] = mmio_read_32(TEGRA_PKA1_BASE +
144 				PKA_MUTEX_WATCHDOG_NS_LIMIT);
145 
146 		/* save 'Secure Boot' Processor Feature Config Register */
147 		val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG);
148 		mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV6, val);
149 
150 		/* save SMMU context */
151 		tegra_smmu_save_context();
152 
153 		/* Prepare for system suspend */
154 		write_ctx_reg(gp_regs, CTX_GPREG_X4, 1);
155 		write_ctx_reg(gp_regs, CTX_GPREG_X5, 0);
156 		write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
157 		(void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO,
158 			TEGRA_ARI_CLUSTER_CC7, 0, TEGRA_ARI_SYSTEM_SC7);
159 
160 		/* Enter system suspend state */
161 		(void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
162 			TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0);
163 
164 	} else {
165 		ERROR("%s: Unknown state id\n", __func__);
166 		return PSCI_E_NOT_SUPPORTED;
167 	}
168 
169 	return PSCI_E_SUCCESS;
170 }
171 
172 int tegra_soc_pwr_domain_on(u_register_t mpidr)
173 {
174 	int target_cpu = mpidr & MPIDR_CPU_MASK;
175 	int target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
176 			MPIDR_AFFINITY_BITS;
177 
178 	if (target_cluster > MPIDR_AFFLVL1) {
179 		ERROR("%s: unsupported CPU (0x%lx)\n", __func__, mpidr);
180 		return PSCI_E_NOT_PRESENT;
181 	}
182 
183 	/* construct the target CPU # */
184 	target_cpu |= (target_cluster << 2);
185 
186 	mce_command_handler(MCE_CMD_ONLINE_CORE, target_cpu, 0, 0);
187 
188 	return PSCI_E_SUCCESS;
189 }
190 
191 int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
192 {
193 	int state_id = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
194 
195 	/*
196 	 * Check if we are exiting from deep sleep and restore SE
197 	 * context if we are.
198 	 */
199 	if (state_id == PSTATE_ID_SOC_POWERDN) {
200 		mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT,
201 			se_regs[0]);
202 		mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT,
203 			se_regs[1]);
204 		mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT,
205 			se_regs[2]);
206 
207 		/* Init SMMU */
208 		tegra_smmu_init();
209 	}
210 
211 	return PSCI_E_SUCCESS;
212 }
213 
214 int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
215 {
216 	cpu_context_t *ctx = cm_get_context(NON_SECURE);
217 	gp_regs_t *gp_regs = get_gpregs_ctx(ctx);
218 	int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
219 
220 	assert(ctx);
221 	assert(gp_regs);
222 
223 	/* Turn off wake_mask */
224 	write_ctx_reg(gp_regs, CTX_GPREG_X4, 0);
225 	write_ctx_reg(gp_regs, CTX_GPREG_X5, 0);
226 	write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
227 	mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO, TEGRA_ARI_CLUSTER_CC7,
228 		0, TEGRA_ARI_SYSTEM_SC7);
229 
230 	/* Disable Denver's DCO operations */
231 	if (impl == DENVER_IMPL)
232 		denver_disable_dco();
233 
234 	/* Turn off CPU */
235 	return mce_command_handler(MCE_CMD_ENTER_CSTATE, TEGRA_ARI_CORE_C7,
236 			MCE_CORE_SLEEP_TIME_INFINITE, 0);
237 }
238 
239 __dead2 void tegra_soc_prepare_system_off(void)
240 {
241 	cpu_context_t *ctx = cm_get_context(NON_SECURE);
242 	gp_regs_t *gp_regs = get_gpregs_ctx(ctx);
243 	uint32_t val;
244 
245 	if (tegra186_system_powerdn_state == TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) {
246 
247 		/* power off the entire system */
248 		mce_enter_ccplex_state(tegra186_system_powerdn_state);
249 
250 	} else if (tegra186_system_powerdn_state == TEGRA_ARI_SYSTEM_SC8) {
251 
252 		/* loop until other CPUs power down */
253 		do {
254 			val = mce_command_handler(MCE_CMD_IS_SC7_ALLOWED,
255 					TEGRA_ARI_CORE_C7,
256 					MCE_CORE_SLEEP_TIME_INFINITE,
257 					0);
258 		} while (val == 0);
259 
260 		/* Prepare for quasi power down */
261 		write_ctx_reg(gp_regs, CTX_GPREG_X4, 1);
262 		write_ctx_reg(gp_regs, CTX_GPREG_X5, 0);
263 		write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
264 		(void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO,
265 			TEGRA_ARI_CLUSTER_CC7, 0, TEGRA_ARI_SYSTEM_SC8);
266 
267 		/* Enter quasi power down state */
268 		(void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
269 			TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0);
270 
271 		/* disable GICC */
272 		tegra_gic_cpuif_deactivate();
273 
274 		/* power down core */
275 		prepare_cpu_pwr_dwn();
276 
277 	} else {
278 		ERROR("%s: unsupported power down state (%d)\n", __func__,
279 			tegra186_system_powerdn_state);
280 	}
281 
282 	wfi();
283 
284 	/* wait for the system to power down */
285 	for (;;) {
286 		;
287 	}
288 }
289 
290 int tegra_soc_prepare_system_reset(void)
291 {
292 	mce_enter_ccplex_state(TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT);
293 
294 	return PSCI_E_SUCCESS;
295 }
296