plat_psci_handlers.c 14.9 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 <memctrl.h>
19
#include <pmc.h>
20
21
#include <platform_def.h>
#include <security_engine.h>
22
23
#include <tegra_def.h>
#include <tegra_private.h>
24
#include <tegra_platform.h>
25
#include <utils.h>
26

27
28
29
30
31
32
33
/*
 * 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

34
35
36
37
38
/* 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

39
static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
40
static bool tegra_bpmp_available = true;
41

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

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

		break;

58
	case PSTATE_ID_CLUSTER_IDLE:
59

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

67
	case PSTATE_ID_SOC_POWERDN:
68
69
70
71
72
73
74
75
76

		/*
		 * 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;

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

		req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
			PLAT_SYS_SUSPEND_STATE_ID;

86
87
88
		break;

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

	return PSCI_E_SUCCESS;
}

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

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

116
117
118
	if ((lvl == MPIDR_AFFLVL1) && (target == PSTATE_ID_CLUSTER_IDLE)) {

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

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

			/*******************************************
			 * 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();
				}
			}
155
156
		} else {

157
			/* Cluster power-down */
158
159
160
161
162
163
164
165
			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));

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

169
				/* Cluster power down not allowed */
170
171
				target = PSCI_LOCAL_STATE_RUN;
			}
172
		}
173

174
175
176
177
178
179
180
181
182
183
184
	} 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;
185
186
}

187
int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
188
{
189
190
191
192
193
194
	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];
195
	uint32_t cfg;
196
	int ret = PSCI_E_SUCCESS;
197
	uint32_t val;
198

199
	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
200

201
		assert((stateid_afflvl0 == PLAT_MAX_OFF_STATE) ||
202
			(stateid_afflvl0 == PSTATE_ID_SOC_POWERDN));
203
		assert((stateid_afflvl1 == PLAT_MAX_OFF_STATE) ||
204
205
206
			(stateid_afflvl1 == PSTATE_ID_SOC_POWERDN));

		if (tegra_chipid_is_t210_b01()) {
207

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

214
	} else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) {
215

216
		assert(stateid_afflvl0 == PSTATE_ID_CORE_POWERDN);
217

218
219
		if (!tegra_bpmp_available) {

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

				/* PWM tristate */
226
227
228
				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);
229
230
231
232
233
234
235
236
237
238
239

				/*
				 * 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);
240
241
242
			}
		}

243
244
		/* Prepare for cluster idle */
		tegra_fc_cluster_idle(mpidr);
245

246
247
248
249
250
251
	} else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {

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

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

257
	return ret;
258
259
}

260
261
262
263
264
265
266
267
268
269
270
271
272
273
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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
static void tegra_reset_all_dma_masters(void)
{
	uint32_t val, mask;

	/*
	 * Reset all possible DMA masters in the system.
	 */
	val = GPU_RESET_BIT;
	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET, val);

	val = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT |
	      NVJPG_RESET_BIT | NVDEC_RESET_BIT;
	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y, val);

	val = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT |
	      VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT |
	      SDMMC2_RESET_BIT;
	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L, val);

	val = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT;
	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H, val);

	val = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT |
	      PCIE_RESET_BIT | SDMMC3_RESET_BIT;
	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U, val);

	val = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT;
	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V, val);

	/*
	 * If any of the DMA masters are still alive, assume
	 * that the system has been compromised and reboot.
	 */
	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET);
	mask = GPU_RESET_BIT;
	if ((val & mask) != mask)
		tegra_pmc_system_reset();

	mask = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT |
	      NVJPG_RESET_BIT | NVDEC_RESET_BIT;
	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y);
	if ((val & mask) != mask)
		tegra_pmc_system_reset();

	mask = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT |
	       VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT |
	       SDMMC2_RESET_BIT;
	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L);
	if ((val & mask) != mask)
		tegra_pmc_system_reset();

	mask = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT;
	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H);
	if ((val & mask) != mask)
		tegra_pmc_system_reset();

	mask = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT |
	       PCIE_RESET_BIT | SDMMC3_RESET_BIT;
	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U);
	if ((val & mask) != mask)
		tegra_pmc_system_reset();

	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V);
	mask = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT;
	if ((val & mask) != mask)
		tegra_pmc_system_reset();
}

328
329
330
331
332
333
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];
334
335
	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
	uint32_t val;
