xref: /arm-trusted-firmware/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
4*91f16700Schasinglulu  *
5*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
6*91f16700Schasinglulu  */
7*91f16700Schasinglulu 
8*91f16700Schasinglulu #include <assert.h>
9*91f16700Schasinglulu #include <stdbool.h>
10*91f16700Schasinglulu #include <string.h>
11*91f16700Schasinglulu 
12*91f16700Schasinglulu #include <arch.h>
13*91f16700Schasinglulu #include <arch_helpers.h>
14*91f16700Schasinglulu #include <common/bl_common.h>
15*91f16700Schasinglulu #include <common/debug.h>
16*91f16700Schasinglulu #include <context.h>
17*91f16700Schasinglulu #include <cortex_a57.h>
18*91f16700Schasinglulu #include <denver.h>
19*91f16700Schasinglulu #include <lib/el3_runtime/context_mgmt.h>
20*91f16700Schasinglulu #include <lib/psci/psci.h>
21*91f16700Schasinglulu #include <plat/common/platform.h>
22*91f16700Schasinglulu 
23*91f16700Schasinglulu #include <bpmp_ipc.h>
24*91f16700Schasinglulu #include <mce.h>
25*91f16700Schasinglulu #include <memctrl_v2.h>
26*91f16700Schasinglulu #include <security_engine.h>
27*91f16700Schasinglulu #include <smmu.h>
28*91f16700Schasinglulu #include <t18x_ari.h>
29*91f16700Schasinglulu #include <tegra186_private.h>
30*91f16700Schasinglulu #include <tegra_private.h>
31*91f16700Schasinglulu 
32*91f16700Schasinglulu extern void memcpy16(void *dest, const void *src, unsigned int length);
33*91f16700Schasinglulu 
34*91f16700Schasinglulu /* state id mask */
35*91f16700Schasinglulu #define TEGRA186_STATE_ID_MASK		0xFU
36*91f16700Schasinglulu /* constants to get power state's wake time */
37*91f16700Schasinglulu #define TEGRA186_WAKE_TIME_MASK		0x0FFFFFF0U
38*91f16700Schasinglulu #define TEGRA186_WAKE_TIME_SHIFT	4U
39*91f16700Schasinglulu /* default core wake mask for CPU_SUSPEND */
40*91f16700Schasinglulu #define TEGRA186_CORE_WAKE_MASK		0x180cU
41*91f16700Schasinglulu /* context size to save during system suspend */
42*91f16700Schasinglulu #define TEGRA186_SE_CONTEXT_SIZE	3U
43*91f16700Schasinglulu 
44*91f16700Schasinglulu static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE];
45*91f16700Schasinglulu static struct tegra_psci_percpu_data {
46*91f16700Schasinglulu 	uint32_t wake_time;
47*91f16700Schasinglulu } __aligned(CACHE_WRITEBACK_GRANULE) tegra_percpu_data[PLATFORM_CORE_COUNT];
48*91f16700Schasinglulu 
49*91f16700Schasinglulu int32_t tegra_soc_validate_power_state(uint32_t power_state,
50*91f16700Schasinglulu 					psci_power_state_t *req_state)
51*91f16700Schasinglulu {
52*91f16700Schasinglulu 	uint8_t state_id = (uint8_t)psci_get_pstate_id(power_state) & TEGRA186_STATE_ID_MASK;
53*91f16700Schasinglulu 	uint32_t cpu = plat_my_core_pos();
54*91f16700Schasinglulu 	int32_t ret = PSCI_E_SUCCESS;
55*91f16700Schasinglulu 
56*91f16700Schasinglulu 	/* save the core wake time (in TSC ticks)*/
57*91f16700Schasinglulu 	tegra_percpu_data[cpu].wake_time = (power_state & TEGRA186_WAKE_TIME_MASK)
58*91f16700Schasinglulu 			<< TEGRA186_WAKE_TIME_SHIFT;
59*91f16700Schasinglulu 
60*91f16700Schasinglulu 	/*
61*91f16700Schasinglulu 	 * Clean percpu_data[cpu] to DRAM. This needs to be done to ensure that
62*91f16700Schasinglulu 	 * the correct value is read in tegra_soc_pwr_domain_suspend(), which
63*91f16700Schasinglulu 	 * is called with caches disabled. It is possible to read a stale value
64*91f16700Schasinglulu 	 * from DRAM in that function, because the L2 cache is not flushed
65*91f16700Schasinglulu 	 * unless the cluster is entering CC6/CC7.
66*91f16700Schasinglulu 	 */
67*91f16700Schasinglulu 	clean_dcache_range((uint64_t)&tegra_percpu_data[cpu],
68*91f16700Schasinglulu 			sizeof(tegra_percpu_data[cpu]));
69*91f16700Schasinglulu 
70*91f16700Schasinglulu 	/* Sanity check the requested state id */
71*91f16700Schasinglulu 	switch (state_id) {
72*91f16700Schasinglulu 	case PSTATE_ID_CORE_IDLE:
73*91f16700Schasinglulu 	case PSTATE_ID_CORE_POWERDN:
74*91f16700Schasinglulu 
75*91f16700Schasinglulu 		if (psci_get_pstate_type(power_state) != PSTATE_TYPE_POWERDOWN) {
76*91f16700Schasinglulu 			ret = PSCI_E_INVALID_PARAMS;
77*91f16700Schasinglulu 			break;
78*91f16700Schasinglulu 		}
79*91f16700Schasinglulu 
80*91f16700Schasinglulu 		/* Core powerdown request */
81*91f16700Schasinglulu 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id;
82*91f16700Schasinglulu 		req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
83*91f16700Schasinglulu 
84*91f16700Schasinglulu 		break;
85*91f16700Schasinglulu 
86*91f16700Schasinglulu 	default:
87*91f16700Schasinglulu 		ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
88*91f16700Schasinglulu 		ret = PSCI_E_INVALID_PARAMS;
89*91f16700Schasinglulu 		break;
90*91f16700Schasinglulu 	}
91*91f16700Schasinglulu 
92*91f16700Schasinglulu 	return ret;
93*91f16700Schasinglulu }
94*91f16700Schasinglulu 
95*91f16700Schasinglulu int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state)
96*91f16700Schasinglulu {
97*91f16700Schasinglulu 	(void)cpu_state;
98*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
99*91f16700Schasinglulu }
100*91f16700Schasinglulu 
101*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
102*91f16700Schasinglulu {
103*91f16700Schasinglulu 	const plat_local_state_t *pwr_domain_state;
104*91f16700Schasinglulu 	uint8_t stateid_afflvl0, stateid_afflvl2;
105*91f16700Schasinglulu 	uint32_t cpu = plat_my_core_pos();
106*91f16700Schasinglulu 	const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
107*91f16700Schasinglulu 	mce_cstate_info_t cstate_info = { 0 };
108*91f16700Schasinglulu 	uint64_t mc_ctx_base;
109*91f16700Schasinglulu 	uint32_t val;
110*91f16700Schasinglulu 
111*91f16700Schasinglulu 	/* get the state ID */
112*91f16700Schasinglulu 	pwr_domain_state = target_state->pwr_domain_state;
113*91f16700Schasinglulu 	stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] &
114*91f16700Schasinglulu 		TEGRA186_STATE_ID_MASK;
115*91f16700Schasinglulu 	stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
116*91f16700Schasinglulu 		TEGRA186_STATE_ID_MASK;
117*91f16700Schasinglulu 
118*91f16700Schasinglulu 	if ((stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ||
119*91f16700Schasinglulu 	    (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN)) {
120*91f16700Schasinglulu 
121*91f16700Schasinglulu 		/* Enter CPU idle/powerdown */
122*91f16700Schasinglulu 		val = (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ?
123*91f16700Schasinglulu 			(uint32_t)TEGRA_ARI_CORE_C6 : (uint32_t)TEGRA_ARI_CORE_C7;
124*91f16700Schasinglulu 		(void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, (uint64_t)val,
125*91f16700Schasinglulu 				tegra_percpu_data[cpu].wake_time, 0U);
126*91f16700Schasinglulu 
127*91f16700Schasinglulu 	} else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
128*91f16700Schasinglulu 
129*91f16700Schasinglulu 		/* save SE registers */
130*91f16700Schasinglulu 		se_regs[0] = mmio_read_32(TEGRA_SE0_BASE +
131*91f16700Schasinglulu 				SE_MUTEX_WATCHDOG_NS_LIMIT);
132*91f16700Schasinglulu 		se_regs[1] = mmio_read_32(TEGRA_RNG1_BASE +
133*91f16700Schasinglulu 				RNG_MUTEX_WATCHDOG_NS_LIMIT);
134*91f16700Schasinglulu 		se_regs[2] = mmio_read_32(TEGRA_PKA1_BASE +
135*91f16700Schasinglulu 				PKA_MUTEX_WATCHDOG_NS_LIMIT);
136*91f16700Schasinglulu 
137*91f16700Schasinglulu 		/* save 'Secure Boot' Processor Feature Config Register */
138*91f16700Schasinglulu 		val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG);
139*91f16700Schasinglulu 		mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SECURE_BOOTP_FCFG, val);
140*91f16700Schasinglulu 
141*91f16700Schasinglulu 		/* save MC context to TZDRAM */
142*91f16700Schasinglulu 		mc_ctx_base = params_from_bl2->tzdram_base;
143*91f16700Schasinglulu 		tegra_mc_save_context((uintptr_t)mc_ctx_base);
144*91f16700Schasinglulu 
145*91f16700Schasinglulu 		/* Prepare for system suspend */
146*91f16700Schasinglulu 		cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
147*91f16700Schasinglulu 		cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC7;
148*91f16700Schasinglulu 		cstate_info.system_state_force = 1;
149*91f16700Schasinglulu 		cstate_info.update_wake_mask = 1;
150*91f16700Schasinglulu 		mce_update_cstate_info(&cstate_info);
151*91f16700Schasinglulu 
152*91f16700Schasinglulu 		/* Loop until system suspend is allowed */
153*91f16700Schasinglulu 		do {
154*91f16700Schasinglulu 			val = (uint32_t)mce_command_handler(
155*91f16700Schasinglulu 					(uint64_t)MCE_CMD_IS_SC7_ALLOWED,
156*91f16700Schasinglulu 					(uint64_t)TEGRA_ARI_CORE_C7,
157*91f16700Schasinglulu 					MCE_CORE_SLEEP_TIME_INFINITE,
158*91f16700Schasinglulu 					0U);
159*91f16700Schasinglulu 		} while (val == 0U);
160*91f16700Schasinglulu 
161*91f16700Schasinglulu 		/* Instruct the MCE to enter system suspend state */
162*91f16700Schasinglulu 		(void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
163*91f16700Schasinglulu 			(uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
164*91f16700Schasinglulu 
165*91f16700Schasinglulu 	} else {
166*91f16700Schasinglulu 		; /* do nothing */
167*91f16700Schasinglulu 	}
168*91f16700Schasinglulu 
169*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
170*91f16700Schasinglulu }
171*91f16700Schasinglulu 
172*91f16700Schasinglulu /*******************************************************************************
173*91f16700Schasinglulu  * Helper function to check if this is the last ON CPU in the cluster
174*91f16700Schasinglulu  ******************************************************************************/
175*91f16700Schasinglulu static bool tegra_last_cpu_in_cluster(const plat_local_state_t *states,
176*91f16700Schasinglulu 			uint32_t ncpu)
177*91f16700Schasinglulu {
178*91f16700Schasinglulu 	plat_local_state_t target;
179*91f16700Schasinglulu 	bool last_on_cpu = true;
180*91f16700Schasinglulu 	uint32_t num_cpus = ncpu, pos = 0;
181*91f16700Schasinglulu 
182*91f16700Schasinglulu 	do {
183*91f16700Schasinglulu 		target = states[pos];
184*91f16700Schasinglulu 		if (target != PLAT_MAX_OFF_STATE) {
185*91f16700Schasinglulu 			last_on_cpu = false;
186*91f16700Schasinglulu 		}
187*91f16700Schasinglulu 		--num_cpus;
188*91f16700Schasinglulu 		pos++;
189*91f16700Schasinglulu 	} while (num_cpus != 0U);
190*91f16700Schasinglulu 
191*91f16700Schasinglulu 	return last_on_cpu;
192*91f16700Schasinglulu }
193*91f16700Schasinglulu 
194*91f16700Schasinglulu /*******************************************************************************
195*91f16700Schasinglulu  * Helper function to get target power state for the cluster
196*91f16700Schasinglulu  ******************************************************************************/
197*91f16700Schasinglulu static plat_local_state_t tegra_get_afflvl1_pwr_state(const plat_local_state_t *states,
198*91f16700Schasinglulu 			uint32_t ncpu)
199*91f16700Schasinglulu {
200*91f16700Schasinglulu 	uint32_t core_pos = (uint32_t)read_mpidr() & (uint32_t)MPIDR_CPU_MASK;
201*91f16700Schasinglulu 	uint32_t cpu = plat_my_core_pos();
202*91f16700Schasinglulu 	int32_t ret;
203*91f16700Schasinglulu 	plat_local_state_t target = states[core_pos];
204*91f16700Schasinglulu 	mce_cstate_info_t cstate_info = { 0 };
205*91f16700Schasinglulu 
206*91f16700Schasinglulu 	/* CPU suspend */
207*91f16700Schasinglulu 	if (target == PSTATE_ID_CORE_POWERDN) {
208*91f16700Schasinglulu 		/* Program default wake mask */
209*91f16700Schasinglulu 		cstate_info.wake_mask = TEGRA186_CORE_WAKE_MASK;
210*91f16700Schasinglulu 		cstate_info.update_wake_mask = 1;
211*91f16700Schasinglulu 		mce_update_cstate_info(&cstate_info);
212*91f16700Schasinglulu 
213*91f16700Schasinglulu 		/* Check if CCx state is allowed. */
214*91f16700Schasinglulu 		ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED,
215*91f16700Schasinglulu 				(uint64_t)TEGRA_ARI_CORE_C7,
216*91f16700Schasinglulu 				tegra_percpu_data[cpu].wake_time,
217*91f16700Schasinglulu 				0U);
218*91f16700Schasinglulu 		if (ret == 0) {
219*91f16700Schasinglulu 			target = PSCI_LOCAL_STATE_RUN;
220*91f16700Schasinglulu 		}
221*91f16700Schasinglulu 	}
222*91f16700Schasinglulu 
223*91f16700Schasinglulu 	/* CPU off */
224*91f16700Schasinglulu 	if (target == PLAT_MAX_OFF_STATE) {
225*91f16700Schasinglulu 		/* Enable cluster powerdn from last CPU in the cluster */
226*91f16700Schasinglulu 		if (tegra_last_cpu_in_cluster(states, ncpu)) {
227*91f16700Schasinglulu 			/* Enable CC7 state and turn off wake mask */
228*91f16700Schasinglulu 			cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
229*91f16700Schasinglulu 			cstate_info.update_wake_mask = 1;
230*91f16700Schasinglulu 			mce_update_cstate_info(&cstate_info);
231*91f16700Schasinglulu 
232*91f16700Schasinglulu 			/* Check if CCx state is allowed. */
233*91f16700Schasinglulu 			ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED,
234*91f16700Schasinglulu 						  (uint64_t)TEGRA_ARI_CORE_C7,
235*91f16700Schasinglulu 						  MCE_CORE_SLEEP_TIME_INFINITE,
236*91f16700Schasinglulu 						  0U);
237*91f16700Schasinglulu 			if (ret == 0) {
238*91f16700Schasinglulu 				target = PSCI_LOCAL_STATE_RUN;
239*91f16700Schasinglulu 			}
240*91f16700Schasinglulu 
241*91f16700Schasinglulu 		} else {
242*91f16700Schasinglulu 
243*91f16700Schasinglulu 			/* Turn off wake_mask */
244*91f16700Schasinglulu 			cstate_info.update_wake_mask = 1;
245*91f16700Schasinglulu 			mce_update_cstate_info(&cstate_info);
246*91f16700Schasinglulu 			target = PSCI_LOCAL_STATE_RUN;
247*91f16700Schasinglulu 		}
248*91f16700Schasinglulu 	}
249*91f16700Schasinglulu 
250*91f16700Schasinglulu 	return target;
251*91f16700Schasinglulu }
252*91f16700Schasinglulu 
253*91f16700Schasinglulu /*******************************************************************************
254*91f16700Schasinglulu  * Platform handler to calculate the proper target power level at the
255*91f16700Schasinglulu  * specified affinity level
256*91f16700Schasinglulu  ******************************************************************************/
257*91f16700Schasinglulu plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl,
258*91f16700Schasinglulu 					     const plat_local_state_t *states,
259*91f16700Schasinglulu 					     uint32_t ncpu)
260*91f16700Schasinglulu {
261*91f16700Schasinglulu 	plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
262*91f16700Schasinglulu 	uint32_t cpu = plat_my_core_pos();
263*91f16700Schasinglulu 
264*91f16700Schasinglulu 	/* System Suspend */
265*91f16700Schasinglulu 	if ((lvl == (uint32_t)MPIDR_AFFLVL2) &&
266*91f16700Schasinglulu 	    (states[cpu] == PSTATE_ID_SOC_POWERDN)) {
267*91f16700Schasinglulu 		target = PSTATE_ID_SOC_POWERDN;
268*91f16700Schasinglulu 	}
269*91f16700Schasinglulu 
270*91f16700Schasinglulu 	/* CPU off, CPU suspend */
271*91f16700Schasinglulu 	if (lvl == (uint32_t)MPIDR_AFFLVL1) {
272*91f16700Schasinglulu 		target = tegra_get_afflvl1_pwr_state(states, ncpu);
273*91f16700Schasinglulu 	}
274*91f16700Schasinglulu 
275*91f16700Schasinglulu 	/* target cluster/system state */
276*91f16700Schasinglulu 	return target;
277*91f16700Schasinglulu }
278*91f16700Schasinglulu 
279*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
280*91f16700Schasinglulu {
281*91f16700Schasinglulu 	const plat_local_state_t *pwr_domain_state =
282*91f16700Schasinglulu 		target_state->pwr_domain_state;
283*91f16700Schasinglulu 	const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
284*91f16700Schasinglulu 	uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
285*91f16700Schasinglulu 		TEGRA186_STATE_ID_MASK;
286*91f16700Schasinglulu 	uint64_t val;
287*91f16700Schasinglulu 	uint64_t src_len_in_bytes = (uint64_t)(((uintptr_t)(&__BL31_END__) -
288*91f16700Schasinglulu 					(uintptr_t)BL31_BASE));
289*91f16700Schasinglulu 	int32_t ret;
290*91f16700Schasinglulu 
291*91f16700Schasinglulu 	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
292*91f16700Schasinglulu 		val = params_from_bl2->tzdram_base +
293*91f16700Schasinglulu 			tegra186_get_mc_ctx_size();
294*91f16700Schasinglulu 
295*91f16700Schasinglulu 		/* Initialise communication channel with BPMP */
296*91f16700Schasinglulu 		assert(tegra_bpmp_ipc_init() == 0);
297*91f16700Schasinglulu 
298*91f16700Schasinglulu 		/* Enable SE clock */
299*91f16700Schasinglulu 		ret = tegra_bpmp_ipc_enable_clock(TEGRA186_CLK_SE);
300*91f16700Schasinglulu 		if (ret != 0) {
301*91f16700Schasinglulu 			ERROR("Failed to enable clock\n");
302*91f16700Schasinglulu 			return ret;
303*91f16700Schasinglulu 		}
304*91f16700Schasinglulu 
305*91f16700Schasinglulu 		/*
306*91f16700Schasinglulu 		 * Generate/save SHA256 of ATF during SC7 entry
307*91f16700Schasinglulu 		 */
308*91f16700Schasinglulu 		if (tegra_se_save_sha256_hash(BL31_BASE,
309*91f16700Schasinglulu 					(uint32_t)src_len_in_bytes) != 0) {
310*91f16700Schasinglulu 			ERROR("Hash calculation failed. Reboot\n");
311*91f16700Schasinglulu 			(void)tegra_soc_prepare_system_reset();
312*91f16700Schasinglulu 		}
313*91f16700Schasinglulu 
314*91f16700Schasinglulu 		/*
315*91f16700Schasinglulu 		 * The TZRAM loses power when we enter system suspend. To
316*91f16700Schasinglulu 		 * allow graceful exit from system suspend, we need to copy
317*91f16700Schasinglulu 		 * BL3-1 over to TZDRAM.
318*91f16700Schasinglulu 		 */
319*91f16700Schasinglulu 		val = params_from_bl2->tzdram_base +
320*91f16700Schasinglulu 			tegra186_get_mc_ctx_size();
321*91f16700Schasinglulu 		memcpy16((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
322*91f16700Schasinglulu 			 (uintptr_t)BL31_END - (uintptr_t)BL31_BASE);
323*91f16700Schasinglulu 
324*91f16700Schasinglulu 		/*
325*91f16700Schasinglulu 		 * Save code base and size; this would be used by SC7-RF to
326*91f16700Schasinglulu 		 * verify binary
327*91f16700Schasinglulu 		 */
328*91f16700Schasinglulu 		mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV68_LO,
329*91f16700Schasinglulu 				(uint32_t)val);
330*91f16700Schasinglulu 		mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV0_HI,
331*91f16700Schasinglulu 				(uint32_t)src_len_in_bytes);
332*91f16700Schasinglulu 
333*91f16700Schasinglulu 		ret = tegra_bpmp_ipc_disable_clock(TEGRA186_CLK_SE);
334*91f16700Schasinglulu 		if (ret != 0) {
335*91f16700Schasinglulu 			ERROR("Failed to disable clock\n");
336*91f16700Schasinglulu 			return ret;
337*91f16700Schasinglulu 		}
338*91f16700Schasinglulu 	}
339*91f16700Schasinglulu 
340*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
341*91f16700Schasinglulu }
342*91f16700Schasinglulu 
343*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
344*91f16700Schasinglulu {
345*91f16700Schasinglulu 	return PSCI_E_NOT_SUPPORTED;
346*91f16700Schasinglulu }
347*91f16700Schasinglulu 
348*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_on(u_register_t mpidr)
349*91f16700Schasinglulu {
350*91f16700Schasinglulu 	int32_t ret = PSCI_E_SUCCESS;
351*91f16700Schasinglulu 	uint64_t target_cpu = mpidr & MPIDR_CPU_MASK;
352*91f16700Schasinglulu 	uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
353*91f16700Schasinglulu 			MPIDR_AFFINITY_BITS;
354*91f16700Schasinglulu 
355*91f16700Schasinglulu 	if (target_cluster > ((uint32_t)PLATFORM_CLUSTER_COUNT - 1U)) {
356*91f16700Schasinglulu 
357*91f16700Schasinglulu 		ERROR("%s: unsupported CPU (0x%lx)\n", __func__, mpidr);
358*91f16700Schasinglulu 		ret = PSCI_E_NOT_PRESENT;
359*91f16700Schasinglulu 
360*91f16700Schasinglulu 	} else {
361*91f16700Schasinglulu 		/* construct the target CPU # */
362*91f16700Schasinglulu 		target_cpu |= (target_cluster << 2);
363*91f16700Schasinglulu 
364*91f16700Schasinglulu 		(void)mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U);
365*91f16700Schasinglulu 	}
366*91f16700Schasinglulu 
367*91f16700Schasinglulu 	return ret;
368*91f16700Schasinglulu }
369*91f16700Schasinglulu 
370*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
371*91f16700Schasinglulu {
372*91f16700Schasinglulu 	uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
373*91f16700Schasinglulu 	uint8_t stateid_afflvl0 = target_state->pwr_domain_state[MPIDR_AFFLVL0];
374*91f16700Schasinglulu 	mce_cstate_info_t cstate_info = { 0 };
375*91f16700Schasinglulu 	uint64_t impl, val;
376*91f16700Schasinglulu 	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
377*91f16700Schasinglulu 
378*91f16700Schasinglulu 	impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
379*91f16700Schasinglulu 
380*91f16700Schasinglulu 	/*
381*91f16700Schasinglulu 	 * Enable ECC and Parity Protection for Cortex-A57 CPUs (Tegra186
382*91f16700Schasinglulu 	 * A02p and beyond).
383*91f16700Schasinglulu 	 */
384*91f16700Schasinglulu 	if ((plat_params->l2_ecc_parity_prot_dis != 1) && (impl != DENVER_IMPL)) {
385*91f16700Schasinglulu 
386*91f16700Schasinglulu 		val = read_l2ctlr_el1();
387*91f16700Schasinglulu 		val |= CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
388*91f16700Schasinglulu 		write_l2ctlr_el1(val);
389*91f16700Schasinglulu 	}
390*91f16700Schasinglulu 
391*91f16700Schasinglulu 	/*
392*91f16700Schasinglulu 	 * Reset power state info for CPUs when onlining, we set
393*91f16700Schasinglulu 	 * deepest power when offlining a core but that may not be
394*91f16700Schasinglulu 	 * requested by non-secure sw which controls idle states. It
395*91f16700Schasinglulu 	 * will re-init this info from non-secure software when the
396*91f16700Schasinglulu 	 * core come online.
397*91f16700Schasinglulu 	 */
398*91f16700Schasinglulu 	if (stateid_afflvl0 == PLAT_MAX_OFF_STATE) {
399*91f16700Schasinglulu 
400*91f16700Schasinglulu 		cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC1;
401*91f16700Schasinglulu 		cstate_info.update_wake_mask = 1;
402*91f16700Schasinglulu 		mce_update_cstate_info(&cstate_info);
403*91f16700Schasinglulu 	}
404*91f16700Schasinglulu 
405*91f16700Schasinglulu 	/*
406*91f16700Schasinglulu 	 * Check if we are exiting from deep sleep and restore SE
407*91f16700Schasinglulu 	 * context if we are.
408*91f16700Schasinglulu 	 */
409*91f16700Schasinglulu 	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
410*91f16700Schasinglulu 
411*91f16700Schasinglulu 		mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT,
412*91f16700Schasinglulu 			se_regs[0]);
413*91f16700Schasinglulu 		mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT,
414*91f16700Schasinglulu 			se_regs[1]);
415*91f16700Schasinglulu 		mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT,
416*91f16700Schasinglulu 			se_regs[2]);
417*91f16700Schasinglulu 
418*91f16700Schasinglulu 		/* Init SMMU */
419*91f16700Schasinglulu 		tegra_smmu_init();
420*91f16700Schasinglulu 
421*91f16700Schasinglulu 		/*
422*91f16700Schasinglulu 		 * Reset power state info for the last core doing SC7
423*91f16700Schasinglulu 		 * entry and exit, we set deepest power state as CC7
424*91f16700Schasinglulu 		 * and SC7 for SC7 entry which may not be requested by
425*91f16700Schasinglulu 		 * non-secure SW which controls idle states.
426*91f16700Schasinglulu 		 */
427*91f16700Schasinglulu 		cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
428*91f16700Schasinglulu 		cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC1;
429*91f16700Schasinglulu 		cstate_info.update_wake_mask = 1;
430*91f16700Schasinglulu 		mce_update_cstate_info(&cstate_info);
431*91f16700Schasinglulu 	}
432*91f16700Schasinglulu 
433*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
434*91f16700Schasinglulu }
435*91f16700Schasinglulu 
436*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_off_early(const psci_power_state_t *target_state)
437*91f16700Schasinglulu {
438*91f16700Schasinglulu 	/* Do not power off the boot CPU */
439*91f16700Schasinglulu 	if (plat_is_my_cpu_primary()) {
440*91f16700Schasinglulu 		return PSCI_E_DENIED;
441*91f16700Schasinglulu 	}
442*91f16700Schasinglulu 
443*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
444*91f16700Schasinglulu }
445*91f16700Schasinglulu 
446*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
447*91f16700Schasinglulu {
448*91f16700Schasinglulu 	uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & (uint64_t)MIDR_IMPL_MASK;
449*91f16700Schasinglulu 
450*91f16700Schasinglulu 	(void)target_state;
451*91f16700Schasinglulu 
452*91f16700Schasinglulu 	/* Disable Denver's DCO operations */
453*91f16700Schasinglulu 	if (impl == DENVER_IMPL) {
454*91f16700Schasinglulu 		denver_disable_dco();
455*91f16700Schasinglulu 	}
456*91f16700Schasinglulu 
457*91f16700Schasinglulu 	/* Turn off CPU */
458*91f16700Schasinglulu 	(void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
459*91f16700Schasinglulu 			(uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
460*91f16700Schasinglulu 
461*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
462*91f16700Schasinglulu }
463*91f16700Schasinglulu 
464*91f16700Schasinglulu __dead2 void tegra_soc_prepare_system_off(void)
465*91f16700Schasinglulu {
466*91f16700Schasinglulu 	/* power off the entire system */
467*91f16700Schasinglulu 	mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF);
468*91f16700Schasinglulu 
469*91f16700Schasinglulu 	wfi();
470*91f16700Schasinglulu 
471*91f16700Schasinglulu 	/* wait for the system to power down */
472*91f16700Schasinglulu 	for (;;) {
473*91f16700Schasinglulu 		;
474*91f16700Schasinglulu 	}
475*91f16700Schasinglulu }
476*91f16700Schasinglulu 
477*91f16700Schasinglulu int32_t tegra_soc_prepare_system_reset(void)
478*91f16700Schasinglulu {
479*91f16700Schasinglulu 	mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT);
480*91f16700Schasinglulu 
481*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
482*91f16700Schasinglulu }
483