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