blob: 27786d3ca66c5415c92b30c8ce5331b14781a5e7 [file] [log] [blame]
Varun Wadekarb316e242015-05-19 16:48:04 +05301/*
Varun Wadekar6077dce2016-01-27 11:31:06 -08002 * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
Varun Wadekarb316e242015-05-19 16:48:04 +05303 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Varun Wadekarb316e242015-05-19 16:48:04 +05305 */
6
Varun Wadekarb316e242015-05-19 16:48:04 +05307#include <assert.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00008
Varun Wadekarb316e242015-05-19 16:48:04 +05309#include <platform_def.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010
11#include <arch_helpers.h>
12#include <common/debug.h>
13#include <drivers/delay_timer.h>
14#include <lib/mmio.h>
15#include <lib/psci/psci.h>
16#include <plat/common/platform.h>
17
18#include <flowctrl.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053019#include <pmc.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053020#include <tegra_def.h>
21#include <tegra_private.h>
22
Varun Wadekar071b7872015-07-08 17:42:02 +053023/*
24 * Register used to clear CPU reset signals. Each CPU has two reset
25 * signals: CPU reset (3:0) and Core reset (19:16).
26 */
27#define CPU_CMPLX_RESET_CLR 0x454
28#define CPU_CORE_RESET_MASK 0x10001
29
Varun Wadekar8b82fae2015-11-09 17:39:28 -080030/* Clock and Reset controller registers for system clock's settings */
31#define SCLK_RATE 0x30
32#define SCLK_BURST_POLICY 0x28
33#define SCLK_BURST_POLICY_DEFAULT 0x10000000
34
Varun Wadekarb316e242015-05-19 16:48:04 +053035static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
36
Varun Wadekara78bb1b2015-08-07 10:03:00 +053037int32_t tegra_soc_validate_power_state(unsigned int power_state,
38 psci_power_state_t *req_state)
Varun Wadekar254441d2015-07-23 10:07:54 +053039{
Varun Wadekara78bb1b2015-08-07 10:03:00 +053040 int state_id = psci_get_pstate_id(power_state);
41
Varun Wadekar254441d2015-07-23 10:07:54 +053042 /* Sanity check the requested state id */
Varun Wadekara78bb1b2015-08-07 10:03:00 +053043 switch (state_id) {
Varun Wadekar254441d2015-07-23 10:07:54 +053044 case PSTATE_ID_CORE_POWERDN:
Varun Wadekara78bb1b2015-08-07 10:03:00 +053045 /*
46 * Core powerdown request only for afflvl 0
47 */
Varun Wadekara78bb1b2015-08-07 10:03:00 +053048 req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff;
49
50 break;
51
Varun Wadekar254441d2015-07-23 10:07:54 +053052 case PSTATE_ID_CLUSTER_IDLE:
53 case PSTATE_ID_CLUSTER_POWERDN:
Varun Wadekara78bb1b2015-08-07 10:03:00 +053054 /*
55 * Cluster powerdown/idle request only for afflvl 1
56 */
Varun Wadekara78bb1b2015-08-07 10:03:00 +053057 req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
Varun Wadekardba80072016-09-01 14:56:17 -070058 req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id;
Varun Wadekara78bb1b2015-08-07 10:03:00 +053059
60 break;
61
Varun Wadekar254441d2015-07-23 10:07:54 +053062 case PSTATE_ID_SOC_POWERDN:
Varun Wadekara78bb1b2015-08-07 10:03:00 +053063 /*
64 * System powerdown request only for afflvl 2
65 */
Varun Wadekar66231d12017-06-07 09:57:42 -070066 for (uint32_t i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
Varun Wadekara78bb1b2015-08-07 10:03:00 +053067 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
68
69 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
70 PLAT_SYS_SUSPEND_STATE_ID;
71
Varun Wadekar254441d2015-07-23 10:07:54 +053072 break;
73
74 default:
Varun Wadekara78bb1b2015-08-07 10:03:00 +053075 ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
76 return PSCI_E_INVALID_PARAMS;
Varun Wadekar254441d2015-07-23 10:07:54 +053077 }
78
79 return PSCI_E_SUCCESS;
80}
81
Varun Wadekarb91b5fc2017-04-18 11:22:01 -070082/*******************************************************************************
83 * Platform handler to calculate the proper target power level at the
84 * specified affinity level
85 ******************************************************************************/
86plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl,
87 const plat_local_state_t *states,
88 unsigned int ncpu)
89{
90 plat_local_state_t target = *states;
91 int cpu = plat_my_core_pos();
92 int core_pos = read_mpidr() & MPIDR_CPU_MASK;
93
94 /* get the power state at this level */
95 if (lvl == MPIDR_AFFLVL1)
96 target = *(states + core_pos);
97 if (lvl == MPIDR_AFFLVL2)
98 target = *(states + cpu);
99
100 /* Cluster idle/power-down */
101 if ((lvl == MPIDR_AFFLVL1) && ((target == PSTATE_ID_CLUSTER_IDLE) ||
102 (target == PSTATE_ID_CLUSTER_POWERDN))) {
103 return target;
104 }
105
106 /* System Suspend */
107 if (((lvl == MPIDR_AFFLVL2) || (lvl == MPIDR_AFFLVL1)) &&
108 (target == PSTATE_ID_SOC_POWERDN))
109 return PSTATE_ID_SOC_POWERDN;
110
111 /* default state */
112 return PSCI_LOCAL_STATE_RUN;
113}
114
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530115int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
Varun Wadekarb316e242015-05-19 16:48:04 +0530116{
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530117 u_register_t mpidr = read_mpidr();
118 const plat_local_state_t *pwr_domain_state =
119 target_state->pwr_domain_state;
120 unsigned int stateid_afflvl2 = pwr_domain_state[MPIDR_AFFLVL2];
121 unsigned int stateid_afflvl1 = pwr_domain_state[MPIDR_AFFLVL1];
122 unsigned int stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0];
Varun Wadekarb316e242015-05-19 16:48:04 +0530123
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530124 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
Varun Wadekarb316e242015-05-19 16:48:04 +0530125
Harvey Hsieh20e9fef2016-12-28 21:53:18 +0800126 assert((stateid_afflvl0 == PLAT_MAX_OFF_STATE) ||
127 (stateid_afflvl0 == PSTATE_ID_SOC_POWERDN));
128 assert((stateid_afflvl1 == PLAT_MAX_OFF_STATE) ||
129 (stateid_afflvl1 == PSTATE_ID_SOC_POWERDN));
Varun Wadekarb316e242015-05-19 16:48:04 +0530130
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530131 /* suspend the entire soc */
132 tegra_fc_soc_powerdn(mpidr);
Varun Wadekarb316e242015-05-19 16:48:04 +0530133
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530134 } else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) {
Varun Wadekarb316e242015-05-19 16:48:04 +0530135
Varun Wadekarb91b5fc2017-04-18 11:22:01 -0700136 assert(stateid_afflvl0 == PSTATE_ID_CLUSTER_IDLE);
Varun Wadekarb316e242015-05-19 16:48:04 +0530137
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530138 /* Prepare for cluster idle */
139 tegra_fc_cluster_idle(mpidr);
Varun Wadekarb316e242015-05-19 16:48:04 +0530140
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530141 } else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_POWERDN) {
Varun Wadekarb316e242015-05-19 16:48:04 +0530142
Varun Wadekarb91b5fc2017-04-18 11:22:01 -0700143 assert(stateid_afflvl0 == PSTATE_ID_CLUSTER_POWERDN);
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530144
145 /* Prepare for cluster powerdn */
146 tegra_fc_cluster_powerdn(mpidr);
147
148 } else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {
149
150 /* Prepare for cpu powerdn */
151 tegra_fc_cpu_powerdn(mpidr);
152
153 } else {
154 ERROR("%s: Unknown state id\n", __func__);
155 return PSCI_E_NOT_SUPPORTED;
Varun Wadekarb316e242015-05-19 16:48:04 +0530156 }
157
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530158 return PSCI_E_SUCCESS;
Varun Wadekarb316e242015-05-19 16:48:04 +0530159}
160
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530161int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
Varun Wadekarb316e242015-05-19 16:48:04 +0530162{
Varun Wadekarbc787442015-07-27 13:00:50 +0530163 uint32_t val;
164
Varun Wadekarb316e242015-05-19 16:48:04 +0530165 /*
166 * Check if we are exiting from SOC_POWERDN.
167 */
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530168 if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
169 PLAT_SYS_SUSPEND_STATE_ID) {
Varun Wadekarb316e242015-05-19 16:48:04 +0530170
171 /*
Varun Wadekar6eec6d62016-03-03 13:28:10 -0800172 * Lock scratch registers which hold the CPU vectors
173 */
174 tegra_pmc_lock_cpu_vectors();
175
176 /*
Varun Wadekarbc787442015-07-27 13:00:50 +0530177 * Enable WRAP to INCR burst type conversions for
178 * incoming requests on the AXI slave ports.
179 */
180 val = mmio_read_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG);
181 val &= ~ENABLE_UNSUP_TX_ERRORS;
182 val |= ENABLE_WRAP_TO_INCR_BURSTS;
183 mmio_write_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG, val);
184
185 /*
Varun Wadekarb316e242015-05-19 16:48:04 +0530186 * Restore Boot and Power Management Processor (BPMP) reset
187 * address and reset it.
188 */
189 tegra_fc_reset_bpmp();
Varun Wadekarb316e242015-05-19 16:48:04 +0530190 }
191
192 /*
193 * T210 has a dedicated ARMv7 boot and power mgmt processor, BPMP. It's
194 * used for power management and boot purposes. Inform the BPMP that
195 * we have completed the cluster power up.
196 */
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530197 tegra_fc_lock_active_cluster();
Varun Wadekarb316e242015-05-19 16:48:04 +0530198
199 return PSCI_E_SUCCESS;
200}
201
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530202int tegra_soc_pwr_domain_on(u_register_t mpidr)
Varun Wadekarb316e242015-05-19 16:48:04 +0530203{
204 int cpu = mpidr & MPIDR_CPU_MASK;
Varun Wadekar071b7872015-07-08 17:42:02 +0530205 uint32_t mask = CPU_CORE_RESET_MASK << cpu;
206
207 /* Deassert CPU reset signals */
208 mmio_write_32(TEGRA_CAR_RESET_BASE + CPU_CMPLX_RESET_CLR, mask);
Varun Wadekarb316e242015-05-19 16:48:04 +0530209
210 /* Turn on CPU using flow controller or PMC */
211 if (cpu_powergate_mask[cpu] == 0) {
212 tegra_pmc_cpu_on(cpu);
213 cpu_powergate_mask[cpu] = 1;
214 } else {
215 tegra_fc_cpu_on(cpu);
216 }
217
218 return PSCI_E_SUCCESS;
219}
220
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530221int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
Varun Wadekarb316e242015-05-19 16:48:04 +0530222{
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530223 tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
Varun Wadekarb316e242015-05-19 16:48:04 +0530224 return PSCI_E_SUCCESS;
225}
Varun Wadekar8b82fae2015-11-09 17:39:28 -0800226
227int tegra_soc_prepare_system_reset(void)
228{
229 /*
230 * Set System Clock (SCLK) to POR default so that the clock source
231 * for the PMC APB clock would not be changed due to system reset.
232 */
233 mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_BURST_POLICY,
234 SCLK_BURST_POLICY_DEFAULT);
235 mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_RATE, 0);
236
237 /* Wait 1 ms to make sure clock source/device logic is stabilized. */
238 mdelay(1);
239
240 return PSCI_E_SUCCESS;
241}