blob: 2d827da81a0cef5d47791744bea138bd15330394 [file] [log] [blame]
Varun Wadekarb316e242015-05-19 16:48:04 +05301/*
2 * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
3 *
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>
Isla Mitchelle3631462017-07-14 10:46:32 +01009#include <cortex_a53.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053010#include <debug.h>
Varun Wadekar85a90cf2015-07-08 13:46:42 +053011#include <delay_timer.h>
Isla Mitchelle3631462017-07-14 10:46:32 +010012#include <flowctrl.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053013#include <mmio.h>
14#include <pmc.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053015#include <tegra_def.h>
16
17#define CLK_RST_DEV_L_SET 0x300
18#define CLK_RST_DEV_L_CLR 0x304
19#define CLK_BPMP_RST (1 << 1)
20
21#define EVP_BPMP_RESET_VECTOR 0x200
22
23static const uint64_t flowctrl_offset_cpu_csr[4] = {
24 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU0_CSR),
25 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR),
26 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 8),
27 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 16)
28};
29
30static const uint64_t flowctrl_offset_halt_cpu[4] = {
31 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU0_EVENTS),
32 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS),
33 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 8),
34 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 16)
35};
36
37static const uint64_t flowctrl_offset_cc4_ctrl[4] = {
38 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL),
39 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 4),
40 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 8),
41 (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 12)
42};
43
44static inline void tegra_fc_cc4_ctrl(int cpu_id, uint32_t val)
45{
46 mmio_write_32(flowctrl_offset_cc4_ctrl[cpu_id], val);
47 val = mmio_read_32(flowctrl_offset_cc4_ctrl[cpu_id]);
48}
49
50static inline void tegra_fc_cpu_csr(int cpu_id, uint32_t val)
51{
52 mmio_write_32(flowctrl_offset_cpu_csr[cpu_id], val);
53 val = mmio_read_32(flowctrl_offset_cpu_csr[cpu_id]);
54}
55
56static inline void tegra_fc_halt_cpu(int cpu_id, uint32_t val)
57{
58 mmio_write_32(flowctrl_offset_halt_cpu[cpu_id], val);
59 val = mmio_read_32(flowctrl_offset_halt_cpu[cpu_id]);
60}
61
62static void tegra_fc_prepare_suspend(int cpu_id, uint32_t csr)
63{
64 uint32_t val;
65
66 val = FLOWCTRL_HALT_GIC_IRQ | FLOWCTRL_HALT_GIC_FIQ |
67 FLOWCTRL_HALT_LIC_IRQ | FLOWCTRL_HALT_LIC_FIQ |
68 FLOWCTRL_WAITEVENT;
69 tegra_fc_halt_cpu(cpu_id, val);
70
71 val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG |
72 FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu_id);
73 tegra_fc_cpu_csr(cpu_id, val | csr);
74}
75
76/*******************************************************************************
Varun Wadekarb2baa892015-08-27 10:25:29 +053077 * Powerdn the current CPU
Varun Wadekarb316e242015-05-19 16:48:04 +053078 ******************************************************************************/
Varun Wadekarb2baa892015-08-27 10:25:29 +053079void tegra_fc_cpu_powerdn(uint32_t mpidr)
Varun Wadekarb316e242015-05-19 16:48:04 +053080{
81 int cpu = mpidr & MPIDR_CPU_MASK;
82
83 VERBOSE("CPU%d powering down...\n", cpu);
84 tegra_fc_prepare_suspend(cpu, 0);
85}
86
87/*******************************************************************************
88 * Suspend the current CPU cluster
89 ******************************************************************************/
90void tegra_fc_cluster_idle(uint32_t mpidr)
91{
92 int cpu = mpidr & MPIDR_CPU_MASK;
93 uint32_t val;
94
95 VERBOSE("Entering cluster idle state...\n");
96
97 tegra_fc_cc4_ctrl(cpu, 0);
98
99 /* hardware L2 flush is faster for A53 only */
100 tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL,
101 !!MPIDR_AFFLVL1_VAL(mpidr));
102
103 /* suspend the CPU cluster */
104 val = FLOWCTRL_PG_CPU_NONCPU << FLOWCTRL_ENABLE_EXT;
105 tegra_fc_prepare_suspend(cpu, val);
106}
107
108/*******************************************************************************
109 * Power down the current CPU cluster
110 ******************************************************************************/
111void tegra_fc_cluster_powerdn(uint32_t mpidr)
112{
113 int cpu = mpidr & MPIDR_CPU_MASK;
114 uint32_t val;
115
116 VERBOSE("Entering cluster powerdn state...\n");
117
118 tegra_fc_cc4_ctrl(cpu, 0);
119
120 /* hardware L2 flush is faster for A53 only */
121 tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL,
122 read_midr() == CORTEX_A53_MIDR);
123
124 /* power down the CPU cluster */
125 val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT;
126 tegra_fc_prepare_suspend(cpu, val);
127}
128
129/*******************************************************************************
130 * Suspend the entire SoC
131 ******************************************************************************/
132void tegra_fc_soc_powerdn(uint32_t mpidr)
133{
134 int cpu = mpidr & MPIDR_CPU_MASK;
135 uint32_t val;
136
137 VERBOSE("Entering SoC powerdn state...\n");
138
139 tegra_fc_cc4_ctrl(cpu, 0);
140
141 tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, 1);
142
143 val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT;
144 tegra_fc_prepare_suspend(cpu, val);
145
146 /* overwrite HALT register */
147 tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT);
148}
149
150/*******************************************************************************
151 * Power up the CPU
152 ******************************************************************************/
153void tegra_fc_cpu_on(int cpu)
154{
155 tegra_fc_cpu_csr(cpu, FLOWCTRL_CSR_ENABLE);
156 tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT | FLOWCTRL_HALT_SCLK);
157}
158
159/*******************************************************************************
160 * Power down the CPU
161 ******************************************************************************/
162void tegra_fc_cpu_off(int cpu)
163{
164 uint32_t val;
165
166 /*
167 * Flow controller powers down the CPU during wfi. The CPU would be
168 * powered on when it receives any interrupt.
169 */
170 val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG |
171 FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu);
172 tegra_fc_cpu_csr(cpu, val);
173 tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT);
174 tegra_fc_cc4_ctrl(cpu, 0);
175}
176
177/*******************************************************************************
178 * Inform the BPMP that we have completed the cluster power up
179 ******************************************************************************/
180void tegra_fc_lock_active_cluster(void)
181{
182 uint32_t val;
183
184 val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL);
185 val |= FLOWCTRL_BPMP_CLUSTER_PWRON_LOCK;
186 tegra_fc_write_32(FLOWCTRL_BPMP_CLUSTER_CONTROL, val);
187 val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL);
188}
189
190/*******************************************************************************
191 * Reset BPMP processor
192 ******************************************************************************/
193void tegra_fc_reset_bpmp(void)
194{
195 uint32_t val;
196
197 /* halt BPMP */
198 tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT);
199
200 /* Assert BPMP reset */
201 mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST);
202
203 /* Restore reset address (stored in PMC_SCRATCH39) */
204 val = tegra_pmc_read_32(PMC_SCRATCH39);
205 mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, val);
206 while (val != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR))
207 ; /* wait till value reaches EVP_BPMP_RESET_VECTOR */
208
209 /* Wait for 2us before de-asserting the reset signal. */
Varun Wadekar85a90cf2015-07-08 13:46:42 +0530210 udelay(2);
Varun Wadekarb316e242015-05-19 16:48:04 +0530211
212 /* De-assert BPMP reset */
213 mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_CLR, CLK_BPMP_RST);
214
215 /* Un-halt BPMP */
216 tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, 0);
217}