blob: 179dd9654e2a0b7277c4e527c81d7d0d6e6a1a3e [file] [log] [blame]
Varun Wadekar921b9062015-08-25 17:03:14 +05301/*
Antonio Nino Diaz4b32e622018-08-16 16:52:57 +01002 * 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 Wadekar921b9062015-08-25 17:03:14 +05304 *
dp-armfa3cf0b2017-05-03 09:38:09 +01005 * SPDX-License-Identifier: BSD-3-Clause
Varun Wadekar921b9062015-08-25 17:03:14 +05306 */
7
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00008#include <assert.h>
Jeetesh Burman50cd1062018-07-19 13:07:23 +05309#include <stdbool.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010#include <string.h>
11
Varun Wadekarabd153c2015-09-14 09:31:39 +053012#include <arch.h>
13#include <arch_helpers.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000014#include <common/bl_common.h>
15#include <common/debug.h>
Varun Wadekara64806a2016-01-05 15:17:41 -080016#include <context.h>
Harvey Hsiehfbdfce12016-11-23 19:13:08 +080017#include <cortex_a57.h>
Varun Wadekar89645092016-02-09 14:55:44 -080018#include <denver.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000019#include <lib/el3_runtime/context_mgmt.h>
20#include <lib/psci/psci.h>
21#include <plat/common/platform.h>
22
Jeetesh Burman50cd1062018-07-19 13:07:23 +053023#include <bpmp_ipc.h>
Varun Wadekarabd153c2015-09-14 09:31:39 +053024#include <mce.h>
Pritesh Raithatha75c94432018-08-03 15:48:15 +053025#include <memctrl_v2.h>
Jeetesh Burman50cd1062018-07-19 13:07:23 +053026#include <security_engine.h>
Varun Wadekarb8776152016-03-03 13:52:52 -080027#include <smmu.h>
Varun Wadekar782c83d2017-03-14 14:25:35 -070028#include <t18x_ari.h>
Varun Wadekarfa887672017-11-08 14:45:08 -080029#include <tegra186_private.h>
Varun Wadekar921b9062015-08-25 17:03:14 +053030#include <tegra_private.h>
31
Antonio Nino Diaz4b32e622018-08-16 16:52:57 +010032extern void memcpy16(void *dest, const void *src, unsigned int length);
Varun Wadekard66ee542016-02-29 10:24:30 -080033
Varun Wadekar42236572016-01-18 19:03:19 -080034/* state id mask */
Anthony Zhou5d1bb052017-03-03 16:23:08 +080035#define TEGRA186_STATE_ID_MASK 0xFU
Varun Wadekar42236572016-01-18 19:03:19 -080036/* constants to get power state's wake time */
Anthony Zhou5d1bb052017-03-03 16:23:08 +080037#define TEGRA186_WAKE_TIME_MASK 0x0FFFFFF0U
38#define TEGRA186_WAKE_TIME_SHIFT 4U
Varun Wadekar698e7c62016-03-28 15:05:03 -070039/* default core wake mask for CPU_SUSPEND */
Anthony Zhou5d1bb052017-03-03 16:23:08 +080040#define TEGRA186_CORE_WAKE_MASK 0x180cU
Varun Wadekarb8776152016-03-03 13:52:52 -080041/* context size to save during system suspend */
Anthony Zhou5d1bb052017-03-03 16:23:08 +080042#define TEGRA186_SE_CONTEXT_SIZE 3U
Varun Wadekar42236572016-01-18 19:03:19 -080043
Varun Wadekarb8776152016-03-03 13:52:52 -080044static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE];
Anthony Zhou5d1bb052017-03-03 16:23:08 +080045static struct tegra_psci_percpu_data {
46 uint32_t wake_time;
47} __aligned(CACHE_WRITEBACK_GRANULE) tegra_percpu_data[PLATFORM_CORE_COUNT];
Varun Wadekar42236572016-01-18 19:03:19 -080048
Anthony Zhou5d1bb052017-03-03 16:23:08 +080049int32_t tegra_soc_validate_power_state(uint32_t power_state,
Varun Wadekarc2c3a2a2016-01-08 17:38:51 -080050 psci_power_state_t *req_state)
Varun Wadekar921b9062015-08-25 17:03:14 +053051{
Anthony Zhou5d1bb052017-03-03 16:23:08 +080052 uint8_t state_id = (uint8_t)psci_get_pstate_id(power_state) & TEGRA186_STATE_ID_MASK;
53 uint32_t cpu = plat_my_core_pos();
54 int32_t ret = PSCI_E_SUCCESS;
Varun Wadekar89645092016-02-09 14:55:44 -080055
Krishna Sitaraman86569d12016-08-18 15:41:21 -070056 /* save the core wake time (in TSC ticks)*/
Anthony Zhou5d1bb052017-03-03 16:23:08 +080057 tegra_percpu_data[cpu].wake_time = (power_state & TEGRA186_WAKE_TIME_MASK)
Krishna Sitaraman86569d12016-08-18 15:41:21 -070058 << TEGRA186_WAKE_TIME_SHIFT;
Varun Wadekar42236572016-01-18 19:03:19 -080059
Mustafa Yigit Bilgenf40bc2c2016-09-02 19:30:22 -070060 /*
61 * Clean percpu_data[cpu] to DRAM. This needs to be done to ensure that
62 * the correct value is read in tegra_soc_pwr_domain_suspend(), which
63 * is called with caches disabled. It is possible to read a stale value
64 * from DRAM in that function, because the L2 cache is not flushed
65 * unless the cluster is entering CC6/CC7.
66 */
Anthony Zhou5d1bb052017-03-03 16:23:08 +080067 clean_dcache_range((uint64_t)&tegra_percpu_data[cpu],
68 sizeof(tegra_percpu_data[cpu]));
Mustafa Yigit Bilgenf40bc2c2016-09-02 19:30:22 -070069
Varun Wadekar42236572016-01-18 19:03:19 -080070 /* Sanity check the requested state id */
71 switch (state_id) {
72 case PSTATE_ID_CORE_IDLE:
73 case PSTATE_ID_CORE_POWERDN:
Varun Wadekar4a0b37a2016-04-09 00:36:42 -070074
75 /* Core powerdown request */
Varun Wadekar42236572016-01-18 19:03:19 -080076 req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -070077 req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
Varun Wadekar42236572016-01-18 19:03:19 -080078
79 break;
80
81 default:
82 ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
Anthony Zhou5d1bb052017-03-03 16:23:08 +080083 ret = PSCI_E_INVALID_PARAMS;
84 break;
Varun Wadekar42236572016-01-18 19:03:19 -080085 }
86
Anthony Zhou5d1bb052017-03-03 16:23:08 +080087 return ret;
Varun Wadekar42236572016-01-18 19:03:19 -080088}
89
Varun Wadekarb5b15b22018-05-17 10:10:25 -070090int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state)
91{
92 (void)cpu_state;
93 return PSCI_E_SUCCESS;
94}
95
Anthony Zhou5d1bb052017-03-03 16:23:08 +080096int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
Varun Wadekar42236572016-01-18 19:03:19 -080097{
98 const plat_local_state_t *pwr_domain_state;
Anthony Zhou5d1bb052017-03-03 16:23:08 +080099 uint8_t stateid_afflvl0, stateid_afflvl2;
100 uint32_t cpu = plat_my_core_pos();
101 const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700102 mce_cstate_info_t cstate_info = { 0 };
Pritesh Raithatha75c94432018-08-03 15:48:15 +0530103 uint64_t mc_ctx_base;
Varun Wadekarb8776152016-03-03 13:52:52 -0800104 uint32_t val;
105
Varun Wadekar42236572016-01-18 19:03:19 -0800106 /* get the state ID */
107 pwr_domain_state = target_state->pwr_domain_state;
108 stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] &
109 TEGRA186_STATE_ID_MASK;
Varun Wadekarb8776152016-03-03 13:52:52 -0800110 stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
111 TEGRA186_STATE_ID_MASK;
Varun Wadekar42236572016-01-18 19:03:19 -0800112
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700113 if ((stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ||
114 (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN)) {
Varun Wadekar42236572016-01-18 19:03:19 -0800115
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700116 /* Enter CPU idle/powerdown */
117 val = (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ?
Anthony Zhou0e07e452017-07-26 17:16:54 +0800118 (uint32_t)TEGRA_ARI_CORE_C6 : (uint32_t)TEGRA_ARI_CORE_C7;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800119 (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, (uint64_t)val,
120 tegra_percpu_data[cpu].wake_time, 0U);
Varun Wadekarc2c3a2a2016-01-08 17:38:51 -0800121
Varun Wadekarb8776152016-03-03 13:52:52 -0800122 } else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
123
Varun Wadekarb8776152016-03-03 13:52:52 -0800124 /* save SE registers */
125 se_regs[0] = mmio_read_32(TEGRA_SE0_BASE +
126 SE_MUTEX_WATCHDOG_NS_LIMIT);
127 se_regs[1] = mmio_read_32(TEGRA_RNG1_BASE +
128 RNG_MUTEX_WATCHDOG_NS_LIMIT);
129 se_regs[2] = mmio_read_32(TEGRA_PKA1_BASE +
130 PKA_MUTEX_WATCHDOG_NS_LIMIT);
131
132 /* save 'Secure Boot' Processor Feature Config Register */
133 val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG);
Steven Kao186485e2017-10-23 18:22:09 +0800134 mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SECURE_BOOTP_FCFG, val);
Varun Wadekarb8776152016-03-03 13:52:52 -0800135
Pritesh Raithatha75c94432018-08-03 15:48:15 +0530136 /* save MC context to TZDRAM */
137 mc_ctx_base = params_from_bl2->tzdram_base +
138 tegra186_get_mc_ctx_offset();
139 tegra_mc_save_context((uintptr_t)mc_ctx_base);
Varun Wadekarb8776152016-03-03 13:52:52 -0800140
141 /* Prepare for system suspend */
Anthony Zhou0e07e452017-07-26 17:16:54 +0800142 cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
143 cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC7;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700144 cstate_info.system_state_force = 1;
145 cstate_info.update_wake_mask = 1;
146 mce_update_cstate_info(&cstate_info);
Varun Wadekar2a7d87e2017-11-10 10:26:57 -0800147
Varun Wadekara9002bb2016-03-28 15:11:43 -0700148 /* Loop until system suspend is allowed */
149 do {
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800150 val = (uint32_t)mce_command_handler(
151 (uint64_t)MCE_CMD_IS_SC7_ALLOWED,
Anthony Zhou0e07e452017-07-26 17:16:54 +0800152 (uint64_t)TEGRA_ARI_CORE_C7,
Varun Wadekara9002bb2016-03-28 15:11:43 -0700153 MCE_CORE_SLEEP_TIME_INFINITE,
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800154 0U);
155 } while (val == 0U);
Varun Wadekara9002bb2016-03-28 15:11:43 -0700156
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700157 /* Instruct the MCE to enter system suspend state */
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800158 (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
Anthony Zhou0e07e452017-07-26 17:16:54 +0800159 (uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
Varun Wadekar2a7d87e2017-11-10 10:26:57 -0800160
161 /* set system suspend state for house-keeping */
162 tegra186_set_system_suspend_entry();
163
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800164 } else {
165 ; /* do nothing */
Varun Wadekar921b9062015-08-25 17:03:14 +0530166 }
167
168 return PSCI_E_SUCCESS;
169}
Varun Wadekarabd153c2015-09-14 09:31:39 +0530170
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700171/*******************************************************************************
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700172 * Helper function to check if this is the last ON CPU in the cluster
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700173 ******************************************************************************/
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700174static bool tegra_last_cpu_in_cluster(const plat_local_state_t *states,
175 uint32_t ncpu)
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700176{
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700177 plat_local_state_t target;
178 bool last_on_cpu = true;
179 uint32_t num_cpus = ncpu, pos = 0;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700180
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700181 do {
182 target = states[pos];
183 if (target != PLAT_MAX_OFF_STATE) {
184 last_on_cpu = false;
185 }
186 --num_cpus;
187 pos++;
188 } while (num_cpus != 0U);
189
190 return last_on_cpu;
191}
192
193/*******************************************************************************
194 * Helper function to get target power state for the cluster
195 ******************************************************************************/
196static plat_local_state_t tegra_get_afflvl1_pwr_state(const plat_local_state_t *states,
197 uint32_t ncpu)
198{
199 uint32_t core_pos = (uint32_t)read_mpidr() & (uint32_t)MPIDR_CPU_MASK;
200 uint32_t cpu = plat_my_core_pos();
201 int32_t ret;
202 plat_local_state_t target = states[core_pos];
203 mce_cstate_info_t cstate_info = { 0 };
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700204
205 /* CPU suspend */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700206 if (target == PSTATE_ID_CORE_POWERDN) {
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700207 /* Program default wake mask */
208 cstate_info.wake_mask = TEGRA186_CORE_WAKE_MASK;
209 cstate_info.update_wake_mask = 1;
210 mce_update_cstate_info(&cstate_info);
211
212 /* Check if CCx state is allowed. */
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800213 ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED,
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700214 (uint64_t)TEGRA_ARI_CORE_C7,
215 tegra_percpu_data[cpu].wake_time,
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800216 0U);
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700217 if (ret == 0) {
218 target = PSCI_LOCAL_STATE_RUN;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800219 }
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700220 }
221
222 /* CPU off */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700223 if (target == PLAT_MAX_OFF_STATE) {
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700224 /* Enable cluster powerdn from last CPU in the cluster */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700225 if (tegra_last_cpu_in_cluster(states, ncpu)) {
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700226 /* Enable CC7 state and turn off wake mask */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700227 cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700228 cstate_info.update_wake_mask = 1;
229 mce_update_cstate_info(&cstate_info);
230
231 /* Check if CCx state is allowed. */
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800232 ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED,
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700233 (uint64_t)TEGRA_ARI_CORE_C7,
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700234 MCE_CORE_SLEEP_TIME_INFINITE,
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800235 0U);
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700236 if (ret == 0) {
237 target = PSCI_LOCAL_STATE_RUN;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800238 }
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700239
240 } else {
241
242 /* Turn off wake_mask */
243 cstate_info.update_wake_mask = 1;
244 mce_update_cstate_info(&cstate_info);
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700245 target = PSCI_LOCAL_STATE_RUN;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700246 }
247 }
248
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700249 return target;
250}
251
252/*******************************************************************************
253 * Platform handler to calculate the proper target power level at the
254 * specified affinity level
255 ******************************************************************************/
Anthony Zhou0e07e452017-07-26 17:16:54 +0800256plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl,
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700257 const plat_local_state_t *states,
258 uint32_t ncpu)
259{
260 plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
Anthony Zhou0e07e452017-07-26 17:16:54 +0800261 uint32_t cpu = plat_my_core_pos();
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700262
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700263 /* System Suspend */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700264 if ((lvl == (uint32_t)MPIDR_AFFLVL2) &&
265 (states[cpu] == PSTATE_ID_SOC_POWERDN)) {
266 target = PSTATE_ID_SOC_POWERDN;
267 }
268
269 /* CPU off, CPU suspend */
270 if (lvl == (uint32_t)MPIDR_AFFLVL1) {
271 target = tegra_get_afflvl1_pwr_state(states, ncpu);
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800272 }
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700273
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700274 /* target cluster/system state */
275 return target;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700276}
277
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800278int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700279{
280 const plat_local_state_t *pwr_domain_state =
281 target_state->pwr_domain_state;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800282 const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
283 uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700284 TEGRA186_STATE_ID_MASK;
Steven Kao235e9c32016-12-23 15:43:17 +0800285 uint64_t val;
Jeetesh Burman50cd1062018-07-19 13:07:23 +0530286 uint64_t src_len_in_bytes = (uint64_t)(((uintptr_t)(&__BL31_END__) -
287 (uintptr_t)BL31_BASE));
288 int32_t ret;
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700289
290 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
Jeetesh Burman50cd1062018-07-19 13:07:23 +0530291 val = params_from_bl2->tzdram_base +
292 tegra186_get_cpu_reset_handler_size();
293
294 /* Initialise communication channel with BPMP */
295 assert(tegra_bpmp_ipc_init() == 0);
296
297 /* Enable SE clock */
Varun Wadekare55c27b2018-09-13 08:47:43 -0700298 ret = tegra_bpmp_ipc_enable_clock(TEGRA186_CLK_SE);
Jeetesh Burman50cd1062018-07-19 13:07:23 +0530299 if (ret != 0) {
300 ERROR("Failed to enable clock\n");
301 return ret;
302 }
303
304 /*
305 * Generate/save SHA256 of ATF during SC7 entry
306 */
307 if (tegra_se_save_sha256_hash(BL31_BASE,
308 (uint32_t)src_len_in_bytes) != 0) {
309 ERROR("Hash calculation failed. Reboot\n");
310 (void)tegra_soc_prepare_system_reset();
311 }
312
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700313 /*
314 * The TZRAM loses power when we enter system suspend. To
315 * allow graceful exit from system suspend, we need to copy
316 * BL3-1 over to TZDRAM.
317 */
318 val = params_from_bl2->tzdram_base +
Varun Wadekarfa887672017-11-08 14:45:08 -0800319 tegra186_get_cpu_reset_handler_size();
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700320 memcpy16((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
Varun Wadekara6c69ab2019-01-11 10:48:47 -0800321 (uintptr_t)BL31_END - (uintptr_t)BL31_BASE);
Jeetesh Burman50cd1062018-07-19 13:07:23 +0530322
Varun Wadekare55c27b2018-09-13 08:47:43 -0700323 ret = tegra_bpmp_ipc_disable_clock(TEGRA186_CLK_SE);
Jeetesh Burman50cd1062018-07-19 13:07:23 +0530324 if (ret != 0) {
325 ERROR("Failed to disable clock\n");
326 return ret;
327 }
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700328 }
329
330 return PSCI_E_SUCCESS;
331}
332
Varun Wadekarb5b15b22018-05-17 10:10:25 -0700333int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
334{
335 return PSCI_E_NOT_SUPPORTED;
336}
337
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800338int32_t tegra_soc_pwr_domain_on(u_register_t mpidr)
Varun Wadekarabd153c2015-09-14 09:31:39 +0530339{
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800340 int32_t ret = PSCI_E_SUCCESS;
Anthony Zhou5a4ce002017-06-28 16:49:16 +0800341 uint64_t target_cpu = mpidr & MPIDR_CPU_MASK;
342 uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
343 MPIDR_AFFINITY_BITS;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800344
Varun Wadekara2dd0b32017-10-17 10:29:24 -0700345 if (target_cluster > ((uint32_t)PLATFORM_CLUSTER_COUNT - 1U)) {
Varun Wadekarabd153c2015-09-14 09:31:39 +0530346
Varun Wadekarabd153c2015-09-14 09:31:39 +0530347 ERROR("%s: unsupported CPU (0x%lx)\n", __func__, mpidr);
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800348 ret = PSCI_E_NOT_PRESENT;
Varun Wadekarabd153c2015-09-14 09:31:39 +0530349
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800350 } else {
351 /* construct the target CPU # */
352 target_cpu |= (target_cluster << 2);
Varun Wadekarabd153c2015-09-14 09:31:39 +0530353
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800354 (void)mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U);
355 }
Varun Wadekarabd153c2015-09-14 09:31:39 +0530356
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800357 return ret;
Varun Wadekarabd153c2015-09-14 09:31:39 +0530358}
359
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800360int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
Varun Wadekarb8776152016-03-03 13:52:52 -0800361{
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800362 uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
363 uint8_t stateid_afflvl0 = target_state->pwr_domain_state[MPIDR_AFFLVL0];
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700364 mce_cstate_info_t cstate_info = { 0 };
Harvey Hsiehfbdfce12016-11-23 19:13:08 +0800365 uint64_t impl, val;
366 const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
367
Anthony Zhou5a4ce002017-06-28 16:49:16 +0800368 impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
Harvey Hsiehfbdfce12016-11-23 19:13:08 +0800369
370 /*
371 * Enable ECC and Parity Protection for Cortex-A57 CPUs (Tegra186
372 * A02p and beyond).
373 */
Anthony Zhou5a4ce002017-06-28 16:49:16 +0800374 if ((plat_params->l2_ecc_parity_prot_dis != 1) && (impl != DENVER_IMPL)) {
Harvey Hsiehfbdfce12016-11-23 19:13:08 +0800375
376 val = read_l2ctlr_el1();
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800377 val |= CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
Harvey Hsiehfbdfce12016-11-23 19:13:08 +0800378 write_l2ctlr_el1(val);
379 }
Varun Wadekarb8776152016-03-03 13:52:52 -0800380
381 /*
Varun Wadekar5a402562016-04-29 11:25:46 -0700382 * Reset power state info for CPUs when onlining, we set
383 * deepest power when offlining a core but that may not be
384 * requested by non-secure sw which controls idle states. It
385 * will re-init this info from non-secure software when the
386 * core come online.
Varun Wadekard2da47a2016-04-09 00:40:45 -0700387 */
Varun Wadekar5a402562016-04-29 11:25:46 -0700388 if (stateid_afflvl0 == PLAT_MAX_OFF_STATE) {
389
Anthony Zhou0e07e452017-07-26 17:16:54 +0800390 cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC1;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700391 cstate_info.update_wake_mask = 1;
392 mce_update_cstate_info(&cstate_info);
Varun Wadekar5a402562016-04-29 11:25:46 -0700393 }
Varun Wadekard2da47a2016-04-09 00:40:45 -0700394
395 /*
Varun Wadekarb8776152016-03-03 13:52:52 -0800396 * Check if we are exiting from deep sleep and restore SE
397 * context if we are.
398 */
Varun Wadekar5a402562016-04-29 11:25:46 -0700399 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
400
Varun Wadekarb8776152016-03-03 13:52:52 -0800401 mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT,
402 se_regs[0]);
403 mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT,
404 se_regs[1]);
405 mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT,
406 se_regs[2]);
407
408 /* Init SMMU */
409 tegra_smmu_init();
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700410
411 /*
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700412 * Reset power state info for the last core doing SC7
413 * entry and exit, we set deepest power state as CC7
414 * and SC7 for SC7 entry which may not be requested by
415 * non-secure SW which controls idle states.
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700416 */
Anthony Zhou0e07e452017-07-26 17:16:54 +0800417 cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
418 cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC1;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700419 cstate_info.update_wake_mask = 1;
420 mce_update_cstate_info(&cstate_info);
Varun Wadekarb8776152016-03-03 13:52:52 -0800421 }
422
423 return PSCI_E_SUCCESS;
424}
425
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800426int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
Varun Wadekarabd153c2015-09-14 09:31:39 +0530427{
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800428 uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & (uint64_t)MIDR_IMPL_MASK;
429
430 (void)target_state;
Varun Wadekara64806a2016-01-05 15:17:41 -0800431
Varun Wadekare26a55a2016-02-26 11:09:21 -0800432 /* Disable Denver's DCO operations */
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800433 if (impl == DENVER_IMPL) {
Varun Wadekare26a55a2016-02-26 11:09:21 -0800434 denver_disable_dco();
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800435 }
Varun Wadekare26a55a2016-02-26 11:09:21 -0800436
Varun Wadekarabd153c2015-09-14 09:31:39 +0530437 /* Turn off CPU */
Anthony Zhou0e07e452017-07-26 17:16:54 +0800438 (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
439 (uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700440
441 return PSCI_E_SUCCESS;
Varun Wadekarabd153c2015-09-14 09:31:39 +0530442}
Varun Wadekar782c83d2017-03-14 14:25:35 -0700443
444__dead2 void tegra_soc_prepare_system_off(void)
445{
Varun Wadekar71d0e8d2017-05-17 14:35:33 -0700446 /* power off the entire system */
Anthony Zhou0e07e452017-07-26 17:16:54 +0800447 mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF);
Varun Wadekard66ee542016-02-29 10:24:30 -0800448
449 wfi();
450
451 /* wait for the system to power down */
452 for (;;) {
453 ;
454 }
Varun Wadekar782c83d2017-03-14 14:25:35 -0700455}
Varun Wadekar38020c92016-01-07 14:36:12 -0800456
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800457int32_t tegra_soc_prepare_system_reset(void)
Varun Wadekar38020c92016-01-07 14:36:12 -0800458{
Anthony Zhou0e07e452017-07-26 17:16:54 +0800459 mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT);
Varun Wadekar38020c92016-01-07 14:36:12 -0800460
461 return PSCI_E_SUCCESS;
462}