xref: /rk3399_ARM-atf/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c (revision 13dcbc6f2265ac4f3ea018cdb785fb1e8d473119)
1 /*
2  * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <arch.h>
8 #include <arch_helpers.h>
9 #include <assert.h>
10 #include <common/bl_common.h>
11 #include <context.h>
12 #include <lib/el3_runtime/context_mgmt.h>
13 #include <common/debug.h>
14 #include <denver.h>
15 #include <mce.h>
16 #include <plat/common/platform.h>
17 #include <lib/psci/psci.h>
18 #include <smmu.h>
19 #include <string.h>
20 #include <tegra_private.h>
21 #include <t194_nvg.h>
22 #include <stdbool.h>
23 
24 extern void prepare_core_pwr_dwn(void);
25 
26 extern void tegra_secure_entrypoint(void);
27 
28 #if ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM
29 extern void tegra186_cpu_reset_handler(void);
30 extern uint32_t __tegra186_cpu_reset_handler_data,
31 		__tegra186_cpu_reset_handler_end;
32 
33 /* TZDRAM offset for saving SMMU context */
34 #define TEGRA186_SMMU_CTX_OFFSET	16
35 #endif
36 
37 /* state id mask */
38 #define TEGRA186_STATE_ID_MASK		0xF
39 /* constants to get power state's wake time */
40 #define TEGRA186_WAKE_TIME_MASK		0x0FFFFFF0
41 #define TEGRA186_WAKE_TIME_SHIFT	4
42 /* default core wake mask for CPU_SUSPEND */
43 #define TEGRA194_CORE_WAKE_MASK		0x180c
44 /* context size to save during system suspend */
45 #define TEGRA186_SE_CONTEXT_SIZE	3
46 
47 static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE];
48 static struct t18x_psci_percpu_data {
49 	unsigned int wake_time;
50 } __aligned(CACHE_WRITEBACK_GRANULE) percpu_data[PLATFORM_CORE_COUNT];
51 
52 /*
53  * tegra_fake_system_suspend acts as a boolean var controlling whether
54  * we are going to take fake system suspend code or normal system suspend code
55  * path. This variable is set inside the sip call handlers, when the kernel
56  * requests an SIP call to set the suspend debug flags.
57  */
58 bool tegra_fake_system_suspend;
59 
60 int32_t tegra_soc_validate_power_state(unsigned int power_state,
61 					psci_power_state_t *req_state)
62 {
63 	int state_id = psci_get_pstate_id(power_state) & TEGRA186_STATE_ID_MASK;
64 	int cpu = plat_my_core_pos();
65 
66 	/* save the core wake time (in TSC ticks)*/
67 	percpu_data[cpu].wake_time = (power_state & TEGRA186_WAKE_TIME_MASK)
68 			<< TEGRA186_WAKE_TIME_SHIFT;
69 
70 	/*
71 	 * Clean percpu_data[cpu] to DRAM. This needs to be done to ensure that
72 	 * the correct value is read in tegra_soc_pwr_domain_suspend(), which
73 	 * is called with caches disabled. It is possible to read a stale value
74 	 * from DRAM in that function, because the L2 cache is not flushed
75 	 * unless the cluster is entering CC6/CC7.
76 	 */
77 	clean_dcache_range((uint64_t)&percpu_data[cpu],
78 			sizeof(percpu_data[cpu]));
79 
80 	/* Sanity check the requested state id */
81 	switch (state_id) {
82 	case PSTATE_ID_CORE_IDLE:
83 	case PSTATE_ID_CORE_POWERDN:
84 
85 		/* Core powerdown request */
86 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id;
87 		req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
88 
89 		break;
90 
91 	default:
92 		ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
93 		return PSCI_E_INVALID_PARAMS;
94 	}
95 
96 	return PSCI_E_SUCCESS;
97 }
98 
99 int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
100 {
101 	const plat_local_state_t *pwr_domain_state;
102 	unsigned int stateid_afflvl0, stateid_afflvl2;
103 #if ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM
104 	plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
105 	uint64_t smmu_ctx_base;
106 #endif
107 	uint32_t val;
108 	mce_cstate_info_t sc7_cstate_info = {
109 		.cluster = TEGRA_NVG_CLUSTER_CC6,
110 		.system = TEGRA_NVG_SYSTEM_SC7,
111 		.system_state_force = 1,
112 		.update_wake_mask = 1,
113 	};
114 	int cpu = plat_my_core_pos();
115 	int32_t ret = 0;
116 
117 	/* get the state ID */
118 	pwr_domain_state = target_state->pwr_domain_state;
119 	stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] &
120 		TEGRA186_STATE_ID_MASK;
121 	stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
122 		TEGRA186_STATE_ID_MASK;
123 
124 	if ((stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ||
125 	    (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN)) {
126 
127 		/* Enter CPU idle/powerdown */
128 		val = (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ?
129 			TEGRA_NVG_CORE_C6 : TEGRA_NVG_CORE_C7;
130 		ret = mce_command_handler(MCE_CMD_ENTER_CSTATE, val,
131 				percpu_data[cpu].wake_time, 0);
132 		assert(ret == 0);
133 
134 	} else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
135 
136 		/* save SE registers */
137 		se_regs[0] = mmio_read_32(TEGRA_SE0_BASE +
138 				SE_MUTEX_WATCHDOG_NS_LIMIT);
139 		se_regs[1] = mmio_read_32(TEGRA_RNG1_BASE +
140 				RNG_MUTEX_WATCHDOG_NS_LIMIT);
141 		se_regs[2] = mmio_read_32(TEGRA_PKA1_BASE +
142 				PKA_MUTEX_WATCHDOG_NS_LIMIT);
143 
144 		/* save 'Secure Boot' Processor Feature Config Register */
145 		val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG);
146 		mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV6, val);
147 
148 #if ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM
149 		/* save SMMU context */
150 		smmu_ctx_base = params_from_bl2->tzdram_base +
151 			((uintptr_t)&__tegra186_cpu_reset_handler_data -
152 			 (uintptr_t)tegra186_cpu_reset_handler) +
153 			TEGRA186_SMMU_CTX_OFFSET;
154 		tegra_smmu_save_context((uintptr_t)smmu_ctx_base);
155 #else
156 		tegra_smmu_save_context(0);
157 #endif
158 
159 		if (!tegra_fake_system_suspend) {
160 
161 			/* Prepare for system suspend */
162 			mce_update_cstate_info(&sc7_cstate_info);
163 
164 			do {
165 				val = mce_command_handler(
166 						MCE_CMD_IS_SC7_ALLOWED,
167 						TEGRA_NVG_CORE_C7,
168 						MCE_CORE_SLEEP_TIME_INFINITE,
169 						0);
170 			} while (val == 0);
171 
172 	                /* Instruct the MCE to enter system suspend state */
173 			(void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
174 			TEGRA_NVG_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0);
175 		}
176 	}
177 
178 	return PSCI_E_SUCCESS;
179 }
180 
181 /*******************************************************************************
182  * Platform handler to calculate the proper target power level at the
183  * specified affinity level
184  ******************************************************************************/
185 plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl,
186 					     const plat_local_state_t *states,
187 					     unsigned int ncpu)
188 {
189 	plat_local_state_t target = *states;
190 	int cluster_powerdn = 1;
191 	int core_pos = read_mpidr() & MPIDR_CPU_MASK;
192 	mce_cstate_info_t cstate_info = { 0 };
193 
194 	/* get the current core's power state */
195 	target = *(states + core_pos);
196 
197 	/* CPU suspend */
198 	if (lvl == MPIDR_AFFLVL1 && target == PSTATE_ID_CORE_POWERDN) {
199 
200 		/* Program default wake mask */
201 		cstate_info.wake_mask = TEGRA194_CORE_WAKE_MASK;
202 		cstate_info.update_wake_mask = 1;
203 		mce_update_cstate_info(&cstate_info);
204 	}
205 
206 	/* CPU off */
207 	if (lvl == MPIDR_AFFLVL1 && target == PLAT_MAX_OFF_STATE) {
208 
209 		/* find out the number of ON cpus in the cluster */
210 		do {
211 			target = *states++;
212 			if (target != PLAT_MAX_OFF_STATE)
213 				cluster_powerdn = 0;
214 		} while (--ncpu);
215 
216 		/* Enable cluster powerdn from last CPU in the cluster */
217 		if (cluster_powerdn) {
218 
219 			/* Enable CC7 state and turn off wake mask */
220 
221 		} else {
222 
223 			/* Turn off wake_mask */
224 		}
225 	}
226 
227 	/* System Suspend */
228 	if ((lvl == MPIDR_AFFLVL2) || (target == PSTATE_ID_SOC_POWERDN))
229 		return PSTATE_ID_SOC_POWERDN;
230 
231 	/* default state */
232 	return PSCI_LOCAL_STATE_RUN;
233 }
234 
235 #if ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM
236 int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
237 {
238 	const plat_local_state_t *pwr_domain_state =
239 		target_state->pwr_domain_state;
240 	plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
241 	unsigned int stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
242 		TEGRA186_STATE_ID_MASK;
243 	uint64_t val;
244 	u_register_t ns_sctlr_el1;
245 
246 	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
247 		/*
248 		 * The TZRAM loses power when we enter system suspend. To
249 		 * allow graceful exit from system suspend, we need to copy
250 		 * BL3-1 over to TZDRAM.
251 		 */
252 		val = params_from_bl2->tzdram_base +
253 			((uintptr_t)&__tegra186_cpu_reset_handler_end -
254 			 (uintptr_t)tegra186_cpu_reset_handler);
255 		memcpy((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
256 		       (uintptr_t)&__BL31_END__ - (uintptr_t)BL31_BASE);
257 
258 
259 		/*
260 		 * In fake suspend mode, ensure that the loopback procedure
261 		 * towards system suspend exit is started, instead of calling
262 		 * WFI. This is done by disabling both MMU's of EL1 & El3
263 		 * and calling tegra_secure_entrypoint().
264 		 */
265 		if (tegra_fake_system_suspend) {
266 
267 			/*
268 			 * Disable EL1's MMU.
269 			 */
270 			ns_sctlr_el1 = read_sctlr_el1();
271 			ns_sctlr_el1 &= (~((u_register_t)SCTLR_M_BIT));
272 			write_sctlr_el1(ns_sctlr_el1);
273 
274 			/*
275 			 * Disable MMU to power up the CPU in a "clean"
276 			 * state
277 			 */
278 			disable_mmu_el3();
279 			tegra_secure_entrypoint();
280 			panic();
281 		}
282 	}
283 
284 	return PSCI_E_SUCCESS;
285 }
286 #endif
287 
288 int tegra_soc_pwr_domain_on(u_register_t mpidr)
289 {
290 	uint32_t target_cpu = mpidr & MPIDR_CPU_MASK;
291 	uint32_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
292 			MPIDR_AFFINITY_BITS;
293 
294 	if (target_cluster > MPIDR_AFFLVL1) {
295 		ERROR("%s: unsupported CPU (0x%lx)\n", __func__ , mpidr);
296 		return PSCI_E_NOT_PRESENT;
297 	}
298 
299 	/* construct the target CPU # */
300 	target_cpu += (target_cluster << 1);
301 
302 	mce_command_handler(MCE_CMD_ONLINE_CORE, target_cpu, 0, 0);
303 
304 	return PSCI_E_SUCCESS;
305 }
306 
307 int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
308 {
309 	int stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
310 
311 	/*
312 	 * Reset power state info for CPUs when onlining, we set
313 	 * deepest power when offlining a core but that may not be
314 	 * requested by non-secure sw which controls idle states. It
315 	 * will re-init this info from non-secure software when the
316 	 * core come online.
317 	 */
318 
319 	/*
320 	 * Check if we are exiting from deep sleep and restore SE
321 	 * context if we are.
322 	 */
323 	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
324 
325 		mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT,
326 			se_regs[0]);
327 		mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT,
328 			se_regs[1]);
329 		mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT,
330 			se_regs[2]);
331 
332 		/* Init SMMU */
333 
334 		tegra_smmu_init();
335 
336 		/*
337 		 * Reset power state info for the last core doing SC7
338 		 * entry and exit, we set deepest power state as CC7
339 		 * and SC7 for SC7 entry which may not be requested by
340 		 * non-secure SW which controls idle states.
341 		 */
342 	}
343 
344 	return PSCI_E_SUCCESS;
345 }
346 
347 int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
348 {
349 	int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
350 
351 	/* Disable Denver's DCO operations */
352 	if (impl == DENVER_IMPL)
353 		denver_disable_dco();
354 
355 	/* Turn off CPU */
356 
357 	return PSCI_E_SUCCESS;
358 }
359 
360 __dead2 void tegra_soc_prepare_system_off(void)
361 {
362 	/* System power off */
363 
364 	/* SC8 */
365 
366 	wfi();
367 
368 	/* wait for the system to power down */
369 	for (;;) {
370 		;
371 	}
372 }
373 
374 int tegra_soc_prepare_system_reset(void)
375 {
376 	return PSCI_E_SUCCESS;
377 }
378