• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 
9 #include <arch_helpers.h>
10 #include <cortex_a53.h>
11 #include <common/debug.h>
12 #include <drivers/delay_timer.h>
13 #include <lib/mmio.h>
14 
15 #include <flowctrl.h>
16 #include <lib/utils_def.h>
17 #include <pmc.h>
18 #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 
26 static 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 
33 static 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 
40 static 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 
tegra_fc_cc4_ctrl(int cpu_id,uint32_t val)47 static 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 
tegra_fc_cpu_csr(int cpu_id,uint32_t val)53 static 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 
tegra_fc_halt_cpu(int cpu_id,uint32_t val)59 static 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 
tegra_fc_prepare_suspend(int cpu_id,uint32_t csr)65 static 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 /*******************************************************************************
80  * 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  ******************************************************************************/
tegra_fc_ccplex_pgexit_lock(void)84 void 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  ******************************************************************************/
tegra_fc_ccplex_pgexit_unlock(void)113 void 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 /*******************************************************************************
121  * Powerdn the current CPU
122  ******************************************************************************/
tegra_fc_cpu_powerdn(uint32_t mpidr)123 void tegra_fc_cpu_powerdn(uint32_t mpidr)
124 {
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  ******************************************************************************/
tegra_fc_cluster_idle(uint32_t mpidr)134 void 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  ******************************************************************************/
tegra_fc_cluster_powerdn(uint32_t mpidr)155 void 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 /*******************************************************************************
174  * Check if cluster idle or power down state is allowed from this CPU
175  ******************************************************************************/
tegra_fc_is_ccx_allowed(void)176 bool 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 /*******************************************************************************
199  * Suspend the entire SoC
200  ******************************************************************************/
tegra_fc_soc_powerdn(uint32_t mpidr)201 void 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  ******************************************************************************/
tegra_fc_cpu_on(int cpu)222 void 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  ******************************************************************************/
tegra_fc_cpu_off(int cpu)231 void 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  ******************************************************************************/
tegra_fc_lock_active_cluster(void)249 void 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 /*******************************************************************************
260  * Power ON BPMP processor
261  ******************************************************************************/
tegra_fc_bpmp_on(uint32_t entrypoint)262 void tegra_fc_bpmp_on(uint32_t entrypoint)
263 {
264 	/* 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 
270 	/* 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))
273 		; /* wait till value reaches EVP_BPMP_RESET_VECTOR */
274 
275 	/* Wait for 2us before de-asserting the reset signal. */
276 	udelay(2);
277 
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 }
284 
285 /*******************************************************************************
286  * Power OFF BPMP processor
287  ******************************************************************************/
tegra_fc_bpmp_off(void)288 void 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 /*******************************************************************************
303  * Route legacy FIQ to the GICD
304  ******************************************************************************/
tegra_fc_enable_fiq_to_ccplex_routing(void)305 void 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  ******************************************************************************/
tegra_fc_disable_fiq_to_ccplex_routing(void)316 void 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 }
323