LCOV - code coverage report
Current view: top level - drivers/gpu/drm/amd/pm/powerplay/hwmgr - vega20_hwmgr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 1915 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 83 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2018 Advanced Micro Devices, Inc.
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a
       5             :  * copy of this software and associated documentation files (the "Software"),
       6             :  * to deal in the Software without restriction, including without limitation
       7             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       8             :  * and/or sell copies of the Software, and to permit persons to whom the
       9             :  * Software is furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in
      12             :  * all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      17             :  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
      18             :  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      19             :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      20             :  * OTHER DEALINGS IN THE SOFTWARE.
      21             :  *
      22             :  */
      23             : 
      24             : #include <linux/delay.h>
      25             : #include <linux/fb.h>
      26             : #include <linux/module.h>
      27             : #include <linux/slab.h>
      28             : 
      29             : #include "hwmgr.h"
      30             : #include "amd_powerplay.h"
      31             : #include "vega20_smumgr.h"
      32             : #include "hardwaremanager.h"
      33             : #include "ppatomfwctrl.h"
      34             : #include "atomfirmware.h"
      35             : #include "cgs_common.h"
      36             : #include "vega20_powertune.h"
      37             : #include "vega20_inc.h"
      38             : #include "pppcielanes.h"
      39             : #include "vega20_hwmgr.h"
      40             : #include "vega20_processpptables.h"
      41             : #include "vega20_pptable.h"
      42             : #include "vega20_thermal.h"
      43             : #include "vega20_ppsmc.h"
      44             : #include "pp_debug.h"
      45             : #include "amd_pcie_helpers.h"
      46             : #include "ppinterrupt.h"
      47             : #include "pp_overdriver.h"
      48             : #include "pp_thermal.h"
      49             : #include "soc15_common.h"
      50             : #include "vega20_baco.h"
      51             : #include "smuio/smuio_9_0_offset.h"
      52             : #include "smuio/smuio_9_0_sh_mask.h"
      53             : #include "nbio/nbio_7_4_sh_mask.h"
      54             : 
      55             : #define smnPCIE_LC_SPEED_CNTL                   0x11140290
      56             : #define smnPCIE_LC_LINK_WIDTH_CNTL              0x11140288
      57             : 
      58             : #define LINK_WIDTH_MAX                          6
      59             : #define LINK_SPEED_MAX                          3
      60             : static const int link_width[] = {0, 1, 2, 4, 8, 12, 16};
      61             : static const int link_speed[] = {25, 50, 80, 160};
      62             : 
      63           0 : static void vega20_set_default_registry_data(struct pp_hwmgr *hwmgr)
      64             : {
      65           0 :         struct vega20_hwmgr *data =
      66             :                         (struct vega20_hwmgr *)(hwmgr->backend);
      67             : 
      68           0 :         data->gfxclk_average_alpha = PPVEGA20_VEGA20GFXCLKAVERAGEALPHA_DFLT;
      69           0 :         data->socclk_average_alpha = PPVEGA20_VEGA20SOCCLKAVERAGEALPHA_DFLT;
      70           0 :         data->uclk_average_alpha = PPVEGA20_VEGA20UCLKCLKAVERAGEALPHA_DFLT;
      71           0 :         data->gfx_activity_average_alpha = PPVEGA20_VEGA20GFXACTIVITYAVERAGEALPHA_DFLT;
      72           0 :         data->lowest_uclk_reserved_for_ulv = PPVEGA20_VEGA20LOWESTUCLKRESERVEDFORULV_DFLT;
      73             : 
      74           0 :         data->display_voltage_mode = PPVEGA20_VEGA20DISPLAYVOLTAGEMODE_DFLT;
      75           0 :         data->dcef_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
      76           0 :         data->dcef_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
      77           0 :         data->dcef_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
      78           0 :         data->disp_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
      79           0 :         data->disp_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
      80           0 :         data->disp_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
      81           0 :         data->pixel_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
      82           0 :         data->pixel_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
      83           0 :         data->pixel_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
      84           0 :         data->phy_clk_quad_eqn_a = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
      85           0 :         data->phy_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
      86           0 :         data->phy_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
      87             : 
      88             :         /*
      89             :          * Disable the following features for now:
      90             :          *   GFXCLK DS
      91             :          *   SOCLK DS
      92             :          *   LCLK DS
      93             :          *   DCEFCLK DS
      94             :          *   FCLK DS
      95             :          *   MP1CLK DS
      96             :          *   MP0CLK DS
      97             :          */
      98           0 :         data->registry_data.disallowed_features = 0xE0041C00;
      99             :         /* ECC feature should be disabled on old SMUs */
     100           0 :         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetSmuVersion, &hwmgr->smu_version);
     101           0 :         if (hwmgr->smu_version < 0x282100)
     102           0 :                 data->registry_data.disallowed_features |= FEATURE_ECC_MASK;
     103             : 
     104           0 :         if (!(hwmgr->feature_mask & PP_PCIE_DPM_MASK))
     105           0 :                 data->registry_data.disallowed_features |= FEATURE_DPM_LINK_MASK;
     106             : 
     107           0 :         if (!(hwmgr->feature_mask & PP_SCLK_DPM_MASK))
     108           0 :                 data->registry_data.disallowed_features |= FEATURE_DPM_GFXCLK_MASK;
     109             : 
     110           0 :         if (!(hwmgr->feature_mask & PP_SOCCLK_DPM_MASK))
     111           0 :                 data->registry_data.disallowed_features |= FEATURE_DPM_SOCCLK_MASK;
     112             : 
     113           0 :         if (!(hwmgr->feature_mask & PP_MCLK_DPM_MASK))
     114           0 :                 data->registry_data.disallowed_features |= FEATURE_DPM_UCLK_MASK;
     115             : 
     116           0 :         if (!(hwmgr->feature_mask & PP_DCEFCLK_DPM_MASK))
     117           0 :                 data->registry_data.disallowed_features |= FEATURE_DPM_DCEFCLK_MASK;
     118             : 
     119           0 :         if (!(hwmgr->feature_mask & PP_ULV_MASK))
     120           0 :                 data->registry_data.disallowed_features |= FEATURE_ULV_MASK;
     121             : 
     122           0 :         if (!(hwmgr->feature_mask & PP_SCLK_DEEP_SLEEP_MASK))
     123           0 :                 data->registry_data.disallowed_features |= FEATURE_DS_GFXCLK_MASK;
     124             : 
     125           0 :         data->registry_data.od_state_in_dc_support = 0;
     126           0 :         data->registry_data.thermal_support = 1;
     127           0 :         data->registry_data.skip_baco_hardware = 0;
     128             : 
     129           0 :         data->registry_data.log_avfs_param = 0;
     130           0 :         data->registry_data.sclk_throttle_low_notification = 1;
     131           0 :         data->registry_data.force_dpm_high = 0;
     132           0 :         data->registry_data.stable_pstate_sclk_dpm_percentage = 75;
     133             : 
     134           0 :         data->registry_data.didt_support = 0;
     135             :         if (data->registry_data.didt_support) {
     136             :                 data->registry_data.didt_mode = 6;
     137             :                 data->registry_data.sq_ramping_support = 1;
     138             :                 data->registry_data.db_ramping_support = 0;
     139             :                 data->registry_data.td_ramping_support = 0;
     140             :                 data->registry_data.tcp_ramping_support = 0;
     141             :                 data->registry_data.dbr_ramping_support = 0;
     142             :                 data->registry_data.edc_didt_support = 1;
     143             :                 data->registry_data.gc_didt_support = 0;
     144             :                 data->registry_data.psm_didt_support = 0;
     145             :         }
     146             : 
     147           0 :         data->registry_data.pcie_lane_override = 0xff;
     148           0 :         data->registry_data.pcie_speed_override = 0xff;
     149           0 :         data->registry_data.pcie_clock_override = 0xffffffff;
     150           0 :         data->registry_data.regulator_hot_gpio_support = 1;
     151           0 :         data->registry_data.ac_dc_switch_gpio_support = 0;
     152           0 :         data->registry_data.quick_transition_support = 0;
     153           0 :         data->registry_data.zrpm_start_temp = 0xffff;
     154           0 :         data->registry_data.zrpm_stop_temp = 0xffff;
     155           0 :         data->registry_data.od8_feature_enable = 1;
     156           0 :         data->registry_data.disable_water_mark = 0;
     157           0 :         data->registry_data.disable_pp_tuning = 0;
     158           0 :         data->registry_data.disable_xlpp_tuning = 0;
     159           0 :         data->registry_data.disable_workload_policy = 0;
     160           0 :         data->registry_data.perf_ui_tuning_profile_turbo = 0x19190F0F;
     161           0 :         data->registry_data.perf_ui_tuning_profile_powerSave = 0x19191919;
     162           0 :         data->registry_data.perf_ui_tuning_profile_xl = 0x00000F0A;
     163           0 :         data->registry_data.force_workload_policy_mask = 0;
     164           0 :         data->registry_data.disable_3d_fs_detection = 0;
     165           0 :         data->registry_data.fps_support = 1;
     166           0 :         data->registry_data.disable_auto_wattman = 1;
     167           0 :         data->registry_data.auto_wattman_debug = 0;
     168           0 :         data->registry_data.auto_wattman_sample_period = 100;
     169           0 :         data->registry_data.fclk_gfxclk_ratio = 0;
     170           0 :         data->registry_data.auto_wattman_threshold = 50;
     171           0 :         data->registry_data.gfxoff_controlled_by_driver = 1;
     172           0 :         data->gfxoff_allowed = false;
     173           0 :         data->counter_gfxoff = 0;
     174           0 :         data->registry_data.pcie_dpm_key_disabled = !(hwmgr->feature_mask & PP_PCIE_DPM_MASK);
     175           0 : }
     176             : 
     177           0 : static int vega20_set_features_platform_caps(struct pp_hwmgr *hwmgr)
     178             : {
     179           0 :         struct vega20_hwmgr *data =
     180             :                         (struct vega20_hwmgr *)(hwmgr->backend);
     181           0 :         struct amdgpu_device *adev = hwmgr->adev;
     182             : 
     183           0 :         if (data->vddci_control == VEGA20_VOLTAGE_CONTROL_NONE)
     184           0 :                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     185             :                                 PHM_PlatformCaps_ControlVDDCI);
     186             : 
     187           0 :         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     188             :                         PHM_PlatformCaps_TablelessHardwareInterface);
     189             : 
     190           0 :         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     191             :                         PHM_PlatformCaps_BACO);
     192             : 
     193           0 :         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     194             :                         PHM_PlatformCaps_EnableSMU7ThermalManagement);
     195             : 
     196           0 :         if (adev->pg_flags & AMD_PG_SUPPORT_UVD)
     197           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     198             :                                 PHM_PlatformCaps_UVDPowerGating);
     199             : 
     200           0 :         if (adev->pg_flags & AMD_PG_SUPPORT_VCE)
     201           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     202             :                                 PHM_PlatformCaps_VCEPowerGating);
     203             : 
     204           0 :         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     205             :                         PHM_PlatformCaps_UnTabledHardwareInterface);
     206             : 
     207           0 :         if (data->registry_data.od8_feature_enable)
     208           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     209             :                                 PHM_PlatformCaps_OD8inACSupport);
     210             : 
     211           0 :         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     212             :                         PHM_PlatformCaps_ActivityReporting);
     213           0 :         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     214             :                         PHM_PlatformCaps_FanSpeedInTableIsRPM);
     215             : 
     216           0 :         if (data->registry_data.od_state_in_dc_support) {
     217           0 :                 if (data->registry_data.od8_feature_enable)
     218           0 :                         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     219             :                                         PHM_PlatformCaps_OD8inDCSupport);
     220             :         }
     221             : 
     222           0 :         if (data->registry_data.thermal_support &&
     223           0 :             data->registry_data.fuzzy_fan_control_support &&
     224           0 :             hwmgr->thermal_controller.advanceFanControlParameters.usTMax)
     225           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     226             :                                 PHM_PlatformCaps_ODFuzzyFanControlSupport);
     227             : 
     228           0 :         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     229             :                         PHM_PlatformCaps_DynamicPowerManagement);
     230           0 :         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     231             :                         PHM_PlatformCaps_SMC);
     232           0 :         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     233             :                         PHM_PlatformCaps_ThermalPolicyDelay);
     234             : 
     235           0 :         if (data->registry_data.force_dpm_high)
     236           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     237             :                                 PHM_PlatformCaps_ExclusiveModeAlwaysHigh);
     238             : 
     239           0 :         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     240             :                         PHM_PlatformCaps_DynamicUVDState);
     241             : 
     242           0 :         if (data->registry_data.sclk_throttle_low_notification)
     243           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     244             :                                 PHM_PlatformCaps_SclkThrottleLowNotification);
     245             : 
     246             :         /* power tune caps */
     247             :         /* assume disabled */
     248           0 :         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     249             :                         PHM_PlatformCaps_PowerContainment);
     250           0 :         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     251             :                         PHM_PlatformCaps_DiDtSupport);
     252           0 :         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     253             :                         PHM_PlatformCaps_SQRamping);
     254           0 :         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     255             :                         PHM_PlatformCaps_DBRamping);
     256           0 :         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     257             :                         PHM_PlatformCaps_TDRamping);
     258           0 :         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     259             :                         PHM_PlatformCaps_TCPRamping);
     260           0 :         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     261             :                         PHM_PlatformCaps_DBRRamping);
     262           0 :         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     263             :                         PHM_PlatformCaps_DiDtEDCEnable);
     264           0 :         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     265             :                         PHM_PlatformCaps_GCEDC);
     266           0 :         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     267             :                         PHM_PlatformCaps_PSM);
     268             : 
     269           0 :         if (data->registry_data.didt_support) {
     270           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     271             :                                 PHM_PlatformCaps_DiDtSupport);
     272           0 :                 if (data->registry_data.sq_ramping_support)
     273           0 :                         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     274             :                                         PHM_PlatformCaps_SQRamping);
     275           0 :                 if (data->registry_data.db_ramping_support)
     276           0 :                         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     277             :                                         PHM_PlatformCaps_DBRamping);
     278           0 :                 if (data->registry_data.td_ramping_support)
     279           0 :                         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     280             :                                         PHM_PlatformCaps_TDRamping);
     281           0 :                 if (data->registry_data.tcp_ramping_support)
     282           0 :                         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     283             :                                         PHM_PlatformCaps_TCPRamping);
     284           0 :                 if (data->registry_data.dbr_ramping_support)
     285           0 :                         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     286             :                                         PHM_PlatformCaps_DBRRamping);
     287           0 :                 if (data->registry_data.edc_didt_support)
     288           0 :                         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     289             :                                         PHM_PlatformCaps_DiDtEDCEnable);
     290           0 :                 if (data->registry_data.gc_didt_support)
     291           0 :                         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     292             :                                         PHM_PlatformCaps_GCEDC);
     293           0 :                 if (data->registry_data.psm_didt_support)
     294           0 :                         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     295             :                                         PHM_PlatformCaps_PSM);
     296             :         }
     297             : 
     298           0 :         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     299             :                         PHM_PlatformCaps_RegulatorHot);
     300             : 
     301           0 :         if (data->registry_data.ac_dc_switch_gpio_support) {
     302           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     303             :                                 PHM_PlatformCaps_AutomaticDCTransition);
     304           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     305             :                                 PHM_PlatformCaps_SMCtoPPLIBAcdcGpioScheme);
     306             :         }
     307             : 
     308           0 :         if (data->registry_data.quick_transition_support) {
     309           0 :                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     310             :                                 PHM_PlatformCaps_AutomaticDCTransition);
     311           0 :                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     312             :                                 PHM_PlatformCaps_SMCtoPPLIBAcdcGpioScheme);
     313           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     314             :                                 PHM_PlatformCaps_Falcon_QuickTransition);
     315             :         }
     316             : 
     317           0 :         if (data->lowest_uclk_reserved_for_ulv != PPVEGA20_VEGA20LOWESTUCLKRESERVEDFORULV_DFLT) {
     318           0 :                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
     319             :                                 PHM_PlatformCaps_LowestUclkReservedForUlv);
     320           0 :                 if (data->lowest_uclk_reserved_for_ulv == 1)
     321           0 :                         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     322             :                                         PHM_PlatformCaps_LowestUclkReservedForUlv);
     323             :         }
     324             : 
     325           0 :         if (data->registry_data.custom_fan_support)
     326           0 :                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
     327             :                                 PHM_PlatformCaps_CustomFanControlSupport);
     328             : 
     329           0 :         return 0;
     330             : }
     331             : 
     332           0 : static void vega20_init_dpm_defaults(struct pp_hwmgr *hwmgr)
     333             : {
     334           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
     335           0 :         struct amdgpu_device *adev = hwmgr->adev;
     336             :         uint32_t top32, bottom32;
     337             :         int i;
     338             : 
     339           0 :         data->smu_features[GNLD_DPM_PREFETCHER].smu_feature_id =
     340             :                         FEATURE_DPM_PREFETCHER_BIT;
     341           0 :         data->smu_features[GNLD_DPM_GFXCLK].smu_feature_id =
     342             :                         FEATURE_DPM_GFXCLK_BIT;
     343           0 :         data->smu_features[GNLD_DPM_UCLK].smu_feature_id =
     344             :                         FEATURE_DPM_UCLK_BIT;
     345           0 :         data->smu_features[GNLD_DPM_SOCCLK].smu_feature_id =
     346             :                         FEATURE_DPM_SOCCLK_BIT;
     347           0 :         data->smu_features[GNLD_DPM_UVD].smu_feature_id =
     348             :                         FEATURE_DPM_UVD_BIT;
     349           0 :         data->smu_features[GNLD_DPM_VCE].smu_feature_id =
     350             :                         FEATURE_DPM_VCE_BIT;
     351           0 :         data->smu_features[GNLD_ULV].smu_feature_id =
     352             :                         FEATURE_ULV_BIT;
     353           0 :         data->smu_features[GNLD_DPM_MP0CLK].smu_feature_id =
     354             :                         FEATURE_DPM_MP0CLK_BIT;
     355           0 :         data->smu_features[GNLD_DPM_LINK].smu_feature_id =
     356             :                         FEATURE_DPM_LINK_BIT;
     357           0 :         data->smu_features[GNLD_DPM_DCEFCLK].smu_feature_id =
     358             :                         FEATURE_DPM_DCEFCLK_BIT;
     359           0 :         data->smu_features[GNLD_DS_GFXCLK].smu_feature_id =
     360             :                         FEATURE_DS_GFXCLK_BIT;
     361           0 :         data->smu_features[GNLD_DS_SOCCLK].smu_feature_id =
     362             :                         FEATURE_DS_SOCCLK_BIT;
     363           0 :         data->smu_features[GNLD_DS_LCLK].smu_feature_id =
     364             :                         FEATURE_DS_LCLK_BIT;
     365           0 :         data->smu_features[GNLD_PPT].smu_feature_id =
     366             :                         FEATURE_PPT_BIT;
     367           0 :         data->smu_features[GNLD_TDC].smu_feature_id =
     368             :                         FEATURE_TDC_BIT;
     369           0 :         data->smu_features[GNLD_THERMAL].smu_feature_id =
     370             :                         FEATURE_THERMAL_BIT;
     371           0 :         data->smu_features[GNLD_GFX_PER_CU_CG].smu_feature_id =
     372             :                         FEATURE_GFX_PER_CU_CG_BIT;
     373           0 :         data->smu_features[GNLD_RM].smu_feature_id =
     374             :                         FEATURE_RM_BIT;
     375           0 :         data->smu_features[GNLD_DS_DCEFCLK].smu_feature_id =
     376             :                         FEATURE_DS_DCEFCLK_BIT;
     377           0 :         data->smu_features[GNLD_ACDC].smu_feature_id =
     378             :                         FEATURE_ACDC_BIT;
     379           0 :         data->smu_features[GNLD_VR0HOT].smu_feature_id =
     380             :                         FEATURE_VR0HOT_BIT;
     381           0 :         data->smu_features[GNLD_VR1HOT].smu_feature_id =
     382             :                         FEATURE_VR1HOT_BIT;
     383           0 :         data->smu_features[GNLD_FW_CTF].smu_feature_id =
     384             :                         FEATURE_FW_CTF_BIT;
     385           0 :         data->smu_features[GNLD_LED_DISPLAY].smu_feature_id =
     386             :                         FEATURE_LED_DISPLAY_BIT;
     387           0 :         data->smu_features[GNLD_FAN_CONTROL].smu_feature_id =
     388             :                         FEATURE_FAN_CONTROL_BIT;
     389           0 :         data->smu_features[GNLD_DIDT].smu_feature_id = FEATURE_GFX_EDC_BIT;
     390           0 :         data->smu_features[GNLD_GFXOFF].smu_feature_id = FEATURE_GFXOFF_BIT;
     391           0 :         data->smu_features[GNLD_CG].smu_feature_id = FEATURE_CG_BIT;
     392           0 :         data->smu_features[GNLD_DPM_FCLK].smu_feature_id = FEATURE_DPM_FCLK_BIT;
     393           0 :         data->smu_features[GNLD_DS_FCLK].smu_feature_id = FEATURE_DS_FCLK_BIT;
     394           0 :         data->smu_features[GNLD_DS_MP1CLK].smu_feature_id = FEATURE_DS_MP1CLK_BIT;
     395           0 :         data->smu_features[GNLD_DS_MP0CLK].smu_feature_id = FEATURE_DS_MP0CLK_BIT;
     396           0 :         data->smu_features[GNLD_XGMI].smu_feature_id = FEATURE_XGMI_BIT;
     397           0 :         data->smu_features[GNLD_ECC].smu_feature_id = FEATURE_ECC_BIT;
     398             : 
     399           0 :         for (i = 0; i < GNLD_FEATURES_MAX; i++) {
     400           0 :                 data->smu_features[i].smu_feature_bitmap =
     401           0 :                         (uint64_t)(1ULL << data->smu_features[i].smu_feature_id);
     402           0 :                 data->smu_features[i].allowed =
     403           0 :                         ((data->registry_data.disallowed_features >> i) & 1) ?
     404           0 :                         false : true;
     405             :         }
     406             : 
     407             :         /* Get the SN to turn into a Unique ID */
     408           0 :         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumTop32, &top32);
     409           0 :         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumBottom32, &bottom32);
     410             : 
     411           0 :         adev->unique_id = ((uint64_t)bottom32 << 32) | top32;
     412           0 : }
     413             : 
     414             : static int vega20_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
     415             : {
     416             :         return 0;
     417             : }
     418             : 
     419           0 : static int vega20_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
     420             : {
     421           0 :         kfree(hwmgr->backend);
     422           0 :         hwmgr->backend = NULL;
     423             : 
     424           0 :         return 0;
     425             : }
     426             : 
     427           0 : static int vega20_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
     428             : {
     429             :         struct vega20_hwmgr *data;
     430           0 :         struct amdgpu_device *adev = hwmgr->adev;
     431             : 
     432           0 :         data = kzalloc(sizeof(struct vega20_hwmgr), GFP_KERNEL);
     433           0 :         if (data == NULL)
     434             :                 return -ENOMEM;
     435             : 
     436           0 :         hwmgr->backend = data;
     437             : 
     438           0 :         hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
     439           0 :         hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
     440           0 :         hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
     441             : 
     442           0 :         vega20_set_default_registry_data(hwmgr);
     443             : 
     444           0 :         data->disable_dpm_mask = 0xff;
     445             : 
     446             :         /* need to set voltage control types before EVV patching */
     447           0 :         data->vddc_control = VEGA20_VOLTAGE_CONTROL_NONE;
     448           0 :         data->mvdd_control = VEGA20_VOLTAGE_CONTROL_NONE;
     449           0 :         data->vddci_control = VEGA20_VOLTAGE_CONTROL_NONE;
     450             : 
     451           0 :         data->water_marks_bitmap = 0;
     452           0 :         data->avfs_exist = false;
     453             : 
     454           0 :         vega20_set_features_platform_caps(hwmgr);
     455             : 
     456           0 :         vega20_init_dpm_defaults(hwmgr);
     457             : 
     458             :         /* Parse pptable data read from VBIOS */
     459           0 :         vega20_set_private_data_based_on_pptable(hwmgr);
     460             : 
     461           0 :         data->is_tlu_enabled = false;
     462             : 
     463           0 :         hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
     464             :                         VEGA20_MAX_HARDWARE_POWERLEVELS;
     465           0 :         hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
     466           0 :         hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50;
     467             : 
     468           0 :         hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */
     469             :         /* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */
     470           0 :         hwmgr->platform_descriptor.clockStep.engineClock = 500;
     471           0 :         hwmgr->platform_descriptor.clockStep.memoryClock = 500;
     472             : 
     473           0 :         data->total_active_cus = adev->gfx.cu_info.number;
     474           0 :         data->is_custom_profile_set = false;
     475             : 
     476           0 :         return 0;
     477             : }
     478             : 
     479             : static int vega20_init_sclk_threshold(struct pp_hwmgr *hwmgr)
     480             : {
     481           0 :         struct vega20_hwmgr *data =
     482             :                         (struct vega20_hwmgr *)(hwmgr->backend);
     483             : 
     484           0 :         data->low_sclk_interrupt_threshold = 0;
     485             : 
     486             :         return 0;
     487             : }
     488             : 
     489           0 : static int vega20_setup_asic_task(struct pp_hwmgr *hwmgr)
     490             : {
     491           0 :         struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
     492           0 :         int ret = 0;
     493           0 :         bool use_baco = (amdgpu_in_reset(adev) &&
     494           0 :                          (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO)) ||
     495           0 :                 (adev->in_runpm && amdgpu_asic_supports_baco(adev));
     496             : 
     497           0 :         ret = vega20_init_sclk_threshold(hwmgr);
     498             :         PP_ASSERT_WITH_CODE(!ret,
     499             :                         "Failed to init sclk threshold!",
     500             :                         return ret);
     501             : 
     502           0 :         if (use_baco) {
     503           0 :                 ret = vega20_baco_apply_vdci_flush_workaround(hwmgr);
     504           0 :                 if (ret)
     505           0 :                         pr_err("Failed to apply vega20 baco workaround!\n");
     506             :         }
     507             : 
     508             :         return ret;
     509             : }
     510             : 
     511             : /*
     512             :  * @fn vega20_init_dpm_state
     513             :  * @brief Function to initialize all Soft Min/Max and Hard Min/Max to 0xff.
     514             :  *
     515             :  * @param    dpm_state - the address of the DPM Table to initiailize.
     516             :  * @return   None.
     517             :  */
     518             : static void vega20_init_dpm_state(struct vega20_dpm_state *dpm_state)
     519             : {
     520           0 :         dpm_state->soft_min_level = 0x0;
     521           0 :         dpm_state->soft_max_level = VG20_CLOCK_MAX_DEFAULT;
     522           0 :         dpm_state->hard_min_level = 0x0;
     523           0 :         dpm_state->hard_max_level = VG20_CLOCK_MAX_DEFAULT;
     524             : }
     525             : 
     526           0 : static int vega20_get_number_of_dpm_level(struct pp_hwmgr *hwmgr,
     527             :                 PPCLK_e clk_id, uint32_t *num_of_levels)
     528             : {
     529           0 :         int ret = 0;
     530             : 
     531           0 :         ret = smum_send_msg_to_smc_with_parameter(hwmgr,
     532             :                         PPSMC_MSG_GetDpmFreqByIndex,
     533           0 :                         (clk_id << 16 | 0xFF),
     534             :                         num_of_levels);
     535           0 :         PP_ASSERT_WITH_CODE(!ret,
     536             :                         "[GetNumOfDpmLevel] failed to get dpm levels!",
     537             :                         return ret);
     538             : 
     539             :         return ret;
     540             : }
     541             : 
     542           0 : static int vega20_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr,
     543             :                 PPCLK_e clk_id, uint32_t index, uint32_t *clk)
     544             : {
     545           0 :         int ret = 0;
     546             : 
     547           0 :         ret = smum_send_msg_to_smc_with_parameter(hwmgr,
     548             :                         PPSMC_MSG_GetDpmFreqByIndex,
     549           0 :                         (clk_id << 16 | index),
     550             :                         clk);
     551           0 :         PP_ASSERT_WITH_CODE(!ret,
     552             :                         "[GetDpmFreqByIndex] failed to get dpm freq by index!",
     553             :                         return ret);
     554             : 
     555             :         return ret;
     556             : }
     557             : 
     558           0 : static int vega20_setup_single_dpm_table(struct pp_hwmgr *hwmgr,
     559             :                 struct vega20_single_dpm_table *dpm_table, PPCLK_e clk_id)
     560             : {
     561           0 :         int ret = 0;
     562             :         uint32_t i, num_of_levels, clk;
     563             : 
     564           0 :         ret = vega20_get_number_of_dpm_level(hwmgr, clk_id, &num_of_levels);
     565           0 :         PP_ASSERT_WITH_CODE(!ret,
     566             :                         "[SetupSingleDpmTable] failed to get clk levels!",
     567             :                         return ret);
     568             : 
     569           0 :         dpm_table->count = num_of_levels;
     570             : 
     571           0 :         for (i = 0; i < num_of_levels; i++) {
     572           0 :                 ret = vega20_get_dpm_frequency_by_index(hwmgr, clk_id, i, &clk);
     573           0 :                 PP_ASSERT_WITH_CODE(!ret,
     574             :                         "[SetupSingleDpmTable] failed to get clk of specific level!",
     575             :                         return ret);
     576           0 :                 dpm_table->dpm_levels[i].value = clk;
     577           0 :                 dpm_table->dpm_levels[i].enabled = true;
     578             :         }
     579             : 
     580             :         return ret;
     581             : }
     582             : 
     583           0 : static int vega20_setup_gfxclk_dpm_table(struct pp_hwmgr *hwmgr)
     584             : {
     585           0 :         struct vega20_hwmgr *data =
     586             :                         (struct vega20_hwmgr *)(hwmgr->backend);
     587             :         struct vega20_single_dpm_table *dpm_table;
     588           0 :         int ret = 0;
     589             : 
     590           0 :         dpm_table = &(data->dpm_table.gfx_table);
     591           0 :         if (data->smu_features[GNLD_DPM_GFXCLK].enabled) {
     592           0 :                 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_GFXCLK);
     593           0 :                 PP_ASSERT_WITH_CODE(!ret,
     594             :                                 "[SetupDefaultDpmTable] failed to get gfxclk dpm levels!",
     595             :                                 return ret);
     596             :         } else {
     597           0 :                 dpm_table->count = 1;
     598           0 :                 dpm_table->dpm_levels[0].value = data->vbios_boot_state.gfx_clock / 100;
     599             :         }
     600             : 
     601             :         return ret;
     602             : }
     603             : 
     604           0 : static int vega20_setup_memclk_dpm_table(struct pp_hwmgr *hwmgr)
     605             : {
     606           0 :         struct vega20_hwmgr *data =
     607             :                         (struct vega20_hwmgr *)(hwmgr->backend);
     608             :         struct vega20_single_dpm_table *dpm_table;
     609           0 :         int ret = 0;
     610             : 
     611           0 :         dpm_table = &(data->dpm_table.mem_table);
     612           0 :         if (data->smu_features[GNLD_DPM_UCLK].enabled) {
     613           0 :                 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_UCLK);
     614           0 :                 PP_ASSERT_WITH_CODE(!ret,
     615             :                                 "[SetupDefaultDpmTable] failed to get memclk dpm levels!",
     616             :                                 return ret);
     617             :         } else {
     618           0 :                 dpm_table->count = 1;
     619           0 :                 dpm_table->dpm_levels[0].value = data->vbios_boot_state.mem_clock / 100;
     620             :         }
     621             : 
     622             :         return ret;
     623             : }
     624             : 
     625             : /*
     626             :  * This function is to initialize all DPM state tables
     627             :  * for SMU based on the dependency table.
     628             :  * Dynamic state patching function will then trim these
     629             :  * state tables to the allowed range based
     630             :  * on the power policy or external client requests,
     631             :  * such as UVD request, etc.
     632             :  */
     633           0 : static int vega20_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
     634             : {
     635           0 :         struct vega20_hwmgr *data =
     636             :                         (struct vega20_hwmgr *)(hwmgr->backend);
     637             :         struct vega20_single_dpm_table *dpm_table;
     638           0 :         int ret = 0;
     639             : 
     640           0 :         memset(&data->dpm_table, 0, sizeof(data->dpm_table));
     641             : 
     642             :         /* socclk */
     643           0 :         dpm_table = &(data->dpm_table.soc_table);
     644           0 :         if (data->smu_features[GNLD_DPM_SOCCLK].enabled) {
     645           0 :                 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_SOCCLK);
     646           0 :                 PP_ASSERT_WITH_CODE(!ret,
     647             :                                 "[SetupDefaultDpmTable] failed to get socclk dpm levels!",
     648             :                                 return ret);
     649             :         } else {
     650           0 :                 dpm_table->count = 1;
     651           0 :                 dpm_table->dpm_levels[0].value = data->vbios_boot_state.soc_clock / 100;
     652             :         }
     653           0 :         vega20_init_dpm_state(&(dpm_table->dpm_state));
     654             : 
     655             :         /* gfxclk */
     656           0 :         dpm_table = &(data->dpm_table.gfx_table);
     657           0 :         ret = vega20_setup_gfxclk_dpm_table(hwmgr);
     658           0 :         if (ret)
     659             :                 return ret;
     660           0 :         vega20_init_dpm_state(&(dpm_table->dpm_state));
     661             : 
     662             :         /* memclk */
     663           0 :         dpm_table = &(data->dpm_table.mem_table);
     664           0 :         ret = vega20_setup_memclk_dpm_table(hwmgr);
     665           0 :         if (ret)
     666             :                 return ret;
     667           0 :         vega20_init_dpm_state(&(dpm_table->dpm_state));
     668             : 
     669             :         /* eclk */
     670           0 :         dpm_table = &(data->dpm_table.eclk_table);
     671           0 :         if (data->smu_features[GNLD_DPM_VCE].enabled) {
     672           0 :                 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_ECLK);
     673           0 :                 PP_ASSERT_WITH_CODE(!ret,
     674             :                                 "[SetupDefaultDpmTable] failed to get eclk dpm levels!",
     675             :                                 return ret);
     676             :         } else {
     677           0 :                 dpm_table->count = 1;
     678           0 :                 dpm_table->dpm_levels[0].value = data->vbios_boot_state.eclock / 100;
     679             :         }
     680           0 :         vega20_init_dpm_state(&(dpm_table->dpm_state));
     681             : 
     682             :         /* vclk */
     683           0 :         dpm_table = &(data->dpm_table.vclk_table);
     684           0 :         if (data->smu_features[GNLD_DPM_UVD].enabled) {
     685           0 :                 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_VCLK);
     686           0 :                 PP_ASSERT_WITH_CODE(!ret,
     687             :                                 "[SetupDefaultDpmTable] failed to get vclk dpm levels!",
     688             :                                 return ret);
     689             :         } else {
     690           0 :                 dpm_table->count = 1;
     691           0 :                 dpm_table->dpm_levels[0].value = data->vbios_boot_state.vclock / 100;
     692             :         }
     693           0 :         vega20_init_dpm_state(&(dpm_table->dpm_state));
     694             : 
     695             :         /* dclk */
     696           0 :         dpm_table = &(data->dpm_table.dclk_table);
     697           0 :         if (data->smu_features[GNLD_DPM_UVD].enabled) {
     698           0 :                 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DCLK);
     699           0 :                 PP_ASSERT_WITH_CODE(!ret,
     700             :                                 "[SetupDefaultDpmTable] failed to get dclk dpm levels!",
     701             :                                 return ret);
     702             :         } else {
     703           0 :                 dpm_table->count = 1;
     704           0 :                 dpm_table->dpm_levels[0].value = data->vbios_boot_state.dclock / 100;
     705             :         }
     706           0 :         vega20_init_dpm_state(&(dpm_table->dpm_state));
     707             : 
     708             :         /* dcefclk */
     709           0 :         dpm_table = &(data->dpm_table.dcef_table);
     710           0 :         if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
     711           0 :                 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DCEFCLK);
     712           0 :                 PP_ASSERT_WITH_CODE(!ret,
     713             :                                 "[SetupDefaultDpmTable] failed to get dcefclk dpm levels!",
     714             :                                 return ret);
     715             :         } else {
     716           0 :                 dpm_table->count = 1;
     717           0 :                 dpm_table->dpm_levels[0].value = data->vbios_boot_state.dcef_clock / 100;
     718             :         }
     719           0 :         vega20_init_dpm_state(&(dpm_table->dpm_state));
     720             : 
     721             :         /* pixclk */
     722           0 :         dpm_table = &(data->dpm_table.pixel_table);
     723           0 :         if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
     724           0 :                 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_PIXCLK);
     725           0 :                 PP_ASSERT_WITH_CODE(!ret,
     726             :                                 "[SetupDefaultDpmTable] failed to get pixclk dpm levels!",
     727             :                                 return ret);
     728             :         } else
     729           0 :                 dpm_table->count = 0;
     730           0 :         vega20_init_dpm_state(&(dpm_table->dpm_state));
     731             : 
     732             :         /* dispclk */
     733           0 :         dpm_table = &(data->dpm_table.display_table);
     734           0 :         if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
     735           0 :                 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DISPCLK);
     736           0 :                 PP_ASSERT_WITH_CODE(!ret,
     737             :                                 "[SetupDefaultDpmTable] failed to get dispclk dpm levels!",
     738             :                                 return ret);
     739             :         } else
     740           0 :                 dpm_table->count = 0;
     741           0 :         vega20_init_dpm_state(&(dpm_table->dpm_state));
     742             : 
     743             :         /* phyclk */
     744           0 :         dpm_table = &(data->dpm_table.phy_table);
     745           0 :         if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
     746           0 :                 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_PHYCLK);
     747           0 :                 PP_ASSERT_WITH_CODE(!ret,
     748             :                                 "[SetupDefaultDpmTable] failed to get phyclk dpm levels!",
     749             :                                 return ret);
     750             :         } else
     751           0 :                 dpm_table->count = 0;
     752           0 :         vega20_init_dpm_state(&(dpm_table->dpm_state));
     753             : 
     754             :         /* fclk */
     755           0 :         dpm_table = &(data->dpm_table.fclk_table);
     756           0 :         if (data->smu_features[GNLD_DPM_FCLK].enabled) {
     757           0 :                 ret = vega20_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_FCLK);
     758           0 :                 PP_ASSERT_WITH_CODE(!ret,
     759             :                                 "[SetupDefaultDpmTable] failed to get fclk dpm levels!",
     760             :                                 return ret);
     761             :         } else {
     762           0 :                 dpm_table->count = 1;
     763           0 :                 dpm_table->dpm_levels[0].value = data->vbios_boot_state.fclock / 100;
     764             :         }
     765           0 :         vega20_init_dpm_state(&(dpm_table->dpm_state));
     766             : 
     767             :         /* save a copy of the default DPM table */
     768           0 :         memcpy(&(data->golden_dpm_table), &(data->dpm_table),
     769             :                         sizeof(struct vega20_dpm_table));
     770             : 
     771           0 :         return 0;
     772             : }
     773             : 
     774             : /**
     775             :  * vega20_init_smc_table - Initializes the SMC table and uploads it
     776             :  *
     777             :  * @hwmgr:  the address of the powerplay hardware manager.
     778             :  * return:  always 0
     779             :  */
     780           0 : static int vega20_init_smc_table(struct pp_hwmgr *hwmgr)
     781             : {
     782             :         int result;
     783           0 :         struct vega20_hwmgr *data =
     784             :                         (struct vega20_hwmgr *)(hwmgr->backend);
     785           0 :         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
     786             :         struct pp_atomfwctrl_bios_boot_up_values boot_up_values;
     787           0 :         struct phm_ppt_v3_information *pptable_information =
     788             :                 (struct phm_ppt_v3_information *)hwmgr->pptable;
     789             : 
     790           0 :         result = pp_atomfwctrl_get_vbios_bootup_values(hwmgr, &boot_up_values);
     791           0 :         PP_ASSERT_WITH_CODE(!result,
     792             :                         "[InitSMCTable] Failed to get vbios bootup values!",
     793             :                         return result);
     794             : 
     795           0 :         data->vbios_boot_state.vddc     = boot_up_values.usVddc;
     796           0 :         data->vbios_boot_state.vddci    = boot_up_values.usVddci;
     797           0 :         data->vbios_boot_state.mvddc    = boot_up_values.usMvddc;
     798           0 :         data->vbios_boot_state.gfx_clock = boot_up_values.ulGfxClk;
     799           0 :         data->vbios_boot_state.mem_clock = boot_up_values.ulUClk;
     800           0 :         data->vbios_boot_state.soc_clock = boot_up_values.ulSocClk;
     801           0 :         data->vbios_boot_state.dcef_clock = boot_up_values.ulDCEFClk;
     802           0 :         data->vbios_boot_state.eclock = boot_up_values.ulEClk;
     803           0 :         data->vbios_boot_state.vclock = boot_up_values.ulVClk;
     804           0 :         data->vbios_boot_state.dclock = boot_up_values.ulDClk;
     805           0 :         data->vbios_boot_state.fclock = boot_up_values.ulFClk;
     806           0 :         data->vbios_boot_state.uc_cooling_id = boot_up_values.ucCoolingID;
     807             : 
     808           0 :         smum_send_msg_to_smc_with_parameter(hwmgr,
     809             :                         PPSMC_MSG_SetMinDeepSleepDcefclk,
     810           0 :                 (uint32_t)(data->vbios_boot_state.dcef_clock / 100),
     811             :                         NULL);
     812             : 
     813           0 :         memcpy(pp_table, pptable_information->smc_pptable, sizeof(PPTable_t));
     814             : 
     815           0 :         result = smum_smc_table_manager(hwmgr,
     816             :                                         (uint8_t *)pp_table, TABLE_PPTABLE, false);
     817           0 :         PP_ASSERT_WITH_CODE(!result,
     818             :                         "[InitSMCTable] Failed to upload PPtable!",
     819             :                         return result);
     820             : 
     821             :         return 0;
     822             : }
     823             : 
     824             : /*
     825             :  * Override PCIe link speed and link width for DPM Level 1. PPTable entries
     826             :  * reflect the ASIC capabilities and not the system capabilities. For e.g.
     827             :  * Vega20 board in a PCI Gen3 system. In this case, when SMU's tries to switch
     828             :  * to DPM1, it fails as system doesn't support Gen4.
     829             :  */
     830           0 : static int vega20_override_pcie_parameters(struct pp_hwmgr *hwmgr)
     831             : {
     832           0 :         struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
     833           0 :         struct vega20_hwmgr *data =
     834             :                         (struct vega20_hwmgr *)(hwmgr->backend);
     835           0 :         uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg, pcie_gen_arg, pcie_width_arg;
     836           0 :         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
     837             :         int i;
     838             :         int ret;
     839             : 
     840           0 :         if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
     841             :                 pcie_gen = 3;
     842           0 :         else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
     843             :                 pcie_gen = 2;
     844           0 :         else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
     845             :                 pcie_gen = 1;
     846             :         else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1)
     847             :                 pcie_gen = 0;
     848             : 
     849           0 :         if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16)
     850             :                 pcie_width = 6;
     851           0 :         else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12)
     852             :                 pcie_width = 5;
     853           0 :         else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8)
     854             :                 pcie_width = 4;
     855           0 :         else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4)
     856             :                 pcie_width = 3;
     857           0 :         else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2)
     858             :                 pcie_width = 2;
     859           0 :         else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1)
     860           0 :                 pcie_width = 1;
     861             : 
     862             :         /* Bit 31:16: LCLK DPM level. 0 is DPM0, and 1 is DPM1
     863             :          * Bit 15:8:  PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4
     864             :          * Bit 7:0:   PCIE lane width, 1 to 7 corresponds is x1 to x32
     865             :          */
     866           0 :         for (i = 0; i < NUM_LINK_LEVELS; i++) {
     867           0 :                 pcie_gen_arg = (pp_table->PcieGenSpeed[i] > pcie_gen) ? pcie_gen :
     868           0 :                         pp_table->PcieGenSpeed[i];
     869           0 :                 pcie_width_arg = (pp_table->PcieLaneCount[i] > pcie_width) ? pcie_width :
     870           0 :                         pp_table->PcieLaneCount[i];
     871             : 
     872           0 :                 if (pcie_gen_arg != pp_table->PcieGenSpeed[i] || pcie_width_arg !=
     873             :                     pp_table->PcieLaneCount[i]) {
     874           0 :                         smu_pcie_arg = (i << 16) | (pcie_gen_arg << 8) | pcie_width_arg;
     875           0 :                         ret = smum_send_msg_to_smc_with_parameter(hwmgr,
     876             :                                 PPSMC_MSG_OverridePcieParameters, smu_pcie_arg,
     877             :                                 NULL);
     878           0 :                         PP_ASSERT_WITH_CODE(!ret,
     879             :                                 "[OverridePcieParameters] Attempt to override pcie params failed!",
     880             :                                 return ret);
     881             :                 }
     882             : 
     883             :                 /* update the pptable */
     884           0 :                 pp_table->PcieGenSpeed[i] = pcie_gen_arg;
     885           0 :                 pp_table->PcieLaneCount[i] = pcie_width_arg;
     886             :         }
     887             : 
     888             :         /* override to the highest if it's disabled from ppfeaturmask */
     889           0 :         if (data->registry_data.pcie_dpm_key_disabled) {
     890           0 :                 for (i = 0; i < NUM_LINK_LEVELS; i++) {
     891           0 :                         smu_pcie_arg = (i << 16) | (pcie_gen << 8) | pcie_width;
     892           0 :                         ret = smum_send_msg_to_smc_with_parameter(hwmgr,
     893             :                                 PPSMC_MSG_OverridePcieParameters, smu_pcie_arg,
     894             :                                 NULL);
     895           0 :                         PP_ASSERT_WITH_CODE(!ret,
     896             :                                 "[OverridePcieParameters] Attempt to override pcie params failed!",
     897             :                                 return ret);
     898             : 
     899           0 :                         pp_table->PcieGenSpeed[i] = pcie_gen;
     900           0 :                         pp_table->PcieLaneCount[i] = pcie_width;
     901             :                 }
     902           0 :                 ret = vega20_enable_smc_features(hwmgr,
     903             :                                 false,
     904             :                                 data->smu_features[GNLD_DPM_LINK].smu_feature_bitmap);
     905           0 :                 PP_ASSERT_WITH_CODE(!ret,
     906             :                                 "Attempt to Disable DPM LINK Failed!",
     907             :                                 return ret);
     908           0 :                 data->smu_features[GNLD_DPM_LINK].enabled = false;
     909           0 :                 data->smu_features[GNLD_DPM_LINK].supported = false;
     910             :         }
     911             : 
     912             :         return 0;
     913             : }
     914             : 
     915           0 : static int vega20_set_allowed_featuresmask(struct pp_hwmgr *hwmgr)
     916             : {
     917           0 :         struct vega20_hwmgr *data =
     918             :                         (struct vega20_hwmgr *)(hwmgr->backend);
     919           0 :         uint32_t allowed_features_low = 0, allowed_features_high = 0;
     920             :         int i;
     921           0 :         int ret = 0;
     922             : 
     923           0 :         for (i = 0; i < GNLD_FEATURES_MAX; i++)
     924           0 :                 if (data->smu_features[i].allowed)
     925           0 :                         data->smu_features[i].smu_feature_id > 31 ?
     926           0 :                                 (allowed_features_high |=
     927           0 :                                  ((data->smu_features[i].smu_feature_bitmap >> SMU_FEATURES_HIGH_SHIFT)
     928           0 :                                   & 0xFFFFFFFF)) :
     929           0 :                                 (allowed_features_low |=
     930           0 :                                  ((data->smu_features[i].smu_feature_bitmap >> SMU_FEATURES_LOW_SHIFT)
     931             :                                   & 0xFFFFFFFF));
     932             : 
     933           0 :         ret = smum_send_msg_to_smc_with_parameter(hwmgr,
     934             :                 PPSMC_MSG_SetAllowedFeaturesMaskHigh, allowed_features_high, NULL);
     935           0 :         PP_ASSERT_WITH_CODE(!ret,
     936             :                 "[SetAllowedFeaturesMask] Attempt to set allowed features mask(high) failed!",
     937             :                 return ret);
     938             : 
     939           0 :         ret = smum_send_msg_to_smc_with_parameter(hwmgr,
     940             :                 PPSMC_MSG_SetAllowedFeaturesMaskLow, allowed_features_low, NULL);
     941           0 :         PP_ASSERT_WITH_CODE(!ret,
     942             :                 "[SetAllowedFeaturesMask] Attempt to set allowed features mask (low) failed!",
     943             :                 return ret);
     944             : 
     945             :         return 0;
     946             : }
     947             : 
     948             : static int vega20_run_btc(struct pp_hwmgr *hwmgr)
     949             : {
     950           0 :         return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunBtc, NULL);
     951             : }
     952             : 
     953             : static int vega20_run_btc_afll(struct pp_hwmgr *hwmgr)
     954             : {
     955           0 :         return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunAfllBtc, NULL);
     956             : }
     957             : 
     958           0 : static int vega20_enable_all_smu_features(struct pp_hwmgr *hwmgr)
     959             : {
     960           0 :         struct vega20_hwmgr *data =
     961             :                         (struct vega20_hwmgr *)(hwmgr->backend);
     962             :         uint64_t features_enabled;
     963             :         int i;
     964             :         bool enabled;
     965           0 :         int ret = 0;
     966             : 
     967           0 :         PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr,
     968             :                         PPSMC_MSG_EnableAllSmuFeatures,
     969             :                         NULL)) == 0,
     970             :                         "[EnableAllSMUFeatures] Failed to enable all smu features!",
     971             :                         return ret);
     972             : 
     973           0 :         ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
     974           0 :         PP_ASSERT_WITH_CODE(!ret,
     975             :                         "[EnableAllSmuFeatures] Failed to get enabled smc features!",
     976             :                         return ret);
     977             : 
     978           0 :         for (i = 0; i < GNLD_FEATURES_MAX; i++) {
     979           0 :                 enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ?
     980             :                         true : false;
     981           0 :                 data->smu_features[i].enabled = enabled;
     982           0 :                 data->smu_features[i].supported = enabled;
     983             : 
     984             : #if 0
     985             :                 if (data->smu_features[i].allowed && !enabled)
     986             :                         pr_info("[EnableAllSMUFeatures] feature %d is expected enabled!", i);
     987             :                 else if (!data->smu_features[i].allowed && enabled)
     988             :                         pr_info("[EnableAllSMUFeatures] feature %d is expected disabled!", i);
     989             : #endif
     990             :         }
     991             : 
     992             :         return 0;
     993             : }
     994             : 
     995             : static int vega20_notify_smc_display_change(struct pp_hwmgr *hwmgr)
     996             : {
     997           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
     998             : 
     999           0 :         if (data->smu_features[GNLD_DPM_UCLK].enabled)
    1000           0 :                 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           0 :         struct vega20_hwmgr *data =
    1011             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    1012             : 
    1013           0 :         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           0 : static int vega20_disable_all_smu_features(struct pp_hwmgr *hwmgr)
    1020             : {
    1021           0 :         struct vega20_hwmgr *data =
    1022             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    1023           0 :         int i, ret = 0;
    1024             : 
    1025           0 :         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           0 :         for (i = 0; i < GNLD_FEATURES_MAX; i++)
    1032           0 :                 data->smu_features[i].enabled = 0;
    1033             : 
    1034             :         return 0;
    1035             : }
    1036             : 
    1037           0 : static int vega20_od8_set_feature_capabilities(
    1038             :                 struct pp_hwmgr *hwmgr)
    1039             : {
    1040           0 :         struct phm_ppt_v3_information *pptable_information =
    1041             :                 (struct phm_ppt_v3_information *)hwmgr->pptable;
    1042           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    1043           0 :         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
    1044           0 :         struct vega20_od8_settings *od_settings = &(data->od8_settings);
    1045             : 
    1046           0 :         od_settings->overdrive8_capabilities = 0;
    1047             : 
    1048           0 :         if (data->smu_features[GNLD_DPM_GFXCLK].enabled) {
    1049           0 :                 if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_LIMITS] &&
    1050           0 :                     pptable_information->od_settings_max[OD8_SETTING_GFXCLK_FMAX] > 0 &&
    1051           0 :                     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           0 :                         od_settings->overdrive8_capabilities |= OD8_GFXCLK_LIMITS;
    1055             : 
    1056           0 :                 if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_CURVE] &&
    1057           0 :                     (pptable_information->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] >=
    1058           0 :                      pp_table->MinVoltageGfx / VOLTAGE_SCALE) &&
    1059           0 :                     (pptable_information->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3] <=
    1060           0 :                      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           0 :                         od_settings->overdrive8_capabilities |= OD8_GFXCLK_CURVE;
    1064             :         }
    1065             : 
    1066           0 :         if (data->smu_features[GNLD_DPM_UCLK].enabled) {
    1067           0 :                 pptable_information->od_settings_min[OD8_SETTING_UCLK_FMAX] =
    1068           0 :                         data->dpm_table.mem_table.dpm_levels[data->dpm_table.mem_table.count - 2].value;
    1069           0 :                 if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_UCLK_MAX] &&
    1070           0 :                     pptable_information->od_settings_min[OD8_SETTING_UCLK_FMAX] > 0 &&
    1071           0 :                     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           0 :                         od_settings->overdrive8_capabilities |= OD8_UCLK_MAX;
    1075             :         }
    1076             : 
    1077           0 :         if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_POWER_LIMIT] &&
    1078           0 :             pptable_information->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
    1079           0 :             pptable_information->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] <= 100 &&
    1080           0 :             pptable_information->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
    1081             :             pptable_information->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] <= 100)
    1082           0 :                 od_settings->overdrive8_capabilities |= OD8_POWER_LIMIT;
    1083             : 
    1084           0 :         if (data->smu_features[GNLD_FAN_CONTROL].enabled) {
    1085           0 :                 if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_ACOUSTIC_LIMIT] &&
    1086           0 :                     pptable_information->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 &&
    1087           0 :                     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           0 :                         od_settings->overdrive8_capabilities |= OD8_ACOUSTIC_LIMIT_SCLK;
    1091             : 
    1092           0 :                 if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_SPEED_MIN] &&
    1093           0 :                     (pptable_information->od_settings_min[OD8_SETTING_FAN_MIN_SPEED] >=
    1094           0 :                     (pp_table->FanPwmMin * pp_table->FanMaximumRpm / 100)) &&
    1095           0 :                     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           0 :                         od_settings->overdrive8_capabilities |= OD8_FAN_SPEED_MIN;
    1099             :         }
    1100             : 
    1101           0 :         if (data->smu_features[GNLD_THERMAL].enabled) {
    1102           0 :                 if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_FAN] &&
    1103           0 :                     pptable_information->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] > 0 &&
    1104           0 :                     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           0 :                         od_settings->overdrive8_capabilities |= OD8_TEMPERATURE_FAN;
    1108             : 
    1109           0 :                 if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_SYSTEM] &&
    1110           0 :                     pptable_information->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] > 0 &&
    1111           0 :                     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           0 :                         od_settings->overdrive8_capabilities |= OD8_TEMPERATURE_SYSTEM;
    1115             :         }
    1116             : 
    1117           0 :         if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_MEMORY_TIMING_TUNE])
    1118           0 :                 od_settings->overdrive8_capabilities |= OD8_MEMORY_TIMING_TUNE;
    1119             : 
    1120           0 :         if (pptable_information->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_ZERO_RPM_CONTROL] &&
    1121           0 :             pp_table->FanZeroRpmEnable)
    1122           0 :                 od_settings->overdrive8_capabilities |= OD8_FAN_ZERO_RPM_CONTROL;
    1123             : 
    1124           0 :         if (!od_settings->overdrive8_capabilities)
    1125           0 :                 hwmgr->od_enabled = false;
    1126             : 
    1127           0 :         return 0;
    1128             : }
    1129             : 
    1130           0 : static int vega20_od8_set_feature_id(
    1131             :                 struct pp_hwmgr *hwmgr)
    1132             : {
    1133           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    1134           0 :         struct vega20_od8_settings *od_settings = &(data->od8_settings);
    1135             : 
    1136           0 :         if (od_settings->overdrive8_capabilities & OD8_GFXCLK_LIMITS) {
    1137           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id =
    1138             :                         OD8_GFXCLK_LIMITS;
    1139           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id =
    1140             :                         OD8_GFXCLK_LIMITS;
    1141             :         } else {
    1142           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id =
    1143             :                         0;
    1144           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id =
    1145             :                         0;
    1146             :         }
    1147             : 
    1148           0 :         if (od_settings->overdrive8_capabilities & OD8_GFXCLK_CURVE) {
    1149           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id =
    1150             :                         OD8_GFXCLK_CURVE;
    1151           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id =
    1152             :                         OD8_GFXCLK_CURVE;
    1153           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id =
    1154             :                         OD8_GFXCLK_CURVE;
    1155           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id =
    1156             :                         OD8_GFXCLK_CURVE;
    1157           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id =
    1158             :                         OD8_GFXCLK_CURVE;
    1159           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id =
    1160             :                         OD8_GFXCLK_CURVE;
    1161             :         } else {
    1162           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id =
    1163             :                         0;
    1164           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id =
    1165             :                         0;
    1166           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id =
    1167             :                         0;
    1168           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id =
    1169             :                         0;
    1170           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id =
    1171             :                         0;
    1172           0 :                 od_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id =
    1173             :                         0;
    1174             :         }
    1175             : 
    1176           0 :         if (od_settings->overdrive8_capabilities & OD8_UCLK_MAX)
    1177           0 :                 od_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id = OD8_UCLK_MAX;
    1178             :         else
    1179           0 :                 od_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id = 0;
    1180             : 
    1181           0 :         if (od_settings->overdrive8_capabilities & OD8_POWER_LIMIT)
    1182           0 :                 od_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id = OD8_POWER_LIMIT;
    1183             :         else
    1184           0 :                 od_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id = 0;
    1185             : 
    1186           0 :         if (od_settings->overdrive8_capabilities & OD8_ACOUSTIC_LIMIT_SCLK)
    1187           0 :                 od_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id =
    1188             :                         OD8_ACOUSTIC_LIMIT_SCLK;
    1189             :         else
    1190           0 :                 od_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id =
    1191             :                         0;
    1192             : 
    1193           0 :         if (od_settings->overdrive8_capabilities & OD8_FAN_SPEED_MIN)
    1194           0 :                 od_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id =
    1195             :                         OD8_FAN_SPEED_MIN;
    1196             :         else
    1197           0 :                 od_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id =
    1198             :                         0;
    1199             : 
    1200           0 :         if (od_settings->overdrive8_capabilities & OD8_TEMPERATURE_FAN)
    1201           0 :                 od_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id =
    1202             :                         OD8_TEMPERATURE_FAN;
    1203             :         else
    1204           0 :                 od_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id =
    1205             :                         0;
    1206             : 
    1207           0 :         if (od_settings->overdrive8_capabilities & OD8_TEMPERATURE_SYSTEM)
    1208           0 :                 od_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id =
    1209             :                         OD8_TEMPERATURE_SYSTEM;
    1210             :         else
    1211           0 :                 od_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id =
    1212             :                         0;
    1213             : 
    1214           0 :         return 0;
    1215             : }
    1216             : 
    1217           0 : static int vega20_od8_get_gfx_clock_base_voltage(
    1218             :                 struct pp_hwmgr *hwmgr,
    1219             :                 uint32_t *voltage,
    1220             :                 uint32_t freq)
    1221             : {
    1222           0 :         int ret = 0;
    1223             : 
    1224           0 :         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           0 :         PP_ASSERT_WITH_CODE(!ret,
    1229             :                         "[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!",
    1230             :                         return ret);
    1231             : 
    1232           0 :         *voltage = *voltage / VOLTAGE_SCALE;
    1233             : 
    1234           0 :         return 0;
    1235             : }
    1236             : 
    1237           0 : static int vega20_od8_initialize_default_settings(
    1238             :                 struct pp_hwmgr *hwmgr)
    1239             : {
    1240           0 :         struct phm_ppt_v3_information *pptable_information =
    1241             :                 (struct phm_ppt_v3_information *)hwmgr->pptable;
    1242           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    1243           0 :         struct vega20_od8_settings *od8_settings = &(data->od8_settings);
    1244           0 :         OverDriveTable_t *od_table = &(data->smc_state_table.overdrive_table);
    1245           0 :         int i, ret = 0;
    1246             : 
    1247             :         /* Set Feature Capabilities */
    1248           0 :         vega20_od8_set_feature_capabilities(hwmgr);
    1249             : 
    1250             :         /* Map FeatureID to individual settings */
    1251           0 :         vega20_od8_set_feature_id(hwmgr);
    1252             : 
    1253             :         /* Set default values */
    1254           0 :         ret = smum_smc_table_manager(hwmgr, (uint8_t *)od_table, TABLE_OVERDRIVE, true);
    1255           0 :         PP_ASSERT_WITH_CODE(!ret,
    1256             :                         "Failed to export over drive table!",
    1257             :                         return ret);
    1258             : 
    1259           0 :         if (od8_settings->overdrive8_capabilities & OD8_GFXCLK_LIMITS) {
    1260           0 :                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value =
    1261           0 :                         od_table->GfxclkFmin;
    1262           0 :                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value =
    1263           0 :                         od_table->GfxclkFmax;
    1264             :         } else {
    1265           0 :                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value =
    1266             :                         0;
    1267           0 :                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value =
    1268             :                         0;
    1269             :         }
    1270             : 
    1271           0 :         if (od8_settings->overdrive8_capabilities & OD8_GFXCLK_CURVE) {
    1272           0 :                 od_table->GfxclkFreq1 = od_table->GfxclkFmin;
    1273           0 :                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value =
    1274           0 :                         od_table->GfxclkFreq1;
    1275             : 
    1276           0 :                 od_table->GfxclkFreq3 = od_table->GfxclkFmax;
    1277           0 :                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value =
    1278           0 :                         od_table->GfxclkFreq3;
    1279             : 
    1280           0 :                 od_table->GfxclkFreq2 = (od_table->GfxclkFreq1 + od_table->GfxclkFreq3) / 2;
    1281           0 :                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value =
    1282           0 :                         od_table->GfxclkFreq2;
    1283             : 
    1284           0 :                 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           0 :                 od_table->GfxclkVolt1 = od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value
    1290             :                         * VOLTAGE_SCALE;
    1291             : 
    1292           0 :                 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           0 :                 od_table->GfxclkVolt2 = od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value
    1298             :                         * VOLTAGE_SCALE;
    1299             : 
    1300           0 :                 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           0 :                 od_table->GfxclkVolt3 = od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value
    1306             :                         * VOLTAGE_SCALE;
    1307             :         } else {
    1308           0 :                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value =
    1309             :                         0;
    1310           0 :                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value =
    1311             :                         0;
    1312           0 :                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value =
    1313             :                         0;
    1314           0 :                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value =
    1315             :                         0;
    1316           0 :                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value =
    1317             :                         0;
    1318           0 :                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value =
    1319             :                         0;
    1320             :         }
    1321             : 
    1322           0 :         if (od8_settings->overdrive8_capabilities & OD8_UCLK_MAX)
    1323           0 :                 od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value =
    1324           0 :                         od_table->UclkFmax;
    1325             :         else
    1326           0 :                 od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value =
    1327             :                         0;
    1328             : 
    1329           0 :         if (od8_settings->overdrive8_capabilities & OD8_POWER_LIMIT)
    1330           0 :                 od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value =
    1331           0 :                         od_table->OverDrivePct;
    1332             :         else
    1333           0 :                 od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value =
    1334             :                         0;
    1335             : 
    1336           0 :         if (od8_settings->overdrive8_capabilities & OD8_ACOUSTIC_LIMIT_SCLK)
    1337           0 :                 od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value =
    1338           0 :                         od_table->FanMaximumRpm;
    1339             :         else
    1340           0 :                 od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value =
    1341             :                         0;
    1342             : 
    1343           0 :         if (od8_settings->overdrive8_capabilities & OD8_FAN_SPEED_MIN)
    1344           0 :                 od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value =
    1345           0 :                         od_table->FanMinimumPwm * data->smc_state_table.pp_table.FanMaximumRpm / 100;
    1346             :         else
    1347           0 :                 od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value =
    1348             :                         0;
    1349             : 
    1350           0 :         if (od8_settings->overdrive8_capabilities & OD8_TEMPERATURE_FAN)
    1351           0 :                 od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value =
    1352           0 :                         od_table->FanTargetTemperature;
    1353             :         else
    1354           0 :                 od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value =
    1355             :                         0;
    1356             : 
    1357           0 :         if (od8_settings->overdrive8_capabilities & OD8_TEMPERATURE_SYSTEM)
    1358           0 :                 od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_value =
    1359           0 :                         od_table->MaxOpTemp;
    1360             :         else
    1361           0 :                 od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_value =
    1362             :                         0;
    1363             : 
    1364           0 :         for (i = 0; i < OD8_SETTING_COUNT; i++) {
    1365           0 :                 if (od8_settings->od8_settings_array[i].feature_id) {
    1366           0 :                         od8_settings->od8_settings_array[i].min_value =
    1367           0 :                                 pptable_information->od_settings_min[i];
    1368           0 :                         od8_settings->od8_settings_array[i].max_value =
    1369           0 :                                 pptable_information->od_settings_max[i];
    1370           0 :                         od8_settings->od8_settings_array[i].current_value =
    1371           0 :                                 od8_settings->od8_settings_array[i].default_value;
    1372             :                 } else {
    1373           0 :                         od8_settings->od8_settings_array[i].min_value =
    1374             :                                 0;
    1375           0 :                         od8_settings->od8_settings_array[i].max_value =
    1376             :                                 0;
    1377           0 :                         od8_settings->od8_settings_array[i].current_value =
    1378             :                                 0;
    1379             :                 }
    1380             :         }
    1381             : 
    1382           0 :         ret = smum_smc_table_manager(hwmgr, (uint8_t *)od_table, TABLE_OVERDRIVE, false);
    1383           0 :         PP_ASSERT_WITH_CODE(!ret,
    1384             :                         "Failed to import over drive table!",
    1385             :                         return ret);
    1386             : 
    1387             :         return 0;
    1388             : }
    1389             : 
    1390           0 : 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           0 :         int ret = 0;
    1397           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    1398           0 :         struct vega20_od8_single_setting *od8_settings =
    1399             :                         data->od8_settings.od8_settings_array;
    1400             : 
    1401           0 :         ret = smum_smc_table_manager(hwmgr, (uint8_t *)(&od_table), TABLE_OVERDRIVE, true);
    1402           0 :         PP_ASSERT_WITH_CODE(!ret,
    1403             :                         "Failed to export over drive table!",
    1404             :                         return ret);
    1405             : 
    1406           0 :         switch(index) {
    1407             :         case OD8_SETTING_GFXCLK_FMIN:
    1408           0 :                 od_table.GfxclkFmin = (uint16_t)value;
    1409           0 :                 break;
    1410             :         case OD8_SETTING_GFXCLK_FMAX:
    1411           0 :                 if (value < od8_settings[OD8_SETTING_GFXCLK_FMAX].min_value ||
    1412           0 :                     value > od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value)
    1413             :                         return -EINVAL;
    1414             : 
    1415           0 :                 od_table.GfxclkFmax = (uint16_t)value;
    1416           0 :                 break;
    1417             :         case OD8_SETTING_GFXCLK_FREQ1:
    1418           0 :                 od_table.GfxclkFreq1 = (uint16_t)value;
    1419           0 :                 break;
    1420             :         case OD8_SETTING_GFXCLK_VOLTAGE1:
    1421           0 :                 od_table.GfxclkVolt1 = (uint16_t)value;
    1422           0 :                 break;
    1423             :         case OD8_SETTING_GFXCLK_FREQ2:
    1424           0 :                 od_table.GfxclkFreq2 = (uint16_t)value;
    1425           0 :                 break;
    1426             :         case OD8_SETTING_GFXCLK_VOLTAGE2:
    1427           0 :                 od_table.GfxclkVolt2 = (uint16_t)value;
    1428           0 :                 break;
    1429             :         case OD8_SETTING_GFXCLK_FREQ3:
    1430           0 :                 od_table.GfxclkFreq3 = (uint16_t)value;
    1431           0 :                 break;
    1432             :         case OD8_SETTING_GFXCLK_VOLTAGE3:
    1433           0 :                 od_table.GfxclkVolt3 = (uint16_t)value;
    1434           0 :                 break;
    1435             :         case OD8_SETTING_UCLK_FMAX:
    1436           0 :                 if (value < od8_settings[OD8_SETTING_UCLK_FMAX].min_value ||
    1437           0 :                     value > od8_settings[OD8_SETTING_UCLK_FMAX].max_value)
    1438             :                         return -EINVAL;
    1439           0 :                 od_table.UclkFmax = (uint16_t)value;
    1440           0 :                 break;
    1441             :         case OD8_SETTING_POWER_PERCENTAGE:
    1442           0 :                 od_table.OverDrivePct = (int16_t)value;
    1443           0 :                 break;
    1444             :         case OD8_SETTING_FAN_ACOUSTIC_LIMIT:
    1445           0 :                 od_table.FanMaximumRpm = (uint16_t)value;
    1446           0 :                 break;
    1447             :         case OD8_SETTING_FAN_MIN_SPEED:
    1448           0 :                 od_table.FanMinimumPwm = (uint16_t)value;
    1449           0 :                 break;
    1450             :         case OD8_SETTING_FAN_TARGET_TEMP:
    1451           0 :                 od_table.FanTargetTemperature = (uint16_t)value;
    1452           0 :                 break;
    1453             :         case OD8_SETTING_OPERATING_TEMP_MAX:
    1454           0 :                 od_table.MaxOpTemp = (uint16_t)value;
    1455           0 :                 break;
    1456             :         }
    1457             : 
    1458           0 :         ret = smum_smc_table_manager(hwmgr, (uint8_t *)(&od_table), TABLE_OVERDRIVE, false);
    1459           0 :         PP_ASSERT_WITH_CODE(!ret,
    1460             :                         "Failed to import over drive table!",
    1461             :                         return ret);
    1462             : 
    1463             :         return 0;
    1464             : }
    1465             : 
    1466           0 : static int vega20_get_sclk_od(
    1467             :                 struct pp_hwmgr *hwmgr)
    1468             : {
    1469           0 :         struct vega20_hwmgr *data = hwmgr->backend;
    1470           0 :         struct vega20_single_dpm_table *sclk_table =
    1471             :                         &(data->dpm_table.gfx_table);
    1472           0 :         struct vega20_single_dpm_table *golden_sclk_table =
    1473             :                         &(data->golden_dpm_table.gfx_table);
    1474           0 :         int value = sclk_table->dpm_levels[sclk_table->count - 1].value;
    1475           0 :         int golden_value = golden_sclk_table->dpm_levels
    1476           0 :                         [golden_sclk_table->count - 1].value;
    1477             : 
    1478             :         /* od percentage */
    1479           0 :         value -= golden_value;
    1480           0 :         value = DIV_ROUND_UP(value * 100, golden_value);
    1481             : 
    1482           0 :         return value;
    1483             : }
    1484             : 
    1485           0 : static int vega20_set_sclk_od(
    1486             :                 struct pp_hwmgr *hwmgr, uint32_t value)
    1487             : {
    1488           0 :         struct vega20_hwmgr *data = hwmgr->backend;
    1489           0 :         struct vega20_single_dpm_table *golden_sclk_table =
    1490             :                         &(data->golden_dpm_table.gfx_table);
    1491             :         uint32_t od_sclk;
    1492           0 :         int ret = 0;
    1493             : 
    1494           0 :         od_sclk = golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value * value;
    1495           0 :         od_sclk /= 100;
    1496           0 :         od_sclk += golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
    1497             : 
    1498           0 :         ret = vega20_od8_set_settings(hwmgr, OD8_SETTING_GFXCLK_FMAX, od_sclk);
    1499           0 :         PP_ASSERT_WITH_CODE(!ret,
    1500             :                         "[SetSclkOD] failed to set od gfxclk!",
    1501             :                         return ret);
    1502             : 
    1503             :         /* retrieve updated gfxclk table */
    1504           0 :         ret = vega20_setup_gfxclk_dpm_table(hwmgr);
    1505           0 :         PP_ASSERT_WITH_CODE(!ret,
    1506             :                         "[SetSclkOD] failed to refresh gfxclk table!",
    1507             :                         return ret);
    1508             : 
    1509             :         return 0;
    1510             : }
    1511             : 
    1512           0 : static int vega20_get_mclk_od(
    1513             :                 struct pp_hwmgr *hwmgr)
    1514             : {
    1515           0 :         struct vega20_hwmgr *data = hwmgr->backend;
    1516           0 :         struct vega20_single_dpm_table *mclk_table =
    1517             :                         &(data->dpm_table.mem_table);
    1518           0 :         struct vega20_single_dpm_table *golden_mclk_table =
    1519             :                         &(data->golden_dpm_table.mem_table);
    1520           0 :         int value = mclk_table->dpm_levels[mclk_table->count - 1].value;
    1521           0 :         int golden_value = golden_mclk_table->dpm_levels
    1522           0 :                         [golden_mclk_table->count - 1].value;
    1523             : 
    1524             :         /* od percentage */
    1525           0 :         value -= golden_value;
    1526           0 :         value = DIV_ROUND_UP(value * 100, golden_value);
    1527             : 
    1528           0 :         return value;
    1529             : }
    1530             : 
    1531           0 : static int vega20_set_mclk_od(
    1532             :                 struct pp_hwmgr *hwmgr, uint32_t value)
    1533             : {
    1534           0 :         struct vega20_hwmgr *data = hwmgr->backend;
    1535           0 :         struct vega20_single_dpm_table *golden_mclk_table =
    1536             :                         &(data->golden_dpm_table.mem_table);
    1537             :         uint32_t od_mclk;
    1538           0 :         int ret = 0;
    1539             : 
    1540           0 :         od_mclk = golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value * value;
    1541           0 :         od_mclk /= 100;
    1542           0 :         od_mclk += golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
    1543             : 
    1544           0 :         ret = vega20_od8_set_settings(hwmgr, OD8_SETTING_UCLK_FMAX, od_mclk);
    1545           0 :         PP_ASSERT_WITH_CODE(!ret,
    1546             :                         "[SetMclkOD] failed to set od memclk!",
    1547             :                         return ret);
    1548             : 
    1549             :         /* retrieve updated memclk table */
    1550           0 :         ret = vega20_setup_memclk_dpm_table(hwmgr);
    1551           0 :         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           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    1562           0 :         struct vega20_single_dpm_table *gfx_table = &(data->dpm_table.gfx_table);
    1563           0 :         struct vega20_single_dpm_table *mem_table = &(data->dpm_table.mem_table);
    1564             : 
    1565           0 :         hwmgr->pstate_sclk = gfx_table->dpm_levels[0].value;
    1566           0 :         hwmgr->pstate_mclk = mem_table->dpm_levels[0].value;
    1567             : 
    1568           0 :         if (gfx_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
    1569           0 :             mem_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL) {
    1570           0 :                 hwmgr->pstate_sclk = gfx_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
    1571           0 :                 hwmgr->pstate_mclk = mem_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
    1572             :         }
    1573             : 
    1574           0 :         hwmgr->pstate_sclk = hwmgr->pstate_sclk * 100;
    1575           0 :         hwmgr->pstate_mclk = hwmgr->pstate_mclk * 100;
    1576             : 
    1577             :         return 0;
    1578             : }
    1579             : 
    1580           0 : static int vega20_get_max_sustainable_clock(struct pp_hwmgr *hwmgr,
    1581             :                 PP_Clock *clock, PPCLK_e clock_select)
    1582             : {
    1583           0 :         int ret = 0;
    1584             : 
    1585           0 :         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           0 :         if (*clock == 0) {
    1594           0 :                 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           0 : static int vega20_init_max_sustainable_clocks(struct pp_hwmgr *hwmgr)
    1606             : {
    1607           0 :         struct vega20_hwmgr *data =
    1608             :                 (struct vega20_hwmgr *)(hwmgr->backend);
    1609           0 :         struct vega20_max_sustainable_clocks *max_sustainable_clocks =
    1610             :                 &(data->max_sustainable_clocks);
    1611           0 :         int ret = 0;
    1612             : 
    1613           0 :         max_sustainable_clocks->uclock = data->vbios_boot_state.mem_clock / 100;
    1614           0 :         max_sustainable_clocks->soc_clock = data->vbios_boot_state.soc_clock / 100;
    1615           0 :         max_sustainable_clocks->dcef_clock = data->vbios_boot_state.dcef_clock / 100;
    1616           0 :         max_sustainable_clocks->display_clock = 0xFFFFFFFF;
    1617           0 :         max_sustainable_clocks->phy_clock = 0xFFFFFFFF;
    1618           0 :         max_sustainable_clocks->pixel_clock = 0xFFFFFFFF;
    1619             : 
    1620           0 :         if (data->smu_features[GNLD_DPM_UCLK].enabled)
    1621           0 :                 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           0 :         if (data->smu_features[GNLD_DPM_SOCCLK].enabled)
    1628           0 :                 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           0 :         if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
    1635           0 :                 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           0 :                 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           0 :                 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           0 :                 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           0 :         if (max_sustainable_clocks->soc_clock < max_sustainable_clocks->uclock)
    1658           0 :                 max_sustainable_clocks->uclock = max_sustainable_clocks->soc_clock;
    1659             : 
    1660             :         return 0;
    1661             : }
    1662             : 
    1663           0 : static int vega20_enable_mgpu_fan_boost(struct pp_hwmgr *hwmgr)
    1664             : {
    1665             :         int result;
    1666             : 
    1667           0 :         result = smum_send_msg_to_smc(hwmgr,
    1668             :                 PPSMC_MSG_SetMGpuFanBoostLimitRpm,
    1669             :                 NULL);
    1670           0 :         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           0 :         struct vega20_hwmgr *data =
    1680             :                 (struct vega20_hwmgr *)(hwmgr->backend);
    1681             : 
    1682           0 :         data->uvd_power_gated = true;
    1683           0 :         data->vce_power_gated = true;
    1684             : }
    1685             : 
    1686           0 : static int vega20_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
    1687             : {
    1688           0 :         int result = 0;
    1689             : 
    1690           0 :         smum_send_msg_to_smc_with_parameter(hwmgr,
    1691             :                         PPSMC_MSG_NumOfDisplays, 0, NULL);
    1692             : 
    1693           0 :         result = vega20_set_allowed_featuresmask(hwmgr);
    1694           0 :         PP_ASSERT_WITH_CODE(!result,
    1695             :                         "[EnableDPMTasks] Failed to set allowed featuresmask!\n",
    1696             :                         return result);
    1697             : 
    1698           0 :         result = vega20_init_smc_table(hwmgr);
    1699           0 :         PP_ASSERT_WITH_CODE(!result,
    1700             :                         "[EnableDPMTasks] Failed to initialize SMC table!",
    1701             :                         return result);
    1702             : 
    1703           0 :         result = vega20_run_btc(hwmgr);
    1704           0 :         PP_ASSERT_WITH_CODE(!result,
    1705             :                         "[EnableDPMTasks] Failed to run btc!",
    1706             :                         return result);
    1707             : 
    1708           0 :         result = vega20_run_btc_afll(hwmgr);
    1709           0 :         PP_ASSERT_WITH_CODE(!result,
    1710             :                         "[EnableDPMTasks] Failed to run btc afll!",
    1711             :                         return result);
    1712             : 
    1713           0 :         result = vega20_enable_all_smu_features(hwmgr);
    1714           0 :         PP_ASSERT_WITH_CODE(!result,
    1715             :                         "[EnableDPMTasks] Failed to enable all smu features!",
    1716             :                         return result);
    1717             : 
    1718           0 :         result = vega20_override_pcie_parameters(hwmgr);
    1719           0 :         PP_ASSERT_WITH_CODE(!result,
    1720             :                         "[EnableDPMTasks] Failed to override pcie parameters!",
    1721             :                         return result);
    1722             : 
    1723           0 :         result = vega20_notify_smc_display_change(hwmgr);
    1724           0 :         PP_ASSERT_WITH_CODE(!result,
    1725             :                         "[EnableDPMTasks] Failed to notify smc display change!",
    1726             :                         return result);
    1727             : 
    1728           0 :         result = vega20_send_clock_ratio(hwmgr);
    1729           0 :         PP_ASSERT_WITH_CODE(!result,
    1730             :                         "[EnableDPMTasks] Failed to send clock ratio!",
    1731             :                         return result);
    1732             : 
    1733             :         /* Initialize UVD/VCE powergating state */
    1734           0 :         vega20_init_powergate_state(hwmgr);
    1735             : 
    1736           0 :         result = vega20_setup_default_dpm_tables(hwmgr);
    1737           0 :         PP_ASSERT_WITH_CODE(!result,
    1738             :                         "[EnableDPMTasks] Failed to setup default DPM tables!",
    1739             :                         return result);
    1740             : 
    1741           0 :         result = vega20_init_max_sustainable_clocks(hwmgr);
    1742           0 :         PP_ASSERT_WITH_CODE(!result,
    1743             :                         "[EnableDPMTasks] Failed to get maximum sustainable clocks!",
    1744             :                         return result);
    1745             : 
    1746           0 :         result = vega20_power_control_set_level(hwmgr);
    1747           0 :         PP_ASSERT_WITH_CODE(!result,
    1748             :                         "[EnableDPMTasks] Failed to power control set level!",
    1749             :                         return result);
    1750             : 
    1751           0 :         result = vega20_od8_initialize_default_settings(hwmgr);
    1752           0 :         PP_ASSERT_WITH_CODE(!result,
    1753             :                         "[EnableDPMTasks] Failed to initialize odn settings!",
    1754             :                         return result);
    1755             : 
    1756           0 :         result = vega20_populate_umdpstate_clocks(hwmgr);
    1757             :         PP_ASSERT_WITH_CODE(!result,
    1758             :                         "[EnableDPMTasks] Failed to populate umdpstate clocks!",
    1759             :                         return result);
    1760             : 
    1761           0 :         result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetPptLimit,
    1762             :                         POWER_SOURCE_AC << 16, &hwmgr->default_power_limit);
    1763           0 :         PP_ASSERT_WITH_CODE(!result,
    1764             :                         "[GetPptLimit] get default PPT limit failed!",
    1765             :                         return result);
    1766           0 :         hwmgr->power_limit =
    1767           0 :                 hwmgr->default_power_limit;
    1768             : 
    1769           0 :         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           0 :         for (i = 0; i < table->count; i++) {
    1778           0 :                 if (table->dpm_levels[i].enabled)
    1779             :                         break;
    1780             :         }
    1781           0 :         if (i >= table->count) {
    1782           0 :                 i = 0;
    1783           0 :                 table->dpm_levels[i].enabled = true;
    1784             :         }
    1785             : 
    1786             :         return i;
    1787             : }
    1788             : 
    1789           0 : static uint32_t vega20_find_highest_dpm_level(
    1790             :                 struct vega20_single_dpm_table *table)
    1791             : {
    1792           0 :         int i = 0;
    1793             : 
    1794           0 :         PP_ASSERT_WITH_CODE(table != NULL,
    1795             :                         "[FindHighestDPMLevel] DPM Table does not exist!",
    1796             :                         return 0);
    1797           0 :         PP_ASSERT_WITH_CODE(table->count > 0,
    1798             :                         "[FindHighestDPMLevel] DPM Table has no entry!",
    1799             :                         return 0);
    1800           0 :         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           0 :         for (i = table->count - 1; i >= 0; i--) {
    1805           0 :                 if (table->dpm_levels[i].enabled)
    1806             :                         break;
    1807             :         }
    1808           0 :         if (i < 0) {
    1809           0 :                 i = 0;
    1810           0 :                 table->dpm_levels[i].enabled = true;
    1811             :         }
    1812             : 
    1813           0 :         return i;
    1814             : }
    1815             : 
    1816           0 : static int vega20_upload_dpm_min_level(struct pp_hwmgr *hwmgr, uint32_t feature_mask)
    1817             : {
    1818           0 :         struct vega20_hwmgr *data =
    1819             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    1820             :         uint32_t min_freq;
    1821           0 :         int ret = 0;
    1822             : 
    1823           0 :         if (data->smu_features[GNLD_DPM_GFXCLK].enabled &&
    1824           0 :            (feature_mask & FEATURE_DPM_GFXCLK_MASK)) {
    1825           0 :                 min_freq = data->dpm_table.gfx_table.dpm_state.soft_min_level;
    1826           0 :                 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           0 :         if (data->smu_features[GNLD_DPM_UCLK].enabled &&
    1835           0 :            (feature_mask & FEATURE_DPM_UCLK_MASK)) {
    1836           0 :                 min_freq = data->dpm_table.mem_table.dpm_state.soft_min_level;
    1837           0 :                 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           0 :         if (data->smu_features[GNLD_DPM_UVD].enabled &&
    1846           0 :            (feature_mask & FEATURE_DPM_UVD_MASK)) {
    1847           0 :                 min_freq = data->dpm_table.vclk_table.dpm_state.soft_min_level;
    1848             : 
    1849           0 :                 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           0 :                 min_freq = data->dpm_table.dclk_table.dpm_state.soft_min_level;
    1857             : 
    1858           0 :                 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           0 :         if (data->smu_features[GNLD_DPM_VCE].enabled &&
    1867           0 :            (feature_mask & FEATURE_DPM_VCE_MASK)) {
    1868           0 :                 min_freq = data->dpm_table.eclk_table.dpm_state.soft_min_level;
    1869             : 
    1870           0 :                 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           0 :         if (data->smu_features[GNLD_DPM_SOCCLK].enabled &&
    1879           0 :            (feature_mask & FEATURE_DPM_SOCCLK_MASK)) {
    1880           0 :                 min_freq = data->dpm_table.soc_table.dpm_state.soft_min_level;
    1881             : 
    1882           0 :                 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           0 :         if (data->smu_features[GNLD_DPM_FCLK].enabled &&
    1891           0 :            (feature_mask & FEATURE_DPM_FCLK_MASK)) {
    1892           0 :                 min_freq = data->dpm_table.fclk_table.dpm_state.soft_min_level;
    1893             : 
    1894           0 :                 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           0 :         if (data->smu_features[GNLD_DPM_DCEFCLK].enabled &&
    1903           0 :            (feature_mask & FEATURE_DPM_DCEFCLK_MASK)) {
    1904           0 :                 min_freq = data->dpm_table.dcef_table.dpm_state.hard_min_level;
    1905             : 
    1906           0 :                 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           0 : static int vega20_upload_dpm_max_level(struct pp_hwmgr *hwmgr, uint32_t feature_mask)
    1918             : {
    1919           0 :         struct vega20_hwmgr *data =
    1920             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    1921             :         uint32_t max_freq;
    1922           0 :         int ret = 0;
    1923             : 
    1924           0 :         if (data->smu_features[GNLD_DPM_GFXCLK].enabled &&
    1925           0 :            (feature_mask & FEATURE_DPM_GFXCLK_MASK)) {
    1926           0 :                 max_freq = data->dpm_table.gfx_table.dpm_state.soft_max_level;
    1927             : 
    1928           0 :                 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           0 :         if (data->smu_features[GNLD_DPM_UCLK].enabled &&
    1937           0 :            (feature_mask & FEATURE_DPM_UCLK_MASK)) {
    1938           0 :                 max_freq = data->dpm_table.mem_table.dpm_state.soft_max_level;
    1939             : 
    1940           0 :                 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           0 :         if (data->smu_features[GNLD_DPM_UVD].enabled &&
    1949           0 :            (feature_mask & FEATURE_DPM_UVD_MASK)) {
    1950           0 :                 max_freq = data->dpm_table.vclk_table.dpm_state.soft_max_level;
    1951             : 
    1952           0 :                 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           0 :                 max_freq = data->dpm_table.dclk_table.dpm_state.soft_max_level;
    1960           0 :                 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           0 :         if (data->smu_features[GNLD_DPM_VCE].enabled &&
    1969           0 :            (feature_mask & FEATURE_DPM_VCE_MASK)) {
    1970           0 :                 max_freq = data->dpm_table.eclk_table.dpm_state.soft_max_level;
    1971             : 
    1972           0 :                 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           0 :         if (data->smu_features[GNLD_DPM_SOCCLK].enabled &&
    1981           0 :            (feature_mask & FEATURE_DPM_SOCCLK_MASK)) {
    1982           0 :                 max_freq = data->dpm_table.soc_table.dpm_state.soft_max_level;
    1983             : 
    1984           0 :                 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           0 :         if (data->smu_features[GNLD_DPM_FCLK].enabled &&
    1993           0 :            (feature_mask & FEATURE_DPM_FCLK_MASK)) {
    1994           0 :                 max_freq = data->dpm_table.fclk_table.dpm_state.soft_max_level;
    1995             : 
    1996           0 :                 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           0 : static int vega20_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
    2008             : {
    2009           0 :         struct vega20_hwmgr *data =
    2010             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    2011           0 :         int ret = 0;
    2012             : 
    2013           0 :         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           0 :                 ret = vega20_enable_smc_features(hwmgr,
    2022             :                                 enable,
    2023             :                                 data->smu_features[GNLD_DPM_VCE].smu_feature_bitmap);
    2024           0 :                 PP_ASSERT_WITH_CODE(!ret,
    2025             :                                 "Attempt to Enable/Disable DPM VCE Failed!",
    2026             :                                 return ret);
    2027           0 :                 data->smu_features[GNLD_DPM_VCE].enabled = enable;
    2028             :         }
    2029             : 
    2030             :         return 0;
    2031             : }
    2032             : 
    2033           0 : 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           0 :         *clock = 0;
    2040             : 
    2041           0 :         if (max) {
    2042           0 :                 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           0 :                 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           0 : static uint32_t vega20_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
    2060             : {
    2061           0 :         struct vega20_hwmgr *data =
    2062             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    2063             :         uint32_t gfx_clk;
    2064           0 :         int ret = 0;
    2065             : 
    2066           0 :         PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_GFXCLK].enabled,
    2067             :                         "[GetSclks]: gfxclk dpm not enabled!\n",
    2068             :                         return -EPERM);
    2069             : 
    2070           0 :         if (low) {
    2071           0 :                 ret = vega20_get_clock_ranges(hwmgr, &gfx_clk, PPCLK_GFXCLK, false);
    2072           0 :                 PP_ASSERT_WITH_CODE(!ret,
    2073             :                         "[GetSclks]: fail to get min PPCLK_GFXCLK\n",
    2074             :                         return ret);
    2075             :         } else {
    2076           0 :                 ret = vega20_get_clock_ranges(hwmgr, &gfx_clk, PPCLK_GFXCLK, true);
    2077           0 :                 PP_ASSERT_WITH_CODE(!ret,
    2078             :                         "[GetSclks]: fail to get max PPCLK_GFXCLK\n",
    2079             :                         return ret);
    2080             :         }
    2081             : 
    2082           0 :         return (gfx_clk * 100);
    2083             : }
    2084             : 
    2085           0 : static uint32_t vega20_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
    2086             : {
    2087           0 :         struct vega20_hwmgr *data =
    2088             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    2089             :         uint32_t mem_clk;
    2090           0 :         int ret = 0;
    2091             : 
    2092           0 :         PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_UCLK].enabled,
    2093             :                         "[MemMclks]: memclk dpm not enabled!\n",
    2094             :                         return -EPERM);
    2095             : 
    2096           0 :         if (low) {
    2097           0 :                 ret = vega20_get_clock_ranges(hwmgr, &mem_clk, PPCLK_UCLK, false);
    2098           0 :                 PP_ASSERT_WITH_CODE(!ret,
    2099             :                         "[GetMclks]: fail to get min PPCLK_UCLK\n",
    2100             :                         return ret);
    2101             :         } else {
    2102           0 :                 ret = vega20_get_clock_ranges(hwmgr, &mem_clk, PPCLK_UCLK, true);
    2103           0 :                 PP_ASSERT_WITH_CODE(!ret,
    2104             :                         "[GetMclks]: fail to get max PPCLK_UCLK\n",
    2105             :                         return ret);
    2106             :         }
    2107             : 
    2108           0 :         return (mem_clk * 100);
    2109             : }
    2110             : 
    2111           0 : static int vega20_get_metrics_table(struct pp_hwmgr *hwmgr,
    2112             :                                     SmuMetrics_t *metrics_table,
    2113             :                                     bool bypass_cache)
    2114             : {
    2115           0 :         struct vega20_hwmgr *data =
    2116             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    2117           0 :         int ret = 0;
    2118             : 
    2119           0 :         if (bypass_cache ||
    2120           0 :             !data->metrics_time ||
    2121           0 :             time_after(jiffies, data->metrics_time + msecs_to_jiffies(1))) {
    2122           0 :                 ret = smum_smc_table_manager(hwmgr,
    2123           0 :                                              (uint8_t *)(&data->metrics_table),
    2124             :                                              TABLE_SMU_METRICS,
    2125             :                                              true);
    2126           0 :                 if (ret) {
    2127           0 :                         pr_info("Failed to export SMU metrics table!\n");
    2128           0 :                         return ret;
    2129             :                 }
    2130           0 :                 data->metrics_time = jiffies;
    2131             :         }
    2132             : 
    2133           0 :         if (metrics_table)
    2134           0 :                 memcpy(metrics_table, &data->metrics_table, sizeof(SmuMetrics_t));
    2135             : 
    2136             :         return ret;
    2137             : }
    2138             : 
    2139           0 : static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr,
    2140             :                 uint32_t *query)
    2141             : {
    2142           0 :         int ret = 0;
    2143             :         SmuMetrics_t metrics_table;
    2144             : 
    2145           0 :         ret = vega20_get_metrics_table(hwmgr, &metrics_table, false);
    2146           0 :         if (ret)
    2147             :                 return ret;
    2148             : 
    2149             :         /* For the 40.46 release, they changed the value name */
    2150           0 :         if (hwmgr->smu_version == 0x282e00)
    2151           0 :                 *query = metrics_table.AverageSocketPower << 8;
    2152             :         else
    2153           0 :                 *query = metrics_table.CurrSocketPower << 8;
    2154             : 
    2155             :         return ret;
    2156             : }
    2157             : 
    2158           0 : static int vega20_get_current_clk_freq(struct pp_hwmgr *hwmgr,
    2159             :                 PPCLK_e clk_id, uint32_t *clk_freq)
    2160             : {
    2161           0 :         int ret = 0;
    2162             : 
    2163           0 :         *clk_freq = 0;
    2164             : 
    2165           0 :         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           0 :         *clk_freq = *clk_freq * 100;
    2172             : 
    2173           0 :         return 0;
    2174             : }
    2175             : 
    2176           0 : static int vega20_get_current_activity_percent(struct pp_hwmgr *hwmgr,
    2177             :                 int idx,
    2178             :                 uint32_t *activity_percent)
    2179             : {
    2180           0 :         int ret = 0;
    2181             :         SmuMetrics_t metrics_table;
    2182             : 
    2183           0 :         ret = vega20_get_metrics_table(hwmgr, &metrics_table, false);
    2184           0 :         if (ret)
    2185             :                 return ret;
    2186             : 
    2187           0 :         switch (idx) {
    2188             :         case AMDGPU_PP_SENSOR_GPU_LOAD:
    2189           0 :                 *activity_percent = metrics_table.AverageGfxActivity;
    2190           0 :                 break;
    2191             :         case AMDGPU_PP_SENSOR_MEM_LOAD:
    2192           0 :                 *activity_percent = metrics_table.AverageUclkActivity;
    2193           0 :                 break;
    2194             :         default:
    2195           0 :                 pr_err("Invalid index for retrieving clock activity\n");
    2196           0 :                 return -EINVAL;
    2197             :         }
    2198             : 
    2199             :         return ret;
    2200             : }
    2201             : 
    2202           0 : static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx,
    2203             :                               void *value, int *size)
    2204             : {
    2205           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    2206           0 :         struct amdgpu_device *adev = hwmgr->adev;
    2207             :         SmuMetrics_t metrics_table;
    2208             :         uint32_t val_vid;
    2209           0 :         int ret = 0;
    2210             : 
    2211           0 :         switch (idx) {
    2212             :         case AMDGPU_PP_SENSOR_GFX_SCLK:
    2213           0 :                 ret = vega20_get_metrics_table(hwmgr, &metrics_table, false);
    2214           0 :                 if (ret)
    2215             :                         return ret;
    2216             : 
    2217           0 :                 *((uint32_t *)value) = metrics_table.AverageGfxclkFrequency * 100;
    2218           0 :                 *size = 4;
    2219           0 :                 break;
    2220             :         case AMDGPU_PP_SENSOR_GFX_MCLK:
    2221           0 :                 ret = vega20_get_current_clk_freq(hwmgr,
    2222             :                                 PPCLK_UCLK,
    2223             :                                 (uint32_t *)value);
    2224           0 :                 if (!ret)
    2225           0 :                         *size = 4;
    2226             :                 break;
    2227             :         case AMDGPU_PP_SENSOR_GPU_LOAD:
    2228             :         case AMDGPU_PP_SENSOR_MEM_LOAD:
    2229           0 :                 ret = vega20_get_current_activity_percent(hwmgr, idx, (uint32_t *)value);
    2230           0 :                 if (!ret)
    2231           0 :                         *size = 4;
    2232             :                 break;
    2233             :         case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
    2234           0 :                 *((uint32_t *)value) = vega20_thermal_get_temperature(hwmgr);
    2235           0 :                 *size = 4;
    2236           0 :                 break;
    2237             :         case AMDGPU_PP_SENSOR_EDGE_TEMP:
    2238           0 :                 ret = vega20_get_metrics_table(hwmgr, &metrics_table, false);
    2239           0 :                 if (ret)
    2240             :                         return ret;
    2241             : 
    2242           0 :                 *((uint32_t *)value) = metrics_table.TemperatureEdge *
    2243             :                         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
    2244           0 :                 *size = 4;
    2245           0 :                 break;
    2246             :         case AMDGPU_PP_SENSOR_MEM_TEMP:
    2247           0 :                 ret = vega20_get_metrics_table(hwmgr, &metrics_table, false);
    2248           0 :                 if (ret)
    2249             :                         return ret;
    2250             : 
    2251           0 :                 *((uint32_t *)value) = metrics_table.TemperatureHBM *
    2252             :                         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
    2253           0 :                 *size = 4;
    2254           0 :                 break;
    2255             :         case AMDGPU_PP_SENSOR_UVD_POWER:
    2256           0 :                 *((uint32_t *)value) = data->uvd_power_gated ? 0 : 1;
    2257           0 :                 *size = 4;
    2258           0 :                 break;
    2259             :         case AMDGPU_PP_SENSOR_VCE_POWER:
    2260           0 :                 *((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
    2261           0 :                 *size = 4;
    2262           0 :                 break;
    2263             :         case AMDGPU_PP_SENSOR_GPU_POWER:
    2264           0 :                 *size = 16;
    2265           0 :                 ret = vega20_get_gpu_power(hwmgr, (uint32_t *)value);
    2266           0 :                 break;
    2267             :         case AMDGPU_PP_SENSOR_VDDGFX:
    2268           0 :                 val_vid = (RREG32_SOC15(SMUIO, 0, mmSMUSVI0_TEL_PLANE0) &
    2269           0 :                         SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR_MASK) >>
    2270             :                         SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR__SHIFT;
    2271           0 :                 *((uint32_t *)value) =
    2272           0 :                         (uint32_t)convert_to_vddc((uint8_t)val_vid);
    2273           0 :                 break;
    2274             :         case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK:
    2275           0 :                 ret = vega20_get_enabled_smc_features(hwmgr, (uint64_t *)value);
    2276           0 :                 if (!ret)
    2277           0 :                         *size = 8;
    2278             :                 break;
    2279             :         default:
    2280             :                 ret = -EOPNOTSUPP;
    2281             :                 break;
    2282             :         }
    2283             :         return ret;
    2284             : }
    2285             : 
    2286           0 : static int vega20_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
    2287             :                 struct pp_display_clock_request *clock_req)
    2288             : {
    2289           0 :         int result = 0;
    2290           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    2291           0 :         enum amd_pp_clock_type clk_type = clock_req->clock_type;
    2292           0 :         uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
    2293           0 :         PPCLK_e clk_select = 0;
    2294           0 :         uint32_t clk_request = 0;
    2295             : 
    2296           0 :         if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
    2297           0 :                 switch (clk_type) {
    2298             :                 case amd_pp_dcef_clock:
    2299             :                         clk_select = PPCLK_DCEFCLK;
    2300             :                         break;
    2301             :                 case amd_pp_disp_clock:
    2302           0 :                         clk_select = PPCLK_DISPCLK;
    2303           0 :                         break;
    2304             :                 case amd_pp_pixel_clock:
    2305           0 :                         clk_select = PPCLK_PIXCLK;
    2306           0 :                         break;
    2307             :                 case amd_pp_phy_clock:
    2308           0 :                         clk_select = PPCLK_PHYCLK;
    2309           0 :                         break;
    2310             :                 default:
    2311           0 :                         pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!");
    2312           0 :                         result = -EINVAL;
    2313           0 :                         break;
    2314             :                 }
    2315             : 
    2316           0 :                 if (!result) {
    2317           0 :                         clk_request = (clk_select << 16) | clk_freq;
    2318           0 :                         result = smum_send_msg_to_smc_with_parameter(hwmgr,
    2319             :                                         PPSMC_MSG_SetHardMinByFreq,
    2320             :                                         clk_request,
    2321             :                                         NULL);
    2322             :                 }
    2323             :         }
    2324             : 
    2325           0 :         return result;
    2326             : }
    2327             : 
    2328           0 : 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           0 :         return 0;
    2333             : }
    2334             : 
    2335           0 : static int vega20_notify_smc_display_config_after_ps_adjustment(
    2336             :                 struct pp_hwmgr *hwmgr)
    2337             : {
    2338           0 :         struct vega20_hwmgr *data =
    2339             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    2340           0 :         struct vega20_single_dpm_table *dpm_table =
    2341             :                         &data->dpm_table.mem_table;
    2342           0 :         struct PP_Clocks min_clocks = {0};
    2343             :         struct pp_display_clock_request clock_req;
    2344           0 :         int ret = 0;
    2345             : 
    2346           0 :         min_clocks.dcefClock = hwmgr->display_config->min_dcef_set_clk;
    2347           0 :         min_clocks.dcefClockInSR = hwmgr->display_config->min_dcef_deep_sleep_set_clk;
    2348           0 :         min_clocks.memoryClock = hwmgr->display_config->min_mem_set_clock;
    2349             : 
    2350           0 :         if (data->smu_features[GNLD_DPM_DCEFCLK].supported) {
    2351           0 :                 clock_req.clock_type = amd_pp_dcef_clock;
    2352           0 :                 clock_req.clock_freq_in_khz = min_clocks.dcefClock * 10;
    2353           0 :                 if (!vega20_display_clock_voltage_request(hwmgr, &clock_req)) {
    2354           0 :                         if (data->smu_features[GNLD_DS_DCEFCLK].supported)
    2355           0 :                                 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           0 :                         pr_info("Attempt to set Hard Min for DCEFCLK Failed!");
    2363             :                 }
    2364             :         }
    2365             : 
    2366           0 :         if (data->smu_features[GNLD_DPM_UCLK].enabled) {
    2367           0 :                 dpm_table->dpm_state.hard_min_level = min_clocks.memoryClock / 100;
    2368           0 :                 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           0 : static int vega20_force_dpm_highest(struct pp_hwmgr *hwmgr)
    2380             : {
    2381           0 :         struct vega20_hwmgr *data =
    2382             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    2383             :         uint32_t soft_level;
    2384           0 :         int ret = 0;
    2385             : 
    2386           0 :         soft_level = vega20_find_highest_dpm_level(&(data->dpm_table.gfx_table));
    2387             : 
    2388           0 :         data->dpm_table.gfx_table.dpm_state.soft_min_level =
    2389           0 :                 data->dpm_table.gfx_table.dpm_state.soft_max_level =
    2390           0 :                 data->dpm_table.gfx_table.dpm_levels[soft_level].value;
    2391             : 
    2392           0 :         soft_level = vega20_find_highest_dpm_level(&(data->dpm_table.mem_table));
    2393             : 
    2394           0 :         data->dpm_table.mem_table.dpm_state.soft_min_level =
    2395           0 :                 data->dpm_table.mem_table.dpm_state.soft_max_level =
    2396           0 :                 data->dpm_table.mem_table.dpm_levels[soft_level].value;
    2397             : 
    2398           0 :         soft_level = vega20_find_highest_dpm_level(&(data->dpm_table.soc_table));
    2399             : 
    2400           0 :         data->dpm_table.soc_table.dpm_state.soft_min_level =
    2401           0 :                 data->dpm_table.soc_table.dpm_state.soft_max_level =
    2402           0 :                 data->dpm_table.soc_table.dpm_levels[soft_level].value;
    2403             : 
    2404           0 :         ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
    2405             :                                                  FEATURE_DPM_UCLK_MASK |
    2406             :                                                  FEATURE_DPM_SOCCLK_MASK);
    2407           0 :         PP_ASSERT_WITH_CODE(!ret,
    2408             :                         "Failed to upload boot level to highest!",
    2409             :                         return ret);
    2410             : 
    2411           0 :         ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
    2412             :                                                  FEATURE_DPM_UCLK_MASK |
    2413             :                                                  FEATURE_DPM_SOCCLK_MASK);
    2414           0 :         PP_ASSERT_WITH_CODE(!ret,
    2415             :                         "Failed to upload dpm max level to highest!",
    2416             :                         return ret);
    2417             : 
    2418             :         return 0;
    2419             : }
    2420             : 
    2421           0 : static int vega20_force_dpm_lowest(struct pp_hwmgr *hwmgr)
    2422             : {
    2423           0 :         struct vega20_hwmgr *data =
    2424             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    2425             :         uint32_t soft_level;
    2426           0 :         int ret = 0;
    2427             : 
    2428           0 :         soft_level = vega20_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
    2429             : 
    2430           0 :         data->dpm_table.gfx_table.dpm_state.soft_min_level =
    2431           0 :                 data->dpm_table.gfx_table.dpm_state.soft_max_level =
    2432           0 :                 data->dpm_table.gfx_table.dpm_levels[soft_level].value;
    2433             : 
    2434           0 :         soft_level = vega20_find_lowest_dpm_level(&(data->dpm_table.mem_table));
    2435             : 
    2436           0 :         data->dpm_table.mem_table.dpm_state.soft_min_level =
    2437           0 :                 data->dpm_table.mem_table.dpm_state.soft_max_level =
    2438           0 :                 data->dpm_table.mem_table.dpm_levels[soft_level].value;
    2439             : 
    2440           0 :         soft_level = vega20_find_lowest_dpm_level(&(data->dpm_table.soc_table));
    2441             : 
    2442           0 :         data->dpm_table.soc_table.dpm_state.soft_min_level =
    2443           0 :                 data->dpm_table.soc_table.dpm_state.soft_max_level =
    2444           0 :                 data->dpm_table.soc_table.dpm_levels[soft_level].value;
    2445             : 
    2446           0 :         ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
    2447             :                                                  FEATURE_DPM_UCLK_MASK |
    2448             :                                                  FEATURE_DPM_SOCCLK_MASK);
    2449           0 :         PP_ASSERT_WITH_CODE(!ret,
    2450             :                         "Failed to upload boot level to highest!",
    2451             :                         return ret);
    2452             : 
    2453           0 :         ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
    2454             :                                                  FEATURE_DPM_UCLK_MASK |
    2455             :                                                  FEATURE_DPM_SOCCLK_MASK);
    2456           0 :         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           0 : static int vega20_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
    2465             : {
    2466           0 :         struct vega20_hwmgr *data =
    2467             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    2468             :         uint32_t soft_min_level, soft_max_level;
    2469           0 :         int ret = 0;
    2470             : 
    2471             :         /* gfxclk soft min/max settings */
    2472           0 :         soft_min_level =
    2473           0 :                 vega20_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
    2474           0 :         soft_max_level =
    2475             :                 vega20_find_highest_dpm_level(&(data->dpm_table.gfx_table));
    2476             : 
    2477           0 :         data->dpm_table.gfx_table.dpm_state.soft_min_level =
    2478           0 :                 data->dpm_table.gfx_table.dpm_levels[soft_min_level].value;
    2479           0 :         data->dpm_table.gfx_table.dpm_state.soft_max_level =
    2480           0 :                 data->dpm_table.gfx_table.dpm_levels[soft_max_level].value;
    2481             : 
    2482             :         /* uclk soft min/max settings */
    2483           0 :         soft_min_level =
    2484           0 :                 vega20_find_lowest_dpm_level(&(data->dpm_table.mem_table));
    2485           0 :         soft_max_level =
    2486             :                 vega20_find_highest_dpm_level(&(data->dpm_table.mem_table));
    2487             : 
    2488           0 :         data->dpm_table.mem_table.dpm_state.soft_min_level =
    2489           0 :                 data->dpm_table.mem_table.dpm_levels[soft_min_level].value;
    2490           0 :         data->dpm_table.mem_table.dpm_state.soft_max_level =
    2491           0 :                 data->dpm_table.mem_table.dpm_levels[soft_max_level].value;
    2492             : 
    2493             :         /* socclk soft min/max settings */
    2494           0 :         soft_min_level =
    2495           0 :                 vega20_find_lowest_dpm_level(&(data->dpm_table.soc_table));
    2496           0 :         soft_max_level =
    2497             :                 vega20_find_highest_dpm_level(&(data->dpm_table.soc_table));
    2498             : 
    2499           0 :         data->dpm_table.soc_table.dpm_state.soft_min_level =
    2500           0 :                 data->dpm_table.soc_table.dpm_levels[soft_min_level].value;
    2501           0 :         data->dpm_table.soc_table.dpm_state.soft_max_level =
    2502           0 :                 data->dpm_table.soc_table.dpm_levels[soft_max_level].value;
    2503             : 
    2504           0 :         ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
    2505             :                                                  FEATURE_DPM_UCLK_MASK |
    2506             :                                                  FEATURE_DPM_SOCCLK_MASK);
    2507           0 :         PP_ASSERT_WITH_CODE(!ret,
    2508             :                         "Failed to upload DPM Bootup Levels!",
    2509             :                         return ret);
    2510             : 
    2511           0 :         ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
    2512             :                                                  FEATURE_DPM_UCLK_MASK |
    2513             :                                                  FEATURE_DPM_SOCCLK_MASK);
    2514           0 :         PP_ASSERT_WITH_CODE(!ret,
    2515             :                         "Failed to upload DPM Max Levels!",
    2516             :                         return ret);
    2517             : 
    2518             :         return 0;
    2519             : }
    2520             : 
    2521           0 : 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           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    2525           0 :         struct vega20_single_dpm_table *gfx_dpm_table = &(data->dpm_table.gfx_table);
    2526           0 :         struct vega20_single_dpm_table *mem_dpm_table = &(data->dpm_table.mem_table);
    2527           0 :         struct vega20_single_dpm_table *soc_dpm_table = &(data->dpm_table.soc_table);
    2528             : 
    2529           0 :         *sclk_mask = 0;
    2530           0 :         *mclk_mask = 0;
    2531           0 :         *soc_mask  = 0;
    2532             : 
    2533           0 :         if (gfx_dpm_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
    2534           0 :             mem_dpm_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL &&
    2535           0 :             soc_dpm_table->count > VEGA20_UMD_PSTATE_SOCCLK_LEVEL) {
    2536           0 :                 *sclk_mask = VEGA20_UMD_PSTATE_GFXCLK_LEVEL;
    2537           0 :                 *mclk_mask = VEGA20_UMD_PSTATE_MCLK_LEVEL;
    2538           0 :                 *soc_mask  = VEGA20_UMD_PSTATE_SOCCLK_LEVEL;
    2539             :         }
    2540             : 
    2541           0 :         if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
    2542           0 :                 *sclk_mask = 0;
    2543           0 :         } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
    2544           0 :                 *mclk_mask = 0;
    2545           0 :         } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
    2546           0 :                 *sclk_mask = gfx_dpm_table->count - 1;
    2547           0 :                 *mclk_mask = mem_dpm_table->count - 1;
    2548           0 :                 *soc_mask  = soc_dpm_table->count - 1;
    2549             :         }
    2550             : 
    2551           0 :         return 0;
    2552             : }
    2553             : 
    2554           0 : static int vega20_force_clock_level(struct pp_hwmgr *hwmgr,
    2555             :                 enum pp_clock_type type, uint32_t mask)
    2556             : {
    2557           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    2558             :         uint32_t soft_min_level, soft_max_level, hard_min_level;
    2559           0 :         int ret = 0;
    2560             : 
    2561           0 :         switch (type) {
    2562             :         case PP_SCLK:
    2563           0 :                 soft_min_level = mask ? (ffs(mask) - 1) : 0;
    2564           0 :                 soft_max_level = mask ? (fls(mask) - 1) : 0;
    2565             : 
    2566           0 :                 if (soft_max_level >= data->dpm_table.gfx_table.count) {
    2567           0 :                         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           0 :                         return -EINVAL;
    2571             :                 }
    2572             : 
    2573           0 :                 data->dpm_table.gfx_table.dpm_state.soft_min_level =
    2574           0 :                         data->dpm_table.gfx_table.dpm_levels[soft_min_level].value;
    2575           0 :                 data->dpm_table.gfx_table.dpm_state.soft_max_level =
    2576           0 :                         data->dpm_table.gfx_table.dpm_levels[soft_max_level].value;
    2577             : 
    2578           0 :                 ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK);
    2579           0 :                 PP_ASSERT_WITH_CODE(!ret,
    2580             :                         "Failed to upload boot level to lowest!",
    2581             :                         return ret);
    2582             : 
    2583           0 :                 ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK);
    2584           0 :                 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           0 :                 soft_min_level = mask ? (ffs(mask) - 1) : 0;
    2591           0 :                 soft_max_level = mask ? (fls(mask) - 1) : 0;
    2592             : 
    2593           0 :                 if (soft_max_level >= data->dpm_table.mem_table.count) {
    2594           0 :                         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           0 :                         return -EINVAL;
    2598             :                 }
    2599             : 
    2600           0 :                 data->dpm_table.mem_table.dpm_state.soft_min_level =
    2601           0 :                         data->dpm_table.mem_table.dpm_levels[soft_min_level].value;
    2602           0 :                 data->dpm_table.mem_table.dpm_state.soft_max_level =
    2603           0 :                         data->dpm_table.mem_table.dpm_levels[soft_max_level].value;
    2604             : 
    2605           0 :                 ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_UCLK_MASK);
    2606           0 :                 PP_ASSERT_WITH_CODE(!ret,
    2607             :                         "Failed to upload boot level to lowest!",
    2608             :                         return ret);
    2609             : 
    2610           0 :                 ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_UCLK_MASK);
    2611           0 :                 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           0 :                 soft_min_level = mask ? (ffs(mask) - 1) : 0;
    2619           0 :                 soft_max_level = mask ? (fls(mask) - 1) : 0;
    2620             : 
    2621           0 :                 if (soft_max_level >= data->dpm_table.soc_table.count) {
    2622           0 :                         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           0 :                         return -EINVAL;
    2626             :                 }
    2627             : 
    2628           0 :                 data->dpm_table.soc_table.dpm_state.soft_min_level =
    2629           0 :                         data->dpm_table.soc_table.dpm_levels[soft_min_level].value;
    2630           0 :                 data->dpm_table.soc_table.dpm_state.soft_max_level =
    2631           0 :                         data->dpm_table.soc_table.dpm_levels[soft_max_level].value;
    2632             : 
    2633           0 :                 ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_SOCCLK_MASK);
    2634           0 :                 PP_ASSERT_WITH_CODE(!ret,
    2635             :                         "Failed to upload boot level to lowest!",
    2636             :                         return ret);
    2637             : 
    2638           0 :                 ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_SOCCLK_MASK);
    2639           0 :                 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           0 :                 soft_min_level = mask ? (ffs(mask) - 1) : 0;
    2647           0 :                 soft_max_level = mask ? (fls(mask) - 1) : 0;
    2648             : 
    2649           0 :                 if (soft_max_level >= data->dpm_table.fclk_table.count) {
    2650           0 :                         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           0 :                         return -EINVAL;
    2654             :                 }
    2655             : 
    2656           0 :                 data->dpm_table.fclk_table.dpm_state.soft_min_level =
    2657           0 :                         data->dpm_table.fclk_table.dpm_levels[soft_min_level].value;
    2658           0 :                 data->dpm_table.fclk_table.dpm_state.soft_max_level =
    2659           0 :                         data->dpm_table.fclk_table.dpm_levels[soft_max_level].value;
    2660             : 
    2661           0 :                 ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_FCLK_MASK);
    2662           0 :                 PP_ASSERT_WITH_CODE(!ret,
    2663             :                         "Failed to upload boot level to lowest!",
    2664             :                         return ret);
    2665             : 
    2666           0 :                 ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_FCLK_MASK);
    2667           0 :                 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           0 :                 hard_min_level = mask ? (ffs(mask) - 1) : 0;
    2675             : 
    2676           0 :                 if (hard_min_level >= data->dpm_table.dcef_table.count) {
    2677           0 :                         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           0 :                         return -EINVAL;
    2681             :                 }
    2682             : 
    2683           0 :                 data->dpm_table.dcef_table.dpm_state.hard_min_level =
    2684           0 :                         data->dpm_table.dcef_table.dpm_levels[hard_min_level].value;
    2685             : 
    2686           0 :                 ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_DCEFCLK_MASK);
    2687           0 :                 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           0 :                 soft_min_level = mask ? (ffs(mask) - 1) : 0;
    2697           0 :                 soft_max_level = mask ? (fls(mask) - 1) : 0;
    2698           0 :                 if (soft_min_level >= NUM_LINK_LEVELS ||
    2699           0 :                     soft_max_level >= NUM_LINK_LEVELS)
    2700             :                         return -EINVAL;
    2701             : 
    2702           0 :                 ret = smum_send_msg_to_smc_with_parameter(hwmgr,
    2703             :                         PPSMC_MSG_SetMinLinkDpmByIndex, soft_min_level,
    2704             :                         NULL);
    2705           0 :                 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           0 : static int vega20_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
    2719             :                                 enum amd_dpm_forced_level level)
    2720             : {
    2721           0 :         int ret = 0;
    2722             :         uint32_t sclk_mask, mclk_mask, soc_mask;
    2723             : 
    2724           0 :         switch (level) {
    2725             :         case AMD_DPM_FORCED_LEVEL_HIGH:
    2726           0 :                 ret = vega20_force_dpm_highest(hwmgr);
    2727           0 :                 break;
    2728             : 
    2729             :         case AMD_DPM_FORCED_LEVEL_LOW:
    2730           0 :                 ret = vega20_force_dpm_lowest(hwmgr);
    2731           0 :                 break;
    2732             : 
    2733             :         case AMD_DPM_FORCED_LEVEL_AUTO:
    2734           0 :                 ret = vega20_unforce_dpm_levels(hwmgr);
    2735           0 :                 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           0 :                 ret = vega20_get_profiling_clk_mask(hwmgr, level, &sclk_mask, &mclk_mask, &soc_mask);
    2742           0 :                 if (ret)
    2743             :                         return ret;
    2744           0 :                 vega20_force_clock_level(hwmgr, PP_SCLK, 1 << sclk_mask);
    2745           0 :                 vega20_force_clock_level(hwmgr, PP_MCLK, 1 << mclk_mask);
    2746           0 :                 vega20_force_clock_level(hwmgr, PP_SOCCLK, 1 << soc_mask);
    2747           0 :                 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           0 : static uint32_t vega20_get_fan_control_mode(struct pp_hwmgr *hwmgr)
    2759             : {
    2760           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    2761             : 
    2762           0 :         if (data->smu_features[GNLD_FAN_CONTROL].enabled == false)
    2763             :                 return AMD_FAN_CTRL_MANUAL;
    2764             :         else
    2765           0 :                 return AMD_FAN_CTRL_AUTO;
    2766             : }
    2767             : 
    2768           0 : static void vega20_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
    2769             : {
    2770           0 :         switch (mode) {
    2771             :         case AMD_FAN_CTRL_NONE:
    2772           0 :                 vega20_fan_ctrl_set_fan_speed_pwm(hwmgr, 255);
    2773           0 :                 break;
    2774             :         case AMD_FAN_CTRL_MANUAL:
    2775           0 :                 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
    2776           0 :                         vega20_fan_ctrl_stop_smc_fan_control(hwmgr);
    2777             :                 break;
    2778             :         case AMD_FAN_CTRL_AUTO:
    2779           0 :                 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
    2780           0 :                         vega20_fan_ctrl_start_smc_fan_control(hwmgr);
    2781             :                 break;
    2782             :         default:
    2783             :                 break;
    2784             :         }
    2785           0 : }
    2786             : 
    2787           0 : 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           0 :         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           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    2807           0 :         struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.gfx_table);
    2808             :         int i, count;
    2809             : 
    2810           0 :         if (!data->smu_features[GNLD_DPM_GFXCLK].enabled)
    2811             :                 return -1;
    2812             : 
    2813           0 :         count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
    2814           0 :         clocks->num_levels = count;
    2815             : 
    2816           0 :         for (i = 0; i < count; i++) {
    2817           0 :                 clocks->data[i].clocks_in_khz =
    2818           0 :                         dpm_table->dpm_levels[i].value * 1000;
    2819           0 :                 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           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    2835           0 :         struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.mem_table);
    2836             :         int i, count;
    2837             : 
    2838           0 :         if (!data->smu_features[GNLD_DPM_UCLK].enabled)
    2839             :                 return -1;
    2840             : 
    2841           0 :         count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
    2842           0 :         clocks->num_levels = data->mclk_latency_table.count = count;
    2843             : 
    2844           0 :         for (i = 0; i < count; i++) {
    2845           0 :                 clocks->data[i].clocks_in_khz =
    2846           0 :                         data->mclk_latency_table.entries[i].frequency =
    2847           0 :                         dpm_table->dpm_levels[i].value * 1000;
    2848           0 :                 clocks->data[i].latency_in_us =
    2849           0 :                         data->mclk_latency_table.entries[i].latency =
    2850           0 :                         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           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    2860           0 :         struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.dcef_table);
    2861             :         int i, count;
    2862             : 
    2863           0 :         if (!data->smu_features[GNLD_DPM_DCEFCLK].enabled)
    2864             :                 return -1;
    2865             : 
    2866           0 :         count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
    2867           0 :         clocks->num_levels = count;
    2868             : 
    2869           0 :         for (i = 0; i < count; i++) {
    2870           0 :                 clocks->data[i].clocks_in_khz =
    2871           0 :                         dpm_table->dpm_levels[i].value * 1000;
    2872           0 :                 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           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    2882           0 :         struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.soc_table);
    2883             :         int i, count;
    2884             : 
    2885           0 :         if (!data->smu_features[GNLD_DPM_SOCCLK].enabled)
    2886             :                 return -1;
    2887             : 
    2888           0 :         count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
    2889           0 :         clocks->num_levels = count;
    2890             : 
    2891           0 :         for (i = 0; i < count; i++) {
    2892           0 :                 clocks->data[i].clocks_in_khz =
    2893           0 :                         dpm_table->dpm_levels[i].value * 1000;
    2894           0 :                 clocks->data[i].latency_in_us = 0;
    2895             :         }
    2896             : 
    2897             :         return 0;
    2898             : 
    2899             : }
    2900             : 
    2901           0 : 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           0 :         switch (type) {
    2908             :         case amd_pp_sys_clock:
    2909           0 :                 ret = vega20_get_sclks(hwmgr, clocks);
    2910             :                 break;
    2911             :         case amd_pp_mem_clock:
    2912           0 :                 ret = vega20_get_memclocks(hwmgr, clocks);
    2913             :                 break;
    2914             :         case amd_pp_dcef_clock:
    2915           0 :                 ret = vega20_get_dcefclocks(hwmgr, clocks);
    2916             :                 break;
    2917             :         case amd_pp_soc_clock:
    2918           0 :                 ret = vega20_get_socclocks(hwmgr, clocks);
    2919             :                 break;
    2920             :         default:
    2921             :                 return -EINVAL;
    2922             :         }
    2923             : 
    2924             :         return ret;
    2925             : }
    2926             : 
    2927           0 : 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           0 :         clocks->num_levels = 0;
    2932             : 
    2933           0 :         return 0;
    2934             : }
    2935             : 
    2936           0 : static int vega20_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr,
    2937             :                                                    void *clock_ranges)
    2938             : {
    2939           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    2940           0 :         Watermarks_t *table = &(data->smc_state_table.water_marks_table);
    2941           0 :         struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges;
    2942             : 
    2943           0 :         if (!data->registry_data.disable_water_mark &&
    2944           0 :             data->smu_features[GNLD_DPM_DCEFCLK].supported &&
    2945           0 :             data->smu_features[GNLD_DPM_SOCCLK].supported) {
    2946           0 :                 smu_set_watermarks_for_clocks_ranges(table, wm_with_clock_ranges);
    2947           0 :                 data->water_marks_bitmap |= WaterMarksExist;
    2948           0 :                 data->water_marks_bitmap &= ~WaterMarksLoaded;
    2949             :         }
    2950             : 
    2951           0 :         return 0;
    2952             : }
    2953             : 
    2954           0 : 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           0 :         struct vega20_hwmgr *data =
    2959             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    2960           0 :         struct vega20_od8_single_setting *od8_settings =
    2961             :                         data->od8_settings.od8_settings_array;
    2962           0 :         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           0 :         PP_ASSERT_WITH_CODE(input, "NULL user input for clock and voltage",
    2969             :                                 return -EINVAL);
    2970             : 
    2971           0 :         switch (type) {
    2972             :         case PP_OD_EDIT_SCLK_VDDC_TABLE:
    2973           0 :                 if (!(od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
    2974           0 :                       od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id)) {
    2975           0 :                         pr_info("Sclk min/max frequency overdrive not supported\n");
    2976           0 :                         return -EOPNOTSUPP;
    2977             :                 }
    2978             : 
    2979           0 :                 for (i = 0; i < size; i += 2) {
    2980           0 :                         if (i + 2 > size) {
    2981           0 :                                 pr_info("invalid number of input parameters %d\n",
    2982             :                                         size);
    2983           0 :                                 return -EINVAL;
    2984             :                         }
    2985             : 
    2986           0 :                         input_index = input[i];
    2987           0 :                         input_clk = input[i + 1];
    2988             : 
    2989           0 :                         if (input_index != 0 && input_index != 1) {
    2990           0 :                                 pr_info("Invalid index %d\n", input_index);
    2991           0 :                                 pr_info("Support min/max sclk frequency setting only which index by 0/1\n");
    2992           0 :                                 return -EINVAL;
    2993             :                         }
    2994             : 
    2995           0 :                         if (input_clk < od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value ||
    2996           0 :                             input_clk > od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value) {
    2997           0 :                                 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           0 :                                 return -EINVAL;
    3002             :                         }
    3003             : 
    3004           0 :                         if ((input_index == 0 && od_table->GfxclkFmin != input_clk) ||
    3005           0 :                             (input_index == 1 && od_table->GfxclkFmax != input_clk))
    3006           0 :                                 data->gfxclk_overdrive = true;
    3007             : 
    3008           0 :                         if (input_index == 0)
    3009           0 :                                 od_table->GfxclkFmin = input_clk;
    3010             :                         else
    3011           0 :                                 od_table->GfxclkFmax = input_clk;
    3012             :                 }
    3013             : 
    3014             :                 break;
    3015             : 
    3016             :         case PP_OD_EDIT_MCLK_VDDC_TABLE:
    3017           0 :                 if (!od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
    3018           0 :                         pr_info("Mclk max frequency overdrive not supported\n");
    3019           0 :                         return -EOPNOTSUPP;
    3020             :                 }
    3021             : 
    3022           0 :                 for (i = 0; i < size; i += 2) {
    3023           0 :                         if (i + 2 > size) {
    3024           0 :                                 pr_info("invalid number of input parameters %d\n",
    3025             :                                         size);
    3026           0 :                                 return -EINVAL;
    3027             :                         }
    3028             : 
    3029           0 :                         input_index = input[i];
    3030           0 :                         input_clk = input[i + 1];
    3031             : 
    3032           0 :                         if (input_index != 1) {
    3033           0 :                                 pr_info("Invalid index %d\n", input_index);
    3034           0 :                                 pr_info("Support max Mclk frequency setting only which index by 1\n");
    3035           0 :                                 return -EINVAL;
    3036             :                         }
    3037             : 
    3038           0 :                         if (input_clk < od8_settings[OD8_SETTING_UCLK_FMAX].min_value ||
    3039           0 :                             input_clk > od8_settings[OD8_SETTING_UCLK_FMAX].max_value) {
    3040           0 :                                 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           0 :                                 return -EINVAL;
    3045             :                         }
    3046             : 
    3047           0 :                         if (input_index == 1 && od_table->UclkFmax != input_clk)
    3048           0 :                                 data->memclk_overdrive = true;
    3049             : 
    3050           0 :                         od_table->UclkFmax = input_clk;
    3051             :                 }
    3052             : 
    3053             :                 break;
    3054             : 
    3055             :         case PP_OD_EDIT_VDDC_CURVE:
    3056           0 :                 if (!(od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
    3057           0 :                     od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
    3058           0 :                     od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
    3059           0 :                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
    3060           0 :                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
    3061           0 :                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id)) {
    3062           0 :                         pr_info("Voltage curve calibrate not supported\n");
    3063           0 :                         return -EOPNOTSUPP;
    3064             :                 }
    3065             : 
    3066           0 :                 for (i = 0; i < size; i += 3) {
    3067           0 :                         if (i + 3 > size) {
    3068           0 :                                 pr_info("invalid number of input parameters %d\n",
    3069             :                                         size);
    3070           0 :                                 return -EINVAL;
    3071             :                         }
    3072             : 
    3073           0 :                         input_index = input[i];
    3074           0 :                         input_clk = input[i + 1];
    3075           0 :                         input_vol = input[i + 2];
    3076             : 
    3077           0 :                         if (input_index > 2) {
    3078           0 :                                 pr_info("Setting for point %d is not supported\n",
    3079             :                                                 input_index + 1);
    3080           0 :                                 pr_info("Three supported points index by 0, 1, 2\n");
    3081           0 :                                 return -EINVAL;
    3082             :                         }
    3083             : 
    3084           0 :                         od8_id = OD8_SETTING_GFXCLK_FREQ1 + 2 * input_index;
    3085           0 :                         if (input_clk < od8_settings[od8_id].min_value ||
    3086           0 :                             input_clk > od8_settings[od8_id].max_value) {
    3087           0 :                                 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           0 :                                 return -EINVAL;
    3092             :                         }
    3093             : 
    3094           0 :                         od8_id = OD8_SETTING_GFXCLK_VOLTAGE1 + 2 * input_index;
    3095           0 :                         if (input_vol < od8_settings[od8_id].min_value ||
    3096           0 :                             input_vol > od8_settings[od8_id].max_value) {
    3097           0 :                                 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           0 :                                 return -EINVAL;
    3102             :                         }
    3103             : 
    3104           0 :                         switch (input_index) {
    3105             :                         case 0:
    3106           0 :                                 od_table->GfxclkFreq1 = input_clk;
    3107           0 :                                 od_table->GfxclkVolt1 = input_vol * VOLTAGE_SCALE;
    3108           0 :                                 break;
    3109             :                         case 1:
    3110           0 :                                 od_table->GfxclkFreq2 = input_clk;
    3111           0 :                                 od_table->GfxclkVolt2 = input_vol * VOLTAGE_SCALE;
    3112           0 :                                 break;
    3113             :                         case 2:
    3114           0 :                                 od_table->GfxclkFreq3 = input_clk;
    3115           0 :                                 od_table->GfxclkVolt3 = input_vol * VOLTAGE_SCALE;
    3116           0 :                                 break;
    3117             :                         }
    3118             :                 }
    3119             :                 break;
    3120             : 
    3121             :         case PP_OD_RESTORE_DEFAULT_TABLE:
    3122           0 :                 data->gfxclk_overdrive = false;
    3123           0 :                 data->memclk_overdrive = false;
    3124             : 
    3125           0 :                 ret = smum_smc_table_manager(hwmgr,
    3126             :                                              (uint8_t *)od_table,
    3127             :                                              TABLE_OVERDRIVE, true);
    3128           0 :                 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           0 :                 ret = smum_smc_table_manager(hwmgr,
    3135             :                                              (uint8_t *)od_table,
    3136             :                                              TABLE_OVERDRIVE, false);
    3137           0 :                 PP_ASSERT_WITH_CODE(!ret,
    3138             :                                 "Failed to import overdrive table!",
    3139             :                                 return ret);
    3140             : 
    3141             :                 /* retrieve updated gfxclk table */
    3142           0 :                 if (data->gfxclk_overdrive) {
    3143           0 :                         data->gfxclk_overdrive = false;
    3144             : 
    3145           0 :                         ret = vega20_setup_gfxclk_dpm_table(hwmgr);
    3146           0 :                         if (ret)
    3147             :                                 return ret;
    3148             :                 }
    3149             : 
    3150             :                 /* retrieve updated memclk table */
    3151           0 :                 if (data->memclk_overdrive) {
    3152           0 :                         data->memclk_overdrive = false;
    3153             : 
    3154           0 :                         ret = vega20_setup_memclk_dpm_table(hwmgr);
    3155           0 :                         if (ret)
    3156             :                                 return ret;
    3157             :                 }
    3158             :                 break;
    3159             : 
    3160             :         default:
    3161             :                 return -EINVAL;
    3162             :         }
    3163             : 
    3164             :         return 0;
    3165             : }
    3166             : 
    3167           0 : 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           0 :         switch (mp1_state) {
    3174             :         case PP_MP1_STATE_SHUTDOWN:
    3175             :                 msg = PPSMC_MSG_PrepareMp1ForShutdown;
    3176             :                 break;
    3177             :         case PP_MP1_STATE_UNLOAD:
    3178           0 :                 msg = PPSMC_MSG_PrepareMp1ForUnload;
    3179           0 :                 break;
    3180             :         case PP_MP1_STATE_RESET:
    3181           0 :                 msg = PPSMC_MSG_PrepareMp1ForReset;
    3182           0 :                 break;
    3183             :         case PP_MP1_STATE_NONE:
    3184             :         default:
    3185             :                 return 0;
    3186             :         }
    3187             : 
    3188           0 :         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           0 : 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           0 :         int ret = 0;
    3239           0 :         int size = 0;
    3240             : 
    3241           0 :         phm_get_sysfs_buf(&buf, &size);
    3242             : 
    3243           0 :         ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
    3244           0 :         PP_ASSERT_WITH_CODE(!ret,
    3245             :                         "[EnableAllSmuFeatures] Failed to get enabled smc features!",
    3246             :                         return ret);
    3247             : 
    3248           0 :         size += sysfs_emit_at(buf, size, "Current ppfeatures: 0x%016llx\n", features_enabled);
    3249           0 :         size += sysfs_emit_at(buf, size, "%-19s %-22s %s\n",
    3250             :                                 output_title[0],
    3251             :                                 output_title[1],
    3252             :                                 output_title[2]);
    3253           0 :         for (i = 0; i < GNLD_FEATURES_MAX; i++) {
    3254           0 :                 size += sysfs_emit_at(buf, size, "%-19s 0x%016llx %6s\n",
    3255             :                                         ppfeature_name[i],
    3256             :                                         1ULL << i,
    3257           0 :                                         (features_enabled & (1ULL << i)) ? "Y" : "N");
    3258             :         }
    3259             : 
    3260             :         return size;
    3261             : }
    3262             : 
    3263           0 : static int vega20_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t new_ppfeature_masks)
    3264             : {
    3265           0 :         struct vega20_hwmgr *data =
    3266             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    3267             :         uint64_t features_enabled, features_to_enable, features_to_disable;
    3268           0 :         int i, ret = 0;
    3269             :         bool enabled;
    3270             : 
    3271           0 :         if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX))
    3272             :                 return -EINVAL;
    3273             : 
    3274           0 :         ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
    3275           0 :         if (ret)
    3276             :                 return ret;
    3277             : 
    3278           0 :         features_to_disable =
    3279           0 :                 features_enabled & ~new_ppfeature_masks;
    3280           0 :         features_to_enable =
    3281           0 :                 ~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           0 :         if (features_to_disable) {
    3287           0 :                 ret = vega20_enable_smc_features(hwmgr, false, features_to_disable);
    3288           0 :                 if (ret)
    3289             :                         return ret;
    3290             :         }
    3291             : 
    3292           0 :         if (features_to_enable) {
    3293           0 :                 ret = vega20_enable_smc_features(hwmgr, true, features_to_enable);
    3294           0 :                 if (ret)
    3295             :                         return ret;
    3296             :         }
    3297             : 
    3298             :         /* Update the cached feature enablement state */
    3299           0 :         ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
    3300           0 :         if (ret)
    3301             :                 return ret;
    3302             : 
    3303           0 :         for (i = 0; i < GNLD_FEATURES_MAX; i++) {
    3304           0 :                 enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ?
    3305             :                         true : false;
    3306           0 :                 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           0 :         struct amdgpu_device *adev = hwmgr->adev;
    3315             : 
    3316           0 :         return (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) &
    3317             :                 PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK)
    3318           0 :                 >> 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           0 :         width_level = vega20_get_current_pcie_link_width_level(hwmgr);
    3326           0 :         if (width_level > LINK_WIDTH_MAX)
    3327           0 :                 width_level = 0;
    3328             : 
    3329           0 :         return link_width[width_level];
    3330             : }
    3331             : 
    3332             : static int vega20_get_current_pcie_link_speed_level(struct pp_hwmgr *hwmgr)
    3333             : {
    3334           0 :         struct amdgpu_device *adev = hwmgr->adev;
    3335             : 
    3336           0 :         return (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) &
    3337             :                 PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK)
    3338           0 :                 >> 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           0 :         speed_level = vega20_get_current_pcie_link_speed_level(hwmgr);
    3346           0 :         if (speed_level > LINK_SPEED_MAX)
    3347           0 :                 speed_level = 0;
    3348             : 
    3349           0 :         return link_speed[speed_level];
    3350             : }
    3351             : 
    3352           0 : static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
    3353             :                 enum pp_clock_type type, char *buf)
    3354             : {
    3355           0 :         struct vega20_hwmgr *data =
    3356             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    3357           0 :         struct vega20_od8_single_setting *od8_settings =
    3358             :                         data->od8_settings.od8_settings_array;
    3359           0 :         OverDriveTable_t *od_table =
    3360             :                         &(data->smc_state_table.overdrive_table);
    3361           0 :         PPTable_t *pptable = &(data->smc_state_table.pp_table);
    3362             :         struct pp_clock_levels_with_latency clocks;
    3363           0 :         struct vega20_single_dpm_table *fclk_dpm_table =
    3364             :                         &(data->dpm_table.fclk_table);
    3365           0 :         int i, now, size = 0;
    3366           0 :         int ret = 0;
    3367             :         uint32_t gen_speed, lane_width, current_gen_speed, current_lane_width;
    3368             : 
    3369           0 :         switch (type) {
    3370             :         case PP_SCLK:
    3371           0 :                 ret = vega20_get_current_clk_freq(hwmgr, PPCLK_GFXCLK, &now);
    3372           0 :                 PP_ASSERT_WITH_CODE(!ret,
    3373             :                                 "Attempt to get current gfx clk Failed!",
    3374             :                                 return ret);
    3375             : 
    3376           0 :                 if (vega20_get_sclks(hwmgr, &clocks)) {
    3377           0 :                         size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
    3378             :                                 now / 100);
    3379           0 :                         break;
    3380             :                 }
    3381             : 
    3382           0 :                 for (i = 0; i < clocks.num_levels; i++)
    3383           0 :                         size += sprintf(buf + size, "%d: %uMhz %s\n",
    3384             :                                 i, clocks.data[i].clocks_in_khz / 1000,
    3385           0 :                                 (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
    3386             :                 break;
    3387             : 
    3388             :         case PP_MCLK:
    3389           0 :                 ret = vega20_get_current_clk_freq(hwmgr, PPCLK_UCLK, &now);
    3390           0 :                 PP_ASSERT_WITH_CODE(!ret,
    3391             :                                 "Attempt to get current mclk freq Failed!",
    3392             :                                 return ret);
    3393             : 
    3394           0 :                 if (vega20_get_memclocks(hwmgr, &clocks)) {
    3395           0 :                         size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
    3396             :                                 now / 100);
    3397           0 :                         break;
    3398             :                 }
    3399             : 
    3400           0 :                 for (i = 0; i < clocks.num_levels; i++)
    3401           0 :                         size += sprintf(buf + size, "%d: %uMhz %s\n",
    3402             :                                 i, clocks.data[i].clocks_in_khz / 1000,
    3403           0 :                                 (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
    3404             :                 break;
    3405             : 
    3406             :         case PP_SOCCLK:
    3407           0 :                 ret = vega20_get_current_clk_freq(hwmgr, PPCLK_SOCCLK, &now);
    3408           0 :                 PP_ASSERT_WITH_CODE(!ret,
    3409             :                                 "Attempt to get current socclk freq Failed!",
    3410             :                                 return ret);
    3411             : 
    3412           0 :                 if (vega20_get_socclocks(hwmgr, &clocks)) {
    3413           0 :                         size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
    3414             :                                 now / 100);
    3415           0 :                         break;
    3416             :                 }
    3417             : 
    3418           0 :                 for (i = 0; i < clocks.num_levels; i++)
    3419           0 :                         size += sprintf(buf + size, "%d: %uMhz %s\n",
    3420             :                                 i, clocks.data[i].clocks_in_khz / 1000,
    3421           0 :                                 (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
    3422             :                 break;
    3423             : 
    3424             :         case PP_FCLK:
    3425           0 :                 ret = vega20_get_current_clk_freq(hwmgr, PPCLK_FCLK, &now);
    3426           0 :                 PP_ASSERT_WITH_CODE(!ret,
    3427             :                                 "Attempt to get current fclk freq Failed!",
    3428             :                                 return ret);
    3429             : 
    3430           0 :                 for (i = 0; i < fclk_dpm_table->count; i++)
    3431           0 :                         size += sprintf(buf + size, "%d: %uMhz %s\n",
    3432             :                                 i, fclk_dpm_table->dpm_levels[i].value,
    3433           0 :                                 fclk_dpm_table->dpm_levels[i].value == (now / 100) ? "*" : "");
    3434             :                 break;
    3435             : 
    3436             :         case PP_DCEFCLK:
    3437           0 :                 ret = vega20_get_current_clk_freq(hwmgr, PPCLK_DCEFCLK, &now);
    3438           0 :                 PP_ASSERT_WITH_CODE(!ret,
    3439             :                                 "Attempt to get current dcefclk freq Failed!",
    3440             :                                 return ret);
    3441             : 
    3442           0 :                 if (vega20_get_dcefclocks(hwmgr, &clocks)) {
    3443           0 :                         size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
    3444             :                                 now / 100);
    3445           0 :                         break;
    3446             :                 }
    3447             : 
    3448           0 :                 for (i = 0; i < clocks.num_levels; i++)
    3449           0 :                         size += sprintf(buf + size, "%d: %uMhz %s\n",
    3450             :                                 i, clocks.data[i].clocks_in_khz / 1000,
    3451           0 :                                 (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
    3452             :                 break;
    3453             : 
    3454             :         case PP_PCIE:
    3455           0 :                 current_gen_speed =
    3456           0 :                         vega20_get_current_pcie_link_speed_level(hwmgr);
    3457           0 :                 current_lane_width =
    3458           0 :                         vega20_get_current_pcie_link_width_level(hwmgr);
    3459           0 :                 for (i = 0; i < NUM_LINK_LEVELS; i++) {
    3460           0 :                         gen_speed = pptable->PcieGenSpeed[i];
    3461           0 :                         lane_width = pptable->PcieLaneCount[i];
    3462             : 
    3463           0 :                         size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
    3464             :                                         (gen_speed == 0) ? "2.5GT/s," :
    3465           0 :                                         (gen_speed == 1) ? "5.0GT/s," :
    3466           0 :                                         (gen_speed == 2) ? "8.0GT/s," :
    3467           0 :                                         (gen_speed == 3) ? "16.0GT/s," : "",
    3468             :                                         (lane_width == 1) ? "x1" :
    3469           0 :                                         (lane_width == 2) ? "x2" :
    3470           0 :                                         (lane_width == 3) ? "x4" :
    3471           0 :                                         (lane_width == 4) ? "x8" :
    3472           0 :                                         (lane_width == 5) ? "x12" :
    3473           0 :                                         (lane_width == 6) ? "x16" : "",
    3474           0 :                                         pptable->LclkFreq[i],
    3475           0 :                                         (current_gen_speed == gen_speed) &&
    3476           0 :                                         (current_lane_width == lane_width) ?
    3477             :                                         "*" : "");
    3478             :                 }
    3479             :                 break;
    3480             : 
    3481             :         case OD_SCLK:
    3482           0 :                 if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
    3483           0 :                     od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
    3484           0 :                         size += sprintf(buf + size, "%s:\n", "OD_SCLK");
    3485           0 :                         size += sprintf(buf + size, "0: %10uMhz\n",
    3486           0 :                                 od_table->GfxclkFmin);
    3487           0 :                         size += sprintf(buf + size, "1: %10uMhz\n",
    3488           0 :                                 od_table->GfxclkFmax);
    3489             :                 }
    3490             :                 break;
    3491             : 
    3492             :         case OD_MCLK:
    3493           0 :                 if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
    3494           0 :                         size += sprintf(buf + size, "%s:\n", "OD_MCLK");
    3495           0 :                         size += sprintf(buf + size, "1: %10uMhz\n",
    3496           0 :                                 od_table->UclkFmax);
    3497             :                 }
    3498             : 
    3499             :                 break;
    3500             : 
    3501             :         case OD_VDDC_CURVE:
    3502           0 :                 if (od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
    3503           0 :                     od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
    3504           0 :                     od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
    3505           0 :                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
    3506           0 :                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
    3507           0 :                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
    3508           0 :                         size += sprintf(buf + size, "%s:\n", "OD_VDDC_CURVE");
    3509           0 :                         size += sprintf(buf + size, "0: %10uMhz %10dmV\n",
    3510           0 :                                 od_table->GfxclkFreq1,
    3511           0 :                                 od_table->GfxclkVolt1 / VOLTAGE_SCALE);
    3512           0 :                         size += sprintf(buf + size, "1: %10uMhz %10dmV\n",
    3513           0 :                                 od_table->GfxclkFreq2,
    3514           0 :                                 od_table->GfxclkVolt2 / VOLTAGE_SCALE);
    3515           0 :                         size += sprintf(buf + size, "2: %10uMhz %10dmV\n",
    3516           0 :                                 od_table->GfxclkFreq3,
    3517           0 :                                 od_table->GfxclkVolt3 / VOLTAGE_SCALE);
    3518             :                 }
    3519             : 
    3520             :                 break;
    3521             : 
    3522             :         case OD_RANGE:
    3523           0 :                 size += sprintf(buf + size, "%s:\n", "OD_RANGE");
    3524             : 
    3525           0 :                 if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
    3526           0 :                     od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
    3527           0 :                         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           0 :                 if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
    3533           0 :                         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           0 :                 if (od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
    3539           0 :                     od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
    3540           0 :                     od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
    3541           0 :                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
    3542           0 :                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
    3543           0 :                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
    3544           0 :                         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           0 :                         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           0 :                         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           0 :                         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           0 :                         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           0 :                         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           0 : static int vega20_set_uclk_to_highest_dpm_level(struct pp_hwmgr *hwmgr,
    3572             :                 struct vega20_single_dpm_table *dpm_table)
    3573             : {
    3574           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    3575           0 :         int ret = 0;
    3576             : 
    3577           0 :         if (data->smu_features[GNLD_DPM_UCLK].enabled) {
    3578           0 :                 PP_ASSERT_WITH_CODE(dpm_table->count > 0,
    3579             :                                 "[SetUclkToHightestDpmLevel] Dpm table has no entry!",
    3580             :                                 return -EINVAL);
    3581           0 :                 PP_ASSERT_WITH_CODE(dpm_table->count <= NUM_UCLK_DPM_LEVELS,
    3582             :                                 "[SetUclkToHightestDpmLevel] Dpm table has too many entries!",
    3583             :                                 return -EINVAL);
    3584             : 
    3585           0 :                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3586           0 :                 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           0 : static int vega20_set_fclk_to_highest_dpm_level(struct pp_hwmgr *hwmgr)
    3598             : {
    3599           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    3600           0 :         struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.fclk_table);
    3601           0 :         int ret = 0;
    3602             : 
    3603           0 :         if (data->smu_features[GNLD_DPM_FCLK].enabled) {
    3604           0 :                 PP_ASSERT_WITH_CODE(dpm_table->count > 0,
    3605             :                                 "[SetFclkToHightestDpmLevel] Dpm table has no entry!",
    3606             :                                 return -EINVAL);
    3607           0 :                 PP_ASSERT_WITH_CODE(dpm_table->count <= NUM_FCLK_DPM_LEVELS,
    3608             :                                 "[SetFclkToHightestDpmLevel] Dpm table has too many entries!",
    3609             :                                 return -EINVAL);
    3610             : 
    3611           0 :                 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3612           0 :                 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           0 : static int vega20_pre_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
    3624             : {
    3625           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    3626           0 :         int ret = 0;
    3627             : 
    3628           0 :         smum_send_msg_to_smc_with_parameter(hwmgr,
    3629             :                         PPSMC_MSG_NumOfDisplays, 0, NULL);
    3630             : 
    3631           0 :         ret = vega20_set_uclk_to_highest_dpm_level(hwmgr,
    3632             :                         &data->dpm_table.mem_table);
    3633           0 :         if (ret)
    3634             :                 return ret;
    3635             : 
    3636           0 :         return vega20_set_fclk_to_highest_dpm_level(hwmgr);
    3637             : }
    3638             : 
    3639           0 : static int vega20_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
    3640             : {
    3641           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    3642           0 :         int result = 0;
    3643           0 :         Watermarks_t *wm_table = &(data->smc_state_table.water_marks_table);
    3644             : 
    3645           0 :         if ((data->water_marks_bitmap & WaterMarksExist) &&
    3646             :             !(data->water_marks_bitmap & WaterMarksLoaded)) {
    3647           0 :                 result = smum_smc_table_manager(hwmgr,
    3648             :                                                 (uint8_t *)wm_table, TABLE_WATERMARKS, false);
    3649           0 :                 PP_ASSERT_WITH_CODE(!result,
    3650             :                                 "Failed to update WMTABLE!",
    3651             :                                 return result);
    3652           0 :                 data->water_marks_bitmap |= WaterMarksLoaded;
    3653             :         }
    3654             : 
    3655           0 :         if ((data->water_marks_bitmap & WaterMarksExist) &&
    3656           0 :             data->smu_features[GNLD_DPM_DCEFCLK].supported &&
    3657           0 :             data->smu_features[GNLD_DPM_SOCCLK].supported) {
    3658           0 :                 result = smum_send_msg_to_smc_with_parameter(hwmgr,
    3659             :                         PPSMC_MSG_NumOfDisplays,
    3660           0 :                         hwmgr->display_config->num_display,
    3661             :                         NULL);
    3662             :         }
    3663             : 
    3664             :         return result;
    3665             : }
    3666             : 
    3667           0 : static int vega20_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
    3668             : {
    3669           0 :         struct vega20_hwmgr *data =
    3670             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    3671           0 :         int ret = 0;
    3672             : 
    3673           0 :         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           0 :                 ret = vega20_enable_smc_features(hwmgr,
    3682             :                                 enable,
    3683             :                                 data->smu_features[GNLD_DPM_UVD].smu_feature_bitmap);
    3684           0 :                 PP_ASSERT_WITH_CODE(!ret,
    3685             :                                 "[EnableDisableUVDDPM] Attempt to Enable/Disable DPM UVD Failed!",
    3686             :                                 return ret);
    3687           0 :                 data->smu_features[GNLD_DPM_UVD].enabled = enable;
    3688             :         }
    3689             : 
    3690             :         return 0;
    3691             : }
    3692             : 
    3693           0 : static void vega20_power_gate_vce(struct pp_hwmgr *hwmgr, bool bgate)
    3694             : {
    3695           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    3696             : 
    3697           0 :         if (data->vce_power_gated == bgate)
    3698             :                 return ;
    3699             : 
    3700           0 :         data->vce_power_gated = bgate;
    3701           0 :         if (bgate) {
    3702           0 :                 vega20_enable_disable_vce_dpm(hwmgr, !bgate);
    3703           0 :                 amdgpu_device_ip_set_powergating_state(hwmgr->adev,
    3704             :                                                 AMD_IP_BLOCK_TYPE_VCE,
    3705             :                                                 AMD_PG_STATE_GATE);
    3706             :         } else {
    3707           0 :                 amdgpu_device_ip_set_powergating_state(hwmgr->adev,
    3708             :                                                 AMD_IP_BLOCK_TYPE_VCE,
    3709             :                                                 AMD_PG_STATE_UNGATE);
    3710           0 :                 vega20_enable_disable_vce_dpm(hwmgr, !bgate);
    3711             :         }
    3712             : 
    3713             : }
    3714             : 
    3715           0 : static void vega20_power_gate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
    3716             : {
    3717           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    3718             : 
    3719           0 :         if (data->uvd_power_gated == bgate)
    3720             :                 return ;
    3721             : 
    3722           0 :         data->uvd_power_gated = bgate;
    3723           0 :         vega20_enable_disable_uvd_dpm(hwmgr, !bgate);
    3724             : }
    3725             : 
    3726           0 : static int vega20_apply_clocks_adjust_rules(struct pp_hwmgr *hwmgr)
    3727             : {
    3728           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    3729             :         struct vega20_single_dpm_table *dpm_table;
    3730           0 :         bool vblank_too_short = false;
    3731             :         bool disable_mclk_switching;
    3732             :         bool disable_fclk_switching;
    3733             :         uint32_t i, latency;
    3734             : 
    3735           0 :         disable_mclk_switching = ((1 < hwmgr->display_config->num_display) &&
    3736           0 :                            !hwmgr->display_config->multi_monitor_in_sync) ||
    3737             :                             vblank_too_short;
    3738           0 :         latency = hwmgr->display_config->dce_tolerable_mclk_in_active_latency;
    3739             : 
    3740             :         /* gfxclk */
    3741           0 :         dpm_table = &(data->dpm_table.gfx_table);
    3742           0 :         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
    3743           0 :         dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
    3744           0 :         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
    3745           0 :         dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
    3746             : 
    3747           0 :         if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
    3748           0 :                 if (VEGA20_UMD_PSTATE_GFXCLK_LEVEL < dpm_table->count) {
    3749           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
    3750           0 :                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
    3751             :                 }
    3752             : 
    3753           0 :                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
    3754           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
    3755           0 :                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
    3756             :                 }
    3757             : 
    3758           0 :                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
    3759           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3760           0 :                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3761             :                 }
    3762             :         }
    3763             : 
    3764             :         /* memclk */
    3765           0 :         dpm_table = &(data->dpm_table.mem_table);
    3766           0 :         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
    3767           0 :         dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
    3768           0 :         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
    3769           0 :         dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
    3770             : 
    3771           0 :         if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
    3772           0 :                 if (VEGA20_UMD_PSTATE_MCLK_LEVEL < dpm_table->count) {
    3773           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
    3774           0 :                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
    3775             :                 }
    3776             : 
    3777           0 :                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
    3778           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
    3779           0 :                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
    3780             :                 }
    3781             : 
    3782           0 :                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
    3783           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3784           0 :                         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           0 :         if (dpm_table->dpm_state.hard_min_level < (hwmgr->display_config->min_mem_set_clock / 100))
    3790           0 :                 dpm_table->dpm_state.hard_min_level = hwmgr->display_config->min_mem_set_clock / 100;
    3791             : 
    3792             :         /* Hardmin is dependent on displayconfig */
    3793           0 :         if (disable_mclk_switching) {
    3794           0 :                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3795           0 :                 for (i = 0; i < data->mclk_latency_table.count - 1; i++) {
    3796           0 :                         if (data->mclk_latency_table.entries[i].latency <= latency) {
    3797           0 :                                 if (dpm_table->dpm_levels[i].value >= (hwmgr->display_config->min_mem_set_clock / 100)) {
    3798           0 :                                         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[i].value;
    3799           0 :                                         break;
    3800             :                                 }
    3801             :                         }
    3802             :                 }
    3803             :         }
    3804             : 
    3805           0 :         if (hwmgr->display_config->nb_pstate_switch_disable)
    3806           0 :                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3807             : 
    3808           0 :         if ((disable_mclk_switching &&
    3809           0 :             (dpm_table->dpm_state.hard_min_level == dpm_table->dpm_levels[dpm_table->count - 1].value)) ||
    3810           0 :              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           0 :                 disable_fclk_switching = false;
    3814             : 
    3815             :         /* fclk */
    3816           0 :         dpm_table = &(data->dpm_table.fclk_table);
    3817           0 :         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
    3818           0 :         dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
    3819           0 :         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
    3820           0 :         dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
    3821           0 :         if (hwmgr->display_config->nb_pstate_switch_disable || disable_fclk_switching)
    3822           0 :                 dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3823             : 
    3824             :         /* vclk */
    3825           0 :         dpm_table = &(data->dpm_table.vclk_table);
    3826           0 :         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
    3827           0 :         dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
    3828           0 :         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
    3829           0 :         dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
    3830             : 
    3831           0 :         if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
    3832           0 :                 if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
    3833           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
    3834           0 :                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
    3835             :                 }
    3836             : 
    3837           0 :                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
    3838           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3839           0 :                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3840             :                 }
    3841             :         }
    3842             : 
    3843             :         /* dclk */
    3844           0 :         dpm_table = &(data->dpm_table.dclk_table);
    3845           0 :         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
    3846           0 :         dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
    3847           0 :         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
    3848           0 :         dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
    3849             : 
    3850           0 :         if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
    3851           0 :                 if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
    3852           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
    3853           0 :                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
    3854             :                 }
    3855             : 
    3856           0 :                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
    3857           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3858           0 :                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3859             :                 }
    3860             :         }
    3861             : 
    3862             :         /* socclk */
    3863           0 :         dpm_table = &(data->dpm_table.soc_table);
    3864           0 :         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
    3865           0 :         dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
    3866           0 :         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
    3867           0 :         dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
    3868             : 
    3869           0 :         if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
    3870           0 :                 if (VEGA20_UMD_PSTATE_SOCCLK_LEVEL < dpm_table->count) {
    3871           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
    3872           0 :                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
    3873             :                 }
    3874             : 
    3875           0 :                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
    3876           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3877           0 :                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3878             :                 }
    3879             :         }
    3880             : 
    3881             :         /* eclk */
    3882           0 :         dpm_table = &(data->dpm_table.eclk_table);
    3883           0 :         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
    3884           0 :         dpm_table->dpm_state.soft_max_level = VG20_CLOCK_MAX_DEFAULT;
    3885           0 :         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
    3886           0 :         dpm_table->dpm_state.hard_max_level = VG20_CLOCK_MAX_DEFAULT;
    3887             : 
    3888           0 :         if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
    3889           0 :                 if (VEGA20_UMD_PSTATE_VCEMCLK_LEVEL < dpm_table->count) {
    3890           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
    3891           0 :                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
    3892             :                 }
    3893             : 
    3894           0 :                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
    3895           0 :                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3896           0 :                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
    3897             :                 }
    3898             :         }
    3899             : 
    3900           0 :         return 0;
    3901             : }
    3902             : 
    3903             : static bool
    3904           0 : vega20_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
    3905             : {
    3906           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    3907           0 :         bool is_update_required = false;
    3908             : 
    3909           0 :         if (data->display_timing.num_existing_displays !=
    3910           0 :                         hwmgr->display_config->num_display)
    3911           0 :                 is_update_required = true;
    3912             : 
    3913           0 :         if (data->registry_data.gfx_clk_deep_sleep_support &&
    3914           0 :            (data->display_timing.min_clock_in_sr !=
    3915           0 :             hwmgr->display_config->min_core_set_clock_in_sr))
    3916           0 :                 is_update_required = true;
    3917             : 
    3918           0 :         return is_update_required;
    3919             : }
    3920             : 
    3921           0 : static int vega20_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
    3922             : {
    3923           0 :         int ret = 0;
    3924             : 
    3925           0 :         ret = vega20_disable_all_smu_features(hwmgr);
    3926           0 :         PP_ASSERT_WITH_CODE(!ret,
    3927             :                         "[DisableDpmTasks] Failed to disable all smu features!",
    3928             :                         return ret);
    3929             : 
    3930             :         return 0;
    3931             : }
    3932             : 
    3933           0 : static int vega20_power_off_asic(struct pp_hwmgr *hwmgr)
    3934             : {
    3935           0 :         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
    3936             :         int result;
    3937             : 
    3938           0 :         result = vega20_disable_dpm_tasks(hwmgr);
    3939           0 :         PP_ASSERT_WITH_CODE((0 == result),
    3940             :                         "[PowerOffAsic] Failed to disable DPM!",
    3941             :                         );
    3942           0 :         data->water_marks_bitmap &= ~(WaterMarksLoaded);
    3943             : 
    3944           0 :         return result;
    3945             : }
    3946             : 
    3947             : static int conv_power_profile_to_pplib_workload(int power_profile)
    3948             : {
    3949           0 :         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           0 : static int vega20_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
    3979             : {
    3980             :         DpmActivityMonitorCoeffInt_t activity_monitor;
    3981           0 :         uint32_t i, size = 0;
    3982           0 :         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           0 :         int result = 0;
    3996             : 
    3997           0 :         if (!buf)
    3998             :                 return -EINVAL;
    3999             : 
    4000           0 :         phm_get_sysfs_buf(&buf, &size);
    4001             : 
    4002           0 :         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           0 :         for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
    4007             :                 /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
    4008           0 :                 workload_type = conv_power_profile_to_pplib_workload(i);
    4009           0 :                 result = vega20_get_activity_monitor_coeff(hwmgr,
    4010             :                                 (uint8_t *)(&activity_monitor), workload_type);
    4011           0 :                 PP_ASSERT_WITH_CODE(!result,
    4012             :                                 "[GetPowerProfile] Failed to get activity monitor!",
    4013             :                                 return result);
    4014             : 
    4015           0 :                 size += sysfs_emit_at(buf, size, "%2d %14s%s:\n",
    4016           0 :                         i, amdgpu_pp_profile_name[i], (i == hwmgr->power_profile_mode) ? "*" : " ");
    4017             : 
    4018           0 :                 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           0 :                         activity_monitor.Gfx_FPS,
    4023           0 :                         activity_monitor.Gfx_UseRlcBusy,
    4024           0 :                         activity_monitor.Gfx_MinActiveFreqType,
    4025           0 :                         activity_monitor.Gfx_MinActiveFreq,
    4026           0 :                         activity_monitor.Gfx_BoosterFreqType,
    4027           0 :                         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           0 :                 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           0 :                         activity_monitor.Soc_FPS,
    4037           0 :                         activity_monitor.Soc_UseRlcBusy,
    4038           0 :                         activity_monitor.Soc_MinActiveFreqType,
    4039           0 :                         activity_monitor.Soc_MinActiveFreq,
    4040           0 :                         activity_monitor.Soc_BoosterFreqType,
    4041           0 :                         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           0 :                 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           0 :                         activity_monitor.Mem_FPS,
    4051           0 :                         activity_monitor.Mem_UseRlcBusy,
    4052           0 :                         activity_monitor.Mem_MinActiveFreqType,
    4053           0 :                         activity_monitor.Mem_MinActiveFreq,
    4054           0 :                         activity_monitor.Mem_BoosterFreqType,
    4055           0 :                         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           0 :                 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           0 :                         activity_monitor.Fclk_FPS,
    4065           0 :                         activity_monitor.Fclk_UseRlcBusy,
    4066           0 :                         activity_monitor.Fclk_MinActiveFreqType,
    4067           0 :                         activity_monitor.Fclk_MinActiveFreq,
    4068           0 :                         activity_monitor.Fclk_BoosterFreqType,
    4069           0 :                         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           0 :         return size;
    4076             : }
    4077             : 
    4078           0 : static int vega20_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint32_t size)
    4079             : {
    4080             :         DpmActivityMonitorCoeffInt_t activity_monitor;
    4081           0 :         int workload_type, result = 0;
    4082           0 :         uint32_t power_profile_mode = input[size];
    4083             : 
    4084           0 :         if (power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
    4085           0 :                 pr_err("Invalid power profile mode %d\n", power_profile_mode);
    4086           0 :                 return -EINVAL;
    4087             :         }
    4088             : 
    4089           0 :         if (power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
    4090           0 :                 struct vega20_hwmgr *data =
    4091             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    4092           0 :                 if (size == 0 && !data->is_custom_profile_set)
    4093             :                         return -EINVAL;
    4094           0 :                 if (size < 10 && size != 0)
    4095             :                         return -EINVAL;
    4096             : 
    4097           0 :                 result = vega20_get_activity_monitor_coeff(hwmgr,
    4098             :                                 (uint8_t *)(&activity_monitor),
    4099             :                                 WORKLOAD_PPLIB_CUSTOM_BIT);
    4100           0 :                 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           0 :                 if (size == 0)
    4109             :                         goto out;
    4110             : 
    4111           0 :                 switch (input[0]) {
    4112             :                 case 0: /* Gfxclk */
    4113           0 :                         activity_monitor.Gfx_FPS = input[1];
    4114           0 :                         activity_monitor.Gfx_UseRlcBusy = input[2];
    4115           0 :                         activity_monitor.Gfx_MinActiveFreqType = input[3];
    4116           0 :                         activity_monitor.Gfx_MinActiveFreq = input[4];
    4117           0 :                         activity_monitor.Gfx_BoosterFreqType = input[5];
    4118           0 :                         activity_monitor.Gfx_BoosterFreq = input[6];
    4119           0 :                         activity_monitor.Gfx_PD_Data_limit_c = input[7];
    4120           0 :                         activity_monitor.Gfx_PD_Data_error_coeff = input[8];
    4121           0 :                         activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
    4122           0 :                         break;
    4123             :                 case 1: /* Socclk */
    4124           0 :                         activity_monitor.Soc_FPS = input[1];
    4125           0 :                         activity_monitor.Soc_UseRlcBusy = input[2];
    4126           0 :                         activity_monitor.Soc_MinActiveFreqType = input[3];
    4127           0 :                         activity_monitor.Soc_MinActiveFreq = input[4];
    4128           0 :                         activity_monitor.Soc_BoosterFreqType = input[5];
    4129           0 :                         activity_monitor.Soc_BoosterFreq = input[6];
    4130           0 :                         activity_monitor.Soc_PD_Data_limit_c = input[7];
    4131           0 :                         activity_monitor.Soc_PD_Data_error_coeff = input[8];
    4132           0 :                         activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
    4133           0 :                         break;
    4134             :                 case 2: /* Uclk */
    4135           0 :                         activity_monitor.Mem_FPS = input[1];
    4136           0 :                         activity_monitor.Mem_UseRlcBusy = input[2];
    4137           0 :                         activity_monitor.Mem_MinActiveFreqType = input[3];
    4138           0 :                         activity_monitor.Mem_MinActiveFreq = input[4];
    4139           0 :                         activity_monitor.Mem_BoosterFreqType = input[5];
    4140           0 :                         activity_monitor.Mem_BoosterFreq = input[6];
    4141           0 :                         activity_monitor.Mem_PD_Data_limit_c = input[7];
    4142           0 :                         activity_monitor.Mem_PD_Data_error_coeff = input[8];
    4143           0 :                         activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
    4144           0 :                         break;
    4145             :                 case 3: /* Fclk */
    4146           0 :                         activity_monitor.Fclk_FPS = input[1];
    4147           0 :                         activity_monitor.Fclk_UseRlcBusy = input[2];
    4148           0 :                         activity_monitor.Fclk_MinActiveFreqType = input[3];
    4149           0 :                         activity_monitor.Fclk_MinActiveFreq = input[4];
    4150           0 :                         activity_monitor.Fclk_BoosterFreqType = input[5];
    4151           0 :                         activity_monitor.Fclk_BoosterFreq = input[6];
    4152           0 :                         activity_monitor.Fclk_PD_Data_limit_c = input[7];
    4153           0 :                         activity_monitor.Fclk_PD_Data_error_coeff = input[8];
    4154           0 :                         activity_monitor.Fclk_PD_Data_error_rate_coeff = input[9];
    4155           0 :                         break;
    4156             :                 }
    4157             : 
    4158           0 :                 result = vega20_set_activity_monitor_coeff(hwmgr,
    4159             :                                 (uint8_t *)(&activity_monitor),
    4160             :                                 WORKLOAD_PPLIB_CUSTOM_BIT);
    4161           0 :                 data->is_custom_profile_set = true;
    4162           0 :                 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           0 :         workload_type =
    4170           0 :                 conv_power_profile_to_pplib_workload(power_profile_mode);
    4171           0 :         smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetWorkloadMask,
    4172           0 :                                                 1 << workload_type,
    4173             :                                                 NULL);
    4174             : 
    4175           0 :         hwmgr->power_profile_mode = power_profile_mode;
    4176             : 
    4177           0 :         return 0;
    4178             : }
    4179             : 
    4180           0 : 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           0 :         smum_send_msg_to_smc_with_parameter(hwmgr,
    4188             :                                         PPSMC_MSG_SetSystemVirtualDramAddrHigh,
    4189             :                                         virtual_addr_hi,
    4190             :                                         NULL);
    4191           0 :         smum_send_msg_to_smc_with_parameter(hwmgr,
    4192             :                                         PPSMC_MSG_SetSystemVirtualDramAddrLow,
    4193             :                                         virtual_addr_low,
    4194             :                                         NULL);
    4195           0 :         smum_send_msg_to_smc_with_parameter(hwmgr,
    4196             :                                         PPSMC_MSG_DramLogSetDramAddrHigh,
    4197             :                                         mc_addr_hi,
    4198             :                                         NULL);
    4199             : 
    4200           0 :         smum_send_msg_to_smc_with_parameter(hwmgr,
    4201             :                                         PPSMC_MSG_DramLogSetDramAddrLow,
    4202             :                                         mc_addr_low,
    4203             :                                         NULL);
    4204             : 
    4205           0 :         smum_send_msg_to_smc_with_parameter(hwmgr,
    4206             :                                         PPSMC_MSG_DramLogSetDramSize,
    4207             :                                         size,
    4208             :                                         NULL);
    4209           0 :         return 0;
    4210             : }
    4211             : 
    4212           0 : static int vega20_get_thermal_temperature_range(struct pp_hwmgr *hwmgr,
    4213             :                 struct PP_TemperatureRange *thermal_data)
    4214             : {
    4215           0 :         struct vega20_hwmgr *data =
    4216             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    4217           0 :         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
    4218             : 
    4219           0 :         memcpy(thermal_data, &SMU7ThermalWithDelayPolicy[0], sizeof(struct PP_TemperatureRange));
    4220             : 
    4221           0 :         thermal_data->max = pp_table->TedgeLimit *
    4222             :                 PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
    4223           0 :         thermal_data->edge_emergency_max = (pp_table->TedgeLimit + CTF_OFFSET_EDGE) *
    4224             :                 PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
    4225           0 :         thermal_data->hotspot_crit_max = pp_table->ThotspotLimit *
    4226             :                 PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
    4227           0 :         thermal_data->hotspot_emergency_max = (pp_table->ThotspotLimit + CTF_OFFSET_HOTSPOT) *
    4228             :                 PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
    4229           0 :         thermal_data->mem_crit_max = pp_table->ThbmLimit *
    4230             :                 PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
    4231           0 :         thermal_data->mem_emergency_max = (pp_table->ThbmLimit + CTF_OFFSET_HBM)*
    4232             :                 PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
    4233             : 
    4234           0 :         return 0;
    4235             : }
    4236             : 
    4237           0 : 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           0 :         if (!vega20_is_smc_ram_running(hwmgr))
    4243             :                 return 0;
    4244             : 
    4245           0 :         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           0 :         PP_ASSERT_WITH_CODE(!res, "[SmuI2CAccessBus] Failed to access bus!", return res);
    4253             :         return res;
    4254             : }
    4255             : 
    4256           0 : 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           0 :         if (hwmgr->smu_version < 0x283200) {
    4263           0 :                 pr_err("Df cstate control is supported with 40.50 and later SMC fw!\n");
    4264           0 :                 return -EINVAL;
    4265             :         }
    4266             : 
    4267           0 :         ret = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DFCstateControl, state,
    4268             :                                 NULL);
    4269           0 :         if (ret)
    4270           0 :                 pr_err("SetDfCstate failed!\n");
    4271             : 
    4272             :         return ret;
    4273             : }
    4274             : 
    4275           0 : static int vega20_set_xgmi_pstate(struct pp_hwmgr *hwmgr,
    4276             :                                   uint32_t pstate)
    4277             : {
    4278             :         int ret;
    4279             : 
    4280           0 :         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           0 :         if (ret)
    4285           0 :                 pr_err("SetXgmiPstate failed!\n");
    4286             : 
    4287           0 :         return ret;
    4288             : }
    4289             : 
    4290           0 : static void vega20_init_gpu_metrics_v1_0(struct gpu_metrics_v1_0 *gpu_metrics)
    4291             : {
    4292           0 :         memset(gpu_metrics, 0xFF, sizeof(struct gpu_metrics_v1_0));
    4293             : 
    4294           0 :         gpu_metrics->common_header.structure_size =
    4295             :                                 sizeof(struct gpu_metrics_v1_0);
    4296           0 :         gpu_metrics->common_header.format_revision = 1;
    4297           0 :         gpu_metrics->common_header.content_revision = 0;
    4298             : 
    4299           0 :         gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
    4300           0 : }
    4301             : 
    4302           0 : static ssize_t vega20_get_gpu_metrics(struct pp_hwmgr *hwmgr,
    4303             :                                       void **table)
    4304             : {
    4305           0 :         struct vega20_hwmgr *data =
    4306             :                         (struct vega20_hwmgr *)(hwmgr->backend);
    4307           0 :         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           0 :         ret = vega20_get_metrics_table(hwmgr, &metrics, true);
    4314           0 :         if (ret)
    4315           0 :                 return ret;
    4316             : 
    4317           0 :         vega20_init_gpu_metrics_v1_0(gpu_metrics);
    4318             : 
    4319           0 :         gpu_metrics->temperature_edge = metrics.TemperatureEdge;
    4320           0 :         gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot;
    4321           0 :         gpu_metrics->temperature_mem = metrics.TemperatureHBM;
    4322           0 :         gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx;
    4323           0 :         gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc;
    4324           0 :         gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem0;
    4325             : 
    4326           0 :         gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity;
    4327           0 :         gpu_metrics->average_umc_activity = metrics.AverageUclkActivity;
    4328             : 
    4329           0 :         gpu_metrics->average_socket_power = metrics.AverageSocketPower;
    4330             : 
    4331           0 :         gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency;
    4332           0 :         gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency;
    4333           0 :         gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency;
    4334             : 
    4335           0 :         gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK];
    4336           0 :         gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK];
    4337           0 :         gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK];
    4338           0 :         gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK];
    4339           0 :         gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK];
    4340             : 
    4341           0 :         gpu_metrics->throttle_status = metrics.ThrottlerStatus;
    4342             : 
    4343           0 :         vega20_fan_ctrl_get_fan_speed_rpm(hwmgr, &fan_speed_rpm);
    4344           0 :         gpu_metrics->current_fan_speed = (uint16_t)fan_speed_rpm;
    4345             : 
    4346           0 :         gpu_metrics->pcie_link_width =
    4347           0 :                         vega20_get_current_pcie_link_width(hwmgr);
    4348           0 :         gpu_metrics->pcie_link_speed =
    4349           0 :                         vega20_get_current_pcie_link_speed(hwmgr);
    4350             : 
    4351           0 :         *table = (void *)gpu_metrics;
    4352             : 
    4353           0 :         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           0 : int vega20_hwmgr_init(struct pp_hwmgr *hwmgr)
    4430             : {
    4431           0 :         hwmgr->hwmgr_func = &vega20_hwmgr_funcs;
    4432           0 :         hwmgr->pptable_func = &vega20_pptable_funcs;
    4433             : 
    4434           0 :         return 0;
    4435             : }

Generated by: LCOV version 1.14