ari.c 14.8 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
8
9
#include <assert.h>
#include <errno.h>

10
11
#include <arch.h>
#include <arch_helpers.h>
12
13
#include <common/debug.h>
#include <drivers/delay_timer.h>
14
#include <denver.h>
15
16
17
#include <lib/mmio.h>
#include <plat/common/platform.h>

18
#include <mce_private.h>
19
20
21
22
23
#include <t18x_ari.h>

/*******************************************************************************
 * Register offsets for ARI request/results
 ******************************************************************************/
24
25
26
27
28
29
30
#define ARI_REQUEST			0x0U
#define ARI_REQUEST_EVENT_MASK		0x4U
#define ARI_STATUS			0x8U
#define ARI_REQUEST_DATA_LO		0xCU
#define ARI_REQUEST_DATA_HI		0x10U
#define ARI_RESPONSE_DATA_LO		0x14U
#define ARI_RESPONSE_DATA_HI		0x18U
31
32

/* Status values for the current request */
33
34
35
36
37
38
39
#define ARI_REQ_PENDING			1U
#define ARI_REQ_ONGOING			3U
#define ARI_REQUEST_VALID_BIT		(1U << 8)
#define ARI_EVT_MASK_STANDBYWFI_BIT	(1U << 7)

/* default timeout (ms) to wait for ARI completion */
#define ARI_MAX_RETRY_COUNT		2000
40
41
42
43
44
45

/*******************************************************************************
 * ARI helper functions
 ******************************************************************************/
static inline uint32_t ari_read_32(uint32_t ari_base, uint32_t reg)
{
46
	return mmio_read_32((uint64_t)ari_base + (uint64_t)reg);
47
48
49
50
}

static inline void ari_write_32(uint32_t ari_base, uint32_t val, uint32_t reg)
{
51
	mmio_write_32((uint64_t)ari_base + (uint64_t)reg, val);
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
79
}

static inline uint32_t ari_get_request_low(uint32_t ari_base)
{
	return ari_read_32(ari_base, ARI_REQUEST_DATA_LO);
}

static inline uint32_t ari_get_request_high(uint32_t ari_base)
{
	return ari_read_32(ari_base, ARI_REQUEST_DATA_HI);
}

static inline uint32_t ari_get_response_low(uint32_t ari_base)
{
	return ari_read_32(ari_base, ARI_RESPONSE_DATA_LO);
}

static inline uint32_t ari_get_response_high(uint32_t ari_base)
{
	return ari_read_32(ari_base, ARI_RESPONSE_DATA_HI);
}

static inline void ari_clobber_response(uint32_t ari_base)
{
	ari_write_32(ari_base, 0, ARI_RESPONSE_DATA_LO);
	ari_write_32(ari_base, 0, ARI_RESPONSE_DATA_HI);
}

