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