]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / drivers / gpu / drm / amd / powerplay / hwmgr / vega10_hwmgr.c
1 /*
2  * Copyright 2016 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 "vega10_smumgr.h"
32 #include "hardwaremanager.h"
33 #include "ppatomfwctrl.h"
34 #include "atomfirmware.h"
35 #include "cgs_common.h"
36 #include "vega10_powertune.h"
37 #include "smu9.h"
38 #include "smu9_driver_if.h"
39 #include "vega10_inc.h"
40 #include "pp_soc15.h"
41 #include "pppcielanes.h"
42 #include "vega10_hwmgr.h"
43 #include "vega10_processpptables.h"
44 #include "vega10_pptable.h"
45 #include "vega10_thermal.h"
46 #include "pp_debug.h"
47 #include "pp_acpi.h"
48 #include "amd_pcie_helpers.h"
49 #include "cgs_linux.h"
50 #include "ppinterrupt.h"
51 #include "pp_overdriver.h"
52
53 #define VOLTAGE_SCALE  4
54 #define VOLTAGE_VID_OFFSET_SCALE1   625
55 #define VOLTAGE_VID_OFFSET_SCALE2   100
56
57 #define HBM_MEMORY_CHANNEL_WIDTH    128
58
59 uint32_t channel_number[] = {1, 2, 0, 4, 0, 8, 0, 16, 2};
60
61 #define MEM_FREQ_LOW_LATENCY        25000
62 #define MEM_FREQ_HIGH_LATENCY       80000
63 #define MEM_LATENCY_HIGH            245
64 #define MEM_LATENCY_LOW             35
65 #define MEM_LATENCY_ERR             0xFFFF
66
67 #define mmDF_CS_AON0_DramBaseAddress0                                                                  0x0044
68 #define mmDF_CS_AON0_DramBaseAddress0_BASE_IDX                                                         0
69
70 //DF_CS_AON0_DramBaseAddress0
71 #define DF_CS_AON0_DramBaseAddress0__AddrRngVal__SHIFT                                                        0x0
72 #define DF_CS_AON0_DramBaseAddress0__LgcyMmioHoleEn__SHIFT                                                    0x1
73 #define DF_CS_AON0_DramBaseAddress0__IntLvNumChan__SHIFT                                                      0x4
74 #define DF_CS_AON0_DramBaseAddress0__IntLvAddrSel__SHIFT                                                      0x8
75 #define DF_CS_AON0_DramBaseAddress0__DramBaseAddr__SHIFT                                                      0xc
76 #define DF_CS_AON0_DramBaseAddress0__AddrRngVal_MASK                                                          0x00000001L
77 #define DF_CS_AON0_DramBaseAddress0__LgcyMmioHoleEn_MASK                                                      0x00000002L
78 #define DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK                                                        0x000000F0L
79 #define DF_CS_AON0_DramBaseAddress0__IntLvAddrSel_MASK                                                        0x00000700L
80 #define DF_CS_AON0_DramBaseAddress0__DramBaseAddr_MASK                                                        0xFFFFF000L
81
82 const ULONG PhwVega10_Magic = (ULONG)(PHM_VIslands_Magic);
83
84 struct vega10_power_state *cast_phw_vega10_power_state(
85                                   struct pp_hw_power_state *hw_ps)
86 {
87         PP_ASSERT_WITH_CODE((PhwVega10_Magic == hw_ps->magic),
88                                 "Invalid Powerstate Type!",
89                                  return NULL;);
90
91         return (struct vega10_power_state *)hw_ps;
92 }
93
94 const struct vega10_power_state *cast_const_phw_vega10_power_state(
95                                  const struct pp_hw_power_state *hw_ps)
96 {
97         PP_ASSERT_WITH_CODE((PhwVega10_Magic == hw_ps->magic),
98                                 "Invalid Powerstate Type!",
99                                  return NULL;);
100
101         return (const struct vega10_power_state *)hw_ps;
102 }
103
104 static void vega10_set_default_registry_data(struct pp_hwmgr *hwmgr)
105 {
106         struct vega10_hwmgr *data =
107                         (struct vega10_hwmgr *)(hwmgr->backend);
108
109         data->registry_data.sclk_dpm_key_disabled =
110                         hwmgr->feature_mask & PP_SCLK_DPM_MASK ? false : true;
111         data->registry_data.socclk_dpm_key_disabled =
112                         hwmgr->feature_mask & PP_SOCCLK_DPM_MASK ? false : true;
113         data->registry_data.mclk_dpm_key_disabled =
114                         hwmgr->feature_mask & PP_MCLK_DPM_MASK ? false : true;
115         data->registry_data.pcie_dpm_key_disabled =
116                         hwmgr->feature_mask & PP_PCIE_DPM_MASK ? false : true;
117
118         data->registry_data.dcefclk_dpm_key_disabled =
119                         hwmgr->feature_mask & PP_DCEFCLK_DPM_MASK ? false : true;
120
121         if (hwmgr->feature_mask & PP_POWER_CONTAINMENT_MASK) {
122                 data->registry_data.power_containment_support = 1;
123                 data->registry_data.enable_pkg_pwr_tracking_feature = 1;
124                 data->registry_data.enable_tdc_limit_feature = 1;
125         }
126
127         data->registry_data.clock_stretcher_support =
128                         hwmgr->feature_mask & PP_CLOCK_STRETCH_MASK ? true : false;
129
130         data->registry_data.ulv_support =
131                         hwmgr->feature_mask & PP_ULV_MASK ? true : false;
132
133         data->registry_data.sclk_deep_sleep_support =
134                         hwmgr->feature_mask & PP_SCLK_DEEP_SLEEP_MASK ? true : false;
135
136         data->registry_data.disable_water_mark = 0;
137
138         data->registry_data.fan_control_support = 1;
139         data->registry_data.thermal_support = 1;
140         data->registry_data.fw_ctf_enabled = 1;
141
142         data->registry_data.avfs_support = 1;
143         data->registry_data.led_dpm_enabled = 1;
144
145         data->registry_data.vr0hot_enabled = 1;
146         data->registry_data.vr1hot_enabled = 1;
147         data->registry_data.regulator_hot_gpio_support = 1;
148
149         data->display_voltage_mode = PPVEGA10_VEGA10DISPLAYVOLTAGEMODE_DFLT;
150         data->dcef_clk_quad_eqn_a = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
151         data->dcef_clk_quad_eqn_b = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
152         data->dcef_clk_quad_eqn_c = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
153         data->disp_clk_quad_eqn_a = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
154         data->disp_clk_quad_eqn_b = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
155         data->disp_clk_quad_eqn_c = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
156         data->pixel_clk_quad_eqn_a = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
157         data->pixel_clk_quad_eqn_b = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
158         data->pixel_clk_quad_eqn_c = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
159         data->phy_clk_quad_eqn_a = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
160         data->phy_clk_quad_eqn_b = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
161         data->phy_clk_quad_eqn_c = PPREGKEY_VEGA10QUADRATICEQUATION_DFLT;
162
163         data->gfxclk_average_alpha = PPVEGA10_VEGA10GFXCLKAVERAGEALPHA_DFLT;
164         data->socclk_average_alpha = PPVEGA10_VEGA10SOCCLKAVERAGEALPHA_DFLT;
165         data->uclk_average_alpha = PPVEGA10_VEGA10UCLKCLKAVERAGEALPHA_DFLT;
166         data->gfx_activity_average_alpha = PPVEGA10_VEGA10GFXACTIVITYAVERAGEALPHA_DFLT;
167 }
168
169 static int vega10_set_features_platform_caps(struct pp_hwmgr *hwmgr)
170 {
171         struct vega10_hwmgr *data =
172                         (struct vega10_hwmgr *)(hwmgr->backend);
173         struct phm_ppt_v2_information *table_info =
174                         (struct phm_ppt_v2_information *)hwmgr->pptable;
175         struct cgs_system_info sys_info = {0};
176         int result;
177
178         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
179                         PHM_PlatformCaps_SclkDeepSleep);
180
181         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
182                         PHM_PlatformCaps_DynamicPatchPowerState);
183
184         if (data->vddci_control == VEGA10_VOLTAGE_CONTROL_NONE)
185                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
186                                 PHM_PlatformCaps_ControlVDDCI);
187
188         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
189                         PHM_PlatformCaps_TablelessHardwareInterface);
190
191         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
192                         PHM_PlatformCaps_EnableSMU7ThermalManagement);
193
194         sys_info.size = sizeof(struct cgs_system_info);
195         sys_info.info_id = CGS_SYSTEM_INFO_PG_FLAGS;
196         result = cgs_query_system_info(hwmgr->device, &sys_info);
197
198         if (!result && (sys_info.value & AMD_PG_SUPPORT_UVD))
199                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
200                                 PHM_PlatformCaps_UVDPowerGating);
201
202         if (!result && (sys_info.value & AMD_PG_SUPPORT_VCE))
203                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
204                                 PHM_PlatformCaps_VCEPowerGating);
205
206         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
207                         PHM_PlatformCaps_UnTabledHardwareInterface);
208
209         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
210                         PHM_PlatformCaps_FanSpeedInTableIsRPM);
211
212         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
213                         PHM_PlatformCaps_ODFuzzyFanControlSupport);
214
215         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
216                                 PHM_PlatformCaps_DynamicPowerManagement);
217
218         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
219                         PHM_PlatformCaps_SMC);
220
221         /* power tune caps */
222         /* assume disabled */
223         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
224                         PHM_PlatformCaps_PowerContainment);
225         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
226                         PHM_PlatformCaps_SQRamping);
227         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
228                         PHM_PlatformCaps_DBRamping);
229         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
230                         PHM_PlatformCaps_TDRamping);
231         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
232                         PHM_PlatformCaps_TCPRamping);
233
234         if (data->registry_data.power_containment_support)
235                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
236                                 PHM_PlatformCaps_PowerContainment);
237         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
238                         PHM_PlatformCaps_CAC);
239
240         if (table_info->tdp_table->usClockStretchAmount &&
241                         data->registry_data.clock_stretcher_support)
242                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
243                                 PHM_PlatformCaps_ClockStretcher);
244
245         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
246                         PHM_PlatformCaps_RegulatorHot);
247         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
248                         PHM_PlatformCaps_AutomaticDCTransition);
249
250         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
251                         PHM_PlatformCaps_UVDDPM);
252         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
253                         PHM_PlatformCaps_VCEDPM);
254
255         return 0;
256 }
257
258 static void vega10_init_dpm_defaults(struct pp_hwmgr *hwmgr)
259 {
260         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
261         int i;
262
263         vega10_initialize_power_tune_defaults(hwmgr);
264
265         for (i = 0; i < GNLD_FEATURES_MAX; i++) {
266                 data->smu_features[i].smu_feature_id = 0xffff;
267                 data->smu_features[i].smu_feature_bitmap = 1 << i;
268                 data->smu_features[i].enabled = false;
269                 data->smu_features[i].supported = false;
270         }
271
272         data->smu_features[GNLD_DPM_PREFETCHER].smu_feature_id =
273                         FEATURE_DPM_PREFETCHER_BIT;
274         data->smu_features[GNLD_DPM_GFXCLK].smu_feature_id =
275                         FEATURE_DPM_GFXCLK_BIT;
276         data->smu_features[GNLD_DPM_UCLK].smu_feature_id =
277                         FEATURE_DPM_UCLK_BIT;
278         data->smu_features[GNLD_DPM_SOCCLK].smu_feature_id =
279                         FEATURE_DPM_SOCCLK_BIT;
280         data->smu_features[GNLD_DPM_UVD].smu_feature_id =
281                         FEATURE_DPM_UVD_BIT;
282         data->smu_features[GNLD_DPM_VCE].smu_feature_id =
283                         FEATURE_DPM_VCE_BIT;
284         data->smu_features[GNLD_DPM_MP0CLK].smu_feature_id =
285                         FEATURE_DPM_MP0CLK_BIT;
286         data->smu_features[GNLD_DPM_LINK].smu_feature_id =
287                         FEATURE_DPM_LINK_BIT;
288         data->smu_features[GNLD_DPM_DCEFCLK].smu_feature_id =
289                         FEATURE_DPM_DCEFCLK_BIT;
290         data->smu_features[GNLD_ULV].smu_feature_id =
291                         FEATURE_ULV_BIT;
292         data->smu_features[GNLD_AVFS].smu_feature_id =
293                         FEATURE_AVFS_BIT;
294         data->smu_features[GNLD_DS_GFXCLK].smu_feature_id =
295                         FEATURE_DS_GFXCLK_BIT;
296         data->smu_features[GNLD_DS_SOCCLK].smu_feature_id =
297                         FEATURE_DS_SOCCLK_BIT;
298         data->smu_features[GNLD_DS_LCLK].smu_feature_id =
299                         FEATURE_DS_LCLK_BIT;
300         data->smu_features[GNLD_PPT].smu_feature_id =
301                         FEATURE_PPT_BIT;
302         data->smu_features[GNLD_TDC].smu_feature_id =
303                         FEATURE_TDC_BIT;
304         data->smu_features[GNLD_THERMAL].smu_feature_id =
305                         FEATURE_THERMAL_BIT;
306         data->smu_features[GNLD_GFX_PER_CU_CG].smu_feature_id =
307                         FEATURE_GFX_PER_CU_CG_BIT;
308         data->smu_features[GNLD_RM].smu_feature_id =
309                         FEATURE_RM_BIT;
310         data->smu_features[GNLD_DS_DCEFCLK].smu_feature_id =
311                         FEATURE_DS_DCEFCLK_BIT;
312         data->smu_features[GNLD_ACDC].smu_feature_id =
313                         FEATURE_ACDC_BIT;
314         data->smu_features[GNLD_VR0HOT].smu_feature_id =
315                         FEATURE_VR0HOT_BIT;
316         data->smu_features[GNLD_VR1HOT].smu_feature_id =
317                         FEATURE_VR1HOT_BIT;
318         data->smu_features[GNLD_FW_CTF].smu_feature_id =
319                         FEATURE_FW_CTF_BIT;
320         data->smu_features[GNLD_LED_DISPLAY].smu_feature_id =
321                         FEATURE_LED_DISPLAY_BIT;
322         data->smu_features[GNLD_FAN_CONTROL].smu_feature_id =
323                         FEATURE_FAN_CONTROL_BIT;
324         data->smu_features[GNLD_VOLTAGE_CONTROLLER].smu_feature_id =
325                         FEATURE_VOLTAGE_CONTROLLER_BIT;
326
327         if (!data->registry_data.prefetcher_dpm_key_disabled)
328                 data->smu_features[GNLD_DPM_PREFETCHER].supported = true;
329
330         if (!data->registry_data.sclk_dpm_key_disabled)
331                 data->smu_features[GNLD_DPM_GFXCLK].supported = true;
332
333         if (!data->registry_data.mclk_dpm_key_disabled)
334                 data->smu_features[GNLD_DPM_UCLK].supported = true;
335
336         if (!data->registry_data.socclk_dpm_key_disabled)
337                 data->smu_features[GNLD_DPM_SOCCLK].supported = true;
338
339         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
340                         PHM_PlatformCaps_UVDDPM))
341                 data->smu_features[GNLD_DPM_UVD].supported = true;
342
343         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
344                         PHM_PlatformCaps_VCEDPM))
345                 data->smu_features[GNLD_DPM_VCE].supported = true;
346
347         if (!data->registry_data.pcie_dpm_key_disabled)
348                 data->smu_features[GNLD_DPM_LINK].supported = true;
349
350         if (!data->registry_data.dcefclk_dpm_key_disabled)
351                 data->smu_features[GNLD_DPM_DCEFCLK].supported = true;
352
353         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
354                         PHM_PlatformCaps_SclkDeepSleep) &&
355                         data->registry_data.sclk_deep_sleep_support) {
356                 data->smu_features[GNLD_DS_GFXCLK].supported = true;
357                 data->smu_features[GNLD_DS_SOCCLK].supported = true;
358                 data->smu_features[GNLD_DS_LCLK].supported = true;
359                 data->smu_features[GNLD_DS_DCEFCLK].supported = true;
360         }
361
362         if (data->registry_data.enable_pkg_pwr_tracking_feature)
363                 data->smu_features[GNLD_PPT].supported = true;
364
365         if (data->registry_data.enable_tdc_limit_feature)
366                 data->smu_features[GNLD_TDC].supported = true;
367
368         if (data->registry_data.thermal_support)
369                 data->smu_features[GNLD_THERMAL].supported = true;
370
371         if (data->registry_data.fan_control_support)
372                 data->smu_features[GNLD_FAN_CONTROL].supported = true;
373
374         if (data->registry_data.fw_ctf_enabled)
375                 data->smu_features[GNLD_FW_CTF].supported = true;
376
377         if (data->registry_data.avfs_support)
378                 data->smu_features[GNLD_AVFS].supported = true;
379
380         if (data->registry_data.led_dpm_enabled)
381                 data->smu_features[GNLD_LED_DISPLAY].supported = true;
382
383         if (data->registry_data.vr1hot_enabled)
384                 data->smu_features[GNLD_VR1HOT].supported = true;
385
386         if (data->registry_data.vr0hot_enabled)
387                 data->smu_features[GNLD_VR0HOT].supported = true;
388
389 }
390
391 #ifdef PPLIB_VEGA10_EVV_SUPPORT
392 static int vega10_get_socclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
393         phm_ppt_v1_voltage_lookup_table *lookup_table,
394         uint16_t virtual_voltage_id, int32_t *socclk)
395 {
396         uint8_t entry_id;
397         uint8_t voltage_id;
398         struct phm_ppt_v2_information *table_info =
399                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
400
401         PP_ASSERT_WITH_CODE(lookup_table->count != 0,
402                         "Lookup table is empty",
403                         return -EINVAL);
404
405         /* search for leakage voltage ID 0xff01 ~ 0xff08 and sclk */
406         for (entry_id = 0; entry_id < table_info->vdd_dep_on_sclk->count; entry_id++) {
407                 voltage_id = table_info->vdd_dep_on_socclk->entries[entry_id].vddInd;
408                 if (lookup_table->entries[voltage_id].us_vdd == virtual_voltage_id)
409                         break;
410         }
411
412         PP_ASSERT_WITH_CODE(entry_id < table_info->vdd_dep_on_socclk->count,
413                         "Can't find requested voltage id in vdd_dep_on_socclk table!",
414                         return -EINVAL);
415
416         *socclk = table_info->vdd_dep_on_socclk->entries[entry_id].clk;
417
418         return 0;
419 }
420
421 #define ATOM_VIRTUAL_VOLTAGE_ID0             0xff01
422 /**
423 * Get Leakage VDDC based on leakage ID.
424 *
425 * @param    hwmgr  the address of the powerplay hardware manager.
426 * @return   always 0.
427 */
428 static int vega10_get_evv_voltages(struct pp_hwmgr *hwmgr)
429 {
430         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
431         uint16_t vv_id;
432         uint32_t vddc = 0;
433         uint16_t i, j;
434         uint32_t sclk = 0;
435         struct phm_ppt_v2_information *table_info =
436                         (struct phm_ppt_v2_information *)hwmgr->pptable;
437         struct phm_ppt_v1_clock_voltage_dependency_table *socclk_table =
438                         table_info->vdd_dep_on_socclk;
439         int result;
440
441         for (i = 0; i < VEGA10_MAX_LEAKAGE_COUNT; i++) {
442                 vv_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
443
444                 if (!vega10_get_socclk_for_voltage_evv(hwmgr,
445                                 table_info->vddc_lookup_table, vv_id, &sclk)) {
446                         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
447                                         PHM_PlatformCaps_ClockStretcher)) {
448                                 for (j = 1; j < socclk_table->count; j++) {
449                                         if (socclk_table->entries[j].clk == sclk &&
450                                                         socclk_table->entries[j].cks_enable == 0) {
451                                                 sclk += 5000;
452                                                 break;
453                                         }
454                                 }
455                         }
456
457                         PP_ASSERT_WITH_CODE(!atomctrl_get_voltage_evv_on_sclk_ai(hwmgr,
458                                         VOLTAGE_TYPE_VDDC, sclk, vv_id, &vddc),
459                                         "Error retrieving EVV voltage value!",
460                                         continue);
461
462
463                         /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
464                         PP_ASSERT_WITH_CODE((vddc < 2000 && vddc != 0),
465                                         "Invalid VDDC value", result = -EINVAL;);
466
467                         /* the voltage should not be zero nor equal to leakage ID */
468                         if (vddc != 0 && vddc != vv_id) {
469                                 data->vddc_leakage.actual_voltage[data->vddc_leakage.count] = (uint16_t)(vddc/100);
470                                 data->vddc_leakage.leakage_id[data->vddc_leakage.count] = vv_id;
471                                 data->vddc_leakage.count++;
472                         }
473                 }
474         }
475
476         return 0;
477 }
478
479 /**
480  * Change virtual leakage voltage to actual value.
481  *
482  * @param     hwmgr  the address of the powerplay hardware manager.
483  * @param     pointer to changing voltage
484  * @param     pointer to leakage table
485  */
486 static void vega10_patch_with_vdd_leakage(struct pp_hwmgr *hwmgr,
487                 uint16_t *voltage, struct vega10_leakage_voltage *leakage_table)
488 {
489         uint32_t index;
490
491         /* search for leakage voltage ID 0xff01 ~ 0xff08 */
492         for (index = 0; index < leakage_table->count; index++) {
493                 /* if this voltage matches a leakage voltage ID */
494                 /* patch with actual leakage voltage */
495                 if (leakage_table->leakage_id[index] == *voltage) {
496                         *voltage = leakage_table->actual_voltage[index];
497                         break;
498                 }
499         }
500
501         if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
502                 pr_info("Voltage value looks like a Leakage ID \
503                                 but it's not patched\n");
504 }
505
506 /**
507 * Patch voltage lookup table by EVV leakages.
508 *
509 * @param     hwmgr  the address of the powerplay hardware manager.
510 * @param     pointer to voltage lookup table
511 * @param     pointer to leakage table
512 * @return     always 0
513 */
514 static int vega10_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
515                 phm_ppt_v1_voltage_lookup_table *lookup_table,
516                 struct vega10_leakage_voltage *leakage_table)
517 {
518         uint32_t i;
519
520         for (i = 0; i < lookup_table->count; i++)
521                 vega10_patch_with_vdd_leakage(hwmgr,
522                                 &lookup_table->entries[i].us_vdd, leakage_table);
523
524         return 0;
525 }
526
527 static int vega10_patch_clock_voltage_limits_with_vddc_leakage(
528                 struct pp_hwmgr *hwmgr, struct vega10_leakage_voltage *leakage_table,
529                 uint16_t *vddc)
530 {
531         vega10_patch_with_vdd_leakage(hwmgr, (uint16_t *)vddc, leakage_table);
532
533         return 0;
534 }
535 #endif
536
537 static int vega10_patch_voltage_dependency_tables_with_lookup_table(
538                 struct pp_hwmgr *hwmgr)
539 {
540         uint8_t entry_id;
541         uint8_t voltage_id;
542         struct phm_ppt_v2_information *table_info =
543                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
544         struct phm_ppt_v1_clock_voltage_dependency_table *socclk_table =
545                         table_info->vdd_dep_on_socclk;
546         struct phm_ppt_v1_clock_voltage_dependency_table *gfxclk_table =
547                         table_info->vdd_dep_on_sclk;
548         struct phm_ppt_v1_clock_voltage_dependency_table *dcefclk_table =
549                         table_info->vdd_dep_on_dcefclk;
550         struct phm_ppt_v1_clock_voltage_dependency_table *pixclk_table =
551                         table_info->vdd_dep_on_pixclk;
552         struct phm_ppt_v1_clock_voltage_dependency_table *dspclk_table =
553                         table_info->vdd_dep_on_dispclk;
554         struct phm_ppt_v1_clock_voltage_dependency_table *phyclk_table =
555                         table_info->vdd_dep_on_phyclk;
556         struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table =
557                         table_info->vdd_dep_on_mclk;
558         struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
559                         table_info->mm_dep_table;
560
561         for (entry_id = 0; entry_id < socclk_table->count; entry_id++) {
562                 voltage_id = socclk_table->entries[entry_id].vddInd;
563                 socclk_table->entries[entry_id].vddc =
564                                 table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
565         }
566
567         for (entry_id = 0; entry_id < gfxclk_table->count; entry_id++) {
568                 voltage_id = gfxclk_table->entries[entry_id].vddInd;
569                 gfxclk_table->entries[entry_id].vddc =
570                                 table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
571         }
572
573         for (entry_id = 0; entry_id < dcefclk_table->count; entry_id++) {
574                 voltage_id = dcefclk_table->entries[entry_id].vddInd;
575                 dcefclk_table->entries[entry_id].vddc =
576                                 table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
577         }
578
579         for (entry_id = 0; entry_id < pixclk_table->count; entry_id++) {
580                 voltage_id = pixclk_table->entries[entry_id].vddInd;
581                 pixclk_table->entries[entry_id].vddc =
582                                 table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
583         }
584
585         for (entry_id = 0; entry_id < dspclk_table->count; entry_id++) {
586                 voltage_id = dspclk_table->entries[entry_id].vddInd;
587                 dspclk_table->entries[entry_id].vddc =
588                                 table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
589         }
590
591         for (entry_id = 0; entry_id < phyclk_table->count; entry_id++) {
592                 voltage_id = phyclk_table->entries[entry_id].vddInd;
593                 phyclk_table->entries[entry_id].vddc =
594                                 table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
595         }
596
597         for (entry_id = 0; entry_id < mclk_table->count; ++entry_id) {
598                 voltage_id = mclk_table->entries[entry_id].vddInd;
599                 mclk_table->entries[entry_id].vddc =
600                                 table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
601                 voltage_id = mclk_table->entries[entry_id].vddciInd;
602                 mclk_table->entries[entry_id].vddci =
603                                 table_info->vddci_lookup_table->entries[voltage_id].us_vdd;
604                 voltage_id = mclk_table->entries[entry_id].mvddInd;
605                 mclk_table->entries[entry_id].mvdd =
606                                 table_info->vddmem_lookup_table->entries[voltage_id].us_vdd;
607         }
608
609         for (entry_id = 0; entry_id < mm_table->count; ++entry_id) {
610                 voltage_id = mm_table->entries[entry_id].vddcInd;
611                 mm_table->entries[entry_id].vddc =
612                         table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
613         }
614
615         return 0;
616
617 }
618
619 static int vega10_sort_lookup_table(struct pp_hwmgr *hwmgr,
620                 struct phm_ppt_v1_voltage_lookup_table *lookup_table)
621 {
622         uint32_t table_size, i, j;
623         struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record;
624
625         PP_ASSERT_WITH_CODE(lookup_table && lookup_table->count,
626                 "Lookup table is empty", return -EINVAL);
627
628         table_size = lookup_table->count;
629
630         /* Sorting voltages */
631         for (i = 0; i < table_size - 1; i++) {
632                 for (j = i + 1; j > 0; j--) {
633                         if (lookup_table->entries[j].us_vdd <
634                                         lookup_table->entries[j - 1].us_vdd) {
635                                 tmp_voltage_lookup_record = lookup_table->entries[j - 1];
636                                 lookup_table->entries[j - 1] = lookup_table->entries[j];
637                                 lookup_table->entries[j] = tmp_voltage_lookup_record;
638                         }
639                 }
640         }
641
642         return 0;
643 }
644
645 static int vega10_complete_dependency_tables(struct pp_hwmgr *hwmgr)
646 {
647         int result = 0;
648         int tmp_result;
649         struct phm_ppt_v2_information *table_info =
650                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
651 #ifdef PPLIB_VEGA10_EVV_SUPPORT
652         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
653
654         tmp_result = vega10_patch_lookup_table_with_leakage(hwmgr,
655                         table_info->vddc_lookup_table, &(data->vddc_leakage));
656         if (tmp_result)
657                 result = tmp_result;
658
659         tmp_result = vega10_patch_clock_voltage_limits_with_vddc_leakage(hwmgr,
660                         &(data->vddc_leakage), &table_info->max_clock_voltage_on_dc.vddc);
661         if (tmp_result)
662                 result = tmp_result;
663 #endif
664
665         tmp_result = vega10_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
666         if (tmp_result)
667                 result = tmp_result;
668
669         tmp_result = vega10_sort_lookup_table(hwmgr, table_info->vddc_lookup_table);
670         if (tmp_result)
671                 result = tmp_result;
672
673         return result;
674 }
675
676 static int vega10_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
677 {
678         struct phm_ppt_v2_information *table_info =
679                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
680         struct phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
681                         table_info->vdd_dep_on_socclk;
682         struct phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
683                         table_info->vdd_dep_on_mclk;
684
685         PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table,
686                 "VDD dependency on SCLK table is missing. \
687                 This table is mandatory", return -EINVAL);
688         PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
689                 "VDD dependency on SCLK table is empty. \
690                 This table is mandatory", return -EINVAL);
691
692         PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table,
693                 "VDD dependency on MCLK table is missing. \
694                 This table is mandatory", return -EINVAL);
695         PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
696                 "VDD dependency on MCLK table is empty. \
697                 This table is mandatory", return -EINVAL);
698
699         table_info->max_clock_voltage_on_ac.sclk =
700                 allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
701         table_info->max_clock_voltage_on_ac.mclk =
702                 allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
703         table_info->max_clock_voltage_on_ac.vddc =
704                 allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
705         table_info->max_clock_voltage_on_ac.vddci =
706                 allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
707
708         hwmgr->dyn_state.max_clock_voltage_on_ac.sclk =
709                 table_info->max_clock_voltage_on_ac.sclk;
710         hwmgr->dyn_state.max_clock_voltage_on_ac.mclk =
711                 table_info->max_clock_voltage_on_ac.mclk;
712         hwmgr->dyn_state.max_clock_voltage_on_ac.vddc =
713                 table_info->max_clock_voltage_on_ac.vddc;
714         hwmgr->dyn_state.max_clock_voltage_on_ac.vddci =
715                 table_info->max_clock_voltage_on_ac.vddci;
716
717         return 0;
718 }
719
720 static int vega10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
721 {
722         kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
723         hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
724
725         kfree(hwmgr->backend);
726         hwmgr->backend = NULL;
727
728         return 0;
729 }
730
731 static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
732 {
733         int result = 0;
734         struct vega10_hwmgr *data;
735         uint32_t config_telemetry = 0;
736         struct pp_atomfwctrl_voltage_table vol_table;
737         struct cgs_system_info sys_info = {0};
738
739         data = kzalloc(sizeof(struct vega10_hwmgr), GFP_KERNEL);
740         if (data == NULL)
741                 return -ENOMEM;
742
743         hwmgr->backend = data;
744
745         vega10_set_default_registry_data(hwmgr);
746
747         data->disable_dpm_mask = 0xff;
748         data->workload_mask = 0xff;
749
750         /* need to set voltage control types before EVV patching */
751         data->vddc_control = VEGA10_VOLTAGE_CONTROL_NONE;
752         data->mvdd_control = VEGA10_VOLTAGE_CONTROL_NONE;
753         data->vddci_control = VEGA10_VOLTAGE_CONTROL_NONE;
754
755         /* VDDCR_SOC */
756         if (pp_atomfwctrl_is_voltage_controlled_by_gpio_v4(hwmgr,
757                         VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2)) {
758                 if (!pp_atomfwctrl_get_voltage_table_v4(hwmgr,
759                                 VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2,
760                                 &vol_table)) {
761                         config_telemetry = ((vol_table.telemetry_slope << 8) & 0xff00) |
762                                         (vol_table.telemetry_offset & 0xff);
763                         data->vddc_control = VEGA10_VOLTAGE_CONTROL_BY_SVID2;
764                 }
765         } else {
766                 kfree(hwmgr->backend);
767                 hwmgr->backend = NULL;
768                 PP_ASSERT_WITH_CODE(false,
769                                 "VDDCR_SOC is not SVID2!",
770                                 return -1);
771         }
772
773         /* MVDDC */
774         if (pp_atomfwctrl_is_voltage_controlled_by_gpio_v4(hwmgr,
775                         VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2)) {
776                 if (!pp_atomfwctrl_get_voltage_table_v4(hwmgr,
777                                 VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2,
778                                 &vol_table)) {
779                         config_telemetry |=
780                                         ((vol_table.telemetry_slope << 24) & 0xff000000) |
781                                         ((vol_table.telemetry_offset << 16) & 0xff0000);
782                         data->mvdd_control = VEGA10_VOLTAGE_CONTROL_BY_SVID2;
783                 }
784         }
785
786          /* VDDCI_MEM */
787         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
788                         PHM_PlatformCaps_ControlVDDCI)) {
789                 if (pp_atomfwctrl_is_voltage_controlled_by_gpio_v4(hwmgr,
790                                 VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
791                         data->vddci_control = VEGA10_VOLTAGE_CONTROL_BY_GPIO;
792         }
793
794         data->config_telemetry = config_telemetry;
795
796         vega10_set_features_platform_caps(hwmgr);
797
798         vega10_init_dpm_defaults(hwmgr);
799
800 #ifdef PPLIB_VEGA10_EVV_SUPPORT
801         /* Get leakage voltage based on leakage ID. */
802         PP_ASSERT_WITH_CODE(!vega10_get_evv_voltages(hwmgr),
803                         "Get EVV Voltage Failed.  Abort Driver loading!",
804                         return -1);
805 #endif
806
807         /* Patch our voltage dependency table with actual leakage voltage
808          * We need to perform leakage translation before it's used by other functions
809          */
810         vega10_complete_dependency_tables(hwmgr);
811
812         /* Parse pptable data read from VBIOS */
813         vega10_set_private_data_based_on_pptable(hwmgr);
814
815         data->is_tlu_enabled = false;
816
817         hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
818                         VEGA10_MAX_HARDWARE_POWERLEVELS;
819         hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
820         hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50;
821
822         hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */
823         /* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */
824         hwmgr->platform_descriptor.clockStep.engineClock = 500;
825         hwmgr->platform_descriptor.clockStep.memoryClock = 500;
826
827         sys_info.size = sizeof(struct cgs_system_info);
828         sys_info.info_id = CGS_SYSTEM_INFO_GFX_CU_INFO;
829         result = cgs_query_system_info(hwmgr->device, &sys_info);
830         data->total_active_cus = sys_info.value;
831         /* Setup default Overdrive Fan control settings */
832         data->odn_fan_table.target_fan_speed =
833                         hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM;
834         data->odn_fan_table.target_temperature =
835                         hwmgr->thermal_controller.
836                         advanceFanControlParameters.ucTargetTemperature;
837         data->odn_fan_table.min_performance_clock =
838                         hwmgr->thermal_controller.advanceFanControlParameters.
839                         ulMinFanSCLKAcousticLimit;
840         data->odn_fan_table.min_fan_limit =
841                         hwmgr->thermal_controller.
842                         advanceFanControlParameters.usFanPWMMinLimit *
843                         hwmgr->thermal_controller.fanInfo.ulMaxRPM / 100;
844
845         return result;
846 }
847
848 static int vega10_init_sclk_threshold(struct pp_hwmgr *hwmgr)
849 {
850         struct vega10_hwmgr *data =
851                         (struct vega10_hwmgr *)(hwmgr->backend);
852
853         data->low_sclk_interrupt_threshold = 0;
854
855         return 0;
856 }
857
858 static int vega10_setup_dpm_led_config(struct pp_hwmgr *hwmgr)
859 {
860         struct vega10_hwmgr *data =
861                         (struct vega10_hwmgr *)(hwmgr->backend);
862         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
863
864         struct pp_atomfwctrl_voltage_table table;
865         uint8_t i, j;
866         uint32_t mask = 0;
867         uint32_t tmp;
868         int32_t ret = 0;
869
870         ret = pp_atomfwctrl_get_voltage_table_v4(hwmgr, VOLTAGE_TYPE_LEDDPM,
871                                                 VOLTAGE_OBJ_GPIO_LUT, &table);
872
873         if (!ret) {
874                 tmp = table.mask_low;
875                 for (i = 0, j = 0; i < 32; i++) {
876                         if (tmp & 1) {
877                                 mask |= (uint32_t)(i << (8 * j));
878                                 if (++j >= 3)
879                                         break;
880                         }
881                         tmp >>= 1;
882                 }
883         }
884
885         pp_table->LedPin0 = (uint8_t)(mask & 0xff);
886         pp_table->LedPin1 = (uint8_t)((mask >> 8) & 0xff);
887         pp_table->LedPin2 = (uint8_t)((mask >> 16) & 0xff);
888         return 0;
889 }
890
891 static int vega10_setup_asic_task(struct pp_hwmgr *hwmgr)
892 {
893         PP_ASSERT_WITH_CODE(!vega10_init_sclk_threshold(hwmgr),
894                         "Failed to init sclk threshold!",
895                         return -EINVAL);
896
897         PP_ASSERT_WITH_CODE(!vega10_setup_dpm_led_config(hwmgr),
898                         "Failed to set up led dpm config!",
899                         return -EINVAL);
900
901         return 0;
902 }
903
904 static bool vega10_is_dpm_running(struct pp_hwmgr *hwmgr)
905 {
906         uint32_t features_enabled;
907
908         if (!vega10_get_smc_features(hwmgr->smumgr, &features_enabled)) {
909                 if (features_enabled & SMC_DPM_FEATURES)
910                         return true;
911         }
912         return false;
913 }
914
915 /**
916 * Remove repeated voltage values and create table with unique values.
917 *
918 * @param    hwmgr  the address of the powerplay hardware manager.
919 * @param    vol_table  the pointer to changing voltage table
920 * @return    0 in success
921 */
922
923 static int vega10_trim_voltage_table(struct pp_hwmgr *hwmgr,
924                 struct pp_atomfwctrl_voltage_table *vol_table)
925 {
926         uint32_t i, j;
927         uint16_t vvalue;
928         bool found = false;
929         struct pp_atomfwctrl_voltage_table *table;
930
931         PP_ASSERT_WITH_CODE(vol_table,
932                         "Voltage Table empty.", return -EINVAL);
933         table = kzalloc(sizeof(struct pp_atomfwctrl_voltage_table),
934                         GFP_KERNEL);
935
936         if (!table)
937                 return -ENOMEM;
938
939         table->mask_low = vol_table->mask_low;
940         table->phase_delay = vol_table->phase_delay;
941
942         for (i = 0; i < vol_table->count; i++) {
943                 vvalue = vol_table->entries[i].value;
944                 found = false;
945
946                 for (j = 0; j < table->count; j++) {
947                         if (vvalue == table->entries[j].value) {
948                                 found = true;
949                                 break;
950                         }
951                 }
952
953                 if (!found) {
954                         table->entries[table->count].value = vvalue;
955                         table->entries[table->count].smio_low =
956                                         vol_table->entries[i].smio_low;
957                         table->count++;
958                 }
959         }
960
961         memcpy(vol_table, table, sizeof(struct pp_atomfwctrl_voltage_table));
962         kfree(table);
963
964         return 0;
965 }
966
967 static int vega10_get_mvdd_voltage_table(struct pp_hwmgr *hwmgr,
968                 phm_ppt_v1_clock_voltage_dependency_table *dep_table,
969                 struct pp_atomfwctrl_voltage_table *vol_table)
970 {
971         int i;
972
973         PP_ASSERT_WITH_CODE(dep_table->count,
974                         "Voltage Dependency Table empty.",
975                         return -EINVAL);
976
977         vol_table->mask_low = 0;
978         vol_table->phase_delay = 0;
979         vol_table->count = dep_table->count;
980
981         for (i = 0; i < vol_table->count; i++) {
982                 vol_table->entries[i].value = dep_table->entries[i].mvdd;
983                 vol_table->entries[i].smio_low = 0;
984         }
985
986         PP_ASSERT_WITH_CODE(!vega10_trim_voltage_table(hwmgr,
987                         vol_table),
988                         "Failed to trim MVDD Table!",
989                         return -1);
990
991         return 0;
992 }
993
994 static int vega10_get_vddci_voltage_table(struct pp_hwmgr *hwmgr,
995                 phm_ppt_v1_clock_voltage_dependency_table *dep_table,
996                 struct pp_atomfwctrl_voltage_table *vol_table)
997 {
998         uint32_t i;
999
1000         PP_ASSERT_WITH_CODE(dep_table->count,
1001                         "Voltage Dependency Table empty.",
1002                         return -EINVAL);
1003
1004         vol_table->mask_low = 0;
1005         vol_table->phase_delay = 0;
1006         vol_table->count = dep_table->count;
1007
1008         for (i = 0; i < dep_table->count; i++) {
1009                 vol_table->entries[i].value = dep_table->entries[i].vddci;
1010                 vol_table->entries[i].smio_low = 0;
1011         }
1012
1013         PP_ASSERT_WITH_CODE(!vega10_trim_voltage_table(hwmgr, vol_table),
1014                         "Failed to trim VDDCI table.",
1015                         return -1);
1016
1017         return 0;
1018 }
1019
1020 static int vega10_get_vdd_voltage_table(struct pp_hwmgr *hwmgr,
1021                 phm_ppt_v1_clock_voltage_dependency_table *dep_table,
1022                 struct pp_atomfwctrl_voltage_table *vol_table)
1023 {
1024         int i;
1025
1026         PP_ASSERT_WITH_CODE(dep_table->count,
1027                         "Voltage Dependency Table empty.",
1028                         return -EINVAL);
1029
1030         vol_table->mask_low = 0;
1031         vol_table->phase_delay = 0;
1032         vol_table->count = dep_table->count;
1033
1034         for (i = 0; i < vol_table->count; i++) {
1035                 vol_table->entries[i].value = dep_table->entries[i].vddc;
1036                 vol_table->entries[i].smio_low = 0;
1037         }
1038
1039         return 0;
1040 }
1041
1042 /* ---- Voltage Tables ----
1043  * If the voltage table would be bigger than
1044  * what will fit into the state table on
1045  * the SMC keep only the higher entries.
1046  */
1047 static void vega10_trim_voltage_table_to_fit_state_table(
1048                 struct pp_hwmgr *hwmgr,
1049                 uint32_t max_vol_steps,
1050                 struct pp_atomfwctrl_voltage_table *vol_table)
1051 {
1052         unsigned int i, diff;
1053
1054         if (vol_table->count <= max_vol_steps)
1055                 return;
1056
1057         diff = vol_table->count - max_vol_steps;
1058
1059         for (i = 0; i < max_vol_steps; i++)
1060                 vol_table->entries[i] = vol_table->entries[i + diff];
1061
1062         vol_table->count = max_vol_steps;
1063 }
1064
1065 /**
1066 * Create Voltage Tables.
1067 *
1068 * @param    hwmgr  the address of the powerplay hardware manager.
1069 * @return   always 0
1070 */
1071 static int vega10_construct_voltage_tables(struct pp_hwmgr *hwmgr)
1072 {
1073         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
1074         struct phm_ppt_v2_information *table_info =
1075                         (struct phm_ppt_v2_information *)hwmgr->pptable;
1076         int result;
1077
1078         if (data->mvdd_control == VEGA10_VOLTAGE_CONTROL_BY_SVID2 ||
1079                         data->mvdd_control == VEGA10_VOLTAGE_CONTROL_NONE) {
1080                 result = vega10_get_mvdd_voltage_table(hwmgr,
1081                                 table_info->vdd_dep_on_mclk,
1082                                 &(data->mvdd_voltage_table));
1083                 PP_ASSERT_WITH_CODE(!result,
1084                                 "Failed to retrieve MVDDC table!",
1085                                 return result);
1086         }
1087
1088         if (data->vddci_control == VEGA10_VOLTAGE_CONTROL_NONE) {
1089                 result = vega10_get_vddci_voltage_table(hwmgr,
1090                                 table_info->vdd_dep_on_mclk,
1091                                 &(data->vddci_voltage_table));
1092                 PP_ASSERT_WITH_CODE(!result,
1093                                 "Failed to retrieve VDDCI_MEM table!",
1094                                 return result);
1095         }
1096
1097         if (data->vddc_control == VEGA10_VOLTAGE_CONTROL_BY_SVID2 ||
1098                         data->vddc_control == VEGA10_VOLTAGE_CONTROL_NONE) {
1099                 result = vega10_get_vdd_voltage_table(hwmgr,
1100                                 table_info->vdd_dep_on_sclk,
1101                                 &(data->vddc_voltage_table));
1102                 PP_ASSERT_WITH_CODE(!result,
1103                                 "Failed to retrieve VDDCR_SOC table!",
1104                                 return result);
1105         }
1106
1107         PP_ASSERT_WITH_CODE(data->vddc_voltage_table.count <= 16,
1108                         "Too many voltage values for VDDC. Trimming to fit state table.",
1109                         vega10_trim_voltage_table_to_fit_state_table(hwmgr,
1110                                         16, &(data->vddc_voltage_table)));
1111
1112         PP_ASSERT_WITH_CODE(data->vddci_voltage_table.count <= 16,
1113                         "Too many voltage values for VDDCI. Trimming to fit state table.",
1114                         vega10_trim_voltage_table_to_fit_state_table(hwmgr,
1115                                         16, &(data->vddci_voltage_table)));
1116
1117         PP_ASSERT_WITH_CODE(data->mvdd_voltage_table.count <= 16,
1118                         "Too many voltage values for MVDD. Trimming to fit state table.",
1119                         vega10_trim_voltage_table_to_fit_state_table(hwmgr,
1120                                         16, &(data->mvdd_voltage_table)));
1121
1122
1123         return 0;
1124 }
1125
1126 /*
1127  * @fn vega10_init_dpm_state
1128  * @brief Function to initialize all Soft Min/Max and Hard Min/Max to 0xff.
1129  *
1130  * @param    dpm_state - the address of the DPM Table to initiailize.
1131  * @return   None.
1132  */
1133 static void vega10_init_dpm_state(struct vega10_dpm_state *dpm_state)
1134 {
1135         dpm_state->soft_min_level = 0xff;
1136         dpm_state->soft_max_level = 0xff;
1137         dpm_state->hard_min_level = 0xff;
1138         dpm_state->hard_max_level = 0xff;
1139 }
1140
1141 static void vega10_setup_default_single_dpm_table(struct pp_hwmgr *hwmgr,
1142                 struct vega10_single_dpm_table *dpm_table,
1143                 struct phm_ppt_v1_clock_voltage_dependency_table *dep_table)
1144 {
1145         int i;
1146
1147         for (i = 0; i < dep_table->count; i++) {
1148                 if (i == 0 || dpm_table->dpm_levels[dpm_table->count - 1].value <=
1149                                 dep_table->entries[i].clk) {
1150                         dpm_table->dpm_levels[dpm_table->count].value =
1151                                         dep_table->entries[i].clk;
1152                         dpm_table->dpm_levels[dpm_table->count].enabled = true;
1153                         dpm_table->count++;
1154                 }
1155         }
1156 }
1157 static int vega10_setup_default_pcie_table(struct pp_hwmgr *hwmgr)
1158 {
1159         struct vega10_hwmgr *data =
1160                         (struct vega10_hwmgr *)(hwmgr->backend);
1161         struct vega10_pcie_table *pcie_table = &(data->dpm_table.pcie_table);
1162         struct phm_ppt_v2_information *table_info =
1163                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
1164         struct phm_ppt_v1_pcie_table *bios_pcie_table =
1165                         table_info->pcie_table;
1166         uint32_t i;
1167
1168         PP_ASSERT_WITH_CODE(bios_pcie_table->count,
1169                         "Incorrect number of PCIE States from VBIOS!",
1170                         return -1);
1171
1172         for (i = 0; i < NUM_LINK_LEVELS; i++) {
1173                 if (data->registry_data.pcieSpeedOverride)
1174                         pcie_table->pcie_gen[i] =
1175                                         data->registry_data.pcieSpeedOverride;
1176                 else
1177                         pcie_table->pcie_gen[i] =
1178                                         bios_pcie_table->entries[i].gen_speed;
1179
1180                 if (data->registry_data.pcieLaneOverride)
1181                         pcie_table->pcie_lane[i] = (uint8_t)encode_pcie_lane_width(
1182                                         data->registry_data.pcieLaneOverride);
1183                 else
1184                         pcie_table->pcie_lane[i] = (uint8_t)encode_pcie_lane_width(
1185                                                         bios_pcie_table->entries[i].lane_width);
1186                 if (data->registry_data.pcieClockOverride)
1187                         pcie_table->lclk[i] =
1188                                         data->registry_data.pcieClockOverride;
1189                 else
1190                         pcie_table->lclk[i] =
1191                                         bios_pcie_table->entries[i].pcie_sclk;
1192         }
1193
1194         pcie_table->count = NUM_LINK_LEVELS;
1195
1196         return 0;
1197 }
1198
1199 /*
1200  * This function is to initialize all DPM state tables
1201  * for SMU based on the dependency table.
1202  * Dynamic state patching function will then trim these
1203  * state tables to the allowed range based
1204  * on the power policy or external client requests,
1205  * such as UVD request, etc.
1206  */
1207 static int vega10_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
1208 {
1209         struct vega10_hwmgr *data =
1210                         (struct vega10_hwmgr *)(hwmgr->backend);
1211         struct phm_ppt_v2_information *table_info =
1212                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
1213         struct vega10_single_dpm_table *dpm_table;
1214         uint32_t i;
1215
1216         struct phm_ppt_v1_clock_voltage_dependency_table *dep_soc_table =
1217                         table_info->vdd_dep_on_socclk;
1218         struct phm_ppt_v1_clock_voltage_dependency_table *dep_gfx_table =
1219                         table_info->vdd_dep_on_sclk;
1220         struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
1221                         table_info->vdd_dep_on_mclk;
1222         struct phm_ppt_v1_mm_clock_voltage_dependency_table *dep_mm_table =
1223                         table_info->mm_dep_table;
1224         struct phm_ppt_v1_clock_voltage_dependency_table *dep_dcef_table =
1225                         table_info->vdd_dep_on_dcefclk;
1226         struct phm_ppt_v1_clock_voltage_dependency_table *dep_pix_table =
1227                         table_info->vdd_dep_on_pixclk;
1228         struct phm_ppt_v1_clock_voltage_dependency_table *dep_disp_table =
1229                         table_info->vdd_dep_on_dispclk;
1230         struct phm_ppt_v1_clock_voltage_dependency_table *dep_phy_table =
1231                         table_info->vdd_dep_on_phyclk;
1232
1233         PP_ASSERT_WITH_CODE(dep_soc_table,
1234                         "SOCCLK dependency table is missing. This table is mandatory",
1235                         return -EINVAL);
1236         PP_ASSERT_WITH_CODE(dep_soc_table->count >= 1,
1237                         "SOCCLK dependency table is empty. This table is mandatory",
1238                         return -EINVAL);
1239
1240         PP_ASSERT_WITH_CODE(dep_gfx_table,
1241                         "GFXCLK dependency table is missing. This table is mandatory",
1242                         return -EINVAL);
1243         PP_ASSERT_WITH_CODE(dep_gfx_table->count >= 1,
1244                         "GFXCLK dependency table is empty. This table is mandatory",
1245                         return -EINVAL);
1246
1247         PP_ASSERT_WITH_CODE(dep_mclk_table,
1248                         "MCLK dependency table is missing. This table is mandatory",
1249                         return -EINVAL);
1250         PP_ASSERT_WITH_CODE(dep_mclk_table->count >= 1,
1251                         "MCLK dependency table has to have is missing. This table is mandatory",
1252                         return -EINVAL);
1253
1254         /* Initialize Sclk DPM table based on allow Sclk values */
1255         data->dpm_table.soc_table.count = 0;
1256         data->dpm_table.gfx_table.count = 0;
1257         data->dpm_table.dcef_table.count = 0;
1258
1259         dpm_table = &(data->dpm_table.soc_table);
1260         vega10_setup_default_single_dpm_table(hwmgr,
1261                         dpm_table,
1262                         dep_soc_table);
1263
1264         vega10_init_dpm_state(&(dpm_table->dpm_state));
1265
1266         dpm_table = &(data->dpm_table.gfx_table);
1267         vega10_setup_default_single_dpm_table(hwmgr,
1268                         dpm_table,
1269                         dep_gfx_table);
1270         vega10_init_dpm_state(&(dpm_table->dpm_state));
1271
1272         /* Initialize Mclk DPM table based on allow Mclk values */
1273         data->dpm_table.mem_table.count = 0;
1274         dpm_table = &(data->dpm_table.mem_table);
1275         vega10_setup_default_single_dpm_table(hwmgr,
1276                         dpm_table,
1277                         dep_mclk_table);
1278         vega10_init_dpm_state(&(dpm_table->dpm_state));
1279
1280         data->dpm_table.eclk_table.count = 0;
1281         dpm_table = &(data->dpm_table.eclk_table);
1282         for (i = 0; i < dep_mm_table->count; i++) {
1283                 if (i == 0 || dpm_table->dpm_levels
1284                                 [dpm_table->count - 1].value <=
1285                                                 dep_mm_table->entries[i].eclk) {
1286                         dpm_table->dpm_levels[dpm_table->count].value =
1287                                         dep_mm_table->entries[i].eclk;
1288                         dpm_table->dpm_levels[dpm_table->count].enabled =
1289                                         (i == 0) ? true : false;
1290                         dpm_table->count++;
1291                 }
1292         }
1293         vega10_init_dpm_state(&(dpm_table->dpm_state));
1294
1295         data->dpm_table.vclk_table.count = 0;
1296         data->dpm_table.dclk_table.count = 0;
1297         dpm_table = &(data->dpm_table.vclk_table);
1298         for (i = 0; i < dep_mm_table->count; i++) {
1299                 if (i == 0 || dpm_table->dpm_levels
1300                                 [dpm_table->count - 1].value <=
1301                                                 dep_mm_table->entries[i].vclk) {
1302                         dpm_table->dpm_levels[dpm_table->count].value =
1303                                         dep_mm_table->entries[i].vclk;
1304                         dpm_table->dpm_levels[dpm_table->count].enabled =
1305                                         (i == 0) ? true : false;
1306                         dpm_table->count++;
1307                 }
1308         }
1309         vega10_init_dpm_state(&(dpm_table->dpm_state));
1310
1311         dpm_table = &(data->dpm_table.dclk_table);
1312         for (i = 0; i < dep_mm_table->count; i++) {
1313                 if (i == 0 || dpm_table->dpm_levels
1314                                 [dpm_table->count - 1].value <=
1315                                                 dep_mm_table->entries[i].dclk) {
1316                         dpm_table->dpm_levels[dpm_table->count].value =
1317                                         dep_mm_table->entries[i].dclk;
1318                         dpm_table->dpm_levels[dpm_table->count].enabled =
1319                                         (i == 0) ? true : false;
1320                         dpm_table->count++;
1321                 }
1322         }
1323         vega10_init_dpm_state(&(dpm_table->dpm_state));
1324
1325         /* Assume there is no headless Vega10 for now */
1326         dpm_table = &(data->dpm_table.dcef_table);
1327         vega10_setup_default_single_dpm_table(hwmgr,
1328                         dpm_table,
1329                         dep_dcef_table);
1330
1331         vega10_init_dpm_state(&(dpm_table->dpm_state));
1332
1333         dpm_table = &(data->dpm_table.pixel_table);
1334         vega10_setup_default_single_dpm_table(hwmgr,
1335                         dpm_table,
1336                         dep_pix_table);
1337
1338         vega10_init_dpm_state(&(dpm_table->dpm_state));
1339
1340         dpm_table = &(data->dpm_table.display_table);
1341         vega10_setup_default_single_dpm_table(hwmgr,
1342                         dpm_table,
1343                         dep_disp_table);
1344
1345         vega10_init_dpm_state(&(dpm_table->dpm_state));
1346
1347         dpm_table = &(data->dpm_table.phy_table);
1348         vega10_setup_default_single_dpm_table(hwmgr,
1349                         dpm_table,
1350                         dep_phy_table);
1351
1352         vega10_init_dpm_state(&(dpm_table->dpm_state));
1353
1354         vega10_setup_default_pcie_table(hwmgr);
1355
1356         /* save a copy of the default DPM table */
1357         memcpy(&(data->golden_dpm_table), &(data->dpm_table),
1358                         sizeof(struct vega10_dpm_table));
1359
1360         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1361                         PHM_PlatformCaps_ODNinACSupport) ||
1362                 phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1363                         PHM_PlatformCaps_ODNinDCSupport)) {
1364                 data->odn_dpm_table.odn_core_clock_dpm_levels.
1365                 number_of_performance_levels = data->dpm_table.gfx_table.count;
1366                 for (i = 0; i < data->dpm_table.gfx_table.count; i++) {
1367                         data->odn_dpm_table.odn_core_clock_dpm_levels.
1368                         performance_level_entries[i].clock =
1369                                         data->dpm_table.gfx_table.dpm_levels[i].value;
1370                         data->odn_dpm_table.odn_core_clock_dpm_levels.
1371                         performance_level_entries[i].enabled = true;
1372                 }
1373
1374                 data->odn_dpm_table.vdd_dependency_on_sclk.count =
1375                                 dep_gfx_table->count;
1376                 for (i = 0; i < dep_gfx_table->count; i++) {
1377                         data->odn_dpm_table.vdd_dependency_on_sclk.entries[i].clk =
1378                                         dep_gfx_table->entries[i].clk;
1379                         data->odn_dpm_table.vdd_dependency_on_sclk.entries[i].vddInd =
1380                                         dep_gfx_table->entries[i].vddInd;
1381                         data->odn_dpm_table.vdd_dependency_on_sclk.entries[i].cks_enable =
1382                                         dep_gfx_table->entries[i].cks_enable;
1383                         data->odn_dpm_table.vdd_dependency_on_sclk.entries[i].cks_voffset =
1384                                         dep_gfx_table->entries[i].cks_voffset;
1385                 }
1386
1387                 data->odn_dpm_table.odn_memory_clock_dpm_levels.
1388                 number_of_performance_levels = data->dpm_table.mem_table.count;
1389                 for (i = 0; i < data->dpm_table.mem_table.count; i++) {
1390                         data->odn_dpm_table.odn_memory_clock_dpm_levels.
1391                         performance_level_entries[i].clock =
1392                                         data->dpm_table.mem_table.dpm_levels[i].value;
1393                         data->odn_dpm_table.odn_memory_clock_dpm_levels.
1394                         performance_level_entries[i].enabled = true;
1395                 }
1396
1397                 data->odn_dpm_table.vdd_dependency_on_mclk.count = dep_mclk_table->count;
1398                 for (i = 0; i < dep_mclk_table->count; i++) {
1399                         data->odn_dpm_table.vdd_dependency_on_mclk.entries[i].clk =
1400                                         dep_mclk_table->entries[i].clk;
1401                         data->odn_dpm_table.vdd_dependency_on_mclk.entries[i].vddInd =
1402                                         dep_mclk_table->entries[i].vddInd;
1403                         data->odn_dpm_table.vdd_dependency_on_mclk.entries[i].vddci =
1404                                         dep_mclk_table->entries[i].vddci;
1405                 }
1406         }
1407
1408         return 0;
1409 }
1410
1411 /*
1412  * @fn vega10_populate_ulv_state
1413  * @brief Function to provide parameters for Utral Low Voltage state to SMC.
1414  *
1415  * @param    hwmgr - the address of the hardware manager.
1416  * @return   Always 0.
1417  */
1418 static int vega10_populate_ulv_state(struct pp_hwmgr *hwmgr)
1419 {
1420         struct vega10_hwmgr *data =
1421                         (struct vega10_hwmgr *)(hwmgr->backend);
1422         struct phm_ppt_v2_information *table_info =
1423                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
1424
1425         data->smc_state_table.pp_table.UlvOffsetVid =
1426                         (uint8_t)table_info->us_ulv_voltage_offset;
1427
1428         data->smc_state_table.pp_table.UlvSmnclkDid =
1429                         (uint8_t)(table_info->us_ulv_smnclk_did);
1430         data->smc_state_table.pp_table.UlvMp1clkDid =
1431                         (uint8_t)(table_info->us_ulv_mp1clk_did);
1432         data->smc_state_table.pp_table.UlvGfxclkBypass =
1433                         (uint8_t)(table_info->us_ulv_gfxclk_bypass);
1434         data->smc_state_table.pp_table.UlvPhaseSheddingPsi0 =
1435                         (uint8_t)(data->vddc_voltage_table.psi0_enable);
1436         data->smc_state_table.pp_table.UlvPhaseSheddingPsi1 =
1437                         (uint8_t)(data->vddc_voltage_table.psi1_enable);
1438
1439         return 0;
1440 }
1441
1442 static int vega10_populate_single_lclk_level(struct pp_hwmgr *hwmgr,
1443                 uint32_t lclock, uint8_t *curr_lclk_did)
1444 {
1445         struct pp_atomfwctrl_clock_dividers_soc15 dividers;
1446
1447         PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(
1448                         hwmgr,
1449                         COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
1450                         lclock, &dividers),
1451                         "Failed to get LCLK clock settings from VBIOS!",
1452                         return -1);
1453
1454         *curr_lclk_did = dividers.ulDid;
1455
1456         return 0;
1457 }
1458
1459 static int vega10_populate_smc_link_levels(struct pp_hwmgr *hwmgr)
1460 {
1461         int result = -1;
1462         struct vega10_hwmgr *data =
1463                         (struct vega10_hwmgr *)(hwmgr->backend);
1464         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
1465         struct vega10_pcie_table *pcie_table =
1466                         &(data->dpm_table.pcie_table);
1467         uint32_t i, j;
1468
1469         for (i = 0; i < pcie_table->count; i++) {
1470                 pp_table->PcieGenSpeed[i] = pcie_table->pcie_gen[i];
1471                 pp_table->PcieLaneCount[i] = pcie_table->pcie_lane[i];
1472
1473                 result = vega10_populate_single_lclk_level(hwmgr,
1474                                 pcie_table->lclk[i], &(pp_table->LclkDid[i]));
1475                 if (result) {
1476                         pr_info("Populate LClock Level %d Failed!\n", i);
1477                         return result;
1478                 }
1479         }
1480
1481         j = i - 1;
1482         while (i < NUM_LINK_LEVELS) {
1483                 pp_table->PcieGenSpeed[i] = pcie_table->pcie_gen[j];
1484                 pp_table->PcieLaneCount[i] = pcie_table->pcie_lane[j];
1485
1486                 result = vega10_populate_single_lclk_level(hwmgr,
1487                                 pcie_table->lclk[j], &(pp_table->LclkDid[i]));
1488                 if (result) {
1489                         pr_info("Populate LClock Level %d Failed!\n", i);
1490                         return result;
1491                 }
1492                 i++;
1493         }
1494
1495         return result;
1496 }
1497
1498 /**
1499 * Populates single SMC GFXSCLK structure using the provided engine clock
1500 *
1501 * @param    hwmgr      the address of the hardware manager
1502 * @param    gfx_clock  the GFX clock to use to populate the structure.
1503 * @param    current_gfxclk_level  location in PPTable for the SMC GFXCLK structure.
1504 */
1505
1506 static int vega10_populate_single_gfx_level(struct pp_hwmgr *hwmgr,
1507                 uint32_t gfx_clock, PllSetting_t *current_gfxclk_level)
1508 {
1509         struct phm_ppt_v2_information *table_info =
1510                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
1511         struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_sclk =
1512                         table_info->vdd_dep_on_sclk;
1513         struct vega10_hwmgr *data =
1514                         (struct vega10_hwmgr *)(hwmgr->backend);
1515         struct pp_atomfwctrl_clock_dividers_soc15 dividers;
1516         uint32_t gfx_max_clock =
1517                         hwmgr->platform_descriptor.overdriveLimit.engineClock;
1518         uint32_t i = 0;
1519
1520         if (data->apply_overdrive_next_settings_mask &
1521                         DPMTABLE_OD_UPDATE_VDDC)
1522                 dep_on_sclk = (struct phm_ppt_v1_clock_voltage_dependency_table *)
1523                                                 &(data->odn_dpm_table.vdd_dependency_on_sclk);
1524
1525         PP_ASSERT_WITH_CODE(dep_on_sclk,
1526                         "Invalid SOC_VDD-GFX_CLK Dependency Table!",
1527                         return -EINVAL);
1528
1529         if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_SCLK)
1530                 gfx_clock = gfx_clock > gfx_max_clock ? gfx_max_clock : gfx_clock;
1531         else {
1532                 for (i = 0; i < dep_on_sclk->count; i++) {
1533                         if (dep_on_sclk->entries[i].clk == gfx_clock)
1534                                 break;
1535                 }
1536                 PP_ASSERT_WITH_CODE(dep_on_sclk->count > i,
1537                                 "Cannot find gfx_clk in SOC_VDD-GFX_CLK!",
1538                                 return -EINVAL);
1539         }
1540
1541         PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr,
1542                         COMPUTE_GPUCLK_INPUT_FLAG_GFXCLK,
1543                         gfx_clock, &dividers),
1544                         "Failed to get GFX Clock settings from VBIOS!",
1545                         return -EINVAL);
1546
1547         /* Feedback Multiplier: bit 0:8 int, bit 15:12 post_div, bit 31:16 frac */
1548         current_gfxclk_level->FbMult =
1549                         cpu_to_le32(dividers.ulPll_fb_mult);
1550         /* Spread FB Multiplier bit: bit 0:8 int, bit 31:16 frac */
1551         current_gfxclk_level->SsOn = dividers.ucPll_ss_enable;
1552         current_gfxclk_level->SsFbMult =
1553                         cpu_to_le32(dividers.ulPll_ss_fbsmult);
1554         current_gfxclk_level->SsSlewFrac =
1555                         cpu_to_le16(dividers.usPll_ss_slew_frac);
1556         current_gfxclk_level->Did = (uint8_t)(dividers.ulDid);
1557
1558         return 0;
1559 }
1560
1561 /**
1562  * @brief Populates single SMC SOCCLK structure using the provided clock.
1563  *
1564  * @param    hwmgr - the address of the hardware manager.
1565  * @param    soc_clock - the SOC clock to use to populate the structure.
1566  * @param    current_socclk_level - location in PPTable for the SMC SOCCLK structure.
1567  * @return   0 on success..
1568  */
1569 static int vega10_populate_single_soc_level(struct pp_hwmgr *hwmgr,
1570                 uint32_t soc_clock, uint8_t *current_soc_did,
1571                 uint8_t *current_vol_index)
1572 {
1573         struct phm_ppt_v2_information *table_info =
1574                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
1575         struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_soc =
1576                         table_info->vdd_dep_on_socclk;
1577         struct pp_atomfwctrl_clock_dividers_soc15 dividers;
1578         uint32_t i;
1579
1580         PP_ASSERT_WITH_CODE(dep_on_soc,
1581                         "Invalid SOC_VDD-SOC_CLK Dependency Table!",
1582                         return -EINVAL);
1583         for (i = 0; i < dep_on_soc->count; i++) {
1584                 if (dep_on_soc->entries[i].clk == soc_clock)
1585                         break;
1586         }
1587         PP_ASSERT_WITH_CODE(dep_on_soc->count > i,
1588                         "Cannot find SOC_CLK in SOC_VDD-SOC_CLK Dependency Table",
1589                         return -EINVAL);
1590         PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr,
1591                         COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
1592                         soc_clock, &dividers),
1593                         "Failed to get SOC Clock settings from VBIOS!",
1594                         return -EINVAL);
1595
1596         *current_soc_did = (uint8_t)dividers.ulDid;
1597         *current_vol_index = (uint8_t)(dep_on_soc->entries[i].vddInd);
1598
1599         return 0;
1600 }
1601
1602 uint16_t vega10_locate_vddc_given_clock(struct pp_hwmgr *hwmgr,
1603                 uint32_t clk,
1604                 struct phm_ppt_v1_clock_voltage_dependency_table *dep_table)
1605 {
1606         uint16_t i;
1607
1608         for (i = 0; i < dep_table->count; i++) {
1609                 if (dep_table->entries[i].clk == clk)
1610                         return dep_table->entries[i].vddc;
1611         }
1612
1613         pr_info("[LocateVddcGivenClock] Cannot locate SOC Vddc for this clock!");
1614         return 0;
1615 }
1616
1617 /**
1618 * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
1619 *
1620 * @param    hwmgr      the address of the hardware manager
1621 */
1622 static int vega10_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
1623 {
1624         struct vega10_hwmgr *data =
1625                         (struct vega10_hwmgr *)(hwmgr->backend);
1626         struct phm_ppt_v2_information *table_info =
1627                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
1628         struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
1629                         table_info->vdd_dep_on_socclk;
1630         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
1631         struct vega10_single_dpm_table *dpm_table = &(data->dpm_table.gfx_table);
1632         int result = 0;
1633         uint32_t i, j;
1634
1635         for (i = 0; i < dpm_table->count; i++) {
1636                 result = vega10_populate_single_gfx_level(hwmgr,
1637                                 dpm_table->dpm_levels[i].value,
1638                                 &(pp_table->GfxclkLevel[i]));
1639                 if (result)
1640                         return result;
1641         }
1642
1643         j = i - 1;
1644         while (i < NUM_GFXCLK_DPM_LEVELS) {
1645                 result = vega10_populate_single_gfx_level(hwmgr,
1646                                 dpm_table->dpm_levels[j].value,
1647                                 &(pp_table->GfxclkLevel[i]));
1648                 if (result)
1649                         return result;
1650                 i++;
1651         }
1652
1653         pp_table->GfxclkSlewRate =
1654                         cpu_to_le16(table_info->us_gfxclk_slew_rate);
1655
1656         dpm_table = &(data->dpm_table.soc_table);
1657         for (i = 0; i < dpm_table->count; i++) {
1658                 pp_table->SocVid[i] =
1659                                 (uint8_t)convert_to_vid(
1660                                 vega10_locate_vddc_given_clock(hwmgr,
1661                                                 dpm_table->dpm_levels[i].value,
1662                                                 dep_table));
1663                 result = vega10_populate_single_soc_level(hwmgr,
1664                                 dpm_table->dpm_levels[i].value,
1665                                 &(pp_table->SocclkDid[i]),
1666                                 &(pp_table->SocDpmVoltageIndex[i]));
1667                 if (result)
1668                         return result;
1669         }
1670
1671         j = i - 1;
1672         while (i < NUM_SOCCLK_DPM_LEVELS) {
1673                 pp_table->SocVid[i] = pp_table->SocVid[j];
1674                 result = vega10_populate_single_soc_level(hwmgr,
1675                                 dpm_table->dpm_levels[j].value,
1676                                 &(pp_table->SocclkDid[i]),
1677                                 &(pp_table->SocDpmVoltageIndex[i]));
1678                 if (result)
1679                         return result;
1680                 i++;
1681         }
1682
1683         return result;
1684 }
1685
1686 /**
1687  * @brief Populates single SMC GFXCLK structure using the provided clock.
1688  *
1689  * @param    hwmgr - the address of the hardware manager.
1690  * @param    mem_clock - the memory clock to use to populate the structure.
1691  * @return   0 on success..
1692  */
1693 static int vega10_populate_single_memory_level(struct pp_hwmgr *hwmgr,
1694                 uint32_t mem_clock, uint8_t *current_mem_vid,
1695                 PllSetting_t *current_memclk_level, uint8_t *current_mem_soc_vind)
1696 {
1697         struct vega10_hwmgr *data =
1698                         (struct vega10_hwmgr *)(hwmgr->backend);
1699         struct phm_ppt_v2_information *table_info =
1700                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
1701         struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_mclk =
1702                         table_info->vdd_dep_on_mclk;
1703         struct pp_atomfwctrl_clock_dividers_soc15 dividers;
1704         uint32_t mem_max_clock =
1705                         hwmgr->platform_descriptor.overdriveLimit.memoryClock;
1706         uint32_t i = 0;
1707
1708         if (data->apply_overdrive_next_settings_mask &
1709                         DPMTABLE_OD_UPDATE_VDDC)
1710                 dep_on_mclk = (struct phm_ppt_v1_clock_voltage_dependency_table *)
1711                                         &data->odn_dpm_table.vdd_dependency_on_mclk;
1712
1713         PP_ASSERT_WITH_CODE(dep_on_mclk,
1714                         "Invalid SOC_VDD-UCLK Dependency Table!",
1715                         return -EINVAL);
1716
1717         if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_MCLK)
1718                 mem_clock = mem_clock > mem_max_clock ? mem_max_clock : mem_clock;
1719         else {
1720                 for (i = 0; i < dep_on_mclk->count; i++) {
1721                         if (dep_on_mclk->entries[i].clk == mem_clock)
1722                                 break;
1723                 }
1724                 PP_ASSERT_WITH_CODE(dep_on_mclk->count > i,
1725                                 "Cannot find UCLK in SOC_VDD-UCLK Dependency Table!",
1726                                 return -EINVAL);
1727         }
1728
1729         PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(
1730                         hwmgr, COMPUTE_GPUCLK_INPUT_FLAG_UCLK, mem_clock, &dividers),
1731                         "Failed to get UCLK settings from VBIOS!",
1732                         return -1);
1733
1734         *current_mem_vid =
1735                         (uint8_t)(convert_to_vid(dep_on_mclk->entries[i].mvdd));
1736         *current_mem_soc_vind =
1737                         (uint8_t)(dep_on_mclk->entries[i].vddInd);
1738         current_memclk_level->FbMult = cpu_to_le32(dividers.ulPll_fb_mult);
1739         current_memclk_level->Did = (uint8_t)(dividers.ulDid);
1740
1741         PP_ASSERT_WITH_CODE(current_memclk_level->Did >= 1,
1742                         "Invalid Divider ID!",
1743                         return -EINVAL);
1744
1745         return 0;
1746 }
1747
1748 /**
1749  * @brief Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states.
1750  *
1751  * @param    pHwMgr - the address of the hardware manager.
1752  * @return   PP_Result_OK on success.
1753  */
1754 static int vega10_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
1755 {
1756         struct vega10_hwmgr *data =
1757                         (struct vega10_hwmgr *)(hwmgr->backend);
1758         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
1759         struct vega10_single_dpm_table *dpm_table =
1760                         &(data->dpm_table.mem_table);
1761         int result = 0;
1762         uint32_t i, j, reg, mem_channels;
1763
1764         for (i = 0; i < dpm_table->count; i++) {
1765                 result = vega10_populate_single_memory_level(hwmgr,
1766                                 dpm_table->dpm_levels[i].value,
1767                                 &(pp_table->MemVid[i]),
1768                                 &(pp_table->UclkLevel[i]),
1769                                 &(pp_table->MemSocVoltageIndex[i]));
1770                 if (result)
1771                         return result;
1772         }
1773
1774         j = i - 1;
1775         while (i < NUM_UCLK_DPM_LEVELS) {
1776                 result = vega10_populate_single_memory_level(hwmgr,
1777                                 dpm_table->dpm_levels[j].value,
1778                                 &(pp_table->MemVid[i]),
1779                                 &(pp_table->UclkLevel[i]),
1780                                 &(pp_table->MemSocVoltageIndex[i]));
1781                 if (result)
1782                         return result;
1783                 i++;
1784         }
1785
1786         reg = soc15_get_register_offset(DF_HWID, 0,
1787                         mmDF_CS_AON0_DramBaseAddress0_BASE_IDX,
1788                         mmDF_CS_AON0_DramBaseAddress0);
1789         mem_channels = (cgs_read_register(hwmgr->device, reg) &
1790                         DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK) >>
1791                         DF_CS_AON0_DramBaseAddress0__IntLvNumChan__SHIFT;
1792         pp_table->NumMemoryChannels = cpu_to_le16(mem_channels);
1793         pp_table->MemoryChannelWidth =
1794                         cpu_to_le16(HBM_MEMORY_CHANNEL_WIDTH *
1795                                         channel_number[mem_channels]);
1796
1797         pp_table->LowestUclkReservedForUlv =
1798                         (uint8_t)(data->lowest_uclk_reserved_for_ulv);
1799
1800         return result;
1801 }
1802
1803 static int vega10_populate_single_display_type(struct pp_hwmgr *hwmgr,
1804                 DSPCLK_e disp_clock)
1805 {
1806         struct vega10_hwmgr *data =
1807                         (struct vega10_hwmgr *)(hwmgr->backend);
1808         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
1809         struct phm_ppt_v2_information *table_info =
1810                         (struct phm_ppt_v2_information *)
1811                         (hwmgr->pptable);
1812         struct phm_ppt_v1_clock_voltage_dependency_table *dep_table;
1813         uint32_t i;
1814         uint16_t clk = 0, vddc = 0;
1815         uint8_t vid = 0;
1816
1817         switch (disp_clock) {
1818         case DSPCLK_DCEFCLK:
1819                 dep_table = table_info->vdd_dep_on_dcefclk;
1820                 break;
1821         case DSPCLK_DISPCLK:
1822                 dep_table = table_info->vdd_dep_on_dispclk;
1823                 break;
1824         case DSPCLK_PIXCLK:
1825                 dep_table = table_info->vdd_dep_on_pixclk;
1826                 break;
1827         case DSPCLK_PHYCLK:
1828                 dep_table = table_info->vdd_dep_on_phyclk;
1829                 break;
1830         default:
1831                 return -1;
1832         }
1833
1834         PP_ASSERT_WITH_CODE(dep_table->count <= NUM_DSPCLK_LEVELS,
1835                         "Number Of Entries Exceeded maximum!",
1836                         return -1);
1837
1838         for (i = 0; i < dep_table->count; i++) {
1839                 clk = (uint16_t)(dep_table->entries[i].clk / 100);
1840                 vddc = table_info->vddc_lookup_table->
1841                                 entries[dep_table->entries[i].vddInd].us_vdd;
1842                 vid = (uint8_t)convert_to_vid(vddc);
1843                 pp_table->DisplayClockTable[disp_clock][i].Freq =
1844                                 cpu_to_le16(clk);
1845                 pp_table->DisplayClockTable[disp_clock][i].Vid =
1846                                 cpu_to_le16(vid);
1847         }
1848
1849         while (i < NUM_DSPCLK_LEVELS) {
1850                 pp_table->DisplayClockTable[disp_clock][i].Freq =
1851                                 cpu_to_le16(clk);
1852                 pp_table->DisplayClockTable[disp_clock][i].Vid =
1853                                 cpu_to_le16(vid);
1854                 i++;
1855         }
1856
1857         return 0;
1858 }
1859
1860 static int vega10_populate_all_display_clock_levels(struct pp_hwmgr *hwmgr)
1861 {
1862         uint32_t i;
1863
1864         for (i = 0; i < DSPCLK_COUNT; i++) {
1865                 PP_ASSERT_WITH_CODE(!vega10_populate_single_display_type(hwmgr, i),
1866                                 "Failed to populate Clock in DisplayClockTable!",
1867                                 return -1);
1868         }
1869
1870         return 0;
1871 }
1872
1873 static int vega10_populate_single_eclock_level(struct pp_hwmgr *hwmgr,
1874                 uint32_t eclock, uint8_t *current_eclk_did,
1875                 uint8_t *current_soc_vol)
1876 {
1877         struct phm_ppt_v2_information *table_info =
1878                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
1879         struct phm_ppt_v1_mm_clock_voltage_dependency_table *dep_table =
1880                         table_info->mm_dep_table;
1881         struct pp_atomfwctrl_clock_dividers_soc15 dividers;
1882         uint32_t i;
1883
1884         PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr,
1885                         COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
1886                         eclock, &dividers),
1887                         "Failed to get ECLK clock settings from VBIOS!",
1888                         return -1);
1889
1890         *current_eclk_did = (uint8_t)dividers.ulDid;
1891
1892         for (i = 0; i < dep_table->count; i++) {
1893                 if (dep_table->entries[i].eclk == eclock)
1894                         *current_soc_vol = dep_table->entries[i].vddcInd;
1895         }
1896
1897         return 0;
1898 }
1899
1900 static int vega10_populate_smc_vce_levels(struct pp_hwmgr *hwmgr)
1901 {
1902         struct vega10_hwmgr *data =
1903                         (struct vega10_hwmgr *)(hwmgr->backend);
1904         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
1905         struct vega10_single_dpm_table *dpm_table = &(data->dpm_table.eclk_table);
1906         int result = -EINVAL;
1907         uint32_t i, j;
1908
1909         for (i = 0; i < dpm_table->count; i++) {
1910                 result = vega10_populate_single_eclock_level(hwmgr,
1911                                 dpm_table->dpm_levels[i].value,
1912                                 &(pp_table->EclkDid[i]),
1913                                 &(pp_table->VceDpmVoltageIndex[i]));
1914                 if (result)
1915                         return result;
1916         }
1917
1918         j = i - 1;
1919         while (i < NUM_VCE_DPM_LEVELS) {
1920                 result = vega10_populate_single_eclock_level(hwmgr,
1921                                 dpm_table->dpm_levels[j].value,
1922                                 &(pp_table->EclkDid[i]),
1923                                 &(pp_table->VceDpmVoltageIndex[i]));
1924                 if (result)
1925                         return result;
1926                 i++;
1927         }
1928
1929         return result;
1930 }
1931
1932 static int vega10_populate_single_vclock_level(struct pp_hwmgr *hwmgr,
1933                 uint32_t vclock, uint8_t *current_vclk_did)
1934 {
1935         struct pp_atomfwctrl_clock_dividers_soc15 dividers;
1936
1937         PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr,
1938                         COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
1939                         vclock, &dividers),
1940                         "Failed to get VCLK clock settings from VBIOS!",
1941                         return -EINVAL);
1942
1943         *current_vclk_did = (uint8_t)dividers.ulDid;
1944
1945         return 0;
1946 }
1947
1948 static int vega10_populate_single_dclock_level(struct pp_hwmgr *hwmgr,
1949                 uint32_t dclock, uint8_t *current_dclk_did)
1950 {
1951         struct pp_atomfwctrl_clock_dividers_soc15 dividers;
1952
1953         PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr,
1954                         COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
1955                         dclock, &dividers),
1956                         "Failed to get DCLK clock settings from VBIOS!",
1957                         return -EINVAL);
1958
1959         *current_dclk_did = (uint8_t)dividers.ulDid;
1960
1961         return 0;
1962 }
1963
1964 static int vega10_populate_smc_uvd_levels(struct pp_hwmgr *hwmgr)
1965 {
1966         struct vega10_hwmgr *data =
1967                         (struct vega10_hwmgr *)(hwmgr->backend);
1968         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
1969         struct vega10_single_dpm_table *vclk_dpm_table =
1970                         &(data->dpm_table.vclk_table);
1971         struct vega10_single_dpm_table *dclk_dpm_table =
1972                         &(data->dpm_table.dclk_table);
1973         struct phm_ppt_v2_information *table_info =
1974                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
1975         struct phm_ppt_v1_mm_clock_voltage_dependency_table *dep_table =
1976                         table_info->mm_dep_table;
1977         int result = -EINVAL;
1978         uint32_t i, j;
1979
1980         for (i = 0; i < vclk_dpm_table->count; i++) {
1981                 result = vega10_populate_single_vclock_level(hwmgr,
1982                                 vclk_dpm_table->dpm_levels[i].value,
1983                                 &(pp_table->VclkDid[i]));
1984                 if (result)
1985                         return result;
1986         }
1987
1988         j = i - 1;
1989         while (i < NUM_UVD_DPM_LEVELS) {
1990                 result = vega10_populate_single_vclock_level(hwmgr,
1991                                 vclk_dpm_table->dpm_levels[j].value,
1992                                 &(pp_table->VclkDid[i]));
1993                 if (result)
1994                         return result;
1995                 i++;
1996         }
1997
1998         for (i = 0; i < dclk_dpm_table->count; i++) {
1999                 result = vega10_populate_single_dclock_level(hwmgr,
2000                                 dclk_dpm_table->dpm_levels[i].value,
2001                                 &(pp_table->DclkDid[i]));
2002                 if (result)
2003                         return result;
2004         }
2005
2006         j = i - 1;
2007         while (i < NUM_UVD_DPM_LEVELS) {
2008                 result = vega10_populate_single_dclock_level(hwmgr,
2009                                 dclk_dpm_table->dpm_levels[j].value,
2010                                 &(pp_table->DclkDid[i]));
2011                 if (result)
2012                         return result;
2013                 i++;
2014         }
2015
2016         for (i = 0; i < dep_table->count; i++) {
2017                 if (dep_table->entries[i].vclk ==
2018                                 vclk_dpm_table->dpm_levels[i].value &&
2019                         dep_table->entries[i].dclk ==
2020                                 dclk_dpm_table->dpm_levels[i].value)
2021                         pp_table->UvdDpmVoltageIndex[i] =
2022                                         dep_table->entries[i].vddcInd;
2023                 else
2024                         return -1;
2025         }
2026
2027         j = i - 1;
2028         while (i < NUM_UVD_DPM_LEVELS) {
2029                 pp_table->UvdDpmVoltageIndex[i] = dep_table->entries[j].vddcInd;
2030                 i++;
2031         }
2032
2033         return 0;
2034 }
2035
2036 static int vega10_populate_clock_stretcher_table(struct pp_hwmgr *hwmgr)
2037 {
2038         struct vega10_hwmgr *data =
2039                         (struct vega10_hwmgr *)(hwmgr->backend);
2040         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
2041         struct phm_ppt_v2_information *table_info =
2042                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
2043         struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
2044                         table_info->vdd_dep_on_sclk;
2045         uint32_t i;
2046
2047         for (i = 0; i < dep_table->count; i++) {
2048                 pp_table->CksEnable[i] = dep_table->entries[i].cks_enable;
2049                 pp_table->CksVidOffset[i] = (uint8_t)(dep_table->entries[i].cks_voffset
2050                                 * VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1);
2051         }
2052
2053         return 0;
2054 }
2055
2056 static int vega10_populate_avfs_parameters(struct pp_hwmgr *hwmgr)
2057 {
2058         struct vega10_hwmgr *data =
2059                         (struct vega10_hwmgr *)(hwmgr->backend);
2060         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
2061         struct phm_ppt_v2_information *table_info =
2062                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
2063         struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
2064                         table_info->vdd_dep_on_sclk;
2065         struct pp_atomfwctrl_avfs_parameters avfs_params = {0};
2066         int result = 0;
2067         uint32_t i;
2068
2069         pp_table->MinVoltageVid = (uint8_t)0xff;
2070         pp_table->MaxVoltageVid = (uint8_t)0;
2071
2072         if (data->smu_features[GNLD_AVFS].supported) {
2073                 result = pp_atomfwctrl_get_avfs_information(hwmgr, &avfs_params);
2074                 if (!result) {
2075                         pp_table->MinVoltageVid = (uint8_t)
2076                                         convert_to_vid((uint16_t)(avfs_params.ulMinVddc));
2077                         pp_table->MaxVoltageVid = (uint8_t)
2078                                         convert_to_vid((uint16_t)(avfs_params.ulMaxVddc));
2079
2080                         pp_table->AConstant[0] = cpu_to_le32(avfs_params.ulMeanNsigmaAcontant0);
2081                         pp_table->AConstant[1] = cpu_to_le32(avfs_params.ulMeanNsigmaAcontant1);
2082                         pp_table->AConstant[2] = cpu_to_le32(avfs_params.ulMeanNsigmaAcontant2);
2083                         pp_table->DC_tol_sigma = cpu_to_le16(avfs_params.usMeanNsigmaDcTolSigma);
2084                         pp_table->Platform_mean = cpu_to_le16(avfs_params.usMeanNsigmaPlatformMean);
2085                         pp_table->Platform_sigma = cpu_to_le16(avfs_params.usMeanNsigmaDcTolSigma);
2086                         pp_table->PSM_Age_CompFactor = cpu_to_le16(avfs_params.usPsmAgeComfactor);
2087
2088                         pp_table->BtcGbVdroopTableCksOff.a0 =
2089                                         cpu_to_le32(avfs_params.ulGbVdroopTableCksoffA0);
2090                         pp_table->BtcGbVdroopTableCksOff.a0_shift = 20;
2091                         pp_table->BtcGbVdroopTableCksOff.a1 =
2092                                         cpu_to_le32(avfs_params.ulGbVdroopTableCksoffA1);
2093                         pp_table->BtcGbVdroopTableCksOff.a1_shift = 20;
2094                         pp_table->BtcGbVdroopTableCksOff.a2 =
2095                                         cpu_to_le32(avfs_params.ulGbVdroopTableCksoffA2);
2096                         pp_table->BtcGbVdroopTableCksOff.a2_shift = 20;
2097
2098                         pp_table->OverrideBtcGbCksOn = avfs_params.ucEnableGbVdroopTableCkson;
2099                         pp_table->BtcGbVdroopTableCksOn.a0 =
2100                                         cpu_to_le32(avfs_params.ulGbVdroopTableCksonA0);
2101                         pp_table->BtcGbVdroopTableCksOn.a0_shift = 20;
2102                         pp_table->BtcGbVdroopTableCksOn.a1 =
2103                                         cpu_to_le32(avfs_params.ulGbVdroopTableCksonA1);
2104                         pp_table->BtcGbVdroopTableCksOn.a1_shift = 20;
2105                         pp_table->BtcGbVdroopTableCksOn.a2 =
2106                                         cpu_to_le32(avfs_params.ulGbVdroopTableCksonA2);
2107                         pp_table->BtcGbVdroopTableCksOn.a2_shift = 20;
2108
2109                         pp_table->AvfsGbCksOn.m1 =
2110                                         cpu_to_le32(avfs_params.ulGbFuseTableCksonM1);
2111                         pp_table->AvfsGbCksOn.m2 =
2112                                         cpu_to_le32(avfs_params.ulGbFuseTableCksonM2);
2113                         pp_table->AvfsGbCksOn.b =
2114                                         cpu_to_le32(avfs_params.ulGbFuseTableCksonB);
2115                         pp_table->AvfsGbCksOn.m1_shift = 24;
2116                         pp_table->AvfsGbCksOn.m2_shift = 12;
2117                         pp_table->AvfsGbCksOn.b_shift = 0;
2118
2119                         pp_table->OverrideAvfsGbCksOn =
2120                                         avfs_params.ucEnableGbFuseTableCkson;
2121                         pp_table->AvfsGbCksOff.m1 =
2122                                         cpu_to_le32(avfs_params.ulGbFuseTableCksoffM1);
2123                         pp_table->AvfsGbCksOff.m2 =
2124                                         cpu_to_le32(avfs_params.ulGbFuseTableCksoffM2);
2125                         pp_table->AvfsGbCksOff.b =
2126                                         cpu_to_le32(avfs_params.ulGbFuseTableCksoffB);
2127                         pp_table->AvfsGbCksOff.m1_shift = 24;
2128                         pp_table->AvfsGbCksOff.m2_shift = 12;
2129                         pp_table->AvfsGbCksOff.b_shift = 0;
2130
2131                         for (i = 0; i < dep_table->count; i++) {
2132                                 if (dep_table->entries[i].sclk_offset == 0)
2133                                         pp_table->StaticVoltageOffsetVid[i] = 248;
2134                                 else
2135                                         pp_table->StaticVoltageOffsetVid[i] =
2136                                                 (uint8_t)(dep_table->entries[i].sclk_offset *
2137                                                                 VOLTAGE_VID_OFFSET_SCALE2 /
2138                                                                 VOLTAGE_VID_OFFSET_SCALE1);
2139                         }
2140
2141                         if ((PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2142                                         data->disp_clk_quad_eqn_a) &&
2143                                 (PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2144                                         data->disp_clk_quad_eqn_b)) {
2145                                 pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m1 =
2146                                                 (int32_t)data->disp_clk_quad_eqn_a;
2147                                 pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m2 =
2148                                                 (int32_t)data->disp_clk_quad_eqn_b;
2149                                 pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].b =
2150                                                 (int32_t)data->disp_clk_quad_eqn_c;
2151                         } else {
2152                                 pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m1 =
2153                                                 (int32_t)avfs_params.ulDispclk2GfxclkM1;
2154                                 pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m2 =
2155                                                 (int32_t)avfs_params.ulDispclk2GfxclkM2;
2156                                 pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].b =
2157                                                 (int32_t)avfs_params.ulDispclk2GfxclkB;
2158                         }
2159
2160                         pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m1_shift = 24;
2161                         pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].m2_shift = 12;
2162                         pp_table->DisplayClock2Gfxclk[DSPCLK_DISPCLK].b_shift = 12;
2163
2164                         if ((PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2165                                         data->dcef_clk_quad_eqn_a) &&
2166                                 (PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2167                                         data->dcef_clk_quad_eqn_b)) {
2168                                 pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m1 =
2169                                                 (int32_t)data->dcef_clk_quad_eqn_a;
2170                                 pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m2 =
2171                                                 (int32_t)data->dcef_clk_quad_eqn_b;
2172                                 pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].b =
2173                                                 (int32_t)data->dcef_clk_quad_eqn_c;
2174                         } else {
2175                                 pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m1 =
2176                                                 (int32_t)avfs_params.ulDcefclk2GfxclkM1;
2177                                 pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m2 =
2178                                                 (int32_t)avfs_params.ulDcefclk2GfxclkM2;
2179                                 pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].b =
2180                                                 (int32_t)avfs_params.ulDcefclk2GfxclkB;
2181                         }
2182
2183                         pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m1_shift = 24;
2184                         pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].m2_shift = 12;
2185                         pp_table->DisplayClock2Gfxclk[DSPCLK_DCEFCLK].b_shift = 12;
2186
2187                         if ((PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2188                                         data->pixel_clk_quad_eqn_a) &&
2189                                 (PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2190                                         data->pixel_clk_quad_eqn_b)) {
2191                                 pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m1 =
2192                                                 (int32_t)data->pixel_clk_quad_eqn_a;
2193                                 pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m2 =
2194                                                 (int32_t)data->pixel_clk_quad_eqn_b;
2195                                 pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].b =
2196                                                 (int32_t)data->pixel_clk_quad_eqn_c;
2197                         } else {
2198                                 pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m1 =
2199                                                 (int32_t)avfs_params.ulPixelclk2GfxclkM1;
2200                                 pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m2 =
2201                                                 (int32_t)avfs_params.ulPixelclk2GfxclkM2;
2202                                 pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].b =
2203                                                 (int32_t)avfs_params.ulPixelclk2GfxclkB;
2204                         }
2205
2206                         pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m1_shift = 24;
2207                         pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].m2_shift = 12;
2208                         pp_table->DisplayClock2Gfxclk[DSPCLK_PIXCLK].b_shift = 12;
2209                         if ((PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2210                                         data->phy_clk_quad_eqn_a) &&
2211                                 (PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
2212                                         data->phy_clk_quad_eqn_b)) {
2213                                 pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m1 =
2214                                                 (int32_t)data->phy_clk_quad_eqn_a;
2215                                 pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m2 =
2216                                                 (int32_t)data->phy_clk_quad_eqn_b;
2217                                 pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].b =
2218                                                 (int32_t)data->phy_clk_quad_eqn_c;
2219                         } else {
2220                                 pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m1 =
2221                                                 (int32_t)avfs_params.ulPhyclk2GfxclkM1;
2222                                 pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m2 =
2223                                                 (int32_t)avfs_params.ulPhyclk2GfxclkM2;
2224                                 pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].b =
2225                                                 (int32_t)avfs_params.ulPhyclk2GfxclkB;
2226                         }
2227
2228                         pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m1_shift = 24;
2229                         pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].m2_shift = 12;
2230                         pp_table->DisplayClock2Gfxclk[DSPCLK_PHYCLK].b_shift = 12;
2231                 } else {
2232                         data->smu_features[GNLD_AVFS].supported = false;
2233                 }
2234         }
2235
2236         return 0;
2237 }
2238
2239 static int vega10_populate_gpio_parameters(struct pp_hwmgr *hwmgr)
2240 {
2241         struct vega10_hwmgr *data =
2242                         (struct vega10_hwmgr *)(hwmgr->backend);
2243         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
2244         struct pp_atomfwctrl_gpio_parameters gpio_params = {0};
2245         int result;
2246
2247         result = pp_atomfwctrl_get_gpio_information(hwmgr, &gpio_params);
2248         if (!result) {
2249                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2250                                 PHM_PlatformCaps_RegulatorHot) &&
2251                                 (data->registry_data.regulator_hot_gpio_support)) {
2252                         pp_table->VR0HotGpio = gpio_params.ucVR0HotGpio;
2253                         pp_table->VR0HotPolarity = gpio_params.ucVR0HotPolarity;
2254                         pp_table->VR1HotGpio = gpio_params.ucVR1HotGpio;
2255                         pp_table->VR1HotPolarity = gpio_params.ucVR1HotPolarity;
2256                 } else {
2257                         pp_table->VR0HotGpio = 0;
2258                         pp_table->VR0HotPolarity = 0;
2259                         pp_table->VR1HotGpio = 0;
2260                         pp_table->VR1HotPolarity = 0;
2261                 }
2262
2263                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2264                                 PHM_PlatformCaps_AutomaticDCTransition) &&
2265                                 (data->registry_data.ac_dc_switch_gpio_support)) {
2266                         pp_table->AcDcGpio = gpio_params.ucAcDcGpio;
2267                         pp_table->AcDcPolarity = gpio_params.ucAcDcPolarity;
2268                 } else {
2269                         pp_table->AcDcGpio = 0;
2270                         pp_table->AcDcPolarity = 0;
2271                 }
2272         }
2273
2274         return result;
2275 }
2276
2277 static int vega10_avfs_enable(struct pp_hwmgr *hwmgr, bool enable)
2278 {
2279         struct vega10_hwmgr *data =
2280                         (struct vega10_hwmgr *)(hwmgr->backend);
2281
2282         if (data->smu_features[GNLD_AVFS].supported) {
2283                 if (enable) {
2284                         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2285                                         true,
2286                                         data->smu_features[GNLD_AVFS].smu_feature_bitmap),
2287                                         "[avfs_control] Attempt to Enable AVFS feature Failed!",
2288                                         return -1);
2289                         data->smu_features[GNLD_AVFS].enabled = true;
2290                 } else {
2291                         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2292                                         false,
2293                                         data->smu_features[GNLD_AVFS].smu_feature_id),
2294                                         "[avfs_control] Attempt to Disable AVFS feature Failed!",
2295                                         return -1);
2296                         data->smu_features[GNLD_AVFS].enabled = false;
2297                 }
2298         }
2299
2300         return 0;
2301 }
2302
2303 static int vega10_populate_and_upload_avfs_fuse_override(struct pp_hwmgr *hwmgr)
2304 {
2305         int result = 0;
2306
2307         uint64_t serial_number = 0;
2308         uint32_t top32, bottom32;
2309         struct phm_fuses_default fuse;
2310
2311         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
2312         AvfsFuseOverride_t *avfs_fuse_table = &(data->smc_state_table.avfs_fuse_override_table);
2313
2314         smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ReadSerialNumTop32);
2315         vega10_read_arg_from_smc(hwmgr->smumgr, &top32);
2316
2317         smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ReadSerialNumBottom32);
2318         vega10_read_arg_from_smc(hwmgr->smumgr, &bottom32);
2319
2320         serial_number = ((uint64_t)bottom32 << 32) | top32;
2321
2322         if (pp_override_get_default_fuse_value(serial_number, vega10_fuses_default, &fuse) == 0) {
2323                 avfs_fuse_table->VFT0_b  = fuse.VFT0_b;
2324                 avfs_fuse_table->VFT0_m1 = fuse.VFT0_m1;
2325                 avfs_fuse_table->VFT0_m2 = fuse.VFT0_m2;
2326                 avfs_fuse_table->VFT1_b  = fuse.VFT1_b;
2327                 avfs_fuse_table->VFT1_m1 = fuse.VFT1_m1;
2328                 avfs_fuse_table->VFT1_m2 = fuse.VFT1_m2;
2329                 avfs_fuse_table->VFT2_b  = fuse.VFT2_b;
2330                 avfs_fuse_table->VFT2_m1 = fuse.VFT2_m1;
2331                 avfs_fuse_table->VFT2_m2 = fuse.VFT2_m2;
2332                 result = vega10_copy_table_to_smc(hwmgr->smumgr,
2333                         (uint8_t *)avfs_fuse_table, AVFSFUSETABLE);
2334                 PP_ASSERT_WITH_CODE(!result,
2335                         "Failed to upload FuseOVerride!",
2336                         );
2337         }
2338
2339         return result;
2340 }
2341
2342 static int vega10_save_default_power_profile(struct pp_hwmgr *hwmgr)
2343 {
2344         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
2345         struct vega10_single_dpm_table *dpm_table = &(data->dpm_table.gfx_table);
2346         uint32_t min_level;
2347
2348         hwmgr->default_gfx_power_profile.type = AMD_PP_GFX_PROFILE;
2349         hwmgr->default_compute_power_profile.type = AMD_PP_COMPUTE_PROFILE;
2350
2351         /* Optimize compute power profile: Use only highest
2352          * 2 power levels (if more than 2 are available)
2353          */
2354         if (dpm_table->count > 2)
2355                 min_level = dpm_table->count - 2;
2356         else if (dpm_table->count == 2)
2357                 min_level = 1;
2358         else
2359                 min_level = 0;
2360
2361         hwmgr->default_compute_power_profile.min_sclk =
2362                         dpm_table->dpm_levels[min_level].value;
2363
2364         hwmgr->gfx_power_profile = hwmgr->default_gfx_power_profile;
2365         hwmgr->compute_power_profile = hwmgr->default_compute_power_profile;
2366
2367         return 0;
2368 }
2369
2370 /**
2371 * Initializes the SMC table and uploads it
2372 *
2373 * @param    hwmgr  the address of the powerplay hardware manager.
2374 * @param    pInput  the pointer to input data (PowerState)
2375 * @return   always 0
2376 */
2377 static int vega10_init_smc_table(struct pp_hwmgr *hwmgr)
2378 {
2379         int result;
2380         struct vega10_hwmgr *data =
2381                         (struct vega10_hwmgr *)(hwmgr->backend);
2382         struct phm_ppt_v2_information *table_info =
2383                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
2384         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
2385         struct pp_atomfwctrl_voltage_table voltage_table;
2386         struct pp_atomfwctrl_bios_boot_up_values boot_up_values;
2387
2388         result = vega10_setup_default_dpm_tables(hwmgr);
2389         PP_ASSERT_WITH_CODE(!result,
2390                         "Failed to setup default DPM tables!",
2391                         return result);
2392
2393         pp_atomfwctrl_get_voltage_table_v4(hwmgr, VOLTAGE_TYPE_VDDC,
2394                         VOLTAGE_OBJ_SVID2,  &voltage_table);
2395         pp_table->MaxVidStep = voltage_table.max_vid_step;
2396
2397         pp_table->GfxDpmVoltageMode =
2398                         (uint8_t)(table_info->uc_gfx_dpm_voltage_mode);
2399         pp_table->SocDpmVoltageMode =
2400                         (uint8_t)(table_info->uc_soc_dpm_voltage_mode);
2401         pp_table->UclkDpmVoltageMode =
2402                         (uint8_t)(table_info->uc_uclk_dpm_voltage_mode);
2403         pp_table->UvdDpmVoltageMode =
2404                         (uint8_t)(table_info->uc_uvd_dpm_voltage_mode);
2405         pp_table->VceDpmVoltageMode =
2406                         (uint8_t)(table_info->uc_vce_dpm_voltage_mode);
2407         pp_table->Mp0DpmVoltageMode =
2408                         (uint8_t)(table_info->uc_mp0_dpm_voltage_mode);
2409
2410         pp_table->DisplayDpmVoltageMode =
2411                         (uint8_t)(table_info->uc_dcef_dpm_voltage_mode);
2412
2413         if (data->registry_data.ulv_support &&
2414                         table_info->us_ulv_voltage_offset) {
2415                 result = vega10_populate_ulv_state(hwmgr);
2416                 PP_ASSERT_WITH_CODE(!result,
2417                                 "Failed to initialize ULV state!",
2418                                 return result);
2419         }
2420
2421         result = vega10_populate_smc_link_levels(hwmgr);
2422         PP_ASSERT_WITH_CODE(!result,
2423                         "Failed to initialize Link Level!",
2424                         return result);
2425
2426         result = vega10_populate_all_graphic_levels(hwmgr);
2427         PP_ASSERT_WITH_CODE(!result,
2428                         "Failed to initialize Graphics Level!",
2429                         return result);
2430
2431         result = vega10_populate_all_memory_levels(hwmgr);
2432         PP_ASSERT_WITH_CODE(!result,
2433                         "Failed to initialize Memory Level!",
2434                         return result);
2435
2436         result = vega10_populate_all_display_clock_levels(hwmgr);
2437         PP_ASSERT_WITH_CODE(!result,
2438                         "Failed to initialize Display Level!",
2439                         return result);
2440
2441         result = vega10_populate_smc_vce_levels(hwmgr);
2442         PP_ASSERT_WITH_CODE(!result,
2443                         "Failed to initialize VCE Level!",
2444                         return result);
2445
2446         result = vega10_populate_smc_uvd_levels(hwmgr);
2447         PP_ASSERT_WITH_CODE(!result,
2448                         "Failed to initialize UVD Level!",
2449                         return result);
2450
2451         if (data->registry_data.clock_stretcher_support) {
2452                 result = vega10_populate_clock_stretcher_table(hwmgr);
2453                 PP_ASSERT_WITH_CODE(!result,
2454                                 "Failed to populate Clock Stretcher Table!",
2455                                 return result);
2456         }
2457
2458         result = pp_atomfwctrl_get_vbios_bootup_values(hwmgr, &boot_up_values);
2459         if (!result) {
2460                 data->vbios_boot_state.vddc     = boot_up_values.usVddc;
2461                 data->vbios_boot_state.vddci    = boot_up_values.usVddci;
2462                 data->vbios_boot_state.mvddc    = boot_up_values.usMvddc;
2463                 data->vbios_boot_state.gfx_clock = boot_up_values.ulGfxClk;
2464                 data->vbios_boot_state.mem_clock = boot_up_values.ulUClk;
2465                 data->vbios_boot_state.soc_clock = boot_up_values.ulSocClk;
2466                 data->vbios_boot_state.dcef_clock = boot_up_values.ulDCEFClk;
2467                 if (0 != boot_up_values.usVddc) {
2468                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
2469                                                 PPSMC_MSG_SetFloorSocVoltage,
2470                                                 (boot_up_values.usVddc * 4));
2471                         data->vbios_boot_state.bsoc_vddc_lock = true;
2472                 } else {
2473                         data->vbios_boot_state.bsoc_vddc_lock = false;
2474                 }
2475                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
2476                                 PPSMC_MSG_SetMinDeepSleepDcefclk,
2477                         (uint32_t)(data->vbios_boot_state.dcef_clock / 100));
2478         }
2479
2480         result = vega10_populate_avfs_parameters(hwmgr);
2481         PP_ASSERT_WITH_CODE(!result,
2482                         "Failed to initialize AVFS Parameters!",
2483                         return result);
2484
2485         result = vega10_populate_gpio_parameters(hwmgr);
2486         PP_ASSERT_WITH_CODE(!result,
2487                         "Failed to initialize GPIO Parameters!",
2488                         return result);
2489
2490         pp_table->GfxclkAverageAlpha = (uint8_t)
2491                         (data->gfxclk_average_alpha);
2492         pp_table->SocclkAverageAlpha = (uint8_t)
2493                         (data->socclk_average_alpha);
2494         pp_table->UclkAverageAlpha = (uint8_t)
2495                         (data->uclk_average_alpha);
2496         pp_table->GfxActivityAverageAlpha = (uint8_t)
2497                         (data->gfx_activity_average_alpha);
2498
2499         vega10_populate_and_upload_avfs_fuse_override(hwmgr);
2500
2501         result = vega10_copy_table_to_smc(hwmgr->smumgr,
2502                         (uint8_t *)pp_table, PPTABLE);
2503         PP_ASSERT_WITH_CODE(!result,
2504                         "Failed to upload PPtable!", return result);
2505
2506         result = vega10_avfs_enable(hwmgr, true);
2507         PP_ASSERT_WITH_CODE(!result, "Attempt to enable AVFS feature Failed!",
2508                                         return result);
2509
2510         vega10_save_default_power_profile(hwmgr);
2511
2512         return 0;
2513 }
2514
2515 static int vega10_enable_thermal_protection(struct pp_hwmgr *hwmgr)
2516 {
2517         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
2518
2519         if (data->smu_features[GNLD_THERMAL].supported) {
2520                 if (data->smu_features[GNLD_THERMAL].enabled)
2521                         pr_info("THERMAL Feature Already enabled!");
2522
2523                 PP_ASSERT_WITH_CODE(
2524                                 !vega10_enable_smc_features(hwmgr->smumgr,
2525                                 true,
2526                                 data->smu_features[GNLD_THERMAL].smu_feature_bitmap),
2527                                 "Enable THERMAL Feature Failed!",
2528                                 return -1);
2529                 data->smu_features[GNLD_THERMAL].enabled = true;
2530         }
2531
2532         return 0;
2533 }
2534
2535 static int vega10_disable_thermal_protection(struct pp_hwmgr *hwmgr)
2536 {
2537         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
2538
2539         if (data->smu_features[GNLD_THERMAL].supported) {
2540                 if (!data->smu_features[GNLD_THERMAL].enabled)
2541                         pr_info("THERMAL Feature Already disabled!");
2542
2543                 PP_ASSERT_WITH_CODE(
2544                                 !vega10_enable_smc_features(hwmgr->smumgr,
2545                                 false,
2546                                 data->smu_features[GNLD_THERMAL].smu_feature_bitmap),
2547                                 "disable THERMAL Feature Failed!",
2548                                 return -1);
2549                 data->smu_features[GNLD_THERMAL].enabled = false;
2550         }
2551
2552         return 0;
2553 }
2554
2555 static int vega10_enable_vrhot_feature(struct pp_hwmgr *hwmgr)
2556 {
2557         struct vega10_hwmgr *data =
2558                         (struct vega10_hwmgr *)(hwmgr->backend);
2559
2560         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2561                         PHM_PlatformCaps_RegulatorHot)) {
2562                 if (data->smu_features[GNLD_VR0HOT].supported) {
2563                         PP_ASSERT_WITH_CODE(
2564                                         !vega10_enable_smc_features(hwmgr->smumgr,
2565                                         true,
2566                                         data->smu_features[GNLD_VR0HOT].smu_feature_bitmap),
2567                                         "Attempt to Enable VR0 Hot feature Failed!",
2568                                         return -1);
2569                         data->smu_features[GNLD_VR0HOT].enabled = true;
2570                 } else {
2571                         if (data->smu_features[GNLD_VR1HOT].supported) {
2572                                 PP_ASSERT_WITH_CODE(
2573                                                 !vega10_enable_smc_features(hwmgr->smumgr,
2574                                                 true,
2575                                                 data->smu_features[GNLD_VR1HOT].smu_feature_bitmap),
2576                                                 "Attempt to Enable VR0 Hot feature Failed!",
2577                                                 return -1);
2578                                 data->smu_features[GNLD_VR1HOT].enabled = true;
2579                         }
2580                 }
2581         }
2582         return 0;
2583 }
2584
2585 static int vega10_enable_ulv(struct pp_hwmgr *hwmgr)
2586 {
2587         struct vega10_hwmgr *data =
2588                         (struct vega10_hwmgr *)(hwmgr->backend);
2589
2590         if (data->registry_data.ulv_support) {
2591                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2592                                 true, data->smu_features[GNLD_ULV].smu_feature_bitmap),
2593                                 "Enable ULV Feature Failed!",
2594                                 return -1);
2595                 data->smu_features[GNLD_ULV].enabled = true;
2596         }
2597
2598         return 0;
2599 }
2600
2601 static int vega10_disable_ulv(struct pp_hwmgr *hwmgr)
2602 {
2603         struct vega10_hwmgr *data =
2604                         (struct vega10_hwmgr *)(hwmgr->backend);
2605
2606         if (data->registry_data.ulv_support) {
2607                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2608                                 false, data->smu_features[GNLD_ULV].smu_feature_bitmap),
2609                                 "disable ULV Feature Failed!",
2610                                 return -EINVAL);
2611                 data->smu_features[GNLD_ULV].enabled = false;
2612         }
2613
2614         return 0;
2615 }
2616
2617 static int vega10_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
2618 {
2619         struct vega10_hwmgr *data =
2620                         (struct vega10_hwmgr *)(hwmgr->backend);
2621
2622         if (data->smu_features[GNLD_DS_GFXCLK].supported) {
2623                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2624                                 true, data->smu_features[GNLD_DS_GFXCLK].smu_feature_bitmap),
2625                                 "Attempt to Enable DS_GFXCLK Feature Failed!",
2626                                 return -EINVAL);
2627                 data->smu_features[GNLD_DS_GFXCLK].enabled = true;
2628         }
2629
2630         if (data->smu_features[GNLD_DS_SOCCLK].supported) {
2631                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2632                                 true, data->smu_features[GNLD_DS_SOCCLK].smu_feature_bitmap),
2633                                 "Attempt to Enable DS_SOCCLK Feature Failed!",
2634                                 return -EINVAL);
2635                 data->smu_features[GNLD_DS_SOCCLK].enabled = true;
2636         }
2637
2638         if (data->smu_features[GNLD_DS_LCLK].supported) {
2639                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2640                                 true, data->smu_features[GNLD_DS_LCLK].smu_feature_bitmap),
2641                                 "Attempt to Enable DS_LCLK Feature Failed!",
2642                                 return -EINVAL);
2643                 data->smu_features[GNLD_DS_LCLK].enabled = true;
2644         }
2645
2646         if (data->smu_features[GNLD_DS_DCEFCLK].supported) {
2647                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2648                                 true, data->smu_features[GNLD_DS_DCEFCLK].smu_feature_bitmap),
2649                                 "Attempt to Enable DS_DCEFCLK Feature Failed!",
2650                                 return -EINVAL);
2651                 data->smu_features[GNLD_DS_DCEFCLK].enabled = true;
2652         }
2653
2654         return 0;
2655 }
2656
2657 static int vega10_disable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
2658 {
2659         struct vega10_hwmgr *data =
2660                         (struct vega10_hwmgr *)(hwmgr->backend);
2661
2662         if (data->smu_features[GNLD_DS_GFXCLK].supported) {
2663                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2664                                 false, data->smu_features[GNLD_DS_GFXCLK].smu_feature_bitmap),
2665                                 "Attempt to disable DS_GFXCLK Feature Failed!",
2666                                 return -EINVAL);
2667                 data->smu_features[GNLD_DS_GFXCLK].enabled = false;
2668         }
2669
2670         if (data->smu_features[GNLD_DS_SOCCLK].supported) {
2671                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2672                                 false, data->smu_features[GNLD_DS_SOCCLK].smu_feature_bitmap),
2673                                 "Attempt to disable DS_ Feature Failed!",
2674                                 return -EINVAL);
2675                 data->smu_features[GNLD_DS_SOCCLK].enabled = false;
2676         }
2677
2678         if (data->smu_features[GNLD_DS_LCLK].supported) {
2679                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2680                                 false, data->smu_features[GNLD_DS_LCLK].smu_feature_bitmap),
2681                                 "Attempt to disable DS_LCLK Feature Failed!",
2682                                 return -EINVAL);
2683                 data->smu_features[GNLD_DS_LCLK].enabled = false;
2684         }
2685
2686         if (data->smu_features[GNLD_DS_DCEFCLK].supported) {
2687                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2688                                 false, data->smu_features[GNLD_DS_DCEFCLK].smu_feature_bitmap),
2689                                 "Attempt to disable DS_DCEFCLK Feature Failed!",
2690                                 return -EINVAL);
2691                 data->smu_features[GNLD_DS_DCEFCLK].enabled = false;
2692         }
2693
2694         return 0;
2695 }
2696
2697 static int vega10_stop_dpm(struct pp_hwmgr *hwmgr, uint32_t bitmap)
2698 {
2699         struct vega10_hwmgr *data =
2700                         (struct vega10_hwmgr *)(hwmgr->backend);
2701         uint32_t i, feature_mask = 0;
2702
2703
2704         if(data->smu_features[GNLD_LED_DISPLAY].supported == true){
2705                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2706                                 false, data->smu_features[GNLD_LED_DISPLAY].smu_feature_bitmap),
2707                 "Attempt to disable LED DPM feature failed!", return -EINVAL);
2708                 data->smu_features[GNLD_LED_DISPLAY].enabled = false;
2709         }
2710
2711         for (i = 0; i < GNLD_DPM_MAX; i++) {
2712                 if (data->smu_features[i].smu_feature_bitmap & bitmap) {
2713                         if (data->smu_features[i].supported) {
2714                                 if (data->smu_features[i].enabled) {
2715                                         feature_mask |= data->smu_features[i].
2716                                                         smu_feature_bitmap;
2717                                         data->smu_features[i].enabled = false;
2718                                 }
2719                         }
2720                 }
2721         }
2722
2723         vega10_enable_smc_features(hwmgr->smumgr, false, feature_mask);
2724
2725         return 0;
2726 }
2727
2728 /**
2729  * @brief Tell SMC to enabled the supported DPMs.
2730  *
2731  * @param    hwmgr - the address of the powerplay hardware manager.
2732  * @Param    bitmap - bitmap for the features to enabled.
2733  * @return   0 on at least one DPM is successfully enabled.
2734  */
2735 static int vega10_start_dpm(struct pp_hwmgr *hwmgr, uint32_t bitmap)
2736 {
2737         struct vega10_hwmgr *data =
2738                         (struct vega10_hwmgr *)(hwmgr->backend);
2739         uint32_t i, feature_mask = 0;
2740
2741         for (i = 0; i < GNLD_DPM_MAX; i++) {
2742                 if (data->smu_features[i].smu_feature_bitmap & bitmap) {
2743                         if (data->smu_features[i].supported) {
2744                                 if (!data->smu_features[i].enabled) {
2745                                         feature_mask |= data->smu_features[i].
2746                                                         smu_feature_bitmap;
2747                                         data->smu_features[i].enabled = true;
2748                                 }
2749                         }
2750                 }
2751         }
2752
2753         if (vega10_enable_smc_features(hwmgr->smumgr,
2754                         true, feature_mask)) {
2755                 for (i = 0; i < GNLD_DPM_MAX; i++) {
2756                         if (data->smu_features[i].smu_feature_bitmap &
2757                                         feature_mask)
2758                                 data->smu_features[i].enabled = false;
2759                 }
2760         }
2761
2762         if(data->smu_features[GNLD_LED_DISPLAY].supported == true){
2763                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2764                                 true, data->smu_features[GNLD_LED_DISPLAY].smu_feature_bitmap),
2765                 "Attempt to Enable LED DPM feature Failed!", return -EINVAL);
2766                 data->smu_features[GNLD_LED_DISPLAY].enabled = true;
2767         }
2768
2769         if (data->vbios_boot_state.bsoc_vddc_lock) {
2770                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
2771                                                 PPSMC_MSG_SetFloorSocVoltage, 0);
2772                 data->vbios_boot_state.bsoc_vddc_lock = false;
2773         }
2774
2775         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2776                         PHM_PlatformCaps_Falcon_QuickTransition)) {
2777                 if (data->smu_features[GNLD_ACDC].supported) {
2778                         PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
2779                                         true, data->smu_features[GNLD_ACDC].smu_feature_bitmap),
2780                                         "Attempt to Enable DS_GFXCLK Feature Failed!",
2781                                         return -1);
2782                         data->smu_features[GNLD_ACDC].enabled = true;
2783                 }
2784         }
2785
2786         return 0;
2787 }
2788
2789 static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
2790 {
2791         struct vega10_hwmgr *data =
2792                         (struct vega10_hwmgr *)(hwmgr->backend);
2793         int tmp_result, result = 0;
2794
2795         tmp_result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
2796                         PPSMC_MSG_ConfigureTelemetry, data->config_telemetry);
2797         PP_ASSERT_WITH_CODE(!tmp_result,
2798                         "Failed to configure telemetry!",
2799                         return tmp_result);
2800
2801         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
2802                         PPSMC_MSG_NumOfDisplays, 0);
2803
2804         tmp_result = (!vega10_is_dpm_running(hwmgr)) ? 0 : -1;
2805         PP_ASSERT_WITH_CODE(!tmp_result,
2806                         "DPM is already running right , skipping re-enablement!",
2807                         return 0);
2808
2809         tmp_result = vega10_construct_voltage_tables(hwmgr);
2810         PP_ASSERT_WITH_CODE(!tmp_result,
2811                         "Failed to contruct voltage tables!",
2812                         result = tmp_result);
2813
2814         tmp_result = vega10_init_smc_table(hwmgr);
2815         PP_ASSERT_WITH_CODE(!tmp_result,
2816                         "Failed to initialize SMC table!",
2817                         result = tmp_result);
2818
2819         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2820                         PHM_PlatformCaps_ThermalController)) {
2821                 tmp_result = vega10_enable_thermal_protection(hwmgr);
2822                 PP_ASSERT_WITH_CODE(!tmp_result,
2823                                 "Failed to enable thermal protection!",
2824                                 result = tmp_result);
2825         }
2826
2827         tmp_result = vega10_enable_vrhot_feature(hwmgr);
2828         PP_ASSERT_WITH_CODE(!tmp_result,
2829                         "Failed to enable VR hot feature!",
2830                         result = tmp_result);
2831
2832         tmp_result = vega10_enable_deep_sleep_master_switch(hwmgr);
2833         PP_ASSERT_WITH_CODE(!tmp_result,
2834                         "Failed to enable deep sleep master switch!",
2835                         result = tmp_result);
2836
2837         tmp_result = vega10_start_dpm(hwmgr, SMC_DPM_FEATURES);
2838         PP_ASSERT_WITH_CODE(!tmp_result,
2839                         "Failed to start DPM!", result = tmp_result);
2840
2841         tmp_result = vega10_enable_power_containment(hwmgr);
2842         PP_ASSERT_WITH_CODE(!tmp_result,
2843                         "Failed to enable power containment!",
2844                         result = tmp_result);
2845
2846         tmp_result = vega10_power_control_set_level(hwmgr);
2847         PP_ASSERT_WITH_CODE(!tmp_result,
2848                         "Failed to power control set level!",
2849                         result = tmp_result);
2850
2851         tmp_result = vega10_enable_ulv(hwmgr);
2852         PP_ASSERT_WITH_CODE(!tmp_result,
2853                         "Failed to enable ULV!",
2854                         result = tmp_result);
2855
2856         return result;
2857 }
2858
2859 static int vega10_get_power_state_size(struct pp_hwmgr *hwmgr)
2860 {
2861         return sizeof(struct vega10_power_state);
2862 }
2863
2864 static int vega10_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
2865                 void *state, struct pp_power_state *power_state,
2866                 void *pp_table, uint32_t classification_flag)
2867 {
2868         ATOM_Vega10_GFXCLK_Dependency_Record_V2 *patom_record_V2;
2869         struct vega10_power_state *vega10_power_state =
2870                         cast_phw_vega10_power_state(&(power_state->hardware));
2871         struct vega10_performance_level *performance_level;
2872         ATOM_Vega10_State *state_entry = (ATOM_Vega10_State *)state;
2873         ATOM_Vega10_POWERPLAYTABLE *powerplay_table =
2874                         (ATOM_Vega10_POWERPLAYTABLE *)pp_table;
2875         ATOM_Vega10_SOCCLK_Dependency_Table *socclk_dep_table =
2876                         (ATOM_Vega10_SOCCLK_Dependency_Table *)
2877                         (((unsigned long)powerplay_table) +
2878                         le16_to_cpu(powerplay_table->usSocclkDependencyTableOffset));
2879         ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table =
2880                         (ATOM_Vega10_GFXCLK_Dependency_Table *)
2881                         (((unsigned long)powerplay_table) +
2882                         le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset));
2883         ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table =
2884                         (ATOM_Vega10_MCLK_Dependency_Table *)
2885                         (((unsigned long)powerplay_table) +
2886                         le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
2887
2888
2889         /* The following fields are not initialized here:
2890          * id orderedList allStatesList
2891          */
2892         power_state->classification.ui_label =
2893                         (le16_to_cpu(state_entry->usClassification) &
2894                         ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
2895                         ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
2896         power_state->classification.flags = classification_flag;
2897         /* NOTE: There is a classification2 flag in BIOS
2898          * that is not being used right now
2899          */
2900         power_state->classification.temporary_state = false;
2901         power_state->classification.to_be_deleted = false;
2902
2903         power_state->validation.disallowOnDC =
2904                         ((le32_to_cpu(state_entry->ulCapsAndSettings) &
2905                                         ATOM_Vega10_DISALLOW_ON_DC) != 0);
2906
2907         power_state->display.disableFrameModulation = false;
2908         power_state->display.limitRefreshrate = false;
2909         power_state->display.enableVariBright =
2910                         ((le32_to_cpu(state_entry->ulCapsAndSettings) &
2911                                         ATOM_Vega10_ENABLE_VARIBRIGHT) != 0);
2912
2913         power_state->validation.supportedPowerLevels = 0;
2914         power_state->uvd_clocks.VCLK = 0;
2915         power_state->uvd_clocks.DCLK = 0;
2916         power_state->temperatures.min = 0;
2917         power_state->temperatures.max = 0;
2918
2919         performance_level = &(vega10_power_state->performance_levels
2920                         [vega10_power_state->performance_level_count++]);
2921
2922         PP_ASSERT_WITH_CODE(
2923                         (vega10_power_state->performance_level_count <
2924                                         NUM_GFXCLK_DPM_LEVELS),
2925                         "Performance levels exceeds SMC limit!",
2926                         return -1);
2927
2928         PP_ASSERT_WITH_CODE(
2929                         (vega10_power_state->performance_level_count <=
2930                                         hwmgr->platform_descriptor.
2931                                         hardwareActivityPerformanceLevels),
2932                         "Performance levels exceeds Driver limit!",
2933                         return -1);
2934
2935         /* Performance levels are arranged from low to high. */
2936         performance_level->soc_clock = socclk_dep_table->entries
2937                         [state_entry->ucSocClockIndexLow].ulClk;
2938         performance_level->gfx_clock = gfxclk_dep_table->entries
2939                         [state_entry->ucGfxClockIndexLow].ulClk;
2940         performance_level->mem_clock = mclk_dep_table->entries
2941                         [state_entry->ucMemClockIndexLow].ulMemClk;
2942
2943         performance_level = &(vega10_power_state->performance_levels
2944                                 [vega10_power_state->performance_level_count++]);
2945         performance_level->soc_clock = socclk_dep_table->entries
2946                                 [state_entry->ucSocClockIndexHigh].ulClk;
2947         if (gfxclk_dep_table->ucRevId == 0) {
2948                 performance_level->gfx_clock = gfxclk_dep_table->entries
2949                         [state_entry->ucGfxClockIndexHigh].ulClk;
2950         } else if (gfxclk_dep_table->ucRevId == 1) {
2951                 patom_record_V2 = (ATOM_Vega10_GFXCLK_Dependency_Record_V2 *)gfxclk_dep_table->entries;
2952                 performance_level->gfx_clock = patom_record_V2[state_entry->ucGfxClockIndexHigh].ulClk;
2953         }
2954
2955         performance_level->mem_clock = mclk_dep_table->entries
2956                         [state_entry->ucMemClockIndexHigh].ulMemClk;
2957         return 0;
2958 }
2959
2960 static int vega10_get_pp_table_entry(struct pp_hwmgr *hwmgr,
2961                 unsigned long entry_index, struct pp_power_state *state)
2962 {
2963         int result;
2964         struct vega10_power_state *ps;
2965
2966         state->hardware.magic = PhwVega10_Magic;
2967
2968         ps = cast_phw_vega10_power_state(&state->hardware);
2969
2970         result = vega10_get_powerplay_table_entry(hwmgr, entry_index, state,
2971                         vega10_get_pp_table_entry_callback_func);
2972
2973         /*
2974          * This is the earliest time we have all the dependency table
2975          * and the VBIOS boot state
2976          */
2977         /* set DC compatible flag if this state supports DC */
2978         if (!state->validation.disallowOnDC)
2979                 ps->dc_compatible = true;
2980
2981         ps->uvd_clks.vclk = state->uvd_clocks.VCLK;
2982         ps->uvd_clks.dclk = state->uvd_clocks.DCLK;
2983
2984         return 0;
2985 }
2986
2987 static int vega10_patch_boot_state(struct pp_hwmgr *hwmgr,
2988              struct pp_hw_power_state *hw_ps)
2989 {
2990         return 0;
2991 }
2992
2993 static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
2994                                 struct pp_power_state  *request_ps,
2995                         const struct pp_power_state *current_ps)
2996 {
2997         struct vega10_power_state *vega10_ps =
2998                                 cast_phw_vega10_power_state(&request_ps->hardware);
2999         uint32_t sclk;
3000         uint32_t mclk;
3001         struct PP_Clocks minimum_clocks = {0};
3002         bool disable_mclk_switching;
3003         bool disable_mclk_switching_for_frame_lock;
3004         bool disable_mclk_switching_for_vr;
3005         bool force_mclk_high;
3006         struct cgs_display_info info = {0};
3007         const struct phm_clock_and_voltage_limits *max_limits;
3008         uint32_t i;
3009         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
3010         struct phm_ppt_v2_information *table_info =
3011                         (struct phm_ppt_v2_information *)(hwmgr->pptable);
3012         int32_t count;
3013         uint32_t stable_pstate_sclk_dpm_percentage;
3014         uint32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
3015         uint32_t latency;
3016
3017         data->battery_state = (PP_StateUILabel_Battery ==
3018                         request_ps->classification.ui_label);
3019
3020         if (vega10_ps->performance_level_count != 2)
3021                 pr_info("VI should always have 2 performance levels");
3022
3023         max_limits = (PP_PowerSource_AC == hwmgr->power_source) ?
3024                         &(hwmgr->dyn_state.max_clock_voltage_on_ac) :
3025                         &(hwmgr->dyn_state.max_clock_voltage_on_dc);
3026
3027         /* Cap clock DPM tables at DC MAX if it is in DC. */
3028         if (PP_PowerSource_DC == hwmgr->power_source) {
3029                 for (i = 0; i < vega10_ps->performance_level_count; i++) {
3030                         if (vega10_ps->performance_levels[i].mem_clock >
3031                                 max_limits->mclk)
3032                                 vega10_ps->performance_levels[i].mem_clock =
3033                                                 max_limits->mclk;
3034                         if (vega10_ps->performance_levels[i].gfx_clock >
3035                                 max_limits->sclk)
3036                                 vega10_ps->performance_levels[i].gfx_clock =
3037                                                 max_limits->sclk;
3038                 }
3039         }
3040
3041         vega10_ps->vce_clks.evclk = hwmgr->vce_arbiter.evclk;
3042         vega10_ps->vce_clks.ecclk = hwmgr->vce_arbiter.ecclk;
3043
3044         cgs_get_active_displays_info(hwmgr->device, &info);
3045
3046         /* result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
3047         minimum_clocks.engineClock = hwmgr->display_config.min_core_set_clock;
3048         minimum_clocks.memoryClock = hwmgr->display_config.min_mem_set_clock;
3049
3050         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3051                         PHM_PlatformCaps_StablePState)) {
3052                 PP_ASSERT_WITH_CODE(
3053                         data->registry_data.stable_pstate_sclk_dpm_percentage >= 1 &&
3054                         data->registry_data.stable_pstate_sclk_dpm_percentage <= 100,
3055                         "percent sclk value must range from 1% to 100%, setting default value",
3056                         stable_pstate_sclk_dpm_percentage = 75);
3057
3058                 max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
3059                 stable_pstate_sclk = (max_limits->sclk *
3060                                 stable_pstate_sclk_dpm_percentage) / 100;
3061
3062                 for (count = table_info->vdd_dep_on_sclk->count - 1;
3063                                 count >= 0; count--) {
3064                         if (stable_pstate_sclk >=
3065                                         table_info->vdd_dep_on_sclk->entries[count].clk) {
3066                                 stable_pstate_sclk =
3067                                                 table_info->vdd_dep_on_sclk->entries[count].clk;
3068                                 break;
3069                         }
3070                 }
3071
3072                 if (count < 0)
3073                         stable_pstate_sclk = table_info->vdd_dep_on_sclk->entries[0].clk;
3074
3075                 stable_pstate_mclk = max_limits->mclk;
3076
3077                 minimum_clocks.engineClock = stable_pstate_sclk;
3078                 minimum_clocks.memoryClock = stable_pstate_mclk;
3079         }
3080
3081         if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk)
3082                 minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk;
3083
3084         if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
3085                 minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
3086
3087         vega10_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold;
3088
3089         if (hwmgr->gfx_arbiter.sclk_over_drive) {
3090                 PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <=
3091                                 hwmgr->platform_descriptor.overdriveLimit.engineClock),
3092                                 "Overdrive sclk exceeds limit",
3093                                 hwmgr->gfx_arbiter.sclk_over_drive =
3094                                                 hwmgr->platform_descriptor.overdriveLimit.engineClock);
3095
3096                 if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk)
3097                         vega10_ps->performance_levels[1].gfx_clock =
3098                                         hwmgr->gfx_arbiter.sclk_over_drive;
3099         }
3100
3101         if (hwmgr->gfx_arbiter.mclk_over_drive) {
3102                 PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <=
3103                                 hwmgr->platform_descriptor.overdriveLimit.memoryClock),
3104                                 "Overdrive mclk exceeds limit",
3105                                 hwmgr->gfx_arbiter.mclk_over_drive =
3106                                                 hwmgr->platform_descriptor.overdriveLimit.memoryClock);
3107
3108                 if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk)
3109                         vega10_ps->performance_levels[1].mem_clock =
3110                                         hwmgr->gfx_arbiter.mclk_over_drive;
3111         }
3112
3113         disable_mclk_switching_for_frame_lock = phm_cap_enabled(
3114                                     hwmgr->platform_descriptor.platformCaps,
3115                                     PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
3116         disable_mclk_switching_for_vr = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3117                         PHM_PlatformCaps_DisableMclkSwitchForVR);
3118         force_mclk_high = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3119                         PHM_PlatformCaps_ForceMclkHigh);
3120
3121         disable_mclk_switching = (info.display_count > 1) ||
3122                                     disable_mclk_switching_for_frame_lock ||
3123                                     disable_mclk_switching_for_vr ||
3124                                     force_mclk_high;
3125
3126         sclk = vega10_ps->performance_levels[0].gfx_clock;
3127         mclk = vega10_ps->performance_levels[0].mem_clock;
3128
3129         if (sclk < minimum_clocks.engineClock)
3130                 sclk = (minimum_clocks.engineClock > max_limits->sclk) ?
3131                                 max_limits->sclk : minimum_clocks.engineClock;
3132
3133         if (mclk < minimum_clocks.memoryClock)
3134                 mclk = (minimum_clocks.memoryClock > max_limits->mclk) ?
3135                                 max_limits->mclk : minimum_clocks.memoryClock;
3136
3137         vega10_ps->performance_levels[0].gfx_clock = sclk;
3138         vega10_ps->performance_levels[0].mem_clock = mclk;
3139
3140         if (vega10_ps->performance_levels[1].gfx_clock <
3141                         vega10_ps->performance_levels[0].gfx_clock)
3142                 vega10_ps->performance_levels[0].gfx_clock =
3143                                 vega10_ps->performance_levels[1].gfx_clock;
3144
3145         if (disable_mclk_switching) {
3146                 /* Set Mclk the max of level 0 and level 1 */
3147                 if (mclk < vega10_ps->performance_levels[1].mem_clock)
3148                         mclk = vega10_ps->performance_levels[1].mem_clock;
3149
3150                 /* Find the lowest MCLK frequency that is within
3151                  * the tolerable latency defined in DAL
3152                  */
3153                 latency = 0;
3154                 for (i = 0; i < data->mclk_latency_table.count; i++) {
3155                         if ((data->mclk_latency_table.entries[i].latency <= latency) &&
3156                                 (data->mclk_latency_table.entries[i].frequency >=
3157                                                 vega10_ps->performance_levels[0].mem_clock) &&
3158                                 (data->mclk_latency_table.entries[i].frequency <=
3159                                                 vega10_ps->performance_levels[1].mem_clock))
3160                                 mclk = data->mclk_latency_table.entries[i].frequency;
3161                 }
3162                 vega10_ps->performance_levels[0].mem_clock = mclk;
3163         } else {
3164                 if (vega10_ps->performance_levels[1].mem_clock <
3165                                 vega10_ps->performance_levels[0].mem_clock)
3166                         vega10_ps->performance_levels[0].mem_clock =
3167                                         vega10_ps->performance_levels[1].mem_clock;
3168         }
3169
3170         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3171                         PHM_PlatformCaps_StablePState)) {
3172                 for (i = 0; i < vega10_ps->performance_level_count; i++) {
3173                         vega10_ps->performance_levels[i].gfx_clock = stable_pstate_sclk;
3174                         vega10_ps->performance_levels[i].mem_clock = stable_pstate_mclk;
3175                 }
3176         }
3177
3178         return 0;
3179 }
3180
3181 static int vega10_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
3182 {
3183         const struct phm_set_power_state_input *states =
3184                         (const struct phm_set_power_state_input *)input;
3185         const struct vega10_power_state *vega10_ps =
3186                         cast_const_phw_vega10_power_state(states->pnew_state);
3187         struct vega10_hwmgr *data =
3188                         (struct vega10_hwmgr *)(hwmgr->backend);
3189         struct vega10_single_dpm_table *sclk_table =
3190                         &(data->dpm_table.gfx_table);
3191         uint32_t sclk = vega10_ps->performance_levels
3192                         [vega10_ps->performance_level_count - 1].gfx_clock;
3193         struct vega10_single_dpm_table *mclk_table =
3194                         &(data->dpm_table.mem_table);
3195         uint32_t mclk = vega10_ps->performance_levels
3196                         [vega10_ps->performance_level_count - 1].mem_clock;
3197         struct PP_Clocks min_clocks = {0};
3198         uint32_t i;
3199         struct cgs_display_info info = {0};
3200
3201         data->need_update_dpm_table = 0;
3202
3203         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3204                         PHM_PlatformCaps_ODNinACSupport) ||
3205                 phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3206                                 PHM_PlatformCaps_ODNinDCSupport)) {
3207                 for (i = 0; i < sclk_table->count; i++) {
3208                         if (sclk == sclk_table->dpm_levels[i].value)
3209                                 break;
3210                 }
3211
3212                 if (!(data->apply_overdrive_next_settings_mask &
3213                                 DPMTABLE_OD_UPDATE_SCLK) && i >= sclk_table->count) {
3214                         /* Check SCLK in DAL's minimum clocks
3215                          * in case DeepSleep divider update is required.
3216                          */
3217                         if (data->display_timing.min_clock_in_sr !=
3218                                         min_clocks.engineClockInSR &&
3219                                 (min_clocks.engineClockInSR >=
3220                                                 VEGA10_MINIMUM_ENGINE_CLOCK ||
3221                                         data->display_timing.min_clock_in_sr >=
3222                                                 VEGA10_MINIMUM_ENGINE_CLOCK))
3223                                 data->need_update_dpm_table |= DPMTABLE_UPDATE_SCLK;
3224                 }
3225
3226                 cgs_get_active_displays_info(hwmgr->device, &info);
3227
3228                 if (data->display_timing.num_existing_displays !=
3229                                 info.display_count)
3230                         data->need_update_dpm_table |= DPMTABLE_UPDATE_MCLK;
3231         } else {
3232                 for (i = 0; i < sclk_table->count; i++) {
3233                         if (sclk == sclk_table->dpm_levels[i].value)
3234                                 break;
3235                 }
3236
3237                 if (i >= sclk_table->count)
3238                         data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
3239                 else {
3240                         /* Check SCLK in DAL's minimum clocks
3241                          * in case DeepSleep divider update is required.
3242                          */
3243                         if (data->display_timing.min_clock_in_sr !=
3244                                         min_clocks.engineClockInSR &&
3245                                 (min_clocks.engineClockInSR >=
3246                                                 VEGA10_MINIMUM_ENGINE_CLOCK ||
3247                                         data->display_timing.min_clock_in_sr >=
3248                                                 VEGA10_MINIMUM_ENGINE_CLOCK))
3249                                 data->need_update_dpm_table |= DPMTABLE_UPDATE_SCLK;
3250                 }
3251
3252                 for (i = 0; i < mclk_table->count; i++) {
3253                         if (mclk == mclk_table->dpm_levels[i].value)
3254                                 break;
3255                 }
3256
3257                 cgs_get_active_displays_info(hwmgr->device, &info);
3258
3259                 if (i >= mclk_table->count)
3260                         data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
3261
3262                 if (data->display_timing.num_existing_displays !=
3263                                 info.display_count ||
3264                                 i >= mclk_table->count)
3265                         data->need_update_dpm_table |= DPMTABLE_UPDATE_MCLK;
3266         }
3267         return 0;
3268 }
3269
3270 static int vega10_populate_and_upload_sclk_mclk_dpm_levels(
3271                 struct pp_hwmgr *hwmgr, const void *input)
3272 {
3273         int result = 0;
3274         const struct phm_set_power_state_input *states =
3275                         (const struct phm_set_power_state_input *)input;
3276         const struct vega10_power_state *vega10_ps =
3277                         cast_const_phw_vega10_power_state(states->pnew_state);
3278         struct vega10_hwmgr *data =
3279                         (struct vega10_hwmgr *)(hwmgr->backend);
3280         uint32_t sclk = vega10_ps->performance_levels
3281                         [vega10_ps->performance_level_count - 1].gfx_clock;
3282         uint32_t mclk = vega10_ps->performance_levels
3283                         [vega10_ps->performance_level_count - 1].mem_clock;
3284         struct vega10_dpm_table *dpm_table = &data->dpm_table;
3285         struct vega10_dpm_table *golden_dpm_table =
3286                         &data->golden_dpm_table;
3287         uint32_t dpm_count, clock_percent;
3288         uint32_t i;
3289
3290         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3291                         PHM_PlatformCaps_ODNinACSupport) ||
3292                 phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3293                         PHM_PlatformCaps_ODNinDCSupport)) {
3294
3295                 if (!data->need_update_dpm_table &&
3296                         !data->apply_optimized_settings &&
3297                         !data->apply_overdrive_next_settings_mask)
3298                         return 0;
3299
3300                 if (data->apply_overdrive_next_settings_mask &
3301                                 DPMTABLE_OD_UPDATE_SCLK) {
3302                         for (dpm_count = 0;
3303                                         dpm_count < dpm_table->gfx_table.count;
3304                                         dpm_count++) {
3305                                 dpm_table->gfx_table.dpm_levels[dpm_count].enabled =
3306                                                 data->odn_dpm_table.odn_core_clock_dpm_levels.
3307                                                 performance_level_entries[dpm_count].enabled;
3308                                 dpm_table->gfx_table.dpm_levels[dpm_count].value =
3309                                                 data->odn_dpm_table.odn_core_clock_dpm_levels.
3310                                                 performance_level_entries[dpm_count].clock;
3311                         }
3312                 }
3313
3314                 if (data->apply_overdrive_next_settings_mask &
3315                                 DPMTABLE_OD_UPDATE_MCLK) {
3316                         for (dpm_count = 0;
3317                                         dpm_count < dpm_table->mem_table.count;
3318                                         dpm_count++) {
3319                                 dpm_table->mem_table.dpm_levels[dpm_count].enabled =
3320                                                 data->odn_dpm_table.odn_memory_clock_dpm_levels.
3321                                                 performance_level_entries[dpm_count].enabled;
3322                                 dpm_table->mem_table.dpm_levels[dpm_count].value =
3323                                                 data->odn_dpm_table.odn_memory_clock_dpm_levels.
3324                                                 performance_level_entries[dpm_count].clock;
3325                         }
3326                 }
3327
3328                 if ((data->need_update_dpm_table & DPMTABLE_UPDATE_SCLK) ||
3329                         data->apply_optimized_settings ||
3330                         (data->apply_overdrive_next_settings_mask &
3331                                         DPMTABLE_OD_UPDATE_SCLK)) {
3332                         result = vega10_populate_all_graphic_levels(hwmgr);
3333                         PP_ASSERT_WITH_CODE(!result,
3334                                         "Failed to populate SCLK during \
3335                                         PopulateNewDPMClocksStates Function!",
3336                                         return result);
3337                 }
3338
3339                 if ((data->need_update_dpm_table & DPMTABLE_UPDATE_MCLK) ||
3340                         (data->apply_overdrive_next_settings_mask &
3341                                         DPMTABLE_OD_UPDATE_MCLK)){
3342                         result = vega10_populate_all_memory_levels(hwmgr);
3343                         PP_ASSERT_WITH_CODE(!result,
3344                                         "Failed to populate MCLK during \
3345                                         PopulateNewDPMClocksStates Function!",
3346                                         return result);
3347                 }
3348         } else {
3349                 if (!data->need_update_dpm_table &&
3350                                 !data->apply_optimized_settings)
3351                         return 0;
3352
3353                 if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_SCLK &&
3354                                 data->smu_features[GNLD_DPM_GFXCLK].supported) {
3355                                 dpm_table->
3356                                 gfx_table.dpm_levels[dpm_table->gfx_table.count - 1].
3357                                 value = sclk;
3358                                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3359                                                 PHM_PlatformCaps_OD6PlusinACSupport) ||
3360                                         phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3361                                                         PHM_PlatformCaps_OD6PlusinDCSupport)) {
3362                                         /* Need to do calculation based on the golden DPM table
3363                                          * as the Heatmap GPU Clock axis is also based on
3364                                          * the default values
3365                                          */
3366                                         PP_ASSERT_WITH_CODE(
3367                                                         golden_dpm_table->gfx_table.dpm_levels
3368                                                         [golden_dpm_table->gfx_table.count - 1].value,
3369                                                         "Divide by 0!",
3370                                                         return -1);
3371
3372                                         dpm_count = dpm_table->gfx_table.count < 2 ?
3373                                                         0 : dpm_table->gfx_table.count - 2;
3374                                         for (i = dpm_count; i > 1; i--) {
3375                                                 if (sclk > golden_dpm_table->gfx_table.dpm_levels
3376                                                         [golden_dpm_table->gfx_table.count - 1].value) {
3377                                                         clock_percent =
3378                                                                 ((sclk - golden_dpm_table->gfx_table.dpm_levels
3379                                                                 [golden_dpm_table->gfx_table.count - 1].value) *
3380                                                                 100) /
3381                                                                 golden_dpm_table->gfx_table.dpm_levels
3382                                                                 [golden_dpm_table->gfx_table.count - 1].value;
3383
3384                                                         dpm_table->gfx_table.dpm_levels[i].value =
3385                                                                 golden_dpm_table->gfx_table.dpm_levels[i].value +
3386                                                                 (golden_dpm_table->gfx_table.dpm_levels[i].value *
3387                                                                 clock_percent) / 100;
3388                                                 } else if (golden_dpm_table->
3389                                                                 gfx_table.dpm_levels[dpm_table->gfx_table.count-1].value >
3390                                                                 sclk) {
3391                                                         clock_percent =
3392                                                                 ((golden_dpm_table->gfx_table.dpm_levels
3393                                                                 [golden_dpm_table->gfx_table.count - 1].value -
3394                                                                 sclk) * 100) /
3395                                                                 golden_dpm_table->gfx_table.dpm_levels
3396                                                                 [golden_dpm_table->gfx_table.count-1].value;
3397
3398                                                         dpm_table->gfx_table.dpm_levels[i].value =
3399                                                                 golden_dpm_table->gfx_table.dpm_levels[i].value -
3400                                                                 (golden_dpm_table->gfx_table.dpm_levels[i].value *
3401                                                                 clock_percent) / 100;
3402                                                 } else
3403                                                         dpm_table->gfx_table.dpm_levels[i].value =
3404                                                                 golden_dpm_table->gfx_table.dpm_levels[i].value;
3405                                         }
3406                                 }
3407                         }
3408
3409                 if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_MCLK &&
3410                                 data->smu_features[GNLD_DPM_UCLK].supported) {
3411                         dpm_table->
3412                         mem_table.dpm_levels[dpm_table->mem_table.count - 1].
3413                         value = mclk;
3414
3415                         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3416                                         PHM_PlatformCaps_OD6PlusinACSupport) ||
3417                                 phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3418                                                 PHM_PlatformCaps_OD6PlusinDCSupport)) {
3419
3420                                 PP_ASSERT_WITH_CODE(
3421                                         golden_dpm_table->mem_table.dpm_levels
3422                                         [golden_dpm_table->mem_table.count - 1].value,
3423                                         "Divide by 0!",
3424                                         return -1);
3425
3426                                 dpm_count = dpm_table->mem_table.count < 2 ?
3427                                                 0 : dpm_table->mem_table.count - 2;
3428                                 for (i = dpm_count; i > 1; i--) {
3429                                         if (mclk > golden_dpm_table->mem_table.dpm_levels
3430                                                 [golden_dpm_table->mem_table.count-1].value) {
3431                                                 clock_percent = ((mclk -
3432                                                         golden_dpm_table->mem_table.dpm_levels
3433                                                         [golden_dpm_table->mem_table.count-1].value) *
3434                                                         100) /
3435                                                         golden_dpm_table->mem_table.dpm_levels
3436                                                         [golden_dpm_table->mem_table.count-1].value;
3437
3438                                                 dpm_table->mem_table.dpm_levels[i].value =
3439                                                         golden_dpm_table->mem_table.dpm_levels[i].value +
3440                                                         (golden_dpm_table->mem_table.dpm_levels[i].value *
3441                                                         clock_percent) / 100;
3442                                         } else if (golden_dpm_table->mem_table.dpm_levels
3443                                                         [dpm_table->mem_table.count-1].value > mclk) {
3444                                                 clock_percent = ((golden_dpm_table->mem_table.dpm_levels
3445                                                         [golden_dpm_table->mem_table.count-1].value - mclk) *
3446                                                         100) /
3447                                                         golden_dpm_table->mem_table.dpm_levels
3448                                                         [golden_dpm_table->mem_table.count-1].value;
3449
3450                                                 dpm_table->mem_table.dpm_levels[i].value =
3451                                                         golden_dpm_table->mem_table.dpm_levels[i].value -
3452                                                         (golden_dpm_table->mem_table.dpm_levels[i].value *
3453                                                         clock_percent) / 100;
3454                                         } else
3455                                                 dpm_table->mem_table.dpm_levels[i].value =
3456                                                         golden_dpm_table->mem_table.dpm_levels[i].value;
3457                                 }
3458                         }
3459                 }
3460
3461                 if ((data->need_update_dpm_table &
3462                         (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) ||
3463                         data->apply_optimized_settings) {
3464                         result = vega10_populate_all_graphic_levels(hwmgr);
3465                         PP_ASSERT_WITH_CODE(!result,
3466                                         "Failed to populate SCLK during \
3467                                         PopulateNewDPMClocksStates Function!",
3468                                         return result);
3469                 }
3470
3471                 if (data->need_update_dpm_table &
3472                                 (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
3473                         result = vega10_populate_all_memory_levels(hwmgr);
3474                         PP_ASSERT_WITH_CODE(!result,
3475                                         "Failed to populate MCLK during \
3476                                         PopulateNewDPMClocksStates Function!",
3477                                         return result);
3478                 }
3479         }
3480         return result;
3481 }
3482
3483 static int vega10_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
3484                 struct vega10_single_dpm_table *dpm_table,
3485                 uint32_t low_limit, uint32_t high_limit)
3486 {
3487         uint32_t i;
3488
3489         for (i = 0; i < dpm_table->count; i++) {
3490                 if ((dpm_table->dpm_levels[i].value < low_limit) ||
3491                     (dpm_table->dpm_levels[i].value > high_limit))
3492                         dpm_table->dpm_levels[i].enabled = false;
3493                 else
3494                         dpm_table->dpm_levels[i].enabled = true;
3495         }
3496         return 0;
3497 }
3498
3499 static int vega10_trim_single_dpm_states_with_mask(struct pp_hwmgr *hwmgr,
3500                 struct vega10_single_dpm_table *dpm_table,
3501                 uint32_t low_limit, uint32_t high_limit,
3502                 uint32_t disable_dpm_mask)
3503 {
3504         uint32_t i;
3505
3506         for (i = 0; i < dpm_table->count; i++) {
3507                 if ((dpm_table->dpm_levels[i].value < low_limit) ||
3508                     (dpm_table->dpm_levels[i].value > high_limit))
3509                         dpm_table->dpm_levels[i].enabled = false;
3510                 else if (!((1 << i) & disable_dpm_mask))
3511                         dpm_table->dpm_levels[i].enabled = false;
3512                 else
3513                         dpm_table->dpm_levels[i].enabled = true;
3514         }
3515         return 0;
3516 }
3517
3518 static int vega10_trim_dpm_states(struct pp_hwmgr *hwmgr,
3519                 const struct vega10_power_state *vega10_ps)
3520 {
3521         struct vega10_hwmgr *data =
3522                         (struct vega10_hwmgr *)(hwmgr->backend);
3523         uint32_t high_limit_count;
3524
3525         PP_ASSERT_WITH_CODE((vega10_ps->performance_level_count >= 1),
3526                         "power state did not have any performance level",
3527                         return -1);
3528
3529         high_limit_count = (vega10_ps->performance_level_count == 1) ? 0 : 1;
3530
3531         vega10_trim_single_dpm_states(hwmgr,
3532                         &(data->dpm_table.soc_table),
3533                         vega10_ps->performance_levels[0].soc_clock,
3534                         vega10_ps->performance_levels[high_limit_count].soc_clock);
3535
3536         vega10_trim_single_dpm_states_with_mask(hwmgr,
3537                         &(data->dpm_table.gfx_table),
3538                         vega10_ps->performance_levels[0].gfx_clock,
3539                         vega10_ps->performance_levels[high_limit_count].gfx_clock,
3540                         data->disable_dpm_mask);
3541
3542         vega10_trim_single_dpm_states(hwmgr,
3543                         &(data->dpm_table.mem_table),
3544                         vega10_ps->performance_levels[0].mem_clock,
3545                         vega10_ps->performance_levels[high_limit_count].mem_clock);
3546
3547         return 0;
3548 }
3549
3550 static uint32_t vega10_find_lowest_dpm_level(
3551                 struct vega10_single_dpm_table *table)
3552 {
3553         uint32_t i;
3554
3555         for (i = 0; i < table->count; i++) {
3556                 if (table->dpm_levels[i].enabled)
3557                         break;
3558         }
3559
3560         return i;
3561 }
3562
3563 static uint32_t vega10_find_highest_dpm_level(
3564                 struct vega10_single_dpm_table *table)
3565 {
3566         uint32_t i = 0;
3567
3568         if (table->count <= MAX_REGULAR_DPM_NUMBER) {
3569                 for (i = table->count; i > 0; i--) {
3570                         if (table->dpm_levels[i - 1].enabled)
3571                                 return i - 1;
3572                 }
3573         } else {
3574                 pr_info("DPM Table Has Too Many Entries!");
3575                 return MAX_REGULAR_DPM_NUMBER - 1;
3576         }
3577
3578         return i;
3579 }
3580
3581 static void vega10_apply_dal_minimum_voltage_request(
3582                 struct pp_hwmgr *hwmgr)
3583 {
3584         return;
3585 }
3586
3587 static int vega10_upload_dpm_bootup_level(struct pp_hwmgr *hwmgr)
3588 {
3589         struct vega10_hwmgr *data =
3590                         (struct vega10_hwmgr *)(hwmgr->backend);
3591
3592         vega10_apply_dal_minimum_voltage_request(hwmgr);
3593
3594         if (!data->registry_data.sclk_dpm_key_disabled) {
3595                 if (data->smc_state_table.gfx_boot_level !=
3596                                 data->dpm_table.gfx_table.dpm_state.soft_min_level) {
3597                                 PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter(
3598                                 hwmgr->smumgr,
3599                                 PPSMC_MSG_SetSoftMinGfxclkByIndex,
3600                                 data->smc_state_table.gfx_boot_level),
3601                                 "Failed to set soft min sclk index!",
3602                                 return -EINVAL);
3603                         data->dpm_table.gfx_table.dpm_state.soft_min_level =
3604                                         data->smc_state_table.gfx_boot_level;
3605                 }
3606         }
3607
3608         if (!data->registry_data.mclk_dpm_key_disabled) {
3609                 if (data->smc_state_table.mem_boot_level !=
3610                                 data->dpm_table.mem_table.dpm_state.soft_min_level) {
3611                                 PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter(
3612                                 hwmgr->smumgr,
3613                                  PPSMC_MSG_SetSoftMinUclkByIndex,
3614                                 data->smc_state_table.mem_boot_level),
3615                                 "Failed to set soft min mclk index!",
3616                                 return -EINVAL);
3617
3618                         data->dpm_table.mem_table.dpm_state.soft_min_level =
3619                                         data->smc_state_table.mem_boot_level;
3620                 }
3621         }
3622
3623         return 0;
3624 }
3625
3626 static int vega10_upload_dpm_max_level(struct pp_hwmgr *hwmgr)
3627 {
3628         struct vega10_hwmgr *data =
3629                         (struct vega10_hwmgr *)(hwmgr->backend);
3630
3631         vega10_apply_dal_minimum_voltage_request(hwmgr);
3632
3633         if (!data->registry_data.sclk_dpm_key_disabled) {
3634                 if (data->smc_state_table.gfx_max_level !=
3635                                 data->dpm_table.gfx_table.dpm_state.soft_max_level) {
3636                                 PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter(
3637                                 hwmgr->smumgr,
3638                                 PPSMC_MSG_SetSoftMaxGfxclkByIndex,
3639                                 data->smc_state_table.gfx_max_level),
3640                                 "Failed to set soft max sclk index!",
3641                                 return -EINVAL);
3642                         data->dpm_table.gfx_table.dpm_state.soft_max_level =
3643                                         data->smc_state_table.gfx_max_level;
3644                 }
3645         }
3646
3647         if (!data->registry_data.mclk_dpm_key_disabled) {
3648                 if (data->smc_state_table.mem_max_level !=
3649                                 data->dpm_table.mem_table.dpm_state.soft_max_level) {
3650                                 PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter(
3651                                 hwmgr->smumgr,
3652                                 PPSMC_MSG_SetSoftMaxUclkByIndex,
3653                                 data->smc_state_table.mem_max_level),
3654                                 "Failed to set soft max mclk index!",
3655                                 return -EINVAL);
3656                         data->dpm_table.mem_table.dpm_state.soft_max_level =
3657                                         data->smc_state_table.mem_max_level;
3658                 }
3659         }
3660
3661         return 0;
3662 }
3663
3664 static int vega10_generate_dpm_level_enable_mask(
3665                 struct pp_hwmgr *hwmgr, const void *input)
3666 {
3667         struct vega10_hwmgr *data =
3668                         (struct vega10_hwmgr *)(hwmgr->backend);
3669         const struct phm_set_power_state_input *states =
3670                         (const struct phm_set_power_state_input *)input;
3671         const struct vega10_power_state *vega10_ps =
3672                         cast_const_phw_vega10_power_state(states->pnew_state);
3673         int i;
3674
3675         PP_ASSERT_WITH_CODE(!vega10_trim_dpm_states(hwmgr, vega10_ps),
3676                         "Attempt to Trim DPM States Failed!",
3677                         return -1);
3678
3679         data->smc_state_table.gfx_boot_level =
3680                         vega10_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
3681         data->smc_state_table.gfx_max_level =
3682                         vega10_find_highest_dpm_level(&(data->dpm_table.gfx_table));
3683         data->smc_state_table.mem_boot_level =
3684                         vega10_find_lowest_dpm_level(&(data->dpm_table.mem_table));
3685         data->smc_state_table.mem_max_level =
3686                         vega10_find_highest_dpm_level(&(data->dpm_table.mem_table));
3687
3688         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
3689                         "Attempt to upload DPM Bootup Levels Failed!",
3690                         return -1);
3691         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
3692                         "Attempt to upload DPM Max Levels Failed!",
3693                         return -1);
3694         for(i = data->smc_state_table.gfx_boot_level; i < data->smc_state_table.gfx_max_level; i++)
3695                 data->dpm_table.gfx_table.dpm_levels[i].enabled = true;
3696
3697
3698         for(i = data->smc_state_table.mem_boot_level; i < data->smc_state_table.mem_max_level; i++)
3699                 data->dpm_table.mem_table.dpm_levels[i].enabled = true;
3700
3701         return 0;
3702 }
3703
3704 int vega10_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
3705 {
3706         struct vega10_hwmgr *data =
3707                         (struct vega10_hwmgr *)(hwmgr->backend);
3708
3709         if (data->smu_features[GNLD_DPM_VCE].supported) {
3710                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
3711                                 enable,
3712                                 data->smu_features[GNLD_DPM_VCE].smu_feature_bitmap),
3713                                 "Attempt to Enable/Disable DPM VCE Failed!",
3714                                 return -1);
3715                 data->smu_features[GNLD_DPM_VCE].enabled = enable;
3716         }
3717
3718         return 0;
3719 }
3720
3721 static int vega10_update_sclk_threshold(struct pp_hwmgr *hwmgr)
3722 {
3723         struct vega10_hwmgr *data =
3724                         (struct vega10_hwmgr *)(hwmgr->backend);
3725         int result = 0;
3726         uint32_t low_sclk_interrupt_threshold = 0;
3727
3728         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3729                         PHM_PlatformCaps_SclkThrottleLowNotification)
3730                 && (hwmgr->gfx_arbiter.sclk_threshold !=
3731                                 data->low_sclk_interrupt_threshold)) {
3732                 data->low_sclk_interrupt_threshold =
3733                                 hwmgr->gfx_arbiter.sclk_threshold;
3734                 low_sclk_interrupt_threshold =
3735                                 data->low_sclk_interrupt_threshold;
3736
3737                 data->smc_state_table.pp_table.LowGfxclkInterruptThreshold =
3738                                 cpu_to_le32(low_sclk_interrupt_threshold);
3739
3740                 /* This message will also enable SmcToHost Interrupt */
3741                 result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3742                                 PPSMC_MSG_SetLowGfxclkInterruptThreshold,
3743                                 (uint32_t)low_sclk_interrupt_threshold);
3744         }
3745
3746         return result;
3747 }
3748
3749 static int vega10_set_power_state_tasks(struct pp_hwmgr *hwmgr,
3750                 const void *input)
3751 {
3752         int tmp_result, result = 0;
3753         struct vega10_hwmgr *data =
3754                         (struct vega10_hwmgr *)(hwmgr->backend);
3755         PPTable_t *pp_table = &(data->smc_state_table.pp_table);
3756
3757         tmp_result = vega10_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
3758         PP_ASSERT_WITH_CODE(!tmp_result,
3759                         "Failed to find DPM states clocks in DPM table!",
3760                         result = tmp_result);
3761
3762         tmp_result = vega10_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
3763         PP_ASSERT_WITH_CODE(!tmp_result,
3764                         "Failed to populate and upload SCLK MCLK DPM levels!",
3765                         result = tmp_result);
3766
3767         tmp_result = vega10_generate_dpm_level_enable_mask(hwmgr, input);
3768         PP_ASSERT_WITH_CODE(!tmp_result,
3769                         "Failed to generate DPM level enabled mask!",
3770                         result = tmp_result);
3771
3772         tmp_result = vega10_update_sclk_threshold(hwmgr);
3773         PP_ASSERT_WITH_CODE(!tmp_result,
3774                         "Failed to update SCLK threshold!",
3775                         result = tmp_result);
3776
3777         result = vega10_copy_table_to_smc(hwmgr->smumgr,
3778                         (uint8_t *)pp_table, PPTABLE);
3779         PP_ASSERT_WITH_CODE(!result,
3780                         "Failed to upload PPtable!", return result);
3781
3782         data->apply_optimized_settings = false;
3783         data->apply_overdrive_next_settings_mask = 0;
3784
3785         return 0;
3786 }
3787
3788 static int vega10_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
3789 {
3790         struct pp_power_state *ps;
3791         struct vega10_power_state *vega10_ps;
3792
3793         if (hwmgr == NULL)
3794                 return -EINVAL;
3795
3796         ps = hwmgr->request_ps;
3797
3798         if (ps == NULL)
3799                 return -EINVAL;
3800
3801         vega10_ps = cast_phw_vega10_power_state(&ps->hardware);
3802
3803         if (low)
3804                 return vega10_ps->performance_levels[0].gfx_clock;
3805         else
3806                 return vega10_ps->performance_levels
3807                                 [vega10_ps->performance_level_count - 1].gfx_clock;
3808 }
3809
3810 static int vega10_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
3811 {
3812         struct pp_power_state *ps;
3813         struct vega10_power_state *vega10_ps;
3814
3815         if (hwmgr == NULL)
3816                 return -EINVAL;
3817
3818         ps = hwmgr->request_ps;
3819
3820         if (ps == NULL)
3821                 return -EINVAL;
3822
3823         vega10_ps = cast_phw_vega10_power_state(&ps->hardware);
3824
3825         if (low)
3826                 return vega10_ps->performance_levels[0].mem_clock;
3827         else
3828                 return vega10_ps->performance_levels
3829                                 [vega10_ps->performance_level_count-1].mem_clock;
3830 }
3831
3832 static int vega10_get_gpu_power(struct pp_hwmgr *hwmgr,
3833                 struct pp_gpu_power *query)
3834 {
3835         uint32_t value;
3836
3837         PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr->smumgr,
3838                         PPSMC_MSG_GetCurrPkgPwr),
3839                         "Failed to get current package power!",
3840                         return -EINVAL);
3841
3842         vega10_read_arg_from_smc(hwmgr->smumgr, &value);
3843         /* power value is an integer */
3844         query->average_gpu_power = value << 8;
3845
3846         return 0;
3847 }
3848
3849 static int vega10_read_sensor(struct pp_hwmgr *hwmgr, int idx,
3850                               void *value, int *size)
3851 {
3852         uint32_t sclk_idx, mclk_idx, activity_percent = 0;
3853         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
3854         struct vega10_dpm_table *dpm_table = &data->dpm_table;
3855         int ret = 0;
3856
3857         switch (idx) {
3858         case AMDGPU_PP_SENSOR_GFX_SCLK:
3859                 ret = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetCurrentGfxclkIndex);
3860                 if (!ret) {
3861                         vega10_read_arg_from_smc(hwmgr->smumgr, &sclk_idx);
3862                         *((uint32_t *)value) = dpm_table->gfx_table.dpm_levels[sclk_idx].value;
3863                         *size = 4;
3864                 }
3865                 break;
3866         case AMDGPU_PP_SENSOR_GFX_MCLK:
3867                 ret = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetCurrentUclkIndex);
3868                 if (!ret) {
3869                         vega10_read_arg_from_smc(hwmgr->smumgr, &mclk_idx);
3870                         *((uint32_t *)value) = dpm_table->mem_table.dpm_levels[mclk_idx].value;
3871                         *size = 4;
3872                 }
3873                 break;
3874         case AMDGPU_PP_SENSOR_GPU_LOAD:
3875                 ret = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_GetAverageGfxActivity, 0);
3876                 if (!ret) {
3877                         vega10_read_arg_from_smc(hwmgr->smumgr, &activity_percent);
3878                         *((uint32_t *)value) = activity_percent > 100 ? 100 : activity_percent;
3879                         *size = 4;
3880                 }
3881                 break;
3882         case AMDGPU_PP_SENSOR_GPU_TEMP:
3883                 *((uint32_t *)value) = vega10_thermal_get_temperature(hwmgr);
3884                 *size = 4;
3885                 break;
3886         case AMDGPU_PP_SENSOR_UVD_POWER:
3887                 *((uint32_t *)value) = data->uvd_power_gated ? 0 : 1;
3888                 *size = 4;
3889                 break;
3890         case AMDGPU_PP_SENSOR_VCE_POWER:
3891                 *((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
3892                 *size = 4;
3893                 break;
3894         case AMDGPU_PP_SENSOR_GPU_POWER:
3895                 if (*size < sizeof(struct pp_gpu_power))
3896                         ret = -EINVAL;
3897                 else {
3898                         *size = sizeof(struct pp_gpu_power);
3899                         ret = vega10_get_gpu_power(hwmgr, (struct pp_gpu_power *)value);
3900                 }
3901                 break;
3902         default:
3903                 ret = -EINVAL;
3904                 break;
3905         }
3906         return ret;
3907 }
3908
3909 static int vega10_notify_smc_display_change(struct pp_hwmgr *hwmgr,
3910                 bool has_disp)
3911 {
3912         return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3913                         PPSMC_MSG_SetUclkFastSwitch,
3914                         has_disp ? 0 : 1);
3915 }
3916
3917 int vega10_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
3918                 struct pp_display_clock_request *clock_req)
3919 {
3920         int result = 0;
3921         enum amd_pp_clock_type clk_type = clock_req->clock_type;
3922         uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
3923         DSPCLK_e clk_select = 0;
3924         uint32_t clk_request = 0;
3925
3926         switch (clk_type) {
3927         case amd_pp_dcef_clock:
3928                 clk_select = DSPCLK_DCEFCLK;
3929                 break;
3930         case amd_pp_disp_clock:
3931                 clk_select = DSPCLK_DISPCLK;
3932                 break;
3933         case amd_pp_pixel_clock:
3934                 clk_select = DSPCLK_PIXCLK;
3935                 break;
3936         case amd_pp_phy_clock:
3937                 clk_select = DSPCLK_PHYCLK;
3938                 break;
3939         default:
3940                 pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!");
3941                 result = -1;
3942                 break;
3943         }
3944
3945         if (!result) {
3946                 clk_request = (clk_freq << 16) | clk_select;
3947                 result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3948                                 PPSMC_MSG_RequestDisplayClockByFreq,
3949                                 clk_request);
3950         }
3951
3952         return result;
3953 }
3954
3955 static uint8_t vega10_get_uclk_index(struct pp_hwmgr *hwmgr,
3956                         struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table,
3957                                                 uint32_t frequency)
3958 {
3959         uint8_t count;
3960         uint8_t i;
3961
3962         if (mclk_table == NULL || mclk_table->count == 0)
3963                 return 0;
3964
3965         count = (uint8_t)(mclk_table->count);
3966
3967         for(i = 0; i < count; i++) {
3968                 if(mclk_table->entries[i].clk >= frequency)
3969                         return i;
3970         }
3971
3972         return i-1;
3973 }
3974
3975 static int vega10_notify_smc_display_config_after_ps_adjustment(
3976                 struct pp_hwmgr *hwmgr)
3977 {
3978         struct vega10_hwmgr *data =
3979                         (struct vega10_hwmgr *)(hwmgr->backend);
3980         struct vega10_single_dpm_table *dpm_table =
3981                         &data->dpm_table.dcef_table;
3982         struct phm_ppt_v2_information *table_info =
3983                         (struct phm_ppt_v2_information *)hwmgr->pptable;
3984         struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table = table_info->vdd_dep_on_mclk;
3985         uint32_t idx;
3986         uint32_t num_active_disps = 0;
3987         struct cgs_display_info info = {0};
3988         struct PP_Clocks min_clocks = {0};
3989         uint32_t i;
3990         struct pp_display_clock_request clock_req;
3991
3992         info.mode_info = NULL;
3993
3994         cgs_get_active_displays_info(hwmgr->device, &info);
3995
3996         num_active_disps = info.display_count;
3997
3998         if (num_active_disps > 1)
3999                 vega10_notify_smc_display_change(hwmgr, false);
4000         else
4001                 vega10_notify_smc_display_change(hwmgr, true);
4002
4003         min_clocks.dcefClock = hwmgr->display_config.min_dcef_set_clk;
4004         min_clocks.dcefClockInSR = hwmgr->display_config.min_dcef_deep_sleep_set_clk;
4005         min_clocks.memoryClock = hwmgr->display_config.min_mem_set_clock;
4006
4007         for (i = 0; i < dpm_table->count; i++) {
4008                 if (dpm_table->dpm_levels[i].value == min_clocks.dcefClock)
4009                         break;
4010         }
4011
4012         if (i < dpm_table->count) {
4013                 clock_req.clock_type = amd_pp_dcef_clock;
4014                 clock_req.clock_freq_in_khz = dpm_table->dpm_levels[i].value;
4015                 if (!vega10_display_clock_voltage_request(hwmgr, &clock_req)) {
4016                         PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter(
4017                                         hwmgr->smumgr, PPSMC_MSG_SetMinDeepSleepDcefclk,
4018                                         min_clocks.dcefClockInSR /100),
4019                                         "Attempt to set divider for DCEFCLK Failed!",);
4020                 } else {
4021                         pr_info("Attempt to set Hard Min for DCEFCLK Failed!");
4022                 }
4023         } else {
4024                 pr_info("Cannot find requested DCEFCLK!");
4025         }
4026
4027         if (min_clocks.memoryClock != 0) {
4028                 idx = vega10_get_uclk_index(hwmgr, mclk_table, min_clocks.memoryClock);
4029                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetSoftMinUclkByIndex, idx);
4030                 data->dpm_table.mem_table.dpm_state.soft_min_level= idx;
4031         }
4032
4033         return 0;
4034 }
4035
4036 static int vega10_force_dpm_highest(struct pp_hwmgr *hwmgr)
4037 {
4038         struct vega10_hwmgr *data =
4039                         (struct vega10_hwmgr *)(hwmgr->backend);
4040
4041         data->smc_state_table.gfx_boot_level =
4042         data->smc_state_table.gfx_max_level =
4043                         vega10_find_highest_dpm_level(&(data->dpm_table.gfx_table));
4044         data->smc_state_table.mem_boot_level =
4045         data->smc_state_table.mem_max_level =
4046                         vega10_find_highest_dpm_level(&(data->dpm_table.mem_table));
4047
4048         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
4049                         "Failed to upload boot level to highest!",
4050                         return -1);
4051
4052         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
4053                         "Failed to upload dpm max level to highest!",
4054                         return -1);
4055
4056         return 0;
4057 }
4058
4059 static int vega10_force_dpm_lowest(struct pp_hwmgr *hwmgr)
4060 {
4061         struct vega10_hwmgr *data =
4062                         (struct vega10_hwmgr *)(hwmgr->backend);
4063
4064         data->smc_state_table.gfx_boot_level =
4065         data->smc_state_table.gfx_max_level =
4066                         vega10_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
4067         data->smc_state_table.mem_boot_level =
4068         data->smc_state_table.mem_max_level =
4069                         vega10_find_lowest_dpm_level(&(data->dpm_table.mem_table));
4070
4071         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
4072                         "Failed to upload boot level to highest!",
4073                         return -1);
4074
4075         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
4076                         "Failed to upload dpm max level to highest!",
4077                         return -1);
4078
4079         return 0;
4080
4081 }
4082
4083 static int vega10_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
4084 {
4085         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4086
4087         data->smc_state_table.gfx_boot_level =
4088                         vega10_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
4089         data->smc_state_table.gfx_max_level =
4090                         vega10_find_highest_dpm_level(&(data->dpm_table.gfx_table));
4091         data->smc_state_table.mem_boot_level =
4092                         vega10_find_lowest_dpm_level(&(data->dpm_table.mem_table));
4093         data->smc_state_table.mem_max_level =
4094                         vega10_find_highest_dpm_level(&(data->dpm_table.mem_table));
4095
4096         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
4097                         "Failed to upload DPM Bootup Levels!",
4098                         return -1);
4099
4100         PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
4101                         "Failed to upload DPM Max Levels!",
4102                         return -1);
4103         return 0;
4104 }
4105
4106 static int vega10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
4107                                 enum amd_dpm_forced_level level)
4108 {
4109         int ret = 0;
4110
4111         switch (level) {
4112         case AMD_DPM_FORCED_LEVEL_HIGH:
4113                 ret = vega10_force_dpm_highest(hwmgr);
4114                 if (ret)
4115                         return ret;
4116                 break;
4117         case AMD_DPM_FORCED_LEVEL_LOW:
4118                 ret = vega10_force_dpm_lowest(hwmgr);
4119                 if (ret)
4120                         return ret;
4121                 break;
4122         case AMD_DPM_FORCED_LEVEL_AUTO:
4123                 ret = vega10_unforce_dpm_levels(hwmgr);
4124                 if (ret)
4125                         return ret;
4126                 break;
4127         default:
4128                 break;
4129         }
4130
4131         hwmgr->dpm_level = level;
4132
4133         return ret;
4134 }
4135
4136 static int vega10_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
4137 {
4138         int result = 0;
4139
4140         switch (mode) {
4141         case AMD_FAN_CTRL_NONE:
4142                 result = vega10_fan_ctrl_set_fan_speed_percent(hwmgr, 100);
4143                 break;
4144         case AMD_FAN_CTRL_MANUAL:
4145                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4146                         PHM_PlatformCaps_MicrocodeFanControl))
4147                         result = vega10_fan_ctrl_stop_smc_fan_control(hwmgr);
4148                 break;
4149         case AMD_FAN_CTRL_AUTO:
4150                 result = vega10_fan_ctrl_set_static_mode(hwmgr, mode);
4151                 if (!result)
4152                         result = vega10_fan_ctrl_start_smc_fan_control(hwmgr);
4153                 break;
4154         default:
4155                 break;
4156         }
4157         return result;
4158 }
4159
4160 static int vega10_get_fan_control_mode(struct pp_hwmgr *hwmgr)
4161 {
4162         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4163
4164         if (data->smu_features[GNLD_FAN_CONTROL].enabled == false)
4165                 return AMD_FAN_CTRL_MANUAL;
4166         else
4167                 return AMD_FAN_CTRL_AUTO;
4168 }
4169
4170 static int vega10_get_dal_power_level(struct pp_hwmgr *hwmgr,
4171                 struct amd_pp_simple_clock_info *info)
4172 {
4173         struct phm_ppt_v2_information *table_info =
4174                         (struct phm_ppt_v2_information *)hwmgr->pptable;
4175         struct phm_clock_and_voltage_limits *max_limits =
4176                         &table_info->max_clock_voltage_on_ac;
4177
4178         info->engine_max_clock = max_limits->sclk;
4179         info->memory_max_clock = max_limits->mclk;
4180
4181         return 0;
4182 }
4183
4184 static void vega10_get_sclks(struct pp_hwmgr *hwmgr,
4185                 struct pp_clock_levels_with_latency *clocks)
4186 {
4187         struct phm_ppt_v2_information *table_info =
4188                         (struct phm_ppt_v2_information *)hwmgr->pptable;
4189         struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
4190                         table_info->vdd_dep_on_sclk;
4191         uint32_t i;
4192
4193         for (i = 0; i < dep_table->count; i++) {
4194                 if (dep_table->entries[i].clk) {
4195                         clocks->data[clocks->num_levels].clocks_in_khz =
4196                                         dep_table->entries[i].clk;
4197                         clocks->num_levels++;
4198                 }
4199         }
4200
4201 }
4202
4203 static uint32_t vega10_get_mem_latency(struct pp_hwmgr *hwmgr,
4204                 uint32_t clock)
4205 {
4206         if (clock >= MEM_FREQ_LOW_LATENCY &&
4207                         clock < MEM_FREQ_HIGH_LATENCY)
4208                 return MEM_LATENCY_HIGH;
4209         else if (clock >= MEM_FREQ_HIGH_LATENCY)
4210                 return MEM_LATENCY_LOW;
4211         else
4212                 return MEM_LATENCY_ERR;
4213 }
4214
4215 static void vega10_get_memclocks(struct pp_hwmgr *hwmgr,
4216                 struct pp_clock_levels_with_latency *clocks)
4217 {
4218         struct phm_ppt_v2_information *table_info =
4219                         (struct phm_ppt_v2_information *)hwmgr->pptable;
4220         struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
4221                         table_info->vdd_dep_on_mclk;
4222         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4223         uint32_t i;
4224
4225         clocks->num_levels = 0;
4226         data->mclk_latency_table.count = 0;
4227
4228         for (i = 0; i < dep_table->count; i++) {
4229                 if (dep_table->entries[i].clk) {
4230                         clocks->data[clocks->num_levels].clocks_in_khz =
4231                         data->mclk_latency_table.entries
4232                         [data->mclk_latency_table.count].frequency =
4233                                         dep_table->entries[i].clk;
4234                         clocks->data[clocks->num_levels].latency_in_us =
4235                         data->mclk_latency_table.entries
4236                         [data->mclk_latency_table.count].latency =
4237                                         vega10_get_mem_latency(hwmgr,
4238                                                 dep_table->entries[i].clk);
4239                         clocks->num_levels++;
4240                         data->mclk_latency_table.count++;
4241                 }
4242         }
4243 }
4244
4245 static void vega10_get_dcefclocks(struct pp_hwmgr *hwmgr,
4246                 struct pp_clock_levels_with_latency *clocks)
4247 {
4248         struct phm_ppt_v2_information *table_info =
4249                         (struct phm_ppt_v2_information *)hwmgr->pptable;
4250         struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
4251                         table_info->vdd_dep_on_dcefclk;
4252         uint32_t i;
4253
4254         for (i = 0; i < dep_table->count; i++) {
4255                 clocks->data[i].clocks_in_khz = dep_table->entries[i].clk;
4256                 clocks->data[i].latency_in_us = 0;
4257                 clocks->num_levels++;
4258         }
4259 }
4260
4261 static void vega10_get_socclocks(struct pp_hwmgr *hwmgr,
4262                 struct pp_clock_levels_with_latency *clocks)
4263 {
4264         struct phm_ppt_v2_information *table_info =
4265                         (struct phm_ppt_v2_information *)hwmgr->pptable;
4266         struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
4267                         table_info->vdd_dep_on_socclk;
4268         uint32_t i;
4269
4270         for (i = 0; i < dep_table->count; i++) {
4271                 clocks->data[i].clocks_in_khz = dep_table->entries[i].clk;
4272                 clocks->data[i].latency_in_us = 0;
4273                 clocks->num_levels++;
4274         }
4275 }
4276
4277 static int vega10_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr,
4278                 enum amd_pp_clock_type type,
4279                 struct pp_clock_levels_with_latency *clocks)
4280 {
4281         switch (type) {
4282         case amd_pp_sys_clock:
4283                 vega10_get_sclks(hwmgr, clocks);
4284                 break;
4285         case amd_pp_mem_clock:
4286                 vega10_get_memclocks(hwmgr, clocks);
4287                 break;
4288         case amd_pp_dcef_clock:
4289                 vega10_get_dcefclocks(hwmgr, clocks);
4290                 break;
4291         case amd_pp_soc_clock:
4292                 vega10_get_socclocks(hwmgr, clocks);
4293                 break;
4294         default:
4295                 return -1;
4296         }
4297
4298         return 0;
4299 }
4300
4301 static int vega10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr,
4302                 enum amd_pp_clock_type type,
4303                 struct pp_clock_levels_with_voltage *clocks)
4304 {
4305         struct phm_ppt_v2_information *table_info =
4306                         (struct phm_ppt_v2_information *)hwmgr->pptable;
4307         struct phm_ppt_v1_clock_voltage_dependency_table *dep_table;
4308         uint32_t i;
4309
4310         switch (type) {
4311         case amd_pp_mem_clock:
4312                 dep_table = table_info->vdd_dep_on_mclk;
4313                 break;
4314         case amd_pp_dcef_clock:
4315                 dep_table = table_info->vdd_dep_on_dcefclk;
4316                 break;
4317         case amd_pp_disp_clock:
4318                 dep_table = table_info->vdd_dep_on_dispclk;
4319                 break;
4320         case amd_pp_pixel_clock:
4321                 dep_table = table_info->vdd_dep_on_pixclk;
4322                 break;
4323         case amd_pp_phy_clock:
4324                 dep_table = table_info->vdd_dep_on_phyclk;
4325                 break;
4326         default:
4327                 return -1;
4328         }
4329
4330         for (i = 0; i < dep_table->count; i++) {
4331                 clocks->data[i].clocks_in_khz = dep_table->entries[i].clk;
4332                 clocks->data[i].voltage_in_mv = (uint32_t)(table_info->vddc_lookup_table->
4333                                 entries[dep_table->entries[i].vddInd].us_vdd);
4334                 clocks->num_levels++;
4335         }
4336
4337         if (i < dep_table->count)
4338                 return -1;
4339
4340         return 0;
4341 }
4342
4343 static int vega10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr,
4344                 struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges)
4345 {
4346         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4347         Watermarks_t *table = &(data->smc_state_table.water_marks_table);
4348         int result = 0;
4349         uint32_t i;
4350
4351         if (!data->registry_data.disable_water_mark) {
4352                 for (i = 0; i < wm_with_clock_ranges->num_wm_sets_dmif; i++) {
4353                         table->WatermarkRow[WM_DCEFCLK][i].MinClock =
4354                                 cpu_to_le16((uint16_t)
4355                                 (wm_with_clock_ranges->wm_sets_dmif[i].wm_min_dcefclk_in_khz) /
4356                                 100);
4357                         table->WatermarkRow[WM_DCEFCLK][i].MaxClock =
4358                                 cpu_to_le16((uint16_t)
4359                                 (wm_with_clock_ranges->wm_sets_dmif[i].wm_max_dcefclk_in_khz) /
4360                                 100);
4361                         table->WatermarkRow[WM_DCEFCLK][i].MinUclk =
4362                                 cpu_to_le16((uint16_t)
4363                                 (wm_with_clock_ranges->wm_sets_dmif[i].wm_min_memclk_in_khz) /
4364                                 100);
4365                         table->WatermarkRow[WM_DCEFCLK][i].MaxUclk =
4366                                 cpu_to_le16((uint16_t)
4367                                 (wm_with_clock_ranges->wm_sets_dmif[i].wm_max_memclk_in_khz) /
4368                                 100);
4369                         table->WatermarkRow[WM_DCEFCLK][i].WmSetting = (uint8_t)
4370                                         wm_with_clock_ranges->wm_sets_dmif[i].wm_set_id;
4371                 }
4372
4373                 for (i = 0; i < wm_with_clock_ranges->num_wm_sets_mcif; i++) {
4374                         table->WatermarkRow[WM_SOCCLK][i].MinClock =
4375                                 cpu_to_le16((uint16_t)
4376                                 (wm_with_clock_ranges->wm_sets_mcif[i].wm_min_socclk_in_khz) /
4377                                 100);
4378                         table->WatermarkRow[WM_SOCCLK][i].MaxClock =
4379                                 cpu_to_le16((uint16_t)
4380                                 (wm_with_clock_ranges->wm_sets_mcif[i].wm_max_socclk_in_khz) /
4381                                 100);
4382                         table->WatermarkRow[WM_SOCCLK][i].MinUclk =
4383                                 cpu_to_le16((uint16_t)
4384                                 (wm_with_clock_ranges->wm_sets_mcif[i].wm_min_memclk_in_khz) /
4385                                 100);
4386                         table->WatermarkRow[WM_SOCCLK][i].MaxUclk =
4387                                 cpu_to_le16((uint16_t)
4388                                 (wm_with_clock_ranges->wm_sets_mcif[i].wm_max_memclk_in_khz) /
4389                                 100);
4390                         table->WatermarkRow[WM_SOCCLK][i].WmSetting = (uint8_t)
4391                                         wm_with_clock_ranges->wm_sets_mcif[i].wm_set_id;
4392                 }
4393                 data->water_marks_bitmap = WaterMarksExist;
4394         }
4395
4396         return result;
4397 }
4398
4399 static int vega10_force_clock_level(struct pp_hwmgr *hwmgr,
4400                 enum pp_clock_type type, uint32_t mask)
4401 {
4402         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4403         int i;
4404
4405         if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
4406                 return -EINVAL;
4407
4408         switch (type) {
4409         case PP_SCLK:
4410                 for (i = 0; i < 32; i++) {
4411                         if (mask & (1 << i))
4412                                 break;
4413                 }
4414                 data->smc_state_table.gfx_boot_level = i;
4415
4416                 for (i = 31; i >= 0; i--) {
4417                         if (mask & (1 << i))
4418                                 break;
4419                 }
4420                 data->smc_state_table.gfx_max_level = i;
4421
4422                 PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
4423                         "Failed to upload boot level to lowest!",
4424                         return -EINVAL);
4425
4426                 PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
4427                         "Failed to upload dpm max level to highest!",
4428                         return -EINVAL);
4429                 break;
4430
4431         case PP_MCLK:
4432                 for (i = 0; i < 32; i++) {
4433                         if (mask & (1 << i))
4434                                 break;
4435                 }
4436                 data->smc_state_table.mem_boot_level = i;
4437
4438                 for (i = 31; i >= 0; i--) {
4439                         if (mask & (1 << i))
4440                                 break;
4441                 }
4442                 data->smc_state_table.mem_max_level = i;
4443
4444                 PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr),
4445                         "Failed to upload boot level to lowest!",
4446                         return -EINVAL);
4447
4448                 PP_ASSERT_WITH_CODE(!vega10_upload_dpm_max_level(hwmgr),
4449                         "Failed to upload dpm max level to highest!",
4450                         return -EINVAL);
4451
4452                 break;
4453
4454         case PP_PCIE:
4455         default:
4456                 break;
4457         }
4458
4459         return 0;
4460 }
4461
4462 static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr,
4463                 enum pp_clock_type type, char *buf)
4464 {
4465         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4466         struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
4467         struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
4468         struct vega10_pcie_table *pcie_table = &(data->dpm_table.pcie_table);
4469         int i, now, size = 0;
4470
4471         switch (type) {
4472         case PP_SCLK:
4473                 if (data->registry_data.sclk_dpm_key_disabled)
4474                         break;
4475
4476                 PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr->smumgr,
4477                                 PPSMC_MSG_GetCurrentGfxclkIndex),
4478                                 "Attempt to get current sclk index Failed!",
4479                                 return -1);
4480                 PP_ASSERT_WITH_CODE(!vega10_read_arg_from_smc(hwmgr->smumgr,
4481                                 &now),
4482                                 "Attempt to read sclk index Failed!",
4483                                 return -1);
4484
4485                 for (i = 0; i < sclk_table->count; i++)
4486                         size += sprintf(buf + size, "%d: %uMhz %s\n",
4487                                         i, sclk_table->dpm_levels[i].value / 100,
4488                                         (i == now) ? "*" : "");
4489                 break;
4490         case PP_MCLK:
4491                 if (data->registry_data.mclk_dpm_key_disabled)
4492                         break;
4493
4494                 PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr->smumgr,
4495                                 PPSMC_MSG_GetCurrentUclkIndex),
4496                                 "Attempt to get current mclk index Failed!",
4497                                 return -1);
4498                 PP_ASSERT_WITH_CODE(!vega10_read_arg_from_smc(hwmgr->smumgr,
4499                                 &now),
4500                                 "Attempt to read mclk index Failed!",
4501                                 return -1);
4502
4503                 for (i = 0; i < mclk_table->count; i++)
4504                         size += sprintf(buf + size, "%d: %uMhz %s\n",
4505                                         i, mclk_table->dpm_levels[i].value / 100,
4506                                         (i == now) ? "*" : "");
4507                 break;
4508         case PP_PCIE:
4509                 PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr->smumgr,
4510                                 PPSMC_MSG_GetCurrentLinkIndex),
4511                                 "Attempt to get current mclk index Failed!",
4512                                 return -1);
4513                 PP_ASSERT_WITH_CODE(!vega10_read_arg_from_smc(hwmgr->smumgr,
4514                                 &now),
4515                                 "Attempt to read mclk index Failed!",
4516                                 return -1);
4517
4518                 for (i = 0; i < pcie_table->count; i++)
4519                         size += sprintf(buf + size, "%d: %s %s\n", i,
4520                                         (pcie_table->pcie_gen[i] == 0) ? "2.5GB, x1" :
4521                                         (pcie_table->pcie_gen[i] == 1) ? "5.0GB, x16" :
4522                                         (pcie_table->pcie_gen[i] == 2) ? "8.0GB, x16" : "",
4523                                         (i == now) ? "*" : "");
4524                 break;
4525         default:
4526                 break;
4527         }
4528         return size;
4529 }
4530
4531 static int vega10_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
4532 {
4533         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4534         int result = 0;
4535         uint32_t num_turned_on_displays = 1;
4536         Watermarks_t *wm_table = &(data->smc_state_table.water_marks_table);
4537         struct cgs_display_info info = {0};
4538
4539         if ((data->water_marks_bitmap & WaterMarksExist) &&
4540                         !(data->water_marks_bitmap & WaterMarksLoaded)) {
4541                 result = vega10_copy_table_to_smc(hwmgr->smumgr,
4542                         (uint8_t *)wm_table, WMTABLE);
4543                 PP_ASSERT_WITH_CODE(result, "Failed to update WMTABLE!", return EINVAL);
4544                 data->water_marks_bitmap |= WaterMarksLoaded;
4545         }
4546
4547         if (data->water_marks_bitmap & WaterMarksLoaded) {
4548                 cgs_get_active_displays_info(hwmgr->device, &info);
4549                 num_turned_on_displays = info.display_count;
4550                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
4551                         PPSMC_MSG_NumOfDisplays, num_turned_on_displays);
4552         }
4553
4554         return result;
4555 }
4556
4557 int vega10_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
4558 {
4559         struct vega10_hwmgr *data =
4560                         (struct vega10_hwmgr *)(hwmgr->backend);
4561
4562         if (data->smu_features[GNLD_DPM_UVD].supported) {
4563                 PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
4564                                 enable,
4565                                 data->smu_features[GNLD_DPM_UVD].smu_feature_bitmap),
4566                                 "Attempt to Enable/Disable DPM UVD Failed!",
4567                                 return -1);
4568                 data->smu_features[GNLD_DPM_UVD].enabled = enable;
4569         }
4570         return 0;
4571 }
4572
4573 static int vega10_power_gate_vce(struct pp_hwmgr *hwmgr, bool bgate)
4574 {
4575         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4576
4577         data->vce_power_gated = bgate;
4578         return vega10_enable_disable_vce_dpm(hwmgr, !bgate);
4579 }
4580
4581 static int vega10_power_gate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
4582 {
4583         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4584
4585         data->uvd_power_gated = bgate;
4586         return vega10_enable_disable_uvd_dpm(hwmgr, !bgate);
4587 }
4588
4589 static inline bool vega10_are_power_levels_equal(
4590                                 const struct vega10_performance_level *pl1,
4591                                 const struct vega10_performance_level *pl2)
4592 {
4593         return ((pl1->soc_clock == pl2->soc_clock) &&
4594                         (pl1->gfx_clock == pl2->gfx_clock) &&
4595                         (pl1->mem_clock == pl2->mem_clock));
4596 }
4597
4598 static int vega10_check_states_equal(struct pp_hwmgr *hwmgr,
4599                                 const struct pp_hw_power_state *pstate1,
4600                         const struct pp_hw_power_state *pstate2, bool *equal)
4601 {
4602         const struct vega10_power_state *psa;
4603         const struct vega10_power_state *psb;
4604         int i;
4605
4606         if (pstate1 == NULL || pstate2 == NULL || equal == NULL)
4607                 return -EINVAL;
4608
4609         psa = cast_const_phw_vega10_power_state(pstate1);
4610         psb = cast_const_phw_vega10_power_state(pstate2);
4611         /* If the two states don't even have the same number of performance levels they cannot be the same state. */
4612         if (psa->performance_level_count != psb->performance_level_count) {
4613                 *equal = false;
4614                 return 0;
4615         }
4616
4617         for (i = 0; i < psa->performance_level_count; i++) {
4618                 if (!vega10_are_power_levels_equal(&(psa->performance_levels[i]), &(psb->performance_levels[i]))) {
4619                         /* If we have found even one performance level pair that is different the states are different. */
4620                         *equal = false;
4621                         return 0;
4622                 }
4623         }
4624
4625         /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
4626         *equal = ((psa->uvd_clks.vclk == psb->uvd_clks.vclk) && (psa->uvd_clks.dclk == psb->uvd_clks.dclk));
4627         *equal &= ((psa->vce_clks.evclk == psb->vce_clks.evclk) && (psa->vce_clks.ecclk == psb->vce_clks.ecclk));
4628         *equal &= (psa->sclk_threshold == psb->sclk_threshold);
4629
4630         return 0;
4631 }
4632
4633 static bool
4634 vega10_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
4635 {
4636         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4637         bool is_update_required = false;
4638         struct cgs_display_info info = {0, 0, NULL};
4639
4640         cgs_get_active_displays_info(hwmgr->device, &info);
4641
4642         if (data->display_timing.num_existing_displays != info.display_count)
4643                 is_update_required = true;
4644
4645         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
4646                 if (data->display_timing.min_clock_in_sr != hwmgr->display_config.min_core_set_clock_in_sr)
4647                         is_update_required = true;
4648         }
4649
4650         return is_update_required;
4651 }
4652
4653 static int vega10_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
4654 {
4655         int tmp_result, result = 0;
4656
4657         tmp_result = (vega10_is_dpm_running(hwmgr)) ? 0 : -1;
4658         PP_ASSERT_WITH_CODE(tmp_result == 0,
4659                         "DPM is not running right now, no need to disable DPM!",
4660                         return 0);
4661
4662         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4663                         PHM_PlatformCaps_ThermalController))
4664                 vega10_disable_thermal_protection(hwmgr);
4665
4666         tmp_result = vega10_disable_power_containment(hwmgr);
4667         PP_ASSERT_WITH_CODE((tmp_result == 0),
4668                         "Failed to disable power containment!", result = tmp_result);
4669
4670         tmp_result = vega10_avfs_enable(hwmgr, false);
4671         PP_ASSERT_WITH_CODE((tmp_result == 0),
4672                         "Failed to disable AVFS!", result = tmp_result);
4673
4674         tmp_result = vega10_stop_dpm(hwmgr, SMC_DPM_FEATURES);
4675         PP_ASSERT_WITH_CODE((tmp_result == 0),
4676                         "Failed to stop DPM!", result = tmp_result);
4677
4678         tmp_result = vega10_disable_deep_sleep_master_switch(hwmgr);
4679         PP_ASSERT_WITH_CODE((tmp_result == 0),
4680                         "Failed to disable deep sleep!", result = tmp_result);
4681
4682         tmp_result = vega10_disable_ulv(hwmgr);
4683         PP_ASSERT_WITH_CODE((tmp_result == 0),
4684                         "Failed to disable ulv!", result = tmp_result);
4685
4686         return result;
4687 }
4688
4689 static int vega10_power_off_asic(struct pp_hwmgr *hwmgr)
4690 {
4691         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4692         int result;
4693
4694         result = vega10_disable_dpm_tasks(hwmgr);
4695         PP_ASSERT_WITH_CODE((0 == result),
4696                         "[disable_dpm_tasks] Failed to disable DPM!",
4697                         );
4698         data->water_marks_bitmap &= ~(WaterMarksLoaded);
4699
4700         return result;
4701 }
4702
4703 static void vega10_find_min_clock_index(struct pp_hwmgr *hwmgr,
4704                 uint32_t *sclk_idx, uint32_t *mclk_idx,
4705                 uint32_t min_sclk, uint32_t min_mclk)
4706 {
4707         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4708         struct vega10_dpm_table *dpm_table = &(data->dpm_table);
4709         uint32_t i;
4710
4711         for (i = 0; i < dpm_table->gfx_table.count; i++) {
4712                 if (dpm_table->gfx_table.dpm_levels[i].enabled &&
4713                         dpm_table->gfx_table.dpm_levels[i].value >= min_sclk) {
4714                         *sclk_idx = i;
4715                         break;
4716                 }
4717         }
4718
4719         for (i = 0; i < dpm_table->mem_table.count; i++) {
4720                 if (dpm_table->mem_table.dpm_levels[i].enabled &&
4721                         dpm_table->mem_table.dpm_levels[i].value >= min_mclk) {
4722                         *mclk_idx = i;
4723                         break;
4724                 }
4725         }
4726 }
4727
4728 static int vega10_set_power_profile_state(struct pp_hwmgr *hwmgr,
4729                 struct amd_pp_profile *request)
4730 {
4731         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4732         uint32_t sclk_idx = ~0, mclk_idx = ~0;
4733
4734         if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_AUTO)
4735                 return -EINVAL;
4736
4737         vega10_find_min_clock_index(hwmgr, &sclk_idx, &mclk_idx,
4738                         request->min_sclk, request->min_mclk);
4739
4740         if (sclk_idx != ~0) {
4741                 if (!data->registry_data.sclk_dpm_key_disabled)
4742                         PP_ASSERT_WITH_CODE(
4743                                         !smum_send_msg_to_smc_with_parameter(
4744                                         hwmgr->smumgr,
4745                                         PPSMC_MSG_SetSoftMinGfxclkByIndex,
4746                                         sclk_idx),
4747                                         "Failed to set soft min sclk index!",
4748                                         return -EINVAL);
4749         }
4750
4751         if (mclk_idx != ~0) {
4752                 if (!data->registry_data.mclk_dpm_key_disabled)
4753                         PP_ASSERT_WITH_CODE(
4754                                         !smum_send_msg_to_smc_with_parameter(
4755                                         hwmgr->smumgr,
4756                                         PPSMC_MSG_SetSoftMinUclkByIndex,
4757                                         mclk_idx),
4758                                         "Failed to set soft min mclk index!",
4759                                         return -EINVAL);
4760         }
4761
4762         return 0;
4763 }
4764
4765 static int vega10_get_sclk_od(struct pp_hwmgr *hwmgr)
4766 {
4767         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4768         struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
4769         struct vega10_single_dpm_table *golden_sclk_table =
4770                         &(data->golden_dpm_table.gfx_table);
4771         int value;
4772
4773         value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
4774                         golden_sclk_table->dpm_levels
4775                         [golden_sclk_table->count - 1].value) *
4776                         100 /
4777                         golden_sclk_table->dpm_levels
4778                         [golden_sclk_table->count - 1].value;
4779
4780         return value;
4781 }
4782
4783 static int vega10_set_sclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
4784 {
4785         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4786         struct vega10_single_dpm_table *golden_sclk_table =
4787                         &(data->golden_dpm_table.gfx_table);
4788         struct pp_power_state *ps;
4789         struct vega10_power_state *vega10_ps;
4790
4791         ps = hwmgr->request_ps;
4792
4793         if (ps == NULL)
4794                 return -EINVAL;
4795
4796         vega10_ps = cast_phw_vega10_power_state(&ps->hardware);
4797
4798         vega10_ps->performance_levels
4799         [vega10_ps->performance_level_count - 1].gfx_clock =
4800                         golden_sclk_table->dpm_levels
4801                         [golden_sclk_table->count - 1].value *
4802                         value / 100 +
4803                         golden_sclk_table->dpm_levels
4804                         [golden_sclk_table->count - 1].value;
4805
4806         if (vega10_ps->performance_levels
4807                         [vega10_ps->performance_level_count - 1].gfx_clock >
4808                         hwmgr->platform_descriptor.overdriveLimit.engineClock)
4809                 vega10_ps->performance_levels
4810                 [vega10_ps->performance_level_count - 1].gfx_clock =
4811                                 hwmgr->platform_descriptor.overdriveLimit.engineClock;
4812
4813         return 0;
4814 }
4815
4816 static int vega10_get_mclk_od(struct pp_hwmgr *hwmgr)
4817 {
4818         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4819         struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
4820         struct vega10_single_dpm_table *golden_mclk_table =
4821                         &(data->golden_dpm_table.mem_table);
4822         int value;
4823
4824         value = (mclk_table->dpm_levels
4825                         [mclk_table->count - 1].value -
4826                         golden_mclk_table->dpm_levels
4827                         [golden_mclk_table->count - 1].value) *
4828                         100 /
4829                         golden_mclk_table->dpm_levels
4830                         [golden_mclk_table->count - 1].value;
4831
4832         return value;
4833 }
4834
4835 static int vega10_set_mclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
4836 {
4837         struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
4838         struct vega10_single_dpm_table *golden_mclk_table =
4839                         &(data->golden_dpm_table.mem_table);
4840         struct pp_power_state  *ps;
4841         struct vega10_power_state  *vega10_ps;
4842
4843         ps = hwmgr->request_ps;
4844
4845         if (ps == NULL)
4846                 return -EINVAL;
4847
4848         vega10_ps = cast_phw_vega10_power_state(&ps->hardware);
4849
4850         vega10_ps->performance_levels
4851         [vega10_ps->performance_level_count - 1].mem_clock =
4852                         golden_mclk_table->dpm_levels
4853                         [golden_mclk_table->count - 1].value *
4854                         value / 100 +
4855                         golden_mclk_table->dpm_levels
4856                         [golden_mclk_table->count - 1].value;
4857
4858         if (vega10_ps->performance_levels
4859                         [vega10_ps->performance_level_count - 1].mem_clock >
4860                         hwmgr->platform_descriptor.overdriveLimit.memoryClock)
4861                 vega10_ps->performance_levels
4862                 [vega10_ps->performance_level_count - 1].mem_clock =
4863                                 hwmgr->platform_descriptor.overdriveLimit.memoryClock;
4864
4865         return 0;
4866 }
4867
4868 static const struct pp_hwmgr_func vega10_hwmgr_funcs = {
4869         .backend_init = vega10_hwmgr_backend_init,
4870         .backend_fini = vega10_hwmgr_backend_fini,
4871         .asic_setup = vega10_setup_asic_task,
4872         .dynamic_state_management_enable = vega10_enable_dpm_tasks,
4873         .dynamic_state_management_disable = vega10_disable_dpm_tasks,
4874         .get_num_of_pp_table_entries =
4875                         vega10_get_number_of_powerplay_table_entries,
4876         .get_power_state_size = vega10_get_power_state_size,
4877         .get_pp_table_entry = vega10_get_pp_table_entry,
4878         .patch_boot_state = vega10_patch_boot_state,
4879         .apply_state_adjust_rules = vega10_apply_state_adjust_rules,
4880         .power_state_set = vega10_set_power_state_tasks,
4881         .get_sclk = vega10_dpm_get_sclk,
4882         .get_mclk = vega10_dpm_get_mclk,
4883         .notify_smc_display_config_after_ps_adjustment =
4884                         vega10_notify_smc_display_config_after_ps_adjustment,
4885         .force_dpm_level = vega10_dpm_force_dpm_level,
4886         .get_temperature = vega10_thermal_get_temperature,
4887         .stop_thermal_controller = vega10_thermal_stop_thermal_controller,
4888         .get_fan_speed_info = vega10_fan_ctrl_get_fan_speed_info,
4889         .get_fan_speed_percent = vega10_fan_ctrl_get_fan_speed_percent,
4890         .set_fan_speed_percent = vega10_fan_ctrl_set_fan_speed_percent,
4891         .reset_fan_speed_to_default =
4892                         vega10_fan_ctrl_reset_fan_speed_to_default,
4893         .get_fan_speed_rpm = vega10_fan_ctrl_get_fan_speed_rpm,
4894         .set_fan_speed_rpm = vega10_fan_ctrl_set_fan_speed_rpm,
4895         .uninitialize_thermal_controller =
4896                         vega10_thermal_ctrl_uninitialize_thermal_controller,
4897         .set_fan_control_mode = vega10_set_fan_control_mode,
4898         .get_fan_control_mode = vega10_get_fan_control_mode,
4899         .read_sensor = vega10_read_sensor,
4900         .get_dal_power_level = vega10_get_dal_power_level,
4901         .get_clock_by_type_with_latency = vega10_get_clock_by_type_with_latency,
4902         .get_clock_by_type_with_voltage = vega10_get_clock_by_type_with_voltage,
4903         .set_watermarks_for_clocks_ranges = vega10_set_watermarks_for_clocks_ranges,
4904         .display_clock_voltage_request = vega10_display_clock_voltage_request,
4905         .force_clock_level = vega10_force_clock_level,
4906         .print_clock_levels = vega10_print_clock_levels,
4907         .display_config_changed = vega10_display_configuration_changed_task,
4908         .powergate_uvd = vega10_power_gate_uvd,
4909         .powergate_vce = vega10_power_gate_vce,
4910         .check_states_equal = vega10_check_states_equal,
4911         .check_smc_update_required_for_display_configuration =
4912                         vega10_check_smc_update_required_for_display_configuration,
4913         .power_off_asic = vega10_power_off_asic,
4914         .disable_smc_firmware_ctf = vega10_thermal_disable_alert,
4915         .set_power_profile_state = vega10_set_power_profile_state,
4916         .get_sclk_od = vega10_get_sclk_od,
4917         .set_sclk_od = vega10_set_sclk_od,
4918         .get_mclk_od = vega10_get_mclk_od,
4919         .set_mclk_od = vega10_set_mclk_od,
4920         .avfs_control = vega10_avfs_enable,
4921 };
4922
4923 int vega10_hwmgr_init(struct pp_hwmgr *hwmgr)
4924 {
4925         hwmgr->hwmgr_func = &vega10_hwmgr_funcs;
4926         hwmgr->pptable_func = &vega10_pptable_funcs;
4927         pp_vega10_thermal_initialize(hwmgr);
4928         return 0;
4929 }