]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/amd/powerplay/vega20_ppt.c
drm/amd/powerplay: move the funciton of conv_profile_to_workload to asic file
[linux.git] / drivers / gpu / drm / amd / powerplay / vega20_ppt.c
1 /*
2  * Copyright 2019 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 "pp_debug.h"
25 #include <linux/firmware.h>
26 #include "amdgpu.h"
27 #include "amdgpu_smu.h"
28 #include "atomfirmware.h"
29 #include "amdgpu_atomfirmware.h"
30 #include "smu_v11_0.h"
31 #include "smu11_driver_if.h"
32 #include "soc15_common.h"
33 #include "atom.h"
34 #include "power_state.h"
35 #include "vega20_ppt.h"
36 #include "vega20_pptable.h"
37 #include "vega20_ppsmc.h"
38 #include "nbio/nbio_7_4_sh_mask.h"
39
40 #define smnPCIE_LC_SPEED_CNTL                   0x11140290
41 #define smnPCIE_LC_LINK_WIDTH_CNTL              0x11140288
42
43 #define MSG_MAP(msg) \
44         [SMU_MSG_##msg] = PPSMC_MSG_##msg
45
46 static int vega20_message_map[SMU_MSG_MAX_COUNT] = {
47         MSG_MAP(TestMessage),
48         MSG_MAP(GetSmuVersion),
49         MSG_MAP(GetDriverIfVersion),
50         MSG_MAP(SetAllowedFeaturesMaskLow),
51         MSG_MAP(SetAllowedFeaturesMaskHigh),
52         MSG_MAP(EnableAllSmuFeatures),
53         MSG_MAP(DisableAllSmuFeatures),
54         MSG_MAP(EnableSmuFeaturesLow),
55         MSG_MAP(EnableSmuFeaturesHigh),
56         MSG_MAP(DisableSmuFeaturesLow),
57         MSG_MAP(DisableSmuFeaturesHigh),
58         MSG_MAP(GetEnabledSmuFeaturesLow),
59         MSG_MAP(GetEnabledSmuFeaturesHigh),
60         MSG_MAP(SetWorkloadMask),
61         MSG_MAP(SetPptLimit),
62         MSG_MAP(SetDriverDramAddrHigh),
63         MSG_MAP(SetDriverDramAddrLow),
64         MSG_MAP(SetToolsDramAddrHigh),
65         MSG_MAP(SetToolsDramAddrLow),
66         MSG_MAP(TransferTableSmu2Dram),
67         MSG_MAP(TransferTableDram2Smu),
68         MSG_MAP(UseDefaultPPTable),
69         MSG_MAP(UseBackupPPTable),
70         MSG_MAP(RunBtc),
71         MSG_MAP(RequestI2CBus),
72         MSG_MAP(ReleaseI2CBus),
73         MSG_MAP(SetFloorSocVoltage),
74         MSG_MAP(SoftReset),
75         MSG_MAP(StartBacoMonitor),
76         MSG_MAP(CancelBacoMonitor),
77         MSG_MAP(EnterBaco),
78         MSG_MAP(SetSoftMinByFreq),
79         MSG_MAP(SetSoftMaxByFreq),
80         MSG_MAP(SetHardMinByFreq),
81         MSG_MAP(SetHardMaxByFreq),
82         MSG_MAP(GetMinDpmFreq),
83         MSG_MAP(GetMaxDpmFreq),
84         MSG_MAP(GetDpmFreqByIndex),
85         MSG_MAP(GetDpmClockFreq),
86         MSG_MAP(GetSsVoltageByDpm),
87         MSG_MAP(SetMemoryChannelConfig),
88         MSG_MAP(SetGeminiMode),
89         MSG_MAP(SetGeminiApertureHigh),
90         MSG_MAP(SetGeminiApertureLow),
91         MSG_MAP(SetMinLinkDpmByIndex),
92         MSG_MAP(OverridePcieParameters),
93         MSG_MAP(OverDriveSetPercentage),
94         MSG_MAP(SetMinDeepSleepDcefclk),
95         MSG_MAP(ReenableAcDcInterrupt),
96         MSG_MAP(NotifyPowerSource),
97         MSG_MAP(SetUclkFastSwitch),
98         MSG_MAP(SetUclkDownHyst),
99         MSG_MAP(GetCurrentRpm),
100         MSG_MAP(SetVideoFps),
101         MSG_MAP(SetTjMax),
102         MSG_MAP(SetFanTemperatureTarget),
103         MSG_MAP(PrepareMp1ForUnload),
104         MSG_MAP(DramLogSetDramAddrHigh),
105         MSG_MAP(DramLogSetDramAddrLow),
106         MSG_MAP(DramLogSetDramSize),
107         MSG_MAP(SetFanMaxRpm),
108         MSG_MAP(SetFanMinPwm),
109         MSG_MAP(ConfigureGfxDidt),
110         MSG_MAP(NumOfDisplays),
111         MSG_MAP(RemoveMargins),
112         MSG_MAP(ReadSerialNumTop32),
113         MSG_MAP(ReadSerialNumBottom32),
114         MSG_MAP(SetSystemVirtualDramAddrHigh),
115         MSG_MAP(SetSystemVirtualDramAddrLow),
116         MSG_MAP(WaflTest),
117         MSG_MAP(SetFclkGfxClkRatio),
118         MSG_MAP(AllowGfxOff),
119         MSG_MAP(DisallowGfxOff),
120         MSG_MAP(GetPptLimit),
121         MSG_MAP(GetDcModeMaxDpmFreq),
122         MSG_MAP(GetDebugData),
123         MSG_MAP(SetXgmiMode),
124         MSG_MAP(RunAfllBtc),
125         MSG_MAP(ExitBaco),
126         MSG_MAP(PrepareMp1ForReset),
127         MSG_MAP(PrepareMp1ForShutdown),
128         MSG_MAP(SetMGpuFanBoostLimitRpm),
129         MSG_MAP(GetAVFSVoltageByDpm),
130 };
131
132 static int vega20_get_smu_msg_index(struct smu_context *smc, uint32_t index)
133 {
134         int val;
135
136         if (index >= SMU_MSG_MAX_COUNT)
137                 return -EINVAL;
138
139         val = vega20_message_map[index];
140         if (val > PPSMC_Message_Count)
141                 return -EINVAL;
142
143         return val;
144 }
145
146 static int vega20_allocate_dpm_context(struct smu_context *smu)
147 {
148         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
149
150         if (smu_dpm->dpm_context)
151                 return -EINVAL;
152
153         smu_dpm->dpm_context = kzalloc(sizeof(struct vega20_dpm_table),
154                                        GFP_KERNEL);
155         if (!smu_dpm->dpm_context)
156                 return -ENOMEM;
157
158         if (smu_dpm->golden_dpm_context)
159                 return -EINVAL;
160
161         smu_dpm->golden_dpm_context = kzalloc(sizeof(struct vega20_dpm_table),
162                                               GFP_KERNEL);
163         if (!smu_dpm->golden_dpm_context)
164                 return -ENOMEM;
165
166         smu_dpm->dpm_context_size = sizeof(struct vega20_dpm_table);
167
168         smu_dpm->dpm_current_power_state = kzalloc(sizeof(struct smu_power_state),
169                                        GFP_KERNEL);
170         if (!smu_dpm->dpm_current_power_state)
171                 return -ENOMEM;
172
173         smu_dpm->dpm_request_power_state = kzalloc(sizeof(struct smu_power_state),
174                                        GFP_KERNEL);
175         if (!smu_dpm->dpm_request_power_state)
176                 return -ENOMEM;
177
178         return 0;
179 }
180
181 static int vega20_setup_od8_information(struct smu_context *smu)
182 {
183         ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL;
184         struct smu_table_context *table_context = &smu->smu_table;
185
186         uint32_t od_feature_count, od_feature_array_size,
187                  od_setting_count, od_setting_array_size;
188
189         if (!table_context->power_play_table)
190                 return -EINVAL;
191
192         powerplay_table = table_context->power_play_table;
193
194         if (powerplay_table->OverDrive8Table.ucODTableRevision == 1) {
195                 /* Setup correct ODFeatureCount, and store ODFeatureArray from
196                  * powerplay table to od_feature_capabilities */
197                 od_feature_count =
198                         (le32_to_cpu(powerplay_table->OverDrive8Table.ODFeatureCount) >
199                          ATOM_VEGA20_ODFEATURE_COUNT) ?
200                         ATOM_VEGA20_ODFEATURE_COUNT :
201                         le32_to_cpu(powerplay_table->OverDrive8Table.ODFeatureCount);
202
203                 od_feature_array_size = sizeof(uint8_t) * od_feature_count;
204
205                 if (table_context->od_feature_capabilities)
206                         return -EINVAL;
207
208                 table_context->od_feature_capabilities = kmemdup(&powerplay_table->OverDrive8Table.ODFeatureCapabilities,
209                                                                  od_feature_array_size,
210                                                                  GFP_KERNEL);
211                 if (!table_context->od_feature_capabilities)
212                         return -ENOMEM;
213
214                 /* Setup correct ODSettingCount, and store ODSettingArray from
215                  * powerplay table to od_settings_max and od_setting_min */
216                 od_setting_count =
217                         (le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingCount) >
218                          ATOM_VEGA20_ODSETTING_COUNT) ?
219                         ATOM_VEGA20_ODSETTING_COUNT :
220                         le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingCount);
221
222                 od_setting_array_size = sizeof(uint32_t) * od_setting_count;
223
224                 if (table_context->od_settings_max)
225                         return -EINVAL;
226
227                 table_context->od_settings_max = kmemdup(&powerplay_table->OverDrive8Table.ODSettingsMax,
228                                                          od_setting_array_size,
229                                                          GFP_KERNEL);
230
231                 if (!table_context->od_settings_max) {
232                         kfree(table_context->od_feature_capabilities);
233                         table_context->od_feature_capabilities = NULL;
234                         return -ENOMEM;
235                 }
236
237                 if (table_context->od_settings_min)
238                         return -EINVAL;
239
240                 table_context->od_settings_min = kmemdup(&powerplay_table->OverDrive8Table.ODSettingsMin,
241                                                          od_setting_array_size,
242                                                          GFP_KERNEL);
243
244                 if (!table_context->od_settings_min) {
245                         kfree(table_context->od_feature_capabilities);
246                         table_context->od_feature_capabilities = NULL;
247                         kfree(table_context->od_settings_max);
248                         table_context->od_settings_max = NULL;
249                         return -ENOMEM;
250                 }
251         }
252
253         return 0;
254 }
255
256 static int vega20_store_powerplay_table(struct smu_context *smu)
257 {
258         ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL;
259         struct smu_table_context *table_context = &smu->smu_table;
260         int ret;
261
262         if (!table_context->power_play_table)
263                 return -EINVAL;
264
265         powerplay_table = table_context->power_play_table;
266
267         memcpy(table_context->driver_pptable, &powerplay_table->smcPPTable,
268                sizeof(PPTable_t));
269
270         table_context->software_shutdown_temp = powerplay_table->usSoftwareShutdownTemp;
271         table_context->thermal_controller_type = powerplay_table->ucThermalControllerType;
272         table_context->TDPODLimit = le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingsMax[ATOM_VEGA20_ODSETTING_POWERPERCENTAGE]);
273
274         ret = vega20_setup_od8_information(smu);
275
276         return ret;
277 }
278
279 static int vega20_append_powerplay_table(struct smu_context *smu)
280 {
281         struct smu_table_context *table_context = &smu->smu_table;
282         PPTable_t *smc_pptable = table_context->driver_pptable;
283         struct atom_smc_dpm_info_v4_4 *smc_dpm_table;
284         int index, i, ret;
285
286         index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
287                                            smc_dpm_info);
288
289         ret = smu_get_atom_data_table(smu, index, NULL, NULL, NULL,
290                                       (uint8_t **)&smc_dpm_table);
291         if (ret)
292                 return ret;
293
294         smc_pptable->MaxVoltageStepGfx = smc_dpm_table->maxvoltagestepgfx;
295         smc_pptable->MaxVoltageStepSoc = smc_dpm_table->maxvoltagestepsoc;
296
297         smc_pptable->VddGfxVrMapping = smc_dpm_table->vddgfxvrmapping;
298         smc_pptable->VddSocVrMapping = smc_dpm_table->vddsocvrmapping;
299         smc_pptable->VddMem0VrMapping = smc_dpm_table->vddmem0vrmapping;
300         smc_pptable->VddMem1VrMapping = smc_dpm_table->vddmem1vrmapping;
301
302         smc_pptable->GfxUlvPhaseSheddingMask = smc_dpm_table->gfxulvphasesheddingmask;
303         smc_pptable->SocUlvPhaseSheddingMask = smc_dpm_table->soculvphasesheddingmask;
304         smc_pptable->ExternalSensorPresent = smc_dpm_table->externalsensorpresent;
305
306         smc_pptable->GfxMaxCurrent = smc_dpm_table->gfxmaxcurrent;
307         smc_pptable->GfxOffset = smc_dpm_table->gfxoffset;
308         smc_pptable->Padding_TelemetryGfx = smc_dpm_table->padding_telemetrygfx;
309
310         smc_pptable->SocMaxCurrent = smc_dpm_table->socmaxcurrent;
311         smc_pptable->SocOffset = smc_dpm_table->socoffset;
312         smc_pptable->Padding_TelemetrySoc = smc_dpm_table->padding_telemetrysoc;
313
314         smc_pptable->Mem0MaxCurrent = smc_dpm_table->mem0maxcurrent;
315         smc_pptable->Mem0Offset = smc_dpm_table->mem0offset;
316         smc_pptable->Padding_TelemetryMem0 = smc_dpm_table->padding_telemetrymem0;
317
318         smc_pptable->Mem1MaxCurrent = smc_dpm_table->mem1maxcurrent;
319         smc_pptable->Mem1Offset = smc_dpm_table->mem1offset;
320         smc_pptable->Padding_TelemetryMem1 = smc_dpm_table->padding_telemetrymem1;
321
322         smc_pptable->AcDcGpio = smc_dpm_table->acdcgpio;
323         smc_pptable->AcDcPolarity = smc_dpm_table->acdcpolarity;
324         smc_pptable->VR0HotGpio = smc_dpm_table->vr0hotgpio;
325         smc_pptable->VR0HotPolarity = smc_dpm_table->vr0hotpolarity;
326
327         smc_pptable->VR1HotGpio = smc_dpm_table->vr1hotgpio;
328         smc_pptable->VR1HotPolarity = smc_dpm_table->vr1hotpolarity;
329         smc_pptable->Padding1 = smc_dpm_table->padding1;
330         smc_pptable->Padding2 = smc_dpm_table->padding2;
331
332         smc_pptable->LedPin0 = smc_dpm_table->ledpin0;
333         smc_pptable->LedPin1 = smc_dpm_table->ledpin1;
334         smc_pptable->LedPin2 = smc_dpm_table->ledpin2;
335
336         smc_pptable->PllGfxclkSpreadEnabled = smc_dpm_table->pllgfxclkspreadenabled;
337         smc_pptable->PllGfxclkSpreadPercent = smc_dpm_table->pllgfxclkspreadpercent;
338         smc_pptable->PllGfxclkSpreadFreq = smc_dpm_table->pllgfxclkspreadfreq;
339
340         smc_pptable->UclkSpreadEnabled = 0;
341         smc_pptable->UclkSpreadPercent = smc_dpm_table->uclkspreadpercent;
342         smc_pptable->UclkSpreadFreq = smc_dpm_table->uclkspreadfreq;
343
344         smc_pptable->FclkSpreadEnabled = smc_dpm_table->fclkspreadenabled;
345         smc_pptable->FclkSpreadPercent = smc_dpm_table->fclkspreadpercent;
346         smc_pptable->FclkSpreadFreq = smc_dpm_table->fclkspreadfreq;
347
348         smc_pptable->FllGfxclkSpreadEnabled = smc_dpm_table->fllgfxclkspreadenabled;
349         smc_pptable->FllGfxclkSpreadPercent = smc_dpm_table->fllgfxclkspreadpercent;
350         smc_pptable->FllGfxclkSpreadFreq = smc_dpm_table->fllgfxclkspreadfreq;
351
352         for (i = 0; i < I2C_CONTROLLER_NAME_COUNT; i++) {
353                 smc_pptable->I2cControllers[i].Enabled =
354                         smc_dpm_table->i2ccontrollers[i].enabled;
355                 smc_pptable->I2cControllers[i].SlaveAddress =
356                         smc_dpm_table->i2ccontrollers[i].slaveaddress;
357                 smc_pptable->I2cControllers[i].ControllerPort =
358                         smc_dpm_table->i2ccontrollers[i].controllerport;
359                 smc_pptable->I2cControllers[i].ThermalThrottler =
360                         smc_dpm_table->i2ccontrollers[i].thermalthrottler;
361                 smc_pptable->I2cControllers[i].I2cProtocol =
362                         smc_dpm_table->i2ccontrollers[i].i2cprotocol;
363                 smc_pptable->I2cControllers[i].I2cSpeed =
364                         smc_dpm_table->i2ccontrollers[i].i2cspeed;
365         }
366
367         return 0;
368 }
369
370 static int vega20_check_powerplay_table(struct smu_context *smu)
371 {
372         ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL;
373         struct smu_table_context *table_context = &smu->smu_table;
374
375         powerplay_table = table_context->power_play_table;
376
377         if (powerplay_table->sHeader.format_revision < ATOM_VEGA20_TABLE_REVISION_VEGA20) {
378                 pr_err("Unsupported PPTable format!");
379                 return -EINVAL;
380         }
381
382         if (!powerplay_table->sHeader.structuresize) {
383                 pr_err("Invalid PowerPlay Table!");
384                 return -EINVAL;
385         }
386
387         return 0;
388 }
389
390 static int vega20_run_btc_afll(struct smu_context *smu)
391 {
392         return smu_send_smc_msg(smu, SMU_MSG_RunAfllBtc);
393 }
394
395 static int
396 vega20_get_unallowed_feature_mask(struct smu_context *smu,
397                                   uint32_t *feature_mask, uint32_t num)
398 {
399         if (num > 2)
400                 return -EINVAL;
401
402         feature_mask[0] = 0xE0041C00;
403         feature_mask[1] = 0xFFFFFFFE; /* bit32~bit63 is Unsupported */
404
405         return 0;
406 }
407
408 static enum
409 amd_pm_state_type vega20_get_current_power_state(struct smu_context *smu)
410 {
411         enum amd_pm_state_type pm_type;
412         struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
413
414         if (!smu_dpm_ctx->dpm_context ||
415             !smu_dpm_ctx->dpm_current_power_state)
416                 return -EINVAL;
417
418         mutex_lock(&(smu->mutex));
419         switch (smu_dpm_ctx->dpm_current_power_state->classification.ui_label) {
420         case SMU_STATE_UI_LABEL_BATTERY:
421                 pm_type = POWER_STATE_TYPE_BATTERY;
422                 break;
423         case SMU_STATE_UI_LABEL_BALLANCED:
424                 pm_type = POWER_STATE_TYPE_BALANCED;
425                 break;
426         case SMU_STATE_UI_LABEL_PERFORMANCE:
427                 pm_type = POWER_STATE_TYPE_PERFORMANCE;
428                 break;
429         default:
430                 if (smu_dpm_ctx->dpm_current_power_state->classification.flags & SMU_STATE_CLASSIFICATION_FLAG_BOOT)
431                         pm_type = POWER_STATE_TYPE_INTERNAL_BOOT;
432                 else
433                         pm_type = POWER_STATE_TYPE_DEFAULT;
434                 break;
435         }
436         mutex_unlock(&(smu->mutex));
437
438         return pm_type;
439 }
440
441 static int
442 vega20_set_single_dpm_table(struct smu_context *smu,
443                             struct vega20_single_dpm_table *single_dpm_table,
444                             PPCLK_e clk_id)
445 {
446         int ret = 0;
447         uint32_t i, num_of_levels = 0, clk;
448
449         ret = smu_send_smc_msg_with_param(smu,
450                         SMU_MSG_GetDpmFreqByIndex,
451                         (clk_id << 16 | 0xFF));
452         if (ret) {
453                 pr_err("[GetNumOfDpmLevel] failed to get dpm levels!");
454                 return ret;
455         }
456
457         smu_read_smc_arg(smu, &num_of_levels);
458         if (!num_of_levels) {
459                 pr_err("[GetNumOfDpmLevel] number of clk levels is invalid!");
460                 return -EINVAL;
461         }
462
463         single_dpm_table->count = num_of_levels;
464
465         for (i = 0; i < num_of_levels; i++) {
466                 ret = smu_send_smc_msg_with_param(smu,
467                                 SMU_MSG_GetDpmFreqByIndex,
468                                 (clk_id << 16 | i));
469                 if (ret) {
470                         pr_err("[GetDpmFreqByIndex] failed to get dpm freq by index!");
471                         return ret;
472                 }
473                 smu_read_smc_arg(smu, &clk);
474                 if (!clk) {
475                         pr_err("[GetDpmFreqByIndex] clk value is invalid!");
476                         return -EINVAL;
477                 }
478                 single_dpm_table->dpm_levels[i].value = clk;
479                 single_dpm_table->dpm_levels[i].enabled = true;
480         }
481         return 0;
482 }
483
484 static void vega20_init_single_dpm_state(struct vega20_dpm_state *dpm_state)
485 {
486         dpm_state->soft_min_level = 0x0;
487         dpm_state->soft_max_level = 0xffff;
488         dpm_state->hard_min_level = 0x0;
489         dpm_state->hard_max_level = 0xffff;
490 }
491
492 static int vega20_set_default_dpm_table(struct smu_context *smu)
493 {
494         int ret;
495
496         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
497         struct vega20_dpm_table *dpm_table = NULL;
498         struct vega20_single_dpm_table *single_dpm_table;
499
500         dpm_table = smu_dpm->dpm_context;
501
502         /* socclk */
503         single_dpm_table = &(dpm_table->soc_table);
504
505         if (smu_feature_is_enabled(smu, FEATURE_DPM_SOCCLK_BIT)) {
506                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
507                                                   PPCLK_SOCCLK);
508                 if (ret) {
509                         pr_err("[SetupDefaultDpmTable] failed to get socclk dpm levels!");
510                         return ret;
511                 }
512         } else {
513                 single_dpm_table->count = 1;
514                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100;
515         }
516         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
517
518         /* gfxclk */
519         single_dpm_table = &(dpm_table->gfx_table);
520
521         if (smu_feature_is_enabled(smu, FEATURE_DPM_GFXCLK_BIT)) {
522                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
523                                                   PPCLK_GFXCLK);
524                 if (ret) {
525                         pr_err("[SetupDefaultDpmTable] failed to get gfxclk dpm levels!");
526                         return ret;
527                 }
528         } else {
529                 single_dpm_table->count = 1;
530                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
531         }
532         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
533
534         /* memclk */
535         single_dpm_table = &(dpm_table->mem_table);
536
537         if (smu_feature_is_enabled(smu, FEATURE_DPM_UCLK_BIT)) {
538                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
539                                                   PPCLK_UCLK);
540                 if (ret) {
541                         pr_err("[SetupDefaultDpmTable] failed to get memclk dpm levels!");
542                         return ret;
543                 }
544         } else {
545                 single_dpm_table->count = 1;
546                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100;
547         }
548         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
549
550         /* eclk */
551         single_dpm_table = &(dpm_table->eclk_table);
552
553         if (smu_feature_is_enabled(smu, FEATURE_DPM_VCE_BIT)) {
554                 ret = vega20_set_single_dpm_table(smu, single_dpm_table, PPCLK_ECLK);
555                 if (ret) {
556                         pr_err("[SetupDefaultDpmTable] failed to get eclk dpm levels!");
557                         return ret;
558                 }
559         } else {
560                 single_dpm_table->count = 1;
561                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.eclk / 100;
562         }
563         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
564
565         /* vclk */
566         single_dpm_table = &(dpm_table->vclk_table);
567
568         if (smu_feature_is_enabled(smu, FEATURE_DPM_UVD_BIT)) {
569                 ret = vega20_set_single_dpm_table(smu, single_dpm_table, PPCLK_VCLK);
570                 if (ret) {
571                         pr_err("[SetupDefaultDpmTable] failed to get vclk dpm levels!");
572                         return ret;
573                 }
574         } else {
575                 single_dpm_table->count = 1;
576                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100;
577         }
578         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
579
580         /* dclk */
581         single_dpm_table = &(dpm_table->dclk_table);
582
583         if (smu_feature_is_enabled(smu, FEATURE_DPM_UVD_BIT)) {
584                 ret = vega20_set_single_dpm_table(smu, single_dpm_table, PPCLK_DCLK);
585                 if (ret) {
586                         pr_err("[SetupDefaultDpmTable] failed to get dclk dpm levels!");
587                         return ret;
588                 }
589         } else {
590                 single_dpm_table->count = 1;
591                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100;
592         }
593         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
594
595         /* dcefclk */
596         single_dpm_table = &(dpm_table->dcef_table);
597
598         if (smu_feature_is_enabled(smu, FEATURE_DPM_DCEFCLK_BIT)) {
599                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
600                                                   PPCLK_DCEFCLK);
601                 if (ret) {
602                         pr_err("[SetupDefaultDpmTable] failed to get dcefclk dpm levels!");
603                         return ret;
604                 }
605         } else {
606                 single_dpm_table->count = 1;
607                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
608         }
609         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
610
611         /* pixclk */
612         single_dpm_table = &(dpm_table->pixel_table);
613
614         if (smu_feature_is_enabled(smu, FEATURE_DPM_DCEFCLK_BIT)) {
615                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
616                                                   PPCLK_PIXCLK);
617                 if (ret) {
618                         pr_err("[SetupDefaultDpmTable] failed to get pixclk dpm levels!");
619                         return ret;
620                 }
621         } else {
622                 single_dpm_table->count = 0;
623         }
624         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
625
626         /* dispclk */
627         single_dpm_table = &(dpm_table->display_table);
628
629         if (smu_feature_is_enabled(smu, FEATURE_DPM_DCEFCLK_BIT)) {
630                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
631                                                   PPCLK_DISPCLK);
632                 if (ret) {
633                         pr_err("[SetupDefaultDpmTable] failed to get dispclk dpm levels!");
634                         return ret;
635                 }
636         } else {
637                 single_dpm_table->count = 0;
638         }
639         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
640
641         /* phyclk */
642         single_dpm_table = &(dpm_table->phy_table);
643
644         if (smu_feature_is_enabled(smu, FEATURE_DPM_DCEFCLK_BIT)) {
645                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
646                                                   PPCLK_PHYCLK);
647                 if (ret) {
648                         pr_err("[SetupDefaultDpmTable] failed to get phyclk dpm levels!");
649                         return ret;
650                 }
651         } else {
652                 single_dpm_table->count = 0;
653         }
654         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
655
656         /* fclk */
657         single_dpm_table = &(dpm_table->fclk_table);
658
659         if (smu_feature_is_enabled(smu,FEATURE_DPM_FCLK_BIT)) {
660                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
661                                                   PPCLK_FCLK);
662                 if (ret) {
663                         pr_err("[SetupDefaultDpmTable] failed to get fclk dpm levels!");
664                         return ret;
665                 }
666         } else {
667                 single_dpm_table->count = 0;
668         }
669         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
670
671         memcpy(smu_dpm->golden_dpm_context, dpm_table,
672                sizeof(struct vega20_dpm_table));
673
674         return 0;
675 }
676
677 static int vega20_populate_umd_state_clk(struct smu_context *smu)
678 {
679         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
680         struct vega20_dpm_table *dpm_table = NULL;
681         struct vega20_single_dpm_table *gfx_table = NULL;
682         struct vega20_single_dpm_table *mem_table = NULL;
683
684         dpm_table = smu_dpm->dpm_context;
685         gfx_table = &(dpm_table->gfx_table);
686         mem_table = &(dpm_table->mem_table);
687
688         smu->pstate_sclk = gfx_table->dpm_levels[0].value;
689         smu->pstate_mclk = mem_table->dpm_levels[0].value;
690
691         if (gfx_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
692             mem_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL) {
693                 smu->pstate_sclk = gfx_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
694                 smu->pstate_mclk = mem_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
695         }
696
697         smu->pstate_sclk = smu->pstate_sclk * 100;
698         smu->pstate_mclk = smu->pstate_mclk * 100;
699
700         return 0;
701 }
702
703 static int vega20_get_clk_table(struct smu_context *smu,
704                         struct pp_clock_levels_with_latency *clocks,
705                         struct vega20_single_dpm_table *dpm_table)
706 {
707         int i, count;
708
709         count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
710         clocks->num_levels = count;
711
712         for (i = 0; i < count; i++) {
713                 clocks->data[i].clocks_in_khz =
714                         dpm_table->dpm_levels[i].value * 1000;
715                 clocks->data[i].latency_in_us = 0;
716         }
717
718         return 0;
719 }
720
721 static int vega20_print_clk_levels(struct smu_context *smu,
722                         enum pp_clock_type type, char *buf)
723 {
724         int i, now, size = 0;
725         int ret = 0;
726         uint32_t gen_speed, lane_width;
727         struct amdgpu_device *adev = smu->adev;
728         struct pp_clock_levels_with_latency clocks;
729         struct vega20_single_dpm_table *single_dpm_table;
730         struct smu_table_context *table_context = &smu->smu_table;
731         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
732         struct vega20_dpm_table *dpm_table = NULL;
733         struct vega20_od8_settings *od8_settings =
734                 (struct vega20_od8_settings *)table_context->od8_settings;
735         OverDriveTable_t *od_table =
736                 (OverDriveTable_t *)(table_context->overdrive_table);
737         PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable;
738
739         dpm_table = smu_dpm->dpm_context;
740
741         switch (type) {
742         case PP_SCLK:
743                 ret = smu_get_current_clk_freq(smu, PPCLK_GFXCLK, &now);
744                 if (ret) {
745                         pr_err("Attempt to get current gfx clk Failed!");
746                         return ret;
747                 }
748
749                 single_dpm_table = &(dpm_table->gfx_table);
750                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
751                 if (ret) {
752                         pr_err("Attempt to get gfx clk levels Failed!");
753                         return ret;
754                 }
755
756                 for (i = 0; i < clocks.num_levels; i++)
757                         size += sprintf(buf + size, "%d: %uMhz %s\n", i,
758                                         clocks.data[i].clocks_in_khz / 1000,
759                                         (clocks.data[i].clocks_in_khz == now * 10)
760                                         ? "*" : "");
761                 break;
762
763         case PP_MCLK:
764                 ret = smu_get_current_clk_freq(smu, PPCLK_UCLK, &now);
765                 if (ret) {
766                         pr_err("Attempt to get current mclk Failed!");
767                         return ret;
768                 }
769
770                 single_dpm_table = &(dpm_table->mem_table);
771                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
772                 if (ret) {
773                         pr_err("Attempt to get memory clk levels Failed!");
774                         return ret;
775                 }
776
777                 for (i = 0; i < clocks.num_levels; i++)
778                         size += sprintf(buf + size, "%d: %uMhz %s\n",
779                                 i, clocks.data[i].clocks_in_khz / 1000,
780                                 (clocks.data[i].clocks_in_khz == now * 10)
781                                 ? "*" : "");
782                 break;
783
784         case PP_SOCCLK:
785                 ret = smu_get_current_clk_freq(smu, PPCLK_SOCCLK, &now);
786                 if (ret) {
787                         pr_err("Attempt to get current socclk Failed!");
788                         return ret;
789                 }
790
791                 single_dpm_table = &(dpm_table->soc_table);
792                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
793                 if (ret) {
794                         pr_err("Attempt to get socclk levels Failed!");
795                         return ret;
796                 }
797
798                 for (i = 0; i < clocks.num_levels; i++)
799                         size += sprintf(buf + size, "%d: %uMhz %s\n",
800                                 i, clocks.data[i].clocks_in_khz / 1000,
801                                 (clocks.data[i].clocks_in_khz == now * 10)
802                                 ? "*" : "");
803                 break;
804
805         case PP_FCLK:
806                 ret = smu_get_current_clk_freq(smu, PPCLK_FCLK, &now);
807                 if (ret) {
808                         pr_err("Attempt to get current fclk Failed!");
809                         return ret;
810                 }
811
812                 single_dpm_table = &(dpm_table->fclk_table);
813                 for (i = 0; i < single_dpm_table->count; i++)
814                         size += sprintf(buf + size, "%d: %uMhz %s\n",
815                                 i, single_dpm_table->dpm_levels[i].value,
816                                 (single_dpm_table->dpm_levels[i].value == now / 100)
817                                 ? "*" : "");
818                 break;
819
820         case PP_DCEFCLK:
821                 ret = smu_get_current_clk_freq(smu, PPCLK_DCEFCLK, &now);
822                 if (ret) {
823                         pr_err("Attempt to get current dcefclk Failed!");
824                         return ret;
825                 }
826
827                 single_dpm_table = &(dpm_table->dcef_table);
828                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
829                 if (ret) {
830                         pr_err("Attempt to get dcefclk levels Failed!");
831                         return ret;
832                 }
833
834                 for (i = 0; i < clocks.num_levels; i++)
835                         size += sprintf(buf + size, "%d: %uMhz %s\n",
836                                 i, clocks.data[i].clocks_in_khz / 1000,
837                                 (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
838                 break;
839
840         case PP_PCIE:
841                 gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) &
842                              PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK)
843                         >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
844                 lane_width = (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) &
845                               PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK)
846                         >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT;
847                 for (i = 0; i < NUM_LINK_LEVELS; i++)
848                         size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
849                                         (pptable->PcieGenSpeed[i] == 0) ? "2.5GT/s," :
850                                         (pptable->PcieGenSpeed[i] == 1) ? "5.0GT/s," :
851                                         (pptable->PcieGenSpeed[i] == 2) ? "8.0GT/s," :
852                                         (pptable->PcieGenSpeed[i] == 3) ? "16.0GT/s," : "",
853                                         (pptable->PcieLaneCount[i] == 1) ? "x1" :
854                                         (pptable->PcieLaneCount[i] == 2) ? "x2" :
855                                         (pptable->PcieLaneCount[i] == 3) ? "x4" :
856                                         (pptable->PcieLaneCount[i] == 4) ? "x8" :
857                                         (pptable->PcieLaneCount[i] == 5) ? "x12" :
858                                         (pptable->PcieLaneCount[i] == 6) ? "x16" : "",
859                                         pptable->LclkFreq[i],
860                                         (gen_speed == pptable->PcieGenSpeed[i]) &&
861                                         (lane_width == pptable->PcieLaneCount[i]) ?
862                                         "*" : "");
863                 break;
864
865         case OD_SCLK:
866                 if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id &&
867                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id) {
868                         size = sprintf(buf, "%s:\n", "OD_SCLK");
869                         size += sprintf(buf + size, "0: %10uMhz\n",
870                                         od_table->GfxclkFmin);
871                         size += sprintf(buf + size, "1: %10uMhz\n",
872                                         od_table->GfxclkFmax);
873                 }
874
875                 break;
876
877         case OD_MCLK:
878                 if (od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) {
879                         size = sprintf(buf, "%s:\n", "OD_MCLK");
880                         size += sprintf(buf + size, "1: %10uMhz\n",
881                                          od_table->UclkFmax);
882                 }
883
884                 break;
885
886         case OD_VDDC_CURVE:
887                 if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
888                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
889                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
890                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
891                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
892                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
893                         size = sprintf(buf, "%s:\n", "OD_VDDC_CURVE");
894                         size += sprintf(buf + size, "0: %10uMhz %10dmV\n",
895                                         od_table->GfxclkFreq1,
896                                         od_table->GfxclkVolt1 / VOLTAGE_SCALE);
897                         size += sprintf(buf + size, "1: %10uMhz %10dmV\n",
898                                         od_table->GfxclkFreq2,
899                                         od_table->GfxclkVolt2 / VOLTAGE_SCALE);
900                         size += sprintf(buf + size, "2: %10uMhz %10dmV\n",
901                                         od_table->GfxclkFreq3,
902                                         od_table->GfxclkVolt3 / VOLTAGE_SCALE);
903                 }
904
905                 break;
906
907         case OD_RANGE:
908                 size = sprintf(buf, "%s:\n", "OD_RANGE");
909
910                 if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id &&
911                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id) {
912                         size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
913                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value,
914                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value);
915                 }
916
917                 if (od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) {
918                         single_dpm_table = &(dpm_table->mem_table);
919                         ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
920                         if (ret) {
921                                 pr_err("Attempt to get memory clk levels Failed!");
922                                 return ret;
923                         }
924
925                         size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
926                                         clocks.data[0].clocks_in_khz / 1000,
927                                         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value);
928                 }
929
930                 if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
931                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
932                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
933                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
934                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
935                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
936                         size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
937                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].min_value,
938                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].max_value);
939                         size += sprintf(buf + size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n",
940                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].min_value,
941                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].max_value);
942                         size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
943                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].min_value,
944                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].max_value);
945                         size += sprintf(buf + size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n",
946                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].min_value,
947                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].max_value);
948                         size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
949                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].min_value,
950                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].max_value);
951                         size += sprintf(buf + size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
952                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].min_value,
953                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].max_value);
954                 }
955
956                 break;
957
958         default:
959                 break;
960         }
961         return size;
962 }
963
964 static int vega20_upload_dpm_level(struct smu_context *smu, bool max,
965                                    uint32_t feature_mask)
966 {
967         struct vega20_dpm_table *dpm_table;
968         struct vega20_single_dpm_table *single_dpm_table;
969         uint32_t freq;
970         int ret = 0;
971
972         dpm_table = smu->smu_dpm.dpm_context;
973
974         if (smu_feature_is_enabled(smu, FEATURE_DPM_GFXCLK_BIT) &&
975             (feature_mask & FEATURE_DPM_GFXCLK_MASK)) {
976                 single_dpm_table = &(dpm_table->gfx_table);
977                 freq = max ? single_dpm_table->dpm_state.soft_max_level :
978                         single_dpm_table->dpm_state.soft_min_level;
979                 ret = smu_send_smc_msg_with_param(smu,
980                         (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
981                         (PPCLK_GFXCLK << 16) | (freq & 0xffff));
982                 if (ret) {
983                         pr_err("Failed to set soft %s gfxclk !\n",
984                                                 max ? "max" : "min");
985                         return ret;
986                 }
987         }
988
989         if (smu_feature_is_enabled(smu, FEATURE_DPM_UCLK_BIT) &&
990             (feature_mask & FEATURE_DPM_UCLK_MASK)) {
991                 single_dpm_table = &(dpm_table->mem_table);
992                 freq = max ? single_dpm_table->dpm_state.soft_max_level :
993                         single_dpm_table->dpm_state.soft_min_level;
994                 ret = smu_send_smc_msg_with_param(smu,
995                         (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
996                         (PPCLK_UCLK << 16) | (freq & 0xffff));
997                 if (ret) {
998                         pr_err("Failed to set soft %s memclk !\n",
999                                                 max ? "max" : "min");
1000                         return ret;
1001                 }
1002         }
1003
1004         if (smu_feature_is_enabled(smu, FEATURE_DPM_SOCCLK_BIT) &&
1005             (feature_mask & FEATURE_DPM_SOCCLK_MASK)) {
1006                 single_dpm_table = &(dpm_table->soc_table);
1007                 freq = max ? single_dpm_table->dpm_state.soft_max_level :
1008                         single_dpm_table->dpm_state.soft_min_level;
1009                 ret = smu_send_smc_msg_with_param(smu,
1010                         (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
1011                         (PPCLK_SOCCLK << 16) | (freq & 0xffff));
1012                 if (ret) {
1013                         pr_err("Failed to set soft %s socclk !\n",
1014                                                 max ? "max" : "min");
1015                         return ret;
1016                 }
1017         }
1018
1019         if (smu_feature_is_enabled(smu, FEATURE_DPM_FCLK_BIT) &&
1020             (feature_mask & FEATURE_DPM_FCLK_MASK)) {
1021                 single_dpm_table = &(dpm_table->fclk_table);
1022                 freq = max ? single_dpm_table->dpm_state.soft_max_level :
1023                         single_dpm_table->dpm_state.soft_min_level;
1024                 ret = smu_send_smc_msg_with_param(smu,
1025                         (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
1026                         (PPCLK_FCLK << 16) | (freq & 0xffff));
1027                 if (ret) {
1028                         pr_err("Failed to set soft %s fclk !\n",
1029                                                 max ? "max" : "min");
1030                         return ret;
1031                 }
1032         }
1033
1034         if (smu_feature_is_enabled(smu, FEATURE_DPM_DCEFCLK_BIT) &&
1035             (feature_mask & FEATURE_DPM_DCEFCLK_MASK)) {
1036                 single_dpm_table = &(dpm_table->dcef_table);
1037                 freq = single_dpm_table->dpm_state.hard_min_level;
1038                 if (!max) {
1039                         ret = smu_send_smc_msg_with_param(smu,
1040                                 SMU_MSG_SetHardMinByFreq,
1041                                 (PPCLK_DCEFCLK << 16) | (freq & 0xffff));
1042                         if (ret) {
1043                                 pr_err("Failed to set hard min dcefclk !\n");
1044                                 return ret;
1045                         }
1046                 }
1047         }
1048
1049         return ret;
1050 }
1051
1052 static int vega20_force_clk_levels(struct smu_context *smu,
1053                         enum pp_clock_type type, uint32_t mask)
1054 {
1055         struct vega20_dpm_table *dpm_table;
1056         struct vega20_single_dpm_table *single_dpm_table;
1057         uint32_t soft_min_level, soft_max_level, hard_min_level;
1058         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
1059         int ret = 0;
1060
1061         if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) {
1062                 pr_info("force clock level is for dpm manual mode only.\n");
1063                 return -EINVAL;
1064         }
1065
1066         mutex_lock(&(smu->mutex));
1067
1068         soft_min_level = mask ? (ffs(mask) - 1) : 0;
1069         soft_max_level = mask ? (fls(mask) - 1) : 0;
1070
1071         dpm_table = smu->smu_dpm.dpm_context;
1072
1073         switch (type) {
1074         case PP_SCLK:
1075                 single_dpm_table = &(dpm_table->gfx_table);
1076
1077                 if (soft_max_level >= single_dpm_table->count) {
1078                         pr_err("Clock level specified %d is over max allowed %d\n",
1079                                         soft_max_level, single_dpm_table->count - 1);
1080                         ret = -EINVAL;
1081                         break;
1082                 }
1083
1084                 single_dpm_table->dpm_state.soft_min_level =
1085                         single_dpm_table->dpm_levels[soft_min_level].value;
1086                 single_dpm_table->dpm_state.soft_max_level =
1087                         single_dpm_table->dpm_levels[soft_max_level].value;
1088
1089                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_GFXCLK_MASK);
1090                 if (ret) {
1091                         pr_err("Failed to upload boot level to lowest!\n");
1092                         break;
1093                 }
1094
1095                 ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_GFXCLK_MASK);
1096                 if (ret)
1097                         pr_err("Failed to upload dpm max level to highest!\n");
1098
1099                 break;
1100
1101         case PP_MCLK:
1102                 single_dpm_table = &(dpm_table->mem_table);
1103
1104                 if (soft_max_level >= single_dpm_table->count) {
1105                         pr_err("Clock level specified %d is over max allowed %d\n",
1106                                         soft_max_level, single_dpm_table->count - 1);
1107                         ret = -EINVAL;
1108                         break;
1109                 }
1110
1111                 single_dpm_table->dpm_state.soft_min_level =
1112                         single_dpm_table->dpm_levels[soft_min_level].value;
1113                 single_dpm_table->dpm_state.soft_max_level =
1114                         single_dpm_table->dpm_levels[soft_max_level].value;
1115
1116                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_UCLK_MASK);
1117                 if (ret) {
1118                         pr_err("Failed to upload boot level to lowest!\n");
1119                         break;
1120                 }
1121
1122                 ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_UCLK_MASK);
1123                 if (ret)
1124                         pr_err("Failed to upload dpm max level to highest!\n");
1125
1126                 break;
1127
1128         case PP_SOCCLK:
1129                 single_dpm_table = &(dpm_table->soc_table);
1130
1131                 if (soft_max_level >= single_dpm_table->count) {
1132                         pr_err("Clock level specified %d is over max allowed %d\n",
1133                                         soft_max_level, single_dpm_table->count - 1);
1134                         ret = -EINVAL;
1135                         break;
1136                 }
1137
1138                 single_dpm_table->dpm_state.soft_min_level =
1139                         single_dpm_table->dpm_levels[soft_min_level].value;
1140                 single_dpm_table->dpm_state.soft_max_level =
1141                         single_dpm_table->dpm_levels[soft_max_level].value;
1142
1143                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_SOCCLK_MASK);
1144                 if (ret) {
1145                         pr_err("Failed to upload boot level to lowest!\n");
1146                         break;
1147                 }
1148
1149                 ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_SOCCLK_MASK);
1150                 if (ret)
1151                         pr_err("Failed to upload dpm max level to highest!\n");
1152
1153                 break;
1154
1155         case PP_FCLK:
1156                 single_dpm_table = &(dpm_table->fclk_table);
1157
1158                 if (soft_max_level >= single_dpm_table->count) {
1159                         pr_err("Clock level specified %d is over max allowed %d\n",
1160                                         soft_max_level, single_dpm_table->count - 1);
1161                         ret = -EINVAL;
1162                         break;
1163                 }
1164
1165                 single_dpm_table->dpm_state.soft_min_level =
1166                         single_dpm_table->dpm_levels[soft_min_level].value;
1167                 single_dpm_table->dpm_state.soft_max_level =
1168                         single_dpm_table->dpm_levels[soft_max_level].value;
1169
1170                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_FCLK_MASK);
1171                 if (ret) {
1172                         pr_err("Failed to upload boot level to lowest!\n");
1173                         break;
1174                 }
1175
1176                 ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_FCLK_MASK);
1177                 if (ret)
1178                         pr_err("Failed to upload dpm max level to highest!\n");
1179
1180                 break;
1181
1182         case PP_DCEFCLK:
1183                 hard_min_level = soft_min_level;
1184                 single_dpm_table = &(dpm_table->dcef_table);
1185
1186                 if (hard_min_level >= single_dpm_table->count) {
1187                         pr_err("Clock level specified %d is over max allowed %d\n",
1188                                         hard_min_level, single_dpm_table->count - 1);
1189                         ret = -EINVAL;
1190                         break;
1191                 }
1192
1193                 single_dpm_table->dpm_state.hard_min_level =
1194                         single_dpm_table->dpm_levels[hard_min_level].value;
1195
1196                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_DCEFCLK_MASK);
1197                 if (ret)
1198                         pr_err("Failed to upload boot level to lowest!\n");
1199
1200                 break;
1201
1202         case PP_PCIE:
1203                 if (soft_min_level >= NUM_LINK_LEVELS ||
1204                     soft_max_level >= NUM_LINK_LEVELS) {
1205                         ret = -EINVAL;
1206                         break;
1207                 }
1208
1209                 ret = smu_send_smc_msg_with_param(smu,
1210                                 SMU_MSG_SetMinLinkDpmByIndex, soft_min_level);
1211                 if (ret)
1212                         pr_err("Failed to set min link dpm level!\n");
1213
1214                 break;
1215
1216         default:
1217                 break;
1218         }
1219
1220         mutex_unlock(&(smu->mutex));
1221         return ret;
1222 }
1223
1224 static int vega20_get_clock_by_type_with_latency(struct smu_context *smu,
1225                                                  enum amd_pp_clock_type type,
1226                                                  struct pp_clock_levels_with_latency *clocks)
1227 {
1228         int ret;
1229         struct vega20_single_dpm_table *single_dpm_table;
1230         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
1231         struct vega20_dpm_table *dpm_table = NULL;
1232
1233         dpm_table = smu_dpm->dpm_context;
1234
1235         mutex_lock(&smu->mutex);
1236
1237         switch (type) {
1238         case amd_pp_sys_clock:
1239                 single_dpm_table = &(dpm_table->gfx_table);
1240                 ret = vega20_get_clk_table(smu, clocks, single_dpm_table);
1241                 break;
1242         case amd_pp_mem_clock:
1243                 single_dpm_table = &(dpm_table->mem_table);
1244                 ret = vega20_get_clk_table(smu, clocks, single_dpm_table);
1245                 break;
1246         case amd_pp_dcef_clock:
1247                 single_dpm_table = &(dpm_table->dcef_table);
1248                 ret = vega20_get_clk_table(smu, clocks, single_dpm_table);
1249                 break;
1250         case amd_pp_soc_clock:
1251                 single_dpm_table = &(dpm_table->soc_table);
1252                 ret = vega20_get_clk_table(smu, clocks, single_dpm_table);
1253                 break;
1254         default:
1255                 ret = -EINVAL;
1256         }
1257
1258         mutex_unlock(&smu->mutex);
1259         return ret;
1260 }
1261
1262 static int vega20_overdrive_get_gfx_clk_base_voltage(struct smu_context *smu,
1263                                                      uint32_t *voltage,
1264                                                      uint32_t freq)
1265 {
1266         int ret;
1267
1268         ret = smu_send_smc_msg_with_param(smu,
1269                         SMU_MSG_GetAVFSVoltageByDpm,
1270                         ((AVFS_CURVE << 24) | (OD8_HOTCURVE_TEMPERATURE << 16) | freq));
1271         if (ret) {
1272                 pr_err("[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!");
1273                 return ret;
1274         }
1275
1276         smu_read_smc_arg(smu, voltage);
1277         *voltage = *voltage / VOLTAGE_SCALE;
1278
1279         return 0;
1280 }
1281
1282 static int vega20_set_default_od8_setttings(struct smu_context *smu)
1283 {
1284         struct smu_table_context *table_context = &smu->smu_table;
1285         OverDriveTable_t *od_table = (OverDriveTable_t *)(table_context->overdrive_table);
1286         struct vega20_od8_settings *od8_settings = NULL;
1287         PPTable_t *smc_pptable = table_context->driver_pptable;
1288         int i, ret;
1289
1290         if (table_context->od8_settings)
1291                 return -EINVAL;
1292
1293         table_context->od8_settings = kzalloc(sizeof(struct vega20_od8_settings), GFP_KERNEL);
1294
1295         if (!table_context->od8_settings)
1296                 return -ENOMEM;
1297
1298         od8_settings = (struct vega20_od8_settings *)table_context->od8_settings;
1299
1300         if (smu_feature_is_enabled(smu, FEATURE_DPM_SOCCLK_BIT)) {
1301                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_LIMITS] &&
1302                     table_context->od_settings_max[OD8_SETTING_GFXCLK_FMAX] > 0 &&
1303                     table_context->od_settings_min[OD8_SETTING_GFXCLK_FMIN] > 0 &&
1304                     (table_context->od_settings_max[OD8_SETTING_GFXCLK_FMAX] >=
1305                      table_context->od_settings_min[OD8_SETTING_GFXCLK_FMIN])) {
1306                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id =
1307                                 OD8_GFXCLK_LIMITS;
1308                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id =
1309                                 OD8_GFXCLK_LIMITS;
1310                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value =
1311                                 od_table->GfxclkFmin;
1312                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value =
1313                                 od_table->GfxclkFmax;
1314                 }
1315
1316                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_CURVE] &&
1317                     (table_context->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] >=
1318                      smc_pptable->MinVoltageGfx / VOLTAGE_SCALE) &&
1319                     (table_context->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3] <=
1320                      smc_pptable->MaxVoltageGfx / VOLTAGE_SCALE) &&
1321                     (table_context->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] <=
1322                      table_context->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3])) {
1323                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id =
1324                                 OD8_GFXCLK_CURVE;
1325                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id =
1326                                 OD8_GFXCLK_CURVE;
1327                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id =
1328                                 OD8_GFXCLK_CURVE;
1329                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id =
1330                                 OD8_GFXCLK_CURVE;
1331                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id =
1332                                 OD8_GFXCLK_CURVE;
1333                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id =
1334                                 OD8_GFXCLK_CURVE;
1335
1336                         od_table->GfxclkFreq1 = od_table->GfxclkFmin;
1337                         od_table->GfxclkFreq2 = (od_table->GfxclkFmin + od_table->GfxclkFmax) / 2;
1338                         od_table->GfxclkFreq3 = od_table->GfxclkFmax;
1339                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value =
1340                                 od_table->GfxclkFreq1;
1341                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value =
1342                                 od_table->GfxclkFreq2;
1343                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value =
1344                                 od_table->GfxclkFreq3;
1345
1346                         ret = vega20_overdrive_get_gfx_clk_base_voltage(smu,
1347                                 &od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value,
1348                                 od_table->GfxclkFreq1);
1349                         if (ret)
1350                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value = 0;
1351                         od_table->GfxclkVolt1 =
1352                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value
1353                                 * VOLTAGE_SCALE;
1354                         ret = vega20_overdrive_get_gfx_clk_base_voltage(smu,
1355                                 &od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value,
1356                                 od_table->GfxclkFreq2);
1357                         if (ret)
1358                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value = 0;
1359                         od_table->GfxclkVolt2 =
1360                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value
1361                                 * VOLTAGE_SCALE;
1362                         ret = vega20_overdrive_get_gfx_clk_base_voltage(smu,
1363                                 &od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value,
1364                                 od_table->GfxclkFreq3);
1365                         if (ret)
1366                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value = 0;
1367                         od_table->GfxclkVolt3 =
1368                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value
1369                                 * VOLTAGE_SCALE;
1370                 }
1371         }
1372
1373         if (smu_feature_is_enabled(smu, FEATURE_DPM_UCLK_BIT)) {
1374                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_UCLK_MAX] &&
1375                     table_context->od_settings_min[OD8_SETTING_UCLK_FMAX] > 0 &&
1376                     table_context->od_settings_max[OD8_SETTING_UCLK_FMAX] > 0 &&
1377                     (table_context->od_settings_max[OD8_SETTING_UCLK_FMAX] >=
1378                      table_context->od_settings_min[OD8_SETTING_UCLK_FMAX])) {
1379                         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id =
1380                                 OD8_UCLK_MAX;
1381                         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value =
1382                                 od_table->UclkFmax;
1383                 }
1384         }
1385
1386         if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_POWER_LIMIT] &&
1387             table_context->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
1388             table_context->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] <= 100 &&
1389             table_context->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
1390             table_context->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] <= 100) {
1391                 od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id =
1392                         OD8_POWER_LIMIT;
1393                 od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value =
1394                         od_table->OverDrivePct;
1395         }
1396
1397         if (smu_feature_is_enabled(smu, FEATURE_FAN_CONTROL_BIT)) {
1398                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_ACOUSTIC_LIMIT] &&
1399                     table_context->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 &&
1400                     table_context->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 &&
1401                     (table_context->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] >=
1402                      table_context->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT])) {
1403                         od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id =
1404                                 OD8_ACOUSTIC_LIMIT_SCLK;
1405                         od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value =
1406                                 od_table->FanMaximumRpm;
1407                 }
1408
1409                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_SPEED_MIN] &&
1410                     table_context->od_settings_min[OD8_SETTING_FAN_MIN_SPEED] > 0 &&
1411                     table_context->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] > 0 &&
1412                     (table_context->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] >=
1413                      table_context->od_settings_min[OD8_SETTING_FAN_MIN_SPEED])) {
1414                         od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id =
1415                                 OD8_FAN_SPEED_MIN;
1416                         od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value =
1417                                 od_table->FanMinimumPwm * smc_pptable->FanMaximumRpm / 100;
1418                 }
1419         }
1420
1421         if (smu_feature_is_enabled(smu, FEATURE_THERMAL_BIT)) {
1422                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_FAN] &&
1423                     table_context->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP] > 0 &&
1424                     table_context->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] > 0 &&
1425                     (table_context->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] >=
1426                      table_context->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP])) {
1427                         od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id =
1428                                 OD8_TEMPERATURE_FAN;
1429                         od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value =
1430                                 od_table->FanTargetTemperature;
1431                 }
1432
1433                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_SYSTEM] &&
1434                     table_context->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX] > 0 &&
1435                     table_context->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] > 0 &&
1436                     (table_context->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] >=
1437                      table_context->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX])) {
1438                         od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id =
1439                                 OD8_TEMPERATURE_SYSTEM;
1440                         od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_value =
1441                                 od_table->MaxOpTemp;
1442                 }
1443         }
1444
1445         for (i = 0; i < OD8_SETTING_COUNT; i++) {
1446                 if (od8_settings->od8_settings_array[i].feature_id) {
1447                         od8_settings->od8_settings_array[i].min_value =
1448                                 table_context->od_settings_min[i];
1449                         od8_settings->od8_settings_array[i].max_value =
1450                                 table_context->od_settings_max[i];
1451                         od8_settings->od8_settings_array[i].current_value =
1452                                 od8_settings->od8_settings_array[i].default_value;
1453                 } else {
1454                         od8_settings->od8_settings_array[i].min_value = 0;
1455                         od8_settings->od8_settings_array[i].max_value = 0;
1456                         od8_settings->od8_settings_array[i].current_value = 0;
1457                 }
1458         }
1459
1460         return 0;
1461 }
1462
1463 static int vega20_get_od_percentage(struct smu_context *smu,
1464                                     enum pp_clock_type type)
1465 {
1466         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
1467         struct vega20_dpm_table *dpm_table = NULL;
1468         struct vega20_dpm_table *golden_table = NULL;
1469         struct vega20_single_dpm_table *single_dpm_table;
1470         struct vega20_single_dpm_table *golden_dpm_table;
1471         int value, golden_value;
1472
1473         dpm_table = smu_dpm->dpm_context;
1474         golden_table = smu_dpm->golden_dpm_context;
1475
1476         switch (type) {
1477         case OD_SCLK:
1478                 single_dpm_table = &(dpm_table->gfx_table);
1479                 golden_dpm_table = &(golden_table->gfx_table);
1480                 break;
1481         case OD_MCLK:
1482                 single_dpm_table = &(dpm_table->mem_table);
1483                 golden_dpm_table = &(golden_table->mem_table);
1484                 break;
1485         default:
1486                 return -EINVAL;
1487                 break;
1488         }
1489
1490         value = single_dpm_table->dpm_levels[single_dpm_table->count - 1].value;
1491         golden_value = golden_dpm_table->dpm_levels[golden_dpm_table->count - 1].value;
1492
1493         value -= golden_value;
1494         value = DIV_ROUND_UP(value * 100, golden_value);
1495
1496         return value;
1497 }
1498
1499 static int vega20_conv_profile_to_workload(struct smu_context *smu, int power_profile)
1500 {
1501         int pplib_workload = 0;
1502
1503         switch (power_profile) {
1504         case PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT:
1505                 pplib_workload = WORKLOAD_DEFAULT_BIT;
1506                 break;
1507         case PP_SMC_POWER_PROFILE_FULLSCREEN3D:
1508                 pplib_workload = WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT;
1509                 break;
1510         case PP_SMC_POWER_PROFILE_POWERSAVING:
1511                 pplib_workload = WORKLOAD_PPLIB_POWER_SAVING_BIT;
1512                 break;
1513         case PP_SMC_POWER_PROFILE_VIDEO:
1514                 pplib_workload = WORKLOAD_PPLIB_VIDEO_BIT;
1515                 break;
1516         case PP_SMC_POWER_PROFILE_VR:
1517                 pplib_workload = WORKLOAD_PPLIB_VR_BIT;
1518                 break;
1519         case PP_SMC_POWER_PROFILE_COMPUTE:
1520                 pplib_workload = WORKLOAD_PPLIB_COMPUTE_BIT;
1521                 break;
1522         case PP_SMC_POWER_PROFILE_CUSTOM:
1523                 pplib_workload = WORKLOAD_PPLIB_CUSTOM_BIT;
1524                 break;
1525         }
1526
1527         return pplib_workload;
1528 }
1529
1530 static int
1531 vega20_get_profiling_clk_mask(struct smu_context *smu,
1532                               enum amd_dpm_forced_level level,
1533                               uint32_t *sclk_mask,
1534                               uint32_t *mclk_mask,
1535                               uint32_t *soc_mask)
1536 {
1537         struct vega20_dpm_table *dpm_table = (struct vega20_dpm_table *)smu->smu_dpm.dpm_context;
1538         struct vega20_single_dpm_table *gfx_dpm_table;
1539         struct vega20_single_dpm_table *mem_dpm_table;
1540         struct vega20_single_dpm_table *soc_dpm_table;
1541
1542         if (!smu->smu_dpm.dpm_context)
1543                 return -EINVAL;
1544
1545         gfx_dpm_table = &dpm_table->gfx_table;
1546         mem_dpm_table = &dpm_table->mem_table;
1547         soc_dpm_table = &dpm_table->soc_table;
1548
1549         *sclk_mask = 0;
1550         *mclk_mask = 0;
1551         *soc_mask  = 0;
1552
1553         if (gfx_dpm_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
1554             mem_dpm_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL &&
1555             soc_dpm_table->count > VEGA20_UMD_PSTATE_SOCCLK_LEVEL) {
1556                 *sclk_mask = VEGA20_UMD_PSTATE_GFXCLK_LEVEL;
1557                 *mclk_mask = VEGA20_UMD_PSTATE_MCLK_LEVEL;
1558                 *soc_mask  = VEGA20_UMD_PSTATE_SOCCLK_LEVEL;
1559         }
1560
1561         if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
1562                 *sclk_mask = 0;
1563         } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
1564                 *mclk_mask = 0;
1565         } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
1566                 *sclk_mask = gfx_dpm_table->count - 1;
1567                 *mclk_mask = mem_dpm_table->count - 1;
1568                 *soc_mask  = soc_dpm_table->count - 1;
1569         }
1570
1571         return 0;
1572 }
1573
1574 static int
1575 vega20_set_uclk_to_highest_dpm_level(struct smu_context *smu,
1576                                      struct vega20_single_dpm_table *dpm_table)
1577 {
1578         int ret = 0;
1579         struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
1580         if (!smu_dpm_ctx->dpm_context)
1581                 return -EINVAL;
1582
1583         if (smu_feature_is_enabled(smu, FEATURE_DPM_UCLK_BIT)) {
1584                 if (dpm_table->count <= 0) {
1585                         pr_err("[%s] Dpm table has no entry!", __func__);
1586                                 return -EINVAL;
1587                 }
1588
1589                 if (dpm_table->count > NUM_UCLK_DPM_LEVELS) {
1590                         pr_err("[%s] Dpm table has too many entries!", __func__);
1591                                 return -EINVAL;
1592                 }
1593
1594                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1595                 ret = smu_send_smc_msg_with_param(smu,
1596                                 SMU_MSG_SetHardMinByFreq,
1597                                 (PPCLK_UCLK << 16) | dpm_table->dpm_state.hard_min_level);
1598                 if (ret) {
1599                         pr_err("[%s] Set hard min uclk failed!", __func__);
1600                                 return ret;
1601                 }
1602         }
1603
1604         return ret;
1605 }
1606
1607 static int vega20_pre_display_config_changed(struct smu_context *smu)
1608 {
1609         int ret = 0;
1610         struct vega20_dpm_table *dpm_table = smu->smu_dpm.dpm_context;
1611
1612         if (!smu->smu_dpm.dpm_context)
1613                 return -EINVAL;
1614
1615         smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, 0);
1616         ret = vega20_set_uclk_to_highest_dpm_level(smu,
1617                                                    &dpm_table->mem_table);
1618         if (ret)
1619                 pr_err("Failed to set uclk to highest dpm level");
1620         return ret;
1621 }
1622
1623 static int vega20_display_config_changed(struct smu_context *smu)
1624 {
1625         int ret = 0;
1626
1627         if (!smu->funcs)
1628                 return -EINVAL;
1629
1630         if (!smu->smu_dpm.dpm_context ||
1631             !smu->smu_table.tables ||
1632             !smu->smu_table.tables[TABLE_WATERMARKS].cpu_addr)
1633                 return -EINVAL;
1634
1635         if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
1636             !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
1637                 ret = smu->funcs->write_watermarks_table(smu);
1638                 if (ret) {
1639                         pr_err("Failed to update WMTABLE!");
1640                         return ret;
1641                 }
1642                 smu->watermarks_bitmap |= WATERMARKS_LOADED;
1643         }
1644
1645         if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
1646             smu_feature_is_supported(smu, FEATURE_DPM_DCEFCLK_BIT) &&
1647             smu_feature_is_supported(smu, FEATURE_DPM_SOCCLK_BIT)) {
1648                 smu_send_smc_msg_with_param(smu,
1649                                             SMU_MSG_NumOfDisplays,
1650                                             smu->display_config->num_display);
1651         }
1652
1653         return ret;
1654 }
1655
1656 static int vega20_apply_clocks_adjust_rules(struct smu_context *smu)
1657 {
1658         struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
1659         struct vega20_dpm_table *dpm_ctx = (struct vega20_dpm_table *)(smu_dpm_ctx->dpm_context);
1660         struct vega20_single_dpm_table *dpm_table;
1661         bool vblank_too_short = false;
1662         bool disable_mclk_switching;
1663         uint32_t i, latency;
1664
1665         disable_mclk_switching = ((1 < smu->display_config->num_display) &&
1666                                   !smu->display_config->multi_monitor_in_sync) || vblank_too_short;
1667         latency = smu->display_config->dce_tolerable_mclk_in_active_latency;
1668
1669         /* gfxclk */
1670         dpm_table = &(dpm_ctx->gfx_table);
1671         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
1672         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1673         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
1674         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1675
1676                 if (VEGA20_UMD_PSTATE_GFXCLK_LEVEL < dpm_table->count) {
1677                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
1678                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
1679                 }
1680
1681                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
1682                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
1683                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
1684                 }
1685
1686                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
1687                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1688                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1689                 }
1690
1691         /* memclk */
1692         dpm_table = &(dpm_ctx->mem_table);
1693         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
1694         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1695         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
1696         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1697
1698                 if (VEGA20_UMD_PSTATE_MCLK_LEVEL < dpm_table->count) {
1699                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
1700                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
1701                 }
1702
1703                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
1704                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
1705                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
1706                 }
1707
1708                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
1709                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1710                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1711                 }
1712
1713         /* honour DAL's UCLK Hardmin */
1714         if (dpm_table->dpm_state.hard_min_level < (smu->display_config->min_mem_set_clock / 100))
1715                 dpm_table->dpm_state.hard_min_level = smu->display_config->min_mem_set_clock / 100;
1716
1717         /* Hardmin is dependent on displayconfig */
1718         if (disable_mclk_switching) {
1719                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1720                 for (i = 0; i < smu_dpm_ctx->mclk_latency_table->count - 1; i++) {
1721                         if (smu_dpm_ctx->mclk_latency_table->entries[i].latency <= latency) {
1722                                 if (dpm_table->dpm_levels[i].value >= (smu->display_config->min_mem_set_clock / 100)) {
1723                                         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[i].value;
1724                                         break;
1725                                 }
1726                         }
1727                 }
1728         }
1729
1730         if (smu->display_config->nb_pstate_switch_disable)
1731                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1732
1733         /* vclk */
1734         dpm_table = &(dpm_ctx->vclk_table);
1735         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
1736         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1737         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
1738         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1739
1740                 if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
1741                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
1742                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
1743                 }
1744
1745                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
1746                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1747                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1748                 }
1749
1750         /* dclk */
1751         dpm_table = &(dpm_ctx->dclk_table);
1752         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
1753         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1754         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
1755         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1756
1757                 if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
1758                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
1759                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
1760                 }
1761
1762                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
1763                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1764                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1765                 }
1766
1767         /* socclk */
1768         dpm_table = &(dpm_ctx->soc_table);
1769         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
1770         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1771         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
1772         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1773
1774                 if (VEGA20_UMD_PSTATE_SOCCLK_LEVEL < dpm_table->count) {
1775                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
1776                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
1777                 }
1778
1779                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
1780                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1781                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1782                 }
1783
1784         /* eclk */
1785         dpm_table = &(dpm_ctx->eclk_table);
1786         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
1787         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1788         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
1789         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1790
1791                 if (VEGA20_UMD_PSTATE_VCEMCLK_LEVEL < dpm_table->count) {
1792                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
1793                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
1794                 }
1795
1796                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
1797                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1798                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1799                 }
1800         return 0;
1801 }
1802
1803 static int
1804 vega20_notify_smc_dispaly_config(struct smu_context *smu)
1805 {
1806         struct vega20_dpm_table *dpm_table = smu->smu_dpm.dpm_context;
1807         struct vega20_single_dpm_table *memtable = &dpm_table->mem_table;
1808         struct smu_clocks min_clocks = {0};
1809         struct pp_display_clock_request clock_req;
1810         int ret = 0;
1811
1812         min_clocks.dcef_clock = smu->display_config->min_dcef_set_clk;
1813         min_clocks.dcef_clock_in_sr = smu->display_config->min_dcef_deep_sleep_set_clk;
1814         min_clocks.memory_clock = smu->display_config->min_mem_set_clock;
1815
1816         if (smu_feature_is_supported(smu, FEATURE_DPM_DCEFCLK_BIT)) {
1817                 clock_req.clock_type = amd_pp_dcef_clock;
1818                 clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10;
1819                 if (!smu->funcs->display_clock_voltage_request(smu, &clock_req)) {
1820                         if (smu_feature_is_supported(smu, FEATURE_DS_DCEFCLK_BIT)) {
1821                                 ret = smu_send_smc_msg_with_param(smu,
1822                                                                   SMU_MSG_SetMinDeepSleepDcefclk,
1823                                                                   min_clocks.dcef_clock_in_sr/100);
1824                                 if (ret) {
1825                                         pr_err("Attempt to set divider for DCEFCLK Failed!");
1826                                         return ret;
1827                                 }
1828                         }
1829                 } else {
1830                         pr_info("Attempt to set Hard Min for DCEFCLK Failed!");
1831                 }
1832         }
1833
1834         if (smu_feature_is_enabled(smu, FEATURE_DPM_UCLK_BIT)) {
1835                 memtable->dpm_state.hard_min_level = min_clocks.memory_clock/100;
1836                 ret = smu_send_smc_msg_with_param(smu,
1837                                                   SMU_MSG_SetHardMinByFreq,
1838                                                   (PPCLK_UCLK << 16) | memtable->dpm_state.hard_min_level);
1839                 if (ret) {
1840                         pr_err("[%s] Set hard min uclk failed!", __func__);
1841                         return ret;
1842                 }
1843         }
1844
1845         return 0;
1846 }
1847
1848 static uint32_t vega20_find_lowest_dpm_level(struct vega20_single_dpm_table *table)
1849 {
1850         uint32_t i;
1851
1852         for (i = 0; i < table->count; i++) {
1853                 if (table->dpm_levels[i].enabled)
1854                         break;
1855         }
1856         if (i >= table->count) {
1857                 i = 0;
1858                 table->dpm_levels[i].enabled = true;
1859         }
1860
1861         return i;
1862 }
1863
1864 static uint32_t vega20_find_highest_dpm_level(struct vega20_single_dpm_table *table)
1865 {
1866         int i = 0;
1867
1868         if (!table) {
1869                 pr_err("[%s] DPM Table does not exist!", __func__);
1870                 return 0;
1871         }
1872         if (table->count <= 0) {
1873                 pr_err("[%s] DPM Table has no entry!", __func__);
1874                 return 0;
1875         }
1876         if (table->count > MAX_REGULAR_DPM_NUMBER) {
1877                 pr_err("[%s] DPM Table has too many entries!", __func__);
1878                 return MAX_REGULAR_DPM_NUMBER - 1;
1879         }
1880
1881         for (i = table->count - 1; i >= 0; i--) {
1882                 if (table->dpm_levels[i].enabled)
1883                         break;
1884         }
1885         if (i < 0) {
1886                 i = 0;
1887                 table->dpm_levels[i].enabled = true;
1888         }
1889
1890         return i;
1891 }
1892
1893 static int vega20_force_dpm_limit_value(struct smu_context *smu, bool highest)
1894 {
1895         uint32_t soft_level;
1896         int ret = 0;
1897         struct vega20_dpm_table *dpm_table =
1898                 (struct vega20_dpm_table *)smu->smu_dpm.dpm_context;
1899
1900         if (highest)
1901                 soft_level = vega20_find_highest_dpm_level(&(dpm_table->gfx_table));
1902         else
1903                 soft_level = vega20_find_lowest_dpm_level(&(dpm_table->gfx_table));
1904
1905         dpm_table->gfx_table.dpm_state.soft_min_level =
1906                 dpm_table->gfx_table.dpm_state.soft_max_level =
1907                 dpm_table->gfx_table.dpm_levels[soft_level].value;
1908
1909         if (highest)
1910                 soft_level = vega20_find_highest_dpm_level(&(dpm_table->mem_table));
1911         else
1912                 soft_level = vega20_find_lowest_dpm_level(&(dpm_table->mem_table));
1913
1914         dpm_table->mem_table.dpm_state.soft_min_level =
1915                 dpm_table->mem_table.dpm_state.soft_max_level =
1916                 dpm_table->mem_table.dpm_levels[soft_level].value;
1917
1918         if (highest)
1919                 soft_level = vega20_find_highest_dpm_level(&(dpm_table->soc_table));
1920         else
1921                 soft_level = vega20_find_lowest_dpm_level(&(dpm_table->soc_table));
1922
1923         dpm_table->soc_table.dpm_state.soft_min_level =
1924                 dpm_table->soc_table.dpm_state.soft_max_level =
1925                 dpm_table->soc_table.dpm_levels[soft_level].value;
1926
1927         ret = vega20_upload_dpm_level(smu, false, 0xFFFFFFFF);
1928         if (ret) {
1929                 pr_err("Failed to upload boot level to %s!\n",
1930                                 highest ? "highest" : "lowest");
1931                 return ret;
1932         }
1933
1934         ret = vega20_upload_dpm_level(smu, true, 0xFFFFFFFF);
1935         if (ret) {
1936                 pr_err("Failed to upload dpm max level to %s!\n!",
1937                                 highest ? "highest" : "lowest");
1938                 return ret;
1939         }
1940
1941         return ret;
1942 }
1943
1944 static int vega20_unforce_dpm_levels(struct smu_context *smu)
1945 {
1946         uint32_t soft_min_level, soft_max_level;
1947         int ret = 0;
1948         struct vega20_dpm_table *dpm_table =
1949                 (struct vega20_dpm_table *)smu->smu_dpm.dpm_context;
1950
1951         soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table->gfx_table));
1952         soft_max_level = vega20_find_highest_dpm_level(&(dpm_table->gfx_table));
1953         dpm_table->gfx_table.dpm_state.soft_min_level =
1954                 dpm_table->gfx_table.dpm_levels[soft_min_level].value;
1955         dpm_table->gfx_table.dpm_state.soft_max_level =
1956                 dpm_table->gfx_table.dpm_levels[soft_max_level].value;
1957
1958         soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table->mem_table));
1959         soft_max_level = vega20_find_highest_dpm_level(&(dpm_table->mem_table));
1960         dpm_table->mem_table.dpm_state.soft_min_level =
1961                 dpm_table->gfx_table.dpm_levels[soft_min_level].value;
1962         dpm_table->mem_table.dpm_state.soft_max_level =
1963                 dpm_table->gfx_table.dpm_levels[soft_max_level].value;
1964
1965         soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table->soc_table));
1966         soft_max_level = vega20_find_highest_dpm_level(&(dpm_table->soc_table));
1967         dpm_table->soc_table.dpm_state.soft_min_level =
1968                 dpm_table->soc_table.dpm_levels[soft_min_level].value;
1969         dpm_table->soc_table.dpm_state.soft_max_level =
1970                 dpm_table->soc_table.dpm_levels[soft_max_level].value;
1971
1972         ret = smu_upload_dpm_level(smu, false, 0xFFFFFFFF);
1973         if (ret) {
1974                 pr_err("Failed to upload DPM Bootup Levels!");
1975                 return ret;
1976         }
1977
1978         ret = smu_upload_dpm_level(smu, true, 0xFFFFFFFF);
1979         if (ret) {
1980                 pr_err("Failed to upload DPM Max Levels!");
1981                 return ret;
1982         }
1983
1984         return ret;
1985 }
1986
1987 static enum amd_dpm_forced_level vega20_get_performance_level(struct smu_context *smu)
1988 {
1989         struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
1990         if (!smu_dpm_ctx->dpm_context)
1991                 return -EINVAL;
1992
1993         if (smu_dpm_ctx->dpm_level != smu_dpm_ctx->saved_dpm_level) {
1994                 mutex_lock(&(smu->mutex));
1995                 smu_dpm_ctx->saved_dpm_level = smu_dpm_ctx->dpm_level;
1996                 mutex_unlock(&(smu->mutex));
1997         }
1998         return smu_dpm_ctx->dpm_level;
1999 }
2000
2001 static int
2002 vega20_force_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level)
2003 {
2004         int ret = 0;
2005         int i;
2006         struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
2007
2008         if (!smu_dpm_ctx->dpm_context)
2009                 return -EINVAL;
2010
2011         for (i = 0; i < smu->adev->num_ip_blocks; i++) {
2012                 if (smu->adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC)
2013                         break;
2014         }
2015
2016         mutex_lock(&smu->mutex);
2017
2018         smu->adev->ip_blocks[i].version->funcs->enable_umd_pstate(smu, &level);
2019         ret = smu_handle_task(smu, level,
2020                               AMD_PP_TASK_READJUST_POWER_STATE);
2021
2022         mutex_unlock(&smu->mutex);
2023
2024         return ret;
2025 }
2026
2027 static int vega20_update_specified_od8_value(struct smu_context *smu,
2028                                              uint32_t index,
2029                                              uint32_t value)
2030 {
2031         struct smu_table_context *table_context = &smu->smu_table;
2032         OverDriveTable_t *od_table =
2033                 (OverDriveTable_t *)(table_context->overdrive_table);
2034         struct vega20_od8_settings *od8_settings =
2035                 (struct vega20_od8_settings *)table_context->od8_settings;
2036
2037         switch (index) {
2038         case OD8_SETTING_GFXCLK_FMIN:
2039                 od_table->GfxclkFmin = (uint16_t)value;
2040                 break;
2041
2042         case OD8_SETTING_GFXCLK_FMAX:
2043                 if (value < od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].min_value ||
2044                     value > od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value)
2045                         return -EINVAL;
2046                 od_table->GfxclkFmax = (uint16_t)value;
2047                 break;
2048
2049         case OD8_SETTING_GFXCLK_FREQ1:
2050                 od_table->GfxclkFreq1 = (uint16_t)value;
2051                 break;
2052
2053         case OD8_SETTING_GFXCLK_VOLTAGE1:
2054                 od_table->GfxclkVolt1 = (uint16_t)value;
2055                 break;
2056
2057         case OD8_SETTING_GFXCLK_FREQ2:
2058                 od_table->GfxclkFreq2 = (uint16_t)value;
2059                 break;
2060
2061         case OD8_SETTING_GFXCLK_VOLTAGE2:
2062                 od_table->GfxclkVolt2 = (uint16_t)value;
2063                 break;
2064
2065         case OD8_SETTING_GFXCLK_FREQ3:
2066                 od_table->GfxclkFreq3 = (uint16_t)value;
2067                 break;
2068
2069         case OD8_SETTING_GFXCLK_VOLTAGE3:
2070                 od_table->GfxclkVolt3 = (uint16_t)value;
2071                 break;
2072
2073         case OD8_SETTING_UCLK_FMAX:
2074                 if (value < od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].min_value ||
2075                     value > od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value)
2076                         return -EINVAL;
2077                 od_table->UclkFmax = (uint16_t)value;
2078                 break;
2079
2080         case OD8_SETTING_POWER_PERCENTAGE:
2081                 od_table->OverDrivePct = (int16_t)value;
2082                 break;
2083
2084         case OD8_SETTING_FAN_ACOUSTIC_LIMIT:
2085                 od_table->FanMaximumRpm = (uint16_t)value;
2086                 break;
2087
2088         case OD8_SETTING_FAN_MIN_SPEED:
2089                 od_table->FanMinimumPwm = (uint16_t)value;
2090                 break;
2091
2092         case OD8_SETTING_FAN_TARGET_TEMP:
2093                 od_table->FanTargetTemperature = (uint16_t)value;
2094                 break;
2095
2096         case OD8_SETTING_OPERATING_TEMP_MAX:
2097                 od_table->MaxOpTemp = (uint16_t)value;
2098                 break;
2099         }
2100
2101         return 0;
2102 }
2103
2104 static int vega20_set_od_percentage(struct smu_context *smu,
2105                                     enum pp_clock_type type,
2106                                     uint32_t value)
2107 {
2108         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
2109         struct vega20_dpm_table *dpm_table = NULL;
2110         struct vega20_dpm_table *golden_table = NULL;
2111         struct vega20_single_dpm_table *single_dpm_table;
2112         struct vega20_single_dpm_table *golden_dpm_table;
2113         uint32_t od_clk, index;
2114         int ret = 0;
2115         int feature_enabled;
2116         PPCLK_e clk_id;
2117
2118         mutex_lock(&(smu->mutex));
2119
2120         dpm_table = smu_dpm->dpm_context;
2121         golden_table = smu_dpm->golden_dpm_context;
2122
2123         switch (type) {
2124         case OD_SCLK:
2125                 single_dpm_table = &(dpm_table->gfx_table);
2126                 golden_dpm_table = &(golden_table->gfx_table);
2127                 feature_enabled = smu_feature_is_enabled(smu, FEATURE_DPM_GFXCLK_BIT);
2128                 clk_id = PPCLK_GFXCLK;
2129                 index = OD8_SETTING_GFXCLK_FMAX;
2130                 break;
2131         case OD_MCLK:
2132                 single_dpm_table = &(dpm_table->mem_table);
2133                 golden_dpm_table = &(golden_table->mem_table);
2134                 feature_enabled = smu_feature_is_enabled(smu, FEATURE_DPM_UCLK_BIT);
2135                 clk_id = PPCLK_UCLK;
2136                 index = OD8_SETTING_UCLK_FMAX;
2137                 break;
2138         default:
2139                 ret = -EINVAL;
2140                 break;
2141         }
2142
2143         if (ret)
2144                 goto set_od_failed;
2145
2146         od_clk = golden_dpm_table->dpm_levels[golden_dpm_table->count - 1].value * value;
2147         od_clk /= 100;
2148         od_clk += golden_dpm_table->dpm_levels[golden_dpm_table->count - 1].value;
2149
2150         ret = smu_update_od8_settings(smu, index, od_clk);
2151         if (ret) {
2152                 pr_err("[Setoverdrive] failed to set od clk!\n");
2153                 goto set_od_failed;
2154         }
2155
2156         if (feature_enabled) {
2157                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
2158                                                   clk_id);
2159                 if (ret) {
2160                         pr_err("[Setoverdrive] failed to refresh dpm table!\n");
2161                         goto set_od_failed;
2162                 }
2163         } else {
2164                 single_dpm_table->count = 1;
2165                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
2166         }
2167
2168         ret = smu_handle_task(smu, smu_dpm->dpm_level,
2169                               AMD_PP_TASK_READJUST_POWER_STATE);
2170
2171 set_od_failed:
2172         mutex_unlock(&(smu->mutex));
2173
2174         return ret;
2175 }
2176
2177 static int vega20_odn_edit_dpm_table(struct smu_context *smu,
2178                                      enum PP_OD_DPM_TABLE_COMMAND type,
2179                                      long *input, uint32_t size)
2180 {
2181         struct smu_table_context *table_context = &smu->smu_table;
2182         OverDriveTable_t *od_table =
2183                 (OverDriveTable_t *)(table_context->overdrive_table);
2184         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
2185         struct vega20_dpm_table *dpm_table = NULL;
2186         struct vega20_single_dpm_table *single_dpm_table;
2187         struct vega20_od8_settings *od8_settings =
2188                 (struct vega20_od8_settings *)table_context->od8_settings;
2189         struct pp_clock_levels_with_latency clocks;
2190         int32_t input_index, input_clk, input_vol, i;
2191         int od8_id;
2192         int ret = 0;
2193
2194         dpm_table = smu_dpm->dpm_context;
2195
2196         if (!input) {
2197                 pr_warn("NULL user input for clock and voltage\n");
2198                 return -EINVAL;
2199         }
2200
2201         switch (type) {
2202         case PP_OD_EDIT_SCLK_VDDC_TABLE:
2203                 if (!(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id &&
2204                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id)) {
2205                         pr_info("Sclk min/max frequency overdrive not supported\n");
2206                         return -EOPNOTSUPP;
2207                 }
2208
2209                 for (i = 0; i < size; i += 2) {
2210                         if (i + 2 > size) {
2211                                 pr_info("invalid number of input parameters %d\n", size);
2212                                 return -EINVAL;
2213                         }
2214
2215                         input_index = input[i];
2216                         input_clk = input[i + 1];
2217
2218                         if (input_index != 0 && input_index != 1) {
2219                                 pr_info("Invalid index %d\n", input_index);
2220                                 pr_info("Support min/max sclk frequency settingonly which index by 0/1\n");
2221                                 return -EINVAL;
2222                         }
2223
2224                         if (input_clk < od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value ||
2225                             input_clk > od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value) {
2226                                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2227                                         input_clk,
2228                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value,
2229                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value);
2230                                 return -EINVAL;
2231                         }
2232
2233                         if (input_index == 0 && od_table->GfxclkFmin != input_clk) {
2234                                 od_table->GfxclkFmin = input_clk;
2235                                 table_context->od_gfxclk_update = true;
2236                         } else if (input_index == 1 && od_table->GfxclkFmax != input_clk) {
2237                                 od_table->GfxclkFmax = input_clk;
2238                                 table_context->od_gfxclk_update = true;
2239                         }
2240                 }
2241
2242                 break;
2243
2244         case PP_OD_EDIT_MCLK_VDDC_TABLE:
2245                 if (!od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) {
2246                         pr_info("Mclk max frequency overdrive not supported\n");
2247                         return -EOPNOTSUPP;
2248                 }
2249
2250                 single_dpm_table = &(dpm_table->mem_table);
2251                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
2252                 if (ret) {
2253                         pr_err("Attempt to get memory clk levels Failed!");
2254                         return ret;
2255                 }
2256
2257                 for (i = 0; i < size; i += 2) {
2258                         if (i + 2 > size) {
2259                                 pr_info("invalid number of input parameters %d\n",
2260                                          size);
2261                                 return -EINVAL;
2262                         }
2263
2264                         input_index = input[i];
2265                         input_clk = input[i + 1];
2266
2267                         if (input_index != 1) {
2268                                 pr_info("Invalid index %d\n", input_index);
2269                                 pr_info("Support max Mclk frequency setting only which index by 1\n");
2270                                 return -EINVAL;
2271                         }
2272
2273                         if (input_clk < clocks.data[0].clocks_in_khz / 1000 ||
2274                             input_clk > od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value) {
2275                                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2276                                         input_clk,
2277                                         clocks.data[0].clocks_in_khz / 1000,
2278                                         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value);
2279                                 return -EINVAL;
2280                         }
2281
2282                         if (input_index == 1 && od_table->UclkFmax != input_clk) {
2283                                 table_context->od_gfxclk_update = true;
2284                                 od_table->UclkFmax = input_clk;
2285                         }
2286                 }
2287
2288                 break;
2289
2290         case PP_OD_EDIT_VDDC_CURVE:
2291                 if (!(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
2292                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
2293                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
2294                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
2295                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
2296                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id)) {
2297                         pr_info("Voltage curve calibrate not supported\n");
2298                         return -EOPNOTSUPP;
2299                 }
2300
2301                 for (i = 0; i < size; i += 3) {
2302                         if (i + 3 > size) {
2303                                 pr_info("invalid number of input parameters %d\n",
2304                                         size);
2305                                 return -EINVAL;
2306                         }
2307
2308                         input_index = input[i];
2309                         input_clk = input[i + 1];
2310                         input_vol = input[i + 2];
2311
2312                         if (input_index > 2) {
2313                                 pr_info("Setting for point %d is not supported\n",
2314                                         input_index + 1);
2315                                 pr_info("Three supported points index by 0, 1, 2\n");
2316                                 return -EINVAL;
2317                         }
2318
2319                         od8_id = OD8_SETTING_GFXCLK_FREQ1 + 2 * input_index;
2320                         if (input_clk < od8_settings->od8_settings_array[od8_id].min_value ||
2321                             input_clk > od8_settings->od8_settings_array[od8_id].max_value) {
2322                                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2323                                         input_clk,
2324                                         od8_settings->od8_settings_array[od8_id].min_value,
2325                                         od8_settings->od8_settings_array[od8_id].max_value);
2326                                 return -EINVAL;
2327                         }
2328
2329                         od8_id = OD8_SETTING_GFXCLK_VOLTAGE1 + 2 * input_index;
2330                         if (input_vol < od8_settings->od8_settings_array[od8_id].min_value ||
2331                             input_vol > od8_settings->od8_settings_array[od8_id].max_value) {
2332                                 pr_info("clock voltage %d is not within allowed range [%d- %d]\n",
2333                                         input_vol,
2334                                         od8_settings->od8_settings_array[od8_id].min_value,
2335                                         od8_settings->od8_settings_array[od8_id].max_value);
2336                                 return -EINVAL;
2337                         }
2338
2339                         switch (input_index) {
2340                         case 0:
2341                                 od_table->GfxclkFreq1 = input_clk;
2342                                 od_table->GfxclkVolt1 = input_vol * VOLTAGE_SCALE;
2343                                 break;
2344                         case 1:
2345                                 od_table->GfxclkFreq2 = input_clk;
2346                                 od_table->GfxclkVolt2 = input_vol * VOLTAGE_SCALE;
2347                                 break;
2348                         case 2:
2349                                 od_table->GfxclkFreq3 = input_clk;
2350                                 od_table->GfxclkVolt3 = input_vol * VOLTAGE_SCALE;
2351                                 break;
2352                         }
2353                 }
2354
2355                 break;
2356
2357         case PP_OD_RESTORE_DEFAULT_TABLE:
2358                 ret = smu_update_table(smu, TABLE_OVERDRIVE, table_context->overdrive_table, false);
2359                 if (ret) {
2360                         pr_err("Failed to export over drive table!\n");
2361                         return ret;
2362                 }
2363
2364                 break;
2365
2366         case PP_OD_COMMIT_DPM_TABLE:
2367                 ret = smu_update_table(smu, TABLE_OVERDRIVE, table_context->overdrive_table, true);
2368                 if (ret) {
2369                         pr_err("Failed to import over drive table!\n");
2370                         return ret;
2371                 }
2372
2373                 /* retrieve updated gfxclk table */
2374                 if (table_context->od_gfxclk_update) {
2375                         table_context->od_gfxclk_update = false;
2376                         single_dpm_table = &(dpm_table->gfx_table);
2377
2378                         if (smu_feature_is_enabled(smu, FEATURE_DPM_GFXCLK_BIT)) {
2379                                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
2380                                                                   PPCLK_GFXCLK);
2381                                 if (ret) {
2382                                         pr_err("[Setoverdrive] failed to refresh dpm table!\n");
2383                                         return ret;
2384                                 }
2385                         } else {
2386                                 single_dpm_table->count = 1;
2387                                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
2388                         }
2389                 }
2390
2391                 break;
2392
2393         default:
2394                 return -EINVAL;
2395         }
2396
2397         if (type == PP_OD_COMMIT_DPM_TABLE) {
2398                 mutex_lock(&(smu->mutex));
2399                 ret = smu_handle_task(smu, smu_dpm->dpm_level,
2400                                       AMD_PP_TASK_READJUST_POWER_STATE);
2401                 mutex_unlock(&(smu->mutex));
2402         }
2403
2404         return ret;
2405 }
2406
2407 static int vega20_get_enabled_smc_features(struct smu_context *smu,
2408                 uint64_t *features_enabled)
2409 {
2410         uint32_t feature_mask[2] = {0, 0};
2411         int ret = 0;
2412
2413         ret = smu_feature_get_enabled_mask(smu, feature_mask, 2);
2414         if (ret)
2415                 return ret;
2416
2417         *features_enabled = ((((uint64_t)feature_mask[0] << SMU_FEATURES_LOW_SHIFT) & SMU_FEATURES_LOW_MASK) |
2418                         (((uint64_t)feature_mask[1] << SMU_FEATURES_HIGH_SHIFT) & SMU_FEATURES_HIGH_MASK));
2419
2420         return ret;
2421 }
2422
2423 static int vega20_enable_smc_features(struct smu_context *smu,
2424                 bool enable, uint64_t feature_mask)
2425 {
2426         uint32_t smu_features_low, smu_features_high;
2427         int ret = 0;
2428
2429         smu_features_low = (uint32_t)((feature_mask & SMU_FEATURES_LOW_MASK) >> SMU_FEATURES_LOW_SHIFT);
2430         smu_features_high = (uint32_t)((feature_mask & SMU_FEATURES_HIGH_MASK) >> SMU_FEATURES_HIGH_SHIFT);
2431
2432         if (enable) {
2433                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesLow,
2434                                                   smu_features_low);
2435                 if (ret)
2436                         return ret;
2437                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesHigh,
2438                                                   smu_features_high);
2439                 if (ret)
2440                         return ret;
2441         } else {
2442                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesLow,
2443                                                   smu_features_low);
2444                 if (ret)
2445                         return ret;
2446                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesHigh,
2447                                                   smu_features_high);
2448                 if (ret)
2449                         return ret;
2450         }
2451
2452         return 0;
2453
2454 }
2455
2456 static int vega20_get_ppfeature_status(struct smu_context *smu, char *buf)
2457 {
2458         static const char *ppfeature_name[] = {
2459                                 "DPM_PREFETCHER",
2460                                 "GFXCLK_DPM",
2461                                 "UCLK_DPM",
2462                                 "SOCCLK_DPM",
2463                                 "UVD_DPM",
2464                                 "VCE_DPM",
2465                                 "ULV",
2466                                 "MP0CLK_DPM",
2467                                 "LINK_DPM",
2468                                 "DCEFCLK_DPM",
2469                                 "GFXCLK_DS",
2470                                 "SOCCLK_DS",
2471                                 "LCLK_DS",
2472                                 "PPT",
2473                                 "TDC",
2474                                 "THERMAL",
2475                                 "GFX_PER_CU_CG",
2476                                 "RM",
2477                                 "DCEFCLK_DS",
2478                                 "ACDC",
2479                                 "VR0HOT",
2480                                 "VR1HOT",
2481                                 "FW_CTF",
2482                                 "LED_DISPLAY",
2483                                 "FAN_CONTROL",
2484                                 "GFX_EDC",
2485                                 "GFXOFF",
2486                                 "CG",
2487                                 "FCLK_DPM",
2488                                 "FCLK_DS",
2489                                 "MP1CLK_DS",
2490                                 "MP0CLK_DS",
2491                                 "XGMI",
2492                                 "ECC"};
2493         static const char *output_title[] = {
2494                                 "FEATURES",
2495                                 "BITMASK",
2496                                 "ENABLEMENT"};
2497         uint64_t features_enabled;
2498         int i;
2499         int ret = 0;
2500         int size = 0;
2501
2502         ret = vega20_get_enabled_smc_features(smu, &features_enabled);
2503         if (ret)
2504                 return ret;
2505
2506         size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", features_enabled);
2507         size += sprintf(buf + size, "%-19s %-22s %s\n",
2508                                 output_title[0],
2509                                 output_title[1],
2510                                 output_title[2]);
2511         for (i = 0; i < GNLD_FEATURES_MAX; i++) {
2512                 size += sprintf(buf + size, "%-19s 0x%016llx %6s\n",
2513                                         ppfeature_name[i],
2514                                         1ULL << i,
2515                                         (features_enabled & (1ULL << i)) ? "Y" : "N");
2516         }
2517
2518         return size;
2519 }
2520
2521 static int vega20_set_ppfeature_status(struct smu_context *smu, uint64_t new_ppfeature_masks)
2522 {
2523         uint64_t features_enabled;
2524         uint64_t features_to_enable;
2525         uint64_t features_to_disable;
2526         int ret = 0;
2527
2528         if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX))
2529                 return -EINVAL;
2530
2531         ret = vega20_get_enabled_smc_features(smu, &features_enabled);
2532         if (ret)
2533                 return ret;
2534
2535         features_to_disable =
2536                 features_enabled & ~new_ppfeature_masks;
2537         features_to_enable =
2538                 ~features_enabled & new_ppfeature_masks;
2539
2540         pr_debug("features_to_disable 0x%llx\n", features_to_disable);
2541         pr_debug("features_to_enable 0x%llx\n", features_to_enable);
2542
2543         if (features_to_disable) {
2544                 ret = vega20_enable_smc_features(smu, false, features_to_disable);
2545                 if (ret)
2546                         return ret;
2547         }
2548
2549         if (features_to_enable) {
2550                 ret = vega20_enable_smc_features(smu, true, features_to_enable);
2551                 if (ret)
2552                         return ret;
2553         }
2554
2555         return 0;
2556 }
2557
2558 static const struct pptable_funcs vega20_ppt_funcs = {
2559         .alloc_dpm_context = vega20_allocate_dpm_context,
2560         .store_powerplay_table = vega20_store_powerplay_table,
2561         .check_powerplay_table = vega20_check_powerplay_table,
2562         .append_powerplay_table = vega20_append_powerplay_table,
2563         .get_smu_msg_index = vega20_get_smu_msg_index,
2564         .run_afll_btc = vega20_run_btc_afll,
2565         .get_unallowed_feature_mask = vega20_get_unallowed_feature_mask,
2566         .get_current_power_state = vega20_get_current_power_state,
2567         .set_default_dpm_table = vega20_set_default_dpm_table,
2568         .set_power_state = NULL,
2569         .populate_umd_state_clk = vega20_populate_umd_state_clk,
2570         .print_clk_levels = vega20_print_clk_levels,
2571         .force_clk_levels = vega20_force_clk_levels,
2572         .get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency,
2573         .set_default_od8_settings = vega20_set_default_od8_setttings,
2574         .get_od_percentage = vega20_get_od_percentage,
2575         .conv_profile_to_workload = vega20_conv_profile_to_workload,
2576         .get_performance_level = vega20_get_performance_level,
2577         .force_performance_level = vega20_force_performance_level,
2578         .update_specified_od8_value = vega20_update_specified_od8_value,
2579         .set_od_percentage = vega20_set_od_percentage,
2580         .od_edit_dpm_table = vega20_odn_edit_dpm_table,
2581         .pre_display_config_changed = vega20_pre_display_config_changed,
2582         .display_config_changed = vega20_display_config_changed,
2583         .apply_clocks_adjust_rules = vega20_apply_clocks_adjust_rules,
2584         .notify_smc_dispaly_config = vega20_notify_smc_dispaly_config,
2585         .force_dpm_limit_value = vega20_force_dpm_limit_value,
2586         .unforce_dpm_levels = vega20_unforce_dpm_levels,
2587         .upload_dpm_level = vega20_upload_dpm_level,
2588         .get_profiling_clk_mask = vega20_get_profiling_clk_mask,
2589         .set_ppfeature_status = vega20_set_ppfeature_status,
2590         .get_ppfeature_status = vega20_get_ppfeature_status,
2591 };
2592
2593 void vega20_set_ppt_funcs(struct smu_context *smu)
2594 {
2595         smu->ppt_funcs = &vega20_ppt_funcs;
2596         smu->smc_if_version = SMU11_DRIVER_IF_VERSION;
2597 }