blob: 6f58427b3be8b4688677700b20ac6b3410e6ee1a [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 */
Varun Wadekar17ad11a2018-11-09 09:08:16 -0800137 mc_ctx_base = params_from_bl2->tzdram_base;
Pritesh Raithatha75c94432018-08-03 15:48:15 +0530138 tegra_mc_save_context((uintptr_t)mc_ctx_base);
Varun Wadekarb8776152016-03-03 13:52:52 -0800139
140 /* Prepare for system suspend */
Anthony Zhou0e07e452017-07-26 17:16:54 +0800141 cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
142 cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC7;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700143 cstate_info.system_state_force = 1;
144 cstate_info.update_wake_mask = 1;
145 mce_update_cstate_info(&cstate_info);
Varun Wadekar2a7d87e2017-11-10 10:26:57 -0800146
Varun Wadekara9002bb2016-03-28 15:11:43 -0700147 /* Loop until system suspend is allowed */
148 do {
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800149 val = (uint32_t)mce_command_handler(
150 (uint64_t)MCE_CMD_IS_SC7_ALLOWED,
Anthony Zhou0e07e452017-07-26 17:16:54 +0800151 (uint64_t)TEGRA_ARI_CORE_C7,
Varun Wadekara9002bb2016-03-28 15:11:43 -0700152 MCE_CORE_SLEEP_TIME_INFINITE,
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800153 0U);
154 } while (val == 0U);
Varun Wadekara9002bb2016-03-28 15:11:43 -0700155
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700156 /* Instruct the MCE to enter system suspend state */
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800157 (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
Anthony Zhou0e07e452017-07-26 17:16:54 +0800158 (uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
Varun Wadekar2a7d87e2017-11-10 10:26:57 -0800159
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800160 } else {
161 ; /* do nothing */
Varun Wadekar921b9062015-08-25 17:03:14 +0530162 }
163
164 return PSCI_E_SUCCESS;
165}
Varun Wadekarabd153c2015-09-14 09:31:39 +0530166
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700167/*******************************************************************************
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700168 * Helper function to check if this is the last ON CPU in the cluster
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700169 ******************************************************************************/
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700170static bool tegra_last_cpu_in_cluster(const plat_local_state_t *states,
171 uint32_t ncpu)
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700172{
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700173 plat_local_state_t target;
174 bool last_on_cpu = true;
175 uint32_t num_cpus = ncpu, pos = 0;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700176
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700177 do {
178 target = states[pos];
179 if (target != PLAT_MAX_OFF_STATE) {
180 last_on_cpu = false;
181 }
182 --num_cpus;
183 pos++;
184 } while (num_cpus != 0U);
185
186 return last_on_cpu;
187}
188
189/*******************************************************************************
190 * Helper function to get target power state for the cluster
191 ******************************************************************************/
192static plat_local_state_t tegra_get_afflvl1_pwr_state(const plat_local_state_t *states,
193 uint32_t ncpu)
194{
195 uint32_t core_pos = (uint32_t)read_mpidr() & (uint32_t)MPIDR_CPU_MASK;
196 uint32_t cpu = plat_my_core_pos();
197 int32_t ret;
198 plat_local_state_t target = states[core_pos];
199 mce_cstate_info_t cstate_info = { 0 };
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700200
201 /* CPU suspend */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700202 if (target == PSTATE_ID_CORE_POWERDN) {
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700203 /* Program default wake mask */
204 cstate_info.wake_mask = TEGRA186_CORE_WAKE_MASK;
205 cstate_info.update_wake_mask = 1;
206 mce_update_cstate_info(&cstate_info);
207
208 /* Check if CCx state is allowed. */
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800209 ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED,
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700210 (uint64_t)TEGRA_ARI_CORE_C7,
211 tegra_percpu_data[cpu].wake_time,
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800212 0U);
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700213 if (ret == 0) {
214 target = PSCI_LOCAL_STATE_RUN;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800215 }
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700216 }
217
218 /* CPU off */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700219 if (target == PLAT_MAX_OFF_STATE) {
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700220 /* Enable cluster powerdn from last CPU in the cluster */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700221 if (tegra_last_cpu_in_cluster(states, ncpu)) {
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700222 /* Enable CC7 state and turn off wake mask */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700223 cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700224 cstate_info.update_wake_mask = 1;
225 mce_update_cstate_info(&cstate_info);
226
227 /* Check if CCx state is allowed. */
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800228 ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED,
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700229 (uint64_t)TEGRA_ARI_CORE_C7,
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700230 MCE_CORE_SLEEP_TIME_INFINITE,
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800231 0U);
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700232 if (ret == 0) {
233 target = PSCI_LOCAL_STATE_RUN;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800234 }
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700235
236 } else {
237
238 /* Turn off wake_mask */
239 cstate_info.update_wake_mask = 1;
240 mce_update_cstate_info(&cstate_info);
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700241 target = PSCI_LOCAL_STATE_RUN;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700242 }
243 }
244
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700245 return target;
246}
247
248/*******************************************************************************
249 * Platform handler to calculate the proper target power level at the
250 * specified affinity level
251 ******************************************************************************/
Anthony Zhou0e07e452017-07-26 17:16:54 +0800252plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl,
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700253 const plat_local_state_t *states,
254 uint32_t ncpu)
255{
256 plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
Anthony Zhou0e07e452017-07-26 17:16:54 +0800257 uint32_t cpu = plat_my_core_pos();
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700258
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700259 /* System Suspend */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700260 if ((lvl == (uint32_t)MPIDR_AFFLVL2) &&
261 (states[cpu] == PSTATE_ID_SOC_POWERDN)) {
262 target = PSTATE_ID_SOC_POWERDN;
263 }
264
265 /* CPU off, CPU suspend */
266 if (lvl == (uint32_t)MPIDR_AFFLVL1) {
267 target = tegra_get_afflvl1_pwr_state(states, ncpu);
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800268 }
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700269
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700270 /* target cluster/system state */
271 return target;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700272}
273
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800274int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700275{
276 const plat_local_state_t *pwr_domain_state =
277 target_state->pwr_domain_state;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800278 const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
279 uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700280 TEGRA186_STATE_ID_MASK;
Steven Kao235e9c32016-12-23 15:43:17 +0800281 uint64_t val;
Jeetesh Burman50cd1062018-07-19 13:07:23 +0530282 uint64_t src_len_in_bytes = (uint64_t)(((uintptr_t)(&__BL31_END__) -
283 (uintptr_t)BL31_BASE));
284 int32_t ret;
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700285
286 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
Jeetesh Burman50cd1062018-07-19 13:07:23 +0530287 val = params_from_bl2->tzdram_base +
Varun Wadekar17ad11a2018-11-09 09:08:16 -0800288 tegra186_get_mc_ctx_size();
Jeetesh Burman50cd1062018-07-19 13:07:23 +0530289
290 /* Initialise communication channel with BPMP */
291 assert(tegra_bpmp_ipc_init() == 0);
292
293 /* Enable SE clock */
Varun Wadekare55c27b2018-09-13 08:47:43 -0700294 ret = tegra_bpmp_ipc_enable_clock(TEGRA186_CLK_SE);
Jeetesh Burman50cd1062018-07-19 13:07:23 +0530295 if (ret != 0) {
296 ERROR("Failed to enable clock\n");
297 return ret;
298 }
299
300 /*
301 * Generate/save SHA256 of ATF during SC7 entry
302 */
303 if (tegra_se_save_sha256_hash(BL31_BASE,
304 (uint32_t)src_len_in_bytes) != 0) {
305 ERROR("Hash calculation failed. Reboot\n");
306 (void)tegra_soc_prepare_system_reset();
307 }
308
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700309 /*
310 * The TZRAM loses power when we enter system suspend. To
311 * allow graceful exit from system suspend, we need to copy
312 * BL3-1 over to TZDRAM.
313 */
314 val = params_from_bl2->tzdram_base +
Varun Wadekar17ad11a2018-11-09 09:08:16 -0800315 tegra186_get_mc_ctx_size();
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700316 memcpy16((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
Varun Wadekara6c69ab2019-01-11 10:48:47 -0800317 (uintptr_t)BL31_END - (uintptr_t)BL31_BASE);
Jeetesh Burman50cd1062018-07-19 13:07:23 +0530318
Varun Wadekar17ad11a2018-11-09 09:08:16 -0800319 /*
320 * Save code base and size; this would be used by SC7-RF to
321 * verify binary
322 */
323 mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV68_LO,
324 (uint32_t)val);
325 mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV0_HI,
326 (uint32_t)src_len_in_bytes);
327
Varun Wadekare55c27b2018-09-13 08:47:43 -0700328 ret = tegra_bpmp_ipc_disable_clock(TEGRA186_CLK_SE);
Jeetesh Burman50cd1062018-07-19 13:07:23 +0530329 if (ret != 0) {
330 ERROR("Failed to disable clock\n");
331 return ret;
332 }
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700333 }
334
335 return PSCI_E_SUCCESS;
336}
337
Varun Wadekarb5b15b22018-05-17 10:10:25 -0700338int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
339{
340 return PSCI_E_NOT_SUPPORTED;
341}
342
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800343int32_t tegra_soc_pwr_domain_on(u_register_t mpidr)
Varun Wadekarabd153c2015-09-14 09:31:39 +0530344{
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800345 int32_t ret = PSCI_E_SUCCESS;
Anthony Zhou5a4ce002017-06-28 16:49:16 +0800346 uint64_t target_cpu = mpidr & MPIDR_CPU_MASK;
347 uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
348 MPIDR_AFFINITY_BITS;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800349
Varun Wadekara2dd0b32017-10-17 10:29:24 -0700350 if (target_cluster > ((uint32_t)PLATFORM_CLUSTER_COUNT - 1U)) {
Varun Wadekarabd153c2015-09-14 09:31:39 +0530351
Varun Wadekarabd153c2015-09-14 09:31:39 +0530352 ERROR("%s: unsupported CPU (0x%lx)\n", __func__, mpidr);
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800353 ret = PSCI_E_NOT_PRESENT;
Varun Wadekarabd153c2015-09-14 09:31:39 +0530354
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800355 } else {
356 /* construct the target CPU # */
357 target_cpu |= (target_cluster << 2);
Varun Wadekarabd153c2015-09-14 09:31:39 +0530358
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800359 (void)mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U);
360 }
Varun Wadekarabd153c2015-09-14 09:31:39 +0530361
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800362 return ret;
Varun Wadekarabd153c2015-09-14 09:31:39 +0530363}
364
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800365int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
Varun Wadekarb8776152016-03-03 13:52:52 -0800366{
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800367 uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
368 uint8_t stateid_afflvl0 = target_state->pwr_domain_state[MPIDR_AFFLVL0];
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700369 mce_cstate_info_t cstate_info = { 0 };
Harvey Hsiehfbdfce12016-11-23 19:13:08 +0800370 uint64_t impl, val;
371 const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
372
Anthony Zhou5a4ce002017-06-28 16:49:16 +0800373 impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
Harvey Hsiehfbdfce12016-11-23 19:13:08 +0800374
375 /*
376 * Enable ECC and Parity Protection for Cortex-A57 CPUs (Tegra186
377 * A02p and beyond).
378 */
Anthony Zhou5a4ce002017-06-28 16:49:16 +0800379 if ((plat_params->l2_ecc_parity_prot_dis != 1) && (impl != DENVER_IMPL)) {
Harvey Hsiehfbdfce12016-11-23 19:13:08 +0800380
381 val = read_l2ctlr_el1();
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800382 val |= CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
Harvey Hsiehfbdfce12016-11-23 19:13:08 +0800383 write_l2ctlr_el1(val);
384 }
Varun Wadekarb8776152016-03-03 13:52:52 -0800385
386 /*
Varun Wadekar5a402562016-04-29 11:25:46 -0700387 * Reset power state info for CPUs when onlining, we set
388 * deepest power when offlining a core but that may not be
389 * requested by non-secure sw which controls idle states. It
390 * will re-init this info from non-secure software when the
391 * core come online.
Varun Wadekard2da47a2016-04-09 00:40:45 -0700392 */
Varun Wadekar5a402562016-04-29 11:25:46 -0700393 if (stateid_afflvl0 == PLAT_MAX_OFF_STATE) {
394
Anthony Zhou0e07e452017-07-26 17:16:54 +0800395 cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC1;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700396 cstate_info.update_wake_mask = 1;
397 mce_update_cstate_info(&cstate_info);
Varun Wadekar5a402562016-04-29 11:25:46 -0700398 }
Varun Wadekard2da47a2016-04-09 00:40:45 -0700399
400 /*
Varun Wadekarb8776152016-03-03 13:52:52 -0800401 * Check if we are exiting from deep sleep and restore SE
402 * context if we are.
403 */
Varun Wadekar5a402562016-04-29 11:25:46 -0700404 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
405
Varun Wadekarb8776152016-03-03 13:52:52 -0800406 mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT,
407 se_regs[0]);
408 mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT,
409 se_regs[1]);
410 mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT,
411 se_regs[2]);
412
413 /* Init SMMU */
414 tegra_smmu_init();
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700415
416 /*
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700417 * Reset power state info for the last core doing SC7
418 * entry and exit, we set deepest power state as CC7
419 * and SC7 for SC7 entry which may not be requested by
420 * non-secure SW which controls idle states.
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700421 */
Anthony Zhou0e07e452017-07-26 17:16:54 +0800422 cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
423 cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC1;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700424 cstate_info.update_wake_mask = 1;
425 mce_update_cstate_info(&cstate_info);
Varun Wadekarb8776152016-03-03 13:52:52 -0800426 }
427
428 return PSCI_E_SUCCESS;
429}
430
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800431int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
Varun Wadekarabd153c2015-09-14 09:31:39 +0530432{
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800433 uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & (uint64_t)MIDR_IMPL_MASK;
434
435 (void)target_state;
Varun Wadekara64806a2016-01-05 15:17:41 -0800436
Varun Wadekare26a55a2016-02-26 11:09:21 -0800437 /* Disable Denver's DCO operations */
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800438 if (impl == DENVER_IMPL) {
Varun Wadekare26a55a2016-02-26 11:09:21 -0800439 denver_disable_dco();
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800440 }
Varun Wadekare26a55a2016-02-26 11:09:21 -0800441
Varun Wadekarabd153c2015-09-14 09:31:39 +0530442 /* Turn off CPU */
Anthony Zhou0e07e452017-07-26 17:16:54 +0800443 (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
444 (uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700445
446 return PSCI_E_SUCCESS;
Varun Wadekarabd153c2015-09-14 09:31:39 +0530447}
Varun Wadekar782c83d2017-03-14 14:25:35 -0700448
449__dead2 void tegra_soc_prepare_system_off(void)
450{
Varun Wadekar71d0e8d2017-05-17 14:35:33 -0700451 /* power off the entire system */
Anthony Zhou0e07e452017-07-26 17:16:54 +0800452 mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF);
Varun Wadekard66ee542016-02-29 10:24:30 -0800453
454 wfi();
455
456 /* wait for the system to power down */
457 for (;;) {
458 ;
459 }
Varun Wadekar782c83d2017-03-14 14:25:35 -0700460}
Varun Wadekar38020c92016-01-07 14:36:12 -0800461
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800462int32_t tegra_soc_prepare_system_reset(void)
Varun Wadekar38020c92016-01-07 14:36:12 -0800463{
Anthony Zhou0e07e452017-07-26 17:16:54 +0800464 mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT);
Varun Wadekar38020c92016-01-07 14:36:12 -0800465
466 return PSCI_E_SUCCESS;
467}