xref: /arm-trusted-firmware/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <arch.h>
8*91f16700Schasinglulu #include <assert.h>
9*91f16700Schasinglulu #include <stdbool.h>
10*91f16700Schasinglulu #include <string.h>
11*91f16700Schasinglulu 
12*91f16700Schasinglulu #include <arch_helpers.h>
13*91f16700Schasinglulu #include <bpmp_ipc.h>
14*91f16700Schasinglulu #include <common/bl_common.h>
15*91f16700Schasinglulu #include <common/debug.h>
16*91f16700Schasinglulu #include <context.h>
17*91f16700Schasinglulu #include <drivers/delay_timer.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 <mce.h>
22*91f16700Schasinglulu #include <mce_private.h>
23*91f16700Schasinglulu #include <memctrl_v2.h>
24*91f16700Schasinglulu #include <plat/common/platform.h>
25*91f16700Schasinglulu #include <se.h>
26*91f16700Schasinglulu #include <smmu.h>
27*91f16700Schasinglulu #include <t194_nvg.h>
28*91f16700Schasinglulu #include <tegra194_private.h>
29*91f16700Schasinglulu #include <tegra_platform.h>
30*91f16700Schasinglulu #include <tegra_private.h>
31*91f16700Schasinglulu 
32*91f16700Schasinglulu extern uint32_t __tegra194_cpu_reset_handler_data,
33*91f16700Schasinglulu 		__tegra194_cpu_reset_handler_end;
34*91f16700Schasinglulu 
35*91f16700Schasinglulu /* TZDRAM offset for saving SMMU context */
36*91f16700Schasinglulu #define TEGRA194_SMMU_CTX_OFFSET	16U
37*91f16700Schasinglulu 
38*91f16700Schasinglulu /* state id mask */
39*91f16700Schasinglulu #define TEGRA194_STATE_ID_MASK		0xFU
40*91f16700Schasinglulu /* constants to get power state's wake time */
41*91f16700Schasinglulu #define TEGRA194_WAKE_TIME_MASK		0x0FFFFFF0U
42*91f16700Schasinglulu #define TEGRA194_WAKE_TIME_SHIFT	4U
43*91f16700Schasinglulu /* default core wake mask for CPU_SUSPEND */
44*91f16700Schasinglulu #define TEGRA194_CORE_WAKE_MASK		0x180cU
45*91f16700Schasinglulu 
46*91f16700Schasinglulu static struct t19x_psci_percpu_data {
47*91f16700Schasinglulu 	uint32_t wake_time;
48*91f16700Schasinglulu } __aligned(CACHE_WRITEBACK_GRANULE) t19x_percpu_data[PLATFORM_CORE_COUNT];
49*91f16700Schasinglulu 
50*91f16700Schasinglulu int32_t tegra_soc_validate_power_state(uint32_t power_state,
51*91f16700Schasinglulu 					psci_power_state_t *req_state)
52*91f16700Schasinglulu {
53*91f16700Schasinglulu 	uint8_t state_id = (uint8_t)psci_get_pstate_id(power_state) &
54*91f16700Schasinglulu 			   TEGRA194_STATE_ID_MASK;
55*91f16700Schasinglulu 	uint32_t cpu = plat_my_core_pos();
56*91f16700Schasinglulu 	int32_t ret = PSCI_E_SUCCESS;
57*91f16700Schasinglulu 
58*91f16700Schasinglulu 	/* save the core wake time (in TSC ticks)*/
59*91f16700Schasinglulu 	t19x_percpu_data[cpu].wake_time = (power_state & TEGRA194_WAKE_TIME_MASK)
60*91f16700Schasinglulu 			<< TEGRA194_WAKE_TIME_SHIFT;
61*91f16700Schasinglulu 
62*91f16700Schasinglulu 	/*
63*91f16700Schasinglulu 	 * Clean t19x_percpu_data[cpu] to DRAM. This needs to be done to ensure
64*91f16700Schasinglulu 	 * that the correct value is read in tegra_soc_pwr_domain_suspend(),
65*91f16700Schasinglulu 	 * which is called with caches disabled. It is possible to read a stale
66*91f16700Schasinglulu 	 * value from DRAM in that function, because the L2 cache is not flushed
67*91f16700Schasinglulu 	 * unless the cluster is entering CC6/CC7.
68*91f16700Schasinglulu 	 */
69*91f16700Schasinglulu 	clean_dcache_range((uint64_t)&t19x_percpu_data[cpu],
70*91f16700Schasinglulu 			sizeof(t19x_percpu_data[cpu]));
71*91f16700Schasinglulu 
72*91f16700Schasinglulu 	/* Sanity check the requested state id */
73*91f16700Schasinglulu 	switch (state_id) {
74*91f16700Schasinglulu 	case PSTATE_ID_CORE_IDLE:
75*91f16700Schasinglulu 
76*91f16700Schasinglulu 		if (psci_get_pstate_type(power_state) != PSTATE_TYPE_STANDBY) {
77*91f16700Schasinglulu 			ret = PSCI_E_INVALID_PARAMS;
78*91f16700Schasinglulu 			break;
79*91f16700Schasinglulu 		}
80*91f16700Schasinglulu 
81*91f16700Schasinglulu 		/* Core idle request */
82*91f16700Schasinglulu 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
83*91f16700Schasinglulu 		req_state->pwr_domain_state[MPIDR_AFFLVL1] = PSCI_LOCAL_STATE_RUN;
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 	uint32_t cpu = plat_my_core_pos();
98*91f16700Schasinglulu 	mce_cstate_info_t cstate_info = { 0 };
99*91f16700Schasinglulu 
100*91f16700Schasinglulu 	/* Program default wake mask */
101*91f16700Schasinglulu 	cstate_info.wake_mask = TEGRA194_CORE_WAKE_MASK;
102*91f16700Schasinglulu 	cstate_info.update_wake_mask = 1;
103*91f16700Schasinglulu 	mce_update_cstate_info(&cstate_info);
104*91f16700Schasinglulu 
105*91f16700Schasinglulu 	/* Enter CPU idle */
106*91f16700Schasinglulu 	(void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
107*91f16700Schasinglulu 				  (uint64_t)TEGRA_NVG_CORE_C6,
108*91f16700Schasinglulu 				  t19x_percpu_data[cpu].wake_time,
109*91f16700Schasinglulu 				  0U);
110*91f16700Schasinglulu 
111*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
112*91f16700Schasinglulu }
113*91f16700Schasinglulu 
114*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
115*91f16700Schasinglulu {
116*91f16700Schasinglulu 	const plat_local_state_t *pwr_domain_state;
117*91f16700Schasinglulu 	uint8_t stateid_afflvl2;
118*91f16700Schasinglulu 	plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
119*91f16700Schasinglulu 	uint64_t mc_ctx_base;
120*91f16700Schasinglulu 	uint32_t val;
121*91f16700Schasinglulu 	mce_cstate_info_t sc7_cstate_info = {
122*91f16700Schasinglulu 		.cluster = (uint32_t)TEGRA_NVG_CLUSTER_CC6,
123*91f16700Schasinglulu 		.ccplex = (uint32_t)TEGRA_NVG_CG_CG7,
124*91f16700Schasinglulu 		.system = (uint32_t)TEGRA_NVG_SYSTEM_SC7,
125*91f16700Schasinglulu 		.system_state_force = 1U,
126*91f16700Schasinglulu 		.update_wake_mask = 1U,
127*91f16700Schasinglulu 	};
128*91f16700Schasinglulu 	int32_t ret = 0;
129*91f16700Schasinglulu 
130*91f16700Schasinglulu 	/* get the state ID */
131*91f16700Schasinglulu 	pwr_domain_state = target_state->pwr_domain_state;
132*91f16700Schasinglulu 	stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
133*91f16700Schasinglulu 		TEGRA194_STATE_ID_MASK;
134*91f16700Schasinglulu 
135*91f16700Schasinglulu 	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
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 */
142*91f16700Schasinglulu 		mc_ctx_base = params_from_bl2->tzdram_base +
143*91f16700Schasinglulu 				tegra194_get_mc_ctx_offset();
144*91f16700Schasinglulu 		tegra_mc_save_context((uintptr_t)mc_ctx_base);
145*91f16700Schasinglulu 
146*91f16700Schasinglulu 		/*
147*91f16700Schasinglulu 		 * Suspend SE, RNG1 and PKA1 only on silcon and fpga,
148*91f16700Schasinglulu 		 * since VDK does not support atomic se ctx save
149*91f16700Schasinglulu 		 */
150*91f16700Schasinglulu 		if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
151*91f16700Schasinglulu 			ret = tegra_se_suspend();
152*91f16700Schasinglulu 			assert(ret == 0);
153*91f16700Schasinglulu 		}
154*91f16700Schasinglulu 
155*91f16700Schasinglulu 		/* Prepare for system suspend */
156*91f16700Schasinglulu 		mce_update_cstate_info(&sc7_cstate_info);
157*91f16700Schasinglulu 
158*91f16700Schasinglulu 		do {
159*91f16700Schasinglulu 			val = (uint32_t)mce_command_handler(
160*91f16700Schasinglulu 					(uint32_t)MCE_CMD_IS_SC7_ALLOWED,
161*91f16700Schasinglulu 					(uint32_t)TEGRA_NVG_CORE_C7,
162*91f16700Schasinglulu 					MCE_CORE_SLEEP_TIME_INFINITE,
163*91f16700Schasinglulu 					0U);
164*91f16700Schasinglulu 		} while (val == 0U);
165*91f16700Schasinglulu 
166*91f16700Schasinglulu 		/* Instruct the MCE to enter system suspend state */
167*91f16700Schasinglulu 		ret = mce_command_handler(
168*91f16700Schasinglulu 				(uint64_t)MCE_CMD_ENTER_CSTATE,
169*91f16700Schasinglulu 				(uint64_t)TEGRA_NVG_CORE_C7,
170*91f16700Schasinglulu 				MCE_CORE_SLEEP_TIME_INFINITE,
171*91f16700Schasinglulu 				0U);
172*91f16700Schasinglulu 		assert(ret == 0);
173*91f16700Schasinglulu 
174*91f16700Schasinglulu 		/* set system suspend state for house-keeping */
175*91f16700Schasinglulu 		tegra194_set_system_suspend_entry();
176*91f16700Schasinglulu 	}
177*91f16700Schasinglulu 
178*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
179*91f16700Schasinglulu }
180*91f16700Schasinglulu 
181*91f16700Schasinglulu /*******************************************************************************
182*91f16700Schasinglulu  * Helper function to check if this is the last ON CPU in the cluster
183*91f16700Schasinglulu  ******************************************************************************/
184*91f16700Schasinglulu static bool tegra_last_on_cpu_in_cluster(const plat_local_state_t *states,
185*91f16700Schasinglulu 			uint32_t ncpu)
186*91f16700Schasinglulu {
187*91f16700Schasinglulu 	plat_local_state_t target;
188*91f16700Schasinglulu 	bool last_on_cpu = true;
189*91f16700Schasinglulu 	uint32_t num_cpus = ncpu, pos = 0;
190*91f16700Schasinglulu 
191*91f16700Schasinglulu 	do {
192*91f16700Schasinglulu 		target = states[pos];
193*91f16700Schasinglulu 		if (target != PLAT_MAX_OFF_STATE) {
194*91f16700Schasinglulu 			last_on_cpu = false;
195*91f16700Schasinglulu 		}
196*91f16700Schasinglulu 		--num_cpus;
197*91f16700Schasinglulu 		pos++;
198*91f16700Schasinglulu 	} while (num_cpus != 0U);
199*91f16700Schasinglulu 
200*91f16700Schasinglulu 	return last_on_cpu;
201*91f16700Schasinglulu }
202*91f16700Schasinglulu 
203*91f16700Schasinglulu /*******************************************************************************
204*91f16700Schasinglulu  * Helper function to get target power state for the cluster
205*91f16700Schasinglulu  ******************************************************************************/
206*91f16700Schasinglulu static plat_local_state_t tegra_get_afflvl1_pwr_state(const plat_local_state_t *states,
207*91f16700Schasinglulu 			uint32_t ncpu)
208*91f16700Schasinglulu {
209*91f16700Schasinglulu 	uint32_t core_pos = (uint32_t)read_mpidr() & (uint32_t)MPIDR_CPU_MASK;
210*91f16700Schasinglulu 	plat_local_state_t target = states[core_pos];
211*91f16700Schasinglulu 	mce_cstate_info_t cstate_info = { 0 };
212*91f16700Schasinglulu 
213*91f16700Schasinglulu 	/* CPU off */
214*91f16700Schasinglulu 	if (target == PLAT_MAX_OFF_STATE) {
215*91f16700Schasinglulu 
216*91f16700Schasinglulu 		/* Enable cluster powerdn from last CPU in the cluster */
217*91f16700Schasinglulu 		if (tegra_last_on_cpu_in_cluster(states, ncpu)) {
218*91f16700Schasinglulu 
219*91f16700Schasinglulu 			/* Enable CC6 state and turn off wake mask */
220*91f16700Schasinglulu 			cstate_info.cluster = (uint32_t)TEGRA_NVG_CLUSTER_CC6;
221*91f16700Schasinglulu 			cstate_info.ccplex = (uint32_t)TEGRA_NVG_CG_CG7;
222*91f16700Schasinglulu 			cstate_info.system_state_force = 1;
223*91f16700Schasinglulu 			cstate_info.update_wake_mask = 1U;
224*91f16700Schasinglulu 			mce_update_cstate_info(&cstate_info);
225*91f16700Schasinglulu 
226*91f16700Schasinglulu 		} else {
227*91f16700Schasinglulu 
228*91f16700Schasinglulu 			/* Turn off wake_mask */
229*91f16700Schasinglulu 			cstate_info.update_wake_mask = 1U;
230*91f16700Schasinglulu 			mce_update_cstate_info(&cstate_info);
231*91f16700Schasinglulu 			target = PSCI_LOCAL_STATE_RUN;
232*91f16700Schasinglulu 		}
233*91f16700Schasinglulu 	}
234*91f16700Schasinglulu 
235*91f16700Schasinglulu 	return target;
236*91f16700Schasinglulu }
237*91f16700Schasinglulu 
238*91f16700Schasinglulu /*******************************************************************************
239*91f16700Schasinglulu  * Platform handler to calculate the proper target power level at the
240*91f16700Schasinglulu  * specified affinity level
241*91f16700Schasinglulu  ******************************************************************************/
242*91f16700Schasinglulu plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl,
243*91f16700Schasinglulu 					     const plat_local_state_t *states,
244*91f16700Schasinglulu 					     uint32_t ncpu)
245*91f16700Schasinglulu {
246*91f16700Schasinglulu 	plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
247*91f16700Schasinglulu 	uint32_t cpu = plat_my_core_pos();
248*91f16700Schasinglulu 
249*91f16700Schasinglulu 	/* System Suspend */
250*91f16700Schasinglulu 	if ((lvl == (uint32_t)MPIDR_AFFLVL2) && (states[cpu] == PSTATE_ID_SOC_POWERDN)) {
251*91f16700Schasinglulu 		target = PSTATE_ID_SOC_POWERDN;
252*91f16700Schasinglulu 	}
253*91f16700Schasinglulu 
254*91f16700Schasinglulu 	/* CPU off, CPU suspend */
255*91f16700Schasinglulu 	if (lvl == (uint32_t)MPIDR_AFFLVL1) {
256*91f16700Schasinglulu 		target = tegra_get_afflvl1_pwr_state(states, ncpu);
257*91f16700Schasinglulu 	}
258*91f16700Schasinglulu 
259*91f16700Schasinglulu 	/* target cluster/system state */
260*91f16700Schasinglulu 	return target;
261*91f16700Schasinglulu }
262*91f16700Schasinglulu 
263*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
264*91f16700Schasinglulu {
265*91f16700Schasinglulu 	const plat_local_state_t *pwr_domain_state =
266*91f16700Schasinglulu 		target_state->pwr_domain_state;
267*91f16700Schasinglulu 	plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
268*91f16700Schasinglulu 	uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
269*91f16700Schasinglulu 		TEGRA194_STATE_ID_MASK;
270*91f16700Schasinglulu 	uint64_t src_len_in_bytes = (uintptr_t)&__BL31_END__ - (uintptr_t)BL31_BASE;
271*91f16700Schasinglulu 	uint64_t val;
272*91f16700Schasinglulu 	int32_t ret = PSCI_E_SUCCESS;
273*91f16700Schasinglulu 
274*91f16700Schasinglulu 	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
275*91f16700Schasinglulu 		val = params_from_bl2->tzdram_base +
276*91f16700Schasinglulu 		      tegra194_get_cpu_reset_handler_size();
277*91f16700Schasinglulu 
278*91f16700Schasinglulu 		/* initialise communication channel with BPMP */
279*91f16700Schasinglulu 		ret = tegra_bpmp_ipc_init();
280*91f16700Schasinglulu 		assert(ret == 0);
281*91f16700Schasinglulu 
282*91f16700Schasinglulu 		/* Enable SE clock before SE context save */
283*91f16700Schasinglulu 		ret = tegra_bpmp_ipc_enable_clock(TEGRA194_CLK_SE);
284*91f16700Schasinglulu 		assert(ret == 0);
285*91f16700Schasinglulu 
286*91f16700Schasinglulu 		/*
287*91f16700Schasinglulu 		 * It is very unlikely that the BL31 image would be
288*91f16700Schasinglulu 		 * bigger than 2^32 bytes
289*91f16700Schasinglulu 		 */
290*91f16700Schasinglulu 		assert(src_len_in_bytes < UINT32_MAX);
291*91f16700Schasinglulu 
292*91f16700Schasinglulu 		if (tegra_se_calculate_save_sha256(BL31_BASE,
293*91f16700Schasinglulu 					(uint32_t)src_len_in_bytes) != 0) {
294*91f16700Schasinglulu 			ERROR("Hash calculation failed. Reboot\n");
295*91f16700Schasinglulu 			(void)tegra_soc_prepare_system_reset();
296*91f16700Schasinglulu 		}
297*91f16700Schasinglulu 
298*91f16700Schasinglulu 		/*
299*91f16700Schasinglulu 		 * The TZRAM loses power when we enter system suspend. To
300*91f16700Schasinglulu 		 * allow graceful exit from system suspend, we need to copy
301*91f16700Schasinglulu 		 * BL3-1 over to TZDRAM.
302*91f16700Schasinglulu 		 */
303*91f16700Schasinglulu 		val = params_from_bl2->tzdram_base +
304*91f16700Schasinglulu 		      tegra194_get_cpu_reset_handler_size();
305*91f16700Schasinglulu 		memcpy((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
306*91f16700Schasinglulu 		       src_len_in_bytes);
307*91f16700Schasinglulu 
308*91f16700Schasinglulu 		/* Disable SE clock after SE context save */
309*91f16700Schasinglulu 		ret = tegra_bpmp_ipc_disable_clock(TEGRA194_CLK_SE);
310*91f16700Schasinglulu 		assert(ret == 0);
311*91f16700Schasinglulu 	}
312*91f16700Schasinglulu 
313*91f16700Schasinglulu 	return ret;
314*91f16700Schasinglulu }
315*91f16700Schasinglulu 
316*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
317*91f16700Schasinglulu {
318*91f16700Schasinglulu 	return PSCI_E_NOT_SUPPORTED;
319*91f16700Schasinglulu }
320*91f16700Schasinglulu 
321*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_on(u_register_t mpidr)
322*91f16700Schasinglulu {
323*91f16700Schasinglulu 	uint64_t target_cpu = mpidr & MPIDR_CPU_MASK;
324*91f16700Schasinglulu 	uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
325*91f16700Schasinglulu 			MPIDR_AFFINITY_BITS;
326*91f16700Schasinglulu 	int32_t ret = 0;
327*91f16700Schasinglulu 
328*91f16700Schasinglulu 	if (target_cluster > ((uint32_t)PLATFORM_CLUSTER_COUNT - 1U)) {
329*91f16700Schasinglulu 		ERROR("%s: unsupported CPU (0x%lx)\n", __func__ , mpidr);
330*91f16700Schasinglulu 		return PSCI_E_NOT_PRESENT;
331*91f16700Schasinglulu 	}
332*91f16700Schasinglulu 
333*91f16700Schasinglulu 	/* construct the target CPU # */
334*91f16700Schasinglulu 	target_cpu += (target_cluster << 1U);
335*91f16700Schasinglulu 
336*91f16700Schasinglulu 	ret = mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U);
337*91f16700Schasinglulu 	if (ret < 0) {
338*91f16700Schasinglulu 		return PSCI_E_DENIED;
339*91f16700Schasinglulu 	}
340*91f16700Schasinglulu 
341*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
342*91f16700Schasinglulu }
343*91f16700Schasinglulu 
344*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
345*91f16700Schasinglulu {
346*91f16700Schasinglulu 	const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
347*91f16700Schasinglulu 	uint8_t enable_ccplex_lock_step = params_from_bl2->enable_ccplex_lock_step;
348*91f16700Schasinglulu 	uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
349*91f16700Schasinglulu 	cpu_context_t *ctx = cm_get_context(NON_SECURE);
350*91f16700Schasinglulu 	uint64_t actlr_elx;
351*91f16700Schasinglulu 
352*91f16700Schasinglulu 	/*
353*91f16700Schasinglulu 	 * Reset power state info for CPUs when onlining, we set
354*91f16700Schasinglulu 	 * deepest power when offlining a core but that may not be
355*91f16700Schasinglulu 	 * requested by non-secure sw which controls idle states. It
356*91f16700Schasinglulu 	 * will re-init this info from non-secure software when the
357*91f16700Schasinglulu 	 * core come online.
358*91f16700Schasinglulu 	 */
359*91f16700Schasinglulu 	actlr_elx = read_ctx_reg((get_el1_sysregs_ctx(ctx)), (CTX_ACTLR_EL1));
360*91f16700Schasinglulu 	actlr_elx &= ~DENVER_CPU_PMSTATE_MASK;
361*91f16700Schasinglulu 	actlr_elx |= DENVER_CPU_PMSTATE_C1;
362*91f16700Schasinglulu 	write_ctx_reg((get_el1_sysregs_ctx(ctx)), (CTX_ACTLR_EL1), (actlr_elx));
363*91f16700Schasinglulu 
364*91f16700Schasinglulu 	/*
365*91f16700Schasinglulu 	 * Check if we are exiting from deep sleep and restore SE
366*91f16700Schasinglulu 	 * context if we are.
367*91f16700Schasinglulu 	 */
368*91f16700Schasinglulu 	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
369*91f16700Schasinglulu 
370*91f16700Schasinglulu #if ENABLE_STRICT_CHECKING_MODE
371*91f16700Schasinglulu 		/*
372*91f16700Schasinglulu 		 * Enable strict checking after programming the GSC for
373*91f16700Schasinglulu 		 * enabling TZSRAM and TZDRAM
374*91f16700Schasinglulu 		 */
375*91f16700Schasinglulu 		mce_enable_strict_checking();
376*91f16700Schasinglulu #endif
377*91f16700Schasinglulu 
378*91f16700Schasinglulu 		/* Init SMMU */
379*91f16700Schasinglulu 		tegra_smmu_init();
380*91f16700Schasinglulu 
381*91f16700Schasinglulu 		/* Resume SE, RNG1 and PKA1 */
382*91f16700Schasinglulu 		tegra_se_resume();
383*91f16700Schasinglulu 
384*91f16700Schasinglulu 		/*
385*91f16700Schasinglulu 		 * Program XUSB STREAMIDs
386*91f16700Schasinglulu 		 * ======================
387*91f16700Schasinglulu 		 * T19x XUSB has support for XUSB virtualization. It will
388*91f16700Schasinglulu 		 * have one physical function (PF) and four Virtual functions
389*91f16700Schasinglulu 		 * (VF)
390*91f16700Schasinglulu 		 *
391*91f16700Schasinglulu 		 * There were below two SIDs for XUSB until T186.
392*91f16700Schasinglulu 		 * 1) #define TEGRA_SID_XUSB_HOST    0x1bU
393*91f16700Schasinglulu 		 * 2) #define TEGRA_SID_XUSB_DEV    0x1cU
394*91f16700Schasinglulu 		 *
395*91f16700Schasinglulu 		 * We have below four new SIDs added for VF(s)
396*91f16700Schasinglulu 		 * 3) #define TEGRA_SID_XUSB_VF0    0x5dU
397*91f16700Schasinglulu 		 * 4) #define TEGRA_SID_XUSB_VF1    0x5eU
398*91f16700Schasinglulu 		 * 5) #define TEGRA_SID_XUSB_VF2    0x5fU
399*91f16700Schasinglulu 		 * 6) #define TEGRA_SID_XUSB_VF3    0x60U
400*91f16700Schasinglulu 		 *
401*91f16700Schasinglulu 		 * When virtualization is enabled then we have to disable SID
402*91f16700Schasinglulu 		 * override and program above SIDs in below newly added SID
403*91f16700Schasinglulu 		 * registers in XUSB PADCTL MMIO space. These registers are
404*91f16700Schasinglulu 		 * TZ protected and so need to be done in ATF.
405*91f16700Schasinglulu 		 *
406*91f16700Schasinglulu 		 * a) #define XUSB_PADCTL_HOST_AXI_STREAMID_PF_0 (0x136cU)
407*91f16700Schasinglulu 		 * b) #define XUSB_PADCTL_DEV_AXI_STREAMID_PF_0  (0x139cU)
408*91f16700Schasinglulu 		 * c) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_0 (0x1370U)
409*91f16700Schasinglulu 		 * d) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_1 (0x1374U)
410*91f16700Schasinglulu 		 * e) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_2 (0x1378U)
411*91f16700Schasinglulu 		 * f) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_3 (0x137cU)
412*91f16700Schasinglulu 		 *
413*91f16700Schasinglulu 		 * This change disables SID override and programs XUSB SIDs
414*91f16700Schasinglulu 		 * in above registers to support both virtualization and
415*91f16700Schasinglulu 		 * non-virtualization platforms
416*91f16700Schasinglulu 		 */
417*91f16700Schasinglulu 		if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
418*91f16700Schasinglulu 
419*91f16700Schasinglulu 			mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
420*91f16700Schasinglulu 				XUSB_PADCTL_HOST_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_HOST);
421*91f16700Schasinglulu 			assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
422*91f16700Schasinglulu 				XUSB_PADCTL_HOST_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_HOST);
423*91f16700Schasinglulu 			mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
424*91f16700Schasinglulu 				XUSB_PADCTL_HOST_AXI_STREAMID_VF_0, TEGRA_SID_XUSB_VF0);
425*91f16700Schasinglulu 			assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
426*91f16700Schasinglulu 				XUSB_PADCTL_HOST_AXI_STREAMID_VF_0) == TEGRA_SID_XUSB_VF0);
427*91f16700Schasinglulu 			mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
428*91f16700Schasinglulu 				XUSB_PADCTL_HOST_AXI_STREAMID_VF_1, TEGRA_SID_XUSB_VF1);
429*91f16700Schasinglulu 			assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
430*91f16700Schasinglulu 				XUSB_PADCTL_HOST_AXI_STREAMID_VF_1) == TEGRA_SID_XUSB_VF1);
431*91f16700Schasinglulu 			mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
432*91f16700Schasinglulu 				XUSB_PADCTL_HOST_AXI_STREAMID_VF_2, TEGRA_SID_XUSB_VF2);
433*91f16700Schasinglulu 			assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
434*91f16700Schasinglulu 				XUSB_PADCTL_HOST_AXI_STREAMID_VF_2) == TEGRA_SID_XUSB_VF2);
435*91f16700Schasinglulu 			mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
436*91f16700Schasinglulu 				XUSB_PADCTL_HOST_AXI_STREAMID_VF_3, TEGRA_SID_XUSB_VF3);
437*91f16700Schasinglulu 			assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
438*91f16700Schasinglulu 				XUSB_PADCTL_HOST_AXI_STREAMID_VF_3) == TEGRA_SID_XUSB_VF3);
439*91f16700Schasinglulu 			mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
440*91f16700Schasinglulu 				XUSB_PADCTL_DEV_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_DEV);
441*91f16700Schasinglulu 			assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
442*91f16700Schasinglulu 				XUSB_PADCTL_DEV_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_DEV);
443*91f16700Schasinglulu 		}
444*91f16700Schasinglulu 	}
445*91f16700Schasinglulu 
446*91f16700Schasinglulu 	/*
447*91f16700Schasinglulu 	 * Enable dual execution optimized translations for all ELx.
448*91f16700Schasinglulu 	 */
449*91f16700Schasinglulu 	if (enable_ccplex_lock_step != 0U) {
450*91f16700Schasinglulu 		actlr_elx = read_actlr_el3();
451*91f16700Schasinglulu 		actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL3;
452*91f16700Schasinglulu 		write_actlr_el3(actlr_elx);
453*91f16700Schasinglulu 
454*91f16700Schasinglulu 		actlr_elx = read_actlr_el2();
455*91f16700Schasinglulu 		actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL2;
456*91f16700Schasinglulu 		write_actlr_el2(actlr_elx);
457*91f16700Schasinglulu 
458*91f16700Schasinglulu 		actlr_elx = read_actlr_el1();
459*91f16700Schasinglulu 		actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL1;
460*91f16700Schasinglulu 		write_actlr_el1(actlr_elx);
461*91f16700Schasinglulu 	}
462*91f16700Schasinglulu 
463*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
464*91f16700Schasinglulu }
465*91f16700Schasinglulu 
466*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_off_early(const psci_power_state_t *target_state)
467*91f16700Schasinglulu {
468*91f16700Schasinglulu 	/* Do not power off the boot CPU */
469*91f16700Schasinglulu 	if (plat_is_my_cpu_primary()) {
470*91f16700Schasinglulu 		return PSCI_E_DENIED;
471*91f16700Schasinglulu 	}
472*91f16700Schasinglulu 
473*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
474*91f16700Schasinglulu }
475*91f16700Schasinglulu 
476*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
477*91f16700Schasinglulu {
478*91f16700Schasinglulu 	uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
479*91f16700Schasinglulu 	int32_t ret = 0;
480*91f16700Schasinglulu 
481*91f16700Schasinglulu 	(void)target_state;
482*91f16700Schasinglulu 
483*91f16700Schasinglulu 	/* Disable Denver's DCO operations */
484*91f16700Schasinglulu 	if (impl == DENVER_IMPL) {
485*91f16700Schasinglulu 		denver_disable_dco();
486*91f16700Schasinglulu 	}
487*91f16700Schasinglulu 
488*91f16700Schasinglulu 	/* Turn off CPU */
489*91f16700Schasinglulu 	ret = mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
490*91f16700Schasinglulu 			(uint64_t)TEGRA_NVG_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
491*91f16700Schasinglulu 	assert(ret == 0);
492*91f16700Schasinglulu 
493*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
494*91f16700Schasinglulu }
495*91f16700Schasinglulu 
496*91f16700Schasinglulu __dead2 void tegra_soc_prepare_system_off(void)
497*91f16700Schasinglulu {
498*91f16700Schasinglulu 	/* System power off */
499*91f16700Schasinglulu 	mce_system_shutdown();
500*91f16700Schasinglulu 
501*91f16700Schasinglulu 	wfi();
502*91f16700Schasinglulu 
503*91f16700Schasinglulu 	/* wait for the system to power down */
504*91f16700Schasinglulu 	for (;;) {
505*91f16700Schasinglulu 		;
506*91f16700Schasinglulu 	}
507*91f16700Schasinglulu }
508*91f16700Schasinglulu 
509*91f16700Schasinglulu int32_t tegra_soc_prepare_system_reset(void)
510*91f16700Schasinglulu {
511*91f16700Schasinglulu 	/* System reboot */
512*91f16700Schasinglulu 	mce_system_reboot();
513*91f16700Schasinglulu 
514*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
515*91f16700Schasinglulu }
516