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