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