80
static int32_t ari_request_wait(uint32_t ari_base, uint32_t evt_mask, uint32_t req,
81
82
		uint32_t lo, uint32_t hi)
{
83
84
	uint32_t retries = ARI_MAX_RETRY_COUNT;
	uint32_t status;
85
	int32_t ret = 0;
86
87
88
89
90
91
92
93
94
95
96
97

	/* program the request, event_mask, hi and lo registers */
	ari_write_32(ari_base, lo, ARI_REQUEST_DATA_LO);
	ari_write_32(ari_base, hi, ARI_REQUEST_DATA_HI);
	ari_write_32(ari_base, evt_mask, ARI_REQUEST_EVENT_MASK);
	ari_write_32(ari_base, req | ARI_REQUEST_VALID_BIT, ARI_REQUEST);

	/*
	 * For commands that have an event trigger, we should bypass
	 * ARI_STATUS polling, since MCE is waiting for SW to trigger
	 * the event.
	 */
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
	if (evt_mask != 0U) {
		ret = 0;
	} else {
		/* For shutdown/reboot commands, we dont have to check for timeouts */
		if ((req == (uint32_t)TEGRA_ARI_MISC_CCPLEX) &&
		    ((lo == (uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) ||
		     (lo == (uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT))) {
				ret = 0;
		} else {
			/*
			 * Wait for the command response for not more than the timeout
			 */
			while (retries != 0U) {

				/* read the command status */
				status = ari_read_32(ari_base, ARI_STATUS);
				if ((status & (ARI_REQ_ONGOING | ARI_REQ_PENDING)) == 0U) {
					break;
				}

				/* delay 1 ms */
				mdelay(1);

				/* decrement the retry count */
				retries--;
			}

			/* assert if the command timed out */
			if (retries == 0U) {
				ERROR("ARI request timed out: req %d on CPU %d\n",
					req, plat_my_core_pos());
				assert(retries != 0U);
			}
		}
132
	}
133

134
	return ret;
135
136
}

137
int32_t ari_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time)
138
{
139
140
	int32_t ret = 0;

141
	/* check for allowed power state */
142
143
144
145
	if ((state != TEGRA_ARI_CORE_C0) &&
	    (state != TEGRA_ARI_CORE_C1) &&
	    (state != TEGRA_ARI_CORE_C6) &&
	    (state != TEGRA_ARI_CORE_C7)) {
146
		ERROR("%s: unknown cstate (%d)\n", __func__, state);
147
148
149
150
		ret = EINVAL;
	} else {
		/* clean the previous response state */
		ari_clobber_response(ari_base);
151

152
153
		/* Enter the cstate, to be woken up after wake_time (TSC ticks) */
		ret = ari_request_wait(ari_base, ARI_EVT_MASK_STANDBYWFI_BIT,
154
		TEGRA_ARI_ENTER_CSTATE, state, wake_time);
155
156
157
	}

	return ret;
158
159
}

160
int32_t ari_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex,
161
162
163
	uint32_t system, uint8_t sys_state_force, uint32_t wake_mask,
	uint8_t update_wake_mask)
{
164
	uint32_t val = 0U;
165

166
167
168
	/* clean the previous response state */
	ari_clobber_response(ari_base);

169
	/* update CLUSTER_CSTATE? */
170
171
172
173
	if (cluster != 0U) {
		val |= (cluster & (uint32_t)CLUSTER_CSTATE_MASK) |
			(uint32_t)CLUSTER_CSTATE_UPDATE_BIT;
	}
174
175

	/* update CCPLEX_CSTATE? */
176
177
178
179
	if (ccplex != 0U) {
		val |= ((ccplex & (uint32_t)CCPLEX_CSTATE_MASK) << (uint32_t)CCPLEX_CSTATE_SHIFT) |
			(uint32_t)CCPLEX_CSTATE_UPDATE_BIT;
	}
180
181

	/* update SYSTEM_CSTATE? */
182
183
184
185
186
	if (system != 0U) {
		val |= ((system & (uint32_t)SYSTEM_CSTATE_MASK) << (uint32_t)SYSTEM_CSTATE_SHIFT) |
		       (((uint32_t)sys_state_force << SYSTEM_CSTATE_FORCE_UPDATE_SHIFT) |
			(uint32_t)SYSTEM_CSTATE_UPDATE_BIT);
	}
187
188

	/* update wake mask value? */
189
190
191
	if (update_wake_mask != 0U) {
		val |= (uint32_t)CSTATE_WAKE_MASK_UPDATE_BIT;
	}
192
193

	/* set the updated cstate info */
194
	return ari_request_wait(ari_base, 0U, TEGRA_ARI_UPDATE_CSTATE_INFO, val,
195
196
197
			wake_mask);
}

198
int32_t ari_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time)
199
{
200
201
	int32_t ret = 0;

202
203
	/* sanity check crossover type */
	if ((type == TEGRA_ARI_CROSSOVER_C1_C6) ||
204
205
206
207
208
209
210
211
	    (type > TEGRA_ARI_CROSSOVER_CCP3_SC1)) {
		ret = EINVAL;
	} else {
		/* clean the previous response state */
		ari_clobber_response(ari_base);

		/* update crossover threshold time */
		ret = ari_request_wait(ari_base, 0U, TEGRA_ARI_UPDATE_CROSSOVER,
212
			type, time);
213
214
215
	}

	return ret;
216
217
218
219
}

uint64_t ari_read_cstate_stats(uint32_t ari_base, uint32_t state)
{
220
221
	int32_t ret;
	uint64_t result;
222
223

	/* sanity check crossover type */
224
225
226
227
228
229
230
231
232
233
234
235
236
237
	if (state == 0U) {
		result = EINVAL;
	} else {
		/* clean the previous response state */
		ari_clobber_response(ari_base);

		ret = ari_request_wait(ari_base, 0U, TEGRA_ARI_CSTATE_STATS, state, 0U);
		if (ret != 0) {
			result = EINVAL;
		} else {
			result = (uint64_t)ari_get_response_low(ari_base);
		}
	}
	return result;
238
239
}

