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