blob: bd13dc2a1dc6a3b4f5edd497780241f8086ac094 [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 Wadekar921b9062015-08-25 17:03:14 +05303 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Varun Wadekar921b9062015-08-25 17:03:14 +05305 */
6
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00007#include <assert.h>
8#include <string.h>
9
Varun Wadekarabd153c2015-09-14 09:31:39 +053010#include <arch.h>
11#include <arch_helpers.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000012#include <common/bl_common.h>
13#include <common/debug.h>
Varun Wadekara64806a2016-01-05 15:17:41 -080014#include <context.h>
Harvey Hsiehfbdfce12016-11-23 19:13:08 +080015#include <cortex_a57.h>
Varun Wadekar89645092016-02-09 14:55:44 -080016#include <denver.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000017#include <lib/el3_runtime/context_mgmt.h>
18#include <lib/psci/psci.h>
19#include <plat/common/platform.h>
20
Varun Wadekarabd153c2015-09-14 09:31:39 +053021#include <mce.h>
Varun Wadekarb8776152016-03-03 13:52:52 -080022#include <smmu.h>
Varun Wadekar1e7250b2017-05-24 08:47:15 -070023#include <stdbool.h>
Varun Wadekar782c83d2017-03-14 14:25:35 -070024#include <t18x_ari.h>
Varun Wadekar921b9062015-08-25 17:03:14 +053025#include <tegra_private.h>
26
Antonio Nino Diaz4b32e622018-08-16 16:52:57 +010027extern void memcpy16(void *dest, const void *src, unsigned int length);
Varun Wadekar93bed2a2016-03-18 13:07:33 -070028extern void tegra186_cpu_reset_handler(void);
Anthony Zhou5a4ce002017-06-28 16:49:16 +080029extern uint64_t __tegra186_cpu_reset_handler_end,
Varun Wadekar27155fc2017-04-20 18:56:09 -070030 __tegra186_smmu_context;
Varun Wadekard66ee542016-02-29 10:24:30 -080031
Varun Wadekar42236572016-01-18 19:03:19 -080032/* state id mask */
Anthony Zhou5d1bb052017-03-03 16:23:08 +080033#define TEGRA186_STATE_ID_MASK 0xFU
Varun Wadekar42236572016-01-18 19:03:19 -080034/* constants to get power state's wake time */
Anthony Zhou5d1bb052017-03-03 16:23:08 +080035#define TEGRA186_WAKE_TIME_MASK 0x0FFFFFF0U
36#define TEGRA186_WAKE_TIME_SHIFT 4U
Varun Wadekar698e7c62016-03-28 15:05:03 -070037/* default core wake mask for CPU_SUSPEND */
Anthony Zhou5d1bb052017-03-03 16:23:08 +080038#define TEGRA186_CORE_WAKE_MASK 0x180cU
Varun Wadekarb8776152016-03-03 13:52:52 -080039/* context size to save during system suspend */
Anthony Zhou5d1bb052017-03-03 16:23:08 +080040#define TEGRA186_SE_CONTEXT_SIZE 3U
Varun Wadekar42236572016-01-18 19:03:19 -080041
Varun Wadekarb8776152016-03-03 13:52:52 -080042static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE];
Anthony Zhou5d1bb052017-03-03 16:23:08 +080043static struct tegra_psci_percpu_data {
44 uint32_t wake_time;
45} __aligned(CACHE_WRITEBACK_GRANULE) tegra_percpu_data[PLATFORM_CORE_COUNT];
Varun Wadekar42236572016-01-18 19:03:19 -080046
Anthony Zhou5d1bb052017-03-03 16:23:08 +080047int32_t tegra_soc_validate_power_state(uint32_t power_state,
Varun Wadekarc2c3a2a2016-01-08 17:38:51 -080048 psci_power_state_t *req_state)
Varun Wadekar921b9062015-08-25 17:03:14 +053049{
Anthony Zhou5d1bb052017-03-03 16:23:08 +080050 uint8_t state_id = (uint8_t)psci_get_pstate_id(power_state) & TEGRA186_STATE_ID_MASK;
51 uint32_t cpu = plat_my_core_pos();
52 int32_t ret = PSCI_E_SUCCESS;
Varun Wadekar89645092016-02-09 14:55:44 -080053
Krishna Sitaraman86569d12016-08-18 15:41:21 -070054 /* save the core wake time (in TSC ticks)*/
Anthony Zhou5d1bb052017-03-03 16:23:08 +080055 tegra_percpu_data[cpu].wake_time = (power_state & TEGRA186_WAKE_TIME_MASK)
Krishna Sitaraman86569d12016-08-18 15:41:21 -070056 << TEGRA186_WAKE_TIME_SHIFT;
Varun Wadekar42236572016-01-18 19:03:19 -080057
Mustafa Yigit Bilgenf40bc2c2016-09-02 19:30:22 -070058 /*
59 * Clean percpu_data[cpu] to DRAM. This needs to be done to ensure that
60 * the correct value is read in tegra_soc_pwr_domain_suspend(), which
61 * is called with caches disabled. It is possible to read a stale value
62 * from DRAM in that function, because the L2 cache is not flushed
63 * unless the cluster is entering CC6/CC7.
64 */
Anthony Zhou5d1bb052017-03-03 16:23:08 +080065 clean_dcache_range((uint64_t)&tegra_percpu_data[cpu],
66 sizeof(tegra_percpu_data[cpu]));
Mustafa Yigit Bilgenf40bc2c2016-09-02 19:30:22 -070067
Varun Wadekar42236572016-01-18 19:03:19 -080068 /* Sanity check the requested state id */
69 switch (state_id) {
70 case PSTATE_ID_CORE_IDLE:
71 case PSTATE_ID_CORE_POWERDN:
Varun Wadekar4a0b37a2016-04-09 00:36:42 -070072
73 /* Core powerdown request */
Varun Wadekar42236572016-01-18 19:03:19 -080074 req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -070075 req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
Varun Wadekar42236572016-01-18 19:03:19 -080076
77 break;
78
79 default:
80 ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
Anthony Zhou5d1bb052017-03-03 16:23:08 +080081 ret = PSCI_E_INVALID_PARAMS;
82 break;
Varun Wadekar42236572016-01-18 19:03:19 -080083 }
84
Anthony Zhou5d1bb052017-03-03 16:23:08 +080085 return ret;
Varun Wadekar42236572016-01-18 19:03:19 -080086}
87
Anthony Zhou5d1bb052017-03-03 16:23:08 +080088int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
Varun Wadekar42236572016-01-18 19:03:19 -080089{
90 const plat_local_state_t *pwr_domain_state;
Anthony Zhou5d1bb052017-03-03 16:23:08 +080091 uint8_t stateid_afflvl0, stateid_afflvl2;
92 uint32_t cpu = plat_my_core_pos();
93 const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
Varun Wadekar4a0b37a2016-04-09 00:36:42 -070094 mce_cstate_info_t cstate_info = { 0 };
Varun Wadekar93bed2a2016-03-18 13:07:33 -070095 uint64_t smmu_ctx_base;
Varun Wadekarb8776152016-03-03 13:52:52 -080096 uint32_t val;
97
Varun Wadekar42236572016-01-18 19:03:19 -080098 /* get the state ID */
99 pwr_domain_state = target_state->pwr_domain_state;
100 stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] &
101 TEGRA186_STATE_ID_MASK;
Varun Wadekarb8776152016-03-03 13:52:52 -0800102 stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
103 TEGRA186_STATE_ID_MASK;
Varun Wadekar42236572016-01-18 19:03:19 -0800104
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700105 if ((stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ||
106 (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN)) {
Varun Wadekar42236572016-01-18 19:03:19 -0800107
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700108 /* Enter CPU idle/powerdown */
109 val = (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ?
Anthony Zhou0e07e452017-07-26 17:16:54 +0800110 (uint32_t)TEGRA_ARI_CORE_C6 : (uint32_t)TEGRA_ARI_CORE_C7;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800111 (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, (uint64_t)val,
112 tegra_percpu_data[cpu].wake_time, 0U);
Varun Wadekarc2c3a2a2016-01-08 17:38:51 -0800113
Varun Wadekarb8776152016-03-03 13:52:52 -0800114 } else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
115
Varun Wadekarb8776152016-03-03 13:52:52 -0800116 /* save SE registers */
117 se_regs[0] = mmio_read_32(TEGRA_SE0_BASE +
118 SE_MUTEX_WATCHDOG_NS_LIMIT);
119 se_regs[1] = mmio_read_32(TEGRA_RNG1_BASE +
120 RNG_MUTEX_WATCHDOG_NS_LIMIT);
121 se_regs[2] = mmio_read_32(TEGRA_PKA1_BASE +
122 PKA_MUTEX_WATCHDOG_NS_LIMIT);
123
124 /* save 'Secure Boot' Processor Feature Config Register */
125 val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG);
126 mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV6, val);
127
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700128 /* save SMMU context to TZDRAM */
129 smmu_ctx_base = params_from_bl2->tzdram_base +
Varun Wadekar27155fc2017-04-20 18:56:09 -0700130 ((uintptr_t)&__tegra186_smmu_context -
Anthony Zhou5a4ce002017-06-28 16:49:16 +0800131 (uintptr_t)&tegra186_cpu_reset_handler);
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700132 tegra_smmu_save_context((uintptr_t)smmu_ctx_base);
Varun Wadekarb8776152016-03-03 13:52:52 -0800133
134 /* Prepare for system suspend */
Anthony Zhou0e07e452017-07-26 17:16:54 +0800135 cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
136 cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC7;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700137 cstate_info.system_state_force = 1;
138 cstate_info.update_wake_mask = 1;
139 mce_update_cstate_info(&cstate_info);
Varun Wadekara9002bb2016-03-28 15:11:43 -0700140 /* Loop until system suspend is allowed */
141 do {
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800142 val = (uint32_t)mce_command_handler(
143 (uint64_t)MCE_CMD_IS_SC7_ALLOWED,
Anthony Zhou0e07e452017-07-26 17:16:54 +0800144 (uint64_t)TEGRA_ARI_CORE_C7,
Varun Wadekara9002bb2016-03-28 15:11:43 -0700145 MCE_CORE_SLEEP_TIME_INFINITE,
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800146 0U);
147 } while (val == 0U);
Varun Wadekara9002bb2016-03-28 15:11:43 -0700148
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700149 /* Instruct the MCE to enter system suspend state */
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800150 (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
Anthony Zhou0e07e452017-07-26 17:16:54 +0800151 (uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800152 } else {
153 ; /* do nothing */
Varun Wadekar921b9062015-08-25 17:03:14 +0530154 }
155
156 return PSCI_E_SUCCESS;
157}
Varun Wadekarabd153c2015-09-14 09:31:39 +0530158
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700159/*******************************************************************************
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700160 * Helper function to check if this is the last ON CPU in the cluster
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700161 ******************************************************************************/
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700162static bool tegra_last_cpu_in_cluster(const plat_local_state_t *states,
163 uint32_t ncpu)
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700164{
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700165 plat_local_state_t target;
166 bool last_on_cpu = true;
167 uint32_t num_cpus = ncpu, pos = 0;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700168
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700169 do {
170 target = states[pos];
171 if (target != PLAT_MAX_OFF_STATE) {
172 last_on_cpu = false;
173 }
174 --num_cpus;
175 pos++;
176 } while (num_cpus != 0U);
177
178 return last_on_cpu;
179}
180
181/*******************************************************************************
182 * Helper function to get target power state for the cluster
183 ******************************************************************************/
184static plat_local_state_t tegra_get_afflvl1_pwr_state(const plat_local_state_t *states,
185 uint32_t ncpu)
186{
187 uint32_t core_pos = (uint32_t)read_mpidr() & (uint32_t)MPIDR_CPU_MASK;
188 uint32_t cpu = plat_my_core_pos();
189 int32_t ret;
190 plat_local_state_t target = states[core_pos];
191 mce_cstate_info_t cstate_info = { 0 };
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700192
193 /* CPU suspend */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700194 if (target == PSTATE_ID_CORE_POWERDN) {
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700195 /* Program default wake mask */
196 cstate_info.wake_mask = TEGRA186_CORE_WAKE_MASK;
197 cstate_info.update_wake_mask = 1;
198 mce_update_cstate_info(&cstate_info);
199
200 /* Check if CCx state is allowed. */
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800201 ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED,
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700202 (uint64_t)TEGRA_ARI_CORE_C7,
203 tegra_percpu_data[cpu].wake_time,
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800204 0U);
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700205 if (ret == 0) {
206 target = PSCI_LOCAL_STATE_RUN;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800207 }
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700208 }
209
210 /* CPU off */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700211 if (target == PLAT_MAX_OFF_STATE) {
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700212 /* Enable cluster powerdn from last CPU in the cluster */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700213 if (tegra_last_cpu_in_cluster(states, ncpu)) {
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700214 /* Enable CC7 state and turn off wake mask */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700215 cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700216 cstate_info.update_wake_mask = 1;
217 mce_update_cstate_info(&cstate_info);
218
219 /* Check if CCx state is allowed. */
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800220 ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED,
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700221 (uint64_t)TEGRA_ARI_CORE_C7,
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700222 MCE_CORE_SLEEP_TIME_INFINITE,
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800223 0U);
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700224 if (ret == 0) {
225 target = PSCI_LOCAL_STATE_RUN;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800226 }
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700227
228 } else {
229
230 /* Turn off wake_mask */
231 cstate_info.update_wake_mask = 1;
232 mce_update_cstate_info(&cstate_info);
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700233 target = PSCI_LOCAL_STATE_RUN;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700234 }
235 }
236
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700237 return target;
238}
239
240/*******************************************************************************
241 * Platform handler to calculate the proper target power level at the
242 * specified affinity level
243 ******************************************************************************/
Anthony Zhou0e07e452017-07-26 17:16:54 +0800244plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl,
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700245 const plat_local_state_t *states,
246 uint32_t ncpu)
247{
248 plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
Anthony Zhou0e07e452017-07-26 17:16:54 +0800249 uint32_t cpu = plat_my_core_pos();
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700250
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700251 /* System Suspend */
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700252 if ((lvl == (uint32_t)MPIDR_AFFLVL2) &&
253 (states[cpu] == PSTATE_ID_SOC_POWERDN)) {
254 target = PSTATE_ID_SOC_POWERDN;
255 }
256
257 /* CPU off, CPU suspend */
258 if (lvl == (uint32_t)MPIDR_AFFLVL1) {
259 target = tegra_get_afflvl1_pwr_state(states, ncpu);
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800260 }
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700261
Varun Wadekar1e7250b2017-05-24 08:47:15 -0700262 /* target cluster/system state */
263 return target;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700264}
265
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800266int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700267{
268 const plat_local_state_t *pwr_domain_state =
269 target_state->pwr_domain_state;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800270 const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
271 uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700272 TEGRA186_STATE_ID_MASK;
Steven Kao235e9c32016-12-23 15:43:17 +0800273 uint64_t val;
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700274
275 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
276 /*
277 * The TZRAM loses power when we enter system suspend. To
278 * allow graceful exit from system suspend, we need to copy
279 * BL3-1 over to TZDRAM.
280 */
281 val = params_from_bl2->tzdram_base +
282 ((uintptr_t)&__tegra186_cpu_reset_handler_end -
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800283 (uintptr_t)&tegra186_cpu_reset_handler);
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700284 memcpy16((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
285 (uintptr_t)&__BL31_END__ - (uintptr_t)BL31_BASE);
286 }
287
288 return PSCI_E_SUCCESS;
289}
290
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800291int32_t tegra_soc_pwr_domain_on(u_register_t mpidr)
Varun Wadekarabd153c2015-09-14 09:31:39 +0530292{
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800293 int32_t ret = PSCI_E_SUCCESS;
Anthony Zhou5a4ce002017-06-28 16:49:16 +0800294 uint64_t target_cpu = mpidr & MPIDR_CPU_MASK;
295 uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
296 MPIDR_AFFINITY_BITS;
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800297
Anthony Zhou5a4ce002017-06-28 16:49:16 +0800298 if (target_cluster > MPIDR_AFFLVL1) {
Varun Wadekarabd153c2015-09-14 09:31:39 +0530299
Varun Wadekarabd153c2015-09-14 09:31:39 +0530300 ERROR("%s: unsupported CPU (0x%lx)\n", __func__, mpidr);
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800301 ret = PSCI_E_NOT_PRESENT;
Varun Wadekarabd153c2015-09-14 09:31:39 +0530302
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800303 } else {
304 /* construct the target CPU # */
305 target_cpu |= (target_cluster << 2);
Varun Wadekarabd153c2015-09-14 09:31:39 +0530306
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800307 (void)mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U);
308 }
Varun Wadekarabd153c2015-09-14 09:31:39 +0530309
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800310 return ret;
Varun Wadekarabd153c2015-09-14 09:31:39 +0530311}
312
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800313int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
Varun Wadekarb8776152016-03-03 13:52:52 -0800314{
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800315 uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
316 uint8_t stateid_afflvl0 = target_state->pwr_domain_state[MPIDR_AFFLVL0];
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700317 mce_cstate_info_t cstate_info = { 0 };
Harvey Hsiehfbdfce12016-11-23 19:13:08 +0800318 uint64_t impl, val;
319 const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
320
Anthony Zhou5a4ce002017-06-28 16:49:16 +0800321 impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
Harvey Hsiehfbdfce12016-11-23 19:13:08 +0800322
323 /*
324 * Enable ECC and Parity Protection for Cortex-A57 CPUs (Tegra186
325 * A02p and beyond).
326 */
Anthony Zhou5a4ce002017-06-28 16:49:16 +0800327 if ((plat_params->l2_ecc_parity_prot_dis != 1) && (impl != DENVER_IMPL)) {
Harvey Hsiehfbdfce12016-11-23 19:13:08 +0800328
329 val = read_l2ctlr_el1();
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800330 val |= CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
Harvey Hsiehfbdfce12016-11-23 19:13:08 +0800331 write_l2ctlr_el1(val);
332 }
Varun Wadekarb8776152016-03-03 13:52:52 -0800333
334 /*
Varun Wadekar5a402562016-04-29 11:25:46 -0700335 * Reset power state info for CPUs when onlining, we set
336 * deepest power when offlining a core but that may not be
337 * requested by non-secure sw which controls idle states. It
338 * will re-init this info from non-secure software when the
339 * core come online.
Varun Wadekard2da47a2016-04-09 00:40:45 -0700340 */
Varun Wadekar5a402562016-04-29 11:25:46 -0700341 if (stateid_afflvl0 == PLAT_MAX_OFF_STATE) {
342
Anthony Zhou0e07e452017-07-26 17:16:54 +0800343 cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC1;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700344 cstate_info.update_wake_mask = 1;
345 mce_update_cstate_info(&cstate_info);
Varun Wadekar5a402562016-04-29 11:25:46 -0700346 }
Varun Wadekard2da47a2016-04-09 00:40:45 -0700347
348 /*
Varun Wadekarb8776152016-03-03 13:52:52 -0800349 * Check if we are exiting from deep sleep and restore SE
350 * context if we are.
351 */
Varun Wadekar5a402562016-04-29 11:25:46 -0700352 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
353
Varun Wadekarb8776152016-03-03 13:52:52 -0800354 mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT,
355 se_regs[0]);
356 mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT,
357 se_regs[1]);
358 mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT,
359 se_regs[2]);
360
361 /* Init SMMU */
362 tegra_smmu_init();
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700363
364 /*
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700365 * Reset power state info for the last core doing SC7
366 * entry and exit, we set deepest power state as CC7
367 * and SC7 for SC7 entry which may not be requested by
368 * non-secure SW which controls idle states.
Varun Wadekar93bed2a2016-03-18 13:07:33 -0700369 */
Anthony Zhou0e07e452017-07-26 17:16:54 +0800370 cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
371 cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC1;
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700372 cstate_info.update_wake_mask = 1;
373 mce_update_cstate_info(&cstate_info);
Varun Wadekarb8776152016-03-03 13:52:52 -0800374 }
375
376 return PSCI_E_SUCCESS;
377}
378
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800379int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
Varun Wadekarabd153c2015-09-14 09:31:39 +0530380{
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800381 uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & (uint64_t)MIDR_IMPL_MASK;
382
383 (void)target_state;
Varun Wadekara64806a2016-01-05 15:17:41 -0800384
Varun Wadekare26a55a2016-02-26 11:09:21 -0800385 /* Disable Denver's DCO operations */
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800386 if (impl == DENVER_IMPL) {
Varun Wadekare26a55a2016-02-26 11:09:21 -0800387 denver_disable_dco();
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800388 }
Varun Wadekare26a55a2016-02-26 11:09:21 -0800389
Varun Wadekarabd153c2015-09-14 09:31:39 +0530390 /* Turn off CPU */
Anthony Zhou0e07e452017-07-26 17:16:54 +0800391 (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
392 (uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
Varun Wadekar4a0b37a2016-04-09 00:36:42 -0700393
394 return PSCI_E_SUCCESS;
Varun Wadekarabd153c2015-09-14 09:31:39 +0530395}
Varun Wadekar782c83d2017-03-14 14:25:35 -0700396
397__dead2 void tegra_soc_prepare_system_off(void)
398{
Varun Wadekar71d0e8d2017-05-17 14:35:33 -0700399 /* power off the entire system */
Anthony Zhou0e07e452017-07-26 17:16:54 +0800400 mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF);
Varun Wadekard66ee542016-02-29 10:24:30 -0800401
402 wfi();
403
404 /* wait for the system to power down */
405 for (;;) {
406 ;
407 }
Varun Wadekar782c83d2017-03-14 14:25:35 -0700408}
Varun Wadekar38020c92016-01-07 14:36:12 -0800409
Anthony Zhou5d1bb052017-03-03 16:23:08 +0800410int32_t tegra_soc_prepare_system_reset(void)
Varun Wadekar38020c92016-01-07 14:36:12 -0800411{
Anthony Zhou0e07e452017-07-26 17:16:54 +0800412 mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT);
Varun Wadekar38020c92016-01-07 14:36:12 -0800413
414 return PSCI_E_SUCCESS;
415}