plat_psci_handlers.c 11.3 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
#include <cortex_a57.h>
9
10
11
12
13
14
15
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
#include <plat/common/platform.h>

16
#include <bpmp.h>
17
#include <flowctrl.h>
18
#include <pmc.h>
19
20
#include <platform_def.h>
#include <security_engine.h>
21
22
#include <tegra_def.h>
#include <tegra_private.h>
23
#include <tegra_platform.h>
24

25
26
27
28
29
30
31
/*
 * Register used to clear CPU reset signals. Each CPU has two reset
 * signals: CPU reset (3:0) and Core reset (19:16).
 */
#define CPU_CMPLX_RESET_CLR		0x454
#define CPU_CORE_RESET_MASK		0x10001

32
33
34
35
36
/* Clock and Reset controller registers for system clock's settings */
#define SCLK_RATE			0x30
#define SCLK_BURST_POLICY		0x28
#define SCLK_BURST_POLICY_DEFAULT	0x10000000

37
static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
38
static bool tegra_bpmp_available = true;
39

40
41
int32_t tegra_soc_validate_power_state(unsigned int power_state,
					psci_power_state_t *req_state)
42
{
43
	int state_id = psci_get_pstate_id(power_state);
44
	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
45

46
	/* Sanity check the requested state id */
47
	switch (state_id) {
48
	case PSTATE_ID_CORE_POWERDN:
49
50
51
52
53
54
55
		/*
		 * Core powerdown request only for afflvl 0
		 */
		req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff;

		break;

56
	case PSTATE_ID_CLUSTER_IDLE:
57

58
		/*
59
		 * Cluster idle request for afflvl 0
60
		 */
61
		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PSTATE_ID_CORE_POWERDN;
62
		req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
63
64
		break;

65
	case PSTATE_ID_SOC_POWERDN:
66
67
68
69
70
71
72
73
74

		/*
		 * sc7entry-fw must be present in the system when the bpmp
		 * firmware is not present, for a successful System Suspend
		 * entry.
		 */
		if (!tegra_bpmp_init() && !plat_params->sc7entry_fw_base)
			return PSCI_E_NOT_SUPPORTED;

75
76
77
		/*
		 * System powerdown request only for afflvl 2
		 */
78
		for (uint32_t i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
79
80
81
82
83
			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;

		req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
			PLAT_SYS_SUSPEND_STATE_ID;

84
85
86
		break;

	default:
87
88
		ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
		return PSCI_E_INVALID_PARAMS;
89
90
91
92
93
	}

	return PSCI_E_SUCCESS;
}

94
95
/*******************************************************************************
 * Platform handler to calculate the proper target power level at the
96
 * specified affinity level.
97
98
99
100
101
 ******************************************************************************/
plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl,
					     const plat_local_state_t *states,
					     unsigned int ncpu)
{
102
	plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
103
104
	int cpu = plat_my_core_pos();
	int core_pos = read_mpidr() & MPIDR_CPU_MASK;
105
	uint32_t bpmp_reply, data[3], val;
106
	int ret;
107
108
109
110
111
112
113

	/* get the power state at this level */
	if (lvl == MPIDR_AFFLVL1)
		target = *(states + core_pos);
	if (lvl == MPIDR_AFFLVL2)
		target = *(states + cpu);

114
115
116
	if ((lvl == MPIDR_AFFLVL1) && (target == PSTATE_ID_CLUSTER_IDLE)) {

		/* initialize the bpmp interface */
117
118
		ret = tegra_bpmp_init();
		if (ret != 0U) {
119
120
121

			/* Cluster idle not allowed */
			target = PSCI_LOCAL_STATE_RUN;
122
123
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

			/*******************************************
			 * BPMP is not present, so handle CC6 entry
			 * from the CPU
			 ******************************************/

			/* check if cluster idle state has been enabled */
			val = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL);
			if (val == ENABLE_CLOSED_LOOP) {
				/*
				 * flag to indicate that BPMP firmware is not
				 * available and the CPU has to handle entry/exit
				 * for all power states
				 */
				tegra_bpmp_available = false;

				/*
				 * Acquire the cluster idle lock to stop
				 * other CPUs from powering up.
				 */
				tegra_fc_ccplex_pgexit_lock();

				/* Cluster idle only from the last standing CPU */
				if (tegra_pmc_is_last_on_cpu() && tegra_fc_is_ccx_allowed()) {
					/* Cluster idle allowed */
					target = PSTATE_ID_CLUSTER_IDLE;
				} else {
					/* release cluster idle lock */
					tegra_fc_ccplex_pgexit_unlock();
				}
			}
153
154
		} else {

155
			/* Cluster power-down */
156
157
158
159
160
161
162
163
			data[0] = (uint32_t)cpu;
			data[1] = TEGRA_PM_CC6;
			data[2] = TEGRA_PM_SC1;
			ret = tegra_bpmp_send_receive_atomic(MRQ_DO_IDLE,
					(void *)&data, (int)sizeof(data),
					(void *)&bpmp_reply,
					(int)sizeof(bpmp_reply));

164
			/* check if cluster power down is allowed */
165
166
			if ((ret != 0L) || (bpmp_reply != BPMP_CCx_ALLOWED)) {

167
				/* Cluster power down not allowed */
168
169
				target = PSCI_LOCAL_STATE_RUN;
			}
170
		}
171

172
173
174
175
176
177
178
179
180
181
182
	} else if (((lvl == MPIDR_AFFLVL2) || (lvl == MPIDR_AFFLVL1)) &&
	    (target == PSTATE_ID_SOC_POWERDN)) {

		/* System Suspend */
		target = PSTATE_ID_SOC_POWERDN;

	} else {
		; /* do nothing */
	}

	return target;
