blob: 7af3b325ddfc3077994f70b36d0ab1e561fac1f1 [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>
Jeetesh Burmandbcc95c2018-07-06 20:03:38 +053013#include <bpmp_ipc.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070014#include <common/bl_common.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070015#include <common/debug.h>
Steven Kao530b2172017-06-23 16:18:58 +080016#include <context.h>
Jeetesh Burmandbcc95c2018-07-06 20:03:38 +053017#include <drivers/delay_timer.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070018#include <denver.h>
Steven Kao530b2172017-06-23 16:18:58 +080019#include <lib/el3_runtime/context_mgmt.h>
20#include <lib/psci/psci.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070021#include <mce.h>
Dilan Lee4e7a63c2017-08-10 16:01:42 +080022#include <mce_private.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070023#include <plat/common/platform.h>
Steven Kao530b2172017-06-23 16:18:58 +080024#include <se.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070025#include <smmu.h>
Tejal Kudav153ba222017-02-14 18:02:04 -080026#include <t194_nvg.h>
Varun Wadekare0c222f2017-11-10 13:23:34 -080027#include <tegra194_private.h>
Steven Kao530b2172017-06-23 16:18:58 +080028#include <tegra_platform.h>
29#include <tegra_private.h>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070030
Varun Wadekar362a6b22017-11-10 11:04:42 -080031extern uint32_t __tegra194_cpu_reset_handler_data,
32 __tegra194_cpu_reset_handler_end;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070033
34/* TZDRAM offset for saving SMMU context */
Varun Wadekar362a6b22017-11-10 11:04:42 -080035#define TEGRA194_SMMU_CTX_OFFSET 16U
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070036
37/* state id mask */
Varun Wadekar362a6b22017-11-10 11:04:42 -080038#define TEGRA194_STATE_ID_MASK 0xFU
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070039/* constants to get power state's wake time */
Varun Wadekar362a6b22017-11-10 11:04:42 -080040#define TEGRA194_WAKE_TIME_MASK 0x0FFFFFF0U
41#define TEGRA194_WAKE_TIME_SHIFT 4U
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070042/* default core wake mask for CPU_SUSPEND */
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080043#define TEGRA194_CORE_WAKE_MASK 0x180cU
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070044
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080045static struct t19x_psci_percpu_data {
46 uint32_t wake_time;
47} __aligned(CACHE_WRITEBACK_GRANULE) t19x_percpu_data[PLATFORM_CORE_COUNT];
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070048
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080049int32_t tegra_soc_validate_power_state(uint32_t power_state,
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070050 psci_power_state_t *req_state)
51{
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080052 uint8_t state_id = (uint8_t)psci_get_pstate_id(power_state) &
Varun Wadekar362a6b22017-11-10 11:04:42 -080053 TEGRA194_STATE_ID_MASK;
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080054 uint32_t cpu = plat_my_core_pos();
55 int32_t ret = PSCI_E_SUCCESS;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070056
57 /* save the core wake time (in TSC ticks)*/
Varun Wadekar362a6b22017-11-10 11:04:42 -080058 t19x_percpu_data[cpu].wake_time = (power_state & TEGRA194_WAKE_TIME_MASK)
59 << TEGRA194_WAKE_TIME_SHIFT;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070060
61 /*
Varun Wadekar56c64592019-12-03 08:50:57 -080062 * Clean t19x_percpu_data[cpu] to DRAM. This needs to be done to ensure
63 * that the correct value is read in tegra_soc_pwr_domain_suspend(),
64 * which is called with caches disabled. It is possible to read a stale
65 * value from DRAM in that function, because the L2 cache is not flushed
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070066 * unless the cluster is entering CC6/CC7.
67 */
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080068 clean_dcache_range((uint64_t)&t19x_percpu_data[cpu],
69 sizeof(t19x_percpu_data[cpu]));
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070070
71 /* Sanity check the requested state id */
72 switch (state_id) {
73 case PSTATE_ID_CORE_IDLE:
Varun Wadekarc61094b2017-12-27 18:01:59 -080074
75 /* Core idle request */
76 req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
77 req_state->pwr_domain_state[MPIDR_AFFLVL1] = PSCI_LOCAL_STATE_RUN;
78 break;
79
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070080 case PSTATE_ID_CORE_POWERDN:
81
82 /* Core powerdown request */
83 req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id;
84 req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
85
86 break;
87
88 default:
89 ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080090 ret = PSCI_E_INVALID_PARAMS;
91 break;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070092 }
93
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +080094 return ret;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -070095}
96
Varun Wadekarc61094b2017-12-27 18:01:59 -080097int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state)
98{
99 uint32_t cpu = plat_my_core_pos();
100 mce_cstate_info_t cstate_info = { 0 };
101
102 /* Program default wake mask */
103 cstate_info.wake_mask = TEGRA194_CORE_WAKE_MASK;
104 cstate_info.update_wake_mask = 1;
105 mce_update_cstate_info(&cstate_info);
106
107 /* Enter CPU idle */
108 (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
109 (uint64_t)TEGRA_NVG_CORE_C6,
110 t19x_percpu_data[cpu].wake_time,
111 0U);
112
113 return PSCI_E_SUCCESS;
114}
115
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800116int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700117{
118 const plat_local_state_t *pwr_domain_state;
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800119 uint8_t stateid_afflvl0, stateid_afflvl2;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700120 plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
121 uint64_t smmu_ctx_base;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700122 uint32_t val;
Vignesh Radhakrishnand7a5c252017-05-25 16:27:42 -0700123 mce_cstate_info_t sc7_cstate_info = {
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800124 .cluster = (uint32_t)TEGRA_NVG_CLUSTER_CC6,
Vignesh Radhakrishnan85c129f2017-12-20 15:04:26 -0800125 .ccplex = (uint32_t)TEGRA_NVG_CG_CG7,
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800126 .system = (uint32_t)TEGRA_NVG_SYSTEM_SC7,
127 .system_state_force = 1U,
128 .update_wake_mask = 1U,
Vignesh Radhakrishnand7a5c252017-05-25 16:27:42 -0700129 };
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800130 uint32_t cpu = plat_my_core_pos();
Vignesh Radhakrishnand7a5c252017-05-25 16:27:42 -0700131 int32_t ret = 0;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700132
133 /* get the state ID */
134 pwr_domain_state = target_state->pwr_domain_state;
135 stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] &
Varun Wadekar362a6b22017-11-10 11:04:42 -0800136 TEGRA194_STATE_ID_MASK;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700137 stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
Varun Wadekar362a6b22017-11-10 11:04:42 -0800138 TEGRA194_STATE_ID_MASK;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700139
kalyani chidambarame480c4e2018-07-24 13:58:27 -0700140 if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700141
Varun Wadekarc61094b2017-12-27 18:01:59 -0800142 /* Enter CPU powerdown */
143 (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
144 (uint64_t)TEGRA_NVG_CORE_C7,
145 t19x_percpu_data[cpu].wake_time,
146 0U);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700147
148 } else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
149
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700150 /* save 'Secure Boot' Processor Feature Config Register */
151 val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG);
Steven Kao4607f172017-10-23 18:35:14 +0800152 mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SECURE_BOOTP_FCFG, val);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700153
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700154 /* save SMMU context */
155 smmu_ctx_base = params_from_bl2->tzdram_base +
Varun Wadekare0c222f2017-11-10 13:23:34 -0800156 tegra194_get_smmu_ctx_offset();
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700157 tegra_smmu_save_context((uintptr_t)smmu_ctx_base);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700158
Steven Kao530b2172017-06-23 16:18:58 +0800159 /*
160 * Suspend SE, RNG1 and PKA1 only on silcon and fpga,
161 * since VDK does not support atomic se ctx save
162 */
163 if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
164 ret = tegra_se_suspend();
165 assert(ret == 0);
166 }
167
Varun Wadekar953699c2018-06-06 17:26:10 -0700168 /* Prepare for system suspend */
169 mce_update_cstate_info(&sc7_cstate_info);
Tejal Kudav153ba222017-02-14 18:02:04 -0800170
Varun Wadekar953699c2018-06-06 17:26:10 -0700171 do {
172 val = (uint32_t)mce_command_handler(
173 (uint32_t)MCE_CMD_IS_SC7_ALLOWED,
174 (uint32_t)TEGRA_NVG_CORE_C7,
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800175 MCE_CORE_SLEEP_TIME_INFINITE,
176 0U);
Varun Wadekar953699c2018-06-06 17:26:10 -0700177 } while (val == 0U);
Varun Wadekarda865de2017-11-10 13:27:29 -0800178
Varun Wadekar953699c2018-06-06 17:26:10 -0700179 /* Instruct the MCE to enter system suspend state */
180 ret = mce_command_handler(
181 (uint64_t)MCE_CMD_ENTER_CSTATE,
182 (uint64_t)TEGRA_NVG_CORE_C7,
183 MCE_CORE_SLEEP_TIME_INFINITE,
184 0U);
185 assert(ret == 0);
186
187 /* set system suspend state for house-keeping */
188 tegra194_set_system_suspend_entry();
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800189 } else {
190 ; /* do nothing */
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700191 }
192
193 return PSCI_E_SUCCESS;
194}
195
196/*******************************************************************************
Varun Wadekar0723bb62017-10-16 15:57:17 -0700197 * Helper function to check if this is the last ON CPU in the cluster
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700198 ******************************************************************************/
Varun Wadekar0723bb62017-10-16 15:57:17 -0700199static bool tegra_last_on_cpu_in_cluster(const plat_local_state_t *states,
200 uint32_t ncpu)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700201{
Varun Wadekar0723bb62017-10-16 15:57:17 -0700202 plat_local_state_t target;
203 bool last_on_cpu = true;
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800204 uint32_t num_cpus = ncpu, pos = 0;
Varun Wadekar0723bb62017-10-16 15:57:17 -0700205
206 do {
207 target = states[pos];
208 if (target != PLAT_MAX_OFF_STATE) {
209 last_on_cpu = false;
210 }
211 --num_cpus;
212 pos++;
213 } while (num_cpus != 0U);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700214
Varun Wadekar0723bb62017-10-16 15:57:17 -0700215 return last_on_cpu;
216}
217
218/*******************************************************************************
219 * Helper function to get target power state for the cluster
220 ******************************************************************************/
221static plat_local_state_t tegra_get_afflvl1_pwr_state(const plat_local_state_t *states,
222 uint32_t ncpu)
223{
224 uint32_t core_pos = (uint32_t)read_mpidr() & (uint32_t)MPIDR_CPU_MASK;
225 plat_local_state_t target = states[core_pos];
226 mce_cstate_info_t cstate_info = { 0 };
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700227
228 /* CPU suspend */
Varun Wadekar0723bb62017-10-16 15:57:17 -0700229 if (target == PSTATE_ID_CORE_POWERDN) {
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700230
231 /* Program default wake mask */
Krishna Sitaramanc64afeb2017-01-23 16:15:44 -0800232 cstate_info.wake_mask = TEGRA194_CORE_WAKE_MASK;
233 cstate_info.update_wake_mask = 1;
234 mce_update_cstate_info(&cstate_info);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700235 }
236
237 /* CPU off */
Varun Wadekar0723bb62017-10-16 15:57:17 -0700238 if (target == PLAT_MAX_OFF_STATE) {
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700239
240 /* Enable cluster powerdn from last CPU in the cluster */
Varun Wadekar0723bb62017-10-16 15:57:17 -0700241 if (tegra_last_on_cpu_in_cluster(states, ncpu)) {
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700242
Varun Wadekar0723bb62017-10-16 15:57:17 -0700243 /* Enable CC6 state and turn off wake mask */
244 cstate_info.cluster = (uint32_t)TEGRA_NVG_CLUSTER_CC6;
Vignesh Radhakrishnan90d80192017-12-27 21:04:49 -0800245 cstate_info.ccplex = (uint32_t)TEGRA_NVG_CG_CG7;
246 cstate_info.system_state_force = 1;
Krishna Sitaraman74813f92017-07-14 13:51:44 -0700247 cstate_info.update_wake_mask = 1U;
248 mce_update_cstate_info(&cstate_info);
249
250 } else {
Varun Wadekar0723bb62017-10-16 15:57:17 -0700251
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700252 /* Turn off wake_mask */
Krishna Sitaraman74813f92017-07-14 13:51:44 -0700253 cstate_info.update_wake_mask = 1U;
254 mce_update_cstate_info(&cstate_info);
Varun Wadekar0723bb62017-10-16 15:57:17 -0700255 target = PSCI_LOCAL_STATE_RUN;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700256 }
257 }
258
Varun Wadekar0723bb62017-10-16 15:57:17 -0700259 return target;
260}
261
262/*******************************************************************************
263 * Platform handler to calculate the proper target power level at the
264 * specified affinity level
265 ******************************************************************************/
266plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl,
267 const plat_local_state_t *states,
268 uint32_t ncpu)
269{
270 plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
271 uint32_t cpu = plat_my_core_pos();
272
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700273 /* System Suspend */
Varun Wadekar0723bb62017-10-16 15:57:17 -0700274 if ((lvl == (uint32_t)MPIDR_AFFLVL2) && (states[cpu] == PSTATE_ID_SOC_POWERDN)) {
275 target = PSTATE_ID_SOC_POWERDN;
276 }
277
278 /* CPU off, CPU suspend */
279 if (lvl == (uint32_t)MPIDR_AFFLVL1) {
280 target = tegra_get_afflvl1_pwr_state(states, ncpu);
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800281 }
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700282
Varun Wadekar0723bb62017-10-16 15:57:17 -0700283 /* target cluster/system state */
284 return target;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700285}
286
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800287int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700288{
289 const plat_local_state_t *pwr_domain_state =
290 target_state->pwr_domain_state;
291 plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800292 uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
Varun Wadekar362a6b22017-11-10 11:04:42 -0800293 TEGRA194_STATE_ID_MASK;
Jeetesh Burmandbcc95c2018-07-06 20:03:38 +0530294 uint64_t src_len_in_bytes = (uintptr_t)&__BL31_END__ - (uintptr_t)BL31_BASE;
Steven Kao55c2ce72016-12-23 15:51:32 +0800295 uint64_t val;
Jeetesh Burmandbcc95c2018-07-06 20:03:38 +0530296 int32_t ret = PSCI_E_SUCCESS;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700297
298 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
Jeetesh Burmandbcc95c2018-07-06 20:03:38 +0530299 val = params_from_bl2->tzdram_base +
300 tegra194_get_cpu_reset_handler_size();
301
302 /* initialise communication channel with BPMP */
303 ret = tegra_bpmp_ipc_init();
304 assert(ret == 0);
305
306 /* Enable SE clock before SE context save */
307 ret = tegra_bpmp_ipc_enable_clock(TEGRA_CLK_SE);
308 assert(ret == 0);
309
310 /*
311 * It is very unlikely that the BL31 image would be
312 * bigger than 2^32 bytes
313 */
314 assert(src_len_in_bytes < UINT32_MAX);
315
316 if (tegra_se_calculate_save_sha256(BL31_BASE,
317 (uint32_t)src_len_in_bytes) != 0) {
318 ERROR("Hash calculation failed. Reboot\n");
319 (void)tegra_soc_prepare_system_reset();
320 }
321
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700322 /*
323 * The TZRAM loses power when we enter system suspend. To
324 * allow graceful exit from system suspend, we need to copy
325 * BL3-1 over to TZDRAM.
326 */
327 val = params_from_bl2->tzdram_base +
Varun Wadekare0c222f2017-11-10 13:23:34 -0800328 tegra194_get_cpu_reset_handler_size();
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700329 memcpy((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
Jeetesh Burmandbcc95c2018-07-06 20:03:38 +0530330 src_len_in_bytes);
331
332 /* Disable SE clock after SE context save */
333 ret = tegra_bpmp_ipc_disable_clock(TEGRA_CLK_SE);
334 assert(ret == 0);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700335 }
336
Jeetesh Burmandbcc95c2018-07-06 20:03:38 +0530337 return ret;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700338}
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700339
Varun Wadekarb5b15b22018-05-17 10:10:25 -0700340int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
341{
342 return PSCI_E_NOT_SUPPORTED;
343}
344
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800345int32_t tegra_soc_pwr_domain_on(u_register_t mpidr)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700346{
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800347 uint64_t target_cpu = mpidr & MPIDR_CPU_MASK;
348 uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700349 MPIDR_AFFINITY_BITS;
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800350 int32_t ret = 0;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700351
Varun Wadekara4e0a812017-10-17 10:53:33 -0700352 if (target_cluster > ((uint32_t)PLATFORM_CLUSTER_COUNT - 1U)) {
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700353 ERROR("%s: unsupported CPU (0x%lx)\n", __func__ , mpidr);
354 return PSCI_E_NOT_PRESENT;
355 }
356
357 /* construct the target CPU # */
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800358 target_cpu += (target_cluster << 1U);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700359
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800360 ret = mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U);
361 if (ret < 0) {
362 return PSCI_E_DENIED;
363 }
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700364
365 return PSCI_E_SUCCESS;
366}
367
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800368int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700369{
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800370 uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700371
372 /*
373 * Reset power state info for CPUs when onlining, we set
374 * deepest power when offlining a core but that may not be
375 * requested by non-secure sw which controls idle states. It
376 * will re-init this info from non-secure software when the
377 * core come online.
378 */
379
380 /*
381 * Check if we are exiting from deep sleep and restore SE
382 * context if we are.
383 */
384 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
Dilan Lee4e7a63c2017-08-10 16:01:42 +0800385
Steven Kao8f4f1022017-12-13 06:39:15 +0800386#if ENABLE_STRICT_CHECKING_MODE
Dilan Lee4e7a63c2017-08-10 16:01:42 +0800387 /*
388 * Enable strict checking after programming the GSC for
389 * enabling TZSRAM and TZDRAM
390 */
391 mce_enable_strict_checking();
Steven Kao8f4f1022017-12-13 06:39:15 +0800392#endif
Dilan Lee4e7a63c2017-08-10 16:01:42 +0800393
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700394 /* Init SMMU */
Vignesh Radhakrishnan978887f2017-07-11 15:16:08 -0700395 tegra_smmu_init();
396
Steven Kao530b2172017-06-23 16:18:58 +0800397 /* Resume SE, RNG1 and PKA1 */
398 tegra_se_resume();
399
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700400 /*
Varun Wadekar4edc17c2017-11-20 17:14:47 -0800401 * Program XUSB STREAMIDs
402 * ======================
403 * T19x XUSB has support for XUSB virtualization. It will
404 * have one physical function (PF) and four Virtual functions
405 * (VF)
406 *
407 * There were below two SIDs for XUSB until T186.
408 * 1) #define TEGRA_SID_XUSB_HOST 0x1bU
409 * 2) #define TEGRA_SID_XUSB_DEV 0x1cU
410 *
411 * We have below four new SIDs added for VF(s)
412 * 3) #define TEGRA_SID_XUSB_VF0 0x5dU
413 * 4) #define TEGRA_SID_XUSB_VF1 0x5eU
414 * 5) #define TEGRA_SID_XUSB_VF2 0x5fU
415 * 6) #define TEGRA_SID_XUSB_VF3 0x60U
416 *
417 * When virtualization is enabled then we have to disable SID
418 * override and program above SIDs in below newly added SID
419 * registers in XUSB PADCTL MMIO space. These registers are
420 * TZ protected and so need to be done in ATF.
421 *
422 * a) #define XUSB_PADCTL_HOST_AXI_STREAMID_PF_0 (0x136cU)
423 * b) #define XUSB_PADCTL_DEV_AXI_STREAMID_PF_0 (0x139cU)
424 * c) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_0 (0x1370U)
425 * d) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_1 (0x1374U)
426 * e) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_2 (0x1378U)
427 * f) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_3 (0x137cU)
428 *
429 * This change disables SID override and programs XUSB SIDs
430 * in above registers to support both virtualization and
431 * non-virtualization platforms
432 */
Varun Wadekara2eb6632018-03-23 10:44:40 -0700433 if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
434
435 mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
436 XUSB_PADCTL_HOST_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_HOST);
437 mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
438 XUSB_PADCTL_HOST_AXI_STREAMID_VF_0, TEGRA_SID_XUSB_VF0);
439 mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
440 XUSB_PADCTL_HOST_AXI_STREAMID_VF_1, TEGRA_SID_XUSB_VF1);
441 mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
442 XUSB_PADCTL_HOST_AXI_STREAMID_VF_2, TEGRA_SID_XUSB_VF2);
443 mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
444 XUSB_PADCTL_HOST_AXI_STREAMID_VF_3, TEGRA_SID_XUSB_VF3);
445 mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
446 XUSB_PADCTL_DEV_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_DEV);
447 }
Varun Wadekar4edc17c2017-11-20 17:14:47 -0800448
449 /*
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700450 * Reset power state info for the last core doing SC7
451 * entry and exit, we set deepest power state as CC7
452 * and SC7 for SC7 entry which may not be requested by
453 * non-secure SW which controls idle states.
454 */
455 }
456
457 return PSCI_E_SUCCESS;
458}
459
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800460int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700461{
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800462 uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
Krishna Sitaraman74813f92017-07-14 13:51:44 -0700463 int32_t ret = 0;
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700464
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800465 (void)target_state;
466
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700467 /* Disable Denver's DCO operations */
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800468 if (impl == DENVER_IMPL) {
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700469 denver_disable_dco();
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800470 }
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700471
472 /* Turn off CPU */
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800473 ret = mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
474 (uint64_t)TEGRA_NVG_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
Krishna Sitaraman74813f92017-07-14 13:51:44 -0700475 assert(ret == 0);
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700476
477 return PSCI_E_SUCCESS;
478}
479
480__dead2 void tegra_soc_prepare_system_off(void)
481{
482 /* System power off */
Vignesh Radhakrishnan2aaa41c2017-06-14 09:59:27 -0700483 mce_system_shutdown();
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700484
485 wfi();
486
487 /* wait for the system to power down */
488 for (;;) {
489 ;
490 }
491}
492
Anthony Zhou8bf6d4e2017-09-20 17:44:43 +0800493int32_t tegra_soc_prepare_system_reset(void)
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700494{
Vignesh Radhakrishnan2aaa41c2017-06-14 09:59:27 -0700495 /* System reboot */
496 mce_system_reboot();
497
Varun Wadekarecd6a5a2018-04-09 17:48:58 -0700498 return PSCI_E_SUCCESS;
499}