blob: f77746cae1ed320b27312005a3f76759595336ac [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
7#include <arch_helpers.h>
8#include <assert.h>
9#include <debug.h>
Varun Wadekar8b82fae2015-11-09 17:39:28 -080010#include <delay_timer.h>
Isla Mitchelle3631462017-07-14 10:46:32 +010011#include <flowctrl.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053012#include <mmio.h>
13#include <platform.h>
14#include <platform_def.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053015#include <pmc.h>
Isla Mitchelle3631462017-07-14 10:46:32 +010016#include <psci.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053017#include <tegra_def.h>
18#include <tegra_private.h>
19
Varun Wadekar071b7872015-07-08 17:42:02 +053020/*
21 * Register used to clear CPU reset signals. Each CPU has two reset
22 * signals: CPU reset (3:0) and Core reset (19:16).
23 */
24#define CPU_CMPLX_RESET_CLR 0x454
25#define CPU_CORE_RESET_MASK 0x10001
26
Varun Wadekar8b82fae2015-11-09 17:39:28 -080027/* Clock and Reset controller registers for system clock's settings */
28#define SCLK_RATE 0x30
29#define SCLK_BURST_POLICY 0x28
30#define SCLK_BURST_POLICY_DEFAULT 0x10000000
31
Varun Wadekarb316e242015-05-19 16:48:04 +053032static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
33
Varun Wadekara78bb1b2015-08-07 10:03:00 +053034int32_t tegra_soc_validate_power_state(unsigned int power_state,
35 psci_power_state_t *req_state)
Varun Wadekar254441d2015-07-23 10:07:54 +053036{
Varun Wadekara78bb1b2015-08-07 10:03:00 +053037 int state_id = psci_get_pstate_id(power_state);
38
Varun Wadekar254441d2015-07-23 10:07:54 +053039 /* Sanity check the requested state id */
Varun Wadekara78bb1b2015-08-07 10:03:00 +053040 switch (state_id) {
Varun Wadekar254441d2015-07-23 10:07:54 +053041 case PSTATE_ID_CORE_POWERDN:
Varun Wadekara78bb1b2015-08-07 10:03:00 +053042 /*
43 * Core powerdown request only for afflvl 0
44 */
Varun Wadekara78bb1b2015-08-07 10:03:00 +053045 req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff;
46
47 break;
48
Varun Wadekar254441d2015-07-23 10:07:54 +053049 case PSTATE_ID_CLUSTER_IDLE:
50 case PSTATE_ID_CLUSTER_POWERDN:
Varun Wadekara78bb1b2015-08-07 10:03:00 +053051 /*
52 * Cluster powerdown/idle request only for afflvl 1
53 */
Varun Wadekara78bb1b2015-08-07 10:03:00 +053054 req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
Varun Wadekardba80072016-09-01 14:56:17 -070055 req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id;
Varun Wadekara78bb1b2015-08-07 10:03:00 +053056
57 break;
58
Varun Wadekar254441d2015-07-23 10:07:54 +053059 case PSTATE_ID_SOC_POWERDN:
Varun Wadekara78bb1b2015-08-07 10:03:00 +053060 /*
61 * System powerdown request only for afflvl 2
62 */
Varun Wadekar66231d12017-06-07 09:57:42 -070063 for (uint32_t i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
Varun Wadekara78bb1b2015-08-07 10:03:00 +053064 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
65
66 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
67 PLAT_SYS_SUSPEND_STATE_ID;
68
Varun Wadekar254441d2015-07-23 10:07:54 +053069 break;
70
71 default:
Varun Wadekara78bb1b2015-08-07 10:03:00 +053072 ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
73 return PSCI_E_INVALID_PARAMS;
Varun Wadekar254441d2015-07-23 10:07:54 +053074 }
75
76 return PSCI_E_SUCCESS;
77}
78
Varun Wadekarb91b5fc2017-04-18 11:22:01 -070079/*******************************************************************************
80 * Platform handler to calculate the proper target power level at the
81 * specified affinity level
82 ******************************************************************************/
83plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl,
84 const plat_local_state_t *states,
85 unsigned int ncpu)
86{
87 plat_local_state_t target = *states;
88 int cpu = plat_my_core_pos();
89 int core_pos = read_mpidr() & MPIDR_CPU_MASK;
90
91 /* get the power state at this level */
92 if (lvl == MPIDR_AFFLVL1)
93 target = *(states + core_pos);
94 if (lvl == MPIDR_AFFLVL2)
95 target = *(states + cpu);
96
97 /* Cluster idle/power-down */
98 if ((lvl == MPIDR_AFFLVL1) && ((target == PSTATE_ID_CLUSTER_IDLE) ||
99 (target == PSTATE_ID_CLUSTER_POWERDN))) {
100 return target;
101 }
102
103 /* System Suspend */
104 if (((lvl == MPIDR_AFFLVL2) || (lvl == MPIDR_AFFLVL1)) &&
105 (target == PSTATE_ID_SOC_POWERDN))
106 return PSTATE_ID_SOC_POWERDN;
107
108 /* default state */
109 return PSCI_LOCAL_STATE_RUN;
110}
111
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530112int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
Varun Wadekarb316e242015-05-19 16:48:04 +0530113{
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530114 u_register_t mpidr = read_mpidr();
115 const plat_local_state_t *pwr_domain_state =
116 target_state->pwr_domain_state;
117 unsigned int stateid_afflvl2 = pwr_domain_state[MPIDR_AFFLVL2];
118 unsigned int stateid_afflvl1 = pwr_domain_state[MPIDR_AFFLVL1];
119 unsigned int stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0];
Varun Wadekarb316e242015-05-19 16:48:04 +0530120
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530121 if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
Varun Wadekarb316e242015-05-19 16:48:04 +0530122
Harvey Hsieh20e9fef2016-12-28 21:53:18 +0800123 assert((stateid_afflvl0 == PLAT_MAX_OFF_STATE) ||
124 (stateid_afflvl0 == PSTATE_ID_SOC_POWERDN));
125 assert((stateid_afflvl1 == PLAT_MAX_OFF_STATE) ||
126 (stateid_afflvl1 == PSTATE_ID_SOC_POWERDN));
Varun Wadekarb316e242015-05-19 16:48:04 +0530127
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530128 /* suspend the entire soc */
129 tegra_fc_soc_powerdn(mpidr);
Varun Wadekarb316e242015-05-19 16:48:04 +0530130
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530131 } else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) {
Varun Wadekarb316e242015-05-19 16:48:04 +0530132
Varun Wadekarb91b5fc2017-04-18 11:22:01 -0700133 assert(stateid_afflvl0 == PSTATE_ID_CLUSTER_IDLE);
Varun Wadekarb316e242015-05-19 16:48:04 +0530134
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530135 /* Prepare for cluster idle */
136 tegra_fc_cluster_idle(mpidr);
Varun Wadekarb316e242015-05-19 16:48:04 +0530137
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530138 } else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_POWERDN) {
Varun Wadekarb316e242015-05-19 16:48:04 +0530139
Varun Wadekarb91b5fc2017-04-18 11:22:01 -0700140 assert(stateid_afflvl0 == PSTATE_ID_CLUSTER_POWERDN);
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530141
142 /* Prepare for cluster powerdn */
143 tegra_fc_cluster_powerdn(mpidr);
144
145 } else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {
146
147 /* Prepare for cpu powerdn */
148 tegra_fc_cpu_powerdn(mpidr);
149
150 } else {
151 ERROR("%s: Unknown state id\n", __func__);
152 return PSCI_E_NOT_SUPPORTED;
Varun Wadekarb316e242015-05-19 16:48:04 +0530153 }
154
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530155 return PSCI_E_SUCCESS;
Varun Wadekarb316e242015-05-19 16:48:04 +0530156}
157
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530158int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
Varun Wadekarb316e242015-05-19 16:48:04 +0530159{
Varun Wadekarbc787442015-07-27 13:00:50 +0530160 uint32_t val;
161
Varun Wadekarb316e242015-05-19 16:48:04 +0530162 /*
163 * Check if we are exiting from SOC_POWERDN.
164 */
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530165 if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
166 PLAT_SYS_SUSPEND_STATE_ID) {
Varun Wadekarb316e242015-05-19 16:48:04 +0530167
168 /*
Varun Wadekar6eec6d62016-03-03 13:28:10 -0800169 * Lock scratch registers which hold the CPU vectors
170 */
171 tegra_pmc_lock_cpu_vectors();
172
173 /*
Varun Wadekarbc787442015-07-27 13:00:50 +0530174 * Enable WRAP to INCR burst type conversions for
175 * incoming requests on the AXI slave ports.
176 */
177 val = mmio_read_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG);
178 val &= ~ENABLE_UNSUP_TX_ERRORS;
179 val |= ENABLE_WRAP_TO_INCR_BURSTS;
180 mmio_write_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG, val);
181
182 /*
Varun Wadekarb316e242015-05-19 16:48:04 +0530183 * Restore Boot and Power Management Processor (BPMP) reset
184 * address and reset it.
185 */
186 tegra_fc_reset_bpmp();
Varun Wadekarb316e242015-05-19 16:48:04 +0530187 }
188
189 /*
190 * T210 has a dedicated ARMv7 boot and power mgmt processor, BPMP. It's
191 * used for power management and boot purposes. Inform the BPMP that
192 * we have completed the cluster power up.
193 */
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530194 tegra_fc_lock_active_cluster();
Varun Wadekarb316e242015-05-19 16:48:04 +0530195
196 return PSCI_E_SUCCESS;
197}
198
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530199int tegra_soc_pwr_domain_on(u_register_t mpidr)
Varun Wadekarb316e242015-05-19 16:48:04 +0530200{
201 int cpu = mpidr & MPIDR_CPU_MASK;
Varun Wadekar071b7872015-07-08 17:42:02 +0530202 uint32_t mask = CPU_CORE_RESET_MASK << cpu;
203
204 /* Deassert CPU reset signals */
205 mmio_write_32(TEGRA_CAR_RESET_BASE + CPU_CMPLX_RESET_CLR, mask);
Varun Wadekarb316e242015-05-19 16:48:04 +0530206
207 /* Turn on CPU using flow controller or PMC */
208 if (cpu_powergate_mask[cpu] == 0) {
209 tegra_pmc_cpu_on(cpu);
210 cpu_powergate_mask[cpu] = 1;
211 } else {
212 tegra_fc_cpu_on(cpu);
213 }
214
215 return PSCI_E_SUCCESS;
216}
217
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530218int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
Varun Wadekarb316e242015-05-19 16:48:04 +0530219{
Varun Wadekara78bb1b2015-08-07 10:03:00 +0530220 tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
Varun Wadekarb316e242015-05-19 16:48:04 +0530221 return PSCI_E_SUCCESS;
222}
Varun Wadekar8b82fae2015-11-09 17:39:28 -0800223
224int tegra_soc_prepare_system_reset(void)
225{
226 /*
227 * Set System Clock (SCLK) to POR default so that the clock source
228 * for the PMC APB clock would not be changed due to system reset.
229 */
230 mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_BURST_POLICY,
231 SCLK_BURST_POLICY_DEFAULT);
232 mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_RATE, 0);
233
234 /* Wait 1 ms to make sure clock source/device logic is stabilized. */
235 mdelay(1);
236
237 return PSCI_E_SUCCESS;
238}