183
184
}

185
int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
186
{
187
188
189
190
191
192
	u_register_t mpidr = read_mpidr();
	const plat_local_state_t *pwr_domain_state =
		target_state->pwr_domain_state;
	unsigned int stateid_afflvl2 = pwr_domain_state[MPIDR_AFFLVL2];
	unsigned int stateid_afflvl1 = pwr_domain_state[MPIDR_AFFLVL1];
	unsigned int stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0];
193
	uint32_t cfg;
194
	int ret = PSCI_E_SUCCESS;
195
	uint32_t val;
196

197
	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
198

199
		assert((stateid_afflvl0 == PLAT_MAX_OFF_STATE) ||
200
			(stateid_afflvl0 == PSTATE_ID_SOC_POWERDN));
201
		assert((stateid_afflvl1 == PLAT_MAX_OFF_STATE) ||
202
203
204
			(stateid_afflvl1 == PSTATE_ID_SOC_POWERDN));

		if (tegra_chipid_is_t210_b01()) {
205

206
207
208
209
210
			/* Suspend se/se2 and pka1 */
			if (tegra_se_suspend() != 0) {
				ret = PSCI_E_INTERN_FAIL;
			}
		}
211

212
	} else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) {
213

214
		assert(stateid_afflvl0 == PSTATE_ID_CORE_POWERDN);
215

216
217
		if (!tegra_bpmp_available) {

218
			/* Find if the platform uses OVR2/MAX77621 PMIC */
219
220
			cfg = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_OUTPUT_CFG);
			if (cfg & DFLL_OUTPUT_CFG_CLK_EN_BIT) {
221
222
223
				/* OVR2 */

				/* PWM tristate */
224
225
226
				val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
				val |= PINMUX_PWM_TRISTATE;
				mmio_write_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM, val);
227
228
229
230
231
232
233
234
235
236
237

				/*
				 * SCRATCH201[1] is being used to identify CPU
				 * PMIC in warmboot code.
				 * 0 : OVR2
				 * 1 : MAX77621
				 */
				tegra_pmc_write_32(PMC_SCRATCH201, 0x0);
			} else {
				/* MAX77621 */
				tegra_pmc_write_32(PMC_SCRATCH201, 0x2);
238
239
240
			}
		}

241
242
		/* Prepare for cluster idle */
		tegra_fc_cluster_idle(mpidr);
243

244
245
246
247
248
249
	} else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {

		/* Prepare for cpu powerdn */
		tegra_fc_cpu_powerdn(mpidr);

	} else {
250
251
		ERROR("%s: Unknown state id (%d, %d, %d)\n", __func__,
			stateid_afflvl2, stateid_afflvl1, stateid_afflvl0);
252
		ret = PSCI_E_NOT_SUPPORTED;
253
254
	}

255
	return ret;
256
257
}

258
259
260
261
262
263
int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
{
	u_register_t mpidr = read_mpidr();
	const plat_local_state_t *pwr_domain_state =
		target_state->pwr_domain_state;
	unsigned int stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL];
264
265
	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
	uint32_t val;
266
267
268
269
270
271
272
273

	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {

		if (tegra_chipid_is_t210_b01()) {
			/* Save tzram contents */
			tegra_se_save_tzram();
		}

274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
		/*
		 * The CPU needs to load the System suspend entry firmware
		 * if nothing is running on the BPMP.
		 */
		if (!tegra_bpmp_available) {

			/*
			 * BPMP firmware is not running on the co-processor, so
			 * we need to explicitly load the firmware to enable
			 * entry/exit to/from System Suspend and set the BPMP
			 * on its way.
			 */

			/* Power off BPMP before we proceed */
			tegra_fc_bpmp_off();

			/* Copy the firmware to BPMP's internal RAM */
			(void)memcpy((void *)(uintptr_t)TEGRA_IRAM_BASE,
				(const void *)plat_params->sc7entry_fw_base,
				plat_params->sc7entry_fw_size);

			/* Power on the BPMP and execute from IRAM base */
			tegra_fc_bpmp_on(TEGRA_IRAM_BASE);

			/* Wait until BPMP powers up */
			do {
				val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET);
			} while (val != SIGN_OF_LIFE);
		}

