xref: /rk3399_ARM-atf/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c (revision 521d4fe6761ce62f06acf2b07248d8d5b5366ea3)
17808b06bSVarun Wadekar /*
293c78ed2SAntonio Nino Diaz  * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
37808b06bSVarun Wadekar  *
482cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
57808b06bSVarun Wadekar  */
67808b06bSVarun Wadekar 
709d40e0eSAntonio Nino Diaz #include <assert.h>
809d40e0eSAntonio Nino Diaz #include <errno.h>
909d40e0eSAntonio Nino Diaz 
107808b06bSVarun Wadekar #include <arch.h>
117808b06bSVarun Wadekar #include <arch_helpers.h>
1209d40e0eSAntonio Nino Diaz #include <common/debug.h>
1309d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h>
147808b06bSVarun Wadekar #include <denver.h>
1509d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
1609d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
1709d40e0eSAntonio Nino Diaz 
1806060028SVarun Wadekar #include <mce_private.h>
197808b06bSVarun Wadekar #include <t18x_ari.h>
207808b06bSVarun Wadekar 
217808b06bSVarun Wadekar /*******************************************************************************
227808b06bSVarun Wadekar  * Register offsets for ARI request/results
237808b06bSVarun Wadekar  ******************************************************************************/
24ab712fd8SAnthony Zhou #define ARI_REQUEST			0x0U
25ab712fd8SAnthony Zhou #define ARI_REQUEST_EVENT_MASK		0x4U
26ab712fd8SAnthony Zhou #define ARI_STATUS			0x8U
27ab712fd8SAnthony Zhou #define ARI_REQUEST_DATA_LO		0xCU
28ab712fd8SAnthony Zhou #define ARI_REQUEST_DATA_HI		0x10U
29ab712fd8SAnthony Zhou #define ARI_RESPONSE_DATA_LO		0x14U
30ab712fd8SAnthony Zhou #define ARI_RESPONSE_DATA_HI		0x18U
317808b06bSVarun Wadekar 
327808b06bSVarun Wadekar /* Status values for the current request */
33ab3a33feSSteven Kao #define ARI_REQ_PENDING			1U
34ab3a33feSSteven Kao #define ARI_REQ_ONGOING			3U
35ab3a33feSSteven Kao #define ARI_REQUEST_VALID_BIT		(1U << 8)
36ab3a33feSSteven Kao #define ARI_EVT_MASK_STANDBYWFI_BIT	(1U << 7)
37ab3a33feSSteven Kao 
38f9f620d6SVarun Wadekar /* default timeout (us) to wait for ARI completion */
39f9f620d6SVarun Wadekar #define ARI_MAX_RETRY_COUNT		U(2000000)
407808b06bSVarun Wadekar 
417808b06bSVarun Wadekar /*******************************************************************************
427808b06bSVarun Wadekar  * ARI helper functions
437808b06bSVarun Wadekar  ******************************************************************************/
ari_read_32(uint32_t ari_base,uint32_t reg)447808b06bSVarun Wadekar static inline uint32_t ari_read_32(uint32_t ari_base, uint32_t reg)
457808b06bSVarun Wadekar {
46ab712fd8SAnthony Zhou 	return mmio_read_32((uint64_t)ari_base + (uint64_t)reg);
477808b06bSVarun Wadekar }
487808b06bSVarun Wadekar 
ari_write_32(uint32_t ari_base,uint32_t val,uint32_t reg)497808b06bSVarun Wadekar static inline void ari_write_32(uint32_t ari_base, uint32_t val, uint32_t reg)
507808b06bSVarun Wadekar {
51ab712fd8SAnthony Zhou 	mmio_write_32((uint64_t)ari_base + (uint64_t)reg, val);
527808b06bSVarun Wadekar }
537808b06bSVarun Wadekar 
ari_get_request_low(uint32_t ari_base)547808b06bSVarun Wadekar static inline uint32_t ari_get_request_low(uint32_t ari_base)
557808b06bSVarun Wadekar {
567808b06bSVarun Wadekar 	return ari_read_32(ari_base, ARI_REQUEST_DATA_LO);
577808b06bSVarun Wadekar }
587808b06bSVarun Wadekar 
ari_get_request_high(uint32_t ari_base)597808b06bSVarun Wadekar static inline uint32_t ari_get_request_high(uint32_t ari_base)
607808b06bSVarun Wadekar {
617808b06bSVarun Wadekar 	return ari_read_32(ari_base, ARI_REQUEST_DATA_HI);
627808b06bSVarun Wadekar }
637808b06bSVarun Wadekar 
ari_get_response_low(uint32_t ari_base)647808b06bSVarun Wadekar static inline uint32_t ari_get_response_low(uint32_t ari_base)
657808b06bSVarun Wadekar {
667808b06bSVarun Wadekar 	return ari_read_32(ari_base, ARI_RESPONSE_DATA_LO);
677808b06bSVarun Wadekar }
687808b06bSVarun Wadekar 
ari_get_response_high(uint32_t ari_base)697808b06bSVarun Wadekar static inline uint32_t ari_get_response_high(uint32_t ari_base)
707808b06bSVarun Wadekar {
717808b06bSVarun Wadekar 	return ari_read_32(ari_base, ARI_RESPONSE_DATA_HI);
727808b06bSVarun Wadekar }
737808b06bSVarun Wadekar 
ari_clobber_response(uint32_t ari_base)747808b06bSVarun Wadekar static inline void ari_clobber_response(uint32_t ari_base)
757808b06bSVarun Wadekar {
767808b06bSVarun Wadekar 	ari_write_32(ari_base, 0, ARI_RESPONSE_DATA_LO);
777808b06bSVarun Wadekar 	ari_write_32(ari_base, 0, ARI_RESPONSE_DATA_HI);
787808b06bSVarun Wadekar }
797808b06bSVarun Wadekar 
ari_request_wait(uint32_t ari_base,uint32_t evt_mask,uint32_t req,uint32_t lo,uint32_t hi)80ab712fd8SAnthony Zhou static int32_t ari_request_wait(uint32_t ari_base, uint32_t evt_mask, uint32_t req,
817808b06bSVarun Wadekar 		uint32_t lo, uint32_t hi)
827808b06bSVarun Wadekar {
83f9f620d6SVarun Wadekar 	uint32_t retries = (uint32_t)ARI_MAX_RETRY_COUNT;
84ab3a33feSSteven Kao 	uint32_t status;
85ab712fd8SAnthony Zhou 	int32_t ret = 0;
867808b06bSVarun Wadekar 
877808b06bSVarun Wadekar 	/* program the request, event_mask, hi and lo registers */
887808b06bSVarun Wadekar 	ari_write_32(ari_base, lo, ARI_REQUEST_DATA_LO);
897808b06bSVarun Wadekar 	ari_write_32(ari_base, hi, ARI_REQUEST_DATA_HI);
907808b06bSVarun Wadekar 	ari_write_32(ari_base, evt_mask, ARI_REQUEST_EVENT_MASK);
917808b06bSVarun Wadekar 	ari_write_32(ari_base, req | ARI_REQUEST_VALID_BIT, ARI_REQUEST);
927808b06bSVarun Wadekar 
937808b06bSVarun Wadekar 	/*
947808b06bSVarun Wadekar 	 * For commands that have an event trigger, we should bypass
957808b06bSVarun Wadekar 	 * ARI_STATUS polling, since MCE is waiting for SW to trigger
967808b06bSVarun Wadekar 	 * the event.
977808b06bSVarun Wadekar 	 */
98ab712fd8SAnthony Zhou 	if (evt_mask != 0U) {
99ab712fd8SAnthony Zhou 		ret = 0;
100ab712fd8SAnthony Zhou 	} else {
101ab3a33feSSteven Kao 		/* For shutdown/reboot commands, we dont have to check for timeouts */
1020f426f8fSAnthony Zhou 		if ((req == TEGRA_ARI_MISC_CCPLEX) &&
1030f426f8fSAnthony Zhou 		    ((lo == TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) ||
1040f426f8fSAnthony Zhou 		     (lo == TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT))) {
105ab712fd8SAnthony Zhou 				ret = 0;
106ab712fd8SAnthony Zhou 		} else {
107ab3a33feSSteven Kao 			/*
108ab3a33feSSteven Kao 			 * Wait for the command response for not more than the timeout
109ab3a33feSSteven Kao 			 */
110ab3a33feSSteven Kao 			while (retries != 0U) {
111ab3a33feSSteven Kao 
112ab3a33feSSteven Kao 				/* read the command status */
1137808b06bSVarun Wadekar 				status = ari_read_32(ari_base, ARI_STATUS);
114ab712fd8SAnthony Zhou 				if ((status & (ARI_REQ_ONGOING | ARI_REQ_PENDING)) == 0U) {
115ab3a33feSSteven Kao 					break;
116ab712fd8SAnthony Zhou 				}
117ab3a33feSSteven Kao 
118f9f620d6SVarun Wadekar 				/* delay 1 us */
119f9f620d6SVarun Wadekar 				udelay(1);
120ab3a33feSSteven Kao 
121ab3a33feSSteven Kao 				/* decrement the retry count */
122ab3a33feSSteven Kao 				retries--;
123ab3a33feSSteven Kao 			}
124ab3a33feSSteven Kao 
125ab3a33feSSteven Kao 			/* assert if the command timed out */
126ab3a33feSSteven Kao 			if (retries == 0U) {
127ab3a33feSSteven Kao 				ERROR("ARI request timed out: req %d on CPU %d\n",
128ab3a33feSSteven Kao 					req, plat_my_core_pos());
129ab3a33feSSteven Kao 				assert(retries != 0U);
130ab3a33feSSteven Kao 			}
131ab712fd8SAnthony Zhou 		}
1327808b06bSVarun Wadekar 	}
1337808b06bSVarun Wadekar 
134ab712fd8SAnthony Zhou 	return ret;
135ab712fd8SAnthony Zhou }
136ab712fd8SAnthony Zhou 
ari_enter_cstate(uint32_t ari_base,uint32_t state,uint32_t wake_time)137ab712fd8SAnthony Zhou int32_t ari_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time)
1387808b06bSVarun Wadekar {
139ab712fd8SAnthony Zhou 	int32_t ret = 0;
1407808b06bSVarun Wadekar 
141ab712fd8SAnthony Zhou 	/* check for allowed power state */
142ab712fd8SAnthony Zhou 	if ((state != TEGRA_ARI_CORE_C0) &&
143ab712fd8SAnthony Zhou 	    (state != TEGRA_ARI_CORE_C1) &&
144ab712fd8SAnthony Zhou 	    (state != TEGRA_ARI_CORE_C6) &&
145ab712fd8SAnthony Zhou 	    (state != TEGRA_ARI_CORE_C7)) {
146ab712fd8SAnthony Zhou 		ERROR("%s: unknown cstate (%d)\n", __func__, state);
147ab712fd8SAnthony Zhou 		ret = EINVAL;
148ab712fd8SAnthony Zhou 	} else {
14910007118SKrishna Sitaraman 		/* clean the previous response state */
15010007118SKrishna Sitaraman 		ari_clobber_response(ari_base);
15110007118SKrishna Sitaraman 
1527808b06bSVarun Wadekar 		/* Enter the cstate, to be woken up after wake_time (TSC ticks) */
153ab712fd8SAnthony Zhou 		ret = ari_request_wait(ari_base, ARI_EVT_MASK_STANDBYWFI_BIT,
154aa64c5fbSAnthony Zhou 			(uint32_t)TEGRA_ARI_ENTER_CSTATE, state, wake_time);
1557808b06bSVarun Wadekar 	}
1567808b06bSVarun Wadekar 
157ab712fd8SAnthony Zhou 	return ret;
158ab712fd8SAnthony Zhou }
159ab712fd8SAnthony Zhou 
ari_update_cstate_info(uint32_t ari_base,uint32_t cluster,uint32_t ccplex,uint32_t system,uint8_t sys_state_force,uint32_t wake_mask,uint8_t update_wake_mask)160ab712fd8SAnthony Zhou int32_t ari_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex,
1617808b06bSVarun Wadekar 	uint32_t system, uint8_t sys_state_force, uint32_t wake_mask,
1627808b06bSVarun Wadekar 	uint8_t update_wake_mask)
1637808b06bSVarun Wadekar {
1640f426f8fSAnthony Zhou 	uint64_t val = 0U;
1657808b06bSVarun Wadekar 
16610007118SKrishna Sitaraman 	/* clean the previous response state */
16710007118SKrishna Sitaraman 	ari_clobber_response(ari_base);
16810007118SKrishna Sitaraman 
1697808b06bSVarun Wadekar 	/* update CLUSTER_CSTATE? */
170ab712fd8SAnthony Zhou 	if (cluster != 0U) {
1710f426f8fSAnthony Zhou 		val |= (cluster & CLUSTER_CSTATE_MASK) |
1720f426f8fSAnthony Zhou 			CLUSTER_CSTATE_UPDATE_BIT;
173ab712fd8SAnthony Zhou 	}
1747808b06bSVarun Wadekar 
1757808b06bSVarun Wadekar 	/* update CCPLEX_CSTATE? */
176ab712fd8SAnthony Zhou 	if (ccplex != 0U) {
1770f426f8fSAnthony Zhou 		val |= ((ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT) |
1780f426f8fSAnthony Zhou 			CCPLEX_CSTATE_UPDATE_BIT;
179ab712fd8SAnthony Zhou 	}
1807808b06bSVarun Wadekar 
1817808b06bSVarun Wadekar 	/* update SYSTEM_CSTATE? */
182ab712fd8SAnthony Zhou 	if (system != 0U) {
1830f426f8fSAnthony Zhou 		val |= ((system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) |
1840f426f8fSAnthony Zhou 		       (((uint64_t)sys_state_force << SYSTEM_CSTATE_FORCE_UPDATE_SHIFT) |
1850f426f8fSAnthony Zhou 			SYSTEM_CSTATE_UPDATE_BIT);
186ab712fd8SAnthony Zhou 	}
1877808b06bSVarun Wadekar 
1887808b06bSVarun Wadekar 	/* update wake mask value? */
189ab712fd8SAnthony Zhou 	if (update_wake_mask != 0U) {
1900f426f8fSAnthony Zhou 		val |= CSTATE_WAKE_MASK_UPDATE_BIT;
191ab712fd8SAnthony Zhou 	}
1927808b06bSVarun Wadekar 
1937808b06bSVarun Wadekar 	/* set the updated cstate info */
194aa64c5fbSAnthony Zhou 	return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_UPDATE_CSTATE_INFO,
1950f426f8fSAnthony Zhou 				(uint32_t)val, wake_mask);
1967808b06bSVarun Wadekar }
1977808b06bSVarun Wadekar 
ari_update_crossover_time(uint32_t ari_base,uint32_t type,uint32_t time)198ab712fd8SAnthony Zhou int32_t ari_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time)
1997808b06bSVarun Wadekar {
200ab712fd8SAnthony Zhou 	int32_t ret = 0;
201ab712fd8SAnthony Zhou 
2027808b06bSVarun Wadekar 	/* sanity check crossover type */
2037808b06bSVarun Wadekar 	if ((type == TEGRA_ARI_CROSSOVER_C1_C6) ||
204ab712fd8SAnthony Zhou 	    (type > TEGRA_ARI_CROSSOVER_CCP3_SC1)) {
205ab712fd8SAnthony Zhou 		ret = EINVAL;
206ab712fd8SAnthony Zhou 	} else {
20710007118SKrishna Sitaraman 		/* clean the previous response state */
20810007118SKrishna Sitaraman 		ari_clobber_response(ari_base);
20910007118SKrishna Sitaraman 
2107808b06bSVarun Wadekar 		/* update crossover threshold time */
211aa64c5fbSAnthony Zhou 		ret = ari_request_wait(ari_base, 0U,
212aa64c5fbSAnthony Zhou 				(uint32_t)TEGRA_ARI_UPDATE_CROSSOVER, type, time);
2137808b06bSVarun Wadekar 	}
2147808b06bSVarun Wadekar 
215ab712fd8SAnthony Zhou 	return ret;
216ab712fd8SAnthony Zhou }
217ab712fd8SAnthony Zhou 
ari_read_cstate_stats(uint32_t ari_base,uint32_t state)2187808b06bSVarun Wadekar uint64_t ari_read_cstate_stats(uint32_t ari_base, uint32_t state)
2197808b06bSVarun Wadekar {
220ab712fd8SAnthony Zhou 	int32_t ret;
221ab712fd8SAnthony Zhou 	uint64_t result;
2227808b06bSVarun Wadekar 
2237808b06bSVarun Wadekar 	/* sanity check crossover type */
224ab712fd8SAnthony Zhou 	if (state == 0U) {
225ab712fd8SAnthony Zhou 		result = EINVAL;
226ab712fd8SAnthony Zhou 	} else {
22710007118SKrishna Sitaraman 		/* clean the previous response state */
22810007118SKrishna Sitaraman 		ari_clobber_response(ari_base);
22910007118SKrishna Sitaraman 
230aa64c5fbSAnthony Zhou 		ret = ari_request_wait(ari_base, 0U,
231aa64c5fbSAnthony Zhou 				(uint32_t)TEGRA_ARI_CSTATE_STATS, state, 0U);
232ab712fd8SAnthony Zhou 		if (ret != 0) {
233ab712fd8SAnthony Zhou 			result = EINVAL;
234ab712fd8SAnthony Zhou 		} else {
235ab712fd8SAnthony Zhou 			result = (uint64_t)ari_get_response_low(ari_base);
236ab712fd8SAnthony Zhou 		}
237ab712fd8SAnthony Zhou 	}
238ab712fd8SAnthony Zhou 	return result;
2397808b06bSVarun Wadekar }
2407808b06bSVarun Wadekar 
ari_write_cstate_stats(uint32_t ari_base,uint32_t state,uint32_t stats)241ab712fd8SAnthony Zhou int32_t ari_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats)
2427808b06bSVarun Wadekar {
24310007118SKrishna Sitaraman 	/* clean the previous response state */
24410007118SKrishna Sitaraman 	ari_clobber_response(ari_base);
24510007118SKrishna Sitaraman 
2467808b06bSVarun Wadekar 	/* write the cstate stats */
247aa64c5fbSAnthony Zhou 	return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_WRITE_CSTATE_STATS,
248aa64c5fbSAnthony Zhou 			state, stats);
2497808b06bSVarun Wadekar }
2507808b06bSVarun Wadekar 
ari_enumeration_misc(uint32_t ari_base,uint32_t cmd,uint32_t data)2517808b06bSVarun Wadekar uint64_t ari_enumeration_misc(uint32_t ari_base, uint32_t cmd, uint32_t data)
2527808b06bSVarun Wadekar {
2537808b06bSVarun Wadekar 	uint64_t resp;
254ab712fd8SAnthony Zhou 	int32_t ret;
255ab712fd8SAnthony Zhou 	uint32_t local_data = data;
2567808b06bSVarun Wadekar 
2577808b06bSVarun Wadekar 	/* clean the previous response state */
2587808b06bSVarun Wadekar 	ari_clobber_response(ari_base);
2597808b06bSVarun Wadekar 
2607808b06bSVarun Wadekar 	/* ARI_REQUEST_DATA_HI is reserved for commands other than 'ECHO' */
261ab712fd8SAnthony Zhou 	if (cmd != TEGRA_ARI_MISC_ECHO) {
262ab712fd8SAnthony Zhou 		local_data = 0U;
263ab712fd8SAnthony Zhou 	}
2647808b06bSVarun Wadekar 
265aa64c5fbSAnthony Zhou 	ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_MISC, cmd, local_data);
266ab712fd8SAnthony Zhou 	if (ret != 0) {
267ab712fd8SAnthony Zhou 		resp = (uint64_t)ret;
268ab712fd8SAnthony Zhou 	} else {
2697808b06bSVarun Wadekar 		/* get the command response */
2707808b06bSVarun Wadekar 		resp = ari_get_response_low(ari_base);
2717808b06bSVarun Wadekar 		resp |= ((uint64_t)ari_get_response_high(ari_base) << 32);
272ab712fd8SAnthony Zhou 	}
2737808b06bSVarun Wadekar 
2747808b06bSVarun Wadekar 	return resp;
2757808b06bSVarun Wadekar }
2767808b06bSVarun Wadekar 
ari_is_ccx_allowed(uint32_t ari_base,uint32_t state,uint32_t wake_time)277ab712fd8SAnthony Zhou int32_t ari_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time)
2787808b06bSVarun Wadekar {
279ab712fd8SAnthony Zhou 	int32_t ret;
280ab712fd8SAnthony Zhou 	uint32_t result;
2817808b06bSVarun Wadekar 
28210007118SKrishna Sitaraman 	/* clean the previous response state */
28310007118SKrishna Sitaraman 	ari_clobber_response(ari_base);
28410007118SKrishna Sitaraman 
285aa64c5fbSAnthony Zhou 	ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_IS_CCX_ALLOWED,
286aa64c5fbSAnthony Zhou 			state & 0x7U, wake_time);
287ab712fd8SAnthony Zhou 	if (ret != 0) {
2887808b06bSVarun Wadekar 		ERROR("%s: failed (%d)\n", __func__, ret);
289ab712fd8SAnthony Zhou 		result = 0U;
290ab712fd8SAnthony Zhou 	} else {
291ab712fd8SAnthony Zhou 		result = ari_get_response_low(ari_base) & 0x1U;
2927808b06bSVarun Wadekar 	}
2937808b06bSVarun Wadekar 
2947808b06bSVarun Wadekar 	/* 1 = CCx allowed, 0 = CCx not allowed */
295ab712fd8SAnthony Zhou 	return (int32_t)result;
2967808b06bSVarun Wadekar }
2977808b06bSVarun Wadekar 
ari_is_sc7_allowed(uint32_t ari_base,uint32_t state,uint32_t wake_time)298ab712fd8SAnthony Zhou int32_t ari_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time)
2997808b06bSVarun Wadekar {
300ab712fd8SAnthony Zhou 	int32_t ret, result;
3017808b06bSVarun Wadekar 
3027808b06bSVarun Wadekar 	/* check for allowed power state */
3030f426f8fSAnthony Zhou 	if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) &&
3040f426f8fSAnthony Zhou 	    (state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) {
3057808b06bSVarun Wadekar 		ERROR("%s: unknown cstate (%d)\n", __func__, state);
306ab712fd8SAnthony Zhou 		result = EINVAL;
307ab712fd8SAnthony Zhou 	} else {
30810007118SKrishna Sitaraman 		/* clean the previous response state */
30910007118SKrishna Sitaraman 		ari_clobber_response(ari_base);
31010007118SKrishna Sitaraman 
311aa64c5fbSAnthony Zhou 		ret = ari_request_wait(ari_base, 0U,
312aa64c5fbSAnthony Zhou 			(uint32_t)TEGRA_ARI_IS_SC7_ALLOWED, state, wake_time);
313ab712fd8SAnthony Zhou 		if (ret != 0) {
3147808b06bSVarun Wadekar 			ERROR("%s: failed (%d)\n", __func__, ret);
315ab712fd8SAnthony Zhou 			result = 0;
316ab712fd8SAnthony Zhou 		} else {
3177808b06bSVarun Wadekar 			/* 1 = SC7 allowed, 0 = SC7 not allowed */
318ab712fd8SAnthony Zhou 			result = (ari_get_response_low(ari_base) != 0U) ? 1 : 0;
319ab712fd8SAnthony Zhou 		}
3207808b06bSVarun Wadekar 	}
3217808b06bSVarun Wadekar 
322ab712fd8SAnthony Zhou 	return result;
323ab712fd8SAnthony Zhou }
324ab712fd8SAnthony Zhou 
ari_online_core(uint32_t ari_base,uint32_t core)325ab712fd8SAnthony Zhou int32_t ari_online_core(uint32_t ari_base, uint32_t core)
3267808b06bSVarun Wadekar {
3270f426f8fSAnthony Zhou 	uint64_t cpu = read_mpidr() & (MPIDR_CPU_MASK);
3280f426f8fSAnthony Zhou 	uint64_t cluster = (read_mpidr() & (MPIDR_CLUSTER_MASK)) >>
3290f426f8fSAnthony Zhou 			   (MPIDR_AFFINITY_BITS);
3300f426f8fSAnthony Zhou 	uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
331ab712fd8SAnthony Zhou 	int32_t ret;
3327808b06bSVarun Wadekar 
3337808b06bSVarun Wadekar 	/* construct the current CPU # */
3347808b06bSVarun Wadekar 	cpu |= (cluster << 2);
3357808b06bSVarun Wadekar 
3367808b06bSVarun Wadekar 	/* sanity check target core id */
337ab712fd8SAnthony Zhou 	if ((core >= MCE_CORE_ID_MAX) || (cpu == (uint64_t)core)) {
3387808b06bSVarun Wadekar 		ERROR("%s: unsupported core id (%d)\n", __func__, core);
339ab712fd8SAnthony Zhou 		ret = EINVAL;
340ab712fd8SAnthony Zhou 	} else {
3417808b06bSVarun Wadekar 		/*
3427808b06bSVarun Wadekar 		 * The Denver cluster has 2 CPUs only - 0, 1.
3437808b06bSVarun Wadekar 		 */
3440f426f8fSAnthony Zhou 		if ((impl == DENVER_IMPL) && ((core == 2U) || (core == 3U))) {
3457808b06bSVarun Wadekar 			ERROR("%s: unknown core id (%d)\n", __func__, core);
346ab712fd8SAnthony Zhou 			ret = EINVAL;
347ab712fd8SAnthony Zhou 		} else {
34810007118SKrishna Sitaraman 			/* clean the previous response state */
34910007118SKrishna Sitaraman 			ari_clobber_response(ari_base);
350aa64c5fbSAnthony Zhou 			ret = ari_request_wait(ari_base, 0U,
351aa64c5fbSAnthony Zhou 				(uint32_t)TEGRA_ARI_ONLINE_CORE, core, 0U);
352ab712fd8SAnthony Zhou 		}
3537808b06bSVarun Wadekar 	}
3547808b06bSVarun Wadekar 
355ab712fd8SAnthony Zhou 	return ret;
356ab712fd8SAnthony Zhou }
357ab712fd8SAnthony Zhou 
ari_cc3_ctrl(uint32_t ari_base,uint32_t freq,uint32_t volt,uint8_t enable)358ab712fd8SAnthony Zhou int32_t ari_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable)
3597808b06bSVarun Wadekar {
360ab712fd8SAnthony Zhou 	uint32_t val;
3617808b06bSVarun Wadekar 
36210007118SKrishna Sitaraman 	/* clean the previous response state */
36310007118SKrishna Sitaraman 	ari_clobber_response(ari_base);
36410007118SKrishna Sitaraman 
3657808b06bSVarun Wadekar 	/*
3667808b06bSVarun Wadekar 	 * If the enable bit is cleared, Auto-CC3 will be disabled by setting
3677808b06bSVarun Wadekar 	 * the SW visible voltage/frequency request registers for all non
3687808b06bSVarun Wadekar 	 * floorswept cores valid independent of StandbyWFI and disabling
3697808b06bSVarun Wadekar 	 * the IDLE voltage/frequency request register. If set, Auto-CC3
3707808b06bSVarun Wadekar 	 * will be enabled by setting the ARM SW visible voltage/frequency
3717808b06bSVarun Wadekar 	 * request registers for all non floorswept cores to be enabled by
3727808b06bSVarun Wadekar 	 * StandbyWFI or the equivalent signal, and always keeping the IDLE
3737808b06bSVarun Wadekar 	 * voltage/frequency request register enabled.
3747808b06bSVarun Wadekar 	 */
375*9a90d720SElyes Haouas 	val = (((freq & MCE_AUTO_CC3_FREQ_MASK) << MCE_AUTO_CC3_FREQ_SHIFT) |
376*9a90d720SElyes Haouas 		((volt & MCE_AUTO_CC3_VTG_MASK) << MCE_AUTO_CC3_VTG_SHIFT) |
377ab712fd8SAnthony Zhou 		((enable != 0U) ? MCE_AUTO_CC3_ENABLE_BIT : 0U));
3787808b06bSVarun Wadekar 
379aa64c5fbSAnthony Zhou 	return ari_request_wait(ari_base, 0U,
380aa64c5fbSAnthony Zhou 			(uint32_t)TEGRA_ARI_CC3_CTRL, val, 0U);
3817808b06bSVarun Wadekar }
3827808b06bSVarun Wadekar 
ari_reset_vector_update(uint32_t ari_base)383ab712fd8SAnthony Zhou int32_t ari_reset_vector_update(uint32_t ari_base)
3847808b06bSVarun Wadekar {
38510007118SKrishna Sitaraman 	/* clean the previous response state */
38610007118SKrishna Sitaraman 	ari_clobber_response(ari_base);
38710007118SKrishna Sitaraman 
3887808b06bSVarun Wadekar 	/*
3897808b06bSVarun Wadekar 	 * Need to program the CPU reset vector one time during cold boot
3907808b06bSVarun Wadekar 	 * and SC7 exit
3917808b06bSVarun Wadekar 	 */
392aa64c5fbSAnthony Zhou 	(void)ari_request_wait(ari_base, 0U,
393aa64c5fbSAnthony Zhou 			(uint32_t)TEGRA_ARI_COPY_MISCREG_AA64_RST, 0U, 0U);
3947808b06bSVarun Wadekar 
3957808b06bSVarun Wadekar 	return 0;
3967808b06bSVarun Wadekar }
3977808b06bSVarun Wadekar 
ari_roc_flush_cache_trbits(uint32_t ari_base)398ab712fd8SAnthony Zhou int32_t ari_roc_flush_cache_trbits(uint32_t ari_base)
3997808b06bSVarun Wadekar {
40010007118SKrishna Sitaraman 	/* clean the previous response state */
40110007118SKrishna Sitaraman 	ari_clobber_response(ari_base);
40210007118SKrishna Sitaraman 
403aa64c5fbSAnthony Zhou 	return ari_request_wait(ari_base, 0U,
404aa64c5fbSAnthony Zhou 			(uint32_t)TEGRA_ARI_ROC_FLUSH_CACHE_TRBITS, 0U, 0U);
4057808b06bSVarun Wadekar }
4067808b06bSVarun Wadekar 
ari_roc_flush_cache(uint32_t ari_base)407ab712fd8SAnthony Zhou int32_t ari_roc_flush_cache(uint32_t ari_base)
4087808b06bSVarun Wadekar {
40910007118SKrishna Sitaraman 	/* clean the previous response state */
41010007118SKrishna Sitaraman 	ari_clobber_response(ari_base);
41110007118SKrishna Sitaraman 
412aa64c5fbSAnthony Zhou 	return ari_request_wait(ari_base, 0U,
413aa64c5fbSAnthony Zhou 			(uint32_t)TEGRA_ARI_ROC_FLUSH_CACHE_ONLY, 0U, 0U);
4147808b06bSVarun Wadekar }
4157808b06bSVarun Wadekar 
ari_roc_clean_cache(uint32_t ari_base)416ab712fd8SAnthony Zhou int32_t ari_roc_clean_cache(uint32_t ari_base)
4177808b06bSVarun Wadekar {
41810007118SKrishna Sitaraman 	/* clean the previous response state */
41910007118SKrishna Sitaraman 	ari_clobber_response(ari_base);
42010007118SKrishna Sitaraman 
421aa64c5fbSAnthony Zhou 	return ari_request_wait(ari_base, 0U,
422aa64c5fbSAnthony Zhou 			(uint32_t)TEGRA_ARI_ROC_CLEAN_CACHE_ONLY, 0U, 0U);
4237808b06bSVarun Wadekar }
4247808b06bSVarun Wadekar 
ari_read_write_mca(uint32_t ari_base,uint64_t cmd,uint64_t * data)425ab712fd8SAnthony Zhou uint64_t ari_read_write_mca(uint32_t ari_base, uint64_t cmd, uint64_t *data)
4267808b06bSVarun Wadekar {
427ab712fd8SAnthony Zhou 	uint64_t mca_arg_data, result = 0;
428ab712fd8SAnthony Zhou 	uint32_t resp_lo, resp_hi;
429ab712fd8SAnthony Zhou 	uint32_t mca_arg_err, mca_arg_finish;
430ab712fd8SAnthony Zhou 	int32_t ret;
4317808b06bSVarun Wadekar 
4327808b06bSVarun Wadekar 	/* Set data (write) */
433ab712fd8SAnthony Zhou 	mca_arg_data = (data != NULL) ? *data : 0ULL;
4347808b06bSVarun Wadekar 
4357808b06bSVarun Wadekar 	/* Set command */
436ab712fd8SAnthony Zhou 	ari_write_32(ari_base, (uint32_t)cmd, ARI_RESPONSE_DATA_LO);
437ab712fd8SAnthony Zhou 	ari_write_32(ari_base, (uint32_t)(cmd >> 32U), ARI_RESPONSE_DATA_HI);
4387808b06bSVarun Wadekar 
439aa64c5fbSAnthony Zhou 	ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_MCA,
440ab712fd8SAnthony Zhou 			       (uint32_t)mca_arg_data,
441e47ac1fdSAntonio Nino Diaz 			       (uint32_t)(mca_arg_data >> 32U));
442ab712fd8SAnthony Zhou 	if (ret == 0) {
443ab712fd8SAnthony Zhou 		resp_lo = ari_get_response_low(ari_base);
444ab712fd8SAnthony Zhou 		resp_hi = ari_get_response_high(ari_base);
4457808b06bSVarun Wadekar 
446ab712fd8SAnthony Zhou 		mca_arg_err = resp_lo & MCA_ARG_ERROR_MASK;
447ab712fd8SAnthony Zhou 		mca_arg_finish = (resp_hi >> MCA_ARG_FINISH_SHIFT) &
448ab712fd8SAnthony Zhou 				 MCA_ARG_FINISH_MASK;
449ab712fd8SAnthony Zhou 
450ab712fd8SAnthony Zhou 		if (mca_arg_finish == 0U) {
451ab712fd8SAnthony Zhou 			result = (uint64_t)mca_arg_err;
452ab712fd8SAnthony Zhou 		} else {
453ab712fd8SAnthony Zhou 			if (data != NULL) {
454ab712fd8SAnthony Zhou 				resp_lo = ari_get_request_low(ari_base);
455ab712fd8SAnthony Zhou 				resp_hi = ari_get_request_high(ari_base);
456e47ac1fdSAntonio Nino Diaz 				*data = ((uint64_t)resp_hi << 32U) |
457ab712fd8SAnthony Zhou 					 (uint64_t)resp_lo;
458ab712fd8SAnthony Zhou 			}
4597808b06bSVarun Wadekar 		}
4607808b06bSVarun Wadekar 	}
4617808b06bSVarun Wadekar 
462ab712fd8SAnthony Zhou 	return result;
4637808b06bSVarun Wadekar }
4647808b06bSVarun Wadekar 
ari_update_ccplex_gsc(uint32_t ari_base,uint32_t gsc_idx)465ab712fd8SAnthony Zhou int32_t ari_update_ccplex_gsc(uint32_t ari_base, uint32_t gsc_idx)
4667808b06bSVarun Wadekar {
467ab712fd8SAnthony Zhou 	int32_t ret = 0;
4687808b06bSVarun Wadekar 	/* sanity check GSC ID */
4690f426f8fSAnthony Zhou 	if (gsc_idx > TEGRA_ARI_GSC_VPR_IDX) {
470ab712fd8SAnthony Zhou 		ret = EINVAL;
471ab712fd8SAnthony Zhou 	} else {
47210007118SKrishna Sitaraman 		/* clean the previous response state */
47310007118SKrishna Sitaraman 		ari_clobber_response(ari_base);
47410007118SKrishna Sitaraman 
4757808b06bSVarun Wadekar 		/*
4767808b06bSVarun Wadekar 		 * The MCE code will read the GSC carveout value, corrseponding to
4777808b06bSVarun Wadekar 		 * the ID, from the MC registers and update the internal GSC registers
4787808b06bSVarun Wadekar 		 * of the CCPLEX.
4797808b06bSVarun Wadekar 		 */
480aa64c5fbSAnthony Zhou 		(void)ari_request_wait(ari_base, 0U,
481aa64c5fbSAnthony Zhou 				(uint32_t)TEGRA_ARI_UPDATE_CCPLEX_GSC, gsc_idx, 0U);
482ab712fd8SAnthony Zhou 	}
4837808b06bSVarun Wadekar 
484ab712fd8SAnthony Zhou 	return ret;
4857808b06bSVarun Wadekar }
4867808b06bSVarun Wadekar 
ari_enter_ccplex_state(uint32_t ari_base,uint32_t state_idx)4877808b06bSVarun Wadekar void ari_enter_ccplex_state(uint32_t ari_base, uint32_t state_idx)
4887808b06bSVarun Wadekar {
48910007118SKrishna Sitaraman 	/* clean the previous response state */
49010007118SKrishna Sitaraman 	ari_clobber_response(ari_base);
49110007118SKrishna Sitaraman 
4927808b06bSVarun Wadekar 	/*
4937808b06bSVarun Wadekar 	 * The MCE will shutdown or restart the entire system
4947808b06bSVarun Wadekar 	 */
495aa64c5fbSAnthony Zhou 	(void)ari_request_wait(ari_base, 0U,
496aa64c5fbSAnthony Zhou 			(uint32_t)TEGRA_ARI_MISC_CCPLEX, state_idx, 0U);
4977808b06bSVarun Wadekar }
498c11e0ddfSVarun Wadekar 
ari_read_write_uncore_perfmon(uint32_t ari_base,uint64_t req,uint64_t * data)499ab712fd8SAnthony Zhou int32_t ari_read_write_uncore_perfmon(uint32_t ari_base, uint64_t req,
500ab712fd8SAnthony Zhou 		uint64_t *data)
501c11e0ddfSVarun Wadekar {
502ab712fd8SAnthony Zhou 	int32_t ret, result;
503a9cd8630SAnthony Zhou 	uint32_t val, req_status;
504a9cd8630SAnthony Zhou 	uint8_t req_cmd;
505ab712fd8SAnthony Zhou 
506f8f400d2SVarun Wadekar 	req_cmd = (uint8_t)(req & UNCORE_PERFMON_CMD_MASK);
507c11e0ddfSVarun Wadekar 
50810007118SKrishna Sitaraman 	/* clean the previous response state */
50910007118SKrishna Sitaraman 	ari_clobber_response(ari_base);
51010007118SKrishna Sitaraman 
511c11e0ddfSVarun Wadekar 	/* sanity check input parameters */
512ab712fd8SAnthony Zhou 	if ((req_cmd == UNCORE_PERFMON_CMD_READ) && (data == NULL)) {
513c11e0ddfSVarun Wadekar 		ERROR("invalid parameters\n");
514ab712fd8SAnthony Zhou 		result = EINVAL;
515ab712fd8SAnthony Zhou 	} else {
516c11e0ddfSVarun Wadekar 		/*
517c11e0ddfSVarun Wadekar 		 * For "write" commands get the value that has to be written
518c11e0ddfSVarun Wadekar 		 * to the uncore perfmon registers
519c11e0ddfSVarun Wadekar 		 */
520ab712fd8SAnthony Zhou 		val = (req_cmd == UNCORE_PERFMON_CMD_WRITE) ?
521e47ac1fdSAntonio Nino Diaz 			(uint32_t)*data : 0U;
522c11e0ddfSVarun Wadekar 
523aa64c5fbSAnthony Zhou 		ret = ari_request_wait(ari_base, 0U,
524aa64c5fbSAnthony Zhou 			(uint32_t)TEGRA_ARI_PERFMON, val, (uint32_t)req);
525ab712fd8SAnthony Zhou 		if (ret != 0) {
526ab712fd8SAnthony Zhou 			result = ret;
527ab712fd8SAnthony Zhou 		} else {
528c11e0ddfSVarun Wadekar 			/* read the command status value */
529a9cd8630SAnthony Zhou 			req_status = ari_get_response_high(ari_base) &
530c11e0ddfSVarun Wadekar 					 UNCORE_PERFMON_RESP_STATUS_MASK;
531c11e0ddfSVarun Wadekar 
532c11e0ddfSVarun Wadekar 			/*
533c11e0ddfSVarun Wadekar 			 * For "read" commands get the data from the uncore
534c11e0ddfSVarun Wadekar 			 * perfmon registers
535c11e0ddfSVarun Wadekar 			 */
536f8f400d2SVarun Wadekar 			req_status &= UNCORE_PERFMON_RESP_STATUS_MASK;
537ab712fd8SAnthony Zhou 			if ((req_status == 0U) && (req_cmd == UNCORE_PERFMON_CMD_READ)) {
538c11e0ddfSVarun Wadekar 				*data = ari_get_response_low(ari_base);
539ab712fd8SAnthony Zhou 			}
540ab712fd8SAnthony Zhou 			result = (int32_t)req_status;
541ab712fd8SAnthony Zhou 		}
542ab712fd8SAnthony Zhou 	}
543c11e0ddfSVarun Wadekar 
544ab712fd8SAnthony Zhou 	return result;
545c11e0ddfSVarun Wadekar }
54653451898SKrishna Sitaraman 
ari_misc_ccplex(uint32_t ari_base,uint32_t index,uint32_t value)54753451898SKrishna Sitaraman void ari_misc_ccplex(uint32_t ari_base, uint32_t index, uint32_t value)
54853451898SKrishna Sitaraman {
54953451898SKrishna Sitaraman 	/*
55053451898SKrishna Sitaraman 	 * This invokes the ARI_MISC_CCPLEX commands. This can be
55153451898SKrishna Sitaraman 	 * used to enable/disable coresight clock gating.
55253451898SKrishna Sitaraman 	 */
55353451898SKrishna Sitaraman 
5545dc574b4SRich Wiley 	if ((index > TEGRA_ARI_MISC_CCPLEX_EDBGREQ) ||
55553451898SKrishna Sitaraman 		((index == TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL) &&
556ab712fd8SAnthony Zhou 		(value > 1U))) {
55753451898SKrishna Sitaraman 		ERROR("%s: invalid parameters \n", __func__);
558ab712fd8SAnthony Zhou 	} else {
55953451898SKrishna Sitaraman 		/* clean the previous response state */
56053451898SKrishna Sitaraman 		ari_clobber_response(ari_base);
561aa64c5fbSAnthony Zhou 		(void)ari_request_wait(ari_base, 0U,
562aa64c5fbSAnthony Zhou 			(uint32_t)TEGRA_ARI_MISC_CCPLEX, index, value);
563ab712fd8SAnthony Zhou 	}
56453451898SKrishna Sitaraman }
565