flowctrl.c 10.1 KB
Newer Older
1
/*
2
 * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
3
 *
dp-arm's avatar
dp-arm committed
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
12
13
14
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>

15
#include <flowctrl.h>
16
17
#include <pmc.h>
#include <tegra_def.h>
18
#include <utils_def.h>
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

#define CLK_RST_DEV_L_SET		0x300
#define CLK_RST_DEV_L_CLR		0x304
#define  CLK_BPMP_RST			(1 << 1)

#define EVP_BPMP_RESET_VECTOR		0x200

static const uint64_t flowctrl_offset_cpu_csr[4] = {
	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU0_CSR),
	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR),
	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 8),
	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 16)
};

static const uint64_t flowctrl_offset_halt_cpu[4] = {
	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU0_EVENTS),
	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS),
	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 8),
	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 16)
};

static const uint64_t flowctrl_offset_cc4_ctrl[4] = {
	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL),
	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 4),
	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 8),
	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 12)
};

static inline void tegra_fc_cc4_ctrl(int cpu_id, uint32_t val)
{
	mmio_write_32(flowctrl_offset_cc4_ctrl[cpu_id], val);
	val = mmio_read_32(flowctrl_offset_cc4_ctrl[cpu_id]);
}

static inline void tegra_fc_cpu_csr(int cpu_id, uint32_t val)
{
	mmio_write_32(flowctrl_offset_cpu_csr[cpu_id], val);
	val = mmio_read_32(flowctrl_offset_cpu_csr[cpu_id]);
}

static inline void tegra_fc_halt_cpu(int cpu_id, uint32_t val)
{
	mmio_write_32(flowctrl_offset_halt_cpu[cpu_id], val);
	val = mmio_read_32(flowctrl_offset_halt_cpu[cpu_id]);
}

static void tegra_fc_prepare_suspend(int cpu_id, uint32_t csr)
{
	uint32_t val;

	val = FLOWCTRL_HALT_GIC_IRQ | FLOWCTRL_HALT_GIC_FIQ |
	      FLOWCTRL_HALT_LIC_IRQ | FLOWCTRL_HALT_LIC_FIQ |
	      FLOWCTRL_WAITEVENT;
	tegra_fc_halt_cpu(cpu_id, val);

	val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG |
	      FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu_id);
	tegra_fc_cpu_csr(cpu_id, val | csr);
}

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/*******************************************************************************
 * After this, no core can wake from C7 until the action is reverted.
 * If a wake up event is asserted, the FC state machine will stall until
 * the action is reverted.
 ******************************************************************************/
void tegra_fc_ccplex_pgexit_lock(void)
{
	unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK;
	uint32_t flags = tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT) & ~INTERCEPT_IRQ_PENDING;;
	uint32_t icept_cpu_flags[] = {
		INTERCEPT_EXIT_PG_CORE0,
		INTERCEPT_EXIT_PG_CORE1,
		INTERCEPT_EXIT_PG_CORE2,
		INTERCEPT_EXIT_PG_CORE3
	};

	/* set the intercept flags */
	for (i = 0; i < ARRAY_SIZE(icept_cpu_flags); i++) {

		/* skip current CPU */
		if (i == cpu)
			continue;

		/* enable power gate exit intercept locks */
		flags |= icept_cpu_flags[i];
	}

	tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, flags);
	(void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT);
}

/*******************************************************************************
 * Revert the ccplex powergate exit locks
 ******************************************************************************/
void tegra_fc_ccplex_pgexit_unlock(void)
{
	/* clear lock bits, clear pending interrupts */
	tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, INTERCEPT_IRQ_PENDING);
	(void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT);
}

120
/*******************************************************************************
121
 * Powerdn the current CPU
122
 ******************************************************************************/
123
void tegra_fc_cpu_powerdn(uint32_t mpidr)
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
{
	int cpu = mpidr & MPIDR_CPU_MASK;

	VERBOSE("CPU%d powering down...\n", cpu);
	tegra_fc_prepare_suspend(cpu, 0);
}

/*******************************************************************************
 * Suspend the current CPU cluster
 ******************************************************************************/
void tegra_fc_cluster_idle(uint32_t mpidr)
{
	int cpu = mpidr & MPIDR_CPU_MASK;
	uint32_t val;

	VERBOSE("Entering cluster idle state...\n");

	tegra_fc_cc4_ctrl(cpu, 0);

	/* hardware L2 flush is faster for A53 only */
	tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL,
		!!MPIDR_AFFLVL1_VAL(mpidr));

	/* suspend the CPU cluster */
	val = FLOWCTRL_PG_CPU_NONCPU << FLOWCTRL_ENABLE_EXT;
	tegra_fc_prepare_suspend(cpu, val);
}

/*******************************************************************************
 * Power down the current CPU cluster
 ******************************************************************************/
