Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2018 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  */
0023 
0024 #include <linux/delay.h>
0025 #include <linux/fb.h>
0026 #include <linux/module.h>
0027 #include <linux/slab.h>
0028 
0029 #include "hwmgr.h"
0030 #include "amd_powerplay.h"
0031 #include "vega20_smumgr.h"
0032 #include "hardwaremanager.h"
0033 #include "ppatomfwctrl.h"
0034 #include "atomfirmware.h"
0035 #include "cgs_common.h"
0036 #include "vega20_powertune.h"
0037 #include "vega20_inc.h"
0038 #include "pppcielanes.h"
0039 #include "vega20_hwmgr.h"
0040 #include "vega20_processpptables.h"
0041 #include "vega20_pptable.h"
0042 #include "vega20_thermal.h"
0043 #include "vega20_ppsmc.h"
0044 #include "pp_debug.h"
0045 #include "amd_pcie_helpers.h"
0046 #include "ppinterrupt.h"
0047 #include "pp_overdriver.h"
0048 #include "pp_thermal.h"
0049 #include "soc15_common.h"
0050 #include "vega20_baco.h"
0051 #include "smuio/smuio_9_0_offset.h"
0052 #include "smuio/smuio_9_0_sh_mask.h"
0053 #include "nbio/nbio_7_4_sh_mask.h"
0054 
0055 #define smnPCIE_LC_SPEED_CNTL           0x11140290
0056 #define smnPCIE_LC_LINK_WIDTH_CNTL      0x11140288
0057 
0058 #define LINK_WIDTH_MAX              6
0059 #define LINK_SPEED_MAX              3
0060 static const int link_width[] = {0, 1, 2, 4, 8, 12, 16};
0061 static const int link_speed[] = {25, 50, 80, 160};
0062 
0063 static void vega20_set_default_registry_data(struct pp_hwmgr *hwmgr)
0064 {
0065     struct vega20_hwmgr *data =
0066             (struct vega20_hwmgr *)(hwmgr->backend);
0067 
0068     data->gfxclk_average_alpha = PPVEGA20_VEGA20GFXCLKAVERAGEALPHA_DFLT;
0069     data->socclk_average_alpha = PPVEGA20_VEGA20SOCCLKAVERAGEALPHA_DFLT;
0070     data->uclk_average_alpha = PPVEGA20_VEGA20UCLKCLKAVERAGEALPHA_DFLT;
0071     data->gfx_activity_average_alpha = PPVEGA20_VEGA20GFXACTIVITYAVERAGEALPHA_DFLT;
0072     data->lowest_uclk_reserved_for_ulv = PPVEGA20_VEGA20LOWESTUCLKRESERVEDFORULV_DFLT;
0073 
0074     data->display_voltage_mode = PPVEGA20_VEGA20DISPLAYVOLTAGEMODE_DFLT;
0075     data->dcef_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
0076     data->dcef_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
0077     data->dcef_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
0078     data->disp_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
0079     data->disp_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
0080     data->disp_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
0081     data->pixel_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
0082     data->pixel_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
0083     data->pixel_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
0084     data->phy_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
0085     data->phy_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
0086     data->phy_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
0087 
0088     /*
0089      * Disable the following features for now:
0090      *   GFXCLK DS
0091      *   SOCLK DS
0092      *   LCLK DS
0093      *   DCEFCLK DS
0094      *   FCLK DS
0095      *   MP1CLK DS
0096      *   MP0CLK DS
0097      */
0098     data->registry_data.disallowed_features = 0xE0041C00;
0099     /* ECC feature should be disabled on old SMUs */
0100     smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetSmuVersion, &hwmgr->smu_version);
0101     if (hwmgr->smu_version < 0x282100)
0102         data->registry_data.disallowed_features |= FEATURE_ECC_MASK;
0103 
0104     if (!(hwmgr->feature_mask & PP_PCIE_DPM_MASK))
0105         data->registry_data.disallowed_features |= FEATURE_DPM_LINK_MASK;
0106 
0107     if (!(hwmgr->feature_mask & PP_SCLK_DPM_MASK))
0108         data->registry_data.disallowed_features |= FEATURE_DPM_GFXCLK_MASK;
0109 
0110     if (!(hwmgr->feature_mask & PP_SOCCLK_DPM_MASK))
0111         data->registry_data.disallowed_features |= FEATURE_DPM_SOCCLK_MASK;
0112 
0113     if (!(hwmgr->feature_mask & PP_MCLK_DPM_MASK))
0114         data->registry_data.disallowed_features |= FEATURE_DPM_UCLK_MASK;
0115 
0116     if (!(hwmgr->feature_mask & PP_DCEFCLK_DPM_MASK))
0117         data->registry_data.disallowed_features |= FEATURE_DPM_DCEFCLK_MASK;
0118 
0119     if (!(hwmgr->feature_mask & PP_ULV_MASK))
0120         data->registry_data.disallowed_features |= FEATURE_ULV_MASK;
0121 
0122     if (!(hwmgr->feature_mask & PP_SCLK_DEEP_SLEEP_MASK))
0123         data->registry_data.disallowed_features |= FEATURE_DS_GFXCLK_MASK;
0124 
0125     data->registry_data.od_state_in_dc_support = 0;
0126     data->registry_data.thermal_support = 1;
0127     data->registry_data.skip_baco_hardware = 0;
0128 
0129     data->registry_data.log_avfs_param = 0;
0130     data->registry_data.sclk_throttle_low_notification = 1;
0131     data->registry_data.force_dpm_high = 0;
0132     data->registry_data.stable_pstate_sclk_dpm_percentage = 75;
0133 
0134     data->registry_data.didt_support = 0;
0135     if (data->registry_data.didt_support) {
0136         data->registry_data.didt_mode = 6;
0137         data->registry_data.sq_ramping_support = 1;
0138         data->registry_data.db_ramping_support = 0;
0139         data->registry_data.td_ramping_support = 0;
0140         data->registry_data.tcp_ramping_support = 0;
0141         data->registry_data.dbr_ramping_support = 0;
0142         data->registry_data.edc_didt_support = 1;
0143         data->registry_data.gc_didt_support = 0;
0144         data->registry_data.psm_didt_support = 0;
0145     }
0146 
0147     data->registry_data.pcie_lane_override = 0xff;
0148     data->registry_data.pcie_speed_override = 0xff;
0149     data->registry_data.pcie_clock_override = 0xffffffff;
0150     data->registry_data.regulator_hot_gpio_support = 1;
0151     data->registry_data.ac_dc_switch_gpio_support = 0;
0152     data->registry_data.quick_transition_support = 0;
0153     data->registry_data.zrpm_start_temp = 0xffff;
0154     data->registry_data.zrpm_stop_temp = 0xffff;
0155     data->registry_data.od8_feature_enable = 1;
0156     data->registry_data.disable_water_mark = 0;
0157     data->registry_data.disable_pp_tuning = 0;
0158     data->registry_data.disable_xlpp_tuning = 0;
0159     data->registry_data.disable_workload_policy = 0;
0160     data->registry_data.perf_ui_tuning_profile_turbo = 0x19190F0F;
0161     data->registry_data.perf_ui_tuning_profile_powerSave = 0x19191919;
0162     data->registry_data.perf_ui_tuning_profile_xl = 0x00000F0A;
0163     data->registry_data.force_workload_policy_mask = 0;
0164     data->registry_data.disable_3d_fs_detection = 0;
0165     data->registry_data.fps_support = 1;
0166     data->registry_data.disable_auto_wattman = 1;
0167     data->registry_data.auto_wattman_debug = 0;
0168     data->registry_data.auto_wattman_sample_period = 100;
0169     data->registry_data.fclk_gfxclk_ratio = 0;
0170     data->registry_data.auto_wattman_threshold = 50;
0171     data->registry_data.gfxoff_controlled_by_driver = 1;
0172     data->gfxoff_allowed = false;
0173     data->counter_gfxoff = 0;
0174     data->registry_data.pcie_dpm_key_disabled = !(hwmgr->feature_mask & PP_PCIE_DPM_MASK);
0175 }
0176 
0177 static int vega20_set_features_platform_caps(struct pp_hwmgr *hwmgr)
0178 {
0179     struct vega20_hwmgr *data =
0180             (struct vega20_hwmgr *)(hwmgr->backend);
0181     struct amdgpu_device *adev = hwmgr->adev;
0182 
0183     if (data->vddci_control == VEGA20_VOLTAGE_CONTROL_NONE)
0184         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0185                 PHM_PlatformCaps_ControlVDDCI);
0186 
0187     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0188             PHM_PlatformCaps_TablelessHardwareInterface);
0189 
0190     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0191             PHM_PlatformCaps_BACO);
0192 
0193     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0194             PHM_PlatformCaps_EnableSMU7ThermalManagement);
0195 
0196     if (adev->pg_flags & AMD_PG_SUPPORT_UVD)
0197         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0198                 PHM_PlatformCaps_UVDPowerGating);
0199 
0200     if (adev->pg_flags & AMD_PG_SUPPORT_VCE)
0201         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0202                 PHM_PlatformCaps_VCEPowerGating);
0203 
0204     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0205             PHM_PlatformCaps_UnTabledHardwareInterface);
0206 
0207     if (data->registry_data.od8_feature_enable)
0208         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0209                 PHM_PlatformCaps_OD8inACSupport);
0210 
0211     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0212             PHM_PlatformCaps_ActivityReporting);
0213     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0214             PHM_PlatformCaps_FanSpeedInTableIsRPM);
0215 
0216     if (data->registry_data.od_state_in_dc_support) {
0217         if (data->registry_data.od8_feature_enable)
0218             phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0219                     PHM_PlatformCaps_OD8inDCSupport);
0220     }
0221 
0222     if (data->registry_data.thermal_support &&
0223         data->registry_data.fuzzy_fan_control_support &&
0224         hwmgr->thermal_controller.advanceFanControlParameters.usTMax)
0225         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0226                 PHM_PlatformCaps_ODFuzzyFanControlSupport);
0227 
0228     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0229             PHM_PlatformCaps_DynamicPowerManagement);
0230     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0231             PHM_PlatformCaps_SMC);
0232     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0233             PHM_PlatformCaps_ThermalPolicyDelay);
0234 
0235     if (data->registry_data.force_dpm_high)
0236         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0237                 PHM_PlatformCaps_ExclusiveModeAlwaysHigh);
0238 
0239     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0240             PHM_PlatformCaps_DynamicUVDState);
0241 
0242     if (data->registry_data.sclk_throttle_low_notification)
0243         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0244                 PHM_PlatformCaps_SclkThrottleLowNotification);
0245 
0246     /* power tune caps */
0247     /* assume disabled */
0248     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0249             PHM_PlatformCaps_PowerContainment);
0250     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0251             PHM_PlatformCaps_DiDtSupport);
0252     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0253             PHM_PlatformCaps_SQRamping);
0254     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0255             PHM_PlatformCaps_DBRamping);
0256     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0257             PHM_PlatformCaps_TDRamping);
0258     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0259             PHM_PlatformCaps_TCPRamping);
0260     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0261             PHM_PlatformCaps_DBRRamping);
0262     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0263             PHM_PlatformCaps_DiDtEDCEnable);
0264     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0265             PHM_PlatformCaps_GCEDC);
0266     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0267             PHM_PlatformCaps_PSM);
0268 
0269     if (data->registry_data.didt_support) {
0270         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0271                 PHM_PlatformCaps_DiDtSupport);
0272         if (data->registry_data.sq_ramping_support)
0273             phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0274                     PHM_PlatformCaps_SQRamping);
0275         if (data->registry_data.db_ramping_support)
0276             phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0277                     PHM_PlatformCaps_DBRamping);
0278         if (data->registry_data.td_ramping_support)
0279             phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0280                     PHM_PlatformCaps_TDRamping);
0281         if (data->registry_data.tcp_ramping_support)
0282             phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0283                     PHM_PlatformCaps_TCPRamping);
0284         if (data->registry_data.dbr_ramping_support)
0285             phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0286                     PHM_PlatformCaps_DBRRamping);
0287         if (data->registry_data.edc_didt_support)
0288             phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0289                     PHM_PlatformCaps_DiDtEDCEnable);
0290         if (data->registry_data.gc_didt_support)
0291             phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0292                     PHM_PlatformCaps_GCEDC);
0293         if (data->registry_data.psm_didt_support)
0294             phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0295                     PHM_PlatformCaps_PSM);
0296     }
0297 
0298     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0299             PHM_PlatformCaps_RegulatorHot);
0300 
0301     if (data->registry_data.ac_dc_switch_gpio_support) {
0302         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0303                 PHM_PlatformCaps_AutomaticDCTransition);
0304         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0305                 PHM_PlatformCaps_SMCtoPPLIBAcdcGpioScheme);
0306     }
0307 
0308     if (data->registry_data.quick_transition_support) {
0309         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0310                 PHM_PlatformCaps_AutomaticDCTransition);
0311         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0312                 PHM_PlatformCaps_SMCtoPPLIBAcdcGpioScheme);
0313         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0314                 PHM_PlatformCaps_Falcon_QuickTransition);
0315     }
0316 
0317     if (data->lowest_uclk_reserved_for_ulv != PPVEGA20_VEGA20LOWESTUCLKRESERVEDFORULV_DFLT) {
0318         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0319                 PHM_PlatformCaps_LowestUclkReservedForUlv);
0320         if (data->lowest_uclk_reserved_for_ulv == 1)
0321             phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0322                     PHM_PlatformCaps_LowestUclkReservedForUlv);
0323     }
0324 
0325     if (data->registry_data.custom_fan_support)
0326         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0327                 PHM_PlatformCaps_CustomFanControlSupport);
0328 
0329     return 0;
0330 }
0331 
0332 static void vega20_init_dpm_defaults(struct pp_hwmgr *hwmgr)
0333 {
0334     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
0335     struct amdgpu_device *adev = hwmgr->adev;
0336     uint32_t top32, bottom32;
0337     int i;
0338 
0339     data->smu_features[GNLD_DPM_PREFETCHER].smu_feature_id =
0340             FEATURE_DPM_PREFETCHER_BIT;
0341     data->smu_features[GNLD_DPM_GFXCLK].smu_feature_id =
0342             FEATURE_DPM_GFXCLK_BIT;
0343     data->smu_features[GNLD_DPM_UCLK].smu_feature_id =
0344             FEATURE_DPM_UCLK_BIT;
0345     data->smu_features[GNLD_DPM_SOCCLK].smu_feature_id =
0346             FEATURE_DPM_SOCCLK_BIT;
0347     data->smu_features[GNLD_DPM_UVD].smu_feature_id =
0348             FEATURE_DPM_UVD_BIT;
0349     data->smu_features[GNLD_DPM_VCE].smu_feature_id =
0350             FEATURE_DPM_VCE_BIT;
0351     data->smu_features[GNLD_ULV].smu_feature_id =
0352             FEATURE_ULV_BIT;
0353     data->smu_features[GNLD_DPM_MP0CLK].smu_feature_id =
0354             FEATURE_DPM_MP0CLK_BIT;
0355     data->smu_features[GNLD_DPM_LINK].smu_feature_id =
0356             FEATURE_DPM_LINK_BIT;
0357     data->smu_features[GNLD_DPM_DCEFCLK].smu_feature_id =
0358             FEATURE_DPM_DCEFCLK_BIT;
0359     data->smu_features[GNLD_DS_GFXCLK].smu_feature_id =
0360             FEATURE_DS_GFXCLK_BIT;
0361     data->smu_features[GNLD_DS_SOCCLK].smu_feature_id =
0362             FEATURE_DS_SOCCLK_BIT;
0363     data->smu_features[GNLD_DS_LCLK].smu_feature_id =
0364             FEATURE_DS_LCLK_BIT;
0365     data->smu_features[GNLD_PPT].smu_feature_id =
0366             FEATURE_PPT_BIT;
0367     data->smu_features[GNLD_TDC].smu_feature_id =
0368             FEATURE_TDC_BIT;
0369     data->smu_features[GNLD_THERMAL].smu_feature_id =
0370             FEATURE_THERMAL_BIT;
0371     data->smu_features[GNLD_GFX_PER_CU_CG].smu_feature_id =
0372             FEATURE_GFX_PER_CU_CG_BIT;
0373     data->smu_features[GNLD_RM].smu_feature_id =
0374             FEATURE_RM_BIT;
0375     data->smu_features[GNLD_DS_DCEFCLK].smu_feature_id =
0376             FEATURE_DS_DCEFCLK_BIT;
0377     data->smu_features[GNLD_ACDC].smu_feature_id =
0378             FEATURE_ACDC_BIT;
0379     data->smu_features[GNLD_VR0HOT].smu_feature_id =
0380             FEATURE_VR0HOT_BIT;
0381     data->smu_features[GNLD_VR1HOT].smu_feature_id =
0382             FEATURE_VR1HOT_BIT;
0383     data->smu_features[GNLD_FW_CTF].smu_feature_id =
0384             FEATURE_FW_CTF_BIT;
0385     data->smu_features[GNLD_LED_DISPLAY].smu_feature_id =
0386             FEATURE_LED_DISPLAY_BIT;
0387     data->smu_features[GNLD_FAN_CONTROL].smu_feature_id =
0388             FEATURE_FAN_CONTROL_BIT;
0389     data->smu_features[GNLD_DIDT].smu_feature_id = FEATURE_GFX_EDC_BIT;
0390     data->smu_features[GNLD_GFXOFF].smu_feature_id = FEATURE_GFXOFF_BIT;
0391     data->smu_features[GNLD_CG].smu_feature_id = FEATURE_CG_BIT;
0392     data->smu_features[GNLD_DPM_FCLK].smu_feature_id = FEATURE_DPM_FCLK_BIT;
0393     data->smu_features[GNLD_DS_FCLK].smu_feature_id = FEATURE_DS_FCLK_BIT;
0394     data->smu_features[GNLD_DS_MP1CLK].smu_feature_id = FEATURE_DS_MP1CLK_BIT;
0395     data->smu_features[GNLD_DS_MP0CLK].smu_feature_id = FEATURE_DS_MP0CLK_BIT;
0396     data->smu_features[GNLD_XGMI].smu_feature_id = FEATURE_XGMI_BIT;
0397     data->smu_features[GNLD_ECC].smu_feature_id = FEATURE_ECC_BIT;
0398 
0399     for (i = 0; i < GNLD_FEATURES_MAX; i++) {
0400         data->smu_features[i].smu_feature_bitmap =
0401             (uint64_t)(1ULL << data->smu_features[i].smu_feature_id);
0402         data->smu_features[i].allowed =
0403             ((data->registry_data.disallowed_features >> i) & 1) ?
0404             false : true;
0405     }
0406 
0407     /* Get the SN to turn into a Unique ID */
0408     smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumTop32, &top32);
0409     smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumBottom32, &bottom32);
0410 
0411     adev->unique_id = ((uint64_t)bottom32 << 32) | top32;
0412 }
0413 
0414 static int vega20_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
0415 {
0416     return 0;
0417 }
0418 
0419 static int vega20_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
0420 {
0421     kfree(hwmgr->backend);
0422     hwmgr->backend = NULL;
0423 
0424     return 0;
0425 }
0426 
0427 static int vega20_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
0428 {
0429     struct vega20_hwmgr *data;
0430     struct amdgpu_device *adev = hwmgr->adev;
0431 
0432     data = kzalloc(sizeof(struct vega20_hwmgr), GFP_KERNEL);
0433     if (data == NULL)
0434         return -ENOMEM;
0435 
0436     hwmgr->backend = data;
0437 
0438     hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
0439     hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
0440     hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
0441 
0442     vega20_set_default_registry_data(hwmgr);
0443 
0444     data->disable_dpm_mask = 0xff;
0445 
0446     /* need to set voltage control types before EVV patching */
0447     data->vddc_control = VEGA20_VOLTAGE_CONTROL_NONE;
0448     data->mvdd_control = VEGA20_VOLTAGE_CONTROL_NONE;
0449     data->vddci_control = VEGA20_VOLTAGE_CONTROL_NONE;
0450 
0451     data->water_marks_bitmap = 0;
0452     data->avfs_exist = false;
0453 
0454     vega20_set_features_platform_caps(hwmgr);
0455 
0456     vega20_init_dpm_defaults(hwmgr);
0457 
0458     /* Parse pptable data read from VBIOS */
0459     vega20_set_private_data_based_on_pptable(hwmgr);
0460 
0461     data->is_tlu_enabled = false;
0462 
0463     hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
0464             VEGA20_MAX_HARDWARE_POWERLEVELS;
0465     hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
0466     hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50;
0467 
0468     hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */
0469     /* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */
0470     hwmgr->platform_descriptor.clockStep.engineClock = 500;
0471     hwmgr->platform_descriptor.clockStep.memoryClock = 500;
0472 
0473     data->total_active_cus = adev->gfx.cu_info.number;
0474     data->is_custom_profile_set = false;
0475 
0476     return 0;
0477 }
0478 
0479 static int vega20_init_sclk_threshold(struct pp_hwmgr *hwmgr)
0480 {
0481     struct vega20_hwmgr *data =
0482             (struct vega20_hwmgr *)(hwmgr->backend);
0483 
0484     data->low_sclk_interrupt_threshold = 0;
0485 
0486     return 0;
0487 }
0488 
0489 static int vega20_setup_asic_task(struct pp_hwmgr *hwmgr)
0490 {
0491     struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
0492     int ret = 0;
0493     bool use_baco = (amdgpu_in_reset(adev) &&
0494              (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO)) ||
0495         (adev->in_runpm && amdgpu_asic_supports_baco(adev));
0496 
0497     ret = vega20_init_sclk_threshold(hwmgr);
0498     PP_ASSERT_WITH_CODE(!ret,
0499             "Failed to init sclk threshold!",
0500             return ret);
0501 
0502     if (use_baco) {
0503         ret = vega20_baco_apply_vdci_flush_workaround(hwmgr);
0504         if (ret)
0505             pr_err("Failed to apply vega20 baco workaround!\n");
0506     }
0507 
0508     return ret;
0509 }
0510 
0511 /*
0512  * @fn vega20_init_dpm_state
0513  * @brief Function to initialize all Soft Min/Max and Hard Min/Max to 0xff.
0514  *
0515  * @param    dpm_state - the address of the DPM Table to initiailize.
0516  * @return   None.
0517  */
0518 static void vega20_init_dpm_state(struct vega20_dpm_state *dpm_state)
0519 {
0520     dpm_state->soft_min_level = 0x0;
0521     dpm_state->soft_max_level = VG20_CLOCK_MAX_DEFAULT;
0522     dpm_state->hard_min_level = 0x0;
0523     dpm_state->hard_max_level = VG20_CLOCK_MAX_DEFAULT;
0524 }
0525 
0526 static int vega20_get_number_of_dpm_level(struct pp_hwmgr *hwmgr,
0527         PPCLK_e clk_id, uint32_t *num_of_levels)
0528 {
0529     int ret = 0;
0530 
0531     ret = smum_send_msg_to_smc_with_parameter(hwmgr,
0532             PPSMC_MSG_GetDpmFreqByIndex,
0533             (clk_id << 16 | 0xFF),
0534             num_of_levels);
0535     PP_ASSERT_WITH_CODE(!ret,
0536             "[GetNumOfDpmLevel] failed to get dpm levels!",
0537             return ret);
0538 
0539     return ret;
0540 }
0541 
0542 static int vega20_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr,
0543         PPCLK_e clk_id, uint32_t index, uint32_t *clk)
0544 {
0545     int ret = 0;
0546 
0547     ret = smum_send_msg_to_smc_with_parameter(hwmgr,
0548             PPSMC_MSG_GetDpmFreqByIndex,
0549             (clk_id << 16 | index),
0550             clk);
0551     PP_ASSERT_WITH_CODE(!ret,
0552             "[GetDpmFreqByIndex] failed to get dpm freq by index!",
0553             return ret);
0554 
0555     return ret;
0556 }
0557 
0558 static int vega20_setup_single_dpm_table(struct pp_hwmgr *hwmgr,
0559         struct vega20_single_dpm_table *dpm_table, PPCLK_e clk_id)
0560 {
0561     int ret = 0;
0562     uint32_t i, num_of_levels, clk;
0563 
0564     ret = vega20_get_number_of_dpm_level(hwmgr, clk_id, &num_of_levels);
0565     PP_ASSERT_WITH_CODE(!ret,
0566             "[SetupSingleDpmTable] failed to get clk levels!",
0567             return ret);
0568 
0569     dpm_table->count = num_of_levels;
0570 
0571     for (i = 0; i < num_of_levels; i++) {
0572         ret = vega20_get_dpm_frequency_by_index(hwmgr, clk_id, i, &clk);
0573         PP_ASSERT_WITH_CODE(!ret,
0574             "[SetupSingleDpmTable] failed to get clk of specific level!",
0575             return ret);
0576         dpm_table->dpm_levels[i].value = clk;
0577         dpm_table->dpm_levels[i].enabled = true;
0578     }
0579 
0580     return ret;
0581 }
0582 
0583 static int vega20_setup_gfxclk_dpm_table(struct pp_hwmgr *hwmgr)
0584 {
0585     struct vega20_hwmgr *data =
0586             (struct vega20_hwmgr *)(hwmgr->backend);
0587     struct vega20_single_dpm_table *dpm_table;
0588     int ret = 0;
0589 
0590     dpm_table = &(data->dpm_table.gfx_table);
0591     if (data->smu_features[GNLD_DPM_GFXCLK].enabled) {
0592         ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_GFXCLK);
0593         PP_ASSERT_WITH_CODE(!ret,
0594                 "[SetupDefaultDpmTable] failed to get gfxclk dpm levels!",
0595                 return ret);
0596     } else {
0597         dpm_table->count = 1;
0598         dpm_table->dpm_levels[0].value = data->vbios_boot_state.gfx_clock / 100;
0599     }
0600 
0601     return ret;
0602 }
0603 
0604 static int vega20_setup_memclk_dpm_table(struct pp_hwmgr *hwmgr)
0605 {
0606     struct vega20_hwmgr *data =
0607             (struct vega20_hwmgr *)(hwmgr->backend);
0608     struct vega20_single_dpm_table *dpm_table;
0609     int ret = 0;
0610 
0611     dpm_table = &(data->dpm_table.mem_table);
0612     if (data->smu_features[GNLD_DPM_UCLK].enabled) {
0613         ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_UCLK);
0614         PP_ASSERT_WITH_CODE(!ret,
0615                 "[SetupDefaultDpmTable] failed to get memclk dpm levels!",
0616                 return ret);
0617     } else {
0618         dpm_table->count = 1;
0619         dpm_table->dpm_levels[0].value = data->vbios_boot_state.mem_clock / 100;
0620     }
0621 
0622     return ret;
0623 }
0624 
0625 /*
0626  * This function is to initialize all DPM state tables
0627  * for SMU based on the dependency table.
0628  * Dynamic state patching function will then trim these
0629  * state tables to the allowed range based
0630  * on the power policy or external client requests,
0631  * such as UVD request, etc.
0632  */
0633 static int vega20_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
0634 {
0635     struct vega20_hwmgr *data =
0636             (struct vega20_hwmgr *)(hwmgr->backend);
0637     struct vega20_single_dpm_table *dpm_table;
0638     int ret = 0;
0639 
0640     memset(&data->dpm_table, 0, sizeof(data->dpm_table));
0641 
0642     /* socclk */
0643     dpm_table = &(data->dpm_table.soc_table);
0644     if (data->smu_features[GNLD_DPM_SOCCLK].enabled) {
0645         ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_SOCCLK);
0646         PP_ASSERT_WITH_CODE(!ret,
0647                 "[SetupDefaultDpmTable] failed to get socclk dpm levels!",
0648                 return ret);
0649     } else {
0650         dpm_table->count = 1;
0651         dpm_table->dpm_levels[0].value = data->vbios_boot_state.soc_clock / 100;
0652     }
0653     vega20_init_dpm_state(&(dpm_table->dpm_state));
0654 
0655     /* gfxclk */
0656     dpm_table = &(data->dpm_table.gfx_table);
0657     ret = vega20_setup_gfxclk_dpm_table(hwmgr);
0658     if (ret)
0659         return ret;
0660     vega20_init_dpm_state(&(dpm_table->dpm_state));
0661 
0662     /* memclk */
0663     dpm_table = &(data->dpm_table.mem_table);
0664     ret = vega20_setup_memclk_dpm_table(hwmgr);
0665     if (ret)
0666         return ret;
0667     vega20_init_dpm_state(&(dpm_table->dpm_state));
0668 
0669     /* eclk */
0670     dpm_table = &(data->dpm_table.eclk_table);
0671     if (data->smu_features[GNLD_DPM_VCE].enabled) {
0672         ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_ECLK);
0673         PP_ASSERT_WITH_CODE(!ret,
0674                 "[SetupDefaultDpmTable] failed to get eclk dpm levels!",
0675                 return ret);
0676     } else {
0677         dpm_table->count = 1;
0678         dpm_table->dpm_levels[0].value = data->vbios_boot_state.eclock / 100;
0679     }
0680     vega20_init_dpm_state(&(dpm_table->dpm_state));
0681 
0682     /* vclk */
0683     dpm_table = &(data->dpm_table.vclk_table);
0684     if (data->smu_features[GNLD_DPM_UVD].enabled) {
0685         ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_VCLK);
0686         PP_ASSERT_WITH_CODE(!ret,
0687                 "[SetupDefaultDpmTable] failed to get vclk dpm levels!",
0688                 return ret);
0689     } else {
0690         dpm_table->count = 1;
0691         dpm_table->dpm_levels[0].value = data->vbios_boot_state.vclock / 100;
0692     }
0693     vega20_init_dpm_state(&(dpm_table->dpm_state));
0694 
0695     /* dclk */
0696     dpm_table = &(data->dpm_table.dclk_table);
0697     if (data->smu_features[GNLD_DPM_UVD].enabled) {
0698         ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DCLK);
0699         PP_ASSERT_WITH_CODE(!ret,
0700                 "[SetupDefaultDpmTable] failed to get dclk dpm levels!",
0701                 return ret);
0702     } else {
0703         dpm_table->count = 1;
0704         dpm_table->dpm_levels[0].value = data->vbios_boot_state.dclock / 100;
0705     }
0706     vega20_init_dpm_state(&(dpm_table->dpm_state));
0707 
0708     /* dcefclk */
0709     dpm_table = &(data->dpm_table.dcef_table);
0710     if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
0711         ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DCEFCLK);
0712         PP_ASSERT_WITH_CODE(!ret,
0713                 "[SetupDefaultDpmTable] failed to get dcefclk dpm levels!",
0714                 return ret);
0715     } else {
0716         dpm_table->count = 1;
0717         dpm_table->dpm_levels[0].value = data->vbios_boot_state.dcef_clock / 100;
0718     }
0719     vega20_init_dpm_state(&(dpm_table->dpm_state));
0720 
0721     /* pixclk */
0722     dpm_table = &(data->dpm_table.pixel_table);
0723     if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
0724         ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_PIXCLK);
0725         PP_ASSERT_WITH_CODE(!ret,
0726                 "[SetupDefaultDpmTable] failed to get pixclk dpm levels!",
0727                 return ret);
0728     } else
0729         dpm_table->count = 0;
0730     vega20_init_dpm_state(&(dpm_table->dpm_state));
0731 
0732     /* dispclk */
0733     dpm_table = &(data->dpm_table.display_table);
0734     if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
0735         ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DISPCLK);
0736         PP_ASSERT_WITH_CODE(!ret,
0737                 "[SetupDefaultDpmTable] failed to get dispclk dpm levels!",
0738                 return ret);
0739     } else
0740         dpm_table->count = 0;
0741     vega20_init_dpm_state(&(dpm_table->dpm_state));
0742 
0743     /* phyclk */
0744     dpm_table = &(data->dpm_table.phy_table);
0745     if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
0746         ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_PHYCLK);
0747         PP_ASSERT_WITH_CODE(!ret,
0748                 "[SetupDefaultDpmTable] failed to get phyclk dpm levels!",
0749                 return ret);
0750     } else
0751         dpm_table->count = 0;
0752     vega20_init_dpm_state(&(dpm_table->dpm_state));
0753 
0754     /* fclk */
0755     dpm_table = &(data->dpm_table.fclk_table);
0756     if (data->smu_features[GNLD_DPM_FCLK].enabled) {
0757         ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_FCLK);
0758         PP_ASSERT_WITH_CODE(!ret,
0759                 "[SetupDefaultDpmTable] failed to get fclk dpm levels!",
0760                 return ret);
0761     } else {
0762         dpm_table->count = 1;
0763         dpm_table->dpm_levels[0].value = data->vbios_boot_state.fclock / 100;
0764     }
0765     vega20_init_dpm_state(&(dpm_table->dpm_state));
0766 
0767     /* save a copy of the default DPM table */
0768     memcpy(&(data->golden_dpm_table), &(data->dpm_table),
0769             sizeof(struct vega20_dpm_table));
0770 
0771     return 0;
0772 }
0773 
0774 /**
0775  * vega20_init_smc_table - Initializes the SMC table and uploads it
0776  *
0777  * @hwmgr:  the address of the powerplay hardware manager.
0778  * return:  always 0
0779  */
0780 static int vega20_init_smc_table(struct pp_hwmgr *hwmgr)
0781 {
0782     int result;
0783     struct vega20_hwmgr *data =
0784             (struct vega20_hwmgr *)(hwmgr->backend);
0785     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
0786     struct pp_atomfwctrl_bios_boot_up_values boot_up_values;
0787     struct phm_ppt_v3_information *pptable_information =
0788         (struct phm_ppt_v3_information *)hwmgr->pptable;
0789 
0790     result = pp_atomfwctrl_get_vbios_bootup_values(hwmgr, &boot_up_values);
0791     PP_ASSERT_WITH_CODE(!result,
0792             "[InitSMCTable] Failed to get vbios bootup values!",
0793             return result);
0794 
0795     data->vbios_boot_state.vddc     = boot_up_values.usVddc;
0796     data->vbios_boot_state.vddci    = boot_up_values.usVddci;
0797     data->vbios_boot_state.mvddc    = boot_up_values.usMvddc;
0798     data->vbios_boot_state.gfx_clock = boot_up_values.ulGfxClk;
0799     data->vbios_boot_state.mem_clock = boot_up_values.ulUClk;
0800     data->vbios_boot_state.soc_clock = boot_up_values.ulSocClk;
0801     data->vbios_boot_state.dcef_clock = boot_up_values.ulDCEFClk;
0802     data->vbios_boot_state.eclock = boot_up_values.ulEClk;
0803     data->vbios_boot_state.vclock = boot_up_values.ulVClk;
0804     data->vbios_boot_state.dclock = boot_up_values.ulDClk;
0805     data->vbios_boot_state.fclock = boot_up_values.ulFClk;
0806     data->vbios_boot_state.uc_cooling_id = boot_up_values.ucCoolingID;
0807 
0808     smum_send_msg_to_smc_with_parameter(hwmgr,
0809             PPSMC_MSG_SetMinDeepSleepDcefclk,
0810         (uint32_t)(data->vbios_boot_state.dcef_clock / 100),
0811             NULL);
0812 
0813     memcpy(pp_table, pptable_information->smc_pptable, sizeof(PPTable_t));
0814 
0815     result = smum_smc_table_manager(hwmgr,
0816                     (uint8_t *)pp_table, TABLE_PPTABLE, false);
0817     PP_ASSERT_WITH_CODE(!result,
0818             "[InitSMCTable] Failed to upload PPtable!",
0819             return result);
0820 
0821     return 0;
0822 }
0823 
0824 /*
0825  * Override PCIe link speed and link width for DPM Level 1. PPTable entries
0826  * reflect the ASIC capabilities and not the system capabilities. For e.g.
0827  * Vega20 board in a PCI Gen3 system. In this case, when SMU's tries to switch
0828  * to DPM1, it fails as system doesn't support Gen4.
0829  */
0830 static int vega20_override_pcie_parameters(struct pp_hwmgr *hwmgr)
0831 {
0832     struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
0833     struct vega20_hwmgr *data =
0834             (struct vega20_hwmgr *)(hwmgr->backend);
0835     uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg, pcie_gen_arg, pcie_width_arg;
0836     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
0837     int i;
0838     int ret;
0839 
0840     if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
0841         pcie_gen = 3;
0842     else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
0843         pcie_gen = 2;
0844     else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
0845         pcie_gen = 1;
0846     else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1)
0847         pcie_gen = 0;
0848 
0849     if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16)
0850         pcie_width = 6;
0851     else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12)
0852         pcie_width = 5;
0853     else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8)
0854         pcie_width = 4;
0855     else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4)
0856         pcie_width = 3;
0857     else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2)
0858         pcie_width = 2;
0859     else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1)
0860         pcie_width = 1;
0861 
0862     /* Bit 31:16: LCLK DPM level. 0 is DPM0, and 1 is DPM1
0863      * Bit 15:8:  PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4
0864      * Bit 7:0:   PCIE lane width, 1 to 7 corresponds is x1 to x32
0865      */
0866     for (i = 0; i < NUM_LINK_LEVELS; i++) {
0867         pcie_gen_arg = (pp_table->PcieGenSpeed[i] > pcie_gen) ? pcie_gen :
0868             pp_table->PcieGenSpeed[i];
0869         pcie_width_arg = (pp_table->PcieLaneCount[i] > pcie_width) ? pcie_width :
0870             pp_table->PcieLaneCount[i];
0871 
0872         if (pcie_gen_arg != pp_table->PcieGenSpeed[i] || pcie_width_arg !=
0873             pp_table->PcieLaneCount[i]) {
0874             smu_pcie_arg = (i << 16) | (pcie_gen_arg << 8) | pcie_width_arg;
0875             ret = smum_send_msg_to_smc_with_parameter(hwmgr,
0876                 PPSMC_MSG_OverridePcieParameters, smu_pcie_arg,
0877                 NULL);
0878             PP_ASSERT_WITH_CODE(!ret,
0879                 "[OverridePcieParameters] Attempt to override pcie params failed!",
0880                 return ret);
0881         }
0882 
0883         /* update the pptable */
0884         pp_table->PcieGenSpeed[i] = pcie_gen_arg;
0885         pp_table->PcieLaneCount[i] = pcie_width_arg;
0886     }
0887 
0888     /* override to the highest if it's disabled from ppfeaturmask */
0889     if (data->registry_data.pcie_dpm_key_disabled) {
0890         for (i = 0; i < NUM_LINK_LEVELS; i++) {
0891             smu_pcie_arg = (i << 16) | (pcie_gen << 8) | pcie_width;
0892             ret = smum_send_msg_to_smc_with_parameter(hwmgr,
0893                 PPSMC_MSG_OverridePcieParameters, smu_pcie_arg,
0894                 NULL);
0895             PP_ASSERT_WITH_CODE(!ret,
0896                 "[OverridePcieParameters] Attempt to override pcie params failed!",
0897                 return ret);
0898 
0899             pp_table->PcieGenSpeed[i] = pcie_gen;
0900             pp_table->PcieLaneCount[i] = pcie_width;
0901         }
0902         ret = vega20_enable_smc_features(hwmgr,
0903                 false,
0904                 data->smu_features[GNLD_DPM_LINK].smu_feature_bitmap);
0905         PP_ASSERT_WITH_CODE(!ret,
0906                 "Attempt to Disable DPM LINK Failed!",
0907                 return ret);
0908         data->smu_features[GNLD_DPM_LINK].enabled = false;
0909         data->smu_features[GNLD_DPM_LINK].supported = false;
0910     }
0911 
0912     return 0;
0913 }
0914 
0915 static int vega20_set_allowed_featuresmask(struct pp_hwmgr *hwmgr)
0916 {
0917     struct vega20_hwmgr *data =
0918             (struct vega20_hwmgr *)(hwmgr->backend);
0919     uint32_t allowed_features_low = 0, allowed_features_high = 0;
0920     int i;
0921     int ret = 0;
0922 
0923     for (i = 0; i < GNLD_FEATURES_MAX; i++)
0924         if (data->smu_features[i].allowed)
0925             data->smu_features[i].smu_feature_id > 31 ?
0926                 (allowed_features_high |=
0927                  ((data->smu_features[i].smu_feature_bitmap >> SMU_FEATURES_HIGH_SHIFT)
0928                   & 0xFFFFFFFF)) :
0929                 (allowed_features_low |=
0930                  ((data->smu_features[i].smu_feature_bitmap >> SMU_FEATURES_LOW_SHIFT)
0931                   & 0xFFFFFFFF));
0932 
0933     ret = smum_send_msg_to_smc_with_parameter(hwmgr,
0934         PPSMC_MSG_SetAllowedFeaturesMaskHigh, allowed_features_high, NULL);
0935     PP_ASSERT_WITH_CODE(!ret,
0936         "[SetAllowedFeaturesMask] Attempt to set allowed features mask(high) failed!",
0937         return ret);
0938 
0939     ret = smum_send_msg_to_smc_with_parameter(hwmgr,
0940         PPSMC_MSG_SetAllowedFeaturesMaskLow, allowed_features_low, NULL);
0941     PP_ASSERT_WITH_CODE(!ret,
0942         "[SetAllowedFeaturesMask] Attempt to set allowed features mask (low) failed!",
0943         return ret);
0944 
0945     return 0;
0946 }
0947 
0948 static int vega20_run_btc(struct pp_hwmgr *hwmgr)
0949 {
0950     return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunBtc, NULL);
0951 }
0952 
0953 static int vega20_run_btc_afll(struct pp_hwmgr *hwmgr)
0954 {
0955     return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunAfllBtc, NULL);
0956 }
0957 
0958 static int vega20_enable_all_smu_features(struct pp_hwmgr *hwmgr)
0959 {
0960     struct vega20_hwmgr *data =
0961             (struct vega20_hwmgr *)(hwmgr->backend);
0962     uint64_t features_enabled;
0963     int i;
0964     bool enabled;
0965     int ret = 0;
0966 
0967     PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr,
0968             PPSMC_MSG_EnableAllSmuFeatures,
0969             NULL)) == 0,
0970             "[EnableAllSMUFeatures] Failed to enable all smu features!",
0971             return ret);
0972 
0973     ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
0974     PP_ASSERT_WITH_CODE(!ret,
0975             "[EnableAllSmuFeatures] Failed to get enabled smc features!",
0976             return ret);
0977 
0978     for (i = 0; i < GNLD_FEATURES_MAX; i++) {
0979         enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ?
0980             true : false;
0981         data->smu_features[i].enabled = enabled;
0982         data->smu_features[i].supported = enabled;
0983 
0984 #if 0
0985         if (data->smu_features[i].allowed && !enabled)
0986             pr_info("[EnableAllSMUFeatures] feature %d is expected enabled!", i);
0987         else if (!data->smu_features[i].allowed && enabled)
0988             pr_info("[EnableAllSMUFeatures] feature %d is expected disabled!", i);
0989 #endif
0990     }
0991 
0992     return 0;
0993 }
0994 
0995 static int vega20_notify_smc_display_change(struct pp_hwmgr *hwmgr)
0996 {
0997     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
0998 
0999     if (data->smu_features[GNLD_DPM_UCLK].enabled)
1000         return smum_send_msg_to_smc_with_parameter(hwmgr,
1001             PPSMC_MSG_SetUclkFastSwitch,
1002             1,
1003             NULL);
1004 
1005     return 0;
1006 }
1007 
1008 static int vega20_send_clock_ratio(struct pp_hwmgr *hwmgr)
1009 {
1010     struct vega20_hwmgr *data =
1011             (struct vega20_hwmgr *)(hwmgr->backend);
1012 
1013     return smum_send_msg_to_smc_with_parameter(hwmgr,
1014             PPSMC_MSG_SetFclkGfxClkRatio,
1015             data->registry_data.fclk_gfxclk_ratio,
1016             NULL);
1017 }
1018 
1019 static int vega20_disable_all_smu_features(struct pp_hwmgr *hwmgr)
1020 {
1021     struct vega20_hwmgr *data =
1022             (struct vega20_hwmgr *)(hwmgr->backend);
1023     int i, ret = 0;
1024 
1025     PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr,
1026             PPSMC_MSG_DisableAllSmuFeatures,
1027             NULL)) == 0,
1028             "[DisableAllSMUFeatures] Failed to disable all smu features!",
1029             return ret);
1030 
1031     for (i = 0; i < GNLD_FEATURES_MAX; i++)
1032         data->smu_features[i].enabled = 0;
1033 
1034     return 0;
1035 }
1036 
1037 static int vega20_od8_set_feature_capabilities(
1038         struct pp_hwmgr *hwmgr)
1039 {
1040     struct phm_ppt_v3_information *pptable_information =
1041         (struct phm_ppt_v3_information *)hwmgr->pptable;
1042     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1043     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
1044     struct vega20_od8_settings *od_settings = &(data->od8_settings);
1045 
1046     od_settings->overdrive8_capabilities = 0;
1047 
1048     if (data->smu_features[GNLD_DPM_GFXCLK].enabled) {
1049         if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_LIMITS] &&
1050             pptable_information->od_settings_max[OD8_SETTING_GFXCLK_FMAX] > 0 &&
1051             pptable_information->od_settings_min[OD8_SETTING_GFXCLK_FMIN] > 0 &&
1052             (pptable_information->od_settings_max[OD8_SETTING_GFXCLK_FMAX] >=
1053             pptable_information->od_settings_min[OD8_SETTING_GFXCLK_FMIN]))
1054             od_settings->overdrive8_capabilities |= OD8_GFXCLK_LIMITS;
1055 
1056         if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_CURVE] &&
1057             (pptable_information->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] >=
1058              pp_table->MinVoltageGfx / VOLTAGE_SCALE) &&
1059             (pptable_information->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3] <=
1060              pp_table->MaxVoltageGfx / VOLTAGE_SCALE) &&
1061             (pptable_information->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3] >=
1062              pptable_information->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1]))
1063             od_settings->overdrive8_capabilities |= OD8_GFXCLK_CURVE;
1064     }
1065 
1066     if (data->smu_features[GNLD_DPM_UCLK].enabled) {
1067         pptable_information->od_settings_min[OD8_SETTING_UCLK_FMAX] =
1068             data->dpm_table.mem_table.dpm_levels[data->dpm_table.mem_table.count - 2].value;
1069         if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_UCLK_MAX] &&
1070             pptable_information->od_settings_min[OD8_SETTING_UCLK_FMAX] > 0 &&
1071             pptable_information->od_settings_max[OD8_SETTING_UCLK_FMAX] > 0 &&
1072             (pptable_information->od_settings_max[OD8_SETTING_UCLK_FMAX] >=
1073             pptable_information->od_settings_min[OD8_SETTING_UCLK_FMAX]))
1074             od_settings->overdrive8_capabilities |= OD8_UCLK_MAX;
1075     }
1076 
1077     if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_POWER_LIMIT] &&
1078         pptable_information->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
1079         pptable_information->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] <= 100 &&
1080         pptable_information->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
1081         pptable_information->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] <= 100)
1082         od_settings->overdrive8_capabilities |= OD8_POWER_LIMIT;
1083 
1084     if (data->smu_features[GNLD_FAN_CONTROL].enabled) {
1085         if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_ACOUSTIC_LIMIT] &&
1086             pptable_information->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 &&
1087             pptable_information->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 &&
1088             (pptable_information->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] >=
1089              pptable_information->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT]))
1090             od_settings->overdrive8_capabilities |= OD8_ACOUSTIC_LIMIT_SCLK;
1091 
1092         if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_SPEED_MIN] &&
1093             (pptable_information->od_settings_min[OD8_SETTING_FAN_MIN_SPEED] >=
1094             (pp_table->FanPwmMin * pp_table->FanMaximumRpm / 100)) &&
1095             pptable_information->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] > 0 &&
1096             (pptable_information->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] >=
1097              pptable_information->od_settings_min[OD8_SETTING_FAN_MIN_SPEED]))
1098             od_settings->overdrive8_capabilities |= OD8_FAN_SPEED_MIN;
1099     }
1100 
1101     if (data->smu_features[GNLD_THERMAL].enabled) {
1102         if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_FAN] &&
1103             pptable_information->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] > 0 &&
1104             pptable_information->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP] > 0 &&
1105             (pptable_information->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] >=
1106              pptable_information->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP]))
1107             od_settings->overdrive8_capabilities |= OD8_TEMPERATURE_FAN;
1108 
1109         if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_SYSTEM] &&
1110             pptable_information->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] > 0 &&
1111             pptable_information->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX] > 0 &&
1112             (pptable_information->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] >=
1113              pptable_information->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX]))
1114             od_settings->overdrive8_capabilities |= OD8_TEMPERATURE_SYSTEM;
1115     }
1116 
1117     if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_MEMORY_TIMING_TUNE])
1118         od_settings->overdrive8_capabilities |= OD8_MEMORY_TIMING_TUNE;
1119 
1120     if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_ZERO_RPM_CONTROL] &&
1121         pp_table->FanZeroRpmEnable)
1122         od_settings->overdrive8_capabilities |= OD8_FAN_ZERO_RPM_CONTROL;
1123 
1124     if (!od_settings->overdrive8_capabilities)
1125         hwmgr->od_enabled = false;
1126 
1127     return 0;
1128 }
1129 
1130 static int vega20_od8_set_feature_id(
1131         struct pp_hwmgr *hwmgr)
1132 {
1133     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1134     struct vega20_od8_settings *od_settings = &(data->od8_settings);
1135 
1136     if (od_settings->overdrive8_capabilities & OD8_GFXCLK_LIMITS) {
1137         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id =
1138             OD8_GFXCLK_LIMITS;
1139         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id =
1140             OD8_GFXCLK_LIMITS;
1141     } else {
1142         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id =
1143             0;
1144         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id =
1145             0;
1146     }
1147 
1148     if (od_settings->overdrive8_capabilities & OD8_GFXCLK_CURVE) {
1149         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id =
1150             OD8_GFXCLK_CURVE;
1151         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id =
1152             OD8_GFXCLK_CURVE;
1153         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id =
1154             OD8_GFXCLK_CURVE;
1155         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id =
1156             OD8_GFXCLK_CURVE;
1157         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id =
1158             OD8_GFXCLK_CURVE;
1159         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id =
1160             OD8_GFXCLK_CURVE;
1161     } else {
1162         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id =
1163             0;
1164         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id =
1165             0;
1166         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id =
1167             0;
1168         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id =
1169             0;
1170         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id =
1171             0;
1172         od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id =
1173             0;
1174     }
1175 
1176     if (od_settings->overdrive8_capabilities & OD8_UCLK_MAX)
1177         od_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id = OD8_UCLK_MAX;
1178     else
1179         od_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id = 0;
1180 
1181     if (od_settings->overdrive8_capabilities & OD8_POWER_LIMIT)
1182         od_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id = OD8_POWER_LIMIT;
1183     else
1184         od_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id = 0;
1185 
1186     if (od_settings->overdrive8_capabilities & OD8_ACOUSTIC_LIMIT_SCLK)
1187         od_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id =
1188             OD8_ACOUSTIC_LIMIT_SCLK;
1189     else
1190         od_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id =
1191             0;
1192 
1193     if (od_settings->overdrive8_capabilities & OD8_FAN_SPEED_MIN)
1194         od_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id =
1195             OD8_FAN_SPEED_MIN;
1196     else
1197         od_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id =
1198             0;
1199 
1200     if (od_settings->overdrive8_capabilities & OD8_TEMPERATURE_FAN)
1201         od_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id =
1202             OD8_TEMPERATURE_FAN;
1203     else
1204         od_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id =
1205             0;
1206 
1207     if (od_settings->overdrive8_capabilities & OD8_TEMPERATURE_SYSTEM)
1208         od_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id =
1209             OD8_TEMPERATURE_SYSTEM;
1210     else
1211         od_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id =
1212             0;
1213 
1214     return 0;
1215 }
1216 
1217 static int vega20_od8_get_gfx_clock_base_voltage(
1218         struct pp_hwmgr *hwmgr,
1219         uint32_t *voltage,
1220         uint32_t freq)
1221 {
1222     int ret = 0;
1223 
1224     ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1225             PPSMC_MSG_GetAVFSVoltageByDpm,
1226             ((AVFS_CURVE << 24) | (OD8_HOTCURVE_TEMPERATURE << 16) | freq),
1227             voltage);
1228     PP_ASSERT_WITH_CODE(!ret,
1229             "[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!",
1230             return ret);
1231 
1232     *voltage = *voltage / VOLTAGE_SCALE;
1233 
1234     return 0;
1235 }
1236 
1237 static int vega20_od8_initialize_default_settings(
1238         struct pp_hwmgr *hwmgr)
1239 {
1240     struct phm_ppt_v3_information *pptable_information =
1241         (struct phm_ppt_v3_information *)hwmgr->pptable;
1242     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1243     struct vega20_od8_settings *od8_settings = &(data->od8_settings);
1244     OverDriveTable_t *od_table = &(data->smc_state_table.overdrive_table);
1245     int i, ret = 0;
1246 
1247     /* Set Feature Capabilities */
1248     vega20_od8_set_feature_capabilities(hwmgr);
1249 
1250     /* Map FeatureID to individual settings */
1251     vega20_od8_set_feature_id(hwmgr);
1252 
1253     /* Set default values */
1254     ret = smum_smc_table_manager(hwmgr, (uint8_t *)od_table, TABLE_OVERDRIVE, true);
1255     PP_ASSERT_WITH_CODE(!ret,
1256             "Failed to export over drive table!",
1257             return ret);
1258 
1259     if (od8_settings->overdrive8_capabilities & OD8_GFXCLK_LIMITS) {
1260         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value =
1261             od_table->GfxclkFmin;
1262         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value =
1263             od_table->GfxclkFmax;
1264     } else {
1265         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value =
1266             0;
1267         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value =
1268             0;
1269     }
1270 
1271     if (od8_settings->overdrive8_capabilities & OD8_GFXCLK_CURVE) {
1272         od_table->GfxclkFreq1 = od_table->GfxclkFmin;
1273         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value =
1274             od_table->GfxclkFreq1;
1275 
1276         od_table->GfxclkFreq3 = od_table->GfxclkFmax;
1277         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value =
1278             od_table->GfxclkFreq3;
1279 
1280         od_table->GfxclkFreq2 = (od_table->GfxclkFreq1 + od_table->GfxclkFreq3) / 2;
1281         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value =
1282             od_table->GfxclkFreq2;
1283 
1284         PP_ASSERT_WITH_CODE(!vega20_od8_get_gfx_clock_base_voltage(hwmgr,
1285                    &(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value),
1286                      od_table->GfxclkFreq1),
1287                 "[PhwVega20_OD8_InitializeDefaultSettings] Failed to get Base clock voltage from SMU!",
1288                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value = 0);
1289         od_table->GfxclkVolt1 = od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value
1290             * VOLTAGE_SCALE;
1291 
1292         PP_ASSERT_WITH_CODE(!vega20_od8_get_gfx_clock_base_voltage(hwmgr,
1293                    &(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value),
1294                      od_table->GfxclkFreq2),
1295                 "[PhwVega20_OD8_InitializeDefaultSettings] Failed to get Base clock voltage from SMU!",
1296                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value = 0);
1297         od_table->GfxclkVolt2 = od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value
1298             * VOLTAGE_SCALE;
1299 
1300         PP_ASSERT_WITH_CODE(!vega20_od8_get_gfx_clock_base_voltage(hwmgr,
1301                    &(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value),
1302                      od_table->GfxclkFreq3),
1303                 "[PhwVega20_OD8_InitializeDefaultSettings] Failed to get Base clock voltage from SMU!",
1304                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value = 0);
1305         od_table->GfxclkVolt3 = od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value
1306             * VOLTAGE_SCALE;
1307     } else {
1308         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value =
1309             0;
1310         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value =
1311             0;
1312         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value =
1313             0;
1314         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value =
1315             0;
1316         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value =
1317             0;
1318         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value =
1319             0;
1320     }
1321 
1322     if (od8_settings->overdrive8_capabilities & OD8_UCLK_MAX)
1323         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value =
1324             od_table->UclkFmax;
1325     else
1326         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value =
1327             0;
1328 
1329     if (od8_settings->overdrive8_capabilities & OD8_POWER_LIMIT)
1330         od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value =
1331             od_table->OverDrivePct;
1332     else
1333         od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value =
1334             0;
1335 
1336     if (od8_settings->overdrive8_capabilities & OD8_ACOUSTIC_LIMIT_SCLK)
1337         od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value =
1338             od_table->FanMaximumRpm;
1339     else
1340         od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value =
1341             0;
1342 
1343     if (od8_settings->overdrive8_capabilities & OD8_FAN_SPEED_MIN)
1344         od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value =
1345             od_table->FanMinimumPwm * data->smc_state_table.pp_table.FanMaximumRpm / 100;
1346     else
1347         od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value =
1348             0;
1349 
1350     if (od8_settings->overdrive8_capabilities & OD8_TEMPERATURE_FAN)
1351         od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value =
1352             od_table->FanTargetTemperature;
1353     else
1354         od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value =
1355             0;
1356 
1357     if (od8_settings->overdrive8_capabilities & OD8_TEMPERATURE_SYSTEM)
1358         od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_value =
1359             od_table->MaxOpTemp;
1360     else
1361         od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_value =
1362             0;
1363 
1364     for (i = 0; i < OD8_SETTING_COUNT; i++) {
1365         if (od8_settings->od8_settings_array[i].feature_id) {
1366             od8_settings->od8_settings_array[i].min_value =
1367                 pptable_information->od_settings_min[i];
1368             od8_settings->od8_settings_array[i].max_value =
1369                 pptable_information->od_settings_max[i];
1370             od8_settings->od8_settings_array[i].current_value =
1371                 od8_settings->od8_settings_array[i].default_value;
1372         } else {
1373             od8_settings->od8_settings_array[i].min_value =
1374                 0;
1375             od8_settings->od8_settings_array[i].max_value =
1376                 0;
1377             od8_settings->od8_settings_array[i].current_value =
1378                 0;
1379         }
1380     }
1381 
1382     ret = smum_smc_table_manager(hwmgr, (uint8_t *)od_table, TABLE_OVERDRIVE, false);
1383     PP_ASSERT_WITH_CODE(!ret,
1384             "Failed to import over drive table!",
1385             return ret);
1386 
1387     return 0;
1388 }
1389 
1390 static int vega20_od8_set_settings(
1391         struct pp_hwmgr *hwmgr,
1392         uint32_t index,
1393         uint32_t value)
1394 {
1395     OverDriveTable_t od_table;
1396     int ret = 0;
1397     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1398     struct vega20_od8_single_setting *od8_settings =
1399             data->od8_settings.od8_settings_array;
1400 
1401     ret = smum_smc_table_manager(hwmgr, (uint8_t *)(&od_table), TABLE_OVERDRIVE, true);
1402     PP_ASSERT_WITH_CODE(!ret,
1403             "Failed to export over drive table!",
1404             return ret);
1405 
1406     switch(index) {
1407     case OD8_SETTING_GFXCLK_FMIN:
1408         od_table.GfxclkFmin = (uint16_t)value;
1409         break;
1410     case OD8_SETTING_GFXCLK_FMAX:
1411         if (value < od8_settings[OD8_SETTING_GFXCLK_FMAX].min_value ||
1412             value > od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value)
1413             return -EINVAL;
1414 
1415         od_table.GfxclkFmax = (uint16_t)value;
1416         break;
1417     case OD8_SETTING_GFXCLK_FREQ1:
1418         od_table.GfxclkFreq1 = (uint16_t)value;
1419         break;
1420     case OD8_SETTING_GFXCLK_VOLTAGE1:
1421         od_table.GfxclkVolt1 = (uint16_t)value;
1422         break;
1423     case OD8_SETTING_GFXCLK_FREQ2:
1424         od_table.GfxclkFreq2 = (uint16_t)value;
1425         break;
1426     case OD8_SETTING_GFXCLK_VOLTAGE2:
1427         od_table.GfxclkVolt2 = (uint16_t)value;
1428         break;
1429     case OD8_SETTING_GFXCLK_FREQ3:
1430         od_table.GfxclkFreq3 = (uint16_t)value;
1431         break;
1432     case OD8_SETTING_GFXCLK_VOLTAGE3:
1433         od_table.GfxclkVolt3 = (uint16_t)value;
1434         break;
1435     case OD8_SETTING_UCLK_FMAX:
1436         if (value < od8_settings[OD8_SETTING_UCLK_FMAX].min_value ||
1437             value > od8_settings[OD8_SETTING_UCLK_FMAX].max_value)
1438             return -EINVAL;
1439         od_table.UclkFmax = (uint16_t)value;
1440         break;
1441     case OD8_SETTING_POWER_PERCENTAGE:
1442         od_table.OverDrivePct = (int16_t)value;
1443         break;
1444     case OD8_SETTING_FAN_ACOUSTIC_LIMIT:
1445         od_table.FanMaximumRpm = (uint16_t)value;
1446         break;
1447     case OD8_SETTING_FAN_MIN_SPEED:
1448         od_table.FanMinimumPwm = (uint16_t)value;
1449         break;
1450     case OD8_SETTING_FAN_TARGET_TEMP:
1451         od_table.FanTargetTemperature = (uint16_t)value;
1452         break;
1453     case OD8_SETTING_OPERATING_TEMP_MAX:
1454         od_table.MaxOpTemp = (uint16_t)value;
1455         break;
1456     }
1457 
1458     ret = smum_smc_table_manager(hwmgr, (uint8_t *)(&od_table), TABLE_OVERDRIVE, false);
1459     PP_ASSERT_WITH_CODE(!ret,
1460             "Failed to import over drive table!",
1461             return ret);
1462 
1463     return 0;
1464 }
1465 
1466 static int vega20_get_sclk_od(
1467         struct pp_hwmgr *hwmgr)
1468 {
1469     struct vega20_hwmgr *data = hwmgr->backend;
1470     struct vega20_single_dpm_table *sclk_table =
1471             &(data->dpm_table.gfx_table);
1472     struct vega20_single_dpm_table *golden_sclk_table =
1473             &(data->golden_dpm_table.gfx_table);
1474     int value = sclk_table->dpm_levels[sclk_table->count - 1].value;
1475     int golden_value = golden_sclk_table->dpm_levels
1476             [golden_sclk_table->count - 1].value;
1477 
1478     /* od percentage */
1479     value -= golden_value;
1480     value = DIV_ROUND_UP(value * 100, golden_value);
1481 
1482     return value;
1483 }
1484 
1485 static int vega20_set_sclk_od(
1486         struct pp_hwmgr *hwmgr, uint32_t value)
1487 {
1488     struct vega20_hwmgr *data = hwmgr->backend;
1489     struct vega20_single_dpm_table *golden_sclk_table =
1490             &(data->golden_dpm_table.gfx_table);
1491     uint32_t od_sclk;
1492     int ret = 0;
1493 
1494     od_sclk = golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value * value;
1495     od_sclk /= 100;
1496     od_sclk += golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
1497 
1498     ret = vega20_od8_set_settings(hwmgr, OD8_SETTING_GFXCLK_FMAX, od_sclk);
1499     PP_ASSERT_WITH_CODE(!ret,
1500             "[SetSclkOD] failed to set od gfxclk!",
1501             return ret);
1502 
1503     /* retrieve updated gfxclk table */
1504     ret = vega20_setup_gfxclk_dpm_table(hwmgr);
1505     PP_ASSERT_WITH_CODE(!ret,
1506             "[SetSclkOD] failed to refresh gfxclk table!",
1507             return ret);
1508 
1509     return 0;
1510 }
1511 
1512 static int vega20_get_mclk_od(
1513         struct pp_hwmgr *hwmgr)
1514 {
1515     struct vega20_hwmgr *data = hwmgr->backend;
1516     struct vega20_single_dpm_table *mclk_table =
1517             &(data->dpm_table.mem_table);
1518     struct vega20_single_dpm_table *golden_mclk_table =
1519             &(data->golden_dpm_table.mem_table);
1520     int value = mclk_table->dpm_levels[mclk_table->count - 1].value;
1521     int golden_value = golden_mclk_table->dpm_levels
1522             [golden_mclk_table->count - 1].value;
1523 
1524     /* od percentage */
1525     value -= golden_value;
1526     value = DIV_ROUND_UP(value * 100, golden_value);
1527 
1528     return value;
1529 }
1530 
1531 static int vega20_set_mclk_od(
1532         struct pp_hwmgr *hwmgr, uint32_t value)
1533 {
1534     struct vega20_hwmgr *data = hwmgr->backend;
1535     struct vega20_single_dpm_table *golden_mclk_table =
1536             &(data->golden_dpm_table.mem_table);
1537     uint32_t od_mclk;
1538     int ret = 0;
1539 
1540     od_mclk = golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value * value;
1541     od_mclk /= 100;
1542     od_mclk += golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
1543 
1544     ret = vega20_od8_set_settings(hwmgr, OD8_SETTING_UCLK_FMAX, od_mclk);
1545     PP_ASSERT_WITH_CODE(!ret,
1546             "[SetMclkOD] failed to set od memclk!",
1547             return ret);
1548 
1549     /* retrieve updated memclk table */
1550     ret = vega20_setup_memclk_dpm_table(hwmgr);
1551     PP_ASSERT_WITH_CODE(!ret,
1552             "[SetMclkOD] failed to refresh memclk table!",
1553             return ret);
1554 
1555     return 0;
1556 }
1557 
1558 static int vega20_populate_umdpstate_clocks(
1559         struct pp_hwmgr *hwmgr)
1560 {
1561     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1562     struct vega20_single_dpm_table *gfx_table = &(data->dpm_table.gfx_table);
1563     struct vega20_single_dpm_table *mem_table = &(data->dpm_table.mem_table);
1564 
1565     hwmgr->pstate_sclk = gfx_table->dpm_levels[0].value;
1566     hwmgr->pstate_mclk = mem_table->dpm_levels[0].value;
1567 
1568     if (gfx_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
1569         mem_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL) {
1570         hwmgr->pstate_sclk = gfx_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
1571         hwmgr->pstate_mclk = mem_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
1572     }
1573 
1574     hwmgr->pstate_sclk = hwmgr->pstate_sclk * 100;
1575     hwmgr->pstate_mclk = hwmgr->pstate_mclk * 100;
1576 
1577     return 0;
1578 }
1579 
1580 static int vega20_get_max_sustainable_clock(struct pp_hwmgr *hwmgr,
1581         PP_Clock *clock, PPCLK_e clock_select)
1582 {
1583     int ret = 0;
1584 
1585     PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1586             PPSMC_MSG_GetDcModeMaxDpmFreq,
1587             (clock_select << 16),
1588             clock)) == 0,
1589             "[GetMaxSustainableClock] Failed to get max DC clock from SMC!",
1590             return ret);
1591 
1592     /* if DC limit is zero, return AC limit */
1593     if (*clock == 0) {
1594         PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1595             PPSMC_MSG_GetMaxDpmFreq,
1596             (clock_select << 16),
1597             clock)) == 0,
1598             "[GetMaxSustainableClock] failed to get max AC clock from SMC!",
1599             return ret);
1600     }
1601 
1602     return 0;
1603 }
1604 
1605 static int vega20_init_max_sustainable_clocks(struct pp_hwmgr *hwmgr)
1606 {
1607     struct vega20_hwmgr *data =
1608         (struct vega20_hwmgr *)(hwmgr->backend);
1609     struct vega20_max_sustainable_clocks *max_sustainable_clocks =
1610         &(data->max_sustainable_clocks);
1611     int ret = 0;
1612 
1613     max_sustainable_clocks->uclock = data->vbios_boot_state.mem_clock / 100;
1614     max_sustainable_clocks->soc_clock = data->vbios_boot_state.soc_clock / 100;
1615     max_sustainable_clocks->dcef_clock = data->vbios_boot_state.dcef_clock / 100;
1616     max_sustainable_clocks->display_clock = 0xFFFFFFFF;
1617     max_sustainable_clocks->phy_clock = 0xFFFFFFFF;
1618     max_sustainable_clocks->pixel_clock = 0xFFFFFFFF;
1619 
1620     if (data->smu_features[GNLD_DPM_UCLK].enabled)
1621         PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1622                 &(max_sustainable_clocks->uclock),
1623                 PPCLK_UCLK)) == 0,
1624                 "[InitMaxSustainableClocks] failed to get max UCLK from SMC!",
1625                 return ret);
1626 
1627     if (data->smu_features[GNLD_DPM_SOCCLK].enabled)
1628         PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1629                 &(max_sustainable_clocks->soc_clock),
1630                 PPCLK_SOCCLK)) == 0,
1631                 "[InitMaxSustainableClocks] failed to get max SOCCLK from SMC!",
1632                 return ret);
1633 
1634     if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
1635         PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1636                 &(max_sustainable_clocks->dcef_clock),
1637                 PPCLK_DCEFCLK)) == 0,
1638                 "[InitMaxSustainableClocks] failed to get max DCEFCLK from SMC!",
1639                 return ret);
1640         PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1641                 &(max_sustainable_clocks->display_clock),
1642                 PPCLK_DISPCLK)) == 0,
1643                 "[InitMaxSustainableClocks] failed to get max DISPCLK from SMC!",
1644                 return ret);
1645         PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1646                 &(max_sustainable_clocks->phy_clock),
1647                 PPCLK_PHYCLK)) == 0,
1648                 "[InitMaxSustainableClocks] failed to get max PHYCLK from SMC!",
1649                 return ret);
1650         PP_ASSERT_WITH_CODE((ret = vega20_get_max_sustainable_clock(hwmgr,
1651                 &(max_sustainable_clocks->pixel_clock),
1652                 PPCLK_PIXCLK)) == 0,
1653                 "[InitMaxSustainableClocks] failed to get max PIXCLK from SMC!",
1654                 return ret);
1655     }
1656 
1657     if (max_sustainable_clocks->soc_clock < max_sustainable_clocks->uclock)
1658         max_sustainable_clocks->uclock = max_sustainable_clocks->soc_clock;
1659 
1660     return 0;
1661 }
1662 
1663 static int vega20_enable_mgpu_fan_boost(struct pp_hwmgr *hwmgr)
1664 {
1665     int result;
1666 
1667     result = smum_send_msg_to_smc(hwmgr,
1668         PPSMC_MSG_SetMGpuFanBoostLimitRpm,
1669         NULL);
1670     PP_ASSERT_WITH_CODE(!result,
1671             "[EnableMgpuFan] Failed to enable mgpu fan boost!",
1672             return result);
1673 
1674     return 0;
1675 }
1676 
1677 static void vega20_init_powergate_state(struct pp_hwmgr *hwmgr)
1678 {
1679     struct vega20_hwmgr *data =
1680         (struct vega20_hwmgr *)(hwmgr->backend);
1681 
1682     data->uvd_power_gated = true;
1683     data->vce_power_gated = true;
1684 }
1685 
1686 static int vega20_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
1687 {
1688     int result = 0;
1689 
1690     smum_send_msg_to_smc_with_parameter(hwmgr,
1691             PPSMC_MSG_NumOfDisplays, 0, NULL);
1692 
1693     result = vega20_set_allowed_featuresmask(hwmgr);
1694     PP_ASSERT_WITH_CODE(!result,
1695             "[EnableDPMTasks] Failed to set allowed featuresmask!\n",
1696             return result);
1697 
1698     result = vega20_init_smc_table(hwmgr);
1699     PP_ASSERT_WITH_CODE(!result,
1700             "[EnableDPMTasks] Failed to initialize SMC table!",
1701             return result);
1702 
1703     result = vega20_run_btc(hwmgr);
1704     PP_ASSERT_WITH_CODE(!result,
1705             "[EnableDPMTasks] Failed to run btc!",
1706             return result);
1707 
1708     result = vega20_run_btc_afll(hwmgr);
1709     PP_ASSERT_WITH_CODE(!result,
1710             "[EnableDPMTasks] Failed to run btc afll!",
1711             return result);
1712 
1713     result = vega20_enable_all_smu_features(hwmgr);
1714     PP_ASSERT_WITH_CODE(!result,
1715             "[EnableDPMTasks] Failed to enable all smu features!",
1716             return result);
1717 
1718     result = vega20_override_pcie_parameters(hwmgr);
1719     PP_ASSERT_WITH_CODE(!result,
1720             "[EnableDPMTasks] Failed to override pcie parameters!",
1721             return result);
1722 
1723     result = vega20_notify_smc_display_change(hwmgr);
1724     PP_ASSERT_WITH_CODE(!result,
1725             "[EnableDPMTasks] Failed to notify smc display change!",
1726             return result);
1727 
1728     result = vega20_send_clock_ratio(hwmgr);
1729     PP_ASSERT_WITH_CODE(!result,
1730             "[EnableDPMTasks] Failed to send clock ratio!",
1731             return result);
1732 
1733     /* Initialize UVD/VCE powergating state */
1734     vega20_init_powergate_state(hwmgr);
1735 
1736     result = vega20_setup_default_dpm_tables(hwmgr);
1737     PP_ASSERT_WITH_CODE(!result,
1738             "[EnableDPMTasks] Failed to setup default DPM tables!",
1739             return result);
1740 
1741     result = vega20_init_max_sustainable_clocks(hwmgr);
1742     PP_ASSERT_WITH_CODE(!result,
1743             "[EnableDPMTasks] Failed to get maximum sustainable clocks!",
1744             return result);
1745 
1746     result = vega20_power_control_set_level(hwmgr);
1747     PP_ASSERT_WITH_CODE(!result,
1748             "[EnableDPMTasks] Failed to power control set level!",
1749             return result);
1750 
1751     result = vega20_od8_initialize_default_settings(hwmgr);
1752     PP_ASSERT_WITH_CODE(!result,
1753             "[EnableDPMTasks] Failed to initialize odn settings!",
1754             return result);
1755 
1756     result = vega20_populate_umdpstate_clocks(hwmgr);
1757     PP_ASSERT_WITH_CODE(!result,
1758             "[EnableDPMTasks] Failed to populate umdpstate clocks!",
1759             return result);
1760 
1761     result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetPptLimit,
1762             POWER_SOURCE_AC << 16, &hwmgr->default_power_limit);
1763     PP_ASSERT_WITH_CODE(!result,
1764             "[GetPptLimit] get default PPT limit failed!",
1765             return result);
1766     hwmgr->power_limit =
1767         hwmgr->default_power_limit;
1768 
1769     return 0;
1770 }
1771 
1772 static uint32_t vega20_find_lowest_dpm_level(
1773         struct vega20_single_dpm_table *table)
1774 {
1775     uint32_t i;
1776 
1777     for (i = 0; i < table->count; i++) {
1778         if (table->dpm_levels[i].enabled)
1779             break;
1780     }
1781     if (i >= table->count) {
1782         i = 0;
1783         table->dpm_levels[i].enabled = true;
1784     }
1785 
1786     return i;
1787 }
1788 
1789 static uint32_t vega20_find_highest_dpm_level(
1790         struct vega20_single_dpm_table *table)
1791 {
1792     int i = 0;
1793 
1794     PP_ASSERT_WITH_CODE(table != NULL,
1795             "[FindHighestDPMLevel] DPM Table does not exist!",
1796             return 0);
1797     PP_ASSERT_WITH_CODE(table->count > 0,
1798             "[FindHighestDPMLevel] DPM Table has no entry!",
1799             return 0);
1800     PP_ASSERT_WITH_CODE(table->count <= MAX_REGULAR_DPM_NUMBER,
1801             "[FindHighestDPMLevel] DPM Table has too many entries!",
1802             return MAX_REGULAR_DPM_NUMBER - 1);
1803 
1804     for (i = table->count - 1; i >= 0; i--) {
1805         if (table->dpm_levels[i].enabled)
1806             break;
1807     }
1808     if (i < 0) {
1809         i = 0;
1810         table->dpm_levels[i].enabled = true;
1811     }
1812 
1813     return i;
1814 }
1815 
1816 static int vega20_upload_dpm_min_level(struct pp_hwmgr *hwmgr, uint32_t feature_mask)
1817 {
1818     struct vega20_hwmgr *data =
1819             (struct vega20_hwmgr *)(hwmgr->backend);
1820     uint32_t min_freq;
1821     int ret = 0;
1822 
1823     if (data->smu_features[GNLD_DPM_GFXCLK].enabled &&
1824        (feature_mask & FEATURE_DPM_GFXCLK_MASK)) {
1825         min_freq = data->dpm_table.gfx_table.dpm_state.soft_min_level;
1826         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1827                     hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1828                     (PPCLK_GFXCLK << 16) | (min_freq & 0xffff),
1829                     NULL)),
1830                     "Failed to set soft min gfxclk !",
1831                     return ret);
1832     }
1833 
1834     if (data->smu_features[GNLD_DPM_UCLK].enabled &&
1835        (feature_mask & FEATURE_DPM_UCLK_MASK)) {
1836         min_freq = data->dpm_table.mem_table.dpm_state.soft_min_level;
1837         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1838                     hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1839                     (PPCLK_UCLK << 16) | (min_freq & 0xffff),
1840                     NULL)),
1841                     "Failed to set soft min memclk !",
1842                     return ret);
1843     }
1844 
1845     if (data->smu_features[GNLD_DPM_UVD].enabled &&
1846        (feature_mask & FEATURE_DPM_UVD_MASK)) {
1847         min_freq = data->dpm_table.vclk_table.dpm_state.soft_min_level;
1848 
1849         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1850                     hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1851                     (PPCLK_VCLK << 16) | (min_freq & 0xffff),
1852                     NULL)),
1853                     "Failed to set soft min vclk!",
1854                     return ret);
1855 
1856         min_freq = data->dpm_table.dclk_table.dpm_state.soft_min_level;
1857 
1858         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1859                     hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1860                     (PPCLK_DCLK << 16) | (min_freq & 0xffff),
1861                     NULL)),
1862                     "Failed to set soft min dclk!",
1863                     return ret);
1864     }
1865 
1866     if (data->smu_features[GNLD_DPM_VCE].enabled &&
1867        (feature_mask & FEATURE_DPM_VCE_MASK)) {
1868         min_freq = data->dpm_table.eclk_table.dpm_state.soft_min_level;
1869 
1870         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1871                     hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1872                     (PPCLK_ECLK << 16) | (min_freq & 0xffff),
1873                     NULL)),
1874                     "Failed to set soft min eclk!",
1875                     return ret);
1876     }
1877 
1878     if (data->smu_features[GNLD_DPM_SOCCLK].enabled &&
1879        (feature_mask & FEATURE_DPM_SOCCLK_MASK)) {
1880         min_freq = data->dpm_table.soc_table.dpm_state.soft_min_level;
1881 
1882         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1883                     hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1884                     (PPCLK_SOCCLK << 16) | (min_freq & 0xffff),
1885                     NULL)),
1886                     "Failed to set soft min socclk!",
1887                     return ret);
1888     }
1889 
1890     if (data->smu_features[GNLD_DPM_FCLK].enabled &&
1891        (feature_mask & FEATURE_DPM_FCLK_MASK)) {
1892         min_freq = data->dpm_table.fclk_table.dpm_state.soft_min_level;
1893 
1894         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1895                     hwmgr, PPSMC_MSG_SetSoftMinByFreq,
1896                     (PPCLK_FCLK << 16) | (min_freq & 0xffff),
1897                     NULL)),
1898                     "Failed to set soft min fclk!",
1899                     return ret);
1900     }
1901 
1902     if (data->smu_features[GNLD_DPM_DCEFCLK].enabled &&
1903        (feature_mask & FEATURE_DPM_DCEFCLK_MASK)) {
1904         min_freq = data->dpm_table.dcef_table.dpm_state.hard_min_level;
1905 
1906         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1907                     hwmgr, PPSMC_MSG_SetHardMinByFreq,
1908                     (PPCLK_DCEFCLK << 16) | (min_freq & 0xffff),
1909                     NULL)),
1910                     "Failed to set hard min dcefclk!",
1911                     return ret);
1912     }
1913 
1914     return ret;
1915 }
1916 
1917 static int vega20_upload_dpm_max_level(struct pp_hwmgr *hwmgr, uint32_t feature_mask)
1918 {
1919     struct vega20_hwmgr *data =
1920             (struct vega20_hwmgr *)(hwmgr->backend);
1921     uint32_t max_freq;
1922     int ret = 0;
1923 
1924     if (data->smu_features[GNLD_DPM_GFXCLK].enabled &&
1925        (feature_mask & FEATURE_DPM_GFXCLK_MASK)) {
1926         max_freq = data->dpm_table.gfx_table.dpm_state.soft_max_level;
1927 
1928         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1929                     hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1930                     (PPCLK_GFXCLK << 16) | (max_freq & 0xffff),
1931                     NULL)),
1932                     "Failed to set soft max gfxclk!",
1933                     return ret);
1934     }
1935 
1936     if (data->smu_features[GNLD_DPM_UCLK].enabled &&
1937        (feature_mask & FEATURE_DPM_UCLK_MASK)) {
1938         max_freq = data->dpm_table.mem_table.dpm_state.soft_max_level;
1939 
1940         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1941                     hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1942                     (PPCLK_UCLK << 16) | (max_freq & 0xffff),
1943                     NULL)),
1944                     "Failed to set soft max memclk!",
1945                     return ret);
1946     }
1947 
1948     if (data->smu_features[GNLD_DPM_UVD].enabled &&
1949        (feature_mask & FEATURE_DPM_UVD_MASK)) {
1950         max_freq = data->dpm_table.vclk_table.dpm_state.soft_max_level;
1951 
1952         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1953                     hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1954                     (PPCLK_VCLK << 16) | (max_freq & 0xffff),
1955                     NULL)),
1956                     "Failed to set soft max vclk!",
1957                     return ret);
1958 
1959         max_freq = data->dpm_table.dclk_table.dpm_state.soft_max_level;
1960         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1961                     hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1962                     (PPCLK_DCLK << 16) | (max_freq & 0xffff),
1963                     NULL)),
1964                     "Failed to set soft max dclk!",
1965                     return ret);
1966     }
1967 
1968     if (data->smu_features[GNLD_DPM_VCE].enabled &&
1969        (feature_mask & FEATURE_DPM_VCE_MASK)) {
1970         max_freq = data->dpm_table.eclk_table.dpm_state.soft_max_level;
1971 
1972         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1973                     hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1974                     (PPCLK_ECLK << 16) | (max_freq & 0xffff),
1975                     NULL)),
1976                     "Failed to set soft max eclk!",
1977                     return ret);
1978     }
1979 
1980     if (data->smu_features[GNLD_DPM_SOCCLK].enabled &&
1981        (feature_mask & FEATURE_DPM_SOCCLK_MASK)) {
1982         max_freq = data->dpm_table.soc_table.dpm_state.soft_max_level;
1983 
1984         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1985                     hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1986                     (PPCLK_SOCCLK << 16) | (max_freq & 0xffff),
1987                     NULL)),
1988                     "Failed to set soft max socclk!",
1989                     return ret);
1990     }
1991 
1992     if (data->smu_features[GNLD_DPM_FCLK].enabled &&
1993        (feature_mask & FEATURE_DPM_FCLK_MASK)) {
1994         max_freq = data->dpm_table.fclk_table.dpm_state.soft_max_level;
1995 
1996         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
1997                     hwmgr, PPSMC_MSG_SetSoftMaxByFreq,
1998                     (PPCLK_FCLK << 16) | (max_freq & 0xffff),
1999                     NULL)),
2000                     "Failed to set soft max fclk!",
2001                     return ret);
2002     }
2003 
2004     return ret;
2005 }
2006 
2007 static int vega20_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
2008 {
2009     struct vega20_hwmgr *data =
2010             (struct vega20_hwmgr *)(hwmgr->backend);
2011     int ret = 0;
2012 
2013     if (data->smu_features[GNLD_DPM_VCE].supported) {
2014         if (data->smu_features[GNLD_DPM_VCE].enabled == enable) {
2015             if (enable)
2016                 PP_DBG_LOG("[EnableDisableVCEDPM] feature VCE DPM already enabled!\n");
2017             else
2018                 PP_DBG_LOG("[EnableDisableVCEDPM] feature VCE DPM already disabled!\n");
2019         }
2020 
2021         ret = vega20_enable_smc_features(hwmgr,
2022                 enable,
2023                 data->smu_features[GNLD_DPM_VCE].smu_feature_bitmap);
2024         PP_ASSERT_WITH_CODE(!ret,
2025                 "Attempt to Enable/Disable DPM VCE Failed!",
2026                 return ret);
2027         data->smu_features[GNLD_DPM_VCE].enabled = enable;
2028     }
2029 
2030     return 0;
2031 }
2032 
2033 static int vega20_get_clock_ranges(struct pp_hwmgr *hwmgr,
2034         uint32_t *clock,
2035         PPCLK_e clock_select,
2036         bool max)
2037 {
2038     int ret;
2039     *clock = 0;
2040 
2041     if (max) {
2042         PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
2043                 PPSMC_MSG_GetMaxDpmFreq, (clock_select << 16),
2044                 clock)) == 0,
2045                 "[GetClockRanges] Failed to get max clock from SMC!",
2046                 return ret);
2047     } else {
2048         PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
2049                 PPSMC_MSG_GetMinDpmFreq,
2050                 (clock_select << 16),
2051                 clock)) == 0,
2052                 "[GetClockRanges] Failed to get min clock from SMC!",
2053                 return ret);
2054     }
2055 
2056     return 0;
2057 }
2058 
2059 static uint32_t vega20_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
2060 {
2061     struct vega20_hwmgr *data =
2062             (struct vega20_hwmgr *)(hwmgr->backend);
2063     uint32_t gfx_clk;
2064     int ret = 0;
2065 
2066     PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_GFXCLK].enabled,
2067             "[GetSclks]: gfxclk dpm not enabled!\n",
2068             return -EPERM);
2069 
2070     if (low) {
2071         ret = vega20_get_clock_ranges(hwmgr, &gfx_clk, PPCLK_GFXCLK, false);
2072         PP_ASSERT_WITH_CODE(!ret,
2073             "[GetSclks]: fail to get min PPCLK_GFXCLK\n",
2074             return ret);
2075     } else {
2076         ret = vega20_get_clock_ranges(hwmgr, &gfx_clk, PPCLK_GFXCLK, true);
2077         PP_ASSERT_WITH_CODE(!ret,
2078             "[GetSclks]: fail to get max PPCLK_GFXCLK\n",
2079             return ret);
2080     }
2081 
2082     return (gfx_clk * 100);
2083 }
2084 
2085 static uint32_t vega20_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
2086 {
2087     struct vega20_hwmgr *data =
2088             (struct vega20_hwmgr *)(hwmgr->backend);
2089     uint32_t mem_clk;
2090     int ret = 0;
2091 
2092     PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_UCLK].enabled,
2093             "[MemMclks]: memclk dpm not enabled!\n",
2094             return -EPERM);
2095 
2096     if (low) {
2097         ret = vega20_get_clock_ranges(hwmgr, &mem_clk, PPCLK_UCLK, false);
2098         PP_ASSERT_WITH_CODE(!ret,
2099             "[GetMclks]: fail to get min PPCLK_UCLK\n",
2100             return ret);
2101     } else {
2102         ret = vega20_get_clock_ranges(hwmgr, &mem_clk, PPCLK_UCLK, true);
2103         PP_ASSERT_WITH_CODE(!ret,
2104             "[GetMclks]: fail to get max PPCLK_UCLK\n",
2105             return ret);
2106     }
2107 
2108     return (mem_clk * 100);
2109 }
2110 
2111 static int vega20_get_metrics_table(struct pp_hwmgr *hwmgr,
2112                     SmuMetrics_t *metrics_table,
2113                     bool bypass_cache)
2114 {
2115     struct vega20_hwmgr *data =
2116             (struct vega20_hwmgr *)(hwmgr->backend);
2117     int ret = 0;
2118 
2119     if (bypass_cache ||
2120         !data->metrics_time ||
2121         time_after(jiffies, data->metrics_time + msecs_to_jiffies(1))) {
2122         ret = smum_smc_table_manager(hwmgr,
2123                          (uint8_t *)(&data->metrics_table),
2124                          TABLE_SMU_METRICS,
2125                          true);
2126         if (ret) {
2127             pr_info("Failed to export SMU metrics table!\n");
2128             return ret;
2129         }
2130         data->metrics_time = jiffies;
2131     }
2132 
2133     if (metrics_table)
2134         memcpy(metrics_table, &data->metrics_table, sizeof(SmuMetrics_t));
2135 
2136     return ret;
2137 }
2138 
2139 static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr,
2140         uint32_t *query)
2141 {
2142     int ret = 0;
2143     SmuMetrics_t metrics_table;
2144 
2145     ret = vega20_get_metrics_table(hwmgr, &metrics_table, false);
2146     if (ret)
2147         return ret;
2148 
2149     /* For the 40.46 release, they changed the value name */
2150     if (hwmgr->smu_version == 0x282e00)
2151         *query = metrics_table.AverageSocketPower << 8;
2152     else
2153         *query = metrics_table.CurrSocketPower << 8;
2154 
2155     return ret;
2156 }
2157 
2158 static int vega20_get_current_clk_freq(struct pp_hwmgr *hwmgr,
2159         PPCLK_e clk_id, uint32_t *clk_freq)
2160 {
2161     int ret = 0;
2162 
2163     *clk_freq = 0;
2164 
2165     PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
2166             PPSMC_MSG_GetDpmClockFreq, (clk_id << 16),
2167             clk_freq)) == 0,
2168             "[GetCurrentClkFreq] Attempt to get Current Frequency Failed!",
2169             return ret);
2170 
2171     *clk_freq = *clk_freq * 100;
2172 
2173     return 0;
2174 }
2175 
2176 static int vega20_get_current_activity_percent(struct pp_hwmgr *hwmgr,
2177         int idx,
2178         uint32_t *activity_percent)
2179 {
2180     int ret = 0;
2181     SmuMetrics_t metrics_table;
2182 
2183     ret = vega20_get_metrics_table(hwmgr, &metrics_table, false);
2184     if (ret)
2185         return ret;
2186 
2187     switch (idx) {
2188     case AMDGPU_PP_SENSOR_GPU_LOAD:
2189         *activity_percent = metrics_table.AverageGfxActivity;
2190         break;
2191     case AMDGPU_PP_SENSOR_MEM_LOAD:
2192         *activity_percent = metrics_table.AverageUclkActivity;
2193         break;
2194     default:
2195         pr_err("Invalid index for retrieving clock activity\n");
2196         return -EINVAL;
2197     }
2198 
2199     return ret;
2200 }
2201 
2202 static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx,
2203                   void *value, int *size)
2204 {
2205     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2206     struct amdgpu_device *adev = hwmgr->adev;
2207     SmuMetrics_t metrics_table;
2208     uint32_t val_vid;
2209     int ret = 0;
2210 
2211     switch (idx) {
2212     case AMDGPU_PP_SENSOR_GFX_SCLK:
2213         ret = vega20_get_metrics_table(hwmgr, &metrics_table, false);
2214         if (ret)
2215             return ret;
2216 
2217         *((uint32_t *)value) = metrics_table.AverageGfxclkFrequency * 100;
2218         *size = 4;
2219         break;
2220     case AMDGPU_PP_SENSOR_GFX_MCLK:
2221         ret = vega20_get_current_clk_freq(hwmgr,
2222                 PPCLK_UCLK,
2223                 (uint32_t *)value);
2224         if (!ret)
2225             *size = 4;
2226         break;
2227     case AMDGPU_PP_SENSOR_GPU_LOAD:
2228     case AMDGPU_PP_SENSOR_MEM_LOAD:
2229         ret = vega20_get_current_activity_percent(hwmgr, idx, (uint32_t *)value);
2230         if (!ret)
2231             *size = 4;
2232         break;
2233     case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
2234         *((uint32_t *)value) = vega20_thermal_get_temperature(hwmgr);
2235         *size = 4;
2236         break;
2237     case AMDGPU_PP_SENSOR_EDGE_TEMP:
2238         ret = vega20_get_metrics_table(hwmgr, &metrics_table, false);
2239         if (ret)
2240             return ret;
2241 
2242         *((uint32_t *)value) = metrics_table.TemperatureEdge *
2243             PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
2244         *size = 4;
2245         break;
2246     case AMDGPU_PP_SENSOR_MEM_TEMP:
2247         ret = vega20_get_metrics_table(hwmgr, &metrics_table, false);
2248         if (ret)
2249             return ret;
2250 
2251         *((uint32_t *)value) = metrics_table.TemperatureHBM *
2252             PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
2253         *size = 4;
2254         break;
2255     case AMDGPU_PP_SENSOR_UVD_POWER:
2256         *((uint32_t *)value) = data->uvd_power_gated ? 0 : 1;
2257         *size = 4;
2258         break;
2259     case AMDGPU_PP_SENSOR_VCE_POWER:
2260         *((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
2261         *size = 4;
2262         break;
2263     case AMDGPU_PP_SENSOR_GPU_POWER:
2264         *size = 16;
2265         ret = vega20_get_gpu_power(hwmgr, (uint32_t *)value);
2266         break;
2267     case AMDGPU_PP_SENSOR_VDDGFX:
2268         val_vid = (RREG32_SOC15(SMUIO, 0, mmSMUSVI0_TEL_PLANE0) &
2269             SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR_MASK) >>
2270             SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR__SHIFT;
2271         *((uint32_t *)value) =
2272             (uint32_t)convert_to_vddc((uint8_t)val_vid);
2273         break;
2274     case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK:
2275         ret = vega20_get_enabled_smc_features(hwmgr, (uint64_t *)value);
2276         if (!ret)
2277             *size = 8;
2278         break;
2279     default:
2280         ret = -EOPNOTSUPP;
2281         break;
2282     }
2283     return ret;
2284 }
2285 
2286 static int vega20_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
2287         struct pp_display_clock_request *clock_req)
2288 {
2289     int result = 0;
2290     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2291     enum amd_pp_clock_type clk_type = clock_req->clock_type;
2292     uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
2293     PPCLK_e clk_select = 0;
2294     uint32_t clk_request = 0;
2295 
2296     if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
2297         switch (clk_type) {
2298         case amd_pp_dcef_clock:
2299             clk_select = PPCLK_DCEFCLK;
2300             break;
2301         case amd_pp_disp_clock:
2302             clk_select = PPCLK_DISPCLK;
2303             break;
2304         case amd_pp_pixel_clock:
2305             clk_select = PPCLK_PIXCLK;
2306             break;
2307         case amd_pp_phy_clock:
2308             clk_select = PPCLK_PHYCLK;
2309             break;
2310         default:
2311             pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!");
2312             result = -EINVAL;
2313             break;
2314         }
2315 
2316         if (!result) {
2317             clk_request = (clk_select << 16) | clk_freq;
2318             result = smum_send_msg_to_smc_with_parameter(hwmgr,
2319                     PPSMC_MSG_SetHardMinByFreq,
2320                     clk_request,
2321                     NULL);
2322         }
2323     }
2324 
2325     return result;
2326 }
2327 
2328 static int vega20_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state,
2329                 PHM_PerformanceLevelDesignation designation, uint32_t index,
2330                 PHM_PerformanceLevel *level)
2331 {
2332     return 0;
2333 }
2334 
2335 static int vega20_notify_smc_display_config_after_ps_adjustment(
2336         struct pp_hwmgr *hwmgr)
2337 {
2338     struct vega20_hwmgr *data =
2339             (struct vega20_hwmgr *)(hwmgr->backend);
2340     struct vega20_single_dpm_table *dpm_table =
2341             &data->dpm_table.mem_table;
2342     struct PP_Clocks min_clocks = {0};
2343     struct pp_display_clock_request clock_req;
2344     int ret = 0;
2345 
2346     min_clocks.dcefClock = hwmgr->display_config->min_dcef_set_clk;
2347     min_clocks.dcefClockInSR = hwmgr->display_config->min_dcef_deep_sleep_set_clk;
2348     min_clocks.memoryClock = hwmgr->display_config->min_mem_set_clock;
2349 
2350     if (data->smu_features[GNLD_DPM_DCEFCLK].supported) {
2351         clock_req.clock_type = amd_pp_dcef_clock;
2352         clock_req.clock_freq_in_khz = min_clocks.dcefClock * 10;
2353         if (!vega20_display_clock_voltage_request(hwmgr, &clock_req)) {
2354             if (data->smu_features[GNLD_DS_DCEFCLK].supported)
2355                 PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(
2356                     hwmgr, PPSMC_MSG_SetMinDeepSleepDcefclk,
2357                     min_clocks.dcefClockInSR / 100,
2358                     NULL)) == 0,
2359                     "Attempt to set divider for DCEFCLK Failed!",
2360                     return ret);
2361         } else {
2362             pr_info("Attempt to set Hard Min for DCEFCLK Failed!");
2363         }
2364     }
2365 
2366     if (data->smu_features[GNLD_DPM_UCLK].enabled) {
2367         dpm_table->dpm_state.hard_min_level = min_clocks.memoryClock / 100;
2368         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(hwmgr,
2369                 PPSMC_MSG_SetHardMinByFreq,
2370                 (PPCLK_UCLK << 16 ) | dpm_table->dpm_state.hard_min_level,
2371                 NULL)),
2372                 "[SetHardMinFreq] Set hard min uclk failed!",
2373                 return ret);
2374     }
2375 
2376     return 0;
2377 }
2378 
2379 static int vega20_force_dpm_highest(struct pp_hwmgr *hwmgr)
2380 {
2381     struct vega20_hwmgr *data =
2382             (struct vega20_hwmgr *)(hwmgr->backend);
2383     uint32_t soft_level;
2384     int ret = 0;
2385 
2386     soft_level = vega20_find_highest_dpm_level(&(data->dpm_table.gfx_table));
2387 
2388     data->dpm_table.gfx_table.dpm_state.soft_min_level =
2389         data->dpm_table.gfx_table.dpm_state.soft_max_level =
2390         data->dpm_table.gfx_table.dpm_levels[soft_level].value;
2391 
2392     soft_level = vega20_find_highest_dpm_level(&(data->dpm_table.mem_table));
2393 
2394     data->dpm_table.mem_table.dpm_state.soft_min_level =
2395         data->dpm_table.mem_table.dpm_state.soft_max_level =
2396         data->dpm_table.mem_table.dpm_levels[soft_level].value;
2397 
2398     soft_level = vega20_find_highest_dpm_level(&(data->dpm_table.soc_table));
2399 
2400     data->dpm_table.soc_table.dpm_state.soft_min_level =
2401         data->dpm_table.soc_table.dpm_state.soft_max_level =
2402         data->dpm_table.soc_table.dpm_levels[soft_level].value;
2403 
2404     ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
2405                          FEATURE_DPM_UCLK_MASK |
2406                          FEATURE_DPM_SOCCLK_MASK);
2407     PP_ASSERT_WITH_CODE(!ret,
2408             "Failed to upload boot level to highest!",
2409             return ret);
2410 
2411     ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
2412                          FEATURE_DPM_UCLK_MASK |
2413                          FEATURE_DPM_SOCCLK_MASK);
2414     PP_ASSERT_WITH_CODE(!ret,
2415             "Failed to upload dpm max level to highest!",
2416             return ret);
2417 
2418     return 0;
2419 }
2420 
2421 static int vega20_force_dpm_lowest(struct pp_hwmgr *hwmgr)
2422 {
2423     struct vega20_hwmgr *data =
2424             (struct vega20_hwmgr *)(hwmgr->backend);
2425     uint32_t soft_level;
2426     int ret = 0;
2427 
2428     soft_level = vega20_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
2429 
2430     data->dpm_table.gfx_table.dpm_state.soft_min_level =
2431         data->dpm_table.gfx_table.dpm_state.soft_max_level =
2432         data->dpm_table.gfx_table.dpm_levels[soft_level].value;
2433 
2434     soft_level = vega20_find_lowest_dpm_level(&(data->dpm_table.mem_table));
2435 
2436     data->dpm_table.mem_table.dpm_state.soft_min_level =
2437         data->dpm_table.mem_table.dpm_state.soft_max_level =
2438         data->dpm_table.mem_table.dpm_levels[soft_level].value;
2439 
2440     soft_level = vega20_find_lowest_dpm_level(&(data->dpm_table.soc_table));
2441 
2442     data->dpm_table.soc_table.dpm_state.soft_min_level =
2443         data->dpm_table.soc_table.dpm_state.soft_max_level =
2444         data->dpm_table.soc_table.dpm_levels[soft_level].value;
2445 
2446     ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
2447                          FEATURE_DPM_UCLK_MASK |
2448                          FEATURE_DPM_SOCCLK_MASK);
2449     PP_ASSERT_WITH_CODE(!ret,
2450             "Failed to upload boot level to highest!",
2451             return ret);
2452 
2453     ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
2454                          FEATURE_DPM_UCLK_MASK |
2455                          FEATURE_DPM_SOCCLK_MASK);
2456     PP_ASSERT_WITH_CODE(!ret,
2457             "Failed to upload dpm max level to highest!",
2458             return ret);
2459 
2460     return 0;
2461 
2462 }
2463 
2464 static int vega20_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
2465 {
2466     struct vega20_hwmgr *data =
2467             (struct vega20_hwmgr *)(hwmgr->backend);
2468     uint32_t soft_min_level, soft_max_level;
2469     int ret = 0;
2470 
2471     /* gfxclk soft min/max settings */
2472     soft_min_level =
2473         vega20_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
2474     soft_max_level =
2475         vega20_find_highest_dpm_level(&(data->dpm_table.gfx_table));
2476 
2477     data->dpm_table.gfx_table.dpm_state.soft_min_level =
2478         data->dpm_table.gfx_table.dpm_levels[soft_min_level].value;
2479     data->dpm_table.gfx_table.dpm_state.soft_max_level =
2480         data->dpm_table.gfx_table.dpm_levels[soft_max_level].value;
2481 
2482     /* uclk soft min/max settings */
2483     soft_min_level =
2484         vega20_find_lowest_dpm_level(&(data->dpm_table.mem_table));
2485     soft_max_level =
2486         vega20_find_highest_dpm_level(&(data->dpm_table.mem_table));
2487 
2488     data->dpm_table.mem_table.dpm_state.soft_min_level =
2489         data->dpm_table.mem_table.dpm_levels[soft_min_level].value;
2490     data->dpm_table.mem_table.dpm_state.soft_max_level =
2491         data->dpm_table.mem_table.dpm_levels[soft_max_level].value;
2492 
2493     /* socclk soft min/max settings */
2494     soft_min_level =
2495         vega20_find_lowest_dpm_level(&(data->dpm_table.soc_table));
2496     soft_max_level =
2497         vega20_find_highest_dpm_level(&(data->dpm_table.soc_table));
2498 
2499     data->dpm_table.soc_table.dpm_state.soft_min_level =
2500         data->dpm_table.soc_table.dpm_levels[soft_min_level].value;
2501     data->dpm_table.soc_table.dpm_state.soft_max_level =
2502         data->dpm_table.soc_table.dpm_levels[soft_max_level].value;
2503 
2504     ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
2505                          FEATURE_DPM_UCLK_MASK |
2506                          FEATURE_DPM_SOCCLK_MASK);
2507     PP_ASSERT_WITH_CODE(!ret,
2508             "Failed to upload DPM Bootup Levels!",
2509             return ret);
2510 
2511     ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
2512                          FEATURE_DPM_UCLK_MASK |
2513                          FEATURE_DPM_SOCCLK_MASK);
2514     PP_ASSERT_WITH_CODE(!ret,
2515             "Failed to upload DPM Max Levels!",
2516             return ret);
2517 
2518     return 0;
2519 }
2520 
2521 static int vega20_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level,
2522                 uint32_t *sclk_mask, uint32_t *mclk_mask, uint32_t *soc_mask)
2523 {
2524     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2525     struct vega20_single_dpm_table *gfx_dpm_table = &(data->dpm_table.gfx_table);
2526     struct vega20_single_dpm_table *mem_dpm_table = &(data->dpm_table.mem_table);
2527     struct vega20_single_dpm_table *soc_dpm_table = &(data->dpm_table.soc_table);
2528 
2529     *sclk_mask = 0;
2530     *mclk_mask = 0;
2531     *soc_mask  = 0;
2532 
2533     if (gfx_dpm_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
2534         mem_dpm_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL &&
2535         soc_dpm_table->count > VEGA20_UMD_PSTATE_SOCCLK_LEVEL) {
2536         *sclk_mask = VEGA20_UMD_PSTATE_GFXCLK_LEVEL;
2537         *mclk_mask = VEGA20_UMD_PSTATE_MCLK_LEVEL;
2538         *soc_mask  = VEGA20_UMD_PSTATE_SOCCLK_LEVEL;
2539     }
2540 
2541     if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
2542         *sclk_mask = 0;
2543     } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
2544         *mclk_mask = 0;
2545     } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2546         *sclk_mask = gfx_dpm_table->count - 1;
2547         *mclk_mask = mem_dpm_table->count - 1;
2548         *soc_mask  = soc_dpm_table->count - 1;
2549     }
2550 
2551     return 0;
2552 }
2553 
2554 static int vega20_force_clock_level(struct pp_hwmgr *hwmgr,
2555         enum pp_clock_type type, uint32_t mask)
2556 {
2557     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2558     uint32_t soft_min_level, soft_max_level, hard_min_level;
2559     int ret = 0;
2560 
2561     switch (type) {
2562     case PP_SCLK:
2563         soft_min_level = mask ? (ffs(mask) - 1) : 0;
2564         soft_max_level = mask ? (fls(mask) - 1) : 0;
2565 
2566         if (soft_max_level >= data->dpm_table.gfx_table.count) {
2567             pr_err("Clock level specified %d is over max allowed %d\n",
2568                     soft_max_level,
2569                     data->dpm_table.gfx_table.count - 1);
2570             return -EINVAL;
2571         }
2572 
2573         data->dpm_table.gfx_table.dpm_state.soft_min_level =
2574             data->dpm_table.gfx_table.dpm_levels[soft_min_level].value;
2575         data->dpm_table.gfx_table.dpm_state.soft_max_level =
2576             data->dpm_table.gfx_table.dpm_levels[soft_max_level].value;
2577 
2578         ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK);
2579         PP_ASSERT_WITH_CODE(!ret,
2580             "Failed to upload boot level to lowest!",
2581             return ret);
2582 
2583         ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK);
2584         PP_ASSERT_WITH_CODE(!ret,
2585             "Failed to upload dpm max level to highest!",
2586             return ret);
2587         break;
2588 
2589     case PP_MCLK:
2590         soft_min_level = mask ? (ffs(mask) - 1) : 0;
2591         soft_max_level = mask ? (fls(mask) - 1) : 0;
2592 
2593         if (soft_max_level >= data->dpm_table.mem_table.count) {
2594             pr_err("Clock level specified %d is over max allowed %d\n",
2595                     soft_max_level,
2596                     data->dpm_table.mem_table.count - 1);
2597             return -EINVAL;
2598         }
2599 
2600         data->dpm_table.mem_table.dpm_state.soft_min_level =
2601             data->dpm_table.mem_table.dpm_levels[soft_min_level].value;
2602         data->dpm_table.mem_table.dpm_state.soft_max_level =
2603             data->dpm_table.mem_table.dpm_levels[soft_max_level].value;
2604 
2605         ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_UCLK_MASK);
2606         PP_ASSERT_WITH_CODE(!ret,
2607             "Failed to upload boot level to lowest!",
2608             return ret);
2609 
2610         ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_UCLK_MASK);
2611         PP_ASSERT_WITH_CODE(!ret,
2612             "Failed to upload dpm max level to highest!",
2613             return ret);
2614 
2615         break;
2616 
2617     case PP_SOCCLK:
2618         soft_min_level = mask ? (ffs(mask) - 1) : 0;
2619         soft_max_level = mask ? (fls(mask) - 1) : 0;
2620 
2621         if (soft_max_level >= data->dpm_table.soc_table.count) {
2622             pr_err("Clock level specified %d is over max allowed %d\n",
2623                     soft_max_level,
2624                     data->dpm_table.soc_table.count - 1);
2625             return -EINVAL;
2626         }
2627 
2628         data->dpm_table.soc_table.dpm_state.soft_min_level =
2629             data->dpm_table.soc_table.dpm_levels[soft_min_level].value;
2630         data->dpm_table.soc_table.dpm_state.soft_max_level =
2631             data->dpm_table.soc_table.dpm_levels[soft_max_level].value;
2632 
2633         ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_SOCCLK_MASK);
2634         PP_ASSERT_WITH_CODE(!ret,
2635             "Failed to upload boot level to lowest!",
2636             return ret);
2637 
2638         ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_SOCCLK_MASK);
2639         PP_ASSERT_WITH_CODE(!ret,
2640             "Failed to upload dpm max level to highest!",
2641             return ret);
2642 
2643         break;
2644 
2645     case PP_FCLK:
2646         soft_min_level = mask ? (ffs(mask) - 1) : 0;
2647         soft_max_level = mask ? (fls(mask) - 1) : 0;
2648 
2649         if (soft_max_level >= data->dpm_table.fclk_table.count) {
2650             pr_err("Clock level specified %d is over max allowed %d\n",
2651                     soft_max_level,
2652                     data->dpm_table.fclk_table.count - 1);
2653             return -EINVAL;
2654         }
2655 
2656         data->dpm_table.fclk_table.dpm_state.soft_min_level =
2657             data->dpm_table.fclk_table.dpm_levels[soft_min_level].value;
2658         data->dpm_table.fclk_table.dpm_state.soft_max_level =
2659             data->dpm_table.fclk_table.dpm_levels[soft_max_level].value;
2660 
2661         ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_FCLK_MASK);
2662         PP_ASSERT_WITH_CODE(!ret,
2663             "Failed to upload boot level to lowest!",
2664             return ret);
2665 
2666         ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_FCLK_MASK);
2667         PP_ASSERT_WITH_CODE(!ret,
2668             "Failed to upload dpm max level to highest!",
2669             return ret);
2670 
2671         break;
2672 
2673     case PP_DCEFCLK:
2674         hard_min_level = mask ? (ffs(mask) - 1) : 0;
2675 
2676         if (hard_min_level >= data->dpm_table.dcef_table.count) {
2677             pr_err("Clock level specified %d is over max allowed %d\n",
2678                     hard_min_level,
2679                     data->dpm_table.dcef_table.count - 1);
2680             return -EINVAL;
2681         }
2682 
2683         data->dpm_table.dcef_table.dpm_state.hard_min_level =
2684             data->dpm_table.dcef_table.dpm_levels[hard_min_level].value;
2685 
2686         ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_DCEFCLK_MASK);
2687         PP_ASSERT_WITH_CODE(!ret,
2688             "Failed to upload boot level to lowest!",
2689             return ret);
2690 
2691         //TODO: Setting DCEFCLK max dpm level is not supported
2692 
2693         break;
2694 
2695     case PP_PCIE:
2696         soft_min_level = mask ? (ffs(mask) - 1) : 0;
2697         soft_max_level = mask ? (fls(mask) - 1) : 0;
2698         if (soft_min_level >= NUM_LINK_LEVELS ||
2699             soft_max_level >= NUM_LINK_LEVELS)
2700             return -EINVAL;
2701 
2702         ret = smum_send_msg_to_smc_with_parameter(hwmgr,
2703             PPSMC_MSG_SetMinLinkDpmByIndex, soft_min_level,
2704             NULL);
2705         PP_ASSERT_WITH_CODE(!ret,
2706             "Failed to set min link dpm level!",
2707             return ret);
2708 
2709         break;
2710 
2711     default:
2712         break;
2713     }
2714 
2715     return 0;
2716 }
2717 
2718 static int vega20_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
2719                 enum amd_dpm_forced_level level)
2720 {
2721     int ret = 0;
2722     uint32_t sclk_mask, mclk_mask, soc_mask;
2723 
2724     switch (level) {
2725     case AMD_DPM_FORCED_LEVEL_HIGH:
2726         ret = vega20_force_dpm_highest(hwmgr);
2727         break;
2728 
2729     case AMD_DPM_FORCED_LEVEL_LOW:
2730         ret = vega20_force_dpm_lowest(hwmgr);
2731         break;
2732 
2733     case AMD_DPM_FORCED_LEVEL_AUTO:
2734         ret = vega20_unforce_dpm_levels(hwmgr);
2735         break;
2736 
2737     case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
2738     case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
2739     case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
2740     case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
2741         ret = vega20_get_profiling_clk_mask(hwmgr, level, &sclk_mask, &mclk_mask, &soc_mask);
2742         if (ret)
2743             return ret;
2744         vega20_force_clock_level(hwmgr, PP_SCLK, 1 << sclk_mask);
2745         vega20_force_clock_level(hwmgr, PP_MCLK, 1 << mclk_mask);
2746         vega20_force_clock_level(hwmgr, PP_SOCCLK, 1 << soc_mask);
2747         break;
2748 
2749     case AMD_DPM_FORCED_LEVEL_MANUAL:
2750     case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
2751     default:
2752         break;
2753     }
2754 
2755     return ret;
2756 }
2757 
2758 static uint32_t vega20_get_fan_control_mode(struct pp_hwmgr *hwmgr)
2759 {
2760     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2761 
2762     if (data->smu_features[GNLD_FAN_CONTROL].enabled == false)
2763         return AMD_FAN_CTRL_MANUAL;
2764     else
2765         return AMD_FAN_CTRL_AUTO;
2766 }
2767 
2768 static void vega20_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
2769 {
2770     switch (mode) {
2771     case AMD_FAN_CTRL_NONE:
2772         vega20_fan_ctrl_set_fan_speed_pwm(hwmgr, 255);
2773         break;
2774     case AMD_FAN_CTRL_MANUAL:
2775         if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
2776             vega20_fan_ctrl_stop_smc_fan_control(hwmgr);
2777         break;
2778     case AMD_FAN_CTRL_AUTO:
2779         if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
2780             vega20_fan_ctrl_start_smc_fan_control(hwmgr);
2781         break;
2782     default:
2783         break;
2784     }
2785 }
2786 
2787 static int vega20_get_dal_power_level(struct pp_hwmgr *hwmgr,
2788         struct amd_pp_simple_clock_info *info)
2789 {
2790 #if 0
2791     struct phm_ppt_v2_information *table_info =
2792             (struct phm_ppt_v2_information *)hwmgr->pptable;
2793     struct phm_clock_and_voltage_limits *max_limits =
2794             &table_info->max_clock_voltage_on_ac;
2795 
2796     info->engine_max_clock = max_limits->sclk;
2797     info->memory_max_clock = max_limits->mclk;
2798 #endif
2799     return 0;
2800 }
2801 
2802 
2803 static int vega20_get_sclks(struct pp_hwmgr *hwmgr,
2804         struct pp_clock_levels_with_latency *clocks)
2805 {
2806     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2807     struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.gfx_table);
2808     int i, count;
2809 
2810     if (!data->smu_features[GNLD_DPM_GFXCLK].enabled)
2811         return -1;
2812 
2813     count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2814     clocks->num_levels = count;
2815 
2816     for (i = 0; i < count; i++) {
2817         clocks->data[i].clocks_in_khz =
2818             dpm_table->dpm_levels[i].value * 1000;
2819         clocks->data[i].latency_in_us = 0;
2820     }
2821 
2822     return 0;
2823 }
2824 
2825 static uint32_t vega20_get_mem_latency(struct pp_hwmgr *hwmgr,
2826         uint32_t clock)
2827 {
2828     return 25;
2829 }
2830 
2831 static int vega20_get_memclocks(struct pp_hwmgr *hwmgr,
2832         struct pp_clock_levels_with_latency *clocks)
2833 {
2834     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2835     struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.mem_table);
2836     int i, count;
2837 
2838     if (!data->smu_features[GNLD_DPM_UCLK].enabled)
2839         return -1;
2840 
2841     count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2842     clocks->num_levels = data->mclk_latency_table.count = count;
2843 
2844     for (i = 0; i < count; i++) {
2845         clocks->data[i].clocks_in_khz =
2846             data->mclk_latency_table.entries[i].frequency =
2847             dpm_table->dpm_levels[i].value * 1000;
2848         clocks->data[i].latency_in_us =
2849             data->mclk_latency_table.entries[i].latency =
2850             vega20_get_mem_latency(hwmgr, dpm_table->dpm_levels[i].value);
2851     }
2852 
2853     return 0;
2854 }
2855 
2856 static int vega20_get_dcefclocks(struct pp_hwmgr *hwmgr,
2857         struct pp_clock_levels_with_latency *clocks)
2858 {
2859     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2860     struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.dcef_table);
2861     int i, count;
2862 
2863     if (!data->smu_features[GNLD_DPM_DCEFCLK].enabled)
2864         return -1;
2865 
2866     count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2867     clocks->num_levels = count;
2868 
2869     for (i = 0; i < count; i++) {
2870         clocks->data[i].clocks_in_khz =
2871             dpm_table->dpm_levels[i].value * 1000;
2872         clocks->data[i].latency_in_us = 0;
2873     }
2874 
2875     return 0;
2876 }
2877 
2878 static int vega20_get_socclocks(struct pp_hwmgr *hwmgr,
2879         struct pp_clock_levels_with_latency *clocks)
2880 {
2881     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2882     struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.soc_table);
2883     int i, count;
2884 
2885     if (!data->smu_features[GNLD_DPM_SOCCLK].enabled)
2886         return -1;
2887 
2888     count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2889     clocks->num_levels = count;
2890 
2891     for (i = 0; i < count; i++) {
2892         clocks->data[i].clocks_in_khz =
2893             dpm_table->dpm_levels[i].value * 1000;
2894         clocks->data[i].latency_in_us = 0;
2895     }
2896 
2897     return 0;
2898 
2899 }
2900 
2901 static int vega20_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr,
2902         enum amd_pp_clock_type type,
2903         struct pp_clock_levels_with_latency *clocks)
2904 {
2905     int ret;
2906 
2907     switch (type) {
2908     case amd_pp_sys_clock:
2909         ret = vega20_get_sclks(hwmgr, clocks);
2910         break;
2911     case amd_pp_mem_clock:
2912         ret = vega20_get_memclocks(hwmgr, clocks);
2913         break;
2914     case amd_pp_dcef_clock:
2915         ret = vega20_get_dcefclocks(hwmgr, clocks);
2916         break;
2917     case amd_pp_soc_clock:
2918         ret = vega20_get_socclocks(hwmgr, clocks);
2919         break;
2920     default:
2921         return -EINVAL;
2922     }
2923 
2924     return ret;
2925 }
2926 
2927 static int vega20_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr,
2928         enum amd_pp_clock_type type,
2929         struct pp_clock_levels_with_voltage *clocks)
2930 {
2931     clocks->num_levels = 0;
2932 
2933     return 0;
2934 }
2935 
2936 static int vega20_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr,
2937                            void *clock_ranges)
2938 {
2939     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2940     Watermarks_t *table = &(data->smc_state_table.water_marks_table);
2941     struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges;
2942 
2943     if (!data->registry_data.disable_water_mark &&
2944         data->smu_features[GNLD_DPM_DCEFCLK].supported &&
2945         data->smu_features[GNLD_DPM_SOCCLK].supported) {
2946         smu_set_watermarks_for_clocks_ranges(table, wm_with_clock_ranges);
2947         data->water_marks_bitmap |= WaterMarksExist;
2948         data->water_marks_bitmap &= ~WaterMarksLoaded;
2949     }
2950 
2951     return 0;
2952 }
2953 
2954 static int vega20_odn_edit_dpm_table(struct pp_hwmgr *hwmgr,
2955                     enum PP_OD_DPM_TABLE_COMMAND type,
2956                     long *input, uint32_t size)
2957 {
2958     struct vega20_hwmgr *data =
2959             (struct vega20_hwmgr *)(hwmgr->backend);
2960     struct vega20_od8_single_setting *od8_settings =
2961             data->od8_settings.od8_settings_array;
2962     OverDriveTable_t *od_table =
2963             &(data->smc_state_table.overdrive_table);
2964     int32_t input_index, input_clk, input_vol, i;
2965     int od8_id;
2966     int ret;
2967 
2968     PP_ASSERT_WITH_CODE(input, "NULL user input for clock and voltage",
2969                 return -EINVAL);
2970 
2971     switch (type) {
2972     case PP_OD_EDIT_SCLK_VDDC_TABLE:
2973         if (!(od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
2974               od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id)) {
2975             pr_info("Sclk min/max frequency overdrive not supported\n");
2976             return -EOPNOTSUPP;
2977         }
2978 
2979         for (i = 0; i < size; i += 2) {
2980             if (i + 2 > size) {
2981                 pr_info("invalid number of input parameters %d\n",
2982                     size);
2983                 return -EINVAL;
2984             }
2985 
2986             input_index = input[i];
2987             input_clk = input[i + 1];
2988 
2989             if (input_index != 0 && input_index != 1) {
2990                 pr_info("Invalid index %d\n", input_index);
2991                 pr_info("Support min/max sclk frequency setting only which index by 0/1\n");
2992                 return -EINVAL;
2993             }
2994 
2995             if (input_clk < od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value ||
2996                 input_clk > od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value) {
2997                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2998                     input_clk,
2999                     od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value,
3000                     od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value);
3001                 return -EINVAL;
3002             }
3003 
3004             if ((input_index == 0 && od_table->GfxclkFmin != input_clk) ||
3005                 (input_index == 1 && od_table->GfxclkFmax != input_clk))
3006                 data->gfxclk_overdrive = true;
3007 
3008             if (input_index == 0)
3009                 od_table->GfxclkFmin = input_clk;
3010             else
3011                 od_table->GfxclkFmax = input_clk;
3012         }
3013 
3014         break;
3015 
3016     case PP_OD_EDIT_MCLK_VDDC_TABLE:
3017         if (!od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
3018             pr_info("Mclk max frequency overdrive not supported\n");
3019             return -EOPNOTSUPP;
3020         }
3021 
3022         for (i = 0; i < size; i += 2) {
3023             if (i + 2 > size) {
3024                 pr_info("invalid number of input parameters %d\n",
3025                     size);
3026                 return -EINVAL;
3027             }
3028 
3029             input_index = input[i];
3030             input_clk = input[i + 1];
3031 
3032             if (input_index != 1) {
3033                 pr_info("Invalid index %d\n", input_index);
3034                 pr_info("Support max Mclk frequency setting only which index by 1\n");
3035                 return -EINVAL;
3036             }
3037 
3038             if (input_clk < od8_settings[OD8_SETTING_UCLK_FMAX].min_value ||
3039                 input_clk > od8_settings[OD8_SETTING_UCLK_FMAX].max_value) {
3040                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
3041                     input_clk,
3042                     od8_settings[OD8_SETTING_UCLK_FMAX].min_value,
3043                     od8_settings[OD8_SETTING_UCLK_FMAX].max_value);
3044                 return -EINVAL;
3045             }
3046 
3047             if (input_index == 1 && od_table->UclkFmax != input_clk)
3048                 data->memclk_overdrive = true;
3049 
3050             od_table->UclkFmax = input_clk;
3051         }
3052 
3053         break;
3054 
3055     case PP_OD_EDIT_VDDC_CURVE:
3056         if (!(od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
3057             od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
3058             od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
3059             od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
3060             od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
3061             od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id)) {
3062             pr_info("Voltage curve calibrate not supported\n");
3063             return -EOPNOTSUPP;
3064         }
3065 
3066         for (i = 0; i < size; i += 3) {
3067             if (i + 3 > size) {
3068                 pr_info("invalid number of input parameters %d\n",
3069                     size);
3070                 return -EINVAL;
3071             }
3072 
3073             input_index = input[i];
3074             input_clk = input[i + 1];
3075             input_vol = input[i + 2];
3076 
3077             if (input_index > 2) {
3078                 pr_info("Setting for point %d is not supported\n",
3079                         input_index + 1);
3080                 pr_info("Three supported points index by 0, 1, 2\n");
3081                 return -EINVAL;
3082             }
3083 
3084             od8_id = OD8_SETTING_GFXCLK_FREQ1 + 2 * input_index;
3085             if (input_clk < od8_settings[od8_id].min_value ||
3086                 input_clk > od8_settings[od8_id].max_value) {
3087                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
3088                     input_clk,
3089                     od8_settings[od8_id].min_value,
3090                     od8_settings[od8_id].max_value);
3091                 return -EINVAL;
3092             }
3093 
3094             od8_id = OD8_SETTING_GFXCLK_VOLTAGE1 + 2 * input_index;
3095             if (input_vol < od8_settings[od8_id].min_value ||
3096                 input_vol > od8_settings[od8_id].max_value) {
3097                 pr_info("clock voltage %d is not within allowed range [%d - %d]\n",
3098                     input_vol,
3099                     od8_settings[od8_id].min_value,
3100                     od8_settings[od8_id].max_value);
3101                 return -EINVAL;
3102             }
3103 
3104             switch (input_index) {
3105             case 0:
3106                 od_table->GfxclkFreq1 = input_clk;
3107                 od_table->GfxclkVolt1 = input_vol * VOLTAGE_SCALE;
3108                 break;
3109             case 1:
3110                 od_table->GfxclkFreq2 = input_clk;
3111                 od_table->GfxclkVolt2 = input_vol * VOLTAGE_SCALE;
3112                 break;
3113             case 2:
3114                 od_table->GfxclkFreq3 = input_clk;
3115                 od_table->GfxclkVolt3 = input_vol * VOLTAGE_SCALE;
3116                 break;
3117             }
3118         }
3119         break;
3120 
3121     case PP_OD_RESTORE_DEFAULT_TABLE:
3122         data->gfxclk_overdrive = false;
3123         data->memclk_overdrive = false;
3124 
3125         ret = smum_smc_table_manager(hwmgr,
3126                          (uint8_t *)od_table,
3127                          TABLE_OVERDRIVE, true);
3128         PP_ASSERT_WITH_CODE(!ret,
3129                 "Failed to export overdrive table!",
3130                 return ret);
3131         break;
3132 
3133     case PP_OD_COMMIT_DPM_TABLE:
3134         ret = smum_smc_table_manager(hwmgr,
3135                          (uint8_t *)od_table,
3136                          TABLE_OVERDRIVE, false);
3137         PP_ASSERT_WITH_CODE(!ret,
3138                 "Failed to import overdrive table!",
3139                 return ret);
3140 
3141         /* retrieve updated gfxclk table */
3142         if (data->gfxclk_overdrive) {
3143             data->gfxclk_overdrive = false;
3144 
3145             ret = vega20_setup_gfxclk_dpm_table(hwmgr);
3146             if (ret)
3147                 return ret;
3148         }
3149 
3150         /* retrieve updated memclk table */
3151         if (data->memclk_overdrive) {
3152             data->memclk_overdrive = false;
3153 
3154             ret = vega20_setup_memclk_dpm_table(hwmgr);
3155             if (ret)
3156                 return ret;
3157         }
3158         break;
3159 
3160     default:
3161         return -EINVAL;
3162     }
3163 
3164     return 0;
3165 }
3166 
3167 static int vega20_set_mp1_state(struct pp_hwmgr *hwmgr,
3168                 enum pp_mp1_state mp1_state)
3169 {
3170     uint16_t msg;
3171     int ret;
3172 
3173     switch (mp1_state) {
3174     case PP_MP1_STATE_SHUTDOWN:
3175         msg = PPSMC_MSG_PrepareMp1ForShutdown;
3176         break;
3177     case PP_MP1_STATE_UNLOAD:
3178         msg = PPSMC_MSG_PrepareMp1ForUnload;
3179         break;
3180     case PP_MP1_STATE_RESET:
3181         msg = PPSMC_MSG_PrepareMp1ForReset;
3182         break;
3183     case PP_MP1_STATE_NONE:
3184     default:
3185         return 0;
3186     }
3187 
3188     PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr, msg, NULL)) == 0,
3189                 "[PrepareMp1] Failed!",
3190                 return ret);
3191 
3192     return 0;
3193 }
3194 
3195 static int vega20_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf)
3196 {
3197     static const char *ppfeature_name[] = {
3198                 "DPM_PREFETCHER",
3199                 "GFXCLK_DPM",
3200                 "UCLK_DPM",
3201                 "SOCCLK_DPM",
3202                 "UVD_DPM",
3203                 "VCE_DPM",
3204                 "ULV",
3205                 "MP0CLK_DPM",
3206                 "LINK_DPM",
3207                 "DCEFCLK_DPM",
3208                 "GFXCLK_DS",
3209                 "SOCCLK_DS",
3210                 "LCLK_DS",
3211                 "PPT",
3212                 "TDC",
3213                 "THERMAL",
3214                 "GFX_PER_CU_CG",
3215                 "RM",
3216                 "DCEFCLK_DS",
3217                 "ACDC",
3218                 "VR0HOT",
3219                 "VR1HOT",
3220                 "FW_CTF",
3221                 "LED_DISPLAY",
3222                 "FAN_CONTROL",
3223                 "GFX_EDC",
3224                 "GFXOFF",
3225                 "CG",
3226                 "FCLK_DPM",
3227                 "FCLK_DS",
3228                 "MP1CLK_DS",
3229                 "MP0CLK_DS",
3230                 "XGMI",
3231                 "ECC"};
3232     static const char *output_title[] = {
3233                 "FEATURES",
3234                 "BITMASK",
3235                 "ENABLEMENT"};
3236     uint64_t features_enabled;
3237     int i;
3238     int ret = 0;
3239     int size = 0;
3240 
3241     phm_get_sysfs_buf(&buf, &size);
3242 
3243     ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
3244     PP_ASSERT_WITH_CODE(!ret,
3245             "[EnableAllSmuFeatures] Failed to get enabled smc features!",
3246             return ret);
3247 
3248     size += sysfs_emit_at(buf, size, "Current ppfeatures: 0x%016llx\n", features_enabled);
3249     size += sysfs_emit_at(buf, size, "%-19s %-22s %s\n",
3250                 output_title[0],
3251                 output_title[1],
3252                 output_title[2]);
3253     for (i = 0; i < GNLD_FEATURES_MAX; i++) {
3254         size += sysfs_emit_at(buf, size, "%-19s 0x%016llx %6s\n",
3255                     ppfeature_name[i],
3256                     1ULL << i,
3257                     (features_enabled & (1ULL << i)) ? "Y" : "N");
3258     }
3259 
3260     return size;
3261 }
3262 
3263 static int vega20_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t new_ppfeature_masks)
3264 {
3265     struct vega20_hwmgr *data =
3266             (struct vega20_hwmgr *)(hwmgr->backend);
3267     uint64_t features_enabled, features_to_enable, features_to_disable;
3268     int i, ret = 0;
3269     bool enabled;
3270 
3271     if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX))
3272         return -EINVAL;
3273 
3274     ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
3275     if (ret)
3276         return ret;
3277 
3278     features_to_disable =
3279         features_enabled & ~new_ppfeature_masks;
3280     features_to_enable =
3281         ~features_enabled & new_ppfeature_masks;
3282 
3283     pr_debug("features_to_disable 0x%llx\n", features_to_disable);
3284     pr_debug("features_to_enable 0x%llx\n", features_to_enable);
3285 
3286     if (features_to_disable) {
3287         ret = vega20_enable_smc_features(hwmgr, false, features_to_disable);
3288         if (ret)
3289             return ret;
3290     }
3291 
3292     if (features_to_enable) {
3293         ret = vega20_enable_smc_features(hwmgr, true, features_to_enable);
3294         if (ret)
3295             return ret;
3296     }
3297 
3298     /* Update the cached feature enablement state */
3299     ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
3300     if (ret)
3301         return ret;
3302 
3303     for (i = 0; i < GNLD_FEATURES_MAX; i++) {
3304         enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ?
3305             true : false;
3306         data->smu_features[i].enabled = enabled;
3307     }
3308 
3309     return 0;
3310 }
3311 
3312 static int vega20_get_current_pcie_link_width_level(struct pp_hwmgr *hwmgr)
3313 {
3314     struct amdgpu_device *adev = hwmgr->adev;
3315 
3316     return (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) &
3317         PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK)
3318         >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT;
3319 }
3320 
3321 static int vega20_get_current_pcie_link_width(struct pp_hwmgr *hwmgr)
3322 {
3323     uint32_t width_level;
3324 
3325     width_level = vega20_get_current_pcie_link_width_level(hwmgr);
3326     if (width_level > LINK_WIDTH_MAX)
3327         width_level = 0;
3328 
3329     return link_width[width_level];
3330 }
3331 
3332 static int vega20_get_current_pcie_link_speed_level(struct pp_hwmgr *hwmgr)
3333 {
3334     struct amdgpu_device *adev = hwmgr->adev;
3335 
3336     return (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) &
3337         PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK)
3338         >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
3339 }
3340 
3341 static int vega20_get_current_pcie_link_speed(struct pp_hwmgr *hwmgr)
3342 {
3343     uint32_t speed_level;
3344 
3345     speed_level = vega20_get_current_pcie_link_speed_level(hwmgr);
3346     if (speed_level > LINK_SPEED_MAX)
3347         speed_level = 0;
3348 
3349     return link_speed[speed_level];
3350 }
3351 
3352 static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
3353         enum pp_clock_type type, char *buf)
3354 {
3355     struct vega20_hwmgr *data =
3356             (struct vega20_hwmgr *)(hwmgr->backend);
3357     struct vega20_od8_single_setting *od8_settings =
3358             data->od8_settings.od8_settings_array;
3359     OverDriveTable_t *od_table =
3360             &(data->smc_state_table.overdrive_table);
3361     PPTable_t *pptable = &(data->smc_state_table.pp_table);
3362     struct pp_clock_levels_with_latency clocks;
3363     struct vega20_single_dpm_table *fclk_dpm_table =
3364             &(data->dpm_table.fclk_table);
3365     int i, now, size = 0;
3366     int ret = 0;
3367     uint32_t gen_speed, lane_width, current_gen_speed, current_lane_width;
3368 
3369     switch (type) {
3370     case PP_SCLK:
3371         ret = vega20_get_current_clk_freq(hwmgr, PPCLK_GFXCLK, &now);
3372         PP_ASSERT_WITH_CODE(!ret,
3373                 "Attempt to get current gfx clk Failed!",
3374                 return ret);
3375 
3376         if (vega20_get_sclks(hwmgr, &clocks)) {
3377             size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
3378                 now / 100);
3379             break;
3380         }
3381 
3382         for (i = 0; i < clocks.num_levels; i++)
3383             size += sprintf(buf + size, "%d: %uMhz %s\n",
3384                 i, clocks.data[i].clocks_in_khz / 1000,
3385                 (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
3386         break;
3387 
3388     case PP_MCLK:
3389         ret = vega20_get_current_clk_freq(hwmgr, PPCLK_UCLK, &now);
3390         PP_ASSERT_WITH_CODE(!ret,
3391                 "Attempt to get current mclk freq Failed!",
3392                 return ret);
3393 
3394         if (vega20_get_memclocks(hwmgr, &clocks)) {
3395             size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
3396                 now / 100);
3397             break;
3398         }
3399 
3400         for (i = 0; i < clocks.num_levels; i++)
3401             size += sprintf(buf + size, "%d: %uMhz %s\n",
3402                 i, clocks.data[i].clocks_in_khz / 1000,
3403                 (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
3404         break;
3405 
3406     case PP_SOCCLK:
3407         ret = vega20_get_current_clk_freq(hwmgr, PPCLK_SOCCLK, &now);
3408         PP_ASSERT_WITH_CODE(!ret,
3409                 "Attempt to get current socclk freq Failed!",
3410                 return ret);
3411 
3412         if (vega20_get_socclocks(hwmgr, &clocks)) {
3413             size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
3414                 now / 100);
3415             break;
3416         }
3417 
3418         for (i = 0; i < clocks.num_levels; i++)
3419             size += sprintf(buf + size, "%d: %uMhz %s\n",
3420                 i, clocks.data[i].clocks_in_khz / 1000,
3421                 (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
3422         break;
3423 
3424     case PP_FCLK:
3425         ret = vega20_get_current_clk_freq(hwmgr, PPCLK_FCLK, &now);
3426         PP_ASSERT_WITH_CODE(!ret,
3427                 "Attempt to get current fclk freq Failed!",
3428                 return ret);
3429 
3430         for (i = 0; i < fclk_dpm_table->count; i++)
3431             size += sprintf(buf + size, "%d: %uMhz %s\n",
3432                 i, fclk_dpm_table->dpm_levels[i].value,
3433                 fclk_dpm_table->dpm_levels[i].value == (now / 100) ? "*" : "");
3434         break;
3435 
3436     case PP_DCEFCLK:
3437         ret = vega20_get_current_clk_freq(hwmgr, PPCLK_DCEFCLK, &now);
3438         PP_ASSERT_WITH_CODE(!ret,
3439                 "Attempt to get current dcefclk freq Failed!",
3440                 return ret);
3441 
3442         if (vega20_get_dcefclocks(hwmgr, &clocks)) {
3443             size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
3444                 now / 100);
3445             break;
3446         }
3447 
3448         for (i = 0; i < clocks.num_levels; i++)
3449             size += sprintf(buf + size, "%d: %uMhz %s\n",
3450                 i, clocks.data[i].clocks_in_khz / 1000,
3451                 (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
3452         break;
3453 
3454     case PP_PCIE:
3455         current_gen_speed =
3456             vega20_get_current_pcie_link_speed_level(hwmgr);
3457         current_lane_width =
3458             vega20_get_current_pcie_link_width_level(hwmgr);
3459         for (i = 0; i < NUM_LINK_LEVELS; i++) {
3460             gen_speed = pptable->PcieGenSpeed[i];
3461             lane_width = pptable->PcieLaneCount[i];
3462 
3463             size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
3464                     (gen_speed == 0) ? "2.5GT/s," :
3465                     (gen_speed == 1) ? "5.0GT/s," :
3466                     (gen_speed == 2) ? "8.0GT/s," :
3467                     (gen_speed == 3) ? "16.0GT/s," : "",
3468                     (lane_width == 1) ? "x1" :
3469                     (lane_width == 2) ? "x2" :
3470                     (lane_width == 3) ? "x4" :
3471                     (lane_width == 4) ? "x8" :
3472                     (lane_width == 5) ? "x12" :
3473                     (lane_width == 6) ? "x16" : "",
3474                     pptable->LclkFreq[i],
3475                     (current_gen_speed == gen_speed) &&
3476                     (current_lane_width == lane_width) ?
3477                     "*" : "");
3478         }
3479         break;
3480 
3481     case OD_SCLK:
3482         if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
3483             od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
3484             size += sprintf(buf + size, "%s:\n", "OD_SCLK");
3485             size += sprintf(buf + size, "0: %10uMhz\n",
3486                 od_table->GfxclkFmin);
3487             size += sprintf(buf + size, "1: %10uMhz\n",
3488                 od_table->GfxclkFmax);
3489         }
3490         break;
3491 
3492     case OD_MCLK:
3493         if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
3494             size += sprintf(buf + size, "%s:\n", "OD_MCLK");
3495             size += sprintf(buf + size, "1: %10uMhz\n",
3496                 od_table->UclkFmax);
3497         }
3498 
3499         break;
3500 
3501     case OD_VDDC_CURVE:
3502         if (od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
3503             od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
3504             od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
3505             od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
3506             od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
3507             od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
3508             size += sprintf(buf + size, "%s:\n", "OD_VDDC_CURVE");
3509             size += sprintf(buf + size, "0: %10uMhz %10dmV\n",
3510                 od_table->GfxclkFreq1,
3511                 od_table->GfxclkVolt1 / VOLTAGE_SCALE);
3512             size += sprintf(buf + size, "1: %10uMhz %10dmV\n",
3513                 od_table->GfxclkFreq2,
3514                 od_table->GfxclkVolt2 / VOLTAGE_SCALE);
3515             size += sprintf(buf + size, "2: %10uMhz %10dmV\n",
3516                 od_table->GfxclkFreq3,
3517                 od_table->GfxclkVolt3 / VOLTAGE_SCALE);
3518         }
3519 
3520         break;
3521 
3522     case OD_RANGE:
3523         size += sprintf(buf + size, "%s:\n", "OD_RANGE");
3524 
3525         if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
3526             od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
3527             size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
3528                 od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value,
3529                 od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value);
3530         }
3531 
3532         if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
3533             size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
3534                 od8_settings[OD8_SETTING_UCLK_FMAX].min_value,
3535                 od8_settings[OD8_SETTING_UCLK_FMAX].max_value);
3536         }
3537 
3538         if (od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
3539             od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
3540             od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
3541             od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
3542             od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
3543             od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
3544             size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
3545                 od8_settings[OD8_SETTING_GFXCLK_FREQ1].min_value,
3546                 od8_settings[OD8_SETTING_GFXCLK_FREQ1].max_value);
3547             size += sprintf(buf + size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n",
3548                 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].min_value,
3549                 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].max_value);
3550             size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
3551                 od8_settings[OD8_SETTING_GFXCLK_FREQ2].min_value,
3552                 od8_settings[OD8_SETTING_GFXCLK_FREQ2].max_value);
3553             size += sprintf(buf + size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n",
3554                 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].min_value,
3555                 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].max_value);
3556             size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
3557                 od8_settings[OD8_SETTING_GFXCLK_FREQ3].min_value,
3558                 od8_settings[OD8_SETTING_GFXCLK_FREQ3].max_value);
3559             size += sprintf(buf + size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
3560                 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].min_value,
3561                 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].max_value);
3562         }
3563 
3564         break;
3565     default:
3566         break;
3567     }
3568     return size;
3569 }
3570 
3571 static int vega20_set_uclk_to_highest_dpm_level(struct pp_hwmgr *hwmgr,
3572         struct vega20_single_dpm_table *dpm_table)
3573 {
3574     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3575     int ret = 0;
3576 
3577     if (data->smu_features[GNLD_DPM_UCLK].enabled) {
3578         PP_ASSERT_WITH_CODE(dpm_table->count > 0,
3579                 "[SetUclkToHightestDpmLevel] Dpm table has no entry!",
3580                 return -EINVAL);
3581         PP_ASSERT_WITH_CODE(dpm_table->count <= NUM_UCLK_DPM_LEVELS,
3582                 "[SetUclkToHightestDpmLevel] Dpm table has too many entries!",
3583                 return -EINVAL);
3584 
3585         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3586         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(hwmgr,
3587                 PPSMC_MSG_SetHardMinByFreq,
3588                 (PPCLK_UCLK << 16 ) | dpm_table->dpm_state.hard_min_level,
3589                 NULL)),
3590                 "[SetUclkToHightestDpmLevel] Set hard min uclk failed!",
3591                 return ret);
3592     }
3593 
3594     return ret;
3595 }
3596 
3597 static int vega20_set_fclk_to_highest_dpm_level(struct pp_hwmgr *hwmgr)
3598 {
3599     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3600     struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.fclk_table);
3601     int ret = 0;
3602 
3603     if (data->smu_features[GNLD_DPM_FCLK].enabled) {
3604         PP_ASSERT_WITH_CODE(dpm_table->count > 0,
3605                 "[SetFclkToHightestDpmLevel] Dpm table has no entry!",
3606                 return -EINVAL);
3607         PP_ASSERT_WITH_CODE(dpm_table->count <= NUM_FCLK_DPM_LEVELS,
3608                 "[SetFclkToHightestDpmLevel] Dpm table has too many entries!",
3609                 return -EINVAL);
3610 
3611         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3612         PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(hwmgr,
3613                 PPSMC_MSG_SetSoftMinByFreq,
3614                 (PPCLK_FCLK << 16 ) | dpm_table->dpm_state.soft_min_level,
3615                 NULL)),
3616                 "[SetFclkToHightestDpmLevel] Set soft min fclk failed!",
3617                 return ret);
3618     }
3619 
3620     return ret;
3621 }
3622 
3623 static int vega20_pre_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
3624 {
3625     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3626     int ret = 0;
3627 
3628     smum_send_msg_to_smc_with_parameter(hwmgr,
3629             PPSMC_MSG_NumOfDisplays, 0, NULL);
3630 
3631     ret = vega20_set_uclk_to_highest_dpm_level(hwmgr,
3632             &data->dpm_table.mem_table);
3633     if (ret)
3634         return ret;
3635 
3636     return vega20_set_fclk_to_highest_dpm_level(hwmgr);
3637 }
3638 
3639 static int vega20_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
3640 {
3641     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3642     int result = 0;
3643     Watermarks_t *wm_table = &(data->smc_state_table.water_marks_table);
3644 
3645     if ((data->water_marks_bitmap & WaterMarksExist) &&
3646         !(data->water_marks_bitmap & WaterMarksLoaded)) {
3647         result = smum_smc_table_manager(hwmgr,
3648                         (uint8_t *)wm_table, TABLE_WATERMARKS, false);
3649         PP_ASSERT_WITH_CODE(!result,
3650                 "Failed to update WMTABLE!",
3651                 return result);
3652         data->water_marks_bitmap |= WaterMarksLoaded;
3653     }
3654 
3655     if ((data->water_marks_bitmap & WaterMarksExist) &&
3656         data->smu_features[GNLD_DPM_DCEFCLK].supported &&
3657         data->smu_features[GNLD_DPM_SOCCLK].supported) {
3658         result = smum_send_msg_to_smc_with_parameter(hwmgr,
3659             PPSMC_MSG_NumOfDisplays,
3660             hwmgr->display_config->num_display,
3661             NULL);
3662     }
3663 
3664     return result;
3665 }
3666 
3667 static int vega20_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
3668 {
3669     struct vega20_hwmgr *data =
3670             (struct vega20_hwmgr *)(hwmgr->backend);
3671     int ret = 0;
3672 
3673     if (data->smu_features[GNLD_DPM_UVD].supported) {
3674         if (data->smu_features[GNLD_DPM_UVD].enabled == enable) {
3675             if (enable)
3676                 PP_DBG_LOG("[EnableDisableUVDDPM] feature DPM UVD already enabled!\n");
3677             else
3678                 PP_DBG_LOG("[EnableDisableUVDDPM] feature DPM UVD already disabled!\n");
3679         }
3680 
3681         ret = vega20_enable_smc_features(hwmgr,
3682                 enable,
3683                 data->smu_features[GNLD_DPM_UVD].smu_feature_bitmap);
3684         PP_ASSERT_WITH_CODE(!ret,
3685                 "[EnableDisableUVDDPM] Attempt to Enable/Disable DPM UVD Failed!",
3686                 return ret);
3687         data->smu_features[GNLD_DPM_UVD].enabled = enable;
3688     }
3689 
3690     return 0;
3691 }
3692 
3693 static void vega20_power_gate_vce(struct pp_hwmgr *hwmgr, bool bgate)
3694 {
3695     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3696 
3697     if (data->vce_power_gated == bgate)
3698         return ;
3699 
3700     data->vce_power_gated = bgate;
3701     if (bgate) {
3702         vega20_enable_disable_vce_dpm(hwmgr, !bgate);
3703         amdgpu_device_ip_set_powergating_state(hwmgr->adev,
3704                         AMD_IP_BLOCK_TYPE_VCE,
3705                         AMD_PG_STATE_GATE);
3706     } else {
3707         amdgpu_device_ip_set_powergating_state(hwmgr->adev,
3708                         AMD_IP_BLOCK_TYPE_VCE,
3709                         AMD_PG_STATE_UNGATE);
3710         vega20_enable_disable_vce_dpm(hwmgr, !bgate);
3711     }
3712 
3713 }
3714 
3715 static void vega20_power_gate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
3716 {
3717     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3718 
3719     if (data->uvd_power_gated == bgate)
3720         return ;
3721 
3722     data->uvd_power_gated = bgate;
3723     vega20_enable_disable_uvd_dpm(hwmgr, !bgate);
3724 }
3725 
3726 static int vega20_apply_clocks_adjust_rules(struct pp_hwmgr *hwmgr)
3727 {
3728     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3729     struct vega20_single_dpm_table *dpm_table;
3730     bool vblank_too_short = false;
3731     bool disable_mclk_switching;
3732     bool disable_fclk_switching;
3733     uint32_t i, latency;
3734 
3735     disable_mclk_switching = ((1 < hwmgr->display_config->num_display) &&
3736                            !hwmgr->display_config->multi_monitor_in_sync) ||
3737                             vblank_too_short;
3738     latency = hwmgr->display_config->dce_tolerable_mclk_in_active_latency;
3739 
3740     /* gfxclk */
3741     dpm_table = &(data->dpm_table.gfx_table);
3742     dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3743     dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
3744     dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3745     dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
3746 
3747     if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3748         if (VEGA20_UMD_PSTATE_GFXCLK_LEVEL < dpm_table->count) {
3749             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
3750             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
3751         }
3752 
3753         if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
3754             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3755             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
3756         }
3757 
3758         if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3759             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3760             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3761         }
3762     }
3763 
3764     /* memclk */
3765     dpm_table = &(data->dpm_table.mem_table);
3766     dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3767     dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
3768     dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3769     dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
3770 
3771     if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3772         if (VEGA20_UMD_PSTATE_MCLK_LEVEL < dpm_table->count) {
3773             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
3774             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
3775         }
3776 
3777         if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
3778             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3779             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
3780         }
3781 
3782         if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3783             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3784             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3785         }
3786     }
3787 
3788     /* honour DAL's UCLK Hardmin */
3789     if (dpm_table->dpm_state.hard_min_level < (hwmgr->display_config->min_mem_set_clock / 100))
3790         dpm_table->dpm_state.hard_min_level = hwmgr->display_config->min_mem_set_clock / 100;
3791 
3792     /* Hardmin is dependent on displayconfig */
3793     if (disable_mclk_switching) {
3794         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3795         for (i = 0; i < data->mclk_latency_table.count - 1; i++) {
3796             if (data->mclk_latency_table.entries[i].latency <= latency) {
3797                 if (dpm_table->dpm_levels[i].value >= (hwmgr->display_config->min_mem_set_clock / 100)) {
3798                     dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[i].value;
3799                     break;
3800                 }
3801             }
3802         }
3803     }
3804 
3805     if (hwmgr->display_config->nb_pstate_switch_disable)
3806         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3807 
3808     if ((disable_mclk_switching &&
3809         (dpm_table->dpm_state.hard_min_level == dpm_table->dpm_levels[dpm_table->count - 1].value)) ||
3810          hwmgr->display_config->min_mem_set_clock / 100 >= dpm_table->dpm_levels[dpm_table->count - 1].value)
3811         disable_fclk_switching = true;
3812     else
3813         disable_fclk_switching = false;
3814 
3815     /* fclk */
3816     dpm_table = &(data->dpm_table.fclk_table);
3817     dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3818     dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
3819     dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3820     dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
3821     if (hwmgr->display_config->nb_pstate_switch_disable || disable_fclk_switching)
3822         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3823 
3824     /* vclk */
3825     dpm_table = &(data->dpm_table.vclk_table);
3826     dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3827     dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
3828     dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3829     dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
3830 
3831     if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3832         if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
3833             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
3834             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
3835         }
3836 
3837         if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3838             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3839             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3840         }
3841     }
3842 
3843     /* dclk */
3844     dpm_table = &(data->dpm_table.dclk_table);
3845     dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3846     dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
3847     dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3848     dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
3849 
3850     if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3851         if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
3852             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
3853             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
3854         }
3855 
3856         if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3857             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3858             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3859         }
3860     }
3861 
3862     /* socclk */
3863     dpm_table = &(data->dpm_table.soc_table);
3864     dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3865     dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
3866     dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3867     dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
3868 
3869     if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3870         if (VEGA20_UMD_PSTATE_SOCCLK_LEVEL < dpm_table->count) {
3871             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
3872             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
3873         }
3874 
3875         if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3876             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3877             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3878         }
3879     }
3880 
3881     /* eclk */
3882     dpm_table = &(data->dpm_table.eclk_table);
3883     dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3884     dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
3885     dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3886     dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
3887 
3888     if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3889         if (VEGA20_UMD_PSTATE_VCEMCLK_LEVEL < dpm_table->count) {
3890             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
3891             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
3892         }
3893 
3894         if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3895             dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3896             dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3897         }
3898     }
3899 
3900     return 0;
3901 }
3902 
3903 static bool
3904 vega20_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
3905 {
3906     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3907     bool is_update_required = false;
3908 
3909     if (data->display_timing.num_existing_displays !=
3910             hwmgr->display_config->num_display)
3911         is_update_required = true;
3912 
3913     if (data->registry_data.gfx_clk_deep_sleep_support &&
3914        (data->display_timing.min_clock_in_sr !=
3915         hwmgr->display_config->min_core_set_clock_in_sr))
3916         is_update_required = true;
3917 
3918     return is_update_required;
3919 }
3920 
3921 static int vega20_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
3922 {
3923     int ret = 0;
3924 
3925     ret = vega20_disable_all_smu_features(hwmgr);
3926     PP_ASSERT_WITH_CODE(!ret,
3927             "[DisableDpmTasks] Failed to disable all smu features!",
3928             return ret);
3929 
3930     return 0;
3931 }
3932 
3933 static int vega20_power_off_asic(struct pp_hwmgr *hwmgr)
3934 {
3935     struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3936     int result;
3937 
3938     result = vega20_disable_dpm_tasks(hwmgr);
3939     PP_ASSERT_WITH_CODE((0 == result),
3940             "[PowerOffAsic] Failed to disable DPM!",
3941             );
3942     data->water_marks_bitmap &= ~(WaterMarksLoaded);
3943 
3944     return result;
3945 }
3946 
3947 static int conv_power_profile_to_pplib_workload(int power_profile)
3948 {
3949     int pplib_workload = 0;
3950 
3951     switch (power_profile) {
3952     case PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT:
3953         pplib_workload = WORKLOAD_DEFAULT_BIT;
3954         break;
3955     case PP_SMC_POWER_PROFILE_FULLSCREEN3D:
3956         pplib_workload = WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT;
3957         break;
3958     case PP_SMC_POWER_PROFILE_POWERSAVING:
3959         pplib_workload = WORKLOAD_PPLIB_POWER_SAVING_BIT;
3960         break;
3961     case PP_SMC_POWER_PROFILE_VIDEO:
3962         pplib_workload = WORKLOAD_PPLIB_VIDEO_BIT;
3963         break;
3964     case PP_SMC_POWER_PROFILE_VR:
3965         pplib_workload = WORKLOAD_PPLIB_VR_BIT;
3966         break;
3967     case PP_SMC_POWER_PROFILE_COMPUTE:
3968         pplib_workload = WORKLOAD_PPLIB_COMPUTE_BIT;
3969         break;
3970     case PP_SMC_POWER_PROFILE_CUSTOM:
3971         pplib_workload = WORKLOAD_PPLIB_CUSTOM_BIT;
3972         break;
3973     }
3974 
3975     return pplib_workload;
3976 }
3977 
3978 static int vega20_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
3979 {
3980     DpmActivityMonitorCoeffInt_t activity_monitor;
3981     uint32_t i, size = 0;
3982     uint16_t workload_type = 0;
3983     static const char *title[] = {
3984             "PROFILE_INDEX(NAME)",
3985             "CLOCK_TYPE(NAME)",
3986             "FPS",
3987             "UseRlcBusy",
3988             "MinActiveFreqType",
3989             "MinActiveFreq",
3990             "BoosterFreqType",
3991             "BoosterFreq",
3992             "PD_Data_limit_c",
3993             "PD_Data_error_coeff",
3994             "PD_Data_error_rate_coeff"};
3995     int result = 0;
3996 
3997     if (!buf)
3998         return -EINVAL;
3999 
4000     phm_get_sysfs_buf(&buf, &size);
4001 
4002     size += sysfs_emit_at(buf, size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
4003             title[0], title[1], title[2], title[3], title[4], title[5],
4004             title[6], title[7], title[8], title[9], title[10]);
4005 
4006     for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
4007         /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
4008         workload_type = conv_power_profile_to_pplib_workload(i);
4009         result = vega20_get_activity_monitor_coeff(hwmgr,
4010                 (uint8_t *)(&activity_monitor), workload_type);
4011         PP_ASSERT_WITH_CODE(!result,
4012                 "[GetPowerProfile] Failed to get activity monitor!",
4013                 return result);
4014 
4015         size += sysfs_emit_at(buf, size, "%2d %14s%s:\n",
4016             i, amdgpu_pp_profile_name[i], (i == hwmgr->power_profile_mode) ? "*" : " ");
4017 
4018         size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
4019             " ",
4020             0,
4021             "GFXCLK",
4022             activity_monitor.Gfx_FPS,
4023             activity_monitor.Gfx_UseRlcBusy,
4024             activity_monitor.Gfx_MinActiveFreqType,
4025             activity_monitor.Gfx_MinActiveFreq,
4026             activity_monitor.Gfx_BoosterFreqType,
4027             activity_monitor.Gfx_BoosterFreq,
4028             activity_monitor.Gfx_PD_Data_limit_c,
4029             activity_monitor.Gfx_PD_Data_error_coeff,
4030             activity_monitor.Gfx_PD_Data_error_rate_coeff);
4031 
4032         size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
4033             " ",
4034             1,
4035             "SOCCLK",
4036             activity_monitor.Soc_FPS,
4037             activity_monitor.Soc_UseRlcBusy,
4038             activity_monitor.Soc_MinActiveFreqType,
4039             activity_monitor.Soc_MinActiveFreq,
4040             activity_monitor.Soc_BoosterFreqType,
4041             activity_monitor.Soc_BoosterFreq,
4042             activity_monitor.Soc_PD_Data_limit_c,
4043             activity_monitor.Soc_PD_Data_error_coeff,
4044             activity_monitor.Soc_PD_Data_error_rate_coeff);
4045 
4046         size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
4047             " ",
4048             2,
4049             "UCLK",
4050             activity_monitor.Mem_FPS,
4051             activity_monitor.Mem_UseRlcBusy,
4052             activity_monitor.Mem_MinActiveFreqType,
4053             activity_monitor.Mem_MinActiveFreq,
4054             activity_monitor.Mem_BoosterFreqType,
4055             activity_monitor.Mem_BoosterFreq,
4056             activity_monitor.Mem_PD_Data_limit_c,
4057             activity_monitor.Mem_PD_Data_error_coeff,
4058             activity_monitor.Mem_PD_Data_error_rate_coeff);
4059 
4060         size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
4061             " ",
4062             3,
4063             "FCLK",
4064             activity_monitor.Fclk_FPS,
4065             activity_monitor.Fclk_UseRlcBusy,
4066             activity_monitor.Fclk_MinActiveFreqType,
4067             activity_monitor.Fclk_MinActiveFreq,
4068             activity_monitor.Fclk_BoosterFreqType,
4069             activity_monitor.Fclk_BoosterFreq,
4070             activity_monitor.Fclk_PD_Data_limit_c,
4071             activity_monitor.Fclk_PD_Data_error_coeff,
4072             activity_monitor.Fclk_PD_Data_error_rate_coeff);
4073     }
4074 
4075     return size;
4076 }
4077 
4078 static int vega20_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint32_t size)
4079 {
4080     DpmActivityMonitorCoeffInt_t activity_monitor;
4081     int workload_type, result = 0;
4082     uint32_t power_profile_mode = input[size];
4083 
4084     if (power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
4085         pr_err("Invalid power profile mode %d\n", power_profile_mode);
4086         return -EINVAL;
4087     }
4088 
4089     if (power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
4090         struct vega20_hwmgr *data =
4091             (struct vega20_hwmgr *)(hwmgr->backend);
4092         if (size == 0 && !data->is_custom_profile_set)
4093             return -EINVAL;
4094         if (size < 10 && size != 0)
4095             return -EINVAL;
4096 
4097         result = vega20_get_activity_monitor_coeff(hwmgr,
4098                 (uint8_t *)(&activity_monitor),
4099                 WORKLOAD_PPLIB_CUSTOM_BIT);
4100         PP_ASSERT_WITH_CODE(!result,
4101                 "[SetPowerProfile] Failed to get activity monitor!",
4102                 return result);
4103 
4104         /* If size==0, then we want to apply the already-configured
4105          * CUSTOM profile again. Just apply it, since we checked its
4106          * validity above
4107          */
4108         if (size == 0)
4109             goto out;
4110 
4111         switch (input[0]) {
4112         case 0: /* Gfxclk */
4113             activity_monitor.Gfx_FPS = input[1];
4114             activity_monitor.Gfx_UseRlcBusy = input[2];
4115             activity_monitor.Gfx_MinActiveFreqType = input[3];
4116             activity_monitor.Gfx_MinActiveFreq = input[4];
4117             activity_monitor.Gfx_BoosterFreqType = input[5];
4118             activity_monitor.Gfx_BoosterFreq = input[6];
4119             activity_monitor.Gfx_PD_Data_limit_c = input[7];
4120             activity_monitor.Gfx_PD_Data_error_coeff = input[8];
4121             activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
4122             break;
4123         case 1: /* Socclk */
4124             activity_monitor.Soc_FPS = input[1];
4125             activity_monitor.Soc_UseRlcBusy = input[2];
4126             activity_monitor.Soc_MinActiveFreqType = input[3];
4127             activity_monitor.Soc_MinActiveFreq = input[4];
4128             activity_monitor.Soc_BoosterFreqType = input[5];
4129             activity_monitor.Soc_BoosterFreq = input[6];
4130             activity_monitor.Soc_PD_Data_limit_c = input[7];
4131             activity_monitor.Soc_PD_Data_error_coeff = input[8];
4132             activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
4133             break;
4134         case 2: /* Uclk */
4135             activity_monitor.Mem_FPS = input[1];
4136             activity_monitor.Mem_UseRlcBusy = input[2];
4137             activity_monitor.Mem_MinActiveFreqType = input[3];
4138             activity_monitor.Mem_MinActiveFreq = input[4];
4139             activity_monitor.Mem_BoosterFreqType = input[5];
4140             activity_monitor.Mem_BoosterFreq = input[6];
4141             activity_monitor.Mem_PD_Data_limit_c = input[7];
4142             activity_monitor.Mem_PD_Data_error_coeff = input[8];
4143             activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
4144             break;
4145         case 3: /* Fclk */
4146             activity_monitor.Fclk_FPS = input[1];
4147             activity_monitor.Fclk_UseRlcBusy = input[2];
4148             activity_monitor.Fclk_MinActiveFreqType = input[3];
4149             activity_monitor.Fclk_MinActiveFreq = input[4];
4150             activity_monitor.Fclk_BoosterFreqType = input[5];
4151             activity_monitor.Fclk_BoosterFreq = input[6];
4152             activity_monitor.Fclk_PD_Data_limit_c = input[7];
4153             activity_monitor.Fclk_PD_Data_error_coeff = input[8];
4154             activity_monitor.Fclk_PD_Data_error_rate_coeff = input[9];
4155             break;
4156         }
4157 
4158         result = vega20_set_activity_monitor_coeff(hwmgr,
4159                 (uint8_t *)(&activity_monitor),
4160                 WORKLOAD_PPLIB_CUSTOM_BIT);
4161         data->is_custom_profile_set = true;
4162         PP_ASSERT_WITH_CODE(!result,
4163                 "[SetPowerProfile] Failed to set activity monitor!",
4164                 return result);
4165     }
4166 
4167 out:
4168     /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
4169     workload_type =
4170         conv_power_profile_to_pplib_workload(power_profile_mode);
4171     smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetWorkloadMask,
4172                         1 << workload_type,
4173                         NULL);
4174 
4175     hwmgr->power_profile_mode = power_profile_mode;
4176 
4177     return 0;
4178 }
4179 
4180 static int vega20_notify_cac_buffer_info(struct pp_hwmgr *hwmgr,
4181                     uint32_t virtual_addr_low,
4182                     uint32_t virtual_addr_hi,
4183                     uint32_t mc_addr_low,
4184                     uint32_t mc_addr_hi,
4185                     uint32_t size)
4186 {
4187     smum_send_msg_to_smc_with_parameter(hwmgr,
4188                     PPSMC_MSG_SetSystemVirtualDramAddrHigh,
4189                     virtual_addr_hi,
4190                     NULL);
4191     smum_send_msg_to_smc_with_parameter(hwmgr,
4192                     PPSMC_MSG_SetSystemVirtualDramAddrLow,
4193                     virtual_addr_low,
4194                     NULL);
4195     smum_send_msg_to_smc_with_parameter(hwmgr,
4196                     PPSMC_MSG_DramLogSetDramAddrHigh,
4197                     mc_addr_hi,
4198                     NULL);
4199 
4200     smum_send_msg_to_smc_with_parameter(hwmgr,
4201                     PPSMC_MSG_DramLogSetDramAddrLow,
4202                     mc_addr_low,
4203                     NULL);
4204 
4205     smum_send_msg_to_smc_with_parameter(hwmgr,
4206                     PPSMC_MSG_DramLogSetDramSize,
4207                     size,
4208                     NULL);
4209     return 0;
4210 }
4211 
4212 static int vega20_get_thermal_temperature_range(struct pp_hwmgr *hwmgr,
4213         struct PP_TemperatureRange *thermal_data)
4214 {
4215     struct vega20_hwmgr *data =
4216             (struct vega20_hwmgr *)(hwmgr->backend);
4217     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
4218 
4219     memcpy(thermal_data, &SMU7ThermalWithDelayPolicy[0], sizeof(struct PP_TemperatureRange));
4220 
4221     thermal_data->max = pp_table->TedgeLimit *
4222         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
4223     thermal_data->edge_emergency_max = (pp_table->TedgeLimit + CTF_OFFSET_EDGE) *
4224         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
4225     thermal_data->hotspot_crit_max = pp_table->ThotspotLimit *
4226         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
4227     thermal_data->hotspot_emergency_max = (pp_table->ThotspotLimit + CTF_OFFSET_HOTSPOT) *
4228         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
4229     thermal_data->mem_crit_max = pp_table->ThbmLimit *
4230         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
4231     thermal_data->mem_emergency_max = (pp_table->ThbmLimit + CTF_OFFSET_HBM)*
4232         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
4233 
4234     return 0;
4235 }
4236 
4237 static int vega20_smu_i2c_bus_access(struct pp_hwmgr *hwmgr, bool acquire)
4238 {
4239     int res;
4240 
4241     /* I2C bus access can happen very early, when SMU not loaded yet */
4242     if (!vega20_is_smc_ram_running(hwmgr))
4243         return 0;
4244 
4245     res = smum_send_msg_to_smc_with_parameter(hwmgr,
4246                           (acquire ?
4247                           PPSMC_MSG_RequestI2CBus :
4248                           PPSMC_MSG_ReleaseI2CBus),
4249                           0,
4250                           NULL);
4251 
4252     PP_ASSERT_WITH_CODE(!res, "[SmuI2CAccessBus] Failed to access bus!", return res);
4253     return res;
4254 }
4255 
4256 static int vega20_set_df_cstate(struct pp_hwmgr *hwmgr,
4257                 enum pp_df_cstate state)
4258 {
4259     int ret;
4260 
4261     /* PPSMC_MSG_DFCstateControl is supported with 40.50 and later fws */
4262     if (hwmgr->smu_version < 0x283200) {
4263         pr_err("Df cstate control is supported with 40.50 and later SMC fw!\n");
4264         return -EINVAL;
4265     }
4266 
4267     ret = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DFCstateControl, state,
4268                 NULL);
4269     if (ret)
4270         pr_err("SetDfCstate failed!\n");
4271 
4272     return ret;
4273 }
4274 
4275 static int vega20_set_xgmi_pstate(struct pp_hwmgr *hwmgr,
4276                   uint32_t pstate)
4277 {
4278     int ret;
4279 
4280     ret = smum_send_msg_to_smc_with_parameter(hwmgr,
4281                           PPSMC_MSG_SetXgmiMode,
4282                           pstate ? XGMI_MODE_PSTATE_D0 : XGMI_MODE_PSTATE_D3,
4283                           NULL);
4284     if (ret)
4285         pr_err("SetXgmiPstate failed!\n");
4286 
4287     return ret;
4288 }
4289 
4290 static void vega20_init_gpu_metrics_v1_0(struct gpu_metrics_v1_0 *gpu_metrics)
4291 {
4292     memset(gpu_metrics, 0xFF, sizeof(struct gpu_metrics_v1_0));
4293 
4294     gpu_metrics->common_header.structure_size =
4295                 sizeof(struct gpu_metrics_v1_0);
4296     gpu_metrics->common_header.format_revision = 1;
4297     gpu_metrics->common_header.content_revision = 0;
4298 
4299     gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
4300 }
4301 
4302 static ssize_t vega20_get_gpu_metrics(struct pp_hwmgr *hwmgr,
4303                       void **table)
4304 {
4305     struct vega20_hwmgr *data =
4306             (struct vega20_hwmgr *)(hwmgr->backend);
4307     struct gpu_metrics_v1_0 *gpu_metrics =
4308             &data->gpu_metrics_table;
4309     SmuMetrics_t metrics;
4310     uint32_t fan_speed_rpm;
4311     int ret;
4312 
4313     ret = vega20_get_metrics_table(hwmgr, &metrics, true);
4314     if (ret)
4315         return ret;
4316 
4317     vega20_init_gpu_metrics_v1_0(gpu_metrics);
4318 
4319     gpu_metrics->temperature_edge = metrics.TemperatureEdge;
4320     gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot;
4321     gpu_metrics->temperature_mem = metrics.TemperatureHBM;
4322     gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx;
4323     gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc;
4324     gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem0;
4325 
4326     gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity;
4327     gpu_metrics->average_umc_activity = metrics.AverageUclkActivity;
4328 
4329     gpu_metrics->average_socket_power = metrics.AverageSocketPower;
4330 
4331     gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency;
4332     gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency;
4333     gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency;
4334 
4335     gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK];
4336     gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK];
4337     gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK];
4338     gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK];
4339     gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK];
4340 
4341     gpu_metrics->throttle_status = metrics.ThrottlerStatus;
4342 
4343     vega20_fan_ctrl_get_fan_speed_rpm(hwmgr, &fan_speed_rpm);
4344     gpu_metrics->current_fan_speed = (uint16_t)fan_speed_rpm;
4345 
4346     gpu_metrics->pcie_link_width =
4347             vega20_get_current_pcie_link_width(hwmgr);
4348     gpu_metrics->pcie_link_speed =
4349             vega20_get_current_pcie_link_speed(hwmgr);
4350 
4351     *table = (void *)gpu_metrics;
4352 
4353     return sizeof(struct gpu_metrics_v1_0);
4354 }
4355 
4356 static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
4357     /* init/fini related */
4358     .backend_init = vega20_hwmgr_backend_init,
4359     .backend_fini = vega20_hwmgr_backend_fini,
4360     .asic_setup = vega20_setup_asic_task,
4361     .power_off_asic = vega20_power_off_asic,
4362     .dynamic_state_management_enable = vega20_enable_dpm_tasks,
4363     .dynamic_state_management_disable = vega20_disable_dpm_tasks,
4364     /* power state related */
4365     .apply_clocks_adjust_rules = vega20_apply_clocks_adjust_rules,
4366     .pre_display_config_changed = vega20_pre_display_configuration_changed_task,
4367     .display_config_changed = vega20_display_configuration_changed_task,
4368     .check_smc_update_required_for_display_configuration =
4369         vega20_check_smc_update_required_for_display_configuration,
4370     .notify_smc_display_config_after_ps_adjustment =
4371         vega20_notify_smc_display_config_after_ps_adjustment,
4372     /* export to DAL */
4373     .get_sclk = vega20_dpm_get_sclk,
4374     .get_mclk = vega20_dpm_get_mclk,
4375     .get_dal_power_level = vega20_get_dal_power_level,
4376     .get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency,
4377     .get_clock_by_type_with_voltage = vega20_get_clock_by_type_with_voltage,
4378     .set_watermarks_for_clocks_ranges = vega20_set_watermarks_for_clocks_ranges,
4379     .display_clock_voltage_request = vega20_display_clock_voltage_request,
4380     .get_performance_level = vega20_get_performance_level,
4381     /* UMD pstate, profile related */
4382     .force_dpm_level = vega20_dpm_force_dpm_level,
4383     .get_power_profile_mode = vega20_get_power_profile_mode,
4384     .set_power_profile_mode = vega20_set_power_profile_mode,
4385     /* od related */
4386     .set_power_limit = vega20_set_power_limit,
4387     .get_sclk_od = vega20_get_sclk_od,
4388     .set_sclk_od = vega20_set_sclk_od,
4389     .get_mclk_od = vega20_get_mclk_od,
4390     .set_mclk_od = vega20_set_mclk_od,
4391     .odn_edit_dpm_table = vega20_odn_edit_dpm_table,
4392     /* for sysfs to retrive/set gfxclk/memclk */
4393     .force_clock_level = vega20_force_clock_level,
4394     .print_clock_levels = vega20_print_clock_levels,
4395     .read_sensor = vega20_read_sensor,
4396     .get_ppfeature_status = vega20_get_ppfeature_status,
4397     .set_ppfeature_status = vega20_set_ppfeature_status,
4398     /* powergate related */
4399     .powergate_uvd = vega20_power_gate_uvd,
4400     .powergate_vce = vega20_power_gate_vce,
4401     /* thermal related */
4402     .start_thermal_controller = vega20_start_thermal_controller,
4403     .stop_thermal_controller = vega20_thermal_stop_thermal_controller,
4404     .get_thermal_temperature_range = vega20_get_thermal_temperature_range,
4405     .register_irq_handlers = smu9_register_irq_handlers,
4406     .disable_smc_firmware_ctf = vega20_thermal_disable_alert,
4407     /* fan control related */
4408     .get_fan_speed_pwm = vega20_fan_ctrl_get_fan_speed_pwm,
4409     .set_fan_speed_pwm = vega20_fan_ctrl_set_fan_speed_pwm,
4410     .get_fan_speed_info = vega20_fan_ctrl_get_fan_speed_info,
4411     .get_fan_speed_rpm = vega20_fan_ctrl_get_fan_speed_rpm,
4412     .set_fan_speed_rpm = vega20_fan_ctrl_set_fan_speed_rpm,
4413     .get_fan_control_mode = vega20_get_fan_control_mode,
4414     .set_fan_control_mode = vega20_set_fan_control_mode,
4415     /* smu memory related */
4416     .notify_cac_buffer_info = vega20_notify_cac_buffer_info,
4417     .enable_mgpu_fan_boost = vega20_enable_mgpu_fan_boost,
4418     /* BACO related */
4419     .get_asic_baco_capability = vega20_baco_get_capability,
4420     .get_asic_baco_state = vega20_baco_get_state,
4421     .set_asic_baco_state = vega20_baco_set_state,
4422     .set_mp1_state = vega20_set_mp1_state,
4423     .smu_i2c_bus_access = vega20_smu_i2c_bus_access,
4424     .set_df_cstate = vega20_set_df_cstate,
4425     .set_xgmi_pstate = vega20_set_xgmi_pstate,
4426     .get_gpu_metrics = vega20_get_gpu_metrics,
4427 };
4428 
4429 int vega20_hwmgr_init(struct pp_hwmgr *hwmgr)
4430 {
4431     hwmgr->hwmgr_func = &vega20_hwmgr_funcs;
4432     hwmgr->pptable_func = &vega20_pptable_funcs;
4433 
4434     return 0;
4435 }