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