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
	uint64_t cpu = read_mpidr() & (uint64_t)(MPIDR_CPU_MASK);
329
330
	uint64_t cluster = (read_mpidr() & ((uint64_t)(MPIDR_AFFLVL_MASK) <<
			   (uint64_t)(MPIDR_AFFINITY_BITS))) >>
331
			   (uint64_t)(MPIDR_AFFINITY_BITS);
332
333
	uint64_t impl = (read_midr() >> (uint64_t)MIDR_IMPL_SHIFT) &
			(uint64_t)MIDR_IMPL_MASK;
334
	int32_t ret;
335
336
337
338
339

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

	/* sanity check target core id */
340
	if ((core >= MCE_CORE_ID_MAX) || (cpu == (uint64_t)core)) {
341
		ERROR("%s: unsupported core id (%d)\n", __func__, core);
342
343
344
345
346
347
348
349
350
351
352
353
354
355
		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);
		}
356
357
	}

358
	return ret;
359
360
}

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

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

368
369
370
371
372
373
374
375
376
377
378
379
	/*
	 * 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) |\
380
		((enable != 0U) ? MCE_AUTO_CC3_ENABLE_BIT : 0U));
381

382
	return ari_request_wait(ari_base, 0U, TEGRA_ARI_CC3_CTRL, val, 0U);
383
384
}

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

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

	return 0;
}

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

404
405
	return ari_request_wait(ari_base, 0U, TEGRA_ARI_ROC_FLUSH_CACHE_TRBITS,
			0U, 0U);
406
407
}

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

413
414
	return ari_request_wait(ari_base, 0U, TEGRA_ARI_ROC_FLUSH_CACHE_ONLY,
			0U, 0U);
415
416
}

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

422
423
	return ari_request_wait(ari_base, 0U, TEGRA_ARI_ROC_CLEAN_CACHE_ONLY,
			0U, 0U);
424
425
}

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

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

	/* Set command */
437
438
439
440
441
	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,
442
			       (uint32_t)(mca_arg_data >> 32U));
443
444
445
446
447
448
449
450
451
452
453
454
455
456
	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);
457
				*data = ((uint64_t)resp_hi << 32U) |
458
459
					 (uint64_t)resp_lo;
			}
460
461
462
		}
	}

463
	return result;
464
465
}

466
int32_t ari_update_ccplex_gsc(uint32_t ari_base, uint32_t gsc_idx)
467
{
468
	int32_t ret = 0;
469
	/* sanity check GSC ID */
470
471
472
473
474
475
476
477
478
479
480
481
482
	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);
	}
483

484
	return ret;
485
486
487
488
}

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

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

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

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

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

510
	/* sanity check input parameters */
511
	if ((req_cmd == UNCORE_PERFMON_CMD_READ) && (data == NULL)) {
512
		ERROR("invalid parameters\n");
513
514
515
516
517
518
519
		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) ?
520
			(uint32_t)*data : 0U;
521
522
523
524
525
526
527

		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 */
528
			req_status = ari_get_response_high(ari_base) &
529
530
531
532
533
534
535
536
537
538
539
540
					 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;
		}
541
542
	}

543
	return result;
544
}
545
546
547
548
549
550
551
552

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

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