240
int32_t ari_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats)
241
{
242
243
244
	/* clean the previous response state */
	ari_clobber_response(ari_base);

245
	/* write the cstate stats */
246
	return ari_request_wait(ari_base, 0U, TEGRA_ARI_WRITE_CSTATE_STATS, state,
247
248
249
250
251
252
			stats);
}

uint64_t ari_enumeration_misc(uint32_t ari_base, uint32_t cmd, uint32_t data)
{
	uint64_t resp;
253
254
	int32_t ret;
	uint32_t local_data = data;
255
256
257
258
259

	/* clean the previous response state */
	ari_clobber_response(ari_base);

	/* ARI_REQUEST_DATA_HI is reserved for commands other than 'ECHO' */
260
261
262
	if (cmd != TEGRA_ARI_MISC_ECHO) {
		local_data = 0U;
	}
263

264
265
266
267
268
269
270
271
	ret = ari_request_wait(ari_base, 0U, TEGRA_ARI_MISC, cmd, local_data);
	if (ret != 0) {
		resp = (uint64_t)ret;
	} else {
		/* get the command response */
		resp = ari_get_response_low(ari_base);
		resp |= ((uint64_t)ari_get_response_high(ari_base) << 32);
	}
272
273
274
275

	return resp;
}

276
int32_t ari_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time)
277
{
278
279
	int32_t ret;
	uint32_t result;
280

281
282
283
	/* clean the previous response state */
	ari_clobber_response(ari_base);

284
	ret = ari_request_wait(ari_base, 0U, TEGRA_ARI_IS_CCX_ALLOWED, state & 0x7U,
285
			wake_time);
286
	if (ret != 0) {
287
		ERROR("%s: failed (%d)\n", __func__, ret);
288
289
290
		result = 0U;
	} else {
		result = ari_get_response_low(ari_base) & 0x1U;
291
292
293
	}

	/* 1 = CCx allowed, 0 = CCx not allowed */
294
	return (int32_t)result;
295
296
}

297
int32_t ari_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time)
298
{
299
	int32_t ret, result;
300
301

	/* check for allowed power state */
302
303
304
305
	if ((state != TEGRA_ARI_CORE_C0) &&
	    (state != TEGRA_ARI_CORE_C1) &&
	    (state != TEGRA_ARI_CORE_C6) &&
	    (state != TEGRA_ARI_CORE_C7)) {
306
		ERROR("%s: unknown cstate (%d)\n", __func__, state);
307
308
309
310
311
312
313
314
315
316
317
318
319
320
		result = EINVAL;
	} else {
		/* clean the previous response state */
		ari_clobber_response(ari_base);

		ret = ari_request_wait(ari_base, 0U, TEGRA_ARI_IS_SC7_ALLOWED, state,
				wake_time);
		if (ret != 0) {
			ERROR("%s: failed (%d)\n", __func__, ret);
			result = 0;
		} else {
			/* 1 = SC7 allowed, 0 = SC7 not allowed */
			result = (ari_get_response_low(ari_base) != 0U) ? 1 : 0;
		}
321
322
	}

323
	return result;
324
325
}

326
int32_t ari_online_core(uint32_t ari_base, uint32_t core)
327
{
328
329
330
331
332
	uint64_t cpu = read_mpidr() & (uint64_t)(MPIDR_CPU_MASK);
	uint64_t cluster = (read_mpidr() & (uint64_t)(MPIDR_CLUSTER_MASK)) >>
			   (uint64_t)(MPIDR_AFFINITY_BITS);
	uint64_t impl = (read_midr() >> (uint64_t)MIDR_IMPL_SHIFT) & (uint64_t)MIDR_IMPL_MASK;
	int32_t ret;
333
334
335
336
337

	/* construct the current CPU # */
	cpu |= (cluster << 2);

	/* sanity check target core id */
338
	if ((core >= MCE_CORE_ID_MAX) || (cpu == (uint64_t)core)) {
339
		ERROR("%s: unsupported core id (%d)\n", __func__, core);
340
341
342
343
344
345
346
347
348
349
350
351
352
353
		ret = EINVAL;
	} else {
		/*
		 * The Denver cluster has 2 CPUs only - 0, 1.
		 */
		if ((impl == (uint32_t)DENVER_IMPL) &&
		    ((core == 2U) || (core == 3U))) {
			ERROR("%s: unknown core id (%d)\n", __func__, core);
			ret = EINVAL;
		} else {
			/* clean the previous response state */
			ari_clobber_response(ari_base);
			ret = ari_request_wait(ari_base, 0U, TEGRA_ARI_ONLINE_CORE, core, 0U);
		}
354
355
	}

356
	return ret;
357
358
}

