blob: 832b8d647f5b623af75600ca6ec7b1a5378e1434 [file] [log] [blame]
Varun Wadekarb316e242015-05-19 16:48:04 +05301/*
Varun Wadekarba313282018-02-13 20:31:12 -08002 * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
Varun Wadekarb5b15b22018-05-17 10:10:25 -07003 * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
Varun Wadekarb316e242015-05-19 16:48:04 +05304 *
dp-armfa3cf0b2017-05-03 09:38:09 +01005 * SPDX-License-Identifier: BSD-3-Clause
Varun Wadekarb316e242015-05-19 16:48:04 +05306 */
7
Varun Wadekarb316e242015-05-19 16:48:04 +05308#include <assert.h>
Sam Payne71ce6ed2017-05-08 12:42:49 -07009#include <cortex_a57.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010#include <arch_helpers.h>
11#include <common/debug.h>
12#include <drivers/delay_timer.h>
13#include <lib/mmio.h>
14#include <lib/psci/psci.h>
15#include <plat/common/platform.h>
16
Varun Wadekara6a357f2017-05-05 09:20:59 -070017#include <bpmp.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000018#include <flowctrl.h>
Ambroise Vincentffbf32a2019-03-28 09:01:18 +000019#include <lib/utils.h>
Varun Wadekar6e29d4d2018-03-07 11:13:58 -080020#include <memctrl.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053021#include <pmc.h>
Varun Wadekara6a357f2017-05-05 09:20:59 -070022#include <platform_def.h>
23#include <security_engine.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053024#include <tegra_def.h>
25#include <tegra_private.h>
Marvin Hsu21eea972017-04-11 11:00:48 +080026#include <tegra_platform.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053027
Varun Wadekar071b7872015-07-08 17:42:02 +053028/*
29 * Register used to clear CPU reset signals. Each CPU has two reset
30 * signals: CPU reset (3:0) and Core reset (19:16).
31 */
32#define CPU_CMPLX_RESET_CLR 0x454
33#define CPU_CORE_RESET_MASK 0x10001
34
Varun Wadekar8b82fae2015-11-09 17:39:28 -080035/* Clock and Reset controller registers for system clock's settings */
36#define SCLK_RATE 0x30
37#define SCLK_BURST_POLICY 0x28
38#define SCLK_BURST_POLICY_DEFAULT 0x10000000
39
Varun Wadekarb316e242015-05-19 16:48:04 +053040static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
Varun Wadekarba313282018-02-13 20:31:12 -080041static bool tegra_bpmp_available = true;
Varun Wadekarb316e242015-05-19 16:48:04 +053042
Varun Wadekara78bb1b2015-08-07 10:03:00 +053043int32_t tegra_soc_validate_power_state(unsigned int power_state,
44 psci_power_state_t *req_state)
Varun Wadekar254441d2015-07-23 10:07:54 +053045{
Varun Wadekara78bb1b2015-08-07 10:03:00 +053046 int state_id = psci_get_pstate_id(power_state);
Varun Wadekarf07d6de2018-02-27 14:33:57 -080047 const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
Varun Wadekara78bb1b2015-08-07 10:03:00 +053048
Varun Wadekar254441d2015-07-23 10:07:54 +053049 /* Sanity check the requested state id */
Varun Wadekara78bb1b2015-08-07 10:03:00 +053050 switch (state_id) {
Varun Wadekar254441d2015-07-23 10:07:54 +053051 case PSTATE_ID_CORE_POWERDN:
Varun Wadekara78bb1b2015-08-07 10:03:00 +053052 /*
53 * Core powerdown request only for afflvl 0
54 */
Varun Wadekara78bb1b2015-08-07 10:03:00 +053055 req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff;
56
57 break;
58
Varun Wadekar254441d2015-07-23 10:07:54 +053059 case PSTATE_ID_CLUSTER_IDLE:
Varun Wadekarba313282018-02-13 20:31:12 -080060
Varun Wadekara78bb1b2015-08-07 10:03:00 +053061 /*
Varun Wadekarba313282018-02-13 20:31:12 -080062 * Cluster idle request for afflvl 0
Varun Wadekara78bb1b2015-08-07 10:03:00 +053063 */
Varun Wadekara6a357f2017-05-05 09:20:59 -070064 req_state->pwr_domain_state[MPIDR_AFFLVL0] = PSTATE_ID_CORE_POWERDN;
Varun Wadekarba313282018-02-13 20:31:12 -080065 req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
Varun Wadekara78bb1b2015-08-07 10:03:00 +053066 break;
67
Varun Wadekar254441d2015-07-23 10:07:54 +053068 case PSTATE_ID_SOC_POWERDN:
Varun Wadekarf07d6de2018-02-27 14:33:57 -080069
70 /*
71 * sc7entry-fw must be present in the system when the bpmp
72 * firmware is not present, for a successful System Suspend
73 * entry.
74 */
75 if (!tegra_bpmp_init() && !plat_params->sc7entry_fw_base)
76 return PSCI_E_NOT_SUPPORTED;
77
Varun Wadekara78bb1b2015-08-07 10:03:00 +053078 /*
79 * System powerdown request only for afflvl 2
80 */
Varun Wadekar66231d12017-06-07 09:57:42 -070081 for (uint32_t i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
Varun Wadekara78bb1b2015-08-07 10:03:00 +053082 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
83
84 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
85 PLAT_SYS_SUSPEND_STATE_ID;
86
Varun Wadekar254441d2015-07-23 10:07:54 +053087 break;
88
89 default:
Varun Wadekara78bb1b2015-08-07 10:03:00 +053090 ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
91 return PSCI_E_INVALID_PARAMS;
Varun Wadekar254441d2015-07-23 10:07:54 +053092 }
93
94 return PSCI_E_SUCCESS;
95}
96
Varun Wadekarb91b5fc2017-04-18 11:22:01 -070097/*******************************************************************************
98 * Platform handler to calculate the proper target power level at the
Varun Wadekarba313282018-02-13 20:31:12 -080099 * specified affinity level.
Varun Wadekarb91b5fc2017-04-18 11:22:01 -0700100 ******************************************************************************/
101plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl,
102 const plat_local_state_t *states,
103 unsigned int ncpu)
104{
Varun Wadekara6a357f2017-05-05 09:20:59 -0700105 plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
Varun Wadekarb91b5fc2017-04-18 11:22:01 -0700106 int cpu = plat_my_core_pos();
107 int core_pos = read_mpidr() & MPIDR_CPU_MASK;
Varun Wadekarba313282018-02-13 20:31:12 -0800108 uint32_t bpmp_reply, data[3], val;
Varun Wadekara6a357f2017-05-05 09:20:59 -0700109 int ret;
Varun Wadekarb91b5fc2017-04-18 11:22:01 -0700110
111 /* get the power state at this level */
112 if (lvl == MPIDR_AFFLVL1)
113 target = *(states + core_pos);
114 if (lvl == MPIDR_AFFLVL2)
115 target = *(states + cpu);
116
Varun Wadekara6a357f2017-05-05 09:20:59 -0700117 if ((lvl == MPIDR_AFFLVL1) && (target == PSTATE_ID_CLUSTER_IDLE)) {
118
119 /* initialize the bpmp interface */
Varun Wadekara9a3a102017-08-23 10:19:25 -0700120 ret = tegra_bpmp_init();
121 if (ret != 0U) {
Varun Wadekarb91b5fc2017-04-18 11:22:01 -0700122
Varun Wadekar22ecc052018-04-19 17:50:31 -0700123 /*
124 * flag to indicate that BPMP firmware is not
125 * available and the CPU has to handle entry/exit
126 * for all power states
127 */
128 tegra_bpmp_available = false;
129
Varun Wadekara6a357f2017-05-05 09:20:59 -0700130 /* Cluster idle not allowed */
131 target = PSCI_LOCAL_STATE_RUN;
Varun Wadekarba313282018-02-13 20:31:12 -0800132
133 /*******************************************
134 * BPMP is not present, so handle CC6 entry
135 * from the CPU
136 ******************************************/
137
138 /* check if cluster idle state has been enabled */
139 val = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL);
140 if (val == ENABLE_CLOSED_LOOP) {
141 /*
Varun Wadekarba313282018-02-13 20:31:12 -0800142 * Acquire the cluster idle lock to stop
143 * other CPUs from powering up.
144 */
145 tegra_fc_ccplex_pgexit_lock();
146
147 /* Cluster idle only from the last standing CPU */
148 if (tegra_pmc_is_last_on_cpu() && tegra_fc_is_ccx_allowed()) {
149 /* Cluster idle allowed */
150 target = PSTATE_ID_CLUSTER_IDLE;
151 } else {
152 /* release cluster idle lock */
153 tegra_fc_ccplex_pgexit_unlock();
154 }
155 }
Varun Wadekara9a3a102017-08-23 10:19:25 -0700156 } else {
157
Varun Wadekarba313282018-02-13 20:31:12 -0800158 /* Cluster power-down */
Varun Wadekara9a3a102017-08-23 10:19:25 -0700159 data[0] = (uint32_t)cpu;
160 data[1] = TEGRA_PM_CC6;
161 data[2] = TEGRA_PM_SC1;
162 ret = tegra_bpmp_send_receive_atomic(MRQ_DO_IDLE,
163 (void *)&data, (int)sizeof(data),
164 (void *)&bpmp_reply,
165 (int)sizeof(bpmp_reply));
166
Varun Wadekarba313282018-02-13 20:31:12 -0800167 /* check if cluster power down is allowed */
Varun Wadekara9a3a102017-08-23 10:19:25 -0700168 if ((ret != 0L) || (bpmp_reply != BPMP_CCx_ALLOWED)) {
169
Varun Wadekarba313282018-02-13 20:31:12 -0800170 /* Cluster power down not allowed */
Varun Wadekara9a3a102017-08-23 10:19:25 -0700171 target = PSCI_LOCAL_STATE_RUN;
172 }
Varun Wadekara6a357f2017-05-05 09:20:59 -0700173 }
174
Varun Wadekara6a357f2017-05-05 09:20:59 -0700175 } else if (((lvl == MPIDR_AFFLVL2) || (lvl == MPIDR_AFFLVL1)) &&
176 (target == PSTATE_ID_SOC_POWERDN)) {
177
178 /* System Suspend */
179 target = PSTATE_ID_SOC_POWERDN;
180
181 } else {
182 ; /* do nothing */
183 }
184
185 return target;
Varun Wadekarb91b5fc2017-04-18 11:22:01 -0700186}
187
Varun Wadekarb5b15b22018-05-17 10:10:25 -0700188int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state)
189{
190 (void)cpu_state;
191 return PSCI_E_SUCCESS;
192}
193
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530194int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
Varun Wadekarb316e242015-05-19 16:48:04 +0530195{
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530196 u_register_t mpidr = read_mpidr();
197 const plat_local_state_t *pwr_domain_state =
198 target_state->pwr_domain_state;
199 unsigned int stateid_afflvl2 = pwr_domain_state[MPIDR_AFFLVL2];
200 unsigned int stateid_afflvl1 = pwr_domain_state[MPIDR_AFFLVL1];
201 unsigned int stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0];
Varun Wadekarba313282018-02-13 20:31:12 -0800202 uint32_t cfg;
Marvin Hsu21eea972017-04-11 11:00:48 +0800203 int ret = PSCI_E_SUCCESS;
Varun Wadekarba313282018-02-13 20:31:12 -0800204 uint32_t val;
Varun Wadekarb316e242015-05-19 16:48:04 +0530205
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530206 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
Varun Wadekarb316e242015-05-19 16:48:04 +0530207
Harvey Hsieh20e9fef2016-12-28 21:53:18 +0800208 assert((stateid_afflvl0 == PLAT_MAX_OFF_STATE) ||
Marvin Hsu21eea972017-04-11 11:00:48 +0800209 (stateid_afflvl0 == PSTATE_ID_SOC_POWERDN));
Harvey Hsieh20e9fef2016-12-28 21:53:18 +0800210 assert((stateid_afflvl1 == PLAT_MAX_OFF_STATE) ||
Marvin Hsu21eea972017-04-11 11:00:48 +0800211 (stateid_afflvl1 == PSTATE_ID_SOC_POWERDN));
212
213 if (tegra_chipid_is_t210_b01()) {
Varun Wadekara6a357f2017-05-05 09:20:59 -0700214
Marvin Hsu21eea972017-04-11 11:00:48 +0800215 /* Suspend se/se2 and pka1 */
216 if (tegra_se_suspend() != 0) {
217 ret = PSCI_E_INTERN_FAIL;
218 }
Marvin Hsu21eea972017-04-11 11:00:48 +0800219 }
Varun Wadekarb316e242015-05-19 16:48:04 +0530220
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530221 } else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) {
Varun Wadekarb316e242015-05-19 16:48:04 +0530222
Varun Wadekara6a357f2017-05-05 09:20:59 -0700223 assert(stateid_afflvl0 == PSTATE_ID_CORE_POWERDN);
Varun Wadekarb316e242015-05-19 16:48:04 +0530224
Varun Wadekarba313282018-02-13 20:31:12 -0800225 if (!tegra_bpmp_available) {
226
Varun Wadekar22ecc052018-04-19 17:50:31 -0700227 /*
228 * When disabled, DFLL loses its state. Enable
229 * open loop state for the DFLL as we dont want
230 * garbage values being written to the pmic
231 * when we enter cluster idle state.
232 */
233 mmio_write_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL,
234 ENABLE_OPEN_LOOP);
235
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800236 /* Find if the platform uses OVR2/MAX77621 PMIC */
Varun Wadekarba313282018-02-13 20:31:12 -0800237 cfg = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_OUTPUT_CFG);
238 if (cfg & DFLL_OUTPUT_CFG_CLK_EN_BIT) {
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800239 /* OVR2 */
240
241 /* PWM tristate */
Varun Wadekarba313282018-02-13 20:31:12 -0800242 val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
243 val |= PINMUX_PWM_TRISTATE;
244 mmio_write_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM, val);
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800245
246 /*
247 * SCRATCH201[1] is being used to identify CPU
248 * PMIC in warmboot code.
249 * 0 : OVR2
250 * 1 : MAX77621
251 */
252 tegra_pmc_write_32(PMC_SCRATCH201, 0x0);
253 } else {
254 /* MAX77621 */
255 tegra_pmc_write_32(PMC_SCRATCH201, 0x2);
Varun Wadekarba313282018-02-13 20:31:12 -0800256 }
257 }
258
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530259 /* Prepare for cluster idle */
260 tegra_fc_cluster_idle(mpidr);
Varun Wadekarb316e242015-05-19 16:48:04 +0530261
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530262 } else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {
263
264 /* Prepare for cpu powerdn */
265 tegra_fc_cpu_powerdn(mpidr);
266
267 } else {
Varun Wadekara6a357f2017-05-05 09:20:59 -0700268 ERROR("%s: Unknown state id (%d, %d, %d)\n", __func__,
269 stateid_afflvl2, stateid_afflvl1, stateid_afflvl0);
Marvin Hsu21eea972017-04-11 11:00:48 +0800270 ret = PSCI_E_NOT_SUPPORTED;
Varun Wadekarb316e242015-05-19 16:48:04 +0530271 }
272
Marvin Hsu21eea972017-04-11 11:00:48 +0800273 return ret;
Varun Wadekarb316e242015-05-19 16:48:04 +0530274}
275
Varun Wadekardae27962018-03-05 10:19:37 -0800276static void tegra_reset_all_dma_masters(void)
277{
278 uint32_t val, mask;
279
280 /*
281 * Reset all possible DMA masters in the system.
282 */
283 val = GPU_RESET_BIT;
284 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET, val);
285
286 val = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT |
287 NVJPG_RESET_BIT | NVDEC_RESET_BIT;
288 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y, val);
289
290 val = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT |
291 VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT |
292 SDMMC2_RESET_BIT;
293 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L, val);
294
295 val = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT;
296 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H, val);
297
298 val = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT |
299 PCIE_RESET_BIT | SDMMC3_RESET_BIT;
300 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U, val);
301
302 val = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT;
303 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V, val);
304
305 /*
306 * If any of the DMA masters are still alive, assume
307 * that the system has been compromised and reboot.
308 */
309 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET);
310 mask = GPU_RESET_BIT;
311 if ((val & mask) != mask)
312 tegra_pmc_system_reset();
313
314 mask = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT |
315 NVJPG_RESET_BIT | NVDEC_RESET_BIT;
316 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y);
317 if ((val & mask) != mask)
318 tegra_pmc_system_reset();
319
320 mask = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT |
321 VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT |
322 SDMMC2_RESET_BIT;
323 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L);
324 if ((val & mask) != mask)
325 tegra_pmc_system_reset();
326
327 mask = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT;
328 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H);
329 if ((val & mask) != mask)
330 tegra_pmc_system_reset();
331
332 mask = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT |
333 PCIE_RESET_BIT | SDMMC3_RESET_BIT;
334 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U);
335 if ((val & mask) != mask)
336 tegra_pmc_system_reset();
337
338 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V);
339 mask = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT;
340 if ((val & mask) != mask)
341 tegra_pmc_system_reset();
342}
343
Harvey Hsieha16d4ea2017-06-15 16:28:43 -0700344int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
345{
346 u_register_t mpidr = read_mpidr();
347 const plat_local_state_t *pwr_domain_state =
348 target_state->pwr_domain_state;
349 unsigned int stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL];
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800350 const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
351 uint32_t val;
Harvey Hsieha16d4ea2017-06-15 16:28:43 -0700352
353 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
354
355 if (tegra_chipid_is_t210_b01()) {
356 /* Save tzram contents */
357 tegra_se_save_tzram();
358 }
359
Varun Wadekara6daf1c2018-04-04 11:14:05 -0700360 /* de-init the interface */
361 tegra_bpmp_suspend();
362
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800363 /*
364 * The CPU needs to load the System suspend entry firmware
365 * if nothing is running on the BPMP.
366 */
367 if (!tegra_bpmp_available) {
368
369 /*
370 * BPMP firmware is not running on the co-processor, so
371 * we need to explicitly load the firmware to enable
372 * entry/exit to/from System Suspend and set the BPMP
373 * on its way.
374 */
375
376 /* Power off BPMP before we proceed */
377 tegra_fc_bpmp_off();
378
Varun Wadekardae27962018-03-05 10:19:37 -0800379 /* bond out IRAM banks B, C and D */
380 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_U,
381 IRAM_B_LOCK_BIT | IRAM_C_LOCK_BIT |
382 IRAM_D_LOCK_BIT);
383
384 /* bond out APB/AHB DMAs */
385 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_H,
386 APB_DMA_LOCK_BIT | AHB_DMA_LOCK_BIT);
387
388 /* Power off BPMP before we proceed */
389 tegra_fc_bpmp_off();
390
391 /*
392 * Reset all the hardware blocks that can act as DMA
393 * masters on the bus.
394 */
395 tegra_reset_all_dma_masters();
396
kalyani chidambaram52dc3ea2018-04-09 15:18:02 -0700397 /*
398 * Mark PMC as accessible to the non-secure world
399 * to allow the COP to execute System Suspend
400 * sequence
401 */
402 val = mmio_read_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE);
403 val &= ~PMC_SECURITY_EN_BIT;
404 mmio_write_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE, val);
405
Varun Wadekardae27962018-03-05 10:19:37 -0800406 /* clean up IRAM of any cruft */
407 zeromem((void *)(uintptr_t)TEGRA_IRAM_BASE,
408 TEGRA_IRAM_A_SIZE);
409
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800410 /* Copy the firmware to BPMP's internal RAM */
411 (void)memcpy((void *)(uintptr_t)TEGRA_IRAM_BASE,
Varun Wadekar8c6517d2018-03-19 15:19:28 -0700412 (const void *)(plat_params->sc7entry_fw_base + SC7ENTRY_FW_HEADER_SIZE_BYTES),
413 plat_params->sc7entry_fw_size - SC7ENTRY_FW_HEADER_SIZE_BYTES);
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800414
415 /* Power on the BPMP and execute from IRAM base */
416 tegra_fc_bpmp_on(TEGRA_IRAM_BASE);
417
418 /* Wait until BPMP powers up */
419 do {
420 val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET);
421 } while (val != SIGN_OF_LIFE);
422 }
423
Harvey Hsieha16d4ea2017-06-15 16:28:43 -0700424 /* enter system suspend */
425 tegra_fc_soc_powerdn(mpidr);
426 }
427
428 return PSCI_E_SUCCESS;
429}
430
Varun Wadekarb5b15b22018-05-17 10:10:25 -0700431int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
432{
433 return PSCI_E_NOT_SUPPORTED;
434}
435
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530436int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
Varun Wadekarb316e242015-05-19 16:48:04 +0530437{
Sam Payne71ce6ed2017-05-08 12:42:49 -0700438 const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
Varun Wadekarba313282018-02-13 20:31:12 -0800439 uint32_t cfg;
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800440 uint32_t val, entrypoint = 0;
Varun Wadekar6e29d4d2018-03-07 11:13:58 -0800441 uint64_t offset;
Varun Wadekarbc787442015-07-27 13:00:50 +0530442
Sam Payne71ce6ed2017-05-08 12:42:49 -0700443 /* platform parameter passed by the previous bootloader */
444 if (plat_params->l2_ecc_parity_prot_dis != 1) {
445 /* Enable ECC Parity Protection for Cortex-A57 CPUs */
446 val = read_l2ctlr_el1();
447 val |= (uint64_t)CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
448 write_l2ctlr_el1(val);
449 }
450
Varun Wadekarb316e242015-05-19 16:48:04 +0530451 /*
452 * Check if we are exiting from SOC_POWERDN.
453 */
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530454 if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
455 PLAT_SYS_SUSPEND_STATE_ID) {
Varun Wadekarb316e242015-05-19 16:48:04 +0530456
457 /*
Marvin Hsu21eea972017-04-11 11:00:48 +0800458 * Security engine resume
459 */
460 if (tegra_chipid_is_t210_b01()) {
461 tegra_se_resume();
462 }
463
464 /*
Varun Wadekar6eec6d62016-03-03 13:28:10 -0800465 * Lock scratch registers which hold the CPU vectors
466 */
467 tegra_pmc_lock_cpu_vectors();
468
469 /*
Varun Wadekarbc787442015-07-27 13:00:50 +0530470 * Enable WRAP to INCR burst type conversions for
471 * incoming requests on the AXI slave ports.
472 */
473 val = mmio_read_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG);
474 val &= ~ENABLE_UNSUP_TX_ERRORS;
475 val |= ENABLE_WRAP_TO_INCR_BURSTS;
476 mmio_write_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG, val);
477
478 /*
Varun Wadekarb316e242015-05-19 16:48:04 +0530479 * Restore Boot and Power Management Processor (BPMP) reset
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800480 * address and reset it, if it is supported by the platform.
Varun Wadekarb316e242015-05-19 16:48:04 +0530481 */
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800482 if (!tegra_bpmp_available) {
483 tegra_fc_bpmp_off();
484 } else {
485 entrypoint = tegra_pmc_read_32(PMC_SCRATCH39);
486 tegra_fc_bpmp_on(entrypoint);
Varun Wadekara6daf1c2018-04-04 11:14:05 -0700487
488 /* initialise the interface */
489 tegra_bpmp_resume();
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800490 }
Varun Wadekar6e29d4d2018-03-07 11:13:58 -0800491
Varun Wadekar6e29d4d2018-03-07 11:13:58 -0800492 if (plat_params->sc7entry_fw_base != 0U) {
kalyani chidambaram52dc3ea2018-04-09 15:18:02 -0700493 /* sc7entry-fw is part of TZDRAM area */
Varun Wadekar6e29d4d2018-03-07 11:13:58 -0800494 offset = plat_params->tzdram_base - plat_params->sc7entry_fw_base;
495 tegra_memctrl_tzdram_setup(plat_params->sc7entry_fw_base,
496 plat_params->tzdram_size + offset);
kalyani chidambaram52dc3ea2018-04-09 15:18:02 -0700497 }
Varun Wadekara8c61ac2018-03-12 15:11:55 -0700498
kalyani chidambaram52dc3ea2018-04-09 15:18:02 -0700499 if (!tegra_chipid_is_t210_b01()) {
Varun Wadekara8c61ac2018-03-12 15:11:55 -0700500 /* restrict PMC access to secure world */
501 val = mmio_read_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE);
502 val |= PMC_SECURITY_EN_BIT;
503 mmio_write_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE, val);
Varun Wadekar6e29d4d2018-03-07 11:13:58 -0800504 }
Varun Wadekarba313282018-02-13 20:31:12 -0800505 }
506
507 /*
508 * Check if we are exiting cluster idle state
509 */
510 if (target_state->pwr_domain_state[MPIDR_AFFLVL1] ==
511 PSTATE_ID_CLUSTER_IDLE) {
512
513 if (!tegra_bpmp_available) {
514
515 /* PWM un-tristate */
516 cfg = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_OUTPUT_CFG);
517 if (cfg & DFLL_OUTPUT_CFG_CLK_EN_BIT) {
518 val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
519 val &= ~PINMUX_PWM_TRISTATE;
520 mmio_write_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM, val);
Varun Wadekar22ecc052018-04-19 17:50:31 -0700521
522 /* make sure the setting took effect */
523 val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
524 assert((val & PINMUX_PWM_TRISTATE) == 0U);
Varun Wadekarba313282018-02-13 20:31:12 -0800525 }
526
Varun Wadekar22ecc052018-04-19 17:50:31 -0700527 /*
528 * Restore operation mode for the DFLL ring
529 * oscillator
530 */
531 mmio_write_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL,
532 ENABLE_CLOSED_LOOP);
533
Varun Wadekarba313282018-02-13 20:31:12 -0800534 /* release cluster idle lock */
535 tegra_fc_ccplex_pgexit_unlock();
536 }
Varun Wadekarb316e242015-05-19 16:48:04 +0530537 }
538
539 /*
540 * T210 has a dedicated ARMv7 boot and power mgmt processor, BPMP. It's
541 * used for power management and boot purposes. Inform the BPMP that
542 * we have completed the cluster power up.
543 */
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530544 tegra_fc_lock_active_cluster();
Varun Wadekarb316e242015-05-19 16:48:04 +0530545
kalyani chidambaramb3873aa2018-04-09 14:40:02 -0700546 /*
kalyani chidambaramcf45aee2018-06-19 15:56:01 -0700547 * Resume PMC hardware block for Tegra210 platforms
548 */
549 if (!tegra_chipid_is_t210_b01()) {
kalyani chidambaramb3873aa2018-04-09 14:40:02 -0700550 tegra_pmc_resume();
kalyani chidambaramcf45aee2018-06-19 15:56:01 -0700551 }
kalyani chidambaramb3873aa2018-04-09 14:40:02 -0700552
Varun Wadekarb316e242015-05-19 16:48:04 +0530553 return PSCI_E_SUCCESS;
554}
555
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530556int tegra_soc_pwr_domain_on(u_register_t mpidr)
Varun Wadekarb316e242015-05-19 16:48:04 +0530557{
558 int cpu = mpidr & MPIDR_CPU_MASK;
Varun Wadekar071b7872015-07-08 17:42:02 +0530559 uint32_t mask = CPU_CORE_RESET_MASK << cpu;
560
561 /* Deassert CPU reset signals */
562 mmio_write_32(TEGRA_CAR_RESET_BASE + CPU_CMPLX_RESET_CLR, mask);
Varun Wadekarb316e242015-05-19 16:48:04 +0530563
564 /* Turn on CPU using flow controller or PMC */
565 if (cpu_powergate_mask[cpu] == 0) {
566 tegra_pmc_cpu_on(cpu);
567 cpu_powergate_mask[cpu] = 1;
568 } else {
569 tegra_fc_cpu_on(cpu);
570 }
571
572 return PSCI_E_SUCCESS;
573}
574
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530575int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
Varun Wadekarb316e242015-05-19 16:48:04 +0530576{
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530577 tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
Varun Wadekarb316e242015-05-19 16:48:04 +0530578 return PSCI_E_SUCCESS;
579}
Varun Wadekar8b82fae2015-11-09 17:39:28 -0800580
581int tegra_soc_prepare_system_reset(void)
582{
583 /*
584 * Set System Clock (SCLK) to POR default so that the clock source
585 * for the PMC APB clock would not be changed due to system reset.
586 */
587 mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_BURST_POLICY,
Marvin Hsu21eea972017-04-11 11:00:48 +0800588 SCLK_BURST_POLICY_DEFAULT);
Varun Wadekar8b82fae2015-11-09 17:39:28 -0800589 mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_RATE, 0);
590
591 /* Wait 1 ms to make sure clock source/device logic is stabilized. */
592 mdelay(1);
593
Varun Wadekar29b46652018-05-17 11:10:13 -0700594 /*
595 * Program the PMC in order to restart the system.
596 */
597 tegra_pmc_system_reset();
598
Varun Wadekar8b82fae2015-11-09 17:39:28 -0800599 return PSCI_E_SUCCESS;
600}
Varun Wadekarb5b15b22018-05-17 10:10:25 -0700601
602__dead2 void tegra_soc_prepare_system_off(void)
603{
604 ERROR("Tegra System Off: operation not handled.\n");
605 panic();
606}