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