359
int32_t ari_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable)
360
{
361
	uint32_t val;
362

363
364
365
	/* clean the previous response state */
	ari_clobber_response(ari_base);

366
367
368
369
370
371
372
373
374
375
376
377
	/*
	 * If the enable bit is cleared, Auto-CC3 will be disabled by setting
	 * the SW visible voltage/frequency request registers for all non
	 * floorswept cores valid independent of StandbyWFI and disabling
	 * the IDLE voltage/frequency request register. If set, Auto-CC3
	 * will be enabled by setting the ARM SW visible voltage/frequency
	 * request registers for all non floorswept cores to be enabled by
	 * StandbyWFI or the equivalent signal, and always keeping the IDLE
	 * voltage/frequency request register enabled.
	 */
	val = (((freq & MCE_AUTO_CC3_FREQ_MASK) << MCE_AUTO_CC3_FREQ_SHIFT) |\
		((volt & MCE_AUTO_CC3_VTG_MASK) << MCE_AUTO_CC3_VTG_SHIFT) |\
378
		((enable != 0U) ? MCE_AUTO_CC3_ENABLE_BIT : 0U));
379

380
	return ari_request_wait(ari_base, 0U, TEGRA_ARI_CC3_CTRL, val, 0U);
381
382
}

383
int32_t ari_reset_vector_update(uint32_t ari_base)
384
{
385
386
387
	/* clean the previous response state */
	ari_clobber_response(ari_base);

388
389
390
391
	/*
	 * Need to program the CPU reset vector one time during cold boot
	 * and SC7 exit
	 */
392
	(void)ari_request_wait(ari_base, 0U, TEGRA_ARI_COPY_MISCREG_AA64_RST, 0U, 0U);
393
394
395
396

	return 0;
}

397
int32_t ari_roc_flush_cache_trbits(uint32_t ari_base)
398
{
399
400
401
	/* clean the previous response state */
	ari_clobber_response(ari_base);

402
403
	return ari_request_wait(ari_base, 0U, TEGRA_ARI_ROC_FLUSH_CACHE_TRBITS,
			0U, 0U);
404
405
}

406
int32_t ari_roc_flush_cache(uint32_t ari_base)
407
{
408
409
410
	/* clean the previous response state */
	ari_clobber_response(ari_base);

411
412
	return ari_request_wait(ari_base, 0U, TEGRA_ARI_ROC_FLUSH_CACHE_ONLY,
			0U, 0U);
413
414
}

415
int32_t ari_roc_clean_cache(uint32_t ari_base)
416
{
417
418
419
	/* clean the previous response state */
	ari_clobber_response(ari_base);

420
421
	return ari_request_wait(ari_base, 0U, TEGRA_ARI_ROC_CLEAN_CACHE_ONLY,
			0U, 0U);
422
423
}

424
uint64_t ari_read_write_mca(uint32_t ari_base, uint64_t cmd, uint64_t *data)
425
{
426
427
428
429
	uint64_t mca_arg_data, result = 0;
	uint32_t resp_lo, resp_hi;
	uint32_t mca_arg_err, mca_arg_finish;
	int32_t ret;
430
431

	/* Set data (write) */
432
	mca_arg_data = (data != NULL) ? *data : 0ULL;
433
434

	/* Set command */
435
436
437
438
439
	ari_write_32(ari_base, (uint32_t)cmd, ARI_RESPONSE_DATA_LO);
	ari_write_32(ari_base, (uint32_t)(cmd >> 32U), ARI_RESPONSE_DATA_HI);

	ret = ari_request_wait(ari_base, 0U, TEGRA_ARI_MCA,
			       (uint32_t)mca_arg_data,
440
			       (uint32_t)(mca_arg_data >> 32U));
441
442
443
444
445
446
447
448
449
450
451
452
453
454
	if (ret == 0) {
		resp_lo = ari_get_response_low(ari_base);
		resp_hi = ari_get_response_high(ari_base);

		mca_arg_err = resp_lo & MCA_ARG_ERROR_MASK;
		mca_arg_finish = (resp_hi >> MCA_ARG_FINISH_SHIFT) &
				 MCA_ARG_FINISH_MASK;

		if (mca_arg_finish == 0U) {
			result = (uint64_t)mca_arg_err;
		} else {
			if (data != NULL) {
				resp_lo = ari_get_request_low(ari_base);
				resp_hi = ari_get_request_high(ari_base);
455
				*data = ((uint64_t)resp_hi << 32U) |
456
457
					 (uint64_t)resp_lo;
			}
458
459
460
		}
	}

461
	return result;
462
463
}

