Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2016 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  */
0023 
0024 #include <linux/delay.h>
0025 #include <linux/fb.h>
0026 #include <linux/module.h>
0027 #include <linux/pci.h>
0028 #include <linux/slab.h>
0029 
0030 #include "hwmgr.h"
0031 #include "amd_powerplay.h"
0032 #include "hardwaremanager.h"
0033 #include "ppatomfwctrl.h"
0034 #include "atomfirmware.h"
0035 #include "cgs_common.h"
0036 #include "vega10_powertune.h"
0037 #include "smu9.h"
0038 #include "smu9_driver_if.h"
0039 #include "vega10_inc.h"
0040 #include "soc15_common.h"
0041 #include "pppcielanes.h"
0042 #include "vega10_hwmgr.h"
0043 #include "vega10_smumgr.h"
0044 #include "vega10_processpptables.h"
0045 #include "vega10_pptable.h"
0046 #include "vega10_thermal.h"
0047 #include "pp_debug.h"
0048 #include "amd_pcie_helpers.h"
0049 #include "ppinterrupt.h"
0050 #include "pp_overdriver.h"
0051 #include "pp_thermal.h"
0052 #include "vega10_baco.h"
0053 
0054 #include "smuio/smuio_9_0_offset.h"
0055 #include "smuio/smuio_9_0_sh_mask.h"
0056 
0057 #define smnPCIE_LC_SPEED_CNTL           0x11140290
0058 #define smnPCIE_LC_LINK_WIDTH_CNTL      0x11140288
0059 
0060 #define HBM_MEMORY_CHANNEL_WIDTH    128
0061 
0062 static const uint32_t channel_number[] = {1, 2, 0, 4, 0, 8, 0, 16, 2};
0063 
0064 #define mmDF_CS_AON0_DramBaseAddress0                                                                  0x0044
0065 #define mmDF_CS_AON0_DramBaseAddress0_BASE_IDX                                                         0
0066 
0067 //DF_CS_AON0_DramBaseAddress0
0068 #define DF_CS_AON0_DramBaseAddress0__AddrRngVal__SHIFT                                                        0x0
0069 #define DF_CS_AON0_DramBaseAddress0__LgcyMmioHoleEn__SHIFT                                                    0x1
0070 #define DF_CS_AON0_DramBaseAddress0__IntLvNumChan__SHIFT                                                      0x4
0071 #define DF_CS_AON0_DramBaseAddress0__IntLvAddrSel__SHIFT                                                      0x8
0072 #define DF_CS_AON0_DramBaseAddress0__DramBaseAddr__SHIFT                                                      0xc
0073 #define DF_CS_AON0_DramBaseAddress0__AddrRngVal_MASK                                                          0x00000001L
0074 #define DF_CS_AON0_DramBaseAddress0__LgcyMmioHoleEn_MASK                                                      0x00000002L
0075 #define DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK                                                        0x000000F0L
0076 #define DF_CS_AON0_DramBaseAddress0__IntLvAddrSel_MASK                                                        0x00000700L
0077 #define DF_CS_AON0_DramBaseAddress0__DramBaseAddr_MASK                                                        0xFFFFF000L
0078 
0079 typedef enum {
0080     CLK_SMNCLK = 0,
0081     CLK_SOCCLK,
0082     CLK_MP0CLK,
0083     CLK_MP1CLK,
0084     CLK_LCLK,
0085     CLK_DCEFCLK,
0086     CLK_VCLK,
0087     CLK_DCLK,
0088     CLK_ECLK,
0089     CLK_UCLK,
0090     CLK_GFXCLK,
0091     CLK_COUNT,
0092 } CLOCK_ID_e;
0093 
0094 static const ULONG PhwVega10_Magic = (ULONG)(PHM_VIslands_Magic);
0095 
0096 static struct vega10_power_state *cast_phw_vega10_power_state(
0097                   struct pp_hw_power_state *hw_ps)
0098 {
0099     PP_ASSERT_WITH_CODE((PhwVega10_Magic == hw_ps->magic),
0100                 "Invalid Powerstate Type!",
0101                  return NULL;);
0102 
0103     return (struct vega10_power_state *)hw_ps;
0104 }
0105 
0106 static const struct vega10_power_state *cast_const_phw_vega10_power_state(
0107                  const struct pp_hw_power_state *hw_ps)
0108 {
0109     PP_ASSERT_WITH_CODE((PhwVega10_Magic == hw_ps->magic),
0110                 "Invalid Powerstate Type!",
0111                  return NULL;);
0112 
0113     return (const struct vega10_power_state *)hw_ps;
0114 }
0115 
0116 static void vega10_set_default_registry_data(struct pp_hwmgr *hwmgr)
0117 {
0118     struct vega10_hwmgr *data = hwmgr->backend;
0119 
0120     data->registry_data.sclk_dpm_key_disabled =
0121             hwmgr->feature_mask & PP_SCLK_DPM_MASK ? false : true;
0122     data->registry_data.socclk_dpm_key_disabled =
0123             hwmgr->feature_mask & PP_SOCCLK_DPM_MASK ? false : true;
0124     data->registry_data.mclk_dpm_key_disabled =
0125             hwmgr->feature_mask & PP_MCLK_DPM_MASK ? false : true;
0126     data->registry_data.pcie_dpm_key_disabled =
0127             hwmgr->feature_mask & PP_PCIE_DPM_MASK ? false : true;
0128 
0129     data->registry_data.dcefclk_dpm_key_disabled =
0130             hwmgr->feature_mask & PP_DCEFCLK_DPM_MASK ? false : true;
0131 
0132     if (hwmgr->feature_mask & PP_POWER_CONTAINMENT_MASK) {
0133         data->registry_data.power_containment_support = 1;
0134         data->registry_data.enable_pkg_pwr_tracking_feature = 1;
0135         data->registry_data.enable_tdc_limit_feature = 1;
0136     }
0137 
0138     data->registry_data.clock_stretcher_support =
0139             hwmgr->feature_mask & PP_CLOCK_STRETCH_MASK ? true : false;
0140 
0141     data->registry_data.ulv_support =
0142             hwmgr->feature_mask & PP_ULV_MASK ? true : false;
0143 
0144     data->registry_data.sclk_deep_sleep_support =
0145             hwmgr->feature_mask & PP_SCLK_DEEP_SLEEP_MASK ? true : false;
0146 
0147     data->registry_data.disable_water_mark = 0;
0148 
0149     data->registry_data.fan_control_support = 1;
0150     data->registry_data.thermal_support = 1;
0151     data->registry_data.fw_ctf_enabled = 1;
0152 
0153     data->registry_data.avfs_support =
0154         hwmgr->feature_mask & PP_AVFS_MASK ? true : false;
0155     data->registry_data.led_dpm_enabled = 1;
0156 
0157     data->registry_data.vr0hot_enabled = 1;
0158     data->registry_data.vr1hot_enabled = 1;
0159     data->registry_data.regulator_hot_gpio_support = 1;
0160 
0161     data->registry_data.didt_support = 1;
0162     if (data->registry_data.didt_support) {
0163         data->registry_data.didt_mode = 6;
0164         data->registry_data.sq_ramping_support = 1;
0165         data->registry_data.db_ramping_support = 0;
0166         data->registry_data.td_ramping_support = 0;
0167         data->registry_data.tcp_ramping_support = 0;
0168         data->registry_data.dbr_ramping_support = 0;
0169         data->registry_data.edc_didt_support = 1;
0170         data->registry_data.gc_didt_support = 0;
0171         data->registry_data.psm_didt_support = 0;
0172     }
0173 
0174     data->display_voltage_mode = PPVEGA10_VEGA10DISPLAYVOLTAGEMODE_DFLT;
0175     data->dcef_clk_quad_eqn_a = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
0176     data->dcef_clk_quad_eqn_b = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
0177     data->dcef_clk_quad_eqn_c = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
0178     data->disp_clk_quad_eqn_a = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
0179     data->disp_clk_quad_eqn_b = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
0180     data->disp_clk_quad_eqn_c = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
0181     data->pixel_clk_quad_eqn_a = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
0182     data->pixel_clk_quad_eqn_b = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
0183     data->pixel_clk_quad_eqn_c = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
0184     data->phy_clk_quad_eqn_a = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
0185     data->phy_clk_quad_eqn_b = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
0186     data->phy_clk_quad_eqn_c = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
0187 
0188     data->gfxclk_average_alpha = PPVEGA10_VEGA10GFXCLKAVERAGEALPHA_DFLT;
0189     data->socclk_average_alpha = PPVEGA10_VEGA10SOCCLKAVERAGEALPHA_DFLT;
0190     data->uclk_average_alpha = PPVEGA10_VEGA10UCLKCLKAVERAGEALPHA_DFLT;
0191     data->gfx_activity_average_alpha = PPVEGA10_VEGA10GFXACTIVITYAVERAGEALPHA_DFLT;
0192 }
0193 
0194 static int vega10_set_features_platform_caps(struct pp_hwmgr *hwmgr)
0195 {
0196     struct vega10_hwmgr *data = hwmgr->backend;
0197     struct phm_ppt_v2_information *table_info =
0198             (struct phm_ppt_v2_information *)hwmgr->pptable;
0199     struct amdgpu_device *adev = hwmgr->adev;
0200 
0201     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0202             PHM_PlatformCaps_SclkDeepSleep);
0203 
0204     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0205             PHM_PlatformCaps_DynamicPatchPowerState);
0206 
0207     if (data->vddci_control == VEGA10_VOLTAGE_CONTROL_NONE)
0208         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0209                 PHM_PlatformCaps_ControlVDDCI);
0210 
0211     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0212             PHM_PlatformCaps_EnableSMU7ThermalManagement);
0213 
0214     if (adev->pg_flags & AMD_PG_SUPPORT_UVD)
0215         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0216                 PHM_PlatformCaps_UVDPowerGating);
0217 
0218     if (adev->pg_flags & AMD_PG_SUPPORT_VCE)
0219         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0220                 PHM_PlatformCaps_VCEPowerGating);
0221 
0222     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0223             PHM_PlatformCaps_UnTabledHardwareInterface);
0224 
0225     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0226             PHM_PlatformCaps_FanSpeedInTableIsRPM);
0227 
0228     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0229             PHM_PlatformCaps_ODFuzzyFanControlSupport);
0230 
0231     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0232                 PHM_PlatformCaps_DynamicPowerManagement);
0233 
0234     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0235             PHM_PlatformCaps_SMC);
0236 
0237     /* power tune caps */
0238     /* assume disabled */
0239     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0240             PHM_PlatformCaps_PowerContainment);
0241     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0242             PHM_PlatformCaps_DiDtSupport);
0243     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0244             PHM_PlatformCaps_SQRamping);
0245     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0246             PHM_PlatformCaps_DBRamping);
0247     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0248             PHM_PlatformCaps_TDRamping);
0249     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0250             PHM_PlatformCaps_TCPRamping);
0251     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0252             PHM_PlatformCaps_DBRRamping);
0253     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0254             PHM_PlatformCaps_DiDtEDCEnable);
0255     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0256             PHM_PlatformCaps_GCEDC);
0257     phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
0258             PHM_PlatformCaps_PSM);
0259 
0260     if (data->registry_data.didt_support) {
0261         phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DiDtSupport);
0262         if (data->registry_data.sq_ramping_support)
0263             phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SQRamping);
0264         if (data->registry_data.db_ramping_support)
0265             phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DBRamping);
0266         if (data->registry_data.td_ramping_support)
0267             phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TDRamping);
0268         if (data->registry_data.tcp_ramping_support)
0269             phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TCPRamping);
0270         if (data->registry_data.dbr_ramping_support)
0271             phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DBRRamping);
0272         if (data->registry_data.edc_didt_support)
0273             phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DiDtEDCEnable);
0274         if (data->registry_data.gc_didt_support)
0275             phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_GCEDC);
0276         if (data->registry_data.psm_didt_support)
0277             phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PSM);
0278     }
0279 
0280     if (data->registry_data.power_containment_support)
0281         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0282                 PHM_PlatformCaps_PowerContainment);
0283     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0284             PHM_PlatformCaps_CAC);
0285 
0286     if (table_info->tdp_table->usClockStretchAmount &&
0287             data->registry_data.clock_stretcher_support)
0288         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0289                 PHM_PlatformCaps_ClockStretcher);
0290 
0291     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0292             PHM_PlatformCaps_RegulatorHot);
0293     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0294             PHM_PlatformCaps_AutomaticDCTransition);
0295 
0296     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0297             PHM_PlatformCaps_UVDDPM);
0298     phm_cap_set(hwmgr->platform_descriptor.platformCaps,
0299             PHM_PlatformCaps_VCEDPM);
0300 
0301     return 0;
0302 }
0303 
0304 static int vega10_odn_initial_default_setting(struct pp_hwmgr *hwmgr)
0305 {
0306     struct vega10_hwmgr *data = hwmgr->backend;
0307     struct phm_ppt_v2_information *table_info =
0308             (struct phm_ppt_v2_information *)(hwmgr->pptable);
0309     struct vega10_odn_dpm_table *odn_table = &(data->odn_dpm_table);
0310     struct vega10_odn_vddc_lookup_table *od_lookup_table;
0311     struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table;
0312     struct phm_ppt_v1_clock_voltage_dependency_table *dep_table[3];
0313     struct phm_ppt_v1_clock_voltage_dependency_table *od_table[3];
0314     struct pp_atomfwctrl_avfs_parameters avfs_params = {0};
0315     uint32_t i;
0316     int result;
0317 
0318     result = pp_atomfwctrl_get_avfs_information(hwmgr, &avfs_params);
0319     if (!result) {
0320         data->odn_dpm_table.max_vddc = avfs_params.ulMaxVddc;
0321         data->odn_dpm_table.min_vddc = avfs_params.ulMinVddc;
0322     }
0323 
0324     od_lookup_table = &odn_table->vddc_lookup_table;
0325     vddc_lookup_table = table_info->vddc_lookup_table;
0326 
0327     for (i = 0; i < vddc_lookup_table->count; i++)
0328         od_lookup_table->entries[i].us_vdd = vddc_lookup_table->entries[i].us_vdd;
0329 
0330     od_lookup_table->count = vddc_lookup_table->count;
0331 
0332     dep_table[0] = table_info->vdd_dep_on_sclk;
0333     dep_table[1] = table_info->vdd_dep_on_mclk;
0334     dep_table[2] = table_info->vdd_dep_on_socclk;
0335     od_table[0] = (struct phm_ppt_v1_clock_voltage_dependency_table *)&odn_table->vdd_dep_on_sclk;
0336     od_table[1] = (struct phm_ppt_v1_clock_voltage_dependency_table *)&odn_table->vdd_dep_on_mclk;
0337     od_table[2] = (struct phm_ppt_v1_clock_voltage_dependency_table *)&odn_table->vdd_dep_on_socclk;
0338 
0339     for (i = 0; i < 3; i++)
0340         smu_get_voltage_dependency_table_ppt_v1(dep_table[i], od_table[i]);
0341 
0342     if (odn_table->max_vddc == 0 || odn_table->max_vddc > 2000)
0343         odn_table->max_vddc = dep_table[0]->entries[dep_table[0]->count - 1].vddc;
0344     if (odn_table->min_vddc == 0 || odn_table->min_vddc > 2000)
0345         odn_table->min_vddc = dep_table[0]->entries[0].vddc;
0346 
0347     i = od_table[2]->count - 1;
0348     od_table[2]->entries[i].clk = hwmgr->platform_descriptor.overdriveLimit.memoryClock > od_table[2]->entries[i].clk ?
0349                     hwmgr->platform_descriptor.overdriveLimit.memoryClock :
0350                     od_table[2]->entries[i].clk;
0351     od_table[2]->entries[i].vddc = odn_table->max_vddc > od_table[2]->entries[i].vddc ?
0352                     odn_table->max_vddc :
0353                     od_table[2]->entries[i].vddc;
0354 
0355     return 0;
0356 }
0357 
0358 static void vega10_init_dpm_defaults(struct pp_hwmgr *hwmgr)
0359 {
0360     struct vega10_hwmgr *data = hwmgr->backend;
0361     int i;
0362     uint32_t sub_vendor_id, hw_revision;
0363     uint32_t top32, bottom32;
0364     struct amdgpu_device *adev = hwmgr->adev;
0365 
0366     vega10_initialize_power_tune_defaults(hwmgr);
0367 
0368     for (i = 0; i < GNLD_FEATURES_MAX; i++) {
0369         data->smu_features[i].smu_feature_id = 0xffff;
0370         data->smu_features[i].smu_feature_bitmap = 1 << i;
0371         data->smu_features[i].enabled = false;
0372         data->smu_features[i].supported = false;
0373     }
0374 
0375     data->smu_features[GNLD_DPM_PREFETCHER].smu_feature_id =
0376             FEATURE_DPM_PREFETCHER_BIT;
0377     data->smu_features[GNLD_DPM_GFXCLK].smu_feature_id =
0378             FEATURE_DPM_GFXCLK_BIT;
0379     data->smu_features[GNLD_DPM_UCLK].smu_feature_id =
0380             FEATURE_DPM_UCLK_BIT;
0381     data->smu_features[GNLD_DPM_SOCCLK].smu_feature_id =
0382             FEATURE_DPM_SOCCLK_BIT;
0383     data->smu_features[GNLD_DPM_UVD].smu_feature_id =
0384             FEATURE_DPM_UVD_BIT;
0385     data->smu_features[GNLD_DPM_VCE].smu_feature_id =
0386             FEATURE_DPM_VCE_BIT;
0387     data->smu_features[GNLD_DPM_MP0CLK].smu_feature_id =
0388             FEATURE_DPM_MP0CLK_BIT;
0389     data->smu_features[GNLD_DPM_LINK].smu_feature_id =
0390             FEATURE_DPM_LINK_BIT;
0391     data->smu_features[GNLD_DPM_DCEFCLK].smu_feature_id =
0392             FEATURE_DPM_DCEFCLK_BIT;
0393     data->smu_features[GNLD_ULV].smu_feature_id =
0394             FEATURE_ULV_BIT;
0395     data->smu_features[GNLD_AVFS].smu_feature_id =
0396             FEATURE_AVFS_BIT;
0397     data->smu_features[GNLD_DS_GFXCLK].smu_feature_id =
0398             FEATURE_DS_GFXCLK_BIT;
0399     data->smu_features[GNLD_DS_SOCCLK].smu_feature_id =
0400             FEATURE_DS_SOCCLK_BIT;
0401     data->smu_features[GNLD_DS_LCLK].smu_feature_id =
0402             FEATURE_DS_LCLK_BIT;
0403     data->smu_features[GNLD_PPT].smu_feature_id =
0404             FEATURE_PPT_BIT;
0405     data->smu_features[GNLD_TDC].smu_feature_id =
0406             FEATURE_TDC_BIT;
0407     data->smu_features[GNLD_THERMAL].smu_feature_id =
0408             FEATURE_THERMAL_BIT;
0409     data->smu_features[GNLD_GFX_PER_CU_CG].smu_feature_id =
0410             FEATURE_GFX_PER_CU_CG_BIT;
0411     data->smu_features[GNLD_RM].smu_feature_id =
0412             FEATURE_RM_BIT;
0413     data->smu_features[GNLD_DS_DCEFCLK].smu_feature_id =
0414             FEATURE_DS_DCEFCLK_BIT;
0415     data->smu_features[GNLD_ACDC].smu_feature_id =
0416             FEATURE_ACDC_BIT;
0417     data->smu_features[GNLD_VR0HOT].smu_feature_id =
0418             FEATURE_VR0HOT_BIT;
0419     data->smu_features[GNLD_VR1HOT].smu_feature_id =
0420             FEATURE_VR1HOT_BIT;
0421     data->smu_features[GNLD_FW_CTF].smu_feature_id =
0422             FEATURE_FW_CTF_BIT;
0423     data->smu_features[GNLD_LED_DISPLAY].smu_feature_id =
0424             FEATURE_LED_DISPLAY_BIT;
0425     data->smu_features[GNLD_FAN_CONTROL].smu_feature_id =
0426             FEATURE_FAN_CONTROL_BIT;
0427     data->smu_features[GNLD_ACG].smu_feature_id = FEATURE_ACG_BIT;
0428     data->smu_features[GNLD_DIDT].smu_feature_id = FEATURE_GFX_EDC_BIT;
0429     data->smu_features[GNLD_PCC_LIMIT].smu_feature_id = FEATURE_PCC_LIMIT_CONTROL_BIT;
0430 
0431     if (!data->registry_data.prefetcher_dpm_key_disabled)
0432         data->smu_features[GNLD_DPM_PREFETCHER].supported = true;
0433 
0434     if (!data->registry_data.sclk_dpm_key_disabled)
0435         data->smu_features[GNLD_DPM_GFXCLK].supported = true;
0436 
0437     if (!data->registry_data.mclk_dpm_key_disabled)
0438         data->smu_features[GNLD_DPM_UCLK].supported = true;
0439 
0440     if (!data->registry_data.socclk_dpm_key_disabled)
0441         data->smu_features[GNLD_DPM_SOCCLK].supported = true;
0442 
0443     if (PP_CAP(PHM_PlatformCaps_UVDDPM))
0444         data->smu_features[GNLD_DPM_UVD].supported = true;
0445 
0446     if (PP_CAP(PHM_PlatformCaps_VCEDPM))
0447         data->smu_features[GNLD_DPM_VCE].supported = true;
0448 
0449     data->smu_features[GNLD_DPM_LINK].supported = true;
0450 
0451     if (!data->registry_data.dcefclk_dpm_key_disabled)
0452         data->smu_features[GNLD_DPM_DCEFCLK].supported = true;
0453 
0454     if (PP_CAP(PHM_PlatformCaps_SclkDeepSleep) &&
0455         data->registry_data.sclk_deep_sleep_support) {
0456         data->smu_features[GNLD_DS_GFXCLK].supported = true;
0457         data->smu_features[GNLD_DS_SOCCLK].supported = true;
0458         data->smu_features[GNLD_DS_LCLK].supported = true;
0459         data->smu_features[GNLD_DS_DCEFCLK].supported = true;
0460     }
0461 
0462     if (data->registry_data.enable_pkg_pwr_tracking_feature)
0463         data->smu_features[GNLD_PPT].supported = true;
0464 
0465     if (data->registry_data.enable_tdc_limit_feature)
0466         data->smu_features[GNLD_TDC].supported = true;
0467 
0468     if (data->registry_data.thermal_support)
0469         data->smu_features[GNLD_THERMAL].supported = true;
0470 
0471     if (data->registry_data.fan_control_support)
0472         data->smu_features[GNLD_FAN_CONTROL].supported = true;
0473 
0474     if (data->registry_data.fw_ctf_enabled)
0475         data->smu_features[GNLD_FW_CTF].supported = true;
0476 
0477     if (data->registry_data.avfs_support)
0478         data->smu_features[GNLD_AVFS].supported = true;
0479 
0480     if (data->registry_data.led_dpm_enabled)
0481         data->smu_features[GNLD_LED_DISPLAY].supported = true;
0482 
0483     if (data->registry_data.vr1hot_enabled)
0484         data->smu_features[GNLD_VR1HOT].supported = true;
0485 
0486     if (data->registry_data.vr0hot_enabled)
0487         data->smu_features[GNLD_VR0HOT].supported = true;
0488 
0489     smum_send_msg_to_smc(hwmgr,
0490             PPSMC_MSG_GetSmuVersion,
0491             &hwmgr->smu_version);
0492         /* ACG firmware has major version 5 */
0493     if ((hwmgr->smu_version & 0xff000000) == 0x5000000)
0494         data->smu_features[GNLD_ACG].supported = true;
0495     if (data->registry_data.didt_support)
0496         data->smu_features[GNLD_DIDT].supported = true;
0497 
0498     hw_revision = adev->pdev->revision;
0499     sub_vendor_id = adev->pdev->subsystem_vendor;
0500 
0501     if ((hwmgr->chip_id == 0x6862 ||
0502         hwmgr->chip_id == 0x6861 ||
0503         hwmgr->chip_id == 0x6868) &&
0504         (hw_revision == 0) &&
0505         (sub_vendor_id != 0x1002))
0506         data->smu_features[GNLD_PCC_LIMIT].supported = true;
0507 
0508     /* Get the SN to turn into a Unique ID */
0509     smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumTop32, &top32);
0510     smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumBottom32, &bottom32);
0511 
0512     adev->unique_id = ((uint64_t)bottom32 << 32) | top32;
0513 }
0514 
0515 #ifdef PPLIB_VEGA10_EVV_SUPPORT
0516 static int vega10_get_socclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
0517     phm_ppt_v1_voltage_lookup_table *lookup_table,
0518     uint16_t virtual_voltage_id, int32_t *socclk)
0519 {
0520     uint8_t entry_id;
0521     uint8_t voltage_id;
0522     struct phm_ppt_v2_information *table_info =
0523             (struct phm_ppt_v2_information *)(hwmgr->pptable);
0524 
0525     PP_ASSERT_WITH_CODE(lookup_table->count != 0,
0526             "Lookup table is empty",
0527             return -EINVAL);
0528 
0529     /* search for leakage voltage ID 0xff01 ~ 0xff08 and sclk */
0530     for (entry_id = 0; entry_id < table_info->vdd_dep_on_sclk->count; entry_id++) {
0531         voltage_id = table_info->vdd_dep_on_socclk->entries[entry_id].vddInd;
0532         if (lookup_table->entries[voltage_id].us_vdd == virtual_voltage_id)
0533             break;
0534     }
0535 
0536     PP_ASSERT_WITH_CODE(entry_id < table_info->vdd_dep_on_socclk->count,
0537             "Can't find requested voltage id in vdd_dep_on_socclk table!",
0538             return -EINVAL);
0539 
0540     *socclk = table_info->vdd_dep_on_socclk->entries[entry_id].clk;
0541 
0542     return 0;
0543 }
0544 
0545 #define ATOM_VIRTUAL_VOLTAGE_ID0             0xff01
0546 /**
0547  * vega10_get_evv_voltages - Get Leakage VDDC based on leakage ID.
0548  *
0549  * @hwmgr:  the address of the powerplay hardware manager.
0550  * return:  always 0.
0551  */
0552 static int vega10_get_evv_voltages(struct pp_hwmgr *hwmgr)
0553 {
0554     struct vega10_hwmgr *data = hwmgr->backend;
0555     uint16_t vv_id;
0556     uint32_t vddc = 0;
0557     uint16_t i, j;
0558     uint32_t sclk = 0;
0559     struct phm_ppt_v2_information *table_info =
0560             (struct phm_ppt_v2_information *)hwmgr->pptable;
0561     struct phm_ppt_v1_clock_voltage_dependency_table *socclk_table =
0562             table_info->vdd_dep_on_socclk;
0563     int result;
0564 
0565     for (i = 0; i < VEGA10_MAX_LEAKAGE_COUNT; i++) {
0566         vv_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
0567 
0568         if (!vega10_get_socclk_for_voltage_evv(hwmgr,
0569                 table_info->vddc_lookup_table, vv_id, &sclk)) {
0570             if (PP_CAP(PHM_PlatformCaps_ClockStretcher)) {
0571                 for (j = 1; j < socclk_table->count; j++) {
0572                     if (socclk_table->entries[j].clk == sclk &&
0573                             socclk_table->entries[j].cks_enable == 0) {
0574                         sclk += 5000;
0575                         break;
0576                     }
0577                 }
0578             }
0579 
0580             PP_ASSERT_WITH_CODE(!atomctrl_get_voltage_evv_on_sclk_ai(hwmgr,
0581                     VOLTAGE_TYPE_VDDC, sclk, vv_id, &vddc),
0582                     "Error retrieving EVV voltage value!",
0583                     continue);
0584 
0585 
0586             /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
0587             PP_ASSERT_WITH_CODE((vddc < 2000 && vddc != 0),
0588                     "Invalid VDDC value", result = -EINVAL;);
0589 
0590             /* the voltage should not be zero nor equal to leakage ID */
0591             if (vddc != 0 && vddc != vv_id) {
0592                 data->vddc_leakage.actual_voltage[data->vddc_leakage.count] = (uint16_t)(vddc/100);
0593                 data->vddc_leakage.leakage_id[data->vddc_leakage.count] = vv_id;
0594                 data->vddc_leakage.count++;
0595             }
0596         }
0597     }
0598 
0599     return 0;
0600 }
0601 
0602 /**
0603  * vega10_patch_with_vdd_leakage - Change virtual leakage voltage to actual value.
0604  *
0605  * @hwmgr:         the address of the powerplay hardware manager.
0606  * @voltage:       pointer to changing voltage
0607  * @leakage_table: pointer to leakage table
0608  */
0609 static void vega10_patch_with_vdd_leakage(struct pp_hwmgr *hwmgr,
0610         uint16_t *voltage, struct vega10_leakage_voltage *leakage_table)
0611 {
0612     uint32_t index;
0613 
0614     /* search for leakage voltage ID 0xff01 ~ 0xff08 */
0615     for (index = 0; index < leakage_table->count; index++) {
0616         /* if this voltage matches a leakage voltage ID */
0617         /* patch with actual leakage voltage */
0618         if (leakage_table->leakage_id[index] == *voltage) {
0619             *voltage = leakage_table->actual_voltage[index];
0620             break;
0621         }
0622     }
0623 
0624     if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
0625         pr_info("Voltage value looks like a Leakage ID but it's not patched\n");
0626 }
0627 
0628 /**
0629  * vega10_patch_lookup_table_with_leakage - Patch voltage lookup table by EVV leakages.
0630  *
0631  * @hwmgr:         the address of the powerplay hardware manager.
0632  * @lookup_table:  pointer to voltage lookup table
0633  * @leakage_table: pointer to leakage table
0634  * return:         always 0
0635  */
0636 static int vega10_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
0637         phm_ppt_v1_voltage_lookup_table *lookup_table,
0638         struct vega10_leakage_voltage *leakage_table)
0639 {
0640     uint32_t i;
0641 
0642     for (i = 0; i < lookup_table->count; i++)
0643         vega10_patch_with_vdd_leakage(hwmgr,
0644                 &lookup_table->entries[i].us_vdd, leakage_table);
0645 
0646     return 0;
0647 }
0648 
0649 static int vega10_patch_clock_voltage_limits_with_vddc_leakage(
0650         struct pp_hwmgr *hwmgr, struct vega10_leakage_voltage *leakage_table,
0651         uint16_t *vddc)
0652 {
0653     vega10_patch_with_vdd_leakage(hwmgr, (uint16_t *)vddc, leakage_table);
0654 
0655     return 0;
0656 }
0657 #endif
0658 
0659 static int vega10_patch_voltage_dependency_tables_with_lookup_table(
0660         struct pp_hwmgr *hwmgr)
0661 {
0662     uint8_t entry_id, voltage_id;
0663     unsigned i;
0664     struct phm_ppt_v2_information *table_info =
0665             (struct phm_ppt_v2_information *)(hwmgr->pptable);
0666     struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
0667             table_info->mm_dep_table;
0668     struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table =
0669             table_info->vdd_dep_on_mclk;
0670 
0671     for (i = 0; i < 6; i++) {
0672         struct phm_ppt_v1_clock_voltage_dependency_table *vdt;
0673         switch (i) {
0674             case 0: vdt = table_info->vdd_dep_on_socclk; break;
0675             case 1: vdt = table_info->vdd_dep_on_sclk; break;
0676             case 2: vdt = table_info->vdd_dep_on_dcefclk; break;
0677             case 3: vdt = table_info->vdd_dep_on_pixclk; break;
0678             case 4: vdt = table_info->vdd_dep_on_dispclk; break;
0679             case 5: vdt = table_info->vdd_dep_on_phyclk; break;
0680         }
0681 
0682         for (entry_id = 0; entry_id < vdt->count; entry_id++) {
0683             voltage_id = vdt->entries[entry_id].vddInd;
0684             vdt->entries[entry_id].vddc =
0685                     table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
0686         }
0687     }
0688 
0689     for (entry_id = 0; entry_id < mm_table->count; ++entry_id) {
0690         voltage_id = mm_table->entries[entry_id].vddcInd;
0691         mm_table->entries[entry_id].vddc =
0692             table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
0693     }
0694 
0695     for (entry_id = 0; entry_id < mclk_table->count; ++entry_id) {
0696         voltage_id = mclk_table->entries[entry_id].vddInd;
0697         mclk_table->entries[entry_id].vddc =
0698                 table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
0699         voltage_id = mclk_table->entries[entry_id].vddciInd;
0700         mclk_table->entries[entry_id].vddci =
0701                 table_info->vddci_lookup_table->entries[voltage_id].us_vdd;
0702         voltage_id = mclk_table->entries[entry_id].mvddInd;
0703         mclk_table->entries[entry_id].mvdd =
0704                 table_info->vddmem_lookup_table->entries[voltage_id].us_vdd;
0705     }
0706 
0707 
0708     return 0;
0709 
0710 }
0711 
0712 static int vega10_sort_lookup_table(struct pp_hwmgr *hwmgr,
0713         struct phm_ppt_v1_voltage_lookup_table *lookup_table)
0714 {
0715     uint32_t table_size, i, j;
0716 
0717     PP_ASSERT_WITH_CODE(lookup_table && lookup_table->count,
0718         "Lookup table is empty", return -EINVAL);
0719 
0720     table_size = lookup_table->count;
0721 
0722     /* Sorting voltages */
0723     for (i = 0; i < table_size - 1; i++) {
0724         for (j = i + 1; j > 0; j--) {
0725             if (lookup_table->entries[j].us_vdd <
0726                     lookup_table->entries[j - 1].us_vdd) {
0727                 swap(lookup_table->entries[j - 1],
0728                      lookup_table->entries[j]);
0729             }
0730         }
0731     }
0732 
0733     return 0;
0734 }
0735 
0736 static int vega10_complete_dependency_tables(struct pp_hwmgr *hwmgr)
0737 {
0738     int result = 0;
0739     int tmp_result;
0740     struct phm_ppt_v2_information *table_info =
0741             (struct phm_ppt_v2_information *)(hwmgr->pptable);
0742 #ifdef PPLIB_VEGA10_EVV_SUPPORT
0743     struct vega10_hwmgr *data = hwmgr->backend;
0744 
0745     tmp_result = vega10_patch_lookup_table_with_leakage(hwmgr,
0746             table_info->vddc_lookup_table, &(data->vddc_leakage));
0747     if (tmp_result)
0748         result = tmp_result;
0749 
0750     tmp_result = vega10_patch_clock_voltage_limits_with_vddc_leakage(hwmgr,
0751             &(data->vddc_leakage), &table_info->max_clock_voltage_on_dc.vddc);
0752     if (tmp_result)
0753         result = tmp_result;
0754 #endif
0755 
0756     tmp_result = vega10_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
0757     if (tmp_result)
0758         result = tmp_result;
0759 
0760     tmp_result = vega10_sort_lookup_table(hwmgr, table_info->vddc_lookup_table);
0761     if (tmp_result)
0762         result = tmp_result;
0763 
0764     return result;
0765 }
0766 
0767 static int vega10_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
0768 {
0769     struct phm_ppt_v2_information *table_info =
0770             (struct phm_ppt_v2_information *)(hwmgr->pptable);
0771     struct phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
0772             table_info->vdd_dep_on_socclk;
0773     struct phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
0774             table_info->vdd_dep_on_mclk;
0775 
0776     PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table,
0777         "VDD dependency on SCLK table is missing. This table is mandatory", return -EINVAL);
0778     PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
0779         "VDD dependency on SCLK table is empty. This table is mandatory", return -EINVAL);
0780 
0781     PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table,
0782         "VDD dependency on MCLK table is missing.  This table is mandatory", return -EINVAL);
0783     PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
0784         "VDD dependency on MCLK table is empty.  This table is mandatory", return -EINVAL);
0785 
0786     table_info->max_clock_voltage_on_ac.sclk =
0787         allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
0788     table_info->max_clock_voltage_on_ac.mclk =
0789         allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
0790     table_info->max_clock_voltage_on_ac.vddc =
0791         allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
0792     table_info->max_clock_voltage_on_ac.vddci =
0793         allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
0794 
0795     hwmgr->dyn_state.max_clock_voltage_on_ac.sclk =
0796         table_info->max_clock_voltage_on_ac.sclk;
0797     hwmgr->dyn_state.max_clock_voltage_on_ac.mclk =
0798         table_info->max_clock_voltage_on_ac.mclk;
0799     hwmgr->dyn_state.max_clock_voltage_on_ac.vddc =
0800         table_info->max_clock_voltage_on_ac.vddc;
0801     hwmgr->dyn_state.max_clock_voltage_on_ac.vddci =
0802         table_info->max_clock_voltage_on_ac.vddci;
0803 
0804     return 0;
0805 }
0806 
0807 static int vega10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
0808 {
0809     kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
0810     hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
0811 
0812     kfree(hwmgr->backend);
0813     hwmgr->backend = NULL;
0814 
0815     return 0;
0816 }
0817 
0818 static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
0819 {
0820     int result = 0;
0821     struct vega10_hwmgr *data;
0822     uint32_t config_telemetry = 0;
0823     struct pp_atomfwctrl_voltage_table vol_table;
0824     struct amdgpu_device *adev = hwmgr->adev;
0825 
0826     data = kzalloc(sizeof(struct vega10_hwmgr), GFP_KERNEL);
0827     if (data == NULL)
0828         return -ENOMEM;
0829 
0830     hwmgr->backend = data;
0831 
0832     hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
0833     hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
0834     hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
0835 
0836     vega10_set_default_registry_data(hwmgr);
0837     data->disable_dpm_mask = 0xff;
0838 
0839     /* need to set voltage control types before EVV patching */
0840     data->vddc_control = VEGA10_VOLTAGE_CONTROL_NONE;
0841     data->mvdd_control = VEGA10_VOLTAGE_CONTROL_NONE;
0842     data->vddci_control = VEGA10_VOLTAGE_CONTROL_NONE;
0843 
0844     /* VDDCR_SOC */
0845     if (pp_atomfwctrl_is_voltage_controlled_by_gpio_v4(hwmgr,
0846             VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2)) {
0847         if (!pp_atomfwctrl_get_voltage_table_v4(hwmgr,
0848                 VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2,
0849                 &vol_table)) {
0850             config_telemetry = ((vol_table.telemetry_slope << 8) & 0xff00) |
0851                     (vol_table.telemetry_offset & 0xff);
0852             data->vddc_control = VEGA10_VOLTAGE_CONTROL_BY_SVID2;
0853         }
0854     } else {
0855         kfree(hwmgr->backend);
0856         hwmgr->backend = NULL;
0857         PP_ASSERT_WITH_CODE(false,
0858                 "VDDCR_SOC is not SVID2!",
0859                 return -1);
0860     }
0861 
0862     /* MVDDC */
0863     if (pp_atomfwctrl_is_voltage_controlled_by_gpio_v4(hwmgr,
0864             VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2)) {
0865         if (!pp_atomfwctrl_get_voltage_table_v4(hwmgr,
0866                 VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2,
0867                 &vol_table)) {
0868             config_telemetry |=
0869                     ((vol_table.telemetry_slope << 24) & 0xff000000) |
0870                     ((vol_table.telemetry_offset << 16) & 0xff0000);
0871             data->mvdd_control = VEGA10_VOLTAGE_CONTROL_BY_SVID2;
0872         }
0873     }
0874 
0875      /* VDDCI_MEM */
0876     if (PP_CAP(PHM_PlatformCaps_ControlVDDCI)) {
0877         if (pp_atomfwctrl_is_voltage_controlled_by_gpio_v4(hwmgr,
0878                 VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
0879             data->vddci_control = VEGA10_VOLTAGE_CONTROL_BY_GPIO;
0880     }
0881 
0882     data->config_telemetry = config_telemetry;
0883 
0884     vega10_set_features_platform_caps(hwmgr);
0885 
0886     vega10_init_dpm_defaults(hwmgr);
0887 
0888 #ifdef PPLIB_VEGA10_EVV_SUPPORT
0889     /* Get leakage voltage based on leakage ID. */
0890     PP_ASSERT_WITH_CODE(!vega10_get_evv_voltages(hwmgr),
0891             "Get EVV Voltage Failed.  Abort Driver loading!",
0892             return -1);
0893 #endif
0894 
0895     /* Patch our voltage dependency table with actual leakage voltage
0896      * We need to perform leakage translation before it's used by other functions
0897      */
0898     vega10_complete_dependency_tables(hwmgr);
0899 
0900     /* Parse pptable data read from VBIOS */
0901     vega10_set_private_data_based_on_pptable(hwmgr);
0902 
0903     data->is_tlu_enabled = false;
0904 
0905     hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
0906             VEGA10_MAX_HARDWARE_POWERLEVELS;
0907     hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
0908     hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50;
0909 
0910     hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */
0911     /* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */
0912     hwmgr->platform_descriptor.clockStep.engineClock = 500;
0913     hwmgr->platform_descriptor.clockStep.memoryClock = 500;
0914 
0915     data->total_active_cus = adev->gfx.cu_info.number;
0916     if (!hwmgr->not_vf)
0917         return result;
0918 
0919     /* Setup default Overdrive Fan control settings */
0920     data->odn_fan_table.target_fan_speed =
0921             hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM;
0922     data->odn_fan_table.target_temperature =
0923             hwmgr->thermal_controller.
0924             advanceFanControlParameters.ucTargetTemperature;
0925     data->odn_fan_table.min_performance_clock =
0926             hwmgr->thermal_controller.advanceFanControlParameters.
0927             ulMinFanSCLKAcousticLimit;
0928     data->odn_fan_table.min_fan_limit =
0929             hwmgr->thermal_controller.
0930             advanceFanControlParameters.usFanPWMMinLimit *
0931             hwmgr->thermal_controller.fanInfo.ulMaxRPM / 100;
0932 
0933     data->mem_channels = (RREG32_SOC15(DF, 0, mmDF_CS_AON0_DramBaseAddress0) &
0934             DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK) >>
0935             DF_CS_AON0_DramBaseAddress0__IntLvNumChan__SHIFT;
0936     PP_ASSERT_WITH_CODE(data->mem_channels < ARRAY_SIZE(channel_number),
0937             "Mem Channel Index Exceeded maximum!",
0938             return -EINVAL);
0939 
0940     return result;
0941 }
0942 
0943 static int vega10_init_sclk_threshold(struct pp_hwmgr *hwmgr)
0944 {
0945     struct vega10_hwmgr *data = hwmgr->backend;
0946 
0947     data->low_sclk_interrupt_threshold = 0;
0948 
0949     return 0;
0950 }
0951 
0952 static int vega10_setup_dpm_led_config(struct pp_hwmgr *hwmgr)
0953 {
0954     struct vega10_hwmgr *data = hwmgr->backend;
0955     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
0956 
0957     struct pp_atomfwctrl_voltage_table table;
0958     uint8_t i, j;
0959     uint32_t mask = 0;
0960     uint32_t tmp;
0961     int32_t ret = 0;
0962 
0963     ret = pp_atomfwctrl_get_voltage_table_v4(hwmgr, VOLTAGE_TYPE_LEDDPM,
0964                         VOLTAGE_OBJ_GPIO_LUT, &table);
0965 
0966     if (!ret) {
0967         tmp = table.mask_low;
0968         for (i = 0, j = 0; i < 32; i++) {
0969             if (tmp & 1) {
0970                 mask |= (uint32_t)(i << (8 * j));
0971                 if (++j >= 3)
0972                     break;
0973             }
0974             tmp >>= 1;
0975         }
0976     }
0977 
0978     pp_table->LedPin0 = (uint8_t)(mask & 0xff);
0979     pp_table->LedPin1 = (uint8_t)((mask >> 8) & 0xff);
0980     pp_table->LedPin2 = (uint8_t)((mask >> 16) & 0xff);
0981     return 0;
0982 }
0983 
0984 static int vega10_setup_asic_task(struct pp_hwmgr *hwmgr)
0985 {
0986     if (!hwmgr->not_vf)
0987         return 0;
0988 
0989     PP_ASSERT_WITH_CODE(!vega10_init_sclk_threshold(hwmgr),
0990             "Failed to init sclk threshold!",
0991             return -EINVAL);
0992 
0993     PP_ASSERT_WITH_CODE(!vega10_setup_dpm_led_config(hwmgr),
0994             "Failed to set up led dpm config!",
0995             return -EINVAL);
0996 
0997     smum_send_msg_to_smc_with_parameter(hwmgr,
0998                 PPSMC_MSG_NumOfDisplays,
0999                 0,
1000                 NULL);
1001 
1002     return 0;
1003 }
1004 
1005 /**
1006  * vega10_trim_voltage_table - Remove repeated voltage values and create table with unique values.
1007  *
1008  * @hwmgr:      the address of the powerplay hardware manager.
1009  * @vol_table:  the pointer to changing voltage table
1010  * return:      0 in success
1011  */
1012 static int vega10_trim_voltage_table(struct pp_hwmgr *hwmgr,
1013         struct pp_atomfwctrl_voltage_table *vol_table)
1014 {
1015     uint32_t i, j;
1016     uint16_t vvalue;
1017     bool found = false;
1018     struct pp_atomfwctrl_voltage_table *table;
1019 
1020     PP_ASSERT_WITH_CODE(vol_table,
1021             "Voltage Table empty.", return -EINVAL);
1022     table = kzalloc(sizeof(struct pp_atomfwctrl_voltage_table),
1023             GFP_KERNEL);
1024 
1025     if (!table)
1026         return -ENOMEM;
1027 
1028     table->mask_low = vol_table->mask_low;
1029     table->phase_delay = vol_table->phase_delay;
1030 
1031     for (i = 0; i < vol_table->count; i++) {
1032         vvalue = vol_table->entries[i].value;
1033         found = false;
1034 
1035         for (j = 0; j < table->count; j++) {
1036             if (vvalue == table->entries[j].value) {
1037                 found = true;
1038                 break;
1039             }
1040         }
1041 
1042         if (!found) {
1043             table->entries[table->count].value = vvalue;
1044             table->entries[table->count].smio_low =
1045                     vol_table->entries[i].smio_low;
1046             table->count++;
1047         }
1048     }
1049 
1050     memcpy(vol_table, table, sizeof(struct pp_atomfwctrl_voltage_table));
1051     kfree(table);
1052 
1053     return 0;
1054 }
1055 
1056 static int vega10_get_mvdd_voltage_table(struct pp_hwmgr *hwmgr,
1057         phm_ppt_v1_clock_voltage_dependency_table *dep_table,
1058         struct pp_atomfwctrl_voltage_table *vol_table)
1059 {
1060     int i;
1061 
1062     PP_ASSERT_WITH_CODE(dep_table->count,
1063             "Voltage Dependency Table empty.",
1064             return -EINVAL);
1065 
1066     vol_table->mask_low = 0;
1067     vol_table->phase_delay = 0;
1068     vol_table->count = dep_table->count;
1069 
1070     for (i = 0; i < vol_table->count; i++) {
1071         vol_table->entries[i].value = dep_table->entries[i].mvdd;
1072         vol_table->entries[i].smio_low = 0;
1073     }
1074 
1075     PP_ASSERT_WITH_CODE(!vega10_trim_voltage_table(hwmgr,
1076             vol_table),
1077             "Failed to trim MVDD Table!",
1078             return -1);
1079 
1080     return 0;
1081 }
1082 
1083 static int vega10_get_vddci_voltage_table(struct pp_hwmgr *hwmgr,
1084         phm_ppt_v1_clock_voltage_dependency_table *dep_table,
1085         struct pp_atomfwctrl_voltage_table *vol_table)
1086 {
1087     uint32_t i;
1088 
1089     PP_ASSERT_WITH_CODE(dep_table->count,
1090             "Voltage Dependency Table empty.",
1091             return -EINVAL);
1092 
1093     vol_table->mask_low = 0;
1094     vol_table->phase_delay = 0;
1095     vol_table->count = dep_table->count;
1096 
1097     for (i = 0; i < dep_table->count; i++) {
1098         vol_table->entries[i].value = dep_table->entries[i].vddci;
1099         vol_table->entries[i].smio_low = 0;
1100     }
1101 
1102     PP_ASSERT_WITH_CODE(!vega10_trim_voltage_table(hwmgr, vol_table),
1103             "Failed to trim VDDCI table.",
1104             return -1);
1105 
1106     return 0;
1107 }
1108 
1109 static int vega10_get_vdd_voltage_table(struct pp_hwmgr *hwmgr,
1110         phm_ppt_v1_clock_voltage_dependency_table *dep_table,
1111         struct pp_atomfwctrl_voltage_table *vol_table)
1112 {
1113     int i;
1114 
1115     PP_ASSERT_WITH_CODE(dep_table->count,
1116             "Voltage Dependency Table empty.",
1117             return -EINVAL);
1118 
1119     vol_table->mask_low = 0;
1120     vol_table->phase_delay = 0;
1121     vol_table->count = dep_table->count;
1122 
1123     for (i = 0; i < vol_table->count; i++) {
1124         vol_table->entries[i].value = dep_table->entries[i].vddc;
1125         vol_table->entries[i].smio_low = 0;
1126     }
1127 
1128     return 0;
1129 }
1130 
1131 /* ---- Voltage Tables ----
1132  * If the voltage table would be bigger than
1133  * what will fit into the state table on
1134  * the SMC keep only the higher entries.
1135  */
1136 static void vega10_trim_voltage_table_to_fit_state_table(
1137         struct pp_hwmgr *hwmgr,
1138         uint32_t max_vol_steps,
1139         struct pp_atomfwctrl_voltage_table *vol_table)
1140 {
1141     unsigned int i, diff;
1142 
1143     if (vol_table->count <= max_vol_steps)
1144         return;
1145 
1146     diff = vol_table->count - max_vol_steps;
1147 
1148     for (i = 0; i < max_vol_steps; i++)
1149         vol_table->entries[i] = vol_table->entries[i + diff];
1150 
1151     vol_table->count = max_vol_steps;
1152 }
1153 
1154 /**
1155  * vega10_construct_voltage_tables - Create Voltage Tables.
1156  *
1157  * @hwmgr:  the address of the powerplay hardware manager.
1158  * return:  always 0
1159  */
1160 static int vega10_construct_voltage_tables(struct pp_hwmgr *hwmgr)
1161 {
1162     struct vega10_hwmgr *data = hwmgr->backend;
1163     struct phm_ppt_v2_information *table_info =
1164             (struct phm_ppt_v2_information *)hwmgr->pptable;
1165     int result;
1166 
1167     if (data->mvdd_control == VEGA10_VOLTAGE_CONTROL_BY_SVID2 ||
1168             data->mvdd_control == VEGA10_VOLTAGE_CONTROL_NONE) {
1169         result = vega10_get_mvdd_voltage_table(hwmgr,
1170                 table_info->vdd_dep_on_mclk,
1171                 &(data->mvdd_voltage_table));
1172         PP_ASSERT_WITH_CODE(!result,
1173                 "Failed to retrieve MVDDC table!",
1174                 return result);
1175     }
1176 
1177     if (data->vddci_control == VEGA10_VOLTAGE_CONTROL_NONE) {
1178         result = vega10_get_vddci_voltage_table(hwmgr,
1179                 table_info->vdd_dep_on_mclk,
1180                 &(data->vddci_voltage_table));
1181         PP_ASSERT_WITH_CODE(!result,
1182                 "Failed to retrieve VDDCI_MEM table!",
1183                 return result);
1184     }
1185 
1186     if (data->vddc_control == VEGA10_VOLTAGE_CONTROL_BY_SVID2 ||
1187             data->vddc_control == VEGA10_VOLTAGE_CONTROL_NONE) {
1188         result = vega10_get_vdd_voltage_table(hwmgr,
1189                 table_info->vdd_dep_on_sclk,
1190                 &(data->vddc_voltage_table));
1191         PP_ASSERT_WITH_CODE(!result,
1192                 "Failed to retrieve VDDCR_SOC table!",
1193                 return result);
1194     }
1195 
1196     PP_ASSERT_WITH_CODE(data->vddc_voltage_table.count <= 16,
1197             "Too many voltage values for VDDC. Trimming to fit state table.",
1198             vega10_trim_voltage_table_to_fit_state_table(hwmgr,
1199                     16, &(data->vddc_voltage_table)));
1200 
1201     PP_ASSERT_WITH_CODE(data->vddci_voltage_table.count <= 16,
1202             "Too many voltage values for VDDCI. Trimming to fit state table.",
1203             vega10_trim_voltage_table_to_fit_state_table(hwmgr,
1204                     16, &(data->vddci_voltage_table)));
1205 
1206     PP_ASSERT_WITH_CODE(data->mvdd_voltage_table.count <= 16,
1207             "Too many voltage values for MVDD. Trimming to fit state table.",
1208             vega10_trim_voltage_table_to_fit_state_table(hwmgr,
1209                     16, &(data->mvdd_voltage_table)));
1210 
1211 
1212     return 0;
1213 }
1214 
1215 /*
1216  * vega10_init_dpm_state
1217  * Function to initialize all Soft Min/Max and Hard Min/Max to 0xff.
1218  *
1219  * @dpm_state: - the address of the DPM Table to initiailize.
1220  * return:   None.
1221  */
1222 static void vega10_init_dpm_state(struct vega10_dpm_state *dpm_state)
1223 {
1224     dpm_state->soft_min_level = 0xff;
1225     dpm_state->soft_max_level = 0xff;
1226     dpm_state->hard_min_level = 0xff;
1227     dpm_state->hard_max_level = 0xff;
1228 }
1229 
1230 static void vega10_setup_default_single_dpm_table(struct pp_hwmgr *hwmgr,
1231         struct vega10_single_dpm_table *dpm_table,
1232         struct phm_ppt_v1_clock_voltage_dependency_table *dep_table)
1233 {
1234     int i;
1235 
1236     dpm_table->count = 0;
1237 
1238     for (i = 0; i < dep_table->count; i++) {
1239         if (i == 0 || dpm_table->dpm_levels[dpm_table->count - 1].value <=
1240                 dep_table->entries[i].clk) {
1241             dpm_table->dpm_levels[dpm_table->count].value =
1242                     dep_table->entries[i].clk;
1243             dpm_table->dpm_levels[dpm_table->count].enabled = true;
1244             dpm_table->count++;
1245         }
1246     }
1247 }
1248 static int vega10_setup_default_pcie_table(struct pp_hwmgr *hwmgr)
1249 {
1250     struct vega10_hwmgr *data = hwmgr->backend;
1251     struct vega10_pcie_table *pcie_table = &(data->dpm_table.pcie_table);
1252     struct phm_ppt_v2_information *table_info =
1253             (struct phm_ppt_v2_information *)(hwmgr->pptable);
1254     struct phm_ppt_v1_pcie_table *bios_pcie_table =
1255             table_info->pcie_table;
1256     uint32_t i;
1257 
1258     PP_ASSERT_WITH_CODE(bios_pcie_table->count,
1259             "Incorrect number of PCIE States from VBIOS!",
1260             return -1);
1261 
1262     for (i = 0; i < NUM_LINK_LEVELS; i++) {
1263         if (data->registry_data.pcieSpeedOverride)
1264             pcie_table->pcie_gen[i] =
1265                     data->registry_data.pcieSpeedOverride;
1266         else
1267             pcie_table->pcie_gen[i] =
1268                     bios_pcie_table->entries[i].gen_speed;
1269 
1270         if (data->registry_data.pcieLaneOverride)
1271             pcie_table->pcie_lane[i] = (uint8_t)encode_pcie_lane_width(
1272                     data->registry_data.pcieLaneOverride);
1273         else
1274             pcie_table->pcie_lane[i] = (uint8_t)encode_pcie_lane_width(
1275                             bios_pcie_table->entries[i].lane_width);
1276         if (data->registry_data.pcieClockOverride)
1277             pcie_table->lclk[i] =
1278                     data->registry_data.pcieClockOverride;
1279         else
1280             pcie_table->lclk[i] =
1281                     bios_pcie_table->entries[i].pcie_sclk;
1282     }
1283 
1284     pcie_table->count = NUM_LINK_LEVELS;
1285 
1286     return 0;
1287 }
1288 
1289 /*
1290  * This function is to initialize all DPM state tables
1291  * for SMU based on the dependency table.
1292  * Dynamic state patching function will then trim these
1293  * state tables to the allowed range based
1294  * on the power policy or external client requests,
1295  * such as UVD request, etc.
1296  */
1297 static int vega10_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
1298 {
1299     struct vega10_hwmgr *data = hwmgr->backend;
1300     struct phm_ppt_v2_information *table_info =
1301             (struct phm_ppt_v2_information *)(hwmgr->pptable);
1302     struct vega10_single_dpm_table *dpm_table;
1303     uint32_t i;
1304 
1305     struct phm_ppt_v1_clock_voltage_dependency_table *dep_soc_table =
1306             table_info->vdd_dep_on_socclk;
1307     struct phm_ppt_v1_clock_voltage_dependency_table *dep_gfx_table =
1308             table_info->vdd_dep_on_sclk;
1309     struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
1310             table_info->vdd_dep_on_mclk;
1311     struct phm_ppt_v1_mm_clock_voltage_dependency_table *dep_mm_table =
1312             table_info->mm_dep_table;
1313     struct phm_ppt_v1_clock_voltage_dependency_table *dep_dcef_table =
1314             table_info->vdd_dep_on_dcefclk;
1315     struct phm_ppt_v1_clock_voltage_dependency_table *dep_pix_table =
1316             table_info->vdd_dep_on_pixclk;
1317     struct phm_ppt_v1_clock_voltage_dependency_table *dep_disp_table =
1318             table_info->vdd_dep_on_dispclk;
1319     struct phm_ppt_v1_clock_voltage_dependency_table *dep_phy_table =
1320             table_info->vdd_dep_on_phyclk;
1321 
1322     PP_ASSERT_WITH_CODE(dep_soc_table,
1323             "SOCCLK dependency table is missing. This table is mandatory",
1324             return -EINVAL);
1325     PP_ASSERT_WITH_CODE(dep_soc_table->count >= 1,
1326             "SOCCLK dependency table is empty. This table is mandatory",
1327             return -EINVAL);
1328 
1329     PP_ASSERT_WITH_CODE(dep_gfx_table,
1330             "GFXCLK dependency table is missing. This table is mandatory",
1331             return -EINVAL);
1332     PP_ASSERT_WITH_CODE(dep_gfx_table->count >= 1,
1333             "GFXCLK dependency table is empty. This table is mandatory",
1334             return -EINVAL);
1335 
1336     PP_ASSERT_WITH_CODE(dep_mclk_table,
1337             "MCLK dependency table is missing. This table is mandatory",
1338             return -EINVAL);
1339     PP_ASSERT_WITH_CODE(dep_mclk_table->count >= 1,
1340             "MCLK dependency table has to have is missing. This table is mandatory",
1341             return -EINVAL);
1342 
1343     /* Initialize Sclk DPM table based on allow Sclk values */
1344     dpm_table = &(data->dpm_table.soc_table);
1345     vega10_setup_default_single_dpm_table(hwmgr,
1346             dpm_table,
1347             dep_soc_table);
1348 
1349     vega10_init_dpm_state(&(dpm_table->dpm_state));
1350 
1351     dpm_table = &(data->dpm_table.gfx_table);
1352     vega10_setup_default_single_dpm_table(hwmgr,
1353             dpm_table,
1354             dep_gfx_table);
1355     if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0)
1356         hwmgr->platform_descriptor.overdriveLimit.engineClock =
1357                     dpm_table->dpm_levels[dpm_table->count-1].value;
1358     vega10_init_dpm_state(&(dpm_table->dpm_state));
1359 
1360     /* Initialize Mclk DPM table based on allow Mclk values */
1361     data->dpm_table.mem_table.count = 0;
1362     dpm_table = &(data->dpm_table.mem_table);
1363     vega10_setup_default_single_dpm_table(hwmgr,
1364             dpm_table,
1365             dep_mclk_table);
1366     if (hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0)
1367         hwmgr->platform_descriptor.overdriveLimit.memoryClock =
1368                     dpm_table->dpm_levels[dpm_table->count-1].value;
1369     vega10_init_dpm_state(&(dpm_table->dpm_state));
1370 
1371     data->dpm_table.eclk_table.count = 0;
1372     dpm_table = &(data->dpm_table.eclk_table);
1373     for (i = 0; i < dep_mm_table->count; i++) {
1374         if (i == 0 || dpm_table->dpm_levels
1375                 [dpm_table->count - 1].value <=
1376                         dep_mm_table->entries[i].eclk) {
1377             dpm_table->dpm_levels[dpm_table->count].value =
1378                     dep_mm_table->entries[i].eclk;
1379             dpm_table->dpm_levels[dpm_table->count].enabled =
1380                     (i == 0) ? true : false;
1381             dpm_table->count++;
1382         }
1383     }
1384     vega10_init_dpm_state(&(dpm_table->dpm_state));
1385 
1386     data->dpm_table.vclk_table.count = 0;
1387     data->dpm_table.dclk_table.count = 0;
1388     dpm_table = &(data->dpm_table.vclk_table);
1389     for (i = 0; i < dep_mm_table->count; i++) {
1390         if (i == 0 || dpm_table->dpm_levels
1391                 [dpm_table->count - 1].value <=
1392                         dep_mm_table->entries[i].vclk) {
1393             dpm_table->dpm_levels[dpm_table->count].value =
1394                     dep_mm_table->entries[i].vclk;
1395             dpm_table->dpm_levels[dpm_table->count].enabled =
1396                     (i == 0) ? true : false;
1397             dpm_table->count++;
1398         }
1399     }
1400     vega10_init_dpm_state(&(dpm_table->dpm_state));
1401 
1402     dpm_table = &(data->dpm_table.dclk_table);
1403     for (i = 0; i < dep_mm_table->count; i++) {
1404         if (i == 0 || dpm_table->dpm_levels
1405                 [dpm_table->count - 1].value <=
1406                         dep_mm_table->entries[i].dclk) {
1407             dpm_table->dpm_levels[dpm_table->count].value =
1408                     dep_mm_table->entries[i].dclk;
1409             dpm_table->dpm_levels[dpm_table->count].enabled =
1410                     (i == 0) ? true : false;
1411             dpm_table->count++;
1412         }
1413     }
1414     vega10_init_dpm_state(&(dpm_table->dpm_state));
1415 
1416     /* Assume there is no headless Vega10 for now */
1417     dpm_table = &(data->dpm_table.dcef_table);
1418     vega10_setup_default_single_dpm_table(hwmgr,
1419             dpm_table,
1420             dep_dcef_table);
1421 
1422     vega10_init_dpm_state(&(dpm_table->dpm_state));
1423 
1424     dpm_table = &(data->dpm_table.pixel_table);
1425     vega10_setup_default_single_dpm_table(hwmgr,
1426             dpm_table,
1427             dep_pix_table);
1428 
1429     vega10_init_dpm_state(&(dpm_table->dpm_state));
1430 
1431     dpm_table = &(data->dpm_table.display_table);
1432     vega10_setup_default_single_dpm_table(hwmgr,
1433             dpm_table,
1434             dep_disp_table);
1435 
1436     vega10_init_dpm_state(&(dpm_table->dpm_state));
1437 
1438     dpm_table = &(data->dpm_table.phy_table);
1439     vega10_setup_default_single_dpm_table(hwmgr,
1440             dpm_table,
1441             dep_phy_table);
1442 
1443     vega10_init_dpm_state(&(dpm_table->dpm_state));
1444 
1445     vega10_setup_default_pcie_table(hwmgr);
1446 
1447     /* Zero out the saved copy of the CUSTOM profile
1448      * This will be checked when trying to set the profile
1449      * and will require that new values be passed in
1450      */
1451     data->custom_profile_mode[0] = 0;
1452     data->custom_profile_mode[1] = 0;
1453     data->custom_profile_mode[2] = 0;
1454     data->custom_profile_mode[3] = 0;
1455 
1456     /* save a copy of the default DPM table */
1457     memcpy(&(data->golden_dpm_table), &(data->dpm_table),
1458             sizeof(struct vega10_dpm_table));
1459 
1460     return 0;
1461 }
1462 
1463 /*
1464  * vega10_populate_ulv_state
1465  * Function to provide parameters for Utral Low Voltage state to SMC.
1466  *
1467  * @hwmgr: - the address of the hardware manager.
1468  * return:   Always 0.
1469  */
1470 static int vega10_populate_ulv_state(struct pp_hwmgr *hwmgr)
1471 {
1472     struct vega10_hwmgr *data = hwmgr->backend;
1473     struct phm_ppt_v2_information *table_info =
1474             (struct phm_ppt_v2_information *)(hwmgr->pptable);
1475 
1476     data->smc_state_table.pp_table.UlvOffsetVid =
1477             (uint8_t)table_info->us_ulv_voltage_offset;
1478 
1479     data->smc_state_table.pp_table.UlvSmnclkDid =
1480             (uint8_t)(table_info->us_ulv_smnclk_did);
1481     data->smc_state_table.pp_table.UlvMp1clkDid =
1482             (uint8_t)(table_info->us_ulv_mp1clk_did);
1483     data->smc_state_table.pp_table.UlvGfxclkBypass =
1484             (uint8_t)(table_info->us_ulv_gfxclk_bypass);
1485     data->smc_state_table.pp_table.UlvPhaseSheddingPsi0 =
1486             (uint8_t)(data->vddc_voltage_table.psi0_enable);
1487     data->smc_state_table.pp_table.UlvPhaseSheddingPsi1 =
1488             (uint8_t)(data->vddc_voltage_table.psi1_enable);
1489 
1490     return 0;
1491 }
1492 
1493 static int vega10_populate_single_lclk_level(struct pp_hwmgr *hwmgr,
1494         uint32_t lclock, uint8_t *curr_lclk_did)
1495 {
1496     struct pp_atomfwctrl_clock_dividers_soc15 dividers;
1497 
1498     PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(
1499             hwmgr,
1500             COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
1501             lclock, &dividers),
1502             "Failed to get LCLK clock settings from VBIOS!",
1503             return -1);
1504 
1505     *curr_lclk_did = dividers.ulDid;
1506 
1507     return 0;
1508 }
1509 
1510 static int vega10_override_pcie_parameters(struct pp_hwmgr *hwmgr)
1511 {
1512     struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
1513     struct vega10_hwmgr *data =
1514             (struct vega10_hwmgr *)(hwmgr->backend);
1515     uint32_t pcie_gen = 0, pcie_width = 0;
1516     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
1517     int i;
1518 
1519     if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
1520         pcie_gen = 3;
1521     else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
1522         pcie_gen = 2;
1523     else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
1524         pcie_gen = 1;
1525     else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1)
1526         pcie_gen = 0;
1527 
1528     if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16)
1529         pcie_width = 6;
1530     else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12)
1531         pcie_width = 5;
1532     else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8)
1533         pcie_width = 4;
1534     else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4)
1535         pcie_width = 3;
1536     else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2)
1537         pcie_width = 2;
1538     else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1)
1539         pcie_width = 1;
1540 
1541     for (i = 0; i < NUM_LINK_LEVELS; i++) {
1542         if (pp_table->PcieGenSpeed[i] > pcie_gen)
1543             pp_table->PcieGenSpeed[i] = pcie_gen;
1544 
1545         if (pp_table->PcieLaneCount[i] > pcie_width)
1546             pp_table->PcieLaneCount[i] = pcie_width;
1547     }
1548 
1549     if (data->registry_data.pcie_dpm_key_disabled) {
1550         for (i = 0; i < NUM_LINK_LEVELS; i++) {
1551             pp_table->PcieGenSpeed[i] = pcie_gen;
1552             pp_table->PcieLaneCount[i] = pcie_width;
1553         }
1554     }
1555 
1556     return 0;
1557 }
1558 
1559 static int vega10_populate_smc_link_levels(struct pp_hwmgr *hwmgr)
1560 {
1561     int result = -1;
1562     struct vega10_hwmgr *data = hwmgr->backend;
1563     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
1564     struct vega10_pcie_table *pcie_table =
1565             &(data->dpm_table.pcie_table);
1566     uint32_t i, j;
1567 
1568     for (i = 0; i < pcie_table->count; i++) {
1569         pp_table->PcieGenSpeed[i] = pcie_table->pcie_gen[i];
1570         pp_table->PcieLaneCount[i] = pcie_table->pcie_lane[i];
1571 
1572         result = vega10_populate_single_lclk_level(hwmgr,
1573                 pcie_table->lclk[i], &(pp_table->LclkDid[i]));
1574         if (result) {
1575             pr_info("Populate LClock Level %d Failed!\n", i);
1576             return result;
1577         }
1578     }
1579 
1580     j = i - 1;
1581     while (i < NUM_LINK_LEVELS) {
1582         pp_table->PcieGenSpeed[i] = pcie_table->pcie_gen[j];
1583         pp_table->PcieLaneCount[i] = pcie_table->pcie_lane[j];
1584 
1585         result = vega10_populate_single_lclk_level(hwmgr,
1586                 pcie_table->lclk[j], &(pp_table->LclkDid[i]));
1587         if (result) {
1588             pr_info("Populate LClock Level %d Failed!\n", i);
1589             return result;
1590         }
1591         i++;
1592     }
1593 
1594     return result;
1595 }
1596 
1597 /**
1598  * vega10_populate_single_gfx_level - Populates single SMC GFXSCLK structure
1599  *                                    using the provided engine clock
1600  *
1601  * @hwmgr:      the address of the hardware manager
1602  * @gfx_clock:  the GFX clock to use to populate the structure.
1603  * @current_gfxclk_level:  location in PPTable for the SMC GFXCLK structure.
1604  * @acg_freq:   ACG frequenty to return (MHz)
1605  */
1606 static int vega10_populate_single_gfx_level(struct pp_hwmgr *hwmgr,
1607         uint32_t gfx_clock, PllSetting_t *current_gfxclk_level,
1608         uint32_t *acg_freq)
1609 {
1610     struct phm_ppt_v2_information *table_info =
1611             (struct phm_ppt_v2_information *)(hwmgr->pptable);
1612     struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_sclk;
1613     struct vega10_hwmgr *data = hwmgr->backend;
1614     struct pp_atomfwctrl_clock_dividers_soc15 dividers;
1615     uint32_t gfx_max_clock =
1616             hwmgr->platform_descriptor.overdriveLimit.engineClock;
1617     uint32_t i = 0;
1618 
1619     if (hwmgr->od_enabled)
1620         dep_on_sclk = (struct phm_ppt_v1_clock_voltage_dependency_table *)
1621                         &(data->odn_dpm_table.vdd_dep_on_sclk);
1622     else
1623         dep_on_sclk = table_info->vdd_dep_on_sclk;
1624 
1625     PP_ASSERT_WITH_CODE(dep_on_sclk,
1626             "Invalid SOC_VDD-GFX_CLK Dependency Table!",
1627             return -EINVAL);
1628 
1629     if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_SCLK)
1630         gfx_clock = gfx_clock > gfx_max_clock ? gfx_max_clock : gfx_clock;
1631     else {
1632         for (i = 0; i < dep_on_sclk->count; i++) {
1633             if (dep_on_sclk->entries[i].clk == gfx_clock)
1634                 break;
1635         }
1636         PP_ASSERT_WITH_CODE(dep_on_sclk->count > i,
1637                 "Cannot find gfx_clk in SOC_VDD-GFX_CLK!",
1638                 return -EINVAL);
1639     }
1640 
1641     PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr,
1642             COMPUTE_GPUCLK_INPUT_FLAG_GFXCLK,
1643             gfx_clock, &dividers),
1644             "Failed to get GFX Clock settings from VBIOS!",
1645             return -EINVAL);
1646 
1647     /* Feedback Multiplier: bit 0:8 int, bit 15:12 post_div, bit 31:16 frac */
1648     current_gfxclk_level->FbMult =
1649             cpu_to_le32(dividers.ulPll_fb_mult);
1650     /* Spread FB Multiplier bit: bit 0:8 int, bit 31:16 frac */
1651     current_gfxclk_level->SsOn = dividers.ucPll_ss_enable;
1652     current_gfxclk_level->SsFbMult =
1653             cpu_to_le32(dividers.ulPll_ss_fbsmult);
1654     current_gfxclk_level->SsSlewFrac =
1655             cpu_to_le16(dividers.usPll_ss_slew_frac);
1656     current_gfxclk_level->Did = (uint8_t)(dividers.ulDid);
1657 
1658     *acg_freq = gfx_clock / 100; /* 100 Khz to Mhz conversion */
1659 
1660     return 0;
1661 }
1662 
1663 /**
1664  * vega10_populate_single_soc_level - Populates single SMC SOCCLK structure
1665  *                                    using the provided clock.
1666  *
1667  * @hwmgr:     the address of the hardware manager.
1668  * @soc_clock: the SOC clock to use to populate the structure.
1669  * @current_soc_did:   DFS divider to pass back to caller
1670  * @current_vol_index: index of current VDD to pass back to caller
1671  * return:      0 on success
1672  */
1673 static int vega10_populate_single_soc_level(struct pp_hwmgr *hwmgr,
1674         uint32_t soc_clock, uint8_t *current_soc_did,
1675         uint8_t *current_vol_index)
1676 {
1677     struct vega10_hwmgr *data = hwmgr->backend;
1678     struct phm_ppt_v2_information *table_info =
1679             (struct phm_ppt_v2_information *)(hwmgr->pptable);
1680     struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_soc;
1681     struct pp_atomfwctrl_clock_dividers_soc15 dividers;
1682     uint32_t i;
1683 
1684     if (hwmgr->od_enabled) {
1685         dep_on_soc = (struct phm_ppt_v1_clock_voltage_dependency_table *)
1686                         &data->odn_dpm_table.vdd_dep_on_socclk;
1687         for (i = 0; i < dep_on_soc->count; i++) {
1688             if (dep_on_soc->entries[i].clk >= soc_clock)
1689                 break;
1690         }
1691     } else {
1692         dep_on_soc = table_info->vdd_dep_on_socclk;
1693         for (i = 0; i < dep_on_soc->count; i++) {
1694             if (dep_on_soc->entries[i].clk == soc_clock)
1695                 break;
1696         }
1697     }
1698 
1699     PP_ASSERT_WITH_CODE(dep_on_soc->count > i,
1700             "Cannot find SOC_CLK in SOC_VDD-SOC_CLK Dependency Table",
1701             return -EINVAL);
1702 
1703     PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr,
1704             COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
1705             soc_clock, &dividers),
1706             "Failed to get SOC Clock settings from VBIOS!",
1707             return -EINVAL);
1708 
1709     *current_soc_did = (uint8_t)dividers.ulDid;
1710     *current_vol_index = (uint8_t)(dep_on_soc->entries[i].vddInd);
1711     return 0;
1712 }
1713 
1714 /**
1715  * vega10_populate_all_graphic_levels - Populates all SMC SCLK levels' structure
1716  *                                      based on the trimmed allowed dpm engine clock states
1717  *
1718  * @hwmgr:      the address of the hardware manager
1719  */
1720 static int vega10_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
1721 {
1722     struct vega10_hwmgr *data = hwmgr->backend;
1723     struct phm_ppt_v2_information *table_info =
1724             (struct phm_ppt_v2_information *)(hwmgr->pptable);
1725     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
1726     struct vega10_single_dpm_table *dpm_table = &(data->dpm_table.gfx_table);
1727     int result = 0;
1728     uint32_t i, j;
1729 
1730     for (i = 0; i < dpm_table->count; i++) {
1731         result = vega10_populate_single_gfx_level(hwmgr,
1732                 dpm_table->dpm_levels[i].value,
1733                 &(pp_table->GfxclkLevel[i]),
1734                 &(pp_table->AcgFreqTable[i]));
1735         if (result)
1736             return result;
1737     }
1738 
1739     j = i - 1;
1740     while (i < NUM_GFXCLK_DPM_LEVELS) {
1741         result = vega10_populate_single_gfx_level(hwmgr,
1742                 dpm_table->dpm_levels[j].value,
1743                 &(pp_table->GfxclkLevel[i]),
1744                 &(pp_table->AcgFreqTable[i]));
1745         if (result)
1746             return result;
1747         i++;
1748     }
1749 
1750     pp_table->GfxclkSlewRate =
1751             cpu_to_le16(table_info->us_gfxclk_slew_rate);
1752 
1753     dpm_table = &(data->dpm_table.soc_table);
1754     for (i = 0; i < dpm_table->count; i++) {
1755         result = vega10_populate_single_soc_level(hwmgr,
1756                 dpm_table->dpm_levels[i].value,
1757                 &(pp_table->SocclkDid[i]),
1758                 &(pp_table->SocDpmVoltageIndex[i]));
1759         if (result)
1760             return result;
1761     }
1762 
1763     j = i - 1;
1764     while (i < NUM_SOCCLK_DPM_LEVELS) {
1765         result = vega10_populate_single_soc_level(hwmgr,
1766                 dpm_table->dpm_levels[j].value,
1767                 &(pp_table->SocclkDid[i]),
1768                 &(pp_table->SocDpmVoltageIndex[i]));
1769         if (result)
1770             return result;
1771         i++;
1772     }
1773 
1774     return result;
1775 }
1776 
1777 static void vega10_populate_vddc_soc_levels(struct pp_hwmgr *hwmgr)
1778 {
1779     struct vega10_hwmgr *data = hwmgr->backend;
1780     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
1781     struct phm_ppt_v2_information *table_info = hwmgr->pptable;
1782     struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table;
1783 
1784     uint8_t soc_vid = 0;
1785     uint32_t i, max_vddc_level;
1786 
1787     if (hwmgr->od_enabled)
1788         vddc_lookup_table = (struct phm_ppt_v1_voltage_lookup_table *)&data->odn_dpm_table.vddc_lookup_table;
1789     else
1790         vddc_lookup_table = table_info->vddc_lookup_table;
1791 
1792     max_vddc_level = vddc_lookup_table->count;
1793     for (i = 0; i < max_vddc_level; i++) {
1794         soc_vid = (uint8_t)convert_to_vid(vddc_lookup_table->entries[i].us_vdd);
1795         pp_table->SocVid[i] = soc_vid;
1796     }
1797     while (i < MAX_REGULAR_DPM_NUMBER) {
1798         pp_table->SocVid[i] = soc_vid;
1799         i++;
1800     }
1801 }
1802 
1803 /*
1804  * Populates single SMC GFXCLK structure using the provided clock.
1805  *
1806  * @hwmgr:     the address of the hardware manager.
1807  * @mem_clock: the memory clock to use to populate the structure.
1808  * return:     0 on success..
1809  */
1810 static int vega10_populate_single_memory_level(struct pp_hwmgr *hwmgr,
1811         uint32_t mem_clock, uint8_t *current_mem_vid,
1812         PllSetting_t *current_memclk_level, uint8_t *current_mem_soc_vind)
1813 {
1814     struct vega10_hwmgr *data = hwmgr->backend;
1815     struct phm_ppt_v2_information *table_info =
1816             (struct phm_ppt_v2_information *)(hwmgr->pptable);
1817     struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_mclk;
1818     struct pp_atomfwctrl_clock_dividers_soc15 dividers;
1819     uint32_t mem_max_clock =
1820             hwmgr->platform_descriptor.overdriveLimit.memoryClock;
1821     uint32_t i = 0;
1822 
1823     if (hwmgr->od_enabled)
1824         dep_on_mclk = (struct phm_ppt_v1_clock_voltage_dependency_table *)
1825                     &data->odn_dpm_table.vdd_dep_on_mclk;
1826     else
1827         dep_on_mclk = table_info->vdd_dep_on_mclk;
1828 
1829     PP_ASSERT_WITH_CODE(dep_on_mclk,
1830             "Invalid SOC_VDD-UCLK Dependency Table!",
1831             return -EINVAL);
1832 
1833     if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
1834         mem_clock = mem_clock > mem_max_clock ? mem_max_clock : mem_clock;
1835     } else {
1836         for (i = 0; i < dep_on_mclk->count; i++) {
1837             if (dep_on_mclk->entries[i].clk == mem_clock)
1838                 break;
1839         }
1840         PP_ASSERT_WITH_CODE(dep_on_mclk->count > i,
1841                 "Cannot find UCLK in SOC_VDD-UCLK Dependency Table!",
1842                 return -EINVAL);
1843     }
1844 
1845     PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(
1846             hwmgr, COMPUTE_GPUCLK_INPUT_FLAG_UCLK, mem_clock, &dividers),
1847             "Failed to get UCLK settings from VBIOS!",
1848             return -1);
1849 
1850     *current_mem_vid =
1851             (uint8_t)(convert_to_vid(dep_on_mclk->entries[i].mvdd));
1852     *current_mem_soc_vind =
1853             (uint8_t)(dep_on_mclk->entries[i].vddInd);
1854     current_memclk_level->FbMult = cpu_to_le32(dividers.ulPll_fb_mult);
1855     current_memclk_level->Did = (uint8_t)(dividers.ulDid);
1856 
1857     PP_ASSERT_WITH_CODE(current_memclk_level->Did >= 1,
1858             "Invalid Divider ID!",
1859             return -EINVAL);
1860 
1861     return 0;
1862 }
1863 
1864 /**
1865  * vega10_populate_all_memory_levels - Populates all SMC MCLK levels' structure
1866  *                                     based on the trimmed allowed dpm memory clock states.
1867  *
1868  * @hwmgr:  the address of the hardware manager.
1869  * return:   PP_Result_OK on success.
1870  */
1871 static int vega10_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
1872 {
1873     struct vega10_hwmgr *data = hwmgr->backend;
1874     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
1875     struct vega10_single_dpm_table *dpm_table =
1876             &(data->dpm_table.mem_table);
1877     int result = 0;
1878     uint32_t i, j;
1879 
1880     for (i = 0; i < dpm_table->count; i++) {
1881         result = vega10_populate_single_memory_level(hwmgr,
1882                 dpm_table->dpm_levels[i].value,
1883                 &(pp_table->MemVid[i]),
1884                 &(pp_table->UclkLevel[i]),
1885                 &(pp_table->MemSocVoltageIndex[i]));
1886         if (result)
1887             return result;
1888     }
1889 
1890     j = i - 1;
1891     while (i < NUM_UCLK_DPM_LEVELS) {
1892         result = vega10_populate_single_memory_level(hwmgr,
1893                 dpm_table->dpm_levels[j].value,
1894                 &(pp_table->MemVid[i]),
1895                 &(pp_table->UclkLevel[i]),
1896                 &(pp_table->MemSocVoltageIndex[i]));
1897         if (result)
1898             return result;
1899         i++;
1900     }
1901 
1902     pp_table->NumMemoryChannels = (uint16_t)(data->mem_channels);
1903     pp_table->MemoryChannelWidth =
1904             (uint16_t)(HBM_MEMORY_CHANNEL_WIDTH *
1905                     channel_number[data->mem_channels]);
1906 
1907     pp_table->LowestUclkReservedForUlv =
1908             (uint8_t)(data->lowest_uclk_reserved_for_ulv);
1909 
1910     return result;
1911 }
1912 
1913 static int vega10_populate_single_display_type(struct pp_hwmgr *hwmgr,
1914         DSPCLK_e disp_clock)
1915 {
1916     struct vega10_hwmgr *data = hwmgr->backend;
1917     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
1918     struct phm_ppt_v2_information *table_info =
1919             (struct phm_ppt_v2_information *)
1920             (hwmgr->pptable);
1921     struct phm_ppt_v1_clock_voltage_dependency_table *dep_table;
1922     uint32_t i;
1923     uint16_t clk = 0, vddc = 0;
1924     uint8_t vid = 0;
1925 
1926     switch (disp_clock) {
1927     case DSPCLK_DCEFCLK:
1928         dep_table = table_info->vdd_dep_on_dcefclk;
1929         break;
1930     case DSPCLK_DISPCLK:
1931         dep_table = table_info->vdd_dep_on_dispclk;
1932         break;
1933     case DSPCLK_PIXCLK:
1934         dep_table = table_info->vdd_dep_on_pixclk;
1935         break;
1936     case DSPCLK_PHYCLK:
1937         dep_table = table_info->vdd_dep_on_phyclk;
1938         break;
1939     default:
1940         return -1;
1941     }
1942 
1943     PP_ASSERT_WITH_CODE(dep_table->count <= NUM_DSPCLK_LEVELS,
1944             "Number Of Entries Exceeded maximum!",
1945             return -1);
1946 
1947     for (i = 0; i < dep_table->count; i++) {
1948         clk = (uint16_t)(dep_table->entries[i].clk / 100);
1949         vddc = table_info->vddc_lookup_table->
1950                 entries[dep_table->entries[i].vddInd].us_vdd;
1951         vid = (uint8_t)convert_to_vid(vddc);
1952         pp_table->DisplayClockTable[disp_clock][i].Freq =
1953                 cpu_to_le16(clk);
1954         pp_table->DisplayClockTable[disp_clock][i].Vid =
1955                 cpu_to_le16(vid);
1956     }
1957 
1958     while (i < NUM_DSPCLK_LEVELS) {
1959         pp_table->DisplayClockTable[disp_clock][i].Freq =
1960                 cpu_to_le16(clk);
1961         pp_table->DisplayClockTable[disp_clock][i].Vid =
1962                 cpu_to_le16(vid);
1963         i++;
1964     }
1965 
1966     return 0;
1967 }
1968 
1969 static int vega10_populate_all_display_clock_levels(struct pp_hwmgr *hwmgr)
1970 {
1971     uint32_t i;
1972 
1973     for (i = 0; i < DSPCLK_COUNT; i++) {
1974         PP_ASSERT_WITH_CODE(!vega10_populate_single_display_type(hwmgr, i),
1975                 "Failed to populate Clock in DisplayClockTable!",
1976                 return -1);
1977     }
1978 
1979     return 0;
1980 }
1981 
1982 static int vega10_populate_single_eclock_level(struct pp_hwmgr *hwmgr,
1983         uint32_t eclock, uint8_t *current_eclk_did,
1984         uint8_t *current_soc_vol)
1985 {
1986     struct phm_ppt_v2_information *table_info =
1987             (struct phm_ppt_v2_information *)(hwmgr->pptable);
1988     struct phm_ppt_v1_mm_clock_voltage_dependency_table *dep_table =
1989             table_info->mm_dep_table;
1990     struct pp_atomfwctrl_clock_dividers_soc15 dividers;
1991     uint32_t i;
1992 
1993     PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr,
1994             COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
1995             eclock, &dividers),
1996             "Failed to get ECLK clock settings from VBIOS!",
1997             return -1);
1998 
1999     *current_eclk_did = (uint8_t)dividers.ulDid;
2000 
2001     for (i = 0; i < dep_table->count; i++) {
2002         if (dep_table->entries[i].eclk == eclock)
2003             *current_soc_vol = dep_table->entries[i].vddcInd;
2004     }
2005 
2006     return 0;
2007 }
2008 
2009 static int vega10_populate_smc_vce_levels(struct pp_hwmgr *hwmgr)
2010 {
2011     struct vega10_hwmgr *data = hwmgr->backend;
2012     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
2013     struct vega10_single_dpm_table *dpm_table = &(data->dpm_table.eclk_table);
2014     int result = -EINVAL;
2015     uint32_t i, j;
2016 
2017     for (i = 0; i < dpm_table->count; i++) {
2018         result = vega10_populate_single_eclock_level(hwmgr,
2019                 dpm_table->dpm_levels[i].value,
2020                 &(pp_table->EclkDid[i]),
2021                 &(pp_table->VceDpmVoltageIndex[i]));
2022         if (result)
2023             return result;
2024     }
2025 
2026     j = i - 1;
2027     while (i < NUM_VCE_DPM_LEVELS) {
2028         result = vega10_populate_single_eclock_level(hwmgr,
2029                 dpm_table->dpm_levels[j].value,
2030                 &(pp_table->EclkDid[i]),
2031                 &(pp_table->VceDpmVoltageIndex[i]));
2032         if (result)
2033             return result;
2034         i++;
2035     }
2036 
2037     return result;
2038 }
2039 
2040 static int vega10_populate_single_vclock_level(struct pp_hwmgr *hwmgr,
2041         uint32_t vclock, uint8_t *current_vclk_did)
2042 {
2043     struct pp_atomfwctrl_clock_dividers_soc15 dividers;
2044 
2045     PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr,
2046             COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
2047             vclock, &dividers),
2048             "Failed to get VCLK clock settings from VBIOS!",
2049             return -EINVAL);
2050 
2051     *current_vclk_did = (uint8_t)dividers.ulDid;
2052 
2053     return 0;
2054 }
2055 
2056 static int vega10_populate_single_dclock_level(struct pp_hwmgr *hwmgr,
2057         uint32_t dclock, uint8_t *current_dclk_did)
2058 {
2059     struct pp_atomfwctrl_clock_dividers_soc15 dividers;
2060 
2061     PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr,
2062             COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
2063             dclock, &dividers),
2064             "Failed to get DCLK clock settings from VBIOS!",
2065             return -EINVAL);
2066 
2067     *current_dclk_did = (uint8_t)dividers.ulDid;
2068 
2069     return 0;
2070 }
2071 
2072 static int vega10_populate_smc_uvd_levels(struct pp_hwmgr *hwmgr)
2073 {
2074     struct vega10_hwmgr *data = hwmgr->backend;
2075     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
2076     struct vega10_single_dpm_table *vclk_dpm_table =
2077             &(data->dpm_table.vclk_table);
2078     struct vega10_single_dpm_table *dclk_dpm_table =
2079             &(data->dpm_table.dclk_table);
2080     struct phm_ppt_v2_information *table_info =
2081             (struct phm_ppt_v2_information *)(hwmgr->pptable);
2082     struct phm_ppt_v1_mm_clock_voltage_dependency_table *dep_table =
2083             table_info->mm_dep_table;
2084     int result = -EINVAL;
2085     uint32_t i, j;
2086 
2087     for (i = 0; i < vclk_dpm_table->count; i++) {
2088         result = vega10_populate_single_vclock_level(hwmgr,
2089                 vclk_dpm_table->dpm_levels[i].value,
2090                 &(pp_table->VclkDid[i]));
2091         if (result)
2092             return result;
2093     }
2094 
2095     j = i - 1;
2096     while (i < NUM_UVD_DPM_LEVELS) {
2097         result = vega10_populate_single_vclock_level(hwmgr,
2098                 vclk_dpm_table->dpm_levels[j].value,
2099                 &(pp_table->VclkDid[i]));
2100         if (result)
2101             return result;
2102         i++;
2103     }
2104 
2105     for (i = 0; i < dclk_dpm_table->count; i++) {
2106         result = vega10_populate_single_dclock_level(hwmgr,
2107                 dclk_dpm_table->dpm_levels[i].value,
2108                 &(pp_table->DclkDid[i]));
2109         if (result)
2110             return result;
2111     }
2112 
2113     j = i - 1;
2114     while (i < NUM_UVD_DPM_LEVELS) {
2115         result = vega10_populate_single_dclock_level(hwmgr,
2116                 dclk_dpm_table->dpm_levels[j].value,
2117                 &(pp_table->DclkDid[i]));
2118         if (result)
2119             return result;
2120         i++;
2121     }
2122 
2123     for (i = 0; i < dep_table->count; i++) {
2124         if (dep_table->entries[i].vclk ==
2125                 vclk_dpm_table->dpm_levels[i].value &&
2126             dep_table->entries[i].dclk ==
2127                 dclk_dpm_table->dpm_levels[i].value)
2128             pp_table->UvdDpmVoltageIndex[i] =
2129                     dep_table->entries[i].vddcInd;
2130         else
2131             return -1;
2132     }
2133 
2134     j = i - 1;
2135     while (i < NUM_UVD_DPM_LEVELS) {
2136         pp_table->UvdDpmVoltageIndex[i] = dep_table->entries[j].vddcInd;
2137         i++;
2138     }
2139 
2140     return 0;
2141 }
2142 
2143 static int vega10_populate_clock_stretcher_table(struct pp_hwmgr *hwmgr)
2144 {
2145     struct vega10_hwmgr *data = hwmgr->backend;
2146     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
2147     struct phm_ppt_v2_information *table_info =
2148             (struct phm_ppt_v2_information *)(hwmgr->pptable);
2149     struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
2150             table_info->vdd_dep_on_sclk;
2151     uint32_t i;
2152 
2153     for (i = 0; i < dep_table->count; i++) {
2154         pp_table->CksEnable[i] = dep_table->entries[i].cks_enable;
2155         pp_table->CksVidOffset[i] = (uint8_t)(dep_table->entries[i].cks_voffset
2156                 * VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1);
2157     }
2158 
2159     return 0;
2160 }
2161 
2162 static int vega10_populate_avfs_parameters(struct pp_hwmgr *hwmgr)
2163 {
2164     struct vega10_hwmgr *data = hwmgr->backend;
2165     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
2166     struct phm_ppt_v2_information *table_info =
2167             (struct phm_ppt_v2_information *)(hwmgr->pptable);
2168     struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
2169             table_info->vdd_dep_on_sclk;
2170     struct pp_atomfwctrl_avfs_parameters avfs_params = {0};
2171     int result = 0;
2172     uint32_t i;
2173 
2174     pp_table->MinVoltageVid = (uint8_t)0xff;
2175     pp_table->MaxVoltageVid = (uint8_t)0;
2176 
2177     if (data->smu_features[GNLD_AVFS].supported) {
2178         result = pp_atomfwctrl_get_avfs_information(hwmgr, &avfs_params);
2179         if (!result) {
2180             pp_table->MinVoltageVid = (uint8_t)
2181                     convert_to_vid((uint16_t)(avfs_params.ulMinVddc));
2182             pp_table->MaxVoltageVid = (uint8_t)
2183                     convert_to_vid((uint16_t)(avfs_params.ulMaxVddc));
2184 
2185             pp_table->AConstant[0] = cpu_to_le32(avfs_params.ulMeanNsigmaAcontant0);
2186             pp_table->AConstant[1] = cpu_to_le32(avfs_params.ulMeanNsigmaAcontant1);
2187             pp_table->AConstant[2] = cpu_to_le32(avfs_params.ulMeanNsigmaAcontant2);
2188             pp_table->DC_tol_sigma = cpu_to_le16(avfs_params.usMeanNsigmaDcTolSigma);
2189             pp_table->Platform_mean = cpu_to_le16(avfs_params.usMeanNsigmaPlatformMean);
2190             pp_table->Platform_sigma = cpu_to_le16(avfs_params.usMeanNsigmaDcTolSigma);
2191             pp_table->PSM_Age_CompFactor = cpu_to_le16(avfs_params.usPsmAgeComfactor);
2192 
2193             pp_table->BtcGbVdroopTableCksOff.a0 =
2194                     cpu_to_le32(avfs_params.ulGbVdroopTableCksoffA0);
2195             pp_table->BtcGbVdroopTableCksOff.a0_shift = 20;
2196             pp_table->BtcGbVdroopTableCksOff.a1 =
2197                     cpu_to_le32(avfs_params.ulGbVdroopTableCksoffA1);
2198             pp_table->BtcGbVdroopTableCksOff.a1_shift = 20;
2199             pp_table->BtcGbVdroopTableCksOff.a2 =
2200                     cpu_to_le32(avfs_params.ulGbVdroopTableCksoffA2);
2201             pp_table->BtcGbVdroopTableCksOff.a2_shift = 20;
2202 
2203             pp_table->OverrideBtcGbCksOn = avfs_params.ucEnableGbVdroopTableCkson;
2204             pp_table->BtcGbVdroopTableCksOn.a0 =
2205                     cpu_to_le32(avfs_params.ulGbVdroopTableCksonA0);
2206             pp_table->BtcGbVdroopTableCksOn.a0_shift = 20;
2207             pp_table->BtcGbVdroopTableCksOn.a1 =
2208                     cpu_to_le32(avfs_params.ulGbVdroopTableCksonA1);
2209             pp_table->BtcGbVdroopTableCksOn.a1_shift = 20;
2210             pp_table->BtcGbVdroopTableCksOn.a2 =
2211                     cpu_to_le32(avfs_params.ulGbVdroopTableCksonA2);
2212             pp_table->BtcGbVdroopTableCksOn.a2_shift = 20;
2213 
2214             pp_table->AvfsGbCksOn.m1 =
2215                     cpu_to_le32(avfs_params.ulGbFuseTableCksonM1);
2216             pp_table->AvfsGbCksOn.m2 =
2217                     cpu_to_le32(avfs_params.ulGbFuseTableCksonM2);
2218             pp_table->AvfsGbCksOn.b =
2219                     cpu_to_le32(avfs_params.ulGbFuseTableCksonB);
2220             pp_table->AvfsGbCksOn.m1_shift = 24;
2221             pp_table->AvfsGbCksOn.m2_shift = 12;
2222             pp_table->AvfsGbCksOn.b_shift = 0;
2223 
2224             pp_table->OverrideAvfsGbCksOn =
2225                     avfs_params.ucEnableGbFuseTableCkson;
2226             pp_table->AvfsGbCksOff.m1 =
2227                     cpu_to_le32(avfs_params.ulGbFuseTableCksoffM1);
2228             pp_table->AvfsGbCksOff.m2 =
2229                     cpu_to_le32(avfs_params.ulGbFuseTableCksoffM2);
2230             pp_table->AvfsGbCksOff.b =
2231                     cpu_to_le32(avfs_params.ulGbFuseTableCksoffB);
2232             pp_table->AvfsGbCksOff.m1_shift = 24;
2233             pp_table->AvfsGbCksOff.m2_shift = 12;
2234             pp_table->AvfsGbCksOff.b_shift = 0;
2235 
2236             for (i = 0; i < dep_table->count; i++)
2237                 pp_table->StaticVoltageOffsetVid[i] =
2238                         convert_to_vid((uint8_t)(dep_table->entries[i].sclk_offset));
2239 
2240             if ((PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2241                     data->disp_clk_quad_eqn_a) &&
2242                 (PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2243                     data->disp_clk_quad_eqn_b)) {
2244                 pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m1 =
2245                         (int32_t)data->disp_clk_quad_eqn_a;
2246                 pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m2 =
2247                         (int32_t)data->disp_clk_quad_eqn_b;
2248                 pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].b =
2249                         (int32_t)data->disp_clk_quad_eqn_c;
2250             } else {
2251                 pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m1 =
2252                         (int32_t)avfs_params.ulDispclk2GfxclkM1;
2253                 pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m2 =
2254                         (int32_t)avfs_params.ulDispclk2GfxclkM2;
2255                 pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].b =
2256                         (int32_t)avfs_params.ulDispclk2GfxclkB;
2257             }
2258 
2259             pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m1_shift = 24;
2260             pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m2_shift = 12;
2261             pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].b_shift = 12;
2262 
2263             if ((PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2264                     data->dcef_clk_quad_eqn_a) &&
2265                 (PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2266                     data->dcef_clk_quad_eqn_b)) {
2267                 pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m1 =
2268                         (int32_t)data->dcef_clk_quad_eqn_a;
2269                 pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m2 =
2270                         (int32_t)data->dcef_clk_quad_eqn_b;
2271                 pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].b =
2272                         (int32_t)data->dcef_clk_quad_eqn_c;
2273             } else {
2274                 pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m1 =
2275                         (int32_t)avfs_params.ulDcefclk2GfxclkM1;
2276                 pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m2 =
2277                         (int32_t)avfs_params.ulDcefclk2GfxclkM2;
2278                 pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].b =
2279                         (int32_t)avfs_params.ulDcefclk2GfxclkB;
2280             }
2281 
2282             pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m1_shift = 24;
2283             pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m2_shift = 12;
2284             pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].b_shift = 12;
2285 
2286             if ((PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2287                     data->pixel_clk_quad_eqn_a) &&
2288                 (PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2289                     data->pixel_clk_quad_eqn_b)) {
2290                 pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m1 =
2291                         (int32_t)data->pixel_clk_quad_eqn_a;
2292                 pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m2 =
2293                         (int32_t)data->pixel_clk_quad_eqn_b;
2294                 pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].b =
2295                         (int32_t)data->pixel_clk_quad_eqn_c;
2296             } else {
2297                 pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m1 =
2298                         (int32_t)avfs_params.ulPixelclk2GfxclkM1;
2299                 pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m2 =
2300                         (int32_t)avfs_params.ulPixelclk2GfxclkM2;
2301                 pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].b =
2302                         (int32_t)avfs_params.ulPixelclk2GfxclkB;
2303             }
2304 
2305             pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m1_shift = 24;
2306             pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m2_shift = 12;
2307             pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].b_shift = 12;
2308             if ((PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2309                     data->phy_clk_quad_eqn_a) &&
2310                 (PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2311                     data->phy_clk_quad_eqn_b)) {
2312                 pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m1 =
2313                         (int32_t)data->phy_clk_quad_eqn_a;
2314                 pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m2 =
2315                         (int32_t)data->phy_clk_quad_eqn_b;
2316                 pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].b =
2317                         (int32_t)data->phy_clk_quad_eqn_c;
2318             } else {
2319                 pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m1 =
2320                         (int32_t)avfs_params.ulPhyclk2GfxclkM1;
2321                 pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m2 =
2322                         (int32_t)avfs_params.ulPhyclk2GfxclkM2;
2323                 pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].b =
2324                         (int32_t)avfs_params.ulPhyclk2GfxclkB;
2325             }
2326 
2327             pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m1_shift = 24;
2328             pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m2_shift = 12;
2329             pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].b_shift = 12;
2330 
2331             pp_table->AcgBtcGbVdroopTable.a0       = avfs_params.ulAcgGbVdroopTableA0;
2332             pp_table->AcgBtcGbVdroopTable.a0_shift = 20;
2333             pp_table->AcgBtcGbVdroopTable.a1       = avfs_params.ulAcgGbVdroopTableA1;
2334             pp_table->AcgBtcGbVdroopTable.a1_shift = 20;
2335             pp_table->AcgBtcGbVdroopTable.a2       = avfs_params.ulAcgGbVdroopTableA2;
2336             pp_table->AcgBtcGbVdroopTable.a2_shift = 20;
2337 
2338             pp_table->AcgAvfsGb.m1                   = avfs_params.ulAcgGbFuseTableM1;
2339             pp_table->AcgAvfsGb.m2                   = avfs_params.ulAcgGbFuseTableM2;
2340             pp_table->AcgAvfsGb.b                    = avfs_params.ulAcgGbFuseTableB;
2341             pp_table->AcgAvfsGb.m1_shift             = 24;
2342             pp_table->AcgAvfsGb.m2_shift             = 12;
2343             pp_table->AcgAvfsGb.b_shift              = 0;
2344 
2345         } else {
2346             data->smu_features[GNLD_AVFS].supported = false;
2347         }
2348     }
2349 
2350     return 0;
2351 }
2352 
2353 static int vega10_acg_enable(struct pp_hwmgr *hwmgr)
2354 {
2355     struct vega10_hwmgr *data = hwmgr->backend;
2356     uint32_t agc_btc_response;
2357 
2358     if (data->smu_features[GNLD_ACG].supported) {
2359         if (0 == vega10_enable_smc_features(hwmgr, true,
2360                     data->smu_features[GNLD_DPM_PREFETCHER].smu_feature_bitmap))
2361             data->smu_features[GNLD_DPM_PREFETCHER].enabled = true;
2362 
2363         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_InitializeAcg, NULL);
2364 
2365         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunAcgBtc, &agc_btc_response);
2366 
2367         if (1 == agc_btc_response) {
2368             if (1 == data->acg_loop_state)
2369                 smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunAcgInClosedLoop, NULL);
2370             else if (2 == data->acg_loop_state)
2371                 smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunAcgInOpenLoop, NULL);
2372             if (0 == vega10_enable_smc_features(hwmgr, true,
2373                 data->smu_features[GNLD_ACG].smu_feature_bitmap))
2374                     data->smu_features[GNLD_ACG].enabled = true;
2375         } else {
2376             pr_info("[ACG_Enable] ACG BTC Returned Failed Status!\n");
2377             data->smu_features[GNLD_ACG].enabled = false;
2378         }
2379     }
2380 
2381     return 0;
2382 }
2383 
2384 static int vega10_acg_disable(struct pp_hwmgr *hwmgr)
2385 {
2386     struct vega10_hwmgr *data = hwmgr->backend;
2387 
2388     if (data->smu_features[GNLD_ACG].supported &&
2389         data->smu_features[GNLD_ACG].enabled)
2390         if (!vega10_enable_smc_features(hwmgr, false,
2391             data->smu_features[GNLD_ACG].smu_feature_bitmap))
2392             data->smu_features[GNLD_ACG].enabled = false;
2393 
2394     return 0;
2395 }
2396 
2397 static int vega10_populate_gpio_parameters(struct pp_hwmgr *hwmgr)
2398 {
2399     struct vega10_hwmgr *data = hwmgr->backend;
2400     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
2401     struct pp_atomfwctrl_gpio_parameters gpio_params = {0};
2402     int result;
2403 
2404     result = pp_atomfwctrl_get_gpio_information(hwmgr, &gpio_params);
2405     if (!result) {
2406         if (PP_CAP(PHM_PlatformCaps_RegulatorHot) &&
2407             data->registry_data.regulator_hot_gpio_support) {
2408             pp_table->VR0HotGpio = gpio_params.ucVR0HotGpio;
2409             pp_table->VR0HotPolarity = gpio_params.ucVR0HotPolarity;
2410             pp_table->VR1HotGpio = gpio_params.ucVR1HotGpio;
2411             pp_table->VR1HotPolarity = gpio_params.ucVR1HotPolarity;
2412         } else {
2413             pp_table->VR0HotGpio = 0;
2414             pp_table->VR0HotPolarity = 0;
2415             pp_table->VR1HotGpio = 0;
2416             pp_table->VR1HotPolarity = 0;
2417         }
2418 
2419         if (PP_CAP(PHM_PlatformCaps_AutomaticDCTransition) &&
2420             data->registry_data.ac_dc_switch_gpio_support) {
2421             pp_table->AcDcGpio = gpio_params.ucAcDcGpio;
2422             pp_table->AcDcPolarity = gpio_params.ucAcDcPolarity;
2423         } else {
2424             pp_table->AcDcGpio = 0;
2425             pp_table->AcDcPolarity = 0;
2426         }
2427     }
2428 
2429     return result;
2430 }
2431 
2432 static int vega10_avfs_enable(struct pp_hwmgr *hwmgr, bool enable)
2433 {
2434     struct vega10_hwmgr *data = hwmgr->backend;
2435 
2436     if (data->smu_features[GNLD_AVFS].supported) {
2437         /* Already enabled or disabled */
2438         if (!(enable ^ data->smu_features[GNLD_AVFS].enabled))
2439             return 0;
2440 
2441         if (enable) {
2442             PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2443                     true,
2444                     data->smu_features[GNLD_AVFS].smu_feature_bitmap),
2445                     "[avfs_control] Attempt to Enable AVFS feature Failed!",
2446                     return -1);
2447             data->smu_features[GNLD_AVFS].enabled = true;
2448         } else {
2449             PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2450                     false,
2451                     data->smu_features[GNLD_AVFS].smu_feature_bitmap),
2452                     "[avfs_control] Attempt to Disable AVFS feature Failed!",
2453                     return -1);
2454             data->smu_features[GNLD_AVFS].enabled = false;
2455         }
2456     }
2457 
2458     return 0;
2459 }
2460 
2461 static int vega10_update_avfs(struct pp_hwmgr *hwmgr)
2462 {
2463     struct vega10_hwmgr *data = hwmgr->backend;
2464 
2465     if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_VDDC) {
2466         vega10_avfs_enable(hwmgr, false);
2467     } else if (data->need_update_dpm_table) {
2468         vega10_avfs_enable(hwmgr, false);
2469         vega10_avfs_enable(hwmgr, true);
2470     } else {
2471         vega10_avfs_enable(hwmgr, true);
2472     }
2473 
2474     return 0;
2475 }
2476 
2477 static int vega10_populate_and_upload_avfs_fuse_override(struct pp_hwmgr *hwmgr)
2478 {
2479     int result = 0;
2480 
2481     uint64_t serial_number = 0;
2482     uint32_t top32, bottom32;
2483     struct phm_fuses_default fuse;
2484 
2485     struct vega10_hwmgr *data = hwmgr->backend;
2486     AvfsFuseOverride_t *avfs_fuse_table = &(data->smc_state_table.avfs_fuse_override_table);
2487 
2488     smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumTop32, &top32);
2489 
2490     smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumBottom32, &bottom32);
2491 
2492     serial_number = ((uint64_t)bottom32 << 32) | top32;
2493 
2494     if (pp_override_get_default_fuse_value(serial_number, &fuse) == 0) {
2495         avfs_fuse_table->VFT0_b  = fuse.VFT0_b;
2496         avfs_fuse_table->VFT0_m1 = fuse.VFT0_m1;
2497         avfs_fuse_table->VFT0_m2 = fuse.VFT0_m2;
2498         avfs_fuse_table->VFT1_b  = fuse.VFT1_b;
2499         avfs_fuse_table->VFT1_m1 = fuse.VFT1_m1;
2500         avfs_fuse_table->VFT1_m2 = fuse.VFT1_m2;
2501         avfs_fuse_table->VFT2_b  = fuse.VFT2_b;
2502         avfs_fuse_table->VFT2_m1 = fuse.VFT2_m1;
2503         avfs_fuse_table->VFT2_m2 = fuse.VFT2_m2;
2504         result = smum_smc_table_manager(hwmgr,  (uint8_t *)avfs_fuse_table,
2505                         AVFSFUSETABLE, false);
2506         PP_ASSERT_WITH_CODE(!result,
2507             "Failed to upload FuseOVerride!",
2508             );
2509     }
2510 
2511     return result;
2512 }
2513 
2514 static void vega10_check_dpm_table_updated(struct pp_hwmgr *hwmgr)
2515 {
2516     struct vega10_hwmgr *data = hwmgr->backend;
2517     struct vega10_odn_dpm_table *odn_table = &(data->odn_dpm_table);
2518     struct phm_ppt_v2_information *table_info = hwmgr->pptable;
2519     struct phm_ppt_v1_clock_voltage_dependency_table *dep_table;
2520     struct phm_ppt_v1_clock_voltage_dependency_table *odn_dep_table;
2521     uint32_t i;
2522 
2523     dep_table = table_info->vdd_dep_on_mclk;
2524     odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dep_on_mclk);
2525 
2526     for (i = 0; i < dep_table->count; i++) {
2527         if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) {
2528             data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_MCLK;
2529             return;
2530         }
2531     }
2532 
2533     dep_table = table_info->vdd_dep_on_sclk;
2534     odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dep_on_sclk);
2535     for (i = 0; i < dep_table->count; i++) {
2536         if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) {
2537             data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_SCLK;
2538             return;
2539         }
2540     }
2541 }
2542 
2543 /**
2544  * vega10_init_smc_table - Initializes the SMC table and uploads it
2545  *
2546  * @hwmgr:  the address of the powerplay hardware manager.
2547  * return:  always 0
2548  */
2549 static int vega10_init_smc_table(struct pp_hwmgr *hwmgr)
2550 {
2551     int result;
2552     struct vega10_hwmgr *data = hwmgr->backend;
2553     struct phm_ppt_v2_information *table_info =
2554             (struct phm_ppt_v2_information *)(hwmgr->pptable);
2555     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
2556     struct pp_atomfwctrl_voltage_table voltage_table;
2557     struct pp_atomfwctrl_bios_boot_up_values boot_up_values;
2558     struct vega10_odn_dpm_table *odn_table = &(data->odn_dpm_table);
2559 
2560     result = vega10_setup_default_dpm_tables(hwmgr);
2561     PP_ASSERT_WITH_CODE(!result,
2562             "Failed to setup default DPM tables!",
2563             return result);
2564 
2565     if (!hwmgr->not_vf)
2566         return 0;
2567 
2568     /* initialize ODN table */
2569     if (hwmgr->od_enabled) {
2570         if (odn_table->max_vddc) {
2571             data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK;
2572             vega10_check_dpm_table_updated(hwmgr);
2573         } else {
2574             vega10_odn_initial_default_setting(hwmgr);
2575         }
2576     }
2577 
2578     pp_atomfwctrl_get_voltage_table_v4(hwmgr, VOLTAGE_TYPE_VDDC,
2579             VOLTAGE_OBJ_SVID2,  &voltage_table);
2580     pp_table->MaxVidStep = voltage_table.max_vid_step;
2581 
2582     pp_table->GfxDpmVoltageMode =
2583             (uint8_t)(table_info->uc_gfx_dpm_voltage_mode);
2584     pp_table->SocDpmVoltageMode =
2585             (uint8_t)(table_info->uc_soc_dpm_voltage_mode);
2586     pp_table->UclkDpmVoltageMode =
2587             (uint8_t)(table_info->uc_uclk_dpm_voltage_mode);
2588     pp_table->UvdDpmVoltageMode =
2589             (uint8_t)(table_info->uc_uvd_dpm_voltage_mode);
2590     pp_table->VceDpmVoltageMode =
2591             (uint8_t)(table_info->uc_vce_dpm_voltage_mode);
2592     pp_table->Mp0DpmVoltageMode =
2593             (uint8_t)(table_info->uc_mp0_dpm_voltage_mode);
2594 
2595     pp_table->DisplayDpmVoltageMode =
2596             (uint8_t)(table_info->uc_dcef_dpm_voltage_mode);
2597 
2598     data->vddc_voltage_table.psi0_enable = voltage_table.psi0_enable;
2599     data->vddc_voltage_table.psi1_enable = voltage_table.psi1_enable;
2600 
2601     if (data->registry_data.ulv_support &&
2602             table_info->us_ulv_voltage_offset) {
2603         result = vega10_populate_ulv_state(hwmgr);
2604         PP_ASSERT_WITH_CODE(!result,
2605                 "Failed to initialize ULV state!",
2606                 return result);
2607     }
2608 
2609     result = vega10_populate_smc_link_levels(hwmgr);
2610     PP_ASSERT_WITH_CODE(!result,
2611             "Failed to initialize Link Level!",
2612             return result);
2613 
2614     result = vega10_override_pcie_parameters(hwmgr);
2615     PP_ASSERT_WITH_CODE(!result,
2616             "Failed to override pcie parameters!",
2617             return result);
2618 
2619     result = vega10_populate_all_graphic_levels(hwmgr);
2620     PP_ASSERT_WITH_CODE(!result,
2621             "Failed to initialize Graphics Level!",
2622             return result);
2623 
2624     result = vega10_populate_all_memory_levels(hwmgr);
2625     PP_ASSERT_WITH_CODE(!result,
2626             "Failed to initialize Memory Level!",
2627             return result);
2628 
2629     vega10_populate_vddc_soc_levels(hwmgr);
2630 
2631     result = vega10_populate_all_display_clock_levels(hwmgr);
2632     PP_ASSERT_WITH_CODE(!result,
2633             "Failed to initialize Display Level!",
2634             return result);
2635 
2636     result = vega10_populate_smc_vce_levels(hwmgr);
2637     PP_ASSERT_WITH_CODE(!result,
2638             "Failed to initialize VCE Level!",
2639             return result);
2640 
2641     result = vega10_populate_smc_uvd_levels(hwmgr);
2642     PP_ASSERT_WITH_CODE(!result,
2643             "Failed to initialize UVD Level!",
2644             return result);
2645 
2646     if (data->registry_data.clock_stretcher_support) {
2647         result = vega10_populate_clock_stretcher_table(hwmgr);
2648         PP_ASSERT_WITH_CODE(!result,
2649                 "Failed to populate Clock Stretcher Table!",
2650                 return result);
2651     }
2652 
2653     result = pp_atomfwctrl_get_vbios_bootup_values(hwmgr, &boot_up_values);
2654     if (!result) {
2655         data->vbios_boot_state.vddc     = boot_up_values.usVddc;
2656         data->vbios_boot_state.vddci    = boot_up_values.usVddci;
2657         data->vbios_boot_state.mvddc    = boot_up_values.usMvddc;
2658         data->vbios_boot_state.gfx_clock = boot_up_values.ulGfxClk;
2659         data->vbios_boot_state.mem_clock = boot_up_values.ulUClk;
2660         pp_atomfwctrl_get_clk_information_by_clkid(hwmgr,
2661                 SMU9_SYSPLL0_SOCCLK_ID, 0, &boot_up_values.ulSocClk);
2662 
2663         pp_atomfwctrl_get_clk_information_by_clkid(hwmgr,
2664                 SMU9_SYSPLL0_DCEFCLK_ID, 0, &boot_up_values.ulDCEFClk);
2665 
2666         data->vbios_boot_state.soc_clock = boot_up_values.ulSocClk;
2667         data->vbios_boot_state.dcef_clock = boot_up_values.ulDCEFClk;
2668         if (0 != boot_up_values.usVddc) {
2669             smum_send_msg_to_smc_with_parameter(hwmgr,
2670                         PPSMC_MSG_SetFloorSocVoltage,
2671                         (boot_up_values.usVddc * 4),
2672                         NULL);
2673             data->vbios_boot_state.bsoc_vddc_lock = true;
2674         } else {
2675             data->vbios_boot_state.bsoc_vddc_lock = false;
2676         }
2677         smum_send_msg_to_smc_with_parameter(hwmgr,
2678                 PPSMC_MSG_SetMinDeepSleepDcefclk,
2679             (uint32_t)(data->vbios_boot_state.dcef_clock / 100),
2680                 NULL);
2681     }
2682 
2683     result = vega10_populate_avfs_parameters(hwmgr);
2684     PP_ASSERT_WITH_CODE(!result,
2685             "Failed to initialize AVFS Parameters!",
2686             return result);
2687 
2688     result = vega10_populate_gpio_parameters(hwmgr);
2689     PP_ASSERT_WITH_CODE(!result,
2690             "Failed to initialize GPIO Parameters!",
2691             return result);
2692 
2693     pp_table->GfxclkAverageAlpha = (uint8_t)
2694             (data->gfxclk_average_alpha);
2695     pp_table->SocclkAverageAlpha = (uint8_t)
2696             (data->socclk_average_alpha);
2697     pp_table->UclkAverageAlpha = (uint8_t)
2698             (data->uclk_average_alpha);
2699     pp_table->GfxActivityAverageAlpha = (uint8_t)
2700             (data->gfx_activity_average_alpha);
2701 
2702     vega10_populate_and_upload_avfs_fuse_override(hwmgr);
2703 
2704     result = smum_smc_table_manager(hwmgr, (uint8_t *)pp_table, PPTABLE, false);
2705 
2706     PP_ASSERT_WITH_CODE(!result,
2707             "Failed to upload PPtable!", return result);
2708 
2709     result = vega10_avfs_enable(hwmgr, true);
2710     PP_ASSERT_WITH_CODE(!result, "Attempt to enable AVFS feature Failed!",
2711                     return result);
2712     vega10_acg_enable(hwmgr);
2713 
2714     return 0;
2715 }
2716 
2717 static int vega10_enable_thermal_protection(struct pp_hwmgr *hwmgr)
2718 {
2719     struct vega10_hwmgr *data = hwmgr->backend;
2720 
2721     if (data->smu_features[GNLD_THERMAL].supported) {
2722         if (data->smu_features[GNLD_THERMAL].enabled)
2723             pr_info("THERMAL Feature Already enabled!");
2724 
2725         PP_ASSERT_WITH_CODE(
2726                 !vega10_enable_smc_features(hwmgr,
2727                 true,
2728                 data->smu_features[GNLD_THERMAL].smu_feature_bitmap),
2729                 "Enable THERMAL Feature Failed!",
2730                 return -1);
2731         data->smu_features[GNLD_THERMAL].enabled = true;
2732     }
2733 
2734     return 0;
2735 }
2736 
2737 static int vega10_disable_thermal_protection(struct pp_hwmgr *hwmgr)
2738 {
2739     struct vega10_hwmgr *data = hwmgr->backend;
2740 
2741     if (data->smu_features[GNLD_THERMAL].supported) {
2742         if (!data->smu_features[GNLD_THERMAL].enabled)
2743             pr_info("THERMAL Feature Already disabled!");
2744 
2745         PP_ASSERT_WITH_CODE(
2746                 !vega10_enable_smc_features(hwmgr,
2747                 false,
2748                 data->smu_features[GNLD_THERMAL].smu_feature_bitmap),
2749                 "disable THERMAL Feature Failed!",
2750                 return -1);
2751         data->smu_features[GNLD_THERMAL].enabled = false;
2752     }
2753 
2754     return 0;
2755 }
2756 
2757 static int vega10_enable_vrhot_feature(struct pp_hwmgr *hwmgr)
2758 {
2759     struct vega10_hwmgr *data = hwmgr->backend;
2760 
2761     if (PP_CAP(PHM_PlatformCaps_RegulatorHot)) {
2762         if (data->smu_features[GNLD_VR0HOT].supported) {
2763             PP_ASSERT_WITH_CODE(
2764                     !vega10_enable_smc_features(hwmgr,
2765                     true,
2766                     data->smu_features[GNLD_VR0HOT].smu_feature_bitmap),
2767                     "Attempt to Enable VR0 Hot feature Failed!",
2768                     return -1);
2769             data->smu_features[GNLD_VR0HOT].enabled = true;
2770         } else {
2771             if (data->smu_features[GNLD_VR1HOT].supported) {
2772                 PP_ASSERT_WITH_CODE(
2773                         !vega10_enable_smc_features(hwmgr,
2774                         true,
2775                         data->smu_features[GNLD_VR1HOT].smu_feature_bitmap),
2776                         "Attempt to Enable VR0 Hot feature Failed!",
2777                         return -1);
2778                 data->smu_features[GNLD_VR1HOT].enabled = true;
2779             }
2780         }
2781     }
2782     return 0;
2783 }
2784 
2785 static int vega10_enable_ulv(struct pp_hwmgr *hwmgr)
2786 {
2787     struct vega10_hwmgr *data = hwmgr->backend;
2788 
2789     if (data->registry_data.ulv_support) {
2790         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2791                 true, data->smu_features[GNLD_ULV].smu_feature_bitmap),
2792                 "Enable ULV Feature Failed!",
2793                 return -1);
2794         data->smu_features[GNLD_ULV].enabled = true;
2795     }
2796 
2797     return 0;
2798 }
2799 
2800 static int vega10_disable_ulv(struct pp_hwmgr *hwmgr)
2801 {
2802     struct vega10_hwmgr *data = hwmgr->backend;
2803 
2804     if (data->registry_data.ulv_support) {
2805         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2806                 false, data->smu_features[GNLD_ULV].smu_feature_bitmap),
2807                 "disable ULV Feature Failed!",
2808                 return -EINVAL);
2809         data->smu_features[GNLD_ULV].enabled = false;
2810     }
2811 
2812     return 0;
2813 }
2814 
2815 static int vega10_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
2816 {
2817     struct vega10_hwmgr *data = hwmgr->backend;
2818 
2819     if (data->smu_features[GNLD_DS_GFXCLK].supported) {
2820         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2821                 true, data->smu_features[GNLD_DS_GFXCLK].smu_feature_bitmap),
2822                 "Attempt to Enable DS_GFXCLK Feature Failed!",
2823                 return -EINVAL);
2824         data->smu_features[GNLD_DS_GFXCLK].enabled = true;
2825     }
2826 
2827     if (data->smu_features[GNLD_DS_SOCCLK].supported) {
2828         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2829                 true, data->smu_features[GNLD_DS_SOCCLK].smu_feature_bitmap),
2830                 "Attempt to Enable DS_SOCCLK Feature Failed!",
2831                 return -EINVAL);
2832         data->smu_features[GNLD_DS_SOCCLK].enabled = true;
2833     }
2834 
2835     if (data->smu_features[GNLD_DS_LCLK].supported) {
2836         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2837                 true, data->smu_features[GNLD_DS_LCLK].smu_feature_bitmap),
2838                 "Attempt to Enable DS_LCLK Feature Failed!",
2839                 return -EINVAL);
2840         data->smu_features[GNLD_DS_LCLK].enabled = true;
2841     }
2842 
2843     if (data->smu_features[GNLD_DS_DCEFCLK].supported) {
2844         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2845                 true, data->smu_features[GNLD_DS_DCEFCLK].smu_feature_bitmap),
2846                 "Attempt to Enable DS_DCEFCLK Feature Failed!",
2847                 return -EINVAL);
2848         data->smu_features[GNLD_DS_DCEFCLK].enabled = true;
2849     }
2850 
2851     return 0;
2852 }
2853 
2854 static int vega10_disable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
2855 {
2856     struct vega10_hwmgr *data = hwmgr->backend;
2857 
2858     if (data->smu_features[GNLD_DS_GFXCLK].supported) {
2859         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2860                 false, data->smu_features[GNLD_DS_GFXCLK].smu_feature_bitmap),
2861                 "Attempt to disable DS_GFXCLK Feature Failed!",
2862                 return -EINVAL);
2863         data->smu_features[GNLD_DS_GFXCLK].enabled = false;
2864     }
2865 
2866     if (data->smu_features[GNLD_DS_SOCCLK].supported) {
2867         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2868                 false, data->smu_features[GNLD_DS_SOCCLK].smu_feature_bitmap),
2869                 "Attempt to disable DS_ Feature Failed!",
2870                 return -EINVAL);
2871         data->smu_features[GNLD_DS_SOCCLK].enabled = false;
2872     }
2873 
2874     if (data->smu_features[GNLD_DS_LCLK].supported) {
2875         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2876                 false, data->smu_features[GNLD_DS_LCLK].smu_feature_bitmap),
2877                 "Attempt to disable DS_LCLK Feature Failed!",
2878                 return -EINVAL);
2879         data->smu_features[GNLD_DS_LCLK].enabled = false;
2880     }
2881 
2882     if (data->smu_features[GNLD_DS_DCEFCLK].supported) {
2883         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2884                 false, data->smu_features[GNLD_DS_DCEFCLK].smu_feature_bitmap),
2885                 "Attempt to disable DS_DCEFCLK Feature Failed!",
2886                 return -EINVAL);
2887         data->smu_features[GNLD_DS_DCEFCLK].enabled = false;
2888     }
2889 
2890     return 0;
2891 }
2892 
2893 static int vega10_stop_dpm(struct pp_hwmgr *hwmgr, uint32_t bitmap)
2894 {
2895     struct vega10_hwmgr *data = hwmgr->backend;
2896     uint32_t i, feature_mask = 0;
2897 
2898     if (!hwmgr->not_vf)
2899         return 0;
2900 
2901     if(data->smu_features[GNLD_LED_DISPLAY].supported == true){
2902         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2903                 false, data->smu_features[GNLD_LED_DISPLAY].smu_feature_bitmap),
2904         "Attempt to disable LED DPM feature failed!", return -EINVAL);
2905         data->smu_features[GNLD_LED_DISPLAY].enabled = false;
2906     }
2907 
2908     for (i = 0; i < GNLD_DPM_MAX; i++) {
2909         if (data->smu_features[i].smu_feature_bitmap & bitmap) {
2910             if (data->smu_features[i].supported) {
2911                 if (data->smu_features[i].enabled) {
2912                     feature_mask |= data->smu_features[i].
2913                             smu_feature_bitmap;
2914                     data->smu_features[i].enabled = false;
2915                 }
2916             }
2917         }
2918     }
2919 
2920     vega10_enable_smc_features(hwmgr, false, feature_mask);
2921 
2922     return 0;
2923 }
2924 
2925 /**
2926  * vega10_start_dpm - Tell SMC to enabled the supported DPMs.
2927  *
2928  * @hwmgr:   the address of the powerplay hardware manager.
2929  * @bitmap:  bitmap for the features to enabled.
2930  * return:  0 on at least one DPM is successfully enabled.
2931  */
2932 static int vega10_start_dpm(struct pp_hwmgr *hwmgr, uint32_t bitmap)
2933 {
2934     struct vega10_hwmgr *data = hwmgr->backend;
2935     uint32_t i, feature_mask = 0;
2936 
2937     for (i = 0; i < GNLD_DPM_MAX; i++) {
2938         if (data->smu_features[i].smu_feature_bitmap & bitmap) {
2939             if (data->smu_features[i].supported) {
2940                 if (!data->smu_features[i].enabled) {
2941                     feature_mask |= data->smu_features[i].
2942                             smu_feature_bitmap;
2943                     data->smu_features[i].enabled = true;
2944                 }
2945             }
2946         }
2947     }
2948 
2949     if (vega10_enable_smc_features(hwmgr,
2950             true, feature_mask)) {
2951         for (i = 0; i < GNLD_DPM_MAX; i++) {
2952             if (data->smu_features[i].smu_feature_bitmap &
2953                     feature_mask)
2954                 data->smu_features[i].enabled = false;
2955         }
2956     }
2957 
2958     if(data->smu_features[GNLD_LED_DISPLAY].supported == true){
2959         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2960                 true, data->smu_features[GNLD_LED_DISPLAY].smu_feature_bitmap),
2961         "Attempt to Enable LED DPM feature Failed!", return -EINVAL);
2962         data->smu_features[GNLD_LED_DISPLAY].enabled = true;
2963     }
2964 
2965     if (data->vbios_boot_state.bsoc_vddc_lock) {
2966         smum_send_msg_to_smc_with_parameter(hwmgr,
2967                         PPSMC_MSG_SetFloorSocVoltage, 0,
2968                         NULL);
2969         data->vbios_boot_state.bsoc_vddc_lock = false;
2970     }
2971 
2972     if (PP_CAP(PHM_PlatformCaps_Falcon_QuickTransition)) {
2973         if (data->smu_features[GNLD_ACDC].supported) {
2974             PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2975                     true, data->smu_features[GNLD_ACDC].smu_feature_bitmap),
2976                     "Attempt to Enable DS_GFXCLK Feature Failed!",
2977                     return -1);
2978             data->smu_features[GNLD_ACDC].enabled = true;
2979         }
2980     }
2981 
2982     if (data->registry_data.pcie_dpm_key_disabled) {
2983         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
2984                 false, data->smu_features[GNLD_DPM_LINK].smu_feature_bitmap),
2985         "Attempt to Disable Link DPM feature Failed!", return -EINVAL);
2986         data->smu_features[GNLD_DPM_LINK].enabled = false;
2987         data->smu_features[GNLD_DPM_LINK].supported = false;
2988     }
2989 
2990     return 0;
2991 }
2992 
2993 
2994 static int vega10_enable_disable_PCC_limit_feature(struct pp_hwmgr *hwmgr, bool enable)
2995 {
2996     struct vega10_hwmgr *data = hwmgr->backend;
2997 
2998     if (data->smu_features[GNLD_PCC_LIMIT].supported) {
2999         if (enable == data->smu_features[GNLD_PCC_LIMIT].enabled)
3000             pr_info("GNLD_PCC_LIMIT has been %s \n", enable ? "enabled" : "disabled");
3001         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
3002                 enable, data->smu_features[GNLD_PCC_LIMIT].smu_feature_bitmap),
3003                 "Attempt to Enable PCC Limit feature Failed!",
3004                 return -EINVAL);
3005         data->smu_features[GNLD_PCC_LIMIT].enabled = enable;
3006     }
3007 
3008     return 0;
3009 }
3010 
3011 static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
3012 {
3013     struct vega10_hwmgr *data = hwmgr->backend;
3014     int tmp_result, result = 0;
3015 
3016     if (hwmgr->not_vf) {
3017         vega10_enable_disable_PCC_limit_feature(hwmgr, true);
3018 
3019         smum_send_msg_to_smc_with_parameter(hwmgr,
3020             PPSMC_MSG_ConfigureTelemetry, data->config_telemetry,
3021             NULL);
3022 
3023         tmp_result = vega10_construct_voltage_tables(hwmgr);
3024         PP_ASSERT_WITH_CODE(!tmp_result,
3025                     "Failed to construct voltage tables!",
3026                     result = tmp_result);
3027     }
3028 
3029     if (hwmgr->not_vf || hwmgr->pp_one_vf) {
3030         tmp_result = vega10_init_smc_table(hwmgr);
3031         PP_ASSERT_WITH_CODE(!tmp_result,
3032                     "Failed to initialize SMC table!",
3033                     result = tmp_result);
3034     }
3035 
3036     if (hwmgr->not_vf) {
3037         if (PP_CAP(PHM_PlatformCaps_ThermalController)) {
3038             tmp_result = vega10_enable_thermal_protection(hwmgr);
3039             PP_ASSERT_WITH_CODE(!tmp_result,
3040                         "Failed to enable thermal protection!",
3041                         result = tmp_result);
3042         }
3043 
3044         tmp_result = vega10_enable_vrhot_feature(hwmgr);
3045         PP_ASSERT_WITH_CODE(!tmp_result,
3046                     "Failed to enable VR hot feature!",
3047                     result = tmp_result);
3048 
3049         tmp_result = vega10_enable_deep_sleep_master_switch(hwmgr);
3050         PP_ASSERT_WITH_CODE(!tmp_result,
3051                     "Failed to enable deep sleep master switch!",
3052                     result = tmp_result);
3053     }
3054 
3055     if (hwmgr->not_vf) {
3056         tmp_result = vega10_start_dpm(hwmgr, SMC_DPM_FEATURES);
3057         PP_ASSERT_WITH_CODE(!tmp_result,
3058                     "Failed to start DPM!", result = tmp_result);
3059     }
3060 
3061     if (hwmgr->not_vf) {
3062         /* enable didt, do not abort if failed didt */
3063         tmp_result = vega10_enable_didt_config(hwmgr);
3064         PP_ASSERT(!tmp_result,
3065               "Failed to enable didt config!");
3066     }
3067 
3068     tmp_result = vega10_enable_power_containment(hwmgr);
3069     PP_ASSERT_WITH_CODE(!tmp_result,
3070                 "Failed to enable power containment!",
3071                 result = tmp_result);
3072 
3073     if (hwmgr->not_vf) {
3074         tmp_result = vega10_power_control_set_level(hwmgr);
3075         PP_ASSERT_WITH_CODE(!tmp_result,
3076                     "Failed to power control set level!",
3077                     result = tmp_result);
3078 
3079         tmp_result = vega10_enable_ulv(hwmgr);
3080         PP_ASSERT_WITH_CODE(!tmp_result,
3081                     "Failed to enable ULV!",
3082                     result = tmp_result);
3083     }
3084 
3085     return result;
3086 }
3087 
3088 static int vega10_get_power_state_size(struct pp_hwmgr *hwmgr)
3089 {
3090     return sizeof(struct vega10_power_state);
3091 }
3092 
3093 static int vega10_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
3094         void *state, struct pp_power_state *power_state,
3095         void *pp_table, uint32_t classification_flag)
3096 {
3097     ATOM_Vega10_GFXCLK_Dependency_Record_V2 *patom_record_V2;
3098     struct vega10_power_state *vega10_ps =
3099             cast_phw_vega10_power_state(&(power_state->hardware));
3100     struct vega10_performance_level *performance_level;
3101     ATOM_Vega10_State *state_entry = (ATOM_Vega10_State *)state;
3102     ATOM_Vega10_POWERPLAYTABLE *powerplay_table =
3103             (ATOM_Vega10_POWERPLAYTABLE *)pp_table;
3104     ATOM_Vega10_SOCCLK_Dependency_Table *socclk_dep_table =
3105             (ATOM_Vega10_SOCCLK_Dependency_Table *)
3106             (((unsigned long)powerplay_table) +
3107             le16_to_cpu(powerplay_table->usSocclkDependencyTableOffset));
3108     ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table =
3109             (ATOM_Vega10_GFXCLK_Dependency_Table *)
3110             (((unsigned long)powerplay_table) +
3111             le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset));
3112     ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table =
3113             (ATOM_Vega10_MCLK_Dependency_Table *)
3114             (((unsigned long)powerplay_table) +
3115             le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
3116 
3117 
3118     /* The following fields are not initialized here:
3119      * id orderedList allStatesList
3120      */
3121     power_state->classification.ui_label =
3122             (le16_to_cpu(state_entry->usClassification) &
3123             ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
3124             ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
3125     power_state->classification.flags = classification_flag;
3126     /* NOTE: There is a classification2 flag in BIOS
3127      * that is not being used right now
3128      */
3129     power_state->classification.temporary_state = false;
3130     power_state->classification.to_be_deleted = false;
3131 
3132     power_state->validation.disallowOnDC =
3133             ((le32_to_cpu(state_entry->ulCapsAndSettings) &
3134                     ATOM_Vega10_DISALLOW_ON_DC) != 0);
3135 
3136     power_state->display.disableFrameModulation = false;
3137     power_state->display.limitRefreshrate = false;
3138     power_state->display.enableVariBright =
3139             ((le32_to_cpu(state_entry->ulCapsAndSettings) &
3140                     ATOM_Vega10_ENABLE_VARIBRIGHT) != 0);
3141 
3142     power_state->validation.supportedPowerLevels = 0;
3143     power_state->uvd_clocks.VCLK = 0;
3144     power_state->uvd_clocks.DCLK = 0;
3145     power_state->temperatures.min = 0;
3146     power_state->temperatures.max = 0;
3147 
3148     performance_level = &(vega10_ps->performance_levels
3149             [vega10_ps->performance_level_count++]);
3150 
3151     PP_ASSERT_WITH_CODE(
3152             (vega10_ps->performance_level_count <
3153                     NUM_GFXCLK_DPM_LEVELS),
3154             "Performance levels exceeds SMC limit!",
3155             return -1);
3156 
3157     PP_ASSERT_WITH_CODE(
3158             (vega10_ps->performance_level_count <=
3159                     hwmgr->platform_descriptor.
3160                     hardwareActivityPerformanceLevels),
3161             "Performance levels exceeds Driver limit!",
3162             return -1);
3163 
3164     /* Performance levels are arranged from low to high. */
3165     performance_level->soc_clock = socclk_dep_table->entries
3166             [state_entry->ucSocClockIndexLow].ulClk;
3167     performance_level->gfx_clock = gfxclk_dep_table->entries
3168             [state_entry->ucGfxClockIndexLow].ulClk;
3169     performance_level->mem_clock = mclk_dep_table->entries
3170             [state_entry->ucMemClockIndexLow].ulMemClk;
3171 
3172     performance_level = &(vega10_ps->performance_levels
3173                 [vega10_ps->performance_level_count++]);
3174     performance_level->soc_clock = socclk_dep_table->entries
3175                 [state_entry->ucSocClockIndexHigh].ulClk;
3176     if (gfxclk_dep_table->ucRevId == 0) {
3177         /* under vega10 pp one vf mode, the gfx clk dpm need be lower
3178          * to level-4 due to the limited 110w-power
3179          */
3180         if (hwmgr->pp_one_vf && (state_entry->ucGfxClockIndexHigh > 0))
3181             performance_level->gfx_clock =
3182                 gfxclk_dep_table->entries[4].ulClk;
3183         else
3184             performance_level->gfx_clock = gfxclk_dep_table->entries
3185                 [state_entry->ucGfxClockIndexHigh].ulClk;
3186     } else if (gfxclk_dep_table->ucRevId == 1) {
3187         patom_record_V2 = (ATOM_Vega10_GFXCLK_Dependency_Record_V2 *)gfxclk_dep_table->entries;
3188         if (hwmgr->pp_one_vf && (state_entry->ucGfxClockIndexHigh > 0))
3189             performance_level->gfx_clock = patom_record_V2[4].ulClk;
3190         else
3191             performance_level->gfx_clock =
3192                 patom_record_V2[state_entry->ucGfxClockIndexHigh].ulClk;
3193     }
3194 
3195     performance_level->mem_clock = mclk_dep_table->entries
3196             [state_entry->ucMemClockIndexHigh].ulMemClk;
3197     return 0;
3198 }
3199 
3200 static int vega10_get_pp_table_entry(struct pp_hwmgr *hwmgr,
3201         unsigned long entry_index, struct pp_power_state *state)
3202 {
3203     int result;
3204     struct vega10_power_state *vega10_ps;
3205 
3206     state->hardware.magic = PhwVega10_Magic;
3207 
3208     vega10_ps = cast_phw_vega10_power_state(&state->hardware);
3209 
3210     result = vega10_get_powerplay_table_entry(hwmgr, entry_index, state,
3211             vega10_get_pp_table_entry_callback_func);
3212     if (result)
3213         return result;
3214 
3215     /*
3216      * This is the earliest time we have all the dependency table
3217      * and the VBIOS boot state
3218      */
3219     /* set DC compatible flag if this state supports DC */
3220     if (!state->validation.disallowOnDC)
3221         vega10_ps->dc_compatible = true;
3222 
3223     vega10_ps->uvd_clks.vclk = state->uvd_clocks.VCLK;
3224     vega10_ps->uvd_clks.dclk = state->uvd_clocks.DCLK;
3225 
3226     return 0;
3227 }
3228 
3229 static int vega10_patch_boot_state(struct pp_hwmgr *hwmgr,
3230          struct pp_hw_power_state *hw_ps)
3231 {
3232     return 0;
3233 }
3234 
3235 static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
3236                 struct pp_power_state  *request_ps,
3237             const struct pp_power_state *current_ps)
3238 {
3239     struct amdgpu_device *adev = hwmgr->adev;
3240     struct vega10_power_state *vega10_ps =
3241                 cast_phw_vega10_power_state(&request_ps->hardware);
3242     uint32_t sclk;
3243     uint32_t mclk;
3244     struct PP_Clocks minimum_clocks = {0};
3245     bool disable_mclk_switching;
3246     bool disable_mclk_switching_for_frame_lock;
3247     bool disable_mclk_switching_for_vr;
3248     bool force_mclk_high;
3249     const struct phm_clock_and_voltage_limits *max_limits;
3250     uint32_t i;
3251     struct vega10_hwmgr *data = hwmgr->backend;
3252     struct phm_ppt_v2_information *table_info =
3253             (struct phm_ppt_v2_information *)(hwmgr->pptable);
3254     int32_t count;
3255     uint32_t stable_pstate_sclk_dpm_percentage;
3256     uint32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
3257     uint32_t latency;
3258 
3259     data->battery_state = (PP_StateUILabel_Battery ==
3260             request_ps->classification.ui_label);
3261 
3262     if (vega10_ps->performance_level_count != 2)
3263         pr_info("VI should always have 2 performance levels");
3264 
3265     max_limits = adev->pm.ac_power ?
3266             &(hwmgr->dyn_state.max_clock_voltage_on_ac) :
3267             &(hwmgr->dyn_state.max_clock_voltage_on_dc);
3268 
3269     /* Cap clock DPM tables at DC MAX if it is in DC. */
3270     if (!adev->pm.ac_power) {
3271         for (i = 0; i < vega10_ps->performance_level_count; i++) {
3272             if (vega10_ps->performance_levels[i].mem_clock >
3273                 max_limits->mclk)
3274                 vega10_ps->performance_levels[i].mem_clock =
3275                         max_limits->mclk;
3276             if (vega10_ps->performance_levels[i].gfx_clock >
3277                 max_limits->sclk)
3278                 vega10_ps->performance_levels[i].gfx_clock =
3279                         max_limits->sclk;
3280         }
3281     }
3282 
3283     /* result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
3284     minimum_clocks.engineClock = hwmgr->display_config->min_core_set_clock;
3285     minimum_clocks.memoryClock = hwmgr->display_config->min_mem_set_clock;
3286 
3287     if (PP_CAP(PHM_PlatformCaps_StablePState)) {
3288         stable_pstate_sclk_dpm_percentage =
3289             data->registry_data.stable_pstate_sclk_dpm_percentage;
3290         PP_ASSERT_WITH_CODE(
3291             data->registry_data.stable_pstate_sclk_dpm_percentage >= 1 &&
3292             data->registry_data.stable_pstate_sclk_dpm_percentage <= 100,
3293             "percent sclk value must range from 1% to 100%, setting default value",
3294             stable_pstate_sclk_dpm_percentage = 75);
3295 
3296         max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
3297         stable_pstate_sclk = (max_limits->sclk *
3298                 stable_pstate_sclk_dpm_percentage) / 100;
3299 
3300         for (count = table_info->vdd_dep_on_sclk->count - 1;
3301                 count >= 0; count--) {
3302             if (stable_pstate_sclk >=
3303                     table_info->vdd_dep_on_sclk->entries[count].clk) {
3304                 stable_pstate_sclk =
3305                         table_info->vdd_dep_on_sclk->entries[count].clk;
3306                 break;
3307             }
3308         }
3309 
3310         if (count < 0)
3311             stable_pstate_sclk = table_info->vdd_dep_on_sclk->entries[0].clk;
3312 
3313         stable_pstate_mclk = max_limits->mclk;
3314 
3315         minimum_clocks.engineClock = stable_pstate_sclk;
3316         minimum_clocks.memoryClock = stable_pstate_mclk;
3317     }
3318 
3319     disable_mclk_switching_for_frame_lock =
3320         PP_CAP(PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
3321     disable_mclk_switching_for_vr =
3322         PP_CAP(PHM_PlatformCaps_DisableMclkSwitchForVR);
3323     force_mclk_high = PP_CAP(PHM_PlatformCaps_ForceMclkHigh);
3324 
3325     if (hwmgr->display_config->num_display == 0)
3326         disable_mclk_switching = false;
3327     else
3328         disable_mclk_switching = ((1 < hwmgr->display_config->num_display) &&
3329                       !hwmgr->display_config->multi_monitor_in_sync) ||
3330             disable_mclk_switching_for_frame_lock ||
3331             disable_mclk_switching_for_vr ||
3332             force_mclk_high;
3333 
3334     sclk = vega10_ps->performance_levels[0].gfx_clock;
3335     mclk = vega10_ps->performance_levels[0].mem_clock;
3336 
3337     if (sclk < minimum_clocks.engineClock)
3338         sclk = (minimum_clocks.engineClock > max_limits->sclk) ?
3339                 max_limits->sclk : minimum_clocks.engineClock;
3340 
3341     if (mclk < minimum_clocks.memoryClock)
3342         mclk = (minimum_clocks.memoryClock > max_limits->mclk) ?
3343                 max_limits->mclk : minimum_clocks.memoryClock;
3344 
3345     vega10_ps->performance_levels[0].gfx_clock = sclk;
3346     vega10_ps->performance_levels[0].mem_clock = mclk;
3347 
3348     if (vega10_ps->performance_levels[1].gfx_clock <
3349             vega10_ps->performance_levels[0].gfx_clock)
3350         vega10_ps->performance_levels[0].gfx_clock =
3351                 vega10_ps->performance_levels[1].gfx_clock;
3352 
3353     if (disable_mclk_switching) {
3354         /* Set Mclk the max of level 0 and level 1 */
3355         if (mclk < vega10_ps->performance_levels[1].mem_clock)
3356             mclk = vega10_ps->performance_levels[1].mem_clock;
3357 
3358         /* Find the lowest MCLK frequency that is within
3359          * the tolerable latency defined in DAL
3360          */
3361         latency = hwmgr->display_config->dce_tolerable_mclk_in_active_latency;
3362         for (i = 0; i < data->mclk_latency_table.count; i++) {
3363             if ((data->mclk_latency_table.entries[i].latency <= latency) &&
3364                 (data->mclk_latency_table.entries[i].frequency >=
3365                         vega10_ps->performance_levels[0].mem_clock) &&
3366                 (data->mclk_latency_table.entries[i].frequency <=
3367                         vega10_ps->performance_levels[1].mem_clock))
3368                 mclk = data->mclk_latency_table.entries[i].frequency;
3369         }
3370         vega10_ps->performance_levels[0].mem_clock = mclk;
3371     } else {
3372         if (vega10_ps->performance_levels[1].mem_clock <
3373                 vega10_ps->performance_levels[0].mem_clock)
3374             vega10_ps->performance_levels[0].mem_clock =
3375                     vega10_ps->performance_levels[1].mem_clock;
3376     }
3377 
3378     if (PP_CAP(PHM_PlatformCaps_StablePState)) {
3379         for (i = 0; i < vega10_ps->performance_level_count; i++) {
3380             vega10_ps->performance_levels[i].gfx_clock = stable_pstate_sclk;
3381             vega10_ps->performance_levels[i].mem_clock = stable_pstate_mclk;
3382         }
3383     }
3384 
3385     return 0;
3386 }
3387 
3388 static int vega10_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
3389 {
3390     struct vega10_hwmgr *data = hwmgr->backend;
3391     const struct phm_set_power_state_input *states =
3392             (const struct phm_set_power_state_input *)input;
3393     const struct vega10_power_state *vega10_ps =
3394             cast_const_phw_vega10_power_state(states->pnew_state);
3395     struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
3396     uint32_t sclk = vega10_ps->performance_levels
3397             [vega10_ps->performance_level_count - 1].gfx_clock;
3398     struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
3399     uint32_t mclk = vega10_ps->performance_levels
3400             [vega10_ps->performance_level_count - 1].mem_clock;
3401     uint32_t i;
3402 
3403     for (i = 0; i < sclk_table->count; i++) {
3404         if (sclk == sclk_table->dpm_levels[i].value)
3405             break;
3406     }
3407 
3408     if (i >= sclk_table->count) {
3409         if (sclk > sclk_table->dpm_levels[i-1].value) {
3410             data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
3411             sclk_table->dpm_levels[i-1].value = sclk;
3412         }
3413     }
3414 
3415     for (i = 0; i < mclk_table->count; i++) {
3416         if (mclk == mclk_table->dpm_levels[i].value)
3417             break;
3418     }
3419 
3420     if (i >= mclk_table->count) {
3421         if (mclk > mclk_table->dpm_levels[i-1].value) {
3422             data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
3423             mclk_table->dpm_levels[i-1].value = mclk;
3424         }
3425     }
3426 
3427     if (data->display_timing.num_existing_displays != hwmgr->display_config->num_display)
3428         data->need_update_dpm_table |= DPMTABLE_UPDATE_MCLK;
3429 
3430     return 0;
3431 }
3432 
3433 static int vega10_populate_and_upload_sclk_mclk_dpm_levels(
3434         struct pp_hwmgr *hwmgr, const void *input)
3435 {
3436     int result = 0;
3437     struct vega10_hwmgr *data = hwmgr->backend;
3438     struct vega10_dpm_table *dpm_table = &data->dpm_table;
3439     struct vega10_odn_dpm_table *odn_table = &data->odn_dpm_table;
3440     struct vega10_odn_clock_voltage_dependency_table *odn_clk_table = &odn_table->vdd_dep_on_sclk;
3441     int count;
3442 
3443     if (!data->need_update_dpm_table)
3444         return 0;
3445 
3446     if (hwmgr->od_enabled && data->need_update_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
3447         for (count = 0; count < dpm_table->gfx_table.count; count++)
3448             dpm_table->gfx_table.dpm_levels[count].value = odn_clk_table->entries[count].clk;
3449     }
3450 
3451     odn_clk_table = &odn_table->vdd_dep_on_mclk;
3452     if (hwmgr->od_enabled && data->need_update_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
3453         for (count = 0; count < dpm_table->mem_table.count; count++)
3454             dpm_table->mem_table.dpm_levels[count].value = odn_clk_table->entries[count].clk;
3455     }
3456 
3457     if (data->need_update_dpm_table &
3458             (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK | DPMTABLE_UPDATE_SOCCLK)) {
3459         result = vega10_populate_all_graphic_levels(hwmgr);
3460         PP_ASSERT_WITH_CODE((0 == result),
3461                 "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
3462                 return result);
3463     }
3464 
3465     if (data->need_update_dpm_table &
3466             (DPMTABLE_OD_UPDATE_MCLK | DPMTABLE_UPDATE_MCLK)) {
3467         result = vega10_populate_all_memory_levels(hwmgr);
3468         PP_ASSERT_WITH_CODE((0 == result),
3469                 "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
3470                 return result);
3471     }
3472 
3473     vega10_populate_vddc_soc_levels(hwmgr);
3474 
3475     return result;
3476 }
3477 
3478 static int vega10_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
3479         struct vega10_single_dpm_table *dpm_table,
3480         uint32_t low_limit, uint32_t high_limit)
3481 {
3482     uint32_t i;
3483 
3484     for (i = 0; i < dpm_table->count; i++) {
3485         if ((dpm_table->dpm_levels[i].value < low_limit) ||
3486             (dpm_table->dpm_levels[i].value > high_limit))
3487             dpm_table->dpm_levels[i].enabled = false;
3488         else
3489             dpm_table->dpm_levels[i].enabled = true;
3490     }
3491     return 0;
3492 }
3493 
3494 static int vega10_trim_single_dpm_states_with_mask(struct pp_hwmgr *hwmgr,
3495         struct vega10_single_dpm_table *dpm_table,
3496         uint32_t low_limit, uint32_t high_limit,
3497         uint32_t disable_dpm_mask)
3498 {
3499     uint32_t i;
3500 
3501     for (i = 0; i < dpm_table->count; i++) {
3502         if ((dpm_table->dpm_levels[i].value < low_limit) ||
3503             (dpm_table->dpm_levels[i].value > high_limit))
3504             dpm_table->dpm_levels[i].enabled = false;
3505         else if (!((1 << i) & disable_dpm_mask))
3506             dpm_table->dpm_levels[i].enabled = false;
3507         else
3508             dpm_table->dpm_levels[i].enabled = true;
3509     }
3510     return 0;
3511 }
3512 
3513 static int vega10_trim_dpm_states(struct pp_hwmgr *hwmgr,
3514         const struct vega10_power_state *vega10_ps)
3515 {
3516     struct vega10_hwmgr *data = hwmgr->backend;
3517     uint32_t high_limit_count;
3518 
3519     PP_ASSERT_WITH_CODE((vega10_ps->performance_level_count >= 1),
3520             "power state did not have any performance level",
3521             return -1);
3522 
3523     high_limit_count = (vega10_ps->performance_level_count == 1) ? 0 : 1;
3524 
3525     vega10_trim_single_dpm_states(hwmgr,
3526             &(data->dpm_table.soc_table),
3527             vega10_ps->performance_levels[0].soc_clock,
3528             vega10_ps->performance_levels[high_limit_count].soc_clock);
3529 
3530     vega10_trim_single_dpm_states_with_mask(hwmgr,
3531             &(data->dpm_table.gfx_table),
3532             vega10_ps->performance_levels[0].gfx_clock,
3533             vega10_ps->performance_levels[high_limit_count].gfx_clock,
3534             data->disable_dpm_mask);
3535 
3536     vega10_trim_single_dpm_states(hwmgr,
3537             &(data->dpm_table.mem_table),
3538             vega10_ps->performance_levels[0].mem_clock,
3539             vega10_ps->performance_levels[high_limit_count].mem_clock);
3540 
3541     return 0;
3542 }
3543 
3544 static uint32_t vega10_find_lowest_dpm_level(
3545         struct vega10_single_dpm_table *table)
3546 {
3547     uint32_t i;
3548 
3549     for (i = 0; i < table->count; i++) {
3550         if (table->dpm_levels[i].enabled)
3551             break;
3552     }
3553 
3554     return i;
3555 }
3556 
3557 static uint32_t vega10_find_highest_dpm_level(
3558         struct vega10_single_dpm_table *table)
3559 {
3560     uint32_t i = 0;
3561 
3562     if (table->count <= MAX_REGULAR_DPM_NUMBER) {
3563         for (i = table->count; i > 0; i--) {
3564             if (table->dpm_levels[i - 1].enabled)
3565                 return i - 1;
3566         }
3567     } else {
3568         pr_info("DPM Table Has Too Many Entries!");
3569         return MAX_REGULAR_DPM_NUMBER - 1;
3570     }
3571 
3572     return i;
3573 }
3574 
3575 static void vega10_apply_dal_minimum_voltage_request(
3576         struct pp_hwmgr *hwmgr)
3577 {
3578     return;
3579 }
3580 
3581 static int vega10_get_soc_index_for_max_uclk(struct pp_hwmgr *hwmgr)
3582 {
3583     struct phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table_on_mclk;
3584     struct phm_ppt_v2_information *table_info =
3585             (struct phm_ppt_v2_information *)(hwmgr->pptable);
3586 
3587     vdd_dep_table_on_mclk  = table_info->vdd_dep_on_mclk;
3588 
3589     return vdd_dep_table_on_mclk->entries[NUM_UCLK_DPM_LEVELS - 1].vddInd + 1;
3590 }
3591 
3592 static int vega10_upload_dpm_bootup_level(struct pp_hwmgr *hwmgr)
3593 {
3594     struct vega10_hwmgr *data = hwmgr->backend;
3595     uint32_t socclk_idx;
3596 
3597     vega10_apply_dal_minimum_voltage_request(hwmgr);
3598 
3599     if (!data->registry_data.sclk_dpm_key_disabled) {
3600         if (data->smc_state_table.gfx_boot_level !=
3601                 data->dpm_table.gfx_table.dpm_state.soft_min_level) {
3602             smum_send_msg_to_smc_with_parameter(hwmgr,
3603                 PPSMC_MSG_SetSoftMinGfxclkByIndex,
3604                 data->smc_state_table.gfx_boot_level,
3605                 NULL);
3606 
3607             data->dpm_table.gfx_table.dpm_state.soft_min_level =
3608                     data->smc_state_table.gfx_boot_level;
3609         }
3610     }
3611 
3612     if (!data->registry_data.mclk_dpm_key_disabled) {
3613         if (data->smc_state_table.mem_boot_level !=
3614                 data->dpm_table.mem_table.dpm_state.soft_min_level) {
3615             if ((data->smc_state_table.mem_boot_level == NUM_UCLK_DPM_LEVELS - 1)
3616                 && hwmgr->not_vf) {
3617                 socclk_idx = vega10_get_soc_index_for_max_uclk(hwmgr);
3618                 smum_send_msg_to_smc_with_parameter(hwmgr,
3619                         PPSMC_MSG_SetSoftMinSocclkByIndex,
3620                         socclk_idx,
3621                         NULL);
3622             } else {
3623                 smum_send_msg_to_smc_with_parameter(hwmgr,
3624                         PPSMC_MSG_SetSoftMinUclkByIndex,
3625                         data->smc_state_table.mem_boot_level,
3626                         NULL);
3627             }
3628             data->dpm_table.mem_table.dpm_state.soft_min_level =
3629                     data->smc_state_table.mem_boot_level;
3630         }
3631     }
3632 
3633     if (!hwmgr->not_vf)
3634         return 0;
3635 
3636     if (!data->registry_data.socclk_dpm_key_disabled) {
3637         if (data->smc_state_table.soc_boot_level !=
3638                 data->dpm_table.soc_table.dpm_state.soft_min_level) {
3639             smum_send_msg_to_smc_with_parameter(hwmgr,
3640                 PPSMC_MSG_SetSoftMinSocclkByIndex,
3641                 data->smc_state_table.soc_boot_level,
3642                 NULL);
3643             data->dpm_table.soc_table.dpm_state.soft_min_level =
3644                     data->smc_state_table.soc_boot_level;
3645         }
3646     }
3647 
3648     return 0;
3649 }
3650 
3651 static int vega10_upload_dpm_max_level(struct pp_hwmgr *hwmgr)
3652 {
3653     struct vega10_hwmgr *data = hwmgr->backend;
3654 
3655     vega10_apply_dal_minimum_voltage_request(hwmgr);
3656 
3657     if (!data->registry_data.sclk_dpm_key_disabled) {
3658         if (data->smc_state_table.gfx_max_level !=
3659             data->dpm_table.gfx_table.dpm_state.soft_max_level) {
3660             smum_send_msg_to_smc_with_parameter(hwmgr,
3661                 PPSMC_MSG_SetSoftMaxGfxclkByIndex,
3662                 data->smc_state_table.gfx_max_level,
3663                 NULL);
3664             data->dpm_table.gfx_table.dpm_state.soft_max_level =
3665                     data->smc_state_table.gfx_max_level;
3666         }
3667     }
3668 
3669     if (!data->registry_data.mclk_dpm_key_disabled) {
3670         if (data->smc_state_table.mem_max_level !=
3671             data->dpm_table.mem_table.dpm_state.soft_max_level) {
3672             smum_send_msg_to_smc_with_parameter(hwmgr,
3673                     PPSMC_MSG_SetSoftMaxUclkByIndex,
3674                     data->smc_state_table.mem_max_level,
3675                     NULL);
3676             data->dpm_table.mem_table.dpm_state.soft_max_level =
3677                     data->smc_state_table.mem_max_level;
3678         }
3679     }
3680 
3681     if (!hwmgr->not_vf)
3682         return 0;
3683 
3684     if (!data->registry_data.socclk_dpm_key_disabled) {
3685         if (data->smc_state_table.soc_max_level !=
3686             data->dpm_table.soc_table.dpm_state.soft_max_level) {
3687             smum_send_msg_to_smc_with_parameter(hwmgr,
3688                 PPSMC_MSG_SetSoftMaxSocclkByIndex,
3689                 data->smc_state_table.soc_max_level,
3690                 NULL);
3691             data->dpm_table.soc_table.dpm_state.soft_max_level =
3692                     data->smc_state_table.soc_max_level;
3693         }
3694     }
3695 
3696     return 0;
3697 }
3698 
3699 static int vega10_generate_dpm_level_enable_mask(
3700         struct pp_hwmgr *hwmgr, const void *input)
3701 {
3702     struct vega10_hwmgr *data = hwmgr->backend;
3703     const struct phm_set_power_state_input *states =
3704             (const struct phm_set_power_state_input *)input;
3705     const struct vega10_power_state *vega10_ps =
3706             cast_const_phw_vega10_power_state(states->pnew_state);
3707     int i;
3708 
3709     PP_ASSERT_WITH_CODE(!vega10_trim_dpm_states(hwmgr, vega10_ps),
3710             "Attempt to Trim DPM States Failed!",
3711             return -1);
3712 
3713     data->smc_state_table.gfx_boot_level =
3714             vega10_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
3715     data->smc_state_table.gfx_max_level =
3716             vega10_find_highest_dpm_level(&(data->dpm_table.gfx_table));
3717     data->smc_state_table.mem_boot_level =
3718             vega10_find_lowest_dpm_level(&(data->dpm_table.mem_table));
3719     data->smc_state_table.mem_max_level =
3720             vega10_find_highest_dpm_level(&(data->dpm_table.mem_table));
3721     data->smc_state_table.soc_boot_level =
3722             vega10_find_lowest_dpm_level(&(data->dpm_table.soc_table));
3723     data->smc_state_table.soc_max_level =
3724             vega10_find_highest_dpm_level(&(data->dpm_table.soc_table));
3725 
3726     PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
3727             "Attempt to upload DPM Bootup Levels Failed!",
3728             return -1);
3729     PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
3730             "Attempt to upload DPM Max Levels Failed!",
3731             return -1);
3732     for(i = data->smc_state_table.gfx_boot_level; i < data->smc_state_table.gfx_max_level; i++)
3733         data->dpm_table.gfx_table.dpm_levels[i].enabled = true;
3734 
3735 
3736     for(i = data->smc_state_table.mem_boot_level; i < data->smc_state_table.mem_max_level; i++)
3737         data->dpm_table.mem_table.dpm_levels[i].enabled = true;
3738 
3739     for (i = data->smc_state_table.soc_boot_level; i < data->smc_state_table.soc_max_level; i++)
3740         data->dpm_table.soc_table.dpm_levels[i].enabled = true;
3741 
3742     return 0;
3743 }
3744 
3745 int vega10_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
3746 {
3747     struct vega10_hwmgr *data = hwmgr->backend;
3748 
3749     if (data->smu_features[GNLD_DPM_VCE].supported) {
3750         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
3751                 enable,
3752                 data->smu_features[GNLD_DPM_VCE].smu_feature_bitmap),
3753                 "Attempt to Enable/Disable DPM VCE Failed!",
3754                 return -1);
3755         data->smu_features[GNLD_DPM_VCE].enabled = enable;
3756     }
3757 
3758     return 0;
3759 }
3760 
3761 static int vega10_update_sclk_threshold(struct pp_hwmgr *hwmgr)
3762 {
3763     struct vega10_hwmgr *data = hwmgr->backend;
3764     uint32_t low_sclk_interrupt_threshold = 0;
3765 
3766     if (PP_CAP(PHM_PlatformCaps_SclkThrottleLowNotification) &&
3767         (data->low_sclk_interrupt_threshold != 0)) {
3768         low_sclk_interrupt_threshold =
3769                 data->low_sclk_interrupt_threshold;
3770 
3771         data->smc_state_table.pp_table.LowGfxclkInterruptThreshold =
3772                 cpu_to_le32(low_sclk_interrupt_threshold);
3773 
3774         /* This message will also enable SmcToHost Interrupt */
3775         smum_send_msg_to_smc_with_parameter(hwmgr,
3776                 PPSMC_MSG_SetLowGfxclkInterruptThreshold,
3777                 (uint32_t)low_sclk_interrupt_threshold,
3778                 NULL);
3779     }
3780 
3781     return 0;
3782 }
3783 
3784 static int vega10_set_power_state_tasks(struct pp_hwmgr *hwmgr,
3785         const void *input)
3786 {
3787     int tmp_result, result = 0;
3788     struct vega10_hwmgr *data = hwmgr->backend;
3789     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
3790 
3791     tmp_result = vega10_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
3792     PP_ASSERT_WITH_CODE(!tmp_result,
3793             "Failed to find DPM states clocks in DPM table!",
3794             result = tmp_result);
3795 
3796     tmp_result = vega10_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
3797     PP_ASSERT_WITH_CODE(!tmp_result,
3798             "Failed to populate and upload SCLK MCLK DPM levels!",
3799             result = tmp_result);
3800 
3801     tmp_result = vega10_generate_dpm_level_enable_mask(hwmgr, input);
3802     PP_ASSERT_WITH_CODE(!tmp_result,
3803             "Failed to generate DPM level enabled mask!",
3804             result = tmp_result);
3805 
3806     tmp_result = vega10_update_sclk_threshold(hwmgr);
3807     PP_ASSERT_WITH_CODE(!tmp_result,
3808             "Failed to update SCLK threshold!",
3809             result = tmp_result);
3810 
3811     result = smum_smc_table_manager(hwmgr, (uint8_t *)pp_table, PPTABLE, false);
3812     PP_ASSERT_WITH_CODE(!result,
3813             "Failed to upload PPtable!", return result);
3814 
3815     /*
3816      * If a custom pp table is loaded, set DPMTABLE_OD_UPDATE_VDDC flag.
3817      * That effectively disables AVFS feature.
3818      */
3819     if(hwmgr->hardcode_pp_table != NULL)
3820         data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_VDDC;
3821 
3822     vega10_update_avfs(hwmgr);
3823 
3824     /*
3825      * Clear all OD flags except DPMTABLE_OD_UPDATE_VDDC.
3826      * That will help to keep AVFS disabled.
3827      */
3828     data->need_update_dpm_table &= DPMTABLE_OD_UPDATE_VDDC;
3829 
3830     return 0;
3831 }
3832 
3833 static uint32_t vega10_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
3834 {
3835     struct pp_power_state *ps;
3836     struct vega10_power_state *vega10_ps;
3837 
3838     if (hwmgr == NULL)
3839         return -EINVAL;
3840 
3841     ps = hwmgr->request_ps;
3842 
3843     if (ps == NULL)
3844         return -EINVAL;
3845 
3846     vega10_ps = cast_phw_vega10_power_state(&ps->hardware);
3847 
3848     if (low)
3849         return vega10_ps->performance_levels[0].gfx_clock;
3850     else
3851         return vega10_ps->performance_levels
3852                 [vega10_ps->performance_level_count - 1].gfx_clock;
3853 }
3854 
3855 static uint32_t vega10_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
3856 {
3857     struct pp_power_state *ps;
3858     struct vega10_power_state *vega10_ps;
3859 
3860     if (hwmgr == NULL)
3861         return -EINVAL;
3862 
3863     ps = hwmgr->request_ps;
3864 
3865     if (ps == NULL)
3866         return -EINVAL;
3867 
3868     vega10_ps = cast_phw_vega10_power_state(&ps->hardware);
3869 
3870     if (low)
3871         return vega10_ps->performance_levels[0].mem_clock;
3872     else
3873         return vega10_ps->performance_levels
3874                 [vega10_ps->performance_level_count-1].mem_clock;
3875 }
3876 
3877 static int vega10_get_gpu_power(struct pp_hwmgr *hwmgr,
3878         uint32_t *query)
3879 {
3880     uint32_t value;
3881 
3882     if (!query)
3883         return -EINVAL;
3884 
3885     smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrPkgPwr, &value);
3886 
3887     /* SMC returning actual watts, keep consistent with legacy asics, low 8 bit as 8 fractional bits */
3888     *query = value << 8;
3889 
3890     return 0;
3891 }
3892 
3893 static int vega10_read_sensor(struct pp_hwmgr *hwmgr, int idx,
3894                   void *value, int *size)
3895 {
3896     struct amdgpu_device *adev = hwmgr->adev;
3897     uint32_t sclk_mhz, mclk_idx, activity_percent = 0;
3898     struct vega10_hwmgr *data = hwmgr->backend;
3899     struct vega10_dpm_table *dpm_table = &data->dpm_table;
3900     int ret = 0;
3901     uint32_t val_vid;
3902 
3903     switch (idx) {
3904     case AMDGPU_PP_SENSOR_GFX_SCLK:
3905         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetAverageGfxclkActualFrequency, &sclk_mhz);
3906         *((uint32_t *)value) = sclk_mhz * 100;
3907         break;
3908     case AMDGPU_PP_SENSOR_GFX_MCLK:
3909         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentUclkIndex, &mclk_idx);
3910         if (mclk_idx < dpm_table->mem_table.count) {
3911             *((uint32_t *)value) = dpm_table->mem_table.dpm_levels[mclk_idx].value;
3912             *size = 4;
3913         } else {
3914             ret = -EINVAL;
3915         }
3916         break;
3917     case AMDGPU_PP_SENSOR_GPU_LOAD:
3918         smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetAverageGfxActivity, 0,
3919                         &activity_percent);
3920         *((uint32_t *)value) = activity_percent > 100 ? 100 : activity_percent;
3921         *size = 4;
3922         break;
3923     case AMDGPU_PP_SENSOR_GPU_TEMP:
3924         *((uint32_t *)value) = vega10_thermal_get_temperature(hwmgr);
3925         *size = 4;
3926         break;
3927     case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
3928         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetTemperatureHotspot, (uint32_t *)value);
3929         *((uint32_t *)value) = *((uint32_t *)value) *
3930             PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
3931         *size = 4;
3932         break;
3933     case AMDGPU_PP_SENSOR_MEM_TEMP:
3934         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetTemperatureHBM, (uint32_t *)value);
3935         *((uint32_t *)value) = *((uint32_t *)value) *
3936             PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
3937         *size = 4;
3938         break;
3939     case AMDGPU_PP_SENSOR_UVD_POWER:
3940         *((uint32_t *)value) = data->uvd_power_gated ? 0 : 1;
3941         *size = 4;
3942         break;
3943     case AMDGPU_PP_SENSOR_VCE_POWER:
3944         *((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
3945         *size = 4;
3946         break;
3947     case AMDGPU_PP_SENSOR_GPU_POWER:
3948         ret = vega10_get_gpu_power(hwmgr, (uint32_t *)value);
3949         break;
3950     case AMDGPU_PP_SENSOR_VDDGFX:
3951         val_vid = (RREG32_SOC15(SMUIO, 0, mmSMUSVI0_PLANE0_CURRENTVID) &
3952             SMUSVI0_PLANE0_CURRENTVID__CURRENT_SVI0_PLANE0_VID_MASK) >>
3953             SMUSVI0_PLANE0_CURRENTVID__CURRENT_SVI0_PLANE0_VID__SHIFT;
3954         *((uint32_t *)value) = (uint32_t)convert_to_vddc((uint8_t)val_vid);
3955         return 0;
3956     case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK:
3957         ret = vega10_get_enabled_smc_features(hwmgr, (uint64_t *)value);
3958         if (!ret)
3959             *size = 8;
3960         break;
3961     default:
3962         ret = -EOPNOTSUPP;
3963         break;
3964     }
3965 
3966     return ret;
3967 }
3968 
3969 static void vega10_notify_smc_display_change(struct pp_hwmgr *hwmgr,
3970         bool has_disp)
3971 {
3972     smum_send_msg_to_smc_with_parameter(hwmgr,
3973             PPSMC_MSG_SetUclkFastSwitch,
3974             has_disp ? 1 : 0,
3975             NULL);
3976 }
3977 
3978 static int vega10_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
3979         struct pp_display_clock_request *clock_req)
3980 {
3981     int result = 0;
3982     enum amd_pp_clock_type clk_type = clock_req->clock_type;
3983     uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
3984     DSPCLK_e clk_select = 0;
3985     uint32_t clk_request = 0;
3986 
3987     switch (clk_type) {
3988     case amd_pp_dcef_clock:
3989         clk_select = DSPCLK_DCEFCLK;
3990         break;
3991     case amd_pp_disp_clock:
3992         clk_select = DSPCLK_DISPCLK;
3993         break;
3994     case amd_pp_pixel_clock:
3995         clk_select = DSPCLK_PIXCLK;
3996         break;
3997     case amd_pp_phy_clock:
3998         clk_select = DSPCLK_PHYCLK;
3999         break;
4000     default:
4001         pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!");
4002         result = -1;
4003         break;
4004     }
4005 
4006     if (!result) {
4007         clk_request = (clk_freq << 16) | clk_select;
4008         smum_send_msg_to_smc_with_parameter(hwmgr,
4009                 PPSMC_MSG_RequestDisplayClockByFreq,
4010                 clk_request,
4011                 NULL);
4012     }
4013 
4014     return result;
4015 }
4016 
4017 static uint8_t vega10_get_uclk_index(struct pp_hwmgr *hwmgr,
4018             struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table,
4019                         uint32_t frequency)
4020 {
4021     uint8_t count;
4022     uint8_t i;
4023 
4024     if (mclk_table == NULL || mclk_table->count == 0)
4025         return 0;
4026 
4027     count = (uint8_t)(mclk_table->count);
4028 
4029     for(i = 0; i < count; i++) {
4030         if(mclk_table->entries[i].clk >= frequency)
4031             return i;
4032     }
4033 
4034     return i-1;
4035 }
4036 
4037 static int vega10_notify_smc_display_config_after_ps_adjustment(
4038         struct pp_hwmgr *hwmgr)
4039 {
4040     struct vega10_hwmgr *data = hwmgr->backend;
4041     struct vega10_single_dpm_table *dpm_table =
4042             &data->dpm_table.dcef_table;
4043     struct phm_ppt_v2_information *table_info =
4044             (struct phm_ppt_v2_information *)hwmgr->pptable;
4045     struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table = table_info->vdd_dep_on_mclk;
4046     uint32_t idx;
4047     struct PP_Clocks min_clocks = {0};
4048     uint32_t i;
4049     struct pp_display_clock_request clock_req;
4050 
4051     if ((hwmgr->display_config->num_display > 1) &&
4052          !hwmgr->display_config->multi_monitor_in_sync &&
4053          !hwmgr->display_config->nb_pstate_switch_disable)
4054         vega10_notify_smc_display_change(hwmgr, false);
4055     else
4056         vega10_notify_smc_display_change(hwmgr, true);
4057 
4058     min_clocks.dcefClock = hwmgr->display_config->min_dcef_set_clk;
4059     min_clocks.dcefClockInSR = hwmgr->display_config->min_dcef_deep_sleep_set_clk;
4060     min_clocks.memoryClock = hwmgr->display_config->min_mem_set_clock;
4061 
4062     for (i = 0; i < dpm_table->count; i++) {
4063         if (dpm_table->dpm_levels[i].value == min_clocks.dcefClock)
4064             break;
4065     }
4066 
4067     if (i < dpm_table->count) {
4068         clock_req.clock_type = amd_pp_dcef_clock;
4069         clock_req.clock_freq_in_khz = dpm_table->dpm_levels[i].value * 10;
4070         if (!vega10_display_clock_voltage_request(hwmgr, &clock_req)) {
4071             smum_send_msg_to_smc_with_parameter(
4072                     hwmgr, PPSMC_MSG_SetMinDeepSleepDcefclk,
4073                     min_clocks.dcefClockInSR / 100,
4074                     NULL);
4075         } else {
4076             pr_info("Attempt to set Hard Min for DCEFCLK Failed!");
4077         }
4078     } else {
4079         pr_debug("Cannot find requested DCEFCLK!");
4080     }
4081 
4082     if (min_clocks.memoryClock != 0) {
4083         idx = vega10_get_uclk_index(hwmgr, mclk_table, min_clocks.memoryClock);
4084         smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMinUclkByIndex, idx,
4085                         NULL);
4086         data->dpm_table.mem_table.dpm_state.soft_min_level= idx;
4087     }
4088 
4089     return 0;
4090 }
4091 
4092 static int vega10_force_dpm_highest(struct pp_hwmgr *hwmgr)
4093 {
4094     struct vega10_hwmgr *data = hwmgr->backend;
4095 
4096     data->smc_state_table.gfx_boot_level =
4097     data->smc_state_table.gfx_max_level =
4098             vega10_find_highest_dpm_level(&(data->dpm_table.gfx_table));
4099     data->smc_state_table.mem_boot_level =
4100     data->smc_state_table.mem_max_level =
4101             vega10_find_highest_dpm_level(&(data->dpm_table.mem_table));
4102 
4103     PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
4104             "Failed to upload boot level to highest!",
4105             return -1);
4106 
4107     PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
4108             "Failed to upload dpm max level to highest!",
4109             return -1);
4110 
4111     return 0;
4112 }
4113 
4114 static int vega10_force_dpm_lowest(struct pp_hwmgr *hwmgr)
4115 {
4116     struct vega10_hwmgr *data = hwmgr->backend;
4117 
4118     data->smc_state_table.gfx_boot_level =
4119     data->smc_state_table.gfx_max_level =
4120             vega10_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
4121     data->smc_state_table.mem_boot_level =
4122     data->smc_state_table.mem_max_level =
4123             vega10_find_lowest_dpm_level(&(data->dpm_table.mem_table));
4124 
4125     PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
4126             "Failed to upload boot level to highest!",
4127             return -1);
4128 
4129     PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
4130             "Failed to upload dpm max level to highest!",
4131             return -1);
4132 
4133     return 0;
4134 
4135 }
4136 
4137 static int vega10_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
4138 {
4139     struct vega10_hwmgr *data = hwmgr->backend;
4140 
4141     data->smc_state_table.gfx_boot_level =
4142             vega10_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
4143     data->smc_state_table.gfx_max_level =
4144             vega10_find_highest_dpm_level(&(data->dpm_table.gfx_table));
4145     data->smc_state_table.mem_boot_level =
4146             vega10_find_lowest_dpm_level(&(data->dpm_table.mem_table));
4147     data->smc_state_table.mem_max_level =
4148             vega10_find_highest_dpm_level(&(data->dpm_table.mem_table));
4149 
4150     PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
4151             "Failed to upload DPM Bootup Levels!",
4152             return -1);
4153 
4154     PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
4155             "Failed to upload DPM Max Levels!",
4156             return -1);
4157     return 0;
4158 }
4159 
4160 static int vega10_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level,
4161                 uint32_t *sclk_mask, uint32_t *mclk_mask, uint32_t *soc_mask)
4162 {
4163     struct phm_ppt_v2_information *table_info =
4164             (struct phm_ppt_v2_information *)(hwmgr->pptable);
4165 
4166     if (table_info->vdd_dep_on_sclk->count > VEGA10_UMD_PSTATE_GFXCLK_LEVEL &&
4167         table_info->vdd_dep_on_socclk->count > VEGA10_UMD_PSTATE_SOCCLK_LEVEL &&
4168         table_info->vdd_dep_on_mclk->count > VEGA10_UMD_PSTATE_MCLK_LEVEL) {
4169         *sclk_mask = VEGA10_UMD_PSTATE_GFXCLK_LEVEL;
4170         *soc_mask = VEGA10_UMD_PSTATE_SOCCLK_LEVEL;
4171         *mclk_mask = VEGA10_UMD_PSTATE_MCLK_LEVEL;
4172         hwmgr->pstate_sclk = table_info->vdd_dep_on_sclk->entries[VEGA10_UMD_PSTATE_GFXCLK_LEVEL].clk;
4173         hwmgr->pstate_mclk = table_info->vdd_dep_on_mclk->entries[VEGA10_UMD_PSTATE_MCLK_LEVEL].clk;
4174     }
4175 
4176     if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
4177         *sclk_mask = 0;
4178     } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
4179         *mclk_mask = 0;
4180     } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
4181         /* under vega10  pp one vf mode, the gfx clk dpm need be lower
4182          * to level-4 due to the limited power
4183          */
4184         if (hwmgr->pp_one_vf)
4185             *sclk_mask = 4;
4186         else
4187             *sclk_mask = table_info->vdd_dep_on_sclk->count - 1;
4188         *soc_mask = table_info->vdd_dep_on_socclk->count - 1;
4189         *mclk_mask = table_info->vdd_dep_on_mclk->count - 1;
4190     }
4191 
4192     return 0;
4193 }
4194 
4195 static void vega10_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
4196 {
4197     if (!hwmgr->not_vf)
4198         return;
4199 
4200     switch (mode) {
4201     case AMD_FAN_CTRL_NONE:
4202         vega10_fan_ctrl_set_fan_speed_pwm(hwmgr, 255);
4203         break;
4204     case AMD_FAN_CTRL_MANUAL:
4205         if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
4206             vega10_fan_ctrl_stop_smc_fan_control(hwmgr);
4207         break;
4208     case AMD_FAN_CTRL_AUTO:
4209         if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
4210             vega10_fan_ctrl_start_smc_fan_control(hwmgr);
4211         break;
4212     default:
4213         break;
4214     }
4215 }
4216 
4217 static int vega10_force_clock_level(struct pp_hwmgr *hwmgr,
4218         enum pp_clock_type type, uint32_t mask)
4219 {
4220     struct vega10_hwmgr *data = hwmgr->backend;
4221 
4222     switch (type) {
4223     case PP_SCLK:
4224         data->smc_state_table.gfx_boot_level = mask ? (ffs(mask) - 1) : 0;
4225         data->smc_state_table.gfx_max_level = mask ? (fls(mask) - 1) : 0;
4226 
4227         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
4228             "Failed to upload boot level to lowest!",
4229             return -EINVAL);
4230 
4231         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
4232             "Failed to upload dpm max level to highest!",
4233             return -EINVAL);
4234         break;
4235 
4236     case PP_MCLK:
4237         data->smc_state_table.mem_boot_level = mask ? (ffs(mask) - 1) : 0;
4238         data->smc_state_table.mem_max_level = mask ? (fls(mask) - 1) : 0;
4239 
4240         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
4241             "Failed to upload boot level to lowest!",
4242             return -EINVAL);
4243 
4244         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
4245             "Failed to upload dpm max level to highest!",
4246             return -EINVAL);
4247 
4248         break;
4249 
4250     case PP_SOCCLK:
4251         data->smc_state_table.soc_boot_level = mask ? (ffs(mask) - 1) : 0;
4252         data->smc_state_table.soc_max_level = mask ? (fls(mask) - 1) : 0;
4253 
4254         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
4255             "Failed to upload boot level to lowest!",
4256             return -EINVAL);
4257 
4258         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
4259             "Failed to upload dpm max level to highest!",
4260             return -EINVAL);
4261 
4262         break;
4263 
4264     case PP_DCEFCLK:
4265         pr_info("Setting DCEFCLK min/max dpm level is not supported!\n");
4266         break;
4267 
4268     case PP_PCIE:
4269     default:
4270         break;
4271     }
4272 
4273     return 0;
4274 }
4275 
4276 static int vega10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
4277                 enum amd_dpm_forced_level level)
4278 {
4279     int ret = 0;
4280     uint32_t sclk_mask = 0;
4281     uint32_t mclk_mask = 0;
4282     uint32_t soc_mask = 0;
4283 
4284     if (hwmgr->pstate_sclk == 0)
4285         vega10_get_profiling_clk_mask(hwmgr, level, &sclk_mask, &mclk_mask, &soc_mask);
4286 
4287     switch (level) {
4288     case AMD_DPM_FORCED_LEVEL_HIGH:
4289         ret = vega10_force_dpm_highest(hwmgr);
4290         break;
4291     case AMD_DPM_FORCED_LEVEL_LOW:
4292         ret = vega10_force_dpm_lowest(hwmgr);
4293         break;
4294     case AMD_DPM_FORCED_LEVEL_AUTO:
4295         ret = vega10_unforce_dpm_levels(hwmgr);
4296         break;
4297     case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
4298     case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
4299     case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
4300     case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
4301         ret = vega10_get_profiling_clk_mask(hwmgr, level, &sclk_mask, &mclk_mask, &soc_mask);
4302         if (ret)
4303             return ret;
4304         vega10_force_clock_level(hwmgr, PP_SCLK, 1<<sclk_mask);
4305         vega10_force_clock_level(hwmgr, PP_MCLK, 1<<mclk_mask);
4306         break;
4307     case AMD_DPM_FORCED_LEVEL_MANUAL:
4308     case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
4309     default:
4310         break;
4311     }
4312 
4313     if (!hwmgr->not_vf)
4314         return ret;
4315 
4316     if (!ret) {
4317         if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
4318             vega10_set_fan_control_mode(hwmgr, AMD_FAN_CTRL_NONE);
4319         else if (level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
4320             vega10_set_fan_control_mode(hwmgr, AMD_FAN_CTRL_AUTO);
4321     }
4322 
4323     return ret;
4324 }
4325 
4326 static uint32_t vega10_get_fan_control_mode(struct pp_hwmgr *hwmgr)
4327 {
4328     struct vega10_hwmgr *data = hwmgr->backend;
4329 
4330     if (data->smu_features[GNLD_FAN_CONTROL].enabled == false)
4331         return AMD_FAN_CTRL_MANUAL;
4332     else
4333         return AMD_FAN_CTRL_AUTO;
4334 }
4335 
4336 static int vega10_get_dal_power_level(struct pp_hwmgr *hwmgr,
4337         struct amd_pp_simple_clock_info *info)
4338 {
4339     struct phm_ppt_v2_information *table_info =
4340             (struct phm_ppt_v2_information *)hwmgr->pptable;
4341     struct phm_clock_and_voltage_limits *max_limits =
4342             &table_info->max_clock_voltage_on_ac;
4343 
4344     info->engine_max_clock = max_limits->sclk;
4345     info->memory_max_clock = max_limits->mclk;
4346 
4347     return 0;
4348 }
4349 
4350 static void vega10_get_sclks(struct pp_hwmgr *hwmgr,
4351         struct pp_clock_levels_with_latency *clocks)
4352 {
4353     struct phm_ppt_v2_information *table_info =
4354             (struct phm_ppt_v2_information *)hwmgr->pptable;
4355     struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
4356             table_info->vdd_dep_on_sclk;
4357     uint32_t i;
4358 
4359     clocks->num_levels = 0;
4360     for (i = 0; i < dep_table->count; i++) {
4361         if (dep_table->entries[i].clk) {
4362             clocks->data[clocks->num_levels].clocks_in_khz =
4363                     dep_table->entries[i].clk * 10;
4364             clocks->num_levels++;
4365         }
4366     }
4367 
4368 }
4369 
4370 static void vega10_get_memclocks(struct pp_hwmgr *hwmgr,
4371         struct pp_clock_levels_with_latency *clocks)
4372 {
4373     struct phm_ppt_v2_information *table_info =
4374             (struct phm_ppt_v2_information *)hwmgr->pptable;
4375     struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
4376             table_info->vdd_dep_on_mclk;
4377     struct vega10_hwmgr *data = hwmgr->backend;
4378     uint32_t j = 0;
4379     uint32_t i;
4380 
4381     for (i = 0; i < dep_table->count; i++) {
4382         if (dep_table->entries[i].clk) {
4383 
4384             clocks->data[j].clocks_in_khz =
4385                         dep_table->entries[i].clk * 10;
4386             data->mclk_latency_table.entries[j].frequency =
4387                             dep_table->entries[i].clk;
4388             clocks->data[j].latency_in_us =
4389                 data->mclk_latency_table.entries[j].latency = 25;
4390             j++;
4391         }
4392     }
4393     clocks->num_levels = data->mclk_latency_table.count = j;
4394 }
4395 
4396 static void vega10_get_dcefclocks(struct pp_hwmgr *hwmgr,
4397         struct pp_clock_levels_with_latency *clocks)
4398 {
4399     struct phm_ppt_v2_information *table_info =
4400             (struct phm_ppt_v2_information *)hwmgr->pptable;
4401     struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
4402             table_info->vdd_dep_on_dcefclk;
4403     uint32_t i;
4404 
4405     for (i = 0; i < dep_table->count; i++) {
4406         clocks->data[i].clocks_in_khz = dep_table->entries[i].clk * 10;
4407         clocks->data[i].latency_in_us = 0;
4408         clocks->num_levels++;
4409     }
4410 }
4411 
4412 static void vega10_get_socclocks(struct pp_hwmgr *hwmgr,
4413         struct pp_clock_levels_with_latency *clocks)
4414 {
4415     struct phm_ppt_v2_information *table_info =
4416             (struct phm_ppt_v2_information *)hwmgr->pptable;
4417     struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
4418             table_info->vdd_dep_on_socclk;
4419     uint32_t i;
4420 
4421     for (i = 0; i < dep_table->count; i++) {
4422         clocks->data[i].clocks_in_khz = dep_table->entries[i].clk * 10;
4423         clocks->data[i].latency_in_us = 0;
4424         clocks->num_levels++;
4425     }
4426 }
4427 
4428 static int vega10_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr,
4429         enum amd_pp_clock_type type,
4430         struct pp_clock_levels_with_latency *clocks)
4431 {
4432     switch (type) {
4433     case amd_pp_sys_clock:
4434         vega10_get_sclks(hwmgr, clocks);
4435         break;
4436     case amd_pp_mem_clock:
4437         vega10_get_memclocks(hwmgr, clocks);
4438         break;
4439     case amd_pp_dcef_clock:
4440         vega10_get_dcefclocks(hwmgr, clocks);
4441         break;
4442     case amd_pp_soc_clock:
4443         vega10_get_socclocks(hwmgr, clocks);
4444         break;
4445     default:
4446         return -1;
4447     }
4448 
4449     return 0;
4450 }
4451 
4452 static int vega10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr,
4453         enum amd_pp_clock_type type,
4454         struct pp_clock_levels_with_voltage *clocks)
4455 {
4456     struct phm_ppt_v2_information *table_info =
4457             (struct phm_ppt_v2_information *)hwmgr->pptable;
4458     struct phm_ppt_v1_clock_voltage_dependency_table *dep_table;
4459     uint32_t i;
4460 
4461     switch (type) {
4462     case amd_pp_mem_clock:
4463         dep_table = table_info->vdd_dep_on_mclk;
4464         break;
4465     case amd_pp_dcef_clock:
4466         dep_table = table_info->vdd_dep_on_dcefclk;
4467         break;
4468     case amd_pp_disp_clock:
4469         dep_table = table_info->vdd_dep_on_dispclk;
4470         break;
4471     case amd_pp_pixel_clock:
4472         dep_table = table_info->vdd_dep_on_pixclk;
4473         break;
4474     case amd_pp_phy_clock:
4475         dep_table = table_info->vdd_dep_on_phyclk;
4476         break;
4477     default:
4478         return -1;
4479     }
4480 
4481     for (i = 0; i < dep_table->count; i++) {
4482         clocks->data[i].clocks_in_khz = dep_table->entries[i].clk  * 10;
4483         clocks->data[i].voltage_in_mv = (uint32_t)(table_info->vddc_lookup_table->
4484                 entries[dep_table->entries[i].vddInd].us_vdd);
4485         clocks->num_levels++;
4486     }
4487 
4488     if (i < dep_table->count)
4489         return -1;
4490 
4491     return 0;
4492 }
4493 
4494 static int vega10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr,
4495                             void *clock_range)
4496 {
4497     struct vega10_hwmgr *data = hwmgr->backend;
4498     struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_range;
4499     Watermarks_t *table = &(data->smc_state_table.water_marks_table);
4500 
4501     if (!data->registry_data.disable_water_mark) {
4502         smu_set_watermarks_for_clocks_ranges(table, wm_with_clock_ranges);
4503         data->water_marks_bitmap = WaterMarksExist;
4504     }
4505 
4506     return 0;
4507 }
4508 
4509 static int vega10_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf)
4510 {
4511     static const char *ppfeature_name[] = {
4512                 "DPM_PREFETCHER",
4513                 "GFXCLK_DPM",
4514                 "UCLK_DPM",
4515                 "SOCCLK_DPM",
4516                 "UVD_DPM",
4517                 "VCE_DPM",
4518                 "ULV",
4519                 "MP0CLK_DPM",
4520                 "LINK_DPM",
4521                 "DCEFCLK_DPM",
4522                 "AVFS",
4523                 "GFXCLK_DS",
4524                 "SOCCLK_DS",
4525                 "LCLK_DS",
4526                 "PPT",
4527                 "TDC",
4528                 "THERMAL",
4529                 "GFX_PER_CU_CG",
4530                 "RM",
4531                 "DCEFCLK_DS",
4532                 "ACDC",
4533                 "VR0HOT",
4534                 "VR1HOT",
4535                 "FW_CTF",
4536                 "LED_DISPLAY",
4537                 "FAN_CONTROL",
4538                 "FAST_PPT",
4539                 "DIDT",
4540                 "ACG",
4541                 "PCC_LIMIT"};
4542     static const char *output_title[] = {
4543                 "FEATURES",
4544                 "BITMASK",
4545                 "ENABLEMENT"};
4546     uint64_t features_enabled;
4547     int i;
4548     int ret = 0;
4549     int size = 0;
4550 
4551     phm_get_sysfs_buf(&buf, &size);
4552 
4553     ret = vega10_get_enabled_smc_features(hwmgr, &features_enabled);
4554     PP_ASSERT_WITH_CODE(!ret,
4555             "[EnableAllSmuFeatures] Failed to get enabled smc features!",
4556             return ret);
4557 
4558     size += sysfs_emit_at(buf, size, "Current ppfeatures: 0x%016llx\n", features_enabled);
4559     size += sysfs_emit_at(buf, size, "%-19s %-22s %s\n",
4560                 output_title[0],
4561                 output_title[1],
4562                 output_title[2]);
4563     for (i = 0; i < GNLD_FEATURES_MAX; i++) {
4564         size += sysfs_emit_at(buf, size, "%-19s 0x%016llx %6s\n",
4565                     ppfeature_name[i],
4566                     1ULL << i,
4567                     (features_enabled & (1ULL << i)) ? "Y" : "N");
4568     }
4569 
4570     return size;
4571 }
4572 
4573 static int vega10_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t new_ppfeature_masks)
4574 {
4575     uint64_t features_enabled;
4576     uint64_t features_to_enable;
4577     uint64_t features_to_disable;
4578     int ret = 0;
4579 
4580     if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX))
4581         return -EINVAL;
4582 
4583     ret = vega10_get_enabled_smc_features(hwmgr, &features_enabled);
4584     if (ret)
4585         return ret;
4586 
4587     features_to_disable =
4588         features_enabled & ~new_ppfeature_masks;
4589     features_to_enable =
4590         ~features_enabled & new_ppfeature_masks;
4591 
4592     pr_debug("features_to_disable 0x%llx\n", features_to_disable);
4593     pr_debug("features_to_enable 0x%llx\n", features_to_enable);
4594 
4595     if (features_to_disable) {
4596         ret = vega10_enable_smc_features(hwmgr, false, features_to_disable);
4597         if (ret)
4598             return ret;
4599     }
4600 
4601     if (features_to_enable) {
4602         ret = vega10_enable_smc_features(hwmgr, true, features_to_enable);
4603         if (ret)
4604             return ret;
4605     }
4606 
4607     return 0;
4608 }
4609 
4610 static int vega10_get_current_pcie_link_width_level(struct pp_hwmgr *hwmgr)
4611 {
4612     struct amdgpu_device *adev = hwmgr->adev;
4613 
4614     return (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) &
4615         PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK)
4616         >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT;
4617 }
4618 
4619 static int vega10_get_current_pcie_link_speed_level(struct pp_hwmgr *hwmgr)
4620 {
4621     struct amdgpu_device *adev = hwmgr->adev;
4622 
4623     return (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) &
4624         PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK)
4625         >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
4626 }
4627 
4628 static int vega10_emit_clock_levels(struct pp_hwmgr *hwmgr,
4629                     enum pp_clock_type type, char *buf, int *offset)
4630 {
4631     struct vega10_hwmgr *data = hwmgr->backend;
4632     struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
4633     struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
4634     struct vega10_single_dpm_table *soc_table = &(data->dpm_table.soc_table);
4635     struct vega10_single_dpm_table *dcef_table = &(data->dpm_table.dcef_table);
4636     struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep = NULL;
4637     uint32_t gen_speed, lane_width, current_gen_speed, current_lane_width;
4638     PPTable_t *pptable = &(data->smc_state_table.pp_table);
4639 
4640     uint32_t i, now, count = 0;
4641     int ret = 0;
4642 
4643     switch (type) {
4644     case PP_SCLK:
4645         if (data->registry_data.sclk_dpm_key_disabled)
4646             return -EOPNOTSUPP;
4647 
4648         ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentGfxclkIndex, &now);
4649         if (unlikely(ret != 0))
4650             return ret;
4651 
4652         if (hwmgr->pp_one_vf &&
4653             (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK))
4654             count = 5;
4655         else
4656             count = sclk_table->count;
4657         for (i = 0; i < count; i++)
4658             *offset += sysfs_emit_at(buf, *offset, "%d: %uMhz %s\n",
4659                     i, sclk_table->dpm_levels[i].value / 100,
4660                     (i == now) ? "*" : "");
4661         break;
4662     case PP_MCLK:
4663         if (data->registry_data.mclk_dpm_key_disabled)
4664             return -EOPNOTSUPP;
4665 
4666         ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentUclkIndex, &now);
4667         if (unlikely(ret != 0))
4668             return ret;
4669 
4670         for (i = 0; i < mclk_table->count; i++)
4671             *offset += sysfs_emit_at(buf, *offset, "%d: %uMhz %s\n",
4672                     i, mclk_table->dpm_levels[i].value / 100,
4673                     (i == now) ? "*" : "");
4674         break;
4675     case PP_SOCCLK:
4676         if (data->registry_data.socclk_dpm_key_disabled)
4677             return -EOPNOTSUPP;
4678 
4679         ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentSocclkIndex, &now);
4680         if (unlikely(ret != 0))
4681             return ret;
4682 
4683         for (i = 0; i < soc_table->count; i++)
4684             *offset += sysfs_emit_at(buf, *offset, "%d: %uMhz %s\n",
4685                     i, soc_table->dpm_levels[i].value / 100,
4686                     (i == now) ? "*" : "");
4687         break;
4688     case PP_DCEFCLK:
4689         if (data->registry_data.dcefclk_dpm_key_disabled)
4690             return -EOPNOTSUPP;
4691 
4692         ret = smum_send_msg_to_smc_with_parameter(hwmgr,
4693                               PPSMC_MSG_GetClockFreqMHz,
4694                               CLK_DCEFCLK, &now);
4695         if (unlikely(ret != 0))
4696             return ret;
4697 
4698         for (i = 0; i < dcef_table->count; i++)
4699             *offset += sysfs_emit_at(buf, *offset, "%d: %uMhz %s\n",
4700                     i, dcef_table->dpm_levels[i].value / 100,
4701                     (dcef_table->dpm_levels[i].value / 100 == now) ?
4702                     "*" : "");
4703         break;
4704     case PP_PCIE:
4705         current_gen_speed =
4706             vega10_get_current_pcie_link_speed_level(hwmgr);
4707         current_lane_width =
4708             vega10_get_current_pcie_link_width_level(hwmgr);
4709         for (i = 0; i < NUM_LINK_LEVELS; i++) {
4710             gen_speed = pptable->PcieGenSpeed[i];
4711             lane_width = pptable->PcieLaneCount[i];
4712 
4713             *offset += sysfs_emit_at(buf, *offset, "%d: %s %s %s\n", i,
4714                     (gen_speed == 0) ? "2.5GT/s," :
4715                     (gen_speed == 1) ? "5.0GT/s," :
4716                     (gen_speed == 2) ? "8.0GT/s," :
4717                     (gen_speed == 3) ? "16.0GT/s," : "",
4718                     (lane_width == 1) ? "x1" :
4719                     (lane_width == 2) ? "x2" :
4720                     (lane_width == 3) ? "x4" :
4721                     (lane_width == 4) ? "x8" :
4722                     (lane_width == 5) ? "x12" :
4723                     (lane_width == 6) ? "x16" : "",
4724                     (current_gen_speed == gen_speed) &&
4725                     (current_lane_width == lane_width) ?
4726                     "*" : "");
4727         }
4728         break;
4729 
4730     case OD_SCLK:
4731         if (!hwmgr->od_enabled)
4732             return -EOPNOTSUPP;
4733 
4734         *offset += sysfs_emit_at(buf, *offset, "%s:\n", "OD_SCLK");
4735         podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_sclk;
4736         for (i = 0; i < podn_vdd_dep->count; i++)
4737             *offset += sysfs_emit_at(buf, *offset, "%d: %10uMhz %10umV\n",
4738                          i, podn_vdd_dep->entries[i].clk / 100,
4739                          podn_vdd_dep->entries[i].vddc);
4740         break;
4741     case OD_MCLK:
4742         if (!hwmgr->od_enabled)
4743             return -EOPNOTSUPP;
4744 
4745         *offset += sysfs_emit_at(buf, *offset, "%s:\n", "OD_MCLK");
4746         podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_mclk;
4747         for (i = 0; i < podn_vdd_dep->count; i++)
4748             *offset += sysfs_emit_at(buf, *offset, "%d: %10uMhz %10umV\n",
4749                          i, podn_vdd_dep->entries[i].clk/100,
4750                          podn_vdd_dep->entries[i].vddc);
4751         break;
4752     case OD_RANGE:
4753         if (!hwmgr->od_enabled)
4754             return -EOPNOTSUPP;
4755 
4756         *offset += sysfs_emit_at(buf, *offset, "%s:\n", "OD_RANGE");
4757         *offset += sysfs_emit_at(buf, *offset, "SCLK: %7uMHz %10uMHz\n",
4758                      data->golden_dpm_table.gfx_table.dpm_levels[0].value/100,
4759                 hwmgr->platform_descriptor.overdriveLimit.engineClock/100);
4760         *offset += sysfs_emit_at(buf, *offset, "MCLK: %7uMHz %10uMHz\n",
4761                      data->golden_dpm_table.mem_table.dpm_levels[0].value/100,
4762                 hwmgr->platform_descriptor.overdriveLimit.memoryClock/100);
4763         *offset += sysfs_emit_at(buf, *offset, "VDDC: %7umV %11umV\n",
4764                      data->odn_dpm_table.min_vddc,
4765                      data->odn_dpm_table.max_vddc);
4766         break;
4767     default:
4768         ret = -ENOENT;
4769         break;
4770     }
4771     return ret;
4772 }
4773 
4774 static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr,
4775         enum pp_clock_type type, char *buf)
4776 {
4777     struct vega10_hwmgr *data = hwmgr->backend;
4778     struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
4779     struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
4780     struct vega10_single_dpm_table *soc_table = &(data->dpm_table.soc_table);
4781     struct vega10_single_dpm_table *dcef_table = &(data->dpm_table.dcef_table);
4782     struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep = NULL;
4783     uint32_t gen_speed, lane_width, current_gen_speed, current_lane_width;
4784     PPTable_t *pptable = &(data->smc_state_table.pp_table);
4785 
4786     int i, now, size = 0, count = 0;
4787 
4788     switch (type) {
4789     case PP_SCLK:
4790         if (data->registry_data.sclk_dpm_key_disabled)
4791             break;
4792 
4793         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentGfxclkIndex, &now);
4794 
4795         if (hwmgr->pp_one_vf &&
4796             (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK))
4797             count = 5;
4798         else
4799             count = sclk_table->count;
4800         for (i = 0; i < count; i++)
4801             size += sprintf(buf + size, "%d: %uMhz %s\n",
4802                     i, sclk_table->dpm_levels[i].value / 100,
4803                     (i == now) ? "*" : "");
4804         break;
4805     case PP_MCLK:
4806         if (data->registry_data.mclk_dpm_key_disabled)
4807             break;
4808 
4809         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentUclkIndex, &now);
4810 
4811         for (i = 0; i < mclk_table->count; i++)
4812             size += sprintf(buf + size, "%d: %uMhz %s\n",
4813                     i, mclk_table->dpm_levels[i].value / 100,
4814                     (i == now) ? "*" : "");
4815         break;
4816     case PP_SOCCLK:
4817         if (data->registry_data.socclk_dpm_key_disabled)
4818             break;
4819 
4820         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentSocclkIndex, &now);
4821 
4822         for (i = 0; i < soc_table->count; i++)
4823             size += sprintf(buf + size, "%d: %uMhz %s\n",
4824                     i, soc_table->dpm_levels[i].value / 100,
4825                     (i == now) ? "*" : "");
4826         break;
4827     case PP_DCEFCLK:
4828         if (data->registry_data.dcefclk_dpm_key_disabled)
4829             break;
4830 
4831         smum_send_msg_to_smc_with_parameter(hwmgr,
4832                 PPSMC_MSG_GetClockFreqMHz, CLK_DCEFCLK, &now);
4833 
4834         for (i = 0; i < dcef_table->count; i++)
4835             size += sprintf(buf + size, "%d: %uMhz %s\n",
4836                     i, dcef_table->dpm_levels[i].value / 100,
4837                     (dcef_table->dpm_levels[i].value / 100 == now) ?
4838                     "*" : "");
4839         break;
4840     case PP_PCIE:
4841         current_gen_speed =
4842             vega10_get_current_pcie_link_speed_level(hwmgr);
4843         current_lane_width =
4844             vega10_get_current_pcie_link_width_level(hwmgr);
4845         for (i = 0; i < NUM_LINK_LEVELS; i++) {
4846             gen_speed = pptable->PcieGenSpeed[i];
4847             lane_width = pptable->PcieLaneCount[i];
4848 
4849             size += sprintf(buf + size, "%d: %s %s %s\n", i,
4850                     (gen_speed == 0) ? "2.5GT/s," :
4851                     (gen_speed == 1) ? "5.0GT/s," :
4852                     (gen_speed == 2) ? "8.0GT/s," :
4853                     (gen_speed == 3) ? "16.0GT/s," : "",
4854                     (lane_width == 1) ? "x1" :
4855                     (lane_width == 2) ? "x2" :
4856                     (lane_width == 3) ? "x4" :
4857                     (lane_width == 4) ? "x8" :
4858                     (lane_width == 5) ? "x12" :
4859                     (lane_width == 6) ? "x16" : "",
4860                     (current_gen_speed == gen_speed) &&
4861                     (current_lane_width == lane_width) ?
4862                     "*" : "");
4863         }
4864         break;
4865 
4866     case OD_SCLK:
4867         if (hwmgr->od_enabled) {
4868             size += sprintf(buf + size, "%s:\n", "OD_SCLK");
4869             podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_sclk;
4870             for (i = 0; i < podn_vdd_dep->count; i++)
4871                 size += sprintf(buf + size, "%d: %10uMhz %10umV\n",
4872                     i, podn_vdd_dep->entries[i].clk / 100,
4873                         podn_vdd_dep->entries[i].vddc);
4874         }
4875         break;
4876     case OD_MCLK:
4877         if (hwmgr->od_enabled) {
4878             size += sprintf(buf + size, "%s:\n", "OD_MCLK");
4879             podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_mclk;
4880             for (i = 0; i < podn_vdd_dep->count; i++)
4881                 size += sprintf(buf + size, "%d: %10uMhz %10umV\n",
4882                     i, podn_vdd_dep->entries[i].clk/100,
4883                         podn_vdd_dep->entries[i].vddc);
4884         }
4885         break;
4886     case OD_RANGE:
4887         if (hwmgr->od_enabled) {
4888             size += sprintf(buf + size, "%s:\n", "OD_RANGE");
4889             size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",
4890                 data->golden_dpm_table.gfx_table.dpm_levels[0].value/100,
4891                 hwmgr->platform_descriptor.overdriveLimit.engineClock/100);
4892             size += sprintf(buf + size, "MCLK: %7uMHz %10uMHz\n",
4893                 data->golden_dpm_table.mem_table.dpm_levels[0].value/100,
4894                 hwmgr->platform_descriptor.overdriveLimit.memoryClock/100);
4895             size += sprintf(buf + size, "VDDC: %7umV %11umV\n",
4896                 data->odn_dpm_table.min_vddc,
4897                 data->odn_dpm_table.max_vddc);
4898         }
4899         break;
4900     default:
4901         break;
4902     }
4903     return size;
4904 }
4905 
4906 static int vega10_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
4907 {
4908     struct vega10_hwmgr *data = hwmgr->backend;
4909     Watermarks_t *wm_table = &(data->smc_state_table.water_marks_table);
4910     int result = 0;
4911 
4912     if ((data->water_marks_bitmap & WaterMarksExist) &&
4913             !(data->water_marks_bitmap & WaterMarksLoaded)) {
4914         result = smum_smc_table_manager(hwmgr, (uint8_t *)wm_table, WMTABLE, false);
4915         PP_ASSERT_WITH_CODE(result, "Failed to update WMTABLE!", return -EINVAL);
4916         data->water_marks_bitmap |= WaterMarksLoaded;
4917     }
4918 
4919     if (data->water_marks_bitmap & WaterMarksLoaded) {
4920         smum_send_msg_to_smc_with_parameter(hwmgr,
4921             PPSMC_MSG_NumOfDisplays, hwmgr->display_config->num_display,
4922             NULL);
4923     }
4924 
4925     return result;
4926 }
4927 
4928 static int vega10_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
4929 {
4930     struct vega10_hwmgr *data = hwmgr->backend;
4931 
4932     if (data->smu_features[GNLD_DPM_UVD].supported) {
4933         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
4934                 enable,
4935                 data->smu_features[GNLD_DPM_UVD].smu_feature_bitmap),
4936                 "Attempt to Enable/Disable DPM UVD Failed!",
4937                 return -1);
4938         data->smu_features[GNLD_DPM_UVD].enabled = enable;
4939     }
4940     return 0;
4941 }
4942 
4943 static void vega10_power_gate_vce(struct pp_hwmgr *hwmgr, bool bgate)
4944 {
4945     struct vega10_hwmgr *data = hwmgr->backend;
4946 
4947     data->vce_power_gated = bgate;
4948     vega10_enable_disable_vce_dpm(hwmgr, !bgate);
4949 }
4950 
4951 static void vega10_power_gate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
4952 {
4953     struct vega10_hwmgr *data = hwmgr->backend;
4954 
4955     data->uvd_power_gated = bgate;
4956     vega10_enable_disable_uvd_dpm(hwmgr, !bgate);
4957 }
4958 
4959 static inline bool vega10_are_power_levels_equal(
4960                 const struct vega10_performance_level *pl1,
4961                 const struct vega10_performance_level *pl2)
4962 {
4963     return ((pl1->soc_clock == pl2->soc_clock) &&
4964             (pl1->gfx_clock == pl2->gfx_clock) &&
4965             (pl1->mem_clock == pl2->mem_clock));
4966 }
4967 
4968 static int vega10_check_states_equal(struct pp_hwmgr *hwmgr,
4969                 const struct pp_hw_power_state *pstate1,
4970             const struct pp_hw_power_state *pstate2, bool *equal)
4971 {
4972     const struct vega10_power_state *vega10_psa;
4973     const struct vega10_power_state *vega10_psb;
4974     int i;
4975 
4976     if (pstate1 == NULL || pstate2 == NULL || equal == NULL)
4977         return -EINVAL;
4978 
4979     vega10_psa = cast_const_phw_vega10_power_state(pstate1);
4980     vega10_psb = cast_const_phw_vega10_power_state(pstate2);
4981 
4982     /* If the two states don't even have the same number of performance levels
4983      * they cannot be the same state.
4984      */
4985     if (vega10_psa->performance_level_count != vega10_psb->performance_level_count) {
4986         *equal = false;
4987         return 0;
4988     }
4989 
4990     for (i = 0; i < vega10_psa->performance_level_count; i++) {
4991         if (!vega10_are_power_levels_equal(&(vega10_psa->performance_levels[i]),
4992                            &(vega10_psb->performance_levels[i]))) {
4993             /* If we have found even one performance level pair
4994              * that is different the states are different.
4995              */
4996             *equal = false;
4997             return 0;
4998         }
4999     }
5000 
5001     /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
5002     *equal = ((vega10_psa->uvd_clks.vclk == vega10_psb->uvd_clks.vclk) &&
5003           (vega10_psa->uvd_clks.dclk == vega10_psb->uvd_clks.dclk));
5004     *equal &= ((vega10_psa->vce_clks.evclk == vega10_psb->vce_clks.evclk) &&
5005            (vega10_psa->vce_clks.ecclk == vega10_psb->vce_clks.ecclk));
5006     *equal &= (vega10_psa->sclk_threshold == vega10_psb->sclk_threshold);
5007 
5008     return 0;
5009 }
5010 
5011 static bool
5012 vega10_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
5013 {
5014     struct vega10_hwmgr *data = hwmgr->backend;
5015     bool is_update_required = false;
5016 
5017     if (data->display_timing.num_existing_displays != hwmgr->display_config->num_display)
5018         is_update_required = true;
5019 
5020     if (PP_CAP(PHM_PlatformCaps_SclkDeepSleep)) {
5021         if (data->display_timing.min_clock_in_sr != hwmgr->display_config->min_core_set_clock_in_sr)
5022             is_update_required = true;
5023     }
5024 
5025     return is_update_required;
5026 }
5027 
5028 static int vega10_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
5029 {
5030     int tmp_result, result = 0;
5031 
5032     if (!hwmgr->not_vf)
5033         return 0;
5034 
5035     if (PP_CAP(PHM_PlatformCaps_ThermalController))
5036         vega10_disable_thermal_protection(hwmgr);
5037 
5038     tmp_result = vega10_disable_power_containment(hwmgr);
5039     PP_ASSERT_WITH_CODE((tmp_result == 0),
5040             "Failed to disable power containment!", result = tmp_result);
5041 
5042     tmp_result = vega10_disable_didt_config(hwmgr);
5043     PP_ASSERT_WITH_CODE((tmp_result == 0),
5044             "Failed to disable didt config!", result = tmp_result);
5045 
5046     tmp_result = vega10_avfs_enable(hwmgr, false);
5047     PP_ASSERT_WITH_CODE((tmp_result == 0),
5048             "Failed to disable AVFS!", result = tmp_result);
5049 
5050     tmp_result = vega10_stop_dpm(hwmgr, SMC_DPM_FEATURES);
5051     PP_ASSERT_WITH_CODE((tmp_result == 0),
5052             "Failed to stop DPM!", result = tmp_result);
5053 
5054     tmp_result = vega10_disable_deep_sleep_master_switch(hwmgr);
5055     PP_ASSERT_WITH_CODE((tmp_result == 0),
5056             "Failed to disable deep sleep!", result = tmp_result);
5057 
5058     tmp_result = vega10_disable_ulv(hwmgr);
5059     PP_ASSERT_WITH_CODE((tmp_result == 0),
5060             "Failed to disable ulv!", result = tmp_result);
5061 
5062     tmp_result =  vega10_acg_disable(hwmgr);
5063     PP_ASSERT_WITH_CODE((tmp_result == 0),
5064             "Failed to disable acg!", result = tmp_result);
5065 
5066     vega10_enable_disable_PCC_limit_feature(hwmgr, false);
5067     return result;
5068 }
5069 
5070 static int vega10_power_off_asic(struct pp_hwmgr *hwmgr)
5071 {
5072     struct vega10_hwmgr *data = hwmgr->backend;
5073     int result;
5074 
5075     result = vega10_disable_dpm_tasks(hwmgr);
5076     PP_ASSERT_WITH_CODE((0 == result),
5077             "[disable_dpm_tasks] Failed to disable DPM!",
5078             );
5079     data->water_marks_bitmap &= ~(WaterMarksLoaded);
5080 
5081     return result;
5082 }
5083 
5084 static int vega10_get_sclk_od(struct pp_hwmgr *hwmgr)
5085 {
5086     struct vega10_hwmgr *data = hwmgr->backend;
5087     struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
5088     struct vega10_single_dpm_table *golden_sclk_table =
5089             &(data->golden_dpm_table.gfx_table);
5090     int value = sclk_table->dpm_levels[sclk_table->count - 1].value;
5091     int golden_value = golden_sclk_table->dpm_levels
5092             [golden_sclk_table->count - 1].value;
5093 
5094     value -= golden_value;
5095     value = DIV_ROUND_UP(value * 100, golden_value);
5096 
5097     return value;
5098 }
5099 
5100 static int vega10_set_sclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
5101 {
5102     struct vega10_hwmgr *data = hwmgr->backend;
5103     struct vega10_single_dpm_table *golden_sclk_table =
5104             &(data->golden_dpm_table.gfx_table);
5105     struct pp_power_state *ps;
5106     struct vega10_power_state *vega10_ps;
5107 
5108     ps = hwmgr->request_ps;
5109 
5110     if (ps == NULL)
5111         return -EINVAL;
5112 
5113     vega10_ps = cast_phw_vega10_power_state(&ps->hardware);
5114 
5115     vega10_ps->performance_levels
5116     [vega10_ps->performance_level_count - 1].gfx_clock =
5117             golden_sclk_table->dpm_levels
5118             [golden_sclk_table->count - 1].value *
5119             value / 100 +
5120             golden_sclk_table->dpm_levels
5121             [golden_sclk_table->count - 1].value;
5122 
5123     if (vega10_ps->performance_levels
5124             [vega10_ps->performance_level_count - 1].gfx_clock >
5125             hwmgr->platform_descriptor.overdriveLimit.engineClock) {
5126         vega10_ps->performance_levels
5127         [vega10_ps->performance_level_count - 1].gfx_clock =
5128                 hwmgr->platform_descriptor.overdriveLimit.engineClock;
5129         pr_warn("max sclk supported by vbios is %d\n",
5130                 hwmgr->platform_descriptor.overdriveLimit.engineClock);
5131     }
5132     return 0;
5133 }
5134 
5135 static int vega10_get_mclk_od(struct pp_hwmgr *hwmgr)
5136 {
5137     struct vega10_hwmgr *data = hwmgr->backend;
5138     struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
5139     struct vega10_single_dpm_table *golden_mclk_table =
5140             &(data->golden_dpm_table.mem_table);
5141     int value = mclk_table->dpm_levels[mclk_table->count - 1].value;
5142     int golden_value = golden_mclk_table->dpm_levels
5143             [golden_mclk_table->count - 1].value;
5144 
5145     value -= golden_value;
5146     value = DIV_ROUND_UP(value * 100, golden_value);
5147 
5148     return value;
5149 }
5150 
5151 static int vega10_set_mclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
5152 {
5153     struct vega10_hwmgr *data = hwmgr->backend;
5154     struct vega10_single_dpm_table *golden_mclk_table =
5155             &(data->golden_dpm_table.mem_table);
5156     struct pp_power_state  *ps;
5157     struct vega10_power_state  *vega10_ps;
5158 
5159     ps = hwmgr->request_ps;
5160 
5161     if (ps == NULL)
5162         return -EINVAL;
5163 
5164     vega10_ps = cast_phw_vega10_power_state(&ps->hardware);
5165 
5166     vega10_ps->performance_levels
5167     [vega10_ps->performance_level_count - 1].mem_clock =
5168             golden_mclk_table->dpm_levels
5169             [golden_mclk_table->count - 1].value *
5170             value / 100 +
5171             golden_mclk_table->dpm_levels
5172             [golden_mclk_table->count - 1].value;
5173 
5174     if (vega10_ps->performance_levels
5175             [vega10_ps->performance_level_count - 1].mem_clock >
5176             hwmgr->platform_descriptor.overdriveLimit.memoryClock) {
5177         vega10_ps->performance_levels
5178         [vega10_ps->performance_level_count - 1].mem_clock =
5179                 hwmgr->platform_descriptor.overdriveLimit.memoryClock;
5180         pr_warn("max mclk supported by vbios is %d\n",
5181                 hwmgr->platform_descriptor.overdriveLimit.memoryClock);
5182     }
5183 
5184     return 0;
5185 }
5186 
5187 static int vega10_notify_cac_buffer_info(struct pp_hwmgr *hwmgr,
5188                     uint32_t virtual_addr_low,
5189                     uint32_t virtual_addr_hi,
5190                     uint32_t mc_addr_low,
5191                     uint32_t mc_addr_hi,
5192                     uint32_t size)
5193 {
5194     smum_send_msg_to_smc_with_parameter(hwmgr,
5195                     PPSMC_MSG_SetSystemVirtualDramAddrHigh,
5196                     virtual_addr_hi,
5197                     NULL);
5198     smum_send_msg_to_smc_with_parameter(hwmgr,
5199                     PPSMC_MSG_SetSystemVirtualDramAddrLow,
5200                     virtual_addr_low,
5201                     NULL);
5202     smum_send_msg_to_smc_with_parameter(hwmgr,
5203                     PPSMC_MSG_DramLogSetDramAddrHigh,
5204                     mc_addr_hi,
5205                     NULL);
5206 
5207     smum_send_msg_to_smc_with_parameter(hwmgr,
5208                     PPSMC_MSG_DramLogSetDramAddrLow,
5209                     mc_addr_low,
5210                     NULL);
5211 
5212     smum_send_msg_to_smc_with_parameter(hwmgr,
5213                     PPSMC_MSG_DramLogSetDramSize,
5214                     size,
5215                     NULL);
5216     return 0;
5217 }
5218 
5219 static int vega10_get_thermal_temperature_range(struct pp_hwmgr *hwmgr,
5220         struct PP_TemperatureRange *thermal_data)
5221 {
5222     struct vega10_hwmgr *data = hwmgr->backend;
5223     PPTable_t *pp_table = &(data->smc_state_table.pp_table);
5224 
5225     memcpy(thermal_data, &SMU7ThermalWithDelayPolicy[0], sizeof(struct PP_TemperatureRange));
5226 
5227     thermal_data->max = pp_table->TedgeLimit *
5228         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
5229     thermal_data->edge_emergency_max = (pp_table->TedgeLimit + CTF_OFFSET_EDGE) *
5230         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
5231     thermal_data->hotspot_crit_max = pp_table->ThotspotLimit *
5232         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
5233     thermal_data->hotspot_emergency_max = (pp_table->ThotspotLimit + CTF_OFFSET_HOTSPOT) *
5234         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
5235     thermal_data->mem_crit_max = pp_table->ThbmLimit *
5236         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
5237     thermal_data->mem_emergency_max = (pp_table->ThbmLimit + CTF_OFFSET_HBM)*
5238         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
5239 
5240     return 0;
5241 }
5242 
5243 static int vega10_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
5244 {
5245     struct vega10_hwmgr *data = hwmgr->backend;
5246     uint32_t i, size = 0;
5247     static const uint8_t profile_mode_setting[6][4] = {{70, 60, 0, 0,},
5248                         {70, 60, 1, 3,},
5249                         {90, 60, 0, 0,},
5250                         {70, 60, 0, 0,},
5251                         {70, 90, 0, 0,},
5252                         {30, 60, 0, 6,},
5253                         };
5254     static const char *title[6] = {"NUM",
5255             "MODE_NAME",
5256             "BUSY_SET_POINT",
5257             "FPS",
5258             "USE_RLC_BUSY",
5259             "MIN_ACTIVE_LEVEL"};
5260 
5261     if (!buf)
5262         return -EINVAL;
5263 
5264     phm_get_sysfs_buf(&buf, &size);
5265 
5266     size += sysfs_emit_at(buf, size, "%s %16s %s %s %s %s\n",title[0],
5267             title[1], title[2], title[3], title[4], title[5]);
5268 
5269     for (i = 0; i < PP_SMC_POWER_PROFILE_CUSTOM; i++)
5270         size += sysfs_emit_at(buf, size, "%3d %14s%s: %14d %3d %10d %14d\n",
5271             i, amdgpu_pp_profile_name[i], (i == hwmgr->power_profile_mode) ? "*" : " ",
5272             profile_mode_setting[i][0], profile_mode_setting[i][1],
5273             profile_mode_setting[i][2], profile_mode_setting[i][3]);
5274 
5275     size += sysfs_emit_at(buf, size, "%3d %14s%s: %14d %3d %10d %14d\n", i,
5276             amdgpu_pp_profile_name[i], (i == hwmgr->power_profile_mode) ? "*" : " ",
5277             data->custom_profile_mode[0], data->custom_profile_mode[1],
5278             data->custom_profile_mode[2], data->custom_profile_mode[3]);
5279     return size;
5280 }
5281 
5282 static bool vega10_get_power_profile_mode_quirks(struct pp_hwmgr *hwmgr)
5283 {
5284     struct amdgpu_device *adev = hwmgr->adev;
5285 
5286     return (adev->pdev->device == 0x6860);
5287 }
5288 
5289 static int vega10_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint32_t size)
5290 {
5291     struct vega10_hwmgr *data = hwmgr->backend;
5292     uint8_t busy_set_point;
5293     uint8_t FPS;
5294     uint8_t use_rlc_busy;
5295     uint8_t min_active_level;
5296     uint32_t power_profile_mode = input[size];
5297 
5298     if (power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
5299         if (size != 0 && size != 4)
5300             return -EINVAL;
5301 
5302         /* If size = 0 and the CUSTOM profile has been set already
5303          * then just apply the profile. The copy stored in the hwmgr
5304          * is zeroed out on init
5305          */
5306         if (size == 0) {
5307             if (data->custom_profile_mode[0] != 0)
5308                 goto out;
5309             else
5310                 return -EINVAL;
5311         }
5312 
5313         data->custom_profile_mode[0] = busy_set_point = input[0];
5314         data->custom_profile_mode[1] = FPS = input[1];
5315         data->custom_profile_mode[2] = use_rlc_busy = input[2];
5316         data->custom_profile_mode[3] = min_active_level = input[3];
5317         smum_send_msg_to_smc_with_parameter(hwmgr,
5318                     PPSMC_MSG_SetCustomGfxDpmParameters,
5319                     busy_set_point | FPS<<8 |
5320                     use_rlc_busy << 16 | min_active_level<<24,
5321                     NULL);
5322     }
5323 
5324 out:
5325     if (vega10_get_power_profile_mode_quirks(hwmgr))
5326         smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetWorkloadMask,
5327                         1 << power_profile_mode,
5328                         NULL);
5329     else
5330         smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetWorkloadMask,
5331                         (!power_profile_mode) ? 0 : 1 << (power_profile_mode - 1),
5332                         NULL);
5333 
5334     hwmgr->power_profile_mode = power_profile_mode;
5335 
5336     return 0;
5337 }
5338 
5339 
5340 static bool vega10_check_clk_voltage_valid(struct pp_hwmgr *hwmgr,
5341                     enum PP_OD_DPM_TABLE_COMMAND type,
5342                     uint32_t clk,
5343                     uint32_t voltage)
5344 {
5345     struct vega10_hwmgr *data = hwmgr->backend;
5346     struct vega10_odn_dpm_table *odn_table = &(data->odn_dpm_table);
5347     struct vega10_single_dpm_table *golden_table;
5348 
5349     if (voltage < odn_table->min_vddc || voltage > odn_table->max_vddc) {
5350         pr_info("OD voltage is out of range [%d - %d] mV\n", odn_table->min_vddc, odn_table->max_vddc);
5351         return false;
5352     }
5353 
5354     if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) {
5355         golden_table = &(data->golden_dpm_table.gfx_table);
5356         if (golden_table->dpm_levels[0].value > clk ||
5357             hwmgr->platform_descriptor.overdriveLimit.engineClock < clk) {
5358             pr_info("OD engine clock is out of range [%d - %d] MHz\n",
5359                 golden_table->dpm_levels[0].value/100,
5360                 hwmgr->platform_descriptor.overdriveLimit.engineClock/100);
5361             return false;
5362         }
5363     } else if (type == PP_OD_EDIT_MCLK_VDDC_TABLE) {
5364         golden_table = &(data->golden_dpm_table.mem_table);
5365         if (golden_table->dpm_levels[0].value > clk ||
5366             hwmgr->platform_descriptor.overdriveLimit.memoryClock < clk) {
5367             pr_info("OD memory clock is out of range [%d - %d] MHz\n",
5368                 golden_table->dpm_levels[0].value/100,
5369                 hwmgr->platform_descriptor.overdriveLimit.memoryClock/100);
5370             return false;
5371         }
5372     } else {
5373         return false;
5374     }
5375 
5376     return true;
5377 }
5378 
5379 static void vega10_odn_update_power_state(struct pp_hwmgr *hwmgr)
5380 {
5381     struct vega10_hwmgr *data = hwmgr->backend;
5382     struct pp_power_state *ps = hwmgr->request_ps;
5383     struct vega10_power_state *vega10_ps;
5384     struct vega10_single_dpm_table *gfx_dpm_table =
5385         &data->dpm_table.gfx_table;
5386     struct vega10_single_dpm_table *soc_dpm_table =
5387         &data->dpm_table.soc_table;
5388     struct vega10_single_dpm_table *mem_dpm_table =
5389         &data->dpm_table.mem_table;
5390     int max_level;
5391 
5392     if (!ps)
5393         return;
5394 
5395     vega10_ps = cast_phw_vega10_power_state(&ps->hardware);
5396     max_level = vega10_ps->performance_level_count - 1;
5397 
5398     if (vega10_ps->performance_levels[max_level].gfx_clock !=
5399         gfx_dpm_table->dpm_levels[gfx_dpm_table->count - 1].value)
5400         vega10_ps->performance_levels[max_level].gfx_clock =
5401             gfx_dpm_table->dpm_levels[gfx_dpm_table->count - 1].value;
5402 
5403     if (vega10_ps->performance_levels[max_level].soc_clock !=
5404         soc_dpm_table->dpm_levels[soc_dpm_table->count - 1].value)
5405         vega10_ps->performance_levels[max_level].soc_clock =
5406             soc_dpm_table->dpm_levels[soc_dpm_table->count - 1].value;
5407 
5408     if (vega10_ps->performance_levels[max_level].mem_clock !=
5409         mem_dpm_table->dpm_levels[mem_dpm_table->count - 1].value)
5410         vega10_ps->performance_levels[max_level].mem_clock =
5411             mem_dpm_table->dpm_levels[mem_dpm_table->count - 1].value;
5412 
5413     if (!hwmgr->ps)
5414         return;
5415 
5416     ps = (struct pp_power_state *)((unsigned long)(hwmgr->ps) + hwmgr->ps_size * (hwmgr->num_ps - 1));
5417     vega10_ps = cast_phw_vega10_power_state(&ps->hardware);
5418     max_level = vega10_ps->performance_level_count - 1;
5419 
5420     if (vega10_ps->performance_levels[max_level].gfx_clock !=
5421         gfx_dpm_table->dpm_levels[gfx_dpm_table->count - 1].value)
5422         vega10_ps->performance_levels[max_level].gfx_clock =
5423             gfx_dpm_table->dpm_levels[gfx_dpm_table->count - 1].value;
5424 
5425     if (vega10_ps->performance_levels[max_level].soc_clock !=
5426         soc_dpm_table->dpm_levels[soc_dpm_table->count - 1].value)
5427         vega10_ps->performance_levels[max_level].soc_clock =
5428             soc_dpm_table->dpm_levels[soc_dpm_table->count - 1].value;
5429 
5430     if (vega10_ps->performance_levels[max_level].mem_clock !=
5431         mem_dpm_table->dpm_levels[mem_dpm_table->count - 1].value)
5432         vega10_ps->performance_levels[max_level].mem_clock =
5433             mem_dpm_table->dpm_levels[mem_dpm_table->count - 1].value;
5434 }
5435 
5436 static void vega10_odn_update_soc_table(struct pp_hwmgr *hwmgr,
5437                         enum PP_OD_DPM_TABLE_COMMAND type)
5438 {
5439     struct vega10_hwmgr *data = hwmgr->backend;
5440     struct phm_ppt_v2_information *table_info = hwmgr->pptable;
5441     struct phm_ppt_v1_clock_voltage_dependency_table *dep_table = table_info->vdd_dep_on_socclk;
5442     struct vega10_single_dpm_table *dpm_table = &data->golden_dpm_table.mem_table;
5443 
5444     struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep_on_socclk =
5445                             &data->odn_dpm_table.vdd_dep_on_socclk;
5446     struct vega10_odn_vddc_lookup_table *od_vddc_lookup_table = &data->odn_dpm_table.vddc_lookup_table;
5447 
5448     struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep;
5449     uint8_t i, j;
5450 
5451     if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) {
5452         podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_sclk;
5453         for (i = 0; i < podn_vdd_dep->count; i++)
5454             od_vddc_lookup_table->entries[i].us_vdd = podn_vdd_dep->entries[i].vddc;
5455     } else if (type == PP_OD_EDIT_MCLK_VDDC_TABLE) {
5456         podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_mclk;
5457         for (i = 0; i < dpm_table->count; i++) {
5458             for (j = 0; j < od_vddc_lookup_table->count; j++) {
5459                 if (od_vddc_lookup_table->entries[j].us_vdd >
5460                     podn_vdd_dep->entries[i].vddc)
5461                     break;
5462             }
5463             if (j == od_vddc_lookup_table->count) {
5464                 j = od_vddc_lookup_table->count - 1;
5465                 od_vddc_lookup_table->entries[j].us_vdd =
5466                     podn_vdd_dep->entries[i].vddc;
5467                 data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_VDDC;
5468             }
5469             podn_vdd_dep->entries[i].vddInd = j;
5470         }
5471         dpm_table = &data->dpm_table.soc_table;
5472         for (i = 0; i < dep_table->count; i++) {
5473             if (dep_table->entries[i].vddInd == podn_vdd_dep->entries[podn_vdd_dep->count-1].vddInd &&
5474                     dep_table->entries[i].clk < podn_vdd_dep->entries[podn_vdd_dep->count-1].clk) {
5475                 data->need_update_dpm_table |= DPMTABLE_UPDATE_SOCCLK;
5476                 for (; (i < dep_table->count) &&
5477                        (dep_table->entries[i].clk < podn_vdd_dep->entries[podn_vdd_dep->count - 1].clk); i++) {
5478                     podn_vdd_dep_on_socclk->entries[i].clk = podn_vdd_dep->entries[podn_vdd_dep->count-1].clk;
5479                     dpm_table->dpm_levels[i].value = podn_vdd_dep_on_socclk->entries[i].clk;
5480                 }
5481                 break;
5482             } else {
5483                 dpm_table->dpm_levels[i].value = dep_table->entries[i].clk;
5484                 podn_vdd_dep_on_socclk->entries[i].vddc = dep_table->entries[i].vddc;
5485                 podn_vdd_dep_on_socclk->entries[i].vddInd = dep_table->entries[i].vddInd;
5486                 podn_vdd_dep_on_socclk->entries[i].clk = dep_table->entries[i].clk;
5487             }
5488         }
5489         if (podn_vdd_dep_on_socclk->entries[podn_vdd_dep_on_socclk->count - 1].clk <
5490                     podn_vdd_dep->entries[podn_vdd_dep->count - 1].clk) {
5491             data->need_update_dpm_table |= DPMTABLE_UPDATE_SOCCLK;
5492             podn_vdd_dep_on_socclk->entries[podn_vdd_dep_on_socclk->count - 1].clk =
5493                 podn_vdd_dep->entries[podn_vdd_dep->count - 1].clk;
5494             dpm_table->dpm_levels[podn_vdd_dep_on_socclk->count - 1].value =
5495                 podn_vdd_dep->entries[podn_vdd_dep->count - 1].clk;
5496         }
5497         if (podn_vdd_dep_on_socclk->entries[podn_vdd_dep_on_socclk->count - 1].vddInd <
5498                     podn_vdd_dep->entries[podn_vdd_dep->count - 1].vddInd) {
5499             data->need_update_dpm_table |= DPMTABLE_UPDATE_SOCCLK;
5500             podn_vdd_dep_on_socclk->entries[podn_vdd_dep_on_socclk->count - 1].vddInd =
5501                 podn_vdd_dep->entries[podn_vdd_dep->count - 1].vddInd;
5502         }
5503     }
5504     vega10_odn_update_power_state(hwmgr);
5505 }
5506 
5507 static int vega10_odn_edit_dpm_table(struct pp_hwmgr *hwmgr,
5508                     enum PP_OD_DPM_TABLE_COMMAND type,
5509                     long *input, uint32_t size)
5510 {
5511     struct vega10_hwmgr *data = hwmgr->backend;
5512     struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep_table;
5513     struct vega10_single_dpm_table *dpm_table;
5514 
5515     uint32_t input_clk;
5516     uint32_t input_vol;
5517     uint32_t input_level;
5518     uint32_t i;
5519 
5520     PP_ASSERT_WITH_CODE(input, "NULL user input for clock and voltage",
5521                 return -EINVAL);
5522 
5523     if (!hwmgr->od_enabled) {
5524         pr_info("OverDrive feature not enabled\n");
5525         return -EINVAL;
5526     }
5527 
5528     if (PP_OD_EDIT_SCLK_VDDC_TABLE == type) {
5529         dpm_table = &data->dpm_table.gfx_table;
5530         podn_vdd_dep_table = &data->odn_dpm_table.vdd_dep_on_sclk;
5531         data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
5532     } else if (PP_OD_EDIT_MCLK_VDDC_TABLE == type) {
5533         dpm_table = &data->dpm_table.mem_table;
5534         podn_vdd_dep_table = &data->odn_dpm_table.vdd_dep_on_mclk;
5535         data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
5536     } else if (PP_OD_RESTORE_DEFAULT_TABLE == type) {
5537         memcpy(&(data->dpm_table), &(data->golden_dpm_table), sizeof(struct vega10_dpm_table));
5538         vega10_odn_initial_default_setting(hwmgr);
5539         vega10_odn_update_power_state(hwmgr);
5540         /* force to update all clock tables */
5541         data->need_update_dpm_table = DPMTABLE_UPDATE_SCLK |
5542                           DPMTABLE_UPDATE_MCLK |
5543                           DPMTABLE_UPDATE_SOCCLK;
5544         return 0;
5545     } else if (PP_OD_COMMIT_DPM_TABLE == type) {
5546         vega10_check_dpm_table_updated(hwmgr);
5547         return 0;
5548     } else {
5549         return -EINVAL;
5550     }
5551 
5552     for (i = 0; i < size; i += 3) {
5553         if (i + 3 > size || input[i] >= podn_vdd_dep_table->count) {
5554             pr_info("invalid clock voltage input\n");
5555             return 0;
5556         }
5557         input_level = input[i];
5558         input_clk = input[i+1] * 100;
5559         input_vol = input[i+2];
5560 
5561         if (vega10_check_clk_voltage_valid(hwmgr, type, input_clk, input_vol)) {
5562             dpm_table->dpm_levels[input_level].value = input_clk;
5563             podn_vdd_dep_table->entries[input_level].clk = input_clk;
5564             podn_vdd_dep_table->entries[input_level].vddc = input_vol;
5565         } else {
5566             return -EINVAL;
5567         }
5568     }
5569     vega10_odn_update_soc_table(hwmgr, type);
5570     return 0;
5571 }
5572 
5573 static int vega10_set_mp1_state(struct pp_hwmgr *hwmgr,
5574                 enum pp_mp1_state mp1_state)
5575 {
5576     uint16_t msg;
5577     int ret;
5578 
5579     switch (mp1_state) {
5580     case PP_MP1_STATE_UNLOAD:
5581         msg = PPSMC_MSG_PrepareMp1ForUnload;
5582         break;
5583     case PP_MP1_STATE_SHUTDOWN:
5584     case PP_MP1_STATE_RESET:
5585     case PP_MP1_STATE_NONE:
5586     default:
5587         return 0;
5588     }
5589 
5590     PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr, msg, NULL)) == 0,
5591                 "[PrepareMp1] Failed!",
5592                 return ret);
5593 
5594     return 0;
5595 }
5596 
5597 static int vega10_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state,
5598                 PHM_PerformanceLevelDesignation designation, uint32_t index,
5599                 PHM_PerformanceLevel *level)
5600 {
5601     const struct vega10_power_state *vega10_ps;
5602     uint32_t i;
5603 
5604     if (level == NULL || hwmgr == NULL || state == NULL)
5605         return -EINVAL;
5606 
5607     vega10_ps = cast_const_phw_vega10_power_state(state);
5608 
5609     i = index > vega10_ps->performance_level_count - 1 ?
5610             vega10_ps->performance_level_count - 1 : index;
5611 
5612     level->coreClock = vega10_ps->performance_levels[i].gfx_clock;
5613     level->memory_clock = vega10_ps->performance_levels[i].mem_clock;
5614 
5615     return 0;
5616 }
5617 
5618 static int vega10_disable_power_features_for_compute_performance(struct pp_hwmgr *hwmgr, bool disable)
5619 {
5620     struct vega10_hwmgr *data = hwmgr->backend;
5621     uint32_t feature_mask = 0;
5622 
5623     if (disable) {
5624         feature_mask |= data->smu_features[GNLD_ULV].enabled ?
5625             data->smu_features[GNLD_ULV].smu_feature_bitmap : 0;
5626         feature_mask |= data->smu_features[GNLD_DS_GFXCLK].enabled ?
5627             data->smu_features[GNLD_DS_GFXCLK].smu_feature_bitmap : 0;
5628         feature_mask |= data->smu_features[GNLD_DS_SOCCLK].enabled ?
5629             data->smu_features[GNLD_DS_SOCCLK].smu_feature_bitmap : 0;
5630         feature_mask |= data->smu_features[GNLD_DS_LCLK].enabled ?
5631             data->smu_features[GNLD_DS_LCLK].smu_feature_bitmap : 0;
5632         feature_mask |= data->smu_features[GNLD_DS_DCEFCLK].enabled ?
5633             data->smu_features[GNLD_DS_DCEFCLK].smu_feature_bitmap : 0;
5634     } else {
5635         feature_mask |= (!data->smu_features[GNLD_ULV].enabled) ?
5636             data->smu_features[GNLD_ULV].smu_feature_bitmap : 0;
5637         feature_mask |= (!data->smu_features[GNLD_DS_GFXCLK].enabled) ?
5638             data->smu_features[GNLD_DS_GFXCLK].smu_feature_bitmap : 0;
5639         feature_mask |= (!data->smu_features[GNLD_DS_SOCCLK].enabled) ?
5640             data->smu_features[GNLD_DS_SOCCLK].smu_feature_bitmap : 0;
5641         feature_mask |= (!data->smu_features[GNLD_DS_LCLK].enabled) ?
5642             data->smu_features[GNLD_DS_LCLK].smu_feature_bitmap : 0;
5643         feature_mask |= (!data->smu_features[GNLD_DS_DCEFCLK].enabled) ?
5644             data->smu_features[GNLD_DS_DCEFCLK].smu_feature_bitmap : 0;
5645     }
5646 
5647     if (feature_mask)
5648         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr,
5649                 !disable, feature_mask),
5650                 "enable/disable power features for compute performance Failed!",
5651                 return -EINVAL);
5652 
5653     if (disable) {
5654         data->smu_features[GNLD_ULV].enabled = false;
5655         data->smu_features[GNLD_DS_GFXCLK].enabled = false;
5656         data->smu_features[GNLD_DS_SOCCLK].enabled = false;
5657         data->smu_features[GNLD_DS_LCLK].enabled = false;
5658         data->smu_features[GNLD_DS_DCEFCLK].enabled = false;
5659     } else {
5660         data->smu_features[GNLD_ULV].enabled = true;
5661         data->smu_features[GNLD_DS_GFXCLK].enabled = true;
5662         data->smu_features[GNLD_DS_SOCCLK].enabled = true;
5663         data->smu_features[GNLD_DS_LCLK].enabled = true;
5664         data->smu_features[GNLD_DS_DCEFCLK].enabled = true;
5665     }
5666 
5667     return 0;
5668 
5669 }
5670 
5671 static const struct pp_hwmgr_func vega10_hwmgr_funcs = {
5672     .backend_init = vega10_hwmgr_backend_init,
5673     .backend_fini = vega10_hwmgr_backend_fini,
5674     .asic_setup = vega10_setup_asic_task,
5675     .dynamic_state_management_enable = vega10_enable_dpm_tasks,
5676     .dynamic_state_management_disable = vega10_disable_dpm_tasks,
5677     .get_num_of_pp_table_entries =
5678             vega10_get_number_of_powerplay_table_entries,
5679     .get_power_state_size = vega10_get_power_state_size,
5680     .get_pp_table_entry = vega10_get_pp_table_entry,
5681     .patch_boot_state = vega10_patch_boot_state,
5682     .apply_state_adjust_rules = vega10_apply_state_adjust_rules,
5683     .power_state_set = vega10_set_power_state_tasks,
5684     .get_sclk = vega10_dpm_get_sclk,
5685     .get_mclk = vega10_dpm_get_mclk,
5686     .notify_smc_display_config_after_ps_adjustment =
5687             vega10_notify_smc_display_config_after_ps_adjustment,
5688     .force_dpm_level = vega10_dpm_force_dpm_level,
5689     .stop_thermal_controller = vega10_thermal_stop_thermal_controller,
5690     .get_fan_speed_info = vega10_fan_ctrl_get_fan_speed_info,
5691     .get_fan_speed_pwm = vega10_fan_ctrl_get_fan_speed_pwm,
5692     .set_fan_speed_pwm = vega10_fan_ctrl_set_fan_speed_pwm,
5693     .reset_fan_speed_to_default =
5694             vega10_fan_ctrl_reset_fan_speed_to_default,
5695     .get_fan_speed_rpm = vega10_fan_ctrl_get_fan_speed_rpm,
5696     .set_fan_speed_rpm = vega10_fan_ctrl_set_fan_speed_rpm,
5697     .uninitialize_thermal_controller =
5698             vega10_thermal_ctrl_uninitialize_thermal_controller,
5699     .set_fan_control_mode = vega10_set_fan_control_mode,
5700     .get_fan_control_mode = vega10_get_fan_control_mode,
5701     .read_sensor = vega10_read_sensor,
5702     .get_dal_power_level = vega10_get_dal_power_level,
5703     .get_clock_by_type_with_latency = vega10_get_clock_by_type_with_latency,
5704     .get_clock_by_type_with_voltage = vega10_get_clock_by_type_with_voltage,
5705     .set_watermarks_for_clocks_ranges = vega10_set_watermarks_for_clocks_ranges,
5706     .display_clock_voltage_request = vega10_display_clock_voltage_request,
5707     .force_clock_level = vega10_force_clock_level,
5708     .emit_clock_levels = vega10_emit_clock_levels,
5709     .print_clock_levels = vega10_print_clock_levels,
5710     .display_config_changed = vega10_display_configuration_changed_task,
5711     .powergate_uvd = vega10_power_gate_uvd,
5712     .powergate_vce = vega10_power_gate_vce,
5713     .check_states_equal = vega10_check_states_equal,
5714     .check_smc_update_required_for_display_configuration =
5715             vega10_check_smc_update_required_for_display_configuration,
5716     .power_off_asic = vega10_power_off_asic,
5717     .disable_smc_firmware_ctf = vega10_thermal_disable_alert,
5718     .get_sclk_od = vega10_get_sclk_od,
5719     .set_sclk_od = vega10_set_sclk_od,
5720     .get_mclk_od = vega10_get_mclk_od,
5721     .set_mclk_od = vega10_set_mclk_od,
5722     .avfs_control = vega10_avfs_enable,
5723     .notify_cac_buffer_info = vega10_notify_cac_buffer_info,
5724     .get_thermal_temperature_range = vega10_get_thermal_temperature_range,
5725     .register_irq_handlers = smu9_register_irq_handlers,
5726     .start_thermal_controller = vega10_start_thermal_controller,
5727     .get_power_profile_mode = vega10_get_power_profile_mode,
5728     .set_power_profile_mode = vega10_set_power_profile_mode,
5729     .set_power_limit = vega10_set_power_limit,
5730     .odn_edit_dpm_table = vega10_odn_edit_dpm_table,
5731     .get_performance_level = vega10_get_performance_level,
5732     .get_asic_baco_capability = smu9_baco_get_capability,
5733     .get_asic_baco_state = smu9_baco_get_state,
5734     .set_asic_baco_state = vega10_baco_set_state,
5735     .enable_mgpu_fan_boost = vega10_enable_mgpu_fan_boost,
5736     .get_ppfeature_status = vega10_get_ppfeature_status,
5737     .set_ppfeature_status = vega10_set_ppfeature_status,
5738     .set_mp1_state = vega10_set_mp1_state,
5739     .disable_power_features_for_compute_performance =
5740             vega10_disable_power_features_for_compute_performance,
5741 };
5742 
5743 int vega10_hwmgr_init(struct pp_hwmgr *hwmgr)
5744 {
5745     struct amdgpu_device *adev = hwmgr->adev;
5746 
5747     hwmgr->hwmgr_func = &vega10_hwmgr_funcs;
5748     hwmgr->pptable_func = &vega10_pptable_funcs;
5749     if (amdgpu_passthrough(adev))
5750         return vega10_baco_set_cap(hwmgr);
5751 
5752     return 0;
5753 }