blob: 7e35cc6b29070dcf92c4c6cf7e43852fede59476 [file] [log] [blame]
Varun Wadekar921b9062015-08-25 17:03:14 +05301/*
Varun Wadekarc2c3a2a2016-01-08 17:38:51 -08002 * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
Varun Wadekar921b9062015-08-25 17:03:14 +05303 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
Varun Wadekarabd153c2015-09-14 09:31:39 +053031#include <arch.h>
32#include <arch_helpers.h>
Varun Wadekara64806a2016-01-05 15:17:41 -080033#include <assert.h>
34#include <bl_common.h>
35#include <context.h>
36#include <context_mgmt.h>
Varun Wadekarabd153c2015-09-14 09:31:39 +053037#include <debug.h>
Varun Wadekar89645092016-02-09 14:55:44 -080038#include <denver.h>
Varun Wadekarabd153c2015-09-14 09:31:39 +053039#include <mce.h>
Varun Wadekar921b9062015-08-25 17:03:14 +053040#include <psci.h>
Varun Wadekarb8776152016-03-03 13:52:52 -080041#include <smmu.h>
Varun Wadekar782c83d2017-03-14 14:25:35 -070042#include <t18x_ari.h>
Varun Wadekar921b9062015-08-25 17:03:14 +053043#include <tegra_private.h>
44
Varun Wadekard66ee542016-02-29 10:24:30 -080045extern void prepare_cpu_pwr_dwn(void);
46
Varun Wadekar42236572016-01-18 19:03:19 -080047/* state id mask */
48#define TEGRA186_STATE_ID_MASK 0xF
49/* constants to get power state's wake time */
50#define TEGRA186_WAKE_TIME_MASK 0xFFFFFF
51#define TEGRA186_WAKE_TIME_SHIFT 4
Varun Wadekarb8776152016-03-03 13:52:52 -080052/* context size to save during system suspend */
53#define TEGRA186_SE_CONTEXT_SIZE 3
Varun Wadekar42236572016-01-18 19:03:19 -080054
Varun Wadekarb8776152016-03-03 13:52:52 -080055static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE];
Varun Wadekar42236572016-01-18 19:03:19 -080056static unsigned int wake_time[PLATFORM_CORE_COUNT];
57
Varun Wadekard66ee542016-02-29 10:24:30 -080058/* System power down state */
59uint32_t tegra186_system_powerdn_state = TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF;
60
Varun Wadekarc2c3a2a2016-01-08 17:38:51 -080061int32_t tegra_soc_validate_power_state(unsigned int power_state,
62 psci_power_state_t *req_state)
Varun Wadekar921b9062015-08-25 17:03:14 +053063{
Varun Wadekar42236572016-01-18 19:03:19 -080064 int state_id = psci_get_pstate_id(power_state) & TEGRA186_STATE_ID_MASK;
65 int cpu = read_mpidr() & MPIDR_CPU_MASK;
Varun Wadekar89645092016-02-09 14:55:44 -080066 int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
Varun Wadekarc2c3a2a2016-01-08 17:38:51 -080067
Varun Wadekar89645092016-02-09 14:55:44 -080068 if (impl == DENVER_IMPL)
69 cpu |= 0x4;
70
71 wake_time[cpu] = (power_state >> TEGRA186_WAKE_TIME_SHIFT) &
72 TEGRA186_WAKE_TIME_MASK;
Varun Wadekar42236572016-01-18 19:03:19 -080073
74 /* Sanity check the requested state id */
75 switch (state_id) {
76 case PSTATE_ID_CORE_IDLE:
77 case PSTATE_ID_CORE_POWERDN:
Varun Wadekar921b9062015-08-25 17:03:14 +053078 /*
Varun Wadekar42236572016-01-18 19:03:19 -080079 * Core powerdown request only for afflvl 0
Varun Wadekar921b9062015-08-25 17:03:14 +053080 */
Varun Wadekar42236572016-01-18 19:03:19 -080081 req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id;
82
83 break;
84
85 default:
86 ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
87 return PSCI_E_INVALID_PARAMS;
88 }
89
90 return PSCI_E_SUCCESS;
91}
92
93int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
94{
95 const plat_local_state_t *pwr_domain_state;
Varun Wadekarb8776152016-03-03 13:52:52 -080096 unsigned int stateid_afflvl0, stateid_afflvl2;
Varun Wadekar42236572016-01-18 19:03:19 -080097 int cpu = read_mpidr() & MPIDR_CPU_MASK;
Varun Wadekar89645092016-02-09 14:55:44 -080098 int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
Varun Wadekarb8776152016-03-03 13:52:52 -080099 cpu_context_t *ctx = cm_get_context(NON_SECURE);
100 gp_regs_t *gp_regs = get_gpregs_ctx(ctx);
101 uint32_t val;
102
103 assert(ctx);
104 assert(gp_regs);
Varun Wadekar89645092016-02-09 14:55:44 -0800105
106 if (impl == DENVER_IMPL)
107 cpu |= 0x4;
Varun Wadekar42236572016-01-18 19:03:19 -0800108
109 /* get the state ID */
110 pwr_domain_state = target_state->pwr_domain_state;
111 stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] &
112 TEGRA186_STATE_ID_MASK;
Varun Wadekarb8776152016-03-03 13:52:52 -0800113 stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
114 TEGRA186_STATE_ID_MASK;
Varun Wadekar42236572016-01-18 19:03:19 -0800115
116 if (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) {
117
118 /* Prepare for cpu idle */
119 (void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
120 TEGRA_ARI_CORE_C6, wake_time[cpu], 0);
121
122 } else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {
123
124 /* Prepare for cpu powerdn */
125 (void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
126 TEGRA_ARI_CORE_C7, wake_time[cpu], 0);
Varun Wadekarc2c3a2a2016-01-08 17:38:51 -0800127
Varun Wadekarb8776152016-03-03 13:52:52 -0800128 } else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
129
130 /* loop until SC7 is allowed */
131 do {
132 val = mce_command_handler(MCE_CMD_IS_SC7_ALLOWED,
133 TEGRA_ARI_CORE_C7,
134 MCE_CORE_SLEEP_TIME_INFINITE,
135 0);
136 } while (val == 0);
137
138 /* save SE registers */
139 se_regs[0] = mmio_read_32(TEGRA_SE0_BASE +
140 SE_MUTEX_WATCHDOG_NS_LIMIT);
141 se_regs[1] = mmio_read_32(TEGRA_RNG1_BASE +
142 RNG_MUTEX_WATCHDOG_NS_LIMIT);
143 se_regs[2] = mmio_read_32(TEGRA_PKA1_BASE +
144 PKA_MUTEX_WATCHDOG_NS_LIMIT);
145
146 /* save 'Secure Boot' Processor Feature Config Register */
147 val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG);
148 mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV6, val);
149
150 /* save SMMU context */
151 tegra_smmu_save_context();
152
153 /* Prepare for system suspend */
154 write_ctx_reg(gp_regs, CTX_GPREG_X4, 1);
155 write_ctx_reg(gp_regs, CTX_GPREG_X5, 0);
156 write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
157 (void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO,
158 TEGRA_ARI_CLUSTER_CC7, 0, TEGRA_ARI_SYSTEM_SC7);
159
160 /* Enter system suspend state */
161 (void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
162 TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0);
163
Varun Wadekar42236572016-01-18 19:03:19 -0800164 } else {
165 ERROR("%s: Unknown state id\n", __func__);
166 return PSCI_E_NOT_SUPPORTED;
Varun Wadekar921b9062015-08-25 17:03:14 +0530167 }
168
169 return PSCI_E_SUCCESS;
170}
Varun Wadekarabd153c2015-09-14 09:31:39 +0530171
Varun Wadekarc2c3a2a2016-01-08 17:38:51 -0800172int tegra_soc_pwr_domain_on(u_register_t mpidr)
Varun Wadekarabd153c2015-09-14 09:31:39 +0530173{
174 int target_cpu = mpidr & MPIDR_CPU_MASK;
175 int target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
176 MPIDR_AFFINITY_BITS;
177
178 if (target_cluster > MPIDR_AFFLVL1) {
179 ERROR("%s: unsupported CPU (0x%lx)\n", __func__, mpidr);
180 return PSCI_E_NOT_PRESENT;
181 }
182
183 /* construct the target CPU # */
184 target_cpu |= (target_cluster << 2);
185
186 mce_command_handler(MCE_CMD_ONLINE_CORE, target_cpu, 0, 0);
187
188 return PSCI_E_SUCCESS;
189}
190
Varun Wadekarb8776152016-03-03 13:52:52 -0800191int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
192{
193 int state_id = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
194
195 /*
196 * Check if we are exiting from deep sleep and restore SE
197 * context if we are.
198 */
199 if (state_id == PSTATE_ID_SOC_POWERDN) {
200 mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT,
201 se_regs[0]);
202 mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT,
203 se_regs[1]);
204 mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT,
205 se_regs[2]);
206
207 /* Init SMMU */
208 tegra_smmu_init();
209 }
210
211 return PSCI_E_SUCCESS;
212}
213
Varun Wadekarc2c3a2a2016-01-08 17:38:51 -0800214int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
Varun Wadekarabd153c2015-09-14 09:31:39 +0530215{
Varun Wadekara64806a2016-01-05 15:17:41 -0800216 cpu_context_t *ctx = cm_get_context(NON_SECURE);
217 gp_regs_t *gp_regs = get_gpregs_ctx(ctx);
Varun Wadekare26a55a2016-02-26 11:09:21 -0800218 int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
Varun Wadekara64806a2016-01-05 15:17:41 -0800219
220 assert(ctx);
221 assert(gp_regs);
222
Varun Wadekarabd153c2015-09-14 09:31:39 +0530223 /* Turn off wake_mask */
Varun Wadekara64806a2016-01-05 15:17:41 -0800224 write_ctx_reg(gp_regs, CTX_GPREG_X4, 0);
225 write_ctx_reg(gp_regs, CTX_GPREG_X5, 0);
226 write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
227 mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO, TEGRA_ARI_CLUSTER_CC7,
228 0, TEGRA_ARI_SYSTEM_SC7);
Varun Wadekarabd153c2015-09-14 09:31:39 +0530229
Varun Wadekare26a55a2016-02-26 11:09:21 -0800230 /* Disable Denver's DCO operations */
231 if (impl == DENVER_IMPL)
232 denver_disable_dco();
233
Varun Wadekarabd153c2015-09-14 09:31:39 +0530234 /* Turn off CPU */
Varun Wadekara64806a2016-01-05 15:17:41 -0800235 return mce_command_handler(MCE_CMD_ENTER_CSTATE, TEGRA_ARI_CORE_C7,
Varun Wadekar89645092016-02-09 14:55:44 -0800236 MCE_CORE_SLEEP_TIME_INFINITE, 0);
Varun Wadekarabd153c2015-09-14 09:31:39 +0530237}
Varun Wadekar782c83d2017-03-14 14:25:35 -0700238
239__dead2 void tegra_soc_prepare_system_off(void)
240{
Varun Wadekard66ee542016-02-29 10:24:30 -0800241 cpu_context_t *ctx = cm_get_context(NON_SECURE);
242 gp_regs_t *gp_regs = get_gpregs_ctx(ctx);
243 uint32_t val;
244
245 if (tegra186_system_powerdn_state == TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) {
246
247 /* power off the entire system */
248 mce_enter_ccplex_state(tegra186_system_powerdn_state);
249
250 } else if (tegra186_system_powerdn_state == TEGRA_ARI_SYSTEM_SC8) {
251
252 /* loop until other CPUs power down */
253 do {
254 val = mce_command_handler(MCE_CMD_IS_SC7_ALLOWED,
255 TEGRA_ARI_CORE_C7,
256 MCE_CORE_SLEEP_TIME_INFINITE,
257 0);
258 } while (val == 0);
259
260 /* Prepare for quasi power down */
261 write_ctx_reg(gp_regs, CTX_GPREG_X4, 1);
262 write_ctx_reg(gp_regs, CTX_GPREG_X5, 0);
263 write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
264 (void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO,
265 TEGRA_ARI_CLUSTER_CC7, 0, TEGRA_ARI_SYSTEM_SC8);
266
267 /* Enter quasi power down state */
268 (void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
269 TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0);
270
271 /* disable GICC */
272 tegra_gic_cpuif_deactivate();
273
274 /* power down core */
275 prepare_cpu_pwr_dwn();
276
277 } else {
278 ERROR("%s: unsupported power down state (%d)\n", __func__,
279 tegra186_system_powerdn_state);
280 }
281
282 wfi();
283
284 /* wait for the system to power down */
285 for (;;) {
286 ;
287 }
Varun Wadekar782c83d2017-03-14 14:25:35 -0700288}
Varun Wadekar38020c92016-01-07 14:36:12 -0800289
290int tegra_soc_prepare_system_reset(void)
291{
292 mce_enter_ccplex_state(TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT);
293
294 return PSCI_E_SUCCESS;
295}