304
305
306
307
308
309
310
		/* enter system suspend */
		tegra_fc_soc_powerdn(mpidr);
	}

	return PSCI_E_SUCCESS;
}

311
int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
312
{
313
	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
314
	uint32_t cfg;
315
	uint32_t val, entrypoint = 0;
316

317
318
319
320
321
322
323
324
	/* platform parameter passed by the previous bootloader */
	if (plat_params->l2_ecc_parity_prot_dis != 1) {
		/* Enable ECC Parity Protection for Cortex-A57 CPUs */
		val = read_l2ctlr_el1();
		val |= (uint64_t)CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
		write_l2ctlr_el1(val);
	}

325
326
327
	/*
	 * Check if we are exiting from SOC_POWERDN.
	 */
328
329
	if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
			PLAT_SYS_SUSPEND_STATE_ID) {
330

331
332
333
334
335
336
337
		/*
		 * Security engine resume
		 */
		if (tegra_chipid_is_t210_b01()) {
			tegra_se_resume();
		}

338
339
340
341
342
		/*
		 * Lock scratch registers which hold the CPU vectors
		 */
		tegra_pmc_lock_cpu_vectors();

343
344
345
346
347
348
349
350
351
		/*
		 * Enable WRAP to INCR burst type conversions for
		 * incoming requests on the AXI slave ports.
		 */
		val = mmio_read_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG);
		val &= ~ENABLE_UNSUP_TX_ERRORS;
		val |= ENABLE_WRAP_TO_INCR_BURSTS;
		mmio_write_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG, val);

352
353
		/*
		 * Restore Boot and Power Management Processor (BPMP) reset
354
		 * address and reset it, if it is supported by the platform.
355
		 */
356
357
358
359
360
361
		if (!tegra_bpmp_available) {
			tegra_fc_bpmp_off();
		} else {
			entrypoint = tegra_pmc_read_32(PMC_SCRATCH39);
			tegra_fc_bpmp_on(entrypoint);
		}
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
	}

	/*
	 * Check if we are exiting cluster idle state
	 */
	if (target_state->pwr_domain_state[MPIDR_AFFLVL1] ==
			PSTATE_ID_CLUSTER_IDLE) {

		if (!tegra_bpmp_available) {

			/* PWM un-tristate */
			cfg = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_OUTPUT_CFG);
			if (cfg & DFLL_OUTPUT_CFG_CLK_EN_BIT) {
				val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
				val &= ~PINMUX_PWM_TRISTATE;
				mmio_write_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM, val);
			}

			/* release cluster idle lock */
			tegra_fc_ccplex_pgexit_unlock();
		}
383
384
385
386
387
388
389
	}

	/*
	 * T210 has a dedicated ARMv7 boot and power mgmt processor, BPMP. It's
	 * used for power management and boot purposes. Inform the BPMP that
	 * we have completed the cluster power up.
	 */
390
	tegra_fc_lock_active_cluster();
391
392
393
394

	return PSCI_E_SUCCESS;
}

395
int tegra_soc_pwr_domain_on(u_register_t mpidr)
396
397
{
	int cpu = mpidr & MPIDR_CPU_MASK;
398
399
400
401
	uint32_t mask = CPU_CORE_RESET_MASK << cpu;

	/* Deassert CPU reset signals */
	mmio_write_32(TEGRA_CAR_RESET_BASE + CPU_CMPLX_RESET_CLR, mask);
402
403
404
405
406
407
408
409
410
411
412
413

	/* Turn on CPU using flow controller or PMC */
	if (cpu_powergate_mask[cpu] == 0) {
		tegra_pmc_cpu_on(cpu);
		cpu_powergate_mask[cpu] = 1;
	} else {
		tegra_fc_cpu_on(cpu);
	}

	return PSCI_E_SUCCESS;
}

414
int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
415
{
416
	tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
417
418
	return PSCI_E_SUCCESS;
}
419
420
421
422
423
424
425
426

int tegra_soc_prepare_system_reset(void)
{
	/*
	 * Set System Clock (SCLK) to POR default so that the clock source
	 * for the PMC APB clock would not be changed due to system reset.
	 */
	mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_BURST_POLICY,
427
		SCLK_BURST_POLICY_DEFAULT);
428
429
430
431
432
433
434
	mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_RATE, 0);

	/* Wait 1 ms to make sure clock source/device logic is stabilized. */
	mdelay(1);

	return PSCI_E_SUCCESS;
}