This is mostly a straightly move to comm place and with built configuration changes. Any point about the idea ? Thanks, Prike > -----Original Message----- > From: amd-gfx <amd-gfx-bounces@xxxxxxxxxxxxxxxxxxxxx> On Behalf Of > Prike Liang > Sent: Thursday, June 27, 2019 6:36 PM > To: amd-gfx@xxxxxxxxxxxxxxxxxxxxx > Cc: Feng, Kenneth <Kenneth.Feng@xxxxxxx>; Liang, Prike > <Prike.Liang@xxxxxxx>; Quan, Evan <Evan.Quan@xxxxxxx>; Huang, Ray > <Ray.Huang@xxxxxxx> > Subject: [PATCH] drm/amd/powerplay:Move powerplay table implement to > pptable centralized management > > centralized manage powerplay table related functions to avoid > various products mess up root placement of powerplay. > > Change-Id: I3d23021ccb5ef5fd7ffe896a64581876d3409d5b > Signed-off-by: Prike Liang <Prike.Liang@xxxxxxx> > --- > drivers/gpu/drm/amd/powerplay/Makefile | 7 +- > drivers/gpu/drm/amd/powerplay/navi10_ppt.c | 1514 --------- > drivers/gpu/drm/amd/powerplay/navi10_ppt.h | 28 - > drivers/gpu/drm/amd/powerplay/pptable/Makefile | 30 + > drivers/gpu/drm/amd/powerplay/pptable/navi10_ppt.c | 1514 +++++++++ > drivers/gpu/drm/amd/powerplay/pptable/navi10_ppt.h | 28 + > drivers/gpu/drm/amd/powerplay/pptable/vega20_ppt.c | 3302 > ++++++++++++++++++++ > drivers/gpu/drm/amd/powerplay/pptable/vega20_ppt.h | 179 ++ > drivers/gpu/drm/amd/powerplay/vega20_ppt.c | 3302 -------------------- > drivers/gpu/drm/amd/powerplay/vega20_ppt.h | 179 -- > 10 files changed, 5057 insertions(+), 5026 deletions(-) > delete mode 100644 drivers/gpu/drm/amd/powerplay/navi10_ppt.c > delete mode 100644 drivers/gpu/drm/amd/powerplay/navi10_ppt.h > create mode 100644 drivers/gpu/drm/amd/powerplay/pptable/Makefile > create mode 100644 > drivers/gpu/drm/amd/powerplay/pptable/navi10_ppt.c > create mode 100644 > drivers/gpu/drm/amd/powerplay/pptable/navi10_ppt.h > create mode 100644 > drivers/gpu/drm/amd/powerplay/pptable/vega20_ppt.c > create mode 100644 > drivers/gpu/drm/amd/powerplay/pptable/vega20_ppt.h > delete mode 100644 drivers/gpu/drm/amd/powerplay/vega20_ppt.c > delete mode 100644 drivers/gpu/drm/amd/powerplay/vega20_ppt.h > > diff --git a/drivers/gpu/drm/amd/powerplay/Makefile > b/drivers/gpu/drm/amd/powerplay/Makefile > index 727c5cf..c273c25 100644 > --- a/drivers/gpu/drm/amd/powerplay/Makefile > +++ b/drivers/gpu/drm/amd/powerplay/Makefile > @@ -25,17 +25,18 @@ subdir-ccflags-y += \ > -I$(FULL_AMD_PATH)/include/asic_reg \ > -I$(FULL_AMD_PATH)/include \ > -I$(FULL_AMD_PATH)/powerplay/smumgr\ > - -I$(FULL_AMD_PATH)/powerplay/hwmgr > + -I$(FULL_AMD_PATH)/powerplay/hwmgr \ > + -I$(FULL_AMD_PATH)/powerplay/pptable > > AMD_PP_PATH = ../powerplay > > -PP_LIBS = smumgr hwmgr > +PP_LIBS = smumgr hwmgr pptable > > AMD_POWERPLAY = $(addsuffix /Makefile,$(addprefix > $(FULL_AMD_PATH)/powerplay/,$(PP_LIBS))) > > include $(AMD_POWERPLAY) > > -POWER_MGR = amd_powerplay.o amdgpu_smu.o smu_v11_0.o > vega20_ppt.o navi10_ppt.o > +POWER_MGR = amd_powerplay.o amdgpu_smu.o smu_v11_0.o > > AMD_PP_POWER = $(addprefix $(AMD_PP_PATH)/,$(POWER_MGR)) > > diff --git a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c > b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c > deleted file mode 100644 > index 99566de..0000000 > --- a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c > +++ /dev/null > @@ -1,1514 +0,0 @@ > -/* > - * Copyright 2019 Advanced Micro Devices, Inc. > - * > - * Permission is hereby granted, free of charge, to any person obtaining a > - * copy of this software and associated documentation files (the "Software"), > - * to deal in the Software without restriction, including without limitation > - * the rights to use, copy, modify, merge, publish, distribute, sublicense, > - * and/or sell copies of the Software, and to permit persons to whom the > - * Software is furnished to do so, subject to the following conditions: > - * > - * The above copyright notice and this permission notice shall be included in > - * all copies or substantial portions of the Software. > - * > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS OR > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO > EVENT SHALL > - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, > DAMAGES OR > - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR > OTHERWISE, > - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR > THE USE OR > - * OTHER DEALINGS IN THE SOFTWARE. > - * > - */ > - > -#include "pp_debug.h" > -#include <linux/firmware.h> > -#include "amdgpu.h" > -#include "amdgpu_smu.h" > -#include "atomfirmware.h" > -#include "amdgpu_atomfirmware.h" > -#include "smu_v11_0.h" > -#include "smu11_driver_if_navi10.h" > -#include "soc15_common.h" > -#include "atom.h" > -#include "navi10_ppt.h" > -#include "smu_v11_0_pptable.h" > -#include "smu_v11_0_ppsmc.h" > - > -#include "asic_reg/mp/mp_11_0_sh_mask.h" > - > -#define FEATURE_MASK(feature) (1ULL << feature) > -#define SMC_DPM_FEATURE ( \ > - FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \ > - FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ > - FEATURE_MASK(FEATURE_DPM_GFX_PACE_BIT) | \ > - FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ > - FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ > - FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) | \ > - FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ > - FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT)) > - > -#define MSG_MAP(msg, index) \ > - [SMU_MSG_##msg] = index > - > -static int navi10_message_map[SMU_MSG_MAX_COUNT] = { > - MSG_MAP(TestMessage, > PPSMC_MSG_TestMessage), > - MSG_MAP(GetSmuVersion, > PPSMC_MSG_GetSmuVersion), > - MSG_MAP(GetDriverIfVersion, > PPSMC_MSG_GetDriverIfVersion), > - MSG_MAP(SetAllowedFeaturesMaskLow, > PPSMC_MSG_SetAllowedFeaturesMaskLow), > - MSG_MAP(SetAllowedFeaturesMaskHigh, > PPSMC_MSG_SetAllowedFeaturesMaskHigh), > - MSG_MAP(EnableAllSmuFeatures, > PPSMC_MSG_EnableAllSmuFeatures), > - MSG_MAP(DisableAllSmuFeatures, > PPSMC_MSG_DisableAllSmuFeatures), > - MSG_MAP(EnableSmuFeaturesLow, > PPSMC_MSG_EnableSmuFeaturesLow), > - MSG_MAP(EnableSmuFeaturesHigh, > PPSMC_MSG_EnableSmuFeaturesHigh), > - MSG_MAP(DisableSmuFeaturesLow, > PPSMC_MSG_DisableSmuFeaturesLow), > - MSG_MAP(DisableSmuFeaturesHigh, > PPSMC_MSG_DisableSmuFeaturesHigh), > - MSG_MAP(GetEnabledSmuFeaturesLow, > PPSMC_MSG_GetEnabledSmuFeaturesLow), > - MSG_MAP(GetEnabledSmuFeaturesHigh, > PPSMC_MSG_GetEnabledSmuFeaturesHigh), > - MSG_MAP(SetWorkloadMask, > PPSMC_MSG_SetWorkloadMask), > - MSG_MAP(SetPptLimit, > PPSMC_MSG_SetPptLimit), > - MSG_MAP(SetDriverDramAddrHigh, > PPSMC_MSG_SetDriverDramAddrHigh), > - MSG_MAP(SetDriverDramAddrLow, > PPSMC_MSG_SetDriverDramAddrLow), > - MSG_MAP(SetToolsDramAddrHigh, > PPSMC_MSG_SetToolsDramAddrHigh), > - MSG_MAP(SetToolsDramAddrLow, > PPSMC_MSG_SetToolsDramAddrLow), > - MSG_MAP(TransferTableSmu2Dram, > PPSMC_MSG_TransferTableSmu2Dram), > - MSG_MAP(TransferTableDram2Smu, > PPSMC_MSG_TransferTableDram2Smu), > - MSG_MAP(UseDefaultPPTable, > PPSMC_MSG_UseDefaultPPTable), > - MSG_MAP(UseBackupPPTable, > PPSMC_MSG_UseBackupPPTable), > - MSG_MAP(RunBtc, > PPSMC_MSG_RunBtc), > - MSG_MAP(EnterBaco, PPSMC_MSG_EnterBaco), > - MSG_MAP(SetSoftMinByFreq, > PPSMC_MSG_SetSoftMinByFreq), > - MSG_MAP(SetSoftMaxByFreq, > PPSMC_MSG_SetSoftMaxByFreq), > - MSG_MAP(SetHardMinByFreq, > PPSMC_MSG_SetHardMinByFreq), > - MSG_MAP(SetHardMaxByFreq, > PPSMC_MSG_SetHardMaxByFreq), > - MSG_MAP(GetMinDpmFreq, > PPSMC_MSG_GetMinDpmFreq), > - MSG_MAP(GetMaxDpmFreq, > PPSMC_MSG_GetMaxDpmFreq), > - MSG_MAP(GetDpmFreqByIndex, > PPSMC_MSG_GetDpmFreqByIndex), > - MSG_MAP(SetMemoryChannelConfig, > PPSMC_MSG_SetMemoryChannelConfig), > - MSG_MAP(SetGeminiMode, > PPSMC_MSG_SetGeminiMode), > - MSG_MAP(SetGeminiApertureHigh, > PPSMC_MSG_SetGeminiApertureHigh), > - MSG_MAP(SetGeminiApertureLow, > PPSMC_MSG_SetGeminiApertureLow), > - MSG_MAP(OverridePcieParameters, > PPSMC_MSG_OverridePcieParameters), > - MSG_MAP(SetMinDeepSleepDcefclk, > PPSMC_MSG_SetMinDeepSleepDcefclk), > - MSG_MAP(ReenableAcDcInterrupt, > PPSMC_MSG_ReenableAcDcInterrupt), > - MSG_MAP(NotifyPowerSource, > PPSMC_MSG_NotifyPowerSource), > - MSG_MAP(SetUclkFastSwitch, > PPSMC_MSG_SetUclkFastSwitch), > - MSG_MAP(SetVideoFps, > PPSMC_MSG_SetVideoFps), > - MSG_MAP(PrepareMp1ForUnload, > PPSMC_MSG_PrepareMp1ForUnload), > - MSG_MAP(DramLogSetDramAddrHigh, > PPSMC_MSG_DramLogSetDramAddrHigh), > - MSG_MAP(DramLogSetDramAddrLow, > PPSMC_MSG_DramLogSetDramAddrLow), > - MSG_MAP(DramLogSetDramSize, > PPSMC_MSG_DramLogSetDramSize), > - MSG_MAP(ConfigureGfxDidt, > PPSMC_MSG_ConfigureGfxDidt), > - MSG_MAP(NumOfDisplays, > PPSMC_MSG_NumOfDisplays), > - MSG_MAP(SetSystemVirtualDramAddrHigh, > PPSMC_MSG_SetSystemVirtualDramAddrHigh), > - MSG_MAP(SetSystemVirtualDramAddrLow, > PPSMC_MSG_SetSystemVirtualDramAddrLow), > - MSG_MAP(AllowGfxOff, > PPSMC_MSG_AllowGfxOff), > - MSG_MAP(DisallowGfxOff, > PPSMC_MSG_DisallowGfxOff), > - MSG_MAP(GetPptLimit, > PPSMC_MSG_GetPptLimit), > - MSG_MAP(GetDcModeMaxDpmFreq, > PPSMC_MSG_GetDcModeMaxDpmFreq), > - MSG_MAP(GetDebugData, > PPSMC_MSG_GetDebugData), > - MSG_MAP(ExitBaco, PPSMC_MSG_ExitBaco), > - MSG_MAP(PrepareMp1ForReset, > PPSMC_MSG_PrepareMp1ForReset), > - MSG_MAP(PrepareMp1ForShutdown, > PPSMC_MSG_PrepareMp1ForShutdown), > - MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn), > - MSG_MAP(PowerDownVcn, > PPSMC_MSG_PowerDownVcn), > - MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg), > - MSG_MAP(PowerDownJpeg, > PPSMC_MSG_PowerDownJpeg), > - MSG_MAP(BacoAudioD3PME, > PPSMC_MSG_BacoAudioD3PME), > -}; > - > -static int navi10_clk_map[SMU_CLK_COUNT] = { > - CLK_MAP(GFXCLK, PPCLK_GFXCLK), > - CLK_MAP(SCLK, PPCLK_GFXCLK), > - CLK_MAP(SOCCLK, PPCLK_SOCCLK), > - CLK_MAP(FCLK, PPCLK_SOCCLK), > - CLK_MAP(UCLK, PPCLK_UCLK), > - CLK_MAP(MCLK, PPCLK_UCLK), > - CLK_MAP(DCLK, PPCLK_DCLK), > - CLK_MAP(VCLK, PPCLK_VCLK), > - CLK_MAP(DCEFCLK, PPCLK_DCEFCLK), > - CLK_MAP(DISPCLK, PPCLK_DISPCLK), > - CLK_MAP(PIXCLK, PPCLK_PIXCLK), > - CLK_MAP(PHYCLK, PPCLK_PHYCLK), > -}; > - > -static int navi10_feature_mask_map[SMU_FEATURE_COUNT] = { > - FEA_MAP(DPM_PREFETCHER), > - FEA_MAP(DPM_GFXCLK), > - FEA_MAP(DPM_GFX_PACE), > - FEA_MAP(DPM_UCLK), > - FEA_MAP(DPM_SOCCLK), > - FEA_MAP(DPM_MP0CLK), > - FEA_MAP(DPM_LINK), > - FEA_MAP(DPM_DCEFCLK), > - FEA_MAP(MEM_VDDCI_SCALING), > - FEA_MAP(MEM_MVDD_SCALING), > - FEA_MAP(DS_GFXCLK), > - FEA_MAP(DS_SOCCLK), > - FEA_MAP(DS_LCLK), > - FEA_MAP(DS_DCEFCLK), > - FEA_MAP(DS_UCLK), > - FEA_MAP(GFX_ULV), > - FEA_MAP(FW_DSTATE), > - FEA_MAP(GFXOFF), > - FEA_MAP(BACO), > - FEA_MAP(VCN_PG), > - FEA_MAP(JPEG_PG), > - FEA_MAP(USB_PG), > - FEA_MAP(RSMU_SMN_CG), > - FEA_MAP(PPT), > - FEA_MAP(TDC), > - FEA_MAP(GFX_EDC), > - FEA_MAP(APCC_PLUS), > - FEA_MAP(GTHR), > - FEA_MAP(ACDC), > - FEA_MAP(VR0HOT), > - FEA_MAP(VR1HOT), > - FEA_MAP(FW_CTF), > - FEA_MAP(FAN_CONTROL), > - FEA_MAP(THERMAL), > - FEA_MAP(GFX_DCS), > - FEA_MAP(RM), > - FEA_MAP(LED_DISPLAY), > - FEA_MAP(GFX_SS), > - FEA_MAP(OUT_OF_BAND_MONITOR), > - FEA_MAP(TEMP_DEPENDENT_VMIN), > - FEA_MAP(MMHUB_PG), > - FEA_MAP(ATHUB_PG), > -}; > - > -static int navi10_table_map[SMU_TABLE_COUNT] = { > - TAB_MAP(PPTABLE), > - TAB_MAP(WATERMARKS), > - TAB_MAP(AVFS), > - TAB_MAP(AVFS_PSM_DEBUG), > - TAB_MAP(AVFS_FUSE_OVERRIDE), > - TAB_MAP(PMSTATUSLOG), > - TAB_MAP(SMU_METRICS), > - TAB_MAP(DRIVER_SMU_CONFIG), > - TAB_MAP(ACTIVITY_MONITOR_COEFF), > - TAB_MAP(OVERDRIVE), > - TAB_MAP(I2C_COMMANDS), > - TAB_MAP(PACE), > -}; > - > -static int navi10_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { > - PWR_MAP(AC), > - PWR_MAP(DC), > -}; > - > -static int navi10_workload_map[] = { > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT, > WORKLOAD_PPLIB_DEFAULT_BIT), > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D, > WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT), > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING, > WORKLOAD_PPLIB_POWER_SAVING_BIT), > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO, > WORKLOAD_PPLIB_VIDEO_BIT), > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR, > WORKLOAD_PPLIB_VR_BIT), > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, > WORKLOAD_PPLIB_CUSTOM_BIT), > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, > WORKLOAD_PPLIB_CUSTOM_BIT), > -}; > - > -static int navi10_get_smu_msg_index(struct smu_context *smc, uint32_t > index) > -{ > - int val; > - if (index > SMU_MSG_MAX_COUNT) > - return -EINVAL; > - > - val = navi10_message_map[index]; > - if (val > PPSMC_Message_Count) > - return -EINVAL; > - > - return val; > -} > - > -static int navi10_get_smu_clk_index(struct smu_context *smc, uint32_t > index) > -{ > - int val; > - if (index >= SMU_CLK_COUNT) > - return -EINVAL; > - > - val = navi10_clk_map[index]; > - if (val >= PPCLK_COUNT) > - return -EINVAL; > - > - return val; > -} > - > -static int navi10_get_smu_feature_index(struct smu_context *smc, > uint32_t index) > -{ > - int val; > - if (index >= SMU_FEATURE_COUNT) > - return -EINVAL; > - > - val = navi10_feature_mask_map[index]; > - if (val > 64) > - return -EINVAL; > - > - return val; > -} > - > -static int navi10_get_smu_table_index(struct smu_context *smc, uint32_t > index) > -{ > - int val; > - if (index >= SMU_TABLE_COUNT) > - return -EINVAL; > - > - val = navi10_table_map[index]; > - if (val >= TABLE_COUNT) > - return -EINVAL; > - > - return val; > -} > - > -static int navi10_get_pwr_src_index(struct smu_context *smc, uint32_t > index) > -{ > - int val; > - if (index >= SMU_POWER_SOURCE_COUNT) > - return -EINVAL; > - > - val = navi10_pwr_src_map[index]; > - if (val >= POWER_SOURCE_COUNT) > - return -EINVAL; > - > - return val; > -} > - > - > -static int navi10_get_workload_type(struct smu_context *smu, enum > PP_SMC_POWER_PROFILE profile) > -{ > - int val; > - if (profile > PP_SMC_POWER_PROFILE_CUSTOM) > - return -EINVAL; > - > - val = navi10_workload_map[profile]; > - > - return val; > -} > - > -static bool is_asic_secure(struct smu_context *smu) > -{ > - struct amdgpu_device *adev = smu->adev; > - bool is_secure = true; > - uint32_t mp0_fw_intf; > - > - mp0_fw_intf = RREG32_PCIE(MP0_Public | > - (smnMP0_FW_INTF & 0xffffffff)); > - > - if (!(mp0_fw_intf & (1 << 19))) > - is_secure = false; > - > - return is_secure; > -} > - > -static int > -navi10_get_allowed_feature_mask(struct smu_context *smu, > - uint32_t *feature_mask, uint32_t num) > -{ > - struct amdgpu_device *adev = smu->adev; > - > - if (num > 2) > - return -EINVAL; > - > - memset(feature_mask, 0, sizeof(uint32_t) * num); > - > - *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) > - | > FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) > - | > FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) > - | > FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) > - | FEATURE_MASK(FEATURE_DPM_LINK_BIT) > - | FEATURE_MASK(FEATURE_GFX_ULV_BIT) > - | > FEATURE_MASK(FEATURE_RSMU_SMN_CG_BIT) > - | FEATURE_MASK(FEATURE_DS_SOCCLK_BIT) > - | FEATURE_MASK(FEATURE_PPT_BIT) > - | FEATURE_MASK(FEATURE_TDC_BIT) > - | FEATURE_MASK(FEATURE_GFX_EDC_BIT) > - | FEATURE_MASK(FEATURE_VR0HOT_BIT) > - | > FEATURE_MASK(FEATURE_FAN_CONTROL_BIT) > - | FEATURE_MASK(FEATURE_THERMAL_BIT) > - | > FEATURE_MASK(FEATURE_LED_DISPLAY_BIT) > - | > FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT) > - | FEATURE_MASK(FEATURE_DS_GFXCLK_BIT) > - | > FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT) > - | > FEATURE_MASK(FEATURE_FW_DSTATE_BIT) > - | FEATURE_MASK(FEATURE_BACO_BIT) > - | FEATURE_MASK(FEATURE_ACDC_BIT); > - > - if (adev->pm.pp_feature & PP_MCLK_DPM_MASK) > - *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_DPM_UCLK_BIT) > - | > FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT) > - | > FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT); > - > - if (adev->pm.pp_feature & PP_GFXOFF_MASK) { > - *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_GFX_SS_BIT) > - | FEATURE_MASK(FEATURE_GFXOFF_BIT); > - /* TODO: remove it once fw fix the bug */ > - *(uint64_t *)feature_mask &= > ~FEATURE_MASK(FEATURE_FW_DSTATE_BIT); > - } > - > - if (smu->adev->pg_flags & AMD_PG_SUPPORT_MMHUB) > - *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_MMHUB_PG_BIT); > - > - if (smu->adev->pg_flags & AMD_PG_SUPPORT_ATHUB) > - *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_ATHUB_PG_BIT); > - > - if (smu->adev->pg_flags & AMD_PG_SUPPORT_VCN) > - *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_VCN_PG_BIT); > - > - /* disable DPM UCLK and DS SOCCLK on navi10 A0 secure board */ > - if (is_asic_secure(smu)) { > - /* only for navi10 A0 */ > - if ((adev->asic_type == CHIP_NAVI10) && > - (adev->rev_id == 0)) { > - *(uint64_t *)feature_mask &= > - > ~(FEATURE_MASK(FEATURE_DPM_UCLK_BIT) > - | > FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT) > - | > FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT)); > - *(uint64_t *)feature_mask &= > - > ~FEATURE_MASK(FEATURE_DS_SOCCLK_BIT); > - } > - } > - > - return 0; > -} > - > -static int navi10_check_powerplay_table(struct smu_context *smu) > -{ > - return 0; > -} > - > -static int navi10_append_powerplay_table(struct smu_context *smu) > -{ > - struct amdgpu_device *adev = smu->adev; > - struct smu_table_context *table_context = &smu->smu_table; > - PPTable_t *smc_pptable = table_context->driver_pptable; > - struct atom_smc_dpm_info_v4_5 *smc_dpm_table; > - int index, ret; > - > - index = > get_index_into_master_table(atom_master_list_of_data_tables_v2_1, > - smc_dpm_info); > - > - ret = smu_get_atom_data_table(smu, index, NULL, NULL, NULL, > - (uint8_t **)&smc_dpm_table); > - if (ret) > - return ret; > - > - memcpy(smc_pptable->I2cControllers, smc_dpm_table- > >I2cControllers, > - sizeof(I2cControllerConfig_t) * NUM_I2C_CONTROLLERS); > - > - /* SVI2 Board Parameters */ > - smc_pptable->MaxVoltageStepGfx = smc_dpm_table- > >MaxVoltageStepGfx; > - smc_pptable->MaxVoltageStepSoc = smc_dpm_table- > >MaxVoltageStepSoc; > - smc_pptable->VddGfxVrMapping = smc_dpm_table- > >VddGfxVrMapping; > - smc_pptable->VddSocVrMapping = smc_dpm_table- > >VddSocVrMapping; > - smc_pptable->VddMem0VrMapping = smc_dpm_table- > >VddMem0VrMapping; > - smc_pptable->VddMem1VrMapping = smc_dpm_table- > >VddMem1VrMapping; > - smc_pptable->GfxUlvPhaseSheddingMask = smc_dpm_table- > >GfxUlvPhaseSheddingMask; > - smc_pptable->SocUlvPhaseSheddingMask = smc_dpm_table- > >SocUlvPhaseSheddingMask; > - smc_pptable->ExternalSensorPresent = smc_dpm_table- > >ExternalSensorPresent; > - smc_pptable->Padding8_V = smc_dpm_table->Padding8_V; > - > - /* Telemetry Settings */ > - smc_pptable->GfxMaxCurrent = smc_dpm_table->GfxMaxCurrent; > - smc_pptable->GfxOffset = smc_dpm_table->GfxOffset; > - smc_pptable->Padding_TelemetryGfx = smc_dpm_table- > >Padding_TelemetryGfx; > - smc_pptable->SocMaxCurrent = smc_dpm_table->SocMaxCurrent; > - smc_pptable->SocOffset = smc_dpm_table->SocOffset; > - smc_pptable->Padding_TelemetrySoc = smc_dpm_table- > >Padding_TelemetrySoc; > - smc_pptable->Mem0MaxCurrent = smc_dpm_table- > >Mem0MaxCurrent; > - smc_pptable->Mem0Offset = smc_dpm_table->Mem0Offset; > - smc_pptable->Padding_TelemetryMem0 = smc_dpm_table- > >Padding_TelemetryMem0; > - smc_pptable->Mem1MaxCurrent = smc_dpm_table- > >Mem1MaxCurrent; > - smc_pptable->Mem1Offset = smc_dpm_table->Mem1Offset; > - smc_pptable->Padding_TelemetryMem1 = smc_dpm_table- > >Padding_TelemetryMem1; > - > - /* GPIO Settings */ > - smc_pptable->AcDcGpio = smc_dpm_table->AcDcGpio; > - smc_pptable->AcDcPolarity = smc_dpm_table->AcDcPolarity; > - smc_pptable->VR0HotGpio = smc_dpm_table->VR0HotGpio; > - smc_pptable->VR0HotPolarity = smc_dpm_table->VR0HotPolarity; > - smc_pptable->VR1HotGpio = smc_dpm_table->VR1HotGpio; > - smc_pptable->VR1HotPolarity = smc_dpm_table->VR1HotPolarity; > - smc_pptable->GthrGpio = smc_dpm_table->GthrGpio; > - smc_pptable->GthrPolarity = smc_dpm_table->GthrPolarity; > - > - /* LED Display Settings */ > - smc_pptable->LedPin0 = smc_dpm_table->LedPin0; > - smc_pptable->LedPin1 = smc_dpm_table->LedPin1; > - smc_pptable->LedPin2 = smc_dpm_table->LedPin2; > - smc_pptable->padding8_4 = smc_dpm_table->padding8_4; > - > - /* GFXCLK PLL Spread Spectrum */ > - smc_pptable->PllGfxclkSpreadEnabled = smc_dpm_table- > >PllGfxclkSpreadEnabled; > - smc_pptable->PllGfxclkSpreadPercent = smc_dpm_table- > >PllGfxclkSpreadPercent; > - smc_pptable->PllGfxclkSpreadFreq = smc_dpm_table- > >PllGfxclkSpreadFreq; > - > - /* GFXCLK DFLL Spread Spectrum */ > - smc_pptable->DfllGfxclkSpreadEnabled = smc_dpm_table- > >DfllGfxclkSpreadEnabled; > - smc_pptable->DfllGfxclkSpreadPercent = smc_dpm_table- > >DfllGfxclkSpreadPercent; > - smc_pptable->DfllGfxclkSpreadFreq = smc_dpm_table- > >DfllGfxclkSpreadFreq; > - > - /* UCLK Spread Spectrum */ > - smc_pptable->UclkSpreadEnabled = smc_dpm_table- > >UclkSpreadEnabled; > - smc_pptable->UclkSpreadPercent = smc_dpm_table- > >UclkSpreadPercent; > - smc_pptable->UclkSpreadFreq = smc_dpm_table->UclkSpreadFreq; > - > - /* SOCCLK Spread Spectrum */ > - smc_pptable->SoclkSpreadEnabled = smc_dpm_table- > >SoclkSpreadEnabled; > - smc_pptable->SocclkSpreadPercent = smc_dpm_table- > >SocclkSpreadPercent; > - smc_pptable->SocclkSpreadFreq = smc_dpm_table- > >SocclkSpreadFreq; > - > - /* Total board power */ > - smc_pptable->TotalBoardPower = smc_dpm_table- > >TotalBoardPower; > - smc_pptable->BoardPadding = smc_dpm_table->BoardPadding; > - > - /* Mvdd Svi2 Div Ratio Setting */ > - smc_pptable->MvddRatio = smc_dpm_table->MvddRatio; > - > - if (adev->pm.pp_feature & PP_GFXOFF_MASK) { > - *(uint64_t *)smc_pptable->FeaturesToRun |= > FEATURE_MASK(FEATURE_GFX_SS_BIT) > - | > FEATURE_MASK(FEATURE_GFXOFF_BIT); > - > - /* TODO: remove it once SMU fw fix it */ > - smc_pptable->DebugOverrides |= > DPM_OVERRIDE_DISABLE_DFLL_PLL_SHUTDOWN; > - } > - > - return 0; > -} > - > -static int navi10_store_powerplay_table(struct smu_context *smu) > -{ > - struct smu_11_0_powerplay_table *powerplay_table = NULL; > - struct smu_table_context *table_context = &smu->smu_table; > - > - if (!table_context->power_play_table) > - return -EINVAL; > - > - powerplay_table = table_context->power_play_table; > - > - memcpy(table_context->driver_pptable, &powerplay_table- > >smc_pptable, > - sizeof(PPTable_t)); > - > - table_context->thermal_controller_type = powerplay_table- > >thermal_controller_type; > - > - return 0; > -} > - > -static int navi10_tables_init(struct smu_context *smu, struct smu_table > *tables) > -{ > - SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), > - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > - SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, > sizeof(Watermarks_t), > - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > - SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, > sizeof(SmuMetrics_t), > - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > - SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, > sizeof(OverDriveTable_t), > - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > - SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, > SMU11_TOOL_SIZE, > - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > - SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF, > - sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE, > - AMDGPU_GEM_DOMAIN_VRAM); > - > - return 0; > -} > - > -static int navi10_allocate_dpm_context(struct smu_context *smu) > -{ > - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > - > - if (smu_dpm->dpm_context) > - return -EINVAL; > - > - smu_dpm->dpm_context = kzalloc(sizeof(struct > smu_11_0_dpm_context), > - GFP_KERNEL); > - if (!smu_dpm->dpm_context) > - return -ENOMEM; > - > - smu_dpm->dpm_context_size = sizeof(struct > smu_11_0_dpm_context); > - > - return 0; > -} > - > -static int navi10_set_default_dpm_table(struct smu_context *smu) > -{ > - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > - struct smu_table_context *table_context = &smu->smu_table; > - struct smu_11_0_dpm_context *dpm_context = smu_dpm- > >dpm_context; > - PPTable_t *driver_ppt = NULL; > - > - driver_ppt = table_context->driver_pptable; > - > - dpm_context->dpm_tables.soc_table.min = driver_ppt- > >FreqTableSocclk[0]; > - dpm_context->dpm_tables.soc_table.max = driver_ppt- > >FreqTableSocclk[NUM_SOCCLK_DPM_LEVELS - 1]; > - > - dpm_context->dpm_tables.gfx_table.min = driver_ppt- > >FreqTableGfx[0]; > - dpm_context->dpm_tables.gfx_table.max = driver_ppt- > >FreqTableGfx[NUM_GFXCLK_DPM_LEVELS - 1]; > - > - dpm_context->dpm_tables.uclk_table.min = driver_ppt- > >FreqTableUclk[0]; > - dpm_context->dpm_tables.uclk_table.max = driver_ppt- > >FreqTableUclk[NUM_UCLK_DPM_LEVELS - 1]; > - > - dpm_context->dpm_tables.vclk_table.min = driver_ppt- > >FreqTableVclk[0]; > - dpm_context->dpm_tables.vclk_table.max = driver_ppt- > >FreqTableVclk[NUM_VCLK_DPM_LEVELS - 1]; > - > - dpm_context->dpm_tables.dclk_table.min = driver_ppt- > >FreqTableDclk[0]; > - dpm_context->dpm_tables.dclk_table.max = driver_ppt- > >FreqTableDclk[NUM_DCLK_DPM_LEVELS - 1]; > - > - dpm_context->dpm_tables.dcef_table.min = driver_ppt- > >FreqTableDcefclk[0]; > - dpm_context->dpm_tables.dcef_table.max = driver_ppt- > >FreqTableDcefclk[NUM_DCEFCLK_DPM_LEVELS - 1]; > - > - dpm_context->dpm_tables.pixel_table.min = driver_ppt- > >FreqTablePixclk[0]; > - dpm_context->dpm_tables.pixel_table.max = driver_ppt- > >FreqTablePixclk[NUM_PIXCLK_DPM_LEVELS - 1]; > - > - dpm_context->dpm_tables.display_table.min = driver_ppt- > >FreqTableDispclk[0]; > - dpm_context->dpm_tables.display_table.max = driver_ppt- > >FreqTableDispclk[NUM_DISPCLK_DPM_LEVELS - 1]; > - > - dpm_context->dpm_tables.phy_table.min = driver_ppt- > >FreqTablePhyclk[0]; > - dpm_context->dpm_tables.phy_table.max = driver_ppt- > >FreqTablePhyclk[NUM_PHYCLK_DPM_LEVELS - 1]; > - > - return 0; > -} > - > -static int navi10_dpm_set_uvd_enable(struct smu_context *smu, bool > enable) > -{ > - int ret = 0; > - struct smu_power_context *smu_power = &smu->smu_power; > - struct smu_power_gate *power_gate = &smu_power->power_gate; > - > - if (enable && power_gate->uvd_gated) { > - if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_UVD_BIT)) { > - ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_PowerUpVcn, 1); > - if (ret) > - return ret; > - } > - power_gate->uvd_gated = false; > - } else { > - if (!enable && !power_gate->uvd_gated) { > - if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_UVD_BIT)) { > - ret = smu_send_smc_msg(smu, > SMU_MSG_PowerDownVcn); > - if (ret) > - return ret; > - } > - power_gate->uvd_gated = true; > - } > - } > - > - return 0; > -} > - > -static int navi10_get_current_clk_freq_by_table(struct smu_context *smu, > - enum smu_clk_type clk_type, > - uint32_t *value) > -{ > - static SmuMetrics_t metrics = {0}; > - int ret = 0, clk_id = 0; > - > - if (!value) > - return -EINVAL; > - > - ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, (void > *)&metrics, false); > - if (ret) > - return ret; > - > - clk_id = smu_clk_get_index(smu, clk_type); > - if (clk_id < 0) > - return clk_id; > - > - *value = metrics.CurrClock[clk_id]; > - > - return ret; > -} > - > -static int navi10_print_clk_levels(struct smu_context *smu, > - enum smu_clk_type clk_type, char *buf) > -{ > - int i, size = 0, ret = 0; > - uint32_t cur_value = 0, value = 0, count = 0; > - > - switch (clk_type) { > - case SMU_GFXCLK: > - case SMU_SCLK: > - case SMU_SOCCLK: > - case SMU_MCLK: > - case SMU_UCLK: > - case SMU_FCLK: > - case SMU_DCEFCLK: > - ret = smu_get_current_clk_freq(smu, clk_type, &cur_value); > - if (ret) > - return size; > - /* 10KHz -> MHz */ > - cur_value = cur_value / 100; > - > - size += sprintf(buf, "current clk: %uMhz\n", cur_value); > - > - ret = smu_get_dpm_level_count(smu, clk_type, &count); > - if (ret) > - return size; > - > - for (i = 0; i < count; i++) { > - ret = smu_get_dpm_freq_by_index(smu, clk_type, i, > &value); > - if (ret) > - return size; > - > - size += sprintf(buf + size, "%d: %uMhz %s\n", i, value, > - cur_value == value ? "*" : ""); > - } > - break; > - default: > - break; > - } > - > - return size; > -} > - > -static int navi10_force_clk_levels(struct smu_context *smu, > - enum smu_clk_type clk_type, uint32_t > mask) > -{ > - > - int ret = 0, size = 0; > - uint32_t soft_min_level = 0, soft_max_level = 0, min_freq = 0, > max_freq = 0; > - > - soft_min_level = mask ? (ffs(mask) - 1) : 0; > - soft_max_level = mask ? (fls(mask) - 1) : 0; > - > - switch (clk_type) { > - case SMU_GFXCLK: > - case SMU_SCLK: > - case SMU_SOCCLK: > - case SMU_MCLK: > - case SMU_UCLK: > - case SMU_DCEFCLK: > - case SMU_FCLK: > - ret = smu_get_dpm_freq_by_index(smu, clk_type, > soft_min_level, &min_freq); > - if (ret) > - return size; > - > - ret = smu_get_dpm_freq_by_index(smu, clk_type, > soft_max_level, &max_freq); > - if (ret) > - return size; > - > - ret = smu_set_soft_freq_range(smu, clk_type, min_freq, > max_freq); > - if (ret) > - return size; > - break; > - default: > - break; > - } > - > - return size; > -} > - > -static int navi10_populate_umd_state_clk(struct smu_context *smu) > -{ > - int ret = 0; > - uint32_t min_sclk_freq = 0; > - > - ret = smu_get_dpm_freq_range(smu, SMU_SCLK, &min_sclk_freq, > NULL); > - if (ret) > - return ret; > - > - smu->pstate_sclk = min_sclk_freq * 100; > - > - return ret; > -} > - > -static int navi10_get_clock_by_type_with_latency(struct smu_context > *smu, > - enum smu_clk_type > clk_type, > - struct > pp_clock_levels_with_latency *clocks) > -{ > - int ret = 0, i = 0; > - uint32_t level_count = 0, freq = 0; > - > - switch (clk_type) { > - case SMU_GFXCLK: > - case SMU_DCEFCLK: > - case SMU_SOCCLK: > - ret = smu_get_dpm_level_count(smu, clk_type, > &level_count); > - if (ret) > - return ret; > - > - level_count = min(level_count, > (uint32_t)MAX_NUM_CLOCKS); > - clocks->num_levels = level_count; > - > - for (i = 0; i < level_count; i++) { > - ret = smu_get_dpm_freq_by_index(smu, clk_type, i, > &freq); > - if (ret) > - return ret; > - > - clocks->data[i].clocks_in_khz = freq * 1000; > - clocks->data[i].latency_in_us = 0; > - } > - break; > - default: > - break; > - } > - > - return ret; > -} > - > -static int navi10_pre_display_config_changed(struct smu_context *smu) > -{ > - int ret = 0; > - uint32_t max_freq = 0; > - > - ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_NumOfDisplays, 0); > - if (ret) > - return ret; > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) > { > - ret = smu_get_dpm_freq_range(smu, SMU_UCLK, NULL, > &max_freq); > - if (ret) > - return ret; > - ret = smu_set_hard_freq_range(smu, SMU_UCLK, 0, > max_freq); > - if (ret) > - return ret; > - } > - > - return ret; > -} > - > -static int navi10_display_config_changed(struct smu_context *smu) > -{ > - int ret = 0; > - > - if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && > - !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { > - ret = smu_write_watermarks_table(smu); > - if (ret) > - return ret; > - > - smu->watermarks_bitmap |= WATERMARKS_LOADED; > - } > - > - if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && > - smu_feature_is_supported(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT) && > - smu_feature_is_supported(smu, > SMU_FEATURE_DPM_SOCCLK_BIT)) { > - ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_NumOfDisplays, > - smu->display_config- > >num_display); > - if (ret) > - return ret; > - } > - > - return ret; > -} > - > -static int navi10_force_dpm_limit_value(struct smu_context *smu, bool > highest) > -{ > - int ret = 0, i = 0; > - uint32_t min_freq, max_freq, force_freq; > - enum smu_clk_type clk_type; > - > - enum smu_clk_type clks[] = { > - SMU_GFXCLK, > - SMU_MCLK, > - SMU_SOCCLK, > - }; > - > - for (i = 0; i < ARRAY_SIZE(clks); i++) { > - clk_type = clks[i]; > - ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, > &max_freq); > - if (ret) > - return ret; > - > - force_freq = highest ? max_freq : min_freq; > - ret = smu_set_soft_freq_range(smu, clk_type, force_freq, > force_freq); > - if (ret) > - return ret; > - } > - > - return ret; > -} > - > -static int navi10_unforce_dpm_levels(struct smu_context *smu) { > - > - int ret = 0, i = 0; > - uint32_t min_freq, max_freq; > - enum smu_clk_type clk_type; > - > - struct clk_feature_map { > - enum smu_clk_type clk_type; > - uint32_t feature; > - } clk_feature_map[] = { > - {SMU_GFXCLK, SMU_FEATURE_DPM_GFXCLK_BIT}, > - {SMU_MCLK, SMU_FEATURE_DPM_UCLK_BIT}, > - {SMU_SOCCLK, SMU_FEATURE_DPM_SOCCLK_BIT}, > - }; > - > - for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) { > - if (!smu_feature_is_enabled(smu, > clk_feature_map[i].feature)) > - continue; > - > - clk_type = clk_feature_map[i].clk_type; > - > - ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, > &max_freq); > - if (ret) > - return ret; > - > - ret = smu_set_soft_freq_range(smu, clk_type, min_freq, > max_freq); > - if (ret) > - return ret; > - } > - > - return ret; > -} > - > -static int navi10_get_gpu_power(struct smu_context *smu, uint32_t *value) > -{ > - int ret = 0; > - SmuMetrics_t metrics; > - > - if (!value) > - return -EINVAL; > - > - ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, (void > *)&metrics, > - false); > - if (ret) > - return ret; > - > - *value = metrics.CurrSocketPower << 8; > - > - return 0; > -} > - > -static int navi10_get_current_activity_percent(struct smu_context *smu, > - uint32_t *value) > -{ > - int ret = 0; > - SmuMetrics_t metrics; > - > - if (!value) > - return -EINVAL; > - > - msleep(1); > - > - ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, > - (void *)&metrics, false); > - if (ret) > - return ret; > - > - *value = metrics.AverageGfxActivity; > - > - return 0; > -} > - > -static bool navi10_is_dpm_running(struct smu_context *smu) > -{ > - int ret = 0; > - uint32_t feature_mask[2]; > - unsigned long feature_enabled; > - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); > - feature_enabled = (unsigned long)((uint64_t)feature_mask[0] | > - ((uint64_t)feature_mask[1] << 32)); > - return !!(feature_enabled & SMC_DPM_FEATURE); > -} > - > -static int navi10_get_fan_speed(struct smu_context *smu, uint16_t *value) > -{ > - SmuMetrics_t metrics = {0}; > - int ret = 0; > - > - if (!value) > - return -EINVAL; > - > - ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, > - (void *)&metrics, false); > - if (ret) > - return ret; > - > - *value = metrics.CurrFanSpeed; > - > - return ret; > -} > - > -static int navi10_get_fan_speed_percent(struct smu_context *smu, > - uint32_t *speed) > -{ > - int ret = 0; > - uint32_t percent = 0; > - uint16_t current_rpm; > - PPTable_t *pptable = smu->smu_table.driver_pptable; > - > - ret = navi10_get_fan_speed(smu, ¤t_rpm); > - if (ret) > - return ret; > - > - percent = current_rpm * 100 / pptable->FanMaximumRpm; > - *speed = percent > 100 ? 100 : percent; > - > - return ret; > -} > - > -static int navi10_get_power_profile_mode(struct smu_context *smu, char > *buf) > -{ > - DpmActivityMonitorCoeffInt_t activity_monitor; > - uint32_t i, size = 0; > - uint16_t workload_type = 0; > - static const char *profile_name[] = { > - "BOOTUP_DEFAULT", > - "3D_FULL_SCREEN", > - "POWER_SAVING", > - "VIDEO", > - "VR", > - "COMPUTE", > - "CUSTOM"}; > - static const char *title[] = { > - "PROFILE_INDEX(NAME)", > - "CLOCK_TYPE(NAME)", > - "FPS", > - "MinFreqType", > - "MinActiveFreqType", > - "MinActiveFreq", > - "BoosterFreqType", > - "BoosterFreq", > - "PD_Data_limit_c", > - "PD_Data_error_coeff", > - "PD_Data_error_rate_coeff"}; > - int result = 0; > - > - if (!buf) > - return -EINVAL; > - > - size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n", > - title[0], title[1], title[2], title[3], title[4], title[5], > - title[6], title[7], title[8], title[9], title[10]); > - > - for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { > - /* conv PP_SMC_POWER_PROFILE* to > WORKLOAD_PPLIB_*_BIT */ > - workload_type = smu_workload_get_type(smu, i); > - result = smu_update_table(smu, > - > SMU_TABLE_ACTIVITY_MONITOR_COEFF | workload_type << 16, > - (void *)(&activity_monitor), false); > - if (result) { > - pr_err("[%s] Failed to get activity monitor!", > __func__); > - return result; > - } > - > - size += sprintf(buf + size, "%2d %14s%s:\n", > - i, profile_name[i], (i == smu->power_profile_mode) ? > "*" : " "); > - > - size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > - " ", > - 0, > - "GFXCLK", > - activity_monitor.Gfx_FPS, > - activity_monitor.Gfx_MinFreqStep, > - activity_monitor.Gfx_MinActiveFreqType, > - activity_monitor.Gfx_MinActiveFreq, > - activity_monitor.Gfx_BoosterFreqType, > - activity_monitor.Gfx_BoosterFreq, > - activity_monitor.Gfx_PD_Data_limit_c, > - activity_monitor.Gfx_PD_Data_error_coeff, > - activity_monitor.Gfx_PD_Data_error_rate_coeff); > - > - size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > - " ", > - 1, > - "SOCCLK", > - activity_monitor.Soc_FPS, > - activity_monitor.Soc_MinFreqStep, > - activity_monitor.Soc_MinActiveFreqType, > - activity_monitor.Soc_MinActiveFreq, > - activity_monitor.Soc_BoosterFreqType, > - activity_monitor.Soc_BoosterFreq, > - activity_monitor.Soc_PD_Data_limit_c, > - activity_monitor.Soc_PD_Data_error_coeff, > - activity_monitor.Soc_PD_Data_error_rate_coeff); > - > - size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > - " ", > - 2, > - "MEMLK", > - activity_monitor.Mem_FPS, > - activity_monitor.Mem_MinFreqStep, > - activity_monitor.Mem_MinActiveFreqType, > - activity_monitor.Mem_MinActiveFreq, > - activity_monitor.Mem_BoosterFreqType, > - activity_monitor.Mem_BoosterFreq, > - activity_monitor.Mem_PD_Data_limit_c, > - activity_monitor.Mem_PD_Data_error_coeff, > - activity_monitor.Mem_PD_Data_error_rate_coeff); > - } > - > - return size; > -} > - > -static int navi10_set_power_profile_mode(struct smu_context *smu, long > *input, uint32_t size) > -{ > - DpmActivityMonitorCoeffInt_t activity_monitor; > - int workload_type, ret = 0; > - > - smu->power_profile_mode = input[size]; > - > - if (smu->power_profile_mode > > PP_SMC_POWER_PROFILE_CUSTOM) { > - pr_err("Invalid power profile mode %d\n", smu- > >power_profile_mode); > - return -EINVAL; > - } > - > - if (smu->power_profile_mode == > PP_SMC_POWER_PROFILE_CUSTOM) { > - if (size < 0) > - return -EINVAL; > - > - ret = smu_update_table(smu, > - SMU_TABLE_ACTIVITY_MONITOR_COEFF > | WORKLOAD_PPLIB_CUSTOM_BIT << 16, > - (void *)(&activity_monitor), false); > - if (ret) { > - pr_err("[%s] Failed to get activity monitor!", > __func__); > - return ret; > - } > - > - switch (input[0]) { > - case 0: /* Gfxclk */ > - activity_monitor.Gfx_FPS = input[1]; > - activity_monitor.Gfx_MinFreqStep = input[2]; > - activity_monitor.Gfx_MinActiveFreqType = input[3]; > - activity_monitor.Gfx_MinActiveFreq = input[4]; > - activity_monitor.Gfx_BoosterFreqType = input[5]; > - activity_monitor.Gfx_BoosterFreq = input[6]; > - activity_monitor.Gfx_PD_Data_limit_c = input[7]; > - activity_monitor.Gfx_PD_Data_error_coeff = > input[8]; > - activity_monitor.Gfx_PD_Data_error_rate_coeff = > input[9]; > - break; > - case 1: /* Socclk */ > - activity_monitor.Soc_FPS = input[1]; > - activity_monitor.Soc_MinFreqStep = input[2]; > - activity_monitor.Soc_MinActiveFreqType = input[3]; > - activity_monitor.Soc_MinActiveFreq = input[4]; > - activity_monitor.Soc_BoosterFreqType = input[5]; > - activity_monitor.Soc_BoosterFreq = input[6]; > - activity_monitor.Soc_PD_Data_limit_c = input[7]; > - activity_monitor.Soc_PD_Data_error_coeff = > input[8]; > - activity_monitor.Soc_PD_Data_error_rate_coeff = > input[9]; > - break; > - case 2: /* Memlk */ > - activity_monitor.Mem_FPS = input[1]; > - activity_monitor.Mem_MinFreqStep = input[2]; > - activity_monitor.Mem_MinActiveFreqType = > input[3]; > - activity_monitor.Mem_MinActiveFreq = input[4]; > - activity_monitor.Mem_BoosterFreqType = input[5]; > - activity_monitor.Mem_BoosterFreq = input[6]; > - activity_monitor.Mem_PD_Data_limit_c = input[7]; > - activity_monitor.Mem_PD_Data_error_coeff = > input[8]; > - activity_monitor.Mem_PD_Data_error_rate_coeff = > input[9]; > - break; > - } > - > - ret = smu_update_table(smu, > - SMU_TABLE_ACTIVITY_MONITOR_COEFF > | WORKLOAD_PPLIB_CUSTOM_BIT << 16, > - (void *)(&activity_monitor), true); > - if (ret) { > - pr_err("[%s] Failed to set activity monitor!", > __func__); > - return ret; > - } > - } > - > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ > - workload_type = smu_workload_get_type(smu, smu- > >power_profile_mode); > - smu_send_smc_msg_with_param(smu, > SMU_MSG_SetWorkloadMask, > - 1 << workload_type); > - > - return ret; > -} > - > -static int navi10_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) > -{ > - int ret = 0; > - uint32_t level_count = 0; > - > - if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { > - if (sclk_mask) > - *sclk_mask = 0; > - } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { > - if (mclk_mask) > - *mclk_mask = 0; > - } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > - if(sclk_mask) { > - ret = smu_get_dpm_level_count(smu, SMU_SCLK, > &level_count); > - if (ret) > - return ret; > - *sclk_mask = level_count - 1; > - } > - > - if(mclk_mask) { > - ret = smu_get_dpm_level_count(smu, SMU_MCLK, > &level_count); > - if (ret) > - return ret; > - *sclk_mask = level_count - 1; > - } > - > - if(soc_mask) { > - ret = smu_get_dpm_level_count(smu, SMU_SOCCLK, > &level_count); > - if (ret) > - return ret; > - *sclk_mask = level_count - 1; > - } > - } > - > - return ret; > -} > - > -static int navi10_notify_smc_dispaly_config(struct smu_context *smu) > -{ > - struct smu_clocks min_clocks = {0}; > - struct pp_display_clock_request clock_req; > - int ret = 0; > - > - min_clocks.dcef_clock = smu->display_config->min_dcef_set_clk; > - min_clocks.dcef_clock_in_sr = smu->display_config- > >min_dcef_deep_sleep_set_clk; > - min_clocks.memory_clock = smu->display_config- > >min_mem_set_clock; > - > - if (smu_feature_is_supported(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT)) { > - clock_req.clock_type = amd_pp_dcef_clock; > - clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10; > - if (!smu_display_clock_voltage_request(smu, &clock_req)) { > - if (smu_feature_is_supported(smu, > SMU_FEATURE_DS_DCEFCLK_BIT)) { > - ret = smu_send_smc_msg_with_param(smu, > - > SMU_MSG_SetMinDeepSleepDcefclk, > - > min_clocks.dcef_clock_in_sr/100); > - if (ret) { > - pr_err("Attempt to set divider for > DCEFCLK Failed!"); > - return ret; > - } > - } > - } else { > - pr_info("Attempt to set Hard Min for DCEFCLK > Failed!"); > - } > - } > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) > { > - ret = smu_set_hard_freq_range(smu, SMU_UCLK, > min_clocks.memory_clock/100, 0); > - if (ret) { > - pr_err("[%s] Set hard min uclk failed!", __func__); > - return ret; > - } > - } > - > - return 0; > -} > - > -static int navi10_set_watermarks_table(struct smu_context *smu, > - void *watermarks, struct > - > dm_pp_wm_sets_with_clock_ranges_soc15 > - *clock_ranges) > -{ > - int i; > - Watermarks_t *table = watermarks; > - > - if (!table || !clock_ranges) > - return -EINVAL; > - > - if (clock_ranges->num_wm_dmif_sets > 4 || > - clock_ranges->num_wm_mcif_sets > 4) > - return -EINVAL; > - > - for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) { > - table->WatermarkRow[1][i].MinClock = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz / > - 1000)); > - table->WatermarkRow[1][i].MaxClock = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz / > - 1000)); > - table->WatermarkRow[1][i].MinUclk = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz / > - 1000)); > - table->WatermarkRow[1][i].MaxUclk = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz / > - 1000)); > - table->WatermarkRow[1][i].WmSetting = (uint8_t) > - clock_ranges- > >wm_dmif_clocks_ranges[i].wm_set_id; > - } > - > - for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) { > - table->WatermarkRow[0][i].MinClock = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz / > - 1000)); > - table->WatermarkRow[0][i].MaxClock = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz / > - 1000)); > - table->WatermarkRow[0][i].MinUclk = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz / > - 1000)); > - table->WatermarkRow[0][i].MaxUclk = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz / > - 1000)); > - table->WatermarkRow[0][i].WmSetting = (uint8_t) > - clock_ranges- > >wm_mcif_clocks_ranges[i].wm_set_id; > - } > - > - return 0; > -} > - > -static int navi10_read_sensor(struct smu_context *smu, > - enum amd_pp_sensors sensor, > - void *data, uint32_t *size) > -{ > - int ret = 0; > - struct smu_table_context *table_context = &smu->smu_table; > - PPTable_t *pptable = table_context->driver_pptable; > - > - switch (sensor) { > - case AMDGPU_PP_SENSOR_MAX_FAN_RPM: > - *(uint32_t *)data = pptable->FanMaximumRpm; > - *size = 4; > - break; > - case AMDGPU_PP_SENSOR_GPU_LOAD: > - ret = navi10_get_current_activity_percent(smu, (uint32_t > *)data); > - *size = 4; > - break; > - case AMDGPU_PP_SENSOR_GPU_POWER: > - ret = navi10_get_gpu_power(smu, (uint32_t *)data); > - *size = 4; > - break; > - default: > - return -EINVAL; > - } > - > - return ret; > -} > - > -static int navi10_get_uclk_dpm_states(struct smu_context *smu, uint32_t > *clocks_in_khz, uint32_t *num_states) > -{ > - uint32_t num_discrete_levels = 0; > - uint16_t *dpm_levels = NULL; > - uint16_t i = 0; > - struct smu_table_context *table_context = &smu->smu_table; > - PPTable_t *driver_ppt = NULL; > - > - if (!clocks_in_khz || ! num_states || !table_context->driver_pptable) > - return -EINVAL; > - > - driver_ppt = table_context->driver_pptable; > - num_discrete_levels = driver_ppt- > >DpmDescriptor[PPCLK_UCLK].NumDiscreteLevels; > - dpm_levels = driver_ppt->FreqTableUclk; > - > - if (num_discrete_levels == 0 || dpm_levels == NULL) > - return -EINVAL; > - > - *num_states = num_discrete_levels; > - for (i = 0; i < num_discrete_levels; i++) { > - /* convert to khz */ > - *clocks_in_khz = (*dpm_levels) * 1000; > - clocks_in_khz++; > - dpm_levels++; > - } > - > - return 0; > -} > - > -static int navi10_get_ppfeature_status(struct smu_context *smu, > - char *buf) > -{ > - static const char *ppfeature_name[] = { > - "DPM_PREFETCHER", > - "DPM_GFXCLK", > - "DPM_GFX_PACE", > - "DPM_UCLK", > - "DPM_SOCCLK", > - "DPM_MP0CLK", > - "DPM_LINK", > - "DPM_DCEFCLK", > - "MEM_VDDCI_SCALING", > - "MEM_MVDD_SCALING", > - "DS_GFXCLK", > - "DS_SOCCLK", > - "DS_LCLK", > - "DS_DCEFCLK", > - "DS_UCLK", > - "GFX_ULV", > - "FW_DSTATE", > - "GFXOFF", > - "BACO", > - "VCN_PG", > - "JPEG_PG", > - "USB_PG", > - "RSMU_SMN_CG", > - "PPT", > - "TDC", > - "GFX_EDC", > - "APCC_PLUS", > - "GTHR", > - "ACDC", > - "VR0HOT", > - "VR1HOT", > - "FW_CTF", > - "FAN_CONTROL", > - "THERMAL", > - "GFX_DCS", > - "RM", > - "LED_DISPLAY", > - "GFX_SS", > - "OUT_OF_BAND_MONITOR", > - "TEMP_DEPENDENT_VMIN", > - "MMHUB_PG", > - "ATHUB_PG"}; > - static const char *output_title[] = { > - "FEATURES", > - "BITMASK", > - "ENABLEMENT"}; > - uint64_t features_enabled; > - uint32_t feature_mask[2]; > - int i; > - int ret = 0; > - int size = 0; > - > - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); > - PP_ASSERT_WITH_CODE(!ret, > - "[GetPPfeatureStatus] Failed to get enabled smc > features!", > - return ret); > - features_enabled = (uint64_t)feature_mask[0] | > - (uint64_t)feature_mask[1] << 32; > - > - size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", > features_enabled); > - size += sprintf(buf + size, "%-19s %-22s %s\n", > - output_title[0], > - output_title[1], > - output_title[2]); > - for (i = 0; i < (sizeof(ppfeature_name) / sizeof(ppfeature_name[0])); > i++) { > - size += sprintf(buf + size, "%-19s 0x%016llx %6s\n", > - ppfeature_name[i], > - 1ULL << i, > - (features_enabled & (1ULL << i)) ? > "Y" : "N"); > - } > - > - return size; > -} > - > -static int navi10_enable_smc_features(struct smu_context *smu, > - bool enabled, > - uint64_t feature_masks) > -{ > - struct smu_feature *feature = &smu->smu_feature; > - uint32_t feature_low, feature_high; > - uint32_t feature_mask[2]; > - int ret = 0; > - > - feature_low = (uint32_t)(feature_masks & 0xFFFFFFFF); > - feature_high = (uint32_t)((feature_masks & > 0xFFFFFFFF00000000ULL) >> 32); > - > - if (enabled) { > - ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_EnableSmuFeaturesLow, > - feature_low); > - if (ret) > - return ret; > - ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_EnableSmuFeaturesHigh, > - feature_high); > - if (ret) > - return ret; > - } else { > - ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_DisableSmuFeaturesLow, > - feature_low); > - if (ret) > - return ret; > - ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_DisableSmuFeaturesHigh, > - feature_high); > - if (ret) > - return ret; > - } > - > - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); > - if (ret) > - return ret; > - > - mutex_lock(&feature->mutex); > - bitmap_copy(feature->enabled, (unsigned long *)&feature_mask, > - feature->feature_num); > - mutex_unlock(&feature->mutex); > - > - return 0; > -} > - > -static int navi10_set_ppfeature_status(struct smu_context *smu, > - uint64_t new_ppfeature_masks) > -{ > - uint64_t features_enabled; > - uint32_t feature_mask[2]; > - uint64_t features_to_enable; > - uint64_t features_to_disable; > - int ret = 0; > - > - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); > - PP_ASSERT_WITH_CODE(!ret, > - "[SetPPfeatureStatus] Failed to get enabled smc > features!", > - return ret); > - features_enabled = (uint64_t)feature_mask[0] | > - (uint64_t)feature_mask[1] << 32; > - > - features_to_disable = > - features_enabled & ~new_ppfeature_masks; > - features_to_enable = > - ~features_enabled & new_ppfeature_masks; > - > - pr_debug("features_to_disable 0x%llx\n", features_to_disable); > - pr_debug("features_to_enable 0x%llx\n", features_to_enable); > - > - if (features_to_disable) { > - ret = navi10_enable_smc_features(smu, false, > features_to_disable); > - PP_ASSERT_WITH_CODE(!ret, > - "[SetPPfeatureStatus] Failed to disable smc > features!", > - return ret); > - } > - > - if (features_to_enable) { > - ret = navi10_enable_smc_features(smu, true, > features_to_enable); > - PP_ASSERT_WITH_CODE(!ret, > - "[SetPPfeatureStatus] Failed to enable smc > features!", > - return ret); > - } > - > - return 0; > -} > - > -static const struct pptable_funcs navi10_ppt_funcs = { > - .tables_init = navi10_tables_init, > - .alloc_dpm_context = navi10_allocate_dpm_context, > - .store_powerplay_table = navi10_store_powerplay_table, > - .check_powerplay_table = navi10_check_powerplay_table, > - .append_powerplay_table = navi10_append_powerplay_table, > - .get_smu_msg_index = navi10_get_smu_msg_index, > - .get_smu_clk_index = navi10_get_smu_clk_index, > - .get_smu_feature_index = navi10_get_smu_feature_index, > - .get_smu_table_index = navi10_get_smu_table_index, > - .get_smu_power_index= navi10_get_pwr_src_index, > - .get_workload_type = navi10_get_workload_type, > - .get_allowed_feature_mask = navi10_get_allowed_feature_mask, > - .set_default_dpm_table = navi10_set_default_dpm_table, > - .dpm_set_uvd_enable = navi10_dpm_set_uvd_enable, > - .get_current_clk_freq_by_table = > navi10_get_current_clk_freq_by_table, > - .print_clk_levels = navi10_print_clk_levels, > - .force_clk_levels = navi10_force_clk_levels, > - .populate_umd_state_clk = navi10_populate_umd_state_clk, > - .get_clock_by_type_with_latency = > navi10_get_clock_by_type_with_latency, > - .pre_display_config_changed = navi10_pre_display_config_changed, > - .display_config_changed = navi10_display_config_changed, > - .notify_smc_dispaly_config = navi10_notify_smc_dispaly_config, > - .force_dpm_limit_value = navi10_force_dpm_limit_value, > - .unforce_dpm_levels = navi10_unforce_dpm_levels, > - .is_dpm_running = navi10_is_dpm_running, > - .get_fan_speed_percent = navi10_get_fan_speed_percent, > - .get_power_profile_mode = navi10_get_power_profile_mode, > - .set_power_profile_mode = navi10_set_power_profile_mode, > - .get_profiling_clk_mask = navi10_get_profiling_clk_mask, > - .set_watermarks_table = navi10_set_watermarks_table, > - .read_sensor = navi10_read_sensor, > - .get_uclk_dpm_states = navi10_get_uclk_dpm_states, > - .get_ppfeature_status = navi10_get_ppfeature_status, > - .set_ppfeature_status = navi10_set_ppfeature_status, > -}; > - > -void navi10_set_ppt_funcs(struct smu_context *smu) > -{ > - struct smu_table_context *smu_table = &smu->smu_table; > - > - smu->ppt_funcs = &navi10_ppt_funcs; > - smu->smc_if_version = SMU11_DRIVER_IF_VERSION; > - smu_table->table_count = TABLE_COUNT; > -} > diff --git a/drivers/gpu/drm/amd/powerplay/navi10_ppt.h > b/drivers/gpu/drm/amd/powerplay/navi10_ppt.h > deleted file mode 100644 > index 957288e..0000000 > --- a/drivers/gpu/drm/amd/powerplay/navi10_ppt.h > +++ /dev/null > @@ -1,28 +0,0 @@ > -/* > - * Copyright 2019 Advanced Micro Devices, Inc. > - * > - * Permission is hereby granted, free of charge, to any person obtaining a > - * copy of this software and associated documentation files (the "Software"), > - * to deal in the Software without restriction, including without limitation > - * the rights to use, copy, modify, merge, publish, distribute, sublicense, > - * and/or sell copies of the Software, and to permit persons to whom the > - * Software is furnished to do so, subject to the following conditions: > - * > - * The above copyright notice and this permission notice shall be included in > - * all copies or substantial portions of the Software. > - * > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS OR > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO > EVENT SHALL > - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, > DAMAGES OR > - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR > OTHERWISE, > - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR > THE USE OR > - * OTHER DEALINGS IN THE SOFTWARE. > - * > - */ > -#ifndef __NAVI10_PPT_H__ > -#define __NAVI10_PPT_H__ > - > -extern void navi10_set_ppt_funcs(struct smu_context *smu); > - > -#endif > diff --git a/drivers/gpu/drm/amd/powerplay/pptable/Makefile > b/drivers/gpu/drm/amd/powerplay/pptable/Makefile > new file mode 100644 > index 0000000..03058fa > --- /dev/null > +++ b/drivers/gpu/drm/amd/powerplay/pptable/Makefile > @@ -0,0 +1,30 @@ > +# > +# Copyright 2017 Advanced Micro Devices, Inc. > +# > +# Permission is hereby granted, free of charge, to any person obtaining a > +# copy of this software and associated documentation files (the "Software"), > +# to deal in the Software without restriction, including without limitation > +# the rights to use, copy, modify, merge, publish, distribute, sublicense, > +# and/or sell copies of the Software, and to permit persons to whom the > +# Software is furnished to do so, subject to the following conditions: > +# > +# The above copyright notice and this permission notice shall be included in > +# all copies or substantial portions of the Software. > +# > +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS OR > +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, > +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO > EVENT SHALL > +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, > DAMAGES OR > +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR > OTHERWISE, > +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR > THE USE OR > +# OTHER DEALINGS IN THE SOFTWARE. > +# > +# > +# Makefile for the 'pp table ' sub-component of powerplay. > +# It provides the pp table function services for the driver. > + > +PPT_MGR = vega20_ppt.o navi10_ppt.o > + > +AMD_PP_PPTMGR = $(addprefix $(AMD_PP_PATH)/pptable/,$(PPT_MGR)) > + > +AMD_POWERPLAY_FILES += $(AMD_PP_PPTMGR) > diff --git a/drivers/gpu/drm/amd/powerplay/pptable/navi10_ppt.c > b/drivers/gpu/drm/amd/powerplay/pptable/navi10_ppt.c > new file mode 100644 > index 0000000..99566de > --- /dev/null > +++ b/drivers/gpu/drm/amd/powerplay/pptable/navi10_ppt.c > @@ -0,0 +1,1514 @@ > +/* > + * Copyright 2019 Advanced Micro Devices, Inc. > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the > "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO > EVENT SHALL > + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, > DAMAGES OR > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR > OTHERWISE, > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR > THE USE OR > + * OTHER DEALINGS IN THE SOFTWARE. > + * > + */ > + > +#include "pp_debug.h" > +#include <linux/firmware.h> > +#include "amdgpu.h" > +#include "amdgpu_smu.h" > +#include "atomfirmware.h" > +#include "amdgpu_atomfirmware.h" > +#include "smu_v11_0.h" > +#include "smu11_driver_if_navi10.h" > +#include "soc15_common.h" > +#include "atom.h" > +#include "navi10_ppt.h" > +#include "smu_v11_0_pptable.h" > +#include "smu_v11_0_ppsmc.h" > + > +#include "asic_reg/mp/mp_11_0_sh_mask.h" > + > +#define FEATURE_MASK(feature) (1ULL << feature) > +#define SMC_DPM_FEATURE ( \ > + FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \ > + FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ > + FEATURE_MASK(FEATURE_DPM_GFX_PACE_BIT) | \ > + FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ > + FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ > + FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) | \ > + FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ > + FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT)) > + > +#define MSG_MAP(msg, index) \ > + [SMU_MSG_##msg] = index > + > +static int navi10_message_map[SMU_MSG_MAX_COUNT] = { > + MSG_MAP(TestMessage, > PPSMC_MSG_TestMessage), > + MSG_MAP(GetSmuVersion, > PPSMC_MSG_GetSmuVersion), > + MSG_MAP(GetDriverIfVersion, > PPSMC_MSG_GetDriverIfVersion), > + MSG_MAP(SetAllowedFeaturesMaskLow, > PPSMC_MSG_SetAllowedFeaturesMaskLow), > + MSG_MAP(SetAllowedFeaturesMaskHigh, > PPSMC_MSG_SetAllowedFeaturesMaskHigh), > + MSG_MAP(EnableAllSmuFeatures, > PPSMC_MSG_EnableAllSmuFeatures), > + MSG_MAP(DisableAllSmuFeatures, > PPSMC_MSG_DisableAllSmuFeatures), > + MSG_MAP(EnableSmuFeaturesLow, > PPSMC_MSG_EnableSmuFeaturesLow), > + MSG_MAP(EnableSmuFeaturesHigh, > PPSMC_MSG_EnableSmuFeaturesHigh), > + MSG_MAP(DisableSmuFeaturesLow, > PPSMC_MSG_DisableSmuFeaturesLow), > + MSG_MAP(DisableSmuFeaturesHigh, > PPSMC_MSG_DisableSmuFeaturesHigh), > + MSG_MAP(GetEnabledSmuFeaturesLow, > PPSMC_MSG_GetEnabledSmuFeaturesLow), > + MSG_MAP(GetEnabledSmuFeaturesHigh, > PPSMC_MSG_GetEnabledSmuFeaturesHigh), > + MSG_MAP(SetWorkloadMask, > PPSMC_MSG_SetWorkloadMask), > + MSG_MAP(SetPptLimit, > PPSMC_MSG_SetPptLimit), > + MSG_MAP(SetDriverDramAddrHigh, > PPSMC_MSG_SetDriverDramAddrHigh), > + MSG_MAP(SetDriverDramAddrLow, > PPSMC_MSG_SetDriverDramAddrLow), > + MSG_MAP(SetToolsDramAddrHigh, > PPSMC_MSG_SetToolsDramAddrHigh), > + MSG_MAP(SetToolsDramAddrLow, > PPSMC_MSG_SetToolsDramAddrLow), > + MSG_MAP(TransferTableSmu2Dram, > PPSMC_MSG_TransferTableSmu2Dram), > + MSG_MAP(TransferTableDram2Smu, > PPSMC_MSG_TransferTableDram2Smu), > + MSG_MAP(UseDefaultPPTable, > PPSMC_MSG_UseDefaultPPTable), > + MSG_MAP(UseBackupPPTable, > PPSMC_MSG_UseBackupPPTable), > + MSG_MAP(RunBtc, > PPSMC_MSG_RunBtc), > + MSG_MAP(EnterBaco, PPSMC_MSG_EnterBaco), > + MSG_MAP(SetSoftMinByFreq, > PPSMC_MSG_SetSoftMinByFreq), > + MSG_MAP(SetSoftMaxByFreq, > PPSMC_MSG_SetSoftMaxByFreq), > + MSG_MAP(SetHardMinByFreq, > PPSMC_MSG_SetHardMinByFreq), > + MSG_MAP(SetHardMaxByFreq, > PPSMC_MSG_SetHardMaxByFreq), > + MSG_MAP(GetMinDpmFreq, > PPSMC_MSG_GetMinDpmFreq), > + MSG_MAP(GetMaxDpmFreq, > PPSMC_MSG_GetMaxDpmFreq), > + MSG_MAP(GetDpmFreqByIndex, > PPSMC_MSG_GetDpmFreqByIndex), > + MSG_MAP(SetMemoryChannelConfig, > PPSMC_MSG_SetMemoryChannelConfig), > + MSG_MAP(SetGeminiMode, > PPSMC_MSG_SetGeminiMode), > + MSG_MAP(SetGeminiApertureHigh, > PPSMC_MSG_SetGeminiApertureHigh), > + MSG_MAP(SetGeminiApertureLow, > PPSMC_MSG_SetGeminiApertureLow), > + MSG_MAP(OverridePcieParameters, > PPSMC_MSG_OverridePcieParameters), > + MSG_MAP(SetMinDeepSleepDcefclk, > PPSMC_MSG_SetMinDeepSleepDcefclk), > + MSG_MAP(ReenableAcDcInterrupt, > PPSMC_MSG_ReenableAcDcInterrupt), > + MSG_MAP(NotifyPowerSource, > PPSMC_MSG_NotifyPowerSource), > + MSG_MAP(SetUclkFastSwitch, > PPSMC_MSG_SetUclkFastSwitch), > + MSG_MAP(SetVideoFps, > PPSMC_MSG_SetVideoFps), > + MSG_MAP(PrepareMp1ForUnload, > PPSMC_MSG_PrepareMp1ForUnload), > + MSG_MAP(DramLogSetDramAddrHigh, > PPSMC_MSG_DramLogSetDramAddrHigh), > + MSG_MAP(DramLogSetDramAddrLow, > PPSMC_MSG_DramLogSetDramAddrLow), > + MSG_MAP(DramLogSetDramSize, > PPSMC_MSG_DramLogSetDramSize), > + MSG_MAP(ConfigureGfxDidt, > PPSMC_MSG_ConfigureGfxDidt), > + MSG_MAP(NumOfDisplays, > PPSMC_MSG_NumOfDisplays), > + MSG_MAP(SetSystemVirtualDramAddrHigh, > PPSMC_MSG_SetSystemVirtualDramAddrHigh), > + MSG_MAP(SetSystemVirtualDramAddrLow, > PPSMC_MSG_SetSystemVirtualDramAddrLow), > + MSG_MAP(AllowGfxOff, > PPSMC_MSG_AllowGfxOff), > + MSG_MAP(DisallowGfxOff, > PPSMC_MSG_DisallowGfxOff), > + MSG_MAP(GetPptLimit, > PPSMC_MSG_GetPptLimit), > + MSG_MAP(GetDcModeMaxDpmFreq, > PPSMC_MSG_GetDcModeMaxDpmFreq), > + MSG_MAP(GetDebugData, > PPSMC_MSG_GetDebugData), > + MSG_MAP(ExitBaco, PPSMC_MSG_ExitBaco), > + MSG_MAP(PrepareMp1ForReset, > PPSMC_MSG_PrepareMp1ForReset), > + MSG_MAP(PrepareMp1ForShutdown, > PPSMC_MSG_PrepareMp1ForShutdown), > + MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn), > + MSG_MAP(PowerDownVcn, > PPSMC_MSG_PowerDownVcn), > + MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg), > + MSG_MAP(PowerDownJpeg, > PPSMC_MSG_PowerDownJpeg), > + MSG_MAP(BacoAudioD3PME, > PPSMC_MSG_BacoAudioD3PME), > +}; > + > +static int navi10_clk_map[SMU_CLK_COUNT] = { > + CLK_MAP(GFXCLK, PPCLK_GFXCLK), > + CLK_MAP(SCLK, PPCLK_GFXCLK), > + CLK_MAP(SOCCLK, PPCLK_SOCCLK), > + CLK_MAP(FCLK, PPCLK_SOCCLK), > + CLK_MAP(UCLK, PPCLK_UCLK), > + CLK_MAP(MCLK, PPCLK_UCLK), > + CLK_MAP(DCLK, PPCLK_DCLK), > + CLK_MAP(VCLK, PPCLK_VCLK), > + CLK_MAP(DCEFCLK, PPCLK_DCEFCLK), > + CLK_MAP(DISPCLK, PPCLK_DISPCLK), > + CLK_MAP(PIXCLK, PPCLK_PIXCLK), > + CLK_MAP(PHYCLK, PPCLK_PHYCLK), > +}; > + > +static int navi10_feature_mask_map[SMU_FEATURE_COUNT] = { > + FEA_MAP(DPM_PREFETCHER), > + FEA_MAP(DPM_GFXCLK), > + FEA_MAP(DPM_GFX_PACE), > + FEA_MAP(DPM_UCLK), > + FEA_MAP(DPM_SOCCLK), > + FEA_MAP(DPM_MP0CLK), > + FEA_MAP(DPM_LINK), > + FEA_MAP(DPM_DCEFCLK), > + FEA_MAP(MEM_VDDCI_SCALING), > + FEA_MAP(MEM_MVDD_SCALING), > + FEA_MAP(DS_GFXCLK), > + FEA_MAP(DS_SOCCLK), > + FEA_MAP(DS_LCLK), > + FEA_MAP(DS_DCEFCLK), > + FEA_MAP(DS_UCLK), > + FEA_MAP(GFX_ULV), > + FEA_MAP(FW_DSTATE), > + FEA_MAP(GFXOFF), > + FEA_MAP(BACO), > + FEA_MAP(VCN_PG), > + FEA_MAP(JPEG_PG), > + FEA_MAP(USB_PG), > + FEA_MAP(RSMU_SMN_CG), > + FEA_MAP(PPT), > + FEA_MAP(TDC), > + FEA_MAP(GFX_EDC), > + FEA_MAP(APCC_PLUS), > + FEA_MAP(GTHR), > + FEA_MAP(ACDC), > + FEA_MAP(VR0HOT), > + FEA_MAP(VR1HOT), > + FEA_MAP(FW_CTF), > + FEA_MAP(FAN_CONTROL), > + FEA_MAP(THERMAL), > + FEA_MAP(GFX_DCS), > + FEA_MAP(RM), > + FEA_MAP(LED_DISPLAY), > + FEA_MAP(GFX_SS), > + FEA_MAP(OUT_OF_BAND_MONITOR), > + FEA_MAP(TEMP_DEPENDENT_VMIN), > + FEA_MAP(MMHUB_PG), > + FEA_MAP(ATHUB_PG), > +}; > + > +static int navi10_table_map[SMU_TABLE_COUNT] = { > + TAB_MAP(PPTABLE), > + TAB_MAP(WATERMARKS), > + TAB_MAP(AVFS), > + TAB_MAP(AVFS_PSM_DEBUG), > + TAB_MAP(AVFS_FUSE_OVERRIDE), > + TAB_MAP(PMSTATUSLOG), > + TAB_MAP(SMU_METRICS), > + TAB_MAP(DRIVER_SMU_CONFIG), > + TAB_MAP(ACTIVITY_MONITOR_COEFF), > + TAB_MAP(OVERDRIVE), > + TAB_MAP(I2C_COMMANDS), > + TAB_MAP(PACE), > +}; > + > +static int navi10_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { > + PWR_MAP(AC), > + PWR_MAP(DC), > +}; > + > +static int navi10_workload_map[] = { > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT, > WORKLOAD_PPLIB_DEFAULT_BIT), > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D, > WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT), > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING, > WORKLOAD_PPLIB_POWER_SAVING_BIT), > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO, > WORKLOAD_PPLIB_VIDEO_BIT), > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR, > WORKLOAD_PPLIB_VR_BIT), > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, > WORKLOAD_PPLIB_CUSTOM_BIT), > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, > WORKLOAD_PPLIB_CUSTOM_BIT), > +}; > + > +static int navi10_get_smu_msg_index(struct smu_context *smc, uint32_t > index) > +{ > + int val; > + if (index > SMU_MSG_MAX_COUNT) > + return -EINVAL; > + > + val = navi10_message_map[index]; > + if (val > PPSMC_Message_Count) > + return -EINVAL; > + > + return val; > +} > + > +static int navi10_get_smu_clk_index(struct smu_context *smc, uint32_t > index) > +{ > + int val; > + if (index >= SMU_CLK_COUNT) > + return -EINVAL; > + > + val = navi10_clk_map[index]; > + if (val >= PPCLK_COUNT) > + return -EINVAL; > + > + return val; > +} > + > +static int navi10_get_smu_feature_index(struct smu_context *smc, > uint32_t index) > +{ > + int val; > + if (index >= SMU_FEATURE_COUNT) > + return -EINVAL; > + > + val = navi10_feature_mask_map[index]; > + if (val > 64) > + return -EINVAL; > + > + return val; > +} > + > +static int navi10_get_smu_table_index(struct smu_context *smc, uint32_t > index) > +{ > + int val; > + if (index >= SMU_TABLE_COUNT) > + return -EINVAL; > + > + val = navi10_table_map[index]; > + if (val >= TABLE_COUNT) > + return -EINVAL; > + > + return val; > +} > + > +static int navi10_get_pwr_src_index(struct smu_context *smc, uint32_t > index) > +{ > + int val; > + if (index >= SMU_POWER_SOURCE_COUNT) > + return -EINVAL; > + > + val = navi10_pwr_src_map[index]; > + if (val >= POWER_SOURCE_COUNT) > + return -EINVAL; > + > + return val; > +} > + > + > +static int navi10_get_workload_type(struct smu_context *smu, enum > PP_SMC_POWER_PROFILE profile) > +{ > + int val; > + if (profile > PP_SMC_POWER_PROFILE_CUSTOM) > + return -EINVAL; > + > + val = navi10_workload_map[profile]; > + > + return val; > +} > + > +static bool is_asic_secure(struct smu_context *smu) > +{ > + struct amdgpu_device *adev = smu->adev; > + bool is_secure = true; > + uint32_t mp0_fw_intf; > + > + mp0_fw_intf = RREG32_PCIE(MP0_Public | > + (smnMP0_FW_INTF & 0xffffffff)); > + > + if (!(mp0_fw_intf & (1 << 19))) > + is_secure = false; > + > + return is_secure; > +} > + > +static int > +navi10_get_allowed_feature_mask(struct smu_context *smu, > + uint32_t *feature_mask, uint32_t num) > +{ > + struct amdgpu_device *adev = smu->adev; > + > + if (num > 2) > + return -EINVAL; > + > + memset(feature_mask, 0, sizeof(uint32_t) * num); > + > + *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) > + | > FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) > + | > FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) > + | > FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) > + | FEATURE_MASK(FEATURE_DPM_LINK_BIT) > + | FEATURE_MASK(FEATURE_GFX_ULV_BIT) > + | > FEATURE_MASK(FEATURE_RSMU_SMN_CG_BIT) > + | FEATURE_MASK(FEATURE_DS_SOCCLK_BIT) > + | FEATURE_MASK(FEATURE_PPT_BIT) > + | FEATURE_MASK(FEATURE_TDC_BIT) > + | FEATURE_MASK(FEATURE_GFX_EDC_BIT) > + | FEATURE_MASK(FEATURE_VR0HOT_BIT) > + | > FEATURE_MASK(FEATURE_FAN_CONTROL_BIT) > + | FEATURE_MASK(FEATURE_THERMAL_BIT) > + | > FEATURE_MASK(FEATURE_LED_DISPLAY_BIT) > + | > FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT) > + | FEATURE_MASK(FEATURE_DS_GFXCLK_BIT) > + | > FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT) > + | > FEATURE_MASK(FEATURE_FW_DSTATE_BIT) > + | FEATURE_MASK(FEATURE_BACO_BIT) > + | FEATURE_MASK(FEATURE_ACDC_BIT); > + > + if (adev->pm.pp_feature & PP_MCLK_DPM_MASK) > + *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_DPM_UCLK_BIT) > + | > FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT) > + | > FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT); > + > + if (adev->pm.pp_feature & PP_GFXOFF_MASK) { > + *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_GFX_SS_BIT) > + | FEATURE_MASK(FEATURE_GFXOFF_BIT); > + /* TODO: remove it once fw fix the bug */ > + *(uint64_t *)feature_mask &= > ~FEATURE_MASK(FEATURE_FW_DSTATE_BIT); > + } > + > + if (smu->adev->pg_flags & AMD_PG_SUPPORT_MMHUB) > + *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_MMHUB_PG_BIT); > + > + if (smu->adev->pg_flags & AMD_PG_SUPPORT_ATHUB) > + *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_ATHUB_PG_BIT); > + > + if (smu->adev->pg_flags & AMD_PG_SUPPORT_VCN) > + *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_VCN_PG_BIT); > + > + /* disable DPM UCLK and DS SOCCLK on navi10 A0 secure board */ > + if (is_asic_secure(smu)) { > + /* only for navi10 A0 */ > + if ((adev->asic_type == CHIP_NAVI10) && > + (adev->rev_id == 0)) { > + *(uint64_t *)feature_mask &= > + > ~(FEATURE_MASK(FEATURE_DPM_UCLK_BIT) > + | > FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT) > + | > FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT)); > + *(uint64_t *)feature_mask &= > + > ~FEATURE_MASK(FEATURE_DS_SOCCLK_BIT); > + } > + } > + > + return 0; > +} > + > +static int navi10_check_powerplay_table(struct smu_context *smu) > +{ > + return 0; > +} > + > +static int navi10_append_powerplay_table(struct smu_context *smu) > +{ > + struct amdgpu_device *adev = smu->adev; > + struct smu_table_context *table_context = &smu->smu_table; > + PPTable_t *smc_pptable = table_context->driver_pptable; > + struct atom_smc_dpm_info_v4_5 *smc_dpm_table; > + int index, ret; > + > + index = > get_index_into_master_table(atom_master_list_of_data_tables_v2_1, > + smc_dpm_info); > + > + ret = smu_get_atom_data_table(smu, index, NULL, NULL, NULL, > + (uint8_t **)&smc_dpm_table); > + if (ret) > + return ret; > + > + memcpy(smc_pptable->I2cControllers, smc_dpm_table- > >I2cControllers, > + sizeof(I2cControllerConfig_t) * NUM_I2C_CONTROLLERS); > + > + /* SVI2 Board Parameters */ > + smc_pptable->MaxVoltageStepGfx = smc_dpm_table- > >MaxVoltageStepGfx; > + smc_pptable->MaxVoltageStepSoc = smc_dpm_table- > >MaxVoltageStepSoc; > + smc_pptable->VddGfxVrMapping = smc_dpm_table- > >VddGfxVrMapping; > + smc_pptable->VddSocVrMapping = smc_dpm_table- > >VddSocVrMapping; > + smc_pptable->VddMem0VrMapping = smc_dpm_table- > >VddMem0VrMapping; > + smc_pptable->VddMem1VrMapping = smc_dpm_table- > >VddMem1VrMapping; > + smc_pptable->GfxUlvPhaseSheddingMask = smc_dpm_table- > >GfxUlvPhaseSheddingMask; > + smc_pptable->SocUlvPhaseSheddingMask = smc_dpm_table- > >SocUlvPhaseSheddingMask; > + smc_pptable->ExternalSensorPresent = smc_dpm_table- > >ExternalSensorPresent; > + smc_pptable->Padding8_V = smc_dpm_table->Padding8_V; > + > + /* Telemetry Settings */ > + smc_pptable->GfxMaxCurrent = smc_dpm_table->GfxMaxCurrent; > + smc_pptable->GfxOffset = smc_dpm_table->GfxOffset; > + smc_pptable->Padding_TelemetryGfx = smc_dpm_table- > >Padding_TelemetryGfx; > + smc_pptable->SocMaxCurrent = smc_dpm_table->SocMaxCurrent; > + smc_pptable->SocOffset = smc_dpm_table->SocOffset; > + smc_pptable->Padding_TelemetrySoc = smc_dpm_table- > >Padding_TelemetrySoc; > + smc_pptable->Mem0MaxCurrent = smc_dpm_table- > >Mem0MaxCurrent; > + smc_pptable->Mem0Offset = smc_dpm_table->Mem0Offset; > + smc_pptable->Padding_TelemetryMem0 = smc_dpm_table- > >Padding_TelemetryMem0; > + smc_pptable->Mem1MaxCurrent = smc_dpm_table- > >Mem1MaxCurrent; > + smc_pptable->Mem1Offset = smc_dpm_table->Mem1Offset; > + smc_pptable->Padding_TelemetryMem1 = smc_dpm_table- > >Padding_TelemetryMem1; > + > + /* GPIO Settings */ > + smc_pptable->AcDcGpio = smc_dpm_table->AcDcGpio; > + smc_pptable->AcDcPolarity = smc_dpm_table->AcDcPolarity; > + smc_pptable->VR0HotGpio = smc_dpm_table->VR0HotGpio; > + smc_pptable->VR0HotPolarity = smc_dpm_table->VR0HotPolarity; > + smc_pptable->VR1HotGpio = smc_dpm_table->VR1HotGpio; > + smc_pptable->VR1HotPolarity = smc_dpm_table->VR1HotPolarity; > + smc_pptable->GthrGpio = smc_dpm_table->GthrGpio; > + smc_pptable->GthrPolarity = smc_dpm_table->GthrPolarity; > + > + /* LED Display Settings */ > + smc_pptable->LedPin0 = smc_dpm_table->LedPin0; > + smc_pptable->LedPin1 = smc_dpm_table->LedPin1; > + smc_pptable->LedPin2 = smc_dpm_table->LedPin2; > + smc_pptable->padding8_4 = smc_dpm_table->padding8_4; > + > + /* GFXCLK PLL Spread Spectrum */ > + smc_pptable->PllGfxclkSpreadEnabled = smc_dpm_table- > >PllGfxclkSpreadEnabled; > + smc_pptable->PllGfxclkSpreadPercent = smc_dpm_table- > >PllGfxclkSpreadPercent; > + smc_pptable->PllGfxclkSpreadFreq = smc_dpm_table- > >PllGfxclkSpreadFreq; > + > + /* GFXCLK DFLL Spread Spectrum */ > + smc_pptable->DfllGfxclkSpreadEnabled = smc_dpm_table- > >DfllGfxclkSpreadEnabled; > + smc_pptable->DfllGfxclkSpreadPercent = smc_dpm_table- > >DfllGfxclkSpreadPercent; > + smc_pptable->DfllGfxclkSpreadFreq = smc_dpm_table- > >DfllGfxclkSpreadFreq; > + > + /* UCLK Spread Spectrum */ > + smc_pptable->UclkSpreadEnabled = smc_dpm_table- > >UclkSpreadEnabled; > + smc_pptable->UclkSpreadPercent = smc_dpm_table- > >UclkSpreadPercent; > + smc_pptable->UclkSpreadFreq = smc_dpm_table->UclkSpreadFreq; > + > + /* SOCCLK Spread Spectrum */ > + smc_pptable->SoclkSpreadEnabled = smc_dpm_table- > >SoclkSpreadEnabled; > + smc_pptable->SocclkSpreadPercent = smc_dpm_table- > >SocclkSpreadPercent; > + smc_pptable->SocclkSpreadFreq = smc_dpm_table- > >SocclkSpreadFreq; > + > + /* Total board power */ > + smc_pptable->TotalBoardPower = smc_dpm_table- > >TotalBoardPower; > + smc_pptable->BoardPadding = smc_dpm_table->BoardPadding; > + > + /* Mvdd Svi2 Div Ratio Setting */ > + smc_pptable->MvddRatio = smc_dpm_table->MvddRatio; > + > + if (adev->pm.pp_feature & PP_GFXOFF_MASK) { > + *(uint64_t *)smc_pptable->FeaturesToRun |= > FEATURE_MASK(FEATURE_GFX_SS_BIT) > + | > FEATURE_MASK(FEATURE_GFXOFF_BIT); > + > + /* TODO: remove it once SMU fw fix it */ > + smc_pptable->DebugOverrides |= > DPM_OVERRIDE_DISABLE_DFLL_PLL_SHUTDOWN; > + } > + > + return 0; > +} > + > +static int navi10_store_powerplay_table(struct smu_context *smu) > +{ > + struct smu_11_0_powerplay_table *powerplay_table = NULL; > + struct smu_table_context *table_context = &smu->smu_table; > + > + if (!table_context->power_play_table) > + return -EINVAL; > + > + powerplay_table = table_context->power_play_table; > + > + memcpy(table_context->driver_pptable, &powerplay_table- > >smc_pptable, > + sizeof(PPTable_t)); > + > + table_context->thermal_controller_type = powerplay_table- > >thermal_controller_type; > + > + return 0; > +} > + > +static int navi10_tables_init(struct smu_context *smu, struct smu_table > *tables) > +{ > + SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), > + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > + SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, > sizeof(Watermarks_t), > + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > + SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, > sizeof(SmuMetrics_t), > + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > + SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, > sizeof(OverDriveTable_t), > + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > + SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, > SMU11_TOOL_SIZE, > + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > + SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF, > + sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE, > + AMDGPU_GEM_DOMAIN_VRAM); > + > + return 0; > +} > + > +static int navi10_allocate_dpm_context(struct smu_context *smu) > +{ > + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > + > + if (smu_dpm->dpm_context) > + return -EINVAL; > + > + smu_dpm->dpm_context = kzalloc(sizeof(struct > smu_11_0_dpm_context), > + GFP_KERNEL); > + if (!smu_dpm->dpm_context) > + return -ENOMEM; > + > + smu_dpm->dpm_context_size = sizeof(struct > smu_11_0_dpm_context); > + > + return 0; > +} > + > +static int navi10_set_default_dpm_table(struct smu_context *smu) > +{ > + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > + struct smu_table_context *table_context = &smu->smu_table; > + struct smu_11_0_dpm_context *dpm_context = smu_dpm- > >dpm_context; > + PPTable_t *driver_ppt = NULL; > + > + driver_ppt = table_context->driver_pptable; > + > + dpm_context->dpm_tables.soc_table.min = driver_ppt- > >FreqTableSocclk[0]; > + dpm_context->dpm_tables.soc_table.max = driver_ppt- > >FreqTableSocclk[NUM_SOCCLK_DPM_LEVELS - 1]; > + > + dpm_context->dpm_tables.gfx_table.min = driver_ppt- > >FreqTableGfx[0]; > + dpm_context->dpm_tables.gfx_table.max = driver_ppt- > >FreqTableGfx[NUM_GFXCLK_DPM_LEVELS - 1]; > + > + dpm_context->dpm_tables.uclk_table.min = driver_ppt- > >FreqTableUclk[0]; > + dpm_context->dpm_tables.uclk_table.max = driver_ppt- > >FreqTableUclk[NUM_UCLK_DPM_LEVELS - 1]; > + > + dpm_context->dpm_tables.vclk_table.min = driver_ppt- > >FreqTableVclk[0]; > + dpm_context->dpm_tables.vclk_table.max = driver_ppt- > >FreqTableVclk[NUM_VCLK_DPM_LEVELS - 1]; > + > + dpm_context->dpm_tables.dclk_table.min = driver_ppt- > >FreqTableDclk[0]; > + dpm_context->dpm_tables.dclk_table.max = driver_ppt- > >FreqTableDclk[NUM_DCLK_DPM_LEVELS - 1]; > + > + dpm_context->dpm_tables.dcef_table.min = driver_ppt- > >FreqTableDcefclk[0]; > + dpm_context->dpm_tables.dcef_table.max = driver_ppt- > >FreqTableDcefclk[NUM_DCEFCLK_DPM_LEVELS - 1]; > + > + dpm_context->dpm_tables.pixel_table.min = driver_ppt- > >FreqTablePixclk[0]; > + dpm_context->dpm_tables.pixel_table.max = driver_ppt- > >FreqTablePixclk[NUM_PIXCLK_DPM_LEVELS - 1]; > + > + dpm_context->dpm_tables.display_table.min = driver_ppt- > >FreqTableDispclk[0]; > + dpm_context->dpm_tables.display_table.max = driver_ppt- > >FreqTableDispclk[NUM_DISPCLK_DPM_LEVELS - 1]; > + > + dpm_context->dpm_tables.phy_table.min = driver_ppt- > >FreqTablePhyclk[0]; > + dpm_context->dpm_tables.phy_table.max = driver_ppt- > >FreqTablePhyclk[NUM_PHYCLK_DPM_LEVELS - 1]; > + > + return 0; > +} > + > +static int navi10_dpm_set_uvd_enable(struct smu_context *smu, bool > enable) > +{ > + int ret = 0; > + struct smu_power_context *smu_power = &smu->smu_power; > + struct smu_power_gate *power_gate = &smu_power->power_gate; > + > + if (enable && power_gate->uvd_gated) { > + if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_UVD_BIT)) { > + ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_PowerUpVcn, 1); > + if (ret) > + return ret; > + } > + power_gate->uvd_gated = false; > + } else { > + if (!enable && !power_gate->uvd_gated) { > + if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_UVD_BIT)) { > + ret = smu_send_smc_msg(smu, > SMU_MSG_PowerDownVcn); > + if (ret) > + return ret; > + } > + power_gate->uvd_gated = true; > + } > + } > + > + return 0; > +} > + > +static int navi10_get_current_clk_freq_by_table(struct smu_context *smu, > + enum smu_clk_type clk_type, > + uint32_t *value) > +{ > + static SmuMetrics_t metrics = {0}; > + int ret = 0, clk_id = 0; > + > + if (!value) > + return -EINVAL; > + > + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, (void > *)&metrics, false); > + if (ret) > + return ret; > + > + clk_id = smu_clk_get_index(smu, clk_type); > + if (clk_id < 0) > + return clk_id; > + > + *value = metrics.CurrClock[clk_id]; > + > + return ret; > +} > + > +static int navi10_print_clk_levels(struct smu_context *smu, > + enum smu_clk_type clk_type, char *buf) > +{ > + int i, size = 0, ret = 0; > + uint32_t cur_value = 0, value = 0, count = 0; > + > + switch (clk_type) { > + case SMU_GFXCLK: > + case SMU_SCLK: > + case SMU_SOCCLK: > + case SMU_MCLK: > + case SMU_UCLK: > + case SMU_FCLK: > + case SMU_DCEFCLK: > + ret = smu_get_current_clk_freq(smu, clk_type, &cur_value); > + if (ret) > + return size; > + /* 10KHz -> MHz */ > + cur_value = cur_value / 100; > + > + size += sprintf(buf, "current clk: %uMhz\n", cur_value); > + > + ret = smu_get_dpm_level_count(smu, clk_type, &count); > + if (ret) > + return size; > + > + for (i = 0; i < count; i++) { > + ret = smu_get_dpm_freq_by_index(smu, clk_type, i, > &value); > + if (ret) > + return size; > + > + size += sprintf(buf + size, "%d: %uMhz %s\n", i, value, > + cur_value == value ? "*" : ""); > + } > + break; > + default: > + break; > + } > + > + return size; > +} > + > +static int navi10_force_clk_levels(struct smu_context *smu, > + enum smu_clk_type clk_type, uint32_t > mask) > +{ > + > + int ret = 0, size = 0; > + uint32_t soft_min_level = 0, soft_max_level = 0, min_freq = 0, > max_freq = 0; > + > + soft_min_level = mask ? (ffs(mask) - 1) : 0; > + soft_max_level = mask ? (fls(mask) - 1) : 0; > + > + switch (clk_type) { > + case SMU_GFXCLK: > + case SMU_SCLK: > + case SMU_SOCCLK: > + case SMU_MCLK: > + case SMU_UCLK: > + case SMU_DCEFCLK: > + case SMU_FCLK: > + ret = smu_get_dpm_freq_by_index(smu, clk_type, > soft_min_level, &min_freq); > + if (ret) > + return size; > + > + ret = smu_get_dpm_freq_by_index(smu, clk_type, > soft_max_level, &max_freq); > + if (ret) > + return size; > + > + ret = smu_set_soft_freq_range(smu, clk_type, min_freq, > max_freq); > + if (ret) > + return size; > + break; > + default: > + break; > + } > + > + return size; > +} > + > +static int navi10_populate_umd_state_clk(struct smu_context *smu) > +{ > + int ret = 0; > + uint32_t min_sclk_freq = 0; > + > + ret = smu_get_dpm_freq_range(smu, SMU_SCLK, &min_sclk_freq, > NULL); > + if (ret) > + return ret; > + > + smu->pstate_sclk = min_sclk_freq * 100; > + > + return ret; > +} > + > +static int navi10_get_clock_by_type_with_latency(struct smu_context > *smu, > + enum smu_clk_type > clk_type, > + struct > pp_clock_levels_with_latency *clocks) > +{ > + int ret = 0, i = 0; > + uint32_t level_count = 0, freq = 0; > + > + switch (clk_type) { > + case SMU_GFXCLK: > + case SMU_DCEFCLK: > + case SMU_SOCCLK: > + ret = smu_get_dpm_level_count(smu, clk_type, > &level_count); > + if (ret) > + return ret; > + > + level_count = min(level_count, > (uint32_t)MAX_NUM_CLOCKS); > + clocks->num_levels = level_count; > + > + for (i = 0; i < level_count; i++) { > + ret = smu_get_dpm_freq_by_index(smu, clk_type, i, > &freq); > + if (ret) > + return ret; > + > + clocks->data[i].clocks_in_khz = freq * 1000; > + clocks->data[i].latency_in_us = 0; > + } > + break; > + default: > + break; > + } > + > + return ret; > +} > + > +static int navi10_pre_display_config_changed(struct smu_context *smu) > +{ > + int ret = 0; > + uint32_t max_freq = 0; > + > + ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_NumOfDisplays, 0); > + if (ret) > + return ret; > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) > { > + ret = smu_get_dpm_freq_range(smu, SMU_UCLK, NULL, > &max_freq); > + if (ret) > + return ret; > + ret = smu_set_hard_freq_range(smu, SMU_UCLK, 0, > max_freq); > + if (ret) > + return ret; > + } > + > + return ret; > +} > + > +static int navi10_display_config_changed(struct smu_context *smu) > +{ > + int ret = 0; > + > + if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && > + !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { > + ret = smu_write_watermarks_table(smu); > + if (ret) > + return ret; > + > + smu->watermarks_bitmap |= WATERMARKS_LOADED; > + } > + > + if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && > + smu_feature_is_supported(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT) && > + smu_feature_is_supported(smu, > SMU_FEATURE_DPM_SOCCLK_BIT)) { > + ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_NumOfDisplays, > + smu->display_config- > >num_display); > + if (ret) > + return ret; > + } > + > + return ret; > +} > + > +static int navi10_force_dpm_limit_value(struct smu_context *smu, bool > highest) > +{ > + int ret = 0, i = 0; > + uint32_t min_freq, max_freq, force_freq; > + enum smu_clk_type clk_type; > + > + enum smu_clk_type clks[] = { > + SMU_GFXCLK, > + SMU_MCLK, > + SMU_SOCCLK, > + }; > + > + for (i = 0; i < ARRAY_SIZE(clks); i++) { > + clk_type = clks[i]; > + ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, > &max_freq); > + if (ret) > + return ret; > + > + force_freq = highest ? max_freq : min_freq; > + ret = smu_set_soft_freq_range(smu, clk_type, force_freq, > force_freq); > + if (ret) > + return ret; > + } > + > + return ret; > +} > + > +static int navi10_unforce_dpm_levels(struct smu_context *smu) { > + > + int ret = 0, i = 0; > + uint32_t min_freq, max_freq; > + enum smu_clk_type clk_type; > + > + struct clk_feature_map { > + enum smu_clk_type clk_type; > + uint32_t feature; > + } clk_feature_map[] = { > + {SMU_GFXCLK, SMU_FEATURE_DPM_GFXCLK_BIT}, > + {SMU_MCLK, SMU_FEATURE_DPM_UCLK_BIT}, > + {SMU_SOCCLK, SMU_FEATURE_DPM_SOCCLK_BIT}, > + }; > + > + for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) { > + if (!smu_feature_is_enabled(smu, > clk_feature_map[i].feature)) > + continue; > + > + clk_type = clk_feature_map[i].clk_type; > + > + ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, > &max_freq); > + if (ret) > + return ret; > + > + ret = smu_set_soft_freq_range(smu, clk_type, min_freq, > max_freq); > + if (ret) > + return ret; > + } > + > + return ret; > +} > + > +static int navi10_get_gpu_power(struct smu_context *smu, uint32_t > *value) > +{ > + int ret = 0; > + SmuMetrics_t metrics; > + > + if (!value) > + return -EINVAL; > + > + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, (void > *)&metrics, > + false); > + if (ret) > + return ret; > + > + *value = metrics.CurrSocketPower << 8; > + > + return 0; > +} > + > +static int navi10_get_current_activity_percent(struct smu_context *smu, > + uint32_t *value) > +{ > + int ret = 0; > + SmuMetrics_t metrics; > + > + if (!value) > + return -EINVAL; > + > + msleep(1); > + > + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, > + (void *)&metrics, false); > + if (ret) > + return ret; > + > + *value = metrics.AverageGfxActivity; > + > + return 0; > +} > + > +static bool navi10_is_dpm_running(struct smu_context *smu) > +{ > + int ret = 0; > + uint32_t feature_mask[2]; > + unsigned long feature_enabled; > + ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); > + feature_enabled = (unsigned long)((uint64_t)feature_mask[0] | > + ((uint64_t)feature_mask[1] << 32)); > + return !!(feature_enabled & SMC_DPM_FEATURE); > +} > + > +static int navi10_get_fan_speed(struct smu_context *smu, uint16_t *value) > +{ > + SmuMetrics_t metrics = {0}; > + int ret = 0; > + > + if (!value) > + return -EINVAL; > + > + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, > + (void *)&metrics, false); > + if (ret) > + return ret; > + > + *value = metrics.CurrFanSpeed; > + > + return ret; > +} > + > +static int navi10_get_fan_speed_percent(struct smu_context *smu, > + uint32_t *speed) > +{ > + int ret = 0; > + uint32_t percent = 0; > + uint16_t current_rpm; > + PPTable_t *pptable = smu->smu_table.driver_pptable; > + > + ret = navi10_get_fan_speed(smu, ¤t_rpm); > + if (ret) > + return ret; > + > + percent = current_rpm * 100 / pptable->FanMaximumRpm; > + *speed = percent > 100 ? 100 : percent; > + > + return ret; > +} > + > +static int navi10_get_power_profile_mode(struct smu_context *smu, char > *buf) > +{ > + DpmActivityMonitorCoeffInt_t activity_monitor; > + uint32_t i, size = 0; > + uint16_t workload_type = 0; > + static const char *profile_name[] = { > + "BOOTUP_DEFAULT", > + "3D_FULL_SCREEN", > + "POWER_SAVING", > + "VIDEO", > + "VR", > + "COMPUTE", > + "CUSTOM"}; > + static const char *title[] = { > + "PROFILE_INDEX(NAME)", > + "CLOCK_TYPE(NAME)", > + "FPS", > + "MinFreqType", > + "MinActiveFreqType", > + "MinActiveFreq", > + "BoosterFreqType", > + "BoosterFreq", > + "PD_Data_limit_c", > + "PD_Data_error_coeff", > + "PD_Data_error_rate_coeff"}; > + int result = 0; > + > + if (!buf) > + return -EINVAL; > + > + size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n", > + title[0], title[1], title[2], title[3], title[4], title[5], > + title[6], title[7], title[8], title[9], title[10]); > + > + for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { > + /* conv PP_SMC_POWER_PROFILE* to > WORKLOAD_PPLIB_*_BIT */ > + workload_type = smu_workload_get_type(smu, i); > + result = smu_update_table(smu, > + > SMU_TABLE_ACTIVITY_MONITOR_COEFF | workload_type << 16, > + (void *)(&activity_monitor), false); > + if (result) { > + pr_err("[%s] Failed to get activity monitor!", > __func__); > + return result; > + } > + > + size += sprintf(buf + size, "%2d %14s%s:\n", > + i, profile_name[i], (i == smu->power_profile_mode) ? > "*" : " "); > + > + size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > + " ", > + 0, > + "GFXCLK", > + activity_monitor.Gfx_FPS, > + activity_monitor.Gfx_MinFreqStep, > + activity_monitor.Gfx_MinActiveFreqType, > + activity_monitor.Gfx_MinActiveFreq, > + activity_monitor.Gfx_BoosterFreqType, > + activity_monitor.Gfx_BoosterFreq, > + activity_monitor.Gfx_PD_Data_limit_c, > + activity_monitor.Gfx_PD_Data_error_coeff, > + activity_monitor.Gfx_PD_Data_error_rate_coeff); > + > + size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > + " ", > + 1, > + "SOCCLK", > + activity_monitor.Soc_FPS, > + activity_monitor.Soc_MinFreqStep, > + activity_monitor.Soc_MinActiveFreqType, > + activity_monitor.Soc_MinActiveFreq, > + activity_monitor.Soc_BoosterFreqType, > + activity_monitor.Soc_BoosterFreq, > + activity_monitor.Soc_PD_Data_limit_c, > + activity_monitor.Soc_PD_Data_error_coeff, > + activity_monitor.Soc_PD_Data_error_rate_coeff); > + > + size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > + " ", > + 2, > + "MEMLK", > + activity_monitor.Mem_FPS, > + activity_monitor.Mem_MinFreqStep, > + activity_monitor.Mem_MinActiveFreqType, > + activity_monitor.Mem_MinActiveFreq, > + activity_monitor.Mem_BoosterFreqType, > + activity_monitor.Mem_BoosterFreq, > + activity_monitor.Mem_PD_Data_limit_c, > + activity_monitor.Mem_PD_Data_error_coeff, > + activity_monitor.Mem_PD_Data_error_rate_coeff); > + } > + > + return size; > +} > + > +static int navi10_set_power_profile_mode(struct smu_context *smu, long > *input, uint32_t size) > +{ > + DpmActivityMonitorCoeffInt_t activity_monitor; > + int workload_type, ret = 0; > + > + smu->power_profile_mode = input[size]; > + > + if (smu->power_profile_mode > > PP_SMC_POWER_PROFILE_CUSTOM) { > + pr_err("Invalid power profile mode %d\n", smu- > >power_profile_mode); > + return -EINVAL; > + } > + > + if (smu->power_profile_mode == > PP_SMC_POWER_PROFILE_CUSTOM) { > + if (size < 0) > + return -EINVAL; > + > + ret = smu_update_table(smu, > + SMU_TABLE_ACTIVITY_MONITOR_COEFF > | WORKLOAD_PPLIB_CUSTOM_BIT << 16, > + (void *)(&activity_monitor), false); > + if (ret) { > + pr_err("[%s] Failed to get activity monitor!", > __func__); > + return ret; > + } > + > + switch (input[0]) { > + case 0: /* Gfxclk */ > + activity_monitor.Gfx_FPS = input[1]; > + activity_monitor.Gfx_MinFreqStep = input[2]; > + activity_monitor.Gfx_MinActiveFreqType = input[3]; > + activity_monitor.Gfx_MinActiveFreq = input[4]; > + activity_monitor.Gfx_BoosterFreqType = input[5]; > + activity_monitor.Gfx_BoosterFreq = input[6]; > + activity_monitor.Gfx_PD_Data_limit_c = input[7]; > + activity_monitor.Gfx_PD_Data_error_coeff = > input[8]; > + activity_monitor.Gfx_PD_Data_error_rate_coeff = > input[9]; > + break; > + case 1: /* Socclk */ > + activity_monitor.Soc_FPS = input[1]; > + activity_monitor.Soc_MinFreqStep = input[2]; > + activity_monitor.Soc_MinActiveFreqType = input[3]; > + activity_monitor.Soc_MinActiveFreq = input[4]; > + activity_monitor.Soc_BoosterFreqType = input[5]; > + activity_monitor.Soc_BoosterFreq = input[6]; > + activity_monitor.Soc_PD_Data_limit_c = input[7]; > + activity_monitor.Soc_PD_Data_error_coeff = > input[8]; > + activity_monitor.Soc_PD_Data_error_rate_coeff = > input[9]; > + break; > + case 2: /* Memlk */ > + activity_monitor.Mem_FPS = input[1]; > + activity_monitor.Mem_MinFreqStep = input[2]; > + activity_monitor.Mem_MinActiveFreqType = > input[3]; > + activity_monitor.Mem_MinActiveFreq = input[4]; > + activity_monitor.Mem_BoosterFreqType = input[5]; > + activity_monitor.Mem_BoosterFreq = input[6]; > + activity_monitor.Mem_PD_Data_limit_c = input[7]; > + activity_monitor.Mem_PD_Data_error_coeff = > input[8]; > + activity_monitor.Mem_PD_Data_error_rate_coeff = > input[9]; > + break; > + } > + > + ret = smu_update_table(smu, > + SMU_TABLE_ACTIVITY_MONITOR_COEFF > | WORKLOAD_PPLIB_CUSTOM_BIT << 16, > + (void *)(&activity_monitor), true); > + if (ret) { > + pr_err("[%s] Failed to set activity monitor!", > __func__); > + return ret; > + } > + } > + > + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ > + workload_type = smu_workload_get_type(smu, smu- > >power_profile_mode); > + smu_send_smc_msg_with_param(smu, > SMU_MSG_SetWorkloadMask, > + 1 << workload_type); > + > + return ret; > +} > + > +static int navi10_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) > +{ > + int ret = 0; > + uint32_t level_count = 0; > + > + if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { > + if (sclk_mask) > + *sclk_mask = 0; > + } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { > + if (mclk_mask) > + *mclk_mask = 0; > + } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > + if(sclk_mask) { > + ret = smu_get_dpm_level_count(smu, SMU_SCLK, > &level_count); > + if (ret) > + return ret; > + *sclk_mask = level_count - 1; > + } > + > + if(mclk_mask) { > + ret = smu_get_dpm_level_count(smu, SMU_MCLK, > &level_count); > + if (ret) > + return ret; > + *sclk_mask = level_count - 1; > + } > + > + if(soc_mask) { > + ret = smu_get_dpm_level_count(smu, SMU_SOCCLK, > &level_count); > + if (ret) > + return ret; > + *sclk_mask = level_count - 1; > + } > + } > + > + return ret; > +} > + > +static int navi10_notify_smc_dispaly_config(struct smu_context *smu) > +{ > + struct smu_clocks min_clocks = {0}; > + struct pp_display_clock_request clock_req; > + int ret = 0; > + > + min_clocks.dcef_clock = smu->display_config->min_dcef_set_clk; > + min_clocks.dcef_clock_in_sr = smu->display_config- > >min_dcef_deep_sleep_set_clk; > + min_clocks.memory_clock = smu->display_config- > >min_mem_set_clock; > + > + if (smu_feature_is_supported(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT)) { > + clock_req.clock_type = amd_pp_dcef_clock; > + clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10; > + if (!smu_display_clock_voltage_request(smu, &clock_req)) { > + if (smu_feature_is_supported(smu, > SMU_FEATURE_DS_DCEFCLK_BIT)) { > + ret = smu_send_smc_msg_with_param(smu, > + > SMU_MSG_SetMinDeepSleepDcefclk, > + > min_clocks.dcef_clock_in_sr/100); > + if (ret) { > + pr_err("Attempt to set divider for > DCEFCLK Failed!"); > + return ret; > + } > + } > + } else { > + pr_info("Attempt to set Hard Min for DCEFCLK > Failed!"); > + } > + } > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) > { > + ret = smu_set_hard_freq_range(smu, SMU_UCLK, > min_clocks.memory_clock/100, 0); > + if (ret) { > + pr_err("[%s] Set hard min uclk failed!", __func__); > + return ret; > + } > + } > + > + return 0; > +} > + > +static int navi10_set_watermarks_table(struct smu_context *smu, > + void *watermarks, struct > + > dm_pp_wm_sets_with_clock_ranges_soc15 > + *clock_ranges) > +{ > + int i; > + Watermarks_t *table = watermarks; > + > + if (!table || !clock_ranges) > + return -EINVAL; > + > + if (clock_ranges->num_wm_dmif_sets > 4 || > + clock_ranges->num_wm_mcif_sets > 4) > + return -EINVAL; > + > + for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) { > + table->WatermarkRow[1][i].MinClock = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz / > + 1000)); > + table->WatermarkRow[1][i].MaxClock = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz / > + 1000)); > + table->WatermarkRow[1][i].MinUclk = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz / > + 1000)); > + table->WatermarkRow[1][i].MaxUclk = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz / > + 1000)); > + table->WatermarkRow[1][i].WmSetting = (uint8_t) > + clock_ranges- > >wm_dmif_clocks_ranges[i].wm_set_id; > + } > + > + for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) { > + table->WatermarkRow[0][i].MinClock = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz / > + 1000)); > + table->WatermarkRow[0][i].MaxClock = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz / > + 1000)); > + table->WatermarkRow[0][i].MinUclk = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz / > + 1000)); > + table->WatermarkRow[0][i].MaxUclk = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz / > + 1000)); > + table->WatermarkRow[0][i].WmSetting = (uint8_t) > + clock_ranges- > >wm_mcif_clocks_ranges[i].wm_set_id; > + } > + > + return 0; > +} > + > +static int navi10_read_sensor(struct smu_context *smu, > + enum amd_pp_sensors sensor, > + void *data, uint32_t *size) > +{ > + int ret = 0; > + struct smu_table_context *table_context = &smu->smu_table; > + PPTable_t *pptable = table_context->driver_pptable; > + > + switch (sensor) { > + case AMDGPU_PP_SENSOR_MAX_FAN_RPM: > + *(uint32_t *)data = pptable->FanMaximumRpm; > + *size = 4; > + break; > + case AMDGPU_PP_SENSOR_GPU_LOAD: > + ret = navi10_get_current_activity_percent(smu, (uint32_t > *)data); > + *size = 4; > + break; > + case AMDGPU_PP_SENSOR_GPU_POWER: > + ret = navi10_get_gpu_power(smu, (uint32_t *)data); > + *size = 4; > + break; > + default: > + return -EINVAL; > + } > + > + return ret; > +} > + > +static int navi10_get_uclk_dpm_states(struct smu_context *smu, uint32_t > *clocks_in_khz, uint32_t *num_states) > +{ > + uint32_t num_discrete_levels = 0; > + uint16_t *dpm_levels = NULL; > + uint16_t i = 0; > + struct smu_table_context *table_context = &smu->smu_table; > + PPTable_t *driver_ppt = NULL; > + > + if (!clocks_in_khz || ! num_states || !table_context->driver_pptable) > + return -EINVAL; > + > + driver_ppt = table_context->driver_pptable; > + num_discrete_levels = driver_ppt- > >DpmDescriptor[PPCLK_UCLK].NumDiscreteLevels; > + dpm_levels = driver_ppt->FreqTableUclk; > + > + if (num_discrete_levels == 0 || dpm_levels == NULL) > + return -EINVAL; > + > + *num_states = num_discrete_levels; > + for (i = 0; i < num_discrete_levels; i++) { > + /* convert to khz */ > + *clocks_in_khz = (*dpm_levels) * 1000; > + clocks_in_khz++; > + dpm_levels++; > + } > + > + return 0; > +} > + > +static int navi10_get_ppfeature_status(struct smu_context *smu, > + char *buf) > +{ > + static const char *ppfeature_name[] = { > + "DPM_PREFETCHER", > + "DPM_GFXCLK", > + "DPM_GFX_PACE", > + "DPM_UCLK", > + "DPM_SOCCLK", > + "DPM_MP0CLK", > + "DPM_LINK", > + "DPM_DCEFCLK", > + "MEM_VDDCI_SCALING", > + "MEM_MVDD_SCALING", > + "DS_GFXCLK", > + "DS_SOCCLK", > + "DS_LCLK", > + "DS_DCEFCLK", > + "DS_UCLK", > + "GFX_ULV", > + "FW_DSTATE", > + "GFXOFF", > + "BACO", > + "VCN_PG", > + "JPEG_PG", > + "USB_PG", > + "RSMU_SMN_CG", > + "PPT", > + "TDC", > + "GFX_EDC", > + "APCC_PLUS", > + "GTHR", > + "ACDC", > + "VR0HOT", > + "VR1HOT", > + "FW_CTF", > + "FAN_CONTROL", > + "THERMAL", > + "GFX_DCS", > + "RM", > + "LED_DISPLAY", > + "GFX_SS", > + "OUT_OF_BAND_MONITOR", > + "TEMP_DEPENDENT_VMIN", > + "MMHUB_PG", > + "ATHUB_PG"}; > + static const char *output_title[] = { > + "FEATURES", > + "BITMASK", > + "ENABLEMENT"}; > + uint64_t features_enabled; > + uint32_t feature_mask[2]; > + int i; > + int ret = 0; > + int size = 0; > + > + ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); > + PP_ASSERT_WITH_CODE(!ret, > + "[GetPPfeatureStatus] Failed to get enabled smc > features!", > + return ret); > + features_enabled = (uint64_t)feature_mask[0] | > + (uint64_t)feature_mask[1] << 32; > + > + size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", > features_enabled); > + size += sprintf(buf + size, "%-19s %-22s %s\n", > + output_title[0], > + output_title[1], > + output_title[2]); > + for (i = 0; i < (sizeof(ppfeature_name) / sizeof(ppfeature_name[0])); > i++) { > + size += sprintf(buf + size, "%-19s 0x%016llx %6s\n", > + ppfeature_name[i], > + 1ULL << i, > + (features_enabled & (1ULL << i)) ? > "Y" : "N"); > + } > + > + return size; > +} > + > +static int navi10_enable_smc_features(struct smu_context *smu, > + bool enabled, > + uint64_t feature_masks) > +{ > + struct smu_feature *feature = &smu->smu_feature; > + uint32_t feature_low, feature_high; > + uint32_t feature_mask[2]; > + int ret = 0; > + > + feature_low = (uint32_t)(feature_masks & 0xFFFFFFFF); > + feature_high = (uint32_t)((feature_masks & > 0xFFFFFFFF00000000ULL) >> 32); > + > + if (enabled) { > + ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_EnableSmuFeaturesLow, > + feature_low); > + if (ret) > + return ret; > + ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_EnableSmuFeaturesHigh, > + feature_high); > + if (ret) > + return ret; > + } else { > + ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_DisableSmuFeaturesLow, > + feature_low); > + if (ret) > + return ret; > + ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_DisableSmuFeaturesHigh, > + feature_high); > + if (ret) > + return ret; > + } > + > + ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); > + if (ret) > + return ret; > + > + mutex_lock(&feature->mutex); > + bitmap_copy(feature->enabled, (unsigned long *)&feature_mask, > + feature->feature_num); > + mutex_unlock(&feature->mutex); > + > + return 0; > +} > + > +static int navi10_set_ppfeature_status(struct smu_context *smu, > + uint64_t new_ppfeature_masks) > +{ > + uint64_t features_enabled; > + uint32_t feature_mask[2]; > + uint64_t features_to_enable; > + uint64_t features_to_disable; > + int ret = 0; > + > + ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); > + PP_ASSERT_WITH_CODE(!ret, > + "[SetPPfeatureStatus] Failed to get enabled smc > features!", > + return ret); > + features_enabled = (uint64_t)feature_mask[0] | > + (uint64_t)feature_mask[1] << 32; > + > + features_to_disable = > + features_enabled & ~new_ppfeature_masks; > + features_to_enable = > + ~features_enabled & new_ppfeature_masks; > + > + pr_debug("features_to_disable 0x%llx\n", features_to_disable); > + pr_debug("features_to_enable 0x%llx\n", features_to_enable); > + > + if (features_to_disable) { > + ret = navi10_enable_smc_features(smu, false, > features_to_disable); > + PP_ASSERT_WITH_CODE(!ret, > + "[SetPPfeatureStatus] Failed to disable smc > features!", > + return ret); > + } > + > + if (features_to_enable) { > + ret = navi10_enable_smc_features(smu, true, > features_to_enable); > + PP_ASSERT_WITH_CODE(!ret, > + "[SetPPfeatureStatus] Failed to enable smc > features!", > + return ret); > + } > + > + return 0; > +} > + > +static const struct pptable_funcs navi10_ppt_funcs = { > + .tables_init = navi10_tables_init, > + .alloc_dpm_context = navi10_allocate_dpm_context, > + .store_powerplay_table = navi10_store_powerplay_table, > + .check_powerplay_table = navi10_check_powerplay_table, > + .append_powerplay_table = navi10_append_powerplay_table, > + .get_smu_msg_index = navi10_get_smu_msg_index, > + .get_smu_clk_index = navi10_get_smu_clk_index, > + .get_smu_feature_index = navi10_get_smu_feature_index, > + .get_smu_table_index = navi10_get_smu_table_index, > + .get_smu_power_index= navi10_get_pwr_src_index, > + .get_workload_type = navi10_get_workload_type, > + .get_allowed_feature_mask = navi10_get_allowed_feature_mask, > + .set_default_dpm_table = navi10_set_default_dpm_table, > + .dpm_set_uvd_enable = navi10_dpm_set_uvd_enable, > + .get_current_clk_freq_by_table = > navi10_get_current_clk_freq_by_table, > + .print_clk_levels = navi10_print_clk_levels, > + .force_clk_levels = navi10_force_clk_levels, > + .populate_umd_state_clk = navi10_populate_umd_state_clk, > + .get_clock_by_type_with_latency = > navi10_get_clock_by_type_with_latency, > + .pre_display_config_changed = navi10_pre_display_config_changed, > + .display_config_changed = navi10_display_config_changed, > + .notify_smc_dispaly_config = navi10_notify_smc_dispaly_config, > + .force_dpm_limit_value = navi10_force_dpm_limit_value, > + .unforce_dpm_levels = navi10_unforce_dpm_levels, > + .is_dpm_running = navi10_is_dpm_running, > + .get_fan_speed_percent = navi10_get_fan_speed_percent, > + .get_power_profile_mode = navi10_get_power_profile_mode, > + .set_power_profile_mode = navi10_set_power_profile_mode, > + .get_profiling_clk_mask = navi10_get_profiling_clk_mask, > + .set_watermarks_table = navi10_set_watermarks_table, > + .read_sensor = navi10_read_sensor, > + .get_uclk_dpm_states = navi10_get_uclk_dpm_states, > + .get_ppfeature_status = navi10_get_ppfeature_status, > + .set_ppfeature_status = navi10_set_ppfeature_status, > +}; > + > +void navi10_set_ppt_funcs(struct smu_context *smu) > +{ > + struct smu_table_context *smu_table = &smu->smu_table; > + > + smu->ppt_funcs = &navi10_ppt_funcs; > + smu->smc_if_version = SMU11_DRIVER_IF_VERSION; > + smu_table->table_count = TABLE_COUNT; > +} > diff --git a/drivers/gpu/drm/amd/powerplay/pptable/navi10_ppt.h > b/drivers/gpu/drm/amd/powerplay/pptable/navi10_ppt.h > new file mode 100644 > index 0000000..957288e > --- /dev/null > +++ b/drivers/gpu/drm/amd/powerplay/pptable/navi10_ppt.h > @@ -0,0 +1,28 @@ > +/* > + * Copyright 2019 Advanced Micro Devices, Inc. > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the > "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO > EVENT SHALL > + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, > DAMAGES OR > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR > OTHERWISE, > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR > THE USE OR > + * OTHER DEALINGS IN THE SOFTWARE. > + * > + */ > +#ifndef __NAVI10_PPT_H__ > +#define __NAVI10_PPT_H__ > + > +extern void navi10_set_ppt_funcs(struct smu_context *smu); > + > +#endif > diff --git a/drivers/gpu/drm/amd/powerplay/pptable/vega20_ppt.c > b/drivers/gpu/drm/amd/powerplay/pptable/vega20_ppt.c > new file mode 100644 > index 0000000..9a535f7 > --- /dev/null > +++ b/drivers/gpu/drm/amd/powerplay/pptable/vega20_ppt.c > @@ -0,0 +1,3302 @@ > +/* > + * Copyright 2019 Advanced Micro Devices, Inc. > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the > "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO > EVENT SHALL > + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, > DAMAGES OR > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR > OTHERWISE, > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR > THE USE OR > + * OTHER DEALINGS IN THE SOFTWARE. > + * > + */ > + > +#include "pp_debug.h" > +#include <linux/firmware.h> > +#include "amdgpu.h" > +#include "amdgpu_smu.h" > +#include "atomfirmware.h" > +#include "amdgpu_atomfirmware.h" > +#include "smu_v11_0.h" > +#include "smu11_driver_if.h" > +#include "soc15_common.h" > +#include "atom.h" > +#include "power_state.h" > +#include "vega20_ppt.h" > +#include "vega20_pptable.h" > +#include "vega20_ppsmc.h" > +#include "nbio/nbio_7_4_sh_mask.h" > +#include "asic_reg/thm/thm_11_0_2_offset.h" > +#include "asic_reg/thm/thm_11_0_2_sh_mask.h" > + > +#define smnPCIE_LC_SPEED_CNTL 0x11140290 > +#define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 > + > +#define CTF_OFFSET_EDGE 5 > +#define CTF_OFFSET_HOTSPOT 5 > +#define CTF_OFFSET_HBM 5 > + > +#define MSG_MAP(msg) \ > + [SMU_MSG_##msg] = PPSMC_MSG_##msg > + > +#define SMC_DPM_FEATURE (FEATURE_DPM_PREFETCHER_MASK | \ > + FEATURE_DPM_GFXCLK_MASK | \ > + FEATURE_DPM_UCLK_MASK | \ > + FEATURE_DPM_SOCCLK_MASK | \ > + FEATURE_DPM_UVD_MASK | \ > + FEATURE_DPM_VCE_MASK | \ > + FEATURE_DPM_MP0CLK_MASK | \ > + FEATURE_DPM_LINK_MASK | \ > + FEATURE_DPM_DCEFCLK_MASK) > + > +static int vega20_message_map[SMU_MSG_MAX_COUNT] = { > + MSG_MAP(TestMessage), > + MSG_MAP(GetSmuVersion), > + MSG_MAP(GetDriverIfVersion), > + MSG_MAP(SetAllowedFeaturesMaskLow), > + MSG_MAP(SetAllowedFeaturesMaskHigh), > + MSG_MAP(EnableAllSmuFeatures), > + MSG_MAP(DisableAllSmuFeatures), > + MSG_MAP(EnableSmuFeaturesLow), > + MSG_MAP(EnableSmuFeaturesHigh), > + MSG_MAP(DisableSmuFeaturesLow), > + MSG_MAP(DisableSmuFeaturesHigh), > + MSG_MAP(GetEnabledSmuFeaturesLow), > + MSG_MAP(GetEnabledSmuFeaturesHigh), > + MSG_MAP(SetWorkloadMask), > + MSG_MAP(SetPptLimit), > + MSG_MAP(SetDriverDramAddrHigh), > + MSG_MAP(SetDriverDramAddrLow), > + MSG_MAP(SetToolsDramAddrHigh), > + MSG_MAP(SetToolsDramAddrLow), > + MSG_MAP(TransferTableSmu2Dram), > + MSG_MAP(TransferTableDram2Smu), > + MSG_MAP(UseDefaultPPTable), > + MSG_MAP(UseBackupPPTable), > + MSG_MAP(RunBtc), > + MSG_MAP(RequestI2CBus), > + MSG_MAP(ReleaseI2CBus), > + MSG_MAP(SetFloorSocVoltage), > + MSG_MAP(SoftReset), > + MSG_MAP(StartBacoMonitor), > + MSG_MAP(CancelBacoMonitor), > + MSG_MAP(EnterBaco), > + MSG_MAP(SetSoftMinByFreq), > + MSG_MAP(SetSoftMaxByFreq), > + MSG_MAP(SetHardMinByFreq), > + MSG_MAP(SetHardMaxByFreq), > + MSG_MAP(GetMinDpmFreq), > + MSG_MAP(GetMaxDpmFreq), > + MSG_MAP(GetDpmFreqByIndex), > + MSG_MAP(GetDpmClockFreq), > + MSG_MAP(GetSsVoltageByDpm), > + MSG_MAP(SetMemoryChannelConfig), > + MSG_MAP(SetGeminiMode), > + MSG_MAP(SetGeminiApertureHigh), > + MSG_MAP(SetGeminiApertureLow), > + MSG_MAP(SetMinLinkDpmByIndex), > + MSG_MAP(OverridePcieParameters), > + MSG_MAP(OverDriveSetPercentage), > + MSG_MAP(SetMinDeepSleepDcefclk), > + MSG_MAP(ReenableAcDcInterrupt), > + MSG_MAP(NotifyPowerSource), > + MSG_MAP(SetUclkFastSwitch), > + MSG_MAP(SetUclkDownHyst), > + MSG_MAP(GetCurrentRpm), > + MSG_MAP(SetVideoFps), > + MSG_MAP(SetTjMax), > + MSG_MAP(SetFanTemperatureTarget), > + MSG_MAP(PrepareMp1ForUnload), > + MSG_MAP(DramLogSetDramAddrHigh), > + MSG_MAP(DramLogSetDramAddrLow), > + MSG_MAP(DramLogSetDramSize), > + MSG_MAP(SetFanMaxRpm), > + MSG_MAP(SetFanMinPwm), > + MSG_MAP(ConfigureGfxDidt), > + MSG_MAP(NumOfDisplays), > + MSG_MAP(RemoveMargins), > + MSG_MAP(ReadSerialNumTop32), > + MSG_MAP(ReadSerialNumBottom32), > + MSG_MAP(SetSystemVirtualDramAddrHigh), > + MSG_MAP(SetSystemVirtualDramAddrLow), > + MSG_MAP(WaflTest), > + MSG_MAP(SetFclkGfxClkRatio), > + MSG_MAP(AllowGfxOff), > + MSG_MAP(DisallowGfxOff), > + MSG_MAP(GetPptLimit), > + MSG_MAP(GetDcModeMaxDpmFreq), > + MSG_MAP(GetDebugData), > + MSG_MAP(SetXgmiMode), > + MSG_MAP(RunAfllBtc), > + MSG_MAP(ExitBaco), > + MSG_MAP(PrepareMp1ForReset), > + MSG_MAP(PrepareMp1ForShutdown), > + MSG_MAP(SetMGpuFanBoostLimitRpm), > + MSG_MAP(GetAVFSVoltageByDpm), > +}; > + > +static int vega20_clk_map[SMU_CLK_COUNT] = { > + CLK_MAP(GFXCLK, PPCLK_GFXCLK), > + CLK_MAP(VCLK, PPCLK_VCLK), > + CLK_MAP(DCLK, PPCLK_DCLK), > + CLK_MAP(ECLK, PPCLK_ECLK), > + CLK_MAP(SOCCLK, PPCLK_SOCCLK), > + CLK_MAP(UCLK, PPCLK_UCLK), > + CLK_MAP(DCEFCLK, PPCLK_DCEFCLK), > + CLK_MAP(DISPCLK, PPCLK_DISPCLK), > + CLK_MAP(PIXCLK, PPCLK_PIXCLK), > + CLK_MAP(PHYCLK, PPCLK_PHYCLK), > + CLK_MAP(FCLK, PPCLK_FCLK), > +}; > + > +static int vega20_feature_mask_map[SMU_FEATURE_COUNT] = { > + FEA_MAP(DPM_PREFETCHER), > + FEA_MAP(DPM_GFXCLK), > + FEA_MAP(DPM_UCLK), > + FEA_MAP(DPM_SOCCLK), > + FEA_MAP(DPM_UVD), > + FEA_MAP(DPM_VCE), > + FEA_MAP(ULV), > + FEA_MAP(DPM_MP0CLK), > + FEA_MAP(DPM_LINK), > + FEA_MAP(DPM_DCEFCLK), > + FEA_MAP(DS_GFXCLK), > + FEA_MAP(DS_SOCCLK), > + FEA_MAP(DS_LCLK), > + FEA_MAP(PPT), > + FEA_MAP(TDC), > + FEA_MAP(THERMAL), > + FEA_MAP(GFX_PER_CU_CG), > + FEA_MAP(RM), > + FEA_MAP(DS_DCEFCLK), > + FEA_MAP(ACDC), > + FEA_MAP(VR0HOT), > + FEA_MAP(VR1HOT), > + FEA_MAP(FW_CTF), > + FEA_MAP(LED_DISPLAY), > + FEA_MAP(FAN_CONTROL), > + FEA_MAP(GFX_EDC), > + FEA_MAP(GFXOFF), > + FEA_MAP(CG), > + FEA_MAP(DPM_FCLK), > + FEA_MAP(DS_FCLK), > + FEA_MAP(DS_MP1CLK), > + FEA_MAP(DS_MP0CLK), > + FEA_MAP(XGMI), > +}; > + > +static int vega20_table_map[SMU_TABLE_COUNT] = { > + TAB_MAP(PPTABLE), > + TAB_MAP(WATERMARKS), > + TAB_MAP(AVFS), > + TAB_MAP(AVFS_PSM_DEBUG), > + TAB_MAP(AVFS_FUSE_OVERRIDE), > + TAB_MAP(PMSTATUSLOG), > + TAB_MAP(SMU_METRICS), > + TAB_MAP(DRIVER_SMU_CONFIG), > + TAB_MAP(ACTIVITY_MONITOR_COEFF), > + TAB_MAP(OVERDRIVE), > +}; > + > +static int vega20_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { > + PWR_MAP(AC), > + PWR_MAP(DC), > +}; > + > +static int vega20_workload_map[] = { > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT, > WORKLOAD_DEFAULT_BIT), > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D, > WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT), > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING, > WORKLOAD_PPLIB_POWER_SAVING_BIT), > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO, > WORKLOAD_PPLIB_VIDEO_BIT), > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR, > WORKLOAD_PPLIB_VR_BIT), > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, > WORKLOAD_PPLIB_CUSTOM_BIT), > + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, > WORKLOAD_PPLIB_CUSTOM_BIT), > +}; > + > +static int vega20_get_smu_table_index(struct smu_context *smc, uint32_t > index) > +{ > + int val; > + if (index >= SMU_TABLE_COUNT) > + return -EINVAL; > + > + val = vega20_table_map[index]; > + if (val >= TABLE_COUNT) > + return -EINVAL; > + > + return val; > +} > + > +static int vega20_get_pwr_src_index(struct smu_context *smc, uint32_t > index) > +{ > + int val; > + if (index >= SMU_POWER_SOURCE_COUNT) > + return -EINVAL; > + > + val = vega20_pwr_src_map[index]; > + if (val >= POWER_SOURCE_COUNT) > + return -EINVAL; > + > + return val; > +} > + > +static int vega20_get_smu_feature_index(struct smu_context *smc, > uint32_t index) > +{ > + int val; > + if (index >= SMU_FEATURE_COUNT) > + return -EINVAL; > + > + val = vega20_feature_mask_map[index]; > + if (val > 64) > + return -EINVAL; > + > + return val; > +} > + > +static int vega20_get_smu_clk_index(struct smu_context *smc, uint32_t > index) > +{ > + int val; > + if (index >= SMU_CLK_COUNT) > + return -EINVAL; > + > + val = vega20_clk_map[index]; > + if (val >= PPCLK_COUNT) > + return -EINVAL; > + > + return val; > +} > + > +static int vega20_get_smu_msg_index(struct smu_context *smc, uint32_t > index) > +{ > + int val; > + > + if (index >= SMU_MSG_MAX_COUNT) > + return -EINVAL; > + > + val = vega20_message_map[index]; > + if (val > PPSMC_Message_Count) > + return -EINVAL; > + > + return val; > +} > + > +static int vega20_get_workload_type(struct smu_context *smu, enum > PP_SMC_POWER_PROFILE profile) > +{ > + int val; > + if (profile > PP_SMC_POWER_PROFILE_CUSTOM) > + return -EINVAL; > + > + val = vega20_workload_map[profile]; > + > + return val; > +} > + > +static int vega20_tables_init(struct smu_context *smu, struct smu_table > *tables) > +{ > + struct smu_table_context *smu_table = &smu->smu_table; > + > + SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), > + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > + SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, > sizeof(Watermarks_t), > + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > + SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, > sizeof(SmuMetrics_t), > + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > + SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, > sizeof(OverDriveTable_t), > + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > + SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, > SMU11_TOOL_SIZE, > + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > + SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF, > + sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE, > + AMDGPU_GEM_DOMAIN_VRAM); > + > + smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), > GFP_KERNEL); > + if (smu_table->metrics_table) > + return -ENOMEM; > + smu_table->metrics_time = 0; > + > + return 0; > +} > + > +static int vega20_allocate_dpm_context(struct smu_context *smu) > +{ > + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > + > + if (smu_dpm->dpm_context) > + return -EINVAL; > + > + smu_dpm->dpm_context = kzalloc(sizeof(struct vega20_dpm_table), > + GFP_KERNEL); > + if (!smu_dpm->dpm_context) > + return -ENOMEM; > + > + if (smu_dpm->golden_dpm_context) > + return -EINVAL; > + > + smu_dpm->golden_dpm_context = kzalloc(sizeof(struct > vega20_dpm_table), > + GFP_KERNEL); > + if (!smu_dpm->golden_dpm_context) > + return -ENOMEM; > + > + smu_dpm->dpm_context_size = sizeof(struct vega20_dpm_table); > + > + smu_dpm->dpm_current_power_state = kzalloc(sizeof(struct > smu_power_state), > + GFP_KERNEL); > + if (!smu_dpm->dpm_current_power_state) > + return -ENOMEM; > + > + smu_dpm->dpm_request_power_state = kzalloc(sizeof(struct > smu_power_state), > + GFP_KERNEL); > + if (!smu_dpm->dpm_request_power_state) > + return -ENOMEM; > + > + return 0; > +} > + > +static int vega20_setup_od8_information(struct smu_context *smu) > +{ > + ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL; > + struct smu_table_context *table_context = &smu->smu_table; > + struct vega20_od8_settings *od8_settings = (struct > vega20_od8_settings *)smu->od_settings; > + > + uint32_t od_feature_count, od_feature_array_size, > + od_setting_count, od_setting_array_size; > + > + if (!table_context->power_play_table) > + return -EINVAL; > + > + powerplay_table = table_context->power_play_table; > + > + if (powerplay_table->OverDrive8Table.ucODTableRevision == 1) { > + /* Setup correct ODFeatureCount, and store ODFeatureArray > from > + * powerplay table to od_feature_capabilities */ > + od_feature_count = > + (le32_to_cpu(powerplay_table- > >OverDrive8Table.ODFeatureCount) > > + ATOM_VEGA20_ODFEATURE_COUNT) ? > + ATOM_VEGA20_ODFEATURE_COUNT : > + le32_to_cpu(powerplay_table- > >OverDrive8Table.ODFeatureCount); > + > + od_feature_array_size = sizeof(uint8_t) * od_feature_count; > + > + if (od8_settings->od_feature_capabilities) > + return -EINVAL; > + > + od8_settings->od_feature_capabilities = > kmemdup(&powerplay_table->OverDrive8Table.ODFeatureCapabilities, > + > od_feature_array_size, > + > GFP_KERNEL); > + if (!od8_settings->od_feature_capabilities) > + return -ENOMEM; > + > + /* Setup correct ODSettingCount, and store ODSettingArray > from > + * powerplay table to od_settings_max and od_setting_min > */ > + od_setting_count = > + (le32_to_cpu(powerplay_table- > >OverDrive8Table.ODSettingCount) > > + ATOM_VEGA20_ODSETTING_COUNT) ? > + ATOM_VEGA20_ODSETTING_COUNT : > + le32_to_cpu(powerplay_table- > >OverDrive8Table.ODSettingCount); > + > + od_setting_array_size = sizeof(uint32_t) * od_setting_count; > + > + if (od8_settings->od_settings_max) > + return -EINVAL; > + > + od8_settings->od_settings_max = > kmemdup(&powerplay_table->OverDrive8Table.ODSettingsMax, > + > od_setting_array_size, > + GFP_KERNEL); > + > + if (!od8_settings->od_settings_max) { > + kfree(od8_settings->od_feature_capabilities); > + od8_settings->od_feature_capabilities = NULL; > + return -ENOMEM; > + } > + > + if (od8_settings->od_settings_min) > + return -EINVAL; > + > + od8_settings->od_settings_min = > kmemdup(&powerplay_table->OverDrive8Table.ODSettingsMin, > + > od_setting_array_size, > + GFP_KERNEL); > + > + if (!od8_settings->od_settings_min) { > + kfree(od8_settings->od_feature_capabilities); > + od8_settings->od_feature_capabilities = NULL; > + kfree(od8_settings->od_settings_max); > + od8_settings->od_settings_max = NULL; > + return -ENOMEM; > + } > + } > + > + return 0; > +} > + > +static int vega20_store_powerplay_table(struct smu_context *smu) > +{ > + ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL; > + struct smu_table_context *table_context = &smu->smu_table; > + int ret; > + > + if (!table_context->power_play_table) > + return -EINVAL; > + > + powerplay_table = table_context->power_play_table; > + > + memcpy(table_context->driver_pptable, &powerplay_table- > >smcPPTable, > + sizeof(PPTable_t)); > + > + table_context->software_shutdown_temp = powerplay_table- > >usSoftwareShutdownTemp; > + table_context->thermal_controller_type = powerplay_table- > >ucThermalControllerType; > + table_context->TDPODLimit = le32_to_cpu(powerplay_table- > >OverDrive8Table.ODSettingsMax[ATOM_VEGA20_ODSETTING_POWERPER > CENTAGE]); > + > + ret = vega20_setup_od8_information(smu); > + > + return ret; > +} > + > +static int vega20_append_powerplay_table(struct smu_context *smu) > +{ > + struct smu_table_context *table_context = &smu->smu_table; > + PPTable_t *smc_pptable = table_context->driver_pptable; > + struct atom_smc_dpm_info_v4_4 *smc_dpm_table; > + int index, i, ret; > + > + index = > get_index_into_master_table(atom_master_list_of_data_tables_v2_1, > + smc_dpm_info); > + > + ret = smu_get_atom_data_table(smu, index, NULL, NULL, NULL, > + (uint8_t **)&smc_dpm_table); > + if (ret) > + return ret; > + > + smc_pptable->MaxVoltageStepGfx = smc_dpm_table- > >maxvoltagestepgfx; > + smc_pptable->MaxVoltageStepSoc = smc_dpm_table- > >maxvoltagestepsoc; > + > + smc_pptable->VddGfxVrMapping = smc_dpm_table- > >vddgfxvrmapping; > + smc_pptable->VddSocVrMapping = smc_dpm_table- > >vddsocvrmapping; > + smc_pptable->VddMem0VrMapping = smc_dpm_table- > >vddmem0vrmapping; > + smc_pptable->VddMem1VrMapping = smc_dpm_table- > >vddmem1vrmapping; > + > + smc_pptable->GfxUlvPhaseSheddingMask = smc_dpm_table- > >gfxulvphasesheddingmask; > + smc_pptable->SocUlvPhaseSheddingMask = smc_dpm_table- > >soculvphasesheddingmask; > + smc_pptable->ExternalSensorPresent = smc_dpm_table- > >externalsensorpresent; > + > + smc_pptable->GfxMaxCurrent = smc_dpm_table->gfxmaxcurrent; > + smc_pptable->GfxOffset = smc_dpm_table->gfxoffset; > + smc_pptable->Padding_TelemetryGfx = smc_dpm_table- > >padding_telemetrygfx; > + > + smc_pptable->SocMaxCurrent = smc_dpm_table->socmaxcurrent; > + smc_pptable->SocOffset = smc_dpm_table->socoffset; > + smc_pptable->Padding_TelemetrySoc = smc_dpm_table- > >padding_telemetrysoc; > + > + smc_pptable->Mem0MaxCurrent = smc_dpm_table- > >mem0maxcurrent; > + smc_pptable->Mem0Offset = smc_dpm_table->mem0offset; > + smc_pptable->Padding_TelemetryMem0 = smc_dpm_table- > >padding_telemetrymem0; > + > + smc_pptable->Mem1MaxCurrent = smc_dpm_table- > >mem1maxcurrent; > + smc_pptable->Mem1Offset = smc_dpm_table->mem1offset; > + smc_pptable->Padding_TelemetryMem1 = smc_dpm_table- > >padding_telemetrymem1; > + > + smc_pptable->AcDcGpio = smc_dpm_table->acdcgpio; > + smc_pptable->AcDcPolarity = smc_dpm_table->acdcpolarity; > + smc_pptable->VR0HotGpio = smc_dpm_table->vr0hotgpio; > + smc_pptable->VR0HotPolarity = smc_dpm_table->vr0hotpolarity; > + > + smc_pptable->VR1HotGpio = smc_dpm_table->vr1hotgpio; > + smc_pptable->VR1HotPolarity = smc_dpm_table->vr1hotpolarity; > + smc_pptable->Padding1 = smc_dpm_table->padding1; > + smc_pptable->Padding2 = smc_dpm_table->padding2; > + > + smc_pptable->LedPin0 = smc_dpm_table->ledpin0; > + smc_pptable->LedPin1 = smc_dpm_table->ledpin1; > + smc_pptable->LedPin2 = smc_dpm_table->ledpin2; > + > + smc_pptable->PllGfxclkSpreadEnabled = smc_dpm_table- > >pllgfxclkspreadenabled; > + smc_pptable->PllGfxclkSpreadPercent = smc_dpm_table- > >pllgfxclkspreadpercent; > + smc_pptable->PllGfxclkSpreadFreq = smc_dpm_table- > >pllgfxclkspreadfreq; > + > + smc_pptable->UclkSpreadEnabled = 0; > + smc_pptable->UclkSpreadPercent = smc_dpm_table- > >uclkspreadpercent; > + smc_pptable->UclkSpreadFreq = smc_dpm_table->uclkspreadfreq; > + > + smc_pptable->FclkSpreadEnabled = smc_dpm_table- > >fclkspreadenabled; > + smc_pptable->FclkSpreadPercent = smc_dpm_table- > >fclkspreadpercent; > + smc_pptable->FclkSpreadFreq = smc_dpm_table->fclkspreadfreq; > + > + smc_pptable->FllGfxclkSpreadEnabled = smc_dpm_table- > >fllgfxclkspreadenabled; > + smc_pptable->FllGfxclkSpreadPercent = smc_dpm_table- > >fllgfxclkspreadpercent; > + smc_pptable->FllGfxclkSpreadFreq = smc_dpm_table- > >fllgfxclkspreadfreq; > + > + for (i = 0; i < I2C_CONTROLLER_NAME_COUNT; i++) { > + smc_pptable->I2cControllers[i].Enabled = > + smc_dpm_table->i2ccontrollers[i].enabled; > + smc_pptable->I2cControllers[i].SlaveAddress = > + smc_dpm_table->i2ccontrollers[i].slaveaddress; > + smc_pptable->I2cControllers[i].ControllerPort = > + smc_dpm_table->i2ccontrollers[i].controllerport; > + smc_pptable->I2cControllers[i].ThermalThrottler = > + smc_dpm_table->i2ccontrollers[i].thermalthrottler; > + smc_pptable->I2cControllers[i].I2cProtocol = > + smc_dpm_table->i2ccontrollers[i].i2cprotocol; > + smc_pptable->I2cControllers[i].I2cSpeed = > + smc_dpm_table->i2ccontrollers[i].i2cspeed; > + } > + > + return 0; > +} > + > +static int vega20_check_powerplay_table(struct smu_context *smu) > +{ > + ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL; > + struct smu_table_context *table_context = &smu->smu_table; > + > + powerplay_table = table_context->power_play_table; > + > + if (powerplay_table->sHeader.format_revision < > ATOM_VEGA20_TABLE_REVISION_VEGA20) { > + pr_err("Unsupported PPTable format!"); > + return -EINVAL; > + } > + > + if (!powerplay_table->sHeader.structuresize) { > + pr_err("Invalid PowerPlay Table!"); > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int vega20_run_btc_afll(struct smu_context *smu) > +{ > + return smu_send_smc_msg(smu, SMU_MSG_RunAfllBtc); > +} > + > +#define FEATURE_MASK(feature) (1ULL << feature) > +static int > +vega20_get_allowed_feature_mask(struct smu_context *smu, > + uint32_t *feature_mask, uint32_t num) > +{ > + if (num > 2) > + return -EINVAL; > + > + memset(feature_mask, 0, sizeof(uint32_t) * num); > + > + *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) > + | > FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) > + | FEATURE_MASK(FEATURE_DPM_UCLK_BIT) > + | > FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) > + | FEATURE_MASK(FEATURE_DPM_UVD_BIT) > + | FEATURE_MASK(FEATURE_DPM_VCE_BIT) > + | FEATURE_MASK(FEATURE_ULV_BIT) > + | > FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) > + | FEATURE_MASK(FEATURE_DPM_LINK_BIT) > + | > FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT) > + | FEATURE_MASK(FEATURE_PPT_BIT) > + | FEATURE_MASK(FEATURE_TDC_BIT) > + | FEATURE_MASK(FEATURE_THERMAL_BIT) > + | > FEATURE_MASK(FEATURE_GFX_PER_CU_CG_BIT) > + | FEATURE_MASK(FEATURE_RM_BIT) > + | FEATURE_MASK(FEATURE_ACDC_BIT) > + | FEATURE_MASK(FEATURE_VR0HOT_BIT) > + | FEATURE_MASK(FEATURE_VR1HOT_BIT) > + | FEATURE_MASK(FEATURE_FW_CTF_BIT) > + | > FEATURE_MASK(FEATURE_LED_DISPLAY_BIT) > + | > FEATURE_MASK(FEATURE_FAN_CONTROL_BIT) > + | FEATURE_MASK(FEATURE_GFX_EDC_BIT) > + | FEATURE_MASK(FEATURE_GFXOFF_BIT) > + | FEATURE_MASK(FEATURE_CG_BIT) > + | FEATURE_MASK(FEATURE_DPM_FCLK_BIT) > + | FEATURE_MASK(FEATURE_XGMI_BIT); > + return 0; > +} > + > +static enum > +amd_pm_state_type vega20_get_current_power_state(struct > smu_context *smu) > +{ > + enum amd_pm_state_type pm_type; > + struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); > + > + if (!smu_dpm_ctx->dpm_context || > + !smu_dpm_ctx->dpm_current_power_state) > + return -EINVAL; > + > + mutex_lock(&(smu->mutex)); > + switch (smu_dpm_ctx->dpm_current_power_state- > >classification.ui_label) { > + case SMU_STATE_UI_LABEL_BATTERY: > + pm_type = POWER_STATE_TYPE_BATTERY; > + break; > + case SMU_STATE_UI_LABEL_BALLANCED: > + pm_type = POWER_STATE_TYPE_BALANCED; > + break; > + case SMU_STATE_UI_LABEL_PERFORMANCE: > + pm_type = POWER_STATE_TYPE_PERFORMANCE; > + break; > + default: > + if (smu_dpm_ctx->dpm_current_power_state- > >classification.flags & SMU_STATE_CLASSIFICATION_FLAG_BOOT) > + pm_type = POWER_STATE_TYPE_INTERNAL_BOOT; > + else > + pm_type = POWER_STATE_TYPE_DEFAULT; > + break; > + } > + mutex_unlock(&(smu->mutex)); > + > + return pm_type; > +} > + > +static int > +vega20_set_single_dpm_table(struct smu_context *smu, > + struct vega20_single_dpm_table > *single_dpm_table, > + PPCLK_e clk_id) > +{ > + int ret = 0; > + uint32_t i, num_of_levels = 0, clk; > + > + ret = smu_send_smc_msg_with_param(smu, > + SMU_MSG_GetDpmFreqByIndex, > + (clk_id << 16 | 0xFF)); > + if (ret) { > + pr_err("[GetNumOfDpmLevel] failed to get dpm levels!"); > + return ret; > + } > + > + smu_read_smc_arg(smu, &num_of_levels); > + if (!num_of_levels) { > + pr_err("[GetNumOfDpmLevel] number of clk levels is > invalid!"); > + return -EINVAL; > + } > + > + single_dpm_table->count = num_of_levels; > + > + for (i = 0; i < num_of_levels; i++) { > + ret = smu_send_smc_msg_with_param(smu, > + SMU_MSG_GetDpmFreqByIndex, > + (clk_id << 16 | i)); > + if (ret) { > + pr_err("[GetDpmFreqByIndex] failed to get dpm freq > by index!"); > + return ret; > + } > + smu_read_smc_arg(smu, &clk); > + if (!clk) { > + pr_err("[GetDpmFreqByIndex] clk value is invalid!"); > + return -EINVAL; > + } > + single_dpm_table->dpm_levels[i].value = clk; > + single_dpm_table->dpm_levels[i].enabled = true; > + } > + return 0; > +} > + > +static void vega20_init_single_dpm_state(struct vega20_dpm_state > *dpm_state) > +{ > + dpm_state->soft_min_level = 0x0; > + dpm_state->soft_max_level = 0xffff; > + dpm_state->hard_min_level = 0x0; > + dpm_state->hard_max_level = 0xffff; > +} > + > +static int vega20_set_default_dpm_table(struct smu_context *smu) > +{ > + int ret; > + > + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > + struct vega20_dpm_table *dpm_table = NULL; > + struct vega20_single_dpm_table *single_dpm_table; > + > + dpm_table = smu_dpm->dpm_context; > + > + /* socclk */ > + single_dpm_table = &(dpm_table->soc_table); > + > + if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_SOCCLK_BIT)) { > + ret = vega20_set_single_dpm_table(smu, single_dpm_table, > + PPCLK_SOCCLK); > + if (ret) { > + pr_err("[SetupDefaultDpmTable] failed to get socclk > dpm levels!"); > + return ret; > + } > + } else { > + single_dpm_table->count = 1; > + single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.socclk / 100; > + } > + vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > + > + /* gfxclk */ > + single_dpm_table = &(dpm_table->gfx_table); > + > + if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_GFXCLK_BIT)) { > + ret = vega20_set_single_dpm_table(smu, single_dpm_table, > + PPCLK_GFXCLK); > + if (ret) { > + pr_err("[SetupDefaultDpmTable] failed to get gfxclk > dpm levels!"); > + return ret; > + } > + } else { > + single_dpm_table->count = 1; > + single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.gfxclk / 100; > + } > + vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > + > + /* memclk */ > + single_dpm_table = &(dpm_table->mem_table); > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) > { > + ret = vega20_set_single_dpm_table(smu, single_dpm_table, > + PPCLK_UCLK); > + if (ret) { > + pr_err("[SetupDefaultDpmTable] failed to get > memclk dpm levels!"); > + return ret; > + } > + } else { > + single_dpm_table->count = 1; > + single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.uclk / 100; > + } > + vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > + > + /* eclk */ > + single_dpm_table = &(dpm_table->eclk_table); > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_VCE_BIT)) { > + ret = vega20_set_single_dpm_table(smu, single_dpm_table, > PPCLK_ECLK); > + if (ret) { > + pr_err("[SetupDefaultDpmTable] failed to get eclk > dpm levels!"); > + return ret; > + } > + } else { > + single_dpm_table->count = 1; > + single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.eclk / 100; > + } > + vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > + > + /* vclk */ > + single_dpm_table = &(dpm_table->vclk_table); > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT)) { > + ret = vega20_set_single_dpm_table(smu, single_dpm_table, > PPCLK_VCLK); > + if (ret) { > + pr_err("[SetupDefaultDpmTable] failed to get vclk > dpm levels!"); > + return ret; > + } > + } else { > + single_dpm_table->count = 1; > + single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.vclk / 100; > + } > + vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > + > + /* dclk */ > + single_dpm_table = &(dpm_table->dclk_table); > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT)) { > + ret = vega20_set_single_dpm_table(smu, single_dpm_table, > PPCLK_DCLK); > + if (ret) { > + pr_err("[SetupDefaultDpmTable] failed to get dclk > dpm levels!"); > + return ret; > + } > + } else { > + single_dpm_table->count = 1; > + single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.dclk / 100; > + } > + vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > + > + /* dcefclk */ > + single_dpm_table = &(dpm_table->dcef_table); > + > + if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT)) { > + ret = vega20_set_single_dpm_table(smu, single_dpm_table, > + PPCLK_DCEFCLK); > + if (ret) { > + pr_err("[SetupDefaultDpmTable] failed to get dcefclk > dpm levels!"); > + return ret; > + } > + } else { > + single_dpm_table->count = 1; > + single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.dcefclk / 100; > + } > + vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > + > + /* pixclk */ > + single_dpm_table = &(dpm_table->pixel_table); > + > + if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT)) { > + ret = vega20_set_single_dpm_table(smu, single_dpm_table, > + PPCLK_PIXCLK); > + if (ret) { > + pr_err("[SetupDefaultDpmTable] failed to get pixclk > dpm levels!"); > + return ret; > + } > + } else { > + single_dpm_table->count = 0; > + } > + vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > + > + /* dispclk */ > + single_dpm_table = &(dpm_table->display_table); > + > + if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT)) { > + ret = vega20_set_single_dpm_table(smu, single_dpm_table, > + PPCLK_DISPCLK); > + if (ret) { > + pr_err("[SetupDefaultDpmTable] failed to get dispclk > dpm levels!"); > + return ret; > + } > + } else { > + single_dpm_table->count = 0; > + } > + vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > + > + /* phyclk */ > + single_dpm_table = &(dpm_table->phy_table); > + > + if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT)) { > + ret = vega20_set_single_dpm_table(smu, single_dpm_table, > + PPCLK_PHYCLK); > + if (ret) { > + pr_err("[SetupDefaultDpmTable] failed to get phyclk > dpm levels!"); > + return ret; > + } > + } else { > + single_dpm_table->count = 0; > + } > + vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > + > + /* fclk */ > + single_dpm_table = &(dpm_table->fclk_table); > + > + if (smu_feature_is_enabled(smu,FEATURE_DPM_FCLK_BIT)) { > + ret = vega20_set_single_dpm_table(smu, single_dpm_table, > + PPCLK_FCLK); > + if (ret) { > + pr_err("[SetupDefaultDpmTable] failed to get fclk > dpm levels!"); > + return ret; > + } > + } else { > + single_dpm_table->count = 0; > + } > + vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > + > + memcpy(smu_dpm->golden_dpm_context, dpm_table, > + sizeof(struct vega20_dpm_table)); > + > + return 0; > +} > + > +static int vega20_populate_umd_state_clk(struct smu_context *smu) > +{ > + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > + struct vega20_dpm_table *dpm_table = NULL; > + struct vega20_single_dpm_table *gfx_table = NULL; > + struct vega20_single_dpm_table *mem_table = NULL; > + > + dpm_table = smu_dpm->dpm_context; > + gfx_table = &(dpm_table->gfx_table); > + mem_table = &(dpm_table->mem_table); > + > + smu->pstate_sclk = gfx_table->dpm_levels[0].value; > + smu->pstate_mclk = mem_table->dpm_levels[0].value; > + > + if (gfx_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL && > + mem_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL) { > + smu->pstate_sclk = gfx_table- > >dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value; > + smu->pstate_mclk = mem_table- > >dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value; > + } > + > + smu->pstate_sclk = smu->pstate_sclk * 100; > + smu->pstate_mclk = smu->pstate_mclk * 100; > + > + return 0; > +} > + > +static int vega20_get_clk_table(struct smu_context *smu, > + struct pp_clock_levels_with_latency *clocks, > + struct vega20_single_dpm_table *dpm_table) > +{ > + int i, count; > + > + count = (dpm_table->count > MAX_NUM_CLOCKS) ? > MAX_NUM_CLOCKS : dpm_table->count; > + clocks->num_levels = count; > + > + for (i = 0; i < count; i++) { > + clocks->data[i].clocks_in_khz = > + dpm_table->dpm_levels[i].value * 1000; > + clocks->data[i].latency_in_us = 0; > + } > + > + return 0; > +} > + > +static int vega20_print_clk_levels(struct smu_context *smu, > + enum smu_clk_type type, char *buf) > +{ > + int i, now, size = 0; > + int ret = 0; > + uint32_t gen_speed, lane_width; > + struct amdgpu_device *adev = smu->adev; > + struct pp_clock_levels_with_latency clocks; > + struct vega20_single_dpm_table *single_dpm_table; > + struct smu_table_context *table_context = &smu->smu_table; > + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > + struct vega20_dpm_table *dpm_table = NULL; > + struct vega20_od8_settings *od8_settings = > + (struct vega20_od8_settings *)smu->od_settings; > + OverDriveTable_t *od_table = > + (OverDriveTable_t *)(table_context->overdrive_table); > + PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable; > + > + dpm_table = smu_dpm->dpm_context; > + > + switch (type) { > + case SMU_SCLK: > + ret = smu_get_current_clk_freq(smu, SMU_GFXCLK, &now); > + if (ret) { > + pr_err("Attempt to get current gfx clk Failed!"); > + return ret; > + } > + > + single_dpm_table = &(dpm_table->gfx_table); > + ret = vega20_get_clk_table(smu, &clocks, single_dpm_table); > + if (ret) { > + pr_err("Attempt to get gfx clk levels Failed!"); > + return ret; > + } > + > + for (i = 0; i < clocks.num_levels; i++) > + size += sprintf(buf + size, "%d: %uMhz %s\n", i, > + clocks.data[i].clocks_in_khz / 1000, > + (clocks.data[i].clocks_in_khz == now > * 10) > + ? "*" : ""); > + break; > + > + case SMU_MCLK: > + ret = smu_get_current_clk_freq(smu, SMU_UCLK, &now); > + if (ret) { > + pr_err("Attempt to get current mclk Failed!"); > + return ret; > + } > + > + single_dpm_table = &(dpm_table->mem_table); > + ret = vega20_get_clk_table(smu, &clocks, single_dpm_table); > + if (ret) { > + pr_err("Attempt to get memory clk levels Failed!"); > + return ret; > + } > + > + for (i = 0; i < clocks.num_levels; i++) > + size += sprintf(buf + size, "%d: %uMhz %s\n", > + i, clocks.data[i].clocks_in_khz / 1000, > + (clocks.data[i].clocks_in_khz == now * 10) > + ? "*" : ""); > + break; > + > + case SMU_SOCCLK: > + ret = smu_get_current_clk_freq(smu, PPCLK_SOCCLK, > &now); > + if (ret) { > + pr_err("Attempt to get current socclk Failed!"); > + return ret; > + } > + > + single_dpm_table = &(dpm_table->soc_table); > + ret = vega20_get_clk_table(smu, &clocks, single_dpm_table); > + if (ret) { > + pr_err("Attempt to get socclk levels Failed!"); > + return ret; > + } > + > + for (i = 0; i < clocks.num_levels; i++) > + size += sprintf(buf + size, "%d: %uMhz %s\n", > + i, clocks.data[i].clocks_in_khz / 1000, > + (clocks.data[i].clocks_in_khz == now * 10) > + ? "*" : ""); > + break; > + > + case SMU_FCLK: > + ret = smu_get_current_clk_freq(smu, PPCLK_FCLK, &now); > + if (ret) { > + pr_err("Attempt to get current fclk Failed!"); > + return ret; > + } > + > + single_dpm_table = &(dpm_table->fclk_table); > + for (i = 0; i < single_dpm_table->count; i++) > + size += sprintf(buf + size, "%d: %uMhz %s\n", > + i, single_dpm_table->dpm_levels[i].value, > + (single_dpm_table->dpm_levels[i].value == > now / 100) > + ? "*" : ""); > + break; > + > + case SMU_DCEFCLK: > + ret = smu_get_current_clk_freq(smu, PPCLK_DCEFCLK, > &now); > + if (ret) { > + pr_err("Attempt to get current dcefclk Failed!"); > + return ret; > + } > + > + single_dpm_table = &(dpm_table->dcef_table); > + ret = vega20_get_clk_table(smu, &clocks, single_dpm_table); > + if (ret) { > + pr_err("Attempt to get dcefclk levels Failed!"); > + return ret; > + } > + > + for (i = 0; i < clocks.num_levels; i++) > + size += sprintf(buf + size, "%d: %uMhz %s\n", > + i, clocks.data[i].clocks_in_khz / 1000, > + (clocks.data[i].clocks_in_khz == now * 10) ? > "*" : ""); > + break; > + > + case SMU_PCIE: > + gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & > + > PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) > + >> > PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT; > + lane_width = > (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) & > + > PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK) > + >> > PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT; > + for (i = 0; i < NUM_LINK_LEVELS; i++) > + size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i, > + (pptable->PcieGenSpeed[i] == 0) ? > "2.5GT/s," : > + (pptable->PcieGenSpeed[i] == 1) ? > "5.0GT/s," : > + (pptable->PcieGenSpeed[i] == 2) ? > "8.0GT/s," : > + (pptable->PcieGenSpeed[i] == 3) ? > "16.0GT/s," : "", > + (pptable->PcieLaneCount[i] == 1) ? > "x1" : > + (pptable->PcieLaneCount[i] == 2) ? > "x2" : > + (pptable->PcieLaneCount[i] == 3) ? > "x4" : > + (pptable->PcieLaneCount[i] == 4) ? > "x8" : > + (pptable->PcieLaneCount[i] == 5) ? > "x12" : > + (pptable->PcieLaneCount[i] == 6) ? > "x16" : "", > + pptable->LclkFreq[i], > + (gen_speed == pptable- > >PcieGenSpeed[i]) && > + (lane_width == pptable- > >PcieLaneCount[i]) ? > + "*" : ""); > + break; > + > + case SMU_OD_SCLK: > + if (od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id) { > + size = sprintf(buf, "%s:\n", "OD_SCLK"); > + size += sprintf(buf + size, "0: %10uMhz\n", > + od_table->GfxclkFmin); > + size += sprintf(buf + size, "1: %10uMhz\n", > + od_table->GfxclkFmax); > + } > + > + break; > + > + case SMU_OD_MCLK: > + if (od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) { > + size = sprintf(buf, "%s:\n", "OD_MCLK"); > + size += sprintf(buf + size, "1: %10uMhz\n", > + od_table->UclkFmax); > + } > + > + break; > + > + case SMU_OD_VDDC_CURVE: > + if (od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) { > + size = sprintf(buf, "%s:\n", "OD_VDDC_CURVE"); > + size += sprintf(buf + size, "0: %10uMhz %10dmV\n", > + od_table->GfxclkFreq1, > + od_table->GfxclkVolt1 / > VOLTAGE_SCALE); > + size += sprintf(buf + size, "1: %10uMhz %10dmV\n", > + od_table->GfxclkFreq2, > + od_table->GfxclkVolt2 / > VOLTAGE_SCALE); > + size += sprintf(buf + size, "2: %10uMhz %10dmV\n", > + od_table->GfxclkFreq3, > + od_table->GfxclkVolt3 / > VOLTAGE_SCALE); > + } > + > + break; > + > + case SMU_OD_RANGE: > + size = sprintf(buf, "%s:\n", "OD_RANGE"); > + > + if (od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id) { > + size += sprintf(buf + size, > "SCLK: %7uMhz %10uMhz\n", > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value, > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value); > + } > + > + if (od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) { > + single_dpm_table = &(dpm_table->mem_table); > + ret = vega20_get_clk_table(smu, &clocks, > single_dpm_table); > + if (ret) { > + pr_err("Attempt to get memory clk levels > Failed!"); > + return ret; > + } > + > + size += sprintf(buf + size, > "MCLK: %7uMhz %10uMhz\n", > + clocks.data[0].clocks_in_khz / 1000, > + od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value); > + } > + > + if (od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) { > + size += sprintf(buf + size, > "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n", > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].min_value, > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].max_value); > + size += sprintf(buf + size, > "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n", > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].min_value, > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].max_value); > + size += sprintf(buf + size, > "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n", > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].min_value, > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].max_value); > + size += sprintf(buf + size, > "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n", > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].min_value, > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].max_value); > + size += sprintf(buf + size, > "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n", > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].min_value, > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].max_value); > + size += sprintf(buf + size, > "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n", > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].min_value, > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].max_value); > + } > + > + break; > + > + default: > + break; > + } > + return size; > +} > + > +static int vega20_upload_dpm_level(struct smu_context *smu, bool max, > + uint32_t feature_mask) > +{ > + struct vega20_dpm_table *dpm_table; > + struct vega20_single_dpm_table *single_dpm_table; > + uint32_t freq; > + int ret = 0; > + > + dpm_table = smu->smu_dpm.dpm_context; > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT) > && > + (feature_mask & FEATURE_DPM_GFXCLK_MASK)) { > + single_dpm_table = &(dpm_table->gfx_table); > + freq = max ? single_dpm_table->dpm_state.soft_max_level : > + single_dpm_table->dpm_state.soft_min_level; > + ret = smu_send_smc_msg_with_param(smu, > + (max ? SMU_MSG_SetSoftMaxByFreq : > SMU_MSG_SetSoftMinByFreq), > + (PPCLK_GFXCLK << 16) | (freq & 0xffff)); > + if (ret) { > + pr_err("Failed to set soft %s gfxclk !\n", > + max ? "max" : "min"); > + return ret; > + } > + } > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT) > && > + (feature_mask & FEATURE_DPM_UCLK_MASK)) { > + single_dpm_table = &(dpm_table->mem_table); > + freq = max ? single_dpm_table->dpm_state.soft_max_level : > + single_dpm_table->dpm_state.soft_min_level; > + ret = smu_send_smc_msg_with_param(smu, > + (max ? SMU_MSG_SetSoftMaxByFreq : > SMU_MSG_SetSoftMinByFreq), > + (PPCLK_UCLK << 16) | (freq & 0xffff)); > + if (ret) { > + pr_err("Failed to set soft %s memclk !\n", > + max ? "max" : "min"); > + return ret; > + } > + } > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT) > && > + (feature_mask & FEATURE_DPM_SOCCLK_MASK)) { > + single_dpm_table = &(dpm_table->soc_table); > + freq = max ? single_dpm_table->dpm_state.soft_max_level : > + single_dpm_table->dpm_state.soft_min_level; > + ret = smu_send_smc_msg_with_param(smu, > + (max ? SMU_MSG_SetSoftMaxByFreq : > SMU_MSG_SetSoftMinByFreq), > + (PPCLK_SOCCLK << 16) | (freq & 0xffff)); > + if (ret) { > + pr_err("Failed to set soft %s socclk !\n", > + max ? "max" : "min"); > + return ret; > + } > + } > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT) > && > + (feature_mask & FEATURE_DPM_FCLK_MASK)) { > + single_dpm_table = &(dpm_table->fclk_table); > + freq = max ? single_dpm_table->dpm_state.soft_max_level : > + single_dpm_table->dpm_state.soft_min_level; > + ret = smu_send_smc_msg_with_param(smu, > + (max ? SMU_MSG_SetSoftMaxByFreq : > SMU_MSG_SetSoftMinByFreq), > + (PPCLK_FCLK << 16) | (freq & 0xffff)); > + if (ret) { > + pr_err("Failed to set soft %s fclk !\n", > + max ? "max" : "min"); > + return ret; > + } > + } > + > + if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT) && > + (feature_mask & FEATURE_DPM_DCEFCLK_MASK)) { > + single_dpm_table = &(dpm_table->dcef_table); > + freq = single_dpm_table->dpm_state.hard_min_level; > + if (!max) { > + ret = smu_send_smc_msg_with_param(smu, > + SMU_MSG_SetHardMinByFreq, > + (PPCLK_DCEFCLK << 16) | (freq & 0xffff)); > + if (ret) { > + pr_err("Failed to set hard min dcefclk !\n"); > + return ret; > + } > + } > + } > + > + return ret; > +} > + > +static int vega20_force_clk_levels(struct smu_context *smu, > + enum smu_clk_type clk_type, uint32_t mask) > +{ > + struct vega20_dpm_table *dpm_table; > + struct vega20_single_dpm_table *single_dpm_table; > + uint32_t soft_min_level, soft_max_level, hard_min_level; > + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > + int ret = 0; > + > + if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) { > + pr_info("force clock level is for dpm manual mode only.\n"); > + return -EINVAL; > + } > + > + mutex_lock(&(smu->mutex)); > + > + soft_min_level = mask ? (ffs(mask) - 1) : 0; > + soft_max_level = mask ? (fls(mask) - 1) : 0; > + > + dpm_table = smu->smu_dpm.dpm_context; > + > + switch (clk_type) { > + case SMU_SCLK: > + single_dpm_table = &(dpm_table->gfx_table); > + > + if (soft_max_level >= single_dpm_table->count) { > + pr_err("Clock level specified %d is over max > allowed %d\n", > + soft_max_level, single_dpm_table- > >count - 1); > + ret = -EINVAL; > + break; > + } > + > + single_dpm_table->dpm_state.soft_min_level = > + single_dpm_table- > >dpm_levels[soft_min_level].value; > + single_dpm_table->dpm_state.soft_max_level = > + single_dpm_table- > >dpm_levels[soft_max_level].value; > + > + ret = vega20_upload_dpm_level(smu, false, > FEATURE_DPM_GFXCLK_MASK); > + if (ret) { > + pr_err("Failed to upload boot level to lowest!\n"); > + break; > + } > + > + ret = vega20_upload_dpm_level(smu, true, > FEATURE_DPM_GFXCLK_MASK); > + if (ret) > + pr_err("Failed to upload dpm max level to > highest!\n"); > + > + break; > + > + case SMU_MCLK: > + single_dpm_table = &(dpm_table->mem_table); > + > + if (soft_max_level >= single_dpm_table->count) { > + pr_err("Clock level specified %d is over max > allowed %d\n", > + soft_max_level, single_dpm_table- > >count - 1); > + ret = -EINVAL; > + break; > + } > + > + single_dpm_table->dpm_state.soft_min_level = > + single_dpm_table- > >dpm_levels[soft_min_level].value; > + single_dpm_table->dpm_state.soft_max_level = > + single_dpm_table- > >dpm_levels[soft_max_level].value; > + > + ret = vega20_upload_dpm_level(smu, false, > FEATURE_DPM_UCLK_MASK); > + if (ret) { > + pr_err("Failed to upload boot level to lowest!\n"); > + break; > + } > + > + ret = vega20_upload_dpm_level(smu, true, > FEATURE_DPM_UCLK_MASK); > + if (ret) > + pr_err("Failed to upload dpm max level to > highest!\n"); > + > + break; > + > + case SMU_SOCCLK: > + single_dpm_table = &(dpm_table->soc_table); > + > + if (soft_max_level >= single_dpm_table->count) { > + pr_err("Clock level specified %d is over max > allowed %d\n", > + soft_max_level, single_dpm_table- > >count - 1); > + ret = -EINVAL; > + break; > + } > + > + single_dpm_table->dpm_state.soft_min_level = > + single_dpm_table- > >dpm_levels[soft_min_level].value; > + single_dpm_table->dpm_state.soft_max_level = > + single_dpm_table- > >dpm_levels[soft_max_level].value; > + > + ret = vega20_upload_dpm_level(smu, false, > FEATURE_DPM_SOCCLK_MASK); > + if (ret) { > + pr_err("Failed to upload boot level to lowest!\n"); > + break; > + } > + > + ret = vega20_upload_dpm_level(smu, true, > FEATURE_DPM_SOCCLK_MASK); > + if (ret) > + pr_err("Failed to upload dpm max level to > highest!\n"); > + > + break; > + > + case SMU_FCLK: > + single_dpm_table = &(dpm_table->fclk_table); > + > + if (soft_max_level >= single_dpm_table->count) { > + pr_err("Clock level specified %d is over max > allowed %d\n", > + soft_max_level, single_dpm_table- > >count - 1); > + ret = -EINVAL; > + break; > + } > + > + single_dpm_table->dpm_state.soft_min_level = > + single_dpm_table- > >dpm_levels[soft_min_level].value; > + single_dpm_table->dpm_state.soft_max_level = > + single_dpm_table- > >dpm_levels[soft_max_level].value; > + > + ret = vega20_upload_dpm_level(smu, false, > FEATURE_DPM_FCLK_MASK); > + if (ret) { > + pr_err("Failed to upload boot level to lowest!\n"); > + break; > + } > + > + ret = vega20_upload_dpm_level(smu, true, > FEATURE_DPM_FCLK_MASK); > + if (ret) > + pr_err("Failed to upload dpm max level to > highest!\n"); > + > + break; > + > + case SMU_DCEFCLK: > + hard_min_level = soft_min_level; > + single_dpm_table = &(dpm_table->dcef_table); > + > + if (hard_min_level >= single_dpm_table->count) { > + pr_err("Clock level specified %d is over max > allowed %d\n", > + hard_min_level, single_dpm_table- > >count - 1); > + ret = -EINVAL; > + break; > + } > + > + single_dpm_table->dpm_state.hard_min_level = > + single_dpm_table- > >dpm_levels[hard_min_level].value; > + > + ret = vega20_upload_dpm_level(smu, false, > FEATURE_DPM_DCEFCLK_MASK); > + if (ret) > + pr_err("Failed to upload boot level to lowest!\n"); > + > + break; > + > + case SMU_PCIE: > + if (soft_min_level >= NUM_LINK_LEVELS || > + soft_max_level >= NUM_LINK_LEVELS) { > + ret = -EINVAL; > + break; > + } > + > + ret = smu_send_smc_msg_with_param(smu, > + SMU_MSG_SetMinLinkDpmByIndex, > soft_min_level); > + if (ret) > + pr_err("Failed to set min link dpm level!\n"); > + > + break; > + > + default: > + break; > + } > + > + mutex_unlock(&(smu->mutex)); > + return ret; > +} > + > +static int vega20_get_clock_by_type_with_latency(struct smu_context > *smu, > + enum smu_clk_type > clk_type, > + struct > pp_clock_levels_with_latency *clocks) > +{ > + int ret; > + struct vega20_single_dpm_table *single_dpm_table; > + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > + struct vega20_dpm_table *dpm_table = NULL; > + > + dpm_table = smu_dpm->dpm_context; > + > + mutex_lock(&smu->mutex); > + > + switch (clk_type) { > + case SMU_GFXCLK: > + single_dpm_table = &(dpm_table->gfx_table); > + ret = vega20_get_clk_table(smu, clocks, single_dpm_table); > + break; > + case SMU_MCLK: > + single_dpm_table = &(dpm_table->mem_table); > + ret = vega20_get_clk_table(smu, clocks, single_dpm_table); > + break; > + case SMU_DCEFCLK: > + single_dpm_table = &(dpm_table->dcef_table); > + ret = vega20_get_clk_table(smu, clocks, single_dpm_table); > + break; > + case SMU_SOCCLK: > + single_dpm_table = &(dpm_table->soc_table); > + ret = vega20_get_clk_table(smu, clocks, single_dpm_table); > + break; > + default: > + ret = -EINVAL; > + } > + > + mutex_unlock(&smu->mutex); > + return ret; > +} > + > +static int vega20_overdrive_get_gfx_clk_base_voltage(struct smu_context > *smu, > + uint32_t *voltage, > + uint32_t freq) > +{ > + int ret; > + > + ret = smu_send_smc_msg_with_param(smu, > + SMU_MSG_GetAVFSVoltageByDpm, > + ((AVFS_CURVE << 24) | > (OD8_HOTCURVE_TEMPERATURE << 16) | freq)); > + if (ret) { > + pr_err("[GetBaseVoltage] failed to get GFXCLK AVFS voltage > from SMU!"); > + return ret; > + } > + > + smu_read_smc_arg(smu, voltage); > + *voltage = *voltage / VOLTAGE_SCALE; > + > + return 0; > +} > + > +static int vega20_set_default_od8_setttings(struct smu_context *smu) > +{ > + struct smu_table_context *table_context = &smu->smu_table; > + OverDriveTable_t *od_table = (OverDriveTable_t *)(table_context- > >overdrive_table); > + struct vega20_od8_settings *od8_settings = NULL; > + PPTable_t *smc_pptable = table_context->driver_pptable; > + int i, ret; > + > + if (smu->od_settings) > + return -EINVAL; > + > + od8_settings = kzalloc(sizeof(struct vega20_od8_settings), > GFP_KERNEL); > + > + if (od8_settings) > + return -ENOMEM; > + > + smu->od_settings = (void *)od8_settings; > + > + if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_SOCCLK_BIT)) { > + if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_LIMITS] && > + od8_settings- > >od_settings_max[OD8_SETTING_GFXCLK_FMAX] > 0 && > + od8_settings- > >od_settings_min[OD8_SETTING_GFXCLK_FMIN] > 0 && > + (od8_settings- > >od_settings_max[OD8_SETTING_GFXCLK_FMAX] >= > + od8_settings- > >od_settings_min[OD8_SETTING_GFXCLK_FMIN])) { > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id = > + OD8_GFXCLK_LIMITS; > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id = > + OD8_GFXCLK_LIMITS; > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value = > + od_table->GfxclkFmin; > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value = > + od_table->GfxclkFmax; > + } > + > + if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_CURVE] && > + (od8_settings- > >od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] >= > + smc_pptable->MinVoltageGfx / VOLTAGE_SCALE) && > + (od8_settings- > >od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3] <= > + smc_pptable->MaxVoltageGfx / VOLTAGE_SCALE) && > + (od8_settings- > >od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] <= > + od8_settings- > >od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3])) { > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id = > + OD8_GFXCLK_CURVE; > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id = > + OD8_GFXCLK_CURVE; > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id = > + OD8_GFXCLK_CURVE; > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id = > + OD8_GFXCLK_CURVE; > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id = > + OD8_GFXCLK_CURVE; > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id = > + OD8_GFXCLK_CURVE; > + > + od_table->GfxclkFreq1 = od_table->GfxclkFmin; > + od_table->GfxclkFreq2 = (od_table->GfxclkFmin + > od_table->GfxclkFmax) / 2; > + od_table->GfxclkFreq3 = od_table->GfxclkFmax; > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value = > + od_table->GfxclkFreq1; > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value = > + od_table->GfxclkFreq2; > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value = > + od_table->GfxclkFreq3; > + > + ret = > vega20_overdrive_get_gfx_clk_base_voltage(smu, > + &od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value, > + od_table->GfxclkFreq1); > + if (ret) > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value = 0; > + od_table->GfxclkVolt1 = > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value > + * VOLTAGE_SCALE; > + ret = > vega20_overdrive_get_gfx_clk_base_voltage(smu, > + &od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value, > + od_table->GfxclkFreq2); > + if (ret) > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value = 0; > + od_table->GfxclkVolt2 = > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value > + * VOLTAGE_SCALE; > + ret = > vega20_overdrive_get_gfx_clk_base_voltage(smu, > + &od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value, > + od_table->GfxclkFreq3); > + if (ret) > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value = 0; > + od_table->GfxclkVolt3 = > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value > + * VOLTAGE_SCALE; > + } > + } > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) > { > + if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_UCLK_MAX] && > + od8_settings- > >od_settings_min[OD8_SETTING_UCLK_FMAX] > 0 && > + od8_settings- > >od_settings_max[OD8_SETTING_UCLK_FMAX] > 0 && > + (od8_settings- > >od_settings_max[OD8_SETTING_UCLK_FMAX] >= > + od8_settings- > >od_settings_min[OD8_SETTING_UCLK_FMAX])) { > + od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id = > + OD8_UCLK_MAX; > + od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value = > + od_table->UclkFmax; > + } > + } > + > + if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_POWER_LIMIT] && > + od8_settings- > >od_settings_min[OD8_SETTING_POWER_PERCENTAGE] > 0 && > + od8_settings- > >od_settings_min[OD8_SETTING_POWER_PERCENTAGE] <= 100 && > + od8_settings- > >od_settings_max[OD8_SETTING_POWER_PERCENTAGE] > 0 && > + od8_settings- > >od_settings_max[OD8_SETTING_POWER_PERCENTAGE] <= 100) { > + od8_settings- > >od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id = > + OD8_POWER_LIMIT; > + od8_settings- > >od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value = > + od_table->OverDrivePct; > + } > + > + if (smu_feature_is_enabled(smu, > SMU_FEATURE_FAN_CONTROL_BIT)) { > + if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_ACOUSTIC_LI > MIT] && > + od8_settings- > >od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 && > + od8_settings- > >od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 && > + (od8_settings- > >od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] >= > + od8_settings- > >od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT])) { > + od8_settings- > >od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id = > + OD8_ACOUSTIC_LIMIT_SCLK; > + od8_settings- > >od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value = > + od_table->FanMaximumRpm; > + } > + > + if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_SPEED_MIN] > && > + od8_settings- > >od_settings_min[OD8_SETTING_FAN_MIN_SPEED] > 0 && > + od8_settings- > >od_settings_max[OD8_SETTING_FAN_MIN_SPEED] > 0 && > + (od8_settings- > >od_settings_max[OD8_SETTING_FAN_MIN_SPEED] >= > + od8_settings- > >od_settings_min[OD8_SETTING_FAN_MIN_SPEED])) { > + od8_settings- > >od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id = > + OD8_FAN_SPEED_MIN; > + od8_settings- > >od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value = > + od_table->FanMinimumPwm * smc_pptable- > >FanMaximumRpm / 100; > + } > + } > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_THERMAL_BIT)) { > + if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_FAN] > && > + od8_settings- > >od_settings_min[OD8_SETTING_FAN_TARGET_TEMP] > 0 && > + od8_settings- > >od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] > 0 && > + (od8_settings- > >od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] >= > + od8_settings- > >od_settings_min[OD8_SETTING_FAN_TARGET_TEMP])) { > + od8_settings- > >od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id = > + OD8_TEMPERATURE_FAN; > + od8_settings- > >od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value = > + od_table->FanTargetTemperature; > + } > + > + if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_SYS > TEM] && > + od8_settings- > >od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX] > 0 && > + od8_settings- > >od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] > 0 && > + (od8_settings- > >od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] >= > + od8_settings- > >od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX])) { > + od8_settings- > >od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id = > + OD8_TEMPERATURE_SYSTEM; > + od8_settings- > >od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_valu > e = > + od_table->MaxOpTemp; > + } > + } > + > + for (i = 0; i < OD8_SETTING_COUNT; i++) { > + if (od8_settings->od8_settings_array[i].feature_id) { > + od8_settings->od8_settings_array[i].min_value = > + od8_settings->od_settings_min[i]; > + od8_settings->od8_settings_array[i].max_value = > + od8_settings->od_settings_max[i]; > + od8_settings->od8_settings_array[i].current_value = > + od8_settings- > >od8_settings_array[i].default_value; > + } else { > + od8_settings->od8_settings_array[i].min_value = 0; > + od8_settings->od8_settings_array[i].max_value = 0; > + od8_settings->od8_settings_array[i].current_value = > 0; > + } > + } > + > + return 0; > +} > + > +static int vega20_get_metrics_table(struct smu_context *smu, > + SmuMetrics_t *metrics_table) > +{ > + struct smu_table_context *smu_table= &smu->smu_table; > + int ret = 0; > + > + if (!smu_table->metrics_time || time_after(jiffies, smu_table- > >metrics_time + HZ / 1000)) { > + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, > + (void *)smu_table->metrics_table, false); > + if (ret) { > + pr_info("Failed to export SMU metrics table!\n"); > + return ret; > + } > + smu_table->metrics_time = jiffies; > + } > + > + memcpy(metrics_table, smu_table->metrics_table, > sizeof(SmuMetrics_t)); > + > + return ret; > +} > + > +static int vega20_set_default_od_settings(struct smu_context *smu, > + bool initialize) > +{ > + struct smu_table_context *table_context = &smu->smu_table; > + int ret; > + > + if (initialize) { > + if (table_context->overdrive_table) > + return -EINVAL; > + > + table_context->overdrive_table = > kzalloc(sizeof(OverDriveTable_t), GFP_KERNEL); > + > + if (!table_context->overdrive_table) > + return -ENOMEM; > + > + ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, > + table_context->overdrive_table, false); > + if (ret) { > + pr_err("Failed to export over drive table!\n"); > + return ret; > + } > + > + ret = vega20_set_default_od8_setttings(smu); > + if (ret) > + return ret; > + } > + > + ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, > + table_context->overdrive_table, true); > + if (ret) { > + pr_err("Failed to import over drive table!\n"); > + return ret; > + } > + > + return 0; > +} > + > +static int vega20_get_od_percentage(struct smu_context *smu, > + enum smu_clk_type clk_type) > +{ > + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > + struct vega20_dpm_table *dpm_table = NULL; > + struct vega20_dpm_table *golden_table = NULL; > + struct vega20_single_dpm_table *single_dpm_table; > + struct vega20_single_dpm_table *golden_dpm_table; > + int value, golden_value; > + > + dpm_table = smu_dpm->dpm_context; > + golden_table = smu_dpm->golden_dpm_context; > + > + switch (clk_type) { > + case SMU_OD_SCLK: > + single_dpm_table = &(dpm_table->gfx_table); > + golden_dpm_table = &(golden_table->gfx_table); > + break; > + case SMU_OD_MCLK: > + single_dpm_table = &(dpm_table->mem_table); > + golden_dpm_table = &(golden_table->mem_table); > + break; > + default: > + return -EINVAL; > + break; > + } > + > + value = single_dpm_table->dpm_levels[single_dpm_table->count - > 1].value; > + golden_value = golden_dpm_table- > >dpm_levels[golden_dpm_table->count - 1].value; > + > + value -= golden_value; > + value = DIV_ROUND_UP(value * 100, golden_value); > + > + return value; > +} > + > +static int vega20_get_power_profile_mode(struct smu_context *smu, char > *buf) > +{ > + DpmActivityMonitorCoeffInt_t activity_monitor; > + uint32_t i, size = 0; > + uint16_t workload_type = 0; > + static const char *profile_name[] = { > + "BOOTUP_DEFAULT", > + "3D_FULL_SCREEN", > + "POWER_SAVING", > + "VIDEO", > + "VR", > + "COMPUTE", > + "CUSTOM"}; > + static const char *title[] = { > + "PROFILE_INDEX(NAME)", > + "CLOCK_TYPE(NAME)", > + "FPS", > + "UseRlcBusy", > + "MinActiveFreqType", > + "MinActiveFreq", > + "BoosterFreqType", > + "BoosterFreq", > + "PD_Data_limit_c", > + "PD_Data_error_coeff", > + "PD_Data_error_rate_coeff"}; > + int result = 0; > + > + if (!smu->pm_enabled || !buf) > + return -EINVAL; > + > + size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n", > + title[0], title[1], title[2], title[3], title[4], title[5], > + title[6], title[7], title[8], title[9], title[10]); > + > + for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { > + /* conv PP_SMC_POWER_PROFILE* to > WORKLOAD_PPLIB_*_BIT */ > + workload_type = smu_workload_get_type(smu, i); > + result = smu_update_table(smu, > + > SMU_TABLE_ACTIVITY_MONITOR_COEFF | workload_type << 16, > + (void *)(&activity_monitor), false); > + if (result) { > + pr_err("[%s] Failed to get activity monitor!", > __func__); > + return result; > + } > + > + size += sprintf(buf + size, "%2d %14s%s:\n", > + i, profile_name[i], (i == smu->power_profile_mode) ? > "*" : " "); > + > + size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > + " ", > + 0, > + "GFXCLK", > + activity_monitor.Gfx_FPS, > + activity_monitor.Gfx_UseRlcBusy, > + activity_monitor.Gfx_MinActiveFreqType, > + activity_monitor.Gfx_MinActiveFreq, > + activity_monitor.Gfx_BoosterFreqType, > + activity_monitor.Gfx_BoosterFreq, > + activity_monitor.Gfx_PD_Data_limit_c, > + activity_monitor.Gfx_PD_Data_error_coeff, > + activity_monitor.Gfx_PD_Data_error_rate_coeff); > + > + size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > + " ", > + 1, > + "SOCCLK", > + activity_monitor.Soc_FPS, > + activity_monitor.Soc_UseRlcBusy, > + activity_monitor.Soc_MinActiveFreqType, > + activity_monitor.Soc_MinActiveFreq, > + activity_monitor.Soc_BoosterFreqType, > + activity_monitor.Soc_BoosterFreq, > + activity_monitor.Soc_PD_Data_limit_c, > + activity_monitor.Soc_PD_Data_error_coeff, > + activity_monitor.Soc_PD_Data_error_rate_coeff); > + > + size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > + " ", > + 2, > + "UCLK", > + activity_monitor.Mem_FPS, > + activity_monitor.Mem_UseRlcBusy, > + activity_monitor.Mem_MinActiveFreqType, > + activity_monitor.Mem_MinActiveFreq, > + activity_monitor.Mem_BoosterFreqType, > + activity_monitor.Mem_BoosterFreq, > + activity_monitor.Mem_PD_Data_limit_c, > + activity_monitor.Mem_PD_Data_error_coeff, > + activity_monitor.Mem_PD_Data_error_rate_coeff); > + > + size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > + " ", > + 3, > + "FCLK", > + activity_monitor.Fclk_FPS, > + activity_monitor.Fclk_UseRlcBusy, > + activity_monitor.Fclk_MinActiveFreqType, > + activity_monitor.Fclk_MinActiveFreq, > + activity_monitor.Fclk_BoosterFreqType, > + activity_monitor.Fclk_BoosterFreq, > + activity_monitor.Fclk_PD_Data_limit_c, > + activity_monitor.Fclk_PD_Data_error_coeff, > + activity_monitor.Fclk_PD_Data_error_rate_coeff); > + } > + > + return size; > +} > + > +static int vega20_set_power_profile_mode(struct smu_context *smu, long > *input, uint32_t size) > +{ > + DpmActivityMonitorCoeffInt_t activity_monitor; > + int workload_type = 0, ret = 0; > + > + smu->power_profile_mode = input[size]; > + > + if (!smu->pm_enabled) > + return ret; > + if (smu->power_profile_mode > > PP_SMC_POWER_PROFILE_CUSTOM) { > + pr_err("Invalid power profile mode %d\n", smu- > >power_profile_mode); > + return -EINVAL; > + } > + > + if (smu->power_profile_mode == > PP_SMC_POWER_PROFILE_CUSTOM) { > + ret = smu_update_table(smu, > + SMU_TABLE_ACTIVITY_MONITOR_COEFF > | WORKLOAD_PPLIB_CUSTOM_BIT << 16, > + (void *)(&activity_monitor), false); > + if (ret) { > + pr_err("[%s] Failed to get activity monitor!", > __func__); > + return ret; > + } > + > + switch (input[0]) { > + case 0: /* Gfxclk */ > + activity_monitor.Gfx_FPS = input[1]; > + activity_monitor.Gfx_UseRlcBusy = input[2]; > + activity_monitor.Gfx_MinActiveFreqType = input[3]; > + activity_monitor.Gfx_MinActiveFreq = input[4]; > + activity_monitor.Gfx_BoosterFreqType = input[5]; > + activity_monitor.Gfx_BoosterFreq = input[6]; > + activity_monitor.Gfx_PD_Data_limit_c = input[7]; > + activity_monitor.Gfx_PD_Data_error_coeff = > input[8]; > + activity_monitor.Gfx_PD_Data_error_rate_coeff = > input[9]; > + break; > + case 1: /* Socclk */ > + activity_monitor.Soc_FPS = input[1]; > + activity_monitor.Soc_UseRlcBusy = input[2]; > + activity_monitor.Soc_MinActiveFreqType = input[3]; > + activity_monitor.Soc_MinActiveFreq = input[4]; > + activity_monitor.Soc_BoosterFreqType = input[5]; > + activity_monitor.Soc_BoosterFreq = input[6]; > + activity_monitor.Soc_PD_Data_limit_c = input[7]; > + activity_monitor.Soc_PD_Data_error_coeff = > input[8]; > + activity_monitor.Soc_PD_Data_error_rate_coeff = > input[9]; > + break; > + case 2: /* Uclk */ > + activity_monitor.Mem_FPS = input[1]; > + activity_monitor.Mem_UseRlcBusy = input[2]; > + activity_monitor.Mem_MinActiveFreqType = > input[3]; > + activity_monitor.Mem_MinActiveFreq = input[4]; > + activity_monitor.Mem_BoosterFreqType = input[5]; > + activity_monitor.Mem_BoosterFreq = input[6]; > + activity_monitor.Mem_PD_Data_limit_c = input[7]; > + activity_monitor.Mem_PD_Data_error_coeff = > input[8]; > + activity_monitor.Mem_PD_Data_error_rate_coeff = > input[9]; > + break; > + case 3: /* Fclk */ > + activity_monitor.Fclk_FPS = input[1]; > + activity_monitor.Fclk_UseRlcBusy = input[2]; > + activity_monitor.Fclk_MinActiveFreqType = input[3]; > + activity_monitor.Fclk_MinActiveFreq = input[4]; > + activity_monitor.Fclk_BoosterFreqType = input[5]; > + activity_monitor.Fclk_BoosterFreq = input[6]; > + activity_monitor.Fclk_PD_Data_limit_c = input[7]; > + activity_monitor.Fclk_PD_Data_error_coeff = > input[8]; > + activity_monitor.Fclk_PD_Data_error_rate_coeff = > input[9]; > + break; > + } > + > + ret = smu_update_table(smu, > + SMU_TABLE_ACTIVITY_MONITOR_COEFF > | WORKLOAD_PPLIB_CUSTOM_BIT << 16, > + (void *)(&activity_monitor), true); > + if (ret) { > + pr_err("[%s] Failed to set activity monitor!", > __func__); > + return ret; > + } > + } > + > + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ > + workload_type = smu_workload_get_type(smu, smu- > >power_profile_mode); > + smu_send_smc_msg_with_param(smu, > SMU_MSG_SetWorkloadMask, > + 1 << workload_type); > + > + return ret; > +} > + > +static int > +vega20_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) > +{ > + struct vega20_dpm_table *dpm_table = (struct vega20_dpm_table > *)smu->smu_dpm.dpm_context; > + struct vega20_single_dpm_table *gfx_dpm_table; > + struct vega20_single_dpm_table *mem_dpm_table; > + struct vega20_single_dpm_table *soc_dpm_table; > + > + if (!smu->smu_dpm.dpm_context) > + return -EINVAL; > + > + gfx_dpm_table = &dpm_table->gfx_table; > + mem_dpm_table = &dpm_table->mem_table; > + soc_dpm_table = &dpm_table->soc_table; > + > + *sclk_mask = 0; > + *mclk_mask = 0; > + *soc_mask = 0; > + > + if (gfx_dpm_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL > && > + mem_dpm_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL > && > + soc_dpm_table->count > VEGA20_UMD_PSTATE_SOCCLK_LEVEL) { > + *sclk_mask = VEGA20_UMD_PSTATE_GFXCLK_LEVEL; > + *mclk_mask = VEGA20_UMD_PSTATE_MCLK_LEVEL; > + *soc_mask = VEGA20_UMD_PSTATE_SOCCLK_LEVEL; > + } > + > + if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { > + *sclk_mask = 0; > + } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { > + *mclk_mask = 0; > + } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > + *sclk_mask = gfx_dpm_table->count - 1; > + *mclk_mask = mem_dpm_table->count - 1; > + *soc_mask = soc_dpm_table->count - 1; > + } > + > + return 0; > +} > + > +static int > +vega20_set_uclk_to_highest_dpm_level(struct smu_context *smu, > + struct vega20_single_dpm_table > *dpm_table) > +{ > + int ret = 0; > + struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); > + if (!smu_dpm_ctx->dpm_context) > + return -EINVAL; > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) > { > + if (dpm_table->count <= 0) { > + pr_err("[%s] Dpm table has no entry!", __func__); > + return -EINVAL; > + } > + > + if (dpm_table->count > NUM_UCLK_DPM_LEVELS) { > + pr_err("[%s] Dpm table has too many entries!", > __func__); > + return -EINVAL; > + } > + > + dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + ret = smu_send_smc_msg_with_param(smu, > + SMU_MSG_SetHardMinByFreq, > + (PPCLK_UCLK << 16) | dpm_table- > >dpm_state.hard_min_level); > + if (ret) { > + pr_err("[%s] Set hard min uclk failed!", __func__); > + return ret; > + } > + } > + > + return ret; > +} > + > +static int vega20_pre_display_config_changed(struct smu_context *smu) > +{ > + int ret = 0; > + struct vega20_dpm_table *dpm_table = smu- > >smu_dpm.dpm_context; > + > + if (!smu->smu_dpm.dpm_context) > + return -EINVAL; > + > + smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, > 0); > + ret = vega20_set_uclk_to_highest_dpm_level(smu, > + &dpm_table->mem_table); > + if (ret) > + pr_err("Failed to set uclk to highest dpm level"); > + return ret; > +} > + > +static int vega20_display_config_changed(struct smu_context *smu) > +{ > + int ret = 0; > + > + if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && > + !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { > + ret = smu_write_watermarks_table(smu); > + if (ret) { > + pr_err("Failed to update WMTABLE!"); > + return ret; > + } > + smu->watermarks_bitmap |= WATERMARKS_LOADED; > + } > + > + if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && > + smu_feature_is_supported(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT) && > + smu_feature_is_supported(smu, > SMU_FEATURE_DPM_SOCCLK_BIT)) { > + smu_send_smc_msg_with_param(smu, > + SMU_MSG_NumOfDisplays, > + smu->display_config- > >num_display); > + } > + > + return ret; > +} > + > +static int vega20_apply_clocks_adjust_rules(struct smu_context *smu) > +{ > + struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); > + struct vega20_dpm_table *dpm_ctx = (struct vega20_dpm_table > *)(smu_dpm_ctx->dpm_context); > + struct vega20_single_dpm_table *dpm_table; > + bool vblank_too_short = false; > + bool disable_mclk_switching; > + uint32_t i, latency; > + > + disable_mclk_switching = ((1 < smu->display_config->num_display) > && > + !smu->display_config- > >multi_monitor_in_sync) || vblank_too_short; > + latency = smu->display_config- > >dce_tolerable_mclk_in_active_latency; > + > + /* gfxclk */ > + dpm_table = &(dpm_ctx->gfx_table); > + dpm_table->dpm_state.soft_min_level = dpm_table- > >dpm_levels[0].value; > + dpm_table->dpm_state.soft_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[0].value; > + dpm_table->dpm_state.hard_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + > + if (VEGA20_UMD_PSTATE_GFXCLK_LEVEL < dpm_table- > >count) { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value; > + } > + > + if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[0].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[0].value; > + } > + > + if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > + } > + > + /* memclk */ > + dpm_table = &(dpm_ctx->mem_table); > + dpm_table->dpm_state.soft_min_level = dpm_table- > >dpm_levels[0].value; > + dpm_table->dpm_state.soft_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[0].value; > + dpm_table->dpm_state.hard_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + > + if (VEGA20_UMD_PSTATE_MCLK_LEVEL < dpm_table->count) > { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value; > + } > + > + if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[0].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[0].value; > + } > + > + if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > + } > + > + /* honour DAL's UCLK Hardmin */ > + if (dpm_table->dpm_state.hard_min_level < (smu->display_config- > >min_mem_set_clock / 100)) > + dpm_table->dpm_state.hard_min_level = smu- > >display_config->min_mem_set_clock / 100; > + > + /* Hardmin is dependent on displayconfig */ > + if (disable_mclk_switching) { > + dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + for (i = 0; i < smu_dpm_ctx->mclk_latency_table->count - 1; > i++) { > + if (smu_dpm_ctx->mclk_latency_table- > >entries[i].latency <= latency) { > + if (dpm_table->dpm_levels[i].value >= (smu- > >display_config->min_mem_set_clock / 100)) { > + dpm_table- > >dpm_state.hard_min_level = dpm_table->dpm_levels[i].value; > + break; > + } > + } > + } > + } > + > + if (smu->display_config->nb_pstate_switch_disable) > + dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + > + /* vclk */ > + dpm_table = &(dpm_ctx->vclk_table); > + dpm_table->dpm_state.soft_min_level = dpm_table- > >dpm_levels[0].value; > + dpm_table->dpm_state.soft_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[0].value; > + dpm_table->dpm_state.hard_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + > + if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table- > >count) { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value; > + } > + > + if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > + } > + > + /* dclk */ > + dpm_table = &(dpm_ctx->dclk_table); > + dpm_table->dpm_state.soft_min_level = dpm_table- > >dpm_levels[0].value; > + dpm_table->dpm_state.soft_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[0].value; > + dpm_table->dpm_state.hard_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + > + if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table- > >count) { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value; > + } > + > + if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > + } > + > + /* socclk */ > + dpm_table = &(dpm_ctx->soc_table); > + dpm_table->dpm_state.soft_min_level = dpm_table- > >dpm_levels[0].value; > + dpm_table->dpm_state.soft_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[0].value; > + dpm_table->dpm_state.hard_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + > + if (VEGA20_UMD_PSTATE_SOCCLK_LEVEL < dpm_table- > >count) { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value; > + } > + > + if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > + } > + > + /* eclk */ > + dpm_table = &(dpm_ctx->eclk_table); > + dpm_table->dpm_state.soft_min_level = dpm_table- > >dpm_levels[0].value; > + dpm_table->dpm_state.soft_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[0].value; > + dpm_table->dpm_state.hard_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > + > + if (VEGA20_UMD_PSTATE_VCEMCLK_LEVEL < dpm_table- > >count) { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value; > + } > + > + if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > + dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > + dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > + } > + return 0; > +} > + > +static int > +vega20_notify_smc_dispaly_config(struct smu_context *smu) > +{ > + struct vega20_dpm_table *dpm_table = smu- > >smu_dpm.dpm_context; > + struct vega20_single_dpm_table *memtable = &dpm_table- > >mem_table; > + struct smu_clocks min_clocks = {0}; > + struct pp_display_clock_request clock_req; > + int ret = 0; > + > + min_clocks.dcef_clock = smu->display_config->min_dcef_set_clk; > + min_clocks.dcef_clock_in_sr = smu->display_config- > >min_dcef_deep_sleep_set_clk; > + min_clocks.memory_clock = smu->display_config- > >min_mem_set_clock; > + > + if (smu_feature_is_supported(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT)) { > + clock_req.clock_type = amd_pp_dcef_clock; > + clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10; > + if (!smu->funcs->display_clock_voltage_request(smu, > &clock_req)) { > + if (smu_feature_is_supported(smu, > SMU_FEATURE_DS_DCEFCLK_BIT)) { > + ret = smu_send_smc_msg_with_param(smu, > + > SMU_MSG_SetMinDeepSleepDcefclk, > + > min_clocks.dcef_clock_in_sr/100); > + if (ret) { > + pr_err("Attempt to set divider for > DCEFCLK Failed!"); > + return ret; > + } > + } > + } else { > + pr_info("Attempt to set Hard Min for DCEFCLK > Failed!"); > + } > + } > + > + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) > { > + memtable->dpm_state.hard_min_level = > min_clocks.memory_clock/100; > + ret = smu_send_smc_msg_with_param(smu, > + > SMU_MSG_SetHardMinByFreq, > + (PPCLK_UCLK << 16) | > memtable->dpm_state.hard_min_level); > + if (ret) { > + pr_err("[%s] Set hard min uclk failed!", __func__); > + return ret; > + } > + } > + > + return 0; > +} > + > +static uint32_t vega20_find_lowest_dpm_level(struct > vega20_single_dpm_table *table) > +{ > + uint32_t i; > + > + for (i = 0; i < table->count; i++) { > + if (table->dpm_levels[i].enabled) > + break; > + } > + if (i >= table->count) { > + i = 0; > + table->dpm_levels[i].enabled = true; > + } > + > + return i; > +} > + > +static uint32_t vega20_find_highest_dpm_level(struct > vega20_single_dpm_table *table) > +{ > + int i = 0; > + > + if (!table) { > + pr_err("[%s] DPM Table does not exist!", __func__); > + return 0; > + } > + if (table->count <= 0) { > + pr_err("[%s] DPM Table has no entry!", __func__); > + return 0; > + } > + if (table->count > MAX_REGULAR_DPM_NUMBER) { > + pr_err("[%s] DPM Table has too many entries!", __func__); > + return MAX_REGULAR_DPM_NUMBER - 1; > + } > + > + for (i = table->count - 1; i >= 0; i--) { > + if (table->dpm_levels[i].enabled) > + break; > + } > + if (i < 0) { > + i = 0; > + table->dpm_levels[i].enabled = true; > + } > + > + return i; > +} > + > +static int vega20_force_dpm_limit_value(struct smu_context *smu, bool > highest) > +{ > + uint32_t soft_level; > + int ret = 0; > + struct vega20_dpm_table *dpm_table = > + (struct vega20_dpm_table *)smu->smu_dpm.dpm_context; > + > + if (highest) > + soft_level = vega20_find_highest_dpm_level(&(dpm_table- > >gfx_table)); > + else > + soft_level = vega20_find_lowest_dpm_level(&(dpm_table- > >gfx_table)); > + > + dpm_table->gfx_table.dpm_state.soft_min_level = > + dpm_table->gfx_table.dpm_state.soft_max_level = > + dpm_table->gfx_table.dpm_levels[soft_level].value; > + > + if (highest) > + soft_level = vega20_find_highest_dpm_level(&(dpm_table- > >mem_table)); > + else > + soft_level = vega20_find_lowest_dpm_level(&(dpm_table- > >mem_table)); > + > + dpm_table->mem_table.dpm_state.soft_min_level = > + dpm_table->mem_table.dpm_state.soft_max_level = > + dpm_table->mem_table.dpm_levels[soft_level].value; > + > + if (highest) > + soft_level = vega20_find_highest_dpm_level(&(dpm_table- > >soc_table)); > + else > + soft_level = vega20_find_lowest_dpm_level(&(dpm_table- > >soc_table)); > + > + dpm_table->soc_table.dpm_state.soft_min_level = > + dpm_table->soc_table.dpm_state.soft_max_level = > + dpm_table->soc_table.dpm_levels[soft_level].value; > + > + ret = vega20_upload_dpm_level(smu, false, 0xFFFFFFFF); > + if (ret) { > + pr_err("Failed to upload boot level to %s!\n", > + highest ? "highest" : "lowest"); > + return ret; > + } > + > + ret = vega20_upload_dpm_level(smu, true, 0xFFFFFFFF); > + if (ret) { > + pr_err("Failed to upload dpm max level to %s!\n!", > + highest ? "highest" : "lowest"); > + return ret; > + } > + > + return ret; > +} > + > +static int vega20_unforce_dpm_levels(struct smu_context *smu) > +{ > + uint32_t soft_min_level, soft_max_level; > + int ret = 0; > + struct vega20_dpm_table *dpm_table = > + (struct vega20_dpm_table *)smu->smu_dpm.dpm_context; > + > + soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table- > >gfx_table)); > + soft_max_level = vega20_find_highest_dpm_level(&(dpm_table- > >gfx_table)); > + dpm_table->gfx_table.dpm_state.soft_min_level = > + dpm_table->gfx_table.dpm_levels[soft_min_level].value; > + dpm_table->gfx_table.dpm_state.soft_max_level = > + dpm_table->gfx_table.dpm_levels[soft_max_level].value; > + > + soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table- > >mem_table)); > + soft_max_level = vega20_find_highest_dpm_level(&(dpm_table- > >mem_table)); > + dpm_table->mem_table.dpm_state.soft_min_level = > + dpm_table->gfx_table.dpm_levels[soft_min_level].value; > + dpm_table->mem_table.dpm_state.soft_max_level = > + dpm_table->gfx_table.dpm_levels[soft_max_level].value; > + > + soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table- > >soc_table)); > + soft_max_level = vega20_find_highest_dpm_level(&(dpm_table- > >soc_table)); > + dpm_table->soc_table.dpm_state.soft_min_level = > + dpm_table->soc_table.dpm_levels[soft_min_level].value; > + dpm_table->soc_table.dpm_state.soft_max_level = > + dpm_table->soc_table.dpm_levels[soft_max_level].value; > + > + ret = vega20_upload_dpm_level(smu, false, 0xFFFFFFFF); > + if (ret) { > + pr_err("Failed to upload DPM Bootup Levels!"); > + return ret; > + } > + > + ret = vega20_upload_dpm_level(smu, true, 0xFFFFFFFF); > + if (ret) { > + pr_err("Failed to upload DPM Max Levels!"); > + return ret; > + } > + > + return ret; > +} > + > +static int vega20_update_specified_od8_value(struct smu_context *smu, > + uint32_t index, > + uint32_t value) > +{ > + struct smu_table_context *table_context = &smu->smu_table; > + OverDriveTable_t *od_table = > + (OverDriveTable_t *)(table_context->overdrive_table); > + struct vega20_od8_settings *od8_settings = > + (struct vega20_od8_settings *)smu->od_settings; > + > + switch (index) { > + case OD8_SETTING_GFXCLK_FMIN: > + od_table->GfxclkFmin = (uint16_t)value; > + break; > + > + case OD8_SETTING_GFXCLK_FMAX: > + if (value < od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].min_value || > + value > od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value) > + return -EINVAL; > + od_table->GfxclkFmax = (uint16_t)value; > + break; > + > + case OD8_SETTING_GFXCLK_FREQ1: > + od_table->GfxclkFreq1 = (uint16_t)value; > + break; > + > + case OD8_SETTING_GFXCLK_VOLTAGE1: > + od_table->GfxclkVolt1 = (uint16_t)value; > + break; > + > + case OD8_SETTING_GFXCLK_FREQ2: > + od_table->GfxclkFreq2 = (uint16_t)value; > + break; > + > + case OD8_SETTING_GFXCLK_VOLTAGE2: > + od_table->GfxclkVolt2 = (uint16_t)value; > + break; > + > + case OD8_SETTING_GFXCLK_FREQ3: > + od_table->GfxclkFreq3 = (uint16_t)value; > + break; > + > + case OD8_SETTING_GFXCLK_VOLTAGE3: > + od_table->GfxclkVolt3 = (uint16_t)value; > + break; > + > + case OD8_SETTING_UCLK_FMAX: > + if (value < od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].min_value || > + value > od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value) > + return -EINVAL; > + od_table->UclkFmax = (uint16_t)value; > + break; > + > + case OD8_SETTING_POWER_PERCENTAGE: > + od_table->OverDrivePct = (int16_t)value; > + break; > + > + case OD8_SETTING_FAN_ACOUSTIC_LIMIT: > + od_table->FanMaximumRpm = (uint16_t)value; > + break; > + > + case OD8_SETTING_FAN_MIN_SPEED: > + od_table->FanMinimumPwm = (uint16_t)value; > + break; > + > + case OD8_SETTING_FAN_TARGET_TEMP: > + od_table->FanTargetTemperature = (uint16_t)value; > + break; > + > + case OD8_SETTING_OPERATING_TEMP_MAX: > + od_table->MaxOpTemp = (uint16_t)value; > + break; > + } > + > + return 0; > +} > + > +static int vega20_update_od8_settings(struct smu_context *smu, > + uint32_t index, > + uint32_t value) > +{ > + struct smu_table_context *table_context = &smu->smu_table; > + int ret; > + > + ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, > + table_context->overdrive_table, false); > + if (ret) { > + pr_err("Failed to export over drive table!\n"); > + return ret; > + } > + > + ret = vega20_update_specified_od8_value(smu, index, value); > + if (ret) > + return ret; > + > + ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, > + table_context->overdrive_table, true); > + if (ret) { > + pr_err("Failed to import over drive table!\n"); > + return ret; > + } > + > + return 0; > +} > + > +static int vega20_set_od_percentage(struct smu_context *smu, > + enum smu_clk_type clk_type, > + uint32_t value) > +{ > + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > + struct vega20_dpm_table *dpm_table = NULL; > + struct vega20_dpm_table *golden_table = NULL; > + struct vega20_single_dpm_table *single_dpm_table; > + struct vega20_single_dpm_table *golden_dpm_table; > + uint32_t od_clk, index; > + int ret = 0; > + int feature_enabled; > + PPCLK_e clk_id; > + > + mutex_lock(&(smu->mutex)); > + > + dpm_table = smu_dpm->dpm_context; > + golden_table = smu_dpm->golden_dpm_context; > + > + switch (clk_type) { > + case SMU_OD_SCLK: > + single_dpm_table = &(dpm_table->gfx_table); > + golden_dpm_table = &(golden_table->gfx_table); > + feature_enabled = smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_GFXCLK_BIT); > + clk_id = PPCLK_GFXCLK; > + index = OD8_SETTING_GFXCLK_FMAX; > + break; > + case SMU_OD_MCLK: > + single_dpm_table = &(dpm_table->mem_table); > + golden_dpm_table = &(golden_table->mem_table); > + feature_enabled = smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_UCLK_BIT); > + clk_id = PPCLK_UCLK; > + index = OD8_SETTING_UCLK_FMAX; > + break; > + default: > + ret = -EINVAL; > + break; > + } > + > + if (ret) > + goto set_od_failed; > + > + od_clk = golden_dpm_table->dpm_levels[golden_dpm_table- > >count - 1].value * value; > + od_clk /= 100; > + od_clk += golden_dpm_table->dpm_levels[golden_dpm_table- > >count - 1].value; > + > + ret = vega20_update_od8_settings(smu, index, od_clk); > + if (ret) { > + pr_err("[Setoverdrive] failed to set od clk!\n"); > + goto set_od_failed; > + } > + > + if (feature_enabled) { > + ret = vega20_set_single_dpm_table(smu, single_dpm_table, > + clk_id); > + if (ret) { > + pr_err("[Setoverdrive] failed to refresh dpm > table!\n"); > + goto set_od_failed; > + } > + } else { > + single_dpm_table->count = 1; > + single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.gfxclk / 100; > + } > + > + ret = smu_handle_task(smu, smu_dpm->dpm_level, > + AMD_PP_TASK_READJUST_POWER_STATE); > + > +set_od_failed: > + mutex_unlock(&(smu->mutex)); > + > + return ret; > +} > + > +static int vega20_odn_edit_dpm_table(struct smu_context *smu, > + enum PP_OD_DPM_TABLE_COMMAND > type, > + long *input, uint32_t size) > +{ > + struct smu_table_context *table_context = &smu->smu_table; > + OverDriveTable_t *od_table = > + (OverDriveTable_t *)(table_context->overdrive_table); > + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > + struct vega20_dpm_table *dpm_table = NULL; > + struct vega20_single_dpm_table *single_dpm_table; > + struct vega20_od8_settings *od8_settings = > + (struct vega20_od8_settings *)smu->od_settings; > + struct pp_clock_levels_with_latency clocks; > + int32_t input_index, input_clk, input_vol, i; > + int od8_id; > + int ret = 0; > + > + dpm_table = smu_dpm->dpm_context; > + > + if (!input) { > + pr_warn("NULL user input for clock and voltage\n"); > + return -EINVAL; > + } > + > + switch (type) { > + case PP_OD_EDIT_SCLK_VDDC_TABLE: > + if (!(od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id)) { > + pr_info("Sclk min/max frequency overdrive not > supported\n"); > + return -EOPNOTSUPP; > + } > + > + for (i = 0; i < size; i += 2) { > + if (i + 2 > size) { > + pr_info("invalid number of input > parameters %d\n", size); > + return -EINVAL; > + } > + > + input_index = input[i]; > + input_clk = input[i + 1]; > + > + if (input_index != 0 && input_index != 1) { > + pr_info("Invalid index %d\n", input_index); > + pr_info("Support min/max sclk frequency > settingonly which index by 0/1\n"); > + return -EINVAL; > + } > + > + if (input_clk < od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value || > + input_clk > od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value) { > + pr_info("clock freq %d is not within allowed > range [%d - %d]\n", > + input_clk, > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value, > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value); > + return -EINVAL; > + } > + > + if (input_index == 0 && od_table->GfxclkFmin != > input_clk) { > + od_table->GfxclkFmin = input_clk; > + od8_settings->od_gfxclk_update = true; > + } else if (input_index == 1 && od_table- > >GfxclkFmax != input_clk) { > + od_table->GfxclkFmax = input_clk; > + od8_settings->od_gfxclk_update = true; > + } > + } > + > + break; > + > + case PP_OD_EDIT_MCLK_VDDC_TABLE: > + if (!od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) { > + pr_info("Mclk max frequency overdrive not > supported\n"); > + return -EOPNOTSUPP; > + } > + > + single_dpm_table = &(dpm_table->mem_table); > + ret = vega20_get_clk_table(smu, &clocks, single_dpm_table); > + if (ret) { > + pr_err("Attempt to get memory clk levels Failed!"); > + return ret; > + } > + > + for (i = 0; i < size; i += 2) { > + if (i + 2 > size) { > + pr_info("invalid number of input > parameters %d\n", > + size); > + return -EINVAL; > + } > + > + input_index = input[i]; > + input_clk = input[i + 1]; > + > + if (input_index != 1) { > + pr_info("Invalid index %d\n", input_index); > + pr_info("Support max Mclk frequency setting > only which index by 1\n"); > + return -EINVAL; > + } > + > + if (input_clk < clocks.data[0].clocks_in_khz / 1000 || > + input_clk > od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value) { > + pr_info("clock freq %d is not within allowed > range [%d - %d]\n", > + input_clk, > + clocks.data[0].clocks_in_khz / 1000, > + od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value); > + return -EINVAL; > + } > + > + if (input_index == 1 && od_table->UclkFmax != > input_clk) { > + od8_settings->od_gfxclk_update = true; > + od_table->UclkFmax = input_clk; > + } > + } > + > + break; > + > + case PP_OD_EDIT_VDDC_CURVE: > + if (!(od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && > + od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id)) { > + pr_info("Voltage curve calibrate not supported\n"); > + return -EOPNOTSUPP; > + } > + > + for (i = 0; i < size; i += 3) { > + if (i + 3 > size) { > + pr_info("invalid number of input > parameters %d\n", > + size); > + return -EINVAL; > + } > + > + input_index = input[i]; > + input_clk = input[i + 1]; > + input_vol = input[i + 2]; > + > + if (input_index > 2) { > + pr_info("Setting for point %d is not > supported\n", > + input_index + 1); > + pr_info("Three supported points index by 0, > 1, 2\n"); > + return -EINVAL; > + } > + > + od8_id = OD8_SETTING_GFXCLK_FREQ1 + 2 * > input_index; > + if (input_clk < od8_settings- > >od8_settings_array[od8_id].min_value || > + input_clk > od8_settings- > >od8_settings_array[od8_id].max_value) { > + pr_info("clock freq %d is not within allowed > range [%d - %d]\n", > + input_clk, > + od8_settings- > >od8_settings_array[od8_id].min_value, > + od8_settings- > >od8_settings_array[od8_id].max_value); > + return -EINVAL; > + } > + > + od8_id = OD8_SETTING_GFXCLK_VOLTAGE1 + 2 * > input_index; > + if (input_vol < od8_settings- > >od8_settings_array[od8_id].min_value || > + input_vol > od8_settings- > >od8_settings_array[od8_id].max_value) { > + pr_info("clock voltage %d is not within > allowed range [%d- %d]\n", > + input_vol, > + od8_settings- > >od8_settings_array[od8_id].min_value, > + od8_settings- > >od8_settings_array[od8_id].max_value); > + return -EINVAL; > + } > + > + switch (input_index) { > + case 0: > + od_table->GfxclkFreq1 = input_clk; > + od_table->GfxclkVolt1 = input_vol * > VOLTAGE_SCALE; > + break; > + case 1: > + od_table->GfxclkFreq2 = input_clk; > + od_table->GfxclkVolt2 = input_vol * > VOLTAGE_SCALE; > + break; > + case 2: > + od_table->GfxclkFreq3 = input_clk; > + od_table->GfxclkVolt3 = input_vol * > VOLTAGE_SCALE; > + break; > + } > + } > + > + break; > + > + case PP_OD_RESTORE_DEFAULT_TABLE: > + ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, > table_context->overdrive_table, false); > + if (ret) { > + pr_err("Failed to export over drive table!\n"); > + return ret; > + } > + > + break; > + > + case PP_OD_COMMIT_DPM_TABLE: > + ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, > table_context->overdrive_table, true); > + if (ret) { > + pr_err("Failed to import over drive table!\n"); > + return ret; > + } > + > + /* retrieve updated gfxclk table */ > + if (od8_settings->od_gfxclk_update) { > + od8_settings->od_gfxclk_update = false; > + single_dpm_table = &(dpm_table->gfx_table); > + > + if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_GFXCLK_BIT)) { > + ret = vega20_set_single_dpm_table(smu, > single_dpm_table, > + > PPCLK_GFXCLK); > + if (ret) { > + pr_err("[Setoverdrive] failed to > refresh dpm table!\n"); > + return ret; > + } > + } else { > + single_dpm_table->count = 1; > + single_dpm_table->dpm_levels[0].value = > smu->smu_table.boot_values.gfxclk / 100; > + } > + } > + > + break; > + > + default: > + return -EINVAL; > + } > + > + if (type == PP_OD_COMMIT_DPM_TABLE) { > + mutex_lock(&(smu->mutex)); > + ret = smu_handle_task(smu, smu_dpm->dpm_level, > + > AMD_PP_TASK_READJUST_POWER_STATE); > + mutex_unlock(&(smu->mutex)); > + } > + > + return ret; > +} > + > +static int vega20_dpm_set_uvd_enable(struct smu_context *smu, bool > enable) > +{ > + if (!smu_feature_is_supported(smu, > SMU_FEATURE_DPM_UVD_BIT)) > + return 0; > + > + if (enable == smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_UVD_BIT)) > + return 0; > + > + return smu_feature_set_enabled(smu, > SMU_FEATURE_DPM_UVD_BIT, enable); > +} > + > +static int vega20_dpm_set_vce_enable(struct smu_context *smu, bool > enable) > +{ > + if (!smu_feature_is_supported(smu, > SMU_FEATURE_DPM_VCE_BIT)) > + return 0; > + > + if (enable == smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_VCE_BIT)) > + return 0; > + > + return smu_feature_set_enabled(smu, > SMU_FEATURE_DPM_VCE_BIT, enable); > +} > + > +static int vega20_get_enabled_smc_features(struct smu_context *smu, > + uint64_t *features_enabled) > +{ > + uint32_t feature_mask[2] = {0, 0}; > + int ret = 0; > + > + ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); > + if (ret) > + return ret; > + > + *features_enabled = ((((uint64_t)feature_mask[0] << > SMU_FEATURES_LOW_SHIFT) & SMU_FEATURES_LOW_MASK) | > + (((uint64_t)feature_mask[1] << > SMU_FEATURES_HIGH_SHIFT) & SMU_FEATURES_HIGH_MASK)); > + > + return ret; > +} > + > +static int vega20_enable_smc_features(struct smu_context *smu, > + bool enable, uint64_t feature_mask) > +{ > + uint32_t smu_features_low, smu_features_high; > + int ret = 0; > + > + smu_features_low = (uint32_t)((feature_mask & > SMU_FEATURES_LOW_MASK) >> SMU_FEATURES_LOW_SHIFT); > + smu_features_high = (uint32_t)((feature_mask & > SMU_FEATURES_HIGH_MASK) >> SMU_FEATURES_HIGH_SHIFT); > + > + if (enable) { > + ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_EnableSmuFeaturesLow, > + smu_features_low); > + if (ret) > + return ret; > + ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_EnableSmuFeaturesHigh, > + smu_features_high); > + if (ret) > + return ret; > + } else { > + ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_DisableSmuFeaturesLow, > + smu_features_low); > + if (ret) > + return ret; > + ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_DisableSmuFeaturesHigh, > + smu_features_high); > + if (ret) > + return ret; > + } > + > + return 0; > + > +} > + > +static int vega20_get_ppfeature_status(struct smu_context *smu, char > *buf) > +{ > + static const char *ppfeature_name[] = { > + "DPM_PREFETCHER", > + "GFXCLK_DPM", > + "UCLK_DPM", > + "SOCCLK_DPM", > + "UVD_DPM", > + "VCE_DPM", > + "ULV", > + "MP0CLK_DPM", > + "LINK_DPM", > + "DCEFCLK_DPM", > + "GFXCLK_DS", > + "SOCCLK_DS", > + "LCLK_DS", > + "PPT", > + "TDC", > + "THERMAL", > + "GFX_PER_CU_CG", > + "RM", > + "DCEFCLK_DS", > + "ACDC", > + "VR0HOT", > + "VR1HOT", > + "FW_CTF", > + "LED_DISPLAY", > + "FAN_CONTROL", > + "GFX_EDC", > + "GFXOFF", > + "CG", > + "FCLK_DPM", > + "FCLK_DS", > + "MP1CLK_DS", > + "MP0CLK_DS", > + "XGMI", > + "ECC"}; > + static const char *output_title[] = { > + "FEATURES", > + "BITMASK", > + "ENABLEMENT"}; > + uint64_t features_enabled; > + int i; > + int ret = 0; > + int size = 0; > + > + ret = vega20_get_enabled_smc_features(smu, &features_enabled); > + if (ret) > + return ret; > + > + size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", > features_enabled); > + size += sprintf(buf + size, "%-19s %-22s %s\n", > + output_title[0], > + output_title[1], > + output_title[2]); > + for (i = 0; i < GNLD_FEATURES_MAX; i++) { > + size += sprintf(buf + size, "%-19s 0x%016llx %6s\n", > + ppfeature_name[i], > + 1ULL << i, > + (features_enabled & (1ULL << i)) ? > "Y" : "N"); > + } > + > + return size; > +} > + > +static int vega20_set_ppfeature_status(struct smu_context *smu, uint64_t > new_ppfeature_masks) > +{ > + uint64_t features_enabled; > + uint64_t features_to_enable; > + uint64_t features_to_disable; > + int ret = 0; > + > + if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX)) > + return -EINVAL; > + > + ret = vega20_get_enabled_smc_features(smu, &features_enabled); > + if (ret) > + return ret; > + > + features_to_disable = > + features_enabled & ~new_ppfeature_masks; > + features_to_enable = > + ~features_enabled & new_ppfeature_masks; > + > + pr_debug("features_to_disable 0x%llx\n", features_to_disable); > + pr_debug("features_to_enable 0x%llx\n", features_to_enable); > + > + if (features_to_disable) { > + ret = vega20_enable_smc_features(smu, false, > features_to_disable); > + if (ret) > + return ret; > + } > + > + if (features_to_enable) { > + ret = vega20_enable_smc_features(smu, true, > features_to_enable); > + if (ret) > + return ret; > + } > + > + return 0; > +} > + > +static bool vega20_is_dpm_running(struct smu_context *smu) > +{ > + int ret = 0; > + uint32_t feature_mask[2]; > + unsigned long feature_enabled; > + ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); > + feature_enabled = (unsigned long)((uint64_t)feature_mask[0] | > + ((uint64_t)feature_mask[1] << 32)); > + return !!(feature_enabled & SMC_DPM_FEATURE); > +} > + > +static int vega20_set_thermal_fan_table(struct smu_context *smu) > +{ > + int ret; > + struct smu_table_context *table_context = &smu->smu_table; > + PPTable_t *pptable = table_context->driver_pptable; > + > + ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_SetFanTemperatureTarget, > + (uint32_t)pptable->FanTargetTemperature); > + > + return ret; > +} > + > +static int vega20_get_fan_speed_percent(struct smu_context *smu, > + uint32_t *speed) > +{ > + int ret = 0; > + uint32_t percent = 0; > + uint32_t current_rpm; > + PPTable_t *pptable = smu->smu_table.driver_pptable; > + > + ret = smu_get_current_rpm(smu, ¤t_rpm); > + percent = current_rpm * 100 / pptable->FanMaximumRpm; > + *speed = percent > 100 ? 100 : percent; > + > + return ret; > +} > + > +static int vega20_get_gpu_power(struct smu_context *smu, uint32_t > *value) > +{ > + int ret = 0; > + SmuMetrics_t metrics; > + > + if (!value) > + return -EINVAL; > + > + ret = vega20_get_metrics_table(smu, &metrics); > + if (ret) > + return ret; > + > + *value = metrics.CurrSocketPower << 8; > + > + return 0; > +} > + > +static int vega20_get_current_activity_percent(struct smu_context *smu, > + enum amd_pp_sensors sensor, > + uint32_t *value) > +{ > + int ret = 0; > + SmuMetrics_t metrics; > + > + if (!value) > + return -EINVAL; > + > + ret = vega20_get_metrics_table(smu, &metrics); > + if (ret) > + return ret; > + > + switch (sensor) { > + case AMDGPU_PP_SENSOR_GPU_LOAD: > + *value = metrics.AverageGfxActivity; > + break; > + case AMDGPU_PP_SENSOR_MEM_LOAD: > + *value = metrics.AverageUclkActivity; > + break; > + default: > + pr_err("Invalid sensor for retrieving clock activity\n"); > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int vega20_thermal_get_temperature(struct smu_context *smu, > + enum amd_pp_sensors sensor, > + uint32_t *value) > +{ > + struct amdgpu_device *adev = smu->adev; > + SmuMetrics_t metrics; > + uint32_t temp = 0; > + int ret = 0; > + > + if (!value) > + return -EINVAL; > + > + ret = vega20_get_metrics_table(smu, &metrics); > + if (ret) > + return ret; > + > + switch (sensor) { > + case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: > + temp = RREG32_SOC15(THM, 0, > mmCG_MULT_THERMAL_STATUS); > + temp = (temp & > CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >> > + > CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT; > + > + temp = temp & 0x1ff; > + temp *= SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > + > + *value = temp; > + break; > + case AMDGPU_PP_SENSOR_EDGE_TEMP: > + *value = metrics.TemperatureEdge * > + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > + break; > + case AMDGPU_PP_SENSOR_MEM_TEMP: > + *value = metrics.TemperatureHBM * > + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > + break; > + default: > + pr_err("Invalid sensor for retrieving temp\n"); > + return -EINVAL; > + } > + > + return 0; > +} > +static int vega20_read_sensor(struct smu_context *smu, > + enum amd_pp_sensors sensor, > + void *data, uint32_t *size) > +{ > + int ret = 0; > + struct smu_table_context *table_context = &smu->smu_table; > + PPTable_t *pptable = table_context->driver_pptable; > + > + switch (sensor) { > + case AMDGPU_PP_SENSOR_MAX_FAN_RPM: > + *(uint32_t *)data = pptable->FanMaximumRpm; > + *size = 4; > + break; > + case AMDGPU_PP_SENSOR_MEM_LOAD: > + case AMDGPU_PP_SENSOR_GPU_LOAD: > + ret = vega20_get_current_activity_percent(smu, > + sensor, > + (uint32_t *)data); > + *size = 4; > + break; > + case AMDGPU_PP_SENSOR_GPU_POWER: > + ret = vega20_get_gpu_power(smu, (uint32_t *)data); > + *size = 4; > + break; > + case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: > + case AMDGPU_PP_SENSOR_EDGE_TEMP: > + case AMDGPU_PP_SENSOR_MEM_TEMP: > + ret = vega20_thermal_get_temperature(smu, sensor, > (uint32_t *)data); > + *size = 4; > + break; > + default: > + return -EINVAL; > + } > + > + return ret; > +} > + > +static int vega20_set_watermarks_table(struct smu_context *smu, > + void *watermarks, struct > + > dm_pp_wm_sets_with_clock_ranges_soc15 > + *clock_ranges) > +{ > + int i; > + Watermarks_t *table = watermarks; > + > + if (!table || !clock_ranges) > + return -EINVAL; > + > + if (clock_ranges->num_wm_dmif_sets > 4 || > + clock_ranges->num_wm_mcif_sets > 4) > + return -EINVAL; > + > + for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) { > + table->WatermarkRow[1][i].MinClock = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz / > + 1000)); > + table->WatermarkRow[1][i].MaxClock = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz / > + 1000)); > + table->WatermarkRow[1][i].MinUclk = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz / > + 1000)); > + table->WatermarkRow[1][i].MaxUclk = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz / > + 1000)); > + table->WatermarkRow[1][i].WmSetting = (uint8_t) > + clock_ranges- > >wm_dmif_clocks_ranges[i].wm_set_id; > + } > + > + for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) { > + table->WatermarkRow[0][i].MinClock = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz / > + 1000)); > + table->WatermarkRow[0][i].MaxClock = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz / > + 1000)); > + table->WatermarkRow[0][i].MinUclk = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz / > + 1000)); > + table->WatermarkRow[0][i].MaxUclk = > + cpu_to_le16((uint16_t) > + (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz / > + 1000)); > + table->WatermarkRow[0][i].WmSetting = (uint8_t) > + clock_ranges- > >wm_mcif_clocks_ranges[i].wm_set_id; > + } > + > + return 0; > +} > + > +static const struct smu_temperature_range vega20_thermal_policy[] = > +{ > + {-273150, 99000, 99000, -273150, 99000, 99000, -273150, 99000, 99000}, > + { 120000, 120000, 120000, 120000, 120000, 120000, 120000, 120000, > 120000}, > +}; > + > +static int vega20_get_thermal_temperature_range(struct smu_context > *smu, > + struct > smu_temperature_range*range) > +{ > + > + PPTable_t *pptable = smu->smu_table.driver_pptable; > + > + if (!range) > + return -EINVAL; > + > + memcpy(range, &vega20_thermal_policy[0], sizeof(struct > smu_temperature_range)); > + > + range->max = pptable->TedgeLimit * > + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > + range->edge_emergency_max = (pptable->TedgeLimit + > CTF_OFFSET_EDGE) * > + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > + range->hotspot_crit_max = pptable->ThotspotLimit * > + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > + range->hotspot_emergency_max = (pptable->ThotspotLimit + > CTF_OFFSET_HOTSPOT) * > + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > + range->mem_crit_max = pptable->ThbmLimit * > + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > + range->mem_emergency_max = (pptable->ThbmLimit + > CTF_OFFSET_HBM)* > + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > + > + > + return 0; > +} > + > +static const struct pptable_funcs vega20_ppt_funcs = { > + .tables_init = vega20_tables_init, > + .alloc_dpm_context = vega20_allocate_dpm_context, > + .store_powerplay_table = vega20_store_powerplay_table, > + .check_powerplay_table = vega20_check_powerplay_table, > + .append_powerplay_table = vega20_append_powerplay_table, > + .get_smu_msg_index = vega20_get_smu_msg_index, > + .get_smu_clk_index = vega20_get_smu_clk_index, > + .get_smu_feature_index = vega20_get_smu_feature_index, > + .get_smu_table_index = vega20_get_smu_table_index, > + .get_smu_power_index = vega20_get_pwr_src_index, > + .get_workload_type = vega20_get_workload_type, > + .run_afll_btc = vega20_run_btc_afll, > + .get_allowed_feature_mask = vega20_get_allowed_feature_mask, > + .get_current_power_state = vega20_get_current_power_state, > + .set_default_dpm_table = vega20_set_default_dpm_table, > + .set_power_state = NULL, > + .populate_umd_state_clk = vega20_populate_umd_state_clk, > + .print_clk_levels = vega20_print_clk_levels, > + .force_clk_levels = vega20_force_clk_levels, > + .get_clock_by_type_with_latency = > vega20_get_clock_by_type_with_latency, > + .get_od_percentage = vega20_get_od_percentage, > + .get_power_profile_mode = vega20_get_power_profile_mode, > + .set_power_profile_mode = vega20_set_power_profile_mode, > + .set_od_percentage = vega20_set_od_percentage, > + .set_default_od_settings = vega20_set_default_od_settings, > + .od_edit_dpm_table = vega20_odn_edit_dpm_table, > + .dpm_set_uvd_enable = vega20_dpm_set_uvd_enable, > + .dpm_set_vce_enable = vega20_dpm_set_vce_enable, > + .read_sensor = vega20_read_sensor, > + .pre_display_config_changed = vega20_pre_display_config_changed, > + .display_config_changed = vega20_display_config_changed, > + .apply_clocks_adjust_rules = vega20_apply_clocks_adjust_rules, > + .notify_smc_dispaly_config = vega20_notify_smc_dispaly_config, > + .force_dpm_limit_value = vega20_force_dpm_limit_value, > + .unforce_dpm_levels = vega20_unforce_dpm_levels, > + .get_profiling_clk_mask = vega20_get_profiling_clk_mask, > + .set_ppfeature_status = vega20_set_ppfeature_status, > + .get_ppfeature_status = vega20_get_ppfeature_status, > + .is_dpm_running = vega20_is_dpm_running, > + .set_thermal_fan_table = vega20_set_thermal_fan_table, > + .get_fan_speed_percent = vega20_get_fan_speed_percent, > + .set_watermarks_table = vega20_set_watermarks_table, > + .get_thermal_temperature_range = > vega20_get_thermal_temperature_range > +}; > + > +void vega20_set_ppt_funcs(struct smu_context *smu) > +{ > + struct smu_table_context *smu_table = &smu->smu_table; > + > + smu->ppt_funcs = &vega20_ppt_funcs; > + smu->smc_if_version = SMU11_DRIVER_IF_VERSION; > + smu_table->table_count = TABLE_COUNT; > +} > diff --git a/drivers/gpu/drm/amd/powerplay/pptable/vega20_ppt.h > b/drivers/gpu/drm/amd/powerplay/pptable/vega20_ppt.h > new file mode 100644 > index 0000000..2dc10e4 > --- /dev/null > +++ b/drivers/gpu/drm/amd/powerplay/pptable/vega20_ppt.h > @@ -0,0 +1,179 @@ > +/* > + * Copyright 2019 Advanced Micro Devices, Inc. > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the > "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO > EVENT SHALL > + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, > DAMAGES OR > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR > OTHERWISE, > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR > THE USE OR > + * OTHER DEALINGS IN THE SOFTWARE. > + * > + */ > +#ifndef __VEGA20_PPT_H__ > +#define __VEGA20_PPT_H__ > + > +#define VEGA20_UMD_PSTATE_GFXCLK_LEVEL 0x3 > +#define VEGA20_UMD_PSTATE_SOCCLK_LEVEL 0x3 > +#define VEGA20_UMD_PSTATE_MCLK_LEVEL 0x2 > +#define VEGA20_UMD_PSTATE_UVDCLK_LEVEL 0x3 > +#define VEGA20_UMD_PSTATE_VCEMCLK_LEVEL 0x3 > + > +#define MAX_REGULAR_DPM_NUMBER 16 > +#define MAX_PCIE_CONF 2 > + > +#define VOLTAGE_SCALE 4 > +#define AVFS_CURVE 0 > +#define OD8_HOTCURVE_TEMPERATURE 85 > + > +#define SMU_FEATURES_LOW_MASK 0x00000000FFFFFFFF > +#define SMU_FEATURES_LOW_SHIFT 0 > +#define SMU_FEATURES_HIGH_MASK 0xFFFFFFFF00000000 > +#define SMU_FEATURES_HIGH_SHIFT 32 > + > +enum { > + GNLD_DPM_PREFETCHER = 0, > + GNLD_DPM_GFXCLK, > + GNLD_DPM_UCLK, > + GNLD_DPM_SOCCLK, > + GNLD_DPM_UVD, > + GNLD_DPM_VCE, > + GNLD_ULV, > + GNLD_DPM_MP0CLK, > + GNLD_DPM_LINK, > + GNLD_DPM_DCEFCLK, > + GNLD_DS_GFXCLK, > + GNLD_DS_SOCCLK, > + GNLD_DS_LCLK, > + GNLD_PPT, > + GNLD_TDC, > + GNLD_THERMAL, > + GNLD_GFX_PER_CU_CG, > + GNLD_RM, > + GNLD_DS_DCEFCLK, > + GNLD_ACDC, > + GNLD_VR0HOT, > + GNLD_VR1HOT, > + GNLD_FW_CTF, > + GNLD_LED_DISPLAY, > + GNLD_FAN_CONTROL, > + GNLD_DIDT, > + GNLD_GFXOFF, > + GNLD_CG, > + GNLD_DPM_FCLK, > + GNLD_DS_FCLK, > + GNLD_DS_MP1CLK, > + GNLD_DS_MP0CLK, > + GNLD_XGMI, > + GNLD_ECC, > + > + GNLD_FEATURES_MAX > +}; > + > +struct vega20_dpm_level { > + bool enabled; > + uint32_t value; > + uint32_t param1; > +}; > + > +struct vega20_dpm_state { > + uint32_t soft_min_level; > + uint32_t soft_max_level; > + uint32_t hard_min_level; > + uint32_t hard_max_level; > +}; > + > +struct vega20_single_dpm_table { > + uint32_t count; > + struct vega20_dpm_state dpm_state; > + struct vega20_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER]; > +}; > + > +struct vega20_pcie_table { > + uint16_t count; > + uint8_t pcie_gen[MAX_PCIE_CONF]; > + uint8_t pcie_lane[MAX_PCIE_CONF]; > + uint32_t lclk[MAX_PCIE_CONF]; > +}; > + > +struct vega20_dpm_table { > + struct vega20_single_dpm_table soc_table; > + struct vega20_single_dpm_table gfx_table; > + struct vega20_single_dpm_table mem_table; > + struct vega20_single_dpm_table eclk_table; > + struct vega20_single_dpm_table vclk_table; > + struct vega20_single_dpm_table dclk_table; > + struct vega20_single_dpm_table dcef_table; > + struct vega20_single_dpm_table pixel_table; > + struct vega20_single_dpm_table display_table; > + struct vega20_single_dpm_table phy_table; > + struct vega20_single_dpm_table fclk_table; > + struct vega20_pcie_table pcie_table; > +}; > + > +enum OD8_FEATURE_ID > +{ > + OD8_GFXCLK_LIMITS = 1 << 0, > + OD8_GFXCLK_CURVE = 1 << 1, > + OD8_UCLK_MAX = 1 << 2, > + OD8_POWER_LIMIT = 1 << 3, > + OD8_ACOUSTIC_LIMIT_SCLK = 1 << 4, //FanMaximumRpm > + OD8_FAN_SPEED_MIN = 1 << 5, //FanMinimumPwm > + OD8_TEMPERATURE_FAN = 1 << 6, //FanTargetTemperature > + OD8_TEMPERATURE_SYSTEM = 1 << 7, //MaxOpTemp > + OD8_MEMORY_TIMING_TUNE = 1 << 8, > + OD8_FAN_ZERO_RPM_CONTROL = 1 << 9 > +}; > + > +enum OD8_SETTING_ID > +{ > + OD8_SETTING_GFXCLK_FMIN = 0, > + OD8_SETTING_GFXCLK_FMAX, > + OD8_SETTING_GFXCLK_FREQ1, > + OD8_SETTING_GFXCLK_VOLTAGE1, > + OD8_SETTING_GFXCLK_FREQ2, > + OD8_SETTING_GFXCLK_VOLTAGE2, > + OD8_SETTING_GFXCLK_FREQ3, > + OD8_SETTING_GFXCLK_VOLTAGE3, > + OD8_SETTING_UCLK_FMAX, > + OD8_SETTING_POWER_PERCENTAGE, > + OD8_SETTING_FAN_ACOUSTIC_LIMIT, > + OD8_SETTING_FAN_MIN_SPEED, > + OD8_SETTING_FAN_TARGET_TEMP, > + OD8_SETTING_OPERATING_TEMP_MAX, > + OD8_SETTING_AC_TIMING, > + OD8_SETTING_FAN_ZERO_RPM_CONTROL, > + OD8_SETTING_COUNT > +}; > + > +struct vega20_od8_single_setting { > + uint32_t feature_id; > + int32_t min_value; > + int32_t max_value; > + int32_t current_value; > + int32_t default_value; > +}; > + > +struct vega20_od8_settings { > + struct vega20_od8_single_setting > od8_settings_array[OD8_SETTING_COUNT]; > + uint8_t *od_feature_capabilities; > + uint32_t *od_settings_max; > + uint32_t *od_settings_min; > + void *od8_settings; > + bool od_gfxclk_update; > + bool od_memclk_update; > +}; > + > +extern void vega20_set_ppt_funcs(struct smu_context *smu); > + > +#endif > diff --git a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c > b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c > deleted file mode 100644 > index 9a535f7..0000000 > --- a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c > +++ /dev/null > @@ -1,3302 +0,0 @@ > -/* > - * Copyright 2019 Advanced Micro Devices, Inc. > - * > - * Permission is hereby granted, free of charge, to any person obtaining a > - * copy of this software and associated documentation files (the "Software"), > - * to deal in the Software without restriction, including without limitation > - * the rights to use, copy, modify, merge, publish, distribute, sublicense, > - * and/or sell copies of the Software, and to permit persons to whom the > - * Software is furnished to do so, subject to the following conditions: > - * > - * The above copyright notice and this permission notice shall be included in > - * all copies or substantial portions of the Software. > - * > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS OR > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO > EVENT SHALL > - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, > DAMAGES OR > - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR > OTHERWISE, > - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR > THE USE OR > - * OTHER DEALINGS IN THE SOFTWARE. > - * > - */ > - > -#include "pp_debug.h" > -#include <linux/firmware.h> > -#include "amdgpu.h" > -#include "amdgpu_smu.h" > -#include "atomfirmware.h" > -#include "amdgpu_atomfirmware.h" > -#include "smu_v11_0.h" > -#include "smu11_driver_if.h" > -#include "soc15_common.h" > -#include "atom.h" > -#include "power_state.h" > -#include "vega20_ppt.h" > -#include "vega20_pptable.h" > -#include "vega20_ppsmc.h" > -#include "nbio/nbio_7_4_sh_mask.h" > -#include "asic_reg/thm/thm_11_0_2_offset.h" > -#include "asic_reg/thm/thm_11_0_2_sh_mask.h" > - > -#define smnPCIE_LC_SPEED_CNTL 0x11140290 > -#define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 > - > -#define CTF_OFFSET_EDGE 5 > -#define CTF_OFFSET_HOTSPOT 5 > -#define CTF_OFFSET_HBM 5 > - > -#define MSG_MAP(msg) \ > - [SMU_MSG_##msg] = PPSMC_MSG_##msg > - > -#define SMC_DPM_FEATURE (FEATURE_DPM_PREFETCHER_MASK | \ > - FEATURE_DPM_GFXCLK_MASK | \ > - FEATURE_DPM_UCLK_MASK | \ > - FEATURE_DPM_SOCCLK_MASK | \ > - FEATURE_DPM_UVD_MASK | \ > - FEATURE_DPM_VCE_MASK | \ > - FEATURE_DPM_MP0CLK_MASK | \ > - FEATURE_DPM_LINK_MASK | \ > - FEATURE_DPM_DCEFCLK_MASK) > - > -static int vega20_message_map[SMU_MSG_MAX_COUNT] = { > - MSG_MAP(TestMessage), > - MSG_MAP(GetSmuVersion), > - MSG_MAP(GetDriverIfVersion), > - MSG_MAP(SetAllowedFeaturesMaskLow), > - MSG_MAP(SetAllowedFeaturesMaskHigh), > - MSG_MAP(EnableAllSmuFeatures), > - MSG_MAP(DisableAllSmuFeatures), > - MSG_MAP(EnableSmuFeaturesLow), > - MSG_MAP(EnableSmuFeaturesHigh), > - MSG_MAP(DisableSmuFeaturesLow), > - MSG_MAP(DisableSmuFeaturesHigh), > - MSG_MAP(GetEnabledSmuFeaturesLow), > - MSG_MAP(GetEnabledSmuFeaturesHigh), > - MSG_MAP(SetWorkloadMask), > - MSG_MAP(SetPptLimit), > - MSG_MAP(SetDriverDramAddrHigh), > - MSG_MAP(SetDriverDramAddrLow), > - MSG_MAP(SetToolsDramAddrHigh), > - MSG_MAP(SetToolsDramAddrLow), > - MSG_MAP(TransferTableSmu2Dram), > - MSG_MAP(TransferTableDram2Smu), > - MSG_MAP(UseDefaultPPTable), > - MSG_MAP(UseBackupPPTable), > - MSG_MAP(RunBtc), > - MSG_MAP(RequestI2CBus), > - MSG_MAP(ReleaseI2CBus), > - MSG_MAP(SetFloorSocVoltage), > - MSG_MAP(SoftReset), > - MSG_MAP(StartBacoMonitor), > - MSG_MAP(CancelBacoMonitor), > - MSG_MAP(EnterBaco), > - MSG_MAP(SetSoftMinByFreq), > - MSG_MAP(SetSoftMaxByFreq), > - MSG_MAP(SetHardMinByFreq), > - MSG_MAP(SetHardMaxByFreq), > - MSG_MAP(GetMinDpmFreq), > - MSG_MAP(GetMaxDpmFreq), > - MSG_MAP(GetDpmFreqByIndex), > - MSG_MAP(GetDpmClockFreq), > - MSG_MAP(GetSsVoltageByDpm), > - MSG_MAP(SetMemoryChannelConfig), > - MSG_MAP(SetGeminiMode), > - MSG_MAP(SetGeminiApertureHigh), > - MSG_MAP(SetGeminiApertureLow), > - MSG_MAP(SetMinLinkDpmByIndex), > - MSG_MAP(OverridePcieParameters), > - MSG_MAP(OverDriveSetPercentage), > - MSG_MAP(SetMinDeepSleepDcefclk), > - MSG_MAP(ReenableAcDcInterrupt), > - MSG_MAP(NotifyPowerSource), > - MSG_MAP(SetUclkFastSwitch), > - MSG_MAP(SetUclkDownHyst), > - MSG_MAP(GetCurrentRpm), > - MSG_MAP(SetVideoFps), > - MSG_MAP(SetTjMax), > - MSG_MAP(SetFanTemperatureTarget), > - MSG_MAP(PrepareMp1ForUnload), > - MSG_MAP(DramLogSetDramAddrHigh), > - MSG_MAP(DramLogSetDramAddrLow), > - MSG_MAP(DramLogSetDramSize), > - MSG_MAP(SetFanMaxRpm), > - MSG_MAP(SetFanMinPwm), > - MSG_MAP(ConfigureGfxDidt), > - MSG_MAP(NumOfDisplays), > - MSG_MAP(RemoveMargins), > - MSG_MAP(ReadSerialNumTop32), > - MSG_MAP(ReadSerialNumBottom32), > - MSG_MAP(SetSystemVirtualDramAddrHigh), > - MSG_MAP(SetSystemVirtualDramAddrLow), > - MSG_MAP(WaflTest), > - MSG_MAP(SetFclkGfxClkRatio), > - MSG_MAP(AllowGfxOff), > - MSG_MAP(DisallowGfxOff), > - MSG_MAP(GetPptLimit), > - MSG_MAP(GetDcModeMaxDpmFreq), > - MSG_MAP(GetDebugData), > - MSG_MAP(SetXgmiMode), > - MSG_MAP(RunAfllBtc), > - MSG_MAP(ExitBaco), > - MSG_MAP(PrepareMp1ForReset), > - MSG_MAP(PrepareMp1ForShutdown), > - MSG_MAP(SetMGpuFanBoostLimitRpm), > - MSG_MAP(GetAVFSVoltageByDpm), > -}; > - > -static int vega20_clk_map[SMU_CLK_COUNT] = { > - CLK_MAP(GFXCLK, PPCLK_GFXCLK), > - CLK_MAP(VCLK, PPCLK_VCLK), > - CLK_MAP(DCLK, PPCLK_DCLK), > - CLK_MAP(ECLK, PPCLK_ECLK), > - CLK_MAP(SOCCLK, PPCLK_SOCCLK), > - CLK_MAP(UCLK, PPCLK_UCLK), > - CLK_MAP(DCEFCLK, PPCLK_DCEFCLK), > - CLK_MAP(DISPCLK, PPCLK_DISPCLK), > - CLK_MAP(PIXCLK, PPCLK_PIXCLK), > - CLK_MAP(PHYCLK, PPCLK_PHYCLK), > - CLK_MAP(FCLK, PPCLK_FCLK), > -}; > - > -static int vega20_feature_mask_map[SMU_FEATURE_COUNT] = { > - FEA_MAP(DPM_PREFETCHER), > - FEA_MAP(DPM_GFXCLK), > - FEA_MAP(DPM_UCLK), > - FEA_MAP(DPM_SOCCLK), > - FEA_MAP(DPM_UVD), > - FEA_MAP(DPM_VCE), > - FEA_MAP(ULV), > - FEA_MAP(DPM_MP0CLK), > - FEA_MAP(DPM_LINK), > - FEA_MAP(DPM_DCEFCLK), > - FEA_MAP(DS_GFXCLK), > - FEA_MAP(DS_SOCCLK), > - FEA_MAP(DS_LCLK), > - FEA_MAP(PPT), > - FEA_MAP(TDC), > - FEA_MAP(THERMAL), > - FEA_MAP(GFX_PER_CU_CG), > - FEA_MAP(RM), > - FEA_MAP(DS_DCEFCLK), > - FEA_MAP(ACDC), > - FEA_MAP(VR0HOT), > - FEA_MAP(VR1HOT), > - FEA_MAP(FW_CTF), > - FEA_MAP(LED_DISPLAY), > - FEA_MAP(FAN_CONTROL), > - FEA_MAP(GFX_EDC), > - FEA_MAP(GFXOFF), > - FEA_MAP(CG), > - FEA_MAP(DPM_FCLK), > - FEA_MAP(DS_FCLK), > - FEA_MAP(DS_MP1CLK), > - FEA_MAP(DS_MP0CLK), > - FEA_MAP(XGMI), > -}; > - > -static int vega20_table_map[SMU_TABLE_COUNT] = { > - TAB_MAP(PPTABLE), > - TAB_MAP(WATERMARKS), > - TAB_MAP(AVFS), > - TAB_MAP(AVFS_PSM_DEBUG), > - TAB_MAP(AVFS_FUSE_OVERRIDE), > - TAB_MAP(PMSTATUSLOG), > - TAB_MAP(SMU_METRICS), > - TAB_MAP(DRIVER_SMU_CONFIG), > - TAB_MAP(ACTIVITY_MONITOR_COEFF), > - TAB_MAP(OVERDRIVE), > -}; > - > -static int vega20_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { > - PWR_MAP(AC), > - PWR_MAP(DC), > -}; > - > -static int vega20_workload_map[] = { > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT, > WORKLOAD_DEFAULT_BIT), > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D, > WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT), > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING, > WORKLOAD_PPLIB_POWER_SAVING_BIT), > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO, > WORKLOAD_PPLIB_VIDEO_BIT), > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR, > WORKLOAD_PPLIB_VR_BIT), > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, > WORKLOAD_PPLIB_CUSTOM_BIT), > - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, > WORKLOAD_PPLIB_CUSTOM_BIT), > -}; > - > -static int vega20_get_smu_table_index(struct smu_context *smc, uint32_t > index) > -{ > - int val; > - if (index >= SMU_TABLE_COUNT) > - return -EINVAL; > - > - val = vega20_table_map[index]; > - if (val >= TABLE_COUNT) > - return -EINVAL; > - > - return val; > -} > - > -static int vega20_get_pwr_src_index(struct smu_context *smc, uint32_t > index) > -{ > - int val; > - if (index >= SMU_POWER_SOURCE_COUNT) > - return -EINVAL; > - > - val = vega20_pwr_src_map[index]; > - if (val >= POWER_SOURCE_COUNT) > - return -EINVAL; > - > - return val; > -} > - > -static int vega20_get_smu_feature_index(struct smu_context *smc, > uint32_t index) > -{ > - int val; > - if (index >= SMU_FEATURE_COUNT) > - return -EINVAL; > - > - val = vega20_feature_mask_map[index]; > - if (val > 64) > - return -EINVAL; > - > - return val; > -} > - > -static int vega20_get_smu_clk_index(struct smu_context *smc, uint32_t > index) > -{ > - int val; > - if (index >= SMU_CLK_COUNT) > - return -EINVAL; > - > - val = vega20_clk_map[index]; > - if (val >= PPCLK_COUNT) > - return -EINVAL; > - > - return val; > -} > - > -static int vega20_get_smu_msg_index(struct smu_context *smc, uint32_t > index) > -{ > - int val; > - > - if (index >= SMU_MSG_MAX_COUNT) > - return -EINVAL; > - > - val = vega20_message_map[index]; > - if (val > PPSMC_Message_Count) > - return -EINVAL; > - > - return val; > -} > - > -static int vega20_get_workload_type(struct smu_context *smu, enum > PP_SMC_POWER_PROFILE profile) > -{ > - int val; > - if (profile > PP_SMC_POWER_PROFILE_CUSTOM) > - return -EINVAL; > - > - val = vega20_workload_map[profile]; > - > - return val; > -} > - > -static int vega20_tables_init(struct smu_context *smu, struct smu_table > *tables) > -{ > - struct smu_table_context *smu_table = &smu->smu_table; > - > - SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), > - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > - SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, > sizeof(Watermarks_t), > - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > - SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, > sizeof(SmuMetrics_t), > - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > - SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, > sizeof(OverDriveTable_t), > - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > - SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, > SMU11_TOOL_SIZE, > - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); > - SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF, > - sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE, > - AMDGPU_GEM_DOMAIN_VRAM); > - > - smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), > GFP_KERNEL); > - if (smu_table->metrics_table) > - return -ENOMEM; > - smu_table->metrics_time = 0; > - > - return 0; > -} > - > -static int vega20_allocate_dpm_context(struct smu_context *smu) > -{ > - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > - > - if (smu_dpm->dpm_context) > - return -EINVAL; > - > - smu_dpm->dpm_context = kzalloc(sizeof(struct vega20_dpm_table), > - GFP_KERNEL); > - if (!smu_dpm->dpm_context) > - return -ENOMEM; > - > - if (smu_dpm->golden_dpm_context) > - return -EINVAL; > - > - smu_dpm->golden_dpm_context = kzalloc(sizeof(struct > vega20_dpm_table), > - GFP_KERNEL); > - if (!smu_dpm->golden_dpm_context) > - return -ENOMEM; > - > - smu_dpm->dpm_context_size = sizeof(struct vega20_dpm_table); > - > - smu_dpm->dpm_current_power_state = kzalloc(sizeof(struct > smu_power_state), > - GFP_KERNEL); > - if (!smu_dpm->dpm_current_power_state) > - return -ENOMEM; > - > - smu_dpm->dpm_request_power_state = kzalloc(sizeof(struct > smu_power_state), > - GFP_KERNEL); > - if (!smu_dpm->dpm_request_power_state) > - return -ENOMEM; > - > - return 0; > -} > - > -static int vega20_setup_od8_information(struct smu_context *smu) > -{ > - ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL; > - struct smu_table_context *table_context = &smu->smu_table; > - struct vega20_od8_settings *od8_settings = (struct > vega20_od8_settings *)smu->od_settings; > - > - uint32_t od_feature_count, od_feature_array_size, > - od_setting_count, od_setting_array_size; > - > - if (!table_context->power_play_table) > - return -EINVAL; > - > - powerplay_table = table_context->power_play_table; > - > - if (powerplay_table->OverDrive8Table.ucODTableRevision == 1) { > - /* Setup correct ODFeatureCount, and store ODFeatureArray > from > - * powerplay table to od_feature_capabilities */ > - od_feature_count = > - (le32_to_cpu(powerplay_table- > >OverDrive8Table.ODFeatureCount) > > - ATOM_VEGA20_ODFEATURE_COUNT) ? > - ATOM_VEGA20_ODFEATURE_COUNT : > - le32_to_cpu(powerplay_table- > >OverDrive8Table.ODFeatureCount); > - > - od_feature_array_size = sizeof(uint8_t) * od_feature_count; > - > - if (od8_settings->od_feature_capabilities) > - return -EINVAL; > - > - od8_settings->od_feature_capabilities = > kmemdup(&powerplay_table->OverDrive8Table.ODFeatureCapabilities, > - > od_feature_array_size, > - > GFP_KERNEL); > - if (!od8_settings->od_feature_capabilities) > - return -ENOMEM; > - > - /* Setup correct ODSettingCount, and store ODSettingArray > from > - * powerplay table to od_settings_max and od_setting_min > */ > - od_setting_count = > - (le32_to_cpu(powerplay_table- > >OverDrive8Table.ODSettingCount) > > - ATOM_VEGA20_ODSETTING_COUNT) ? > - ATOM_VEGA20_ODSETTING_COUNT : > - le32_to_cpu(powerplay_table- > >OverDrive8Table.ODSettingCount); > - > - od_setting_array_size = sizeof(uint32_t) * od_setting_count; > - > - if (od8_settings->od_settings_max) > - return -EINVAL; > - > - od8_settings->od_settings_max = > kmemdup(&powerplay_table->OverDrive8Table.ODSettingsMax, > - > od_setting_array_size, > - GFP_KERNEL); > - > - if (!od8_settings->od_settings_max) { > - kfree(od8_settings->od_feature_capabilities); > - od8_settings->od_feature_capabilities = NULL; > - return -ENOMEM; > - } > - > - if (od8_settings->od_settings_min) > - return -EINVAL; > - > - od8_settings->od_settings_min = > kmemdup(&powerplay_table->OverDrive8Table.ODSettingsMin, > - > od_setting_array_size, > - GFP_KERNEL); > - > - if (!od8_settings->od_settings_min) { > - kfree(od8_settings->od_feature_capabilities); > - od8_settings->od_feature_capabilities = NULL; > - kfree(od8_settings->od_settings_max); > - od8_settings->od_settings_max = NULL; > - return -ENOMEM; > - } > - } > - > - return 0; > -} > - > -static int vega20_store_powerplay_table(struct smu_context *smu) > -{ > - ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL; > - struct smu_table_context *table_context = &smu->smu_table; > - int ret; > - > - if (!table_context->power_play_table) > - return -EINVAL; > - > - powerplay_table = table_context->power_play_table; > - > - memcpy(table_context->driver_pptable, &powerplay_table- > >smcPPTable, > - sizeof(PPTable_t)); > - > - table_context->software_shutdown_temp = powerplay_table- > >usSoftwareShutdownTemp; > - table_context->thermal_controller_type = powerplay_table- > >ucThermalControllerType; > - table_context->TDPODLimit = le32_to_cpu(powerplay_table- > >OverDrive8Table.ODSettingsMax[ATOM_VEGA20_ODSETTING_POWERPER > CENTAGE]); > - > - ret = vega20_setup_od8_information(smu); > - > - return ret; > -} > - > -static int vega20_append_powerplay_table(struct smu_context *smu) > -{ > - struct smu_table_context *table_context = &smu->smu_table; > - PPTable_t *smc_pptable = table_context->driver_pptable; > - struct atom_smc_dpm_info_v4_4 *smc_dpm_table; > - int index, i, ret; > - > - index = > get_index_into_master_table(atom_master_list_of_data_tables_v2_1, > - smc_dpm_info); > - > - ret = smu_get_atom_data_table(smu, index, NULL, NULL, NULL, > - (uint8_t **)&smc_dpm_table); > - if (ret) > - return ret; > - > - smc_pptable->MaxVoltageStepGfx = smc_dpm_table- > >maxvoltagestepgfx; > - smc_pptable->MaxVoltageStepSoc = smc_dpm_table- > >maxvoltagestepsoc; > - > - smc_pptable->VddGfxVrMapping = smc_dpm_table- > >vddgfxvrmapping; > - smc_pptable->VddSocVrMapping = smc_dpm_table- > >vddsocvrmapping; > - smc_pptable->VddMem0VrMapping = smc_dpm_table- > >vddmem0vrmapping; > - smc_pptable->VddMem1VrMapping = smc_dpm_table- > >vddmem1vrmapping; > - > - smc_pptable->GfxUlvPhaseSheddingMask = smc_dpm_table- > >gfxulvphasesheddingmask; > - smc_pptable->SocUlvPhaseSheddingMask = smc_dpm_table- > >soculvphasesheddingmask; > - smc_pptable->ExternalSensorPresent = smc_dpm_table- > >externalsensorpresent; > - > - smc_pptable->GfxMaxCurrent = smc_dpm_table->gfxmaxcurrent; > - smc_pptable->GfxOffset = smc_dpm_table->gfxoffset; > - smc_pptable->Padding_TelemetryGfx = smc_dpm_table- > >padding_telemetrygfx; > - > - smc_pptable->SocMaxCurrent = smc_dpm_table->socmaxcurrent; > - smc_pptable->SocOffset = smc_dpm_table->socoffset; > - smc_pptable->Padding_TelemetrySoc = smc_dpm_table- > >padding_telemetrysoc; > - > - smc_pptable->Mem0MaxCurrent = smc_dpm_table- > >mem0maxcurrent; > - smc_pptable->Mem0Offset = smc_dpm_table->mem0offset; > - smc_pptable->Padding_TelemetryMem0 = smc_dpm_table- > >padding_telemetrymem0; > - > - smc_pptable->Mem1MaxCurrent = smc_dpm_table- > >mem1maxcurrent; > - smc_pptable->Mem1Offset = smc_dpm_table->mem1offset; > - smc_pptable->Padding_TelemetryMem1 = smc_dpm_table- > >padding_telemetrymem1; > - > - smc_pptable->AcDcGpio = smc_dpm_table->acdcgpio; > - smc_pptable->AcDcPolarity = smc_dpm_table->acdcpolarity; > - smc_pptable->VR0HotGpio = smc_dpm_table->vr0hotgpio; > - smc_pptable->VR0HotPolarity = smc_dpm_table->vr0hotpolarity; > - > - smc_pptable->VR1HotGpio = smc_dpm_table->vr1hotgpio; > - smc_pptable->VR1HotPolarity = smc_dpm_table->vr1hotpolarity; > - smc_pptable->Padding1 = smc_dpm_table->padding1; > - smc_pptable->Padding2 = smc_dpm_table->padding2; > - > - smc_pptable->LedPin0 = smc_dpm_table->ledpin0; > - smc_pptable->LedPin1 = smc_dpm_table->ledpin1; > - smc_pptable->LedPin2 = smc_dpm_table->ledpin2; > - > - smc_pptable->PllGfxclkSpreadEnabled = smc_dpm_table- > >pllgfxclkspreadenabled; > - smc_pptable->PllGfxclkSpreadPercent = smc_dpm_table- > >pllgfxclkspreadpercent; > - smc_pptable->PllGfxclkSpreadFreq = smc_dpm_table- > >pllgfxclkspreadfreq; > - > - smc_pptable->UclkSpreadEnabled = 0; > - smc_pptable->UclkSpreadPercent = smc_dpm_table- > >uclkspreadpercent; > - smc_pptable->UclkSpreadFreq = smc_dpm_table->uclkspreadfreq; > - > - smc_pptable->FclkSpreadEnabled = smc_dpm_table- > >fclkspreadenabled; > - smc_pptable->FclkSpreadPercent = smc_dpm_table- > >fclkspreadpercent; > - smc_pptable->FclkSpreadFreq = smc_dpm_table->fclkspreadfreq; > - > - smc_pptable->FllGfxclkSpreadEnabled = smc_dpm_table- > >fllgfxclkspreadenabled; > - smc_pptable->FllGfxclkSpreadPercent = smc_dpm_table- > >fllgfxclkspreadpercent; > - smc_pptable->FllGfxclkSpreadFreq = smc_dpm_table- > >fllgfxclkspreadfreq; > - > - for (i = 0; i < I2C_CONTROLLER_NAME_COUNT; i++) { > - smc_pptable->I2cControllers[i].Enabled = > - smc_dpm_table->i2ccontrollers[i].enabled; > - smc_pptable->I2cControllers[i].SlaveAddress = > - smc_dpm_table->i2ccontrollers[i].slaveaddress; > - smc_pptable->I2cControllers[i].ControllerPort = > - smc_dpm_table->i2ccontrollers[i].controllerport; > - smc_pptable->I2cControllers[i].ThermalThrottler = > - smc_dpm_table->i2ccontrollers[i].thermalthrottler; > - smc_pptable->I2cControllers[i].I2cProtocol = > - smc_dpm_table->i2ccontrollers[i].i2cprotocol; > - smc_pptable->I2cControllers[i].I2cSpeed = > - smc_dpm_table->i2ccontrollers[i].i2cspeed; > - } > - > - return 0; > -} > - > -static int vega20_check_powerplay_table(struct smu_context *smu) > -{ > - ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL; > - struct smu_table_context *table_context = &smu->smu_table; > - > - powerplay_table = table_context->power_play_table; > - > - if (powerplay_table->sHeader.format_revision < > ATOM_VEGA20_TABLE_REVISION_VEGA20) { > - pr_err("Unsupported PPTable format!"); > - return -EINVAL; > - } > - > - if (!powerplay_table->sHeader.structuresize) { > - pr_err("Invalid PowerPlay Table!"); > - return -EINVAL; > - } > - > - return 0; > -} > - > -static int vega20_run_btc_afll(struct smu_context *smu) > -{ > - return smu_send_smc_msg(smu, SMU_MSG_RunAfllBtc); > -} > - > -#define FEATURE_MASK(feature) (1ULL << feature) > -static int > -vega20_get_allowed_feature_mask(struct smu_context *smu, > - uint32_t *feature_mask, uint32_t num) > -{ > - if (num > 2) > - return -EINVAL; > - > - memset(feature_mask, 0, sizeof(uint32_t) * num); > - > - *(uint64_t *)feature_mask |= > FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) > - | > FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) > - | FEATURE_MASK(FEATURE_DPM_UCLK_BIT) > - | > FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) > - | FEATURE_MASK(FEATURE_DPM_UVD_BIT) > - | FEATURE_MASK(FEATURE_DPM_VCE_BIT) > - | FEATURE_MASK(FEATURE_ULV_BIT) > - | > FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) > - | FEATURE_MASK(FEATURE_DPM_LINK_BIT) > - | > FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT) > - | FEATURE_MASK(FEATURE_PPT_BIT) > - | FEATURE_MASK(FEATURE_TDC_BIT) > - | FEATURE_MASK(FEATURE_THERMAL_BIT) > - | > FEATURE_MASK(FEATURE_GFX_PER_CU_CG_BIT) > - | FEATURE_MASK(FEATURE_RM_BIT) > - | FEATURE_MASK(FEATURE_ACDC_BIT) > - | FEATURE_MASK(FEATURE_VR0HOT_BIT) > - | FEATURE_MASK(FEATURE_VR1HOT_BIT) > - | FEATURE_MASK(FEATURE_FW_CTF_BIT) > - | > FEATURE_MASK(FEATURE_LED_DISPLAY_BIT) > - | > FEATURE_MASK(FEATURE_FAN_CONTROL_BIT) > - | FEATURE_MASK(FEATURE_GFX_EDC_BIT) > - | FEATURE_MASK(FEATURE_GFXOFF_BIT) > - | FEATURE_MASK(FEATURE_CG_BIT) > - | FEATURE_MASK(FEATURE_DPM_FCLK_BIT) > - | FEATURE_MASK(FEATURE_XGMI_BIT); > - return 0; > -} > - > -static enum > -amd_pm_state_type vega20_get_current_power_state(struct > smu_context *smu) > -{ > - enum amd_pm_state_type pm_type; > - struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); > - > - if (!smu_dpm_ctx->dpm_context || > - !smu_dpm_ctx->dpm_current_power_state) > - return -EINVAL; > - > - mutex_lock(&(smu->mutex)); > - switch (smu_dpm_ctx->dpm_current_power_state- > >classification.ui_label) { > - case SMU_STATE_UI_LABEL_BATTERY: > - pm_type = POWER_STATE_TYPE_BATTERY; > - break; > - case SMU_STATE_UI_LABEL_BALLANCED: > - pm_type = POWER_STATE_TYPE_BALANCED; > - break; > - case SMU_STATE_UI_LABEL_PERFORMANCE: > - pm_type = POWER_STATE_TYPE_PERFORMANCE; > - break; > - default: > - if (smu_dpm_ctx->dpm_current_power_state- > >classification.flags & SMU_STATE_CLASSIFICATION_FLAG_BOOT) > - pm_type = POWER_STATE_TYPE_INTERNAL_BOOT; > - else > - pm_type = POWER_STATE_TYPE_DEFAULT; > - break; > - } > - mutex_unlock(&(smu->mutex)); > - > - return pm_type; > -} > - > -static int > -vega20_set_single_dpm_table(struct smu_context *smu, > - struct vega20_single_dpm_table > *single_dpm_table, > - PPCLK_e clk_id) > -{ > - int ret = 0; > - uint32_t i, num_of_levels = 0, clk; > - > - ret = smu_send_smc_msg_with_param(smu, > - SMU_MSG_GetDpmFreqByIndex, > - (clk_id << 16 | 0xFF)); > - if (ret) { > - pr_err("[GetNumOfDpmLevel] failed to get dpm levels!"); > - return ret; > - } > - > - smu_read_smc_arg(smu, &num_of_levels); > - if (!num_of_levels) { > - pr_err("[GetNumOfDpmLevel] number of clk levels is > invalid!"); > - return -EINVAL; > - } > - > - single_dpm_table->count = num_of_levels; > - > - for (i = 0; i < num_of_levels; i++) { > - ret = smu_send_smc_msg_with_param(smu, > - SMU_MSG_GetDpmFreqByIndex, > - (clk_id << 16 | i)); > - if (ret) { > - pr_err("[GetDpmFreqByIndex] failed to get dpm freq > by index!"); > - return ret; > - } > - smu_read_smc_arg(smu, &clk); > - if (!clk) { > - pr_err("[GetDpmFreqByIndex] clk value is invalid!"); > - return -EINVAL; > - } > - single_dpm_table->dpm_levels[i].value = clk; > - single_dpm_table->dpm_levels[i].enabled = true; > - } > - return 0; > -} > - > -static void vega20_init_single_dpm_state(struct vega20_dpm_state > *dpm_state) > -{ > - dpm_state->soft_min_level = 0x0; > - dpm_state->soft_max_level = 0xffff; > - dpm_state->hard_min_level = 0x0; > - dpm_state->hard_max_level = 0xffff; > -} > - > -static int vega20_set_default_dpm_table(struct smu_context *smu) > -{ > - int ret; > - > - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > - struct vega20_dpm_table *dpm_table = NULL; > - struct vega20_single_dpm_table *single_dpm_table; > - > - dpm_table = smu_dpm->dpm_context; > - > - /* socclk */ > - single_dpm_table = &(dpm_table->soc_table); > - > - if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_SOCCLK_BIT)) { > - ret = vega20_set_single_dpm_table(smu, single_dpm_table, > - PPCLK_SOCCLK); > - if (ret) { > - pr_err("[SetupDefaultDpmTable] failed to get socclk > dpm levels!"); > - return ret; > - } > - } else { > - single_dpm_table->count = 1; > - single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.socclk / 100; > - } > - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > - > - /* gfxclk */ > - single_dpm_table = &(dpm_table->gfx_table); > - > - if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_GFXCLK_BIT)) { > - ret = vega20_set_single_dpm_table(smu, single_dpm_table, > - PPCLK_GFXCLK); > - if (ret) { > - pr_err("[SetupDefaultDpmTable] failed to get gfxclk > dpm levels!"); > - return ret; > - } > - } else { > - single_dpm_table->count = 1; > - single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.gfxclk / 100; > - } > - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > - > - /* memclk */ > - single_dpm_table = &(dpm_table->mem_table); > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) > { > - ret = vega20_set_single_dpm_table(smu, single_dpm_table, > - PPCLK_UCLK); > - if (ret) { > - pr_err("[SetupDefaultDpmTable] failed to get > memclk dpm levels!"); > - return ret; > - } > - } else { > - single_dpm_table->count = 1; > - single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.uclk / 100; > - } > - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > - > - /* eclk */ > - single_dpm_table = &(dpm_table->eclk_table); > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_VCE_BIT)) { > - ret = vega20_set_single_dpm_table(smu, single_dpm_table, > PPCLK_ECLK); > - if (ret) { > - pr_err("[SetupDefaultDpmTable] failed to get eclk > dpm levels!"); > - return ret; > - } > - } else { > - single_dpm_table->count = 1; > - single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.eclk / 100; > - } > - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > - > - /* vclk */ > - single_dpm_table = &(dpm_table->vclk_table); > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT)) { > - ret = vega20_set_single_dpm_table(smu, single_dpm_table, > PPCLK_VCLK); > - if (ret) { > - pr_err("[SetupDefaultDpmTable] failed to get vclk > dpm levels!"); > - return ret; > - } > - } else { > - single_dpm_table->count = 1; > - single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.vclk / 100; > - } > - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > - > - /* dclk */ > - single_dpm_table = &(dpm_table->dclk_table); > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT)) { > - ret = vega20_set_single_dpm_table(smu, single_dpm_table, > PPCLK_DCLK); > - if (ret) { > - pr_err("[SetupDefaultDpmTable] failed to get dclk > dpm levels!"); > - return ret; > - } > - } else { > - single_dpm_table->count = 1; > - single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.dclk / 100; > - } > - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > - > - /* dcefclk */ > - single_dpm_table = &(dpm_table->dcef_table); > - > - if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT)) { > - ret = vega20_set_single_dpm_table(smu, single_dpm_table, > - PPCLK_DCEFCLK); > - if (ret) { > - pr_err("[SetupDefaultDpmTable] failed to get dcefclk > dpm levels!"); > - return ret; > - } > - } else { > - single_dpm_table->count = 1; > - single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.dcefclk / 100; > - } > - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > - > - /* pixclk */ > - single_dpm_table = &(dpm_table->pixel_table); > - > - if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT)) { > - ret = vega20_set_single_dpm_table(smu, single_dpm_table, > - PPCLK_PIXCLK); > - if (ret) { > - pr_err("[SetupDefaultDpmTable] failed to get pixclk > dpm levels!"); > - return ret; > - } > - } else { > - single_dpm_table->count = 0; > - } > - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > - > - /* dispclk */ > - single_dpm_table = &(dpm_table->display_table); > - > - if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT)) { > - ret = vega20_set_single_dpm_table(smu, single_dpm_table, > - PPCLK_DISPCLK); > - if (ret) { > - pr_err("[SetupDefaultDpmTable] failed to get dispclk > dpm levels!"); > - return ret; > - } > - } else { > - single_dpm_table->count = 0; > - } > - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > - > - /* phyclk */ > - single_dpm_table = &(dpm_table->phy_table); > - > - if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT)) { > - ret = vega20_set_single_dpm_table(smu, single_dpm_table, > - PPCLK_PHYCLK); > - if (ret) { > - pr_err("[SetupDefaultDpmTable] failed to get phyclk > dpm levels!"); > - return ret; > - } > - } else { > - single_dpm_table->count = 0; > - } > - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > - > - /* fclk */ > - single_dpm_table = &(dpm_table->fclk_table); > - > - if (smu_feature_is_enabled(smu,FEATURE_DPM_FCLK_BIT)) { > - ret = vega20_set_single_dpm_table(smu, single_dpm_table, > - PPCLK_FCLK); > - if (ret) { > - pr_err("[SetupDefaultDpmTable] failed to get fclk > dpm levels!"); > - return ret; > - } > - } else { > - single_dpm_table->count = 0; > - } > - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); > - > - memcpy(smu_dpm->golden_dpm_context, dpm_table, > - sizeof(struct vega20_dpm_table)); > - > - return 0; > -} > - > -static int vega20_populate_umd_state_clk(struct smu_context *smu) > -{ > - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > - struct vega20_dpm_table *dpm_table = NULL; > - struct vega20_single_dpm_table *gfx_table = NULL; > - struct vega20_single_dpm_table *mem_table = NULL; > - > - dpm_table = smu_dpm->dpm_context; > - gfx_table = &(dpm_table->gfx_table); > - mem_table = &(dpm_table->mem_table); > - > - smu->pstate_sclk = gfx_table->dpm_levels[0].value; > - smu->pstate_mclk = mem_table->dpm_levels[0].value; > - > - if (gfx_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL && > - mem_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL) { > - smu->pstate_sclk = gfx_table- > >dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value; > - smu->pstate_mclk = mem_table- > >dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value; > - } > - > - smu->pstate_sclk = smu->pstate_sclk * 100; > - smu->pstate_mclk = smu->pstate_mclk * 100; > - > - return 0; > -} > - > -static int vega20_get_clk_table(struct smu_context *smu, > - struct pp_clock_levels_with_latency *clocks, > - struct vega20_single_dpm_table *dpm_table) > -{ > - int i, count; > - > - count = (dpm_table->count > MAX_NUM_CLOCKS) ? > MAX_NUM_CLOCKS : dpm_table->count; > - clocks->num_levels = count; > - > - for (i = 0; i < count; i++) { > - clocks->data[i].clocks_in_khz = > - dpm_table->dpm_levels[i].value * 1000; > - clocks->data[i].latency_in_us = 0; > - } > - > - return 0; > -} > - > -static int vega20_print_clk_levels(struct smu_context *smu, > - enum smu_clk_type type, char *buf) > -{ > - int i, now, size = 0; > - int ret = 0; > - uint32_t gen_speed, lane_width; > - struct amdgpu_device *adev = smu->adev; > - struct pp_clock_levels_with_latency clocks; > - struct vega20_single_dpm_table *single_dpm_table; > - struct smu_table_context *table_context = &smu->smu_table; > - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > - struct vega20_dpm_table *dpm_table = NULL; > - struct vega20_od8_settings *od8_settings = > - (struct vega20_od8_settings *)smu->od_settings; > - OverDriveTable_t *od_table = > - (OverDriveTable_t *)(table_context->overdrive_table); > - PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable; > - > - dpm_table = smu_dpm->dpm_context; > - > - switch (type) { > - case SMU_SCLK: > - ret = smu_get_current_clk_freq(smu, SMU_GFXCLK, &now); > - if (ret) { > - pr_err("Attempt to get current gfx clk Failed!"); > - return ret; > - } > - > - single_dpm_table = &(dpm_table->gfx_table); > - ret = vega20_get_clk_table(smu, &clocks, single_dpm_table); > - if (ret) { > - pr_err("Attempt to get gfx clk levels Failed!"); > - return ret; > - } > - > - for (i = 0; i < clocks.num_levels; i++) > - size += sprintf(buf + size, "%d: %uMhz %s\n", i, > - clocks.data[i].clocks_in_khz / 1000, > - (clocks.data[i].clocks_in_khz == now > * 10) > - ? "*" : ""); > - break; > - > - case SMU_MCLK: > - ret = smu_get_current_clk_freq(smu, SMU_UCLK, &now); > - if (ret) { > - pr_err("Attempt to get current mclk Failed!"); > - return ret; > - } > - > - single_dpm_table = &(dpm_table->mem_table); > - ret = vega20_get_clk_table(smu, &clocks, single_dpm_table); > - if (ret) { > - pr_err("Attempt to get memory clk levels Failed!"); > - return ret; > - } > - > - for (i = 0; i < clocks.num_levels; i++) > - size += sprintf(buf + size, "%d: %uMhz %s\n", > - i, clocks.data[i].clocks_in_khz / 1000, > - (clocks.data[i].clocks_in_khz == now * 10) > - ? "*" : ""); > - break; > - > - case SMU_SOCCLK: > - ret = smu_get_current_clk_freq(smu, PPCLK_SOCCLK, > &now); > - if (ret) { > - pr_err("Attempt to get current socclk Failed!"); > - return ret; > - } > - > - single_dpm_table = &(dpm_table->soc_table); > - ret = vega20_get_clk_table(smu, &clocks, single_dpm_table); > - if (ret) { > - pr_err("Attempt to get socclk levels Failed!"); > - return ret; > - } > - > - for (i = 0; i < clocks.num_levels; i++) > - size += sprintf(buf + size, "%d: %uMhz %s\n", > - i, clocks.data[i].clocks_in_khz / 1000, > - (clocks.data[i].clocks_in_khz == now * 10) > - ? "*" : ""); > - break; > - > - case SMU_FCLK: > - ret = smu_get_current_clk_freq(smu, PPCLK_FCLK, &now); > - if (ret) { > - pr_err("Attempt to get current fclk Failed!"); > - return ret; > - } > - > - single_dpm_table = &(dpm_table->fclk_table); > - for (i = 0; i < single_dpm_table->count; i++) > - size += sprintf(buf + size, "%d: %uMhz %s\n", > - i, single_dpm_table->dpm_levels[i].value, > - (single_dpm_table->dpm_levels[i].value == > now / 100) > - ? "*" : ""); > - break; > - > - case SMU_DCEFCLK: > - ret = smu_get_current_clk_freq(smu, PPCLK_DCEFCLK, > &now); > - if (ret) { > - pr_err("Attempt to get current dcefclk Failed!"); > - return ret; > - } > - > - single_dpm_table = &(dpm_table->dcef_table); > - ret = vega20_get_clk_table(smu, &clocks, single_dpm_table); > - if (ret) { > - pr_err("Attempt to get dcefclk levels Failed!"); > - return ret; > - } > - > - for (i = 0; i < clocks.num_levels; i++) > - size += sprintf(buf + size, "%d: %uMhz %s\n", > - i, clocks.data[i].clocks_in_khz / 1000, > - (clocks.data[i].clocks_in_khz == now * 10) ? > "*" : ""); > - break; > - > - case SMU_PCIE: > - gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & > - > PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) > - >> > PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT; > - lane_width = > (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) & > - > PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK) > - >> > PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT; > - for (i = 0; i < NUM_LINK_LEVELS; i++) > - size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i, > - (pptable->PcieGenSpeed[i] == 0) ? > "2.5GT/s," : > - (pptable->PcieGenSpeed[i] == 1) ? > "5.0GT/s," : > - (pptable->PcieGenSpeed[i] == 2) ? > "8.0GT/s," : > - (pptable->PcieGenSpeed[i] == 3) ? > "16.0GT/s," : "", > - (pptable->PcieLaneCount[i] == 1) ? > "x1" : > - (pptable->PcieLaneCount[i] == 2) ? > "x2" : > - (pptable->PcieLaneCount[i] == 3) ? > "x4" : > - (pptable->PcieLaneCount[i] == 4) ? > "x8" : > - (pptable->PcieLaneCount[i] == 5) ? > "x12" : > - (pptable->PcieLaneCount[i] == 6) ? > "x16" : "", > - pptable->LclkFreq[i], > - (gen_speed == pptable- > >PcieGenSpeed[i]) && > - (lane_width == pptable- > >PcieLaneCount[i]) ? > - "*" : ""); > - break; > - > - case SMU_OD_SCLK: > - if (od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id) { > - size = sprintf(buf, "%s:\n", "OD_SCLK"); > - size += sprintf(buf + size, "0: %10uMhz\n", > - od_table->GfxclkFmin); > - size += sprintf(buf + size, "1: %10uMhz\n", > - od_table->GfxclkFmax); > - } > - > - break; > - > - case SMU_OD_MCLK: > - if (od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) { > - size = sprintf(buf, "%s:\n", "OD_MCLK"); > - size += sprintf(buf + size, "1: %10uMhz\n", > - od_table->UclkFmax); > - } > - > - break; > - > - case SMU_OD_VDDC_CURVE: > - if (od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) { > - size = sprintf(buf, "%s:\n", "OD_VDDC_CURVE"); > - size += sprintf(buf + size, "0: %10uMhz %10dmV\n", > - od_table->GfxclkFreq1, > - od_table->GfxclkVolt1 / > VOLTAGE_SCALE); > - size += sprintf(buf + size, "1: %10uMhz %10dmV\n", > - od_table->GfxclkFreq2, > - od_table->GfxclkVolt2 / > VOLTAGE_SCALE); > - size += sprintf(buf + size, "2: %10uMhz %10dmV\n", > - od_table->GfxclkFreq3, > - od_table->GfxclkVolt3 / > VOLTAGE_SCALE); > - } > - > - break; > - > - case SMU_OD_RANGE: > - size = sprintf(buf, "%s:\n", "OD_RANGE"); > - > - if (od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id) { > - size += sprintf(buf + size, > "SCLK: %7uMhz %10uMhz\n", > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value, > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value); > - } > - > - if (od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) { > - single_dpm_table = &(dpm_table->mem_table); > - ret = vega20_get_clk_table(smu, &clocks, > single_dpm_table); > - if (ret) { > - pr_err("Attempt to get memory clk levels > Failed!"); > - return ret; > - } > - > - size += sprintf(buf + size, > "MCLK: %7uMhz %10uMhz\n", > - clocks.data[0].clocks_in_khz / 1000, > - od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value); > - } > - > - if (od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) { > - size += sprintf(buf + size, > "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n", > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].min_value, > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].max_value); > - size += sprintf(buf + size, > "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n", > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].min_value, > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].max_value); > - size += sprintf(buf + size, > "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n", > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].min_value, > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].max_value); > - size += sprintf(buf + size, > "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n", > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].min_value, > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].max_value); > - size += sprintf(buf + size, > "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n", > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].min_value, > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].max_value); > - size += sprintf(buf + size, > "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n", > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].min_value, > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].max_value); > - } > - > - break; > - > - default: > - break; > - } > - return size; > -} > - > -static int vega20_upload_dpm_level(struct smu_context *smu, bool max, > - uint32_t feature_mask) > -{ > - struct vega20_dpm_table *dpm_table; > - struct vega20_single_dpm_table *single_dpm_table; > - uint32_t freq; > - int ret = 0; > - > - dpm_table = smu->smu_dpm.dpm_context; > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT) > && > - (feature_mask & FEATURE_DPM_GFXCLK_MASK)) { > - single_dpm_table = &(dpm_table->gfx_table); > - freq = max ? single_dpm_table->dpm_state.soft_max_level : > - single_dpm_table->dpm_state.soft_min_level; > - ret = smu_send_smc_msg_with_param(smu, > - (max ? SMU_MSG_SetSoftMaxByFreq : > SMU_MSG_SetSoftMinByFreq), > - (PPCLK_GFXCLK << 16) | (freq & 0xffff)); > - if (ret) { > - pr_err("Failed to set soft %s gfxclk !\n", > - max ? "max" : "min"); > - return ret; > - } > - } > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT) > && > - (feature_mask & FEATURE_DPM_UCLK_MASK)) { > - single_dpm_table = &(dpm_table->mem_table); > - freq = max ? single_dpm_table->dpm_state.soft_max_level : > - single_dpm_table->dpm_state.soft_min_level; > - ret = smu_send_smc_msg_with_param(smu, > - (max ? SMU_MSG_SetSoftMaxByFreq : > SMU_MSG_SetSoftMinByFreq), > - (PPCLK_UCLK << 16) | (freq & 0xffff)); > - if (ret) { > - pr_err("Failed to set soft %s memclk !\n", > - max ? "max" : "min"); > - return ret; > - } > - } > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT) > && > - (feature_mask & FEATURE_DPM_SOCCLK_MASK)) { > - single_dpm_table = &(dpm_table->soc_table); > - freq = max ? single_dpm_table->dpm_state.soft_max_level : > - single_dpm_table->dpm_state.soft_min_level; > - ret = smu_send_smc_msg_with_param(smu, > - (max ? SMU_MSG_SetSoftMaxByFreq : > SMU_MSG_SetSoftMinByFreq), > - (PPCLK_SOCCLK << 16) | (freq & 0xffff)); > - if (ret) { > - pr_err("Failed to set soft %s socclk !\n", > - max ? "max" : "min"); > - return ret; > - } > - } > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT) > && > - (feature_mask & FEATURE_DPM_FCLK_MASK)) { > - single_dpm_table = &(dpm_table->fclk_table); > - freq = max ? single_dpm_table->dpm_state.soft_max_level : > - single_dpm_table->dpm_state.soft_min_level; > - ret = smu_send_smc_msg_with_param(smu, > - (max ? SMU_MSG_SetSoftMaxByFreq : > SMU_MSG_SetSoftMinByFreq), > - (PPCLK_FCLK << 16) | (freq & 0xffff)); > - if (ret) { > - pr_err("Failed to set soft %s fclk !\n", > - max ? "max" : "min"); > - return ret; > - } > - } > - > - if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT) && > - (feature_mask & FEATURE_DPM_DCEFCLK_MASK)) { > - single_dpm_table = &(dpm_table->dcef_table); > - freq = single_dpm_table->dpm_state.hard_min_level; > - if (!max) { > - ret = smu_send_smc_msg_with_param(smu, > - SMU_MSG_SetHardMinByFreq, > - (PPCLK_DCEFCLK << 16) | (freq & 0xffff)); > - if (ret) { > - pr_err("Failed to set hard min dcefclk !\n"); > - return ret; > - } > - } > - } > - > - return ret; > -} > - > -static int vega20_force_clk_levels(struct smu_context *smu, > - enum smu_clk_type clk_type, uint32_t mask) > -{ > - struct vega20_dpm_table *dpm_table; > - struct vega20_single_dpm_table *single_dpm_table; > - uint32_t soft_min_level, soft_max_level, hard_min_level; > - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > - int ret = 0; > - > - if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) { > - pr_info("force clock level is for dpm manual mode only.\n"); > - return -EINVAL; > - } > - > - mutex_lock(&(smu->mutex)); > - > - soft_min_level = mask ? (ffs(mask) - 1) : 0; > - soft_max_level = mask ? (fls(mask) - 1) : 0; > - > - dpm_table = smu->smu_dpm.dpm_context; > - > - switch (clk_type) { > - case SMU_SCLK: > - single_dpm_table = &(dpm_table->gfx_table); > - > - if (soft_max_level >= single_dpm_table->count) { > - pr_err("Clock level specified %d is over max > allowed %d\n", > - soft_max_level, single_dpm_table- > >count - 1); > - ret = -EINVAL; > - break; > - } > - > - single_dpm_table->dpm_state.soft_min_level = > - single_dpm_table- > >dpm_levels[soft_min_level].value; > - single_dpm_table->dpm_state.soft_max_level = > - single_dpm_table- > >dpm_levels[soft_max_level].value; > - > - ret = vega20_upload_dpm_level(smu, false, > FEATURE_DPM_GFXCLK_MASK); > - if (ret) { > - pr_err("Failed to upload boot level to lowest!\n"); > - break; > - } > - > - ret = vega20_upload_dpm_level(smu, true, > FEATURE_DPM_GFXCLK_MASK); > - if (ret) > - pr_err("Failed to upload dpm max level to > highest!\n"); > - > - break; > - > - case SMU_MCLK: > - single_dpm_table = &(dpm_table->mem_table); > - > - if (soft_max_level >= single_dpm_table->count) { > - pr_err("Clock level specified %d is over max > allowed %d\n", > - soft_max_level, single_dpm_table- > >count - 1); > - ret = -EINVAL; > - break; > - } > - > - single_dpm_table->dpm_state.soft_min_level = > - single_dpm_table- > >dpm_levels[soft_min_level].value; > - single_dpm_table->dpm_state.soft_max_level = > - single_dpm_table- > >dpm_levels[soft_max_level].value; > - > - ret = vega20_upload_dpm_level(smu, false, > FEATURE_DPM_UCLK_MASK); > - if (ret) { > - pr_err("Failed to upload boot level to lowest!\n"); > - break; > - } > - > - ret = vega20_upload_dpm_level(smu, true, > FEATURE_DPM_UCLK_MASK); > - if (ret) > - pr_err("Failed to upload dpm max level to > highest!\n"); > - > - break; > - > - case SMU_SOCCLK: > - single_dpm_table = &(dpm_table->soc_table); > - > - if (soft_max_level >= single_dpm_table->count) { > - pr_err("Clock level specified %d is over max > allowed %d\n", > - soft_max_level, single_dpm_table- > >count - 1); > - ret = -EINVAL; > - break; > - } > - > - single_dpm_table->dpm_state.soft_min_level = > - single_dpm_table- > >dpm_levels[soft_min_level].value; > - single_dpm_table->dpm_state.soft_max_level = > - single_dpm_table- > >dpm_levels[soft_max_level].value; > - > - ret = vega20_upload_dpm_level(smu, false, > FEATURE_DPM_SOCCLK_MASK); > - if (ret) { > - pr_err("Failed to upload boot level to lowest!\n"); > - break; > - } > - > - ret = vega20_upload_dpm_level(smu, true, > FEATURE_DPM_SOCCLK_MASK); > - if (ret) > - pr_err("Failed to upload dpm max level to > highest!\n"); > - > - break; > - > - case SMU_FCLK: > - single_dpm_table = &(dpm_table->fclk_table); > - > - if (soft_max_level >= single_dpm_table->count) { > - pr_err("Clock level specified %d is over max > allowed %d\n", > - soft_max_level, single_dpm_table- > >count - 1); > - ret = -EINVAL; > - break; > - } > - > - single_dpm_table->dpm_state.soft_min_level = > - single_dpm_table- > >dpm_levels[soft_min_level].value; > - single_dpm_table->dpm_state.soft_max_level = > - single_dpm_table- > >dpm_levels[soft_max_level].value; > - > - ret = vega20_upload_dpm_level(smu, false, > FEATURE_DPM_FCLK_MASK); > - if (ret) { > - pr_err("Failed to upload boot level to lowest!\n"); > - break; > - } > - > - ret = vega20_upload_dpm_level(smu, true, > FEATURE_DPM_FCLK_MASK); > - if (ret) > - pr_err("Failed to upload dpm max level to > highest!\n"); > - > - break; > - > - case SMU_DCEFCLK: > - hard_min_level = soft_min_level; > - single_dpm_table = &(dpm_table->dcef_table); > - > - if (hard_min_level >= single_dpm_table->count) { > - pr_err("Clock level specified %d is over max > allowed %d\n", > - hard_min_level, single_dpm_table- > >count - 1); > - ret = -EINVAL; > - break; > - } > - > - single_dpm_table->dpm_state.hard_min_level = > - single_dpm_table- > >dpm_levels[hard_min_level].value; > - > - ret = vega20_upload_dpm_level(smu, false, > FEATURE_DPM_DCEFCLK_MASK); > - if (ret) > - pr_err("Failed to upload boot level to lowest!\n"); > - > - break; > - > - case SMU_PCIE: > - if (soft_min_level >= NUM_LINK_LEVELS || > - soft_max_level >= NUM_LINK_LEVELS) { > - ret = -EINVAL; > - break; > - } > - > - ret = smu_send_smc_msg_with_param(smu, > - SMU_MSG_SetMinLinkDpmByIndex, > soft_min_level); > - if (ret) > - pr_err("Failed to set min link dpm level!\n"); > - > - break; > - > - default: > - break; > - } > - > - mutex_unlock(&(smu->mutex)); > - return ret; > -} > - > -static int vega20_get_clock_by_type_with_latency(struct smu_context > *smu, > - enum smu_clk_type > clk_type, > - struct > pp_clock_levels_with_latency *clocks) > -{ > - int ret; > - struct vega20_single_dpm_table *single_dpm_table; > - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > - struct vega20_dpm_table *dpm_table = NULL; > - > - dpm_table = smu_dpm->dpm_context; > - > - mutex_lock(&smu->mutex); > - > - switch (clk_type) { > - case SMU_GFXCLK: > - single_dpm_table = &(dpm_table->gfx_table); > - ret = vega20_get_clk_table(smu, clocks, single_dpm_table); > - break; > - case SMU_MCLK: > - single_dpm_table = &(dpm_table->mem_table); > - ret = vega20_get_clk_table(smu, clocks, single_dpm_table); > - break; > - case SMU_DCEFCLK: > - single_dpm_table = &(dpm_table->dcef_table); > - ret = vega20_get_clk_table(smu, clocks, single_dpm_table); > - break; > - case SMU_SOCCLK: > - single_dpm_table = &(dpm_table->soc_table); > - ret = vega20_get_clk_table(smu, clocks, single_dpm_table); > - break; > - default: > - ret = -EINVAL; > - } > - > - mutex_unlock(&smu->mutex); > - return ret; > -} > - > -static int vega20_overdrive_get_gfx_clk_base_voltage(struct smu_context > *smu, > - uint32_t *voltage, > - uint32_t freq) > -{ > - int ret; > - > - ret = smu_send_smc_msg_with_param(smu, > - SMU_MSG_GetAVFSVoltageByDpm, > - ((AVFS_CURVE << 24) | > (OD8_HOTCURVE_TEMPERATURE << 16) | freq)); > - if (ret) { > - pr_err("[GetBaseVoltage] failed to get GFXCLK AVFS voltage > from SMU!"); > - return ret; > - } > - > - smu_read_smc_arg(smu, voltage); > - *voltage = *voltage / VOLTAGE_SCALE; > - > - return 0; > -} > - > -static int vega20_set_default_od8_setttings(struct smu_context *smu) > -{ > - struct smu_table_context *table_context = &smu->smu_table; > - OverDriveTable_t *od_table = (OverDriveTable_t *)(table_context- > >overdrive_table); > - struct vega20_od8_settings *od8_settings = NULL; > - PPTable_t *smc_pptable = table_context->driver_pptable; > - int i, ret; > - > - if (smu->od_settings) > - return -EINVAL; > - > - od8_settings = kzalloc(sizeof(struct vega20_od8_settings), > GFP_KERNEL); > - > - if (od8_settings) > - return -ENOMEM; > - > - smu->od_settings = (void *)od8_settings; > - > - if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_SOCCLK_BIT)) { > - if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_LIMITS] && > - od8_settings- > >od_settings_max[OD8_SETTING_GFXCLK_FMAX] > 0 && > - od8_settings- > >od_settings_min[OD8_SETTING_GFXCLK_FMIN] > 0 && > - (od8_settings- > >od_settings_max[OD8_SETTING_GFXCLK_FMAX] >= > - od8_settings- > >od_settings_min[OD8_SETTING_GFXCLK_FMIN])) { > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id = > - OD8_GFXCLK_LIMITS; > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id = > - OD8_GFXCLK_LIMITS; > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value = > - od_table->GfxclkFmin; > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value = > - od_table->GfxclkFmax; > - } > - > - if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_CURVE] && > - (od8_settings- > >od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] >= > - smc_pptable->MinVoltageGfx / VOLTAGE_SCALE) && > - (od8_settings- > >od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3] <= > - smc_pptable->MaxVoltageGfx / VOLTAGE_SCALE) && > - (od8_settings- > >od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] <= > - od8_settings- > >od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3])) { > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id = > - OD8_GFXCLK_CURVE; > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id = > - OD8_GFXCLK_CURVE; > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id = > - OD8_GFXCLK_CURVE; > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id = > - OD8_GFXCLK_CURVE; > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id = > - OD8_GFXCLK_CURVE; > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id = > - OD8_GFXCLK_CURVE; > - > - od_table->GfxclkFreq1 = od_table->GfxclkFmin; > - od_table->GfxclkFreq2 = (od_table->GfxclkFmin + > od_table->GfxclkFmax) / 2; > - od_table->GfxclkFreq3 = od_table->GfxclkFmax; > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value = > - od_table->GfxclkFreq1; > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value = > - od_table->GfxclkFreq2; > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value = > - od_table->GfxclkFreq3; > - > - ret = > vega20_overdrive_get_gfx_clk_base_voltage(smu, > - &od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value, > - od_table->GfxclkFreq1); > - if (ret) > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value = 0; > - od_table->GfxclkVolt1 = > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value > - * VOLTAGE_SCALE; > - ret = > vega20_overdrive_get_gfx_clk_base_voltage(smu, > - &od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value, > - od_table->GfxclkFreq2); > - if (ret) > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value = 0; > - od_table->GfxclkVolt2 = > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value > - * VOLTAGE_SCALE; > - ret = > vega20_overdrive_get_gfx_clk_base_voltage(smu, > - &od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value, > - od_table->GfxclkFreq3); > - if (ret) > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value = 0; > - od_table->GfxclkVolt3 = > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value > - * VOLTAGE_SCALE; > - } > - } > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) > { > - if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_UCLK_MAX] && > - od8_settings- > >od_settings_min[OD8_SETTING_UCLK_FMAX] > 0 && > - od8_settings- > >od_settings_max[OD8_SETTING_UCLK_FMAX] > 0 && > - (od8_settings- > >od_settings_max[OD8_SETTING_UCLK_FMAX] >= > - od8_settings- > >od_settings_min[OD8_SETTING_UCLK_FMAX])) { > - od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id = > - OD8_UCLK_MAX; > - od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value = > - od_table->UclkFmax; > - } > - } > - > - if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_POWER_LIMIT] && > - od8_settings- > >od_settings_min[OD8_SETTING_POWER_PERCENTAGE] > 0 && > - od8_settings- > >od_settings_min[OD8_SETTING_POWER_PERCENTAGE] <= 100 && > - od8_settings- > >od_settings_max[OD8_SETTING_POWER_PERCENTAGE] > 0 && > - od8_settings- > >od_settings_max[OD8_SETTING_POWER_PERCENTAGE] <= 100) { > - od8_settings- > >od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id = > - OD8_POWER_LIMIT; > - od8_settings- > >od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value = > - od_table->OverDrivePct; > - } > - > - if (smu_feature_is_enabled(smu, > SMU_FEATURE_FAN_CONTROL_BIT)) { > - if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_ACOUSTIC_LI > MIT] && > - od8_settings- > >od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 && > - od8_settings- > >od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 && > - (od8_settings- > >od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] >= > - od8_settings- > >od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT])) { > - od8_settings- > >od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id = > - OD8_ACOUSTIC_LIMIT_SCLK; > - od8_settings- > >od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value = > - od_table->FanMaximumRpm; > - } > - > - if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_SPEED_MIN] > && > - od8_settings- > >od_settings_min[OD8_SETTING_FAN_MIN_SPEED] > 0 && > - od8_settings- > >od_settings_max[OD8_SETTING_FAN_MIN_SPEED] > 0 && > - (od8_settings- > >od_settings_max[OD8_SETTING_FAN_MIN_SPEED] >= > - od8_settings- > >od_settings_min[OD8_SETTING_FAN_MIN_SPEED])) { > - od8_settings- > >od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id = > - OD8_FAN_SPEED_MIN; > - od8_settings- > >od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value = > - od_table->FanMinimumPwm * smc_pptable- > >FanMaximumRpm / 100; > - } > - } > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_THERMAL_BIT)) { > - if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_FAN] > && > - od8_settings- > >od_settings_min[OD8_SETTING_FAN_TARGET_TEMP] > 0 && > - od8_settings- > >od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] > 0 && > - (od8_settings- > >od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] >= > - od8_settings- > >od_settings_min[OD8_SETTING_FAN_TARGET_TEMP])) { > - od8_settings- > >od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id = > - OD8_TEMPERATURE_FAN; > - od8_settings- > >od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value = > - od_table->FanTargetTemperature; > - } > - > - if (od8_settings- > >od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_SYS > TEM] && > - od8_settings- > >od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX] > 0 && > - od8_settings- > >od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] > 0 && > - (od8_settings- > >od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] >= > - od8_settings- > >od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX])) { > - od8_settings- > >od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id = > - OD8_TEMPERATURE_SYSTEM; > - od8_settings- > >od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_valu > e = > - od_table->MaxOpTemp; > - } > - } > - > - for (i = 0; i < OD8_SETTING_COUNT; i++) { > - if (od8_settings->od8_settings_array[i].feature_id) { > - od8_settings->od8_settings_array[i].min_value = > - od8_settings->od_settings_min[i]; > - od8_settings->od8_settings_array[i].max_value = > - od8_settings->od_settings_max[i]; > - od8_settings->od8_settings_array[i].current_value = > - od8_settings- > >od8_settings_array[i].default_value; > - } else { > - od8_settings->od8_settings_array[i].min_value = 0; > - od8_settings->od8_settings_array[i].max_value = 0; > - od8_settings->od8_settings_array[i].current_value = > 0; > - } > - } > - > - return 0; > -} > - > -static int vega20_get_metrics_table(struct smu_context *smu, > - SmuMetrics_t *metrics_table) > -{ > - struct smu_table_context *smu_table= &smu->smu_table; > - int ret = 0; > - > - if (!smu_table->metrics_time || time_after(jiffies, smu_table- > >metrics_time + HZ / 1000)) { > - ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, > - (void *)smu_table->metrics_table, false); > - if (ret) { > - pr_info("Failed to export SMU metrics table!\n"); > - return ret; > - } > - smu_table->metrics_time = jiffies; > - } > - > - memcpy(metrics_table, smu_table->metrics_table, > sizeof(SmuMetrics_t)); > - > - return ret; > -} > - > -static int vega20_set_default_od_settings(struct smu_context *smu, > - bool initialize) > -{ > - struct smu_table_context *table_context = &smu->smu_table; > - int ret; > - > - if (initialize) { > - if (table_context->overdrive_table) > - return -EINVAL; > - > - table_context->overdrive_table = > kzalloc(sizeof(OverDriveTable_t), GFP_KERNEL); > - > - if (!table_context->overdrive_table) > - return -ENOMEM; > - > - ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, > - table_context->overdrive_table, false); > - if (ret) { > - pr_err("Failed to export over drive table!\n"); > - return ret; > - } > - > - ret = vega20_set_default_od8_setttings(smu); > - if (ret) > - return ret; > - } > - > - ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, > - table_context->overdrive_table, true); > - if (ret) { > - pr_err("Failed to import over drive table!\n"); > - return ret; > - } > - > - return 0; > -} > - > -static int vega20_get_od_percentage(struct smu_context *smu, > - enum smu_clk_type clk_type) > -{ > - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > - struct vega20_dpm_table *dpm_table = NULL; > - struct vega20_dpm_table *golden_table = NULL; > - struct vega20_single_dpm_table *single_dpm_table; > - struct vega20_single_dpm_table *golden_dpm_table; > - int value, golden_value; > - > - dpm_table = smu_dpm->dpm_context; > - golden_table = smu_dpm->golden_dpm_context; > - > - switch (clk_type) { > - case SMU_OD_SCLK: > - single_dpm_table = &(dpm_table->gfx_table); > - golden_dpm_table = &(golden_table->gfx_table); > - break; > - case SMU_OD_MCLK: > - single_dpm_table = &(dpm_table->mem_table); > - golden_dpm_table = &(golden_table->mem_table); > - break; > - default: > - return -EINVAL; > - break; > - } > - > - value = single_dpm_table->dpm_levels[single_dpm_table->count - > 1].value; > - golden_value = golden_dpm_table- > >dpm_levels[golden_dpm_table->count - 1].value; > - > - value -= golden_value; > - value = DIV_ROUND_UP(value * 100, golden_value); > - > - return value; > -} > - > -static int vega20_get_power_profile_mode(struct smu_context *smu, char > *buf) > -{ > - DpmActivityMonitorCoeffInt_t activity_monitor; > - uint32_t i, size = 0; > - uint16_t workload_type = 0; > - static const char *profile_name[] = { > - "BOOTUP_DEFAULT", > - "3D_FULL_SCREEN", > - "POWER_SAVING", > - "VIDEO", > - "VR", > - "COMPUTE", > - "CUSTOM"}; > - static const char *title[] = { > - "PROFILE_INDEX(NAME)", > - "CLOCK_TYPE(NAME)", > - "FPS", > - "UseRlcBusy", > - "MinActiveFreqType", > - "MinActiveFreq", > - "BoosterFreqType", > - "BoosterFreq", > - "PD_Data_limit_c", > - "PD_Data_error_coeff", > - "PD_Data_error_rate_coeff"}; > - int result = 0; > - > - if (!smu->pm_enabled || !buf) > - return -EINVAL; > - > - size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n", > - title[0], title[1], title[2], title[3], title[4], title[5], > - title[6], title[7], title[8], title[9], title[10]); > - > - for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { > - /* conv PP_SMC_POWER_PROFILE* to > WORKLOAD_PPLIB_*_BIT */ > - workload_type = smu_workload_get_type(smu, i); > - result = smu_update_table(smu, > - > SMU_TABLE_ACTIVITY_MONITOR_COEFF | workload_type << 16, > - (void *)(&activity_monitor), false); > - if (result) { > - pr_err("[%s] Failed to get activity monitor!", > __func__); > - return result; > - } > - > - size += sprintf(buf + size, "%2d %14s%s:\n", > - i, profile_name[i], (i == smu->power_profile_mode) ? > "*" : " "); > - > - size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > - " ", > - 0, > - "GFXCLK", > - activity_monitor.Gfx_FPS, > - activity_monitor.Gfx_UseRlcBusy, > - activity_monitor.Gfx_MinActiveFreqType, > - activity_monitor.Gfx_MinActiveFreq, > - activity_monitor.Gfx_BoosterFreqType, > - activity_monitor.Gfx_BoosterFreq, > - activity_monitor.Gfx_PD_Data_limit_c, > - activity_monitor.Gfx_PD_Data_error_coeff, > - activity_monitor.Gfx_PD_Data_error_rate_coeff); > - > - size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > - " ", > - 1, > - "SOCCLK", > - activity_monitor.Soc_FPS, > - activity_monitor.Soc_UseRlcBusy, > - activity_monitor.Soc_MinActiveFreqType, > - activity_monitor.Soc_MinActiveFreq, > - activity_monitor.Soc_BoosterFreqType, > - activity_monitor.Soc_BoosterFreq, > - activity_monitor.Soc_PD_Data_limit_c, > - activity_monitor.Soc_PD_Data_error_coeff, > - activity_monitor.Soc_PD_Data_error_rate_coeff); > - > - size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > - " ", > - 2, > - "UCLK", > - activity_monitor.Mem_FPS, > - activity_monitor.Mem_UseRlcBusy, > - activity_monitor.Mem_MinActiveFreqType, > - activity_monitor.Mem_MinActiveFreq, > - activity_monitor.Mem_BoosterFreqType, > - activity_monitor.Mem_BoosterFreq, > - activity_monitor.Mem_PD_Data_limit_c, > - activity_monitor.Mem_PD_Data_error_coeff, > - activity_monitor.Mem_PD_Data_error_rate_coeff); > - > - size += sprintf(buf + size, > "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", > - " ", > - 3, > - "FCLK", > - activity_monitor.Fclk_FPS, > - activity_monitor.Fclk_UseRlcBusy, > - activity_monitor.Fclk_MinActiveFreqType, > - activity_monitor.Fclk_MinActiveFreq, > - activity_monitor.Fclk_BoosterFreqType, > - activity_monitor.Fclk_BoosterFreq, > - activity_monitor.Fclk_PD_Data_limit_c, > - activity_monitor.Fclk_PD_Data_error_coeff, > - activity_monitor.Fclk_PD_Data_error_rate_coeff); > - } > - > - return size; > -} > - > -static int vega20_set_power_profile_mode(struct smu_context *smu, long > *input, uint32_t size) > -{ > - DpmActivityMonitorCoeffInt_t activity_monitor; > - int workload_type = 0, ret = 0; > - > - smu->power_profile_mode = input[size]; > - > - if (!smu->pm_enabled) > - return ret; > - if (smu->power_profile_mode > > PP_SMC_POWER_PROFILE_CUSTOM) { > - pr_err("Invalid power profile mode %d\n", smu- > >power_profile_mode); > - return -EINVAL; > - } > - > - if (smu->power_profile_mode == > PP_SMC_POWER_PROFILE_CUSTOM) { > - ret = smu_update_table(smu, > - SMU_TABLE_ACTIVITY_MONITOR_COEFF > | WORKLOAD_PPLIB_CUSTOM_BIT << 16, > - (void *)(&activity_monitor), false); > - if (ret) { > - pr_err("[%s] Failed to get activity monitor!", > __func__); > - return ret; > - } > - > - switch (input[0]) { > - case 0: /* Gfxclk */ > - activity_monitor.Gfx_FPS = input[1]; > - activity_monitor.Gfx_UseRlcBusy = input[2]; > - activity_monitor.Gfx_MinActiveFreqType = input[3]; > - activity_monitor.Gfx_MinActiveFreq = input[4]; > - activity_monitor.Gfx_BoosterFreqType = input[5]; > - activity_monitor.Gfx_BoosterFreq = input[6]; > - activity_monitor.Gfx_PD_Data_limit_c = input[7]; > - activity_monitor.Gfx_PD_Data_error_coeff = > input[8]; > - activity_monitor.Gfx_PD_Data_error_rate_coeff = > input[9]; > - break; > - case 1: /* Socclk */ > - activity_monitor.Soc_FPS = input[1]; > - activity_monitor.Soc_UseRlcBusy = input[2]; > - activity_monitor.Soc_MinActiveFreqType = input[3]; > - activity_monitor.Soc_MinActiveFreq = input[4]; > - activity_monitor.Soc_BoosterFreqType = input[5]; > - activity_monitor.Soc_BoosterFreq = input[6]; > - activity_monitor.Soc_PD_Data_limit_c = input[7]; > - activity_monitor.Soc_PD_Data_error_coeff = > input[8]; > - activity_monitor.Soc_PD_Data_error_rate_coeff = > input[9]; > - break; > - case 2: /* Uclk */ > - activity_monitor.Mem_FPS = input[1]; > - activity_monitor.Mem_UseRlcBusy = input[2]; > - activity_monitor.Mem_MinActiveFreqType = > input[3]; > - activity_monitor.Mem_MinActiveFreq = input[4]; > - activity_monitor.Mem_BoosterFreqType = input[5]; > - activity_monitor.Mem_BoosterFreq = input[6]; > - activity_monitor.Mem_PD_Data_limit_c = input[7]; > - activity_monitor.Mem_PD_Data_error_coeff = > input[8]; > - activity_monitor.Mem_PD_Data_error_rate_coeff = > input[9]; > - break; > - case 3: /* Fclk */ > - activity_monitor.Fclk_FPS = input[1]; > - activity_monitor.Fclk_UseRlcBusy = input[2]; > - activity_monitor.Fclk_MinActiveFreqType = input[3]; > - activity_monitor.Fclk_MinActiveFreq = input[4]; > - activity_monitor.Fclk_BoosterFreqType = input[5]; > - activity_monitor.Fclk_BoosterFreq = input[6]; > - activity_monitor.Fclk_PD_Data_limit_c = input[7]; > - activity_monitor.Fclk_PD_Data_error_coeff = > input[8]; > - activity_monitor.Fclk_PD_Data_error_rate_coeff = > input[9]; > - break; > - } > - > - ret = smu_update_table(smu, > - SMU_TABLE_ACTIVITY_MONITOR_COEFF > | WORKLOAD_PPLIB_CUSTOM_BIT << 16, > - (void *)(&activity_monitor), true); > - if (ret) { > - pr_err("[%s] Failed to set activity monitor!", > __func__); > - return ret; > - } > - } > - > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ > - workload_type = smu_workload_get_type(smu, smu- > >power_profile_mode); > - smu_send_smc_msg_with_param(smu, > SMU_MSG_SetWorkloadMask, > - 1 << workload_type); > - > - return ret; > -} > - > -static int > -vega20_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) > -{ > - struct vega20_dpm_table *dpm_table = (struct vega20_dpm_table > *)smu->smu_dpm.dpm_context; > - struct vega20_single_dpm_table *gfx_dpm_table; > - struct vega20_single_dpm_table *mem_dpm_table; > - struct vega20_single_dpm_table *soc_dpm_table; > - > - if (!smu->smu_dpm.dpm_context) > - return -EINVAL; > - > - gfx_dpm_table = &dpm_table->gfx_table; > - mem_dpm_table = &dpm_table->mem_table; > - soc_dpm_table = &dpm_table->soc_table; > - > - *sclk_mask = 0; > - *mclk_mask = 0; > - *soc_mask = 0; > - > - if (gfx_dpm_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL > && > - mem_dpm_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL > && > - soc_dpm_table->count > VEGA20_UMD_PSTATE_SOCCLK_LEVEL) { > - *sclk_mask = VEGA20_UMD_PSTATE_GFXCLK_LEVEL; > - *mclk_mask = VEGA20_UMD_PSTATE_MCLK_LEVEL; > - *soc_mask = VEGA20_UMD_PSTATE_SOCCLK_LEVEL; > - } > - > - if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { > - *sclk_mask = 0; > - } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { > - *mclk_mask = 0; > - } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > - *sclk_mask = gfx_dpm_table->count - 1; > - *mclk_mask = mem_dpm_table->count - 1; > - *soc_mask = soc_dpm_table->count - 1; > - } > - > - return 0; > -} > - > -static int > -vega20_set_uclk_to_highest_dpm_level(struct smu_context *smu, > - struct vega20_single_dpm_table > *dpm_table) > -{ > - int ret = 0; > - struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); > - if (!smu_dpm_ctx->dpm_context) > - return -EINVAL; > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) > { > - if (dpm_table->count <= 0) { > - pr_err("[%s] Dpm table has no entry!", __func__); > - return -EINVAL; > - } > - > - if (dpm_table->count > NUM_UCLK_DPM_LEVELS) { > - pr_err("[%s] Dpm table has too many entries!", > __func__); > - return -EINVAL; > - } > - > - dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - ret = smu_send_smc_msg_with_param(smu, > - SMU_MSG_SetHardMinByFreq, > - (PPCLK_UCLK << 16) | dpm_table- > >dpm_state.hard_min_level); > - if (ret) { > - pr_err("[%s] Set hard min uclk failed!", __func__); > - return ret; > - } > - } > - > - return ret; > -} > - > -static int vega20_pre_display_config_changed(struct smu_context *smu) > -{ > - int ret = 0; > - struct vega20_dpm_table *dpm_table = smu- > >smu_dpm.dpm_context; > - > - if (!smu->smu_dpm.dpm_context) > - return -EINVAL; > - > - smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, > 0); > - ret = vega20_set_uclk_to_highest_dpm_level(smu, > - &dpm_table->mem_table); > - if (ret) > - pr_err("Failed to set uclk to highest dpm level"); > - return ret; > -} > - > -static int vega20_display_config_changed(struct smu_context *smu) > -{ > - int ret = 0; > - > - if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && > - !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { > - ret = smu_write_watermarks_table(smu); > - if (ret) { > - pr_err("Failed to update WMTABLE!"); > - return ret; > - } > - smu->watermarks_bitmap |= WATERMARKS_LOADED; > - } > - > - if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && > - smu_feature_is_supported(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT) && > - smu_feature_is_supported(smu, > SMU_FEATURE_DPM_SOCCLK_BIT)) { > - smu_send_smc_msg_with_param(smu, > - SMU_MSG_NumOfDisplays, > - smu->display_config- > >num_display); > - } > - > - return ret; > -} > - > -static int vega20_apply_clocks_adjust_rules(struct smu_context *smu) > -{ > - struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); > - struct vega20_dpm_table *dpm_ctx = (struct vega20_dpm_table > *)(smu_dpm_ctx->dpm_context); > - struct vega20_single_dpm_table *dpm_table; > - bool vblank_too_short = false; > - bool disable_mclk_switching; > - uint32_t i, latency; > - > - disable_mclk_switching = ((1 < smu->display_config->num_display) > && > - !smu->display_config- > >multi_monitor_in_sync) || vblank_too_short; > - latency = smu->display_config- > >dce_tolerable_mclk_in_active_latency; > - > - /* gfxclk */ > - dpm_table = &(dpm_ctx->gfx_table); > - dpm_table->dpm_state.soft_min_level = dpm_table- > >dpm_levels[0].value; > - dpm_table->dpm_state.soft_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[0].value; > - dpm_table->dpm_state.hard_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - > - if (VEGA20_UMD_PSTATE_GFXCLK_LEVEL < dpm_table- > >count) { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value; > - } > - > - if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[0].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[0].value; > - } > - > - if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > - } > - > - /* memclk */ > - dpm_table = &(dpm_ctx->mem_table); > - dpm_table->dpm_state.soft_min_level = dpm_table- > >dpm_levels[0].value; > - dpm_table->dpm_state.soft_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[0].value; > - dpm_table->dpm_state.hard_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - > - if (VEGA20_UMD_PSTATE_MCLK_LEVEL < dpm_table->count) > { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value; > - } > - > - if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[0].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[0].value; > - } > - > - if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > - } > - > - /* honour DAL's UCLK Hardmin */ > - if (dpm_table->dpm_state.hard_min_level < (smu->display_config- > >min_mem_set_clock / 100)) > - dpm_table->dpm_state.hard_min_level = smu- > >display_config->min_mem_set_clock / 100; > - > - /* Hardmin is dependent on displayconfig */ > - if (disable_mclk_switching) { > - dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - for (i = 0; i < smu_dpm_ctx->mclk_latency_table->count - 1; > i++) { > - if (smu_dpm_ctx->mclk_latency_table- > >entries[i].latency <= latency) { > - if (dpm_table->dpm_levels[i].value >= (smu- > >display_config->min_mem_set_clock / 100)) { > - dpm_table- > >dpm_state.hard_min_level = dpm_table->dpm_levels[i].value; > - break; > - } > - } > - } > - } > - > - if (smu->display_config->nb_pstate_switch_disable) > - dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - > - /* vclk */ > - dpm_table = &(dpm_ctx->vclk_table); > - dpm_table->dpm_state.soft_min_level = dpm_table- > >dpm_levels[0].value; > - dpm_table->dpm_state.soft_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[0].value; > - dpm_table->dpm_state.hard_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - > - if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table- > >count) { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value; > - } > - > - if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > - } > - > - /* dclk */ > - dpm_table = &(dpm_ctx->dclk_table); > - dpm_table->dpm_state.soft_min_level = dpm_table- > >dpm_levels[0].value; > - dpm_table->dpm_state.soft_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[0].value; > - dpm_table->dpm_state.hard_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - > - if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table- > >count) { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value; > - } > - > - if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > - } > - > - /* socclk */ > - dpm_table = &(dpm_ctx->soc_table); > - dpm_table->dpm_state.soft_min_level = dpm_table- > >dpm_levels[0].value; > - dpm_table->dpm_state.soft_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[0].value; > - dpm_table->dpm_state.hard_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - > - if (VEGA20_UMD_PSTATE_SOCCLK_LEVEL < dpm_table- > >count) { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value; > - } > - > - if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > - } > - > - /* eclk */ > - dpm_table = &(dpm_ctx->eclk_table); > - dpm_table->dpm_state.soft_min_level = dpm_table- > >dpm_levels[0].value; > - dpm_table->dpm_state.soft_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - dpm_table->dpm_state.hard_min_level = dpm_table- > >dpm_levels[0].value; > - dpm_table->dpm_state.hard_max_level = dpm_table- > >dpm_levels[dpm_table->count - 1].value; > - > - if (VEGA20_UMD_PSTATE_VCEMCLK_LEVEL < dpm_table- > >count) { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value; > - } > - > - if (smu_dpm_ctx->dpm_level == > AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { > - dpm_table->dpm_state.soft_min_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > - dpm_table->dpm_state.soft_max_level = > dpm_table->dpm_levels[dpm_table->count - 1].value; > - } > - return 0; > -} > - > -static int > -vega20_notify_smc_dispaly_config(struct smu_context *smu) > -{ > - struct vega20_dpm_table *dpm_table = smu- > >smu_dpm.dpm_context; > - struct vega20_single_dpm_table *memtable = &dpm_table- > >mem_table; > - struct smu_clocks min_clocks = {0}; > - struct pp_display_clock_request clock_req; > - int ret = 0; > - > - min_clocks.dcef_clock = smu->display_config->min_dcef_set_clk; > - min_clocks.dcef_clock_in_sr = smu->display_config- > >min_dcef_deep_sleep_set_clk; > - min_clocks.memory_clock = smu->display_config- > >min_mem_set_clock; > - > - if (smu_feature_is_supported(smu, > SMU_FEATURE_DPM_DCEFCLK_BIT)) { > - clock_req.clock_type = amd_pp_dcef_clock; > - clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10; > - if (!smu->funcs->display_clock_voltage_request(smu, > &clock_req)) { > - if (smu_feature_is_supported(smu, > SMU_FEATURE_DS_DCEFCLK_BIT)) { > - ret = smu_send_smc_msg_with_param(smu, > - > SMU_MSG_SetMinDeepSleepDcefclk, > - > min_clocks.dcef_clock_in_sr/100); > - if (ret) { > - pr_err("Attempt to set divider for > DCEFCLK Failed!"); > - return ret; > - } > - } > - } else { > - pr_info("Attempt to set Hard Min for DCEFCLK > Failed!"); > - } > - } > - > - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) > { > - memtable->dpm_state.hard_min_level = > min_clocks.memory_clock/100; > - ret = smu_send_smc_msg_with_param(smu, > - > SMU_MSG_SetHardMinByFreq, > - (PPCLK_UCLK << 16) | > memtable->dpm_state.hard_min_level); > - if (ret) { > - pr_err("[%s] Set hard min uclk failed!", __func__); > - return ret; > - } > - } > - > - return 0; > -} > - > -static uint32_t vega20_find_lowest_dpm_level(struct > vega20_single_dpm_table *table) > -{ > - uint32_t i; > - > - for (i = 0; i < table->count; i++) { > - if (table->dpm_levels[i].enabled) > - break; > - } > - if (i >= table->count) { > - i = 0; > - table->dpm_levels[i].enabled = true; > - } > - > - return i; > -} > - > -static uint32_t vega20_find_highest_dpm_level(struct > vega20_single_dpm_table *table) > -{ > - int i = 0; > - > - if (!table) { > - pr_err("[%s] DPM Table does not exist!", __func__); > - return 0; > - } > - if (table->count <= 0) { > - pr_err("[%s] DPM Table has no entry!", __func__); > - return 0; > - } > - if (table->count > MAX_REGULAR_DPM_NUMBER) { > - pr_err("[%s] DPM Table has too many entries!", __func__); > - return MAX_REGULAR_DPM_NUMBER - 1; > - } > - > - for (i = table->count - 1; i >= 0; i--) { > - if (table->dpm_levels[i].enabled) > - break; > - } > - if (i < 0) { > - i = 0; > - table->dpm_levels[i].enabled = true; > - } > - > - return i; > -} > - > -static int vega20_force_dpm_limit_value(struct smu_context *smu, bool > highest) > -{ > - uint32_t soft_level; > - int ret = 0; > - struct vega20_dpm_table *dpm_table = > - (struct vega20_dpm_table *)smu->smu_dpm.dpm_context; > - > - if (highest) > - soft_level = vega20_find_highest_dpm_level(&(dpm_table- > >gfx_table)); > - else > - soft_level = vega20_find_lowest_dpm_level(&(dpm_table- > >gfx_table)); > - > - dpm_table->gfx_table.dpm_state.soft_min_level = > - dpm_table->gfx_table.dpm_state.soft_max_level = > - dpm_table->gfx_table.dpm_levels[soft_level].value; > - > - if (highest) > - soft_level = vega20_find_highest_dpm_level(&(dpm_table- > >mem_table)); > - else > - soft_level = vega20_find_lowest_dpm_level(&(dpm_table- > >mem_table)); > - > - dpm_table->mem_table.dpm_state.soft_min_level = > - dpm_table->mem_table.dpm_state.soft_max_level = > - dpm_table->mem_table.dpm_levels[soft_level].value; > - > - if (highest) > - soft_level = vega20_find_highest_dpm_level(&(dpm_table- > >soc_table)); > - else > - soft_level = vega20_find_lowest_dpm_level(&(dpm_table- > >soc_table)); > - > - dpm_table->soc_table.dpm_state.soft_min_level = > - dpm_table->soc_table.dpm_state.soft_max_level = > - dpm_table->soc_table.dpm_levels[soft_level].value; > - > - ret = vega20_upload_dpm_level(smu, false, 0xFFFFFFFF); > - if (ret) { > - pr_err("Failed to upload boot level to %s!\n", > - highest ? "highest" : "lowest"); > - return ret; > - } > - > - ret = vega20_upload_dpm_level(smu, true, 0xFFFFFFFF); > - if (ret) { > - pr_err("Failed to upload dpm max level to %s!\n!", > - highest ? "highest" : "lowest"); > - return ret; > - } > - > - return ret; > -} > - > -static int vega20_unforce_dpm_levels(struct smu_context *smu) > -{ > - uint32_t soft_min_level, soft_max_level; > - int ret = 0; > - struct vega20_dpm_table *dpm_table = > - (struct vega20_dpm_table *)smu->smu_dpm.dpm_context; > - > - soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table- > >gfx_table)); > - soft_max_level = vega20_find_highest_dpm_level(&(dpm_table- > >gfx_table)); > - dpm_table->gfx_table.dpm_state.soft_min_level = > - dpm_table->gfx_table.dpm_levels[soft_min_level].value; > - dpm_table->gfx_table.dpm_state.soft_max_level = > - dpm_table->gfx_table.dpm_levels[soft_max_level].value; > - > - soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table- > >mem_table)); > - soft_max_level = vega20_find_highest_dpm_level(&(dpm_table- > >mem_table)); > - dpm_table->mem_table.dpm_state.soft_min_level = > - dpm_table->gfx_table.dpm_levels[soft_min_level].value; > - dpm_table->mem_table.dpm_state.soft_max_level = > - dpm_table->gfx_table.dpm_levels[soft_max_level].value; > - > - soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table- > >soc_table)); > - soft_max_level = vega20_find_highest_dpm_level(&(dpm_table- > >soc_table)); > - dpm_table->soc_table.dpm_state.soft_min_level = > - dpm_table->soc_table.dpm_levels[soft_min_level].value; > - dpm_table->soc_table.dpm_state.soft_max_level = > - dpm_table->soc_table.dpm_levels[soft_max_level].value; > - > - ret = vega20_upload_dpm_level(smu, false, 0xFFFFFFFF); > - if (ret) { > - pr_err("Failed to upload DPM Bootup Levels!"); > - return ret; > - } > - > - ret = vega20_upload_dpm_level(smu, true, 0xFFFFFFFF); > - if (ret) { > - pr_err("Failed to upload DPM Max Levels!"); > - return ret; > - } > - > - return ret; > -} > - > -static int vega20_update_specified_od8_value(struct smu_context *smu, > - uint32_t index, > - uint32_t value) > -{ > - struct smu_table_context *table_context = &smu->smu_table; > - OverDriveTable_t *od_table = > - (OverDriveTable_t *)(table_context->overdrive_table); > - struct vega20_od8_settings *od8_settings = > - (struct vega20_od8_settings *)smu->od_settings; > - > - switch (index) { > - case OD8_SETTING_GFXCLK_FMIN: > - od_table->GfxclkFmin = (uint16_t)value; > - break; > - > - case OD8_SETTING_GFXCLK_FMAX: > - if (value < od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].min_value || > - value > od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value) > - return -EINVAL; > - od_table->GfxclkFmax = (uint16_t)value; > - break; > - > - case OD8_SETTING_GFXCLK_FREQ1: > - od_table->GfxclkFreq1 = (uint16_t)value; > - break; > - > - case OD8_SETTING_GFXCLK_VOLTAGE1: > - od_table->GfxclkVolt1 = (uint16_t)value; > - break; > - > - case OD8_SETTING_GFXCLK_FREQ2: > - od_table->GfxclkFreq2 = (uint16_t)value; > - break; > - > - case OD8_SETTING_GFXCLK_VOLTAGE2: > - od_table->GfxclkVolt2 = (uint16_t)value; > - break; > - > - case OD8_SETTING_GFXCLK_FREQ3: > - od_table->GfxclkFreq3 = (uint16_t)value; > - break; > - > - case OD8_SETTING_GFXCLK_VOLTAGE3: > - od_table->GfxclkVolt3 = (uint16_t)value; > - break; > - > - case OD8_SETTING_UCLK_FMAX: > - if (value < od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].min_value || > - value > od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value) > - return -EINVAL; > - od_table->UclkFmax = (uint16_t)value; > - break; > - > - case OD8_SETTING_POWER_PERCENTAGE: > - od_table->OverDrivePct = (int16_t)value; > - break; > - > - case OD8_SETTING_FAN_ACOUSTIC_LIMIT: > - od_table->FanMaximumRpm = (uint16_t)value; > - break; > - > - case OD8_SETTING_FAN_MIN_SPEED: > - od_table->FanMinimumPwm = (uint16_t)value; > - break; > - > - case OD8_SETTING_FAN_TARGET_TEMP: > - od_table->FanTargetTemperature = (uint16_t)value; > - break; > - > - case OD8_SETTING_OPERATING_TEMP_MAX: > - od_table->MaxOpTemp = (uint16_t)value; > - break; > - } > - > - return 0; > -} > - > -static int vega20_update_od8_settings(struct smu_context *smu, > - uint32_t index, > - uint32_t value) > -{ > - struct smu_table_context *table_context = &smu->smu_table; > - int ret; > - > - ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, > - table_context->overdrive_table, false); > - if (ret) { > - pr_err("Failed to export over drive table!\n"); > - return ret; > - } > - > - ret = vega20_update_specified_od8_value(smu, index, value); > - if (ret) > - return ret; > - > - ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, > - table_context->overdrive_table, true); > - if (ret) { > - pr_err("Failed to import over drive table!\n"); > - return ret; > - } > - > - return 0; > -} > - > -static int vega20_set_od_percentage(struct smu_context *smu, > - enum smu_clk_type clk_type, > - uint32_t value) > -{ > - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > - struct vega20_dpm_table *dpm_table = NULL; > - struct vega20_dpm_table *golden_table = NULL; > - struct vega20_single_dpm_table *single_dpm_table; > - struct vega20_single_dpm_table *golden_dpm_table; > - uint32_t od_clk, index; > - int ret = 0; > - int feature_enabled; > - PPCLK_e clk_id; > - > - mutex_lock(&(smu->mutex)); > - > - dpm_table = smu_dpm->dpm_context; > - golden_table = smu_dpm->golden_dpm_context; > - > - switch (clk_type) { > - case SMU_OD_SCLK: > - single_dpm_table = &(dpm_table->gfx_table); > - golden_dpm_table = &(golden_table->gfx_table); > - feature_enabled = smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_GFXCLK_BIT); > - clk_id = PPCLK_GFXCLK; > - index = OD8_SETTING_GFXCLK_FMAX; > - break; > - case SMU_OD_MCLK: > - single_dpm_table = &(dpm_table->mem_table); > - golden_dpm_table = &(golden_table->mem_table); > - feature_enabled = smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_UCLK_BIT); > - clk_id = PPCLK_UCLK; > - index = OD8_SETTING_UCLK_FMAX; > - break; > - default: > - ret = -EINVAL; > - break; > - } > - > - if (ret) > - goto set_od_failed; > - > - od_clk = golden_dpm_table->dpm_levels[golden_dpm_table- > >count - 1].value * value; > - od_clk /= 100; > - od_clk += golden_dpm_table->dpm_levels[golden_dpm_table- > >count - 1].value; > - > - ret = vega20_update_od8_settings(smu, index, od_clk); > - if (ret) { > - pr_err("[Setoverdrive] failed to set od clk!\n"); > - goto set_od_failed; > - } > - > - if (feature_enabled) { > - ret = vega20_set_single_dpm_table(smu, single_dpm_table, > - clk_id); > - if (ret) { > - pr_err("[Setoverdrive] failed to refresh dpm > table!\n"); > - goto set_od_failed; > - } > - } else { > - single_dpm_table->count = 1; > - single_dpm_table->dpm_levels[0].value = smu- > >smu_table.boot_values.gfxclk / 100; > - } > - > - ret = smu_handle_task(smu, smu_dpm->dpm_level, > - AMD_PP_TASK_READJUST_POWER_STATE); > - > -set_od_failed: > - mutex_unlock(&(smu->mutex)); > - > - return ret; > -} > - > -static int vega20_odn_edit_dpm_table(struct smu_context *smu, > - enum PP_OD_DPM_TABLE_COMMAND > type, > - long *input, uint32_t size) > -{ > - struct smu_table_context *table_context = &smu->smu_table; > - OverDriveTable_t *od_table = > - (OverDriveTable_t *)(table_context->overdrive_table); > - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; > - struct vega20_dpm_table *dpm_table = NULL; > - struct vega20_single_dpm_table *single_dpm_table; > - struct vega20_od8_settings *od8_settings = > - (struct vega20_od8_settings *)smu->od_settings; > - struct pp_clock_levels_with_latency clocks; > - int32_t input_index, input_clk, input_vol, i; > - int od8_id; > - int ret = 0; > - > - dpm_table = smu_dpm->dpm_context; > - > - if (!input) { > - pr_warn("NULL user input for clock and voltage\n"); > - return -EINVAL; > - } > - > - switch (type) { > - case PP_OD_EDIT_SCLK_VDDC_TABLE: > - if (!(od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id)) { > - pr_info("Sclk min/max frequency overdrive not > supported\n"); > - return -EOPNOTSUPP; > - } > - > - for (i = 0; i < size; i += 2) { > - if (i + 2 > size) { > - pr_info("invalid number of input > parameters %d\n", size); > - return -EINVAL; > - } > - > - input_index = input[i]; > - input_clk = input[i + 1]; > - > - if (input_index != 0 && input_index != 1) { > - pr_info("Invalid index %d\n", input_index); > - pr_info("Support min/max sclk frequency > settingonly which index by 0/1\n"); > - return -EINVAL; > - } > - > - if (input_clk < od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value || > - input_clk > od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value) { > - pr_info("clock freq %d is not within allowed > range [%d - %d]\n", > - input_clk, > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value, > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value); > - return -EINVAL; > - } > - > - if (input_index == 0 && od_table->GfxclkFmin != > input_clk) { > - od_table->GfxclkFmin = input_clk; > - od8_settings->od_gfxclk_update = true; > - } else if (input_index == 1 && od_table- > >GfxclkFmax != input_clk) { > - od_table->GfxclkFmax = input_clk; > - od8_settings->od_gfxclk_update = true; > - } > - } > - > - break; > - > - case PP_OD_EDIT_MCLK_VDDC_TABLE: > - if (!od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) { > - pr_info("Mclk max frequency overdrive not > supported\n"); > - return -EOPNOTSUPP; > - } > - > - single_dpm_table = &(dpm_table->mem_table); > - ret = vega20_get_clk_table(smu, &clocks, single_dpm_table); > - if (ret) { > - pr_err("Attempt to get memory clk levels Failed!"); > - return ret; > - } > - > - for (i = 0; i < size; i += 2) { > - if (i + 2 > size) { > - pr_info("invalid number of input > parameters %d\n", > - size); > - return -EINVAL; > - } > - > - input_index = input[i]; > - input_clk = input[i + 1]; > - > - if (input_index != 1) { > - pr_info("Invalid index %d\n", input_index); > - pr_info("Support max Mclk frequency setting > only which index by 1\n"); > - return -EINVAL; > - } > - > - if (input_clk < clocks.data[0].clocks_in_khz / 1000 || > - input_clk > od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value) { > - pr_info("clock freq %d is not within allowed > range [%d - %d]\n", > - input_clk, > - clocks.data[0].clocks_in_khz / 1000, > - od8_settings- > >od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value); > - return -EINVAL; > - } > - > - if (input_index == 1 && od_table->UclkFmax != > input_clk) { > - od8_settings->od_gfxclk_update = true; > - od_table->UclkFmax = input_clk; > - } > - } > - > - break; > - > - case PP_OD_EDIT_VDDC_CURVE: > - if (!(od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && > - od8_settings- > >od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id)) { > - pr_info("Voltage curve calibrate not supported\n"); > - return -EOPNOTSUPP; > - } > - > - for (i = 0; i < size; i += 3) { > - if (i + 3 > size) { > - pr_info("invalid number of input > parameters %d\n", > - size); > - return -EINVAL; > - } > - > - input_index = input[i]; > - input_clk = input[i + 1]; > - input_vol = input[i + 2]; > - > - if (input_index > 2) { > - pr_info("Setting for point %d is not > supported\n", > - input_index + 1); > - pr_info("Three supported points index by 0, > 1, 2\n"); > - return -EINVAL; > - } > - > - od8_id = OD8_SETTING_GFXCLK_FREQ1 + 2 * > input_index; > - if (input_clk < od8_settings- > >od8_settings_array[od8_id].min_value || > - input_clk > od8_settings- > >od8_settings_array[od8_id].max_value) { > - pr_info("clock freq %d is not within allowed > range [%d - %d]\n", > - input_clk, > - od8_settings- > >od8_settings_array[od8_id].min_value, > - od8_settings- > >od8_settings_array[od8_id].max_value); > - return -EINVAL; > - } > - > - od8_id = OD8_SETTING_GFXCLK_VOLTAGE1 + 2 * > input_index; > - if (input_vol < od8_settings- > >od8_settings_array[od8_id].min_value || > - input_vol > od8_settings- > >od8_settings_array[od8_id].max_value) { > - pr_info("clock voltage %d is not within > allowed range [%d- %d]\n", > - input_vol, > - od8_settings- > >od8_settings_array[od8_id].min_value, > - od8_settings- > >od8_settings_array[od8_id].max_value); > - return -EINVAL; > - } > - > - switch (input_index) { > - case 0: > - od_table->GfxclkFreq1 = input_clk; > - od_table->GfxclkVolt1 = input_vol * > VOLTAGE_SCALE; > - break; > - case 1: > - od_table->GfxclkFreq2 = input_clk; > - od_table->GfxclkVolt2 = input_vol * > VOLTAGE_SCALE; > - break; > - case 2: > - od_table->GfxclkFreq3 = input_clk; > - od_table->GfxclkVolt3 = input_vol * > VOLTAGE_SCALE; > - break; > - } > - } > - > - break; > - > - case PP_OD_RESTORE_DEFAULT_TABLE: > - ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, > table_context->overdrive_table, false); > - if (ret) { > - pr_err("Failed to export over drive table!\n"); > - return ret; > - } > - > - break; > - > - case PP_OD_COMMIT_DPM_TABLE: > - ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, > table_context->overdrive_table, true); > - if (ret) { > - pr_err("Failed to import over drive table!\n"); > - return ret; > - } > - > - /* retrieve updated gfxclk table */ > - if (od8_settings->od_gfxclk_update) { > - od8_settings->od_gfxclk_update = false; > - single_dpm_table = &(dpm_table->gfx_table); > - > - if (smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_GFXCLK_BIT)) { > - ret = vega20_set_single_dpm_table(smu, > single_dpm_table, > - > PPCLK_GFXCLK); > - if (ret) { > - pr_err("[Setoverdrive] failed to > refresh dpm table!\n"); > - return ret; > - } > - } else { > - single_dpm_table->count = 1; > - single_dpm_table->dpm_levels[0].value = > smu->smu_table.boot_values.gfxclk / 100; > - } > - } > - > - break; > - > - default: > - return -EINVAL; > - } > - > - if (type == PP_OD_COMMIT_DPM_TABLE) { > - mutex_lock(&(smu->mutex)); > - ret = smu_handle_task(smu, smu_dpm->dpm_level, > - > AMD_PP_TASK_READJUST_POWER_STATE); > - mutex_unlock(&(smu->mutex)); > - } > - > - return ret; > -} > - > -static int vega20_dpm_set_uvd_enable(struct smu_context *smu, bool > enable) > -{ > - if (!smu_feature_is_supported(smu, > SMU_FEATURE_DPM_UVD_BIT)) > - return 0; > - > - if (enable == smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_UVD_BIT)) > - return 0; > - > - return smu_feature_set_enabled(smu, > SMU_FEATURE_DPM_UVD_BIT, enable); > -} > - > -static int vega20_dpm_set_vce_enable(struct smu_context *smu, bool > enable) > -{ > - if (!smu_feature_is_supported(smu, > SMU_FEATURE_DPM_VCE_BIT)) > - return 0; > - > - if (enable == smu_feature_is_enabled(smu, > SMU_FEATURE_DPM_VCE_BIT)) > - return 0; > - > - return smu_feature_set_enabled(smu, > SMU_FEATURE_DPM_VCE_BIT, enable); > -} > - > -static int vega20_get_enabled_smc_features(struct smu_context *smu, > - uint64_t *features_enabled) > -{ > - uint32_t feature_mask[2] = {0, 0}; > - int ret = 0; > - > - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); > - if (ret) > - return ret; > - > - *features_enabled = ((((uint64_t)feature_mask[0] << > SMU_FEATURES_LOW_SHIFT) & SMU_FEATURES_LOW_MASK) | > - (((uint64_t)feature_mask[1] << > SMU_FEATURES_HIGH_SHIFT) & SMU_FEATURES_HIGH_MASK)); > - > - return ret; > -} > - > -static int vega20_enable_smc_features(struct smu_context *smu, > - bool enable, uint64_t feature_mask) > -{ > - uint32_t smu_features_low, smu_features_high; > - int ret = 0; > - > - smu_features_low = (uint32_t)((feature_mask & > SMU_FEATURES_LOW_MASK) >> SMU_FEATURES_LOW_SHIFT); > - smu_features_high = (uint32_t)((feature_mask & > SMU_FEATURES_HIGH_MASK) >> SMU_FEATURES_HIGH_SHIFT); > - > - if (enable) { > - ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_EnableSmuFeaturesLow, > - smu_features_low); > - if (ret) > - return ret; > - ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_EnableSmuFeaturesHigh, > - smu_features_high); > - if (ret) > - return ret; > - } else { > - ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_DisableSmuFeaturesLow, > - smu_features_low); > - if (ret) > - return ret; > - ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_DisableSmuFeaturesHigh, > - smu_features_high); > - if (ret) > - return ret; > - } > - > - return 0; > - > -} > - > -static int vega20_get_ppfeature_status(struct smu_context *smu, char > *buf) > -{ > - static const char *ppfeature_name[] = { > - "DPM_PREFETCHER", > - "GFXCLK_DPM", > - "UCLK_DPM", > - "SOCCLK_DPM", > - "UVD_DPM", > - "VCE_DPM", > - "ULV", > - "MP0CLK_DPM", > - "LINK_DPM", > - "DCEFCLK_DPM", > - "GFXCLK_DS", > - "SOCCLK_DS", > - "LCLK_DS", > - "PPT", > - "TDC", > - "THERMAL", > - "GFX_PER_CU_CG", > - "RM", > - "DCEFCLK_DS", > - "ACDC", > - "VR0HOT", > - "VR1HOT", > - "FW_CTF", > - "LED_DISPLAY", > - "FAN_CONTROL", > - "GFX_EDC", > - "GFXOFF", > - "CG", > - "FCLK_DPM", > - "FCLK_DS", > - "MP1CLK_DS", > - "MP0CLK_DS", > - "XGMI", > - "ECC"}; > - static const char *output_title[] = { > - "FEATURES", > - "BITMASK", > - "ENABLEMENT"}; > - uint64_t features_enabled; > - int i; > - int ret = 0; > - int size = 0; > - > - ret = vega20_get_enabled_smc_features(smu, &features_enabled); > - if (ret) > - return ret; > - > - size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", > features_enabled); > - size += sprintf(buf + size, "%-19s %-22s %s\n", > - output_title[0], > - output_title[1], > - output_title[2]); > - for (i = 0; i < GNLD_FEATURES_MAX; i++) { > - size += sprintf(buf + size, "%-19s 0x%016llx %6s\n", > - ppfeature_name[i], > - 1ULL << i, > - (features_enabled & (1ULL << i)) ? > "Y" : "N"); > - } > - > - return size; > -} > - > -static int vega20_set_ppfeature_status(struct smu_context *smu, uint64_t > new_ppfeature_masks) > -{ > - uint64_t features_enabled; > - uint64_t features_to_enable; > - uint64_t features_to_disable; > - int ret = 0; > - > - if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX)) > - return -EINVAL; > - > - ret = vega20_get_enabled_smc_features(smu, &features_enabled); > - if (ret) > - return ret; > - > - features_to_disable = > - features_enabled & ~new_ppfeature_masks; > - features_to_enable = > - ~features_enabled & new_ppfeature_masks; > - > - pr_debug("features_to_disable 0x%llx\n", features_to_disable); > - pr_debug("features_to_enable 0x%llx\n", features_to_enable); > - > - if (features_to_disable) { > - ret = vega20_enable_smc_features(smu, false, > features_to_disable); > - if (ret) > - return ret; > - } > - > - if (features_to_enable) { > - ret = vega20_enable_smc_features(smu, true, > features_to_enable); > - if (ret) > - return ret; > - } > - > - return 0; > -} > - > -static bool vega20_is_dpm_running(struct smu_context *smu) > -{ > - int ret = 0; > - uint32_t feature_mask[2]; > - unsigned long feature_enabled; > - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); > - feature_enabled = (unsigned long)((uint64_t)feature_mask[0] | > - ((uint64_t)feature_mask[1] << 32)); > - return !!(feature_enabled & SMC_DPM_FEATURE); > -} > - > -static int vega20_set_thermal_fan_table(struct smu_context *smu) > -{ > - int ret; > - struct smu_table_context *table_context = &smu->smu_table; > - PPTable_t *pptable = table_context->driver_pptable; > - > - ret = smu_send_smc_msg_with_param(smu, > SMU_MSG_SetFanTemperatureTarget, > - (uint32_t)pptable->FanTargetTemperature); > - > - return ret; > -} > - > -static int vega20_get_fan_speed_percent(struct smu_context *smu, > - uint32_t *speed) > -{ > - int ret = 0; > - uint32_t percent = 0; > - uint32_t current_rpm; > - PPTable_t *pptable = smu->smu_table.driver_pptable; > - > - ret = smu_get_current_rpm(smu, ¤t_rpm); > - percent = current_rpm * 100 / pptable->FanMaximumRpm; > - *speed = percent > 100 ? 100 : percent; > - > - return ret; > -} > - > -static int vega20_get_gpu_power(struct smu_context *smu, uint32_t > *value) > -{ > - int ret = 0; > - SmuMetrics_t metrics; > - > - if (!value) > - return -EINVAL; > - > - ret = vega20_get_metrics_table(smu, &metrics); > - if (ret) > - return ret; > - > - *value = metrics.CurrSocketPower << 8; > - > - return 0; > -} > - > -static int vega20_get_current_activity_percent(struct smu_context *smu, > - enum amd_pp_sensors sensor, > - uint32_t *value) > -{ > - int ret = 0; > - SmuMetrics_t metrics; > - > - if (!value) > - return -EINVAL; > - > - ret = vega20_get_metrics_table(smu, &metrics); > - if (ret) > - return ret; > - > - switch (sensor) { > - case AMDGPU_PP_SENSOR_GPU_LOAD: > - *value = metrics.AverageGfxActivity; > - break; > - case AMDGPU_PP_SENSOR_MEM_LOAD: > - *value = metrics.AverageUclkActivity; > - break; > - default: > - pr_err("Invalid sensor for retrieving clock activity\n"); > - return -EINVAL; > - } > - > - return 0; > -} > - > -static int vega20_thermal_get_temperature(struct smu_context *smu, > - enum amd_pp_sensors sensor, > - uint32_t *value) > -{ > - struct amdgpu_device *adev = smu->adev; > - SmuMetrics_t metrics; > - uint32_t temp = 0; > - int ret = 0; > - > - if (!value) > - return -EINVAL; > - > - ret = vega20_get_metrics_table(smu, &metrics); > - if (ret) > - return ret; > - > - switch (sensor) { > - case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: > - temp = RREG32_SOC15(THM, 0, > mmCG_MULT_THERMAL_STATUS); > - temp = (temp & > CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >> > - > CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT; > - > - temp = temp & 0x1ff; > - temp *= SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > - > - *value = temp; > - break; > - case AMDGPU_PP_SENSOR_EDGE_TEMP: > - *value = metrics.TemperatureEdge * > - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > - break; > - case AMDGPU_PP_SENSOR_MEM_TEMP: > - *value = metrics.TemperatureHBM * > - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > - break; > - default: > - pr_err("Invalid sensor for retrieving temp\n"); > - return -EINVAL; > - } > - > - return 0; > -} > -static int vega20_read_sensor(struct smu_context *smu, > - enum amd_pp_sensors sensor, > - void *data, uint32_t *size) > -{ > - int ret = 0; > - struct smu_table_context *table_context = &smu->smu_table; > - PPTable_t *pptable = table_context->driver_pptable; > - > - switch (sensor) { > - case AMDGPU_PP_SENSOR_MAX_FAN_RPM: > - *(uint32_t *)data = pptable->FanMaximumRpm; > - *size = 4; > - break; > - case AMDGPU_PP_SENSOR_MEM_LOAD: > - case AMDGPU_PP_SENSOR_GPU_LOAD: > - ret = vega20_get_current_activity_percent(smu, > - sensor, > - (uint32_t *)data); > - *size = 4; > - break; > - case AMDGPU_PP_SENSOR_GPU_POWER: > - ret = vega20_get_gpu_power(smu, (uint32_t *)data); > - *size = 4; > - break; > - case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: > - case AMDGPU_PP_SENSOR_EDGE_TEMP: > - case AMDGPU_PP_SENSOR_MEM_TEMP: > - ret = vega20_thermal_get_temperature(smu, sensor, > (uint32_t *)data); > - *size = 4; > - break; > - default: > - return -EINVAL; > - } > - > - return ret; > -} > - > -static int vega20_set_watermarks_table(struct smu_context *smu, > - void *watermarks, struct > - > dm_pp_wm_sets_with_clock_ranges_soc15 > - *clock_ranges) > -{ > - int i; > - Watermarks_t *table = watermarks; > - > - if (!table || !clock_ranges) > - return -EINVAL; > - > - if (clock_ranges->num_wm_dmif_sets > 4 || > - clock_ranges->num_wm_mcif_sets > 4) > - return -EINVAL; > - > - for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) { > - table->WatermarkRow[1][i].MinClock = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz / > - 1000)); > - table->WatermarkRow[1][i].MaxClock = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz / > - 1000)); > - table->WatermarkRow[1][i].MinUclk = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz / > - 1000)); > - table->WatermarkRow[1][i].MaxUclk = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz / > - 1000)); > - table->WatermarkRow[1][i].WmSetting = (uint8_t) > - clock_ranges- > >wm_dmif_clocks_ranges[i].wm_set_id; > - } > - > - for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) { > - table->WatermarkRow[0][i].MinClock = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz / > - 1000)); > - table->WatermarkRow[0][i].MaxClock = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz / > - 1000)); > - table->WatermarkRow[0][i].MinUclk = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz / > - 1000)); > - table->WatermarkRow[0][i].MaxUclk = > - cpu_to_le16((uint16_t) > - (clock_ranges- > >wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz / > - 1000)); > - table->WatermarkRow[0][i].WmSetting = (uint8_t) > - clock_ranges- > >wm_mcif_clocks_ranges[i].wm_set_id; > - } > - > - return 0; > -} > - > -static const struct smu_temperature_range vega20_thermal_policy[] = > -{ > - {-273150, 99000, 99000, -273150, 99000, 99000, -273150, 99000, 99000}, > - { 120000, 120000, 120000, 120000, 120000, 120000, 120000, 120000, > 120000}, > -}; > - > -static int vega20_get_thermal_temperature_range(struct smu_context > *smu, > - struct > smu_temperature_range*range) > -{ > - > - PPTable_t *pptable = smu->smu_table.driver_pptable; > - > - if (!range) > - return -EINVAL; > - > - memcpy(range, &vega20_thermal_policy[0], sizeof(struct > smu_temperature_range)); > - > - range->max = pptable->TedgeLimit * > - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > - range->edge_emergency_max = (pptable->TedgeLimit + > CTF_OFFSET_EDGE) * > - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > - range->hotspot_crit_max = pptable->ThotspotLimit * > - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > - range->hotspot_emergency_max = (pptable->ThotspotLimit + > CTF_OFFSET_HOTSPOT) * > - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > - range->mem_crit_max = pptable->ThbmLimit * > - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > - range->mem_emergency_max = (pptable->ThbmLimit + > CTF_OFFSET_HBM)* > - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; > - > - > - return 0; > -} > - > -static const struct pptable_funcs vega20_ppt_funcs = { > - .tables_init = vega20_tables_init, > - .alloc_dpm_context = vega20_allocate_dpm_context, > - .store_powerplay_table = vega20_store_powerplay_table, > - .check_powerplay_table = vega20_check_powerplay_table, > - .append_powerplay_table = vega20_append_powerplay_table, > - .get_smu_msg_index = vega20_get_smu_msg_index, > - .get_smu_clk_index = vega20_get_smu_clk_index, > - .get_smu_feature_index = vega20_get_smu_feature_index, > - .get_smu_table_index = vega20_get_smu_table_index, > - .get_smu_power_index = vega20_get_pwr_src_index, > - .get_workload_type = vega20_get_workload_type, > - .run_afll_btc = vega20_run_btc_afll, > - .get_allowed_feature_mask = vega20_get_allowed_feature_mask, > - .get_current_power_state = vega20_get_current_power_state, > - .set_default_dpm_table = vega20_set_default_dpm_table, > - .set_power_state = NULL, > - .populate_umd_state_clk = vega20_populate_umd_state_clk, > - .print_clk_levels = vega20_print_clk_levels, > - .force_clk_levels = vega20_force_clk_levels, > - .get_clock_by_type_with_latency = > vega20_get_clock_by_type_with_latency, > - .get_od_percentage = vega20_get_od_percentage, > - .get_power_profile_mode = vega20_get_power_profile_mode, > - .set_power_profile_mode = vega20_set_power_profile_mode, > - .set_od_percentage = vega20_set_od_percentage, > - .set_default_od_settings = vega20_set_default_od_settings, > - .od_edit_dpm_table = vega20_odn_edit_dpm_table, > - .dpm_set_uvd_enable = vega20_dpm_set_uvd_enable, > - .dpm_set_vce_enable = vega20_dpm_set_vce_enable, > - .read_sensor = vega20_read_sensor, > - .pre_display_config_changed = vega20_pre_display_config_changed, > - .display_config_changed = vega20_display_config_changed, > - .apply_clocks_adjust_rules = vega20_apply_clocks_adjust_rules, > - .notify_smc_dispaly_config = vega20_notify_smc_dispaly_config, > - .force_dpm_limit_value = vega20_force_dpm_limit_value, > - .unforce_dpm_levels = vega20_unforce_dpm_levels, > - .get_profiling_clk_mask = vega20_get_profiling_clk_mask, > - .set_ppfeature_status = vega20_set_ppfeature_status, > - .get_ppfeature_status = vega20_get_ppfeature_status, > - .is_dpm_running = vega20_is_dpm_running, > - .set_thermal_fan_table = vega20_set_thermal_fan_table, > - .get_fan_speed_percent = vega20_get_fan_speed_percent, > - .set_watermarks_table = vega20_set_watermarks_table, > - .get_thermal_temperature_range = > vega20_get_thermal_temperature_range > -}; > - > -void vega20_set_ppt_funcs(struct smu_context *smu) > -{ > - struct smu_table_context *smu_table = &smu->smu_table; > - > - smu->ppt_funcs = &vega20_ppt_funcs; > - smu->smc_if_version = SMU11_DRIVER_IF_VERSION; > - smu_table->table_count = TABLE_COUNT; > -} > diff --git a/drivers/gpu/drm/amd/powerplay/vega20_ppt.h > b/drivers/gpu/drm/amd/powerplay/vega20_ppt.h > deleted file mode 100644 > index 2dc10e4..0000000 > --- a/drivers/gpu/drm/amd/powerplay/vega20_ppt.h > +++ /dev/null > @@ -1,179 +0,0 @@ > -/* > - * Copyright 2019 Advanced Micro Devices, Inc. > - * > - * Permission is hereby granted, free of charge, to any person obtaining a > - * copy of this software and associated documentation files (the "Software"), > - * to deal in the Software without restriction, including without limitation > - * the rights to use, copy, modify, merge, publish, distribute, sublicense, > - * and/or sell copies of the Software, and to permit persons to whom the > - * Software is furnished to do so, subject to the following conditions: > - * > - * The above copyright notice and this permission notice shall be included in > - * all copies or substantial portions of the Software. > - * > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS OR > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO > EVENT SHALL > - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, > DAMAGES OR > - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR > OTHERWISE, > - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR > THE USE OR > - * OTHER DEALINGS IN THE SOFTWARE. > - * > - */ > -#ifndef __VEGA20_PPT_H__ > -#define __VEGA20_PPT_H__ > - > -#define VEGA20_UMD_PSTATE_GFXCLK_LEVEL 0x3 > -#define VEGA20_UMD_PSTATE_SOCCLK_LEVEL 0x3 > -#define VEGA20_UMD_PSTATE_MCLK_LEVEL 0x2 > -#define VEGA20_UMD_PSTATE_UVDCLK_LEVEL 0x3 > -#define VEGA20_UMD_PSTATE_VCEMCLK_LEVEL 0x3 > - > -#define MAX_REGULAR_DPM_NUMBER 16 > -#define MAX_PCIE_CONF 2 > - > -#define VOLTAGE_SCALE 4 > -#define AVFS_CURVE 0 > -#define OD8_HOTCURVE_TEMPERATURE 85 > - > -#define SMU_FEATURES_LOW_MASK 0x00000000FFFFFFFF > -#define SMU_FEATURES_LOW_SHIFT 0 > -#define SMU_FEATURES_HIGH_MASK 0xFFFFFFFF00000000 > -#define SMU_FEATURES_HIGH_SHIFT 32 > - > -enum { > - GNLD_DPM_PREFETCHER = 0, > - GNLD_DPM_GFXCLK, > - GNLD_DPM_UCLK, > - GNLD_DPM_SOCCLK, > - GNLD_DPM_UVD, > - GNLD_DPM_VCE, > - GNLD_ULV, > - GNLD_DPM_MP0CLK, > - GNLD_DPM_LINK, > - GNLD_DPM_DCEFCLK, > - GNLD_DS_GFXCLK, > - GNLD_DS_SOCCLK, > - GNLD_DS_LCLK, > - GNLD_PPT, > - GNLD_TDC, > - GNLD_THERMAL, > - GNLD_GFX_PER_CU_CG, > - GNLD_RM, > - GNLD_DS_DCEFCLK, > - GNLD_ACDC, > - GNLD_VR0HOT, > - GNLD_VR1HOT, > - GNLD_FW_CTF, > - GNLD_LED_DISPLAY, > - GNLD_FAN_CONTROL, > - GNLD_DIDT, > - GNLD_GFXOFF, > - GNLD_CG, > - GNLD_DPM_FCLK, > - GNLD_DS_FCLK, > - GNLD_DS_MP1CLK, > - GNLD_DS_MP0CLK, > - GNLD_XGMI, > - GNLD_ECC, > - > - GNLD_FEATURES_MAX > -}; > - > -struct vega20_dpm_level { > - bool enabled; > - uint32_t value; > - uint32_t param1; > -}; > - > -struct vega20_dpm_state { > - uint32_t soft_min_level; > - uint32_t soft_max_level; > - uint32_t hard_min_level; > - uint32_t hard_max_level; > -}; > - > -struct vega20_single_dpm_table { > - uint32_t count; > - struct vega20_dpm_state dpm_state; > - struct vega20_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER]; > -}; > - > -struct vega20_pcie_table { > - uint16_t count; > - uint8_t pcie_gen[MAX_PCIE_CONF]; > - uint8_t pcie_lane[MAX_PCIE_CONF]; > - uint32_t lclk[MAX_PCIE_CONF]; > -}; > - > -struct vega20_dpm_table { > - struct vega20_single_dpm_table soc_table; > - struct vega20_single_dpm_table gfx_table; > - struct vega20_single_dpm_table mem_table; > - struct vega20_single_dpm_table eclk_table; > - struct vega20_single_dpm_table vclk_table; > - struct vega20_single_dpm_table dclk_table; > - struct vega20_single_dpm_table dcef_table; > - struct vega20_single_dpm_table pixel_table; > - struct vega20_single_dpm_table display_table; > - struct vega20_single_dpm_table phy_table; > - struct vega20_single_dpm_table fclk_table; > - struct vega20_pcie_table pcie_table; > -}; > - > -enum OD8_FEATURE_ID > -{ > - OD8_GFXCLK_LIMITS = 1 << 0, > - OD8_GFXCLK_CURVE = 1 << 1, > - OD8_UCLK_MAX = 1 << 2, > - OD8_POWER_LIMIT = 1 << 3, > - OD8_ACOUSTIC_LIMIT_SCLK = 1 << 4, //FanMaximumRpm > - OD8_FAN_SPEED_MIN = 1 << 5, //FanMinimumPwm > - OD8_TEMPERATURE_FAN = 1 << 6, //FanTargetTemperature > - OD8_TEMPERATURE_SYSTEM = 1 << 7, //MaxOpTemp > - OD8_MEMORY_TIMING_TUNE = 1 << 8, > - OD8_FAN_ZERO_RPM_CONTROL = 1 << 9 > -}; > - > -enum OD8_SETTING_ID > -{ > - OD8_SETTING_GFXCLK_FMIN = 0, > - OD8_SETTING_GFXCLK_FMAX, > - OD8_SETTING_GFXCLK_FREQ1, > - OD8_SETTING_GFXCLK_VOLTAGE1, > - OD8_SETTING_GFXCLK_FREQ2, > - OD8_SETTING_GFXCLK_VOLTAGE2, > - OD8_SETTING_GFXCLK_FREQ3, > - OD8_SETTING_GFXCLK_VOLTAGE3, > - OD8_SETTING_UCLK_FMAX, > - OD8_SETTING_POWER_PERCENTAGE, > - OD8_SETTING_FAN_ACOUSTIC_LIMIT, > - OD8_SETTING_FAN_MIN_SPEED, > - OD8_SETTING_FAN_TARGET_TEMP, > - OD8_SETTING_OPERATING_TEMP_MAX, > - OD8_SETTING_AC_TIMING, > - OD8_SETTING_FAN_ZERO_RPM_CONTROL, > - OD8_SETTING_COUNT > -}; > - > -struct vega20_od8_single_setting { > - uint32_t feature_id; > - int32_t min_value; > - int32_t max_value; > - int32_t current_value; > - int32_t default_value; > -}; > - > -struct vega20_od8_settings { > - struct vega20_od8_single_setting > od8_settings_array[OD8_SETTING_COUNT]; > - uint8_t *od_feature_capabilities; > - uint32_t *od_settings_max; > - uint32_t *od_settings_min; > - void *od8_settings; > - bool od_gfxclk_update; > - bool od_memclk_update; > -}; > - > -extern void vega20_set_ppt_funcs(struct smu_context *smu); > - > -#endif > -- > 2.7.4 > > _______________________________________________ > amd-gfx mailing list > amd-gfx@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/amd-gfx _______________________________________________ amd-gfx mailing list amd-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/amd-gfx