464
int32_t ari_update_ccplex_gsc(uint32_t ari_base, uint32_t gsc_idx)
465
{
466
	int32_t ret = 0;
467
	/* sanity check GSC ID */
468
469
470
471
472
473
474
475
476
477
478
479
480
	if (gsc_idx > (uint32_t)TEGRA_ARI_GSC_VPR_IDX) {
		ret = EINVAL;
	} else {
		/* clean the previous response state */
		ari_clobber_response(ari_base);

		/*
		 * The MCE code will read the GSC carveout value, corrseponding to
		 * the ID, from the MC registers and update the internal GSC registers
		 * of the CCPLEX.
		 */
		(void)ari_request_wait(ari_base, 0U, TEGRA_ARI_UPDATE_CCPLEX_GSC, gsc_idx, 0U);
	}
481

482
	return ret;
483
484
485
486
}

void ari_enter_ccplex_state(uint32_t ari_base, uint32_t state_idx)
{
487
488
489
	/* clean the previous response state */
	ari_clobber_response(ari_base);

490
491
492
	/*
	 * The MCE will shutdown or restart the entire system
	 */
493
	(void)ari_request_wait(ari_base, 0U, TEGRA_ARI_MISC_CCPLEX, state_idx, 0U);
494
}
495

496
497
int32_t ari_read_write_uncore_perfmon(uint32_t ari_base, uint64_t req,
		uint64_t *data)
498
{
499
	int32_t ret, result;
500
	uint32_t val;
501
502
503
	uint8_t req_cmd, req_status;

	req_cmd = (uint8_t)(req >> UNCORE_PERFMON_CMD_SHIFT);
504

505
506
507
	/* clean the previous response state */
	ari_clobber_response(ari_base);

508
	/* sanity check input parameters */
509
	if ((req_cmd == UNCORE_PERFMON_CMD_READ) && (data == NULL)) {
510
		ERROR("invalid parameters\n");
511
512
513
514
515
516
517
		result = EINVAL;
	} else {
		/*
		 * For "write" commands get the value that has to be written
		 * to the uncore perfmon registers
		 */
		val = (req_cmd == UNCORE_PERFMON_CMD_WRITE) ?
518
			(uint32_t)*data : 0U;
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538

		ret = ari_request_wait(ari_base, 0U, TEGRA_ARI_PERFMON, val,
				       (uint32_t)req);
		if (ret != 0) {
			result = ret;
		} else {
			/* read the command status value */
			req_status = (uint8_t)ari_get_response_high(ari_base) &
					 UNCORE_PERFMON_RESP_STATUS_MASK;

			/*
			 * For "read" commands get the data from the uncore
			 * perfmon registers
			 */
			req_status >>= UNCORE_PERFMON_RESP_STATUS_SHIFT;
			if ((req_status == 0U) && (req_cmd == UNCORE_PERFMON_CMD_READ)) {
				*data = ari_get_response_low(ari_base);
			}
			result = (int32_t)req_status;
		}
539
540
	}

541
	return result;
542
}
543
544
545
546
547
548
549
550

void ari_misc_ccplex(uint32_t ari_base, uint32_t index, uint32_t value)
{
	/*
	 * This invokes the ARI_MISC_CCPLEX commands. This can be
	 * used to enable/disable coresight clock gating.
	 */

551
	if ((index > TEGRA_ARI_MISC_CCPLEX_EDBGREQ) ||
552
		((index == TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL) &&
553
		(value > 1U))) {
554
		ERROR("%s: invalid parameters \n", __func__);
555
556
557
558
	} else {
		/* clean the previous response state */
		ari_clobber_response(ari_base);
		(void)ari_request_wait(ari_base, 0U, TEGRA_ARI_MISC_CCPLEX, index, value);
559
560
	}
}