linux/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
<<
>>
Prefs
   1/*
   2 * Copyright 2018 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 <linux/delay.h>
  25#include <linux/fb.h>
  26#include <linux/module.h>
  27#include <linux/slab.h>
  28
  29#include "hwmgr.h"
  30#include "amd_powerplay.h"
  31#include "vega20_smumgr.h"
  32#include "hardwaremanager.h"
  33#include "ppatomfwctrl.h"
  34#include "atomfirmware.h"
  35#include "cgs_common.h"
  36#include "vega20_powertune.h"
  37#include "vega20_inc.h"
  38#include "pppcielanes.h"
  39#include "vega20_hwmgr.h"
  40#include "vega20_processpptables.h"
  41#include "vega20_pptable.h"
  42#include "vega20_thermal.h"
  43#include "vega20_ppsmc.h"
  44#include "pp_debug.h"
  45#include "amd_pcie_helpers.h"
  46#include "ppinterrupt.h"
  47#include "pp_overdriver.h"
  48#include "pp_thermal.h"
  49#include "soc15_common.h"
  50#include "smuio/smuio_9_0_offset.h"
  51#include "smuio/smuio_9_0_sh_mask.h"
  52#include "nbio/nbio_7_4_sh_mask.h"
  53
  54#define smnPCIE_LC_SPEED_CNTL                   0x11140290
  55#define smnPCIE_LC_LINK_WIDTH_CNTL              0x11140288
  56
  57static void vega20_set_default_registry_data(struct pp_hwmgr *hwmgr)
  58{
  59        struct vega20_hwmgr *data =
  60                        (struct vega20_hwmgr *)(hwmgr->backend);
  61
  62        data->gfxclk_average_alpha = PPVEGA20_VEGA20GFXCLKAVERAGEALPHA_DFLT;
  63        data->socclk_average_alpha = PPVEGA20_VEGA20SOCCLKAVERAGEALPHA_DFLT;
  64        data->uclk_average_alpha = PPVEGA20_VEGA20UCLKCLKAVERAGEALPHA_DFLT;
  65        data->gfx_activity_average_alpha = PPVEGA20_VEGA20GFXACTIVITYAVERAGEALPHA_DFLT;
  66        data->lowest_uclk_reserved_for_ulv = PPVEGA20_VEGA20LOWESTUCLKRESERVEDFORULV_DFLT;
  67
  68        data->display_voltage_mode = PPVEGA20_VEGA20DISPLAYVOLTAGEMODE_DFLT;
  69        data->dcef_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
  70        data->dcef_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
  71        data->dcef_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
  72        data->disp_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
  73        data->disp_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
  74        data->disp_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
  75        data->pixel_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
  76        data->pixel_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
  77        data->pixel_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
  78        data->phy_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
  79        data->phy_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
  80        data->phy_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
  81
  82        /*
  83         * Disable the following features for now:
  84         *   GFXCLK DS
  85         *   SOCLK DS
  86         *   LCLK DS
  87         *   DCEFCLK DS
  88         *   FCLK DS
  89         *   MP1CLK DS
  90         *   MP0CLK DS
  91         */
  92        data->registry_data.disallowed_features = 0xE0041C00;
  93        data->registry_data.od_state_in_dc_support = 0;
  94        data->registry_data.thermal_support = 1;
  95        data->registry_data.skip_baco_hardware = 0;
  96
  97        data->registry_data.log_avfs_param = 0;
  98        data->registry_data.sclk_throttle_low_notification = 1;
  99        data->registry_data.force_dpm_high = 0;
 100        data->registry_data.stable_pstate_sclk_dpm_percentage = 75;
 101
 102        data->registry_data.didt_support = 0;
 103        if (data->registry_data.didt_support) {
 104                data->registry_data.didt_mode = 6;
 105                data->registry_data.sq_ramping_support = 1;
 106                data->registry_data.db_ramping_support = 0;
 107                data->registry_data.td_ramping_support = 0;
 108                data->registry_data.tcp_ramping_support = 0;
 109                data->registry_data.dbr_ramping_support = 0;
 110                data->registry_data.edc_didt_support = 1;
 111                data->registry_data.gc_didt_support = 0;
 112                data->registry_data.psm_didt_support = 0;
 113        }
 114
 115        data->registry_data.pcie_lane_override = 0xff;
 116        data->registry_data.pcie_speed_override = 0xff;
 117        data->registry_data.pcie_clock_override = 0xffffffff;
 118        data->registry_data.regulator_hot_gpio_support = 1;
 119        data->registry_data.ac_dc_switch_gpio_support = 0;
 120        data->registry_data.quick_transition_support = 0;
 121        data->registry_data.zrpm_start_temp = 0xffff;
 122        data->registry_data.zrpm_stop_temp = 0xffff;
 123        data->registry_data.od8_feature_enable = 1;
 124        data->registry_data.disable_water_mark = 0;
 125        data->registry_data.disable_pp_tuning = 0;
 126        data->registry_data.disable_xlpp_tuning = 0;
 127        data->registry_data.disable_workload_policy = 0;
 128        data->registry_data.perf_ui_tuning_profile_turbo = 0x19190F0F;
 129        data->registry_data.perf_ui_tuning_profile_powerSave = 0x19191919;
 130        data->registry_data.perf_ui_tuning_profile_xl = 0x00000F0A;
 131        data->registry_data.force_workload_policy_mask = 0;
 132        data->registry_data.disable_3d_fs_detection = 0;
 133        data->registry_data.fps_support = 1;
 134        data->registry_data.disable_auto_wattman = 1;
 135        data->registry_data.auto_wattman_debug = 0;
 136        data->registry_data.auto_wattman_sample_period = 100;
 137        data->registry_data.fclk_gfxclk_ratio = 0;
 138        data->registry_data.auto_wattman_threshold = 50;
 139        data->registry_data.gfxoff_controlled_by_driver = 1;
 140        data->gfxoff_allowed = false;
 141        data->counter_gfxoff = 0;
 142}
 143
 144static int vega20_set_features_platform_caps(struct pp_hwmgr *hwmgr)
 145{
 146        struct vega20_hwmgr *data =
 147                        (struct vega20_hwmgr *)(hwmgr->backend);
 148        struct amdgpu_device *adev = hwmgr->adev;
 149
 150        if (data->vddci_control == VEGA20_VOLTAGE_CONTROL_NONE)
 151                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 152                                PHM_PlatformCaps_ControlVDDCI);
 153
 154        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 155                        PHM_PlatformCaps_TablelessHardwareInterface);
 156
 157        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 158                        PHM_PlatformCaps_EnableSMU7ThermalManagement);
 159
 160        if (adev->pg_flags & AMD_PG_SUPPORT_UVD)
 161                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 162                                PHM_PlatformCaps_UVDPowerGating);
 163
 164        if (adev->pg_flags & AMD_PG_SUPPORT_VCE)
 165                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 166                                PHM_PlatformCaps_VCEPowerGating);
 167
 168        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 169                        PHM_PlatformCaps_UnTabledHardwareInterface);
 170
 171        if (data->registry_data.od8_feature_enable)
 172                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 173                                PHM_PlatformCaps_OD8inACSupport);
 174
 175        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 176                        PHM_PlatformCaps_ActivityReporting);
 177        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 178                        PHM_PlatformCaps_FanSpeedInTableIsRPM);
 179
 180        if (data->registry_data.od_state_in_dc_support) {
 181                if (data->registry_data.od8_feature_enable)
 182                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 183                                        PHM_PlatformCaps_OD8inDCSupport);
 184        }
 185
 186        if (data->registry_data.thermal_support &&
 187            data->registry_data.fuzzy_fan_control_support &&
 188            hwmgr->thermal_controller.advanceFanControlParameters.usTMax)
 189                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 190                                PHM_PlatformCaps_ODFuzzyFanControlSupport);
 191
 192        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 193                        PHM_PlatformCaps_DynamicPowerManagement);
 194        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 195                        PHM_PlatformCaps_SMC);
 196        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 197                        PHM_PlatformCaps_ThermalPolicyDelay);
 198
 199        if (data->registry_data.force_dpm_high)
 200                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 201                                PHM_PlatformCaps_ExclusiveModeAlwaysHigh);
 202
 203        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 204                        PHM_PlatformCaps_DynamicUVDState);
 205
 206        if (data->registry_data.sclk_throttle_low_notification)
 207                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 208                                PHM_PlatformCaps_SclkThrottleLowNotification);
 209
 210        /* power tune caps */
 211        /* assume disabled */
 212        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 213                        PHM_PlatformCaps_PowerContainment);
 214        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 215                        PHM_PlatformCaps_DiDtSupport);
 216        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 217                        PHM_PlatformCaps_SQRamping);
 218        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 219                        PHM_PlatformCaps_DBRamping);
 220        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 221                        PHM_PlatformCaps_TDRamping);
 222        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 223                        PHM_PlatformCaps_TCPRamping);
 224        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 225                        PHM_PlatformCaps_DBRRamping);
 226        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 227                        PHM_PlatformCaps_DiDtEDCEnable);
 228        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 229                        PHM_PlatformCaps_GCEDC);
 230        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 231                        PHM_PlatformCaps_PSM);
 232
 233        if (data->registry_data.didt_support) {
 234                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 235                                PHM_PlatformCaps_DiDtSupport);
 236                if (data->registry_data.sq_ramping_support)
 237                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 238                                        PHM_PlatformCaps_SQRamping);
 239                if (data->registry_data.db_ramping_support)
 240                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 241                                        PHM_PlatformCaps_DBRamping);
 242                if (data->registry_data.td_ramping_support)
 243                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 244                                        PHM_PlatformCaps_TDRamping);
 245                if (data->registry_data.tcp_ramping_support)
 246                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 247                                        PHM_PlatformCaps_TCPRamping);
 248                if (data->registry_data.dbr_ramping_support)
 249                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 250                                        PHM_PlatformCaps_DBRRamping);
 251                if (data->registry_data.edc_didt_support)
 252                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 253                                        PHM_PlatformCaps_DiDtEDCEnable);
 254                if (data->registry_data.gc_didt_support)
 255                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 256                                        PHM_PlatformCaps_GCEDC);
 257                if (data->registry_data.psm_didt_support)
 258                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 259                                        PHM_PlatformCaps_PSM);
 260        }
 261
 262        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 263                        PHM_PlatformCaps_RegulatorHot);
 264
 265        if (data->registry_data.ac_dc_switch_gpio_support) {
 266                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 267                                PHM_PlatformCaps_AutomaticDCTransition);
 268                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 269                                PHM_PlatformCaps_SMCtoPPLIBAcdcGpioScheme);
 270        }
 271
 272        if (data->registry_data.quick_transition_support) {
 273                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 274                                PHM_PlatformCaps_AutomaticDCTransition);
 275                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 276                                PHM_PlatformCaps_SMCtoPPLIBAcdcGpioScheme);
 277                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 278                                PHM_PlatformCaps_Falcon_QuickTransition);
 279        }
 280
 281        if (data->lowest_uclk_reserved_for_ulv != PPVEGA20_VEGA20LOWESTUCLKRESERVEDFORULV_DFLT) {
 282                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 283                                PHM_PlatformCaps_LowestUclkReservedForUlv);
 284                if (data->lowest_uclk_reserved_for_ulv == 1)
 285                        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 286                                        PHM_PlatformCaps_LowestUclkReservedForUlv);
 287        }
 288
 289        if (data->registry_data.custom_fan_support)
 290                phm_cap_set(hwmgr->platform_descriptor.platformCaps,
 291                                PHM_PlatformCaps_CustomFanControlSupport);
 292
 293        return 0;
 294}
 295
 296static void vega20_init_dpm_defaults(struct pp_hwmgr *hwmgr)
 297{
 298        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
 299        int i;
 300
 301        data->smu_features[GNLD_DPM_PREFETCHER].smu_feature_id =
 302                        FEATURE_DPM_PREFETCHER_BIT;
 303        data->smu_features[GNLD_DPM_GFXCLK].smu_feature_id =
 304                        FEATURE_DPM_GFXCLK_BIT;
 305        data->smu_features[GNLD_DPM_UCLK].smu_feature_id =
 306                        FEATURE_DPM_UCLK_BIT;
 307        data->smu_features[GNLD_DPM_SOCCLK].smu_feature_id =
 308                        FEATURE_DPM_SOCCLK_BIT;
 309        data->smu_features[GNLD_DPM_UVD].smu_feature_id =
 310                        FEATURE_DPM_UVD_BIT;
 311        data->smu_features[GNLD_DPM_VCE].smu_feature_id =
 312                        FEATURE_DPM_VCE_BIT;
 313        data->smu_features[GNLD_ULV].smu_feature_id =
 314                        FEATURE_ULV_BIT;
 315        data->smu_features[GNLD_DPM_MP0CLK].smu_feature_id =
 316                        FEATURE_DPM_MP0CLK_BIT;
 317        data->smu_features[GNLD_DPM_LINK].smu_feature_id =
 318                        FEATURE_DPM_LINK_BIT;
 319        data->smu_features[GNLD_DPM_DCEFCLK].smu_feature_id =
 320                        FEATURE_DPM_DCEFCLK_BIT;
 321        data->smu_features[GNLD_DS_GFXCLK].smu_feature_id =
 322                        FEATURE_DS_GFXCLK_BIT;
 323        data->smu_features[GNLD_DS_SOCCLK].smu_feature_id =
 324                        FEATURE_DS_SOCCLK_BIT;
 325        data->smu_features[GNLD_DS_LCLK].smu_feature_id =
 326                        FEATURE_DS_LCLK_BIT;
 327        data->smu_features[GNLD_PPT].smu_feature_id =
 328                        FEATURE_PPT_BIT;
 329        data->smu_features[GNLD_TDC].smu_feature_id =
 330                        FEATURE_TDC_BIT;
 331        data->smu_features[GNLD_THERMAL].smu_feature_id =
 332                        FEATURE_THERMAL_BIT;
 333        data->smu_features[GNLD_GFX_PER_CU_CG].smu_feature_id =
 334                        FEATURE_GFX_PER_CU_CG_BIT;
 335        data->smu_features[GNLD_RM].smu_feature_id =
 336                        FEATURE_RM_BIT;
 337        data->smu_features[GNLD_DS_DCEFCLK].smu_feature_id =
 338                        FEATURE_DS_DCEFCLK_BIT;
 339        data->smu_features[GNLD_ACDC].smu_feature_id =
 340                        FEATURE_ACDC_BIT;
 341        data->smu_features[GNLD_VR0HOT].smu_feature_id =
 342                        FEATURE_VR0HOT_BIT;
 343        data->smu_features[GNLD_VR1HOT].smu_feature_id =
 344                        FEATURE_VR1HOT_BIT;
 345        data->smu_features[GNLD_FW_CTF].smu_feature_id =
 346                        FEATURE_FW_CTF_BIT;
 347        data->smu_features[GNLD_LED_DISPLAY].smu_feature_id =
 348                        FEATURE_LED_DISPLAY_BIT;
 349        data->smu_features[GNLD_FAN_CONTROL].smu_feature_id =
 350                        FEATURE_FAN_CONTROL_BIT;
 351        data->smu_features[GNLD_DIDT].smu_feature_id = FEATURE_GFX_EDC_BIT;
 352        data->smu_features[GNLD_GFXOFF].smu_feature_id = FEATURE_GFXOFF_BIT;
 353        data->smu_features[GNLD_CG].smu_feature_id = FEATURE_CG_BIT;
 354        data->smu_features[GNLD_DPM_FCLK].smu_feature_id = FEATURE_DPM_FCLK_BIT;
 355        data->smu_features[GNLD_DS_FCLK].smu_feature_id = FEATURE_DS_FCLK_BIT;
 356        data->smu_features[GNLD_DS_MP1CLK].smu_feature_id = FEATURE_DS_MP1CLK_BIT;
 357        data->smu_features[GNLD_DS_MP0CLK].smu_feature_id = FEATURE_DS_MP0CLK_BIT;
 358        data->smu_features[GNLD_XGMI].smu_feature_id = FEATURE_XGMI_BIT;
 359
 360        for (i = 0; i < GNLD_FEATURES_MAX; i++) {
 361                data->smu_features[i].smu_feature_bitmap =
 362                        (uint64_t)(1ULL << data->smu_features[i].smu_feature_id);
 363                data->smu_features[i].allowed =
 364                        ((data->registry_data.disallowed_features >> i) & 1) ?
 365                        false : true;
 366        }
 367}
 368
 369static int vega20_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
 370{
 371        return 0;
 372}
 373
 374static int vega20_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
 375{
 376        kfree(hwmgr->backend);
 377        hwmgr->backend = NULL;
 378
 379        return 0;
 380}
 381
 382static int vega20_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
 383{
 384        struct vega20_hwmgr *data;
 385        struct amdgpu_device *adev = hwmgr->adev;
 386
 387        data = kzalloc(sizeof(struct vega20_hwmgr), GFP_KERNEL);
 388        if (data == NULL)
 389                return -ENOMEM;
 390
 391        hwmgr->backend = data;
 392
 393        hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
 394        hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
 395        hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
 396
 397        vega20_set_default_registry_data(hwmgr);
 398
 399        data->disable_dpm_mask = 0xff;
 400
 401        /* need to set voltage control types before EVV patching */
 402        data->vddc_control = VEGA20_VOLTAGE_CONTROL_NONE;
 403        data->mvdd_control = VEGA20_VOLTAGE_CONTROL_NONE;
 404        data->vddci_control = VEGA20_VOLTAGE_CONTROL_NONE;
 405
 406        data->water_marks_bitmap = 0;
 407        data->avfs_exist = false;
 408
 409        vega20_set_features_platform_caps(hwmgr);
 410
 411        vega20_init_dpm_defaults(hwmgr);
 412
 413        /* Parse pptable data read from VBIOS */
 414        vega20_set_private_data_based_on_pptable(hwmgr);
 415
 416        data->is_tlu_enabled = false;
 417
 418        hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
 419                        VEGA20_MAX_HARDWARE_POWERLEVELS;
 420        hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
 421        hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50;
 422
 423        hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */
 424        /* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */
 425        hwmgr->platform_descriptor.clockStep.engineClock = 500;
 426        hwmgr->platform_descriptor.clockStep.memoryClock = 500;
 427
 428        data->total_active_cus = adev->gfx.cu_info.number;
 429
 430        return 0;
 431}
 432
 433static int vega20_init_sclk_threshold(struct pp_hwmgr *hwmgr)
 434{
 435        struct vega20_hwmgr *data =
 436                        (struct vega20_hwmgr *)(hwmgr->backend);
 437
 438        data->low_sclk_interrupt_threshold = 0;
 439
 440        return 0;
 441}
 442
 443static int vega20_setup_asic_task(struct pp_hwmgr *hwmgr)
 444{
 445        int ret = 0;
 446
 447        ret = vega20_init_sclk_threshold(hwmgr);
 448        PP_ASSERT_WITH_CODE(!ret,
 449                        "Failed to init sclk threshold!",
 450                        return ret);
 451
 452        return 0;
 453}
 454
 455/*
 456 * @fn vega20_init_dpm_state
 457 * @brief Function to initialize all Soft Min/Max and Hard Min/Max to 0xff.
 458 *
 459 * @param    dpm_state - the address of the DPM Table to initiailize.
 460 * @return   None.
 461 */
 462static void vega20_init_dpm_state(struct vega20_dpm_state *dpm_state)
 463{
 464        dpm_state->soft_min_level = 0x0;
 465        dpm_state->soft_max_level = 0xffff;
 466        dpm_state->hard_min_level = 0x0;
 467        dpm_state->hard_max_level = 0xffff;
 468}
 469
 470static int vega20_get_number_of_dpm_level(struct pp_hwmgr *hwmgr,
 471                PPCLK_e clk_id, uint32_t *num_of_levels)
 472{
 473        int ret = 0;
 474
 475        ret = smum_send_msg_to_smc_with_parameter(hwmgr,
 476                        PPSMC_MSG_GetDpmFreqByIndex,
 477                        (clk_id << 16 | 0xFF));
 478        PP_ASSERT_WITH_CODE(!ret,
 479                        "[GetNumOfDpmLevel] failed to get dpm levels!",
 480                        return ret);
 481
 482        *num_of_levels = smum_get_argument(hwmgr);
 483        PP_ASSERT_WITH_CODE(*num_of_levels > 0,
 484                        "[GetNumOfDpmLevel] number of clk levels is invalid!",
 485                        return -EINVAL);
 486
 487        return ret;
 488}
 489
 490static int vega20_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr,
 491                PPCLK_e clk_id, uint32_t index, uint32_t *clk)
 492{
 493        int ret = 0;
 494
 495        ret = smum_send_msg_to_smc_with_parameter(hwmgr,
 496                        PPSMC_MSG_GetDpmFreqByIndex,
 497                        (clk_id << 16 | index));
 498        PP_ASSERT_WITH_CODE(!ret,
 499                        "[GetDpmFreqByIndex] failed to get dpm freq by index!",
 500                        return ret);
 501
 502        *clk = smum_get_argument(hwmgr);
 503        PP_ASSERT_WITH_CODE(*clk,
 504                        "[GetDpmFreqByIndex] clk value is invalid!",
 505                        return -EINVAL);
 506
 507        return ret;
 508}
 509
 510static int vega20_setup_single_dpm_table(struct pp_hwmgr *hwmgr,
 511                struct vega20_single_dpm_table *dpm_table, PPCLK_e clk_id)
 512{
 513        int ret = 0;
 514        uint32_t i, num_of_levels, clk;
 515
 516        ret = vega20_get_number_of_dpm_level(hwmgr, clk_id, &num_of_levels);
 517        PP_ASSERT_WITH_CODE(!ret,
 518                        "[SetupSingleDpmTable] failed to get clk levels!",
 519                        return ret);
 520
 521        dpm_table->count = num_of_levels;
 522
 523        for (i = 0; i < num_of_levels; i++) {
 524                ret = vega20_get_dpm_frequency_by_index(hwmgr, clk_id, i, &clk);
 525                PP_ASSERT_WITH_CODE(!ret,
 526                        "[SetupSingleDpmTable] failed to get clk of specific level!",
 527                        return ret);
 528                dpm_table->dpm_levels[i].value = clk;
 529                dpm_table->dpm_levels[i].enabled = true;
 530        }
 531
 532        return ret;
 533}
 534
 535static int vega20_setup_gfxclk_dpm_table(struct pp_hwmgr *hwmgr)
 536{
 537        struct vega20_hwmgr *data =
 538                        (struct vega20_hwmgr *)(hwmgr->backend);
 539        struct vega20_single_dpm_table *dpm_table;
 540        int ret = 0;
 541
 542        dpm_table = &(data->dpm_table.gfx_table);
 543        if (data->smu_features[GNLD_DPM_GFXCLK].enabled) {
 544                ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_GFXCLK);
 545                PP_ASSERT_WITH_CODE(!ret,
 546                                "[SetupDefaultDpmTable] failed to get gfxclk dpm levels!",
 547                                return ret);
 548        } else {
 549                dpm_table->count = 1;
 550                dpm_table->dpm_levels[0].value = data->vbios_boot_state.gfx_clock / 100;
 551        }
 552
 553        return ret;
 554}
 555
 556static int vega20_setup_memclk_dpm_table(struct pp_hwmgr *hwmgr)
 557{
 558        struct vega20_hwmgr *data =
 559                        (struct vega20_hwmgr *)(hwmgr->backend);
 560        struct vega20_single_dpm_table *dpm_table;
 561        int ret = 0;
 562
 563        dpm_table = &(data->dpm_table.mem_table);
 564        if (data->smu_features[GNLD_DPM_UCLK].enabled) {
 565                ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_UCLK);
 566                PP_ASSERT_WITH_CODE(!ret,
 567                                "[SetupDefaultDpmTable] failed to get memclk dpm levels!",
 568                                return ret);
 569        } else {
 570                dpm_table->count = 1;
 571                dpm_table->dpm_levels[0].value = data->vbios_boot_state.mem_clock / 100;
 572        }
 573
 574        return ret;
 575}
 576
 577/*
 578 * This function is to initialize all DPM state tables
 579 * for SMU based on the dependency table.
 580 * Dynamic state patching function will then trim these
 581 * state tables to the allowed range based
 582 * on the power policy or external client requests,
 583 * such as UVD request, etc.
 584 */
 585static int vega20_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
 586{
 587        struct vega20_hwmgr *data =
 588                        (struct vega20_hwmgr *)(hwmgr->backend);
 589        struct vega20_single_dpm_table *dpm_table;
 590        int ret = 0;
 591
 592        memset(&data->dpm_table, 0, sizeof(data->dpm_table));
 593
 594        /* socclk */
 595        dpm_table = &(data->dpm_table.soc_table);
 596        if (data->smu_features[GNLD_DPM_SOCCLK].enabled) {
 597                ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_SOCCLK);
 598                PP_ASSERT_WITH_CODE(!ret,
 599                                "[SetupDefaultDpmTable] failed to get socclk dpm levels!",
 600                                return ret);
 601        } else {
 602                dpm_table->count = 1;
 603                dpm_table->dpm_levels[0].value = data->vbios_boot_state.soc_clock / 100;
 604        }
 605        vega20_init_dpm_state(&(dpm_table->dpm_state));
 606
 607        /* gfxclk */
 608        dpm_table = &(data->dpm_table.gfx_table);
 609        ret = vega20_setup_gfxclk_dpm_table(hwmgr);
 610        if (ret)
 611                return ret;
 612        vega20_init_dpm_state(&(dpm_table->dpm_state));
 613
 614        /* memclk */
 615        dpm_table = &(data->dpm_table.mem_table);
 616        ret = vega20_setup_memclk_dpm_table(hwmgr);
 617        if (ret)
 618                return ret;
 619        vega20_init_dpm_state(&(dpm_table->dpm_state));
 620
 621        /* eclk */
 622        dpm_table = &(data->dpm_table.eclk_table);
 623        if (data->smu_features[GNLD_DPM_VCE].enabled) {
 624                ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_ECLK);
 625                PP_ASSERT_WITH_CODE(!ret,
 626                                "[SetupDefaultDpmTable] failed to get eclk dpm levels!",
 627                                return ret);
 628        } else {
 629                dpm_table->count = 1;
 630                dpm_table->dpm_levels[0].value = data->vbios_boot_state.eclock / 100;
 631        }
 632        vega20_init_dpm_state(&(dpm_table->dpm_state));
 633
 634        /* vclk */
 635        dpm_table = &(data->dpm_table.vclk_table);
 636        if (data->smu_features[GNLD_DPM_UVD].enabled) {
 637                ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_VCLK);
 638                PP_ASSERT_WITH_CODE(!ret,
 639                                "[SetupDefaultDpmTable] failed to get vclk dpm levels!",
 640                                return ret);
 641        } else {
 642                dpm_table->count = 1;
 643                dpm_table->dpm_levels[0].value = data->vbios_boot_state.vclock / 100;
 644        }
 645        vega20_init_dpm_state(&(dpm_table->dpm_state));
 646
 647        /* dclk */
 648        dpm_table = &(data->dpm_table.dclk_table);
 649        if (data->smu_features[GNLD_DPM_UVD].enabled) {
 650                ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DCLK);
 651                PP_ASSERT_WITH_CODE(!ret,
 652                                "[SetupDefaultDpmTable] failed to get dclk dpm levels!",
 653                                return ret);
 654        } else {
 655                dpm_table->count = 1;
 656                dpm_table->dpm_levels[0].value = data->vbios_boot_state.dclock / 100;
 657        }
 658        vega20_init_dpm_state(&(dpm_table->dpm_state));
 659
 660        /* dcefclk */
 661        dpm_table = &(data->dpm_table.dcef_table);
 662        if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
 663                ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DCEFCLK);
 664                PP_ASSERT_WITH_CODE(!ret,
 665                                "[SetupDefaultDpmTable] failed to get dcefclk dpm levels!",
 666                                return ret);
 667        } else {
 668                dpm_table->count = 1;
 669                dpm_table->dpm_levels[0].value = data->vbios_boot_state.dcef_clock / 100;
 670        }
 671        vega20_init_dpm_state(&(dpm_table->dpm_state));
 672
 673        /* pixclk */
 674        dpm_table = &(data->dpm_table.pixel_table);
 675        if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
 676                ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_PIXCLK);
 677                PP_ASSERT_WITH_CODE(!ret,
 678                                "[SetupDefaultDpmTable] failed to get pixclk dpm levels!",
 679                                return ret);
 680        } else
 681                dpm_table->count = 0;
 682        vega20_init_dpm_state(&(dpm_table->dpm_state));
 683
 684        /* dispclk */
 685        dpm_table = &(data->dpm_table.display_table);
 686        if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
 687                ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DISPCLK);
 688                PP_ASSERT_WITH_CODE(!ret,
 689                                "[SetupDefaultDpmTable] failed to get dispclk dpm levels!",
 690                                return ret);
 691        } else
 692                dpm_table->count = 0;
 693        vega20_init_dpm_state(&(dpm_table->dpm_state));
 694
 695        /* phyclk */
 696        dpm_table = &(data->dpm_table.phy_table);
 697        if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
 698                ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_PHYCLK);
 699                PP_ASSERT_WITH_CODE(!ret,
 700                                "[SetupDefaultDpmTable] failed to get phyclk dpm levels!",
 701                                return ret);
 702        } else
 703                dpm_table->count = 0;
 704        vega20_init_dpm_state(&(dpm_table->dpm_state));
 705
 706        /* fclk */
 707        dpm_table = &(data->dpm_table.fclk_table);
 708        if (data->smu_features[GNLD_DPM_FCLK].enabled) {
 709                ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_FCLK);
 710                PP_ASSERT_WITH_CODE(!ret,
 711                                "[SetupDefaultDpmTable] failed to get fclk dpm levels!",
 712                                return ret);
 713        } else
 714                dpm_table->count = 0;
 715        vega20_init_dpm_state(&(dpm_table->dpm_state));
 716
 717        /* save a copy of the default DPM table */
 718        memcpy(&(data->golden_dpm_table), &(data->dpm_table),
 719                        sizeof(struct vega20_dpm_table));
 720
 721        return 0;
 722}
 723
 724/**
 725* Initializes the SMC table and uploads it
 726*
 727* @param    hwmgr  the address of the powerplay hardware manager.
 728* @param    pInput  the pointer to input data (PowerState)
 729* @return   always 0
 730*/
 731static int vega20_init_smc_table(struct pp_hwmgr *hwmgr)
 732{
 733        int result;
 734        struct vega20_hwmgr *data =
 735                        (struct vega20_hwmgr *)(hwmgr->backend);
 736        PPTable_t *pp_table = &(data->smc_state_table.pp_table);
 737        struct pp_atomfwctrl_bios_boot_up_values boot_up_values;
 738        struct phm_ppt_v3_information *pptable_information =
 739                (struct phm_ppt_v3_information *)hwmgr->pptable;
 740
 741        result = pp_atomfwctrl_get_vbios_bootup_values(hwmgr, &boot_up_values);
 742        PP_ASSERT_WITH_CODE(!result,
 743                        "[InitSMCTable] Failed to get vbios bootup values!",
 744                        return result);
 745
 746        data->vbios_boot_state.vddc     = boot_up_values.usVddc;
 747        data->vbios_boot_state.vddci    = boot_up_values.usVddci;
 748        data->vbios_boot_state.mvddc    = boot_up_values.usMvddc;
 749        data->vbios_boot_state.gfx_clock = boot_up_values.ulGfxClk;
 750        data->vbios_boot_state.mem_clock = boot_up_values.ulUClk;
 751        data->vbios_boot_state.soc_clock = boot_up_values.ulSocClk;
 752        data->vbios_boot_state.dcef_clock = boot_up_values.ulDCEFClk;
 753        data->vbios_boot_state.eclock = boot_up_values.ulEClk;
 754        data->vbios_boot_state.vclock = boot_up_values.ulVClk;
 755        data->vbios_boot_state.dclock = boot_up_values.ulDClk;
 756        data->vbios_boot_state.uc_cooling_id = boot_up_values.ucCoolingID;
 757
 758        smum_send_msg_to_smc_with_parameter(hwmgr,
 759                        PPSMC_MSG_SetMinDeepSleepDcefclk,
 760                (uint32_t)(data->vbios_boot_state.dcef_clock / 100));
 761
 762        memcpy(pp_table, pptable_information->smc_pptable, sizeof(PPTable_t));
 763
 764        result = smum_smc_table_manager(hwmgr,
 765                                        (uint8_t *)pp_table, TABLE_PPTABLE, false);
 766        PP_ASSERT_WITH_CODE(!result,
 767                        "[InitSMCTable] Failed to upload PPtable!",
 768                        return result);
 769
 770        return 0;
 771}
 772
 773static int vega20_set_allowed_featuresmask(struct pp_hwmgr *hwmgr)
 774{
 775        struct vega20_hwmgr *data =
 776                        (struct vega20_hwmgr *)(hwmgr->backend);
 777        uint32_t allowed_features_low = 0, allowed_features_high = 0;
 778        int i;
 779        int ret = 0;
 780
 781        for (i = 0; i < GNLD_FEATURES_MAX; i++)
 782                if (data->smu_features[i].allowed)
 783                        data->smu_features[i].smu_feature_id > 31 ?
 784                                (allowed_features_high |=
 785                                 ((data->smu_features[i].smu_feature_bitmap >> SMU_FEATURES_HIGH_SHIFT)
 786                                  & 0xFFFFFFFF)) :
 787                                (allowed_features_low |=
 788                                 ((data->smu_features[i].smu_feature_bitmap >> SMU_FEATURES_LOW_SHIFT)
 789                                  & 0xFFFFFFFF));
 790
 791        ret = smum_send_msg_to_smc_with_parameter(hwmgr,
 792                PPSMC_MSG_SetAllowedFeaturesMaskHigh, allowed_features_high);
 793        PP_ASSERT_WITH_CODE(!ret,
 794                "[SetAllowedFeaturesMask] Attempt to set allowed features mask(high) failed!",
 795                return ret);
 796
 797        ret = smum_send_msg_to_smc_with_parameter(hwmgr,
 798                PPSMC_MSG_SetAllowedFeaturesMaskLow, allowed_features_low);
 799        PP_ASSERT_WITH_CODE(!ret,
 800                "[SetAllowedFeaturesMask] Attempt to set allowed features mask (low) failed!",
 801                return ret);
 802
 803        return 0;
 804}
 805
 806static int vega20_run_btc_afll(struct pp_hwmgr *hwmgr)
 807{
 808        return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunAfllBtc);
 809}
 810
 811static int vega20_enable_all_smu_features(struct pp_hwmgr *hwmgr)
 812{
 813        struct vega20_hwmgr *data =
 814                        (struct vega20_hwmgr *)(hwmgr->backend);
 815        uint64_t features_enabled;
 816        int i;
 817        bool enabled;
 818        int ret = 0;
 819
 820        PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr,
 821                        PPSMC_MSG_EnableAllSmuFeatures)) == 0,
 822                        "[EnableAllSMUFeatures] Failed to enable all smu features!",
 823                        return ret);
 824
 825        ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
 826        PP_ASSERT_WITH_CODE(!ret,
 827                        "[EnableAllSmuFeatures] Failed to get enabled smc features!",
 828                        return ret);
 829
 830        for (i = 0; i < GNLD_FEATURES_MAX; i++) {
 831                enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ?
 832                        true : false;
 833                data->smu_features[i].enabled = enabled;
 834                data->smu_features[i].supported = enabled;
 835
 836#if 0
 837                if (data->smu_features[i].allowed && !enabled)
 838                        pr_info("[EnableAllSMUFeatures] feature %d is expected enabled!", i);
 839                else if (!data->smu_features[i].allowed && enabled)
 840                        pr_info("[EnableAllSMUFeatures] feature %d is expected disabled!", i);
 841#endif
 842        }
 843
 844        return 0;
 845}
 846
 847static int vega20_notify_smc_display_change(struct pp_hwmgr *hwmgr)
 848{
 849        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
 850
 851        if (data->smu_features[GNLD_DPM_UCLK].enabled)
 852                return smum_send_msg_to_smc_with_parameter(hwmgr,
 853                        PPSMC_MSG_SetUclkFastSwitch,
 854                        1);
 855
 856        return 0;
 857}
 858
 859static int vega20_send_clock_ratio(struct pp_hwmgr *hwmgr)
 860{
 861        struct vega20_hwmgr *data =
 862                        (struct vega20_hwmgr *)(hwmgr->backend);
 863
 864        return smum_send_msg_to_smc_with_parameter(hwmgr,
 865                        PPSMC_MSG_SetFclkGfxClkRatio,
 866                        data->registry_data.fclk_gfxclk_ratio);
 867}
 868
 869static int vega20_disable_all_smu_features(struct pp_hwmgr *hwmgr)
 870{
 871        struct vega20_hwmgr *data =
 872                        (struct vega20_hwmgr *)(hwmgr->backend);
 873        uint64_t features_enabled;
 874        int i;
 875        bool enabled;
 876        int ret = 0;
 877
 878        PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr,
 879                        PPSMC_MSG_DisableAllSmuFeatures)) == 0,
 880                        "[DisableAllSMUFeatures] Failed to disable all smu features!",
 881                        return ret);
 882
 883        ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
 884        PP_ASSERT_WITH_CODE(!ret,
 885                        "[DisableAllSMUFeatures] Failed to get enabled smc features!",
 886                        return ret);
 887
 888        for (i = 0; i < GNLD_FEATURES_MAX; i++) {
 889                enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ?
 890                        true : false;
 891                data->smu_features[i].enabled = enabled;
 892                data->smu_features[i].supported = enabled;
 893        }
 894
 895        return 0;
 896}
 897
 898static int vega20_od8_set_feature_capabilities(
 899                struct pp_hwmgr *hwmgr)
 900{
 901        struct phm_ppt_v3_information *pptable_information =
 902                (struct phm_ppt_v3_information *)hwmgr->pptable;
 903        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
 904        PPTable_t *pp_table = &(data->smc_state_table.pp_table);
 905        struct vega20_od8_settings *od_settings = &(data->od8_settings);
 906
 907        od_settings->overdrive8_capabilities = 0;
 908
 909        if (data->smu_features[GNLD_DPM_GFXCLK].enabled) {
 910                if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_LIMITS] &&
 911                    pptable_information->od_settings_max[OD8_SETTING_GFXCLK_FMAX] > 0 &&
 912                    pptable_information->od_settings_min[OD8_SETTING_GFXCLK_FMIN] > 0 &&
 913                    (pptable_information->od_settings_max[OD8_SETTING_GFXCLK_FMAX] >=
 914                    pptable_information->od_settings_min[OD8_SETTING_GFXCLK_FMIN]))
 915                        od_settings->overdrive8_capabilities |= OD8_GFXCLK_LIMITS;
 916
 917                if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_CURVE] &&
 918                    (pptable_information->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] >=
 919                     pp_table->MinVoltageGfx / VOLTAGE_SCALE) &&
 920                    (pptable_information->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3] <=
 921                     pp_table->MaxVoltageGfx / VOLTAGE_SCALE) &&
 922                    (pptable_information->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3] >=
 923                     pptable_information->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1]))
 924                        od_settings->overdrive8_capabilities |= OD8_GFXCLK_CURVE;
 925        }
 926
 927        if (data->smu_features[GNLD_DPM_UCLK].enabled) {
 928                if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_UCLK_MAX] &&
 929                    pptable_information->od_settings_min[OD8_SETTING_UCLK_FMAX] > 0 &&
 930                    pptable_information->od_settings_max[OD8_SETTING_UCLK_FMAX] > 0 &&
 931                    (pptable_information->od_settings_max[OD8_SETTING_UCLK_FMAX] >=
 932                    pptable_information->od_settings_min[OD8_SETTING_UCLK_FMAX]))
 933                        od_settings->overdrive8_capabilities |= OD8_UCLK_MAX;
 934        }
 935
 936        if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_POWER_LIMIT] &&
 937            pptable_information->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
 938            pptable_information->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] <= 100 &&
 939            pptable_information->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
 940            pptable_information->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] <= 100)
 941                od_settings->overdrive8_capabilities |= OD8_POWER_LIMIT;
 942
 943        if (data->smu_features[GNLD_FAN_CONTROL].enabled) {
 944                if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_ACOUSTIC_LIMIT] &&
 945                    pptable_information->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 &&
 946                    pptable_information->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 &&
 947                    (pptable_information->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] >=
 948                     pptable_information->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT]))
 949                        od_settings->overdrive8_capabilities |= OD8_ACOUSTIC_LIMIT_SCLK;
 950
 951                if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_SPEED_MIN] &&
 952                    (pptable_information->od_settings_min[OD8_SETTING_FAN_MIN_SPEED] >=
 953                    (pp_table->FanPwmMin * pp_table->FanMaximumRpm / 100)) &&
 954                    pptable_information->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] > 0 &&
 955                    (pptable_information->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] >=
 956                     pptable_information->od_settings_min[OD8_SETTING_FAN_MIN_SPEED]))
 957                        od_settings->overdrive8_capabilities |= OD8_FAN_SPEED_MIN;
 958        }
 959
 960        if (data->smu_features[GNLD_THERMAL].enabled) {
 961                if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_FAN] &&
 962                    pptable_information->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] > 0 &&
 963                    pptable_information->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP] > 0 &&
 964                    (pptable_information->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] >=
 965                     pptable_information->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP]))
 966                        od_settings->overdrive8_capabilities |= OD8_TEMPERATURE_FAN;
 967
 968                if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_SYSTEM] &&
 969                    pptable_information->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] > 0 &&
 970                    pptable_information->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX] > 0 &&
 971                    (pptable_information->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] >=
 972                     pptable_information->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX]))
 973                        od_settings->overdrive8_capabilities |= OD8_TEMPERATURE_SYSTEM;
 974        }
 975
 976        if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_MEMORY_TIMING_TUNE])
 977                od_settings->overdrive8_capabilities |= OD8_MEMORY_TIMING_TUNE;
 978
 979        if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_ZERO_RPM_CONTROL] &&
 980            pp_table->FanZeroRpmEnable)
 981                od_settings->overdrive8_capabilities |= OD8_FAN_ZERO_RPM_CONTROL;
 982
 983        if (!od_settings->overdrive8_capabilities)
 984                hwmgr->od_enabled = false;
 985
 986        return 0;
 987}
 988
 989static int vega20_od8_set_feature_id(
 990                struct pp_hwmgr *hwmgr)
 991{
 992        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
 993        struct vega20_od8_settings *od_settings = &(data->od8_settings);
 994
 995        if (od_settings->overdrive8_capabilities & OD8_GFXCLK_LIMITS) {
 996                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id =
 997                        OD8_GFXCLK_LIMITS;
 998                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id =
 999                        OD8_GFXCLK_LIMITS;
1000        } else {
1001                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id =
1002                        0;
1003                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id =
1004                        0;
1005        }
1006
1007        if (od_settings->overdrive8_capabilities & OD8_GFXCLK_CURVE) {
1008                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id =
1009                        OD8_GFXCLK_CURVE;
1010                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id =
1011                        OD8_GFXCLK_CURVE;
1012                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id =
1013                        OD8_GFXCLK_CURVE;
1014                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id =
1015                        OD8_GFXCLK_CURVE;
1016                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id =
1017                        OD8_GFXCLK_CURVE;
1018                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id =
1019                        OD8_GFXCLK_CURVE;
1020        } else {
1021                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id =
1022                        0;
1023                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id =
1024                        0;
1025                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id =
1026                        0;
1027                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id =
1028                        0;
1029                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id =
1030                        0;
1031                od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id =
1032                        0;
1033        }
1034
1035        if (od_settings->overdrive8_capabilities & OD8_UCLK_MAX)
1036                od_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id = OD8_UCLK_MAX;
1037        else
1038                od_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id = 0;
1039
1040        if (od_settings->overdrive8_capabilities & OD8_POWER_LIMIT)
1041                od_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id = OD8_POWER_LIMIT;
1042        else
1043                od_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id = 0;
1044
1045        if (od_settings->overdrive8_capabilities & OD8_ACOUSTIC_LIMIT_SCLK)
1046                od_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id =
1047                        OD8_ACOUSTIC_LIMIT_SCLK;
1048        else
1049                od_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id =
1050                        0;
1051
1052        if (od_settings->overdrive8_capabilities & OD8_FAN_SPEED_MIN)
1053                od_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id =
1054                        OD8_FAN_SPEED_MIN;
1055        else
1056                od_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id =
1057                        0;
1058
1059        if (od_settings->overdrive8_capabilities & OD8_TEMPERATURE_FAN)
1060                od_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id =
1061                        OD8_TEMPERATURE_FAN;
1062        else
1063                od_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id =
1064                        0;
1065
1066        if (od_settings->overdrive8_capabilities & OD8_TEMPERATURE_SYSTEM)
1067                od_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id =
1068                        OD8_TEMPERATURE_SYSTEM;
1069        else
1070                od_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id =
1071                        0;
1072
1073        return 0;
1074}
1075
1076static int vega20_od8_get_gfx_clock_base_voltage(
1077                struct pp_hwmgr *hwmgr,
1078                uint32_t *voltage,
1079                uint32_t freq)
1080{
1081        int ret = 0;
1082
1083        ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1084                        PPSMC_MSG_GetAVFSVoltageByDpm,
1085                        ((AVFS_CURVE << 24) | (OD8_HOTCURVE_TEMPERATURE << 16) | freq));
1086        PP_ASSERT_WITH_CODE(!ret,
1087                        "[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!",
1088                        return ret);
1089
1090        *voltage = smum_get_argument(hwmgr);
1091        *voltage = *voltage / VOLTAGE_SCALE;
1092
1093        return 0;
1094}
1095
1096static int vega20_od8_initialize_default_settings(
1097                struct pp_hwmgr *hwmgr)
1098{
1099        struct phm_ppt_v3_information *pptable_information =
1100                (struct phm_ppt_v3_information *)hwmgr->pptable;
1101        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1102        struct vega20_od8_settings *od8_settings = &(data->od8_settings);
1103        OverDriveTable_t *od_table = &(data->smc_state_table.overdrive_table);
1104        int i, ret = 0;
1105
1106        /* Set Feature Capabilities */
1107        vega20_od8_set_feature_capabilities(hwmgr);
1108
1109        /* Map FeatureID to individual settings */
1110        vega20_od8_set_feature_id(hwmgr);
1111
1112        /* Set default values */
1113        ret = smum_smc_table_manager(hwmgr, (uint8_t *)od_table, TABLE_OVERDRIVE, true);
1114        PP_ASSERT_WITH_CODE(!ret,
1115                        "Failed to export over drive table!",
1116                        return ret);
1117
1118        if (od8_settings->overdrive8_capabilities & OD8_GFXCLK_LIMITS) {
1119                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value =
1120                        od_table->GfxclkFmin;
1121                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value =
1122                        od_table->GfxclkFmax;
1123        } else {
1124                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value =
1125                        0;
1126                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value =
1127                        0;
1128        }
1129
1130        if (od8_settings->overdrive8_capabilities & OD8_GFXCLK_CURVE) {
1131                od_table->GfxclkFreq1 = od_table->GfxclkFmin;
1132                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value =
1133                        od_table->GfxclkFreq1;
1134
1135                od_table->GfxclkFreq3 = od_table->GfxclkFmax;
1136                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value =
1137                        od_table->GfxclkFreq3;
1138
1139                od_table->GfxclkFreq2 = (od_table->GfxclkFreq1 + od_table->GfxclkFreq3) / 2;
1140                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value =
1141                        od_table->GfxclkFreq2;
1142
1143                PP_ASSERT_WITH_CODE(!vega20_od8_get_gfx_clock_base_voltage(hwmgr,
1144                                   &(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value),
1145                                     od_table->GfxclkFreq1),
1146                                "[PhwVega20_OD8_InitializeDefaultSettings] Failed to get Base clock voltage from SMU!",
1147                                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value = 0);
1148                od_table->GfxclkVolt1 = od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value
1149                        * VOLTAGE_SCALE;
1150
1151                PP_ASSERT_WITH_CODE(!vega20_od8_get_gfx_clock_base_voltage(hwmgr,
1152                                   &(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value),
1153                                     od_table->GfxclkFreq2),
1154                                "[PhwVega20_OD8_InitializeDefaultSettings] Failed to get Base clock voltage from SMU!",
1155                                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value = 0);
1156                od_table->GfxclkVolt2 = od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value
1157                        * VOLTAGE_SCALE;
1158
1159                PP_ASSERT_WITH_CODE(!vega20_od8_get_gfx_clock_base_voltage(hwmgr,
1160                                   &(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value),
1161                                     od_table->GfxclkFreq3),
1162                                "[PhwVega20_OD8_InitializeDefaultSettings] Failed to get Base clock voltage from SMU!",
1163                                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value = 0);
1164                od_table->GfxclkVolt3 = od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value
1165                        * VOLTAGE_SCALE;
1166        } else {
1167                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value =
1168                        0;
1169                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value =
1170                        0;
1171                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value =
1172                        0;
1173                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value =
1174                        0;
1175                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value =
1176                        0;
1177                od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value =
1178                        0;
1179        }
1180
1181        if (od8_settings->overdrive8_capabilities & OD8_UCLK_MAX)
1182                od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value =
1183                        od_table->UclkFmax;
1184        else
1185                od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value =
1186                        0;
1187
1188        if (od8_settings->overdrive8_capabilities & OD8_POWER_LIMIT)
1189                od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value =
1190                        od_table->OverDrivePct;
1191        else
1192                od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value =
1193                        0;
1194
1195        if (od8_settings->overdrive8_capabilities & OD8_ACOUSTIC_LIMIT_SCLK)
1196                od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value =
1197                        od_table->FanMaximumRpm;
1198        else
1199                od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value =
1200                        0;
1201
1202        if (od8_settings->overdrive8_capabilities & OD8_FAN_SPEED_MIN)
1203                od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value =
1204                        od_table->FanMinimumPwm * data->smc_state_table.pp_table.FanMaximumRpm / 100;
1205        else
1206                od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value =
1207                        0;
1208
1209        if (od8_settings->overdrive8_capabilities & OD8_TEMPERATURE_FAN)
1210                od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value =
1211                        od_table->FanTargetTemperature;
1212        else
1213                od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value =
1214                        0;
1215
1216        if (od8_settings->overdrive8_capabilities & OD8_TEMPERATURE_SYSTEM)
1217                od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_value =
1218                        od_table->MaxOpTemp;
1219        else
1220                od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_value =
1221                        0;
1222
1223        for (i = 0; i < OD8_SETTING_COUNT; i++) {
1224                if (od8_settings->od8_settings_array[i].feature_id) {
1225                        od8_settings->od8_settings_array[i].min_value =
1226                                pptable_information->od_settings_min[i];
1227                        od8_settings->od8_settings_array[i].max_value =
1228                                pptable_information->od_settings_max[i];
1229                        od8_settings->od8_settings_array[i].current_value =
1230                                od8_settings->od8_settings_array[i].default_value;
1231                } else {
1232                        od8_settings->od8_settings_array[i].min_value =
1233                                0;
1234                        od8_settings->od8_settings_array[i].max_value =
1235                                0;
1236                        od8_settings->od8_settings_array[i].current_value =
1237                                0;
1238                }
1239        }
1240
1241        ret = smum_smc_table_manager(hwmgr, (uint8_t *)od_table, TABLE_OVERDRIVE, false);
1242        PP_ASSERT_WITH_CODE(!ret,
1243                        "Failed to import over drive table!",
1244                        return ret);
1245
1246        return 0;
1247}
1248
1249static int vega20_od8_set_settings(
1250                struct pp_hwmgr *hwmgr,
1251                uint32_t index,
1252                uint32_t value)
1253{
1254        OverDriveTable_t od_table;
1255        int ret = 0;
1256        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1257        struct vega20_od8_single_setting *od8_settings =
1258                        data->od8_settings.od8_settings_array;
1259
1260        ret = smum_smc_table_manager(hwmgr, (uint8_t *)(&od_table), TABLE_OVERDRIVE, true);
1261        PP_ASSERT_WITH_CODE(!ret,
1262                        "Failed to export over drive table!",
1263                        return ret);
1264
1265        switch(index) {
1266        case OD8_SETTING_GFXCLK_FMIN:
1267                od_table.GfxclkFmin = (uint16_t)value;
1268                break;
1269        case OD8_SETTING_GFXCLK_FMAX:
1270                if (value < od8_settings[OD8_SETTING_GFXCLK_FMAX].min_value ||
1271                    value > od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value)
1272                        return -EINVAL;
1273
1274                od_table.GfxclkFmax = (uint16_t)value;
1275                break;
1276        case OD8_SETTING_GFXCLK_FREQ1:
1277                od_table.GfxclkFreq1 = (uint16_t)value;
1278                break;
1279        case OD8_SETTING_GFXCLK_VOLTAGE1:
1280                od_table.GfxclkVolt1 = (uint16_t)value;
1281                break;
1282        case OD8_SETTING_GFXCLK_FREQ2:
1283                od_table.GfxclkFreq2 = (uint16_t)value;
1284                break;
1285        case OD8_SETTING_GFXCLK_VOLTAGE2:
1286                od_table.GfxclkVolt2 = (uint16_t)value;
1287                break;
1288        case OD8_SETTING_GFXCLK_FREQ3:
1289                od_table.GfxclkFreq3 = (uint16_t)value;
1290                break;
1291        case OD8_SETTING_GFXCLK_VOLTAGE3:
1292                od_table.GfxclkVolt3 = (uint16_t)value;
1293                break;
1294        case OD8_SETTING_UCLK_FMAX:
1295                if (value < od8_settings[OD8_SETTING_UCLK_FMAX].min_value ||
1296                    value > od8_settings[OD8_SETTING_UCLK_FMAX].max_value)
1297                        return -EINVAL;
1298                od_table.UclkFmax = (uint16_t)value;
1299                break;
1300        case OD8_SETTING_POWER_PERCENTAGE:
1301                od_table.OverDrivePct = (int16_t)value;
1302                break;
1303        case OD8_SETTING_FAN_ACOUSTIC_LIMIT:
1304                od_table.FanMaximumRpm = (uint16_t)value;
1305                break;
1306        case OD8_SETTING_FAN_MIN_SPEED:
1307                od_table.FanMinimumPwm = (uint16_t)value;
1308                break;
1309        case OD8_SETTING_FAN_TARGET_TEMP:
1310                od_table.FanTargetTemperature = (uint16_t)value;
1311                break;
1312        case OD8_SETTING_OPERATING_TEMP_MAX:
1313                od_table.MaxOpTemp = (uint16_t)value;
1314                break;
1315        }
1316
1317        ret = smum_smc_table_manager(hwmgr, (uint8_t *)(&od_table), TABLE_OVERDRIVE, false);
1318        PP_ASSERT_WITH_CODE(!ret,
1319                        "Failed to import over drive table!",
1320                        return ret);
1321
1322        return 0;
1323}
1324
1325static int vega20_get_sclk_od(
1326                struct pp_hwmgr *hwmgr)
1327{
1328        struct vega20_hwmgr *data = hwmgr->backend;
1329        struct vega20_single_dpm_table *sclk_table =
1330                        &(data->dpm_table.gfx_table);
1331        struct vega20_single_dpm_table *golden_sclk_table =
1332                        &(data->golden_dpm_table.gfx_table);
1333        int value = sclk_table->dpm_levels[sclk_table->count - 1].value;
1334        int golden_value = golden_sclk_table->dpm_levels
1335                        [golden_sclk_table->count - 1].value;
1336
1337        /* od percentage */
1338        value -= golden_value;
1339        value = DIV_ROUND_UP(value * 100, golden_value);
1340
1341        return value;
1342}
1343
1344static int vega20_set_sclk_od(
1345                struct pp_hwmgr *hwmgr, uint32_t value)
1346{
1347        struct vega20_hwmgr *data = hwmgr->backend;
1348        struct vega20_single_dpm_table *golden_sclk_table =
1349                        &(data->golden_dpm_table.gfx_table);
1350        uint32_t od_sclk;
1351        int ret = 0;
1352
1353        od_sclk = golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value * value;
1354        od_sclk /= 100;
1355        od_sclk += golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
1356
1357        ret = vega20_od8_set_settings(hwmgr, OD8_SETTING_GFXCLK_FMAX, od_sclk);
1358        PP_ASSERT_WITH_CODE(!ret,
1359                        "[SetSclkOD] failed to set od gfxclk!",
1360                        return ret);
1361
1362        /* retrieve updated gfxclk table */
1363        ret = vega20_setup_gfxclk_dpm_table(hwmgr);
1364        PP_ASSERT_WITH_CODE(!ret,
1365                        "[SetSclkOD] failed to refresh gfxclk table!",
1366                        return ret);
1367
1368        return 0;
1369}
1370
1371static int vega20_get_mclk_od(
1372                struct pp_hwmgr *hwmgr)
1373{
1374        struct vega20_hwmgr *data = hwmgr->backend;
1375        struct vega20_single_dpm_table *mclk_table =
1376                        &(data->dpm_table.mem_table);
1377        struct vega20_single_dpm_table *golden_mclk_table =
1378                        &(data->golden_dpm_table.mem_table);
1379        int value = mclk_table->dpm_levels[mclk_table->count - 1].value;
1380        int golden_value = golden_mclk_table->dpm_levels
1381                        [golden_mclk_table->count - 1].value;
1382
1383        /* od percentage */
1384        value -= golden_value;
1385        value = DIV_ROUND_UP(value * 100, golden_value);
1386
1387        return value;
1388}
1389
1390static int vega20_set_mclk_od(
1391                struct pp_hwmgr *hwmgr, uint32_t value)
1392{
1393        struct vega20_hwmgr *data = hwmgr->backend;
1394        struct vega20_single_dpm_table *golden_mclk_table =
1395                        &(data->golden_dpm_table.mem_table);
1396        uint32_t od_mclk;
1397        int ret = 0;
1398
1399        od_mclk = golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value * value;
1400        od_mclk /= 100;
1401        od_mclk += golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
1402
1403        ret = vega20_od8_set_settings(hwmgr, OD8_SETTING_UCLK_FMAX, od_mclk);
1404        PP_ASSERT_WITH_CODE(!ret,
1405                        "[SetMclkOD] failed to set od memclk!",
1406                        return ret);
1407
1408        /* retrieve updated memclk table */
1409        ret = vega20_setup_memclk_dpm_table(hwmgr);
1410        PP_ASSERT_WITH_CODE(!ret,
1411                        "[SetMclkOD] failed to refresh memclk table!",
1412                        return ret);
1413
1414        return 0;
1415}
1416
1417static int vega20_populate_umdpstate_clocks(
1418                struct pp_hwmgr *hwmgr)
1419{
1420        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1421        struct vega20_single_dpm_table *gfx_table = &(data->dpm_table.gfx_table);
1422        struct vega20_single_dpm_table *mem_table = &(data->dpm_table.mem_table);
1423
1424        hwmgr->pstate_sclk = gfx_table->dpm_levels[0].value;
1425        hwmgr->pstate_mclk = mem_table->dpm_levels[0].value;
1426
1427        if (gfx_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
1428            mem_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL) {
1429                hwmgr->pstate_sclk = gfx_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
1430                hwmgr->pstate_mclk = mem_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
1431        }
1432
1433        hwmgr->pstate_sclk = hwmgr->pstate_sclk * 100;
1434        hwmgr->pstate_mclk = hwmgr->pstate_mclk * 100;
1435
1436        return 0;
1437}
1438
1439static int vega20_get_max_sustainable_clock(struct pp_hwmgr *hwmgr,
1440                PP_Clock *clock, PPCLK_e clock_select)
1441{
1442        int ret = 0;
1443
1444        PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1445                        PPSMC_MSG_GetDcModeMaxDpmFreq,
1446                        (clock_select << 16))) == 0,
1447                        "[GetMaxSustainableClock] Failed to get max DC clock from SMC!",
1448                        return ret);
1449        *clock = smum_get_argument(hwmgr);
1450
1451        /* if DC limit is zero, return AC limit */
1452        if (*clock == 0) {
1453                PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1454                        PPSMC_MSG_GetMaxDpmFreq,
1455                        (clock_select << 16))) == 0,
1456                        "[GetMaxSustainableClock] failed to get max AC clock from SMC!",
1457                        return ret);
1458                *clock = smum_get_argument(hwmgr);
1459        }
1460
1461        return 0;
1462}
1463
1464static int vega20_init_max_sustainable_clocks(struct pp_hwmgr *hwmgr)
1465{
1466        struct vega20_hwmgr *data =
1467                (struct vega20_hwmgr *)(hwmgr->backend);
1468        struct vega20_max_sustainable_clocks *max_sustainable_clocks =
1469                &(data->max_sustainable_clocks);
1470        int ret = 0;
1471
1472        max_sustainable_clocks->uclock = data->vbios_boot_state.mem_clock / 100;
1473        max_sustainable_clocks->soc_clock = data->vbios_boot_state.soc_clock / 100;
1474        max_sustainable_clocks->dcef_clock = data->vbios_boot_state.dcef_clock / 100;
1475        max_sustainable_clocks->display_clock = 0xFFFFFFFF;
1476        max_sustainable_clocks->phy_clock = 0xFFFFFFFF;
1477        max_sustainable_clocks->pixel_clock = 0xFFFFFFFF;
1478
1479        if (data->smu_features[GNLD_DPM_UCLK].enabled)
1480                PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1481                                &(max_sustainable_clocks->uclock),
1482                                PPCLK_UCLK)) == 0,
1483                                "[InitMaxSustainableClocks] failed to get max UCLK from SMC!",
1484                                return ret);
1485
1486        if (data->smu_features[GNLD_DPM_SOCCLK].enabled)
1487                PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1488                                &(max_sustainable_clocks->soc_clock),
1489                                PPCLK_SOCCLK)) == 0,
1490                                "[InitMaxSustainableClocks] failed to get max SOCCLK from SMC!",
1491                                return ret);
1492
1493        if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
1494                PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1495                                &(max_sustainable_clocks->dcef_clock),
1496                                PPCLK_DCEFCLK)) == 0,
1497                                "[InitMaxSustainableClocks] failed to get max DCEFCLK from SMC!",
1498                                return ret);
1499                PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1500                                &(max_sustainable_clocks->display_clock),
1501                                PPCLK_DISPCLK)) == 0,
1502                                "[InitMaxSustainableClocks] failed to get max DISPCLK from SMC!",
1503                                return ret);
1504                PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1505                                &(max_sustainable_clocks->phy_clock),
1506                                PPCLK_PHYCLK)) == 0,
1507                                "[InitMaxSustainableClocks] failed to get max PHYCLK from SMC!",
1508                                return ret);
1509                PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1510                                &(max_sustainable_clocks->pixel_clock),
1511                                PPCLK_PIXCLK)) == 0,
1512                                "[InitMaxSustainableClocks] failed to get max PIXCLK from SMC!",
1513                                return ret);
1514        }
1515
1516        if (max_sustainable_clocks->soc_clock < max_sustainable_clocks->uclock)
1517                max_sustainable_clocks->uclock = max_sustainable_clocks->soc_clock;
1518
1519        return 0;
1520}
1521
1522static int vega20_enable_mgpu_fan_boost(struct pp_hwmgr *hwmgr)
1523{
1524        int result;
1525
1526        result = smum_send_msg_to_smc(hwmgr,
1527                PPSMC_MSG_SetMGpuFanBoostLimitRpm);
1528        PP_ASSERT_WITH_CODE(!result,
1529                        "[EnableMgpuFan] Failed to enable mgpu fan boost!",
1530                        return result);
1531
1532        return 0;
1533}
1534
1535static void vega20_init_powergate_state(struct pp_hwmgr *hwmgr)
1536{
1537        struct vega20_hwmgr *data =
1538                (struct vega20_hwmgr *)(hwmgr->backend);
1539
1540        data->uvd_power_gated = true;
1541        data->vce_power_gated = true;
1542
1543        if (data->smu_features[GNLD_DPM_UVD].enabled)
1544                data->uvd_power_gated = false;
1545
1546        if (data->smu_features[GNLD_DPM_VCE].enabled)
1547                data->vce_power_gated = false;
1548}
1549
1550static int vega20_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
1551{
1552        int result = 0;
1553
1554        smum_send_msg_to_smc_with_parameter(hwmgr,
1555                        PPSMC_MSG_NumOfDisplays, 0);
1556
1557        result = vega20_set_allowed_featuresmask(hwmgr);
1558        PP_ASSERT_WITH_CODE(!result,
1559                        "[EnableDPMTasks] Failed to set allowed featuresmask!\n",
1560                        return result);
1561
1562        result = vega20_init_smc_table(hwmgr);
1563        PP_ASSERT_WITH_CODE(!result,
1564                        "[EnableDPMTasks] Failed to initialize SMC table!",
1565                        return result);
1566
1567        result = vega20_run_btc_afll(hwmgr);
1568        PP_ASSERT_WITH_CODE(!result,
1569                        "[EnableDPMTasks] Failed to run btc afll!",
1570                        return result);
1571
1572        result = vega20_enable_all_smu_features(hwmgr);
1573        PP_ASSERT_WITH_CODE(!result,
1574                        "[EnableDPMTasks] Failed to enable all smu features!",
1575                        return result);
1576
1577        result = vega20_notify_smc_display_change(hwmgr);
1578        PP_ASSERT_WITH_CODE(!result,
1579                        "[EnableDPMTasks] Failed to notify smc display change!",
1580                        return result);
1581
1582        result = vega20_send_clock_ratio(hwmgr);
1583        PP_ASSERT_WITH_CODE(!result,
1584                        "[EnableDPMTasks] Failed to send clock ratio!",
1585                        return result);
1586
1587        /* Initialize UVD/VCE powergating state */
1588        vega20_init_powergate_state(hwmgr);
1589
1590        result = vega20_setup_default_dpm_tables(hwmgr);
1591        PP_ASSERT_WITH_CODE(!result,
1592                        "[EnableDPMTasks] Failed to setup default DPM tables!",
1593                        return result);
1594
1595        result = vega20_init_max_sustainable_clocks(hwmgr);
1596        PP_ASSERT_WITH_CODE(!result,
1597                        "[EnableDPMTasks] Failed to get maximum sustainable clocks!",
1598                        return result);
1599
1600        result = vega20_power_control_set_level(hwmgr);
1601        PP_ASSERT_WITH_CODE(!result,
1602                        "[EnableDPMTasks] Failed to power control set level!",
1603                        return result);
1604
1605        result = vega20_od8_initialize_default_settings(hwmgr);
1606        PP_ASSERT_WITH_CODE(!result,
1607                        "[EnableDPMTasks] Failed to initialize odn settings!",
1608                        return result);
1609
1610        result = vega20_populate_umdpstate_clocks(hwmgr);
1611        PP_ASSERT_WITH_CODE(!result,
1612                        "[EnableDPMTasks] Failed to populate umdpstate clocks!",
1613                        return result);
1614
1615        result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetPptLimit,
1616                        POWER_SOURCE_AC << 16);
1617        PP_ASSERT_WITH_CODE(!result,
1618                        "[GetPptLimit] get default PPT limit failed!",
1619                        return result);
1620        hwmgr->power_limit =
1621                hwmgr->default_power_limit = smum_get_argument(hwmgr);
1622
1623        return 0;
1624}
1625
1626static uint32_t vega20_find_lowest_dpm_level(
1627                struct vega20_single_dpm_table *table)
1628{
1629        uint32_t i;
1630
1631        for (i = 0; i < table->count; i++) {
1632                if (table->dpm_levels[i].enabled)
1633                        break;
1634        }
1635        if (i >= table->count) {
1636                i = 0;
1637                table->dpm_levels[i].enabled = true;
1638        }
1639
1640        return i;
1641}
1642
1643static uint32_t vega20_find_highest_dpm_level(
1644                struct vega20_single_dpm_table *table)
1645{
1646        int i = 0;
1647
1648        PP_ASSERT_WITH_CODE(table != NULL,
1649                        "[FindHighestDPMLevel] DPM Table does not exist!",
1650                        return 0);
1651        PP_ASSERT_WITH_CODE(table->count > 0,
1652                        "[FindHighestDPMLevel] DPM Table has no entry!",
1653                        return 0);
1654        PP_ASSERT_WITH_CODE(table->count <= MAX_REGULAR_DPM_NUMBER,
1655                        "[FindHighestDPMLevel] DPM Table has too many entries!",
1656                        return MAX_REGULAR_DPM_NUMBER - 1);
1657
1658        for (i = table->count - 1; i >= 0; i--) {
1659                if (table->dpm_levels[i].enabled)
1660                        break;
1661        }
1662        if (i < 0) {
1663                i = 0;
1664                table->dpm_levels[i].enabled = true;
1665        }
1666
1667        return i;
1668}
1669
1670static int vega20_upload_dpm_min_level(struct pp_hwmgr *hwmgr, uint32_t feature_mask)
1671{
1672        struct vega20_hwmgr *data =
1673                        (struct vega20_hwmgr *)(hwmgr->backend);
1674        uint32_t min_freq;
1675        int ret = 0;
1676
1677        if (data->smu_features[GNLD_DPM_GFXCLK].enabled &&
1678           (feature_mask & FEATURE_DPM_GFXCLK_MASK)) {
1679                min_freq = data->dpm_table.gfx_table.dpm_state.soft_min_level;
1680                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1681                                        hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1682                                        (PPCLK_GFXCLK << 16) | (min_freq & 0xffff))),
1683                                        "Failed to set soft min gfxclk !",
1684                                        return ret);
1685        }
1686
1687        if (data->smu_features[GNLD_DPM_UCLK].enabled &&
1688           (feature_mask & FEATURE_DPM_UCLK_MASK)) {
1689                min_freq = data->dpm_table.mem_table.dpm_state.soft_min_level;
1690                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1691                                        hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1692                                        (PPCLK_UCLK << 16) | (min_freq & 0xffff))),
1693                                        "Failed to set soft min memclk !",
1694                                        return ret);
1695        }
1696
1697        if (data->smu_features[GNLD_DPM_UVD].enabled &&
1698           (feature_mask & FEATURE_DPM_UVD_MASK)) {
1699                min_freq = data->dpm_table.vclk_table.dpm_state.soft_min_level;
1700
1701                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1702                                        hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1703                                        (PPCLK_VCLK << 16) | (min_freq & 0xffff))),
1704                                        "Failed to set soft min vclk!",
1705                                        return ret);
1706
1707                min_freq = data->dpm_table.dclk_table.dpm_state.soft_min_level;
1708
1709                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1710                                        hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1711                                        (PPCLK_DCLK << 16) | (min_freq & 0xffff))),
1712                                        "Failed to set soft min dclk!",
1713                                        return ret);
1714        }
1715
1716        if (data->smu_features[GNLD_DPM_VCE].enabled &&
1717           (feature_mask & FEATURE_DPM_VCE_MASK)) {
1718                min_freq = data->dpm_table.eclk_table.dpm_state.soft_min_level;
1719
1720                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1721                                        hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1722                                        (PPCLK_ECLK << 16) | (min_freq & 0xffff))),
1723                                        "Failed to set soft min eclk!",
1724                                        return ret);
1725        }
1726
1727        if (data->smu_features[GNLD_DPM_SOCCLK].enabled &&
1728           (feature_mask & FEATURE_DPM_SOCCLK_MASK)) {
1729                min_freq = data->dpm_table.soc_table.dpm_state.soft_min_level;
1730
1731                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1732                                        hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1733                                        (PPCLK_SOCCLK << 16) | (min_freq & 0xffff))),
1734                                        "Failed to set soft min socclk!",
1735                                        return ret);
1736        }
1737
1738        return ret;
1739}
1740
1741static int vega20_upload_dpm_max_level(struct pp_hwmgr *hwmgr, uint32_t feature_mask)
1742{
1743        struct vega20_hwmgr *data =
1744                        (struct vega20_hwmgr *)(hwmgr->backend);
1745        uint32_t max_freq;
1746        int ret = 0;
1747
1748        if (data->smu_features[GNLD_DPM_GFXCLK].enabled &&
1749           (feature_mask & FEATURE_DPM_GFXCLK_MASK)) {
1750                max_freq = data->dpm_table.gfx_table.dpm_state.soft_max_level;
1751
1752                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1753                                        hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1754                                        (PPCLK_GFXCLK << 16) | (max_freq & 0xffff))),
1755                                        "Failed to set soft max gfxclk!",
1756                                        return ret);
1757        }
1758
1759        if (data->smu_features[GNLD_DPM_UCLK].enabled &&
1760           (feature_mask & FEATURE_DPM_UCLK_MASK)) {
1761                max_freq = data->dpm_table.mem_table.dpm_state.soft_max_level;
1762
1763                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1764                                        hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1765                                        (PPCLK_UCLK << 16) | (max_freq & 0xffff))),
1766                                        "Failed to set soft max memclk!",
1767                                        return ret);
1768        }
1769
1770        if (data->smu_features[GNLD_DPM_UVD].enabled &&
1771           (feature_mask & FEATURE_DPM_UVD_MASK)) {
1772                max_freq = data->dpm_table.vclk_table.dpm_state.soft_max_level;
1773
1774                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1775                                        hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1776                                        (PPCLK_VCLK << 16) | (max_freq & 0xffff))),
1777                                        "Failed to set soft max vclk!",
1778                                        return ret);
1779
1780                max_freq = data->dpm_table.dclk_table.dpm_state.soft_max_level;
1781                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1782                                        hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1783                                        (PPCLK_DCLK << 16) | (max_freq & 0xffff))),
1784                                        "Failed to set soft max dclk!",
1785                                        return ret);
1786        }
1787
1788        if (data->smu_features[GNLD_DPM_VCE].enabled &&
1789           (feature_mask & FEATURE_DPM_VCE_MASK)) {
1790                max_freq = data->dpm_table.eclk_table.dpm_state.soft_max_level;
1791
1792                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1793                                        hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1794                                        (PPCLK_ECLK << 16) | (max_freq & 0xffff))),
1795                                        "Failed to set soft max eclk!",
1796                                        return ret);
1797        }
1798
1799        if (data->smu_features[GNLD_DPM_SOCCLK].enabled &&
1800           (feature_mask & FEATURE_DPM_SOCCLK_MASK)) {
1801                max_freq = data->dpm_table.soc_table.dpm_state.soft_max_level;
1802
1803                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1804                                        hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1805                                        (PPCLK_SOCCLK << 16) | (max_freq & 0xffff))),
1806                                        "Failed to set soft max socclk!",
1807                                        return ret);
1808        }
1809
1810        return ret;
1811}
1812
1813int vega20_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
1814{
1815        struct vega20_hwmgr *data =
1816                        (struct vega20_hwmgr *)(hwmgr->backend);
1817        int ret = 0;
1818
1819        if (data->smu_features[GNLD_DPM_VCE].supported) {
1820                if (data->smu_features[GNLD_DPM_VCE].enabled == enable) {
1821                        if (enable)
1822                                PP_DBG_LOG("[EnableDisableVCEDPM] feature VCE DPM already enabled!\n");
1823                        else
1824                                PP_DBG_LOG("[EnableDisableVCEDPM] feature VCE DPM already disabled!\n");
1825                }
1826
1827                ret = vega20_enable_smc_features(hwmgr,
1828                                enable,
1829                                data->smu_features[GNLD_DPM_VCE].smu_feature_bitmap);
1830                PP_ASSERT_WITH_CODE(!ret,
1831                                "Attempt to Enable/Disable DPM VCE Failed!",
1832                                return ret);
1833                data->smu_features[GNLD_DPM_VCE].enabled = enable;
1834        }
1835
1836        return 0;
1837}
1838
1839static int vega20_get_clock_ranges(struct pp_hwmgr *hwmgr,
1840                uint32_t *clock,
1841                PPCLK_e clock_select,
1842                bool max)
1843{
1844        int ret;
1845        *clock = 0;
1846
1847        if (max) {
1848                PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1849                                PPSMC_MSG_GetMaxDpmFreq, (clock_select << 16))) == 0,
1850                                "[GetClockRanges] Failed to get max clock from SMC!",
1851                                return ret);
1852                *clock = smum_get_argument(hwmgr);
1853        } else {
1854                PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1855                                PPSMC_MSG_GetMinDpmFreq,
1856                                (clock_select << 16))) == 0,
1857                                "[GetClockRanges] Failed to get min clock from SMC!",
1858                                return ret);
1859                *clock = smum_get_argument(hwmgr);
1860        }
1861
1862        return 0;
1863}
1864
1865static uint32_t vega20_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
1866{
1867        struct vega20_hwmgr *data =
1868                        (struct vega20_hwmgr *)(hwmgr->backend);
1869        uint32_t gfx_clk;
1870        int ret = 0;
1871
1872        PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_GFXCLK].enabled,
1873                        "[GetSclks]: gfxclk dpm not enabled!\n",
1874                        return -EPERM);
1875
1876        if (low) {
1877                ret = vega20_get_clock_ranges(hwmgr, &gfx_clk, PPCLK_GFXCLK, false);
1878                PP_ASSERT_WITH_CODE(!ret,
1879                        "[GetSclks]: fail to get min PPCLK_GFXCLK\n",
1880                        return ret);
1881        } else {
1882                ret = vega20_get_clock_ranges(hwmgr, &gfx_clk, PPCLK_GFXCLK, true);
1883                PP_ASSERT_WITH_CODE(!ret,
1884                        "[GetSclks]: fail to get max PPCLK_GFXCLK\n",
1885                        return ret);
1886        }
1887
1888        return (gfx_clk * 100);
1889}
1890
1891static uint32_t vega20_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
1892{
1893        struct vega20_hwmgr *data =
1894                        (struct vega20_hwmgr *)(hwmgr->backend);
1895        uint32_t mem_clk;
1896        int ret = 0;
1897
1898        PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_UCLK].enabled,
1899                        "[MemMclks]: memclk dpm not enabled!\n",
1900                        return -EPERM);
1901
1902        if (low) {
1903                ret = vega20_get_clock_ranges(hwmgr, &mem_clk, PPCLK_UCLK, false);
1904                PP_ASSERT_WITH_CODE(!ret,
1905                        "[GetMclks]: fail to get min PPCLK_UCLK\n",
1906                        return ret);
1907        } else {
1908                ret = vega20_get_clock_ranges(hwmgr, &mem_clk, PPCLK_UCLK, true);
1909                PP_ASSERT_WITH_CODE(!ret,
1910                        "[GetMclks]: fail to get max PPCLK_UCLK\n",
1911                        return ret);
1912        }
1913
1914        return (mem_clk * 100);
1915}
1916
1917static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr,
1918                uint32_t *query)
1919{
1920        int ret = 0;
1921        SmuMetrics_t metrics_table;
1922
1923        ret = smum_smc_table_manager(hwmgr, (uint8_t *)&metrics_table, TABLE_SMU_METRICS, true);
1924        PP_ASSERT_WITH_CODE(!ret,
1925                        "Failed to export SMU METRICS table!",
1926                        return ret);
1927
1928        *query = metrics_table.CurrSocketPower << 8;
1929
1930        return ret;
1931}
1932
1933static int vega20_get_current_clk_freq(struct pp_hwmgr *hwmgr,
1934                PPCLK_e clk_id, uint32_t *clk_freq)
1935{
1936        int ret = 0;
1937
1938        *clk_freq = 0;
1939
1940        PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1941                        PPSMC_MSG_GetDpmClockFreq, (clk_id << 16))) == 0,
1942                        "[GetCurrentClkFreq] Attempt to get Current Frequency Failed!",
1943                        return ret);
1944        *clk_freq = smum_get_argument(hwmgr);
1945
1946        *clk_freq = *clk_freq * 100;
1947
1948        return 0;
1949}
1950
1951static int vega20_get_current_activity_percent(struct pp_hwmgr *hwmgr,
1952                uint32_t *activity_percent)
1953{
1954        int ret = 0;
1955        SmuMetrics_t metrics_table;
1956
1957        ret = smum_smc_table_manager(hwmgr, (uint8_t *)&metrics_table, TABLE_SMU_METRICS, true);
1958        PP_ASSERT_WITH_CODE(!ret,
1959                        "Failed to export SMU METRICS table!",
1960                        return ret);
1961
1962        *activity_percent = metrics_table.AverageGfxActivity;
1963
1964        return ret;
1965}
1966
1967static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx,
1968                              void *value, int *size)
1969{
1970        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1971        struct amdgpu_device *adev = hwmgr->adev;
1972        uint32_t val_vid;
1973        int ret = 0;
1974
1975        switch (idx) {
1976        case AMDGPU_PP_SENSOR_GFX_SCLK:
1977                ret = vega20_get_current_clk_freq(hwmgr,
1978                                PPCLK_GFXCLK,
1979                                (uint32_t *)value);
1980                if (!ret)
1981                        *size = 4;
1982                break;
1983        case AMDGPU_PP_SENSOR_GFX_MCLK:
1984                ret = vega20_get_current_clk_freq(hwmgr,
1985                                PPCLK_UCLK,
1986                                (uint32_t *)value);
1987                if (!ret)
1988                        *size = 4;
1989                break;
1990        case AMDGPU_PP_SENSOR_GPU_LOAD:
1991                ret = vega20_get_current_activity_percent(hwmgr, (uint32_t *)value);
1992                if (!ret)
1993                        *size = 4;
1994                break;
1995        case AMDGPU_PP_SENSOR_GPU_TEMP:
1996                *((uint32_t *)value) = vega20_thermal_get_temperature(hwmgr);
1997                *size = 4;
1998                break;
1999        case AMDGPU_PP_SENSOR_UVD_POWER:
2000                *((uint32_t *)value) = data->uvd_power_gated ? 0 : 1;
2001                *size = 4;
2002                break;
2003        case AMDGPU_PP_SENSOR_VCE_POWER:
2004                *((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
2005                *size = 4;
2006                break;
2007        case AMDGPU_PP_SENSOR_GPU_POWER:
2008                *size = 16;
2009                ret = vega20_get_gpu_power(hwmgr, (uint32_t *)value);
2010                break;
2011        case AMDGPU_PP_SENSOR_VDDGFX:
2012                val_vid = (RREG32_SOC15(SMUIO, 0, mmSMUSVI0_TEL_PLANE0) &
2013                        SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR_MASK) >>
2014                        SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR__SHIFT;
2015                *((uint32_t *)value) =
2016                        (uint32_t)convert_to_vddc((uint8_t)val_vid);
2017                break;
2018        case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK:
2019                ret = vega20_get_enabled_smc_features(hwmgr, (uint64_t *)value);
2020                if (!ret)
2021                        *size = 8;
2022                break;
2023        default:
2024                ret = -EINVAL;
2025                break;
2026        }
2027        return ret;
2028}
2029
2030int vega20_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
2031                struct pp_display_clock_request *clock_req)
2032{
2033        int result = 0;
2034        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2035        enum amd_pp_clock_type clk_type = clock_req->clock_type;
2036        uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
2037        PPCLK_e clk_select = 0;
2038        uint32_t clk_request = 0;
2039
2040        if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
2041                switch (clk_type) {
2042                case amd_pp_dcef_clock:
2043                        clk_select = PPCLK_DCEFCLK;
2044                        break;
2045                case amd_pp_disp_clock:
2046                        clk_select = PPCLK_DISPCLK;
2047                        break;
2048                case amd_pp_pixel_clock:
2049                        clk_select = PPCLK_PIXCLK;
2050                        break;
2051                case amd_pp_phy_clock:
2052                        clk_select = PPCLK_PHYCLK;
2053                        break;
2054                default:
2055                        pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!");
2056                        result = -EINVAL;
2057                        break;
2058                }
2059
2060                if (!result) {
2061                        clk_request = (clk_select << 16) | clk_freq;
2062                        result = smum_send_msg_to_smc_with_parameter(hwmgr,
2063                                        PPSMC_MSG_SetHardMinByFreq,
2064                                        clk_request);
2065                }
2066        }
2067
2068        return result;
2069}
2070
2071static int vega20_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state,
2072                                PHM_PerformanceLevelDesignation designation, uint32_t index,
2073                                PHM_PerformanceLevel *level)
2074{
2075        return 0;
2076}
2077
2078static int vega20_notify_smc_display_config_after_ps_adjustment(
2079                struct pp_hwmgr *hwmgr)
2080{
2081        struct vega20_hwmgr *data =
2082                        (struct vega20_hwmgr *)(hwmgr->backend);
2083        struct vega20_single_dpm_table *dpm_table =
2084                        &data->dpm_table.mem_table;
2085        struct PP_Clocks min_clocks = {0};
2086        struct pp_display_clock_request clock_req;
2087        int ret = 0;
2088
2089        min_clocks.dcefClock = hwmgr->display_config->min_dcef_set_clk;
2090        min_clocks.dcefClockInSR = hwmgr->display_config->min_dcef_deep_sleep_set_clk;
2091        min_clocks.memoryClock = hwmgr->display_config->min_mem_set_clock;
2092
2093        if (data->smu_features[GNLD_DPM_DCEFCLK].supported) {
2094                clock_req.clock_type = amd_pp_dcef_clock;
2095                clock_req.clock_freq_in_khz = min_clocks.dcefClock * 10;
2096                if (!vega20_display_clock_voltage_request(hwmgr, &clock_req)) {
2097                        if (data->smu_features[GNLD_DS_DCEFCLK].supported)
2098                                PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(
2099                                        hwmgr, PPSMC_MSG_SetMinDeepSleepDcefclk,
2100                                        min_clocks.dcefClockInSR / 100)) == 0,
2101                                        "Attempt to set divider for DCEFCLK Failed!",
2102                                        return ret);
2103                } else {
2104                        pr_info("Attempt to set Hard Min for DCEFCLK Failed!");
2105                }
2106        }
2107
2108        if (data->smu_features[GNLD_DPM_UCLK].enabled) {
2109                dpm_table->dpm_state.hard_min_level = min_clocks.memoryClock / 100;
2110                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(hwmgr,
2111                                PPSMC_MSG_SetHardMinByFreq,
2112                                (PPCLK_UCLK << 16 ) | dpm_table->dpm_state.hard_min_level)),
2113                                "[SetHardMinFreq] Set hard min uclk failed!",
2114                                return ret);
2115        }
2116
2117        return 0;
2118}
2119
2120static int vega20_force_dpm_highest(struct pp_hwmgr *hwmgr)
2121{
2122        struct vega20_hwmgr *data =
2123                        (struct vega20_hwmgr *)(hwmgr->backend);
2124        uint32_t soft_level;
2125        int ret = 0;
2126
2127        soft_level = vega20_find_highest_dpm_level(&(data->dpm_table.gfx_table));
2128
2129        data->dpm_table.gfx_table.dpm_state.soft_min_level =
2130                data->dpm_table.gfx_table.dpm_state.soft_max_level =
2131                data->dpm_table.gfx_table.dpm_levels[soft_level].value;
2132
2133        soft_level = vega20_find_highest_dpm_level(&(data->dpm_table.mem_table));
2134
2135        data->dpm_table.mem_table.dpm_state.soft_min_level =
2136                data->dpm_table.mem_table.dpm_state.soft_max_level =
2137                data->dpm_table.mem_table.dpm_levels[soft_level].value;
2138
2139        ret = vega20_upload_dpm_min_level(hwmgr, 0xFFFFFFFF);
2140        PP_ASSERT_WITH_CODE(!ret,
2141                        "Failed to upload boot level to highest!",
2142                        return ret);
2143
2144        ret = vega20_upload_dpm_max_level(hwmgr, 0xFFFFFFFF);
2145        PP_ASSERT_WITH_CODE(!ret,
2146                        "Failed to upload dpm max level to highest!",
2147                        return ret);
2148
2149        return 0;
2150}
2151
2152static int vega20_force_dpm_lowest(struct pp_hwmgr *hwmgr)
2153{
2154        struct vega20_hwmgr *data =
2155                        (struct vega20_hwmgr *)(hwmgr->backend);
2156        uint32_t soft_level;
2157        int ret = 0;
2158
2159        soft_level = vega20_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
2160
2161        data->dpm_table.gfx_table.dpm_state.soft_min_level =
2162                data->dpm_table.gfx_table.dpm_state.soft_max_level =
2163                data->dpm_table.gfx_table.dpm_levels[soft_level].value;
2164
2165        soft_level = vega20_find_lowest_dpm_level(&(data->dpm_table.mem_table));
2166
2167        data->dpm_table.mem_table.dpm_state.soft_min_level =
2168                data->dpm_table.mem_table.dpm_state.soft_max_level =
2169                data->dpm_table.mem_table.dpm_levels[soft_level].value;
2170
2171        ret = vega20_upload_dpm_min_level(hwmgr, 0xFFFFFFFF);
2172        PP_ASSERT_WITH_CODE(!ret,
2173                        "Failed to upload boot level to highest!",
2174                        return ret);
2175
2176        ret = vega20_upload_dpm_max_level(hwmgr, 0xFFFFFFFF);
2177        PP_ASSERT_WITH_CODE(!ret,
2178                        "Failed to upload dpm max level to highest!",
2179                        return ret);
2180
2181        return 0;
2182
2183}
2184
2185static int vega20_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
2186{
2187        int ret = 0;
2188
2189        ret = vega20_upload_dpm_min_level(hwmgr, 0xFFFFFFFF);
2190        PP_ASSERT_WITH_CODE(!ret,
2191                        "Failed to upload DPM Bootup Levels!",
2192                        return ret);
2193
2194        ret = vega20_upload_dpm_max_level(hwmgr, 0xFFFFFFFF);
2195        PP_ASSERT_WITH_CODE(!ret,
2196                        "Failed to upload DPM Max Levels!",
2197                        return ret);
2198
2199        return 0;
2200}
2201
2202static int vega20_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level,
2203                                uint32_t *sclk_mask, uint32_t *mclk_mask, uint32_t *soc_mask)
2204{
2205        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2206        struct vega20_single_dpm_table *gfx_dpm_table = &(data->dpm_table.gfx_table);
2207        struct vega20_single_dpm_table *mem_dpm_table = &(data->dpm_table.mem_table);
2208        struct vega20_single_dpm_table *soc_dpm_table = &(data->dpm_table.soc_table);
2209
2210        *sclk_mask = 0;
2211        *mclk_mask = 0;
2212        *soc_mask  = 0;
2213
2214        if (gfx_dpm_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
2215            mem_dpm_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL &&
2216            soc_dpm_table->count > VEGA20_UMD_PSTATE_SOCCLK_LEVEL) {
2217                *sclk_mask = VEGA20_UMD_PSTATE_GFXCLK_LEVEL;
2218                *mclk_mask = VEGA20_UMD_PSTATE_MCLK_LEVEL;
2219                *soc_mask  = VEGA20_UMD_PSTATE_SOCCLK_LEVEL;
2220        }
2221
2222        if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
2223                *sclk_mask = 0;
2224        } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
2225                *mclk_mask = 0;
2226        } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2227                *sclk_mask = gfx_dpm_table->count - 1;
2228                *mclk_mask = mem_dpm_table->count - 1;
2229                *soc_mask  = soc_dpm_table->count - 1;
2230        }
2231
2232        return 0;
2233}
2234
2235static int vega20_force_clock_level(struct pp_hwmgr *hwmgr,
2236                enum pp_clock_type type, uint32_t mask)
2237{
2238        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2239        uint32_t soft_min_level, soft_max_level;
2240        int ret = 0;
2241
2242        switch (type) {
2243        case PP_SCLK:
2244                soft_min_level = mask ? (ffs(mask) - 1) : 0;
2245                soft_max_level = mask ? (fls(mask) - 1) : 0;
2246
2247                if (soft_max_level >= data->dpm_table.gfx_table.count) {
2248                        pr_err("Clock level specified %d is over max allowed %d\n",
2249                                        soft_max_level,
2250                                        data->dpm_table.gfx_table.count - 1);
2251                        return -EINVAL;
2252                }
2253
2254                data->dpm_table.gfx_table.dpm_state.soft_min_level =
2255                        data->dpm_table.gfx_table.dpm_levels[soft_min_level].value;
2256                data->dpm_table.gfx_table.dpm_state.soft_max_level =
2257                        data->dpm_table.gfx_table.dpm_levels[soft_max_level].value;
2258
2259                ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK);
2260                PP_ASSERT_WITH_CODE(!ret,
2261                        "Failed to upload boot level to lowest!",
2262                        return ret);
2263
2264                ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK);
2265                PP_ASSERT_WITH_CODE(!ret,
2266                        "Failed to upload dpm max level to highest!",
2267                        return ret);
2268                break;
2269
2270        case PP_MCLK:
2271                soft_min_level = mask ? (ffs(mask) - 1) : 0;
2272                soft_max_level = mask ? (fls(mask) - 1) : 0;
2273
2274                if (soft_max_level >= data->dpm_table.mem_table.count) {
2275                        pr_err("Clock level specified %d is over max allowed %d\n",
2276                                        soft_max_level,
2277                                        data->dpm_table.mem_table.count - 1);
2278                        return -EINVAL;
2279                }
2280
2281                data->dpm_table.mem_table.dpm_state.soft_min_level =
2282                        data->dpm_table.mem_table.dpm_levels[soft_min_level].value;
2283                data->dpm_table.mem_table.dpm_state.soft_max_level =
2284                        data->dpm_table.mem_table.dpm_levels[soft_max_level].value;
2285
2286                ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_UCLK_MASK);
2287                PP_ASSERT_WITH_CODE(!ret,
2288                        "Failed to upload boot level to lowest!",
2289                        return ret);
2290
2291                ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_UCLK_MASK);
2292                PP_ASSERT_WITH_CODE(!ret,
2293                        "Failed to upload dpm max level to highest!",
2294                        return ret);
2295
2296                break;
2297
2298        case PP_PCIE:
2299                soft_min_level = mask ? (ffs(mask) - 1) : 0;
2300                soft_max_level = mask ? (fls(mask) - 1) : 0;
2301                if (soft_min_level >= NUM_LINK_LEVELS ||
2302                    soft_max_level >= NUM_LINK_LEVELS)
2303                        return -EINVAL;
2304
2305                ret = smum_send_msg_to_smc_with_parameter(hwmgr,
2306                        PPSMC_MSG_SetMinLinkDpmByIndex, soft_min_level);
2307                PP_ASSERT_WITH_CODE(!ret,
2308                        "Failed to set min link dpm level!",
2309                        return ret);
2310
2311                break;
2312
2313        default:
2314                break;
2315        }
2316
2317        return 0;
2318}
2319
2320static int vega20_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
2321                                enum amd_dpm_forced_level level)
2322{
2323        int ret = 0;
2324        uint32_t sclk_mask, mclk_mask, soc_mask;
2325
2326        switch (level) {
2327        case AMD_DPM_FORCED_LEVEL_HIGH:
2328                ret = vega20_force_dpm_highest(hwmgr);
2329                break;
2330
2331        case AMD_DPM_FORCED_LEVEL_LOW:
2332                ret = vega20_force_dpm_lowest(hwmgr);
2333                break;
2334
2335        case AMD_DPM_FORCED_LEVEL_AUTO:
2336                ret = vega20_unforce_dpm_levels(hwmgr);
2337                break;
2338
2339        case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
2340        case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
2341        case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
2342        case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
2343                ret = vega20_get_profiling_clk_mask(hwmgr, level, &sclk_mask, &mclk_mask, &soc_mask);
2344                if (ret)
2345                        return ret;
2346                vega20_force_clock_level(hwmgr, PP_SCLK, 1 << sclk_mask);
2347                vega20_force_clock_level(hwmgr, PP_MCLK, 1 << mclk_mask);
2348                break;
2349
2350        case AMD_DPM_FORCED_LEVEL_MANUAL:
2351        case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
2352        default:
2353                break;
2354        }
2355
2356        return ret;
2357}
2358
2359static uint32_t vega20_get_fan_control_mode(struct pp_hwmgr *hwmgr)
2360{
2361        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2362
2363        if (data->smu_features[GNLD_FAN_CONTROL].enabled == false)
2364                return AMD_FAN_CTRL_MANUAL;
2365        else
2366                return AMD_FAN_CTRL_AUTO;
2367}
2368
2369static void vega20_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
2370{
2371        switch (mode) {
2372        case AMD_FAN_CTRL_NONE:
2373                vega20_fan_ctrl_set_fan_speed_percent(hwmgr, 100);
2374                break;
2375        case AMD_FAN_CTRL_MANUAL:
2376                if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
2377                        vega20_fan_ctrl_stop_smc_fan_control(hwmgr);
2378                break;
2379        case AMD_FAN_CTRL_AUTO:
2380                if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
2381                        vega20_fan_ctrl_start_smc_fan_control(hwmgr);
2382                break;
2383        default:
2384                break;
2385        }
2386}
2387
2388static int vega20_get_dal_power_level(struct pp_hwmgr *hwmgr,
2389                struct amd_pp_simple_clock_info *info)
2390{
2391#if 0
2392        struct phm_ppt_v2_information *table_info =
2393                        (struct phm_ppt_v2_information *)hwmgr->pptable;
2394        struct phm_clock_and_voltage_limits *max_limits =
2395                        &table_info->max_clock_voltage_on_ac;
2396
2397        info->engine_max_clock = max_limits->sclk;
2398        info->memory_max_clock = max_limits->mclk;
2399#endif
2400        return 0;
2401}
2402
2403
2404static int vega20_get_sclks(struct pp_hwmgr *hwmgr,
2405                struct pp_clock_levels_with_latency *clocks)
2406{
2407        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2408        struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.gfx_table);
2409        int i, count;
2410
2411        PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_GFXCLK].enabled,
2412                "[GetSclks]: gfxclk dpm not enabled!\n",
2413                return -EPERM);
2414
2415        count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2416        clocks->num_levels = count;
2417
2418        for (i = 0; i < count; i++) {
2419                clocks->data[i].clocks_in_khz =
2420                        dpm_table->dpm_levels[i].value * 1000;
2421                clocks->data[i].latency_in_us = 0;
2422        }
2423
2424        return 0;
2425}
2426
2427static uint32_t vega20_get_mem_latency(struct pp_hwmgr *hwmgr,
2428                uint32_t clock)
2429{
2430        return 25;
2431}
2432
2433static int vega20_get_memclocks(struct pp_hwmgr *hwmgr,
2434                struct pp_clock_levels_with_latency *clocks)
2435{
2436        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2437        struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.mem_table);
2438        int i, count;
2439
2440        PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_UCLK].enabled,
2441                "[GetMclks]: uclk dpm not enabled!\n",
2442                return -EPERM);
2443
2444        count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2445        clocks->num_levels = data->mclk_latency_table.count = count;
2446
2447        for (i = 0; i < count; i++) {
2448                clocks->data[i].clocks_in_khz =
2449                        data->mclk_latency_table.entries[i].frequency =
2450                        dpm_table->dpm_levels[i].value * 1000;
2451                clocks->data[i].latency_in_us =
2452                        data->mclk_latency_table.entries[i].latency =
2453                        vega20_get_mem_latency(hwmgr, dpm_table->dpm_levels[i].value);
2454        }
2455
2456        return 0;
2457}
2458
2459static int vega20_get_dcefclocks(struct pp_hwmgr *hwmgr,
2460                struct pp_clock_levels_with_latency *clocks)
2461{
2462        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2463        struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.dcef_table);
2464        int i, count;
2465
2466        PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_DCEFCLK].enabled,
2467                "[GetDcfclocks]: dcefclk dpm not enabled!\n",
2468                return -EPERM);
2469
2470        count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2471        clocks->num_levels = count;
2472
2473        for (i = 0; i < count; i++) {
2474                clocks->data[i].clocks_in_khz =
2475                        dpm_table->dpm_levels[i].value * 1000;
2476                clocks->data[i].latency_in_us = 0;
2477        }
2478
2479        return 0;
2480}
2481
2482static int vega20_get_socclocks(struct pp_hwmgr *hwmgr,
2483                struct pp_clock_levels_with_latency *clocks)
2484{
2485        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2486        struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.soc_table);
2487        int i, count;
2488
2489        PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_SOCCLK].enabled,
2490                "[GetSocclks]: socclk dpm not enabled!\n",
2491                return -EPERM);
2492
2493        count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2494        clocks->num_levels = count;
2495
2496        for (i = 0; i < count; i++) {
2497                clocks->data[i].clocks_in_khz =
2498                        dpm_table->dpm_levels[i].value * 1000;
2499                clocks->data[i].latency_in_us = 0;
2500        }
2501
2502        return 0;
2503
2504}
2505
2506static int vega20_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr,
2507                enum amd_pp_clock_type type,
2508                struct pp_clock_levels_with_latency *clocks)
2509{
2510        int ret;
2511
2512        switch (type) {
2513        case amd_pp_sys_clock:
2514                ret = vega20_get_sclks(hwmgr, clocks);
2515                break;
2516        case amd_pp_mem_clock:
2517                ret = vega20_get_memclocks(hwmgr, clocks);
2518                break;
2519        case amd_pp_dcef_clock:
2520                ret = vega20_get_dcefclocks(hwmgr, clocks);
2521                break;
2522        case amd_pp_soc_clock:
2523                ret = vega20_get_socclocks(hwmgr, clocks);
2524                break;
2525        default:
2526                return -EINVAL;
2527        }
2528
2529        return ret;
2530}
2531
2532static int vega20_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr,
2533                enum amd_pp_clock_type type,
2534                struct pp_clock_levels_with_voltage *clocks)
2535{
2536        clocks->num_levels = 0;
2537
2538        return 0;
2539}
2540
2541static int vega20_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr,
2542                                                   void *clock_ranges)
2543{
2544        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2545        Watermarks_t *table = &(data->smc_state_table.water_marks_table);
2546        struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges;
2547
2548        if (!data->registry_data.disable_water_mark &&
2549            data->smu_features[GNLD_DPM_DCEFCLK].supported &&
2550            data->smu_features[GNLD_DPM_SOCCLK].supported) {
2551                smu_set_watermarks_for_clocks_ranges(table, wm_with_clock_ranges);
2552                data->water_marks_bitmap |= WaterMarksExist;
2553                data->water_marks_bitmap &= ~WaterMarksLoaded;
2554        }
2555
2556        return 0;
2557}
2558
2559static int vega20_odn_edit_dpm_table(struct pp_hwmgr *hwmgr,
2560                                        enum PP_OD_DPM_TABLE_COMMAND type,
2561                                        long *input, uint32_t size)
2562{
2563        struct vega20_hwmgr *data =
2564                        (struct vega20_hwmgr *)(hwmgr->backend);
2565        struct vega20_od8_single_setting *od8_settings =
2566                        data->od8_settings.od8_settings_array;
2567        OverDriveTable_t *od_table =
2568                        &(data->smc_state_table.overdrive_table);
2569        struct pp_clock_levels_with_latency clocks;
2570        int32_t input_index, input_clk, input_vol, i;
2571        int od8_id;
2572        int ret;
2573
2574        PP_ASSERT_WITH_CODE(input, "NULL user input for clock and voltage",
2575                                return -EINVAL);
2576
2577        switch (type) {
2578        case PP_OD_EDIT_SCLK_VDDC_TABLE:
2579                if (!(od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
2580                      od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id)) {
2581                        pr_info("Sclk min/max frequency overdrive not supported\n");
2582                        return -EOPNOTSUPP;
2583                }
2584
2585                for (i = 0; i < size; i += 2) {
2586                        if (i + 2 > size) {
2587                                pr_info("invalid number of input parameters %d\n",
2588                                        size);
2589                                return -EINVAL;
2590                        }
2591
2592                        input_index = input[i];
2593                        input_clk = input[i + 1];
2594
2595                        if (input_index != 0 && input_index != 1) {
2596                                pr_info("Invalid index %d\n", input_index);
2597                                pr_info("Support min/max sclk frequency setting only which index by 0/1\n");
2598                                return -EINVAL;
2599                        }
2600
2601                        if (input_clk < od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value ||
2602                            input_clk > od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value) {
2603                                pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2604                                        input_clk,
2605                                        od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value,
2606                                        od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value);
2607                                return -EINVAL;
2608                        }
2609
2610                        if ((input_index == 0 && od_table->GfxclkFmin != input_clk) ||
2611                            (input_index == 1 && od_table->GfxclkFmax != input_clk))
2612                                data->gfxclk_overdrive = true;
2613
2614                        if (input_index == 0)
2615                                od_table->GfxclkFmin = input_clk;
2616                        else
2617                                od_table->GfxclkFmax = input_clk;
2618                }
2619
2620                break;
2621
2622        case PP_OD_EDIT_MCLK_VDDC_TABLE:
2623                if (!od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
2624                        pr_info("Mclk max frequency overdrive not supported\n");
2625                        return -EOPNOTSUPP;
2626                }
2627
2628                ret = vega20_get_memclocks(hwmgr, &clocks);
2629                PP_ASSERT_WITH_CODE(!ret,
2630                                "Attempt to get memory clk levels failed!",
2631                                return ret);
2632
2633                for (i = 0; i < size; i += 2) {
2634                        if (i + 2 > size) {
2635                                pr_info("invalid number of input parameters %d\n",
2636                                        size);
2637                                return -EINVAL;
2638                        }
2639
2640                        input_index = input[i];
2641                        input_clk = input[i + 1];
2642
2643                        if (input_index != 1) {
2644                                pr_info("Invalid index %d\n", input_index);
2645                                pr_info("Support max Mclk frequency setting only which index by 1\n");
2646                                return -EINVAL;
2647                        }
2648
2649                        if (input_clk < clocks.data[0].clocks_in_khz / 1000 ||
2650                            input_clk > od8_settings[OD8_SETTING_UCLK_FMAX].max_value) {
2651                                pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2652                                        input_clk,
2653                                        clocks.data[0].clocks_in_khz / 1000,
2654                                        od8_settings[OD8_SETTING_UCLK_FMAX].max_value);
2655                                return -EINVAL;
2656                        }
2657
2658                        if (input_index == 1 && od_table->UclkFmax != input_clk)
2659                                data->memclk_overdrive = true;
2660
2661                        od_table->UclkFmax = input_clk;
2662                }
2663
2664                break;
2665
2666        case PP_OD_EDIT_VDDC_CURVE:
2667                if (!(od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
2668                    od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
2669                    od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
2670                    od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
2671                    od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
2672                    od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id)) {
2673                        pr_info("Voltage curve calibrate not supported\n");
2674                        return -EOPNOTSUPP;
2675                }
2676
2677                for (i = 0; i < size; i += 3) {
2678                        if (i + 3 > size) {
2679                                pr_info("invalid number of input parameters %d\n",
2680                                        size);
2681                                return -EINVAL;
2682                        }
2683
2684                        input_index = input[i];
2685                        input_clk = input[i + 1];
2686                        input_vol = input[i + 2];
2687
2688                        if (input_index > 2) {
2689                                pr_info("Setting for point %d is not supported\n",
2690                                                input_index + 1);
2691                                pr_info("Three supported points index by 0, 1, 2\n");
2692                                return -EINVAL;
2693                        }
2694
2695                        od8_id = OD8_SETTING_GFXCLK_FREQ1 + 2 * input_index;
2696                        if (input_clk < od8_settings[od8_id].min_value ||
2697                            input_clk > od8_settings[od8_id].max_value) {
2698                                pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2699                                        input_clk,
2700                                        od8_settings[od8_id].min_value,
2701                                        od8_settings[od8_id].max_value);
2702                                return -EINVAL;
2703                        }
2704
2705                        od8_id = OD8_SETTING_GFXCLK_VOLTAGE1 + 2 * input_index;
2706                        if (input_vol < od8_settings[od8_id].min_value ||
2707                            input_vol > od8_settings[od8_id].max_value) {
2708                                pr_info("clock voltage %d is not within allowed range [%d - %d]\n",
2709                                        input_vol,
2710                                        od8_settings[od8_id].min_value,
2711                                        od8_settings[od8_id].max_value);
2712                                return -EINVAL;
2713                        }
2714
2715                        switch (input_index) {
2716                        case 0:
2717                                od_table->GfxclkFreq1 = input_clk;
2718                                od_table->GfxclkVolt1 = input_vol * VOLTAGE_SCALE;
2719                                break;
2720                        case 1:
2721                                od_table->GfxclkFreq2 = input_clk;
2722                                od_table->GfxclkVolt2 = input_vol * VOLTAGE_SCALE;
2723                                break;
2724                        case 2:
2725                                od_table->GfxclkFreq3 = input_clk;
2726                                od_table->GfxclkVolt3 = input_vol * VOLTAGE_SCALE;
2727                                break;
2728                        }
2729                }
2730                break;
2731
2732        case PP_OD_RESTORE_DEFAULT_TABLE:
2733                data->gfxclk_overdrive = false;
2734                data->memclk_overdrive = false;
2735
2736                ret = smum_smc_table_manager(hwmgr,
2737                                             (uint8_t *)od_table,
2738                                             TABLE_OVERDRIVE, true);
2739                PP_ASSERT_WITH_CODE(!ret,
2740                                "Failed to export overdrive table!",
2741                                return ret);
2742                break;
2743
2744        case PP_OD_COMMIT_DPM_TABLE:
2745                ret = smum_smc_table_manager(hwmgr,
2746                                             (uint8_t *)od_table,
2747                                             TABLE_OVERDRIVE, false);
2748                PP_ASSERT_WITH_CODE(!ret,
2749                                "Failed to import overdrive table!",
2750                                return ret);
2751
2752                /* retrieve updated gfxclk table */
2753                if (data->gfxclk_overdrive) {
2754                        data->gfxclk_overdrive = false;
2755
2756                        ret = vega20_setup_gfxclk_dpm_table(hwmgr);
2757                        if (ret)
2758                                return ret;
2759                }
2760
2761                /* retrieve updated memclk table */
2762                if (data->memclk_overdrive) {
2763                        data->memclk_overdrive = false;
2764
2765                        ret = vega20_setup_memclk_dpm_table(hwmgr);
2766                        if (ret)
2767                                return ret;
2768                }
2769                break;
2770
2771        default:
2772                return -EINVAL;
2773        }
2774
2775        return 0;
2776}
2777
2778static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
2779                enum pp_clock_type type, char *buf)
2780{
2781        struct vega20_hwmgr *data =
2782                        (struct vega20_hwmgr *)(hwmgr->backend);
2783        struct vega20_od8_single_setting *od8_settings =
2784                        data->od8_settings.od8_settings_array;
2785        OverDriveTable_t *od_table =
2786                        &(data->smc_state_table.overdrive_table);
2787        struct phm_ppt_v3_information *pptable_information =
2788                (struct phm_ppt_v3_information *)hwmgr->pptable;
2789        PPTable_t *pptable = (PPTable_t *)pptable_information->smc_pptable;
2790        struct amdgpu_device *adev = hwmgr->adev;
2791        struct pp_clock_levels_with_latency clocks;
2792        int i, now, size = 0;
2793        int ret = 0;
2794        uint32_t gen_speed, lane_width;
2795
2796        switch (type) {
2797        case PP_SCLK:
2798                ret = vega20_get_current_clk_freq(hwmgr, PPCLK_GFXCLK, &now);
2799                PP_ASSERT_WITH_CODE(!ret,
2800                                "Attempt to get current gfx clk Failed!",
2801                                return ret);
2802
2803                ret = vega20_get_sclks(hwmgr, &clocks);
2804                PP_ASSERT_WITH_CODE(!ret,
2805                                "Attempt to get gfx clk levels Failed!",
2806                                return ret);
2807
2808                for (i = 0; i < clocks.num_levels; i++)
2809                        size += sprintf(buf + size, "%d: %uMhz %s\n",
2810                                i, clocks.data[i].clocks_in_khz / 1000,
2811                                (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
2812                break;
2813
2814        case PP_MCLK:
2815                ret = vega20_get_current_clk_freq(hwmgr, PPCLK_UCLK, &now);
2816                PP_ASSERT_WITH_CODE(!ret,
2817                                "Attempt to get current mclk freq Failed!",
2818                                return ret);
2819
2820                ret = vega20_get_memclocks(hwmgr, &clocks);
2821                PP_ASSERT_WITH_CODE(!ret,
2822                                "Attempt to get memory clk levels Failed!",
2823                                return ret);
2824
2825                for (i = 0; i < clocks.num_levels; i++)
2826                        size += sprintf(buf + size, "%d: %uMhz %s\n",
2827                                i, clocks.data[i].clocks_in_khz / 1000,
2828                                (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
2829                break;
2830
2831        case PP_PCIE:
2832                gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) &
2833                             PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK)
2834                            >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
2835                lane_width = (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) &
2836                              PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK)
2837                            >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT;
2838                for (i = 0; i < NUM_LINK_LEVELS; i++)
2839                        size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
2840                                        (pptable->PcieGenSpeed[i] == 0) ? "2.5GT/s," :
2841                                        (pptable->PcieGenSpeed[i] == 1) ? "5.0GT/s," :
2842                                        (pptable->PcieGenSpeed[i] == 2) ? "8.0GT/s," :
2843                                        (pptable->PcieGenSpeed[i] == 3) ? "16.0GT/s," : "",
2844                                        (pptable->PcieLaneCount[i] == 1) ? "x1" :
2845                                        (pptable->PcieLaneCount[i] == 2) ? "x2" :
2846                                        (pptable->PcieLaneCount[i] == 3) ? "x4" :
2847                                        (pptable->PcieLaneCount[i] == 4) ? "x8" :
2848                                        (pptable->PcieLaneCount[i] == 5) ? "x12" :
2849                                        (pptable->PcieLaneCount[i] == 6) ? "x16" : "",
2850                                        pptable->LclkFreq[i],
2851                                        (gen_speed == pptable->PcieGenSpeed[i]) &&
2852                                        (lane_width == pptable->PcieLaneCount[i]) ?
2853                                        "*" : "");
2854                break;
2855
2856        case OD_SCLK:
2857                if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
2858                    od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
2859                        size = sprintf(buf, "%s:\n", "OD_SCLK");
2860                        size += sprintf(buf + size, "0: %10uMhz\n",
2861                                od_table->GfxclkFmin);
2862                        size += sprintf(buf + size, "1: %10uMhz\n",
2863                                od_table->GfxclkFmax);
2864                }
2865                break;
2866
2867        case OD_MCLK:
2868                if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
2869                        size = sprintf(buf, "%s:\n", "OD_MCLK");
2870                        size += sprintf(buf + size, "1: %10uMhz\n",
2871                                od_table->UclkFmax);
2872                }
2873
2874                break;
2875
2876        case OD_VDDC_CURVE:
2877                if (od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
2878                    od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
2879                    od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
2880                    od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
2881                    od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
2882                    od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
2883                        size = sprintf(buf, "%s:\n", "OD_VDDC_CURVE");
2884                        size += sprintf(buf + size, "0: %10uMhz %10dmV\n",
2885                                od_table->GfxclkFreq1,
2886                                od_table->GfxclkVolt1 / VOLTAGE_SCALE);
2887                        size += sprintf(buf + size, "1: %10uMhz %10dmV\n",
2888                                od_table->GfxclkFreq2,
2889                                od_table->GfxclkVolt2 / VOLTAGE_SCALE);
2890                        size += sprintf(buf + size, "2: %10uMhz %10dmV\n",
2891                                od_table->GfxclkFreq3,
2892                                od_table->GfxclkVolt3 / VOLTAGE_SCALE);
2893                }
2894
2895                break;
2896
2897        case OD_RANGE:
2898                size = sprintf(buf, "%s:\n", "OD_RANGE");
2899
2900                if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
2901                    od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
2902                        size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
2903                                od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value,
2904                                od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value);
2905                }
2906
2907                if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
2908                        ret = vega20_get_memclocks(hwmgr, &clocks);
2909                        PP_ASSERT_WITH_CODE(!ret,
2910                                        "Fail to get memory clk levels!",
2911                                        return ret);
2912
2913                        size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
2914                                clocks.data[0].clocks_in_khz / 1000,
2915                                od8_settings[OD8_SETTING_UCLK_FMAX].max_value);
2916                }
2917
2918                if (od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
2919                    od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
2920                    od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
2921                    od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
2922                    od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
2923                    od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
2924                        size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
2925                                od8_settings[OD8_SETTING_GFXCLK_FREQ1].min_value,
2926                                od8_settings[OD8_SETTING_GFXCLK_FREQ1].max_value);
2927                        size += sprintf(buf + size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n",
2928                                od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].min_value,
2929                                od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].max_value);
2930                        size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
2931                                od8_settings[OD8_SETTING_GFXCLK_FREQ2].min_value,
2932                                od8_settings[OD8_SETTING_GFXCLK_FREQ2].max_value);
2933                        size += sprintf(buf + size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n",
2934                                od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].min_value,
2935                                od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].max_value);
2936                        size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
2937                                od8_settings[OD8_SETTING_GFXCLK_FREQ3].min_value,
2938                                od8_settings[OD8_SETTING_GFXCLK_FREQ3].max_value);
2939                        size += sprintf(buf + size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
2940                                od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].min_value,
2941                                od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].max_value);
2942                }
2943
2944                break;
2945        default:
2946                break;
2947        }
2948        return size;
2949}
2950
2951static int vega20_set_uclk_to_highest_dpm_level(struct pp_hwmgr *hwmgr,
2952                struct vega20_single_dpm_table *dpm_table)
2953{
2954        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2955        int ret = 0;
2956
2957        if (data->smu_features[GNLD_DPM_UCLK].enabled) {
2958                PP_ASSERT_WITH_CODE(dpm_table->count > 0,
2959                                "[SetUclkToHightestDpmLevel] Dpm table has no entry!",
2960                                return -EINVAL);
2961                PP_ASSERT_WITH_CODE(dpm_table->count <= NUM_UCLK_DPM_LEVELS,
2962                                "[SetUclkToHightestDpmLevel] Dpm table has too many entries!",
2963                                return -EINVAL);
2964
2965                dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2966                PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(hwmgr,
2967                                PPSMC_MSG_SetHardMinByFreq,
2968                                (PPCLK_UCLK << 16 ) | dpm_table->dpm_state.hard_min_level)),
2969                                "[SetUclkToHightestDpmLevel] Set hard min uclk failed!",
2970                                return ret);
2971        }
2972
2973        return ret;
2974}
2975
2976static int vega20_pre_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
2977{
2978        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2979        int ret = 0;
2980
2981        smum_send_msg_to_smc_with_parameter(hwmgr,
2982                        PPSMC_MSG_NumOfDisplays, 0);
2983
2984        ret = vega20_set_uclk_to_highest_dpm_level(hwmgr,
2985                        &data->dpm_table.mem_table);
2986
2987        return ret;
2988}
2989
2990static int vega20_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
2991{
2992        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2993        int result = 0;
2994        Watermarks_t *wm_table = &(data->smc_state_table.water_marks_table);
2995
2996        if ((data->water_marks_bitmap & WaterMarksExist) &&
2997            !(data->water_marks_bitmap & WaterMarksLoaded)) {
2998                result = smum_smc_table_manager(hwmgr,
2999                                                (uint8_t *)wm_table, TABLE_WATERMARKS, false);
3000                PP_ASSERT_WITH_CODE(!result,
3001                                "Failed to update WMTABLE!",
3002                                return result);
3003                data->water_marks_bitmap |= WaterMarksLoaded;
3004        }
3005
3006        if ((data->water_marks_bitmap & WaterMarksExist) &&
3007            data->smu_features[GNLD_DPM_DCEFCLK].supported &&
3008            data->smu_features[GNLD_DPM_SOCCLK].supported) {
3009                result = smum_send_msg_to_smc_with_parameter(hwmgr,
3010                        PPSMC_MSG_NumOfDisplays,
3011                        hwmgr->display_config->num_display);
3012        }
3013
3014        return result;
3015}
3016
3017int vega20_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
3018{
3019        struct vega20_hwmgr *data =
3020                        (struct vega20_hwmgr *)(hwmgr->backend);
3021        int ret = 0;
3022
3023        if (data->smu_features[GNLD_DPM_UVD].supported) {
3024                if (data->smu_features[GNLD_DPM_UVD].enabled == enable) {
3025                        if (enable)
3026                                PP_DBG_LOG("[EnableDisableUVDDPM] feature DPM UVD already enabled!\n");
3027                        else
3028                                PP_DBG_LOG("[EnableDisableUVDDPM] feature DPM UVD already disabled!\n");
3029                }
3030
3031                ret = vega20_enable_smc_features(hwmgr,
3032                                enable,
3033                                data->smu_features[GNLD_DPM_UVD].smu_feature_bitmap);
3034                PP_ASSERT_WITH_CODE(!ret,
3035                                "[EnableDisableUVDDPM] Attempt to Enable/Disable DPM UVD Failed!",
3036                                return ret);
3037                data->smu_features[GNLD_DPM_UVD].enabled = enable;
3038        }
3039
3040        return 0;
3041}
3042
3043static void vega20_power_gate_vce(struct pp_hwmgr *hwmgr, bool bgate)
3044{
3045        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3046
3047        if (data->vce_power_gated == bgate)
3048                return ;
3049
3050        data->vce_power_gated = bgate;
3051        vega20_enable_disable_vce_dpm(hwmgr, !bgate);
3052}
3053
3054static void vega20_power_gate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
3055{
3056        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3057
3058        if (data->uvd_power_gated == bgate)
3059                return ;
3060
3061        data->uvd_power_gated = bgate;
3062        vega20_enable_disable_uvd_dpm(hwmgr, !bgate);
3063}
3064
3065static int vega20_apply_clocks_adjust_rules(struct pp_hwmgr *hwmgr)
3066{
3067        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3068        struct vega20_single_dpm_table *dpm_table;
3069        bool vblank_too_short = false;
3070        bool disable_mclk_switching;
3071        uint32_t i, latency;
3072
3073        disable_mclk_switching = ((1 < hwmgr->display_config->num_display) &&
3074                           !hwmgr->display_config->multi_monitor_in_sync) ||
3075                            vblank_too_short;
3076    latency = hwmgr->display_config->dce_tolerable_mclk_in_active_latency;
3077
3078        /* gfxclk */
3079        dpm_table = &(data->dpm_table.gfx_table);
3080        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3081        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3082        dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3083        dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3084
3085        if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3086                if (VEGA20_UMD_PSTATE_GFXCLK_LEVEL < dpm_table->count) {
3087                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
3088                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
3089                }
3090
3091                if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
3092                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3093                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
3094                }
3095
3096                if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3097                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3098                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3099                }
3100        }
3101
3102        /* memclk */
3103        dpm_table = &(data->dpm_table.mem_table);
3104        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3105        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3106        dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3107        dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3108
3109        if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3110                if (VEGA20_UMD_PSTATE_MCLK_LEVEL < dpm_table->count) {
3111                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
3112                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
3113                }
3114
3115                if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
3116                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3117                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
3118                }
3119
3120                if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3121                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3122                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3123                }
3124        }
3125
3126        /* honour DAL's UCLK Hardmin */
3127        if (dpm_table->dpm_state.hard_min_level < (hwmgr->display_config->min_mem_set_clock / 100))
3128                dpm_table->dpm_state.hard_min_level = hwmgr->display_config->min_mem_set_clock / 100;
3129
3130        /* Hardmin is dependent on displayconfig */
3131        if (disable_mclk_switching) {
3132                dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3133                for (i = 0; i < data->mclk_latency_table.count - 1; i++) {
3134                        if (data->mclk_latency_table.entries[i].latency <= latency) {
3135                                if (dpm_table->dpm_levels[i].value >= (hwmgr->display_config->min_mem_set_clock / 100)) {
3136                                        dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[i].value;
3137                                        break;
3138                                }
3139                        }
3140                }
3141        }
3142
3143        if (hwmgr->display_config->nb_pstate_switch_disable)
3144                dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3145
3146        /* vclk */
3147        dpm_table = &(data->dpm_table.vclk_table);
3148        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3149        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3150        dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3151        dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3152
3153        if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3154                if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
3155                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
3156                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
3157                }
3158
3159                if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3160                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3161                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3162                }
3163        }
3164
3165        /* dclk */
3166        dpm_table = &(data->dpm_table.dclk_table);
3167        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3168        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3169        dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3170        dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3171
3172        if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3173                if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
3174                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
3175                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
3176                }
3177
3178                if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3179                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3180                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3181                }
3182        }
3183
3184        /* socclk */
3185        dpm_table = &(data->dpm_table.soc_table);
3186        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3187        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3188        dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3189        dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3190
3191        if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3192                if (VEGA20_UMD_PSTATE_SOCCLK_LEVEL < dpm_table->count) {
3193                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
3194                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
3195                }
3196
3197                if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3198                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3199                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3200                }
3201        }
3202
3203        /* eclk */
3204        dpm_table = &(data->dpm_table.eclk_table);
3205        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3206        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3207        dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3208        dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3209
3210        if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3211                if (VEGA20_UMD_PSTATE_VCEMCLK_LEVEL < dpm_table->count) {
3212                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
3213                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
3214                }
3215
3216                if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3217                        dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3218                        dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3219                }
3220        }
3221
3222        return 0;
3223}
3224
3225static bool
3226vega20_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
3227{
3228        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3229        bool is_update_required = false;
3230
3231        if (data->display_timing.num_existing_displays !=
3232                        hwmgr->display_config->num_display)
3233                is_update_required = true;
3234
3235        if (data->registry_data.gfx_clk_deep_sleep_support &&
3236           (data->display_timing.min_clock_in_sr !=
3237            hwmgr->display_config->min_core_set_clock_in_sr))
3238                is_update_required = true;
3239
3240        return is_update_required;
3241}
3242
3243static int vega20_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
3244{
3245        int ret = 0;
3246
3247        ret = vega20_disable_all_smu_features(hwmgr);
3248        PP_ASSERT_WITH_CODE(!ret,
3249                        "[DisableDpmTasks] Failed to disable all smu features!",
3250                        return ret);
3251
3252        return 0;
3253}
3254
3255static int vega20_power_off_asic(struct pp_hwmgr *hwmgr)
3256{
3257        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3258        int result;
3259
3260        result = vega20_disable_dpm_tasks(hwmgr);
3261        PP_ASSERT_WITH_CODE((0 == result),
3262                        "[PowerOffAsic] Failed to disable DPM!",
3263                        );
3264        data->water_marks_bitmap &= ~(WaterMarksLoaded);
3265
3266        return result;
3267}
3268
3269static int conv_power_profile_to_pplib_workload(int power_profile)
3270{
3271        int pplib_workload = 0;
3272
3273        switch (power_profile) {
3274        case PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT:
3275                pplib_workload = WORKLOAD_DEFAULT_BIT;
3276                break;
3277        case PP_SMC_POWER_PROFILE_FULLSCREEN3D:
3278                pplib_workload = WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT;
3279                break;
3280        case PP_SMC_POWER_PROFILE_POWERSAVING:
3281                pplib_workload = WORKLOAD_PPLIB_POWER_SAVING_BIT;
3282                break;
3283        case PP_SMC_POWER_PROFILE_VIDEO:
3284                pplib_workload = WORKLOAD_PPLIB_VIDEO_BIT;
3285                break;
3286        case PP_SMC_POWER_PROFILE_VR:
3287                pplib_workload = WORKLOAD_PPLIB_VR_BIT;
3288                break;
3289        case PP_SMC_POWER_PROFILE_COMPUTE:
3290                pplib_workload = WORKLOAD_PPLIB_COMPUTE_BIT;
3291                break;
3292        case PP_SMC_POWER_PROFILE_CUSTOM:
3293                pplib_workload = WORKLOAD_PPLIB_CUSTOM_BIT;
3294                break;
3295        }
3296
3297        return pplib_workload;
3298}
3299
3300static int vega20_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
3301{
3302        DpmActivityMonitorCoeffInt_t activity_monitor;
3303        uint32_t i, size = 0;
3304        uint16_t workload_type = 0;
3305        static const char *profile_name[] = {
3306                                        "BOOTUP_DEFAULT",
3307                                        "3D_FULL_SCREEN",
3308                                        "POWER_SAVING",
3309                                        "VIDEO",
3310                                        "VR",
3311                                        "COMPUTE",
3312                                        "CUSTOM"};
3313        static const char *title[] = {
3314                        "PROFILE_INDEX(NAME)",
3315                        "CLOCK_TYPE(NAME)",
3316                        "FPS",
3317                        "UseRlcBusy",
3318                        "MinActiveFreqType",
3319                        "MinActiveFreq",
3320                        "BoosterFreqType",
3321                        "BoosterFreq",
3322                        "PD_Data_limit_c",
3323                        "PD_Data_error_coeff",
3324                        "PD_Data_error_rate_coeff"};
3325        int result = 0;
3326
3327        if (!buf)
3328                return -EINVAL;
3329
3330        size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
3331                        title[0], title[1], title[2], title[3], title[4], title[5],
3332                        title[6], title[7], title[8], title[9], title[10]);
3333
3334        for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
3335                /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
3336                workload_type = conv_power_profile_to_pplib_workload(i);
3337                result = vega20_get_activity_monitor_coeff(hwmgr,
3338                                (uint8_t *)(&activity_monitor), workload_type);
3339                PP_ASSERT_WITH_CODE(!result,
3340                                "[GetPowerProfile] Failed to get activity monitor!",
3341                                return result);
3342
3343                size += sprintf(buf + size, "%2d %14s%s:\n",
3344                        i, profile_name[i], (i == hwmgr->power_profile_mode) ? "*" : " ");
3345
3346                size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
3347                        " ",
3348                        0,
3349                        "GFXCLK",
3350                        activity_monitor.Gfx_FPS,
3351                        activity_monitor.Gfx_UseRlcBusy,
3352                        activity_monitor.Gfx_MinActiveFreqType,
3353                        activity_monitor.Gfx_MinActiveFreq,
3354                        activity_monitor.Gfx_BoosterFreqType,
3355                        activity_monitor.Gfx_BoosterFreq,
3356                        activity_monitor.Gfx_PD_Data_limit_c,
3357                        activity_monitor.Gfx_PD_Data_error_coeff,
3358                        activity_monitor.Gfx_PD_Data_error_rate_coeff);
3359
3360                size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
3361                        " ",
3362                        1,
3363                        "SOCCLK",
3364                        activity_monitor.Soc_FPS,
3365                        activity_monitor.Soc_UseRlcBusy,
3366                        activity_monitor.Soc_MinActiveFreqType,
3367                        activity_monitor.Soc_MinActiveFreq,
3368                        activity_monitor.Soc_BoosterFreqType,
3369                        activity_monitor.Soc_BoosterFreq,
3370                        activity_monitor.Soc_PD_Data_limit_c,
3371                        activity_monitor.Soc_PD_Data_error_coeff,
3372                        activity_monitor.Soc_PD_Data_error_rate_coeff);
3373
3374                size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
3375                        " ",
3376                        2,
3377                        "UCLK",
3378                        activity_monitor.Mem_FPS,
3379                        activity_monitor.Mem_UseRlcBusy,
3380                        activity_monitor.Mem_MinActiveFreqType,
3381                        activity_monitor.Mem_MinActiveFreq,
3382                        activity_monitor.Mem_BoosterFreqType,
3383                        activity_monitor.Mem_BoosterFreq,
3384                        activity_monitor.Mem_PD_Data_limit_c,
3385                        activity_monitor.Mem_PD_Data_error_coeff,
3386                        activity_monitor.Mem_PD_Data_error_rate_coeff);
3387
3388                size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
3389                        " ",
3390                        3,
3391                        "FCLK",
3392                        activity_monitor.Fclk_FPS,
3393                        activity_monitor.Fclk_UseRlcBusy,
3394                        activity_monitor.Fclk_MinActiveFreqType,
3395                        activity_monitor.Fclk_MinActiveFreq,
3396                        activity_monitor.Fclk_BoosterFreqType,
3397                        activity_monitor.Fclk_BoosterFreq,
3398                        activity_monitor.Fclk_PD_Data_limit_c,
3399                        activity_monitor.Fclk_PD_Data_error_coeff,
3400                        activity_monitor.Fclk_PD_Data_error_rate_coeff);
3401        }
3402
3403        return size;
3404}
3405
3406static int vega20_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint32_t size)
3407{
3408        DpmActivityMonitorCoeffInt_t activity_monitor;
3409        int workload_type, result = 0;
3410
3411        hwmgr->power_profile_mode = input[size];
3412
3413        if (hwmgr->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
3414                pr_err("Invalid power profile mode %d\n", hwmgr->power_profile_mode);
3415                return -EINVAL;
3416        }
3417
3418        if (hwmgr->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
3419                if (size < 10)
3420                        return -EINVAL;
3421
3422                result = vega20_get_activity_monitor_coeff(hwmgr,
3423                                (uint8_t *)(&activity_monitor),
3424                                WORKLOAD_PPLIB_CUSTOM_BIT);
3425                PP_ASSERT_WITH_CODE(!result,
3426                                "[SetPowerProfile] Failed to get activity monitor!",
3427                                return result);
3428
3429                switch (input[0]) {
3430                case 0: /* Gfxclk */
3431                        activity_monitor.Gfx_FPS = input[1];
3432                        activity_monitor.Gfx_UseRlcBusy = input[2];
3433                        activity_monitor.Gfx_MinActiveFreqType = input[3];
3434                        activity_monitor.Gfx_MinActiveFreq = input[4];
3435                        activity_monitor.Gfx_BoosterFreqType = input[5];
3436                        activity_monitor.Gfx_BoosterFreq = input[6];
3437                        activity_monitor.Gfx_PD_Data_limit_c = input[7];
3438                        activity_monitor.Gfx_PD_Data_error_coeff = input[8];
3439                        activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
3440                        break;
3441                case 1: /* Socclk */
3442                        activity_monitor.Soc_FPS = input[1];
3443                        activity_monitor.Soc_UseRlcBusy = input[2];
3444                        activity_monitor.Soc_MinActiveFreqType = input[3];
3445                        activity_monitor.Soc_MinActiveFreq = input[4];
3446                        activity_monitor.Soc_BoosterFreqType = input[5];
3447                        activity_monitor.Soc_BoosterFreq = input[6];
3448                        activity_monitor.Soc_PD_Data_limit_c = input[7];
3449                        activity_monitor.Soc_PD_Data_error_coeff = input[8];
3450                        activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
3451                        break;
3452                case 2: /* Uclk */
3453                        activity_monitor.Mem_FPS = input[1];
3454                        activity_monitor.Mem_UseRlcBusy = input[2];
3455                        activity_monitor.Mem_MinActiveFreqType = input[3];
3456                        activity_monitor.Mem_MinActiveFreq = input[4];
3457                        activity_monitor.Mem_BoosterFreqType = input[5];
3458                        activity_monitor.Mem_BoosterFreq = input[6];
3459                        activity_monitor.Mem_PD_Data_limit_c = input[7];
3460                        activity_monitor.Mem_PD_Data_error_coeff = input[8];
3461                        activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
3462                        break;
3463                case 3: /* Fclk */
3464                        activity_monitor.Fclk_FPS = input[1];
3465                        activity_monitor.Fclk_UseRlcBusy = input[2];
3466                        activity_monitor.Fclk_MinActiveFreqType = input[3];
3467                        activity_monitor.Fclk_MinActiveFreq = input[4];
3468                        activity_monitor.Fclk_BoosterFreqType = input[5];
3469                        activity_monitor.Fclk_BoosterFreq = input[6];
3470                        activity_monitor.Fclk_PD_Data_limit_c = input[7];
3471                        activity_monitor.Fclk_PD_Data_error_coeff = input[8];
3472                        activity_monitor.Fclk_PD_Data_error_rate_coeff = input[9];
3473                        break;
3474                }
3475
3476                result = vega20_set_activity_monitor_coeff(hwmgr,
3477                                (uint8_t *)(&activity_monitor),
3478                                WORKLOAD_PPLIB_CUSTOM_BIT);
3479                PP_ASSERT_WITH_CODE(!result,
3480                                "[SetPowerProfile] Failed to set activity monitor!",
3481                                return result);
3482        }
3483
3484        /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
3485        workload_type =
3486                conv_power_profile_to_pplib_workload(hwmgr->power_profile_mode);
3487        smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetWorkloadMask,
3488                                                1 << workload_type);
3489
3490        return 0;
3491}
3492
3493static int vega20_notify_cac_buffer_info(struct pp_hwmgr *hwmgr,
3494                                        uint32_t virtual_addr_low,
3495                                        uint32_t virtual_addr_hi,
3496                                        uint32_t mc_addr_low,
3497                                        uint32_t mc_addr_hi,
3498                                        uint32_t size)
3499{
3500        smum_send_msg_to_smc_with_parameter(hwmgr,
3501                                        PPSMC_MSG_SetSystemVirtualDramAddrHigh,
3502                                        virtual_addr_hi);
3503        smum_send_msg_to_smc_with_parameter(hwmgr,
3504                                        PPSMC_MSG_SetSystemVirtualDramAddrLow,
3505                                        virtual_addr_low);
3506        smum_send_msg_to_smc_with_parameter(hwmgr,
3507                                        PPSMC_MSG_DramLogSetDramAddrHigh,
3508                                        mc_addr_hi);
3509
3510        smum_send_msg_to_smc_with_parameter(hwmgr,
3511                                        PPSMC_MSG_DramLogSetDramAddrLow,
3512                                        mc_addr_low);
3513
3514        smum_send_msg_to_smc_with_parameter(hwmgr,
3515                                        PPSMC_MSG_DramLogSetDramSize,
3516                                        size);
3517        return 0;
3518}
3519
3520static int vega20_get_thermal_temperature_range(struct pp_hwmgr *hwmgr,
3521                struct PP_TemperatureRange *thermal_data)
3522{
3523        struct phm_ppt_v3_information *pptable_information =
3524                (struct phm_ppt_v3_information *)hwmgr->pptable;
3525
3526        memcpy(thermal_data, &SMU7ThermalWithDelayPolicy[0], sizeof(struct PP_TemperatureRange));
3527
3528        thermal_data->max = pptable_information->us_software_shutdown_temp *
3529                PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
3530
3531        return 0;
3532}
3533
3534static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
3535        /* init/fini related */
3536        .backend_init = vega20_hwmgr_backend_init,
3537        .backend_fini = vega20_hwmgr_backend_fini,
3538        .asic_setup = vega20_setup_asic_task,
3539        .power_off_asic = vega20_power_off_asic,
3540        .dynamic_state_management_enable = vega20_enable_dpm_tasks,
3541        .dynamic_state_management_disable = vega20_disable_dpm_tasks,
3542        /* power state related */
3543        .apply_clocks_adjust_rules = vega20_apply_clocks_adjust_rules,
3544        .pre_display_config_changed = vega20_pre_display_configuration_changed_task,
3545        .display_config_changed = vega20_display_configuration_changed_task,
3546        .check_smc_update_required_for_display_configuration =
3547                vega20_check_smc_update_required_for_display_configuration,
3548        .notify_smc_display_config_after_ps_adjustment =
3549                vega20_notify_smc_display_config_after_ps_adjustment,
3550        /* export to DAL */
3551        .get_sclk = vega20_dpm_get_sclk,
3552        .get_mclk = vega20_dpm_get_mclk,
3553        .get_dal_power_level = vega20_get_dal_power_level,
3554        .get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency,
3555        .get_clock_by_type_with_voltage = vega20_get_clock_by_type_with_voltage,
3556        .set_watermarks_for_clocks_ranges = vega20_set_watermarks_for_clocks_ranges,
3557        .display_clock_voltage_request = vega20_display_clock_voltage_request,
3558        .get_performance_level = vega20_get_performance_level,
3559        /* UMD pstate, profile related */
3560        .force_dpm_level = vega20_dpm_force_dpm_level,
3561        .get_power_profile_mode = vega20_get_power_profile_mode,
3562        .set_power_profile_mode = vega20_set_power_profile_mode,
3563        /* od related */
3564        .set_power_limit = vega20_set_power_limit,
3565        .get_sclk_od = vega20_get_sclk_od,
3566        .set_sclk_od = vega20_set_sclk_od,
3567        .get_mclk_od = vega20_get_mclk_od,
3568        .set_mclk_od = vega20_set_mclk_od,
3569        .odn_edit_dpm_table = vega20_odn_edit_dpm_table,
3570        /* for sysfs to retrive/set gfxclk/memclk */
3571        .force_clock_level = vega20_force_clock_level,
3572        .print_clock_levels = vega20_print_clock_levels,
3573        .read_sensor = vega20_read_sensor,
3574        /* powergate related */
3575        .powergate_uvd = vega20_power_gate_uvd,
3576        .powergate_vce = vega20_power_gate_vce,
3577        /* thermal related */
3578        .start_thermal_controller = vega20_start_thermal_controller,
3579        .stop_thermal_controller = vega20_thermal_stop_thermal_controller,
3580        .get_thermal_temperature_range = vega20_get_thermal_temperature_range,
3581        .register_irq_handlers = smu9_register_irq_handlers,
3582        .disable_smc_firmware_ctf = vega20_thermal_disable_alert,
3583        /* fan control related */
3584        .get_fan_speed_percent = vega20_fan_ctrl_get_fan_speed_percent,
3585        .set_fan_speed_percent = vega20_fan_ctrl_set_fan_speed_percent,
3586        .get_fan_speed_info = vega20_fan_ctrl_get_fan_speed_info,
3587        .get_fan_speed_rpm = vega20_fan_ctrl_get_fan_speed_rpm,
3588        .set_fan_speed_rpm = vega20_fan_ctrl_set_fan_speed_rpm,
3589        .get_fan_control_mode = vega20_get_fan_control_mode,
3590        .set_fan_control_mode = vega20_set_fan_control_mode,
3591        /* smu memory related */
3592        .notify_cac_buffer_info = vega20_notify_cac_buffer_info,
3593        .enable_mgpu_fan_boost = vega20_enable_mgpu_fan_boost,
3594};
3595
3596int vega20_hwmgr_init(struct pp_hwmgr *hwmgr)
3597{
3598        hwmgr->hwmgr_func = &vega20_hwmgr_funcs;
3599        hwmgr->pptable_func = &vega20_pptable_funcs;
3600
3601        return 0;
3602}
3603