155c89494STim Huang /* 255c89494STim Huang * Copyright 2022 Advanced Micro Devices, Inc. 355c89494STim Huang * 455c89494STim Huang * Permission is hereby granted, free of charge, to any person obtaining a 555c89494STim Huang * copy of this software and associated documentation files (the "Software"), 655c89494STim Huang * to deal in the Software without restriction, including without limitation 755c89494STim Huang * the rights to use, copy, modify, merge, publish, distribute, sublicense, 855c89494STim Huang * and/or sell copies of the Software, and to permit persons to whom the 955c89494STim Huang * Software is furnished to do so, subject to the following conditions: 1055c89494STim Huang * 1155c89494STim Huang * The above copyright notice and this permission notice shall be included in 1255c89494STim Huang * all copies or substantial portions of the Software. 1355c89494STim Huang * 1455c89494STim Huang * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1555c89494STim Huang * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1655c89494STim Huang * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1755c89494STim Huang * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1855c89494STim Huang * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1955c89494STim Huang * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2055c89494STim Huang * OTHER DEALINGS IN THE SOFTWARE. 2155c89494STim Huang * 2255c89494STim Huang */ 2355c89494STim Huang 2455c89494STim Huang #include "smu_types.h" 2555c89494STim Huang #define SWSMU_CODE_LAYER_L2 2655c89494STim Huang 2755c89494STim Huang #include "amdgpu.h" 2855c89494STim Huang #include "amdgpu_smu.h" 2955c89494STim Huang #include "smu_v13_0.h" 3055c89494STim Huang #include "smu13_driver_if_v13_0_4.h" 3155c89494STim Huang #include "smu_v13_0_4_ppt.h" 3255c89494STim Huang #include "smu_v13_0_4_ppsmc.h" 3355c89494STim Huang #include "smu_v13_0_4_pmfw.h" 3455c89494STim Huang #include "smu_cmn.h" 3555c89494STim Huang 3655c89494STim Huang /* 3755c89494STim Huang * DO NOT use these for err/warn/info/debug messages. 3855c89494STim Huang * Use dev_err, dev_warn, dev_info and dev_dbg instead. 3955c89494STim Huang * They are more MGPU friendly. 4055c89494STim Huang */ 4155c89494STim Huang #undef pr_err 4255c89494STim Huang #undef pr_warn 4355c89494STim Huang #undef pr_info 4455c89494STim Huang #undef pr_debug 4555c89494STim Huang 46da1db031SAlex Deucher #define mmMP1_SMN_C2PMSG_66 0x0282 47da1db031SAlex Deucher #define mmMP1_SMN_C2PMSG_66_BASE_IDX 1 48da1db031SAlex Deucher 49da1db031SAlex Deucher #define mmMP1_SMN_C2PMSG_82 0x0292 50da1db031SAlex Deucher #define mmMP1_SMN_C2PMSG_82_BASE_IDX 1 51da1db031SAlex Deucher 52da1db031SAlex Deucher #define mmMP1_SMN_C2PMSG_90 0x029a 53da1db031SAlex Deucher #define mmMP1_SMN_C2PMSG_90_BASE_IDX 1 54da1db031SAlex Deucher 5555c89494STim Huang #define FEATURE_MASK(feature) (1ULL << feature) 5655c89494STim Huang 5755c89494STim Huang #define SMC_DPM_FEATURE ( \ 5855c89494STim Huang FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ 5955c89494STim Huang FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ 6055c89494STim Huang FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ 6155c89494STim Huang FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \ 6255c89494STim Huang FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT) | \ 6355c89494STim Huang FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ 6455c89494STim Huang FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \ 6555c89494STim Huang FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT) | \ 6655c89494STim Huang FEATURE_MASK(FEATURE_ISP_DPM_BIT) | \ 6755c89494STim Huang FEATURE_MASK(FEATURE_IPU_DPM_BIT) | \ 6855c89494STim Huang FEATURE_MASK(FEATURE_GFX_DPM_BIT)) 6955c89494STim Huang 7055c89494STim Huang static struct cmn2asic_msg_mapping smu_v13_0_4_message_map[SMU_MSG_MAX_COUNT] = { 7155c89494STim Huang MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), 7255c89494STim Huang MSG_MAP(GetSmuVersion, PPSMC_MSG_GetPmfwVersion, 1), 7355c89494STim Huang MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1), 7455c89494STim Huang MSG_MAP(AllowGfxOff, PPSMC_MSG_AllowGfxOff, 1), 7555c89494STim Huang MSG_MAP(DisallowGfxOff, PPSMC_MSG_DisallowGfxOff, 1), 7655c89494STim Huang MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn, 1), 7755c89494STim Huang MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn, 1), 7855c89494STim Huang MSG_MAP(SetHardMinVcn, PPSMC_MSG_SetHardMinVcn, 1), 7955c89494STim Huang MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 1), 8055c89494STim Huang MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 1), 8155c89494STim Huang MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 1), 8255c89494STim Huang MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 1), 8355c89494STim Huang MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu, 1), 8455c89494STim Huang MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDeviceDriverReset, 1), 8555c89494STim Huang MSG_MAP(GetEnabledSmuFeatures, PPSMC_MSG_GetEnabledSmuFeatures, 1), 8655c89494STim Huang MSG_MAP(SetHardMinSocclkByFreq, PPSMC_MSG_SetHardMinSocclkByFreq, 1), 8755c89494STim Huang MSG_MAP(SetSoftMinVcn, PPSMC_MSG_SetSoftMinVcn, 1), 8855c89494STim Huang MSG_MAP(GetGfxclkFrequency, PPSMC_MSG_GetGfxclkFrequency, 1), 8955c89494STim Huang MSG_MAP(GetFclkFrequency, PPSMC_MSG_GetFclkFrequency, 1), 9055c89494STim Huang MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1), 9155c89494STim Huang MSG_MAP(SetHardMinGfxClk, PPSMC_MSG_SetHardMinGfxClk, 1), 9255c89494STim Huang MSG_MAP(SetSoftMaxSocclkByFreq, PPSMC_MSG_SetSoftMaxSocclkByFreq, 1), 9355c89494STim Huang MSG_MAP(SetSoftMaxFclkByFreq, PPSMC_MSG_SetSoftMaxFclkByFreq, 1), 9455c89494STim Huang MSG_MAP(SetSoftMaxVcn, PPSMC_MSG_SetSoftMaxVcn, 1), 9555c89494STim Huang MSG_MAP(SetPowerLimitPercentage, PPSMC_MSG_SetPowerLimitPercentage, 1), 9655c89494STim Huang MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg, 1), 9755c89494STim Huang MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg, 1), 9855c89494STim Huang MSG_MAP(SetHardMinFclkByFreq, PPSMC_MSG_SetHardMinFclkByFreq, 1), 9955c89494STim Huang MSG_MAP(SetSoftMinSocclkByFreq, PPSMC_MSG_SetSoftMinSocclkByFreq, 1), 10055c89494STim Huang MSG_MAP(EnableGfxImu, PPSMC_MSG_EnableGfxImu, 1), 10155c89494STim Huang MSG_MAP(PowerUpIspByTile, PPSMC_MSG_PowerUpIspByTile, 1), 10255c89494STim Huang MSG_MAP(PowerDownIspByTile, PPSMC_MSG_PowerDownIspByTile, 1), 10355c89494STim Huang }; 10455c89494STim Huang 10555c89494STim Huang static struct cmn2asic_mapping smu_v13_0_4_feature_mask_map[SMU_FEATURE_COUNT] = { 10655c89494STim Huang FEA_MAP(CCLK_DPM), 10755c89494STim Huang FEA_MAP(FAN_CONTROLLER), 10855c89494STim Huang FEA_MAP(PPT), 10955c89494STim Huang FEA_MAP(TDC), 11055c89494STim Huang FEA_MAP(THERMAL), 11155c89494STim Huang FEA_MAP(VCN_DPM), 11255c89494STim Huang FEA_MAP_REVERSE(FCLK), 11355c89494STim Huang FEA_MAP_REVERSE(SOCCLK), 11455c89494STim Huang FEA_MAP(LCLK_DPM), 11555c89494STim Huang FEA_MAP(SHUBCLK_DPM), 11655c89494STim Huang FEA_MAP(DCFCLK_DPM), 11755c89494STim Huang FEA_MAP_HALF_REVERSE(GFX), 11855c89494STim Huang FEA_MAP(DS_GFXCLK), 11955c89494STim Huang FEA_MAP(DS_SOCCLK), 12055c89494STim Huang FEA_MAP(DS_LCLK), 12155c89494STim Huang FEA_MAP(DS_DCFCLK), 12255c89494STim Huang FEA_MAP(DS_FCLK), 12355c89494STim Huang FEA_MAP(DS_MP1CLK), 12455c89494STim Huang FEA_MAP(DS_MP0CLK), 12555c89494STim Huang FEA_MAP(GFX_DEM), 12655c89494STim Huang FEA_MAP(PSI), 12755c89494STim Huang FEA_MAP(PROCHOT), 12855c89494STim Huang FEA_MAP(CPUOFF), 12955c89494STim Huang FEA_MAP(STAPM), 13055c89494STim Huang FEA_MAP(S0I3), 13155c89494STim Huang FEA_MAP(PERF_LIMIT), 13255c89494STim Huang FEA_MAP(CORE_DLDO), 13355c89494STim Huang FEA_MAP(DS_VCN), 13455c89494STim Huang FEA_MAP(CPPC), 13555c89494STim Huang FEA_MAP(DF_CSTATES), 13655c89494STim Huang FEA_MAP(ATHUB_PG), 13755c89494STim Huang }; 13855c89494STim Huang 13955c89494STim Huang static struct cmn2asic_mapping smu_v13_0_4_table_map[SMU_TABLE_COUNT] = { 14055c89494STim Huang TAB_MAP_VALID(WATERMARKS), 14155c89494STim Huang TAB_MAP_VALID(SMU_METRICS), 14255c89494STim Huang TAB_MAP_VALID(CUSTOM_DPM), 14355c89494STim Huang TAB_MAP_VALID(DPMCLOCKS), 14455c89494STim Huang }; 14555c89494STim Huang 14655c89494STim Huang static int smu_v13_0_4_init_smc_tables(struct smu_context *smu) 14755c89494STim Huang { 14855c89494STim Huang struct smu_table_context *smu_table = &smu->smu_table; 14955c89494STim Huang struct smu_table *tables = smu_table->tables; 15055c89494STim Huang 15155c89494STim Huang SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), 15255c89494STim Huang PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); 15355c89494STim Huang SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t), 15455c89494STim Huang PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); 15555c89494STim Huang SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), 15655c89494STim Huang PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); 15755c89494STim Huang 15855c89494STim Huang smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL); 15955c89494STim Huang if (!smu_table->clocks_table) 16055c89494STim Huang goto err0_out; 16155c89494STim Huang 16255c89494STim Huang smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); 16355c89494STim Huang if (!smu_table->metrics_table) 16455c89494STim Huang goto err1_out; 16555c89494STim Huang smu_table->metrics_time = 0; 16655c89494STim Huang 16755c89494STim Huang smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); 16855c89494STim Huang if (!smu_table->watermarks_table) 16955c89494STim Huang goto err2_out; 17055c89494STim Huang 17155c89494STim Huang smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_1); 17255c89494STim Huang smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); 17355c89494STim Huang if (!smu_table->gpu_metrics_table) 17455c89494STim Huang goto err3_out; 17555c89494STim Huang 17655c89494STim Huang return 0; 17755c89494STim Huang 17855c89494STim Huang err3_out: 17955c89494STim Huang kfree(smu_table->watermarks_table); 18055c89494STim Huang err2_out: 18155c89494STim Huang kfree(smu_table->metrics_table); 18255c89494STim Huang err1_out: 18355c89494STim Huang kfree(smu_table->clocks_table); 18455c89494STim Huang err0_out: 18555c89494STim Huang return -ENOMEM; 18655c89494STim Huang } 18755c89494STim Huang 18855c89494STim Huang static int smu_v13_0_4_fini_smc_tables(struct smu_context *smu) 18955c89494STim Huang { 19055c89494STim Huang struct smu_table_context *smu_table = &smu->smu_table; 19155c89494STim Huang 19255c89494STim Huang kfree(smu_table->clocks_table); 19355c89494STim Huang smu_table->clocks_table = NULL; 19455c89494STim Huang 19555c89494STim Huang kfree(smu_table->metrics_table); 19655c89494STim Huang smu_table->metrics_table = NULL; 19755c89494STim Huang 19855c89494STim Huang kfree(smu_table->watermarks_table); 19955c89494STim Huang smu_table->watermarks_table = NULL; 20055c89494STim Huang 201*5afb7652SZhen Ni kfree(smu_table->gpu_metrics_table); 202*5afb7652SZhen Ni smu_table->gpu_metrics_table = NULL; 203*5afb7652SZhen Ni 20455c89494STim Huang return 0; 20555c89494STim Huang } 20655c89494STim Huang 20755c89494STim Huang static bool smu_v13_0_4_is_dpm_running(struct smu_context *smu) 20855c89494STim Huang { 20955c89494STim Huang int ret = 0; 21055c89494STim Huang uint64_t feature_enabled; 21155c89494STim Huang 21255c89494STim Huang ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); 21355c89494STim Huang 21455c89494STim Huang if (ret) 21555c89494STim Huang return false; 21655c89494STim Huang 21755c89494STim Huang return !!(feature_enabled & SMC_DPM_FEATURE); 21855c89494STim Huang } 21955c89494STim Huang 22055c89494STim Huang static int smu_v13_0_4_system_features_control(struct smu_context *smu, bool en) 22155c89494STim Huang { 22255c89494STim Huang struct amdgpu_device *adev = smu->adev; 22355c89494STim Huang int ret = 0; 224526e6ca5STim Huang 225526e6ca5STim Huang if (!en && !adev->in_s0ix) 226526e6ca5STim Huang ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL); 227526e6ca5STim Huang 22855c89494STim Huang return ret; 22955c89494STim Huang } 23055c89494STim Huang 23155c89494STim Huang static ssize_t smu_v13_0_4_get_gpu_metrics(struct smu_context *smu, 23255c89494STim Huang void **table) 23355c89494STim Huang { 23455c89494STim Huang struct smu_table_context *smu_table = &smu->smu_table; 23555c89494STim Huang struct gpu_metrics_v2_1 *gpu_metrics = 23655c89494STim Huang (struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table; 23755c89494STim Huang SmuMetrics_t metrics; 23855c89494STim Huang int ret = 0; 23955c89494STim Huang 24055c89494STim Huang ret = smu_cmn_get_metrics_table(smu, &metrics, true); 24155c89494STim Huang if (ret) 24255c89494STim Huang return ret; 24355c89494STim Huang 24455c89494STim Huang smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 1); 24555c89494STim Huang 24655c89494STim Huang gpu_metrics->temperature_gfx = metrics.GfxTemperature; 24755c89494STim Huang gpu_metrics->temperature_soc = metrics.SocTemperature; 24855c89494STim Huang memcpy(&gpu_metrics->temperature_core[0], 24955c89494STim Huang &metrics.CoreTemperature[0], 25055c89494STim Huang sizeof(uint16_t) * 8); 25155c89494STim Huang gpu_metrics->temperature_l3[0] = metrics.L3Temperature; 25255c89494STim Huang 25355c89494STim Huang gpu_metrics->average_gfx_activity = metrics.GfxActivity; 25455c89494STim Huang gpu_metrics->average_mm_activity = metrics.UvdActivity; 25555c89494STim Huang 25655c89494STim Huang gpu_metrics->average_socket_power = metrics.CurrentSocketPower; 25755c89494STim Huang gpu_metrics->average_gfx_power = metrics.Power[0]; 25855c89494STim Huang gpu_metrics->average_soc_power = metrics.Power[1]; 25955c89494STim Huang memcpy(&gpu_metrics->average_core_power[0], 26055c89494STim Huang &metrics.CorePower[0], 26155c89494STim Huang sizeof(uint16_t) * 8); 26255c89494STim Huang 26355c89494STim Huang gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency; 26455c89494STim Huang gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency; 26555c89494STim Huang gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency; 26655c89494STim Huang gpu_metrics->average_fclk_frequency = metrics.MemclkFrequency; 26755c89494STim Huang gpu_metrics->average_vclk_frequency = metrics.VclkFrequency; 26855c89494STim Huang gpu_metrics->average_dclk_frequency = metrics.DclkFrequency; 26955c89494STim Huang 27055c89494STim Huang memcpy(&gpu_metrics->current_coreclk[0], 27155c89494STim Huang &metrics.CoreFrequency[0], 27255c89494STim Huang sizeof(uint16_t) * 8); 27355c89494STim Huang gpu_metrics->current_l3clk[0] = metrics.L3Frequency; 27455c89494STim Huang 27555c89494STim Huang gpu_metrics->throttle_status = metrics.ThrottlerStatus; 27655c89494STim Huang 27755c89494STim Huang gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); 27855c89494STim Huang 27955c89494STim Huang *table = (void *)gpu_metrics; 28055c89494STim Huang 28155c89494STim Huang return sizeof(struct gpu_metrics_v2_1); 28255c89494STim Huang } 28355c89494STim Huang 28455c89494STim Huang static int smu_v13_0_4_get_smu_metrics_data(struct smu_context *smu, 28555c89494STim Huang MetricsMember_t member, 28655c89494STim Huang uint32_t *value) 28755c89494STim Huang { 28855c89494STim Huang struct smu_table_context *smu_table = &smu->smu_table; 28955c89494STim Huang 29055c89494STim Huang SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table; 29155c89494STim Huang int ret = 0; 29255c89494STim Huang 29355c89494STim Huang ret = smu_cmn_get_metrics_table(smu, NULL, false); 29455c89494STim Huang if (ret) 29555c89494STim Huang return ret; 29655c89494STim Huang 29755c89494STim Huang switch (member) { 29855c89494STim Huang case METRICS_AVERAGE_GFXCLK: 29955c89494STim Huang *value = metrics->GfxclkFrequency; 30055c89494STim Huang break; 30155c89494STim Huang case METRICS_AVERAGE_SOCCLK: 30255c89494STim Huang *value = metrics->SocclkFrequency; 30355c89494STim Huang break; 30455c89494STim Huang case METRICS_AVERAGE_VCLK: 30555c89494STim Huang *value = metrics->VclkFrequency; 30655c89494STim Huang break; 30755c89494STim Huang case METRICS_AVERAGE_DCLK: 30855c89494STim Huang *value = metrics->DclkFrequency; 30955c89494STim Huang break; 31055c89494STim Huang case METRICS_AVERAGE_UCLK: 31155c89494STim Huang *value = metrics->MemclkFrequency; 31255c89494STim Huang break; 31355c89494STim Huang case METRICS_AVERAGE_GFXACTIVITY: 31455c89494STim Huang *value = metrics->GfxActivity / 100; 31555c89494STim Huang break; 31655c89494STim Huang case METRICS_AVERAGE_VCNACTIVITY: 31755c89494STim Huang *value = metrics->UvdActivity; 31855c89494STim Huang break; 31955c89494STim Huang case METRICS_AVERAGE_SOCKETPOWER: 32055c89494STim Huang *value = (metrics->CurrentSocketPower << 8) / 1000; 32155c89494STim Huang break; 32255c89494STim Huang case METRICS_TEMPERATURE_EDGE: 32355c89494STim Huang *value = metrics->GfxTemperature / 100 * 32455c89494STim Huang SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; 32555c89494STim Huang break; 32655c89494STim Huang case METRICS_TEMPERATURE_HOTSPOT: 32755c89494STim Huang *value = metrics->SocTemperature / 100 * 32855c89494STim Huang SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; 32955c89494STim Huang break; 33055c89494STim Huang case METRICS_THROTTLER_STATUS: 33155c89494STim Huang *value = metrics->ThrottlerStatus; 33255c89494STim Huang break; 33355c89494STim Huang case METRICS_VOLTAGE_VDDGFX: 33455c89494STim Huang *value = metrics->Voltage[0]; 33555c89494STim Huang break; 33655c89494STim Huang case METRICS_VOLTAGE_VDDSOC: 33755c89494STim Huang *value = metrics->Voltage[1]; 33855c89494STim Huang break; 33955c89494STim Huang case METRICS_SS_APU_SHARE: 34055c89494STim Huang /* return the percentage of APU power with respect to APU's power limit. 34155c89494STim Huang * percentage is reported, this isn't boost value. Smartshift power 34255c89494STim Huang * boost/shift is only when the percentage is more than 100. 34355c89494STim Huang */ 34455c89494STim Huang if (metrics->StapmOpnLimit > 0) 34555c89494STim Huang *value = (metrics->ApuPower * 100) / metrics->StapmOpnLimit; 34655c89494STim Huang else 34755c89494STim Huang *value = 0; 34855c89494STim Huang break; 34955c89494STim Huang case METRICS_SS_DGPU_SHARE: 35055c89494STim Huang /* return the percentage of dGPU power with respect to dGPU's power limit. 35155c89494STim Huang * percentage is reported, this isn't boost value. Smartshift power 35255c89494STim Huang * boost/shift is only when the percentage is more than 100. 35355c89494STim Huang */ 35455c89494STim Huang if ((metrics->dGpuPower > 0) && 35555c89494STim Huang (metrics->StapmCurrentLimit > metrics->StapmOpnLimit)) 35655c89494STim Huang *value = (metrics->dGpuPower * 100) / 35755c89494STim Huang (metrics->StapmCurrentLimit - metrics->StapmOpnLimit); 35855c89494STim Huang else 35955c89494STim Huang *value = 0; 36055c89494STim Huang break; 36155c89494STim Huang default: 36255c89494STim Huang *value = UINT_MAX; 36355c89494STim Huang break; 36455c89494STim Huang } 36555c89494STim Huang 36655c89494STim Huang return ret; 36755c89494STim Huang } 36855c89494STim Huang 36955c89494STim Huang static int smu_v13_0_4_get_current_clk_freq(struct smu_context *smu, 37055c89494STim Huang enum smu_clk_type clk_type, 37155c89494STim Huang uint32_t *value) 37255c89494STim Huang { 37355c89494STim Huang MetricsMember_t member_type; 37455c89494STim Huang 37555c89494STim Huang switch (clk_type) { 37655c89494STim Huang case SMU_SOCCLK: 37755c89494STim Huang member_type = METRICS_AVERAGE_SOCCLK; 37855c89494STim Huang break; 37955c89494STim Huang case SMU_VCLK: 38055c89494STim Huang member_type = METRICS_AVERAGE_VCLK; 38155c89494STim Huang break; 38255c89494STim Huang case SMU_DCLK: 38355c89494STim Huang member_type = METRICS_AVERAGE_DCLK; 38455c89494STim Huang break; 38555c89494STim Huang case SMU_MCLK: 38655c89494STim Huang member_type = METRICS_AVERAGE_UCLK; 38755c89494STim Huang break; 38855c89494STim Huang case SMU_FCLK: 38955c89494STim Huang return smu_cmn_send_smc_msg_with_param(smu, 39055c89494STim Huang SMU_MSG_GetFclkFrequency, 39155c89494STim Huang 0, value); 39255c89494STim Huang case SMU_GFXCLK: 39355c89494STim Huang case SMU_SCLK: 39455c89494STim Huang return smu_cmn_send_smc_msg_with_param(smu, 39555c89494STim Huang SMU_MSG_GetGfxclkFrequency, 39655c89494STim Huang 0, value); 39755c89494STim Huang break; 39855c89494STim Huang default: 39955c89494STim Huang return -EINVAL; 40055c89494STim Huang } 40155c89494STim Huang 40255c89494STim Huang return smu_v13_0_4_get_smu_metrics_data(smu, member_type, value); 40355c89494STim Huang } 40455c89494STim Huang 40555c89494STim Huang static int smu_v13_0_4_get_dpm_freq_by_index(struct smu_context *smu, 40655c89494STim Huang enum smu_clk_type clk_type, 40755c89494STim Huang uint32_t dpm_level, 40855c89494STim Huang uint32_t *freq) 40955c89494STim Huang { 41055c89494STim Huang DpmClocks_t *clk_table = smu->smu_table.clocks_table; 41155c89494STim Huang 41255c89494STim Huang if (!clk_table || clk_type >= SMU_CLK_COUNT) 41355c89494STim Huang return -EINVAL; 41455c89494STim Huang 41555c89494STim Huang switch (clk_type) { 41655c89494STim Huang case SMU_SOCCLK: 41755c89494STim Huang if (dpm_level >= clk_table->NumSocClkLevelsEnabled) 41855c89494STim Huang return -EINVAL; 41955c89494STim Huang *freq = clk_table->SocClocks[dpm_level]; 42055c89494STim Huang break; 42155c89494STim Huang case SMU_VCLK: 42255c89494STim Huang if (dpm_level >= clk_table->VcnClkLevelsEnabled) 42355c89494STim Huang return -EINVAL; 42455c89494STim Huang *freq = clk_table->VClocks[dpm_level]; 42555c89494STim Huang break; 42655c89494STim Huang case SMU_DCLK: 42755c89494STim Huang if (dpm_level >= clk_table->VcnClkLevelsEnabled) 42855c89494STim Huang return -EINVAL; 42955c89494STim Huang *freq = clk_table->DClocks[dpm_level]; 43055c89494STim Huang break; 43155c89494STim Huang case SMU_UCLK: 43255c89494STim Huang case SMU_MCLK: 43355c89494STim Huang if (dpm_level >= clk_table->NumDfPstatesEnabled) 43455c89494STim Huang return -EINVAL; 43555c89494STim Huang *freq = clk_table->DfPstateTable[dpm_level].MemClk; 43655c89494STim Huang break; 43755c89494STim Huang case SMU_FCLK: 43855c89494STim Huang if (dpm_level >= clk_table->NumDfPstatesEnabled) 43955c89494STim Huang return -EINVAL; 44055c89494STim Huang *freq = clk_table->DfPstateTable[dpm_level].FClk; 44155c89494STim Huang break; 44255c89494STim Huang default: 44355c89494STim Huang return -EINVAL; 44455c89494STim Huang } 44555c89494STim Huang 44655c89494STim Huang return 0; 44755c89494STim Huang } 44855c89494STim Huang 44955c89494STim Huang static int smu_v13_0_4_get_dpm_level_count(struct smu_context *smu, 45055c89494STim Huang enum smu_clk_type clk_type, 45155c89494STim Huang uint32_t *count) 45255c89494STim Huang { 45355c89494STim Huang DpmClocks_t *clk_table = smu->smu_table.clocks_table; 45455c89494STim Huang 45555c89494STim Huang switch (clk_type) { 45655c89494STim Huang case SMU_SOCCLK: 45755c89494STim Huang *count = clk_table->NumSocClkLevelsEnabled; 45855c89494STim Huang break; 45955c89494STim Huang case SMU_VCLK: 46055c89494STim Huang *count = clk_table->VcnClkLevelsEnabled; 46155c89494STim Huang break; 46255c89494STim Huang case SMU_DCLK: 46355c89494STim Huang *count = clk_table->VcnClkLevelsEnabled; 46455c89494STim Huang break; 46555c89494STim Huang case SMU_MCLK: 46655c89494STim Huang *count = clk_table->NumDfPstatesEnabled; 46755c89494STim Huang break; 46855c89494STim Huang case SMU_FCLK: 46955c89494STim Huang *count = clk_table->NumDfPstatesEnabled; 47055c89494STim Huang break; 47155c89494STim Huang default: 47255c89494STim Huang break; 47355c89494STim Huang } 47455c89494STim Huang 47555c89494STim Huang return 0; 47655c89494STim Huang } 47755c89494STim Huang 47855c89494STim Huang static int smu_v13_0_4_print_clk_levels(struct smu_context *smu, 47955c89494STim Huang enum smu_clk_type clk_type, char *buf) 48055c89494STim Huang { 48155c89494STim Huang int i, size = 0, ret = 0; 48255c89494STim Huang uint32_t cur_value = 0, value = 0, count = 0; 48355c89494STim Huang uint32_t min, max; 48455c89494STim Huang 48555c89494STim Huang smu_cmn_get_sysfs_buf(&buf, &size); 48655c89494STim Huang 48755c89494STim Huang switch (clk_type) { 48855c89494STim Huang case SMU_OD_SCLK: 48955c89494STim Huang size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); 49055c89494STim Huang size += sysfs_emit_at(buf, size, "0: %10uMhz\n", 49155c89494STim Huang (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq); 49255c89494STim Huang size += sysfs_emit_at(buf, size, "1: %10uMhz\n", 49355c89494STim Huang (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq); 49455c89494STim Huang break; 49555c89494STim Huang case SMU_OD_RANGE: 49655c89494STim Huang size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); 49755c89494STim Huang size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n", 49855c89494STim Huang smu->gfx_default_hard_min_freq, 49955c89494STim Huang smu->gfx_default_soft_max_freq); 50055c89494STim Huang break; 50155c89494STim Huang case SMU_SOCCLK: 50255c89494STim Huang case SMU_VCLK: 50355c89494STim Huang case SMU_DCLK: 50455c89494STim Huang case SMU_MCLK: 50555c89494STim Huang case SMU_FCLK: 50655c89494STim Huang ret = smu_v13_0_4_get_current_clk_freq(smu, clk_type, &cur_value); 50755c89494STim Huang if (ret) 50855c89494STim Huang break; 50955c89494STim Huang 51055c89494STim Huang ret = smu_v13_0_4_get_dpm_level_count(smu, clk_type, &count); 51155c89494STim Huang if (ret) 51255c89494STim Huang break; 51355c89494STim Huang 51455c89494STim Huang for (i = 0; i < count; i++) { 51555c89494STim Huang ret = smu_v13_0_4_get_dpm_freq_by_index(smu, clk_type, i, &value); 51655c89494STim Huang if (ret) 51755c89494STim Huang break; 51855c89494STim Huang 51955c89494STim Huang size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value, 52055c89494STim Huang cur_value == value ? "*" : ""); 52155c89494STim Huang } 52255c89494STim Huang break; 52355c89494STim Huang case SMU_GFXCLK: 52455c89494STim Huang case SMU_SCLK: 52555c89494STim Huang ret = smu_v13_0_4_get_current_clk_freq(smu, clk_type, &cur_value); 52655c89494STim Huang if (ret) 52755c89494STim Huang break; 52855c89494STim Huang min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq; 52955c89494STim Huang max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq; 53055c89494STim Huang if (cur_value == max) 53155c89494STim Huang i = 2; 53255c89494STim Huang else if (cur_value == min) 53355c89494STim Huang i = 0; 53455c89494STim Huang else 53555c89494STim Huang i = 1; 53655c89494STim Huang size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min, 53755c89494STim Huang i == 0 ? "*" : ""); 53855c89494STim Huang size += sysfs_emit_at(buf, size, "1: %uMhz %s\n", 53955c89494STim Huang i == 1 ? cur_value : 1100, /* UMD PSTATE GFXCLK 1100 */ 54055c89494STim Huang i == 1 ? "*" : ""); 54155c89494STim Huang size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max, 54255c89494STim Huang i == 2 ? "*" : ""); 54355c89494STim Huang break; 54455c89494STim Huang default: 54555c89494STim Huang break; 54655c89494STim Huang } 54755c89494STim Huang 54855c89494STim Huang return size; 54955c89494STim Huang } 55055c89494STim Huang 55155c89494STim Huang static int smu_v13_0_4_read_sensor(struct smu_context *smu, 55255c89494STim Huang enum amd_pp_sensors sensor, 55355c89494STim Huang void *data, uint32_t *size) 55455c89494STim Huang { 55555c89494STim Huang int ret = 0; 55655c89494STim Huang 55755c89494STim Huang if (!data || !size) 55855c89494STim Huang return -EINVAL; 55955c89494STim Huang 56055c89494STim Huang switch (sensor) { 56155c89494STim Huang case AMDGPU_PP_SENSOR_GPU_LOAD: 56255c89494STim Huang ret = smu_v13_0_4_get_smu_metrics_data(smu, 56355c89494STim Huang METRICS_AVERAGE_GFXACTIVITY, 56455c89494STim Huang (uint32_t *)data); 56555c89494STim Huang *size = 4; 56655c89494STim Huang break; 56755c89494STim Huang case AMDGPU_PP_SENSOR_GPU_POWER: 56855c89494STim Huang ret = smu_v13_0_4_get_smu_metrics_data(smu, 56955c89494STim Huang METRICS_AVERAGE_SOCKETPOWER, 57055c89494STim Huang (uint32_t *)data); 57155c89494STim Huang *size = 4; 57255c89494STim Huang break; 57355c89494STim Huang case AMDGPU_PP_SENSOR_EDGE_TEMP: 57455c89494STim Huang ret = smu_v13_0_4_get_smu_metrics_data(smu, 57555c89494STim Huang METRICS_TEMPERATURE_EDGE, 57655c89494STim Huang (uint32_t *)data); 57755c89494STim Huang *size = 4; 57855c89494STim Huang break; 57955c89494STim Huang case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: 58055c89494STim Huang ret = smu_v13_0_4_get_smu_metrics_data(smu, 58155c89494STim Huang METRICS_TEMPERATURE_HOTSPOT, 58255c89494STim Huang (uint32_t *)data); 58355c89494STim Huang *size = 4; 58455c89494STim Huang break; 58555c89494STim Huang case AMDGPU_PP_SENSOR_GFX_MCLK: 58655c89494STim Huang ret = smu_v13_0_4_get_smu_metrics_data(smu, 58755c89494STim Huang METRICS_AVERAGE_UCLK, 58855c89494STim Huang (uint32_t *)data); 58955c89494STim Huang *(uint32_t *)data *= 100; 59055c89494STim Huang *size = 4; 59155c89494STim Huang break; 59255c89494STim Huang case AMDGPU_PP_SENSOR_GFX_SCLK: 59355c89494STim Huang ret = smu_v13_0_4_get_smu_metrics_data(smu, 59455c89494STim Huang METRICS_AVERAGE_GFXCLK, 59555c89494STim Huang (uint32_t *)data); 59655c89494STim Huang *(uint32_t *)data *= 100; 59755c89494STim Huang *size = 4; 59855c89494STim Huang break; 59955c89494STim Huang case AMDGPU_PP_SENSOR_VDDGFX: 60055c89494STim Huang ret = smu_v13_0_4_get_smu_metrics_data(smu, 60155c89494STim Huang METRICS_VOLTAGE_VDDGFX, 60255c89494STim Huang (uint32_t *)data); 60355c89494STim Huang *size = 4; 60455c89494STim Huang break; 60555c89494STim Huang case AMDGPU_PP_SENSOR_VDDNB: 60655c89494STim Huang ret = smu_v13_0_4_get_smu_metrics_data(smu, 60755c89494STim Huang METRICS_VOLTAGE_VDDSOC, 60855c89494STim Huang (uint32_t *)data); 60955c89494STim Huang *size = 4; 61055c89494STim Huang break; 61155c89494STim Huang case AMDGPU_PP_SENSOR_SS_APU_SHARE: 61255c89494STim Huang ret = smu_v13_0_4_get_smu_metrics_data(smu, 61355c89494STim Huang METRICS_SS_APU_SHARE, 61455c89494STim Huang (uint32_t *)data); 61555c89494STim Huang *size = 4; 61655c89494STim Huang break; 61755c89494STim Huang case AMDGPU_PP_SENSOR_SS_DGPU_SHARE: 61855c89494STim Huang ret = smu_v13_0_4_get_smu_metrics_data(smu, 61955c89494STim Huang METRICS_SS_DGPU_SHARE, 62055c89494STim Huang (uint32_t *)data); 62155c89494STim Huang *size = 4; 62255c89494STim Huang break; 62355c89494STim Huang default: 62455c89494STim Huang ret = -EOPNOTSUPP; 62555c89494STim Huang break; 62655c89494STim Huang } 62755c89494STim Huang 62855c89494STim Huang return ret; 62955c89494STim Huang } 63055c89494STim Huang 63155c89494STim Huang static int smu_v13_0_4_set_watermarks_table(struct smu_context *smu, 63255c89494STim Huang struct pp_smu_wm_range_sets *clock_ranges) 63355c89494STim Huang { 63455c89494STim Huang int i; 63555c89494STim Huang int ret = 0; 63655c89494STim Huang Watermarks_t *table = smu->smu_table.watermarks_table; 63755c89494STim Huang 63855c89494STim Huang if (!table || !clock_ranges) 63955c89494STim Huang return -EINVAL; 64055c89494STim Huang 64155c89494STim Huang if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES || 64255c89494STim Huang clock_ranges->num_writer_wm_sets > NUM_WM_RANGES) 64355c89494STim Huang return -EINVAL; 64455c89494STim Huang 64555c89494STim Huang for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) { 64655c89494STim Huang table->WatermarkRow[WM_DCFCLK][i].MinClock = 64755c89494STim Huang clock_ranges->reader_wm_sets[i].min_drain_clk_mhz; 64855c89494STim Huang table->WatermarkRow[WM_DCFCLK][i].MaxClock = 64955c89494STim Huang clock_ranges->reader_wm_sets[i].max_drain_clk_mhz; 65055c89494STim Huang table->WatermarkRow[WM_DCFCLK][i].MinMclk = 65155c89494STim Huang clock_ranges->reader_wm_sets[i].min_fill_clk_mhz; 65255c89494STim Huang table->WatermarkRow[WM_DCFCLK][i].MaxMclk = 65355c89494STim Huang clock_ranges->reader_wm_sets[i].max_fill_clk_mhz; 65455c89494STim Huang 65555c89494STim Huang table->WatermarkRow[WM_DCFCLK][i].WmSetting = 65655c89494STim Huang clock_ranges->reader_wm_sets[i].wm_inst; 65755c89494STim Huang } 65855c89494STim Huang 65955c89494STim Huang for (i = 0; i < clock_ranges->num_writer_wm_sets; i++) { 66055c89494STim Huang table->WatermarkRow[WM_SOCCLK][i].MinClock = 66155c89494STim Huang clock_ranges->writer_wm_sets[i].min_fill_clk_mhz; 66255c89494STim Huang table->WatermarkRow[WM_SOCCLK][i].MaxClock = 66355c89494STim Huang clock_ranges->writer_wm_sets[i].max_fill_clk_mhz; 66455c89494STim Huang table->WatermarkRow[WM_SOCCLK][i].MinMclk = 66555c89494STim Huang clock_ranges->writer_wm_sets[i].min_drain_clk_mhz; 66655c89494STim Huang table->WatermarkRow[WM_SOCCLK][i].MaxMclk = 66755c89494STim Huang clock_ranges->writer_wm_sets[i].max_drain_clk_mhz; 66855c89494STim Huang 66955c89494STim Huang table->WatermarkRow[WM_SOCCLK][i].WmSetting = 67055c89494STim Huang clock_ranges->writer_wm_sets[i].wm_inst; 67155c89494STim Huang } 67255c89494STim Huang 67355c89494STim Huang smu->watermarks_bitmap |= WATERMARKS_EXIST; 67455c89494STim Huang 67555c89494STim Huang /* pass data to smu controller */ 67655c89494STim Huang if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && 67755c89494STim Huang !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { 67855c89494STim Huang ret = smu_cmn_write_watermarks_table(smu); 67955c89494STim Huang if (ret) { 68055c89494STim Huang dev_err(smu->adev->dev, "Failed to update WMTABLE!"); 68155c89494STim Huang return ret; 68255c89494STim Huang } 68355c89494STim Huang smu->watermarks_bitmap |= WATERMARKS_LOADED; 68455c89494STim Huang } 68555c89494STim Huang 68655c89494STim Huang return 0; 68755c89494STim Huang } 68855c89494STim Huang 68955c89494STim Huang static bool smu_v13_0_4_clk_dpm_is_enabled(struct smu_context *smu, 69055c89494STim Huang enum smu_clk_type clk_type) 69155c89494STim Huang { 69255c89494STim Huang enum smu_feature_mask feature_id = 0; 69355c89494STim Huang 69455c89494STim Huang switch (clk_type) { 69555c89494STim Huang case SMU_MCLK: 69655c89494STim Huang case SMU_UCLK: 69755c89494STim Huang case SMU_FCLK: 69855c89494STim Huang feature_id = SMU_FEATURE_DPM_FCLK_BIT; 69955c89494STim Huang break; 70055c89494STim Huang case SMU_GFXCLK: 70155c89494STim Huang case SMU_SCLK: 70255c89494STim Huang feature_id = SMU_FEATURE_DPM_GFXCLK_BIT; 70355c89494STim Huang break; 70455c89494STim Huang case SMU_SOCCLK: 70555c89494STim Huang feature_id = SMU_FEATURE_DPM_SOCCLK_BIT; 70655c89494STim Huang break; 70755c89494STim Huang case SMU_VCLK: 70855c89494STim Huang case SMU_DCLK: 70955c89494STim Huang feature_id = SMU_FEATURE_VCN_DPM_BIT; 71055c89494STim Huang break; 71155c89494STim Huang default: 71255c89494STim Huang return true; 71355c89494STim Huang } 71455c89494STim Huang 71555c89494STim Huang return smu_cmn_feature_is_enabled(smu, feature_id); 71655c89494STim Huang } 71755c89494STim Huang 71855c89494STim Huang static int smu_v13_0_4_get_dpm_ultimate_freq(struct smu_context *smu, 71955c89494STim Huang enum smu_clk_type clk_type, 72055c89494STim Huang uint32_t *min, 72155c89494STim Huang uint32_t *max) 72255c89494STim Huang { 72355c89494STim Huang DpmClocks_t *clk_table = smu->smu_table.clocks_table; 72455c89494STim Huang uint32_t clock_limit; 72555c89494STim Huang uint32_t max_dpm_level, min_dpm_level; 72655c89494STim Huang int ret = 0; 72755c89494STim Huang 72855c89494STim Huang if (!smu_v13_0_4_clk_dpm_is_enabled(smu, clk_type)) { 72955c89494STim Huang switch (clk_type) { 73055c89494STim Huang case SMU_MCLK: 73155c89494STim Huang case SMU_UCLK: 73255c89494STim Huang clock_limit = smu->smu_table.boot_values.uclk; 73355c89494STim Huang break; 73455c89494STim Huang case SMU_FCLK: 73555c89494STim Huang clock_limit = smu->smu_table.boot_values.fclk; 73655c89494STim Huang break; 73755c89494STim Huang case SMU_GFXCLK: 73855c89494STim Huang case SMU_SCLK: 73955c89494STim Huang clock_limit = smu->smu_table.boot_values.gfxclk; 74055c89494STim Huang break; 74155c89494STim Huang case SMU_SOCCLK: 74255c89494STim Huang clock_limit = smu->smu_table.boot_values.socclk; 74355c89494STim Huang break; 74455c89494STim Huang case SMU_VCLK: 74555c89494STim Huang clock_limit = smu->smu_table.boot_values.vclk; 74655c89494STim Huang break; 74755c89494STim Huang case SMU_DCLK: 74855c89494STim Huang clock_limit = smu->smu_table.boot_values.dclk; 74955c89494STim Huang break; 75055c89494STim Huang default: 75155c89494STim Huang clock_limit = 0; 75255c89494STim Huang break; 75355c89494STim Huang } 75455c89494STim Huang 75555c89494STim Huang /* clock in Mhz unit */ 75655c89494STim Huang if (min) 75755c89494STim Huang *min = clock_limit / 100; 75855c89494STim Huang if (max) 75955c89494STim Huang *max = clock_limit / 100; 76055c89494STim Huang 76155c89494STim Huang return 0; 76255c89494STim Huang } 76355c89494STim Huang 76455c89494STim Huang if (max) { 76555c89494STim Huang switch (clk_type) { 76655c89494STim Huang case SMU_GFXCLK: 76755c89494STim Huang case SMU_SCLK: 76855c89494STim Huang *max = clk_table->MaxGfxClk; 76955c89494STim Huang break; 77055c89494STim Huang case SMU_MCLK: 77155c89494STim Huang case SMU_UCLK: 77255c89494STim Huang case SMU_FCLK: 77355c89494STim Huang max_dpm_level = 0; 77455c89494STim Huang break; 77555c89494STim Huang case SMU_SOCCLK: 77655c89494STim Huang max_dpm_level = clk_table->NumSocClkLevelsEnabled - 1; 77755c89494STim Huang break; 77855c89494STim Huang case SMU_VCLK: 77955c89494STim Huang case SMU_DCLK: 78055c89494STim Huang max_dpm_level = clk_table->VcnClkLevelsEnabled - 1; 78155c89494STim Huang break; 78255c89494STim Huang default: 78355c89494STim Huang return -EINVAL; 78455c89494STim Huang } 78555c89494STim Huang 78655c89494STim Huang if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) { 78755c89494STim Huang ret = smu_v13_0_4_get_dpm_freq_by_index(smu, clk_type, 78855c89494STim Huang max_dpm_level, 78955c89494STim Huang max); 79055c89494STim Huang if (ret) 79155c89494STim Huang return ret; 79255c89494STim Huang } 79355c89494STim Huang } 79455c89494STim Huang 79555c89494STim Huang if (min) { 79655c89494STim Huang switch (clk_type) { 79755c89494STim Huang case SMU_GFXCLK: 79855c89494STim Huang case SMU_SCLK: 79955c89494STim Huang *min = clk_table->MinGfxClk; 80055c89494STim Huang break; 80155c89494STim Huang case SMU_MCLK: 80255c89494STim Huang case SMU_UCLK: 80355c89494STim Huang case SMU_FCLK: 80455c89494STim Huang min_dpm_level = clk_table->NumDfPstatesEnabled - 1; 80555c89494STim Huang break; 80655c89494STim Huang case SMU_SOCCLK: 80755c89494STim Huang min_dpm_level = 0; 80855c89494STim Huang break; 80955c89494STim Huang case SMU_VCLK: 81055c89494STim Huang case SMU_DCLK: 81155c89494STim Huang min_dpm_level = 0; 81255c89494STim Huang break; 81355c89494STim Huang default: 81455c89494STim Huang return -EINVAL; 81555c89494STim Huang } 81655c89494STim Huang 81755c89494STim Huang if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) { 81855c89494STim Huang ret = smu_v13_0_4_get_dpm_freq_by_index(smu, clk_type, 81955c89494STim Huang min_dpm_level, 82055c89494STim Huang min); 82155c89494STim Huang } 82255c89494STim Huang } 82355c89494STim Huang 82455c89494STim Huang return ret; 82555c89494STim Huang } 82655c89494STim Huang 82755c89494STim Huang static int smu_v13_0_4_set_soft_freq_limited_range(struct smu_context *smu, 82855c89494STim Huang enum smu_clk_type clk_type, 82955c89494STim Huang uint32_t min, 83055c89494STim Huang uint32_t max) 83155c89494STim Huang { 83255c89494STim Huang enum smu_message_type msg_set_min, msg_set_max; 83355c89494STim Huang int ret = 0; 83455c89494STim Huang 83555c89494STim Huang if (!smu_v13_0_4_clk_dpm_is_enabled(smu, clk_type)) 83655c89494STim Huang return -EINVAL; 83755c89494STim Huang 83855c89494STim Huang switch (clk_type) { 83955c89494STim Huang case SMU_GFXCLK: 84055c89494STim Huang case SMU_SCLK: 84155c89494STim Huang msg_set_min = SMU_MSG_SetHardMinGfxClk; 84255c89494STim Huang msg_set_max = SMU_MSG_SetSoftMaxGfxClk; 84355c89494STim Huang break; 84455c89494STim Huang case SMU_FCLK: 84555c89494STim Huang msg_set_min = SMU_MSG_SetHardMinFclkByFreq; 84655c89494STim Huang msg_set_max = SMU_MSG_SetSoftMaxFclkByFreq; 84755c89494STim Huang break; 84855c89494STim Huang case SMU_SOCCLK: 84955c89494STim Huang msg_set_min = SMU_MSG_SetHardMinSocclkByFreq; 85055c89494STim Huang msg_set_max = SMU_MSG_SetSoftMaxSocclkByFreq; 85155c89494STim Huang break; 85255c89494STim Huang case SMU_VCLK: 85355c89494STim Huang case SMU_DCLK: 85455c89494STim Huang msg_set_min = SMU_MSG_SetHardMinVcn; 85555c89494STim Huang msg_set_max = SMU_MSG_SetSoftMaxVcn; 85655c89494STim Huang break; 85755c89494STim Huang default: 85855c89494STim Huang return -EINVAL; 85955c89494STim Huang } 86055c89494STim Huang 86155c89494STim Huang ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL); 86255c89494STim Huang if (ret) 86355c89494STim Huang return ret; 86455c89494STim Huang 86555c89494STim Huang return smu_cmn_send_smc_msg_with_param(smu, msg_set_max, 86655c89494STim Huang max, NULL); 86755c89494STim Huang } 86855c89494STim Huang 86955c89494STim Huang static int smu_v13_0_4_force_clk_levels(struct smu_context *smu, 87055c89494STim Huang enum smu_clk_type clk_type, 87155c89494STim Huang uint32_t mask) 87255c89494STim Huang { 87355c89494STim Huang uint32_t soft_min_level = 0, soft_max_level = 0; 87455c89494STim Huang uint32_t min_freq = 0, max_freq = 0; 87555c89494STim Huang int ret = 0; 87655c89494STim Huang 87755c89494STim Huang soft_min_level = mask ? (ffs(mask) - 1) : 0; 87855c89494STim Huang soft_max_level = mask ? (fls(mask) - 1) : 0; 87955c89494STim Huang 88055c89494STim Huang switch (clk_type) { 88155c89494STim Huang case SMU_SOCCLK: 88255c89494STim Huang case SMU_FCLK: 88355c89494STim Huang case SMU_VCLK: 88455c89494STim Huang case SMU_DCLK: 88555c89494STim Huang ret = smu_v13_0_4_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq); 88655c89494STim Huang if (ret) 88755c89494STim Huang break; 88855c89494STim Huang 88955c89494STim Huang ret = smu_v13_0_4_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq); 89055c89494STim Huang if (ret) 89155c89494STim Huang break; 89255c89494STim Huang 89355c89494STim Huang ret = smu_v13_0_4_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); 89455c89494STim Huang break; 89555c89494STim Huang default: 89655c89494STim Huang ret = -EINVAL; 89755c89494STim Huang break; 89855c89494STim Huang } 89955c89494STim Huang 90055c89494STim Huang return ret; 90155c89494STim Huang } 90255c89494STim Huang 90355c89494STim Huang static int smu_v13_0_4_set_performance_level(struct smu_context *smu, 90455c89494STim Huang enum amd_dpm_forced_level level) 90555c89494STim Huang { 90655c89494STim Huang struct amdgpu_device *adev = smu->adev; 90755c89494STim Huang uint32_t sclk_min = 0, sclk_max = 0; 90855c89494STim Huang uint32_t fclk_min = 0, fclk_max = 0; 90955c89494STim Huang uint32_t socclk_min = 0, socclk_max = 0; 91055c89494STim Huang int ret = 0; 91155c89494STim Huang 91255c89494STim Huang switch (level) { 91355c89494STim Huang case AMD_DPM_FORCED_LEVEL_HIGH: 91455c89494STim Huang smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_max); 91555c89494STim Huang smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_max); 91655c89494STim Huang smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_max); 91755c89494STim Huang sclk_min = sclk_max; 91855c89494STim Huang fclk_min = fclk_max; 91955c89494STim Huang socclk_min = socclk_max; 92055c89494STim Huang break; 92155c89494STim Huang case AMD_DPM_FORCED_LEVEL_LOW: 92255c89494STim Huang smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, NULL); 92355c89494STim Huang smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, NULL); 92455c89494STim Huang smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, NULL); 92555c89494STim Huang sclk_max = sclk_min; 92655c89494STim Huang fclk_max = fclk_min; 92755c89494STim Huang socclk_max = socclk_min; 92855c89494STim Huang break; 92955c89494STim Huang case AMD_DPM_FORCED_LEVEL_AUTO: 93055c89494STim Huang smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, &sclk_max); 93155c89494STim Huang smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, &fclk_max); 93255c89494STim Huang smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, &socclk_max); 93355c89494STim Huang break; 93455c89494STim Huang case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: 93555c89494STim Huang case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: 93655c89494STim Huang case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: 93755c89494STim Huang case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: 93855c89494STim Huang /* Temporarily do nothing since the optimal clocks haven't been provided yet */ 93955c89494STim Huang break; 94055c89494STim Huang case AMD_DPM_FORCED_LEVEL_MANUAL: 94155c89494STim Huang case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: 94255c89494STim Huang return 0; 94355c89494STim Huang default: 94455c89494STim Huang dev_err(adev->dev, "Invalid performance level %d\n", level); 94555c89494STim Huang return -EINVAL; 94655c89494STim Huang } 94755c89494STim Huang 94855c89494STim Huang if (sclk_min && sclk_max) { 94955c89494STim Huang ret = smu_v13_0_4_set_soft_freq_limited_range(smu, 95055c89494STim Huang SMU_SCLK, 95155c89494STim Huang sclk_min, 95255c89494STim Huang sclk_max); 95355c89494STim Huang if (ret) 95455c89494STim Huang return ret; 95555c89494STim Huang 95655c89494STim Huang smu->gfx_actual_hard_min_freq = sclk_min; 95755c89494STim Huang smu->gfx_actual_soft_max_freq = sclk_max; 95855c89494STim Huang } 95955c89494STim Huang 96055c89494STim Huang if (fclk_min && fclk_max) { 96155c89494STim Huang ret = smu_v13_0_4_set_soft_freq_limited_range(smu, 96255c89494STim Huang SMU_FCLK, 96355c89494STim Huang fclk_min, 96455c89494STim Huang fclk_max); 96555c89494STim Huang if (ret) 96655c89494STim Huang return ret; 96755c89494STim Huang } 96855c89494STim Huang 96955c89494STim Huang if (socclk_min && socclk_max) { 97055c89494STim Huang ret = smu_v13_0_4_set_soft_freq_limited_range(smu, 97155c89494STim Huang SMU_SOCCLK, 97255c89494STim Huang socclk_min, 97355c89494STim Huang socclk_max); 97455c89494STim Huang if (ret) 97555c89494STim Huang return ret; 97655c89494STim Huang } 97755c89494STim Huang 97855c89494STim Huang return ret; 97955c89494STim Huang } 98055c89494STim Huang 98155c89494STim Huang static int smu_v13_0_4_mode2_reset(struct smu_context *smu) 98255c89494STim Huang { 98355c89494STim Huang return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, 98455c89494STim Huang SMU_RESET_MODE_2, NULL); 98555c89494STim Huang } 98655c89494STim Huang 98755c89494STim Huang static int smu_v13_0_4_set_fine_grain_gfx_freq_parameters(struct smu_context *smu) 98855c89494STim Huang { 98955c89494STim Huang DpmClocks_t *clk_table = smu->smu_table.clocks_table; 99055c89494STim Huang 99155c89494STim Huang smu->gfx_default_hard_min_freq = clk_table->MinGfxClk; 99255c89494STim Huang smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk; 99355c89494STim Huang smu->gfx_actual_hard_min_freq = 0; 99455c89494STim Huang smu->gfx_actual_soft_max_freq = 0; 99555c89494STim Huang 99655c89494STim Huang return 0; 99755c89494STim Huang } 99855c89494STim Huang 99955c89494STim Huang static const struct pptable_funcs smu_v13_0_4_ppt_funcs = { 100055c89494STim Huang .check_fw_status = smu_v13_0_check_fw_status, 100155c89494STim Huang .check_fw_version = smu_v13_0_check_fw_version, 100255c89494STim Huang .init_smc_tables = smu_v13_0_4_init_smc_tables, 100355c89494STim Huang .fini_smc_tables = smu_v13_0_4_fini_smc_tables, 100455c89494STim Huang .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, 100555c89494STim Huang .system_features_control = smu_v13_0_4_system_features_control, 100655c89494STim Huang .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, 100755c89494STim Huang .send_smc_msg = smu_cmn_send_smc_msg, 100855c89494STim Huang .dpm_set_vcn_enable = smu_v13_0_set_vcn_enable, 100955c89494STim Huang .dpm_set_jpeg_enable = smu_v13_0_set_jpeg_enable, 101055c89494STim Huang .set_default_dpm_table = smu_v13_0_set_default_dpm_tables, 101155c89494STim Huang .read_sensor = smu_v13_0_4_read_sensor, 101255c89494STim Huang .is_dpm_running = smu_v13_0_4_is_dpm_running, 101355c89494STim Huang .set_watermarks_table = smu_v13_0_4_set_watermarks_table, 101455c89494STim Huang .get_gpu_metrics = smu_v13_0_4_get_gpu_metrics, 101555c89494STim Huang .get_enabled_mask = smu_cmn_get_enabled_mask, 101655c89494STim Huang .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, 101755c89494STim Huang .set_driver_table_location = smu_v13_0_set_driver_table_location, 101855c89494STim Huang .gfx_off_control = smu_v13_0_gfx_off_control, 101955c89494STim Huang .mode2_reset = smu_v13_0_4_mode2_reset, 102055c89494STim Huang .get_dpm_ultimate_freq = smu_v13_0_4_get_dpm_ultimate_freq, 102155c89494STim Huang .od_edit_dpm_table = smu_v13_0_od_edit_dpm_table, 102255c89494STim Huang .print_clk_levels = smu_v13_0_4_print_clk_levels, 102355c89494STim Huang .force_clk_levels = smu_v13_0_4_force_clk_levels, 102455c89494STim Huang .set_performance_level = smu_v13_0_4_set_performance_level, 102555c89494STim Huang .set_fine_grain_gfx_freq_parameters = smu_v13_0_4_set_fine_grain_gfx_freq_parameters, 10267101ab97SHuang Rui .set_gfx_power_up_by_imu = smu_v13_0_set_gfx_power_up_by_imu, 102755c89494STim Huang }; 102855c89494STim Huang 102955c89494STim Huang void smu_v13_0_4_set_ppt_funcs(struct smu_context *smu) 103055c89494STim Huang { 1031da1db031SAlex Deucher struct amdgpu_device *adev = smu->adev; 1032da1db031SAlex Deucher 103355c89494STim Huang smu->ppt_funcs = &smu_v13_0_4_ppt_funcs; 103455c89494STim Huang smu->message_map = smu_v13_0_4_message_map; 103555c89494STim Huang smu->feature_map = smu_v13_0_4_feature_mask_map; 103655c89494STim Huang smu->table_map = smu_v13_0_4_table_map; 103755c89494STim Huang smu->is_apu = true; 1038da1db031SAlex Deucher smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); 1039da1db031SAlex Deucher smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); 1040da1db031SAlex Deucher smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); 104155c89494STim Huang } 1042