blob: 8f5555459ddfe21cdfa873da8680f0281c4536de [file] [log] [blame]
Varun Wadekarb316e242015-05-19 16:48:04 +05301/*
Varun Wadekar90e99002018-02-14 08:38:27 -08002 * Copyright (c) 2015-2018, 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
9#include <arch_helpers.h>
Isla Mitchelle3631462017-07-14 10:46:32 +010010#include <cortex_a53.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000011#include <common/debug.h>
12#include <drivers/delay_timer.h>
13#include <lib/mmio.h>
14
Isla Mitchelle3631462017-07-14 10:46:32 +010015#include <flowctrl.h>
Ambroise Vincentffbf32a2019-03-28 09:01:18 +000016#include <lib/utils_def.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053017#include <pmc.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053018#include <tegra_def.h>
19
20#define CLK_RST_DEV_L_SET 0x300
21#define CLK_RST_DEV_L_CLR 0x304
22#define CLK_BPMP_RST (1 << 1)
23
24#define EVP_BPMP_RESET_VECTOR 0x200
25
26static const uint64_t flowctrl_offset_cpu_csr[4] = {
27 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU0_CSR),
28 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR),
29 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 8),
30 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 16)
31};
32
33static const uint64_t flowctrl_offset_halt_cpu[4] = {
34 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU0_EVENTS),
35 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS),
36 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 8),
37 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 16)
38};
39
40static const uint64_t flowctrl_offset_cc4_ctrl[4] = {
41 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL),
42 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 4),
43 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 8),
44 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 12)
45};
46
47static inline void tegra_fc_cc4_ctrl(int cpu_id, uint32_t val)
48{
49 mmio_write_32(flowctrl_offset_cc4_ctrl[cpu_id], val);
50 val = mmio_read_32(flowctrl_offset_cc4_ctrl[cpu_id]);
51}
52
53static inline void tegra_fc_cpu_csr(int cpu_id, uint32_t val)
54{
55 mmio_write_32(flowctrl_offset_cpu_csr[cpu_id], val);
56 val = mmio_read_32(flowctrl_offset_cpu_csr[cpu_id]);
57}
58
59static inline void tegra_fc_halt_cpu(int cpu_id, uint32_t val)
60{
61 mmio_write_32(flowctrl_offset_halt_cpu[cpu_id], val);
62 val = mmio_read_32(flowctrl_offset_halt_cpu[cpu_id]);
63}
64
65static void tegra_fc_prepare_suspend(int cpu_id, uint32_t csr)
66{
67 uint32_t val;
68
69 val = FLOWCTRL_HALT_GIC_IRQ | FLOWCTRL_HALT_GIC_FIQ |
70 FLOWCTRL_HALT_LIC_IRQ | FLOWCTRL_HALT_LIC_FIQ |
71 FLOWCTRL_WAITEVENT;
72 tegra_fc_halt_cpu(cpu_id, val);
73
74 val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG |
75 FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu_id);
76 tegra_fc_cpu_csr(cpu_id, val | csr);
77}
78
79/*******************************************************************************
Varun Wadekar90e99002018-02-14 08:38:27 -080080 * After this, no core can wake from C7 until the action is reverted.
81 * If a wake up event is asserted, the FC state machine will stall until
82 * the action is reverted.
83 ******************************************************************************/
84void tegra_fc_ccplex_pgexit_lock(void)
85{
86 unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK;
87 uint32_t flags = tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT) & ~INTERCEPT_IRQ_PENDING;;
88 uint32_t icept_cpu_flags[] = {
89 INTERCEPT_EXIT_PG_CORE0,
90 INTERCEPT_EXIT_PG_CORE1,
91 INTERCEPT_EXIT_PG_CORE2,
92 INTERCEPT_EXIT_PG_CORE3
93 };
94
95 /* set the intercept flags */
96 for (i = 0; i < ARRAY_SIZE(icept_cpu_flags); i++) {
97
98 /* skip current CPU */
99 if (i == cpu)
100 continue;
101
102 /* enable power gate exit intercept locks */
103 flags |= icept_cpu_flags[i];
104 }
105
106 tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, flags);
107 (void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT);
108}
109
110/*******************************************************************************
111 * Revert the ccplex powergate exit locks
112 ******************************************************************************/
113void tegra_fc_ccplex_pgexit_unlock(void)
114{
115 /* clear lock bits, clear pending interrupts */
116 tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, INTERCEPT_IRQ_PENDING);
117 (void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT);
118}
119
120/*******************************************************************************
Varun Wadekarb2baa892015-08-27 10:25:29 +0530121 * Powerdn the current CPU
Varun Wadekarb316e242015-05-19 16:48:04 +0530122 ******************************************************************************/
Varun Wadekarb2baa892015-08-27 10:25:29 +0530123void tegra_fc_cpu_powerdn(uint32_t mpidr)
Varun Wadekarb316e242015-05-19 16:48:04 +0530124{
125 int cpu = mpidr & MPIDR_CPU_MASK;
126
127 VERBOSE("CPU%d powering down...\n", cpu);
128 tegra_fc_prepare_suspend(cpu, 0);
129}
130
131/*******************************************************************************
132 * Suspend the current CPU cluster
133 ******************************************************************************/
134void tegra_fc_cluster_idle(uint32_t mpidr)
135{
136 int cpu = mpidr & MPIDR_CPU_MASK;
137 uint32_t val;
138
139 VERBOSE("Entering cluster idle state...\n");
140
141 tegra_fc_cc4_ctrl(cpu, 0);
142
143 /* hardware L2 flush is faster for A53 only */
144 tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL,
145 !!MPIDR_AFFLVL1_VAL(mpidr));
146
147 /* suspend the CPU cluster */
148 val = FLOWCTRL_PG_CPU_NONCPU << FLOWCTRL_ENABLE_EXT;
149 tegra_fc_prepare_suspend(cpu, val);
150}
151
152/*******************************************************************************
153 * Power down the current CPU cluster
154 ******************************************************************************/
155void tegra_fc_cluster_powerdn(uint32_t mpidr)
156{
157 int cpu = mpidr & MPIDR_CPU_MASK;
158 uint32_t val;
159
160 VERBOSE("Entering cluster powerdn state...\n");
161
162 tegra_fc_cc4_ctrl(cpu, 0);
163
164 /* hardware L2 flush is faster for A53 only */
165 tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL,
166 read_midr() == CORTEX_A53_MIDR);
167
168 /* power down the CPU cluster */
169 val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT;
170 tegra_fc_prepare_suspend(cpu, val);
171}
172
173/*******************************************************************************
Varun Wadekar90e99002018-02-14 08:38:27 -0800174 * Check if cluster idle or power down state is allowed from this CPU
175 ******************************************************************************/
176bool tegra_fc_is_ccx_allowed(void)
177{
178 unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK;
179 uint32_t val;
180 bool ccx_allowed = true;
181
182 for (i = 0; i < ARRAY_SIZE(flowctrl_offset_cpu_csr); i++) {
183
184 /* skip current CPU */
185 if (i == cpu)
186 continue;
187
188 /* check if all other CPUs are already halted */
189 val = mmio_read_32(flowctrl_offset_cpu_csr[i]);
190 if ((val & FLOWCTRL_CSR_HALT_MASK) == 0U) {
191 ccx_allowed = false;
192 }
193 }
194
195 return ccx_allowed;
196}
197
198/*******************************************************************************
Varun Wadekarb316e242015-05-19 16:48:04 +0530199 * Suspend the entire SoC
200 ******************************************************************************/
201void tegra_fc_soc_powerdn(uint32_t mpidr)
202{
203 int cpu = mpidr & MPIDR_CPU_MASK;
204 uint32_t val;
205
206 VERBOSE("Entering SoC powerdn state...\n");
207
208 tegra_fc_cc4_ctrl(cpu, 0);
209
210 tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, 1);
211
212 val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT;
213 tegra_fc_prepare_suspend(cpu, val);
214
215 /* overwrite HALT register */
216 tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT);
217}
218
219/*******************************************************************************
220 * Power up the CPU
221 ******************************************************************************/
222void tegra_fc_cpu_on(int cpu)
223{
224 tegra_fc_cpu_csr(cpu, FLOWCTRL_CSR_ENABLE);
225 tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT | FLOWCTRL_HALT_SCLK);
226}
227
228/*******************************************************************************
229 * Power down the CPU
230 ******************************************************************************/
231void tegra_fc_cpu_off(int cpu)
232{
233 uint32_t val;
234
235 /*
236 * Flow controller powers down the CPU during wfi. The CPU would be
237 * powered on when it receives any interrupt.
238 */
239 val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG |
240 FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu);
241 tegra_fc_cpu_csr(cpu, val);
242 tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT);
243 tegra_fc_cc4_ctrl(cpu, 0);
244}
245
246/*******************************************************************************
247 * Inform the BPMP that we have completed the cluster power up
248 ******************************************************************************/
249void tegra_fc_lock_active_cluster(void)
250{
251 uint32_t val;
252
253 val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL);
254 val |= FLOWCTRL_BPMP_CLUSTER_PWRON_LOCK;
255 tegra_fc_write_32(FLOWCTRL_BPMP_CLUSTER_CONTROL, val);
256 val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL);
257}
258
259/*******************************************************************************
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800260 * Power ON BPMP processor
Varun Wadekarb316e242015-05-19 16:48:04 +0530261 ******************************************************************************/
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800262void tegra_fc_bpmp_on(uint32_t entrypoint)
Varun Wadekarb316e242015-05-19 16:48:04 +0530263{
Varun Wadekarb316e242015-05-19 16:48:04 +0530264 /* halt BPMP */
265 tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT);
266
267 /* Assert BPMP reset */
268 mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST);
269
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800270 /* Set reset address (stored in PMC_SCRATCH39) */
271 mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, entrypoint);
272 while (entrypoint != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR))
Varun Wadekarb316e242015-05-19 16:48:04 +0530273 ; /* wait till value reaches EVP_BPMP_RESET_VECTOR */
274
275 /* Wait for 2us before de-asserting the reset signal. */
Varun Wadekar85a90cf2015-07-08 13:46:42 +0530276 udelay(2);
Varun Wadekarb316e242015-05-19 16:48:04 +0530277
278 /* De-assert BPMP reset */
279 mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_CLR, CLK_BPMP_RST);
280
281 /* Un-halt BPMP */
282 tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, 0);
283}
Varun Wadekar13b4ad02018-01-26 10:05:02 -0800284
285/*******************************************************************************
Varun Wadekarf07d6de2018-02-27 14:33:57 -0800286 * Power OFF BPMP processor
287 ******************************************************************************/
288void tegra_fc_bpmp_off(void)
289{
290 /* halt BPMP */
291 tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT);
292
293 /* Assert BPMP reset */
294 mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST);
295
296 /* Clear reset address */
297 mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, 0);
298 while (0 != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR))
299 ; /* wait till value reaches EVP_BPMP_RESET_VECTOR */
300}
301
302/*******************************************************************************
Varun Wadekar13b4ad02018-01-26 10:05:02 -0800303 * Route legacy FIQ to the GICD
304 ******************************************************************************/
305void tegra_fc_enable_fiq_to_ccplex_routing(void)
306{
307 uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL);
308
309 /* set the bit to pass FIQs to the GICD */
310 tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val | FLOWCTRL_FIQ2CCPLEX_ENABLE);
311}
312
313/*******************************************************************************
314 * Disable routing legacy FIQ to the GICD
315 ******************************************************************************/
316void tegra_fc_disable_fiq_to_ccplex_routing(void)
317{
318 uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL);
319
320 /* clear the bit to pass FIQs to the GICD */
321 tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val & ~FLOWCTRL_FIQ2CCPLEX_ENABLE);
322}