18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2012 Advanced Micro Devices, Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "radeon.h"
258c2ecf20Sopenharmony_ci#include "sumod.h"
268c2ecf20Sopenharmony_ci#include "sumo_dpm.h"
278c2ecf20Sopenharmony_ci#include "ppsmc.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define SUMO_SMU_SERVICE_ROUTINE_PG_INIT        1
308c2ecf20Sopenharmony_ci#define SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY  27
318c2ecf20Sopenharmony_ci#define SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20  20
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistruct sumo_power_info *sumo_get_pi(struct radeon_device *rdev);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic void sumo_send_msg_to_smu(struct radeon_device *rdev, u32 id)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	u32 gfx_int_req;
388c2ecf20Sopenharmony_ci	int i;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
418c2ecf20Sopenharmony_ci		if (RREG32(GFX_INT_STATUS) & INT_DONE)
428c2ecf20Sopenharmony_ci			break;
438c2ecf20Sopenharmony_ci		udelay(1);
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	gfx_int_req = SERV_INDEX(id) | INT_REQ;
478c2ecf20Sopenharmony_ci	WREG32(GFX_INT_REQ, gfx_int_req);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
508c2ecf20Sopenharmony_ci		if (RREG32(GFX_INT_REQ) & INT_REQ)
518c2ecf20Sopenharmony_ci			break;
528c2ecf20Sopenharmony_ci		udelay(1);
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
568c2ecf20Sopenharmony_ci		if (RREG32(GFX_INT_STATUS) & INT_ACK)
578c2ecf20Sopenharmony_ci			break;
588c2ecf20Sopenharmony_ci		udelay(1);
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
628c2ecf20Sopenharmony_ci		if (RREG32(GFX_INT_STATUS) & INT_DONE)
638c2ecf20Sopenharmony_ci			break;
648c2ecf20Sopenharmony_ci		udelay(1);
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	gfx_int_req &= ~INT_REQ;
688c2ecf20Sopenharmony_ci	WREG32(GFX_INT_REQ, gfx_int_req);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_civoid sumo_initialize_m3_arb(struct radeon_device *rdev)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
748c2ecf20Sopenharmony_ci	u32 i;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (!pi->enable_dynamic_m3_arbiter)
778c2ecf20Sopenharmony_ci		return;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	for (i = 0; i < NUMBER_OF_M3ARB_PARAM_SETS; i++)
808c2ecf20Sopenharmony_ci		WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
818c2ecf20Sopenharmony_ci			   pi->sys_info.csr_m3_arb_cntl_default[i]);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 2; i++)
848c2ecf20Sopenharmony_ci		WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
858c2ecf20Sopenharmony_ci			   pi->sys_info.csr_m3_arb_cntl_uvd[i % NUMBER_OF_M3ARB_PARAM_SETS]);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 3; i++)
888c2ecf20Sopenharmony_ci		WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
898c2ecf20Sopenharmony_ci			   pi->sys_info.csr_m3_arb_cntl_fs3d[i % NUMBER_OF_M3ARB_PARAM_SETS]);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic bool sumo_is_alt_vddnb_supported(struct radeon_device *rdev)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
958c2ecf20Sopenharmony_ci	bool return_code = false;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	if (!pi->enable_alt_vddnb)
988c2ecf20Sopenharmony_ci		return return_code;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	if ((rdev->family == CHIP_SUMO) || (rdev->family == CHIP_SUMO2)) {
1018c2ecf20Sopenharmony_ci		if (pi->fw_version >= 0x00010C00)
1028c2ecf20Sopenharmony_ci			return_code = true;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return return_code;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_civoid sumo_smu_notify_alt_vddnb_change(struct radeon_device *rdev,
1098c2ecf20Sopenharmony_ci				      bool powersaving, bool force_nbps1)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	u32 param = 0;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (!sumo_is_alt_vddnb_supported(rdev))
1148c2ecf20Sopenharmony_ci		return;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (powersaving)
1178c2ecf20Sopenharmony_ci		param |= 1;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (force_nbps1)
1208c2ecf20Sopenharmony_ci		param |= 2;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	WREG32_RCU(RCU_ALTVDDNB_NOTIFY, param);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_civoid sumo_smu_pg_init(struct radeon_device *rdev)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_PG_INIT);
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic u32 sumo_power_of_4(u32 unit)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	u32 ret = 1;
1358c2ecf20Sopenharmony_ci	u32 i;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	for (i = 0; i < unit; i++)
1388c2ecf20Sopenharmony_ci		ret *= 4;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return ret;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_civoid sumo_enable_boost_timer(struct radeon_device *rdev)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
1468c2ecf20Sopenharmony_ci	u32 period, unit, timer_value;
1478c2ecf20Sopenharmony_ci	u32 xclk = radeon_get_xclk(rdev);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	unit = (RREG32_RCU(RCU_LCLK_SCALING_CNTL) & LCLK_SCALING_TIMER_PRESCALER_MASK)
1508c2ecf20Sopenharmony_ci		>> LCLK_SCALING_TIMER_PRESCALER_SHIFT;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	period = 100 * (xclk / 100 / sumo_power_of_4(unit));
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	timer_value = (period << 16) | (unit << 4);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	WREG32_RCU(RCU_GNB_PWR_REP_TIMER_CNTL, timer_value);
1578c2ecf20Sopenharmony_ci	WREG32_RCU(RCU_BOOST_MARGIN, pi->sys_info.sclk_dpm_boost_margin);
1588c2ecf20Sopenharmony_ci	WREG32_RCU(RCU_THROTTLE_MARGIN, pi->sys_info.sclk_dpm_throttle_margin);
1598c2ecf20Sopenharmony_ci	WREG32_RCU(GNB_TDP_LIMIT, pi->sys_info.gnb_tdp_limit);
1608c2ecf20Sopenharmony_ci	WREG32_RCU(RCU_SclkDpmTdpLimitPG, pi->sys_info.sclk_dpm_tdp_limit_pg);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20);
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_civoid sumo_set_tdp_limit(struct radeon_device *rdev, u32 index, u32 tdp_limit)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	u32 regoffset = 0;
1688c2ecf20Sopenharmony_ci	u32 shift = 0;
1698c2ecf20Sopenharmony_ci	u32 mask = 0xFFF;
1708c2ecf20Sopenharmony_ci	u32 sclk_dpm_tdp_limit;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	switch (index) {
1738c2ecf20Sopenharmony_ci	case 0:
1748c2ecf20Sopenharmony_ci		regoffset = RCU_SclkDpmTdpLimit01;
1758c2ecf20Sopenharmony_ci		shift = 16;
1768c2ecf20Sopenharmony_ci		break;
1778c2ecf20Sopenharmony_ci	case 1:
1788c2ecf20Sopenharmony_ci		regoffset = RCU_SclkDpmTdpLimit01;
1798c2ecf20Sopenharmony_ci		shift = 0;
1808c2ecf20Sopenharmony_ci		break;
1818c2ecf20Sopenharmony_ci	case 2:
1828c2ecf20Sopenharmony_ci		regoffset = RCU_SclkDpmTdpLimit23;
1838c2ecf20Sopenharmony_ci		shift = 16;
1848c2ecf20Sopenharmony_ci		break;
1858c2ecf20Sopenharmony_ci	case 3:
1868c2ecf20Sopenharmony_ci		regoffset = RCU_SclkDpmTdpLimit23;
1878c2ecf20Sopenharmony_ci		shift = 0;
1888c2ecf20Sopenharmony_ci		break;
1898c2ecf20Sopenharmony_ci	case 4:
1908c2ecf20Sopenharmony_ci		regoffset = RCU_SclkDpmTdpLimit47;
1918c2ecf20Sopenharmony_ci		shift = 16;
1928c2ecf20Sopenharmony_ci		break;
1938c2ecf20Sopenharmony_ci	case 7:
1948c2ecf20Sopenharmony_ci		regoffset = RCU_SclkDpmTdpLimit47;
1958c2ecf20Sopenharmony_ci		shift = 0;
1968c2ecf20Sopenharmony_ci		break;
1978c2ecf20Sopenharmony_ci	default:
1988c2ecf20Sopenharmony_ci		break;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	sclk_dpm_tdp_limit = RREG32_RCU(regoffset);
2028c2ecf20Sopenharmony_ci	sclk_dpm_tdp_limit &= ~(mask << shift);
2038c2ecf20Sopenharmony_ci	sclk_dpm_tdp_limit |= (tdp_limit << shift);
2048c2ecf20Sopenharmony_ci	WREG32_RCU(regoffset, sclk_dpm_tdp_limit);
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_civoid sumo_boost_state_enable(struct radeon_device *rdev, bool enable)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	u32 boost_disable = RREG32_RCU(RCU_GPU_BOOST_DISABLE);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	boost_disable &= 0xFFFFFFFE;
2128c2ecf20Sopenharmony_ci	boost_disable |= (enable ? 0 : 1);
2138c2ecf20Sopenharmony_ci	WREG32_RCU(RCU_GPU_BOOST_DISABLE, boost_disable);
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ciu32 sumo_get_running_fw_version(struct radeon_device *rdev)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	return RREG32_RCU(RCU_FW_VERSION);
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
221