1*8267edfdSriastradh /*	$NetBSD: amdgpu_renoir_ppt.c,v 1.4 2021/12/19 12:37:54 riastradh Exp $	*/
21571a7a1Sriastradh 
31571a7a1Sriastradh /*
41571a7a1Sriastradh  * Copyright 2019 Advanced Micro Devices, Inc.
51571a7a1Sriastradh  *
61571a7a1Sriastradh  * Permission is hereby granted, free of charge, to any person obtaining a
71571a7a1Sriastradh  * copy of this software and associated documentation files (the "Software"),
81571a7a1Sriastradh  * to deal in the Software without restriction, including without limitation
91571a7a1Sriastradh  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
101571a7a1Sriastradh  * and/or sell copies of the Software, and to permit persons to whom the
111571a7a1Sriastradh  * Software is furnished to do so, subject to the following conditions:
121571a7a1Sriastradh  *
131571a7a1Sriastradh  * The above copyright notice and this permission notice shall be included in
141571a7a1Sriastradh  * all copies or substantial portions of the Software.
151571a7a1Sriastradh  *
161571a7a1Sriastradh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171571a7a1Sriastradh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181571a7a1Sriastradh  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
191571a7a1Sriastradh  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
201571a7a1Sriastradh  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
211571a7a1Sriastradh  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
221571a7a1Sriastradh  * OTHER DEALINGS IN THE SOFTWARE.
231571a7a1Sriastradh  *
241571a7a1Sriastradh  */
251571a7a1Sriastradh 
261571a7a1Sriastradh #include <sys/cdefs.h>
27*8267edfdSriastradh __KERNEL_RCSID(0, "$NetBSD: amdgpu_renoir_ppt.c,v 1.4 2021/12/19 12:37:54 riastradh Exp $");
281571a7a1Sriastradh 
291571a7a1Sriastradh #include "amdgpu.h"
301571a7a1Sriastradh #include "amdgpu_smu.h"
311571a7a1Sriastradh #include "smu_internal.h"
321571a7a1Sriastradh #include "soc15_common.h"
331571a7a1Sriastradh #include "smu_v12_0_ppsmc.h"
341571a7a1Sriastradh #include "smu12_driver_if.h"
351571a7a1Sriastradh #include "smu_v12_0.h"
361571a7a1Sriastradh #include "renoir_ppt.h"
371571a7a1Sriastradh 
38*8267edfdSriastradh #include <linux/nbsd-namespace.h>
39*8267edfdSriastradh 
401571a7a1Sriastradh 
411571a7a1Sriastradh #define CLK_MAP(clk, index) \
421571a7a1Sriastradh 	[SMU_##clk] = {1, (index)}
431571a7a1Sriastradh 
441571a7a1Sriastradh #define MSG_MAP(msg, index) \
451571a7a1Sriastradh 	[SMU_MSG_##msg] = {1, (index)}
461571a7a1Sriastradh 
471571a7a1Sriastradh #define TAB_MAP_VALID(tab) \
481571a7a1Sriastradh 	[SMU_TABLE_##tab] = {1, TABLE_##tab}
491571a7a1Sriastradh 
501571a7a1Sriastradh #define TAB_MAP_INVALID(tab) \
511571a7a1Sriastradh 	[SMU_TABLE_##tab] = {0, TABLE_##tab}
521571a7a1Sriastradh 
531571a7a1Sriastradh static struct smu_12_0_cmn2aisc_mapping renoir_message_map[SMU_MSG_MAX_COUNT] = {
541571a7a1Sriastradh 	MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage),
551571a7a1Sriastradh 	MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion),
561571a7a1Sriastradh 	MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion),
571571a7a1Sriastradh 	MSG_MAP(PowerUpGfx,                     PPSMC_MSG_PowerUpGfx),
581571a7a1Sriastradh 	MSG_MAP(AllowGfxOff,                    PPSMC_MSG_EnableGfxOff),
591571a7a1Sriastradh 	MSG_MAP(DisallowGfxOff,                 PPSMC_MSG_DisableGfxOff),
601571a7a1Sriastradh 	MSG_MAP(PowerDownIspByTile,             PPSMC_MSG_PowerDownIspByTile),
611571a7a1Sriastradh 	MSG_MAP(PowerUpIspByTile,               PPSMC_MSG_PowerUpIspByTile),
621571a7a1Sriastradh 	MSG_MAP(PowerDownVcn,                   PPSMC_MSG_PowerDownVcn),
631571a7a1Sriastradh 	MSG_MAP(PowerUpVcn,                     PPSMC_MSG_PowerUpVcn),
641571a7a1Sriastradh 	MSG_MAP(PowerDownSdma,                  PPSMC_MSG_PowerDownSdma),
651571a7a1Sriastradh 	MSG_MAP(PowerUpSdma,                    PPSMC_MSG_PowerUpSdma),
661571a7a1Sriastradh 	MSG_MAP(SetHardMinIspclkByFreq,         PPSMC_MSG_SetHardMinIspclkByFreq),
671571a7a1Sriastradh 	MSG_MAP(SetHardMinVcn,                  PPSMC_MSG_SetHardMinVcn),
681571a7a1Sriastradh 	MSG_MAP(Spare1,                         PPSMC_MSG_spare1),
691571a7a1Sriastradh 	MSG_MAP(Spare2,                         PPSMC_MSG_spare2),
701571a7a1Sriastradh 	MSG_MAP(SetAllowFclkSwitch,             PPSMC_MSG_SetAllowFclkSwitch),
711571a7a1Sriastradh 	MSG_MAP(SetMinVideoGfxclkFreq,          PPSMC_MSG_SetMinVideoGfxclkFreq),
721571a7a1Sriastradh 	MSG_MAP(ActiveProcessNotify,            PPSMC_MSG_ActiveProcessNotify),
731571a7a1Sriastradh 	MSG_MAP(SetCustomPolicy,                PPSMC_MSG_SetCustomPolicy),
741571a7a1Sriastradh 	MSG_MAP(SetVideoFps,                    PPSMC_MSG_SetVideoFps),
751571a7a1Sriastradh 	MSG_MAP(NumOfDisplays,                  PPSMC_MSG_SetDisplayCount),
761571a7a1Sriastradh 	MSG_MAP(QueryPowerLimit,                PPSMC_MSG_QueryPowerLimit),
771571a7a1Sriastradh 	MSG_MAP(SetDriverDramAddrHigh,          PPSMC_MSG_SetDriverDramAddrHigh),
781571a7a1Sriastradh 	MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverDramAddrLow),
791571a7a1Sriastradh 	MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram),
801571a7a1Sriastradh 	MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu),
811571a7a1Sriastradh 	MSG_MAP(GfxDeviceDriverReset,           PPSMC_MSG_GfxDeviceDriverReset),
821571a7a1Sriastradh 	MSG_MAP(SetGfxclkOverdriveByFreqVid,    PPSMC_MSG_SetGfxclkOverdriveByFreqVid),
831571a7a1Sriastradh 	MSG_MAP(SetHardMinDcfclkByFreq,         PPSMC_MSG_SetHardMinDcfclkByFreq),
841571a7a1Sriastradh 	MSG_MAP(SetHardMinSocclkByFreq,         PPSMC_MSG_SetHardMinSocclkByFreq),
851571a7a1Sriastradh 	MSG_MAP(ControlIgpuATS,                 PPSMC_MSG_ControlIgpuATS),
861571a7a1Sriastradh 	MSG_MAP(SetMinVideoFclkFreq,            PPSMC_MSG_SetMinVideoFclkFreq),
871571a7a1Sriastradh 	MSG_MAP(SetMinDeepSleepDcfclk,          PPSMC_MSG_SetMinDeepSleepDcfclk),
881571a7a1Sriastradh 	MSG_MAP(ForcePowerDownGfx,              PPSMC_MSG_ForcePowerDownGfx),
891571a7a1Sriastradh 	MSG_MAP(SetPhyclkVoltageByFreq,         PPSMC_MSG_SetPhyclkVoltageByFreq),
901571a7a1Sriastradh 	MSG_MAP(SetDppclkVoltageByFreq,         PPSMC_MSG_SetDppclkVoltageByFreq),
911571a7a1Sriastradh 	MSG_MAP(SetSoftMinVcn,                  PPSMC_MSG_SetSoftMinVcn),
921571a7a1Sriastradh 	MSG_MAP(EnablePostCode,                 PPSMC_MSG_EnablePostCode),
931571a7a1Sriastradh 	MSG_MAP(GetGfxclkFrequency,             PPSMC_MSG_GetGfxclkFrequency),
941571a7a1Sriastradh 	MSG_MAP(GetFclkFrequency,               PPSMC_MSG_GetFclkFrequency),
951571a7a1Sriastradh 	MSG_MAP(GetMinGfxclkFrequency,          PPSMC_MSG_GetMinGfxclkFrequency),
961571a7a1Sriastradh 	MSG_MAP(GetMaxGfxclkFrequency,          PPSMC_MSG_GetMaxGfxclkFrequency),
971571a7a1Sriastradh 	MSG_MAP(SoftReset,                      PPSMC_MSG_SoftReset),
981571a7a1Sriastradh 	MSG_MAP(SetGfxCGPG,                     PPSMC_MSG_SetGfxCGPG),
991571a7a1Sriastradh 	MSG_MAP(SetSoftMaxGfxClk,               PPSMC_MSG_SetSoftMaxGfxClk),
1001571a7a1Sriastradh 	MSG_MAP(SetHardMinGfxClk,               PPSMC_MSG_SetHardMinGfxClk),
1011571a7a1Sriastradh 	MSG_MAP(SetSoftMaxSocclkByFreq,         PPSMC_MSG_SetSoftMaxSocclkByFreq),
1021571a7a1Sriastradh 	MSG_MAP(SetSoftMaxFclkByFreq,           PPSMC_MSG_SetSoftMaxFclkByFreq),
1031571a7a1Sriastradh 	MSG_MAP(SetSoftMaxVcn,                  PPSMC_MSG_SetSoftMaxVcn),
1041571a7a1Sriastradh 	MSG_MAP(PowerGateMmHub,                 PPSMC_MSG_PowerGateMmHub),
1051571a7a1Sriastradh 	MSG_MAP(UpdatePmeRestore,               PPSMC_MSG_UpdatePmeRestore),
1061571a7a1Sriastradh 	MSG_MAP(GpuChangeState,                 PPSMC_MSG_GpuChangeState),
1071571a7a1Sriastradh 	MSG_MAP(SetPowerLimitPercentage,        PPSMC_MSG_SetPowerLimitPercentage),
1081571a7a1Sriastradh 	MSG_MAP(ForceGfxContentSave,            PPSMC_MSG_ForceGfxContentSave),
1091571a7a1Sriastradh 	MSG_MAP(EnableTmdp48MHzRefclkPwrDown,   PPSMC_MSG_EnableTmdp48MHzRefclkPwrDown),
1101571a7a1Sriastradh 	MSG_MAP(PowerDownJpeg,                  PPSMC_MSG_PowerDownJpeg),
1111571a7a1Sriastradh 	MSG_MAP(PowerUpJpeg,                    PPSMC_MSG_PowerUpJpeg),
1121571a7a1Sriastradh 	MSG_MAP(PowerGateAtHub,                 PPSMC_MSG_PowerGateAtHub),
1131571a7a1Sriastradh 	MSG_MAP(SetSoftMinJpeg,                 PPSMC_MSG_SetSoftMinJpeg),
1141571a7a1Sriastradh 	MSG_MAP(SetHardMinFclkByFreq,           PPSMC_MSG_SetHardMinFclkByFreq),
1151571a7a1Sriastradh };
1161571a7a1Sriastradh 
1171571a7a1Sriastradh static struct smu_12_0_cmn2aisc_mapping renoir_clk_map[SMU_CLK_COUNT] = {
1181571a7a1Sriastradh 	CLK_MAP(GFXCLK, CLOCK_GFXCLK),
1191571a7a1Sriastradh 	CLK_MAP(SCLK,	CLOCK_GFXCLK),
1201571a7a1Sriastradh 	CLK_MAP(SOCCLK, CLOCK_SOCCLK),
1211571a7a1Sriastradh 	CLK_MAP(UCLK, CLOCK_UMCCLK),
1221571a7a1Sriastradh 	CLK_MAP(MCLK, CLOCK_UMCCLK),
1231571a7a1Sriastradh };
1241571a7a1Sriastradh 
1251571a7a1Sriastradh static struct smu_12_0_cmn2aisc_mapping renoir_table_map[SMU_TABLE_COUNT] = {
1261571a7a1Sriastradh 	TAB_MAP_VALID(WATERMARKS),
1271571a7a1Sriastradh 	TAB_MAP_INVALID(CUSTOM_DPM),
1281571a7a1Sriastradh 	TAB_MAP_VALID(DPMCLOCKS),
1291571a7a1Sriastradh 	TAB_MAP_VALID(SMU_METRICS),
1301571a7a1Sriastradh };
1311571a7a1Sriastradh 
renoir_get_smu_msg_index(struct smu_context * smc,uint32_t index)1321571a7a1Sriastradh static int renoir_get_smu_msg_index(struct smu_context *smc, uint32_t index)
1331571a7a1Sriastradh {
1341571a7a1Sriastradh 	struct smu_12_0_cmn2aisc_mapping mapping;
1351571a7a1Sriastradh 
1361571a7a1Sriastradh 	if (index >= SMU_MSG_MAX_COUNT)
1371571a7a1Sriastradh 		return -EINVAL;
1381571a7a1Sriastradh 
1391571a7a1Sriastradh 	mapping = renoir_message_map[index];
1401571a7a1Sriastradh 	if (!(mapping.valid_mapping))
1411571a7a1Sriastradh 		return -EINVAL;
1421571a7a1Sriastradh 
1431571a7a1Sriastradh 	return mapping.map_to;
1441571a7a1Sriastradh }
1451571a7a1Sriastradh 
renoir_get_smu_clk_index(struct smu_context * smc,uint32_t index)1461571a7a1Sriastradh static int renoir_get_smu_clk_index(struct smu_context *smc, uint32_t index)
1471571a7a1Sriastradh {
1481571a7a1Sriastradh 	struct smu_12_0_cmn2aisc_mapping mapping;
1491571a7a1Sriastradh 
1501571a7a1Sriastradh 	if (index >= SMU_CLK_COUNT)
1511571a7a1Sriastradh 		return -EINVAL;
1521571a7a1Sriastradh 
1531571a7a1Sriastradh 	mapping = renoir_clk_map[index];
1541571a7a1Sriastradh 	if (!(mapping.valid_mapping)) {
1551571a7a1Sriastradh 		return -EINVAL;
1561571a7a1Sriastradh 	}
1571571a7a1Sriastradh 
1581571a7a1Sriastradh 	return mapping.map_to;
1591571a7a1Sriastradh }
1601571a7a1Sriastradh 
renoir_get_smu_table_index(struct smu_context * smc,uint32_t index)1611571a7a1Sriastradh static int renoir_get_smu_table_index(struct smu_context *smc, uint32_t index)
1621571a7a1Sriastradh {
1631571a7a1Sriastradh 	struct smu_12_0_cmn2aisc_mapping mapping;
1641571a7a1Sriastradh 
1651571a7a1Sriastradh 	if (index >= SMU_TABLE_COUNT)
1661571a7a1Sriastradh 		return -EINVAL;
1671571a7a1Sriastradh 
1681571a7a1Sriastradh 	mapping = renoir_table_map[index];
1691571a7a1Sriastradh 	if (!(mapping.valid_mapping))
1701571a7a1Sriastradh 		return -EINVAL;
1711571a7a1Sriastradh 
1721571a7a1Sriastradh 	return mapping.map_to;
1731571a7a1Sriastradh }
1741571a7a1Sriastradh 
renoir_get_metrics_table(struct smu_context * smu,SmuMetrics_t * metrics_table)1751571a7a1Sriastradh static int renoir_get_metrics_table(struct smu_context *smu,
1761571a7a1Sriastradh 				    SmuMetrics_t *metrics_table)
1771571a7a1Sriastradh {
1781571a7a1Sriastradh 	struct smu_table_context *smu_table= &smu->smu_table;
1791571a7a1Sriastradh 	int ret = 0;
1801571a7a1Sriastradh 
1811571a7a1Sriastradh 	mutex_lock(&smu->metrics_lock);
1821571a7a1Sriastradh 	if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(100))) {
1831571a7a1Sriastradh 		ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0,
1841571a7a1Sriastradh 				(void *)smu_table->metrics_table, false);
1851571a7a1Sriastradh 		if (ret) {
1861571a7a1Sriastradh 			pr_info("Failed to export SMU metrics table!\n");
1871571a7a1Sriastradh 			mutex_unlock(&smu->metrics_lock);
1881571a7a1Sriastradh 			return ret;
1891571a7a1Sriastradh 		}
1901571a7a1Sriastradh 		smu_table->metrics_time = jiffies;
1911571a7a1Sriastradh 	}
1921571a7a1Sriastradh 
1931571a7a1Sriastradh 	memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t));
1941571a7a1Sriastradh 	mutex_unlock(&smu->metrics_lock);
1951571a7a1Sriastradh 
1961571a7a1Sriastradh 	return ret;
1971571a7a1Sriastradh }
1981571a7a1Sriastradh 
renoir_tables_init(struct smu_context * smu,struct smu_table * tables)1991571a7a1Sriastradh static int renoir_tables_init(struct smu_context *smu, struct smu_table *tables)
2001571a7a1Sriastradh {
2011571a7a1Sriastradh 	struct smu_table_context *smu_table = &smu->smu_table;
2021571a7a1Sriastradh 
2031571a7a1Sriastradh 	SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
2041571a7a1Sriastradh 		PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
2051571a7a1Sriastradh 	SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
2061571a7a1Sriastradh 		PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
2071571a7a1Sriastradh 	SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
2081571a7a1Sriastradh 		PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
2091571a7a1Sriastradh 
2101571a7a1Sriastradh 	smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
2111571a7a1Sriastradh 	if (!smu_table->clocks_table)
2121571a7a1Sriastradh 		return -ENOMEM;
2131571a7a1Sriastradh 
2141571a7a1Sriastradh 	smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
2151571a7a1Sriastradh 	if (!smu_table->metrics_table)
2161571a7a1Sriastradh 		return -ENOMEM;
2171571a7a1Sriastradh 	smu_table->metrics_time = 0;
2181571a7a1Sriastradh 
2191571a7a1Sriastradh 	smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
2201571a7a1Sriastradh 	if (!smu_table->watermarks_table)
2211571a7a1Sriastradh 		return -ENOMEM;
2221571a7a1Sriastradh 
2231571a7a1Sriastradh 	return 0;
2241571a7a1Sriastradh }
2251571a7a1Sriastradh 
2261571a7a1Sriastradh /**
2271571a7a1Sriastradh  * This interface just for getting uclk ultimate freq and should't introduce
2281571a7a1Sriastradh  * other likewise function result in overmuch callback.
2291571a7a1Sriastradh  */
renoir_get_dpm_clk_limited(struct smu_context * smu,enum smu_clk_type clk_type,uint32_t dpm_level,uint32_t * freq)2301571a7a1Sriastradh static int renoir_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type clk_type,
2311571a7a1Sriastradh 						uint32_t dpm_level, uint32_t *freq)
2321571a7a1Sriastradh {
2331571a7a1Sriastradh 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
2341571a7a1Sriastradh 
2351571a7a1Sriastradh 	if (!clk_table || clk_type >= SMU_CLK_COUNT)
2361571a7a1Sriastradh 		return -EINVAL;
2371571a7a1Sriastradh 
2381571a7a1Sriastradh 	GET_DPM_CUR_FREQ(clk_table, clk_type, dpm_level, *freq);
2391571a7a1Sriastradh 
2401571a7a1Sriastradh 	return 0;
2411571a7a1Sriastradh }
2421571a7a1Sriastradh 
renoir_print_clk_levels(struct smu_context * smu,enum smu_clk_type clk_type,char * buf)2431571a7a1Sriastradh static int renoir_print_clk_levels(struct smu_context *smu,
2441571a7a1Sriastradh 			enum smu_clk_type clk_type, char *buf)
2451571a7a1Sriastradh {
2461571a7a1Sriastradh 	int i, size = 0, ret = 0;
2471571a7a1Sriastradh 	uint32_t cur_value = 0, value = 0, count = 0, min = 0, max = 0;
2481571a7a1Sriastradh 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
2491571a7a1Sriastradh 	SmuMetrics_t metrics;
2501571a7a1Sriastradh 
2511571a7a1Sriastradh 	if (!clk_table || clk_type >= SMU_CLK_COUNT)
2521571a7a1Sriastradh 		return -EINVAL;
2531571a7a1Sriastradh 
2541571a7a1Sriastradh 	memset(&metrics, 0, sizeof(metrics));
2551571a7a1Sriastradh 
2561571a7a1Sriastradh 	ret = renoir_get_metrics_table(smu, &metrics);
2571571a7a1Sriastradh 	if (ret)
2581571a7a1Sriastradh 		return ret;
2591571a7a1Sriastradh 
2601571a7a1Sriastradh 	switch (clk_type) {
2611571a7a1Sriastradh 	case SMU_GFXCLK:
2621571a7a1Sriastradh 	case SMU_SCLK:
2631571a7a1Sriastradh 		/* retirve table returned paramters unit is MHz */
2641571a7a1Sriastradh 		cur_value = metrics.ClockFrequency[CLOCK_GFXCLK];
2651571a7a1Sriastradh 		ret = smu_get_dpm_freq_range(smu, SMU_GFXCLK, &min, &max, false);
2661571a7a1Sriastradh 		if (!ret) {
2671571a7a1Sriastradh 			/* driver only know min/max gfx_clk, Add level 1 for all other gfx clks */
2681571a7a1Sriastradh 			if (cur_value  == max)
2691571a7a1Sriastradh 				i = 2;
2701571a7a1Sriastradh 			else if (cur_value == min)
2711571a7a1Sriastradh 				i = 0;
2721571a7a1Sriastradh 			else
2731571a7a1Sriastradh 				i = 1;
2741571a7a1Sriastradh 
275*8267edfdSriastradh 			size += sprintf(buf + size, "0: %uMhz %s\n", min,
2761571a7a1Sriastradh 					i == 0 ? "*" : "");
277*8267edfdSriastradh 			size += sprintf(buf + size, "1: %uMhz %s\n",
2781571a7a1Sriastradh 					i == 1 ? cur_value : RENOIR_UMD_PSTATE_GFXCLK,
2791571a7a1Sriastradh 					i == 1 ? "*" : "");
280*8267edfdSriastradh 			size += sprintf(buf + size, "2: %uMhz %s\n", max,
2811571a7a1Sriastradh 					i == 2 ? "*" : "");
2821571a7a1Sriastradh 		}
2831571a7a1Sriastradh 		return size;
2841571a7a1Sriastradh 	case SMU_SOCCLK:
2851571a7a1Sriastradh 		count = NUM_SOCCLK_DPM_LEVELS;
2861571a7a1Sriastradh 		cur_value = metrics.ClockFrequency[CLOCK_SOCCLK];
2871571a7a1Sriastradh 		break;
2881571a7a1Sriastradh 	case SMU_MCLK:
2891571a7a1Sriastradh 		count = NUM_MEMCLK_DPM_LEVELS;
2901571a7a1Sriastradh 		cur_value = metrics.ClockFrequency[CLOCK_UMCCLK];
2911571a7a1Sriastradh 		break;
2921571a7a1Sriastradh 	case SMU_DCEFCLK:
2931571a7a1Sriastradh 		count = NUM_DCFCLK_DPM_LEVELS;
2941571a7a1Sriastradh 		cur_value = metrics.ClockFrequency[CLOCK_DCFCLK];
2951571a7a1Sriastradh 		break;
2961571a7a1Sriastradh 	case SMU_FCLK:
2971571a7a1Sriastradh 		count = NUM_FCLK_DPM_LEVELS;
2981571a7a1Sriastradh 		cur_value = metrics.ClockFrequency[CLOCK_FCLK];
2991571a7a1Sriastradh 		break;
3001571a7a1Sriastradh 	default:
3011571a7a1Sriastradh 		return -EINVAL;
3021571a7a1Sriastradh 	}
3031571a7a1Sriastradh 
3041571a7a1Sriastradh 	for (i = 0; i < count; i++) {
3051571a7a1Sriastradh 		GET_DPM_CUR_FREQ(clk_table, clk_type, i, value);
306*8267edfdSriastradh 		size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
3071571a7a1Sriastradh 				cur_value == value ? "*" : "");
3081571a7a1Sriastradh 	}
3091571a7a1Sriastradh 
3101571a7a1Sriastradh 	return size;
3111571a7a1Sriastradh }
3121571a7a1Sriastradh 
renoir_get_current_power_state(struct smu_context * smu)3131571a7a1Sriastradh static enum amd_pm_state_type renoir_get_current_power_state(struct smu_context *smu)
3141571a7a1Sriastradh {
3151571a7a1Sriastradh 	enum amd_pm_state_type pm_type;
3161571a7a1Sriastradh 	struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
3171571a7a1Sriastradh 
3181571a7a1Sriastradh 	if (!smu_dpm_ctx->dpm_context ||
3191571a7a1Sriastradh 	    !smu_dpm_ctx->dpm_current_power_state)
3201571a7a1Sriastradh 		return -EINVAL;
3211571a7a1Sriastradh 
3221571a7a1Sriastradh 	switch (smu_dpm_ctx->dpm_current_power_state->classification.ui_label) {
3231571a7a1Sriastradh 	case SMU_STATE_UI_LABEL_BATTERY:
3241571a7a1Sriastradh 		pm_type = POWER_STATE_TYPE_BATTERY;
3251571a7a1Sriastradh 		break;
3261571a7a1Sriastradh 	case SMU_STATE_UI_LABEL_BALLANCED:
3271571a7a1Sriastradh 		pm_type = POWER_STATE_TYPE_BALANCED;
3281571a7a1Sriastradh 		break;
3291571a7a1Sriastradh 	case SMU_STATE_UI_LABEL_PERFORMANCE:
3301571a7a1Sriastradh 		pm_type = POWER_STATE_TYPE_PERFORMANCE;
3311571a7a1Sriastradh 		break;
3321571a7a1Sriastradh 	default:
3331571a7a1Sriastradh 		if (smu_dpm_ctx->dpm_current_power_state->classification.flags & SMU_STATE_CLASSIFICATION_FLAG_BOOT)
3341571a7a1Sriastradh 			pm_type = POWER_STATE_TYPE_INTERNAL_BOOT;
3351571a7a1Sriastradh 		else
3361571a7a1Sriastradh 			pm_type = POWER_STATE_TYPE_DEFAULT;
3371571a7a1Sriastradh 		break;
3381571a7a1Sriastradh 	}
3391571a7a1Sriastradh 
3401571a7a1Sriastradh 	return pm_type;
3411571a7a1Sriastradh }
3421571a7a1Sriastradh 
renoir_dpm_set_uvd_enable(struct smu_context * smu,bool enable)3431571a7a1Sriastradh static int renoir_dpm_set_uvd_enable(struct smu_context *smu, bool enable)
3441571a7a1Sriastradh {
3451571a7a1Sriastradh 	struct smu_power_context *smu_power = &smu->smu_power;
3461571a7a1Sriastradh 	struct smu_power_gate *power_gate = &smu_power->power_gate;
3471571a7a1Sriastradh 	int ret = 0;
3481571a7a1Sriastradh 
3491571a7a1Sriastradh 	if (enable) {
3501571a7a1Sriastradh 		/* vcn dpm on is a prerequisite for vcn power gate messages */
3511571a7a1Sriastradh 		if (smu_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
3521571a7a1Sriastradh 			ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 0);
3531571a7a1Sriastradh 			if (ret)
3541571a7a1Sriastradh 				return ret;
3551571a7a1Sriastradh 		}
3561571a7a1Sriastradh 		power_gate->vcn_gated = false;
3571571a7a1Sriastradh 	} else {
3581571a7a1Sriastradh 		if (smu_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
3591571a7a1Sriastradh 			ret = smu_send_smc_msg(smu, SMU_MSG_PowerDownVcn);
3601571a7a1Sriastradh 			if (ret)
3611571a7a1Sriastradh 				return ret;
3621571a7a1Sriastradh 		}
3631571a7a1Sriastradh 		power_gate->vcn_gated = true;
3641571a7a1Sriastradh 	}
3651571a7a1Sriastradh 
3661571a7a1Sriastradh 	return ret;
3671571a7a1Sriastradh }
3681571a7a1Sriastradh 
renoir_dpm_set_jpeg_enable(struct smu_context * smu,bool enable)3691571a7a1Sriastradh static int renoir_dpm_set_jpeg_enable(struct smu_context *smu, bool enable)
3701571a7a1Sriastradh {
3711571a7a1Sriastradh 	struct smu_power_context *smu_power = &smu->smu_power;
3721571a7a1Sriastradh 	struct smu_power_gate *power_gate = &smu_power->power_gate;
3731571a7a1Sriastradh 	int ret = 0;
3741571a7a1Sriastradh 
3751571a7a1Sriastradh 	if (enable) {
3761571a7a1Sriastradh 		if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) {
3771571a7a1Sriastradh 			ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0);
3781571a7a1Sriastradh 			if (ret)
3791571a7a1Sriastradh 				return ret;
3801571a7a1Sriastradh 		}
3811571a7a1Sriastradh 		power_gate->jpeg_gated = false;
3821571a7a1Sriastradh 	} else {
3831571a7a1Sriastradh 		if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) {
3841571a7a1Sriastradh 			ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0);
3851571a7a1Sriastradh 			if (ret)
3861571a7a1Sriastradh 				return ret;
3871571a7a1Sriastradh 		}
3881571a7a1Sriastradh 		power_gate->jpeg_gated = true;
3891571a7a1Sriastradh 	}
3901571a7a1Sriastradh 
3911571a7a1Sriastradh 	return ret;
3921571a7a1Sriastradh }
3931571a7a1Sriastradh 
renoir_get_current_clk_freq_by_table(struct smu_context * smu,enum smu_clk_type clk_type,uint32_t * value)3941571a7a1Sriastradh static int renoir_get_current_clk_freq_by_table(struct smu_context *smu,
3951571a7a1Sriastradh 				       enum smu_clk_type clk_type,
3961571a7a1Sriastradh 				       uint32_t *value)
3971571a7a1Sriastradh {
3981571a7a1Sriastradh 	int ret = 0, clk_id = 0;
3991571a7a1Sriastradh 	SmuMetrics_t metrics;
4001571a7a1Sriastradh 
4011571a7a1Sriastradh 	ret = renoir_get_metrics_table(smu, &metrics);
4021571a7a1Sriastradh 	if (ret)
4031571a7a1Sriastradh 		return ret;
4041571a7a1Sriastradh 
4051571a7a1Sriastradh 	clk_id = smu_clk_get_index(smu, clk_type);
4061571a7a1Sriastradh 	if (clk_id < 0)
4071571a7a1Sriastradh 		return clk_id;
4081571a7a1Sriastradh 
4091571a7a1Sriastradh 	*value = metrics.ClockFrequency[clk_id];
4101571a7a1Sriastradh 
4111571a7a1Sriastradh 	return ret;
4121571a7a1Sriastradh }
4131571a7a1Sriastradh 
renoir_force_dpm_limit_value(struct smu_context * smu,bool highest)4141571a7a1Sriastradh static int renoir_force_dpm_limit_value(struct smu_context *smu, bool highest)
4151571a7a1Sriastradh {
4161571a7a1Sriastradh 	int ret = 0, i = 0;
4171571a7a1Sriastradh 	uint32_t min_freq, max_freq, force_freq;
4181571a7a1Sriastradh 	enum smu_clk_type clk_type;
4191571a7a1Sriastradh 
4201571a7a1Sriastradh 	enum smu_clk_type clks[] = {
4211571a7a1Sriastradh 		SMU_GFXCLK,
4221571a7a1Sriastradh 		SMU_MCLK,
4231571a7a1Sriastradh 		SMU_SOCCLK,
4241571a7a1Sriastradh 	};
4251571a7a1Sriastradh 
4261571a7a1Sriastradh 	for (i = 0; i < ARRAY_SIZE(clks); i++) {
4271571a7a1Sriastradh 		clk_type = clks[i];
4281571a7a1Sriastradh 		ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq, false);
4291571a7a1Sriastradh 		if (ret)
4301571a7a1Sriastradh 			return ret;
4311571a7a1Sriastradh 
4321571a7a1Sriastradh 		force_freq = highest ? max_freq : min_freq;
4331571a7a1Sriastradh 		ret = smu_set_soft_freq_range(smu, clk_type, force_freq, force_freq);
4341571a7a1Sriastradh 		if (ret)
4351571a7a1Sriastradh 			return ret;
4361571a7a1Sriastradh 	}
4371571a7a1Sriastradh 
4381571a7a1Sriastradh 	return ret;
4391571a7a1Sriastradh }
4401571a7a1Sriastradh 
renoir_unforce_dpm_levels(struct smu_context * smu)4411571a7a1Sriastradh static int renoir_unforce_dpm_levels(struct smu_context *smu) {
4421571a7a1Sriastradh 
4431571a7a1Sriastradh 	int ret = 0, i = 0;
4441571a7a1Sriastradh 	uint32_t min_freq, max_freq;
4451571a7a1Sriastradh 	enum smu_clk_type clk_type;
4461571a7a1Sriastradh 
4471571a7a1Sriastradh 	struct clk_feature_map {
4481571a7a1Sriastradh 		enum smu_clk_type clk_type;
4491571a7a1Sriastradh 		uint32_t	feature;
4501571a7a1Sriastradh 	} clk_feature_map[] = {
4511571a7a1Sriastradh 		{SMU_GFXCLK, SMU_FEATURE_DPM_GFXCLK_BIT},
4521571a7a1Sriastradh 		{SMU_MCLK,   SMU_FEATURE_DPM_UCLK_BIT},
4531571a7a1Sriastradh 		{SMU_SOCCLK, SMU_FEATURE_DPM_SOCCLK_BIT},
4541571a7a1Sriastradh 	};
4551571a7a1Sriastradh 
4561571a7a1Sriastradh 	for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) {
4571571a7a1Sriastradh 		if (!smu_feature_is_enabled(smu, clk_feature_map[i].feature))
4581571a7a1Sriastradh 		    continue;
4591571a7a1Sriastradh 
4601571a7a1Sriastradh 		clk_type = clk_feature_map[i].clk_type;
4611571a7a1Sriastradh 
4621571a7a1Sriastradh 		ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq, false);
4631571a7a1Sriastradh 		if (ret)
4641571a7a1Sriastradh 			return ret;
4651571a7a1Sriastradh 
4661571a7a1Sriastradh 		ret = smu_set_soft_freq_range(smu, clk_type, min_freq, max_freq);
4671571a7a1Sriastradh 		if (ret)
4681571a7a1Sriastradh 			return ret;
4691571a7a1Sriastradh 	}
4701571a7a1Sriastradh 
4711571a7a1Sriastradh 	return ret;
4721571a7a1Sriastradh }
4731571a7a1Sriastradh 
renoir_get_gpu_temperature(struct smu_context * smu,uint32_t * value)4741571a7a1Sriastradh static int renoir_get_gpu_temperature(struct smu_context *smu, uint32_t *value)
4751571a7a1Sriastradh {
4761571a7a1Sriastradh 	int ret = 0;
4771571a7a1Sriastradh 	SmuMetrics_t metrics;
4781571a7a1Sriastradh 
4791571a7a1Sriastradh 	if (!value)
4801571a7a1Sriastradh 		return -EINVAL;
4811571a7a1Sriastradh 
4821571a7a1Sriastradh 	ret = renoir_get_metrics_table(smu, &metrics);
4831571a7a1Sriastradh 	if (ret)
4841571a7a1Sriastradh 		return ret;
4851571a7a1Sriastradh 
4861571a7a1Sriastradh 	*value = (metrics.GfxTemperature / 100) *
4871571a7a1Sriastradh 		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
4881571a7a1Sriastradh 
4891571a7a1Sriastradh 	return 0;
4901571a7a1Sriastradh }
4911571a7a1Sriastradh 
renoir_get_current_activity_percent(struct smu_context * smu,enum amd_pp_sensors sensor,uint32_t * value)4921571a7a1Sriastradh static int renoir_get_current_activity_percent(struct smu_context *smu,
4931571a7a1Sriastradh 					       enum amd_pp_sensors sensor,
4941571a7a1Sriastradh 					       uint32_t *value)
4951571a7a1Sriastradh {
4961571a7a1Sriastradh 	int ret = 0;
4971571a7a1Sriastradh 	SmuMetrics_t metrics;
4981571a7a1Sriastradh 
4991571a7a1Sriastradh 	if (!value)
5001571a7a1Sriastradh 		return -EINVAL;
5011571a7a1Sriastradh 
5021571a7a1Sriastradh 	ret = renoir_get_metrics_table(smu, &metrics);
5031571a7a1Sriastradh 	if (ret)
5041571a7a1Sriastradh 		return ret;
5051571a7a1Sriastradh 
5061571a7a1Sriastradh 	switch (sensor) {
5071571a7a1Sriastradh 	case AMDGPU_PP_SENSOR_GPU_LOAD:
5081571a7a1Sriastradh 		*value = metrics.AverageGfxActivity / 100;
5091571a7a1Sriastradh 		break;
5101571a7a1Sriastradh 	default:
5111571a7a1Sriastradh 		pr_err("Invalid sensor for retrieving clock activity\n");
5121571a7a1Sriastradh 		return -EINVAL;
5131571a7a1Sriastradh 	}
5141571a7a1Sriastradh 
5151571a7a1Sriastradh 	return 0;
5161571a7a1Sriastradh }
5171571a7a1Sriastradh 
renoir_get_workload_type(struct smu_context * smu,uint32_t profile)5181571a7a1Sriastradh static int renoir_get_workload_type(struct smu_context *smu, uint32_t profile)
5191571a7a1Sriastradh {
5201571a7a1Sriastradh 
5211571a7a1Sriastradh 	uint32_t  pplib_workload = 0;
5221571a7a1Sriastradh 
5231571a7a1Sriastradh 	switch (profile) {
5241571a7a1Sriastradh 	case PP_SMC_POWER_PROFILE_FULLSCREEN3D:
5251571a7a1Sriastradh 		pplib_workload = WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT;
5261571a7a1Sriastradh 		break;
5271571a7a1Sriastradh 	case PP_SMC_POWER_PROFILE_CUSTOM:
5281571a7a1Sriastradh 		pplib_workload = WORKLOAD_PPLIB_COUNT;
5291571a7a1Sriastradh 		break;
5301571a7a1Sriastradh 	case PP_SMC_POWER_PROFILE_VIDEO:
5311571a7a1Sriastradh 		pplib_workload = WORKLOAD_PPLIB_VIDEO_BIT;
5321571a7a1Sriastradh 		break;
5331571a7a1Sriastradh 	case PP_SMC_POWER_PROFILE_VR:
5341571a7a1Sriastradh 		pplib_workload = WORKLOAD_PPLIB_VR_BIT;
5351571a7a1Sriastradh 		break;
5361571a7a1Sriastradh 	case PP_SMC_POWER_PROFILE_COMPUTE:
5371571a7a1Sriastradh 		pplib_workload = WORKLOAD_PPLIB_COMPUTE_BIT;
5381571a7a1Sriastradh 		break;
5391571a7a1Sriastradh 	default:
5401571a7a1Sriastradh 		return -EINVAL;
5411571a7a1Sriastradh 	}
5421571a7a1Sriastradh 
5431571a7a1Sriastradh 	return pplib_workload;
5441571a7a1Sriastradh }
5451571a7a1Sriastradh 
renoir_get_profiling_clk_mask(struct smu_context * smu,enum amd_dpm_forced_level level,uint32_t * sclk_mask,uint32_t * mclk_mask,uint32_t * soc_mask)5461571a7a1Sriastradh static int renoir_get_profiling_clk_mask(struct smu_context *smu,
5471571a7a1Sriastradh 					 enum amd_dpm_forced_level level,
5481571a7a1Sriastradh 					 uint32_t *sclk_mask,
5491571a7a1Sriastradh 					 uint32_t *mclk_mask,
5501571a7a1Sriastradh 					 uint32_t *soc_mask)
5511571a7a1Sriastradh {
5521571a7a1Sriastradh 
5531571a7a1Sriastradh 	if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
5541571a7a1Sriastradh 		if (sclk_mask)
5551571a7a1Sriastradh 			*sclk_mask = 0;
5561571a7a1Sriastradh 	} else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
5571571a7a1Sriastradh 		if (mclk_mask)
5581571a7a1Sriastradh 			*mclk_mask = 0;
5591571a7a1Sriastradh 	} else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
5601571a7a1Sriastradh 		if(sclk_mask)
5611571a7a1Sriastradh 			/* The sclk as gfxclk and has three level about max/min/current */
5621571a7a1Sriastradh 			*sclk_mask = 3 - 1;
5631571a7a1Sriastradh 
5641571a7a1Sriastradh 		if(mclk_mask)
5651571a7a1Sriastradh 			*mclk_mask = NUM_MEMCLK_DPM_LEVELS - 1;
5661571a7a1Sriastradh 
5671571a7a1Sriastradh 		if(soc_mask)
5681571a7a1Sriastradh 			*soc_mask = NUM_SOCCLK_DPM_LEVELS - 1;
5691571a7a1Sriastradh 	}
5701571a7a1Sriastradh 
5711571a7a1Sriastradh 	return 0;
5721571a7a1Sriastradh }
5731571a7a1Sriastradh 
5741571a7a1Sriastradh /**
5751571a7a1Sriastradh  * This interface get dpm clock table for dc
5761571a7a1Sriastradh  */
renoir_get_dpm_clock_table(struct smu_context * smu,struct dpm_clocks * clock_table)5771571a7a1Sriastradh static int renoir_get_dpm_clock_table(struct smu_context *smu, struct dpm_clocks *clock_table)
5781571a7a1Sriastradh {
5791571a7a1Sriastradh 	DpmClocks_t *table = smu->smu_table.clocks_table;
5801571a7a1Sriastradh 	int i;
5811571a7a1Sriastradh 
5821571a7a1Sriastradh 	if (!clock_table || !table)
5831571a7a1Sriastradh 		return -EINVAL;
5841571a7a1Sriastradh 
5851571a7a1Sriastradh 	for (i = 0; i < NUM_DCFCLK_DPM_LEVELS; i++) {
5861571a7a1Sriastradh 		clock_table->DcfClocks[i].Freq = table->DcfClocks[i].Freq;
5871571a7a1Sriastradh 		clock_table->DcfClocks[i].Vol = table->DcfClocks[i].Vol;
5881571a7a1Sriastradh 	}
5891571a7a1Sriastradh 
5901571a7a1Sriastradh 	for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) {
5911571a7a1Sriastradh 		clock_table->SocClocks[i].Freq = table->SocClocks[i].Freq;
5921571a7a1Sriastradh 		clock_table->SocClocks[i].Vol = table->SocClocks[i].Vol;
5931571a7a1Sriastradh 	}
5941571a7a1Sriastradh 
5951571a7a1Sriastradh 	for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
5961571a7a1Sriastradh 		clock_table->FClocks[i].Freq = table->FClocks[i].Freq;
5971571a7a1Sriastradh 		clock_table->FClocks[i].Vol = table->FClocks[i].Vol;
5981571a7a1Sriastradh 	}
5991571a7a1Sriastradh 
6001571a7a1Sriastradh 	for (i = 0; i<  NUM_MEMCLK_DPM_LEVELS; i++) {
6011571a7a1Sriastradh 		clock_table->MemClocks[i].Freq = table->MemClocks[i].Freq;
6021571a7a1Sriastradh 		clock_table->MemClocks[i].Vol = table->MemClocks[i].Vol;
6031571a7a1Sriastradh 	}
6041571a7a1Sriastradh 
6051571a7a1Sriastradh 	return 0;
6061571a7a1Sriastradh }
6071571a7a1Sriastradh 
renoir_force_clk_levels(struct smu_context * smu,enum smu_clk_type clk_type,uint32_t mask)6081571a7a1Sriastradh static int renoir_force_clk_levels(struct smu_context *smu,
6091571a7a1Sriastradh 				   enum smu_clk_type clk_type, uint32_t mask)
6101571a7a1Sriastradh {
6111571a7a1Sriastradh 
6121571a7a1Sriastradh 	int ret = 0 ;
6131571a7a1Sriastradh 	uint32_t soft_min_level = 0, soft_max_level = 0, min_freq = 0, max_freq = 0;
6141571a7a1Sriastradh 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
6151571a7a1Sriastradh 
6161571a7a1Sriastradh 	soft_min_level = mask ? (ffs(mask) - 1) : 0;
6171571a7a1Sriastradh 	soft_max_level = mask ? (fls(mask) - 1) : 0;
6181571a7a1Sriastradh 
6191571a7a1Sriastradh 	switch (clk_type) {
6201571a7a1Sriastradh 	case SMU_GFXCLK:
6211571a7a1Sriastradh 	case SMU_SCLK:
6221571a7a1Sriastradh 		if (soft_min_level > 2 || soft_max_level > 2) {
6231571a7a1Sriastradh 			pr_info("Currently sclk only support 3 levels on APU\n");
6241571a7a1Sriastradh 			return -EINVAL;
6251571a7a1Sriastradh 		}
6261571a7a1Sriastradh 
6271571a7a1Sriastradh 		ret = smu_get_dpm_freq_range(smu, SMU_GFXCLK, &min_freq, &max_freq, false);
6281571a7a1Sriastradh 		if (ret)
6291571a7a1Sriastradh 			return ret;
6301571a7a1Sriastradh 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
6311571a7a1Sriastradh 					soft_max_level == 0 ? min_freq :
6321571a7a1Sriastradh 					soft_max_level == 1 ? RENOIR_UMD_PSTATE_GFXCLK : max_freq);
6331571a7a1Sriastradh 		if (ret)
6341571a7a1Sriastradh 			return ret;
6351571a7a1Sriastradh 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
6361571a7a1Sriastradh 					soft_min_level == 2 ? max_freq :
6371571a7a1Sriastradh 					soft_min_level == 1 ? RENOIR_UMD_PSTATE_GFXCLK : min_freq);
6381571a7a1Sriastradh 		if (ret)
6391571a7a1Sriastradh 			return ret;
6401571a7a1Sriastradh 		break;
6411571a7a1Sriastradh 	case SMU_SOCCLK:
6421571a7a1Sriastradh 		GET_DPM_CUR_FREQ(clk_table, clk_type, soft_min_level, min_freq);
6431571a7a1Sriastradh 		GET_DPM_CUR_FREQ(clk_table, clk_type, soft_max_level, max_freq);
6441571a7a1Sriastradh 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxSocclkByFreq, max_freq);
6451571a7a1Sriastradh 		if (ret)
6461571a7a1Sriastradh 			return ret;
6471571a7a1Sriastradh 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinSocclkByFreq, min_freq);
6481571a7a1Sriastradh 		if (ret)
6491571a7a1Sriastradh 			return ret;
6501571a7a1Sriastradh 		break;
6511571a7a1Sriastradh 	case SMU_MCLK:
6521571a7a1Sriastradh 	case SMU_FCLK:
6531571a7a1Sriastradh 		GET_DPM_CUR_FREQ(clk_table, clk_type, soft_min_level, min_freq);
6541571a7a1Sriastradh 		GET_DPM_CUR_FREQ(clk_table, clk_type, soft_max_level, max_freq);
6551571a7a1Sriastradh 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxFclkByFreq, max_freq);
6561571a7a1Sriastradh 		if (ret)
6571571a7a1Sriastradh 			return ret;
6581571a7a1Sriastradh 		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min_freq);
6591571a7a1Sriastradh 		if (ret)
6601571a7a1Sriastradh 			return ret;
6611571a7a1Sriastradh 		break;
6621571a7a1Sriastradh 	default:
6631571a7a1Sriastradh 		break;
6641571a7a1Sriastradh 	}
6651571a7a1Sriastradh 
6661571a7a1Sriastradh 	return ret;
6671571a7a1Sriastradh }
6681571a7a1Sriastradh 
renoir_set_power_profile_mode(struct smu_context * smu,long * input,uint32_t size)6691571a7a1Sriastradh static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
6701571a7a1Sriastradh {
6711571a7a1Sriastradh 	int workload_type, ret;
6721571a7a1Sriastradh 	uint32_t profile_mode = input[size];
6731571a7a1Sriastradh 
6741571a7a1Sriastradh 	if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
6751571a7a1Sriastradh 		pr_err("Invalid power profile mode %d\n", smu->power_profile_mode);
6761571a7a1Sriastradh 		return -EINVAL;
6771571a7a1Sriastradh 	}
6781571a7a1Sriastradh 
6791571a7a1Sriastradh 	/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
6801571a7a1Sriastradh 	workload_type = smu_workload_get_type(smu, smu->power_profile_mode);
6811571a7a1Sriastradh 	if (workload_type < 0) {
6821571a7a1Sriastradh 		pr_err("Unsupported power profile mode %d on RENOIR\n",smu->power_profile_mode);
6831571a7a1Sriastradh 		return -EINVAL;
6841571a7a1Sriastradh 	}
6851571a7a1Sriastradh 
6861571a7a1Sriastradh 	ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
6871571a7a1Sriastradh 				    1 << workload_type);
6881571a7a1Sriastradh 	if (ret) {
6891571a7a1Sriastradh 		pr_err("Fail to set workload type %d\n", workload_type);
6901571a7a1Sriastradh 		return ret;
6911571a7a1Sriastradh 	}
6921571a7a1Sriastradh 
6931571a7a1Sriastradh 	smu->power_profile_mode = profile_mode;
6941571a7a1Sriastradh 
6951571a7a1Sriastradh 	return 0;
6961571a7a1Sriastradh }
6971571a7a1Sriastradh 
renoir_set_peak_clock_by_device(struct smu_context * smu)6981571a7a1Sriastradh static int renoir_set_peak_clock_by_device(struct smu_context *smu)
6991571a7a1Sriastradh {
7001571a7a1Sriastradh 	int ret = 0;
7011571a7a1Sriastradh 	uint32_t sclk_freq = 0, uclk_freq = 0;
7021571a7a1Sriastradh 
7031571a7a1Sriastradh 	ret = smu_get_dpm_freq_range(smu, SMU_SCLK, NULL, &sclk_freq, false);
7041571a7a1Sriastradh 	if (ret)
7051571a7a1Sriastradh 		return ret;
7061571a7a1Sriastradh 
7071571a7a1Sriastradh 	ret = smu_set_soft_freq_range(smu, SMU_SCLK, sclk_freq, sclk_freq);
7081571a7a1Sriastradh 	if (ret)
7091571a7a1Sriastradh 		return ret;
7101571a7a1Sriastradh 
7111571a7a1Sriastradh 	ret = smu_get_dpm_freq_range(smu, SMU_UCLK, NULL, &uclk_freq, false);
7121571a7a1Sriastradh 	if (ret)
7131571a7a1Sriastradh 		return ret;
7141571a7a1Sriastradh 
7151571a7a1Sriastradh 	ret = smu_set_soft_freq_range(smu, SMU_UCLK, uclk_freq, uclk_freq);
7161571a7a1Sriastradh 	if (ret)
7171571a7a1Sriastradh 		return ret;
7181571a7a1Sriastradh 
7191571a7a1Sriastradh 	return ret;
7201571a7a1Sriastradh }
7211571a7a1Sriastradh 
renoir_set_performance_level(struct smu_context * smu,enum amd_dpm_forced_level level)7221571a7a1Sriastradh static int renoir_set_performance_level(struct smu_context *smu,
7231571a7a1Sriastradh 					enum amd_dpm_forced_level level)
7241571a7a1Sriastradh {
7251571a7a1Sriastradh 	int ret = 0;
7261571a7a1Sriastradh 	uint32_t sclk_mask, mclk_mask, soc_mask;
7271571a7a1Sriastradh 
7281571a7a1Sriastradh 	switch (level) {
7291571a7a1Sriastradh 	case AMD_DPM_FORCED_LEVEL_HIGH:
7301571a7a1Sriastradh 		ret = smu_force_dpm_limit_value(smu, true);
7311571a7a1Sriastradh 		break;
7321571a7a1Sriastradh 	case AMD_DPM_FORCED_LEVEL_LOW:
7331571a7a1Sriastradh 		ret = smu_force_dpm_limit_value(smu, false);
7341571a7a1Sriastradh 		break;
7351571a7a1Sriastradh 	case AMD_DPM_FORCED_LEVEL_AUTO:
7361571a7a1Sriastradh 	case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
7371571a7a1Sriastradh 		ret = smu_unforce_dpm_levels(smu);
7381571a7a1Sriastradh 		break;
7391571a7a1Sriastradh 	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
7401571a7a1Sriastradh 	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
7411571a7a1Sriastradh 		ret = smu_get_profiling_clk_mask(smu, level,
7421571a7a1Sriastradh 						 &sclk_mask,
7431571a7a1Sriastradh 						 &mclk_mask,
7441571a7a1Sriastradh 						 &soc_mask);
7451571a7a1Sriastradh 		if (ret)
7461571a7a1Sriastradh 			return ret;
7471571a7a1Sriastradh 		smu_force_clk_levels(smu, SMU_SCLK, 1 << sclk_mask, false);
7481571a7a1Sriastradh 		smu_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask, false);
7491571a7a1Sriastradh 		smu_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask, false);
7501571a7a1Sriastradh 		break;
7511571a7a1Sriastradh 	case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
7521571a7a1Sriastradh 		ret = renoir_set_peak_clock_by_device(smu);
7531571a7a1Sriastradh 		break;
7541571a7a1Sriastradh 	case AMD_DPM_FORCED_LEVEL_MANUAL:
7551571a7a1Sriastradh 	case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
7561571a7a1Sriastradh 	default:
7571571a7a1Sriastradh 		break;
7581571a7a1Sriastradh 	}
7591571a7a1Sriastradh 	return ret;
7601571a7a1Sriastradh }
7611571a7a1Sriastradh 
7621571a7a1Sriastradh /* save watermark settings into pplib smu structure,
7631571a7a1Sriastradh  * also pass data to smu controller
7641571a7a1Sriastradh  */
renoir_set_watermarks_table(struct smu_context * smu,void * watermarks,struct dm_pp_wm_sets_with_clock_ranges_soc15 * clock_ranges)7651571a7a1Sriastradh static int renoir_set_watermarks_table(
7661571a7a1Sriastradh 		struct smu_context *smu,
7671571a7a1Sriastradh 		void *watermarks,
7681571a7a1Sriastradh 		struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges)
7691571a7a1Sriastradh {
7701571a7a1Sriastradh 	int i;
7711571a7a1Sriastradh 	int ret = 0;
7721571a7a1Sriastradh 	Watermarks_t *table = watermarks;
7731571a7a1Sriastradh 
7741571a7a1Sriastradh 	if (!table || !clock_ranges)
7751571a7a1Sriastradh 		return -EINVAL;
7761571a7a1Sriastradh 
7771571a7a1Sriastradh 	if (clock_ranges->num_wm_dmif_sets > 4 ||
7781571a7a1Sriastradh 			clock_ranges->num_wm_mcif_sets > 4)
7791571a7a1Sriastradh 		return -EINVAL;
7801571a7a1Sriastradh 
7811571a7a1Sriastradh 	/* save into smu->smu_table.tables[SMU_TABLE_WATERMARKS]->cpu_addr*/
7821571a7a1Sriastradh 	for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) {
7831571a7a1Sriastradh 		table->WatermarkRow[WM_DCFCLK][i].MinClock =
7841571a7a1Sriastradh 			cpu_to_le16((uint16_t)
7851571a7a1Sriastradh 			(clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz));
7861571a7a1Sriastradh 		table->WatermarkRow[WM_DCFCLK][i].MaxClock =
7871571a7a1Sriastradh 			cpu_to_le16((uint16_t)
7881571a7a1Sriastradh 			(clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz));
7891571a7a1Sriastradh 		table->WatermarkRow[WM_DCFCLK][i].MinMclk =
7901571a7a1Sriastradh 			cpu_to_le16((uint16_t)
7911571a7a1Sriastradh 			(clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz));
7921571a7a1Sriastradh 		table->WatermarkRow[WM_DCFCLK][i].MaxMclk =
7931571a7a1Sriastradh 			cpu_to_le16((uint16_t)
7941571a7a1Sriastradh 			(clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz));
7951571a7a1Sriastradh 		table->WatermarkRow[WM_DCFCLK][i].WmSetting = (uint8_t)
7961571a7a1Sriastradh 				clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id;
7971571a7a1Sriastradh 	}
7981571a7a1Sriastradh 
7991571a7a1Sriastradh 	for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) {
8001571a7a1Sriastradh 		table->WatermarkRow[WM_SOCCLK][i].MinClock =
8011571a7a1Sriastradh 			cpu_to_le16((uint16_t)
8021571a7a1Sriastradh 			(clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz));
8031571a7a1Sriastradh 		table->WatermarkRow[WM_SOCCLK][i].MaxClock =
8041571a7a1Sriastradh 			cpu_to_le16((uint16_t)
8051571a7a1Sriastradh 			(clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz));
8061571a7a1Sriastradh 		table->WatermarkRow[WM_SOCCLK][i].MinMclk =
8071571a7a1Sriastradh 			cpu_to_le16((uint16_t)
8081571a7a1Sriastradh 			(clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz));
8091571a7a1Sriastradh 		table->WatermarkRow[WM_SOCCLK][i].MaxMclk =
8101571a7a1Sriastradh 			cpu_to_le16((uint16_t)
8111571a7a1Sriastradh 			(clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz));
8121571a7a1Sriastradh 		table->WatermarkRow[WM_SOCCLK][i].WmSetting = (uint8_t)
8131571a7a1Sriastradh 				clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
8141571a7a1Sriastradh 	}
8151571a7a1Sriastradh 
8161571a7a1Sriastradh 	/* pass data to smu controller */
8171571a7a1Sriastradh 	if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
8181571a7a1Sriastradh 			!(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
8191571a7a1Sriastradh 		ret = smu_write_watermarks_table(smu);
8201571a7a1Sriastradh 		if (ret) {
8211571a7a1Sriastradh 			pr_err("Failed to update WMTABLE!");
8221571a7a1Sriastradh 			return ret;
8231571a7a1Sriastradh 		}
8241571a7a1Sriastradh 		smu->watermarks_bitmap |= WATERMARKS_LOADED;
8251571a7a1Sriastradh 	}
8261571a7a1Sriastradh 
8271571a7a1Sriastradh 	return 0;
8281571a7a1Sriastradh }
8291571a7a1Sriastradh 
renoir_get_power_profile_mode(struct smu_context * smu,char * buf)8301571a7a1Sriastradh static int renoir_get_power_profile_mode(struct smu_context *smu,
8311571a7a1Sriastradh 					   char *buf)
8321571a7a1Sriastradh {
8331571a7a1Sriastradh 	static const char *profile_name[] = {
8341571a7a1Sriastradh 					"BOOTUP_DEFAULT",
8351571a7a1Sriastradh 					"3D_FULL_SCREEN",
8361571a7a1Sriastradh 					"POWER_SAVING",
8371571a7a1Sriastradh 					"VIDEO",
8381571a7a1Sriastradh 					"VR",
8391571a7a1Sriastradh 					"COMPUTE",
8401571a7a1Sriastradh 					"CUSTOM"};
8411571a7a1Sriastradh 	uint32_t i, size = 0;
8421571a7a1Sriastradh 	int16_t workload_type = 0;
8431571a7a1Sriastradh 
8441571a7a1Sriastradh 	if (!smu->pm_enabled || !buf)
8451571a7a1Sriastradh 		return -EINVAL;
8461571a7a1Sriastradh 
8471571a7a1Sriastradh 	for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
8481571a7a1Sriastradh 		/*
8491571a7a1Sriastradh 		 * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
8501571a7a1Sriastradh 		 * Not all profile modes are supported on arcturus.
8511571a7a1Sriastradh 		 */
8521571a7a1Sriastradh 		workload_type = smu_workload_get_type(smu, i);
8531571a7a1Sriastradh 		if (workload_type < 0)
8541571a7a1Sriastradh 			continue;
8551571a7a1Sriastradh 
856*8267edfdSriastradh 		size += sprintf(buf + size, "%2d %14s%s\n",
8571571a7a1Sriastradh 			i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");
8581571a7a1Sriastradh 	}
8591571a7a1Sriastradh 
8601571a7a1Sriastradh 	return size;
8611571a7a1Sriastradh }
8621571a7a1Sriastradh 
renoir_read_sensor(struct smu_context * smu,enum amd_pp_sensors sensor,void * data,uint32_t * size)8631571a7a1Sriastradh static int renoir_read_sensor(struct smu_context *smu,
8641571a7a1Sriastradh 				 enum amd_pp_sensors sensor,
8651571a7a1Sriastradh 				 void *data, uint32_t *size)
8661571a7a1Sriastradh {
8671571a7a1Sriastradh 	int ret = 0;
8681571a7a1Sriastradh 
8691571a7a1Sriastradh 	if (!data || !size)
8701571a7a1Sriastradh 		return -EINVAL;
8711571a7a1Sriastradh 
8721571a7a1Sriastradh 	mutex_lock(&smu->sensor_lock);
8731571a7a1Sriastradh 	switch (sensor) {
8741571a7a1Sriastradh 	case AMDGPU_PP_SENSOR_GPU_LOAD:
8751571a7a1Sriastradh 		ret = renoir_get_current_activity_percent(smu, sensor, (uint32_t *)data);
8761571a7a1Sriastradh 		*size = 4;
8771571a7a1Sriastradh 		break;
8781571a7a1Sriastradh 	case AMDGPU_PP_SENSOR_GPU_TEMP:
8791571a7a1Sriastradh 		ret = renoir_get_gpu_temperature(smu, (uint32_t *)data);
8801571a7a1Sriastradh 		*size = 4;
8811571a7a1Sriastradh 		break;
8821571a7a1Sriastradh 	default:
8831571a7a1Sriastradh 		ret = smu_v12_0_read_sensor(smu, sensor, data, size);
8841571a7a1Sriastradh 	}
8851571a7a1Sriastradh 	mutex_unlock(&smu->sensor_lock);
8861571a7a1Sriastradh 
8871571a7a1Sriastradh 	return ret;
8881571a7a1Sriastradh }
8891571a7a1Sriastradh 
8901571a7a1Sriastradh static const struct pptable_funcs renoir_ppt_funcs = {
8911571a7a1Sriastradh 	.get_smu_msg_index = renoir_get_smu_msg_index,
8921571a7a1Sriastradh 	.get_smu_clk_index = renoir_get_smu_clk_index,
8931571a7a1Sriastradh 	.get_smu_table_index = renoir_get_smu_table_index,
8941571a7a1Sriastradh 	.tables_init = renoir_tables_init,
8951571a7a1Sriastradh 	.set_power_state = NULL,
8961571a7a1Sriastradh 	.get_dpm_clk_limited = renoir_get_dpm_clk_limited,
8971571a7a1Sriastradh 	.print_clk_levels = renoir_print_clk_levels,
8981571a7a1Sriastradh 	.get_current_power_state = renoir_get_current_power_state,
8991571a7a1Sriastradh 	.dpm_set_uvd_enable = renoir_dpm_set_uvd_enable,
9001571a7a1Sriastradh 	.dpm_set_jpeg_enable = renoir_dpm_set_jpeg_enable,
9011571a7a1Sriastradh 	.get_current_clk_freq_by_table = renoir_get_current_clk_freq_by_table,
9021571a7a1Sriastradh 	.force_dpm_limit_value = renoir_force_dpm_limit_value,
9031571a7a1Sriastradh 	.unforce_dpm_levels = renoir_unforce_dpm_levels,
9041571a7a1Sriastradh 	.get_workload_type = renoir_get_workload_type,
9051571a7a1Sriastradh 	.get_profiling_clk_mask = renoir_get_profiling_clk_mask,
9061571a7a1Sriastradh 	.force_clk_levels = renoir_force_clk_levels,
9071571a7a1Sriastradh 	.set_power_profile_mode = renoir_set_power_profile_mode,
9081571a7a1Sriastradh 	.set_performance_level = renoir_set_performance_level,
9091571a7a1Sriastradh 	.get_dpm_clock_table = renoir_get_dpm_clock_table,
9101571a7a1Sriastradh 	.set_watermarks_table = renoir_set_watermarks_table,
9111571a7a1Sriastradh 	.get_power_profile_mode = renoir_get_power_profile_mode,
9121571a7a1Sriastradh 	.read_sensor = renoir_read_sensor,
9131571a7a1Sriastradh 	.check_fw_status = smu_v12_0_check_fw_status,
9141571a7a1Sriastradh 	.check_fw_version = smu_v12_0_check_fw_version,
9151571a7a1Sriastradh 	.powergate_sdma = smu_v12_0_powergate_sdma,
9161571a7a1Sriastradh 	.powergate_vcn = smu_v12_0_powergate_vcn,
9171571a7a1Sriastradh 	.powergate_jpeg = smu_v12_0_powergate_jpeg,
9181571a7a1Sriastradh 	.send_smc_msg_with_param = smu_v12_0_send_msg_with_param,
9191571a7a1Sriastradh 	.read_smc_arg = smu_v12_0_read_arg,
9201571a7a1Sriastradh 	.set_gfx_cgpg = smu_v12_0_set_gfx_cgpg,
9211571a7a1Sriastradh 	.gfx_off_control = smu_v12_0_gfx_off_control,
9221571a7a1Sriastradh 	.init_smc_tables = smu_v12_0_init_smc_tables,
9231571a7a1Sriastradh 	.fini_smc_tables = smu_v12_0_fini_smc_tables,
9241571a7a1Sriastradh 	.populate_smc_tables = smu_v12_0_populate_smc_tables,
9251571a7a1Sriastradh 	.get_enabled_mask = smu_v12_0_get_enabled_mask,
9261571a7a1Sriastradh 	.get_current_clk_freq = smu_v12_0_get_current_clk_freq,
9271571a7a1Sriastradh 	.get_dpm_ultimate_freq = smu_v12_0_get_dpm_ultimate_freq,
9281571a7a1Sriastradh 	.mode2_reset = smu_v12_0_mode2_reset,
9291571a7a1Sriastradh 	.set_soft_freq_limited_range = smu_v12_0_set_soft_freq_limited_range,
9301571a7a1Sriastradh 	.set_driver_table_location = smu_v12_0_set_driver_table_location,
9311571a7a1Sriastradh };
9321571a7a1Sriastradh 
renoir_set_ppt_funcs(struct smu_context * smu)9331571a7a1Sriastradh void renoir_set_ppt_funcs(struct smu_context *smu)
9341571a7a1Sriastradh {
9351571a7a1Sriastradh 	smu->ppt_funcs = &renoir_ppt_funcs;
9361571a7a1Sriastradh 	smu->smc_if_version = SMU12_DRIVER_IF_VERSION;
9371571a7a1Sriastradh 	smu->is_apu = true;
9381571a7a1Sriastradh }
939