root/drivers/gpu/drm/amd/powerplay/vega20_ppt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vega20_get_smu_table_index
  2. vega20_get_pwr_src_index
  3. vega20_get_smu_feature_index
  4. vega20_get_smu_clk_index
  5. vega20_get_smu_msg_index
  6. vega20_get_workload_type
  7. vega20_tables_init
  8. vega20_allocate_dpm_context
  9. vega20_setup_od8_information
  10. vega20_store_powerplay_table
  11. vega20_append_powerplay_table
  12. vega20_check_powerplay_table
  13. vega20_run_btc_afll
  14. vega20_get_allowed_feature_mask
  15. vega20_get_current_power_state
  16. vega20_set_single_dpm_table
  17. vega20_init_single_dpm_state
  18. vega20_set_default_dpm_table
  19. vega20_populate_umd_state_clk
  20. vega20_get_clk_table
  21. vega20_print_clk_levels
  22. vega20_upload_dpm_level
  23. vega20_force_clk_levels
  24. vega20_get_clock_by_type_with_latency
  25. vega20_overdrive_get_gfx_clk_base_voltage
  26. vega20_set_default_od8_setttings
  27. vega20_get_metrics_table
  28. vega20_set_default_od_settings
  29. vega20_get_od_percentage
  30. vega20_get_power_profile_mode
  31. vega20_set_power_profile_mode
  32. vega20_get_profiling_clk_mask
  33. vega20_set_uclk_to_highest_dpm_level
  34. vega20_pre_display_config_changed
  35. vega20_display_config_changed
  36. vega20_apply_clocks_adjust_rules
  37. vega20_notify_smc_dispaly_config
  38. vega20_find_lowest_dpm_level
  39. vega20_find_highest_dpm_level
  40. vega20_force_dpm_limit_value
  41. vega20_unforce_dpm_levels
  42. vega20_update_specified_od8_value
  43. vega20_update_od8_settings
  44. vega20_set_od_percentage
  45. vega20_odn_edit_dpm_table
  46. vega20_dpm_set_uvd_enable
  47. vega20_dpm_set_vce_enable
  48. vega20_is_dpm_running
  49. vega20_set_thermal_fan_table
  50. vega20_get_fan_speed_rpm
  51. vega20_get_fan_speed_percent
  52. vega20_get_gpu_power
  53. vega20_get_current_activity_percent
  54. vega20_thermal_get_temperature
  55. vega20_read_sensor
  56. vega20_set_watermarks_table
  57. vega20_get_thermal_temperature_range
  58. vega20_set_ppt_funcs

   1 /*
   2  * Copyright 2019 Advanced Micro Devices, Inc.
   3  *
   4  * Permission is hereby granted, free of charge, to any person obtaining a
   5  * copy of this software and associated documentation files (the "Software"),
   6  * to deal in the Software without restriction, including without limitation
   7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8  * and/or sell copies of the Software, and to permit persons to whom the
   9  * Software is furnished to do so, subject to the following conditions:
  10  *
  11  * The above copyright notice and this permission notice shall be included in
  12  * all copies or substantial portions of the Software.
  13  *
  14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20  * OTHER DEALINGS IN THE SOFTWARE.
  21  *
  22  */
  23 
  24 #include "pp_debug.h"
  25 #include <linux/firmware.h>
  26 #include "amdgpu.h"
  27 #include "amdgpu_smu.h"
  28 #include "atomfirmware.h"
  29 #include "amdgpu_atomfirmware.h"
  30 #include "smu_v11_0.h"
  31 #include "smu11_driver_if.h"
  32 #include "soc15_common.h"
  33 #include "atom.h"
  34 #include "power_state.h"
  35 #include "vega20_ppt.h"
  36 #include "vega20_pptable.h"
  37 #include "vega20_ppsmc.h"
  38 #include "nbio/nbio_7_4_sh_mask.h"
  39 #include "asic_reg/thm/thm_11_0_2_offset.h"
  40 #include "asic_reg/thm/thm_11_0_2_sh_mask.h"
  41 
  42 #define smnPCIE_LC_SPEED_CNTL                   0x11140290
  43 #define smnPCIE_LC_LINK_WIDTH_CNTL              0x11140288
  44 
  45 #define CTF_OFFSET_EDGE                 5
  46 #define CTF_OFFSET_HOTSPOT              5
  47 #define CTF_OFFSET_HBM                  5
  48 
  49 #define MSG_MAP(msg) \
  50         [SMU_MSG_##msg] = {1, PPSMC_MSG_##msg}
  51 
  52 #define SMC_DPM_FEATURE (FEATURE_DPM_PREFETCHER_MASK | \
  53                          FEATURE_DPM_GFXCLK_MASK | \
  54                          FEATURE_DPM_UCLK_MASK | \
  55                          FEATURE_DPM_SOCCLK_MASK | \
  56                          FEATURE_DPM_UVD_MASK | \
  57                          FEATURE_DPM_VCE_MASK | \
  58                          FEATURE_DPM_MP0CLK_MASK | \
  59                          FEATURE_DPM_LINK_MASK | \
  60                          FEATURE_DPM_DCEFCLK_MASK)
  61 
  62 static struct smu_11_0_cmn2aisc_mapping vega20_message_map[SMU_MSG_MAX_COUNT] = {
  63         MSG_MAP(TestMessage),
  64         MSG_MAP(GetSmuVersion),
  65         MSG_MAP(GetDriverIfVersion),
  66         MSG_MAP(SetAllowedFeaturesMaskLow),
  67         MSG_MAP(SetAllowedFeaturesMaskHigh),
  68         MSG_MAP(EnableAllSmuFeatures),
  69         MSG_MAP(DisableAllSmuFeatures),
  70         MSG_MAP(EnableSmuFeaturesLow),
  71         MSG_MAP(EnableSmuFeaturesHigh),
  72         MSG_MAP(DisableSmuFeaturesLow),
  73         MSG_MAP(DisableSmuFeaturesHigh),
  74         MSG_MAP(GetEnabledSmuFeaturesLow),
  75         MSG_MAP(GetEnabledSmuFeaturesHigh),
  76         MSG_MAP(SetWorkloadMask),
  77         MSG_MAP(SetPptLimit),
  78         MSG_MAP(SetDriverDramAddrHigh),
  79         MSG_MAP(SetDriverDramAddrLow),
  80         MSG_MAP(SetToolsDramAddrHigh),
  81         MSG_MAP(SetToolsDramAddrLow),
  82         MSG_MAP(TransferTableSmu2Dram),
  83         MSG_MAP(TransferTableDram2Smu),
  84         MSG_MAP(UseDefaultPPTable),
  85         MSG_MAP(UseBackupPPTable),
  86         MSG_MAP(RunBtc),
  87         MSG_MAP(RequestI2CBus),
  88         MSG_MAP(ReleaseI2CBus),
  89         MSG_MAP(SetFloorSocVoltage),
  90         MSG_MAP(SoftReset),
  91         MSG_MAP(StartBacoMonitor),
  92         MSG_MAP(CancelBacoMonitor),
  93         MSG_MAP(EnterBaco),
  94         MSG_MAP(SetSoftMinByFreq),
  95         MSG_MAP(SetSoftMaxByFreq),
  96         MSG_MAP(SetHardMinByFreq),
  97         MSG_MAP(SetHardMaxByFreq),
  98         MSG_MAP(GetMinDpmFreq),
  99         MSG_MAP(GetMaxDpmFreq),
 100         MSG_MAP(GetDpmFreqByIndex),
 101         MSG_MAP(GetDpmClockFreq),
 102         MSG_MAP(GetSsVoltageByDpm),
 103         MSG_MAP(SetMemoryChannelConfig),
 104         MSG_MAP(SetGeminiMode),
 105         MSG_MAP(SetGeminiApertureHigh),
 106         MSG_MAP(SetGeminiApertureLow),
 107         MSG_MAP(SetMinLinkDpmByIndex),
 108         MSG_MAP(OverridePcieParameters),
 109         MSG_MAP(OverDriveSetPercentage),
 110         MSG_MAP(SetMinDeepSleepDcefclk),
 111         MSG_MAP(ReenableAcDcInterrupt),
 112         MSG_MAP(NotifyPowerSource),
 113         MSG_MAP(SetUclkFastSwitch),
 114         MSG_MAP(SetUclkDownHyst),
 115         MSG_MAP(GetCurrentRpm),
 116         MSG_MAP(SetVideoFps),
 117         MSG_MAP(SetTjMax),
 118         MSG_MAP(SetFanTemperatureTarget),
 119         MSG_MAP(PrepareMp1ForUnload),
 120         MSG_MAP(DramLogSetDramAddrHigh),
 121         MSG_MAP(DramLogSetDramAddrLow),
 122         MSG_MAP(DramLogSetDramSize),
 123         MSG_MAP(SetFanMaxRpm),
 124         MSG_MAP(SetFanMinPwm),
 125         MSG_MAP(ConfigureGfxDidt),
 126         MSG_MAP(NumOfDisplays),
 127         MSG_MAP(RemoveMargins),
 128         MSG_MAP(ReadSerialNumTop32),
 129         MSG_MAP(ReadSerialNumBottom32),
 130         MSG_MAP(SetSystemVirtualDramAddrHigh),
 131         MSG_MAP(SetSystemVirtualDramAddrLow),
 132         MSG_MAP(WaflTest),
 133         MSG_MAP(SetFclkGfxClkRatio),
 134         MSG_MAP(AllowGfxOff),
 135         MSG_MAP(DisallowGfxOff),
 136         MSG_MAP(GetPptLimit),
 137         MSG_MAP(GetDcModeMaxDpmFreq),
 138         MSG_MAP(GetDebugData),
 139         MSG_MAP(SetXgmiMode),
 140         MSG_MAP(RunAfllBtc),
 141         MSG_MAP(ExitBaco),
 142         MSG_MAP(PrepareMp1ForReset),
 143         MSG_MAP(PrepareMp1ForShutdown),
 144         MSG_MAP(SetMGpuFanBoostLimitRpm),
 145         MSG_MAP(GetAVFSVoltageByDpm),
 146 };
 147 
 148 static struct smu_11_0_cmn2aisc_mapping vega20_clk_map[SMU_CLK_COUNT] = {
 149         CLK_MAP(GFXCLK, PPCLK_GFXCLK),
 150         CLK_MAP(VCLK, PPCLK_VCLK),
 151         CLK_MAP(DCLK, PPCLK_DCLK),
 152         CLK_MAP(ECLK, PPCLK_ECLK),
 153         CLK_MAP(SOCCLK, PPCLK_SOCCLK),
 154         CLK_MAP(UCLK, PPCLK_UCLK),
 155         CLK_MAP(DCEFCLK, PPCLK_DCEFCLK),
 156         CLK_MAP(DISPCLK, PPCLK_DISPCLK),
 157         CLK_MAP(PIXCLK, PPCLK_PIXCLK),
 158         CLK_MAP(PHYCLK, PPCLK_PHYCLK),
 159         CLK_MAP(FCLK, PPCLK_FCLK),
 160 };
 161 
 162 static struct smu_11_0_cmn2aisc_mapping vega20_feature_mask_map[SMU_FEATURE_COUNT] = {
 163         FEA_MAP(DPM_PREFETCHER),
 164         FEA_MAP(DPM_GFXCLK),
 165         FEA_MAP(DPM_UCLK),
 166         FEA_MAP(DPM_SOCCLK),
 167         FEA_MAP(DPM_UVD),
 168         FEA_MAP(DPM_VCE),
 169         FEA_MAP(ULV),
 170         FEA_MAP(DPM_MP0CLK),
 171         FEA_MAP(DPM_LINK),
 172         FEA_MAP(DPM_DCEFCLK),
 173         FEA_MAP(DS_GFXCLK),
 174         FEA_MAP(DS_SOCCLK),
 175         FEA_MAP(DS_LCLK),
 176         FEA_MAP(PPT),
 177         FEA_MAP(TDC),
 178         FEA_MAP(THERMAL),
 179         FEA_MAP(GFX_PER_CU_CG),
 180         FEA_MAP(RM),
 181         FEA_MAP(DS_DCEFCLK),
 182         FEA_MAP(ACDC),
 183         FEA_MAP(VR0HOT),
 184         FEA_MAP(VR1HOT),
 185         FEA_MAP(FW_CTF),
 186         FEA_MAP(LED_DISPLAY),
 187         FEA_MAP(FAN_CONTROL),
 188         FEA_MAP(GFX_EDC),
 189         FEA_MAP(GFXOFF),
 190         FEA_MAP(CG),
 191         FEA_MAP(DPM_FCLK),
 192         FEA_MAP(DS_FCLK),
 193         FEA_MAP(DS_MP1CLK),
 194         FEA_MAP(DS_MP0CLK),
 195         FEA_MAP(XGMI),
 196 };
 197 
 198 static struct smu_11_0_cmn2aisc_mapping vega20_table_map[SMU_TABLE_COUNT] = {
 199         TAB_MAP(PPTABLE),
 200         TAB_MAP(WATERMARKS),
 201         TAB_MAP(AVFS),
 202         TAB_MAP(AVFS_PSM_DEBUG),
 203         TAB_MAP(AVFS_FUSE_OVERRIDE),
 204         TAB_MAP(PMSTATUSLOG),
 205         TAB_MAP(SMU_METRICS),
 206         TAB_MAP(DRIVER_SMU_CONFIG),
 207         TAB_MAP(ACTIVITY_MONITOR_COEFF),
 208         TAB_MAP(OVERDRIVE),
 209 };
 210 
 211 static struct smu_11_0_cmn2aisc_mapping vega20_pwr_src_map[SMU_POWER_SOURCE_COUNT] = {
 212         PWR_MAP(AC),
 213         PWR_MAP(DC),
 214 };
 215 
 216 static struct smu_11_0_cmn2aisc_mapping vega20_workload_map[PP_SMC_POWER_PROFILE_COUNT] = {
 217         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT,       WORKLOAD_DEFAULT_BIT),
 218         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D,         WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT),
 219         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING,          WORKLOAD_PPLIB_POWER_SAVING_BIT),
 220         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO,                WORKLOAD_PPLIB_VIDEO_BIT),
 221         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR,                   WORKLOAD_PPLIB_VR_BIT),
 222         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE,              WORKLOAD_PPLIB_COMPUTE_BIT),
 223         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM,               WORKLOAD_PPLIB_CUSTOM_BIT),
 224 };
 225 
 226 static int vega20_get_smu_table_index(struct smu_context *smc, uint32_t index)
 227 {
 228         struct smu_11_0_cmn2aisc_mapping mapping;
 229 
 230         if (index >= SMU_TABLE_COUNT)
 231                 return -EINVAL;
 232 
 233         mapping = vega20_table_map[index];
 234         if (!(mapping.valid_mapping)) {
 235                 return -EINVAL;
 236         }
 237 
 238         return mapping.map_to;
 239 }
 240 
 241 static int vega20_get_pwr_src_index(struct smu_context *smc, uint32_t index)
 242 {
 243         struct smu_11_0_cmn2aisc_mapping mapping;
 244 
 245         if (index >= SMU_POWER_SOURCE_COUNT)
 246                 return -EINVAL;
 247 
 248         mapping = vega20_pwr_src_map[index];
 249         if (!(mapping.valid_mapping)) {
 250                 return -EINVAL;
 251         }
 252 
 253         return mapping.map_to;
 254 }
 255 
 256 static int vega20_get_smu_feature_index(struct smu_context *smc, uint32_t index)
 257 {
 258         struct smu_11_0_cmn2aisc_mapping mapping;
 259 
 260         if (index >= SMU_FEATURE_COUNT)
 261                 return -EINVAL;
 262 
 263         mapping = vega20_feature_mask_map[index];
 264         if (!(mapping.valid_mapping)) {
 265                 return -EINVAL;
 266         }
 267 
 268         return mapping.map_to;
 269 }
 270 
 271 static int vega20_get_smu_clk_index(struct smu_context *smc, uint32_t index)
 272 {
 273         struct smu_11_0_cmn2aisc_mapping mapping;
 274 
 275         if (index >= SMU_CLK_COUNT)
 276                 return -EINVAL;
 277 
 278         mapping = vega20_clk_map[index];
 279         if (!(mapping.valid_mapping)) {
 280                 return -EINVAL;
 281         }
 282 
 283         return mapping.map_to;
 284 }
 285 
 286 static int vega20_get_smu_msg_index(struct smu_context *smc, uint32_t index)
 287 {
 288         struct smu_11_0_cmn2aisc_mapping mapping;
 289 
 290         if (index >= SMU_MSG_MAX_COUNT)
 291                 return -EINVAL;
 292 
 293         mapping = vega20_message_map[index];
 294         if (!(mapping.valid_mapping)) {
 295                 return -EINVAL;
 296         }
 297 
 298         return mapping.map_to;
 299 }
 300 
 301 static int vega20_get_workload_type(struct smu_context *smu, enum PP_SMC_POWER_PROFILE profile)
 302 {
 303         struct smu_11_0_cmn2aisc_mapping mapping;
 304 
 305         if (profile > PP_SMC_POWER_PROFILE_CUSTOM)
 306                 return -EINVAL;
 307 
 308         mapping = vega20_workload_map[profile];
 309         if (!(mapping.valid_mapping)) {
 310                 return -EINVAL;
 311         }
 312 
 313         return mapping.map_to;
 314 }
 315 
 316 static int vega20_tables_init(struct smu_context *smu, struct smu_table *tables)
 317 {
 318         struct smu_table_context *smu_table = &smu->smu_table;
 319 
 320         SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t),
 321                        PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 322         SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
 323                        PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 324         SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
 325                        PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 326         SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t),
 327                        PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 328         SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE,
 329                        PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 330         SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF,
 331                        sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE,
 332                        AMDGPU_GEM_DOMAIN_VRAM);
 333 
 334         smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
 335         if (!smu_table->metrics_table)
 336                 return -ENOMEM;
 337         smu_table->metrics_time = 0;
 338 
 339         return 0;
 340 }
 341 
 342 static int vega20_allocate_dpm_context(struct smu_context *smu)
 343 {
 344         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
 345 
 346         if (smu_dpm->dpm_context)
 347                 return -EINVAL;
 348 
 349         smu_dpm->dpm_context = kzalloc(sizeof(struct vega20_dpm_table),
 350                                        GFP_KERNEL);
 351         if (!smu_dpm->dpm_context)
 352                 return -ENOMEM;
 353 
 354         if (smu_dpm->golden_dpm_context)
 355                 return -EINVAL;
 356 
 357         smu_dpm->golden_dpm_context = kzalloc(sizeof(struct vega20_dpm_table),
 358                                               GFP_KERNEL);
 359         if (!smu_dpm->golden_dpm_context)
 360                 return -ENOMEM;
 361 
 362         smu_dpm->dpm_context_size = sizeof(struct vega20_dpm_table);
 363 
 364         smu_dpm->dpm_current_power_state = kzalloc(sizeof(struct smu_power_state),
 365                                        GFP_KERNEL);
 366         if (!smu_dpm->dpm_current_power_state)
 367                 return -ENOMEM;
 368 
 369         smu_dpm->dpm_request_power_state = kzalloc(sizeof(struct smu_power_state),
 370                                        GFP_KERNEL);
 371         if (!smu_dpm->dpm_request_power_state)
 372                 return -ENOMEM;
 373 
 374         return 0;
 375 }
 376 
 377 static int vega20_setup_od8_information(struct smu_context *smu)
 378 {
 379         ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL;
 380         struct smu_table_context *table_context = &smu->smu_table;
 381         struct vega20_od8_settings *od8_settings = (struct vega20_od8_settings *)smu->od_settings;
 382 
 383         uint32_t od_feature_count, od_feature_array_size,
 384                  od_setting_count, od_setting_array_size;
 385 
 386         if (!table_context->power_play_table)
 387                 return -EINVAL;
 388 
 389         powerplay_table = table_context->power_play_table;
 390 
 391         if (powerplay_table->OverDrive8Table.ucODTableRevision == 1) {
 392                 /* Setup correct ODFeatureCount, and store ODFeatureArray from
 393                  * powerplay table to od_feature_capabilities */
 394                 od_feature_count =
 395                         (le32_to_cpu(powerplay_table->OverDrive8Table.ODFeatureCount) >
 396                          ATOM_VEGA20_ODFEATURE_COUNT) ?
 397                         ATOM_VEGA20_ODFEATURE_COUNT :
 398                         le32_to_cpu(powerplay_table->OverDrive8Table.ODFeatureCount);
 399 
 400                 od_feature_array_size = sizeof(uint8_t) * od_feature_count;
 401 
 402                 if (od8_settings->od_feature_capabilities)
 403                         return -EINVAL;
 404 
 405                 od8_settings->od_feature_capabilities = kmemdup(&powerplay_table->OverDrive8Table.ODFeatureCapabilities,
 406                                                                  od_feature_array_size,
 407                                                                  GFP_KERNEL);
 408                 if (!od8_settings->od_feature_capabilities)
 409                         return -ENOMEM;
 410 
 411                 /* Setup correct ODSettingCount, and store ODSettingArray from
 412                  * powerplay table to od_settings_max and od_setting_min */
 413                 od_setting_count =
 414                         (le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingCount) >
 415                          ATOM_VEGA20_ODSETTING_COUNT) ?
 416                         ATOM_VEGA20_ODSETTING_COUNT :
 417                         le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingCount);
 418 
 419                 od_setting_array_size = sizeof(uint32_t) * od_setting_count;
 420 
 421                 if (od8_settings->od_settings_max)
 422                         return -EINVAL;
 423 
 424                 od8_settings->od_settings_max = kmemdup(&powerplay_table->OverDrive8Table.ODSettingsMax,
 425                                                          od_setting_array_size,
 426                                                          GFP_KERNEL);
 427 
 428                 if (!od8_settings->od_settings_max) {
 429                         kfree(od8_settings->od_feature_capabilities);
 430                         od8_settings->od_feature_capabilities = NULL;
 431                         return -ENOMEM;
 432                 }
 433 
 434                 if (od8_settings->od_settings_min)
 435                         return -EINVAL;
 436 
 437                 od8_settings->od_settings_min = kmemdup(&powerplay_table->OverDrive8Table.ODSettingsMin,
 438                                                          od_setting_array_size,
 439                                                          GFP_KERNEL);
 440 
 441                 if (!od8_settings->od_settings_min) {
 442                         kfree(od8_settings->od_feature_capabilities);
 443                         od8_settings->od_feature_capabilities = NULL;
 444                         kfree(od8_settings->od_settings_max);
 445                         od8_settings->od_settings_max = NULL;
 446                         return -ENOMEM;
 447                 }
 448         }
 449 
 450         return 0;
 451 }
 452 
 453 static int vega20_store_powerplay_table(struct smu_context *smu)
 454 {
 455         ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL;
 456         struct smu_table_context *table_context = &smu->smu_table;
 457 
 458         if (!table_context->power_play_table)
 459                 return -EINVAL;
 460 
 461         powerplay_table = table_context->power_play_table;
 462 
 463         memcpy(table_context->driver_pptable, &powerplay_table->smcPPTable,
 464                sizeof(PPTable_t));
 465 
 466         table_context->thermal_controller_type = powerplay_table->ucThermalControllerType;
 467         table_context->TDPODLimit = le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingsMax[ATOM_VEGA20_ODSETTING_POWERPERCENTAGE]);
 468 
 469         return 0;
 470 }
 471 
 472 static int vega20_append_powerplay_table(struct smu_context *smu)
 473 {
 474         struct smu_table_context *table_context = &smu->smu_table;
 475         PPTable_t *smc_pptable = table_context->driver_pptable;
 476         struct atom_smc_dpm_info_v4_4 *smc_dpm_table;
 477         int index, i, ret;
 478 
 479         index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
 480                                            smc_dpm_info);
 481 
 482         ret = smu_get_atom_data_table(smu, index, NULL, NULL, NULL,
 483                                       (uint8_t **)&smc_dpm_table);
 484         if (ret)
 485                 return ret;
 486 
 487         smc_pptable->MaxVoltageStepGfx = smc_dpm_table->maxvoltagestepgfx;
 488         smc_pptable->MaxVoltageStepSoc = smc_dpm_table->maxvoltagestepsoc;
 489 
 490         smc_pptable->VddGfxVrMapping = smc_dpm_table->vddgfxvrmapping;
 491         smc_pptable->VddSocVrMapping = smc_dpm_table->vddsocvrmapping;
 492         smc_pptable->VddMem0VrMapping = smc_dpm_table->vddmem0vrmapping;
 493         smc_pptable->VddMem1VrMapping = smc_dpm_table->vddmem1vrmapping;
 494 
 495         smc_pptable->GfxUlvPhaseSheddingMask = smc_dpm_table->gfxulvphasesheddingmask;
 496         smc_pptable->SocUlvPhaseSheddingMask = smc_dpm_table->soculvphasesheddingmask;
 497         smc_pptable->ExternalSensorPresent = smc_dpm_table->externalsensorpresent;
 498 
 499         smc_pptable->GfxMaxCurrent = smc_dpm_table->gfxmaxcurrent;
 500         smc_pptable->GfxOffset = smc_dpm_table->gfxoffset;
 501         smc_pptable->Padding_TelemetryGfx = smc_dpm_table->padding_telemetrygfx;
 502 
 503         smc_pptable->SocMaxCurrent = smc_dpm_table->socmaxcurrent;
 504         smc_pptable->SocOffset = smc_dpm_table->socoffset;
 505         smc_pptable->Padding_TelemetrySoc = smc_dpm_table->padding_telemetrysoc;
 506 
 507         smc_pptable->Mem0MaxCurrent = smc_dpm_table->mem0maxcurrent;
 508         smc_pptable->Mem0Offset = smc_dpm_table->mem0offset;
 509         smc_pptable->Padding_TelemetryMem0 = smc_dpm_table->padding_telemetrymem0;
 510 
 511         smc_pptable->Mem1MaxCurrent = smc_dpm_table->mem1maxcurrent;
 512         smc_pptable->Mem1Offset = smc_dpm_table->mem1offset;
 513         smc_pptable->Padding_TelemetryMem1 = smc_dpm_table->padding_telemetrymem1;
 514 
 515         smc_pptable->AcDcGpio = smc_dpm_table->acdcgpio;
 516         smc_pptable->AcDcPolarity = smc_dpm_table->acdcpolarity;
 517         smc_pptable->VR0HotGpio = smc_dpm_table->vr0hotgpio;
 518         smc_pptable->VR0HotPolarity = smc_dpm_table->vr0hotpolarity;
 519 
 520         smc_pptable->VR1HotGpio = smc_dpm_table->vr1hotgpio;
 521         smc_pptable->VR1HotPolarity = smc_dpm_table->vr1hotpolarity;
 522         smc_pptable->Padding1 = smc_dpm_table->padding1;
 523         smc_pptable->Padding2 = smc_dpm_table->padding2;
 524 
 525         smc_pptable->LedPin0 = smc_dpm_table->ledpin0;
 526         smc_pptable->LedPin1 = smc_dpm_table->ledpin1;
 527         smc_pptable->LedPin2 = smc_dpm_table->ledpin2;
 528 
 529         smc_pptable->PllGfxclkSpreadEnabled = smc_dpm_table->pllgfxclkspreadenabled;
 530         smc_pptable->PllGfxclkSpreadPercent = smc_dpm_table->pllgfxclkspreadpercent;
 531         smc_pptable->PllGfxclkSpreadFreq = smc_dpm_table->pllgfxclkspreadfreq;
 532 
 533         smc_pptable->UclkSpreadEnabled = 0;
 534         smc_pptable->UclkSpreadPercent = smc_dpm_table->uclkspreadpercent;
 535         smc_pptable->UclkSpreadFreq = smc_dpm_table->uclkspreadfreq;
 536 
 537         smc_pptable->FclkSpreadEnabled = smc_dpm_table->fclkspreadenabled;
 538         smc_pptable->FclkSpreadPercent = smc_dpm_table->fclkspreadpercent;
 539         smc_pptable->FclkSpreadFreq = smc_dpm_table->fclkspreadfreq;
 540 
 541         smc_pptable->FllGfxclkSpreadEnabled = smc_dpm_table->fllgfxclkspreadenabled;
 542         smc_pptable->FllGfxclkSpreadPercent = smc_dpm_table->fllgfxclkspreadpercent;
 543         smc_pptable->FllGfxclkSpreadFreq = smc_dpm_table->fllgfxclkspreadfreq;
 544 
 545         for (i = 0; i < I2C_CONTROLLER_NAME_COUNT; i++) {
 546                 smc_pptable->I2cControllers[i].Enabled =
 547                         smc_dpm_table->i2ccontrollers[i].enabled;
 548                 smc_pptable->I2cControllers[i].SlaveAddress =
 549                         smc_dpm_table->i2ccontrollers[i].slaveaddress;
 550                 smc_pptable->I2cControllers[i].ControllerPort =
 551                         smc_dpm_table->i2ccontrollers[i].controllerport;
 552                 smc_pptable->I2cControllers[i].ThermalThrottler =
 553                         smc_dpm_table->i2ccontrollers[i].thermalthrottler;
 554                 smc_pptable->I2cControllers[i].I2cProtocol =
 555                         smc_dpm_table->i2ccontrollers[i].i2cprotocol;
 556                 smc_pptable->I2cControllers[i].I2cSpeed =
 557                         smc_dpm_table->i2ccontrollers[i].i2cspeed;
 558         }
 559 
 560         return 0;
 561 }
 562 
 563 static int vega20_check_powerplay_table(struct smu_context *smu)
 564 {
 565         ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL;
 566         struct smu_table_context *table_context = &smu->smu_table;
 567 
 568         powerplay_table = table_context->power_play_table;
 569 
 570         if (powerplay_table->sHeader.format_revision < ATOM_VEGA20_TABLE_REVISION_VEGA20) {
 571                 pr_err("Unsupported PPTable format!");
 572                 return -EINVAL;
 573         }
 574 
 575         if (!powerplay_table->sHeader.structuresize) {
 576                 pr_err("Invalid PowerPlay Table!");
 577                 return -EINVAL;
 578         }
 579 
 580         return 0;
 581 }
 582 
 583 static int vega20_run_btc_afll(struct smu_context *smu)
 584 {
 585         return smu_send_smc_msg(smu, SMU_MSG_RunAfllBtc);
 586 }
 587 
 588 #define FEATURE_MASK(feature) (1ULL << feature)
 589 static int
 590 vega20_get_allowed_feature_mask(struct smu_context *smu,
 591                                   uint32_t *feature_mask, uint32_t num)
 592 {
 593         if (num > 2)
 594                 return -EINVAL;
 595 
 596         memset(feature_mask, 0, sizeof(uint32_t) * num);
 597 
 598         *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT)
 599                                 | FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT)
 600                                 | FEATURE_MASK(FEATURE_DPM_UCLK_BIT)
 601                                 | FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT)
 602                                 | FEATURE_MASK(FEATURE_DPM_UVD_BIT)
 603                                 | FEATURE_MASK(FEATURE_DPM_VCE_BIT)
 604                                 | FEATURE_MASK(FEATURE_ULV_BIT)
 605                                 | FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT)
 606                                 | FEATURE_MASK(FEATURE_DPM_LINK_BIT)
 607                                 | FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT)
 608                                 | FEATURE_MASK(FEATURE_PPT_BIT)
 609                                 | FEATURE_MASK(FEATURE_TDC_BIT)
 610                                 | FEATURE_MASK(FEATURE_THERMAL_BIT)
 611                                 | FEATURE_MASK(FEATURE_GFX_PER_CU_CG_BIT)
 612                                 | FEATURE_MASK(FEATURE_RM_BIT)
 613                                 | FEATURE_MASK(FEATURE_ACDC_BIT)
 614                                 | FEATURE_MASK(FEATURE_VR0HOT_BIT)
 615                                 | FEATURE_MASK(FEATURE_VR1HOT_BIT)
 616                                 | FEATURE_MASK(FEATURE_FW_CTF_BIT)
 617                                 | FEATURE_MASK(FEATURE_LED_DISPLAY_BIT)
 618                                 | FEATURE_MASK(FEATURE_FAN_CONTROL_BIT)
 619                                 | FEATURE_MASK(FEATURE_GFX_EDC_BIT)
 620                                 | FEATURE_MASK(FEATURE_GFXOFF_BIT)
 621                                 | FEATURE_MASK(FEATURE_CG_BIT)
 622                                 | FEATURE_MASK(FEATURE_DPM_FCLK_BIT)
 623                                 | FEATURE_MASK(FEATURE_XGMI_BIT);
 624         return 0;
 625 }
 626 
 627 static enum
 628 amd_pm_state_type vega20_get_current_power_state(struct smu_context *smu)
 629 {
 630         enum amd_pm_state_type pm_type;
 631         struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
 632 
 633         if (!smu_dpm_ctx->dpm_context ||
 634             !smu_dpm_ctx->dpm_current_power_state)
 635                 return -EINVAL;
 636 
 637         mutex_lock(&(smu->mutex));
 638         switch (smu_dpm_ctx->dpm_current_power_state->classification.ui_label) {
 639         case SMU_STATE_UI_LABEL_BATTERY:
 640                 pm_type = POWER_STATE_TYPE_BATTERY;
 641                 break;
 642         case SMU_STATE_UI_LABEL_BALLANCED:
 643                 pm_type = POWER_STATE_TYPE_BALANCED;
 644                 break;
 645         case SMU_STATE_UI_LABEL_PERFORMANCE:
 646                 pm_type = POWER_STATE_TYPE_PERFORMANCE;
 647                 break;
 648         default:
 649                 if (smu_dpm_ctx->dpm_current_power_state->classification.flags & SMU_STATE_CLASSIFICATION_FLAG_BOOT)
 650                         pm_type = POWER_STATE_TYPE_INTERNAL_BOOT;
 651                 else
 652                         pm_type = POWER_STATE_TYPE_DEFAULT;
 653                 break;
 654         }
 655         mutex_unlock(&(smu->mutex));
 656 
 657         return pm_type;
 658 }
 659 
 660 static int
 661 vega20_set_single_dpm_table(struct smu_context *smu,
 662                             struct vega20_single_dpm_table *single_dpm_table,
 663                             PPCLK_e clk_id)
 664 {
 665         int ret = 0;
 666         uint32_t i, num_of_levels = 0, clk;
 667 
 668         ret = smu_send_smc_msg_with_param(smu,
 669                         SMU_MSG_GetDpmFreqByIndex,
 670                         (clk_id << 16 | 0xFF));
 671         if (ret) {
 672                 pr_err("[GetNumOfDpmLevel] failed to get dpm levels!");
 673                 return ret;
 674         }
 675 
 676         smu_read_smc_arg(smu, &num_of_levels);
 677         if (!num_of_levels) {
 678                 pr_err("[GetNumOfDpmLevel] number of clk levels is invalid!");
 679                 return -EINVAL;
 680         }
 681 
 682         single_dpm_table->count = num_of_levels;
 683 
 684         for (i = 0; i < num_of_levels; i++) {
 685                 ret = smu_send_smc_msg_with_param(smu,
 686                                 SMU_MSG_GetDpmFreqByIndex,
 687                                 (clk_id << 16 | i));
 688                 if (ret) {
 689                         pr_err("[GetDpmFreqByIndex] failed to get dpm freq by index!");
 690                         return ret;
 691                 }
 692                 smu_read_smc_arg(smu, &clk);
 693                 if (!clk) {
 694                         pr_err("[GetDpmFreqByIndex] clk value is invalid!");
 695                         return -EINVAL;
 696                 }
 697                 single_dpm_table->dpm_levels[i].value = clk;
 698                 single_dpm_table->dpm_levels[i].enabled = true;
 699         }
 700         return 0;
 701 }
 702 
 703 static void vega20_init_single_dpm_state(struct vega20_dpm_state *dpm_state)
 704 {
 705         dpm_state->soft_min_level = 0x0;
 706         dpm_state->soft_max_level = 0xffff;
 707         dpm_state->hard_min_level = 0x0;
 708         dpm_state->hard_max_level = 0xffff;
 709 }
 710 
 711 static int vega20_set_default_dpm_table(struct smu_context *smu)
 712 {
 713         int ret;
 714 
 715         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
 716         struct vega20_dpm_table *dpm_table = NULL;
 717         struct vega20_single_dpm_table *single_dpm_table;
 718 
 719         dpm_table = smu_dpm->dpm_context;
 720 
 721         /* socclk */
 722         single_dpm_table = &(dpm_table->soc_table);
 723 
 724         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
 725                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
 726                                                   PPCLK_SOCCLK);
 727                 if (ret) {
 728                         pr_err("[SetupDefaultDpmTable] failed to get socclk dpm levels!");
 729                         return ret;
 730                 }
 731         } else {
 732                 single_dpm_table->count = 1;
 733                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100;
 734         }
 735         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
 736 
 737         /* gfxclk */
 738         single_dpm_table = &(dpm_table->gfx_table);
 739 
 740         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
 741                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
 742                                                   PPCLK_GFXCLK);
 743                 if (ret) {
 744                         pr_err("[SetupDefaultDpmTable] failed to get gfxclk dpm levels!");
 745                         return ret;
 746                 }
 747         } else {
 748                 single_dpm_table->count = 1;
 749                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
 750         }
 751         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
 752 
 753         /* memclk */
 754         single_dpm_table = &(dpm_table->mem_table);
 755 
 756         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
 757                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
 758                                                   PPCLK_UCLK);
 759                 if (ret) {
 760                         pr_err("[SetupDefaultDpmTable] failed to get memclk dpm levels!");
 761                         return ret;
 762                 }
 763         } else {
 764                 single_dpm_table->count = 1;
 765                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100;
 766         }
 767         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
 768 
 769         /* eclk */
 770         single_dpm_table = &(dpm_table->eclk_table);
 771 
 772         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_VCE_BIT)) {
 773                 ret = vega20_set_single_dpm_table(smu, single_dpm_table, PPCLK_ECLK);
 774                 if (ret) {
 775                         pr_err("[SetupDefaultDpmTable] failed to get eclk dpm levels!");
 776                         return ret;
 777                 }
 778         } else {
 779                 single_dpm_table->count = 1;
 780                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.eclk / 100;
 781         }
 782         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
 783 
 784         /* vclk */
 785         single_dpm_table = &(dpm_table->vclk_table);
 786 
 787         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT)) {
 788                 ret = vega20_set_single_dpm_table(smu, single_dpm_table, PPCLK_VCLK);
 789                 if (ret) {
 790                         pr_err("[SetupDefaultDpmTable] failed to get vclk dpm levels!");
 791                         return ret;
 792                 }
 793         } else {
 794                 single_dpm_table->count = 1;
 795                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100;
 796         }
 797         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
 798 
 799         /* dclk */
 800         single_dpm_table = &(dpm_table->dclk_table);
 801 
 802         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT)) {
 803                 ret = vega20_set_single_dpm_table(smu, single_dpm_table, PPCLK_DCLK);
 804                 if (ret) {
 805                         pr_err("[SetupDefaultDpmTable] failed to get dclk dpm levels!");
 806                         return ret;
 807                 }
 808         } else {
 809                 single_dpm_table->count = 1;
 810                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100;
 811         }
 812         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
 813 
 814         /* dcefclk */
 815         single_dpm_table = &(dpm_table->dcef_table);
 816 
 817         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
 818                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
 819                                                   PPCLK_DCEFCLK);
 820                 if (ret) {
 821                         pr_err("[SetupDefaultDpmTable] failed to get dcefclk dpm levels!");
 822                         return ret;
 823                 }
 824         } else {
 825                 single_dpm_table->count = 1;
 826                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
 827         }
 828         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
 829 
 830         /* pixclk */
 831         single_dpm_table = &(dpm_table->pixel_table);
 832 
 833         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
 834                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
 835                                                   PPCLK_PIXCLK);
 836                 if (ret) {
 837                         pr_err("[SetupDefaultDpmTable] failed to get pixclk dpm levels!");
 838                         return ret;
 839                 }
 840         } else {
 841                 single_dpm_table->count = 0;
 842         }
 843         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
 844 
 845         /* dispclk */
 846         single_dpm_table = &(dpm_table->display_table);
 847 
 848         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
 849                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
 850                                                   PPCLK_DISPCLK);
 851                 if (ret) {
 852                         pr_err("[SetupDefaultDpmTable] failed to get dispclk dpm levels!");
 853                         return ret;
 854                 }
 855         } else {
 856                 single_dpm_table->count = 0;
 857         }
 858         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
 859 
 860         /* phyclk */
 861         single_dpm_table = &(dpm_table->phy_table);
 862 
 863         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
 864                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
 865                                                   PPCLK_PHYCLK);
 866                 if (ret) {
 867                         pr_err("[SetupDefaultDpmTable] failed to get phyclk dpm levels!");
 868                         return ret;
 869                 }
 870         } else {
 871                 single_dpm_table->count = 0;
 872         }
 873         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
 874 
 875         /* fclk */
 876         single_dpm_table = &(dpm_table->fclk_table);
 877 
 878         if (smu_feature_is_enabled(smu,FEATURE_DPM_FCLK_BIT)) {
 879                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
 880                                                   PPCLK_FCLK);
 881                 if (ret) {
 882                         pr_err("[SetupDefaultDpmTable] failed to get fclk dpm levels!");
 883                         return ret;
 884                 }
 885         } else {
 886                 single_dpm_table->count = 0;
 887         }
 888         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
 889 
 890         memcpy(smu_dpm->golden_dpm_context, dpm_table,
 891                sizeof(struct vega20_dpm_table));
 892 
 893         return 0;
 894 }
 895 
 896 static int vega20_populate_umd_state_clk(struct smu_context *smu)
 897 {
 898         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
 899         struct vega20_dpm_table *dpm_table = NULL;
 900         struct vega20_single_dpm_table *gfx_table = NULL;
 901         struct vega20_single_dpm_table *mem_table = NULL;
 902 
 903         dpm_table = smu_dpm->dpm_context;
 904         gfx_table = &(dpm_table->gfx_table);
 905         mem_table = &(dpm_table->mem_table);
 906 
 907         smu->pstate_sclk = gfx_table->dpm_levels[0].value;
 908         smu->pstate_mclk = mem_table->dpm_levels[0].value;
 909 
 910         if (gfx_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
 911             mem_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL) {
 912                 smu->pstate_sclk = gfx_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
 913                 smu->pstate_mclk = mem_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
 914         }
 915 
 916         smu->pstate_sclk = smu->pstate_sclk * 100;
 917         smu->pstate_mclk = smu->pstate_mclk * 100;
 918 
 919         return 0;
 920 }
 921 
 922 static int vega20_get_clk_table(struct smu_context *smu,
 923                         struct pp_clock_levels_with_latency *clocks,
 924                         struct vega20_single_dpm_table *dpm_table)
 925 {
 926         int i, count;
 927 
 928         count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
 929         clocks->num_levels = count;
 930 
 931         for (i = 0; i < count; i++) {
 932                 clocks->data[i].clocks_in_khz =
 933                         dpm_table->dpm_levels[i].value * 1000;
 934                 clocks->data[i].latency_in_us = 0;
 935         }
 936 
 937         return 0;
 938 }
 939 
 940 static int vega20_print_clk_levels(struct smu_context *smu,
 941                         enum smu_clk_type type, char *buf)
 942 {
 943         int i, now, size = 0;
 944         int ret = 0;
 945         uint32_t gen_speed, lane_width;
 946         struct amdgpu_device *adev = smu->adev;
 947         struct pp_clock_levels_with_latency clocks;
 948         struct vega20_single_dpm_table *single_dpm_table;
 949         struct smu_table_context *table_context = &smu->smu_table;
 950         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
 951         struct vega20_dpm_table *dpm_table = NULL;
 952         struct vega20_od8_settings *od8_settings =
 953                 (struct vega20_od8_settings *)smu->od_settings;
 954         OverDriveTable_t *od_table =
 955                 (OverDriveTable_t *)(table_context->overdrive_table);
 956         PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable;
 957 
 958         dpm_table = smu_dpm->dpm_context;
 959 
 960         switch (type) {
 961         case SMU_SCLK:
 962                 ret = smu_get_current_clk_freq(smu, SMU_GFXCLK, &now);
 963                 if (ret) {
 964                         pr_err("Attempt to get current gfx clk Failed!");
 965                         return ret;
 966                 }
 967 
 968                 single_dpm_table = &(dpm_table->gfx_table);
 969                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
 970                 if (ret) {
 971                         pr_err("Attempt to get gfx clk levels Failed!");
 972                         return ret;
 973                 }
 974 
 975                 for (i = 0; i < clocks.num_levels; i++)
 976                         size += sprintf(buf + size, "%d: %uMhz %s\n", i,
 977                                         clocks.data[i].clocks_in_khz / 1000,
 978                                         (clocks.data[i].clocks_in_khz == now * 10)
 979                                         ? "*" : "");
 980                 break;
 981 
 982         case SMU_MCLK:
 983                 ret = smu_get_current_clk_freq(smu, SMU_UCLK, &now);
 984                 if (ret) {
 985                         pr_err("Attempt to get current mclk Failed!");
 986                         return ret;
 987                 }
 988 
 989                 single_dpm_table = &(dpm_table->mem_table);
 990                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
 991                 if (ret) {
 992                         pr_err("Attempt to get memory clk levels Failed!");
 993                         return ret;
 994                 }
 995 
 996                 for (i = 0; i < clocks.num_levels; i++)
 997                         size += sprintf(buf + size, "%d: %uMhz %s\n",
 998                                 i, clocks.data[i].clocks_in_khz / 1000,
 999                                 (clocks.data[i].clocks_in_khz == now * 10)
1000                                 ? "*" : "");
1001                 break;
1002 
1003         case SMU_SOCCLK:
1004                 ret = smu_get_current_clk_freq(smu, SMU_SOCCLK, &now);
1005                 if (ret) {
1006                         pr_err("Attempt to get current socclk Failed!");
1007                         return ret;
1008                 }
1009 
1010                 single_dpm_table = &(dpm_table->soc_table);
1011                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
1012                 if (ret) {
1013                         pr_err("Attempt to get socclk levels Failed!");
1014                         return ret;
1015                 }
1016 
1017                 for (i = 0; i < clocks.num_levels; i++)
1018                         size += sprintf(buf + size, "%d: %uMhz %s\n",
1019                                 i, clocks.data[i].clocks_in_khz / 1000,
1020                                 (clocks.data[i].clocks_in_khz == now * 10)
1021                                 ? "*" : "");
1022                 break;
1023 
1024         case SMU_FCLK:
1025                 ret = smu_get_current_clk_freq(smu, SMU_FCLK, &now);
1026                 if (ret) {
1027                         pr_err("Attempt to get current fclk Failed!");
1028                         return ret;
1029                 }
1030 
1031                 single_dpm_table = &(dpm_table->fclk_table);
1032                 for (i = 0; i < single_dpm_table->count; i++)
1033                         size += sprintf(buf + size, "%d: %uMhz %s\n",
1034                                 i, single_dpm_table->dpm_levels[i].value,
1035                                 (single_dpm_table->dpm_levels[i].value == now / 100)
1036                                 ? "*" : "");
1037                 break;
1038 
1039         case SMU_DCEFCLK:
1040                 ret = smu_get_current_clk_freq(smu, SMU_DCEFCLK, &now);
1041                 if (ret) {
1042                         pr_err("Attempt to get current dcefclk Failed!");
1043                         return ret;
1044                 }
1045 
1046                 single_dpm_table = &(dpm_table->dcef_table);
1047                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
1048                 if (ret) {
1049                         pr_err("Attempt to get dcefclk levels Failed!");
1050                         return ret;
1051                 }
1052 
1053                 for (i = 0; i < clocks.num_levels; i++)
1054                         size += sprintf(buf + size, "%d: %uMhz %s\n",
1055                                 i, clocks.data[i].clocks_in_khz / 1000,
1056                                 (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
1057                 break;
1058 
1059         case SMU_PCIE:
1060                 gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) &
1061                              PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK)
1062                         >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
1063                 lane_width = (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) &
1064                               PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK)
1065                         >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT;
1066                 for (i = 0; i < NUM_LINK_LEVELS; i++)
1067                         size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
1068                                         (pptable->PcieGenSpeed[i] == 0) ? "2.5GT/s," :
1069                                         (pptable->PcieGenSpeed[i] == 1) ? "5.0GT/s," :
1070                                         (pptable->PcieGenSpeed[i] == 2) ? "8.0GT/s," :
1071                                         (pptable->PcieGenSpeed[i] == 3) ? "16.0GT/s," : "",
1072                                         (pptable->PcieLaneCount[i] == 1) ? "x1" :
1073                                         (pptable->PcieLaneCount[i] == 2) ? "x2" :
1074                                         (pptable->PcieLaneCount[i] == 3) ? "x4" :
1075                                         (pptable->PcieLaneCount[i] == 4) ? "x8" :
1076                                         (pptable->PcieLaneCount[i] == 5) ? "x12" :
1077                                         (pptable->PcieLaneCount[i] == 6) ? "x16" : "",
1078                                         pptable->LclkFreq[i],
1079                                         (gen_speed == pptable->PcieGenSpeed[i]) &&
1080                                         (lane_width == pptable->PcieLaneCount[i]) ?
1081                                         "*" : "");
1082                 break;
1083 
1084         case SMU_OD_SCLK:
1085                 if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id &&
1086                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id) {
1087                         size = sprintf(buf, "%s:\n", "OD_SCLK");
1088                         size += sprintf(buf + size, "0: %10uMhz\n",
1089                                         od_table->GfxclkFmin);
1090                         size += sprintf(buf + size, "1: %10uMhz\n",
1091                                         od_table->GfxclkFmax);
1092                 }
1093 
1094                 break;
1095 
1096         case SMU_OD_MCLK:
1097                 if (od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) {
1098                         size = sprintf(buf, "%s:\n", "OD_MCLK");
1099                         size += sprintf(buf + size, "1: %10uMhz\n",
1100                                          od_table->UclkFmax);
1101                 }
1102 
1103                 break;
1104 
1105         case SMU_OD_VDDC_CURVE:
1106                 if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
1107                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
1108                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
1109                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
1110                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
1111                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
1112                         size = sprintf(buf, "%s:\n", "OD_VDDC_CURVE");
1113                         size += sprintf(buf + size, "0: %10uMhz %10dmV\n",
1114                                         od_table->GfxclkFreq1,
1115                                         od_table->GfxclkVolt1 / VOLTAGE_SCALE);
1116                         size += sprintf(buf + size, "1: %10uMhz %10dmV\n",
1117                                         od_table->GfxclkFreq2,
1118                                         od_table->GfxclkVolt2 / VOLTAGE_SCALE);
1119                         size += sprintf(buf + size, "2: %10uMhz %10dmV\n",
1120                                         od_table->GfxclkFreq3,
1121                                         od_table->GfxclkVolt3 / VOLTAGE_SCALE);
1122                 }
1123 
1124                 break;
1125 
1126         case SMU_OD_RANGE:
1127                 size = sprintf(buf, "%s:\n", "OD_RANGE");
1128 
1129                 if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id &&
1130                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id) {
1131                         size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
1132                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value,
1133                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value);
1134                 }
1135 
1136                 if (od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) {
1137                         single_dpm_table = &(dpm_table->mem_table);
1138                         ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
1139                         if (ret) {
1140                                 pr_err("Attempt to get memory clk levels Failed!");
1141                                 return ret;
1142                         }
1143 
1144                         size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
1145                                         clocks.data[0].clocks_in_khz / 1000,
1146                                         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value);
1147                 }
1148 
1149                 if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
1150                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
1151                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
1152                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
1153                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
1154                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
1155                         size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
1156                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].min_value,
1157                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].max_value);
1158                         size += sprintf(buf + size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n",
1159                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].min_value,
1160                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].max_value);
1161                         size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
1162                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].min_value,
1163                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].max_value);
1164                         size += sprintf(buf + size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n",
1165                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].min_value,
1166                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].max_value);
1167                         size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
1168                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].min_value,
1169                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].max_value);
1170                         size += sprintf(buf + size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
1171                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].min_value,
1172                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].max_value);
1173                 }
1174 
1175                 break;
1176 
1177         default:
1178                 break;
1179         }
1180         return size;
1181 }
1182 
1183 static int vega20_upload_dpm_level(struct smu_context *smu, bool max,
1184                                    uint32_t feature_mask)
1185 {
1186         struct vega20_dpm_table *dpm_table;
1187         struct vega20_single_dpm_table *single_dpm_table;
1188         uint32_t freq;
1189         int ret = 0;
1190 
1191         dpm_table = smu->smu_dpm.dpm_context;
1192 
1193         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT) &&
1194             (feature_mask & FEATURE_DPM_GFXCLK_MASK)) {
1195                 single_dpm_table = &(dpm_table->gfx_table);
1196                 freq = max ? single_dpm_table->dpm_state.soft_max_level :
1197                         single_dpm_table->dpm_state.soft_min_level;
1198                 ret = smu_send_smc_msg_with_param(smu,
1199                         (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
1200                         (PPCLK_GFXCLK << 16) | (freq & 0xffff));
1201                 if (ret) {
1202                         pr_err("Failed to set soft %s gfxclk !\n",
1203                                                 max ? "max" : "min");
1204                         return ret;
1205                 }
1206         }
1207 
1208         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT) &&
1209             (feature_mask & FEATURE_DPM_UCLK_MASK)) {
1210                 single_dpm_table = &(dpm_table->mem_table);
1211                 freq = max ? single_dpm_table->dpm_state.soft_max_level :
1212                         single_dpm_table->dpm_state.soft_min_level;
1213                 ret = smu_send_smc_msg_with_param(smu,
1214                         (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
1215                         (PPCLK_UCLK << 16) | (freq & 0xffff));
1216                 if (ret) {
1217                         pr_err("Failed to set soft %s memclk !\n",
1218                                                 max ? "max" : "min");
1219                         return ret;
1220                 }
1221         }
1222 
1223         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT) &&
1224             (feature_mask & FEATURE_DPM_SOCCLK_MASK)) {
1225                 single_dpm_table = &(dpm_table->soc_table);
1226                 freq = max ? single_dpm_table->dpm_state.soft_max_level :
1227                         single_dpm_table->dpm_state.soft_min_level;
1228                 ret = smu_send_smc_msg_with_param(smu,
1229                         (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
1230                         (PPCLK_SOCCLK << 16) | (freq & 0xffff));
1231                 if (ret) {
1232                         pr_err("Failed to set soft %s socclk !\n",
1233                                                 max ? "max" : "min");
1234                         return ret;
1235                 }
1236         }
1237 
1238         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT) &&
1239             (feature_mask & FEATURE_DPM_FCLK_MASK)) {
1240                 single_dpm_table = &(dpm_table->fclk_table);
1241                 freq = max ? single_dpm_table->dpm_state.soft_max_level :
1242                         single_dpm_table->dpm_state.soft_min_level;
1243                 ret = smu_send_smc_msg_with_param(smu,
1244                         (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
1245                         (PPCLK_FCLK << 16) | (freq & 0xffff));
1246                 if (ret) {
1247                         pr_err("Failed to set soft %s fclk !\n",
1248                                                 max ? "max" : "min");
1249                         return ret;
1250                 }
1251         }
1252 
1253         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
1254             (feature_mask & FEATURE_DPM_DCEFCLK_MASK)) {
1255                 single_dpm_table = &(dpm_table->dcef_table);
1256                 freq = single_dpm_table->dpm_state.hard_min_level;
1257                 if (!max) {
1258                         ret = smu_send_smc_msg_with_param(smu,
1259                                 SMU_MSG_SetHardMinByFreq,
1260                                 (PPCLK_DCEFCLK << 16) | (freq & 0xffff));
1261                         if (ret) {
1262                                 pr_err("Failed to set hard min dcefclk !\n");
1263                                 return ret;
1264                         }
1265                 }
1266         }
1267 
1268         return ret;
1269 }
1270 
1271 static int vega20_force_clk_levels(struct smu_context *smu,
1272                         enum  smu_clk_type clk_type, uint32_t mask)
1273 {
1274         struct vega20_dpm_table *dpm_table;
1275         struct vega20_single_dpm_table *single_dpm_table;
1276         uint32_t soft_min_level, soft_max_level, hard_min_level;
1277         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
1278         int ret = 0;
1279 
1280         if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) {
1281                 pr_info("force clock level is for dpm manual mode only.\n");
1282                 return -EINVAL;
1283         }
1284 
1285         mutex_lock(&(smu->mutex));
1286 
1287         soft_min_level = mask ? (ffs(mask) - 1) : 0;
1288         soft_max_level = mask ? (fls(mask) - 1) : 0;
1289 
1290         dpm_table = smu->smu_dpm.dpm_context;
1291 
1292         switch (clk_type) {
1293         case SMU_SCLK:
1294                 single_dpm_table = &(dpm_table->gfx_table);
1295 
1296                 if (soft_max_level >= single_dpm_table->count) {
1297                         pr_err("Clock level specified %d is over max allowed %d\n",
1298                                         soft_max_level, single_dpm_table->count - 1);
1299                         ret = -EINVAL;
1300                         break;
1301                 }
1302 
1303                 single_dpm_table->dpm_state.soft_min_level =
1304                         single_dpm_table->dpm_levels[soft_min_level].value;
1305                 single_dpm_table->dpm_state.soft_max_level =
1306                         single_dpm_table->dpm_levels[soft_max_level].value;
1307 
1308                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_GFXCLK_MASK);
1309                 if (ret) {
1310                         pr_err("Failed to upload boot level to lowest!\n");
1311                         break;
1312                 }
1313 
1314                 ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_GFXCLK_MASK);
1315                 if (ret)
1316                         pr_err("Failed to upload dpm max level to highest!\n");
1317 
1318                 break;
1319 
1320         case SMU_MCLK:
1321                 single_dpm_table = &(dpm_table->mem_table);
1322 
1323                 if (soft_max_level >= single_dpm_table->count) {
1324                         pr_err("Clock level specified %d is over max allowed %d\n",
1325                                         soft_max_level, single_dpm_table->count - 1);
1326                         ret = -EINVAL;
1327                         break;
1328                 }
1329 
1330                 single_dpm_table->dpm_state.soft_min_level =
1331                         single_dpm_table->dpm_levels[soft_min_level].value;
1332                 single_dpm_table->dpm_state.soft_max_level =
1333                         single_dpm_table->dpm_levels[soft_max_level].value;
1334 
1335                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_UCLK_MASK);
1336                 if (ret) {
1337                         pr_err("Failed to upload boot level to lowest!\n");
1338                         break;
1339                 }
1340 
1341                 ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_UCLK_MASK);
1342                 if (ret)
1343                         pr_err("Failed to upload dpm max level to highest!\n");
1344 
1345                 break;
1346 
1347         case SMU_SOCCLK:
1348                 single_dpm_table = &(dpm_table->soc_table);
1349 
1350                 if (soft_max_level >= single_dpm_table->count) {
1351                         pr_err("Clock level specified %d is over max allowed %d\n",
1352                                         soft_max_level, single_dpm_table->count - 1);
1353                         ret = -EINVAL;
1354                         break;
1355                 }
1356 
1357                 single_dpm_table->dpm_state.soft_min_level =
1358                         single_dpm_table->dpm_levels[soft_min_level].value;
1359                 single_dpm_table->dpm_state.soft_max_level =
1360                         single_dpm_table->dpm_levels[soft_max_level].value;
1361 
1362                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_SOCCLK_MASK);
1363                 if (ret) {
1364                         pr_err("Failed to upload boot level to lowest!\n");
1365                         break;
1366                 }
1367 
1368                 ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_SOCCLK_MASK);
1369                 if (ret)
1370                         pr_err("Failed to upload dpm max level to highest!\n");
1371 
1372                 break;
1373 
1374         case SMU_FCLK:
1375                 single_dpm_table = &(dpm_table->fclk_table);
1376 
1377                 if (soft_max_level >= single_dpm_table->count) {
1378                         pr_err("Clock level specified %d is over max allowed %d\n",
1379                                         soft_max_level, single_dpm_table->count - 1);
1380                         ret = -EINVAL;
1381                         break;
1382                 }
1383 
1384                 single_dpm_table->dpm_state.soft_min_level =
1385                         single_dpm_table->dpm_levels[soft_min_level].value;
1386                 single_dpm_table->dpm_state.soft_max_level =
1387                         single_dpm_table->dpm_levels[soft_max_level].value;
1388 
1389                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_FCLK_MASK);
1390                 if (ret) {
1391                         pr_err("Failed to upload boot level to lowest!\n");
1392                         break;
1393                 }
1394 
1395                 ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_FCLK_MASK);
1396                 if (ret)
1397                         pr_err("Failed to upload dpm max level to highest!\n");
1398 
1399                 break;
1400 
1401         case SMU_DCEFCLK:
1402                 hard_min_level = soft_min_level;
1403                 single_dpm_table = &(dpm_table->dcef_table);
1404 
1405                 if (hard_min_level >= single_dpm_table->count) {
1406                         pr_err("Clock level specified %d is over max allowed %d\n",
1407                                         hard_min_level, single_dpm_table->count - 1);
1408                         ret = -EINVAL;
1409                         break;
1410                 }
1411 
1412                 single_dpm_table->dpm_state.hard_min_level =
1413                         single_dpm_table->dpm_levels[hard_min_level].value;
1414 
1415                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_DCEFCLK_MASK);
1416                 if (ret)
1417                         pr_err("Failed to upload boot level to lowest!\n");
1418 
1419                 break;
1420 
1421         case SMU_PCIE:
1422                 if (soft_min_level >= NUM_LINK_LEVELS ||
1423                     soft_max_level >= NUM_LINK_LEVELS) {
1424                         ret = -EINVAL;
1425                         break;
1426                 }
1427 
1428                 ret = smu_send_smc_msg_with_param(smu,
1429                                 SMU_MSG_SetMinLinkDpmByIndex, soft_min_level);
1430                 if (ret)
1431                         pr_err("Failed to set min link dpm level!\n");
1432 
1433                 break;
1434 
1435         default:
1436                 break;
1437         }
1438 
1439         mutex_unlock(&(smu->mutex));
1440         return ret;
1441 }
1442 
1443 static int vega20_get_clock_by_type_with_latency(struct smu_context *smu,
1444                                                  enum smu_clk_type clk_type,
1445                                                  struct pp_clock_levels_with_latency *clocks)
1446 {
1447         int ret;
1448         struct vega20_single_dpm_table *single_dpm_table;
1449         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
1450         struct vega20_dpm_table *dpm_table = NULL;
1451 
1452         dpm_table = smu_dpm->dpm_context;
1453 
1454         mutex_lock(&smu->mutex);
1455 
1456         switch (clk_type) {
1457         case SMU_GFXCLK:
1458                 single_dpm_table = &(dpm_table->gfx_table);
1459                 ret = vega20_get_clk_table(smu, clocks, single_dpm_table);
1460                 break;
1461         case SMU_MCLK:
1462                 single_dpm_table = &(dpm_table->mem_table);
1463                 ret = vega20_get_clk_table(smu, clocks, single_dpm_table);
1464                 break;
1465         case SMU_DCEFCLK:
1466                 single_dpm_table = &(dpm_table->dcef_table);
1467                 ret = vega20_get_clk_table(smu, clocks, single_dpm_table);
1468                 break;
1469         case SMU_SOCCLK:
1470                 single_dpm_table = &(dpm_table->soc_table);
1471                 ret = vega20_get_clk_table(smu, clocks, single_dpm_table);
1472                 break;
1473         default:
1474                 ret = -EINVAL;
1475         }
1476 
1477         mutex_unlock(&smu->mutex);
1478         return ret;
1479 }
1480 
1481 static int vega20_overdrive_get_gfx_clk_base_voltage(struct smu_context *smu,
1482                                                      uint32_t *voltage,
1483                                                      uint32_t freq)
1484 {
1485         int ret;
1486 
1487         ret = smu_send_smc_msg_with_param(smu,
1488                         SMU_MSG_GetAVFSVoltageByDpm,
1489                         ((AVFS_CURVE << 24) | (OD8_HOTCURVE_TEMPERATURE << 16) | freq));
1490         if (ret) {
1491                 pr_err("[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!");
1492                 return ret;
1493         }
1494 
1495         smu_read_smc_arg(smu, voltage);
1496         *voltage = *voltage / VOLTAGE_SCALE;
1497 
1498         return 0;
1499 }
1500 
1501 static int vega20_set_default_od8_setttings(struct smu_context *smu)
1502 {
1503         struct smu_table_context *table_context = &smu->smu_table;
1504         OverDriveTable_t *od_table = (OverDriveTable_t *)(table_context->overdrive_table);
1505         struct vega20_od8_settings *od8_settings = NULL;
1506         PPTable_t *smc_pptable = table_context->driver_pptable;
1507         int i, ret;
1508 
1509         if (smu->od_settings)
1510                 return -EINVAL;
1511 
1512         od8_settings = kzalloc(sizeof(struct vega20_od8_settings), GFP_KERNEL);
1513 
1514         if (!od8_settings)
1515                 return -ENOMEM;
1516 
1517         smu->od_settings = (void *)od8_settings;
1518 
1519         ret = vega20_setup_od8_information(smu);
1520         if (ret) {
1521                 pr_err("Retrieve board OD limits failed!\n");
1522                 return ret;
1523         }
1524 
1525         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
1526                 if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_LIMITS] &&
1527                     od8_settings->od_settings_max[OD8_SETTING_GFXCLK_FMAX] > 0 &&
1528                     od8_settings->od_settings_min[OD8_SETTING_GFXCLK_FMIN] > 0 &&
1529                     (od8_settings->od_settings_max[OD8_SETTING_GFXCLK_FMAX] >=
1530                      od8_settings->od_settings_min[OD8_SETTING_GFXCLK_FMIN])) {
1531                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id =
1532                                 OD8_GFXCLK_LIMITS;
1533                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id =
1534                                 OD8_GFXCLK_LIMITS;
1535                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value =
1536                                 od_table->GfxclkFmin;
1537                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value =
1538                                 od_table->GfxclkFmax;
1539                 }
1540 
1541                 if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_CURVE] &&
1542                     (od8_settings->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] >=
1543                      smc_pptable->MinVoltageGfx / VOLTAGE_SCALE) &&
1544                     (od8_settings->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3] <=
1545                      smc_pptable->MaxVoltageGfx / VOLTAGE_SCALE) &&
1546                     (od8_settings->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] <=
1547                      od8_settings->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3])) {
1548                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id =
1549                                 OD8_GFXCLK_CURVE;
1550                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id =
1551                                 OD8_GFXCLK_CURVE;
1552                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id =
1553                                 OD8_GFXCLK_CURVE;
1554                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id =
1555                                 OD8_GFXCLK_CURVE;
1556                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id =
1557                                 OD8_GFXCLK_CURVE;
1558                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id =
1559                                 OD8_GFXCLK_CURVE;
1560 
1561                         od_table->GfxclkFreq1 = od_table->GfxclkFmin;
1562                         od_table->GfxclkFreq2 = (od_table->GfxclkFmin + od_table->GfxclkFmax) / 2;
1563                         od_table->GfxclkFreq3 = od_table->GfxclkFmax;
1564                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value =
1565                                 od_table->GfxclkFreq1;
1566                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value =
1567                                 od_table->GfxclkFreq2;
1568                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value =
1569                                 od_table->GfxclkFreq3;
1570 
1571                         ret = vega20_overdrive_get_gfx_clk_base_voltage(smu,
1572                                 &od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value,
1573                                 od_table->GfxclkFreq1);
1574                         if (ret)
1575                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value = 0;
1576                         od_table->GfxclkVolt1 =
1577                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value
1578                                 * VOLTAGE_SCALE;
1579                         ret = vega20_overdrive_get_gfx_clk_base_voltage(smu,
1580                                 &od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value,
1581                                 od_table->GfxclkFreq2);
1582                         if (ret)
1583                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value = 0;
1584                         od_table->GfxclkVolt2 =
1585                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value
1586                                 * VOLTAGE_SCALE;
1587                         ret = vega20_overdrive_get_gfx_clk_base_voltage(smu,
1588                                 &od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value,
1589                                 od_table->GfxclkFreq3);
1590                         if (ret)
1591                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value = 0;
1592                         od_table->GfxclkVolt3 =
1593                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value
1594                                 * VOLTAGE_SCALE;
1595                 }
1596         }
1597 
1598         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
1599                 if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_UCLK_MAX] &&
1600                     od8_settings->od_settings_min[OD8_SETTING_UCLK_FMAX] > 0 &&
1601                     od8_settings->od_settings_max[OD8_SETTING_UCLK_FMAX] > 0 &&
1602                     (od8_settings->od_settings_max[OD8_SETTING_UCLK_FMAX] >=
1603                      od8_settings->od_settings_min[OD8_SETTING_UCLK_FMAX])) {
1604                         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id =
1605                                 OD8_UCLK_MAX;
1606                         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value =
1607                                 od_table->UclkFmax;
1608                 }
1609         }
1610 
1611         if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_POWER_LIMIT] &&
1612             od8_settings->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
1613             od8_settings->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] <= 100 &&
1614             od8_settings->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
1615             od8_settings->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] <= 100) {
1616                 od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id =
1617                         OD8_POWER_LIMIT;
1618                 od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value =
1619                         od_table->OverDrivePct;
1620         }
1621 
1622         if (smu_feature_is_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT)) {
1623                 if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_ACOUSTIC_LIMIT] &&
1624                     od8_settings->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 &&
1625                     od8_settings->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 &&
1626                     (od8_settings->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] >=
1627                      od8_settings->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT])) {
1628                         od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id =
1629                                 OD8_ACOUSTIC_LIMIT_SCLK;
1630                         od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value =
1631                                 od_table->FanMaximumRpm;
1632                 }
1633 
1634                 if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_SPEED_MIN] &&
1635                     od8_settings->od_settings_min[OD8_SETTING_FAN_MIN_SPEED] > 0 &&
1636                     od8_settings->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] > 0 &&
1637                     (od8_settings->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] >=
1638                      od8_settings->od_settings_min[OD8_SETTING_FAN_MIN_SPEED])) {
1639                         od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id =
1640                                 OD8_FAN_SPEED_MIN;
1641                         od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value =
1642                                 od_table->FanMinimumPwm * smc_pptable->FanMaximumRpm / 100;
1643                 }
1644         }
1645 
1646         if (smu_feature_is_enabled(smu, SMU_FEATURE_THERMAL_BIT)) {
1647                 if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_FAN] &&
1648                     od8_settings->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP] > 0 &&
1649                     od8_settings->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] > 0 &&
1650                     (od8_settings->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] >=
1651                      od8_settings->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP])) {
1652                         od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id =
1653                                 OD8_TEMPERATURE_FAN;
1654                         od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value =
1655                                 od_table->FanTargetTemperature;
1656                 }
1657 
1658                 if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_SYSTEM] &&
1659                     od8_settings->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX] > 0 &&
1660                     od8_settings->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] > 0 &&
1661                     (od8_settings->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] >=
1662                      od8_settings->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX])) {
1663                         od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id =
1664                                 OD8_TEMPERATURE_SYSTEM;
1665                         od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_value =
1666                                 od_table->MaxOpTemp;
1667                 }
1668         }
1669 
1670         for (i = 0; i < OD8_SETTING_COUNT; i++) {
1671                 if (od8_settings->od8_settings_array[i].feature_id) {
1672                         od8_settings->od8_settings_array[i].min_value =
1673                                 od8_settings->od_settings_min[i];
1674                         od8_settings->od8_settings_array[i].max_value =
1675                                 od8_settings->od_settings_max[i];
1676                         od8_settings->od8_settings_array[i].current_value =
1677                                 od8_settings->od8_settings_array[i].default_value;
1678                 } else {
1679                         od8_settings->od8_settings_array[i].min_value = 0;
1680                         od8_settings->od8_settings_array[i].max_value = 0;
1681                         od8_settings->od8_settings_array[i].current_value = 0;
1682                 }
1683         }
1684 
1685         return 0;
1686 }
1687 
1688 static int vega20_get_metrics_table(struct smu_context *smu,
1689                                     SmuMetrics_t *metrics_table)
1690 {
1691         struct smu_table_context *smu_table= &smu->smu_table;
1692         int ret = 0;
1693 
1694         mutex_lock(&smu->metrics_lock);
1695         if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + HZ / 1000)) {
1696                 ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0,
1697                                 (void *)smu_table->metrics_table, false);
1698                 if (ret) {
1699                         pr_info("Failed to export SMU metrics table!\n");
1700                         mutex_unlock(&smu->metrics_lock);
1701                         return ret;
1702                 }
1703                 smu_table->metrics_time = jiffies;
1704         }
1705 
1706         memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t));
1707         mutex_unlock(&smu->metrics_lock);
1708 
1709         return ret;
1710 }
1711 
1712 static int vega20_set_default_od_settings(struct smu_context *smu,
1713                                           bool initialize)
1714 {
1715         struct smu_table_context *table_context = &smu->smu_table;
1716         int ret;
1717 
1718         if (initialize) {
1719                 if (table_context->overdrive_table)
1720                         return -EINVAL;
1721 
1722                 table_context->overdrive_table = kzalloc(sizeof(OverDriveTable_t), GFP_KERNEL);
1723 
1724                 if (!table_context->overdrive_table)
1725                         return -ENOMEM;
1726 
1727                 ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0,
1728                                        table_context->overdrive_table, false);
1729                 if (ret) {
1730                         pr_err("Failed to export over drive table!\n");
1731                         return ret;
1732                 }
1733 
1734                 ret = vega20_set_default_od8_setttings(smu);
1735                 if (ret)
1736                         return ret;
1737         }
1738 
1739         ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0,
1740                                table_context->overdrive_table, true);
1741         if (ret) {
1742                 pr_err("Failed to import over drive table!\n");
1743                 return ret;
1744         }
1745 
1746         return 0;
1747 }
1748 
1749 static int vega20_get_od_percentage(struct smu_context *smu,
1750                                     enum smu_clk_type clk_type)
1751 {
1752         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
1753         struct vega20_dpm_table *dpm_table = NULL;
1754         struct vega20_dpm_table *golden_table = NULL;
1755         struct vega20_single_dpm_table *single_dpm_table;
1756         struct vega20_single_dpm_table *golden_dpm_table;
1757         int value, golden_value;
1758 
1759         dpm_table = smu_dpm->dpm_context;
1760         golden_table = smu_dpm->golden_dpm_context;
1761 
1762         switch (clk_type) {
1763         case SMU_OD_SCLK:
1764                 single_dpm_table = &(dpm_table->gfx_table);
1765                 golden_dpm_table = &(golden_table->gfx_table);
1766                 break;
1767         case SMU_OD_MCLK:
1768                 single_dpm_table = &(dpm_table->mem_table);
1769                 golden_dpm_table = &(golden_table->mem_table);
1770                 break;
1771         default:
1772                 return -EINVAL;
1773                 break;
1774         }
1775 
1776         value = single_dpm_table->dpm_levels[single_dpm_table->count - 1].value;
1777         golden_value = golden_dpm_table->dpm_levels[golden_dpm_table->count - 1].value;
1778 
1779         value -= golden_value;
1780         value = DIV_ROUND_UP(value * 100, golden_value);
1781 
1782         return value;
1783 }
1784 
1785 static int vega20_get_power_profile_mode(struct smu_context *smu, char *buf)
1786 {
1787         DpmActivityMonitorCoeffInt_t activity_monitor;
1788         uint32_t i, size = 0;
1789         int16_t workload_type = 0;
1790         static const char *profile_name[] = {
1791                                         "BOOTUP_DEFAULT",
1792                                         "3D_FULL_SCREEN",
1793                                         "POWER_SAVING",
1794                                         "VIDEO",
1795                                         "VR",
1796                                         "COMPUTE",
1797                                         "CUSTOM"};
1798         static const char *title[] = {
1799                         "PROFILE_INDEX(NAME)",
1800                         "CLOCK_TYPE(NAME)",
1801                         "FPS",
1802                         "UseRlcBusy",
1803                         "MinActiveFreqType",
1804                         "MinActiveFreq",
1805                         "BoosterFreqType",
1806                         "BoosterFreq",
1807                         "PD_Data_limit_c",
1808                         "PD_Data_error_coeff",
1809                         "PD_Data_error_rate_coeff"};
1810         int result = 0;
1811 
1812         if (!smu->pm_enabled || !buf)
1813                 return -EINVAL;
1814 
1815         size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
1816                         title[0], title[1], title[2], title[3], title[4], title[5],
1817                         title[6], title[7], title[8], title[9], title[10]);
1818 
1819         for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
1820                 /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
1821                 workload_type = smu_workload_get_type(smu, i);
1822                 if (workload_type < 0)
1823                         return -EINVAL;
1824 
1825                 result = smu_update_table(smu,
1826                                           SMU_TABLE_ACTIVITY_MONITOR_COEFF, workload_type,
1827                                           (void *)(&activity_monitor), false);
1828                 if (result) {
1829                         pr_err("[%s] Failed to get activity monitor!", __func__);
1830                         return result;
1831                 }
1832 
1833                 size += sprintf(buf + size, "%2d %14s%s:\n",
1834                         i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");
1835 
1836                 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
1837                         " ",
1838                         0,
1839                         "GFXCLK",
1840                         activity_monitor.Gfx_FPS,
1841                         activity_monitor.Gfx_UseRlcBusy,
1842                         activity_monitor.Gfx_MinActiveFreqType,
1843                         activity_monitor.Gfx_MinActiveFreq,
1844                         activity_monitor.Gfx_BoosterFreqType,
1845                         activity_monitor.Gfx_BoosterFreq,
1846                         activity_monitor.Gfx_PD_Data_limit_c,
1847                         activity_monitor.Gfx_PD_Data_error_coeff,
1848                         activity_monitor.Gfx_PD_Data_error_rate_coeff);
1849 
1850                 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
1851                         " ",
1852                         1,
1853                         "SOCCLK",
1854                         activity_monitor.Soc_FPS,
1855                         activity_monitor.Soc_UseRlcBusy,
1856                         activity_monitor.Soc_MinActiveFreqType,
1857                         activity_monitor.Soc_MinActiveFreq,
1858                         activity_monitor.Soc_BoosterFreqType,
1859                         activity_monitor.Soc_BoosterFreq,
1860                         activity_monitor.Soc_PD_Data_limit_c,
1861                         activity_monitor.Soc_PD_Data_error_coeff,
1862                         activity_monitor.Soc_PD_Data_error_rate_coeff);
1863 
1864                 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
1865                         " ",
1866                         2,
1867                         "UCLK",
1868                         activity_monitor.Mem_FPS,
1869                         activity_monitor.Mem_UseRlcBusy,
1870                         activity_monitor.Mem_MinActiveFreqType,
1871                         activity_monitor.Mem_MinActiveFreq,
1872                         activity_monitor.Mem_BoosterFreqType,
1873                         activity_monitor.Mem_BoosterFreq,
1874                         activity_monitor.Mem_PD_Data_limit_c,
1875                         activity_monitor.Mem_PD_Data_error_coeff,
1876                         activity_monitor.Mem_PD_Data_error_rate_coeff);
1877 
1878                 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
1879                         " ",
1880                         3,
1881                         "FCLK",
1882                         activity_monitor.Fclk_FPS,
1883                         activity_monitor.Fclk_UseRlcBusy,
1884                         activity_monitor.Fclk_MinActiveFreqType,
1885                         activity_monitor.Fclk_MinActiveFreq,
1886                         activity_monitor.Fclk_BoosterFreqType,
1887                         activity_monitor.Fclk_BoosterFreq,
1888                         activity_monitor.Fclk_PD_Data_limit_c,
1889                         activity_monitor.Fclk_PD_Data_error_coeff,
1890                         activity_monitor.Fclk_PD_Data_error_rate_coeff);
1891         }
1892 
1893         return size;
1894 }
1895 
1896 static int vega20_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
1897 {
1898         DpmActivityMonitorCoeffInt_t activity_monitor;
1899         int workload_type = 0, ret = 0;
1900 
1901         smu->power_profile_mode = input[size];
1902 
1903         if (!smu->pm_enabled)
1904                 return ret;
1905         if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
1906                 pr_err("Invalid power profile mode %d\n", smu->power_profile_mode);
1907                 return -EINVAL;
1908         }
1909 
1910         if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
1911                 ret = smu_update_table(smu,
1912                                        SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
1913                                        (void *)(&activity_monitor), false);
1914                 if (ret) {
1915                         pr_err("[%s] Failed to get activity monitor!", __func__);
1916                         return ret;
1917                 }
1918 
1919                 switch (input[0]) {
1920                 case 0: /* Gfxclk */
1921                         activity_monitor.Gfx_FPS = input[1];
1922                         activity_monitor.Gfx_UseRlcBusy = input[2];
1923                         activity_monitor.Gfx_MinActiveFreqType = input[3];
1924                         activity_monitor.Gfx_MinActiveFreq = input[4];
1925                         activity_monitor.Gfx_BoosterFreqType = input[5];
1926                         activity_monitor.Gfx_BoosterFreq = input[6];
1927                         activity_monitor.Gfx_PD_Data_limit_c = input[7];
1928                         activity_monitor.Gfx_PD_Data_error_coeff = input[8];
1929                         activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
1930                         break;
1931                 case 1: /* Socclk */
1932                         activity_monitor.Soc_FPS = input[1];
1933                         activity_monitor.Soc_UseRlcBusy = input[2];
1934                         activity_monitor.Soc_MinActiveFreqType = input[3];
1935                         activity_monitor.Soc_MinActiveFreq = input[4];
1936                         activity_monitor.Soc_BoosterFreqType = input[5];
1937                         activity_monitor.Soc_BoosterFreq = input[6];
1938                         activity_monitor.Soc_PD_Data_limit_c = input[7];
1939                         activity_monitor.Soc_PD_Data_error_coeff = input[8];
1940                         activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
1941                         break;
1942                 case 2: /* Uclk */
1943                         activity_monitor.Mem_FPS = input[1];
1944                         activity_monitor.Mem_UseRlcBusy = input[2];
1945                         activity_monitor.Mem_MinActiveFreqType = input[3];
1946                         activity_monitor.Mem_MinActiveFreq = input[4];
1947                         activity_monitor.Mem_BoosterFreqType = input[5];
1948                         activity_monitor.Mem_BoosterFreq = input[6];
1949                         activity_monitor.Mem_PD_Data_limit_c = input[7];
1950                         activity_monitor.Mem_PD_Data_error_coeff = input[8];
1951                         activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
1952                         break;
1953                 case 3: /* Fclk */
1954                         activity_monitor.Fclk_FPS = input[1];
1955                         activity_monitor.Fclk_UseRlcBusy = input[2];
1956                         activity_monitor.Fclk_MinActiveFreqType = input[3];
1957                         activity_monitor.Fclk_MinActiveFreq = input[4];
1958                         activity_monitor.Fclk_BoosterFreqType = input[5];
1959                         activity_monitor.Fclk_BoosterFreq = input[6];
1960                         activity_monitor.Fclk_PD_Data_limit_c = input[7];
1961                         activity_monitor.Fclk_PD_Data_error_coeff = input[8];
1962                         activity_monitor.Fclk_PD_Data_error_rate_coeff = input[9];
1963                         break;
1964                 }
1965 
1966                 ret = smu_update_table(smu,
1967                                        SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
1968                                        (void *)(&activity_monitor), true);
1969                 if (ret) {
1970                         pr_err("[%s] Failed to set activity monitor!", __func__);
1971                         return ret;
1972                 }
1973         }
1974 
1975         /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
1976         workload_type = smu_workload_get_type(smu, smu->power_profile_mode);
1977         if (workload_type < 0)
1978                 return -EINVAL;
1979         smu_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
1980                                     1 << workload_type);
1981 
1982         return ret;
1983 }
1984 
1985 static int
1986 vega20_get_profiling_clk_mask(struct smu_context *smu,
1987                               enum amd_dpm_forced_level level,
1988                               uint32_t *sclk_mask,
1989                               uint32_t *mclk_mask,
1990                               uint32_t *soc_mask)
1991 {
1992         struct vega20_dpm_table *dpm_table = (struct vega20_dpm_table *)smu->smu_dpm.dpm_context;
1993         struct vega20_single_dpm_table *gfx_dpm_table;
1994         struct vega20_single_dpm_table *mem_dpm_table;
1995         struct vega20_single_dpm_table *soc_dpm_table;
1996 
1997         if (!smu->smu_dpm.dpm_context)
1998                 return -EINVAL;
1999 
2000         gfx_dpm_table = &dpm_table->gfx_table;
2001         mem_dpm_table = &dpm_table->mem_table;
2002         soc_dpm_table = &dpm_table->soc_table;
2003 
2004         *sclk_mask = 0;
2005         *mclk_mask = 0;
2006         *soc_mask  = 0;
2007 
2008         if (gfx_dpm_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
2009             mem_dpm_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL &&
2010             soc_dpm_table->count > VEGA20_UMD_PSTATE_SOCCLK_LEVEL) {
2011                 *sclk_mask = VEGA20_UMD_PSTATE_GFXCLK_LEVEL;
2012                 *mclk_mask = VEGA20_UMD_PSTATE_MCLK_LEVEL;
2013                 *soc_mask  = VEGA20_UMD_PSTATE_SOCCLK_LEVEL;
2014         }
2015 
2016         if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
2017                 *sclk_mask = 0;
2018         } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
2019                 *mclk_mask = 0;
2020         } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2021                 *sclk_mask = gfx_dpm_table->count - 1;
2022                 *mclk_mask = mem_dpm_table->count - 1;
2023                 *soc_mask  = soc_dpm_table->count - 1;
2024         }
2025 
2026         return 0;
2027 }
2028 
2029 static int
2030 vega20_set_uclk_to_highest_dpm_level(struct smu_context *smu,
2031                                      struct vega20_single_dpm_table *dpm_table)
2032 {
2033         int ret = 0;
2034         struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
2035         if (!smu_dpm_ctx->dpm_context)
2036                 return -EINVAL;
2037 
2038         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
2039                 if (dpm_table->count <= 0) {
2040                         pr_err("[%s] Dpm table has no entry!", __func__);
2041                                 return -EINVAL;
2042                 }
2043 
2044                 if (dpm_table->count > NUM_UCLK_DPM_LEVELS) {
2045                         pr_err("[%s] Dpm table has too many entries!", __func__);
2046                                 return -EINVAL;
2047                 }
2048 
2049                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2050                 ret = smu_send_smc_msg_with_param(smu,
2051                                 SMU_MSG_SetHardMinByFreq,
2052                                 (PPCLK_UCLK << 16) | dpm_table->dpm_state.hard_min_level);
2053                 if (ret) {
2054                         pr_err("[%s] Set hard min uclk failed!", __func__);
2055                                 return ret;
2056                 }
2057         }
2058 
2059         return ret;
2060 }
2061 
2062 static int vega20_pre_display_config_changed(struct smu_context *smu)
2063 {
2064         int ret = 0;
2065         struct vega20_dpm_table *dpm_table = smu->smu_dpm.dpm_context;
2066 
2067         if (!smu->smu_dpm.dpm_context)
2068                 return -EINVAL;
2069 
2070         smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, 0);
2071         ret = vega20_set_uclk_to_highest_dpm_level(smu,
2072                                                    &dpm_table->mem_table);
2073         if (ret)
2074                 pr_err("Failed to set uclk to highest dpm level");
2075         return ret;
2076 }
2077 
2078 static int vega20_display_config_changed(struct smu_context *smu)
2079 {
2080         int ret = 0;
2081 
2082         if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
2083             !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
2084                 ret = smu_write_watermarks_table(smu);
2085                 if (ret) {
2086                         pr_err("Failed to update WMTABLE!");
2087                         return ret;
2088                 }
2089                 smu->watermarks_bitmap |= WATERMARKS_LOADED;
2090         }
2091 
2092         if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
2093             smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
2094             smu_feature_is_supported(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
2095                 smu_send_smc_msg_with_param(smu,
2096                                             SMU_MSG_NumOfDisplays,
2097                                             smu->display_config->num_display);
2098         }
2099 
2100         return ret;
2101 }
2102 
2103 static int vega20_apply_clocks_adjust_rules(struct smu_context *smu)
2104 {
2105         struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
2106         struct vega20_dpm_table *dpm_ctx = (struct vega20_dpm_table *)(smu_dpm_ctx->dpm_context);
2107         struct vega20_single_dpm_table *dpm_table;
2108         bool vblank_too_short = false;
2109         bool disable_mclk_switching;
2110         uint32_t i, latency;
2111 
2112         disable_mclk_switching = ((1 < smu->display_config->num_display) &&
2113                                   !smu->display_config->multi_monitor_in_sync) || vblank_too_short;
2114         latency = smu->display_config->dce_tolerable_mclk_in_active_latency;
2115 
2116         /* gfxclk */
2117         dpm_table = &(dpm_ctx->gfx_table);
2118         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2119         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2120         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2121         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2122 
2123                 if (VEGA20_UMD_PSTATE_GFXCLK_LEVEL < dpm_table->count) {
2124                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
2125                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
2126                 }
2127 
2128                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
2129                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2130                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
2131                 }
2132 
2133                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2134                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2135                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2136                 }
2137 
2138         /* memclk */
2139         dpm_table = &(dpm_ctx->mem_table);
2140         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2141         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2142         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2143         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2144 
2145                 if (VEGA20_UMD_PSTATE_MCLK_LEVEL < dpm_table->count) {
2146                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
2147                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
2148                 }
2149 
2150                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
2151                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2152                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
2153                 }
2154 
2155                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2156                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2157                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2158                 }
2159 
2160         /* honour DAL's UCLK Hardmin */
2161         if (dpm_table->dpm_state.hard_min_level < (smu->display_config->min_mem_set_clock / 100))
2162                 dpm_table->dpm_state.hard_min_level = smu->display_config->min_mem_set_clock / 100;
2163 
2164         /* Hardmin is dependent on displayconfig */
2165         if (disable_mclk_switching) {
2166                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2167                 for (i = 0; i < smu_dpm_ctx->mclk_latency_table->count - 1; i++) {
2168                         if (smu_dpm_ctx->mclk_latency_table->entries[i].latency <= latency) {
2169                                 if (dpm_table->dpm_levels[i].value >= (smu->display_config->min_mem_set_clock / 100)) {
2170                                         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[i].value;
2171                                         break;
2172                                 }
2173                         }
2174                 }
2175         }
2176 
2177         if (smu->display_config->nb_pstate_switch_disable)
2178                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2179 
2180         /* vclk */
2181         dpm_table = &(dpm_ctx->vclk_table);
2182         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2183         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2184         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2185         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2186 
2187                 if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
2188                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
2189                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
2190                 }
2191 
2192                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2193                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2194                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2195                 }
2196 
2197         /* dclk */
2198         dpm_table = &(dpm_ctx->dclk_table);
2199         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2200         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2201         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2202         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2203 
2204                 if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
2205                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
2206                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
2207                 }
2208 
2209                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2210                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2211                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2212                 }
2213 
2214         /* socclk */
2215         dpm_table = &(dpm_ctx->soc_table);
2216         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2217         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2218         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2219         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2220 
2221                 if (VEGA20_UMD_PSTATE_SOCCLK_LEVEL < dpm_table->count) {
2222                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
2223                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
2224                 }
2225 
2226                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2227                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2228                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2229                 }
2230 
2231         /* eclk */
2232         dpm_table = &(dpm_ctx->eclk_table);
2233         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2234         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2235         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2236         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2237 
2238                 if (VEGA20_UMD_PSTATE_VCEMCLK_LEVEL < dpm_table->count) {
2239                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
2240                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
2241                 }
2242 
2243                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2244                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2245                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2246                 }
2247         return 0;
2248 }
2249 
2250 static int
2251 vega20_notify_smc_dispaly_config(struct smu_context *smu)
2252 {
2253         struct vega20_dpm_table *dpm_table = smu->smu_dpm.dpm_context;
2254         struct vega20_single_dpm_table *memtable = &dpm_table->mem_table;
2255         struct smu_clocks min_clocks = {0};
2256         struct pp_display_clock_request clock_req;
2257         int ret = 0;
2258 
2259         min_clocks.dcef_clock = smu->display_config->min_dcef_set_clk;
2260         min_clocks.dcef_clock_in_sr = smu->display_config->min_dcef_deep_sleep_set_clk;
2261         min_clocks.memory_clock = smu->display_config->min_mem_set_clock;
2262 
2263         if (smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
2264                 clock_req.clock_type = amd_pp_dcef_clock;
2265                 clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10;
2266                 if (!smu->funcs->display_clock_voltage_request(smu, &clock_req)) {
2267                         if (smu_feature_is_supported(smu, SMU_FEATURE_DS_DCEFCLK_BIT)) {
2268                                 ret = smu_send_smc_msg_with_param(smu,
2269                                                                   SMU_MSG_SetMinDeepSleepDcefclk,
2270                                                                   min_clocks.dcef_clock_in_sr/100);
2271                                 if (ret) {
2272                                         pr_err("Attempt to set divider for DCEFCLK Failed!");
2273                                         return ret;
2274                                 }
2275                         }
2276                 } else {
2277                         pr_info("Attempt to set Hard Min for DCEFCLK Failed!");
2278                 }
2279         }
2280 
2281         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
2282                 memtable->dpm_state.hard_min_level = min_clocks.memory_clock/100;
2283                 ret = smu_send_smc_msg_with_param(smu,
2284                                                   SMU_MSG_SetHardMinByFreq,
2285                                                   (PPCLK_UCLK << 16) | memtable->dpm_state.hard_min_level);
2286                 if (ret) {
2287                         pr_err("[%s] Set hard min uclk failed!", __func__);
2288                         return ret;
2289                 }
2290         }
2291 
2292         return 0;
2293 }
2294 
2295 static uint32_t vega20_find_lowest_dpm_level(struct vega20_single_dpm_table *table)
2296 {
2297         uint32_t i;
2298 
2299         for (i = 0; i < table->count; i++) {
2300                 if (table->dpm_levels[i].enabled)
2301                         break;
2302         }
2303         if (i >= table->count) {
2304                 i = 0;
2305                 table->dpm_levels[i].enabled = true;
2306         }
2307 
2308         return i;
2309 }
2310 
2311 static uint32_t vega20_find_highest_dpm_level(struct vega20_single_dpm_table *table)
2312 {
2313         int i = 0;
2314 
2315         if (!table) {
2316                 pr_err("[%s] DPM Table does not exist!", __func__);
2317                 return 0;
2318         }
2319         if (table->count <= 0) {
2320                 pr_err("[%s] DPM Table has no entry!", __func__);
2321                 return 0;
2322         }
2323         if (table->count > MAX_REGULAR_DPM_NUMBER) {
2324                 pr_err("[%s] DPM Table has too many entries!", __func__);
2325                 return MAX_REGULAR_DPM_NUMBER - 1;
2326         }
2327 
2328         for (i = table->count - 1; i >= 0; i--) {
2329                 if (table->dpm_levels[i].enabled)
2330                         break;
2331         }
2332         if (i < 0) {
2333                 i = 0;
2334                 table->dpm_levels[i].enabled = true;
2335         }
2336 
2337         return i;
2338 }
2339 
2340 static int vega20_force_dpm_limit_value(struct smu_context *smu, bool highest)
2341 {
2342         uint32_t soft_level;
2343         int ret = 0;
2344         struct vega20_dpm_table *dpm_table =
2345                 (struct vega20_dpm_table *)smu->smu_dpm.dpm_context;
2346 
2347         if (highest)
2348                 soft_level = vega20_find_highest_dpm_level(&(dpm_table->gfx_table));
2349         else
2350                 soft_level = vega20_find_lowest_dpm_level(&(dpm_table->gfx_table));
2351 
2352         dpm_table->gfx_table.dpm_state.soft_min_level =
2353                 dpm_table->gfx_table.dpm_state.soft_max_level =
2354                 dpm_table->gfx_table.dpm_levels[soft_level].value;
2355 
2356         if (highest)
2357                 soft_level = vega20_find_highest_dpm_level(&(dpm_table->mem_table));
2358         else
2359                 soft_level = vega20_find_lowest_dpm_level(&(dpm_table->mem_table));
2360 
2361         dpm_table->mem_table.dpm_state.soft_min_level =
2362                 dpm_table->mem_table.dpm_state.soft_max_level =
2363                 dpm_table->mem_table.dpm_levels[soft_level].value;
2364 
2365         if (highest)
2366                 soft_level = vega20_find_highest_dpm_level(&(dpm_table->soc_table));
2367         else
2368                 soft_level = vega20_find_lowest_dpm_level(&(dpm_table->soc_table));
2369 
2370         dpm_table->soc_table.dpm_state.soft_min_level =
2371                 dpm_table->soc_table.dpm_state.soft_max_level =
2372                 dpm_table->soc_table.dpm_levels[soft_level].value;
2373 
2374         ret = vega20_upload_dpm_level(smu, false, 0xFFFFFFFF);
2375         if (ret) {
2376                 pr_err("Failed to upload boot level to %s!\n",
2377                                 highest ? "highest" : "lowest");
2378                 return ret;
2379         }
2380 
2381         ret = vega20_upload_dpm_level(smu, true, 0xFFFFFFFF);
2382         if (ret) {
2383                 pr_err("Failed to upload dpm max level to %s!\n!",
2384                                 highest ? "highest" : "lowest");
2385                 return ret;
2386         }
2387 
2388         return ret;
2389 }
2390 
2391 static int vega20_unforce_dpm_levels(struct smu_context *smu)
2392 {
2393         uint32_t soft_min_level, soft_max_level;
2394         int ret = 0;
2395         struct vega20_dpm_table *dpm_table =
2396                 (struct vega20_dpm_table *)smu->smu_dpm.dpm_context;
2397 
2398         soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table->gfx_table));
2399         soft_max_level = vega20_find_highest_dpm_level(&(dpm_table->gfx_table));
2400         dpm_table->gfx_table.dpm_state.soft_min_level =
2401                 dpm_table->gfx_table.dpm_levels[soft_min_level].value;
2402         dpm_table->gfx_table.dpm_state.soft_max_level =
2403                 dpm_table->gfx_table.dpm_levels[soft_max_level].value;
2404 
2405         soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table->mem_table));
2406         soft_max_level = vega20_find_highest_dpm_level(&(dpm_table->mem_table));
2407         dpm_table->mem_table.dpm_state.soft_min_level =
2408                 dpm_table->gfx_table.dpm_levels[soft_min_level].value;
2409         dpm_table->mem_table.dpm_state.soft_max_level =
2410                 dpm_table->gfx_table.dpm_levels[soft_max_level].value;
2411 
2412         soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table->soc_table));
2413         soft_max_level = vega20_find_highest_dpm_level(&(dpm_table->soc_table));
2414         dpm_table->soc_table.dpm_state.soft_min_level =
2415                 dpm_table->soc_table.dpm_levels[soft_min_level].value;
2416         dpm_table->soc_table.dpm_state.soft_max_level =
2417                 dpm_table->soc_table.dpm_levels[soft_max_level].value;
2418 
2419         ret = vega20_upload_dpm_level(smu, false, 0xFFFFFFFF);
2420         if (ret) {
2421                 pr_err("Failed to upload DPM Bootup Levels!");
2422                 return ret;
2423         }
2424 
2425         ret = vega20_upload_dpm_level(smu, true, 0xFFFFFFFF);
2426         if (ret) {
2427                 pr_err("Failed to upload DPM Max Levels!");
2428                 return ret;
2429         }
2430 
2431         return ret;
2432 }
2433 
2434 static int vega20_update_specified_od8_value(struct smu_context *smu,
2435                                              uint32_t index,
2436                                              uint32_t value)
2437 {
2438         struct smu_table_context *table_context = &smu->smu_table;
2439         OverDriveTable_t *od_table =
2440                 (OverDriveTable_t *)(table_context->overdrive_table);
2441         struct vega20_od8_settings *od8_settings =
2442                 (struct vega20_od8_settings *)smu->od_settings;
2443 
2444         switch (index) {
2445         case OD8_SETTING_GFXCLK_FMIN:
2446                 od_table->GfxclkFmin = (uint16_t)value;
2447                 break;
2448 
2449         case OD8_SETTING_GFXCLK_FMAX:
2450                 if (value < od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].min_value ||
2451                     value > od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value)
2452                         return -EINVAL;
2453                 od_table->GfxclkFmax = (uint16_t)value;
2454                 break;
2455 
2456         case OD8_SETTING_GFXCLK_FREQ1:
2457                 od_table->GfxclkFreq1 = (uint16_t)value;
2458                 break;
2459 
2460         case OD8_SETTING_GFXCLK_VOLTAGE1:
2461                 od_table->GfxclkVolt1 = (uint16_t)value;
2462                 break;
2463 
2464         case OD8_SETTING_GFXCLK_FREQ2:
2465                 od_table->GfxclkFreq2 = (uint16_t)value;
2466                 break;
2467 
2468         case OD8_SETTING_GFXCLK_VOLTAGE2:
2469                 od_table->GfxclkVolt2 = (uint16_t)value;
2470                 break;
2471 
2472         case OD8_SETTING_GFXCLK_FREQ3:
2473                 od_table->GfxclkFreq3 = (uint16_t)value;
2474                 break;
2475 
2476         case OD8_SETTING_GFXCLK_VOLTAGE3:
2477                 od_table->GfxclkVolt3 = (uint16_t)value;
2478                 break;
2479 
2480         case OD8_SETTING_UCLK_FMAX:
2481                 if (value < od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].min_value ||
2482                     value > od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value)
2483                         return -EINVAL;
2484                 od_table->UclkFmax = (uint16_t)value;
2485                 break;
2486 
2487         case OD8_SETTING_POWER_PERCENTAGE:
2488                 od_table->OverDrivePct = (int16_t)value;
2489                 break;
2490 
2491         case OD8_SETTING_FAN_ACOUSTIC_LIMIT:
2492                 od_table->FanMaximumRpm = (uint16_t)value;
2493                 break;
2494 
2495         case OD8_SETTING_FAN_MIN_SPEED:
2496                 od_table->FanMinimumPwm = (uint16_t)value;
2497                 break;
2498 
2499         case OD8_SETTING_FAN_TARGET_TEMP:
2500                 od_table->FanTargetTemperature = (uint16_t)value;
2501                 break;
2502 
2503         case OD8_SETTING_OPERATING_TEMP_MAX:
2504                 od_table->MaxOpTemp = (uint16_t)value;
2505                 break;
2506         }
2507 
2508         return 0;
2509 }
2510 
2511 static int vega20_update_od8_settings(struct smu_context *smu,
2512                                       uint32_t index,
2513                                       uint32_t value)
2514 {
2515         struct smu_table_context *table_context = &smu->smu_table;
2516         int ret;
2517 
2518         ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0,
2519                                table_context->overdrive_table, false);
2520         if (ret) {
2521                 pr_err("Failed to export over drive table!\n");
2522                 return ret;
2523         }
2524 
2525         ret = vega20_update_specified_od8_value(smu, index, value);
2526         if (ret)
2527                 return ret;
2528 
2529         ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0,
2530                                table_context->overdrive_table, true);
2531         if (ret) {
2532                 pr_err("Failed to import over drive table!\n");
2533                 return ret;
2534         }
2535 
2536         return 0;
2537 }
2538 
2539 static int vega20_set_od_percentage(struct smu_context *smu,
2540                                     enum smu_clk_type clk_type,
2541                                     uint32_t value)
2542 {
2543         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
2544         struct vega20_dpm_table *dpm_table = NULL;
2545         struct vega20_dpm_table *golden_table = NULL;
2546         struct vega20_single_dpm_table *single_dpm_table;
2547         struct vega20_single_dpm_table *golden_dpm_table;
2548         uint32_t od_clk, index;
2549         int ret = 0;
2550         int feature_enabled;
2551         PPCLK_e clk_id;
2552 
2553         mutex_lock(&(smu->mutex));
2554 
2555         dpm_table = smu_dpm->dpm_context;
2556         golden_table = smu_dpm->golden_dpm_context;
2557 
2558         switch (clk_type) {
2559         case SMU_OD_SCLK:
2560                 single_dpm_table = &(dpm_table->gfx_table);
2561                 golden_dpm_table = &(golden_table->gfx_table);
2562                 feature_enabled = smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT);
2563                 clk_id = PPCLK_GFXCLK;
2564                 index = OD8_SETTING_GFXCLK_FMAX;
2565                 break;
2566         case SMU_OD_MCLK:
2567                 single_dpm_table = &(dpm_table->mem_table);
2568                 golden_dpm_table = &(golden_table->mem_table);
2569                 feature_enabled = smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT);
2570                 clk_id = PPCLK_UCLK;
2571                 index = OD8_SETTING_UCLK_FMAX;
2572                 break;
2573         default:
2574                 ret = -EINVAL;
2575                 break;
2576         }
2577 
2578         if (ret)
2579                 goto set_od_failed;
2580 
2581         od_clk = golden_dpm_table->dpm_levels[golden_dpm_table->count - 1].value * value;
2582         od_clk /= 100;
2583         od_clk += golden_dpm_table->dpm_levels[golden_dpm_table->count - 1].value;
2584 
2585         ret = vega20_update_od8_settings(smu, index, od_clk);
2586         if (ret) {
2587                 pr_err("[Setoverdrive] failed to set od clk!\n");
2588                 goto set_od_failed;
2589         }
2590 
2591         if (feature_enabled) {
2592                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
2593                                                   clk_id);
2594                 if (ret) {
2595                         pr_err("[Setoverdrive] failed to refresh dpm table!\n");
2596                         goto set_od_failed;
2597                 }
2598         } else {
2599                 single_dpm_table->count = 1;
2600                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
2601         }
2602 
2603         ret = smu_handle_task(smu, smu_dpm->dpm_level,
2604                               AMD_PP_TASK_READJUST_POWER_STATE);
2605 
2606 set_od_failed:
2607         mutex_unlock(&(smu->mutex));
2608 
2609         return ret;
2610 }
2611 
2612 static int vega20_odn_edit_dpm_table(struct smu_context *smu,
2613                                      enum PP_OD_DPM_TABLE_COMMAND type,
2614                                      long *input, uint32_t size)
2615 {
2616         struct smu_table_context *table_context = &smu->smu_table;
2617         OverDriveTable_t *od_table =
2618                 (OverDriveTable_t *)(table_context->overdrive_table);
2619         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
2620         struct vega20_dpm_table *dpm_table = NULL;
2621         struct vega20_single_dpm_table *single_dpm_table;
2622         struct vega20_od8_settings *od8_settings =
2623                 (struct vega20_od8_settings *)smu->od_settings;
2624         struct pp_clock_levels_with_latency clocks;
2625         int32_t input_index, input_clk, input_vol, i;
2626         int od8_id;
2627         int ret = 0;
2628 
2629         dpm_table = smu_dpm->dpm_context;
2630 
2631         if (!input) {
2632                 pr_warn("NULL user input for clock and voltage\n");
2633                 return -EINVAL;
2634         }
2635 
2636         switch (type) {
2637         case PP_OD_EDIT_SCLK_VDDC_TABLE:
2638                 if (!(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id &&
2639                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id)) {
2640                         pr_info("Sclk min/max frequency overdrive not supported\n");
2641                         return -EOPNOTSUPP;
2642                 }
2643 
2644                 for (i = 0; i < size; i += 2) {
2645                         if (i + 2 > size) {
2646                                 pr_info("invalid number of input parameters %d\n", size);
2647                                 return -EINVAL;
2648                         }
2649 
2650                         input_index = input[i];
2651                         input_clk = input[i + 1];
2652 
2653                         if (input_index != 0 && input_index != 1) {
2654                                 pr_info("Invalid index %d\n", input_index);
2655                                 pr_info("Support min/max sclk frequency settingonly which index by 0/1\n");
2656                                 return -EINVAL;
2657                         }
2658 
2659                         if (input_clk < od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value ||
2660                             input_clk > od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value) {
2661                                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2662                                         input_clk,
2663                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value,
2664                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value);
2665                                 return -EINVAL;
2666                         }
2667 
2668                         if (input_index == 0 && od_table->GfxclkFmin != input_clk) {
2669                                 od_table->GfxclkFmin = input_clk;
2670                                 od8_settings->od_gfxclk_update = true;
2671                         } else if (input_index == 1 && od_table->GfxclkFmax != input_clk) {
2672                                 od_table->GfxclkFmax = input_clk;
2673                                 od8_settings->od_gfxclk_update = true;
2674                         }
2675                 }
2676 
2677                 break;
2678 
2679         case PP_OD_EDIT_MCLK_VDDC_TABLE:
2680                 if (!od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) {
2681                         pr_info("Mclk max frequency overdrive not supported\n");
2682                         return -EOPNOTSUPP;
2683                 }
2684 
2685                 single_dpm_table = &(dpm_table->mem_table);
2686                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
2687                 if (ret) {
2688                         pr_err("Attempt to get memory clk levels Failed!");
2689                         return ret;
2690                 }
2691 
2692                 for (i = 0; i < size; i += 2) {
2693                         if (i + 2 > size) {
2694                                 pr_info("invalid number of input parameters %d\n",
2695                                          size);
2696                                 return -EINVAL;
2697                         }
2698 
2699                         input_index = input[i];
2700                         input_clk = input[i + 1];
2701 
2702                         if (input_index != 1) {
2703                                 pr_info("Invalid index %d\n", input_index);
2704                                 pr_info("Support max Mclk frequency setting only which index by 1\n");
2705                                 return -EINVAL;
2706                         }
2707 
2708                         if (input_clk < clocks.data[0].clocks_in_khz / 1000 ||
2709                             input_clk > od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value) {
2710                                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2711                                         input_clk,
2712                                         clocks.data[0].clocks_in_khz / 1000,
2713                                         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value);
2714                                 return -EINVAL;
2715                         }
2716 
2717                         if (input_index == 1 && od_table->UclkFmax != input_clk) {
2718                                 od8_settings->od_gfxclk_update = true;
2719                                 od_table->UclkFmax = input_clk;
2720                         }
2721                 }
2722 
2723                 break;
2724 
2725         case PP_OD_EDIT_VDDC_CURVE:
2726                 if (!(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
2727                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
2728                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
2729                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
2730                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
2731                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id)) {
2732                         pr_info("Voltage curve calibrate not supported\n");
2733                         return -EOPNOTSUPP;
2734                 }
2735 
2736                 for (i = 0; i < size; i += 3) {
2737                         if (i + 3 > size) {
2738                                 pr_info("invalid number of input parameters %d\n",
2739                                         size);
2740                                 return -EINVAL;
2741                         }
2742 
2743                         input_index = input[i];
2744                         input_clk = input[i + 1];
2745                         input_vol = input[i + 2];
2746 
2747                         if (input_index > 2) {
2748                                 pr_info("Setting for point %d is not supported\n",
2749                                         input_index + 1);
2750                                 pr_info("Three supported points index by 0, 1, 2\n");
2751                                 return -EINVAL;
2752                         }
2753 
2754                         od8_id = OD8_SETTING_GFXCLK_FREQ1 + 2 * input_index;
2755                         if (input_clk < od8_settings->od8_settings_array[od8_id].min_value ||
2756                             input_clk > od8_settings->od8_settings_array[od8_id].max_value) {
2757                                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2758                                         input_clk,
2759                                         od8_settings->od8_settings_array[od8_id].min_value,
2760                                         od8_settings->od8_settings_array[od8_id].max_value);
2761                                 return -EINVAL;
2762                         }
2763 
2764                         od8_id = OD8_SETTING_GFXCLK_VOLTAGE1 + 2 * input_index;
2765                         if (input_vol < od8_settings->od8_settings_array[od8_id].min_value ||
2766                             input_vol > od8_settings->od8_settings_array[od8_id].max_value) {
2767                                 pr_info("clock voltage %d is not within allowed range [%d- %d]\n",
2768                                         input_vol,
2769                                         od8_settings->od8_settings_array[od8_id].min_value,
2770                                         od8_settings->od8_settings_array[od8_id].max_value);
2771                                 return -EINVAL;
2772                         }
2773 
2774                         switch (input_index) {
2775                         case 0:
2776                                 od_table->GfxclkFreq1 = input_clk;
2777                                 od_table->GfxclkVolt1 = input_vol * VOLTAGE_SCALE;
2778                                 break;
2779                         case 1:
2780                                 od_table->GfxclkFreq2 = input_clk;
2781                                 od_table->GfxclkVolt2 = input_vol * VOLTAGE_SCALE;
2782                                 break;
2783                         case 2:
2784                                 od_table->GfxclkFreq3 = input_clk;
2785                                 od_table->GfxclkVolt3 = input_vol * VOLTAGE_SCALE;
2786                                 break;
2787                         }
2788                 }
2789 
2790                 break;
2791 
2792         case PP_OD_RESTORE_DEFAULT_TABLE:
2793                 ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0, table_context->overdrive_table, false);
2794                 if (ret) {
2795                         pr_err("Failed to export over drive table!\n");
2796                         return ret;
2797                 }
2798 
2799                 break;
2800 
2801         case PP_OD_COMMIT_DPM_TABLE:
2802                 ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0, table_context->overdrive_table, true);
2803                 if (ret) {
2804                         pr_err("Failed to import over drive table!\n");
2805                         return ret;
2806                 }
2807 
2808                 /* retrieve updated gfxclk table */
2809                 if (od8_settings->od_gfxclk_update) {
2810                         od8_settings->od_gfxclk_update = false;
2811                         single_dpm_table = &(dpm_table->gfx_table);
2812 
2813                         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
2814                                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
2815                                                                   PPCLK_GFXCLK);
2816                                 if (ret) {
2817                                         pr_err("[Setoverdrive] failed to refresh dpm table!\n");
2818                                         return ret;
2819                                 }
2820                         } else {
2821                                 single_dpm_table->count = 1;
2822                                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
2823                         }
2824                 }
2825 
2826                 break;
2827 
2828         default:
2829                 return -EINVAL;
2830         }
2831 
2832         if (type == PP_OD_COMMIT_DPM_TABLE) {
2833                 mutex_lock(&(smu->mutex));
2834                 ret = smu_handle_task(smu, smu_dpm->dpm_level,
2835                                       AMD_PP_TASK_READJUST_POWER_STATE);
2836                 mutex_unlock(&(smu->mutex));
2837         }
2838 
2839         return ret;
2840 }
2841 
2842 static int vega20_dpm_set_uvd_enable(struct smu_context *smu, bool enable)
2843 {
2844         if (!smu_feature_is_supported(smu, SMU_FEATURE_DPM_UVD_BIT))
2845                 return 0;
2846 
2847         if (enable == smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT))
2848                 return 0;
2849 
2850         return smu_feature_set_enabled(smu, SMU_FEATURE_DPM_UVD_BIT, enable);
2851 }
2852 
2853 static int vega20_dpm_set_vce_enable(struct smu_context *smu, bool enable)
2854 {
2855         if (!smu_feature_is_supported(smu, SMU_FEATURE_DPM_VCE_BIT))
2856                 return 0;
2857 
2858         if (enable == smu_feature_is_enabled(smu, SMU_FEATURE_DPM_VCE_BIT))
2859                 return 0;
2860 
2861         return smu_feature_set_enabled(smu, SMU_FEATURE_DPM_VCE_BIT, enable);
2862 }
2863 
2864 static bool vega20_is_dpm_running(struct smu_context *smu)
2865 {
2866         int ret = 0;
2867         uint32_t feature_mask[2];
2868         unsigned long feature_enabled;
2869         ret = smu_feature_get_enabled_mask(smu, feature_mask, 2);
2870         feature_enabled = (unsigned long)((uint64_t)feature_mask[0] |
2871                            ((uint64_t)feature_mask[1] << 32));
2872         return !!(feature_enabled & SMC_DPM_FEATURE);
2873 }
2874 
2875 static int vega20_set_thermal_fan_table(struct smu_context *smu)
2876 {
2877         int ret;
2878         struct smu_table_context *table_context = &smu->smu_table;
2879         PPTable_t *pptable = table_context->driver_pptable;
2880 
2881         ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetFanTemperatureTarget,
2882                         (uint32_t)pptable->FanTargetTemperature);
2883 
2884         return ret;
2885 }
2886 
2887 static int vega20_get_fan_speed_rpm(struct smu_context *smu,
2888                                     uint32_t *speed)
2889 {
2890         int ret;
2891 
2892         ret = smu_send_smc_msg(smu, SMU_MSG_GetCurrentRpm);
2893 
2894         if (ret) {
2895                 pr_err("Attempt to get current RPM from SMC Failed!\n");
2896                 return ret;
2897         }
2898 
2899         smu_read_smc_arg(smu, speed);
2900 
2901         return 0;
2902 }
2903 
2904 static int vega20_get_fan_speed_percent(struct smu_context *smu,
2905                                         uint32_t *speed)
2906 {
2907         int ret = 0;
2908         uint32_t current_rpm = 0, percent = 0;
2909         PPTable_t *pptable = smu->smu_table.driver_pptable;
2910 
2911         ret = vega20_get_fan_speed_rpm(smu, &current_rpm);
2912         if (ret)
2913                 return ret;
2914 
2915         percent = current_rpm * 100 / pptable->FanMaximumRpm;
2916         *speed = percent > 100 ? 100 : percent;
2917 
2918         return 0;
2919 }
2920 
2921 static int vega20_get_gpu_power(struct smu_context *smu, uint32_t *value)
2922 {
2923         uint32_t smu_version;
2924         int ret = 0;
2925         SmuMetrics_t metrics;
2926 
2927         if (!value)
2928                 return -EINVAL;
2929 
2930         ret = vega20_get_metrics_table(smu, &metrics);
2931         if (ret)
2932                 return ret;
2933 
2934         ret = smu_get_smc_version(smu, NULL, &smu_version);
2935         if (ret)
2936                 return ret;
2937 
2938         /* For the 40.46 release, they changed the value name */
2939         if (smu_version == 0x282e00)
2940                 *value = metrics.AverageSocketPower << 8;
2941         else
2942                 *value = metrics.CurrSocketPower << 8;
2943 
2944         return 0;
2945 }
2946 
2947 static int vega20_get_current_activity_percent(struct smu_context *smu,
2948                                                enum amd_pp_sensors sensor,
2949                                                uint32_t *value)
2950 {
2951         int ret = 0;
2952         SmuMetrics_t metrics;
2953 
2954         if (!value)
2955                 return -EINVAL;
2956 
2957         ret = vega20_get_metrics_table(smu, &metrics);
2958         if (ret)
2959                 return ret;
2960 
2961         switch (sensor) {
2962         case AMDGPU_PP_SENSOR_GPU_LOAD:
2963                 *value = metrics.AverageGfxActivity;
2964                 break;
2965         case AMDGPU_PP_SENSOR_MEM_LOAD:
2966                 *value = metrics.AverageUclkActivity;
2967                 break;
2968         default:
2969                 pr_err("Invalid sensor for retrieving clock activity\n");
2970                 return -EINVAL;
2971         }
2972 
2973         return 0;
2974 }
2975 
2976 static int vega20_thermal_get_temperature(struct smu_context *smu,
2977                                              enum amd_pp_sensors sensor,
2978                                              uint32_t *value)
2979 {
2980         struct amdgpu_device *adev = smu->adev;
2981         SmuMetrics_t metrics;
2982         uint32_t temp = 0;
2983         int ret = 0;
2984 
2985         if (!value)
2986                 return -EINVAL;
2987 
2988         ret = vega20_get_metrics_table(smu, &metrics);
2989         if (ret)
2990                 return ret;
2991 
2992         switch (sensor) {
2993         case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
2994                 temp = RREG32_SOC15(THM, 0, mmCG_MULT_THERMAL_STATUS);
2995                 temp = (temp & CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >>
2996                                 CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT;
2997 
2998                 temp = temp & 0x1ff;
2999                 temp *= SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
3000 
3001                 *value = temp;
3002                 break;
3003         case AMDGPU_PP_SENSOR_EDGE_TEMP:
3004                 *value = metrics.TemperatureEdge *
3005                         SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
3006                 break;
3007         case AMDGPU_PP_SENSOR_MEM_TEMP:
3008                 *value = metrics.TemperatureHBM *
3009                         SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
3010                 break;
3011         default:
3012                 pr_err("Invalid sensor for retrieving temp\n");
3013                 return -EINVAL;
3014         }
3015 
3016         return 0;
3017 }
3018 static int vega20_read_sensor(struct smu_context *smu,
3019                                  enum amd_pp_sensors sensor,
3020                                  void *data, uint32_t *size)
3021 {
3022         int ret = 0;
3023         struct smu_table_context *table_context = &smu->smu_table;
3024         PPTable_t *pptable = table_context->driver_pptable;
3025 
3026         if(!data || !size)
3027                 return -EINVAL;
3028 
3029         mutex_lock(&smu->sensor_lock);
3030         switch (sensor) {
3031         case AMDGPU_PP_SENSOR_MAX_FAN_RPM:
3032                 *(uint32_t *)data = pptable->FanMaximumRpm;
3033                 *size = 4;
3034                 break;
3035         case AMDGPU_PP_SENSOR_MEM_LOAD:
3036         case AMDGPU_PP_SENSOR_GPU_LOAD:
3037                 ret = vega20_get_current_activity_percent(smu,
3038                                                 sensor,
3039                                                 (uint32_t *)data);
3040                 *size = 4;
3041                 break;
3042         case AMDGPU_PP_SENSOR_GPU_POWER:
3043                 ret = vega20_get_gpu_power(smu, (uint32_t *)data);
3044                 *size = 4;
3045                 break;
3046         case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
3047         case AMDGPU_PP_SENSOR_EDGE_TEMP:
3048         case AMDGPU_PP_SENSOR_MEM_TEMP:
3049                 ret = vega20_thermal_get_temperature(smu, sensor, (uint32_t *)data);
3050                 *size = 4;
3051                 break;
3052         default:
3053                 ret = smu_smc_read_sensor(smu, sensor, data, size);
3054         }
3055         mutex_unlock(&smu->sensor_lock);
3056 
3057         return ret;
3058 }
3059 
3060 static int vega20_set_watermarks_table(struct smu_context *smu,
3061                                        void *watermarks, struct
3062                                        dm_pp_wm_sets_with_clock_ranges_soc15
3063                                        *clock_ranges)
3064 {
3065         int i;
3066         Watermarks_t *table = watermarks;
3067 
3068         if (!table || !clock_ranges)
3069                 return -EINVAL;
3070 
3071         if (clock_ranges->num_wm_dmif_sets > 4 ||
3072             clock_ranges->num_wm_mcif_sets > 4)
3073                 return -EINVAL;
3074 
3075         for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) {
3076                 table->WatermarkRow[1][i].MinClock =
3077                         cpu_to_le16((uint16_t)
3078                         (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz /
3079                         1000));
3080                 table->WatermarkRow[1][i].MaxClock =
3081                         cpu_to_le16((uint16_t)
3082                         (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz /
3083                         1000));
3084                 table->WatermarkRow[1][i].MinUclk =
3085                         cpu_to_le16((uint16_t)
3086                         (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz /
3087                         1000));
3088                 table->WatermarkRow[1][i].MaxUclk =
3089                         cpu_to_le16((uint16_t)
3090                         (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz /
3091                         1000));
3092                 table->WatermarkRow[1][i].WmSetting = (uint8_t)
3093                                 clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id;
3094         }
3095 
3096         for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) {
3097                 table->WatermarkRow[0][i].MinClock =
3098                         cpu_to_le16((uint16_t)
3099                         (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz /
3100                         1000));
3101                 table->WatermarkRow[0][i].MaxClock =
3102                         cpu_to_le16((uint16_t)
3103                         (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz /
3104                         1000));
3105                 table->WatermarkRow[0][i].MinUclk =
3106                         cpu_to_le16((uint16_t)
3107                         (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz /
3108                         1000));
3109                 table->WatermarkRow[0][i].MaxUclk =
3110                         cpu_to_le16((uint16_t)
3111                         (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz /
3112                         1000));
3113                 table->WatermarkRow[0][i].WmSetting = (uint8_t)
3114                                 clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
3115         }
3116 
3117         return 0;
3118 }
3119 
3120 static int vega20_get_thermal_temperature_range(struct smu_context *smu,
3121                                                 struct smu_temperature_range *range)
3122 {
3123         struct smu_table_context *table_context = &smu->smu_table;
3124         ATOM_Vega20_POWERPLAYTABLE *powerplay_table = table_context->power_play_table;
3125         PPTable_t *pptable = smu->smu_table.driver_pptable;
3126 
3127         if (!range || !powerplay_table)
3128                 return -EINVAL;
3129 
3130         range->max = powerplay_table->usSoftwareShutdownTemp *
3131                 SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
3132         range->edge_emergency_max = (pptable->TedgeLimit + CTF_OFFSET_EDGE) *
3133                 SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
3134         range->hotspot_crit_max = pptable->ThotspotLimit *
3135                 SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
3136         range->hotspot_emergency_max = (pptable->ThotspotLimit + CTF_OFFSET_HOTSPOT) *
3137                 SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
3138         range->mem_crit_max = pptable->ThbmLimit *
3139                 SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
3140         range->mem_emergency_max = (pptable->ThbmLimit + CTF_OFFSET_HBM) *
3141                 SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
3142 
3143 
3144         return 0;
3145 }
3146 
3147 static const struct pptable_funcs vega20_ppt_funcs = {
3148         .tables_init = vega20_tables_init,
3149         .alloc_dpm_context = vega20_allocate_dpm_context,
3150         .store_powerplay_table = vega20_store_powerplay_table,
3151         .check_powerplay_table = vega20_check_powerplay_table,
3152         .append_powerplay_table = vega20_append_powerplay_table,
3153         .get_smu_msg_index = vega20_get_smu_msg_index,
3154         .get_smu_clk_index = vega20_get_smu_clk_index,
3155         .get_smu_feature_index = vega20_get_smu_feature_index,
3156         .get_smu_table_index = vega20_get_smu_table_index,
3157         .get_smu_power_index = vega20_get_pwr_src_index,
3158         .get_workload_type = vega20_get_workload_type,
3159         .run_afll_btc = vega20_run_btc_afll,
3160         .get_allowed_feature_mask = vega20_get_allowed_feature_mask,
3161         .get_current_power_state = vega20_get_current_power_state,
3162         .set_default_dpm_table = vega20_set_default_dpm_table,
3163         .set_power_state = NULL,
3164         .populate_umd_state_clk = vega20_populate_umd_state_clk,
3165         .print_clk_levels = vega20_print_clk_levels,
3166         .force_clk_levels = vega20_force_clk_levels,
3167         .get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency,
3168         .get_od_percentage = vega20_get_od_percentage,
3169         .get_power_profile_mode = vega20_get_power_profile_mode,
3170         .set_power_profile_mode = vega20_set_power_profile_mode,
3171         .set_od_percentage = vega20_set_od_percentage,
3172         .set_default_od_settings = vega20_set_default_od_settings,
3173         .od_edit_dpm_table = vega20_odn_edit_dpm_table,
3174         .dpm_set_uvd_enable = vega20_dpm_set_uvd_enable,
3175         .dpm_set_vce_enable = vega20_dpm_set_vce_enable,
3176         .read_sensor = vega20_read_sensor,
3177         .pre_display_config_changed = vega20_pre_display_config_changed,
3178         .display_config_changed = vega20_display_config_changed,
3179         .apply_clocks_adjust_rules = vega20_apply_clocks_adjust_rules,
3180         .notify_smc_dispaly_config = vega20_notify_smc_dispaly_config,
3181         .force_dpm_limit_value = vega20_force_dpm_limit_value,
3182         .unforce_dpm_levels = vega20_unforce_dpm_levels,
3183         .get_profiling_clk_mask = vega20_get_profiling_clk_mask,
3184         .is_dpm_running = vega20_is_dpm_running,
3185         .set_thermal_fan_table = vega20_set_thermal_fan_table,
3186         .get_fan_speed_percent = vega20_get_fan_speed_percent,
3187         .get_fan_speed_rpm = vega20_get_fan_speed_rpm,
3188         .set_watermarks_table = vega20_set_watermarks_table,
3189         .get_thermal_temperature_range = vega20_get_thermal_temperature_range
3190 };
3191 
3192 void vega20_set_ppt_funcs(struct smu_context *smu)
3193 {
3194         struct smu_table_context *smu_table = &smu->smu_table;
3195 
3196         smu->ppt_funcs = &vega20_ppt_funcs;
3197         smu_table->table_count = TABLE_COUNT;
3198 }

/* [<][>][^][v][top][bottom][index][help] */