xref: /arm-trusted-firmware/plat/nvidia/tegra/soc/t210/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 <cortex_a57.h>
10*91f16700Schasinglulu #include <arch_helpers.h>
11*91f16700Schasinglulu #include <common/debug.h>
12*91f16700Schasinglulu #include <drivers/delay_timer.h>
13*91f16700Schasinglulu #include <lib/mmio.h>
14*91f16700Schasinglulu #include <lib/psci/psci.h>
15*91f16700Schasinglulu #include <plat/common/platform.h>
16*91f16700Schasinglulu 
17*91f16700Schasinglulu #include <bpmp.h>
18*91f16700Schasinglulu #include <flowctrl.h>
19*91f16700Schasinglulu #include <lib/utils.h>
20*91f16700Schasinglulu #include <memctrl.h>
21*91f16700Schasinglulu #include <pmc.h>
22*91f16700Schasinglulu #include <platform_def.h>
23*91f16700Schasinglulu #include <security_engine.h>
24*91f16700Schasinglulu #include <tegra_def.h>
25*91f16700Schasinglulu #include <tegra_private.h>
26*91f16700Schasinglulu #include <tegra_platform.h>
27*91f16700Schasinglulu 
28*91f16700Schasinglulu /*
29*91f16700Schasinglulu  * Register used to clear CPU reset signals. Each CPU has two reset
30*91f16700Schasinglulu  * signals: CPU reset (3:0) and Core reset (19:16).
31*91f16700Schasinglulu  */
32*91f16700Schasinglulu #define CPU_CMPLX_RESET_CLR		0x454
33*91f16700Schasinglulu #define CPU_CORE_RESET_MASK		0x10001
34*91f16700Schasinglulu 
35*91f16700Schasinglulu /* Clock and Reset controller registers for system clock's settings */
36*91f16700Schasinglulu #define SCLK_RATE			0x30
37*91f16700Schasinglulu #define SCLK_BURST_POLICY		0x28
38*91f16700Schasinglulu #define SCLK_BURST_POLICY_DEFAULT	0x10000000
39*91f16700Schasinglulu 
40*91f16700Schasinglulu static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
41*91f16700Schasinglulu static bool tegra_bpmp_available = true;
42*91f16700Schasinglulu 
43*91f16700Schasinglulu int32_t tegra_soc_validate_power_state(unsigned int power_state,
44*91f16700Schasinglulu 					psci_power_state_t *req_state)
45*91f16700Schasinglulu {
46*91f16700Schasinglulu 	int state_id = psci_get_pstate_id(power_state);
47*91f16700Schasinglulu 	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
48*91f16700Schasinglulu 
49*91f16700Schasinglulu 	/* Sanity check the requested state id */
50*91f16700Schasinglulu 	switch (state_id) {
51*91f16700Schasinglulu 	case PSTATE_ID_CORE_POWERDN:
52*91f16700Schasinglulu 		/*
53*91f16700Schasinglulu 		 * Core powerdown request only for afflvl 0
54*91f16700Schasinglulu 		 */
55*91f16700Schasinglulu 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff;
56*91f16700Schasinglulu 
57*91f16700Schasinglulu 		break;
58*91f16700Schasinglulu 
59*91f16700Schasinglulu 	case PSTATE_ID_CLUSTER_IDLE:
60*91f16700Schasinglulu 
61*91f16700Schasinglulu 		/*
62*91f16700Schasinglulu 		 * Cluster idle request for afflvl 0
63*91f16700Schasinglulu 		 */
64*91f16700Schasinglulu 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PSTATE_ID_CORE_POWERDN;
65*91f16700Schasinglulu 		req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
66*91f16700Schasinglulu 		break;
67*91f16700Schasinglulu 
68*91f16700Schasinglulu 	case PSTATE_ID_SOC_POWERDN:
69*91f16700Schasinglulu 
70*91f16700Schasinglulu 		/*
71*91f16700Schasinglulu 		 * sc7entry-fw must be present in the system when the bpmp
72*91f16700Schasinglulu 		 * firmware is not present, for a successful System Suspend
73*91f16700Schasinglulu 		 * entry.
74*91f16700Schasinglulu 		 */
75*91f16700Schasinglulu 		if (!tegra_bpmp_init() && !plat_params->sc7entry_fw_base)
76*91f16700Schasinglulu 			return PSCI_E_NOT_SUPPORTED;
77*91f16700Schasinglulu 
78*91f16700Schasinglulu 		/*
79*91f16700Schasinglulu 		 * System powerdown request only for afflvl 2
80*91f16700Schasinglulu 		 */
81*91f16700Schasinglulu 		for (uint32_t i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
82*91f16700Schasinglulu 			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
83*91f16700Schasinglulu 
84*91f16700Schasinglulu 		req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
85*91f16700Schasinglulu 			PLAT_SYS_SUSPEND_STATE_ID;
86*91f16700Schasinglulu 
87*91f16700Schasinglulu 		break;
88*91f16700Schasinglulu 
89*91f16700Schasinglulu 	default:
90*91f16700Schasinglulu 		ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
91*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
92*91f16700Schasinglulu 	}
93*91f16700Schasinglulu 
94*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
95*91f16700Schasinglulu }
96*91f16700Schasinglulu 
97*91f16700Schasinglulu /*******************************************************************************
98*91f16700Schasinglulu  * Platform handler to calculate the proper target power level at the
99*91f16700Schasinglulu  * specified affinity level.
100*91f16700Schasinglulu  ******************************************************************************/
101*91f16700Schasinglulu plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl,
102*91f16700Schasinglulu 					     const plat_local_state_t *states,
103*91f16700Schasinglulu 					     unsigned int ncpu)
104*91f16700Schasinglulu {
105*91f16700Schasinglulu 	plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
106*91f16700Schasinglulu 	int cpu = plat_my_core_pos();
107*91f16700Schasinglulu 	int core_pos = read_mpidr() & MPIDR_CPU_MASK;
108*91f16700Schasinglulu 	uint32_t bpmp_reply, data[3], val;
109*91f16700Schasinglulu 	int ret;
110*91f16700Schasinglulu 
111*91f16700Schasinglulu 	/* get the power state at this level */
112*91f16700Schasinglulu 	if (lvl == MPIDR_AFFLVL1)
113*91f16700Schasinglulu 		target = *(states + core_pos);
114*91f16700Schasinglulu 	if (lvl == MPIDR_AFFLVL2)
115*91f16700Schasinglulu 		target = *(states + cpu);
116*91f16700Schasinglulu 
117*91f16700Schasinglulu 	if ((lvl == MPIDR_AFFLVL1) && (target == PSTATE_ID_CLUSTER_IDLE)) {
118*91f16700Schasinglulu 
119*91f16700Schasinglulu 		/* initialize the bpmp interface */
120*91f16700Schasinglulu 		ret = tegra_bpmp_init();
121*91f16700Schasinglulu 		if (ret != 0U) {
122*91f16700Schasinglulu 
123*91f16700Schasinglulu 			/*
124*91f16700Schasinglulu 			 * flag to indicate that BPMP firmware is not
125*91f16700Schasinglulu 			 * available and the CPU has to handle entry/exit
126*91f16700Schasinglulu 			 * for all power states
127*91f16700Schasinglulu 			 */
128*91f16700Schasinglulu 			tegra_bpmp_available = false;
129*91f16700Schasinglulu 
130*91f16700Schasinglulu 			/* Cluster idle not allowed */
131*91f16700Schasinglulu 			target = PSCI_LOCAL_STATE_RUN;
132*91f16700Schasinglulu 
133*91f16700Schasinglulu 			/*******************************************
134*91f16700Schasinglulu 			 * BPMP is not present, so handle CC6 entry
135*91f16700Schasinglulu 			 * from the CPU
136*91f16700Schasinglulu 			 ******************************************/
137*91f16700Schasinglulu 
138*91f16700Schasinglulu 			/* check if cluster idle state has been enabled */
139*91f16700Schasinglulu 			val = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL);
140*91f16700Schasinglulu 			if (val == ENABLE_CLOSED_LOOP) {
141*91f16700Schasinglulu 				/*
142*91f16700Schasinglulu 				 * Acquire the cluster idle lock to stop
143*91f16700Schasinglulu 				 * other CPUs from powering up.
144*91f16700Schasinglulu 				 */
145*91f16700Schasinglulu 				tegra_fc_ccplex_pgexit_lock();
146*91f16700Schasinglulu 
147*91f16700Schasinglulu 				/* Cluster idle only from the last standing CPU */
148*91f16700Schasinglulu 				if (tegra_pmc_is_last_on_cpu() && tegra_fc_is_ccx_allowed()) {
149*91f16700Schasinglulu 					/* Cluster idle allowed */
150*91f16700Schasinglulu 					target = PSTATE_ID_CLUSTER_IDLE;
151*91f16700Schasinglulu 				} else {
152*91f16700Schasinglulu 					/* release cluster idle lock */
153*91f16700Schasinglulu 					tegra_fc_ccplex_pgexit_unlock();
154*91f16700Schasinglulu 				}
155*91f16700Schasinglulu 			}
156*91f16700Schasinglulu 		} else {
157*91f16700Schasinglulu 
158*91f16700Schasinglulu 			/* Cluster power-down */
159*91f16700Schasinglulu 			data[0] = (uint32_t)cpu;
160*91f16700Schasinglulu 			data[1] = TEGRA_PM_CC6;
161*91f16700Schasinglulu 			data[2] = TEGRA_PM_SC1;
162*91f16700Schasinglulu 			ret = tegra_bpmp_send_receive_atomic(MRQ_DO_IDLE,
163*91f16700Schasinglulu 					(void *)&data, (int)sizeof(data),
164*91f16700Schasinglulu 					(void *)&bpmp_reply,
165*91f16700Schasinglulu 					(int)sizeof(bpmp_reply));
166*91f16700Schasinglulu 
167*91f16700Schasinglulu 			/* check if cluster power down is allowed */
168*91f16700Schasinglulu 			if ((ret != 0L) || (bpmp_reply != BPMP_CCx_ALLOWED)) {
169*91f16700Schasinglulu 
170*91f16700Schasinglulu 				/* Cluster power down not allowed */
171*91f16700Schasinglulu 				target = PSCI_LOCAL_STATE_RUN;
172*91f16700Schasinglulu 			}
173*91f16700Schasinglulu 		}
174*91f16700Schasinglulu 
175*91f16700Schasinglulu 	} else if (((lvl == MPIDR_AFFLVL2) || (lvl == MPIDR_AFFLVL1)) &&
176*91f16700Schasinglulu 	    (target == PSTATE_ID_SOC_POWERDN)) {
177*91f16700Schasinglulu 
178*91f16700Schasinglulu 		/* System Suspend */
179*91f16700Schasinglulu 		target = PSTATE_ID_SOC_POWERDN;
180*91f16700Schasinglulu 
181*91f16700Schasinglulu 	} else {
182*91f16700Schasinglulu 		; /* do nothing */
183*91f16700Schasinglulu 	}
184*91f16700Schasinglulu 
185*91f16700Schasinglulu 	return target;
186*91f16700Schasinglulu }
187*91f16700Schasinglulu 
188*91f16700Schasinglulu int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state)
189*91f16700Schasinglulu {
190*91f16700Schasinglulu 	(void)cpu_state;
191*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
192*91f16700Schasinglulu }
193*91f16700Schasinglulu 
194*91f16700Schasinglulu int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
195*91f16700Schasinglulu {
196*91f16700Schasinglulu 	u_register_t mpidr = read_mpidr();
197*91f16700Schasinglulu 	const plat_local_state_t *pwr_domain_state =
198*91f16700Schasinglulu 		target_state->pwr_domain_state;
199*91f16700Schasinglulu 	unsigned int stateid_afflvl2 = pwr_domain_state[MPIDR_AFFLVL2];
200*91f16700Schasinglulu 	unsigned int stateid_afflvl1 = pwr_domain_state[MPIDR_AFFLVL1];
201*91f16700Schasinglulu 	unsigned int stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0];
202*91f16700Schasinglulu 	uint32_t cfg;
203*91f16700Schasinglulu 	int ret = PSCI_E_SUCCESS;
204*91f16700Schasinglulu 	uint32_t val;
205*91f16700Schasinglulu 
206*91f16700Schasinglulu 	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
207*91f16700Schasinglulu 
208*91f16700Schasinglulu 		assert((stateid_afflvl0 == PLAT_MAX_OFF_STATE) ||
209*91f16700Schasinglulu 			(stateid_afflvl0 == PSTATE_ID_SOC_POWERDN));
210*91f16700Schasinglulu 		assert((stateid_afflvl1 == PLAT_MAX_OFF_STATE) ||
211*91f16700Schasinglulu 			(stateid_afflvl1 == PSTATE_ID_SOC_POWERDN));
212*91f16700Schasinglulu 
213*91f16700Schasinglulu 		/* Suspend se/se2 and pka1 for T210 B01 and se for T210 */
214*91f16700Schasinglulu 		if (tegra_se_suspend() != 0) {
215*91f16700Schasinglulu 			ret = PSCI_E_INTERN_FAIL;
216*91f16700Schasinglulu 		}
217*91f16700Schasinglulu 
218*91f16700Schasinglulu 	} else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) {
219*91f16700Schasinglulu 
220*91f16700Schasinglulu 		assert(stateid_afflvl0 == PSTATE_ID_CORE_POWERDN);
221*91f16700Schasinglulu 
222*91f16700Schasinglulu 		if (!tegra_bpmp_available) {
223*91f16700Schasinglulu 
224*91f16700Schasinglulu 			/*
225*91f16700Schasinglulu 			 * When disabled, DFLL loses its state. Enable
226*91f16700Schasinglulu 			 * open loop state for the DFLL as we dont want
227*91f16700Schasinglulu 			 * garbage values being written to the pmic
228*91f16700Schasinglulu 			 * when we enter cluster idle state.
229*91f16700Schasinglulu 			 */
230*91f16700Schasinglulu 			mmio_write_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL,
231*91f16700Schasinglulu 				      ENABLE_OPEN_LOOP);
232*91f16700Schasinglulu 
233*91f16700Schasinglulu 			/* Find if the platform uses OVR2/MAX77621 PMIC */
234*91f16700Schasinglulu 			cfg = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_OUTPUT_CFG);
235*91f16700Schasinglulu 			if (cfg & DFLL_OUTPUT_CFG_CLK_EN_BIT) {
236*91f16700Schasinglulu 				/* OVR2 */
237*91f16700Schasinglulu 
238*91f16700Schasinglulu 				/* PWM tristate */
239*91f16700Schasinglulu 				val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
240*91f16700Schasinglulu 				val |= PINMUX_PWM_TRISTATE;
241*91f16700Schasinglulu 				mmio_write_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM, val);
242*91f16700Schasinglulu 
243*91f16700Schasinglulu 				/*
244*91f16700Schasinglulu 				 * SCRATCH201[1] is being used to identify CPU
245*91f16700Schasinglulu 				 * PMIC in warmboot code.
246*91f16700Schasinglulu 				 * 0 : OVR2
247*91f16700Schasinglulu 				 * 1 : MAX77621
248*91f16700Schasinglulu 				 */
249*91f16700Schasinglulu 				tegra_pmc_write_32(PMC_SCRATCH201, 0x0);
250*91f16700Schasinglulu 			} else {
251*91f16700Schasinglulu 				/* MAX77621 */
252*91f16700Schasinglulu 				tegra_pmc_write_32(PMC_SCRATCH201, 0x2);
253*91f16700Schasinglulu 			}
254*91f16700Schasinglulu 		}
255*91f16700Schasinglulu 
256*91f16700Schasinglulu 		/* Prepare for cluster idle */
257*91f16700Schasinglulu 		tegra_fc_cluster_idle(mpidr);
258*91f16700Schasinglulu 
259*91f16700Schasinglulu 	} else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {
260*91f16700Schasinglulu 
261*91f16700Schasinglulu 		/* Prepare for cpu powerdn */
262*91f16700Schasinglulu 		tegra_fc_cpu_powerdn(mpidr);
263*91f16700Schasinglulu 
264*91f16700Schasinglulu 	} else {
265*91f16700Schasinglulu 		ERROR("%s: Unknown state id (%d, %d, %d)\n", __func__,
266*91f16700Schasinglulu 			stateid_afflvl2, stateid_afflvl1, stateid_afflvl0);
267*91f16700Schasinglulu 		ret = PSCI_E_NOT_SUPPORTED;
268*91f16700Schasinglulu 	}
269*91f16700Schasinglulu 
270*91f16700Schasinglulu 	return ret;
271*91f16700Schasinglulu }
272*91f16700Schasinglulu 
273*91f16700Schasinglulu static void tegra_reset_all_dma_masters(void)
274*91f16700Schasinglulu {
275*91f16700Schasinglulu 	uint32_t val, mask;
276*91f16700Schasinglulu 
277*91f16700Schasinglulu 	/*
278*91f16700Schasinglulu 	 * Reset all possible DMA masters in the system.
279*91f16700Schasinglulu 	 */
280*91f16700Schasinglulu 	val = GPU_RESET_BIT;
281*91f16700Schasinglulu 	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET, val);
282*91f16700Schasinglulu 
283*91f16700Schasinglulu 	val = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT |
284*91f16700Schasinglulu 	      NVJPG_RESET_BIT | NVDEC_RESET_BIT;
285*91f16700Schasinglulu 	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y, val);
286*91f16700Schasinglulu 
287*91f16700Schasinglulu 	val = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT |
288*91f16700Schasinglulu 	      VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT |
289*91f16700Schasinglulu 	      SDMMC2_RESET_BIT;
290*91f16700Schasinglulu 	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L, val);
291*91f16700Schasinglulu 
292*91f16700Schasinglulu 	val = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT;
293*91f16700Schasinglulu 	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H, val);
294*91f16700Schasinglulu 
295*91f16700Schasinglulu 	val = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT |
296*91f16700Schasinglulu 	      PCIE_RESET_BIT | SDMMC3_RESET_BIT;
297*91f16700Schasinglulu 	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U, val);
298*91f16700Schasinglulu 
299*91f16700Schasinglulu 	val = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT;
300*91f16700Schasinglulu 	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V, val);
301*91f16700Schasinglulu 
302*91f16700Schasinglulu 	/*
303*91f16700Schasinglulu 	 * If any of the DMA masters are still alive, assume
304*91f16700Schasinglulu 	 * that the system has been compromised and reboot.
305*91f16700Schasinglulu 	 */
306*91f16700Schasinglulu 	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET);
307*91f16700Schasinglulu 	mask = GPU_RESET_BIT;
308*91f16700Schasinglulu 	if ((val & mask) != mask)
309*91f16700Schasinglulu 		tegra_pmc_system_reset();
310*91f16700Schasinglulu 
311*91f16700Schasinglulu 	mask = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT |
312*91f16700Schasinglulu 	      NVJPG_RESET_BIT | NVDEC_RESET_BIT;
313*91f16700Schasinglulu 	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y);
314*91f16700Schasinglulu 	if ((val & mask) != mask)
315*91f16700Schasinglulu 		tegra_pmc_system_reset();
316*91f16700Schasinglulu 
317*91f16700Schasinglulu 	mask = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT |
318*91f16700Schasinglulu 	       VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT |
319*91f16700Schasinglulu 	       SDMMC2_RESET_BIT;
320*91f16700Schasinglulu 	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L);
321*91f16700Schasinglulu 	if ((val & mask) != mask)
322*91f16700Schasinglulu 		tegra_pmc_system_reset();
323*91f16700Schasinglulu 
324*91f16700Schasinglulu 	mask = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT;
325*91f16700Schasinglulu 	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H);
326*91f16700Schasinglulu 	if ((val & mask) != mask)
327*91f16700Schasinglulu 		tegra_pmc_system_reset();
328*91f16700Schasinglulu 
329*91f16700Schasinglulu 	mask = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT |
330*91f16700Schasinglulu 	       PCIE_RESET_BIT | SDMMC3_RESET_BIT;
331*91f16700Schasinglulu 	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U);
332*91f16700Schasinglulu 	if ((val & mask) != mask)
333*91f16700Schasinglulu 		tegra_pmc_system_reset();
334*91f16700Schasinglulu 
335*91f16700Schasinglulu 	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V);
336*91f16700Schasinglulu 	mask = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT;
337*91f16700Schasinglulu 	if ((val & mask) != mask)
338*91f16700Schasinglulu 		tegra_pmc_system_reset();
339*91f16700Schasinglulu }
340*91f16700Schasinglulu 
341*91f16700Schasinglulu int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
342*91f16700Schasinglulu {
343*91f16700Schasinglulu 	u_register_t mpidr = read_mpidr();
344*91f16700Schasinglulu 	const plat_local_state_t *pwr_domain_state =
345*91f16700Schasinglulu 		target_state->pwr_domain_state;
346*91f16700Schasinglulu 	unsigned int stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL];
347*91f16700Schasinglulu 	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
348*91f16700Schasinglulu 	uint32_t val;
349*91f16700Schasinglulu 
350*91f16700Schasinglulu 	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
351*91f16700Schasinglulu 
352*91f16700Schasinglulu 		if (tegra_chipid_is_t210_b01()) {
353*91f16700Schasinglulu 			/* Save tzram contents */
354*91f16700Schasinglulu 			tegra_se_save_tzram();
355*91f16700Schasinglulu 		}
356*91f16700Schasinglulu 
357*91f16700Schasinglulu 		/* de-init the interface */
358*91f16700Schasinglulu 		tegra_bpmp_suspend();
359*91f16700Schasinglulu 
360*91f16700Schasinglulu 		/*
361*91f16700Schasinglulu 		 * The CPU needs to load the System suspend entry firmware
362*91f16700Schasinglulu 		 * if nothing is running on the BPMP.
363*91f16700Schasinglulu 		 */
364*91f16700Schasinglulu 		if (!tegra_bpmp_available) {
365*91f16700Schasinglulu 
366*91f16700Schasinglulu 			/*
367*91f16700Schasinglulu 			 * BPMP firmware is not running on the co-processor, so
368*91f16700Schasinglulu 			 * we need to explicitly load the firmware to enable
369*91f16700Schasinglulu 			 * entry/exit to/from System Suspend and set the BPMP
370*91f16700Schasinglulu 			 * on its way.
371*91f16700Schasinglulu 			 */
372*91f16700Schasinglulu 
373*91f16700Schasinglulu 			/* Power off BPMP before we proceed */
374*91f16700Schasinglulu 			tegra_fc_bpmp_off();
375*91f16700Schasinglulu 
376*91f16700Schasinglulu 			/* bond out IRAM banks B, C and D */
377*91f16700Schasinglulu 			mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_U,
378*91f16700Schasinglulu 				IRAM_B_LOCK_BIT | IRAM_C_LOCK_BIT |
379*91f16700Schasinglulu 				IRAM_D_LOCK_BIT);
380*91f16700Schasinglulu 
381*91f16700Schasinglulu 			/* bond out APB/AHB DMAs */
382*91f16700Schasinglulu 			mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_H,
383*91f16700Schasinglulu 				APB_DMA_LOCK_BIT | AHB_DMA_LOCK_BIT);
384*91f16700Schasinglulu 
385*91f16700Schasinglulu 			/* Power off BPMP before we proceed */
386*91f16700Schasinglulu 			tegra_fc_bpmp_off();
387*91f16700Schasinglulu 
388*91f16700Schasinglulu 			/*
389*91f16700Schasinglulu 			 * Reset all the hardware blocks that can act as DMA
390*91f16700Schasinglulu 			 * masters on the bus.
391*91f16700Schasinglulu 			 */
392*91f16700Schasinglulu 			tegra_reset_all_dma_masters();
393*91f16700Schasinglulu 
394*91f16700Schasinglulu 			/*
395*91f16700Schasinglulu 			 * Mark PMC as accessible to the non-secure world
396*91f16700Schasinglulu 			 * to allow the COP to execute System Suspend
397*91f16700Schasinglulu 			 * sequence
398*91f16700Schasinglulu 			 */
399*91f16700Schasinglulu 			val = mmio_read_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE);
400*91f16700Schasinglulu 			val &= ~PMC_SECURITY_EN_BIT;
401*91f16700Schasinglulu 			mmio_write_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE, val);
402*91f16700Schasinglulu 
403*91f16700Schasinglulu 			/* clean up IRAM of any cruft */
404*91f16700Schasinglulu 			zeromem((void *)(uintptr_t)TEGRA_IRAM_BASE,
405*91f16700Schasinglulu 					TEGRA_IRAM_A_SIZE);
406*91f16700Schasinglulu 
407*91f16700Schasinglulu 			/* Copy the firmware to BPMP's internal RAM */
408*91f16700Schasinglulu 			(void)memcpy((void *)(uintptr_t)TEGRA_IRAM_BASE,
409*91f16700Schasinglulu 				(const void *)(plat_params->sc7entry_fw_base + SC7ENTRY_FW_HEADER_SIZE_BYTES),
410*91f16700Schasinglulu 				plat_params->sc7entry_fw_size - SC7ENTRY_FW_HEADER_SIZE_BYTES);
411*91f16700Schasinglulu 
412*91f16700Schasinglulu 			/* Power on the BPMP and execute from IRAM base */
413*91f16700Schasinglulu 			tegra_fc_bpmp_on(TEGRA_IRAM_BASE);
414*91f16700Schasinglulu 
415*91f16700Schasinglulu 			/* Wait until BPMP powers up */
416*91f16700Schasinglulu 			do {
417*91f16700Schasinglulu 				val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET);
418*91f16700Schasinglulu 			} while (val != SIGN_OF_LIFE);
419*91f16700Schasinglulu 		}
420*91f16700Schasinglulu 
421*91f16700Schasinglulu 		/* enter system suspend */
422*91f16700Schasinglulu 		tegra_fc_soc_powerdn(mpidr);
423*91f16700Schasinglulu 	}
424*91f16700Schasinglulu 
425*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
426*91f16700Schasinglulu }
427*91f16700Schasinglulu 
428*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
429*91f16700Schasinglulu {
430*91f16700Schasinglulu 	return PSCI_E_NOT_SUPPORTED;
431*91f16700Schasinglulu }
432*91f16700Schasinglulu 
433*91f16700Schasinglulu int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
434*91f16700Schasinglulu {
435*91f16700Schasinglulu 	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
436*91f16700Schasinglulu 	uint32_t cfg;
437*91f16700Schasinglulu 	uint32_t val, entrypoint = 0;
438*91f16700Schasinglulu 	uint64_t offset;
439*91f16700Schasinglulu 
440*91f16700Schasinglulu 	/* platform parameter passed by the previous bootloader */
441*91f16700Schasinglulu 	if (plat_params->l2_ecc_parity_prot_dis != 1) {
442*91f16700Schasinglulu 		/* Enable ECC Parity Protection for Cortex-A57 CPUs */
443*91f16700Schasinglulu 		val = read_l2ctlr_el1();
444*91f16700Schasinglulu 		val |= (uint64_t)CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
445*91f16700Schasinglulu 		write_l2ctlr_el1(val);
446*91f16700Schasinglulu 	}
447*91f16700Schasinglulu 
448*91f16700Schasinglulu 	/*
449*91f16700Schasinglulu 	 * Check if we are exiting from SOC_POWERDN.
450*91f16700Schasinglulu 	 */
451*91f16700Schasinglulu 	if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
452*91f16700Schasinglulu 			PLAT_SYS_SUSPEND_STATE_ID) {
453*91f16700Schasinglulu 
454*91f16700Schasinglulu 		/*
455*91f16700Schasinglulu 		 * Security engine resume
456*91f16700Schasinglulu 		 */
457*91f16700Schasinglulu 		if (tegra_chipid_is_t210_b01()) {
458*91f16700Schasinglulu 			tegra_se_resume();
459*91f16700Schasinglulu 		}
460*91f16700Schasinglulu 
461*91f16700Schasinglulu 		/*
462*91f16700Schasinglulu 		 * Lock scratch registers which hold the CPU vectors
463*91f16700Schasinglulu 		 */
464*91f16700Schasinglulu 		tegra_pmc_lock_cpu_vectors();
465*91f16700Schasinglulu 
466*91f16700Schasinglulu 		/*
467*91f16700Schasinglulu 		 * Enable WRAP to INCR burst type conversions for
468*91f16700Schasinglulu 		 * incoming requests on the AXI slave ports.
469*91f16700Schasinglulu 		 */
470*91f16700Schasinglulu 		val = mmio_read_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG);
471*91f16700Schasinglulu 		val &= ~ENABLE_UNSUP_TX_ERRORS;
472*91f16700Schasinglulu 		val |= ENABLE_WRAP_TO_INCR_BURSTS;
473*91f16700Schasinglulu 		mmio_write_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG, val);
474*91f16700Schasinglulu 
475*91f16700Schasinglulu 		/*
476*91f16700Schasinglulu 		 * Restore Boot and Power Management Processor (BPMP) reset
477*91f16700Schasinglulu 		 * address and reset it, if it is supported by the platform.
478*91f16700Schasinglulu 		 */
479*91f16700Schasinglulu 		if (!tegra_bpmp_available) {
480*91f16700Schasinglulu 			tegra_fc_bpmp_off();
481*91f16700Schasinglulu 		} else {
482*91f16700Schasinglulu 			entrypoint = tegra_pmc_read_32(PMC_SCRATCH39);
483*91f16700Schasinglulu 			tegra_fc_bpmp_on(entrypoint);
484*91f16700Schasinglulu 
485*91f16700Schasinglulu 			/* initialise the interface */
486*91f16700Schasinglulu 			tegra_bpmp_resume();
487*91f16700Schasinglulu 		}
488*91f16700Schasinglulu 
489*91f16700Schasinglulu 		if (plat_params->sc7entry_fw_base != 0U) {
490*91f16700Schasinglulu 			/* sc7entry-fw is part of TZDRAM area */
491*91f16700Schasinglulu 			offset = plat_params->tzdram_base - plat_params->sc7entry_fw_base;
492*91f16700Schasinglulu 			tegra_memctrl_tzdram_setup(plat_params->sc7entry_fw_base,
493*91f16700Schasinglulu 				plat_params->tzdram_size + offset);
494*91f16700Schasinglulu 		}
495*91f16700Schasinglulu 
496*91f16700Schasinglulu 		if (!tegra_chipid_is_t210_b01()) {
497*91f16700Schasinglulu 			/* restrict PMC access to secure world */
498*91f16700Schasinglulu 			val = mmio_read_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE);
499*91f16700Schasinglulu 			val |= PMC_SECURITY_EN_BIT;
500*91f16700Schasinglulu 			mmio_write_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE, val);
501*91f16700Schasinglulu 		}
502*91f16700Schasinglulu 	}
503*91f16700Schasinglulu 
504*91f16700Schasinglulu 	/*
505*91f16700Schasinglulu 	 * Check if we are exiting cluster idle state
506*91f16700Schasinglulu 	 */
507*91f16700Schasinglulu 	if (target_state->pwr_domain_state[MPIDR_AFFLVL1] ==
508*91f16700Schasinglulu 			PSTATE_ID_CLUSTER_IDLE) {
509*91f16700Schasinglulu 
510*91f16700Schasinglulu 		if (!tegra_bpmp_available) {
511*91f16700Schasinglulu 
512*91f16700Schasinglulu 			/* PWM un-tristate */
513*91f16700Schasinglulu 			cfg = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_OUTPUT_CFG);
514*91f16700Schasinglulu 			if (cfg & DFLL_OUTPUT_CFG_CLK_EN_BIT) {
515*91f16700Schasinglulu 				val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
516*91f16700Schasinglulu 				val &= ~PINMUX_PWM_TRISTATE;
517*91f16700Schasinglulu 				mmio_write_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM, val);
518*91f16700Schasinglulu 
519*91f16700Schasinglulu 				/* make sure the setting took effect */
520*91f16700Schasinglulu 				val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
521*91f16700Schasinglulu 				assert((val & PINMUX_PWM_TRISTATE) == 0U);
522*91f16700Schasinglulu 			}
523*91f16700Schasinglulu 
524*91f16700Schasinglulu 			/*
525*91f16700Schasinglulu 			 * Restore operation mode for the DFLL ring
526*91f16700Schasinglulu 			 * oscillator
527*91f16700Schasinglulu 			 */
528*91f16700Schasinglulu 			mmio_write_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL,
529*91f16700Schasinglulu 				      ENABLE_CLOSED_LOOP);
530*91f16700Schasinglulu 
531*91f16700Schasinglulu 			/* release cluster idle lock */
532*91f16700Schasinglulu 			tegra_fc_ccplex_pgexit_unlock();
533*91f16700Schasinglulu 		}
534*91f16700Schasinglulu 	}
535*91f16700Schasinglulu 
536*91f16700Schasinglulu 	/*
537*91f16700Schasinglulu 	 * Mark this CPU as ON in the cpu_powergate_mask[],
538*91f16700Schasinglulu 	 * so that we use Flow Controller for all subsequent
539*91f16700Schasinglulu 	 * power ups.
540*91f16700Schasinglulu 	 */
541*91f16700Schasinglulu 	cpu_powergate_mask[plat_my_core_pos()] = 1;
542*91f16700Schasinglulu 
543*91f16700Schasinglulu 	/*
544*91f16700Schasinglulu 	 * T210 has a dedicated ARMv7 boot and power mgmt processor, BPMP. It's
545*91f16700Schasinglulu 	 * used for power management and boot purposes. Inform the BPMP that
546*91f16700Schasinglulu 	 * we have completed the cluster power up.
547*91f16700Schasinglulu 	 */
548*91f16700Schasinglulu 	tegra_fc_lock_active_cluster();
549*91f16700Schasinglulu 
550*91f16700Schasinglulu 	/*
551*91f16700Schasinglulu 	 * Resume PMC hardware block for Tegra210 platforms
552*91f16700Schasinglulu 	 */
553*91f16700Schasinglulu 	if (!tegra_chipid_is_t210_b01()) {
554*91f16700Schasinglulu 		tegra_pmc_resume();
555*91f16700Schasinglulu 	}
556*91f16700Schasinglulu 
557*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
558*91f16700Schasinglulu }
559*91f16700Schasinglulu 
560*91f16700Schasinglulu int tegra_soc_pwr_domain_on(u_register_t mpidr)
561*91f16700Schasinglulu {
562*91f16700Schasinglulu 	int cpu = mpidr & MPIDR_CPU_MASK;
563*91f16700Schasinglulu 	uint32_t mask = CPU_CORE_RESET_MASK << cpu;
564*91f16700Schasinglulu 
565*91f16700Schasinglulu 	/* Deassert CPU reset signals */
566*91f16700Schasinglulu 	mmio_write_32(TEGRA_CAR_RESET_BASE + CPU_CMPLX_RESET_CLR, mask);
567*91f16700Schasinglulu 
568*91f16700Schasinglulu 	/* Turn on CPU using flow controller or PMC */
569*91f16700Schasinglulu 	if (cpu_powergate_mask[cpu] == 0) {
570*91f16700Schasinglulu 		tegra_pmc_cpu_on(cpu);
571*91f16700Schasinglulu 	} else {
572*91f16700Schasinglulu 		tegra_fc_cpu_on(cpu);
573*91f16700Schasinglulu 	}
574*91f16700Schasinglulu 
575*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
576*91f16700Schasinglulu }
577*91f16700Schasinglulu 
578*91f16700Schasinglulu int32_t tegra_soc_pwr_domain_off_early(const psci_power_state_t *target_state)
579*91f16700Schasinglulu {
580*91f16700Schasinglulu 	/* Do not power off the boot CPU */
581*91f16700Schasinglulu 	if (plat_is_my_cpu_primary()) {
582*91f16700Schasinglulu 		return PSCI_E_DENIED;
583*91f16700Schasinglulu 	}
584*91f16700Schasinglulu 
585*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
586*91f16700Schasinglulu }
587*91f16700Schasinglulu 
588*91f16700Schasinglulu int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
589*91f16700Schasinglulu {
590*91f16700Schasinglulu 	tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
591*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
592*91f16700Schasinglulu }
593*91f16700Schasinglulu 
594*91f16700Schasinglulu int tegra_soc_prepare_system_reset(void)
595*91f16700Schasinglulu {
596*91f16700Schasinglulu 	/*
597*91f16700Schasinglulu 	 * Set System Clock (SCLK) to POR default so that the clock source
598*91f16700Schasinglulu 	 * for the PMC APB clock would not be changed due to system reset.
599*91f16700Schasinglulu 	 */
600*91f16700Schasinglulu 	mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_BURST_POLICY,
601*91f16700Schasinglulu 		SCLK_BURST_POLICY_DEFAULT);
602*91f16700Schasinglulu 	mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_RATE, 0);
603*91f16700Schasinglulu 
604*91f16700Schasinglulu 	/* Wait 1 ms to make sure clock source/device logic is stabilized. */
605*91f16700Schasinglulu 	mdelay(1);
606*91f16700Schasinglulu 
607*91f16700Schasinglulu 	/*
608*91f16700Schasinglulu 	 * Program the PMC in order to restart the system.
609*91f16700Schasinglulu 	 */
610*91f16700Schasinglulu 	tegra_pmc_system_reset();
611*91f16700Schasinglulu 
612*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
613*91f16700Schasinglulu }
614*91f16700Schasinglulu 
615*91f16700Schasinglulu __dead2 void tegra_soc_prepare_system_off(void)
616*91f16700Schasinglulu {
617*91f16700Schasinglulu 	ERROR("Tegra System Off: operation not handled.\n");
618*91f16700Schasinglulu 	panic();
619*91f16700Schasinglulu }
620