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