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