void tegra_fc_cluster_powerdn(uint32_t mpidr)
{
	int cpu = mpidr & MPIDR_CPU_MASK;
	uint32_t val;

	VERBOSE("Entering cluster powerdn state...\n");

	tegra_fc_cc4_ctrl(cpu, 0);

	/* hardware L2 flush is faster for A53 only */
	tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL,
		read_midr() == CORTEX_A53_MIDR);

	/* power down the CPU cluster */
	val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT;
	tegra_fc_prepare_suspend(cpu, val);
}

173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*******************************************************************************
 * Check if cluster idle or power down state is allowed from this CPU
 ******************************************************************************/
bool tegra_fc_is_ccx_allowed(void)
{
	unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK;
	uint32_t val;
	bool ccx_allowed = true;

	for (i = 0; i < ARRAY_SIZE(flowctrl_offset_cpu_csr); i++) {

		/* skip current CPU */
		if (i == cpu)
			continue;

		/* check if all other CPUs are already halted */
		val = mmio_read_32(flowctrl_offset_cpu_csr[i]);
		if ((val & FLOWCTRL_CSR_HALT_MASK) == 0U) {
			ccx_allowed = false;
		}
	}

	return ccx_allowed;
}

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/*******************************************************************************
 * Suspend the entire SoC
 ******************************************************************************/
void tegra_fc_soc_powerdn(uint32_t mpidr)
{
	int cpu = mpidr & MPIDR_CPU_MASK;
	uint32_t val;

	VERBOSE("Entering SoC powerdn state...\n");

	tegra_fc_cc4_ctrl(cpu, 0);

	tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, 1);

	val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT;
	tegra_fc_prepare_suspend(cpu, val);

	/* overwrite HALT register */
	tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT);
}

/*******************************************************************************
 * Power up the CPU
 ******************************************************************************/
void tegra_fc_cpu_on(int cpu)
{
	tegra_fc_cpu_csr(cpu, FLOWCTRL_CSR_ENABLE);
	tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT | FLOWCTRL_HALT_SCLK);
}

/*******************************************************************************
 * Power down the CPU
 ******************************************************************************/
void tegra_fc_cpu_off(int cpu)
{
	uint32_t val;

	/*
	 * Flow controller powers down the CPU during wfi. The CPU would be
	 * powered on when it receives any interrupt.
	 */
	val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG |
		FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu);
	tegra_fc_cpu_csr(cpu, val);
	tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT);
	tegra_fc_cc4_ctrl(cpu, 0);
}

/*******************************************************************************
 * Inform the BPMP that we have completed the cluster power up
 ******************************************************************************/
void tegra_fc_lock_active_cluster(void)
{
	uint32_t val;

	val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL);
	val |= FLOWCTRL_BPMP_CLUSTER_PWRON_LOCK;
	tegra_fc_write_32(FLOWCTRL_BPMP_CLUSTER_CONTROL, val);
	val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL);
}

/*******************************************************************************
260
 * Power ON BPMP processor
261
 ******************************************************************************/
262
void tegra_fc_bpmp_on(uint32_t entrypoint)
263
264
265
266
267
268
269
{
	/* halt BPMP */
	tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT);

	/* Assert BPMP reset */
	mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST);

270
271
272
	/* Set reset address (stored in PMC_SCRATCH39) */
	mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, entrypoint);
	while (entrypoint != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR))
273
274
275
		; /* wait till value reaches EVP_BPMP_RESET_VECTOR */

	/* Wait for 2us before de-asserting the reset signal. */
276
	udelay(2);
277
278
279
280
281
282
283

	/* De-assert BPMP reset */
	mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_CLR, CLK_BPMP_RST);

	/* Un-halt BPMP */
	tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, 0);
}
284

285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
/*******************************************************************************
 * Power OFF BPMP processor
 ******************************************************************************/
void tegra_fc_bpmp_off(void)
{
	/* halt BPMP */
	tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT);

	/* Assert BPMP reset */
	mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST);

	/* Clear reset address */
	mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, 0);
	while (0 != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR))
		; /* wait till value reaches EVP_BPMP_RESET_VECTOR */
}

302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
/*******************************************************************************
 * Route legacy FIQ to the GICD
 ******************************************************************************/
void tegra_fc_enable_fiq_to_ccplex_routing(void)
{
	uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL);

	/* set the bit to pass FIQs to the GICD */
	tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val | FLOWCTRL_FIQ2CCPLEX_ENABLE);
}

/*******************************************************************************
 * Disable routing legacy FIQ to the GICD
 ******************************************************************************/
void tegra_fc_disable_fiq_to_ccplex_routing(void)
{
	uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL);

	/* clear the bit to pass FIQs to the GICD */
	tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val & ~FLOWCTRL_FIQ2CCPLEX_ENABLE);
}