Hi Prike, Thanks for the update. The original plan for swSMU based driver should be out of powerplay. So far, we don't need separate them under powerplay. Because it will bring additional effort while we move them out. I understand your intention, maybe we can discuss it after I come back. Thanks, Ray -----Original Message----- From: Liang, Prike <Prike.Liang@xxxxxxx> Sent: Monday, July 1, 2019 4:33 AM To: Liang, Prike <Prike.Liang@xxxxxxx>; amd-gfx@xxxxxxxxxxxxxxxxxxxxx Cc: Feng, Kenneth <Kenneth.Feng@xxxxxxx>; Quan, Evan <Evan.Quan@xxxxxxx>; Huang, Ray <Ray.Huang@xxxxxxx> Subject: RE: [PATCH] drm/amd/powerplay:Move powerplay table implement to pptable centralized management 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