336
337
338
339
340
341
342
343

	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {

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

344
345
346
		/* de-init the interface */
		tegra_bpmp_suspend();

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
		/*
		 * 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();

363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
			/* bond out IRAM banks B, C and D */
			mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_U,
				IRAM_B_LOCK_BIT | IRAM_C_LOCK_BIT |
				IRAM_D_LOCK_BIT);

			/* bond out APB/AHB DMAs */
			mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_H,
				APB_DMA_LOCK_BIT | AHB_DMA_LOCK_BIT);

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

			/*
			 * Reset all the hardware blocks that can act as DMA
			 * masters on the bus.
			 */
			tegra_reset_all_dma_masters();

			/* clean up IRAM of any cruft */
			zeromem((void *)(uintptr_t)TEGRA_IRAM_BASE,
					TEGRA_IRAM_A_SIZE);

385
386
			/* Copy the firmware to BPMP's internal RAM */
			(void)memcpy((void *)(uintptr_t)TEGRA_IRAM_BASE,
387
388
				(const void *)(plat_params->sc7entry_fw_base + SC7ENTRY_FW_HEADER_SIZE_BYTES),
				plat_params->sc7entry_fw_size - SC7ENTRY_FW_HEADER_SIZE_BYTES);
389
390
391
392
393
394
395
396
397
398

			/* 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);
		}

399
400
401
402
403
404
405
		/* enter system suspend */
		tegra_fc_soc_powerdn(mpidr);
	}

	return PSCI_E_SUCCESS;
}

406
int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
407
{
408
	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
409
	uint32_t cfg;
410
	uint32_t val, entrypoint = 0;
411
	uint64_t offset;
412

413
414
415
416
417
418
419
420
	/* 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);
	}

421
422
423
	/*
	 * Check if we are exiting from SOC_POWERDN.
	 */
424
425
	if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
			PLAT_SYS_SUSPEND_STATE_ID) {
426

427
428
429
430
431
432
433
		/*
		 * Security engine resume
		 */
		if (tegra_chipid_is_t210_b01()) {
			tegra_se_resume();
		}

434
435
436
437
438
		/*
		 * Lock scratch registers which hold the CPU vectors
		 */
		tegra_pmc_lock_cpu_vectors();

439
440
441
442
443
444
445
446
447
		/*
		 * 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);

448
449
		/*
		 * Restore Boot and Power Management Processor (BPMP) reset
450
		 * address and reset it, if it is supported by the platform.
451
		 */
452
453
454
455
456
		if (!tegra_bpmp_available) {
			tegra_fc_bpmp_off();
		} else {
			entrypoint = tegra_pmc_read_32(PMC_SCRATCH39);
			tegra_fc_bpmp_on(entrypoint);
457
458
459

			/* initialise the interface */
			tegra_bpmp_resume();
460
		}
461
462
463
464
465
466
467

		/* sc7entry-fw is part of TZDRAM area */
		if (plat_params->sc7entry_fw_base != 0U) {
			offset = plat_params->tzdram_base - plat_params->sc7entry_fw_base;
			tegra_memctrl_tzdram_setup(plat_params->sc7entry_fw_base,
				plat_params->tzdram_size + offset);
		}
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
	}

	/*
	 * 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();
		}
489
490
491
492
493
494
495
	}

	/*
	 * 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.
	 */
496
	tegra_fc_lock_active_cluster();
497

498
499
500
501
502
503
	/*
         * Resume PMC hardware block for Tegra210 platforms supporting sc7entry-fw
         */
	if (!tegra_chipid_is_t210_b01() && (plat_params->sc7entry_fw_base != 0U))
		tegra_pmc_resume();

504
505
506
	return PSCI_E_SUCCESS;
}

507
int tegra_soc_pwr_domain_on(u_register_t mpidr)
508
509
{
	int cpu = mpidr & MPIDR_CPU_MASK;
510
511
512
513
	uint32_t mask = CPU_CORE_RESET_MASK << cpu;

	/* Deassert CPU reset signals */
	mmio_write_32(TEGRA_CAR_RESET_BASE + CPU_CMPLX_RESET_CLR, mask);
514
515
516
517
518
519
520
521
522
523
524
525

	/* 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;
}

526
int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
527
{
528
	tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
529
530
	return PSCI_E_SUCCESS;
}
531
532
533
534
535
536
537
538

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,
539
		SCLK_BURST_POLICY_DEFAULT);
540
541
542
543
544
545
546
	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;
}