]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu
[linux.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_gfx_clk_freq(struct pp_hwmgr *hwmgr, uint32_t *gfx_freq)
1879 {
1880         uint32_t gfx_clk = 0;
1881         int ret = 0;
1882
1883         *gfx_freq = 0;
1884
1885         PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1886                         PPSMC_MSG_GetDpmClockFreq, (PPCLK_GFXCLK << 16))) == 0,
1887                         "[GetCurrentGfxClkFreq] Attempt to get Current GFXCLK Frequency Failed!",
1888                         return ret);
1889         gfx_clk = smum_get_argument(hwmgr);
1890
1891         *gfx_freq = gfx_clk * 100;
1892
1893         return 0;
1894 }
1895
1896 static int vega20_get_current_mclk_freq(struct pp_hwmgr *hwmgr, uint32_t *mclk_freq)
1897 {
1898         uint32_t mem_clk = 0;
1899         int ret = 0;
1900
1901         *mclk_freq = 0;
1902
1903         PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
1904                         PPSMC_MSG_GetDpmClockFreq, (PPCLK_UCLK << 16))) == 0,
1905                         "[GetCurrentMClkFreq] Attempt to get Current MCLK Frequency Failed!",
1906                         return ret);
1907         mem_clk = smum_get_argument(hwmgr);
1908
1909         *mclk_freq = mem_clk * 100;
1910
1911         return 0;
1912 }
1913
1914 static int vega20_get_current_activity_percent(struct pp_hwmgr *hwmgr,
1915                 uint32_t *activity_percent)
1916 {
1917         int ret = 0;
1918         SmuMetrics_t metrics_table;
1919
1920         ret = smum_smc_table_manager(hwmgr, (uint8_t *)&metrics_table, TABLE_SMU_METRICS, true);
1921         PP_ASSERT_WITH_CODE(!ret,
1922                         "Failed to export SMU METRICS table!",
1923                         return ret);
1924
1925         *activity_percent = metrics_table.AverageGfxActivity;
1926
1927         return ret;
1928 }
1929
1930 static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx,
1931                               void *value, int *size)
1932 {
1933         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1934         struct amdgpu_device *adev = hwmgr->adev;
1935         uint32_t val_vid;
1936         int ret = 0;
1937
1938         switch (idx) {
1939         case AMDGPU_PP_SENSOR_GFX_SCLK:
1940                 ret = vega20_get_current_gfx_clk_freq(hwmgr, (uint32_t *)value);
1941                 if (!ret)
1942                         *size = 4;
1943                 break;
1944         case AMDGPU_PP_SENSOR_GFX_MCLK:
1945                 ret = vega20_get_current_mclk_freq(hwmgr, (uint32_t *)value);
1946                 if (!ret)
1947                         *size = 4;
1948                 break;
1949         case AMDGPU_PP_SENSOR_GPU_LOAD:
1950                 ret = vega20_get_current_activity_percent(hwmgr, (uint32_t *)value);
1951                 if (!ret)
1952                         *size = 4;
1953                 break;
1954         case AMDGPU_PP_SENSOR_GPU_TEMP:
1955                 *((uint32_t *)value) = vega20_thermal_get_temperature(hwmgr);
1956                 *size = 4;
1957                 break;
1958         case AMDGPU_PP_SENSOR_UVD_POWER:
1959                 *((uint32_t *)value) = data->uvd_power_gated ? 0 : 1;
1960                 *size = 4;
1961                 break;
1962         case AMDGPU_PP_SENSOR_VCE_POWER:
1963                 *((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
1964                 *size = 4;
1965                 break;
1966         case AMDGPU_PP_SENSOR_GPU_POWER:
1967                 *size = 16;
1968                 ret = vega20_get_gpu_power(hwmgr, (uint32_t *)value);
1969                 break;
1970         case AMDGPU_PP_SENSOR_VDDGFX:
1971                 val_vid = (RREG32_SOC15(SMUIO, 0, mmSMUSVI0_TEL_PLANE0) &
1972                         SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR_MASK) >>
1973                         SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR__SHIFT;
1974                 *((uint32_t *)value) =
1975                         (uint32_t)convert_to_vddc((uint8_t)val_vid);
1976                 break;
1977         case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK:
1978                 ret = vega20_get_enabled_smc_features(hwmgr, (uint64_t *)value);
1979                 if (!ret)
1980                         *size = 8;
1981                 break;
1982         default:
1983                 ret = -EINVAL;
1984                 break;
1985         }
1986         return ret;
1987 }
1988
1989 static int vega20_notify_smc_display_change(struct pp_hwmgr *hwmgr,
1990                 bool has_disp)
1991 {
1992         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
1993
1994         if (data->smu_features[GNLD_DPM_UCLK].enabled)
1995                 return smum_send_msg_to_smc_with_parameter(hwmgr,
1996                         PPSMC_MSG_SetUclkFastSwitch,
1997                         has_disp ? 1 : 0);
1998
1999         return 0;
2000 }
2001
2002 int vega20_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
2003                 struct pp_display_clock_request *clock_req)
2004 {
2005         int result = 0;
2006         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2007         enum amd_pp_clock_type clk_type = clock_req->clock_type;
2008         uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
2009         PPCLK_e clk_select = 0;
2010         uint32_t clk_request = 0;
2011
2012         if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) {
2013                 switch (clk_type) {
2014                 case amd_pp_dcef_clock:
2015                         clk_freq = clock_req->clock_freq_in_khz / 100;
2016                         clk_select = PPCLK_DCEFCLK;
2017                         break;
2018                 case amd_pp_disp_clock:
2019                         clk_select = PPCLK_DISPCLK;
2020                         break;
2021                 case amd_pp_pixel_clock:
2022                         clk_select = PPCLK_PIXCLK;
2023                         break;
2024                 case amd_pp_phy_clock:
2025                         clk_select = PPCLK_PHYCLK;
2026                         break;
2027                 default:
2028                         pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!");
2029                         result = -EINVAL;
2030                         break;
2031                 }
2032
2033                 if (!result) {
2034                         clk_request = (clk_select << 16) | clk_freq;
2035                         result = smum_send_msg_to_smc_with_parameter(hwmgr,
2036                                         PPSMC_MSG_SetHardMinByFreq,
2037                                         clk_request);
2038                 }
2039         }
2040
2041         return result;
2042 }
2043
2044 static int vega20_notify_smc_display_config_after_ps_adjustment(
2045                 struct pp_hwmgr *hwmgr)
2046 {
2047         struct vega20_hwmgr *data =
2048                         (struct vega20_hwmgr *)(hwmgr->backend);
2049         struct PP_Clocks min_clocks = {0};
2050         struct pp_display_clock_request clock_req;
2051         int ret = 0;
2052
2053         if ((hwmgr->display_config->num_display > 1) &&
2054              !hwmgr->display_config->multi_monitor_in_sync &&
2055              !hwmgr->display_config->nb_pstate_switch_disable)
2056                 vega20_notify_smc_display_change(hwmgr, false);
2057         else
2058                 vega20_notify_smc_display_change(hwmgr, true);
2059
2060         min_clocks.dcefClock = hwmgr->display_config->min_dcef_set_clk;
2061         min_clocks.dcefClockInSR = hwmgr->display_config->min_dcef_deep_sleep_set_clk;
2062         min_clocks.memoryClock = hwmgr->display_config->min_mem_set_clock;
2063
2064         if (data->smu_features[GNLD_DPM_DCEFCLK].supported) {
2065                 clock_req.clock_type = amd_pp_dcef_clock;
2066                 clock_req.clock_freq_in_khz = min_clocks.dcefClock;
2067                 if (!vega20_display_clock_voltage_request(hwmgr, &clock_req)) {
2068                         if (data->smu_features[GNLD_DS_DCEFCLK].supported)
2069                                 PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(
2070                                         hwmgr, PPSMC_MSG_SetMinDeepSleepDcefclk,
2071                                         min_clocks.dcefClockInSR / 100)) == 0,
2072                                         "Attempt to set divider for DCEFCLK Failed!",
2073                                         return ret);
2074                 } else {
2075                         pr_info("Attempt to set Hard Min for DCEFCLK Failed!");
2076                 }
2077         }
2078
2079         return 0;
2080 }
2081
2082 static int vega20_force_dpm_highest(struct pp_hwmgr *hwmgr)
2083 {
2084         struct vega20_hwmgr *data =
2085                         (struct vega20_hwmgr *)(hwmgr->backend);
2086         uint32_t soft_level;
2087         int ret = 0;
2088
2089         soft_level = vega20_find_highest_dpm_level(&(data->dpm_table.gfx_table));
2090
2091         data->dpm_table.gfx_table.dpm_state.soft_min_level =
2092                 data->dpm_table.gfx_table.dpm_state.soft_max_level =
2093                 data->dpm_table.gfx_table.dpm_levels[soft_level].value;
2094
2095         soft_level = vega20_find_highest_dpm_level(&(data->dpm_table.mem_table));
2096
2097         data->dpm_table.mem_table.dpm_state.soft_min_level =
2098                 data->dpm_table.mem_table.dpm_state.soft_max_level =
2099                 data->dpm_table.mem_table.dpm_levels[soft_level].value;
2100
2101         ret = vega20_upload_dpm_min_level(hwmgr);
2102         PP_ASSERT_WITH_CODE(!ret,
2103                         "Failed to upload boot level to highest!",
2104                         return ret);
2105
2106         ret = vega20_upload_dpm_max_level(hwmgr);
2107         PP_ASSERT_WITH_CODE(!ret,
2108                         "Failed to upload dpm max level to highest!",
2109                         return ret);
2110
2111         return 0;
2112 }
2113
2114 static int vega20_force_dpm_lowest(struct pp_hwmgr *hwmgr)
2115 {
2116         struct vega20_hwmgr *data =
2117                         (struct vega20_hwmgr *)(hwmgr->backend);
2118         uint32_t soft_level;
2119         int ret = 0;
2120
2121         soft_level = vega20_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
2122
2123         data->dpm_table.gfx_table.dpm_state.soft_min_level =
2124                 data->dpm_table.gfx_table.dpm_state.soft_max_level =
2125                 data->dpm_table.gfx_table.dpm_levels[soft_level].value;
2126
2127         soft_level = vega20_find_lowest_dpm_level(&(data->dpm_table.mem_table));
2128
2129         data->dpm_table.mem_table.dpm_state.soft_min_level =
2130                 data->dpm_table.mem_table.dpm_state.soft_max_level =
2131                 data->dpm_table.mem_table.dpm_levels[soft_level].value;
2132
2133         ret = vega20_upload_dpm_min_level(hwmgr);
2134         PP_ASSERT_WITH_CODE(!ret,
2135                         "Failed to upload boot level to highest!",
2136                         return ret);
2137
2138         ret = vega20_upload_dpm_max_level(hwmgr);
2139         PP_ASSERT_WITH_CODE(!ret,
2140                         "Failed to upload dpm max level to highest!",
2141                         return ret);
2142
2143         return 0;
2144
2145 }
2146
2147 static int vega20_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
2148 {
2149         int ret = 0;
2150
2151         ret = vega20_upload_dpm_min_level(hwmgr);
2152         PP_ASSERT_WITH_CODE(!ret,
2153                         "Failed to upload DPM Bootup Levels!",
2154                         return ret);
2155
2156         ret = vega20_upload_dpm_max_level(hwmgr);
2157         PP_ASSERT_WITH_CODE(!ret,
2158                         "Failed to upload DPM Max Levels!",
2159                         return ret);
2160
2161         return 0;
2162 }
2163
2164 static int vega20_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level,
2165                                 uint32_t *sclk_mask, uint32_t *mclk_mask, uint32_t *soc_mask)
2166 {
2167         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2168         struct vega20_single_dpm_table *gfx_dpm_table = &(data->dpm_table.gfx_table);
2169         struct vega20_single_dpm_table *mem_dpm_table = &(data->dpm_table.mem_table);
2170         struct vega20_single_dpm_table *soc_dpm_table = &(data->dpm_table.soc_table);
2171
2172         *sclk_mask = 0;
2173         *mclk_mask = 0;
2174         *soc_mask  = 0;
2175
2176         if (gfx_dpm_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
2177             mem_dpm_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL &&
2178             soc_dpm_table->count > VEGA20_UMD_PSTATE_SOCCLK_LEVEL) {
2179                 *sclk_mask = VEGA20_UMD_PSTATE_GFXCLK_LEVEL;
2180                 *mclk_mask = VEGA20_UMD_PSTATE_MCLK_LEVEL;
2181                 *soc_mask  = VEGA20_UMD_PSTATE_SOCCLK_LEVEL;
2182         }
2183
2184         if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
2185                 *sclk_mask = 0;
2186         } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
2187                 *mclk_mask = 0;
2188         } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2189                 *sclk_mask = gfx_dpm_table->count - 1;
2190                 *mclk_mask = mem_dpm_table->count - 1;
2191                 *soc_mask  = soc_dpm_table->count - 1;
2192         }
2193
2194         return 0;
2195 }
2196
2197 static int vega20_force_clock_level(struct pp_hwmgr *hwmgr,
2198                 enum pp_clock_type type, uint32_t mask)
2199 {
2200         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2201         uint32_t soft_min_level, soft_max_level;
2202         int ret = 0;
2203
2204         switch (type) {
2205         case PP_SCLK:
2206                 soft_min_level = mask ? (ffs(mask) - 1) : 0;
2207                 soft_max_level = mask ? (fls(mask) - 1) : 0;
2208
2209                 data->dpm_table.gfx_table.dpm_state.soft_min_level =
2210                         data->dpm_table.gfx_table.dpm_levels[soft_min_level].value;
2211                 data->dpm_table.gfx_table.dpm_state.soft_max_level =
2212                         data->dpm_table.gfx_table.dpm_levels[soft_max_level].value;
2213
2214                 ret = vega20_upload_dpm_min_level(hwmgr);
2215                 PP_ASSERT_WITH_CODE(!ret,
2216                         "Failed to upload boot level to lowest!",
2217                         return ret);
2218
2219                 ret = vega20_upload_dpm_max_level(hwmgr);
2220                 PP_ASSERT_WITH_CODE(!ret,
2221                         "Failed to upload dpm max level to highest!",
2222                         return ret);
2223                 break;
2224
2225         case PP_MCLK:
2226                 soft_min_level = mask ? (ffs(mask) - 1) : 0;
2227                 soft_max_level = mask ? (fls(mask) - 1) : 0;
2228
2229                 data->dpm_table.mem_table.dpm_state.soft_min_level =
2230                         data->dpm_table.mem_table.dpm_levels[soft_min_level].value;
2231                 data->dpm_table.mem_table.dpm_state.soft_max_level =
2232                         data->dpm_table.mem_table.dpm_levels[soft_max_level].value;
2233
2234                 ret = vega20_upload_dpm_min_level(hwmgr);
2235                 PP_ASSERT_WITH_CODE(!ret,
2236                         "Failed to upload boot level to lowest!",
2237                         return ret);
2238
2239                 ret = vega20_upload_dpm_max_level(hwmgr);
2240                 PP_ASSERT_WITH_CODE(!ret,
2241                         "Failed to upload dpm max level to highest!",
2242                         return ret);
2243
2244                 break;
2245
2246         case PP_PCIE:
2247                 break;
2248
2249         default:
2250                 break;
2251         }
2252
2253         return 0;
2254 }
2255
2256 static int vega20_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
2257                                 enum amd_dpm_forced_level level)
2258 {
2259         int ret = 0;
2260         uint32_t sclk_mask, mclk_mask, soc_mask;
2261
2262         switch (level) {
2263         case AMD_DPM_FORCED_LEVEL_HIGH:
2264                 ret = vega20_force_dpm_highest(hwmgr);
2265                 break;
2266
2267         case AMD_DPM_FORCED_LEVEL_LOW:
2268                 ret = vega20_force_dpm_lowest(hwmgr);
2269                 break;
2270
2271         case AMD_DPM_FORCED_LEVEL_AUTO:
2272                 ret = vega20_unforce_dpm_levels(hwmgr);
2273                 break;
2274
2275         case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
2276         case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
2277         case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
2278         case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
2279                 ret = vega20_get_profiling_clk_mask(hwmgr, level, &sclk_mask, &mclk_mask, &soc_mask);
2280                 if (ret)
2281                         return ret;
2282                 vega20_force_clock_level(hwmgr, PP_SCLK, 1 << sclk_mask);
2283                 vega20_force_clock_level(hwmgr, PP_MCLK, 1 << mclk_mask);
2284                 break;
2285
2286         case AMD_DPM_FORCED_LEVEL_MANUAL:
2287         case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
2288         default:
2289                 break;
2290         }
2291
2292         return ret;
2293 }
2294
2295 static uint32_t vega20_get_fan_control_mode(struct pp_hwmgr *hwmgr)
2296 {
2297         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2298
2299         if (data->smu_features[GNLD_FAN_CONTROL].enabled == false)
2300                 return AMD_FAN_CTRL_MANUAL;
2301         else
2302                 return AMD_FAN_CTRL_AUTO;
2303 }
2304
2305 static void vega20_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
2306 {
2307         switch (mode) {
2308         case AMD_FAN_CTRL_NONE:
2309                 vega20_fan_ctrl_set_fan_speed_percent(hwmgr, 100);
2310                 break;
2311         case AMD_FAN_CTRL_MANUAL:
2312                 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
2313                         vega20_fan_ctrl_stop_smc_fan_control(hwmgr);
2314                 break;
2315         case AMD_FAN_CTRL_AUTO:
2316                 if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
2317                         vega20_fan_ctrl_start_smc_fan_control(hwmgr);
2318                 break;
2319         default:
2320                 break;
2321         }
2322 }
2323
2324 static int vega20_get_dal_power_level(struct pp_hwmgr *hwmgr,
2325                 struct amd_pp_simple_clock_info *info)
2326 {
2327 #if 0
2328         struct phm_ppt_v2_information *table_info =
2329                         (struct phm_ppt_v2_information *)hwmgr->pptable;
2330         struct phm_clock_and_voltage_limits *max_limits =
2331                         &table_info->max_clock_voltage_on_ac;
2332
2333         info->engine_max_clock = max_limits->sclk;
2334         info->memory_max_clock = max_limits->mclk;
2335 #endif
2336         return 0;
2337 }
2338
2339
2340 static int vega20_get_sclks(struct pp_hwmgr *hwmgr,
2341                 struct pp_clock_levels_with_latency *clocks)
2342 {
2343         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2344         struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.gfx_table);
2345         int i, count;
2346
2347         PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_GFXCLK].enabled,
2348                 "[GetSclks]: gfxclk dpm not enabled!\n",
2349                 return -EPERM);
2350
2351         count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2352         clocks->num_levels = count;
2353
2354         for (i = 0; i < count; i++) {
2355                 clocks->data[i].clocks_in_khz =
2356                         dpm_table->dpm_levels[i].value * 100;
2357                 clocks->data[i].latency_in_us = 0;
2358         }
2359
2360         return 0;
2361 }
2362
2363 static uint32_t vega20_get_mem_latency(struct pp_hwmgr *hwmgr,
2364                 uint32_t clock)
2365 {
2366         return 25;
2367 }
2368
2369 static int vega20_get_memclocks(struct pp_hwmgr *hwmgr,
2370                 struct pp_clock_levels_with_latency *clocks)
2371 {
2372         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2373         struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.mem_table);
2374         int i, count;
2375
2376         PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_UCLK].enabled,
2377                 "[GetMclks]: uclk dpm not enabled!\n",
2378                 return -EPERM);
2379
2380         count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2381         clocks->num_levels = data->mclk_latency_table.count = count;
2382
2383         for (i = 0; i < count; i++) {
2384                 clocks->data[i].clocks_in_khz =
2385                         data->mclk_latency_table.entries[i].frequency =
2386                         dpm_table->dpm_levels[i].value * 100;
2387                 clocks->data[i].latency_in_us =
2388                         data->mclk_latency_table.entries[i].latency =
2389                         vega20_get_mem_latency(hwmgr, dpm_table->dpm_levels[i].value);
2390         }
2391
2392         return 0;
2393 }
2394
2395 static int vega20_get_dcefclocks(struct pp_hwmgr *hwmgr,
2396                 struct pp_clock_levels_with_latency *clocks)
2397 {
2398         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2399         struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.dcef_table);
2400         int i, count;
2401
2402         PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_DCEFCLK].enabled,
2403                 "[GetDcfclocks]: dcefclk dpm not enabled!\n",
2404                 return -EPERM);
2405
2406         count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2407         clocks->num_levels = count;
2408
2409         for (i = 0; i < count; i++) {
2410                 clocks->data[i].clocks_in_khz =
2411                         dpm_table->dpm_levels[i].value * 100;
2412                 clocks->data[i].latency_in_us = 0;
2413         }
2414
2415         return 0;
2416 }
2417
2418 static int vega20_get_socclocks(struct pp_hwmgr *hwmgr,
2419                 struct pp_clock_levels_with_latency *clocks)
2420 {
2421         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2422         struct vega20_single_dpm_table *dpm_table = &(data->dpm_table.soc_table);
2423         int i, count;
2424
2425         PP_ASSERT_WITH_CODE(data->smu_features[GNLD_DPM_SOCCLK].enabled,
2426                 "[GetSocclks]: socclk dpm not enabled!\n",
2427                 return -EPERM);
2428
2429         count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
2430         clocks->num_levels = count;
2431
2432         for (i = 0; i < count; i++) {
2433                 clocks->data[i].clocks_in_khz =
2434                         dpm_table->dpm_levels[i].value * 100;
2435                 clocks->data[i].latency_in_us = 0;
2436         }
2437
2438         return 0;
2439
2440 }
2441
2442 static int vega20_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr,
2443                 enum amd_pp_clock_type type,
2444                 struct pp_clock_levels_with_latency *clocks)
2445 {
2446         int ret;
2447
2448         switch (type) {
2449         case amd_pp_sys_clock:
2450                 ret = vega20_get_sclks(hwmgr, clocks);
2451                 break;
2452         case amd_pp_mem_clock:
2453                 ret = vega20_get_memclocks(hwmgr, clocks);
2454                 break;
2455         case amd_pp_dcef_clock:
2456                 ret = vega20_get_dcefclocks(hwmgr, clocks);
2457                 break;
2458         case amd_pp_soc_clock:
2459                 ret = vega20_get_socclocks(hwmgr, clocks);
2460                 break;
2461         default:
2462                 return -EINVAL;
2463         }
2464
2465         return ret;
2466 }
2467
2468 static int vega20_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr,
2469                 enum amd_pp_clock_type type,
2470                 struct pp_clock_levels_with_voltage *clocks)
2471 {
2472         clocks->num_levels = 0;
2473
2474         return 0;
2475 }
2476
2477 static int vega20_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr,
2478                                                    void *clock_ranges)
2479 {
2480         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2481         Watermarks_t *table = &(data->smc_state_table.water_marks_table);
2482         struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges;
2483
2484         if (!data->registry_data.disable_water_mark &&
2485             data->smu_features[GNLD_DPM_DCEFCLK].supported &&
2486             data->smu_features[GNLD_DPM_SOCCLK].supported) {
2487                 smu_set_watermarks_for_clocks_ranges(table, wm_with_clock_ranges);
2488                 data->water_marks_bitmap |= WaterMarksExist;
2489                 data->water_marks_bitmap &= ~WaterMarksLoaded;
2490         }
2491
2492         return 0;
2493 }
2494
2495 static int vega20_odn_edit_dpm_table(struct pp_hwmgr *hwmgr,
2496                                         enum PP_OD_DPM_TABLE_COMMAND type,
2497                                         long *input, uint32_t size)
2498 {
2499         struct vega20_hwmgr *data =
2500                         (struct vega20_hwmgr *)(hwmgr->backend);
2501         struct vega20_od8_single_setting *od8_settings =
2502                         data->od8_settings.od8_settings_array;
2503         OverDriveTable_t *od_table =
2504                         &(data->smc_state_table.overdrive_table);
2505         struct pp_clock_levels_with_latency clocks;
2506         int32_t input_index, input_clk, input_vol, i;
2507         int od8_id;
2508         int ret;
2509
2510         PP_ASSERT_WITH_CODE(input, "NULL user input for clock and voltage",
2511                                 return -EINVAL);
2512
2513         switch (type) {
2514         case PP_OD_EDIT_SCLK_VDDC_TABLE:
2515                 if (!(od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
2516                       od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id)) {
2517                         pr_info("Sclk min/max frequency overdrive not supported\n");
2518                         return -EOPNOTSUPP;
2519                 }
2520
2521                 for (i = 0; i < size; i += 2) {
2522                         if (i + 2 > size) {
2523                                 pr_info("invalid number of input parameters %d\n",
2524                                         size);
2525                                 return -EINVAL;
2526                         }
2527
2528                         input_index = input[i];
2529                         input_clk = input[i + 1];
2530
2531                         if (input_index != 0 && input_index != 1) {
2532                                 pr_info("Invalid index %d\n", input_index);
2533                                 pr_info("Support min/max sclk frequency setting only which index by 0/1\n");
2534                                 return -EINVAL;
2535                         }
2536
2537                         if (input_clk < od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value ||
2538                             input_clk > od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value) {
2539                                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2540                                         input_clk,
2541                                         od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value,
2542                                         od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value);
2543                                 return -EINVAL;
2544                         }
2545
2546                         if ((input_index == 0 && od_table->GfxclkFmin != input_clk) ||
2547                             (input_index == 1 && od_table->GfxclkFmax != input_clk))
2548                                 data->gfxclk_overdrive = true;
2549
2550                         if (input_index == 0)
2551                                 od_table->GfxclkFmin = input_clk;
2552                         else
2553                                 od_table->GfxclkFmax = input_clk;
2554                 }
2555
2556                 break;
2557
2558         case PP_OD_EDIT_MCLK_VDDC_TABLE:
2559                 if (!od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
2560                         pr_info("Mclk max frequency overdrive not supported\n");
2561                         return -EOPNOTSUPP;
2562                 }
2563
2564                 ret = vega20_get_memclocks(hwmgr, &clocks);
2565                 PP_ASSERT_WITH_CODE(!ret,
2566                                 "Attempt to get memory clk levels failed!",
2567                                 return ret);
2568
2569                 for (i = 0; i < size; i += 2) {
2570                         if (i + 2 > size) {
2571                                 pr_info("invalid number of input parameters %d\n",
2572                                         size);
2573                                 return -EINVAL;
2574                         }
2575
2576                         input_index = input[i];
2577                         input_clk = input[i + 1];
2578
2579                         if (input_index != 1) {
2580                                 pr_info("Invalid index %d\n", input_index);
2581                                 pr_info("Support max Mclk frequency setting only which index by 1\n");
2582                                 return -EINVAL;
2583                         }
2584
2585                         if (input_clk < clocks.data[0].clocks_in_khz / 100 ||
2586                             input_clk > od8_settings[OD8_SETTING_UCLK_FMAX].max_value) {
2587                                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2588                                         input_clk,
2589                                         clocks.data[0].clocks_in_khz / 100,
2590                                         od8_settings[OD8_SETTING_UCLK_FMAX].max_value);
2591                                 return -EINVAL;
2592                         }
2593
2594                         if (input_index == 1 && od_table->UclkFmax != input_clk)
2595                                 data->memclk_overdrive = true;
2596
2597                         od_table->UclkFmax = input_clk;
2598                 }
2599
2600                 break;
2601
2602         case PP_OD_EDIT_VDDC_CURVE:
2603                 if (!(od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
2604                     od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
2605                     od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
2606                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
2607                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
2608                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id)) {
2609                         pr_info("Voltage curve calibrate not supported\n");
2610                         return -EOPNOTSUPP;
2611                 }
2612
2613                 for (i = 0; i < size; i += 3) {
2614                         if (i + 3 > size) {
2615                                 pr_info("invalid number of input parameters %d\n",
2616                                         size);
2617                                 return -EINVAL;
2618                         }
2619
2620                         input_index = input[i];
2621                         input_clk = input[i + 1];
2622                         input_vol = input[i + 2];
2623
2624                         if (input_index > 2) {
2625                                 pr_info("Setting for point %d is not supported\n",
2626                                                 input_index + 1);
2627                                 pr_info("Three supported points index by 0, 1, 2\n");
2628                                 return -EINVAL;
2629                         }
2630
2631                         od8_id = OD8_SETTING_GFXCLK_FREQ1 + 2 * input_index;
2632                         if (input_clk < od8_settings[od8_id].min_value ||
2633                             input_clk > od8_settings[od8_id].max_value) {
2634                                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2635                                         input_clk,
2636                                         od8_settings[od8_id].min_value,
2637                                         od8_settings[od8_id].max_value);
2638                                 return -EINVAL;
2639                         }
2640
2641                         od8_id = OD8_SETTING_GFXCLK_VOLTAGE1 + 2 * input_index;
2642                         if (input_vol < od8_settings[od8_id].min_value ||
2643                             input_vol > od8_settings[od8_id].max_value) {
2644                                 pr_info("clock voltage %d is not within allowed range [%d - %d]\n",
2645                                         input_vol,
2646                                         od8_settings[od8_id].min_value,
2647                                         od8_settings[od8_id].max_value);
2648                                 return -EINVAL;
2649                         }
2650
2651                         switch (input_index) {
2652                         case 0:
2653                                 od_table->GfxclkFreq1 = input_clk;
2654                                 od_table->GfxclkVolt1 = input_vol * VOLTAGE_SCALE;
2655                                 break;
2656                         case 1:
2657                                 od_table->GfxclkFreq2 = input_clk;
2658                                 od_table->GfxclkVolt2 = input_vol * VOLTAGE_SCALE;
2659                                 break;
2660                         case 2:
2661                                 od_table->GfxclkFreq3 = input_clk;
2662                                 od_table->GfxclkVolt3 = input_vol * VOLTAGE_SCALE;
2663                                 break;
2664                         }
2665                 }
2666                 break;
2667
2668         case PP_OD_RESTORE_DEFAULT_TABLE:
2669                 data->gfxclk_overdrive = false;
2670                 data->memclk_overdrive = false;
2671
2672                 ret = smum_smc_table_manager(hwmgr,
2673                                              (uint8_t *)od_table,
2674                                              TABLE_OVERDRIVE, true);
2675                 PP_ASSERT_WITH_CODE(!ret,
2676                                 "Failed to export overdrive table!",
2677                                 return ret);
2678                 break;
2679
2680         case PP_OD_COMMIT_DPM_TABLE:
2681                 ret = smum_smc_table_manager(hwmgr,
2682                                              (uint8_t *)od_table,
2683                                              TABLE_OVERDRIVE, false);
2684                 PP_ASSERT_WITH_CODE(!ret,
2685                                 "Failed to import overdrive table!",
2686                                 return ret);
2687
2688                 /* retrieve updated gfxclk table */
2689                 if (data->gfxclk_overdrive) {
2690                         data->gfxclk_overdrive = false;
2691
2692                         ret = vega20_setup_gfxclk_dpm_table(hwmgr);
2693                         if (ret)
2694                                 return ret;
2695                 }
2696
2697                 /* retrieve updated memclk table */
2698                 if (data->memclk_overdrive) {
2699                         data->memclk_overdrive = false;
2700
2701                         ret = vega20_setup_memclk_dpm_table(hwmgr);
2702                         if (ret)
2703                                 return ret;
2704                 }
2705                 break;
2706
2707         default:
2708                 return -EINVAL;
2709         }
2710
2711         return 0;
2712 }
2713
2714 static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
2715                 enum pp_clock_type type, char *buf)
2716 {
2717         struct vega20_hwmgr *data =
2718                         (struct vega20_hwmgr *)(hwmgr->backend);
2719         struct vega20_od8_single_setting *od8_settings =
2720                         data->od8_settings.od8_settings_array;
2721         OverDriveTable_t *od_table =
2722                         &(data->smc_state_table.overdrive_table);
2723         struct pp_clock_levels_with_latency clocks;
2724         int i, now, size = 0;
2725         int ret = 0;
2726
2727         switch (type) {
2728         case PP_SCLK:
2729                 ret = vega20_get_current_gfx_clk_freq(hwmgr, &now);
2730                 PP_ASSERT_WITH_CODE(!ret,
2731                                 "Attempt to get current gfx clk Failed!",
2732                                 return ret);
2733
2734                 ret = vega20_get_sclks(hwmgr, &clocks);
2735                 PP_ASSERT_WITH_CODE(!ret,
2736                                 "Attempt to get gfx clk levels Failed!",
2737                                 return ret);
2738
2739                 for (i = 0; i < clocks.num_levels; i++)
2740                         size += sprintf(buf + size, "%d: %uMhz %s\n",
2741                                 i, clocks.data[i].clocks_in_khz / 100,
2742                                 (clocks.data[i].clocks_in_khz == now) ? "*" : "");
2743                 break;
2744
2745         case PP_MCLK:
2746                 ret = vega20_get_current_mclk_freq(hwmgr, &now);
2747                 PP_ASSERT_WITH_CODE(!ret,
2748                                 "Attempt to get current mclk freq Failed!",
2749                                 return ret);
2750
2751                 ret = vega20_get_memclocks(hwmgr, &clocks);
2752                 PP_ASSERT_WITH_CODE(!ret,
2753                                 "Attempt to get memory clk levels Failed!",
2754                                 return ret);
2755
2756                 for (i = 0; i < clocks.num_levels; i++)
2757                         size += sprintf(buf + size, "%d: %uMhz %s\n",
2758                                 i, clocks.data[i].clocks_in_khz / 100,
2759                                 (clocks.data[i].clocks_in_khz == now) ? "*" : "");
2760                 break;
2761
2762         case PP_PCIE:
2763                 break;
2764
2765         case OD_SCLK:
2766                 if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
2767                     od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
2768                         size = sprintf(buf, "%s:\n", "OD_SCLK");
2769                         size += sprintf(buf + size, "0: %10uMhz\n",
2770                                 od_table->GfxclkFmin);
2771                         size += sprintf(buf + size, "1: %10uMhz\n",
2772                                 od_table->GfxclkFmax);
2773                 }
2774                 break;
2775
2776         case OD_MCLK:
2777                 if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
2778                         size = sprintf(buf, "%s:\n", "OD_MCLK");
2779                         size += sprintf(buf + size, "1: %10uMhz\n",
2780                                 od_table->UclkFmax);
2781                 }
2782
2783                 break;
2784
2785         case OD_VDDC_CURVE:
2786                 if (od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
2787                     od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
2788                     od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
2789                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
2790                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
2791                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
2792                         size = sprintf(buf, "%s:\n", "OD_VDDC_CURVE");
2793                         size += sprintf(buf + size, "0: %10uMhz %10dmV\n",
2794                                 od_table->GfxclkFreq1,
2795                                 od_table->GfxclkVolt1 / VOLTAGE_SCALE);
2796                         size += sprintf(buf + size, "1: %10uMhz %10dmV\n",
2797                                 od_table->GfxclkFreq2,
2798                                 od_table->GfxclkVolt2 / VOLTAGE_SCALE);
2799                         size += sprintf(buf + size, "2: %10uMhz %10dmV\n",
2800                                 od_table->GfxclkFreq3,
2801                                 od_table->GfxclkVolt3 / VOLTAGE_SCALE);
2802                 }
2803
2804                 break;
2805
2806         case OD_RANGE:
2807                 size = sprintf(buf, "%s:\n", "OD_RANGE");
2808
2809                 if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
2810                     od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
2811                         size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
2812                                 od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value,
2813                                 od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value);
2814                 }
2815
2816                 if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
2817                         ret = vega20_get_memclocks(hwmgr, &clocks);
2818                         PP_ASSERT_WITH_CODE(!ret,
2819                                         "Fail to get memory clk levels!",
2820                                         return ret);
2821
2822                         size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
2823                                 clocks.data[0].clocks_in_khz / 100,
2824                                 od8_settings[OD8_SETTING_UCLK_FMAX].max_value);
2825                 }
2826
2827                 if (od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
2828                     od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
2829                     od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
2830                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
2831                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
2832                     od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
2833                         size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
2834                                 od8_settings[OD8_SETTING_GFXCLK_FREQ1].min_value,
2835                                 od8_settings[OD8_SETTING_GFXCLK_FREQ1].max_value);
2836                         size += sprintf(buf + size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n",
2837                                 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].min_value,
2838                                 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].max_value);
2839                         size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
2840                                 od8_settings[OD8_SETTING_GFXCLK_FREQ2].min_value,
2841                                 od8_settings[OD8_SETTING_GFXCLK_FREQ2].max_value);
2842                         size += sprintf(buf + size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n",
2843                                 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].min_value,
2844                                 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].max_value);
2845                         size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
2846                                 od8_settings[OD8_SETTING_GFXCLK_FREQ3].min_value,
2847                                 od8_settings[OD8_SETTING_GFXCLK_FREQ3].max_value);
2848                         size += sprintf(buf + size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
2849                                 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].min_value,
2850                                 od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].max_value);
2851                 }
2852
2853                 break;
2854         default:
2855                 break;
2856         }
2857         return size;
2858 }
2859
2860 static int vega20_set_uclk_to_highest_dpm_level(struct pp_hwmgr *hwmgr,
2861                 struct vega20_single_dpm_table *dpm_table)
2862 {
2863         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2864         int ret = 0;
2865
2866         if (data->smu_features[GNLD_DPM_UCLK].enabled) {
2867                 PP_ASSERT_WITH_CODE(dpm_table->count > 0,
2868                                 "[SetUclkToHightestDpmLevel] Dpm table has no entry!",
2869                                 return -EINVAL);
2870                 PP_ASSERT_WITH_CODE(dpm_table->count <= NUM_UCLK_DPM_LEVELS,
2871                                 "[SetUclkToHightestDpmLevel] Dpm table has too many entries!",
2872                                 return -EINVAL);
2873
2874                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2875                 PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(hwmgr,
2876                                 PPSMC_MSG_SetHardMinByFreq,
2877                                 (PPCLK_UCLK << 16 ) | dpm_table->dpm_state.hard_min_level)),
2878                                 "[SetUclkToHightestDpmLevel] Set hard min uclk failed!",
2879                                 return ret);
2880         }
2881
2882         return ret;
2883 }
2884
2885 static int vega20_pre_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
2886 {
2887         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2888         int ret = 0;
2889
2890         smum_send_msg_to_smc_with_parameter(hwmgr,
2891                         PPSMC_MSG_NumOfDisplays, 0);
2892
2893         ret = vega20_set_uclk_to_highest_dpm_level(hwmgr,
2894                         &data->dpm_table.mem_table);
2895
2896         return ret;
2897 }
2898
2899 static int vega20_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
2900 {
2901         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2902         int result = 0;
2903         Watermarks_t *wm_table = &(data->smc_state_table.water_marks_table);
2904
2905         if ((data->water_marks_bitmap & WaterMarksExist) &&
2906             !(data->water_marks_bitmap & WaterMarksLoaded)) {
2907                 result = smum_smc_table_manager(hwmgr,
2908                                                 (uint8_t *)wm_table, TABLE_WATERMARKS, false);
2909                 PP_ASSERT_WITH_CODE(!result,
2910                                 "Failed to update WMTABLE!",
2911                                 return result);
2912                 data->water_marks_bitmap |= WaterMarksLoaded;
2913         }
2914
2915         if ((data->water_marks_bitmap & WaterMarksExist) &&
2916             data->smu_features[GNLD_DPM_DCEFCLK].supported &&
2917             data->smu_features[GNLD_DPM_SOCCLK].supported) {
2918                 result = smum_send_msg_to_smc_with_parameter(hwmgr,
2919                         PPSMC_MSG_NumOfDisplays,
2920                         hwmgr->display_config->num_display);
2921         }
2922
2923         return result;
2924 }
2925
2926 int vega20_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
2927 {
2928         struct vega20_hwmgr *data =
2929                         (struct vega20_hwmgr *)(hwmgr->backend);
2930         int ret = 0;
2931
2932         if (data->smu_features[GNLD_DPM_UVD].supported) {
2933                 if (data->smu_features[GNLD_DPM_UVD].enabled == enable) {
2934                         if (enable)
2935                                 PP_DBG_LOG("[EnableDisableUVDDPM] feature DPM UVD already enabled!\n");
2936                         else
2937                                 PP_DBG_LOG("[EnableDisableUVDDPM] feature DPM UVD already disabled!\n");
2938                 }
2939
2940                 ret = vega20_enable_smc_features(hwmgr,
2941                                 enable,
2942                                 data->smu_features[GNLD_DPM_UVD].smu_feature_bitmap);
2943                 PP_ASSERT_WITH_CODE(!ret,
2944                                 "[EnableDisableUVDDPM] Attempt to Enable/Disable DPM UVD Failed!",
2945                                 return ret);
2946                 data->smu_features[GNLD_DPM_UVD].enabled = enable;
2947         }
2948
2949         return 0;
2950 }
2951
2952 static void vega20_power_gate_vce(struct pp_hwmgr *hwmgr, bool bgate)
2953 {
2954         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2955
2956         if (data->vce_power_gated == bgate)
2957                 return ;
2958
2959         data->vce_power_gated = bgate;
2960         vega20_enable_disable_vce_dpm(hwmgr, !bgate);
2961 }
2962
2963 static void vega20_power_gate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
2964 {
2965         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2966
2967         if (data->uvd_power_gated == bgate)
2968                 return ;
2969
2970         data->uvd_power_gated = bgate;
2971         vega20_enable_disable_uvd_dpm(hwmgr, !bgate);
2972 }
2973
2974 static int vega20_apply_clocks_adjust_rules(struct pp_hwmgr *hwmgr)
2975 {
2976         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
2977         struct vega20_single_dpm_table *dpm_table;
2978         bool vblank_too_short = false;
2979         bool disable_mclk_switching;
2980         uint32_t i, latency;
2981
2982         disable_mclk_switching = ((1 < hwmgr->display_config->num_display) &&
2983                            !hwmgr->display_config->multi_monitor_in_sync) ||
2984                             vblank_too_short;
2985     latency = hwmgr->display_config->dce_tolerable_mclk_in_active_latency;
2986
2987         /* gfxclk */
2988         dpm_table = &(data->dpm_table.gfx_table);
2989         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2990         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2991         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2992         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2993
2994         if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
2995                 if (VEGA20_UMD_PSTATE_GFXCLK_LEVEL < dpm_table->count) {
2996                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
2997                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
2998                 }
2999
3000                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
3001                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3002                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
3003                 }
3004
3005                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3006                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3007                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3008                 }
3009         }
3010
3011         /* memclk */
3012         dpm_table = &(data->dpm_table.mem_table);
3013         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3014         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3015         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3016         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3017
3018         if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3019                 if (VEGA20_UMD_PSTATE_MCLK_LEVEL < dpm_table->count) {
3020                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
3021                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
3022                 }
3023
3024                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
3025                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3026                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
3027                 }
3028
3029                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3030                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3031                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3032                 }
3033         }
3034
3035         /* honour DAL's UCLK Hardmin */
3036         if (dpm_table->dpm_state.hard_min_level < (hwmgr->display_config->min_mem_set_clock / 100))
3037                 dpm_table->dpm_state.hard_min_level = hwmgr->display_config->min_mem_set_clock / 100;
3038
3039         /* Hardmin is dependent on displayconfig */
3040         if (disable_mclk_switching) {
3041                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3042                 for (i = 0; i < data->mclk_latency_table.count - 1; i++) {
3043                         if (data->mclk_latency_table.entries[i].latency <= latency) {
3044                                 if (dpm_table->dpm_levels[i].value >= (hwmgr->display_config->min_mem_set_clock / 100)) {
3045                                         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[i].value;
3046                                         break;
3047                                 }
3048                         }
3049                 }
3050         }
3051
3052         if (hwmgr->display_config->nb_pstate_switch_disable)
3053                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3054
3055         /* vclk */
3056         dpm_table = &(data->dpm_table.vclk_table);
3057         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3058         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3059         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3060         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3061
3062         if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3063                 if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
3064                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
3065                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
3066                 }
3067
3068                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3069                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3070                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3071                 }
3072         }
3073
3074         /* dclk */
3075         dpm_table = &(data->dpm_table.dclk_table);
3076         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3077         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3078         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3079         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3080
3081         if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3082                 if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
3083                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
3084                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
3085                 }
3086
3087                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3088                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3089                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3090                 }
3091         }
3092
3093         /* socclk */
3094         dpm_table = &(data->dpm_table.soc_table);
3095         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3096         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3097         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3098         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3099
3100         if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3101                 if (VEGA20_UMD_PSTATE_SOCCLK_LEVEL < dpm_table->count) {
3102                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
3103                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
3104                 }
3105
3106                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3107                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3108                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3109                 }
3110         }
3111
3112         /* eclk */
3113         dpm_table = &(data->dpm_table.eclk_table);
3114         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
3115         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3116         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
3117         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3118
3119         if (PP_CAP(PHM_PlatformCaps_UMDPState)) {
3120                 if (VEGA20_UMD_PSTATE_VCEMCLK_LEVEL < dpm_table->count) {
3121                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
3122                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
3123                 }
3124
3125                 if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
3126                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3127                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
3128                 }
3129         }
3130
3131         return 0;
3132 }
3133
3134 static bool
3135 vega20_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
3136 {
3137         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3138         bool is_update_required = false;
3139
3140         if (data->display_timing.num_existing_displays !=
3141                         hwmgr->display_config->num_display)
3142                 is_update_required = true;
3143
3144         if (data->registry_data.gfx_clk_deep_sleep_support &&
3145            (data->display_timing.min_clock_in_sr !=
3146             hwmgr->display_config->min_core_set_clock_in_sr))
3147                 is_update_required = true;
3148
3149         return is_update_required;
3150 }
3151
3152 static int vega20_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
3153 {
3154         int ret = 0;
3155
3156         ret = vega20_disable_all_smu_features(hwmgr);
3157         PP_ASSERT_WITH_CODE(!ret,
3158                         "[DisableDpmTasks] Failed to disable all smu features!",
3159                         return ret);
3160
3161         return 0;
3162 }
3163
3164 static int vega20_power_off_asic(struct pp_hwmgr *hwmgr)
3165 {
3166         struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
3167         int result;
3168
3169         result = vega20_disable_dpm_tasks(hwmgr);
3170         PP_ASSERT_WITH_CODE((0 == result),
3171                         "[PowerOffAsic] Failed to disable DPM!",
3172                         );
3173         data->water_marks_bitmap &= ~(WaterMarksLoaded);
3174
3175         return result;
3176 }
3177
3178 static int conv_power_profile_to_pplib_workload(int power_profile)
3179 {
3180         int pplib_workload = 0;
3181
3182         switch (power_profile) {
3183         case PP_SMC_POWER_PROFILE_FULLSCREEN3D:
3184                 pplib_workload = WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT;
3185                 break;
3186         case PP_SMC_POWER_PROFILE_POWERSAVING:
3187                 pplib_workload = WORKLOAD_PPLIB_POWER_SAVING_BIT;
3188                 break;
3189         case PP_SMC_POWER_PROFILE_VIDEO:
3190                 pplib_workload = WORKLOAD_PPLIB_VIDEO_BIT;
3191                 break;
3192         case PP_SMC_POWER_PROFILE_VR:
3193                 pplib_workload = WORKLOAD_PPLIB_VR_BIT;
3194                 break;
3195         case PP_SMC_POWER_PROFILE_COMPUTE:
3196                 pplib_workload = WORKLOAD_PPLIB_COMPUTE_BIT;
3197                 break;
3198         case PP_SMC_POWER_PROFILE_CUSTOM:
3199                 pplib_workload = WORKLOAD_PPLIB_CUSTOM_BIT;
3200                 break;
3201         }
3202
3203         return pplib_workload;
3204 }
3205
3206 static int vega20_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
3207 {
3208         DpmActivityMonitorCoeffInt_t activity_monitor;
3209         uint32_t i, size = 0;
3210         uint16_t workload_type = 0;
3211         static const char *profile_name[] = {
3212                                         "3D_FULL_SCREEN",
3213                                         "POWER_SAVING",
3214                                         "VIDEO",
3215                                         "VR",
3216                                         "COMPUTE",
3217                                         "CUSTOM"};
3218         static const char *title[] = {
3219                         "PROFILE_INDEX(NAME)",
3220                         "CLOCK_TYPE(NAME)",
3221                         "FPS",
3222                         "UseRlcBusy",
3223                         "MinActiveFreqType",
3224                         "MinActiveFreq",
3225                         "BoosterFreqType",
3226                         "BoosterFreq",
3227                         "PD_Data_limit_c",
3228                         "PD_Data_error_coeff",
3229                         "PD_Data_error_rate_coeff"};
3230         int result = 0;
3231
3232         if (!buf)
3233                 return -EINVAL;
3234
3235         size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
3236                         title[0], title[1], title[2], title[3], title[4], title[5],
3237                         title[6], title[7], title[8], title[9], title[10]);
3238
3239         for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
3240                 /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
3241                 workload_type = conv_power_profile_to_pplib_workload(i);
3242                 result = vega20_get_activity_monitor_coeff(hwmgr,
3243                                 (uint8_t *)(&activity_monitor), workload_type);
3244                 PP_ASSERT_WITH_CODE(!result,
3245                                 "[GetPowerProfile] Failed to get activity monitor!",
3246                                 return result);
3247
3248                 size += sprintf(buf + size, "%2d %14s%s:\n",
3249                         i, profile_name[i], (i == hwmgr->power_profile_mode) ? "*" : " ");
3250
3251                 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
3252                         " ",
3253                         0,
3254                         "GFXCLK",
3255                         activity_monitor.Gfx_FPS,
3256                         activity_monitor.Gfx_UseRlcBusy,
3257                         activity_monitor.Gfx_MinActiveFreqType,
3258                         activity_monitor.Gfx_MinActiveFreq,
3259                         activity_monitor.Gfx_BoosterFreqType,
3260                         activity_monitor.Gfx_BoosterFreq,
3261                         activity_monitor.Gfx_PD_Data_limit_c,
3262                         activity_monitor.Gfx_PD_Data_error_coeff,
3263                         activity_monitor.Gfx_PD_Data_error_rate_coeff);
3264
3265                 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
3266                         " ",
3267                         1,
3268                         "SOCCLK",
3269                         activity_monitor.Soc_FPS,
3270                         activity_monitor.Soc_UseRlcBusy,
3271                         activity_monitor.Soc_MinActiveFreqType,
3272                         activity_monitor.Soc_MinActiveFreq,
3273                         activity_monitor.Soc_BoosterFreqType,
3274                         activity_monitor.Soc_BoosterFreq,
3275                         activity_monitor.Soc_PD_Data_limit_c,
3276                         activity_monitor.Soc_PD_Data_error_coeff,
3277                         activity_monitor.Soc_PD_Data_error_rate_coeff);
3278
3279                 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
3280                         " ",
3281                         2,
3282                         "UCLK",
3283                         activity_monitor.Mem_FPS,
3284                         activity_monitor.Mem_UseRlcBusy,
3285                         activity_monitor.Mem_MinActiveFreqType,
3286                         activity_monitor.Mem_MinActiveFreq,
3287                         activity_monitor.Mem_BoosterFreqType,
3288                         activity_monitor.Mem_BoosterFreq,
3289                         activity_monitor.Mem_PD_Data_limit_c,
3290                         activity_monitor.Mem_PD_Data_error_coeff,
3291                         activity_monitor.Mem_PD_Data_error_rate_coeff);
3292
3293                 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
3294                         " ",
3295                         3,
3296                         "FCLK",
3297                         activity_monitor.Fclk_FPS,
3298                         activity_monitor.Fclk_UseRlcBusy,
3299                         activity_monitor.Fclk_MinActiveFreqType,
3300                         activity_monitor.Fclk_MinActiveFreq,
3301                         activity_monitor.Fclk_BoosterFreqType,
3302                         activity_monitor.Fclk_BoosterFreq,
3303                         activity_monitor.Fclk_PD_Data_limit_c,
3304                         activity_monitor.Fclk_PD_Data_error_coeff,
3305                         activity_monitor.Fclk_PD_Data_error_rate_coeff);
3306         }
3307
3308         return size;
3309 }
3310
3311 static int vega20_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint32_t size)
3312 {
3313         DpmActivityMonitorCoeffInt_t activity_monitor;
3314         int workload_type, result = 0;
3315
3316         hwmgr->power_profile_mode = input[size];
3317
3318         if (hwmgr->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
3319                 pr_err("Invalid power profile mode %d\n", hwmgr->power_profile_mode);
3320                 return -EINVAL;
3321         }
3322
3323         if (hwmgr->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
3324                 if (size < 10)
3325                         return -EINVAL;
3326
3327                 result = vega20_get_activity_monitor_coeff(hwmgr,
3328                                 (uint8_t *)(&activity_monitor),
3329                                 WORKLOAD_PPLIB_CUSTOM_BIT);
3330                 PP_ASSERT_WITH_CODE(!result,
3331                                 "[SetPowerProfile] Failed to get activity monitor!",
3332                                 return result);
3333
3334                 switch (input[0]) {
3335                 case 0: /* Gfxclk */
3336                         activity_monitor.Gfx_FPS = input[1];
3337                         activity_monitor.Gfx_UseRlcBusy = input[2];
3338                         activity_monitor.Gfx_MinActiveFreqType = input[3];
3339                         activity_monitor.Gfx_MinActiveFreq = input[4];
3340                         activity_monitor.Gfx_BoosterFreqType = input[5];
3341                         activity_monitor.Gfx_BoosterFreq = input[6];
3342                         activity_monitor.Gfx_PD_Data_limit_c = input[7];
3343                         activity_monitor.Gfx_PD_Data_error_coeff = input[8];
3344                         activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
3345                         break;
3346                 case 1: /* Socclk */
3347                         activity_monitor.Soc_FPS = input[1];
3348                         activity_monitor.Soc_UseRlcBusy = input[2];
3349                         activity_monitor.Soc_MinActiveFreqType = input[3];
3350                         activity_monitor.Soc_MinActiveFreq = input[4];
3351                         activity_monitor.Soc_BoosterFreqType = input[5];
3352                         activity_monitor.Soc_BoosterFreq = input[6];
3353                         activity_monitor.Soc_PD_Data_limit_c = input[7];
3354                         activity_monitor.Soc_PD_Data_error_coeff = input[8];
3355                         activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
3356                         break;
3357                 case 2: /* Uclk */
3358                         activity_monitor.Mem_FPS = input[1];
3359                         activity_monitor.Mem_UseRlcBusy = input[2];
3360                         activity_monitor.Mem_MinActiveFreqType = input[3];
3361                         activity_monitor.Mem_MinActiveFreq = input[4];
3362                         activity_monitor.Mem_BoosterFreqType = input[5];
3363                         activity_monitor.Mem_BoosterFreq = input[6];
3364                         activity_monitor.Mem_PD_Data_limit_c = input[7];
3365                         activity_monitor.Mem_PD_Data_error_coeff = input[8];
3366                         activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
3367                         break;
3368                 case 3: /* Fclk */
3369                         activity_monitor.Fclk_FPS = input[1];
3370                         activity_monitor.Fclk_UseRlcBusy = input[2];
3371                         activity_monitor.Fclk_MinActiveFreqType = input[3];
3372                         activity_monitor.Fclk_MinActiveFreq = input[4];
3373                         activity_monitor.Fclk_BoosterFreqType = input[5];
3374                         activity_monitor.Fclk_BoosterFreq = input[6];
3375                         activity_monitor.Fclk_PD_Data_limit_c = input[7];
3376                         activity_monitor.Fclk_PD_Data_error_coeff = input[8];
3377                         activity_monitor.Fclk_PD_Data_error_rate_coeff = input[9];
3378                         break;
3379                 }
3380
3381                 result = vega20_set_activity_monitor_coeff(hwmgr,
3382                                 (uint8_t *)(&activity_monitor),
3383                                 WORKLOAD_PPLIB_CUSTOM_BIT);
3384                 PP_ASSERT_WITH_CODE(!result,
3385                                 "[SetPowerProfile] Failed to set activity monitor!",
3386                                 return result);
3387         }
3388
3389         /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
3390         workload_type =
3391                 conv_power_profile_to_pplib_workload(hwmgr->power_profile_mode);
3392         smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetWorkloadMask,
3393                                                 1 << workload_type);
3394
3395         return 0;
3396 }
3397
3398 static int vega20_notify_cac_buffer_info(struct pp_hwmgr *hwmgr,
3399                                         uint32_t virtual_addr_low,
3400                                         uint32_t virtual_addr_hi,
3401                                         uint32_t mc_addr_low,
3402                                         uint32_t mc_addr_hi,
3403                                         uint32_t size)
3404 {
3405         smum_send_msg_to_smc_with_parameter(hwmgr,
3406                                         PPSMC_MSG_SetSystemVirtualDramAddrHigh,
3407                                         virtual_addr_hi);
3408         smum_send_msg_to_smc_with_parameter(hwmgr,
3409                                         PPSMC_MSG_SetSystemVirtualDramAddrLow,
3410                                         virtual_addr_low);
3411         smum_send_msg_to_smc_with_parameter(hwmgr,
3412                                         PPSMC_MSG_DramLogSetDramAddrHigh,
3413                                         mc_addr_hi);
3414
3415         smum_send_msg_to_smc_with_parameter(hwmgr,
3416                                         PPSMC_MSG_DramLogSetDramAddrLow,
3417                                         mc_addr_low);
3418
3419         smum_send_msg_to_smc_with_parameter(hwmgr,
3420                                         PPSMC_MSG_DramLogSetDramSize,
3421                                         size);
3422         return 0;
3423 }
3424
3425 static int vega20_get_thermal_temperature_range(struct pp_hwmgr *hwmgr,
3426                 struct PP_TemperatureRange *thermal_data)
3427 {
3428         struct phm_ppt_v3_information *pptable_information =
3429                 (struct phm_ppt_v3_information *)hwmgr->pptable;
3430
3431         memcpy(thermal_data, &SMU7ThermalWithDelayPolicy[0], sizeof(struct PP_TemperatureRange));
3432
3433         thermal_data->max = pptable_information->us_software_shutdown_temp *
3434                 PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
3435
3436         return 0;
3437 }
3438
3439 static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
3440         /* init/fini related */
3441         .backend_init =
3442                 vega20_hwmgr_backend_init,
3443         .backend_fini =
3444                 vega20_hwmgr_backend_fini,
3445         .asic_setup =
3446                 vega20_setup_asic_task,
3447         .power_off_asic =
3448                 vega20_power_off_asic,
3449         .dynamic_state_management_enable =
3450                 vega20_enable_dpm_tasks,
3451         .dynamic_state_management_disable =
3452                 vega20_disable_dpm_tasks,
3453         /* power state related */
3454         .apply_clocks_adjust_rules =
3455                 vega20_apply_clocks_adjust_rules,
3456         .pre_display_config_changed =
3457                 vega20_pre_display_configuration_changed_task,
3458         .display_config_changed =
3459                 vega20_display_configuration_changed_task,
3460         .check_smc_update_required_for_display_configuration =
3461                 vega20_check_smc_update_required_for_display_configuration,
3462         .notify_smc_display_config_after_ps_adjustment =
3463                 vega20_notify_smc_display_config_after_ps_adjustment,
3464         /* export to DAL */
3465         .get_sclk =
3466                 vega20_dpm_get_sclk,
3467         .get_mclk =
3468                 vega20_dpm_get_mclk,
3469         .get_dal_power_level =
3470                 vega20_get_dal_power_level,
3471         .get_clock_by_type_with_latency =
3472                 vega20_get_clock_by_type_with_latency,
3473         .get_clock_by_type_with_voltage =
3474                 vega20_get_clock_by_type_with_voltage,
3475         .set_watermarks_for_clocks_ranges =
3476                 vega20_set_watermarks_for_clocks_ranges,
3477         .display_clock_voltage_request =
3478                 vega20_display_clock_voltage_request,
3479         /* UMD pstate, profile related */
3480         .force_dpm_level =
3481                 vega20_dpm_force_dpm_level,
3482         .get_power_profile_mode =
3483                 vega20_get_power_profile_mode,
3484         .set_power_profile_mode =
3485                 vega20_set_power_profile_mode,
3486         /* od related */
3487         .set_power_limit =
3488                 vega20_set_power_limit,
3489         .get_sclk_od =
3490                 vega20_get_sclk_od,
3491         .set_sclk_od =
3492                 vega20_set_sclk_od,
3493         .get_mclk_od =
3494                 vega20_get_mclk_od,
3495         .set_mclk_od =
3496                 vega20_set_mclk_od,
3497         .odn_edit_dpm_table =
3498                 vega20_odn_edit_dpm_table,
3499         /* for sysfs to retrive/set gfxclk/memclk */
3500         .force_clock_level =
3501                 vega20_force_clock_level,
3502         .print_clock_levels =
3503                 vega20_print_clock_levels,
3504         .read_sensor =
3505                 vega20_read_sensor,
3506         /* powergate related */
3507         .powergate_uvd =
3508                 vega20_power_gate_uvd,
3509         .powergate_vce =
3510                 vega20_power_gate_vce,
3511         /* thermal related */
3512         .start_thermal_controller =
3513                 vega20_start_thermal_controller,
3514         .stop_thermal_controller =
3515                 vega20_thermal_stop_thermal_controller,
3516         .get_thermal_temperature_range =
3517                 vega20_get_thermal_temperature_range,
3518         .register_irq_handlers =
3519                 smu9_register_irq_handlers,
3520         .disable_smc_firmware_ctf =
3521                 vega20_thermal_disable_alert,
3522         /* fan control related */
3523         .get_fan_speed_percent =
3524                 vega20_fan_ctrl_get_fan_speed_percent,
3525         .set_fan_speed_percent =
3526                 vega20_fan_ctrl_set_fan_speed_percent,
3527         .get_fan_speed_info =
3528                 vega20_fan_ctrl_get_fan_speed_info,
3529         .get_fan_speed_rpm =
3530                 vega20_fan_ctrl_get_fan_speed_rpm,
3531         .set_fan_speed_rpm =
3532                 vega20_fan_ctrl_set_fan_speed_rpm,
3533         .get_fan_control_mode =
3534                 vega20_get_fan_control_mode,
3535         .set_fan_control_mode =
3536                 vega20_set_fan_control_mode,
3537         /* smu memory related */
3538         .notify_cac_buffer_info =
3539                 vega20_notify_cac_buffer_info,
3540         .enable_mgpu_fan_boost =
3541                 vega20_enable_mgpu_fan_boost,
3542 };
3543
3544 int vega20_hwmgr_init(struct pp_hwmgr *hwmgr)
3545 {
3546         hwmgr->hwmgr_func = &vega20_hwmgr_funcs;
3547         hwmgr->pptable_func = &vega20_pptable_funcs;
3548
3549         return 0;
3550 }