blob: 144e41885db146fc92d3f0a7d3719d3c5b1eec81 [file] [log] [blame]
Varun Wadekarecd6a5a2018-04-09 17:48:58 -07001/*
Varun Wadekar4edc17c2017-11-20 17:14:47 -08002 * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
Varun Wadekarecd6a5a2018-04-09 17:48:58 -07003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -07008#include <assert.h>
Steven Kao530b2172017-06-23 16:18:58 +08009#include <stdbool.h>
10#include <string.h>
11
12#include <arch_helpers.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070013#include <common/bl_common.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070014#include <common/debug.h>
Steven Kao530b2172017-06-23 16:18:58 +080015#include <context.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070016#include <denver.h>
Steven Kao530b2172017-06-23 16:18:58 +080017#include <lib/el3_runtime/context_mgmt.h>
18#include <lib/psci/psci.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070019#include <mce.h>
Dilan Lee4e7a63c2017-08-10 16:01:42 +080020#include <mce_private.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070021#include <plat/common/platform.h>
Steven Kao530b2172017-06-23 16:18:58 +080022#include <se.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070023#include <smmu.h>
Tejal Kudav153ba222017-02-14 18:02:04 -080024#include <t194_nvg.h>
Varun Wadekare0c222f2017-11-10 13:23:34 -080025#include <tegra194_private.h>
Steven Kao530b2172017-06-23 16:18:58 +080026#include <tegra_platform.h>
27#include <tegra_private.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070028
Varun Wadekar362a6b22017-11-10 11:04:42 -080029extern uint32_t __tegra194_cpu_reset_handler_data,
30 __tegra194_cpu_reset_handler_end;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070031
32/* TZDRAM offset for saving SMMU context */
Varun Wadekar362a6b22017-11-10 11:04:42 -080033#define TEGRA194_SMMU_CTX_OFFSET 16U
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070034
35/* state id mask */
Varun Wadekar362a6b22017-11-10 11:04:42 -080036#define TEGRA194_STATE_ID_MASK 0xFU
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070037/* constants to get power state's wake time */
Varun Wadekar362a6b22017-11-10 11:04:42 -080038#define TEGRA194_WAKE_TIME_MASK 0x0FFFFFF0U
39#define TEGRA194_WAKE_TIME_SHIFT 4U
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070040/* default core wake mask for CPU_SUSPEND */
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080041#define TEGRA194_CORE_WAKE_MASK 0x180cU
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070042
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080043static struct t19x_psci_percpu_data {
44 uint32_t wake_time;
45} __aligned(CACHE_WRITEBACK_GRANULE) t19x_percpu_data[PLATFORM_CORE_COUNT];
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070046
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080047int32_t tegra_soc_validate_power_state(uint32_t power_state,
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070048 psci_power_state_t *req_state)
49{
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080050 uint8_t state_id = (uint8_t)psci_get_pstate_id(power_state) &
Varun Wadekar362a6b22017-11-10 11:04:42 -080051 TEGRA194_STATE_ID_MASK;
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080052 uint32_t cpu = plat_my_core_pos();
53 int32_t ret = PSCI_E_SUCCESS;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070054
55 /* save the core wake time (in TSC ticks)*/
Varun Wadekar362a6b22017-11-10 11:04:42 -080056 t19x_percpu_data[cpu].wake_time = (power_state & TEGRA194_WAKE_TIME_MASK)
57 << TEGRA194_WAKE_TIME_SHIFT;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070058
59 /*
Varun Wadekar56c64592019-12-03 08:50:57 -080060 * Clean t19x_percpu_data[cpu] to DRAM. This needs to be done to ensure
61 * that the correct value is read in tegra_soc_pwr_domain_suspend(),
62 * which is called with caches disabled. It is possible to read a stale
63 * value from DRAM in that function, because the L2 cache is not flushed
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070064 * unless the cluster is entering CC6/CC7.
65 */
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080066 clean_dcache_range((uint64_t)&t19x_percpu_data[cpu],
67 sizeof(t19x_percpu_data[cpu]));
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070068
69 /* Sanity check the requested state id */
70 switch (state_id) {
71 case PSTATE_ID_CORE_IDLE:
Varun Wadekarc61094b2017-12-27 18:01:59 -080072
73 /* Core idle request */
74 req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
75 req_state->pwr_domain_state[MPIDR_AFFLVL1] = PSCI_LOCAL_STATE_RUN;
76 break;
77
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070078 case PSTATE_ID_CORE_POWERDN:
79
80 /* Core powerdown request */
81 req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id;
82 req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
83
84 break;
85
86 default:
87 ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080088 ret = PSCI_E_INVALID_PARAMS;
89 break;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070090 }
91
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080092 return ret;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070093}
94
Varun Wadekarc61094b2017-12-27 18:01:59 -080095int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state)
96{
97 uint32_t cpu = plat_my_core_pos();
98 mce_cstate_info_t cstate_info = { 0 };
99
100 /* Program default wake mask */
101 cstate_info.wake_mask = TEGRA194_CORE_WAKE_MASK;
102 cstate_info.update_wake_mask = 1;
103 mce_update_cstate_info(&cstate_info);
104
105 /* Enter CPU idle */
106 (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
107 (uint64_t)TEGRA_NVG_CORE_C6,
108 t19x_percpu_data[cpu].wake_time,
109 0U);
110
111 return PSCI_E_SUCCESS;
112}
113
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800114int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700115{
116 const plat_local_state_t *pwr_domain_state;
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800117 uint8_t stateid_afflvl0, stateid_afflvl2;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700118 plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
119 uint64_t smmu_ctx_base;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700120 uint32_t val;
Vignesh Radhakrishnand7a5c252017-05-25 16:27:42 -0700121 mce_cstate_info_t sc7_cstate_info = {
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800122 .cluster = (uint32_t)TEGRA_NVG_CLUSTER_CC6,
Vignesh Radhakrishnan85c129f2017-12-20 15:04:26 -0800123 .ccplex = (uint32_t)TEGRA_NVG_CG_CG7,
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800124 .system = (uint32_t)TEGRA_NVG_SYSTEM_SC7,
125 .system_state_force = 1U,
126 .update_wake_mask = 1U,
Vignesh Radhakrishnand7a5c252017-05-25 16:27:42 -0700127 };
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800128 uint32_t cpu = plat_my_core_pos();
Vignesh Radhakrishnand7a5c252017-05-25 16:27:42 -0700129 int32_t ret = 0;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700130
131 /* get the state ID */
132 pwr_domain_state = target_state->pwr_domain_state;
133 stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] &
Varun Wadekar362a6b22017-11-10 11:04:42 -0800134 TEGRA194_STATE_ID_MASK;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700135 stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
Varun Wadekar362a6b22017-11-10 11:04:42 -0800136 TEGRA194_STATE_ID_MASK;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700137
Varun Wadekarc61094b2017-12-27 18:01:59 -0800138 if ((stateid_afflvl0 == PSTATE_ID_CORE_POWERDN)) {
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700139
Varun Wadekarc61094b2017-12-27 18:01:59 -0800140 /* Enter CPU powerdown */
141 (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
142 (uint64_t)TEGRA_NVG_CORE_C7,
143 t19x_percpu_data[cpu].wake_time,
144 0U);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700145
146 } else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
147
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700148 /* save 'Secure Boot' Processor Feature Config Register */
149 val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG);
Steven Kao4607f172017-10-23 18:35:14 +0800150 mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SECURE_BOOTP_FCFG, val);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700151
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700152 /* save SMMU context */
153 smmu_ctx_base = params_from_bl2->tzdram_base +
Varun Wadekare0c222f2017-11-10 13:23:34 -0800154 tegra194_get_smmu_ctx_offset();
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700155 tegra_smmu_save_context((uintptr_t)smmu_ctx_base);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700156
Steven Kao530b2172017-06-23 16:18:58 +0800157 /*
158 * Suspend SE, RNG1 and PKA1 only on silcon and fpga,
159 * since VDK does not support atomic se ctx save
160 */
161 if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
162 ret = tegra_se_suspend();
163 assert(ret == 0);
164 }
165
Varun Wadekar953699c2018-06-06 17:26:10 -0700166 /* Prepare for system suspend */
167 mce_update_cstate_info(&sc7_cstate_info);
Tejal Kudav153ba222017-02-14 18:02:04 -0800168
Varun Wadekar953699c2018-06-06 17:26:10 -0700169 do {
170 val = (uint32_t)mce_command_handler(
171 (uint32_t)MCE_CMD_IS_SC7_ALLOWED,
172 (uint32_t)TEGRA_NVG_CORE_C7,
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800173 MCE_CORE_SLEEP_TIME_INFINITE,
174 0U);
Varun Wadekar953699c2018-06-06 17:26:10 -0700175 } while (val == 0U);
Varun Wadekarda865de2017-11-10 13:27:29 -0800176
Varun Wadekar953699c2018-06-06 17:26:10 -0700177 /* Instruct the MCE to enter system suspend state */
178 ret = mce_command_handler(
179 (uint64_t)MCE_CMD_ENTER_CSTATE,
180 (uint64_t)TEGRA_NVG_CORE_C7,
181 MCE_CORE_SLEEP_TIME_INFINITE,
182 0U);
183 assert(ret == 0);
184
185 /* set system suspend state for house-keeping */
186 tegra194_set_system_suspend_entry();
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800187 } else {
188 ; /* do nothing */
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700189 }
190
191 return PSCI_E_SUCCESS;
192}
193
194/*******************************************************************************
Varun Wadekar0723bb62017-10-16 15:57:17 -0700195 * Helper function to check if this is the last ON CPU in the cluster
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700196 ******************************************************************************/
Varun Wadekar0723bb62017-10-16 15:57:17 -0700197static bool tegra_last_on_cpu_in_cluster(const plat_local_state_t *states,
198 uint32_t ncpu)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700199{
Varun Wadekar0723bb62017-10-16 15:57:17 -0700200 plat_local_state_t target;
201 bool last_on_cpu = true;
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800202 uint32_t num_cpus = ncpu, pos = 0;
Varun Wadekar0723bb62017-10-16 15:57:17 -0700203
204 do {
205 target = states[pos];
206 if (target != PLAT_MAX_OFF_STATE) {
207 last_on_cpu = false;
208 }
209 --num_cpus;
210 pos++;
211 } while (num_cpus != 0U);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700212
Varun Wadekar0723bb62017-10-16 15:57:17 -0700213 return last_on_cpu;
214}
215
216/*******************************************************************************
217 * Helper function to get target power state for the cluster
218 ******************************************************************************/
219static plat_local_state_t tegra_get_afflvl1_pwr_state(const plat_local_state_t *states,
220 uint32_t ncpu)
221{
222 uint32_t core_pos = (uint32_t)read_mpidr() & (uint32_t)MPIDR_CPU_MASK;
223 plat_local_state_t target = states[core_pos];
224 mce_cstate_info_t cstate_info = { 0 };
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700225
226 /* CPU suspend */
Varun Wadekar0723bb62017-10-16 15:57:17 -0700227 if (target == PSTATE_ID_CORE_POWERDN) {
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700228
229 /* Program default wake mask */
Krishna Sitaramanc64afeb2017-01-23 16:15:44 -0800230 cstate_info.wake_mask = TEGRA194_CORE_WAKE_MASK;
231 cstate_info.update_wake_mask = 1;
232 mce_update_cstate_info(&cstate_info);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700233 }
234
235 /* CPU off */
Varun Wadekar0723bb62017-10-16 15:57:17 -0700236 if (target == PLAT_MAX_OFF_STATE) {
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700237
238 /* Enable cluster powerdn from last CPU in the cluster */
Varun Wadekar0723bb62017-10-16 15:57:17 -0700239 if (tegra_last_on_cpu_in_cluster(states, ncpu)) {
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700240
Varun Wadekar0723bb62017-10-16 15:57:17 -0700241 /* Enable CC6 state and turn off wake mask */
242 cstate_info.cluster = (uint32_t)TEGRA_NVG_CLUSTER_CC6;
Vignesh Radhakrishnan90d80192017-12-27 21:04:49 -0800243 cstate_info.ccplex = (uint32_t)TEGRA_NVG_CG_CG7;
244 cstate_info.system_state_force = 1;
Krishna Sitaraman74813f92017-07-14 13:51:44 -0700245 cstate_info.update_wake_mask = 1U;
246 mce_update_cstate_info(&cstate_info);
247
248 } else {
Varun Wadekar0723bb62017-10-16 15:57:17 -0700249
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700250 /* Turn off wake_mask */
Krishna Sitaraman74813f92017-07-14 13:51:44 -0700251 cstate_info.update_wake_mask = 1U;
252 mce_update_cstate_info(&cstate_info);
Varun Wadekar0723bb62017-10-16 15:57:17 -0700253 target = PSCI_LOCAL_STATE_RUN;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700254 }
255 }
256
Varun Wadekar0723bb62017-10-16 15:57:17 -0700257 return target;
258}
259
260/*******************************************************************************
261 * Platform handler to calculate the proper target power level at the
262 * specified affinity level
263 ******************************************************************************/
264plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl,
265 const plat_local_state_t *states,
266 uint32_t ncpu)
267{
268 plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
269 uint32_t cpu = plat_my_core_pos();
270
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700271 /* System Suspend */
Varun Wadekar0723bb62017-10-16 15:57:17 -0700272 if ((lvl == (uint32_t)MPIDR_AFFLVL2) && (states[cpu] == PSTATE_ID_SOC_POWERDN)) {
273 target = PSTATE_ID_SOC_POWERDN;
274 }
275
276 /* CPU off, CPU suspend */
277 if (lvl == (uint32_t)MPIDR_AFFLVL1) {
278 target = tegra_get_afflvl1_pwr_state(states, ncpu);
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800279 }
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700280
Varun Wadekar0723bb62017-10-16 15:57:17 -0700281 /* target cluster/system state */
282 return target;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700283}
284
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800285int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700286{
287 const plat_local_state_t *pwr_domain_state =
288 target_state->pwr_domain_state;
289 plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800290 uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
Varun Wadekar362a6b22017-11-10 11:04:42 -0800291 TEGRA194_STATE_ID_MASK;
Steven Kao55c2ce72016-12-23 15:51:32 +0800292 uint64_t val;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700293
294 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
295 /*
296 * The TZRAM loses power when we enter system suspend. To
297 * allow graceful exit from system suspend, we need to copy
298 * BL3-1 over to TZDRAM.
299 */
300 val = params_from_bl2->tzdram_base +
Varun Wadekare0c222f2017-11-10 13:23:34 -0800301 tegra194_get_cpu_reset_handler_size();
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700302 memcpy((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
303 (uintptr_t)&__BL31_END__ - (uintptr_t)BL31_BASE);
304 }
305
306 return PSCI_E_SUCCESS;
307}
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700308
Varun Wadekarb5b15b22018-05-17 10:10:25 -0700309int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
310{
311 return PSCI_E_NOT_SUPPORTED;
312}
313
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800314int32_t tegra_soc_pwr_domain_on(u_register_t mpidr)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700315{
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800316 uint64_t target_cpu = mpidr & MPIDR_CPU_MASK;
317 uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700318 MPIDR_AFFINITY_BITS;
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800319 int32_t ret = 0;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700320
Varun Wadekara4e0a812017-10-17 10:53:33 -0700321 if (target_cluster > ((uint32_t)PLATFORM_CLUSTER_COUNT - 1U)) {
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700322 ERROR("%s: unsupported CPU (0x%lx)\n", __func__ , mpidr);
323 return PSCI_E_NOT_PRESENT;
324 }
325
326 /* construct the target CPU # */
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800327 target_cpu += (target_cluster << 1U);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700328
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800329 ret = mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U);
330 if (ret < 0) {
331 return PSCI_E_DENIED;
332 }
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700333
334 return PSCI_E_SUCCESS;
335}
336
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800337int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700338{
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800339 uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700340
341 /*
342 * Reset power state info for CPUs when onlining, we set
343 * deepest power when offlining a core but that may not be
344 * requested by non-secure sw which controls idle states. It
345 * will re-init this info from non-secure software when the
346 * core come online.
347 */
348
349 /*
350 * Check if we are exiting from deep sleep and restore SE
351 * context if we are.
352 */
353 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
Dilan Lee4e7a63c2017-08-10 16:01:42 +0800354
Steven Kao8f4f1022017-12-13 06:39:15 +0800355#if ENABLE_STRICT_CHECKING_MODE
Dilan Lee4e7a63c2017-08-10 16:01:42 +0800356 /*
357 * Enable strict checking after programming the GSC for
358 * enabling TZSRAM and TZDRAM
359 */
360 mce_enable_strict_checking();
Steven Kao8f4f1022017-12-13 06:39:15 +0800361#endif
Dilan Lee4e7a63c2017-08-10 16:01:42 +0800362
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700363 /* Init SMMU */
Vignesh Radhakrishnan978887f2017-07-11 15:16:08 -0700364 tegra_smmu_init();
365
Steven Kao530b2172017-06-23 16:18:58 +0800366 /* Resume SE, RNG1 and PKA1 */
367 tegra_se_resume();
368
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700369 /*
Varun Wadekar4edc17c2017-11-20 17:14:47 -0800370 * Program XUSB STREAMIDs
371 * ======================
372 * T19x XUSB has support for XUSB virtualization. It will
373 * have one physical function (PF) and four Virtual functions
374 * (VF)
375 *
376 * There were below two SIDs for XUSB until T186.
377 * 1) #define TEGRA_SID_XUSB_HOST 0x1bU
378 * 2) #define TEGRA_SID_XUSB_DEV 0x1cU
379 *
380 * We have below four new SIDs added for VF(s)
381 * 3) #define TEGRA_SID_XUSB_VF0 0x5dU
382 * 4) #define TEGRA_SID_XUSB_VF1 0x5eU
383 * 5) #define TEGRA_SID_XUSB_VF2 0x5fU
384 * 6) #define TEGRA_SID_XUSB_VF3 0x60U
385 *
386 * When virtualization is enabled then we have to disable SID
387 * override and program above SIDs in below newly added SID
388 * registers in XUSB PADCTL MMIO space. These registers are
389 * TZ protected and so need to be done in ATF.
390 *
391 * a) #define XUSB_PADCTL_HOST_AXI_STREAMID_PF_0 (0x136cU)
392 * b) #define XUSB_PADCTL_DEV_AXI_STREAMID_PF_0 (0x139cU)
393 * c) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_0 (0x1370U)
394 * d) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_1 (0x1374U)
395 * e) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_2 (0x1378U)
396 * f) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_3 (0x137cU)
397 *
398 * This change disables SID override and programs XUSB SIDs
399 * in above registers to support both virtualization and
400 * non-virtualization platforms
401 */
Varun Wadekara2eb6632018-03-23 10:44:40 -0700402 if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
403
404 mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
405 XUSB_PADCTL_HOST_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_HOST);
406 mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
407 XUSB_PADCTL_HOST_AXI_STREAMID_VF_0, TEGRA_SID_XUSB_VF0);
408 mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
409 XUSB_PADCTL_HOST_AXI_STREAMID_VF_1, TEGRA_SID_XUSB_VF1);
410 mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
411 XUSB_PADCTL_HOST_AXI_STREAMID_VF_2, TEGRA_SID_XUSB_VF2);
412 mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
413 XUSB_PADCTL_HOST_AXI_STREAMID_VF_3, TEGRA_SID_XUSB_VF3);
414 mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
415 XUSB_PADCTL_DEV_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_DEV);
416 }
Varun Wadekar4edc17c2017-11-20 17:14:47 -0800417
418 /*
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700419 * Reset power state info for the last core doing SC7
420 * entry and exit, we set deepest power state as CC7
421 * and SC7 for SC7 entry which may not be requested by
422 * non-secure SW which controls idle states.
423 */
424 }
425
426 return PSCI_E_SUCCESS;
427}
428
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800429int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700430{
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800431 uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
Krishna Sitaraman74813f92017-07-14 13:51:44 -0700432 int32_t ret = 0;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700433
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800434 (void)target_state;
435
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700436 /* Disable Denver's DCO operations */
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800437 if (impl == DENVER_IMPL) {
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700438 denver_disable_dco();
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800439 }
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700440
441 /* Turn off CPU */
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800442 ret = mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
443 (uint64_t)TEGRA_NVG_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
Krishna Sitaraman74813f92017-07-14 13:51:44 -0700444 assert(ret == 0);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700445
446 return PSCI_E_SUCCESS;
447}
448
449__dead2 void tegra_soc_prepare_system_off(void)
450{
451 /* System power off */
Vignesh Radhakrishnan2aaa41c2017-06-14 09:59:27 -0700452 mce_system_shutdown();
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700453
454 wfi();
455
456 /* wait for the system to power down */
457 for (;;) {
458 ;
459 }
460}
461
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800462int32_t tegra_soc_prepare_system_reset(void)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700463{
Vignesh Radhakrishnan2aaa41c2017-06-14 09:59:27 -0700464 /* System reboot */
465 mce_system_reboot();
466
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700467 return PSCI_E_SUCCESS;
468}