xref: /rk3399_ARM-atf/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c (revision 859df7d55bc5176c8c1dac69920de22809fa600d)
141612559SVarun Wadekar /*
2e1fcb1bfSVarun Wadekar  * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
341612559SVarun Wadekar  *
441612559SVarun Wadekar  * SPDX-License-Identifier: BSD-3-Clause
541612559SVarun Wadekar  */
641612559SVarun Wadekar 
7*5ce05d6bSAnthony Zhou #include <assert.h>
8*5ce05d6bSAnthony Zhou #include <errno.h>
9*5ce05d6bSAnthony Zhou 
1041612559SVarun Wadekar #include <arch.h>
1141612559SVarun Wadekar #include <arch_helpers.h>
1241612559SVarun Wadekar #include <common/debug.h>
1341612559SVarun Wadekar #include <denver.h>
1441612559SVarun Wadekar #include <lib/mmio.h>
15*5ce05d6bSAnthony Zhou 
1641612559SVarun Wadekar #include <mce_private.h>
179808032cSSteven Kao #include <platform_def.h>
189808032cSSteven Kao #include <t194_nvg.h>
192cd2e399SSteven Kao #include <tegra_private.h>
2041612559SVarun Wadekar 
214a232d5bSVarun Wadekar #define	ID_AFR0_EL1_CACHE_OPS_SHIFT	U(12)
224a232d5bSVarun Wadekar #define	ID_AFR0_EL1_CACHE_OPS_MASK	U(0xF)
239808032cSSteven Kao /*
249808032cSSteven Kao  * Reports the major and minor version of this interface.
259808032cSSteven Kao  *
269808032cSSteven Kao  * NVGDATA[0:31]: SW(R) Minor Version
279808032cSSteven Kao  * NVGDATA[32:63]: SW(R) Major Version
289808032cSSteven Kao  */
nvg_get_version(void)299808032cSSteven Kao uint64_t nvg_get_version(void)
3041612559SVarun Wadekar {
316152de3bSAnthony Zhou 	nvg_set_request((uint64_t)TEGRA_NVG_CHANNEL_VERSION);
329808032cSSteven Kao 
339808032cSSteven Kao 	return (uint64_t)nvg_get_result();
3441612559SVarun Wadekar }
3541612559SVarun Wadekar 
369808032cSSteven Kao /*
379808032cSSteven Kao  * Set the expected wake time in TSC ticks for the next low-power state the
389808032cSSteven Kao  * core enters.
399808032cSSteven Kao  *
409808032cSSteven Kao  * NVGDATA[0:31]: SW(RW), WAKE_TIME
419808032cSSteven Kao  */
nvg_set_wake_time(uint32_t wake_time)429808032cSSteven Kao void nvg_set_wake_time(uint32_t wake_time)
439808032cSSteven Kao {
449808032cSSteven Kao 	/* time (TSC ticks) until the core is expected to get a wake event */
456152de3bSAnthony Zhou 	nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_WAKE_TIME, (uint64_t)wake_time);
469808032cSSteven Kao }
479808032cSSteven Kao 
489808032cSSteven Kao /*
4941612559SVarun Wadekar  * This request allows updating of CLUSTER_CSTATE, CCPLEX_CSTATE and
5041612559SVarun Wadekar  * SYSTEM_CSTATE values.
519808032cSSteven Kao  *
529808032cSSteven Kao  * NVGDATA[0:2]: SW(RW), CLUSTER_CSTATE
539808032cSSteven Kao  * NVGDATA[7]: SW(W), update cluster flag
544b412b50SVignesh Radhakrishnan  * NVGDATA[8:10]: SW(RW), CG_CSTATE
559808032cSSteven Kao  * NVGDATA[15]: SW(W), update ccplex flag
569808032cSSteven Kao  * NVGDATA[16:19]: SW(RW), SYSTEM_CSTATE
579808032cSSteven Kao  * NVGDATA[23]: SW(W), update system flag
589808032cSSteven Kao  * NVGDATA[31]: SW(W), update wake mask flag
599808032cSSteven Kao  * NVGDATA[32:63]: SW(RW), WAKE_MASK
6041612559SVarun Wadekar  */
nvg_update_cstate_info(uint32_t cluster,uint32_t ccplex,uint32_t system,uint32_t wake_mask,uint8_t update_wake_mask)619808032cSSteven Kao void nvg_update_cstate_info(uint32_t cluster, uint32_t ccplex,
629808032cSSteven Kao 		uint32_t system, uint32_t wake_mask, uint8_t update_wake_mask)
6341612559SVarun Wadekar {
6441612559SVarun Wadekar 	uint64_t val = 0;
6541612559SVarun Wadekar 
6641612559SVarun Wadekar 	/* update CLUSTER_CSTATE? */
679808032cSSteven Kao 	if (cluster != 0U) {
689808032cSSteven Kao 		val |= ((uint64_t)cluster & CLUSTER_CSTATE_MASK) |
6941612559SVarun Wadekar 				CLUSTER_CSTATE_UPDATE_BIT;
709808032cSSteven Kao 	}
7141612559SVarun Wadekar 
7241612559SVarun Wadekar 	/* update CCPLEX_CSTATE? */
739808032cSSteven Kao 	if (ccplex != 0U) {
749808032cSSteven Kao 		val |= (((uint64_t)ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT) |
7541612559SVarun Wadekar 				CCPLEX_CSTATE_UPDATE_BIT;
769808032cSSteven Kao 	}
7741612559SVarun Wadekar 
7841612559SVarun Wadekar 	/* update SYSTEM_CSTATE? */
799808032cSSteven Kao 	if (system != 0U) {
809808032cSSteven Kao 		val |= (((uint64_t)system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) |
819808032cSSteven Kao 				SYSTEM_CSTATE_UPDATE_BIT;
829808032cSSteven Kao 	}
8341612559SVarun Wadekar 
8441612559SVarun Wadekar 	/* update wake mask value? */
859808032cSSteven Kao 	if (update_wake_mask != 0U) {
8641612559SVarun Wadekar 		val |= CSTATE_WAKE_MASK_UPDATE_BIT;
879808032cSSteven Kao 	}
8841612559SVarun Wadekar 
8941612559SVarun Wadekar 	/* set the wake mask */
909808032cSSteven Kao 	val |= ((uint64_t)wake_mask & CSTATE_WAKE_MASK_CLEAR) << CSTATE_WAKE_MASK_SHIFT;
9141612559SVarun Wadekar 
9241612559SVarun Wadekar 	/* set the updated cstate info */
936152de3bSAnthony Zhou 	nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_CSTATE_INFO, val);
9441612559SVarun Wadekar }
9541612559SVarun Wadekar 
9641612559SVarun Wadekar /*
979808032cSSteven Kao  * Return a non-zero value if the CCPLEX is able to enter SC7
989808032cSSteven Kao  *
999808032cSSteven Kao  * NVGDATA[0]: SW(R), Is allowed result
1009808032cSSteven Kao  */
nvg_is_sc7_allowed(void)1019808032cSSteven Kao int32_t nvg_is_sc7_allowed(void)
1029808032cSSteven Kao {
10341612559SVarun Wadekar 	/* issue command to check if SC7 is allowed */
1046152de3bSAnthony Zhou 	nvg_set_request((uint64_t)TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED);
10541612559SVarun Wadekar 
10641612559SVarun Wadekar 	/* 1 = SC7 allowed, 0 = SC7 not allowed */
1079808032cSSteven Kao 	return (int32_t)nvg_get_result();
10841612559SVarun Wadekar }
10941612559SVarun Wadekar 
11041612559SVarun Wadekar /*
1119808032cSSteven Kao  * Wake an offlined logical core. Note that a core is offlined by entering
1129808032cSSteven Kao  * a C-state where the WAKE_MASK is all 0.
1139808032cSSteven Kao  *
1149808032cSSteven Kao  * NVGDATA[0:3]: SW(W) logical core to online
11541612559SVarun Wadekar  */
nvg_online_core(uint32_t core)1169808032cSSteven Kao int32_t nvg_online_core(uint32_t core)
11741612559SVarun Wadekar {
1189808032cSSteven Kao 	int32_t ret = 0;
1199808032cSSteven Kao 
1209808032cSSteven Kao 	/* sanity check the core ID value */
1219808032cSSteven Kao 	if (core > (uint32_t)PLATFORM_CORE_COUNT) {
1229808032cSSteven Kao 		ERROR("%s: unknown core id (%d)\n", __func__, core);
123e1fcb1bfSVarun Wadekar 		ret = -EINVAL;
1249808032cSSteven Kao 	} else {
1259808032cSSteven Kao 		/* get a core online */
1266152de3bSAnthony Zhou 		nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_ONLINE_CORE,
1279808032cSSteven Kao 					(uint64_t)core & MCE_CORE_ID_MASK);
1289808032cSSteven Kao 	}
1299808032cSSteven Kao 
1309808032cSSteven Kao 	return ret;
1319808032cSSteven Kao }
1329808032cSSteven Kao 
1339808032cSSteven Kao /*
1349808032cSSteven Kao  * MC GSC (General Security Carveout) register values are expected to be
1359808032cSSteven Kao  * changed by TrustZone ARM code after boot.
1369808032cSSteven Kao  *
1379808032cSSteven Kao  * NVGDATA[0:15] SW(R) GSC enun
1389808032cSSteven Kao  */
nvg_update_ccplex_gsc(uint32_t gsc_idx)1399808032cSSteven Kao int32_t nvg_update_ccplex_gsc(uint32_t gsc_idx)
1409808032cSSteven Kao {
141e1fcb1bfSVarun Wadekar 	int32_t ret = 0;
1429808032cSSteven Kao 
1439808032cSSteven Kao 	/* sanity check GSC ID */
1442bda9202SSteven Kao 	if (gsc_idx > (uint32_t)TEGRA_NVG_CHANNEL_UPDATE_GSC_VPR) {
1452bda9202SSteven Kao 		ERROR("%s: unknown gsc_idx (%u)\n", __func__, gsc_idx);
146e1fcb1bfSVarun Wadekar 		ret = -EINVAL;
1479808032cSSteven Kao 	} else {
1486152de3bSAnthony Zhou 		nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_UPDATE_CCPLEX_GSC,
1499808032cSSteven Kao 				     (uint64_t)gsc_idx);
1509808032cSSteven Kao 	}
1519808032cSSteven Kao 
1529808032cSSteven Kao 	return ret;
1539808032cSSteven Kao }
1549808032cSSteven Kao 
1559808032cSSteven Kao /*
1569808032cSSteven Kao  * Cache clean and invalidate, clear TR-bit operation for all CCPLEX caches.
1579808032cSSteven Kao  */
nvg_roc_clean_cache_trbits(void)1589808032cSSteven Kao int32_t nvg_roc_clean_cache_trbits(void)
1599808032cSSteven Kao {
16072e8caa7SSteven Kao 	int32_t ret = 0;
1619808032cSSteven Kao 
16272e8caa7SSteven Kao 	/* check if cache flush through mts is supported */
16372e8caa7SSteven Kao 	if (((read_id_afr0_el1() >> ID_AFR0_EL1_CACHE_OPS_SHIFT) &
16472e8caa7SSteven Kao 			ID_AFR0_EL1_CACHE_OPS_MASK) == 1U) {
16572e8caa7SSteven Kao 		if (nvg_cache_inval_all() == 0U) {
16672e8caa7SSteven Kao 			ERROR("%s: failed\n", __func__);
167e1fcb1bfSVarun Wadekar 			ret = -ENODEV;
16872e8caa7SSteven Kao 		}
16972e8caa7SSteven Kao 	} else {
170e1fcb1bfSVarun Wadekar 		ret = -ENOTSUP;
17172e8caa7SSteven Kao 	}
172e1fcb1bfSVarun Wadekar 
17372e8caa7SSteven Kao 	return ret;
1749808032cSSteven Kao }
1759808032cSSteven Kao 
1769808032cSSteven Kao /*
1779808032cSSteven Kao  * Set the power state for a core
1789808032cSSteven Kao  */
nvg_enter_cstate(uint32_t state,uint32_t wake_time)1799808032cSSteven Kao int32_t nvg_enter_cstate(uint32_t state, uint32_t wake_time)
1809808032cSSteven Kao {
1819808032cSSteven Kao 	int32_t ret = 0;
1822cd2e399SSteven Kao 	uint64_t val = 0ULL;
1839808032cSSteven Kao 
1849808032cSSteven Kao 	/* check for allowed power state */
1859808032cSSteven Kao 	if ((state != (uint32_t)TEGRA_NVG_CORE_C0) &&
1869808032cSSteven Kao 		(state != (uint32_t)TEGRA_NVG_CORE_C1) &&
1879808032cSSteven Kao 	    (state != (uint32_t)TEGRA_NVG_CORE_C6) &&
1889808032cSSteven Kao 		(state != (uint32_t)TEGRA_NVG_CORE_C7))
1899808032cSSteven Kao 	{
190e1fcb1bfSVarun Wadekar 		ERROR("%s: unknown cstate (%u)\n", __func__, state);
191e1fcb1bfSVarun Wadekar 		ret = -EINVAL;
1929808032cSSteven Kao 	} else {
1939808032cSSteven Kao 		/* time (TSC ticks) until the core is expected to get a wake event */
1949808032cSSteven Kao 		nvg_set_wake_time(wake_time);
1959808032cSSteven Kao 
1969808032cSSteven Kao 		/* set the core cstate */
1972cd2e399SSteven Kao 		val = read_actlr_el1() & ~ACTLR_EL1_PMSTATE_MASK;
1982cd2e399SSteven Kao 		write_actlr_el1(val | (uint64_t)state);
1999808032cSSteven Kao 	}
2009808032cSSteven Kao 
2019808032cSSteven Kao 	return ret;
2029808032cSSteven Kao }
203ac252f95SDilan Lee 
204a3c2c0e9SSteven Kao #if ENABLE_STRICT_CHECKING_MODE
205ac252f95SDilan Lee /*
206ac252f95SDilan Lee  * Enable strict checking mode
207ac252f95SDilan Lee  *
208ac252f95SDilan Lee  * NVGDATA[3] strict_check ON + lock
209ac252f95SDilan Lee  */
nvg_enable_strict_checking_mode(void)210ac252f95SDilan Lee void nvg_enable_strict_checking_mode(void)
211ac252f95SDilan Lee {
212ac252f95SDilan Lee 	uint64_t params = (uint64_t)(STRICT_CHECKING_ENABLED_SET |
213ac252f95SDilan Lee 				     STRICT_CHECKING_LOCKED_SET);
214ac252f95SDilan Lee 
2154a232d5bSVarun Wadekar 	nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_SECURITY_CONFIG, params);
216ac252f95SDilan Lee }
217*5ce05d6bSAnthony Zhou 
nvg_verify_strict_checking_mode(void)218*5ce05d6bSAnthony Zhou void nvg_verify_strict_checking_mode(void)
219*5ce05d6bSAnthony Zhou {
220*5ce05d6bSAnthony Zhou 	uint64_t params = (uint64_t)(STRICT_CHECKING_ENABLED_SET |
221*5ce05d6bSAnthony Zhou 				     STRICT_CHECKING_LOCKED_SET);
222*5ce05d6bSAnthony Zhou 
223*5ce05d6bSAnthony Zhou 	nvg_set_request((uint64_t)TEGRA_NVG_CHANNEL_SECURITY_CONFIG);
224*5ce05d6bSAnthony Zhou 	assert(params == (uint64_t)nvg_get_result());
225*5ce05d6bSAnthony Zhou }
226a3c2c0e9SSteven Kao #endif
2270789758aSVignesh Radhakrishnan 
2280789758aSVignesh Radhakrishnan /*
2290789758aSVignesh Radhakrishnan  * Request a reboot
2300789758aSVignesh Radhakrishnan  *
2310789758aSVignesh Radhakrishnan  * NVGDATA[0]: reboot command
2320789758aSVignesh Radhakrishnan  */
nvg_system_reboot(void)2330789758aSVignesh Radhakrishnan void nvg_system_reboot(void)
2340789758aSVignesh Radhakrishnan {
2350789758aSVignesh Radhakrishnan 	/* issue command for reboot */
2364a232d5bSVarun Wadekar 	nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_SHUTDOWN,
2374a232d5bSVarun Wadekar 			     (uint64_t)TEGRA_NVG_REBOOT);
2380789758aSVignesh Radhakrishnan }
2390789758aSVignesh Radhakrishnan 
2400789758aSVignesh Radhakrishnan /*
2410789758aSVignesh Radhakrishnan  * Request a shutdown
2420789758aSVignesh Radhakrishnan  *
2430789758aSVignesh Radhakrishnan  * NVGDATA[0]: shutdown command
2440789758aSVignesh Radhakrishnan  */
nvg_system_shutdown(void)2450789758aSVignesh Radhakrishnan void nvg_system_shutdown(void)
2460789758aSVignesh Radhakrishnan {
2470789758aSVignesh Radhakrishnan 	/* issue command for shutdown */
2484a232d5bSVarun Wadekar 	nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_SHUTDOWN,
2494a232d5bSVarun Wadekar 			     (uint64_t)TEGRA_NVG_SHUTDOWN);
2500789758aSVignesh Radhakrishnan }
2510d851195SVarun Wadekar 
2520d851195SVarun Wadekar /*
2530d851195SVarun Wadekar  * Request to clear CCPLEX->HSM correctable error signal.
2540d851195SVarun Wadekar  * NVGDATA[1]: A write of 1 clears the CCPLEX->HSM correctable error signal,
2550d851195SVarun Wadekar  *             A write of 0 has no effect.
2560d851195SVarun Wadekar  */
nvg_clear_hsm_corr_status(void)2570d851195SVarun Wadekar void nvg_clear_hsm_corr_status(void)
2580d851195SVarun Wadekar {
2590d851195SVarun Wadekar 	nvg_hsm_error_ctrl_channel_t status = { .bits = { .corr = 1U, }, };
2600d851195SVarun Wadekar 
2610d851195SVarun Wadekar 	nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_HSM_ERROR_CTRL, status.flat);
2620d851195SVarun Wadekar }
263