]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/amd/powerplay/vega20_ppt.c
drm/amd/powerplay: move power_dpm_force_performance_level to amdgpu_smu 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 #define SMC_DPM_FEATURE (FEATURE_DPM_PREFETCHER_MASK | \
47                          FEATURE_DPM_GFXCLK_MASK | \
48                          FEATURE_DPM_UCLK_MASK | \
49                          FEATURE_DPM_SOCCLK_MASK | \
50                          FEATURE_DPM_UVD_MASK | \
51                          FEATURE_DPM_VCE_MASK | \
52                          FEATURE_DPM_MP0CLK_MASK | \
53                          FEATURE_DPM_LINK_MASK | \
54                          FEATURE_DPM_DCEFCLK_MASK)
55
56 static int vega20_message_map[SMU_MSG_MAX_COUNT] = {
57         MSG_MAP(TestMessage),
58         MSG_MAP(GetSmuVersion),
59         MSG_MAP(GetDriverIfVersion),
60         MSG_MAP(SetAllowedFeaturesMaskLow),
61         MSG_MAP(SetAllowedFeaturesMaskHigh),
62         MSG_MAP(EnableAllSmuFeatures),
63         MSG_MAP(DisableAllSmuFeatures),
64         MSG_MAP(EnableSmuFeaturesLow),
65         MSG_MAP(EnableSmuFeaturesHigh),
66         MSG_MAP(DisableSmuFeaturesLow),
67         MSG_MAP(DisableSmuFeaturesHigh),
68         MSG_MAP(GetEnabledSmuFeaturesLow),
69         MSG_MAP(GetEnabledSmuFeaturesHigh),
70         MSG_MAP(SetWorkloadMask),
71         MSG_MAP(SetPptLimit),
72         MSG_MAP(SetDriverDramAddrHigh),
73         MSG_MAP(SetDriverDramAddrLow),
74         MSG_MAP(SetToolsDramAddrHigh),
75         MSG_MAP(SetToolsDramAddrLow),
76         MSG_MAP(TransferTableSmu2Dram),
77         MSG_MAP(TransferTableDram2Smu),
78         MSG_MAP(UseDefaultPPTable),
79         MSG_MAP(UseBackupPPTable),
80         MSG_MAP(RunBtc),
81         MSG_MAP(RequestI2CBus),
82         MSG_MAP(ReleaseI2CBus),
83         MSG_MAP(SetFloorSocVoltage),
84         MSG_MAP(SoftReset),
85         MSG_MAP(StartBacoMonitor),
86         MSG_MAP(CancelBacoMonitor),
87         MSG_MAP(EnterBaco),
88         MSG_MAP(SetSoftMinByFreq),
89         MSG_MAP(SetSoftMaxByFreq),
90         MSG_MAP(SetHardMinByFreq),
91         MSG_MAP(SetHardMaxByFreq),
92         MSG_MAP(GetMinDpmFreq),
93         MSG_MAP(GetMaxDpmFreq),
94         MSG_MAP(GetDpmFreqByIndex),
95         MSG_MAP(GetDpmClockFreq),
96         MSG_MAP(GetSsVoltageByDpm),
97         MSG_MAP(SetMemoryChannelConfig),
98         MSG_MAP(SetGeminiMode),
99         MSG_MAP(SetGeminiApertureHigh),
100         MSG_MAP(SetGeminiApertureLow),
101         MSG_MAP(SetMinLinkDpmByIndex),
102         MSG_MAP(OverridePcieParameters),
103         MSG_MAP(OverDriveSetPercentage),
104         MSG_MAP(SetMinDeepSleepDcefclk),
105         MSG_MAP(ReenableAcDcInterrupt),
106         MSG_MAP(NotifyPowerSource),
107         MSG_MAP(SetUclkFastSwitch),
108         MSG_MAP(SetUclkDownHyst),
109         MSG_MAP(GetCurrentRpm),
110         MSG_MAP(SetVideoFps),
111         MSG_MAP(SetTjMax),
112         MSG_MAP(SetFanTemperatureTarget),
113         MSG_MAP(PrepareMp1ForUnload),
114         MSG_MAP(DramLogSetDramAddrHigh),
115         MSG_MAP(DramLogSetDramAddrLow),
116         MSG_MAP(DramLogSetDramSize),
117         MSG_MAP(SetFanMaxRpm),
118         MSG_MAP(SetFanMinPwm),
119         MSG_MAP(ConfigureGfxDidt),
120         MSG_MAP(NumOfDisplays),
121         MSG_MAP(RemoveMargins),
122         MSG_MAP(ReadSerialNumTop32),
123         MSG_MAP(ReadSerialNumBottom32),
124         MSG_MAP(SetSystemVirtualDramAddrHigh),
125         MSG_MAP(SetSystemVirtualDramAddrLow),
126         MSG_MAP(WaflTest),
127         MSG_MAP(SetFclkGfxClkRatio),
128         MSG_MAP(AllowGfxOff),
129         MSG_MAP(DisallowGfxOff),
130         MSG_MAP(GetPptLimit),
131         MSG_MAP(GetDcModeMaxDpmFreq),
132         MSG_MAP(GetDebugData),
133         MSG_MAP(SetXgmiMode),
134         MSG_MAP(RunAfllBtc),
135         MSG_MAP(ExitBaco),
136         MSG_MAP(PrepareMp1ForReset),
137         MSG_MAP(PrepareMp1ForShutdown),
138         MSG_MAP(SetMGpuFanBoostLimitRpm),
139         MSG_MAP(GetAVFSVoltageByDpm),
140 };
141
142 static int vega20_clk_map[SMU_CLK_COUNT] = {
143         CLK_MAP(GFXCLK, PPCLK_GFXCLK),
144         CLK_MAP(VCLK, PPCLK_VCLK),
145         CLK_MAP(DCLK, PPCLK_DCLK),
146         CLK_MAP(ECLK, PPCLK_ECLK),
147         CLK_MAP(SOCCLK, PPCLK_SOCCLK),
148         CLK_MAP(UCLK, PPCLK_UCLK),
149         CLK_MAP(DCEFCLK, PPCLK_DCEFCLK),
150         CLK_MAP(DISPCLK, PPCLK_DISPCLK),
151         CLK_MAP(PIXCLK, PPCLK_PIXCLK),
152         CLK_MAP(PHYCLK, PPCLK_PHYCLK),
153         CLK_MAP(FCLK, PPCLK_FCLK),
154 };
155
156 static int vega20_feature_mask_map[SMU_FEATURE_COUNT] = {
157         FEA_MAP(DPM_PREFETCHER),
158         FEA_MAP(DPM_GFXCLK),
159         FEA_MAP(DPM_UCLK),
160         FEA_MAP(DPM_SOCCLK),
161         FEA_MAP(DPM_UVD),
162         FEA_MAP(DPM_VCE),
163         FEA_MAP(ULV),
164         FEA_MAP(DPM_MP0CLK),
165         FEA_MAP(DPM_LINK),
166         FEA_MAP(DPM_DCEFCLK),
167         FEA_MAP(DS_GFXCLK),
168         FEA_MAP(DS_SOCCLK),
169         FEA_MAP(DS_LCLK),
170         FEA_MAP(PPT),
171         FEA_MAP(TDC),
172         FEA_MAP(THERMAL),
173         FEA_MAP(GFX_PER_CU_CG),
174         FEA_MAP(RM),
175         FEA_MAP(DS_DCEFCLK),
176         FEA_MAP(ACDC),
177         FEA_MAP(VR0HOT),
178         FEA_MAP(VR1HOT),
179         FEA_MAP(FW_CTF),
180         FEA_MAP(LED_DISPLAY),
181         FEA_MAP(FAN_CONTROL),
182         FEA_MAP(GFX_EDC),
183         FEA_MAP(GFXOFF),
184         FEA_MAP(CG),
185         FEA_MAP(DPM_FCLK),
186         FEA_MAP(DS_FCLK),
187         FEA_MAP(DS_MP1CLK),
188         FEA_MAP(DS_MP0CLK),
189         FEA_MAP(XGMI),
190 };
191
192 static int vega20_table_map[SMU_TABLE_COUNT] = {
193         TAB_MAP(PPTABLE),
194         TAB_MAP(WATERMARKS),
195         TAB_MAP(AVFS),
196         TAB_MAP(AVFS_PSM_DEBUG),
197         TAB_MAP(AVFS_FUSE_OVERRIDE),
198         TAB_MAP(PMSTATUSLOG),
199         TAB_MAP(SMU_METRICS),
200         TAB_MAP(DRIVER_SMU_CONFIG),
201         TAB_MAP(ACTIVITY_MONITOR_COEFF),
202         TAB_MAP(OVERDRIVE),
203 };
204
205 static int vega20_pwr_src_map[SMU_POWER_SOURCE_COUNT] = {
206         PWR_MAP(AC),
207         PWR_MAP(DC),
208 };
209
210 static int vega20_workload_map[] = {
211         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT,       WORKLOAD_DEFAULT_BIT),
212         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D,         WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT),
213         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING,          WORKLOAD_PPLIB_POWER_SAVING_BIT),
214         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO,                WORKLOAD_PPLIB_VIDEO_BIT),
215         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR,                   WORKLOAD_PPLIB_VR_BIT),
216         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE,              WORKLOAD_PPLIB_CUSTOM_BIT),
217         WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM,               WORKLOAD_PPLIB_CUSTOM_BIT),
218 };
219
220 static int vega20_get_smu_table_index(struct smu_context *smc, uint32_t index)
221 {
222         int val;
223         if (index >= SMU_TABLE_COUNT)
224                 return -EINVAL;
225
226         val = vega20_table_map[index];
227         if (val >= TABLE_COUNT)
228                 return -EINVAL;
229
230         return val;
231 }
232
233 static int vega20_get_pwr_src_index(struct smu_context *smc, uint32_t index)
234 {
235         int val;
236         if (index >= SMU_POWER_SOURCE_COUNT)
237                 return -EINVAL;
238
239         val = vega20_pwr_src_map[index];
240         if (val >= POWER_SOURCE_COUNT)
241                 return -EINVAL;
242
243         return val;
244 }
245
246 static int vega20_get_smu_feature_index(struct smu_context *smc, uint32_t index)
247 {
248         int val;
249         if (index >= SMU_FEATURE_COUNT)
250                 return -EINVAL;
251
252         val = vega20_feature_mask_map[index];
253         if (val > 64)
254                 return -EINVAL;
255
256         return val;
257 }
258
259 static int vega20_get_smu_clk_index(struct smu_context *smc, uint32_t index)
260 {
261         int val;
262         if (index >= SMU_CLK_COUNT)
263                 return -EINVAL;
264
265         val = vega20_clk_map[index];
266         if (val >= PPCLK_COUNT)
267                 return -EINVAL;
268
269         return val;
270 }
271
272 static int vega20_get_smu_msg_index(struct smu_context *smc, uint32_t index)
273 {
274         int val;
275
276         if (index >= SMU_MSG_MAX_COUNT)
277                 return -EINVAL;
278
279         val = vega20_message_map[index];
280         if (val > PPSMC_Message_Count)
281                 return -EINVAL;
282
283         return val;
284 }
285
286 static int vega20_get_workload_type(struct smu_context *smu, enum PP_SMC_POWER_PROFILE profile)
287 {
288         int val;
289         if (profile > PP_SMC_POWER_PROFILE_CUSTOM)
290                 return -EINVAL;
291
292         val = vega20_workload_map[profile];
293
294         return val;
295 }
296
297 static void vega20_tables_init(struct smu_context *smu, struct smu_table *tables)
298 {
299         SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t),
300                        PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
301         SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
302                        PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
303         SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
304                        PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
305         SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t),
306                        PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
307         SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE,
308                        PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
309         SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF,
310                        sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE,
311                        AMDGPU_GEM_DOMAIN_VRAM);
312 }
313
314 static int vega20_allocate_dpm_context(struct smu_context *smu)
315 {
316         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
317
318         if (smu_dpm->dpm_context)
319                 return -EINVAL;
320
321         smu_dpm->dpm_context = kzalloc(sizeof(struct vega20_dpm_table),
322                                        GFP_KERNEL);
323         if (!smu_dpm->dpm_context)
324                 return -ENOMEM;
325
326         if (smu_dpm->golden_dpm_context)
327                 return -EINVAL;
328
329         smu_dpm->golden_dpm_context = kzalloc(sizeof(struct vega20_dpm_table),
330                                               GFP_KERNEL);
331         if (!smu_dpm->golden_dpm_context)
332                 return -ENOMEM;
333
334         smu_dpm->dpm_context_size = sizeof(struct vega20_dpm_table);
335
336         smu_dpm->dpm_current_power_state = kzalloc(sizeof(struct smu_power_state),
337                                        GFP_KERNEL);
338         if (!smu_dpm->dpm_current_power_state)
339                 return -ENOMEM;
340
341         smu_dpm->dpm_request_power_state = kzalloc(sizeof(struct smu_power_state),
342                                        GFP_KERNEL);
343         if (!smu_dpm->dpm_request_power_state)
344                 return -ENOMEM;
345
346         return 0;
347 }
348
349 static int vega20_setup_od8_information(struct smu_context *smu)
350 {
351         ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL;
352         struct smu_table_context *table_context = &smu->smu_table;
353
354         uint32_t od_feature_count, od_feature_array_size,
355                  od_setting_count, od_setting_array_size;
356
357         if (!table_context->power_play_table)
358                 return -EINVAL;
359
360         powerplay_table = table_context->power_play_table;
361
362         if (powerplay_table->OverDrive8Table.ucODTableRevision == 1) {
363                 /* Setup correct ODFeatureCount, and store ODFeatureArray from
364                  * powerplay table to od_feature_capabilities */
365                 od_feature_count =
366                         (le32_to_cpu(powerplay_table->OverDrive8Table.ODFeatureCount) >
367                          ATOM_VEGA20_ODFEATURE_COUNT) ?
368                         ATOM_VEGA20_ODFEATURE_COUNT :
369                         le32_to_cpu(powerplay_table->OverDrive8Table.ODFeatureCount);
370
371                 od_feature_array_size = sizeof(uint8_t) * od_feature_count;
372
373                 if (table_context->od_feature_capabilities)
374                         return -EINVAL;
375
376                 table_context->od_feature_capabilities = kmemdup(&powerplay_table->OverDrive8Table.ODFeatureCapabilities,
377                                                                  od_feature_array_size,
378                                                                  GFP_KERNEL);
379                 if (!table_context->od_feature_capabilities)
380                         return -ENOMEM;
381
382                 /* Setup correct ODSettingCount, and store ODSettingArray from
383                  * powerplay table to od_settings_max and od_setting_min */
384                 od_setting_count =
385                         (le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingCount) >
386                          ATOM_VEGA20_ODSETTING_COUNT) ?
387                         ATOM_VEGA20_ODSETTING_COUNT :
388                         le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingCount);
389
390                 od_setting_array_size = sizeof(uint32_t) * od_setting_count;
391
392                 if (table_context->od_settings_max)
393                         return -EINVAL;
394
395                 table_context->od_settings_max = kmemdup(&powerplay_table->OverDrive8Table.ODSettingsMax,
396                                                          od_setting_array_size,
397                                                          GFP_KERNEL);
398
399                 if (!table_context->od_settings_max) {
400                         kfree(table_context->od_feature_capabilities);
401                         table_context->od_feature_capabilities = NULL;
402                         return -ENOMEM;
403                 }
404
405                 if (table_context->od_settings_min)
406                         return -EINVAL;
407
408                 table_context->od_settings_min = kmemdup(&powerplay_table->OverDrive8Table.ODSettingsMin,
409                                                          od_setting_array_size,
410                                                          GFP_KERNEL);
411
412                 if (!table_context->od_settings_min) {
413                         kfree(table_context->od_feature_capabilities);
414                         table_context->od_feature_capabilities = NULL;
415                         kfree(table_context->od_settings_max);
416                         table_context->od_settings_max = NULL;
417                         return -ENOMEM;
418                 }
419         }
420
421         return 0;
422 }
423
424 static int vega20_store_powerplay_table(struct smu_context *smu)
425 {
426         ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL;
427         struct smu_table_context *table_context = &smu->smu_table;
428         int ret;
429
430         if (!table_context->power_play_table)
431                 return -EINVAL;
432
433         powerplay_table = table_context->power_play_table;
434
435         memcpy(table_context->driver_pptable, &powerplay_table->smcPPTable,
436                sizeof(PPTable_t));
437
438         table_context->software_shutdown_temp = powerplay_table->usSoftwareShutdownTemp;
439         table_context->thermal_controller_type = powerplay_table->ucThermalControllerType;
440         table_context->TDPODLimit = le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingsMax[ATOM_VEGA20_ODSETTING_POWERPERCENTAGE]);
441
442         ret = vega20_setup_od8_information(smu);
443
444         return ret;
445 }
446
447 static int vega20_append_powerplay_table(struct smu_context *smu)
448 {
449         struct smu_table_context *table_context = &smu->smu_table;
450         PPTable_t *smc_pptable = table_context->driver_pptable;
451         struct atom_smc_dpm_info_v4_4 *smc_dpm_table;
452         int index, i, ret;
453
454         index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
455                                            smc_dpm_info);
456
457         ret = smu_get_atom_data_table(smu, index, NULL, NULL, NULL,
458                                       (uint8_t **)&smc_dpm_table);
459         if (ret)
460                 return ret;
461
462         smc_pptable->MaxVoltageStepGfx = smc_dpm_table->maxvoltagestepgfx;
463         smc_pptable->MaxVoltageStepSoc = smc_dpm_table->maxvoltagestepsoc;
464
465         smc_pptable->VddGfxVrMapping = smc_dpm_table->vddgfxvrmapping;
466         smc_pptable->VddSocVrMapping = smc_dpm_table->vddsocvrmapping;
467         smc_pptable->VddMem0VrMapping = smc_dpm_table->vddmem0vrmapping;
468         smc_pptable->VddMem1VrMapping = smc_dpm_table->vddmem1vrmapping;
469
470         smc_pptable->GfxUlvPhaseSheddingMask = smc_dpm_table->gfxulvphasesheddingmask;
471         smc_pptable->SocUlvPhaseSheddingMask = smc_dpm_table->soculvphasesheddingmask;
472         smc_pptable->ExternalSensorPresent = smc_dpm_table->externalsensorpresent;
473
474         smc_pptable->GfxMaxCurrent = smc_dpm_table->gfxmaxcurrent;
475         smc_pptable->GfxOffset = smc_dpm_table->gfxoffset;
476         smc_pptable->Padding_TelemetryGfx = smc_dpm_table->padding_telemetrygfx;
477
478         smc_pptable->SocMaxCurrent = smc_dpm_table->socmaxcurrent;
479         smc_pptable->SocOffset = smc_dpm_table->socoffset;
480         smc_pptable->Padding_TelemetrySoc = smc_dpm_table->padding_telemetrysoc;
481
482         smc_pptable->Mem0MaxCurrent = smc_dpm_table->mem0maxcurrent;
483         smc_pptable->Mem0Offset = smc_dpm_table->mem0offset;
484         smc_pptable->Padding_TelemetryMem0 = smc_dpm_table->padding_telemetrymem0;
485
486         smc_pptable->Mem1MaxCurrent = smc_dpm_table->mem1maxcurrent;
487         smc_pptable->Mem1Offset = smc_dpm_table->mem1offset;
488         smc_pptable->Padding_TelemetryMem1 = smc_dpm_table->padding_telemetrymem1;
489
490         smc_pptable->AcDcGpio = smc_dpm_table->acdcgpio;
491         smc_pptable->AcDcPolarity = smc_dpm_table->acdcpolarity;
492         smc_pptable->VR0HotGpio = smc_dpm_table->vr0hotgpio;
493         smc_pptable->VR0HotPolarity = smc_dpm_table->vr0hotpolarity;
494
495         smc_pptable->VR1HotGpio = smc_dpm_table->vr1hotgpio;
496         smc_pptable->VR1HotPolarity = smc_dpm_table->vr1hotpolarity;
497         smc_pptable->Padding1 = smc_dpm_table->padding1;
498         smc_pptable->Padding2 = smc_dpm_table->padding2;
499
500         smc_pptable->LedPin0 = smc_dpm_table->ledpin0;
501         smc_pptable->LedPin1 = smc_dpm_table->ledpin1;
502         smc_pptable->LedPin2 = smc_dpm_table->ledpin2;
503
504         smc_pptable->PllGfxclkSpreadEnabled = smc_dpm_table->pllgfxclkspreadenabled;
505         smc_pptable->PllGfxclkSpreadPercent = smc_dpm_table->pllgfxclkspreadpercent;
506         smc_pptable->PllGfxclkSpreadFreq = smc_dpm_table->pllgfxclkspreadfreq;
507
508         smc_pptable->UclkSpreadEnabled = 0;
509         smc_pptable->UclkSpreadPercent = smc_dpm_table->uclkspreadpercent;
510         smc_pptable->UclkSpreadFreq = smc_dpm_table->uclkspreadfreq;
511
512         smc_pptable->FclkSpreadEnabled = smc_dpm_table->fclkspreadenabled;
513         smc_pptable->FclkSpreadPercent = smc_dpm_table->fclkspreadpercent;
514         smc_pptable->FclkSpreadFreq = smc_dpm_table->fclkspreadfreq;
515
516         smc_pptable->FllGfxclkSpreadEnabled = smc_dpm_table->fllgfxclkspreadenabled;
517         smc_pptable->FllGfxclkSpreadPercent = smc_dpm_table->fllgfxclkspreadpercent;
518         smc_pptable->FllGfxclkSpreadFreq = smc_dpm_table->fllgfxclkspreadfreq;
519
520         for (i = 0; i < I2C_CONTROLLER_NAME_COUNT; i++) {
521                 smc_pptable->I2cControllers[i].Enabled =
522                         smc_dpm_table->i2ccontrollers[i].enabled;
523                 smc_pptable->I2cControllers[i].SlaveAddress =
524                         smc_dpm_table->i2ccontrollers[i].slaveaddress;
525                 smc_pptable->I2cControllers[i].ControllerPort =
526                         smc_dpm_table->i2ccontrollers[i].controllerport;
527                 smc_pptable->I2cControllers[i].ThermalThrottler =
528                         smc_dpm_table->i2ccontrollers[i].thermalthrottler;
529                 smc_pptable->I2cControllers[i].I2cProtocol =
530                         smc_dpm_table->i2ccontrollers[i].i2cprotocol;
531                 smc_pptable->I2cControllers[i].I2cSpeed =
532                         smc_dpm_table->i2ccontrollers[i].i2cspeed;
533         }
534
535         return 0;
536 }
537
538 static int vega20_check_powerplay_table(struct smu_context *smu)
539 {
540         ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL;
541         struct smu_table_context *table_context = &smu->smu_table;
542
543         powerplay_table = table_context->power_play_table;
544
545         if (powerplay_table->sHeader.format_revision < ATOM_VEGA20_TABLE_REVISION_VEGA20) {
546                 pr_err("Unsupported PPTable format!");
547                 return -EINVAL;
548         }
549
550         if (!powerplay_table->sHeader.structuresize) {
551                 pr_err("Invalid PowerPlay Table!");
552                 return -EINVAL;
553         }
554
555         return 0;
556 }
557
558 static int vega20_run_btc_afll(struct smu_context *smu)
559 {
560         return smu_send_smc_msg(smu, SMU_MSG_RunAfllBtc);
561 }
562
563 #define FEATURE_MASK(feature) (1UL << feature)
564 static int
565 vega20_get_allowed_feature_mask(struct smu_context *smu,
566                                   uint32_t *feature_mask, uint32_t num)
567 {
568         if (num > 2)
569                 return -EINVAL;
570
571         memset(feature_mask, 0, sizeof(uint32_t) * num);
572
573         *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT)
574                                 | FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT)
575                                 | FEATURE_MASK(FEATURE_DPM_UCLK_BIT)
576                                 | FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT)
577                                 | FEATURE_MASK(FEATURE_DPM_UVD_BIT)
578                                 | FEATURE_MASK(FEATURE_DPM_VCE_BIT)
579                                 | FEATURE_MASK(FEATURE_ULV_BIT)
580                                 | FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT)
581                                 | FEATURE_MASK(FEATURE_DPM_LINK_BIT)
582                                 | FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT)
583                                 | FEATURE_MASK(FEATURE_PPT_BIT)
584                                 | FEATURE_MASK(FEATURE_TDC_BIT)
585                                 | FEATURE_MASK(FEATURE_THERMAL_BIT)
586                                 | FEATURE_MASK(FEATURE_GFX_PER_CU_CG_BIT)
587                                 | FEATURE_MASK(FEATURE_RM_BIT)
588                                 | FEATURE_MASK(FEATURE_ACDC_BIT)
589                                 | FEATURE_MASK(FEATURE_VR0HOT_BIT)
590                                 | FEATURE_MASK(FEATURE_VR1HOT_BIT)
591                                 | FEATURE_MASK(FEATURE_FW_CTF_BIT)
592                                 | FEATURE_MASK(FEATURE_LED_DISPLAY_BIT)
593                                 | FEATURE_MASK(FEATURE_FAN_CONTROL_BIT)
594                                 | FEATURE_MASK(FEATURE_GFX_EDC_BIT)
595                                 | FEATURE_MASK(FEATURE_GFXOFF_BIT)
596                                 | FEATURE_MASK(FEATURE_CG_BIT)
597                                 | FEATURE_MASK(FEATURE_DPM_FCLK_BIT)
598                                 | FEATURE_MASK(FEATURE_XGMI_BIT);
599         return 0;
600 }
601
602 static enum
603 amd_pm_state_type vega20_get_current_power_state(struct smu_context *smu)
604 {
605         enum amd_pm_state_type pm_type;
606         struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
607
608         if (!smu_dpm_ctx->dpm_context ||
609             !smu_dpm_ctx->dpm_current_power_state)
610                 return -EINVAL;
611
612         mutex_lock(&(smu->mutex));
613         switch (smu_dpm_ctx->dpm_current_power_state->classification.ui_label) {
614         case SMU_STATE_UI_LABEL_BATTERY:
615                 pm_type = POWER_STATE_TYPE_BATTERY;
616                 break;
617         case SMU_STATE_UI_LABEL_BALLANCED:
618                 pm_type = POWER_STATE_TYPE_BALANCED;
619                 break;
620         case SMU_STATE_UI_LABEL_PERFORMANCE:
621                 pm_type = POWER_STATE_TYPE_PERFORMANCE;
622                 break;
623         default:
624                 if (smu_dpm_ctx->dpm_current_power_state->classification.flags & SMU_STATE_CLASSIFICATION_FLAG_BOOT)
625                         pm_type = POWER_STATE_TYPE_INTERNAL_BOOT;
626                 else
627                         pm_type = POWER_STATE_TYPE_DEFAULT;
628                 break;
629         }
630         mutex_unlock(&(smu->mutex));
631
632         return pm_type;
633 }
634
635 static int
636 vega20_set_single_dpm_table(struct smu_context *smu,
637                             struct vega20_single_dpm_table *single_dpm_table,
638                             PPCLK_e clk_id)
639 {
640         int ret = 0;
641         uint32_t i, num_of_levels = 0, clk;
642
643         ret = smu_send_smc_msg_with_param(smu,
644                         SMU_MSG_GetDpmFreqByIndex,
645                         (clk_id << 16 | 0xFF));
646         if (ret) {
647                 pr_err("[GetNumOfDpmLevel] failed to get dpm levels!");
648                 return ret;
649         }
650
651         smu_read_smc_arg(smu, &num_of_levels);
652         if (!num_of_levels) {
653                 pr_err("[GetNumOfDpmLevel] number of clk levels is invalid!");
654                 return -EINVAL;
655         }
656
657         single_dpm_table->count = num_of_levels;
658
659         for (i = 0; i < num_of_levels; i++) {
660                 ret = smu_send_smc_msg_with_param(smu,
661                                 SMU_MSG_GetDpmFreqByIndex,
662                                 (clk_id << 16 | i));
663                 if (ret) {
664                         pr_err("[GetDpmFreqByIndex] failed to get dpm freq by index!");
665                         return ret;
666                 }
667                 smu_read_smc_arg(smu, &clk);
668                 if (!clk) {
669                         pr_err("[GetDpmFreqByIndex] clk value is invalid!");
670                         return -EINVAL;
671                 }
672                 single_dpm_table->dpm_levels[i].value = clk;
673                 single_dpm_table->dpm_levels[i].enabled = true;
674         }
675         return 0;
676 }
677
678 static void vega20_init_single_dpm_state(struct vega20_dpm_state *dpm_state)
679 {
680         dpm_state->soft_min_level = 0x0;
681         dpm_state->soft_max_level = 0xffff;
682         dpm_state->hard_min_level = 0x0;
683         dpm_state->hard_max_level = 0xffff;
684 }
685
686 static int vega20_set_default_dpm_table(struct smu_context *smu)
687 {
688         int ret;
689
690         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
691         struct vega20_dpm_table *dpm_table = NULL;
692         struct vega20_single_dpm_table *single_dpm_table;
693
694         dpm_table = smu_dpm->dpm_context;
695
696         /* socclk */
697         single_dpm_table = &(dpm_table->soc_table);
698
699         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
700                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
701                                                   PPCLK_SOCCLK);
702                 if (ret) {
703                         pr_err("[SetupDefaultDpmTable] failed to get socclk dpm levels!");
704                         return ret;
705                 }
706         } else {
707                 single_dpm_table->count = 1;
708                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100;
709         }
710         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
711
712         /* gfxclk */
713         single_dpm_table = &(dpm_table->gfx_table);
714
715         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
716                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
717                                                   PPCLK_GFXCLK);
718                 if (ret) {
719                         pr_err("[SetupDefaultDpmTable] failed to get gfxclk dpm levels!");
720                         return ret;
721                 }
722         } else {
723                 single_dpm_table->count = 1;
724                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
725         }
726         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
727
728         /* memclk */
729         single_dpm_table = &(dpm_table->mem_table);
730
731         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
732                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
733                                                   PPCLK_UCLK);
734                 if (ret) {
735                         pr_err("[SetupDefaultDpmTable] failed to get memclk dpm levels!");
736                         return ret;
737                 }
738         } else {
739                 single_dpm_table->count = 1;
740                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100;
741         }
742         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
743
744         /* eclk */
745         single_dpm_table = &(dpm_table->eclk_table);
746
747         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_VCE_BIT)) {
748                 ret = vega20_set_single_dpm_table(smu, single_dpm_table, PPCLK_ECLK);
749                 if (ret) {
750                         pr_err("[SetupDefaultDpmTable] failed to get eclk dpm levels!");
751                         return ret;
752                 }
753         } else {
754                 single_dpm_table->count = 1;
755                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.eclk / 100;
756         }
757         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
758
759         /* vclk */
760         single_dpm_table = &(dpm_table->vclk_table);
761
762         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT)) {
763                 ret = vega20_set_single_dpm_table(smu, single_dpm_table, PPCLK_VCLK);
764                 if (ret) {
765                         pr_err("[SetupDefaultDpmTable] failed to get vclk dpm levels!");
766                         return ret;
767                 }
768         } else {
769                 single_dpm_table->count = 1;
770                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100;
771         }
772         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
773
774         /* dclk */
775         single_dpm_table = &(dpm_table->dclk_table);
776
777         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT)) {
778                 ret = vega20_set_single_dpm_table(smu, single_dpm_table, PPCLK_DCLK);
779                 if (ret) {
780                         pr_err("[SetupDefaultDpmTable] failed to get dclk dpm levels!");
781                         return ret;
782                 }
783         } else {
784                 single_dpm_table->count = 1;
785                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100;
786         }
787         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
788
789         /* dcefclk */
790         single_dpm_table = &(dpm_table->dcef_table);
791
792         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
793                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
794                                                   PPCLK_DCEFCLK);
795                 if (ret) {
796                         pr_err("[SetupDefaultDpmTable] failed to get dcefclk dpm levels!");
797                         return ret;
798                 }
799         } else {
800                 single_dpm_table->count = 1;
801                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
802         }
803         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
804
805         /* pixclk */
806         single_dpm_table = &(dpm_table->pixel_table);
807
808         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
809                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
810                                                   PPCLK_PIXCLK);
811                 if (ret) {
812                         pr_err("[SetupDefaultDpmTable] failed to get pixclk dpm levels!");
813                         return ret;
814                 }
815         } else {
816                 single_dpm_table->count = 0;
817         }
818         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
819
820         /* dispclk */
821         single_dpm_table = &(dpm_table->display_table);
822
823         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
824                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
825                                                   PPCLK_DISPCLK);
826                 if (ret) {
827                         pr_err("[SetupDefaultDpmTable] failed to get dispclk dpm levels!");
828                         return ret;
829                 }
830         } else {
831                 single_dpm_table->count = 0;
832         }
833         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
834
835         /* phyclk */
836         single_dpm_table = &(dpm_table->phy_table);
837
838         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
839                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
840                                                   PPCLK_PHYCLK);
841                 if (ret) {
842                         pr_err("[SetupDefaultDpmTable] failed to get phyclk dpm levels!");
843                         return ret;
844                 }
845         } else {
846                 single_dpm_table->count = 0;
847         }
848         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
849
850         /* fclk */
851         single_dpm_table = &(dpm_table->fclk_table);
852
853         if (smu_feature_is_enabled(smu,FEATURE_DPM_FCLK_BIT)) {
854                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
855                                                   PPCLK_FCLK);
856                 if (ret) {
857                         pr_err("[SetupDefaultDpmTable] failed to get fclk dpm levels!");
858                         return ret;
859                 }
860         } else {
861                 single_dpm_table->count = 0;
862         }
863         vega20_init_single_dpm_state(&(single_dpm_table->dpm_state));
864
865         memcpy(smu_dpm->golden_dpm_context, dpm_table,
866                sizeof(struct vega20_dpm_table));
867
868         return 0;
869 }
870
871 static int vega20_populate_umd_state_clk(struct smu_context *smu)
872 {
873         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
874         struct vega20_dpm_table *dpm_table = NULL;
875         struct vega20_single_dpm_table *gfx_table = NULL;
876         struct vega20_single_dpm_table *mem_table = NULL;
877
878         dpm_table = smu_dpm->dpm_context;
879         gfx_table = &(dpm_table->gfx_table);
880         mem_table = &(dpm_table->mem_table);
881
882         smu->pstate_sclk = gfx_table->dpm_levels[0].value;
883         smu->pstate_mclk = mem_table->dpm_levels[0].value;
884
885         if (gfx_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
886             mem_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL) {
887                 smu->pstate_sclk = gfx_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
888                 smu->pstate_mclk = mem_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
889         }
890
891         smu->pstate_sclk = smu->pstate_sclk * 100;
892         smu->pstate_mclk = smu->pstate_mclk * 100;
893
894         return 0;
895 }
896
897 static int vega20_get_clk_table(struct smu_context *smu,
898                         struct pp_clock_levels_with_latency *clocks,
899                         struct vega20_single_dpm_table *dpm_table)
900 {
901         int i, count;
902
903         count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count;
904         clocks->num_levels = count;
905
906         for (i = 0; i < count; i++) {
907                 clocks->data[i].clocks_in_khz =
908                         dpm_table->dpm_levels[i].value * 1000;
909                 clocks->data[i].latency_in_us = 0;
910         }
911
912         return 0;
913 }
914
915 static int vega20_print_clk_levels(struct smu_context *smu,
916                         enum smu_clk_type type, char *buf)
917 {
918         int i, now, size = 0;
919         int ret = 0;
920         uint32_t gen_speed, lane_width;
921         struct amdgpu_device *adev = smu->adev;
922         struct pp_clock_levels_with_latency clocks;
923         struct vega20_single_dpm_table *single_dpm_table;
924         struct smu_table_context *table_context = &smu->smu_table;
925         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
926         struct vega20_dpm_table *dpm_table = NULL;
927         struct vega20_od8_settings *od8_settings =
928                 (struct vega20_od8_settings *)table_context->od8_settings;
929         OverDriveTable_t *od_table =
930                 (OverDriveTable_t *)(table_context->overdrive_table);
931         PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable;
932
933         dpm_table = smu_dpm->dpm_context;
934
935         switch (type) {
936         case SMU_SCLK:
937                 ret = smu_get_current_clk_freq(smu, SMU_GFXCLK, &now);
938                 if (ret) {
939                         pr_err("Attempt to get current gfx clk Failed!");
940                         return ret;
941                 }
942
943                 single_dpm_table = &(dpm_table->gfx_table);
944                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
945                 if (ret) {
946                         pr_err("Attempt to get gfx clk levels Failed!");
947                         return ret;
948                 }
949
950                 for (i = 0; i < clocks.num_levels; i++)
951                         size += sprintf(buf + size, "%d: %uMhz %s\n", i,
952                                         clocks.data[i].clocks_in_khz / 1000,
953                                         (clocks.data[i].clocks_in_khz == now * 10)
954                                         ? "*" : "");
955                 break;
956
957         case SMU_MCLK:
958                 ret = smu_get_current_clk_freq(smu, SMU_UCLK, &now);
959                 if (ret) {
960                         pr_err("Attempt to get current mclk Failed!");
961                         return ret;
962                 }
963
964                 single_dpm_table = &(dpm_table->mem_table);
965                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
966                 if (ret) {
967                         pr_err("Attempt to get memory clk levels Failed!");
968                         return ret;
969                 }
970
971                 for (i = 0; i < clocks.num_levels; i++)
972                         size += sprintf(buf + size, "%d: %uMhz %s\n",
973                                 i, clocks.data[i].clocks_in_khz / 1000,
974                                 (clocks.data[i].clocks_in_khz == now * 10)
975                                 ? "*" : "");
976                 break;
977
978         case SMU_SOCCLK:
979                 ret = smu_get_current_clk_freq(smu, PPCLK_SOCCLK, &now);
980                 if (ret) {
981                         pr_err("Attempt to get current socclk Failed!");
982                         return ret;
983                 }
984
985                 single_dpm_table = &(dpm_table->soc_table);
986                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
987                 if (ret) {
988                         pr_err("Attempt to get socclk levels Failed!");
989                         return ret;
990                 }
991
992                 for (i = 0; i < clocks.num_levels; i++)
993                         size += sprintf(buf + size, "%d: %uMhz %s\n",
994                                 i, clocks.data[i].clocks_in_khz / 1000,
995                                 (clocks.data[i].clocks_in_khz == now * 10)
996                                 ? "*" : "");
997                 break;
998
999         case SMU_FCLK:
1000                 ret = smu_get_current_clk_freq(smu, PPCLK_FCLK, &now);
1001                 if (ret) {
1002                         pr_err("Attempt to get current fclk Failed!");
1003                         return ret;
1004                 }
1005
1006                 single_dpm_table = &(dpm_table->fclk_table);
1007                 for (i = 0; i < single_dpm_table->count; i++)
1008                         size += sprintf(buf + size, "%d: %uMhz %s\n",
1009                                 i, single_dpm_table->dpm_levels[i].value,
1010                                 (single_dpm_table->dpm_levels[i].value == now / 100)
1011                                 ? "*" : "");
1012                 break;
1013
1014         case SMU_DCEFCLK:
1015                 ret = smu_get_current_clk_freq(smu, PPCLK_DCEFCLK, &now);
1016                 if (ret) {
1017                         pr_err("Attempt to get current dcefclk Failed!");
1018                         return ret;
1019                 }
1020
1021                 single_dpm_table = &(dpm_table->dcef_table);
1022                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
1023                 if (ret) {
1024                         pr_err("Attempt to get dcefclk levels Failed!");
1025                         return ret;
1026                 }
1027
1028                 for (i = 0; i < clocks.num_levels; i++)
1029                         size += sprintf(buf + size, "%d: %uMhz %s\n",
1030                                 i, clocks.data[i].clocks_in_khz / 1000,
1031                                 (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
1032                 break;
1033
1034         case SMU_PCIE:
1035                 gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) &
1036                              PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK)
1037                         >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
1038                 lane_width = (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) &
1039                               PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK)
1040                         >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT;
1041                 for (i = 0; i < NUM_LINK_LEVELS; i++)
1042                         size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
1043                                         (pptable->PcieGenSpeed[i] == 0) ? "2.5GT/s," :
1044                                         (pptable->PcieGenSpeed[i] == 1) ? "5.0GT/s," :
1045                                         (pptable->PcieGenSpeed[i] == 2) ? "8.0GT/s," :
1046                                         (pptable->PcieGenSpeed[i] == 3) ? "16.0GT/s," : "",
1047                                         (pptable->PcieLaneCount[i] == 1) ? "x1" :
1048                                         (pptable->PcieLaneCount[i] == 2) ? "x2" :
1049                                         (pptable->PcieLaneCount[i] == 3) ? "x4" :
1050                                         (pptable->PcieLaneCount[i] == 4) ? "x8" :
1051                                         (pptable->PcieLaneCount[i] == 5) ? "x12" :
1052                                         (pptable->PcieLaneCount[i] == 6) ? "x16" : "",
1053                                         pptable->LclkFreq[i],
1054                                         (gen_speed == pptable->PcieGenSpeed[i]) &&
1055                                         (lane_width == pptable->PcieLaneCount[i]) ?
1056                                         "*" : "");
1057                 break;
1058
1059         case SMU_OD_SCLK:
1060                 if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id &&
1061                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id) {
1062                         size = sprintf(buf, "%s:\n", "OD_SCLK");
1063                         size += sprintf(buf + size, "0: %10uMhz\n",
1064                                         od_table->GfxclkFmin);
1065                         size += sprintf(buf + size, "1: %10uMhz\n",
1066                                         od_table->GfxclkFmax);
1067                 }
1068
1069                 break;
1070
1071         case SMU_OD_MCLK:
1072                 if (od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) {
1073                         size = sprintf(buf, "%s:\n", "OD_MCLK");
1074                         size += sprintf(buf + size, "1: %10uMhz\n",
1075                                          od_table->UclkFmax);
1076                 }
1077
1078                 break;
1079
1080         case SMU_OD_VDDC_CURVE:
1081                 if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
1082                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
1083                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
1084                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
1085                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
1086                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
1087                         size = sprintf(buf, "%s:\n", "OD_VDDC_CURVE");
1088                         size += sprintf(buf + size, "0: %10uMhz %10dmV\n",
1089                                         od_table->GfxclkFreq1,
1090                                         od_table->GfxclkVolt1 / VOLTAGE_SCALE);
1091                         size += sprintf(buf + size, "1: %10uMhz %10dmV\n",
1092                                         od_table->GfxclkFreq2,
1093                                         od_table->GfxclkVolt2 / VOLTAGE_SCALE);
1094                         size += sprintf(buf + size, "2: %10uMhz %10dmV\n",
1095                                         od_table->GfxclkFreq3,
1096                                         od_table->GfxclkVolt3 / VOLTAGE_SCALE);
1097                 }
1098
1099                 break;
1100
1101         case SMU_OD_RANGE:
1102                 size = sprintf(buf, "%s:\n", "OD_RANGE");
1103
1104                 if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id &&
1105                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id) {
1106                         size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
1107                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value,
1108                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value);
1109                 }
1110
1111                 if (od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) {
1112                         single_dpm_table = &(dpm_table->mem_table);
1113                         ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
1114                         if (ret) {
1115                                 pr_err("Attempt to get memory clk levels Failed!");
1116                                 return ret;
1117                         }
1118
1119                         size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
1120                                         clocks.data[0].clocks_in_khz / 1000,
1121                                         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value);
1122                 }
1123
1124                 if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
1125                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
1126                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
1127                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
1128                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
1129                     od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
1130                         size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
1131                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].min_value,
1132                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].max_value);
1133                         size += sprintf(buf + size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n",
1134                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].min_value,
1135                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].max_value);
1136                         size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
1137                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].min_value,
1138                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].max_value);
1139                         size += sprintf(buf + size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n",
1140                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].min_value,
1141                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].max_value);
1142                         size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
1143                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].min_value,
1144                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].max_value);
1145                         size += sprintf(buf + size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
1146                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].min_value,
1147                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].max_value);
1148                 }
1149
1150                 break;
1151
1152         default:
1153                 break;
1154         }
1155         return size;
1156 }
1157
1158 static int vega20_upload_dpm_level(struct smu_context *smu, bool max,
1159                                    uint32_t feature_mask)
1160 {
1161         struct vega20_dpm_table *dpm_table;
1162         struct vega20_single_dpm_table *single_dpm_table;
1163         uint32_t freq;
1164         int ret = 0;
1165
1166         dpm_table = smu->smu_dpm.dpm_context;
1167
1168         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT) &&
1169             (feature_mask & FEATURE_DPM_GFXCLK_MASK)) {
1170                 single_dpm_table = &(dpm_table->gfx_table);
1171                 freq = max ? single_dpm_table->dpm_state.soft_max_level :
1172                         single_dpm_table->dpm_state.soft_min_level;
1173                 ret = smu_send_smc_msg_with_param(smu,
1174                         (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
1175                         (PPCLK_GFXCLK << 16) | (freq & 0xffff));
1176                 if (ret) {
1177                         pr_err("Failed to set soft %s gfxclk !\n",
1178                                                 max ? "max" : "min");
1179                         return ret;
1180                 }
1181         }
1182
1183         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT) &&
1184             (feature_mask & FEATURE_DPM_UCLK_MASK)) {
1185                 single_dpm_table = &(dpm_table->mem_table);
1186                 freq = max ? single_dpm_table->dpm_state.soft_max_level :
1187                         single_dpm_table->dpm_state.soft_min_level;
1188                 ret = smu_send_smc_msg_with_param(smu,
1189                         (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
1190                         (PPCLK_UCLK << 16) | (freq & 0xffff));
1191                 if (ret) {
1192                         pr_err("Failed to set soft %s memclk !\n",
1193                                                 max ? "max" : "min");
1194                         return ret;
1195                 }
1196         }
1197
1198         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT) &&
1199             (feature_mask & FEATURE_DPM_SOCCLK_MASK)) {
1200                 single_dpm_table = &(dpm_table->soc_table);
1201                 freq = max ? single_dpm_table->dpm_state.soft_max_level :
1202                         single_dpm_table->dpm_state.soft_min_level;
1203                 ret = smu_send_smc_msg_with_param(smu,
1204                         (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
1205                         (PPCLK_SOCCLK << 16) | (freq & 0xffff));
1206                 if (ret) {
1207                         pr_err("Failed to set soft %s socclk !\n",
1208                                                 max ? "max" : "min");
1209                         return ret;
1210                 }
1211         }
1212
1213         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT) &&
1214             (feature_mask & FEATURE_DPM_FCLK_MASK)) {
1215                 single_dpm_table = &(dpm_table->fclk_table);
1216                 freq = max ? single_dpm_table->dpm_state.soft_max_level :
1217                         single_dpm_table->dpm_state.soft_min_level;
1218                 ret = smu_send_smc_msg_with_param(smu,
1219                         (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
1220                         (PPCLK_FCLK << 16) | (freq & 0xffff));
1221                 if (ret) {
1222                         pr_err("Failed to set soft %s fclk !\n",
1223                                                 max ? "max" : "min");
1224                         return ret;
1225                 }
1226         }
1227
1228         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
1229             (feature_mask & FEATURE_DPM_DCEFCLK_MASK)) {
1230                 single_dpm_table = &(dpm_table->dcef_table);
1231                 freq = single_dpm_table->dpm_state.hard_min_level;
1232                 if (!max) {
1233                         ret = smu_send_smc_msg_with_param(smu,
1234                                 SMU_MSG_SetHardMinByFreq,
1235                                 (PPCLK_DCEFCLK << 16) | (freq & 0xffff));
1236                         if (ret) {
1237                                 pr_err("Failed to set hard min dcefclk !\n");
1238                                 return ret;
1239                         }
1240                 }
1241         }
1242
1243         return ret;
1244 }
1245
1246 static int vega20_force_clk_levels(struct smu_context *smu,
1247                         enum  smu_clk_type clk_type, uint32_t mask)
1248 {
1249         struct vega20_dpm_table *dpm_table;
1250         struct vega20_single_dpm_table *single_dpm_table;
1251         uint32_t soft_min_level, soft_max_level, hard_min_level;
1252         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
1253         int ret = 0;
1254
1255         if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) {
1256                 pr_info("force clock level is for dpm manual mode only.\n");
1257                 return -EINVAL;
1258         }
1259
1260         mutex_lock(&(smu->mutex));
1261
1262         soft_min_level = mask ? (ffs(mask) - 1) : 0;
1263         soft_max_level = mask ? (fls(mask) - 1) : 0;
1264
1265         dpm_table = smu->smu_dpm.dpm_context;
1266
1267         switch (clk_type) {
1268         case SMU_SCLK:
1269                 single_dpm_table = &(dpm_table->gfx_table);
1270
1271                 if (soft_max_level >= single_dpm_table->count) {
1272                         pr_err("Clock level specified %d is over max allowed %d\n",
1273                                         soft_max_level, single_dpm_table->count - 1);
1274                         ret = -EINVAL;
1275                         break;
1276                 }
1277
1278                 single_dpm_table->dpm_state.soft_min_level =
1279                         single_dpm_table->dpm_levels[soft_min_level].value;
1280                 single_dpm_table->dpm_state.soft_max_level =
1281                         single_dpm_table->dpm_levels[soft_max_level].value;
1282
1283                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_GFXCLK_MASK);
1284                 if (ret) {
1285                         pr_err("Failed to upload boot level to lowest!\n");
1286                         break;
1287                 }
1288
1289                 ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_GFXCLK_MASK);
1290                 if (ret)
1291                         pr_err("Failed to upload dpm max level to highest!\n");
1292
1293                 break;
1294
1295         case SMU_MCLK:
1296                 single_dpm_table = &(dpm_table->mem_table);
1297
1298                 if (soft_max_level >= single_dpm_table->count) {
1299                         pr_err("Clock level specified %d is over max allowed %d\n",
1300                                         soft_max_level, single_dpm_table->count - 1);
1301                         ret = -EINVAL;
1302                         break;
1303                 }
1304
1305                 single_dpm_table->dpm_state.soft_min_level =
1306                         single_dpm_table->dpm_levels[soft_min_level].value;
1307                 single_dpm_table->dpm_state.soft_max_level =
1308                         single_dpm_table->dpm_levels[soft_max_level].value;
1309
1310                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_UCLK_MASK);
1311                 if (ret) {
1312                         pr_err("Failed to upload boot level to lowest!\n");
1313                         break;
1314                 }
1315
1316                 ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_UCLK_MASK);
1317                 if (ret)
1318                         pr_err("Failed to upload dpm max level to highest!\n");
1319
1320                 break;
1321
1322         case SMU_SOCCLK:
1323                 single_dpm_table = &(dpm_table->soc_table);
1324
1325                 if (soft_max_level >= single_dpm_table->count) {
1326                         pr_err("Clock level specified %d is over max allowed %d\n",
1327                                         soft_max_level, single_dpm_table->count - 1);
1328                         ret = -EINVAL;
1329                         break;
1330                 }
1331
1332                 single_dpm_table->dpm_state.soft_min_level =
1333                         single_dpm_table->dpm_levels[soft_min_level].value;
1334                 single_dpm_table->dpm_state.soft_max_level =
1335                         single_dpm_table->dpm_levels[soft_max_level].value;
1336
1337                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_SOCCLK_MASK);
1338                 if (ret) {
1339                         pr_err("Failed to upload boot level to lowest!\n");
1340                         break;
1341                 }
1342
1343                 ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_SOCCLK_MASK);
1344                 if (ret)
1345                         pr_err("Failed to upload dpm max level to highest!\n");
1346
1347                 break;
1348
1349         case SMU_FCLK:
1350                 single_dpm_table = &(dpm_table->fclk_table);
1351
1352                 if (soft_max_level >= single_dpm_table->count) {
1353                         pr_err("Clock level specified %d is over max allowed %d\n",
1354                                         soft_max_level, single_dpm_table->count - 1);
1355                         ret = -EINVAL;
1356                         break;
1357                 }
1358
1359                 single_dpm_table->dpm_state.soft_min_level =
1360                         single_dpm_table->dpm_levels[soft_min_level].value;
1361                 single_dpm_table->dpm_state.soft_max_level =
1362                         single_dpm_table->dpm_levels[soft_max_level].value;
1363
1364                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_FCLK_MASK);
1365                 if (ret) {
1366                         pr_err("Failed to upload boot level to lowest!\n");
1367                         break;
1368                 }
1369
1370                 ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_FCLK_MASK);
1371                 if (ret)
1372                         pr_err("Failed to upload dpm max level to highest!\n");
1373
1374                 break;
1375
1376         case SMU_DCEFCLK:
1377                 hard_min_level = soft_min_level;
1378                 single_dpm_table = &(dpm_table->dcef_table);
1379
1380                 if (hard_min_level >= single_dpm_table->count) {
1381                         pr_err("Clock level specified %d is over max allowed %d\n",
1382                                         hard_min_level, single_dpm_table->count - 1);
1383                         ret = -EINVAL;
1384                         break;
1385                 }
1386
1387                 single_dpm_table->dpm_state.hard_min_level =
1388                         single_dpm_table->dpm_levels[hard_min_level].value;
1389
1390                 ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_DCEFCLK_MASK);
1391                 if (ret)
1392                         pr_err("Failed to upload boot level to lowest!\n");
1393
1394                 break;
1395
1396         case SMU_PCIE:
1397                 if (soft_min_level >= NUM_LINK_LEVELS ||
1398                     soft_max_level >= NUM_LINK_LEVELS) {
1399                         ret = -EINVAL;
1400                         break;
1401                 }
1402
1403                 ret = smu_send_smc_msg_with_param(smu,
1404                                 SMU_MSG_SetMinLinkDpmByIndex, soft_min_level);
1405                 if (ret)
1406                         pr_err("Failed to set min link dpm level!\n");
1407
1408                 break;
1409
1410         default:
1411                 break;
1412         }
1413
1414         mutex_unlock(&(smu->mutex));
1415         return ret;
1416 }
1417
1418 static int vega20_get_clock_by_type_with_latency(struct smu_context *smu,
1419                                                  enum smu_clk_type clk_type,
1420                                                  struct pp_clock_levels_with_latency *clocks)
1421 {
1422         int ret;
1423         struct vega20_single_dpm_table *single_dpm_table;
1424         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
1425         struct vega20_dpm_table *dpm_table = NULL;
1426
1427         dpm_table = smu_dpm->dpm_context;
1428
1429         mutex_lock(&smu->mutex);
1430
1431         switch (clk_type) {
1432         case SMU_GFXCLK:
1433                 single_dpm_table = &(dpm_table->gfx_table);
1434                 ret = vega20_get_clk_table(smu, clocks, single_dpm_table);
1435                 break;
1436         case SMU_MCLK:
1437                 single_dpm_table = &(dpm_table->mem_table);
1438                 ret = vega20_get_clk_table(smu, clocks, single_dpm_table);
1439                 break;
1440         case SMU_DCEFCLK:
1441                 single_dpm_table = &(dpm_table->dcef_table);
1442                 ret = vega20_get_clk_table(smu, clocks, single_dpm_table);
1443                 break;
1444         case SMU_SOCCLK:
1445                 single_dpm_table = &(dpm_table->soc_table);
1446                 ret = vega20_get_clk_table(smu, clocks, single_dpm_table);
1447                 break;
1448         default:
1449                 ret = -EINVAL;
1450         }
1451
1452         mutex_unlock(&smu->mutex);
1453         return ret;
1454 }
1455
1456 static int vega20_overdrive_get_gfx_clk_base_voltage(struct smu_context *smu,
1457                                                      uint32_t *voltage,
1458                                                      uint32_t freq)
1459 {
1460         int ret;
1461
1462         ret = smu_send_smc_msg_with_param(smu,
1463                         SMU_MSG_GetAVFSVoltageByDpm,
1464                         ((AVFS_CURVE << 24) | (OD8_HOTCURVE_TEMPERATURE << 16) | freq));
1465         if (ret) {
1466                 pr_err("[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!");
1467                 return ret;
1468         }
1469
1470         smu_read_smc_arg(smu, voltage);
1471         *voltage = *voltage / VOLTAGE_SCALE;
1472
1473         return 0;
1474 }
1475
1476 static int vega20_set_default_od8_setttings(struct smu_context *smu)
1477 {
1478         struct smu_table_context *table_context = &smu->smu_table;
1479         OverDriveTable_t *od_table = (OverDriveTable_t *)(table_context->overdrive_table);
1480         struct vega20_od8_settings *od8_settings = NULL;
1481         PPTable_t *smc_pptable = table_context->driver_pptable;
1482         int i, ret;
1483
1484         if (table_context->od8_settings)
1485                 return -EINVAL;
1486
1487         table_context->od8_settings = kzalloc(sizeof(struct vega20_od8_settings), GFP_KERNEL);
1488
1489         if (!table_context->od8_settings)
1490                 return -ENOMEM;
1491
1492         od8_settings = (struct vega20_od8_settings *)table_context->od8_settings;
1493
1494         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
1495                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_LIMITS] &&
1496                     table_context->od_settings_max[OD8_SETTING_GFXCLK_FMAX] > 0 &&
1497                     table_context->od_settings_min[OD8_SETTING_GFXCLK_FMIN] > 0 &&
1498                     (table_context->od_settings_max[OD8_SETTING_GFXCLK_FMAX] >=
1499                      table_context->od_settings_min[OD8_SETTING_GFXCLK_FMIN])) {
1500                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id =
1501                                 OD8_GFXCLK_LIMITS;
1502                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id =
1503                                 OD8_GFXCLK_LIMITS;
1504                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value =
1505                                 od_table->GfxclkFmin;
1506                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value =
1507                                 od_table->GfxclkFmax;
1508                 }
1509
1510                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_CURVE] &&
1511                     (table_context->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] >=
1512                      smc_pptable->MinVoltageGfx / VOLTAGE_SCALE) &&
1513                     (table_context->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3] <=
1514                      smc_pptable->MaxVoltageGfx / VOLTAGE_SCALE) &&
1515                     (table_context->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] <=
1516                      table_context->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3])) {
1517                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id =
1518                                 OD8_GFXCLK_CURVE;
1519                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id =
1520                                 OD8_GFXCLK_CURVE;
1521                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id =
1522                                 OD8_GFXCLK_CURVE;
1523                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id =
1524                                 OD8_GFXCLK_CURVE;
1525                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id =
1526                                 OD8_GFXCLK_CURVE;
1527                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id =
1528                                 OD8_GFXCLK_CURVE;
1529
1530                         od_table->GfxclkFreq1 = od_table->GfxclkFmin;
1531                         od_table->GfxclkFreq2 = (od_table->GfxclkFmin + od_table->GfxclkFmax) / 2;
1532                         od_table->GfxclkFreq3 = od_table->GfxclkFmax;
1533                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value =
1534                                 od_table->GfxclkFreq1;
1535                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value =
1536                                 od_table->GfxclkFreq2;
1537                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value =
1538                                 od_table->GfxclkFreq3;
1539
1540                         ret = vega20_overdrive_get_gfx_clk_base_voltage(smu,
1541                                 &od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value,
1542                                 od_table->GfxclkFreq1);
1543                         if (ret)
1544                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value = 0;
1545                         od_table->GfxclkVolt1 =
1546                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value
1547                                 * VOLTAGE_SCALE;
1548                         ret = vega20_overdrive_get_gfx_clk_base_voltage(smu,
1549                                 &od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value,
1550                                 od_table->GfxclkFreq2);
1551                         if (ret)
1552                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value = 0;
1553                         od_table->GfxclkVolt2 =
1554                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value
1555                                 * VOLTAGE_SCALE;
1556                         ret = vega20_overdrive_get_gfx_clk_base_voltage(smu,
1557                                 &od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value,
1558                                 od_table->GfxclkFreq3);
1559                         if (ret)
1560                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value = 0;
1561                         od_table->GfxclkVolt3 =
1562                                 od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value
1563                                 * VOLTAGE_SCALE;
1564                 }
1565         }
1566
1567         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
1568                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_UCLK_MAX] &&
1569                     table_context->od_settings_min[OD8_SETTING_UCLK_FMAX] > 0 &&
1570                     table_context->od_settings_max[OD8_SETTING_UCLK_FMAX] > 0 &&
1571                     (table_context->od_settings_max[OD8_SETTING_UCLK_FMAX] >=
1572                      table_context->od_settings_min[OD8_SETTING_UCLK_FMAX])) {
1573                         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id =
1574                                 OD8_UCLK_MAX;
1575                         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value =
1576                                 od_table->UclkFmax;
1577                 }
1578         }
1579
1580         if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_POWER_LIMIT] &&
1581             table_context->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
1582             table_context->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] <= 100 &&
1583             table_context->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
1584             table_context->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] <= 100) {
1585                 od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id =
1586                         OD8_POWER_LIMIT;
1587                 od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value =
1588                         od_table->OverDrivePct;
1589         }
1590
1591         if (smu_feature_is_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT)) {
1592                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_ACOUSTIC_LIMIT] &&
1593                     table_context->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 &&
1594                     table_context->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 &&
1595                     (table_context->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] >=
1596                      table_context->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT])) {
1597                         od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id =
1598                                 OD8_ACOUSTIC_LIMIT_SCLK;
1599                         od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value =
1600                                 od_table->FanMaximumRpm;
1601                 }
1602
1603                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_SPEED_MIN] &&
1604                     table_context->od_settings_min[OD8_SETTING_FAN_MIN_SPEED] > 0 &&
1605                     table_context->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] > 0 &&
1606                     (table_context->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] >=
1607                      table_context->od_settings_min[OD8_SETTING_FAN_MIN_SPEED])) {
1608                         od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id =
1609                                 OD8_FAN_SPEED_MIN;
1610                         od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value =
1611                                 od_table->FanMinimumPwm * smc_pptable->FanMaximumRpm / 100;
1612                 }
1613         }
1614
1615         if (smu_feature_is_enabled(smu, SMU_FEATURE_THERMAL_BIT)) {
1616                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_FAN] &&
1617                     table_context->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP] > 0 &&
1618                     table_context->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] > 0 &&
1619                     (table_context->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] >=
1620                      table_context->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP])) {
1621                         od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id =
1622                                 OD8_TEMPERATURE_FAN;
1623                         od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value =
1624                                 od_table->FanTargetTemperature;
1625                 }
1626
1627                 if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_SYSTEM] &&
1628                     table_context->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX] > 0 &&
1629                     table_context->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] > 0 &&
1630                     (table_context->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] >=
1631                      table_context->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX])) {
1632                         od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id =
1633                                 OD8_TEMPERATURE_SYSTEM;
1634                         od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_value =
1635                                 od_table->MaxOpTemp;
1636                 }
1637         }
1638
1639         for (i = 0; i < OD8_SETTING_COUNT; i++) {
1640                 if (od8_settings->od8_settings_array[i].feature_id) {
1641                         od8_settings->od8_settings_array[i].min_value =
1642                                 table_context->od_settings_min[i];
1643                         od8_settings->od8_settings_array[i].max_value =
1644                                 table_context->od_settings_max[i];
1645                         od8_settings->od8_settings_array[i].current_value =
1646                                 od8_settings->od8_settings_array[i].default_value;
1647                 } else {
1648                         od8_settings->od8_settings_array[i].min_value = 0;
1649                         od8_settings->od8_settings_array[i].max_value = 0;
1650                         od8_settings->od8_settings_array[i].current_value = 0;
1651                 }
1652         }
1653
1654         return 0;
1655 }
1656
1657 static int vega20_get_od_percentage(struct smu_context *smu,
1658                                     enum pp_clock_type type)
1659 {
1660         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
1661         struct vega20_dpm_table *dpm_table = NULL;
1662         struct vega20_dpm_table *golden_table = NULL;
1663         struct vega20_single_dpm_table *single_dpm_table;
1664         struct vega20_single_dpm_table *golden_dpm_table;
1665         int value, golden_value;
1666
1667         dpm_table = smu_dpm->dpm_context;
1668         golden_table = smu_dpm->golden_dpm_context;
1669
1670         switch (type) {
1671         case OD_SCLK:
1672                 single_dpm_table = &(dpm_table->gfx_table);
1673                 golden_dpm_table = &(golden_table->gfx_table);
1674                 break;
1675         case OD_MCLK:
1676                 single_dpm_table = &(dpm_table->mem_table);
1677                 golden_dpm_table = &(golden_table->mem_table);
1678                 break;
1679         default:
1680                 return -EINVAL;
1681                 break;
1682         }
1683
1684         value = single_dpm_table->dpm_levels[single_dpm_table->count - 1].value;
1685         golden_value = golden_dpm_table->dpm_levels[golden_dpm_table->count - 1].value;
1686
1687         value -= golden_value;
1688         value = DIV_ROUND_UP(value * 100, golden_value);
1689
1690         return value;
1691 }
1692
1693 static int vega20_get_power_profile_mode(struct smu_context *smu, char *buf)
1694 {
1695         DpmActivityMonitorCoeffInt_t activity_monitor;
1696         uint32_t i, size = 0;
1697         uint16_t workload_type = 0;
1698         static const char *profile_name[] = {
1699                                         "BOOTUP_DEFAULT",
1700                                         "3D_FULL_SCREEN",
1701                                         "POWER_SAVING",
1702                                         "VIDEO",
1703                                         "VR",
1704                                         "COMPUTE",
1705                                         "CUSTOM"};
1706         static const char *title[] = {
1707                         "PROFILE_INDEX(NAME)",
1708                         "CLOCK_TYPE(NAME)",
1709                         "FPS",
1710                         "UseRlcBusy",
1711                         "MinActiveFreqType",
1712                         "MinActiveFreq",
1713                         "BoosterFreqType",
1714                         "BoosterFreq",
1715                         "PD_Data_limit_c",
1716                         "PD_Data_error_coeff",
1717                         "PD_Data_error_rate_coeff"};
1718         int result = 0;
1719
1720         if (!smu->pm_enabled || !buf)
1721                 return -EINVAL;
1722
1723         size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
1724                         title[0], title[1], title[2], title[3], title[4], title[5],
1725                         title[6], title[7], title[8], title[9], title[10]);
1726
1727         for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
1728                 /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
1729                 workload_type = smu_workload_get_type(smu, i);
1730                 result = smu_update_table(smu,
1731                                           TABLE_ACTIVITY_MONITOR_COEFF | workload_type << 16,
1732                                           (void *)(&activity_monitor), false);
1733                 if (result) {
1734                         pr_err("[%s] Failed to get activity monitor!", __func__);
1735                         return result;
1736                 }
1737
1738                 size += sprintf(buf + size, "%2d %14s%s:\n",
1739                         i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");
1740
1741                 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
1742                         " ",
1743                         0,
1744                         "GFXCLK",
1745                         activity_monitor.Gfx_FPS,
1746                         activity_monitor.Gfx_UseRlcBusy,
1747                         activity_monitor.Gfx_MinActiveFreqType,
1748                         activity_monitor.Gfx_MinActiveFreq,
1749                         activity_monitor.Gfx_BoosterFreqType,
1750                         activity_monitor.Gfx_BoosterFreq,
1751                         activity_monitor.Gfx_PD_Data_limit_c,
1752                         activity_monitor.Gfx_PD_Data_error_coeff,
1753                         activity_monitor.Gfx_PD_Data_error_rate_coeff);
1754
1755                 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
1756                         " ",
1757                         1,
1758                         "SOCCLK",
1759                         activity_monitor.Soc_FPS,
1760                         activity_monitor.Soc_UseRlcBusy,
1761                         activity_monitor.Soc_MinActiveFreqType,
1762                         activity_monitor.Soc_MinActiveFreq,
1763                         activity_monitor.Soc_BoosterFreqType,
1764                         activity_monitor.Soc_BoosterFreq,
1765                         activity_monitor.Soc_PD_Data_limit_c,
1766                         activity_monitor.Soc_PD_Data_error_coeff,
1767                         activity_monitor.Soc_PD_Data_error_rate_coeff);
1768
1769                 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
1770                         " ",
1771                         2,
1772                         "UCLK",
1773                         activity_monitor.Mem_FPS,
1774                         activity_monitor.Mem_UseRlcBusy,
1775                         activity_monitor.Mem_MinActiveFreqType,
1776                         activity_monitor.Mem_MinActiveFreq,
1777                         activity_monitor.Mem_BoosterFreqType,
1778                         activity_monitor.Mem_BoosterFreq,
1779                         activity_monitor.Mem_PD_Data_limit_c,
1780                         activity_monitor.Mem_PD_Data_error_coeff,
1781                         activity_monitor.Mem_PD_Data_error_rate_coeff);
1782
1783                 size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
1784                         " ",
1785                         3,
1786                         "FCLK",
1787                         activity_monitor.Fclk_FPS,
1788                         activity_monitor.Fclk_UseRlcBusy,
1789                         activity_monitor.Fclk_MinActiveFreqType,
1790                         activity_monitor.Fclk_MinActiveFreq,
1791                         activity_monitor.Fclk_BoosterFreqType,
1792                         activity_monitor.Fclk_BoosterFreq,
1793                         activity_monitor.Fclk_PD_Data_limit_c,
1794                         activity_monitor.Fclk_PD_Data_error_coeff,
1795                         activity_monitor.Fclk_PD_Data_error_rate_coeff);
1796         }
1797
1798         return size;
1799 }
1800
1801 static int vega20_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
1802 {
1803         DpmActivityMonitorCoeffInt_t activity_monitor;
1804         int workload_type = 0, ret = 0;
1805
1806         smu->power_profile_mode = input[size];
1807
1808         if (!smu->pm_enabled)
1809                 return ret;
1810         if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
1811                 pr_err("Invalid power profile mode %d\n", smu->power_profile_mode);
1812                 return -EINVAL;
1813         }
1814
1815         if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
1816                 ret = smu_update_table(smu,
1817                                        TABLE_ACTIVITY_MONITOR_COEFF | WORKLOAD_PPLIB_CUSTOM_BIT << 16,
1818                                        (void *)(&activity_monitor), false);
1819                 if (ret) {
1820                         pr_err("[%s] Failed to get activity monitor!", __func__);
1821                         return ret;
1822                 }
1823
1824                 switch (input[0]) {
1825                 case 0: /* Gfxclk */
1826                         activity_monitor.Gfx_FPS = input[1];
1827                         activity_monitor.Gfx_UseRlcBusy = input[2];
1828                         activity_monitor.Gfx_MinActiveFreqType = input[3];
1829                         activity_monitor.Gfx_MinActiveFreq = input[4];
1830                         activity_monitor.Gfx_BoosterFreqType = input[5];
1831                         activity_monitor.Gfx_BoosterFreq = input[6];
1832                         activity_monitor.Gfx_PD_Data_limit_c = input[7];
1833                         activity_monitor.Gfx_PD_Data_error_coeff = input[8];
1834                         activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
1835                         break;
1836                 case 1: /* Socclk */
1837                         activity_monitor.Soc_FPS = input[1];
1838                         activity_monitor.Soc_UseRlcBusy = input[2];
1839                         activity_monitor.Soc_MinActiveFreqType = input[3];
1840                         activity_monitor.Soc_MinActiveFreq = input[4];
1841                         activity_monitor.Soc_BoosterFreqType = input[5];
1842                         activity_monitor.Soc_BoosterFreq = input[6];
1843                         activity_monitor.Soc_PD_Data_limit_c = input[7];
1844                         activity_monitor.Soc_PD_Data_error_coeff = input[8];
1845                         activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
1846                         break;
1847                 case 2: /* Uclk */
1848                         activity_monitor.Mem_FPS = input[1];
1849                         activity_monitor.Mem_UseRlcBusy = input[2];
1850                         activity_monitor.Mem_MinActiveFreqType = input[3];
1851                         activity_monitor.Mem_MinActiveFreq = input[4];
1852                         activity_monitor.Mem_BoosterFreqType = input[5];
1853                         activity_monitor.Mem_BoosterFreq = input[6];
1854                         activity_monitor.Mem_PD_Data_limit_c = input[7];
1855                         activity_monitor.Mem_PD_Data_error_coeff = input[8];
1856                         activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
1857                         break;
1858                 case 3: /* Fclk */
1859                         activity_monitor.Fclk_FPS = input[1];
1860                         activity_monitor.Fclk_UseRlcBusy = input[2];
1861                         activity_monitor.Fclk_MinActiveFreqType = input[3];
1862                         activity_monitor.Fclk_MinActiveFreq = input[4];
1863                         activity_monitor.Fclk_BoosterFreqType = input[5];
1864                         activity_monitor.Fclk_BoosterFreq = input[6];
1865                         activity_monitor.Fclk_PD_Data_limit_c = input[7];
1866                         activity_monitor.Fclk_PD_Data_error_coeff = input[8];
1867                         activity_monitor.Fclk_PD_Data_error_rate_coeff = input[9];
1868                         break;
1869                 }
1870
1871                 ret = smu_update_table(smu,
1872                                        TABLE_ACTIVITY_MONITOR_COEFF | WORKLOAD_PPLIB_CUSTOM_BIT << 16,
1873                                        (void *)(&activity_monitor), true);
1874                 if (ret) {
1875                         pr_err("[%s] Failed to set activity monitor!", __func__);
1876                         return ret;
1877                 }
1878         }
1879
1880         /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
1881         workload_type = smu_workload_get_type(smu, smu->power_profile_mode);
1882         smu_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
1883                                     1 << workload_type);
1884
1885         return ret;
1886 }
1887
1888 static int
1889 vega20_get_profiling_clk_mask(struct smu_context *smu,
1890                               enum amd_dpm_forced_level level,
1891                               uint32_t *sclk_mask,
1892                               uint32_t *mclk_mask,
1893                               uint32_t *soc_mask)
1894 {
1895         struct vega20_dpm_table *dpm_table = (struct vega20_dpm_table *)smu->smu_dpm.dpm_context;
1896         struct vega20_single_dpm_table *gfx_dpm_table;
1897         struct vega20_single_dpm_table *mem_dpm_table;
1898         struct vega20_single_dpm_table *soc_dpm_table;
1899
1900         if (!smu->smu_dpm.dpm_context)
1901                 return -EINVAL;
1902
1903         gfx_dpm_table = &dpm_table->gfx_table;
1904         mem_dpm_table = &dpm_table->mem_table;
1905         soc_dpm_table = &dpm_table->soc_table;
1906
1907         *sclk_mask = 0;
1908         *mclk_mask = 0;
1909         *soc_mask  = 0;
1910
1911         if (gfx_dpm_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
1912             mem_dpm_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL &&
1913             soc_dpm_table->count > VEGA20_UMD_PSTATE_SOCCLK_LEVEL) {
1914                 *sclk_mask = VEGA20_UMD_PSTATE_GFXCLK_LEVEL;
1915                 *mclk_mask = VEGA20_UMD_PSTATE_MCLK_LEVEL;
1916                 *soc_mask  = VEGA20_UMD_PSTATE_SOCCLK_LEVEL;
1917         }
1918
1919         if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
1920                 *sclk_mask = 0;
1921         } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
1922                 *mclk_mask = 0;
1923         } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
1924                 *sclk_mask = gfx_dpm_table->count - 1;
1925                 *mclk_mask = mem_dpm_table->count - 1;
1926                 *soc_mask  = soc_dpm_table->count - 1;
1927         }
1928
1929         return 0;
1930 }
1931
1932 static int
1933 vega20_set_uclk_to_highest_dpm_level(struct smu_context *smu,
1934                                      struct vega20_single_dpm_table *dpm_table)
1935 {
1936         int ret = 0;
1937         struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
1938         if (!smu_dpm_ctx->dpm_context)
1939                 return -EINVAL;
1940
1941         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
1942                 if (dpm_table->count <= 0) {
1943                         pr_err("[%s] Dpm table has no entry!", __func__);
1944                                 return -EINVAL;
1945                 }
1946
1947                 if (dpm_table->count > NUM_UCLK_DPM_LEVELS) {
1948                         pr_err("[%s] Dpm table has too many entries!", __func__);
1949                                 return -EINVAL;
1950                 }
1951
1952                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
1953                 ret = smu_send_smc_msg_with_param(smu,
1954                                 SMU_MSG_SetHardMinByFreq,
1955                                 (PPCLK_UCLK << 16) | dpm_table->dpm_state.hard_min_level);
1956                 if (ret) {
1957                         pr_err("[%s] Set hard min uclk failed!", __func__);
1958                                 return ret;
1959                 }
1960         }
1961
1962         return ret;
1963 }
1964
1965 static int vega20_pre_display_config_changed(struct smu_context *smu)
1966 {
1967         int ret = 0;
1968         struct vega20_dpm_table *dpm_table = smu->smu_dpm.dpm_context;
1969
1970         if (!smu->smu_dpm.dpm_context)
1971                 return -EINVAL;
1972
1973         smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, 0);
1974         ret = vega20_set_uclk_to_highest_dpm_level(smu,
1975                                                    &dpm_table->mem_table);
1976         if (ret)
1977                 pr_err("Failed to set uclk to highest dpm level");
1978         return ret;
1979 }
1980
1981 static int vega20_display_config_changed(struct smu_context *smu)
1982 {
1983         int ret = 0;
1984
1985         if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
1986             !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
1987                 ret = smu_write_watermarks_table(smu);
1988                 if (ret) {
1989                         pr_err("Failed to update WMTABLE!");
1990                         return ret;
1991                 }
1992                 smu->watermarks_bitmap |= WATERMARKS_LOADED;
1993         }
1994
1995         if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
1996             smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
1997             smu_feature_is_supported(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
1998                 smu_send_smc_msg_with_param(smu,
1999                                             SMU_MSG_NumOfDisplays,
2000                                             smu->display_config->num_display);
2001         }
2002
2003         return ret;
2004 }
2005
2006 static int vega20_apply_clocks_adjust_rules(struct smu_context *smu)
2007 {
2008         struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
2009         struct vega20_dpm_table *dpm_ctx = (struct vega20_dpm_table *)(smu_dpm_ctx->dpm_context);
2010         struct vega20_single_dpm_table *dpm_table;
2011         bool vblank_too_short = false;
2012         bool disable_mclk_switching;
2013         uint32_t i, latency;
2014
2015         disable_mclk_switching = ((1 < smu->display_config->num_display) &&
2016                                   !smu->display_config->multi_monitor_in_sync) || vblank_too_short;
2017         latency = smu->display_config->dce_tolerable_mclk_in_active_latency;
2018
2019         /* gfxclk */
2020         dpm_table = &(dpm_ctx->gfx_table);
2021         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2022         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2023         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2024         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2025
2026                 if (VEGA20_UMD_PSTATE_GFXCLK_LEVEL < dpm_table->count) {
2027                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
2028                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
2029                 }
2030
2031                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
2032                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2033                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
2034                 }
2035
2036                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2037                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2038                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2039                 }
2040
2041         /* memclk */
2042         dpm_table = &(dpm_ctx->mem_table);
2043         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2044         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2045         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2046         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2047
2048                 if (VEGA20_UMD_PSTATE_MCLK_LEVEL < dpm_table->count) {
2049                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
2050                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
2051                 }
2052
2053                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
2054                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2055                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value;
2056                 }
2057
2058                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2059                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2060                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2061                 }
2062
2063         /* honour DAL's UCLK Hardmin */
2064         if (dpm_table->dpm_state.hard_min_level < (smu->display_config->min_mem_set_clock / 100))
2065                 dpm_table->dpm_state.hard_min_level = smu->display_config->min_mem_set_clock / 100;
2066
2067         /* Hardmin is dependent on displayconfig */
2068         if (disable_mclk_switching) {
2069                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2070                 for (i = 0; i < smu_dpm_ctx->mclk_latency_table->count - 1; i++) {
2071                         if (smu_dpm_ctx->mclk_latency_table->entries[i].latency <= latency) {
2072                                 if (dpm_table->dpm_levels[i].value >= (smu->display_config->min_mem_set_clock / 100)) {
2073                                         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[i].value;
2074                                         break;
2075                                 }
2076                         }
2077                 }
2078         }
2079
2080         if (smu->display_config->nb_pstate_switch_disable)
2081                 dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2082
2083         /* vclk */
2084         dpm_table = &(dpm_ctx->vclk_table);
2085         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2086         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2087         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2088         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2089
2090                 if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
2091                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
2092                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
2093                 }
2094
2095                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2096                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2097                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2098                 }
2099
2100         /* dclk */
2101         dpm_table = &(dpm_ctx->dclk_table);
2102         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2103         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2104         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2105         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2106
2107                 if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) {
2108                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
2109                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value;
2110                 }
2111
2112                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2113                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2114                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2115                 }
2116
2117         /* socclk */
2118         dpm_table = &(dpm_ctx->soc_table);
2119         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2120         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2121         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2122         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2123
2124                 if (VEGA20_UMD_PSTATE_SOCCLK_LEVEL < dpm_table->count) {
2125                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
2126                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value;
2127                 }
2128
2129                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2130                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2131                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2132                 }
2133
2134         /* eclk */
2135         dpm_table = &(dpm_ctx->eclk_table);
2136         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value;
2137         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2138         dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value;
2139         dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2140
2141                 if (VEGA20_UMD_PSTATE_VCEMCLK_LEVEL < dpm_table->count) {
2142                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
2143                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value;
2144                 }
2145
2146                 if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
2147                         dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2148                         dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
2149                 }
2150         return 0;
2151 }
2152
2153 static int
2154 vega20_notify_smc_dispaly_config(struct smu_context *smu)
2155 {
2156         struct vega20_dpm_table *dpm_table = smu->smu_dpm.dpm_context;
2157         struct vega20_single_dpm_table *memtable = &dpm_table->mem_table;
2158         struct smu_clocks min_clocks = {0};
2159         struct pp_display_clock_request clock_req;
2160         int ret = 0;
2161
2162         min_clocks.dcef_clock = smu->display_config->min_dcef_set_clk;
2163         min_clocks.dcef_clock_in_sr = smu->display_config->min_dcef_deep_sleep_set_clk;
2164         min_clocks.memory_clock = smu->display_config->min_mem_set_clock;
2165
2166         if (smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
2167                 clock_req.clock_type = amd_pp_dcef_clock;
2168                 clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10;
2169                 if (!smu->funcs->display_clock_voltage_request(smu, &clock_req)) {
2170                         if (smu_feature_is_supported(smu, SMU_FEATURE_DS_DCEFCLK_BIT)) {
2171                                 ret = smu_send_smc_msg_with_param(smu,
2172                                                                   SMU_MSG_SetMinDeepSleepDcefclk,
2173                                                                   min_clocks.dcef_clock_in_sr/100);
2174                                 if (ret) {
2175                                         pr_err("Attempt to set divider for DCEFCLK Failed!");
2176                                         return ret;
2177                                 }
2178                         }
2179                 } else {
2180                         pr_info("Attempt to set Hard Min for DCEFCLK Failed!");
2181                 }
2182         }
2183
2184         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
2185                 memtable->dpm_state.hard_min_level = min_clocks.memory_clock/100;
2186                 ret = smu_send_smc_msg_with_param(smu,
2187                                                   SMU_MSG_SetHardMinByFreq,
2188                                                   (PPCLK_UCLK << 16) | memtable->dpm_state.hard_min_level);
2189                 if (ret) {
2190                         pr_err("[%s] Set hard min uclk failed!", __func__);
2191                         return ret;
2192                 }
2193         }
2194
2195         return 0;
2196 }
2197
2198 static uint32_t vega20_find_lowest_dpm_level(struct vega20_single_dpm_table *table)
2199 {
2200         uint32_t i;
2201
2202         for (i = 0; i < table->count; i++) {
2203                 if (table->dpm_levels[i].enabled)
2204                         break;
2205         }
2206         if (i >= table->count) {
2207                 i = 0;
2208                 table->dpm_levels[i].enabled = true;
2209         }
2210
2211         return i;
2212 }
2213
2214 static uint32_t vega20_find_highest_dpm_level(struct vega20_single_dpm_table *table)
2215 {
2216         int i = 0;
2217
2218         if (!table) {
2219                 pr_err("[%s] DPM Table does not exist!", __func__);
2220                 return 0;
2221         }
2222         if (table->count <= 0) {
2223                 pr_err("[%s] DPM Table has no entry!", __func__);
2224                 return 0;
2225         }
2226         if (table->count > MAX_REGULAR_DPM_NUMBER) {
2227                 pr_err("[%s] DPM Table has too many entries!", __func__);
2228                 return MAX_REGULAR_DPM_NUMBER - 1;
2229         }
2230
2231         for (i = table->count - 1; i >= 0; i--) {
2232                 if (table->dpm_levels[i].enabled)
2233                         break;
2234         }
2235         if (i < 0) {
2236                 i = 0;
2237                 table->dpm_levels[i].enabled = true;
2238         }
2239
2240         return i;
2241 }
2242
2243 static int vega20_force_dpm_limit_value(struct smu_context *smu, bool highest)
2244 {
2245         uint32_t soft_level;
2246         int ret = 0;
2247         struct vega20_dpm_table *dpm_table =
2248                 (struct vega20_dpm_table *)smu->smu_dpm.dpm_context;
2249
2250         if (highest)
2251                 soft_level = vega20_find_highest_dpm_level(&(dpm_table->gfx_table));
2252         else
2253                 soft_level = vega20_find_lowest_dpm_level(&(dpm_table->gfx_table));
2254
2255         dpm_table->gfx_table.dpm_state.soft_min_level =
2256                 dpm_table->gfx_table.dpm_state.soft_max_level =
2257                 dpm_table->gfx_table.dpm_levels[soft_level].value;
2258
2259         if (highest)
2260                 soft_level = vega20_find_highest_dpm_level(&(dpm_table->mem_table));
2261         else
2262                 soft_level = vega20_find_lowest_dpm_level(&(dpm_table->mem_table));
2263
2264         dpm_table->mem_table.dpm_state.soft_min_level =
2265                 dpm_table->mem_table.dpm_state.soft_max_level =
2266                 dpm_table->mem_table.dpm_levels[soft_level].value;
2267
2268         if (highest)
2269                 soft_level = vega20_find_highest_dpm_level(&(dpm_table->soc_table));
2270         else
2271                 soft_level = vega20_find_lowest_dpm_level(&(dpm_table->soc_table));
2272
2273         dpm_table->soc_table.dpm_state.soft_min_level =
2274                 dpm_table->soc_table.dpm_state.soft_max_level =
2275                 dpm_table->soc_table.dpm_levels[soft_level].value;
2276
2277         ret = vega20_upload_dpm_level(smu, false, 0xFFFFFFFF);
2278         if (ret) {
2279                 pr_err("Failed to upload boot level to %s!\n",
2280                                 highest ? "highest" : "lowest");
2281                 return ret;
2282         }
2283
2284         ret = vega20_upload_dpm_level(smu, true, 0xFFFFFFFF);
2285         if (ret) {
2286                 pr_err("Failed to upload dpm max level to %s!\n!",
2287                                 highest ? "highest" : "lowest");
2288                 return ret;
2289         }
2290
2291         return ret;
2292 }
2293
2294 static int vega20_unforce_dpm_levels(struct smu_context *smu)
2295 {
2296         uint32_t soft_min_level, soft_max_level;
2297         int ret = 0;
2298         struct vega20_dpm_table *dpm_table =
2299                 (struct vega20_dpm_table *)smu->smu_dpm.dpm_context;
2300
2301         soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table->gfx_table));
2302         soft_max_level = vega20_find_highest_dpm_level(&(dpm_table->gfx_table));
2303         dpm_table->gfx_table.dpm_state.soft_min_level =
2304                 dpm_table->gfx_table.dpm_levels[soft_min_level].value;
2305         dpm_table->gfx_table.dpm_state.soft_max_level =
2306                 dpm_table->gfx_table.dpm_levels[soft_max_level].value;
2307
2308         soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table->mem_table));
2309         soft_max_level = vega20_find_highest_dpm_level(&(dpm_table->mem_table));
2310         dpm_table->mem_table.dpm_state.soft_min_level =
2311                 dpm_table->gfx_table.dpm_levels[soft_min_level].value;
2312         dpm_table->mem_table.dpm_state.soft_max_level =
2313                 dpm_table->gfx_table.dpm_levels[soft_max_level].value;
2314
2315         soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table->soc_table));
2316         soft_max_level = vega20_find_highest_dpm_level(&(dpm_table->soc_table));
2317         dpm_table->soc_table.dpm_state.soft_min_level =
2318                 dpm_table->soc_table.dpm_levels[soft_min_level].value;
2319         dpm_table->soc_table.dpm_state.soft_max_level =
2320                 dpm_table->soc_table.dpm_levels[soft_max_level].value;
2321
2322         ret = vega20_upload_dpm_level(smu, false, 0xFFFFFFFF);
2323         if (ret) {
2324                 pr_err("Failed to upload DPM Bootup Levels!");
2325                 return ret;
2326         }
2327
2328         ret = vega20_upload_dpm_level(smu, true, 0xFFFFFFFF);
2329         if (ret) {
2330                 pr_err("Failed to upload DPM Max Levels!");
2331                 return ret;
2332         }
2333
2334         return ret;
2335 }
2336
2337 static int vega20_update_specified_od8_value(struct smu_context *smu,
2338                                              uint32_t index,
2339                                              uint32_t value)
2340 {
2341         struct smu_table_context *table_context = &smu->smu_table;
2342         OverDriveTable_t *od_table =
2343                 (OverDriveTable_t *)(table_context->overdrive_table);
2344         struct vega20_od8_settings *od8_settings =
2345                 (struct vega20_od8_settings *)table_context->od8_settings;
2346
2347         switch (index) {
2348         case OD8_SETTING_GFXCLK_FMIN:
2349                 od_table->GfxclkFmin = (uint16_t)value;
2350                 break;
2351
2352         case OD8_SETTING_GFXCLK_FMAX:
2353                 if (value < od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].min_value ||
2354                     value > od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value)
2355                         return -EINVAL;
2356                 od_table->GfxclkFmax = (uint16_t)value;
2357                 break;
2358
2359         case OD8_SETTING_GFXCLK_FREQ1:
2360                 od_table->GfxclkFreq1 = (uint16_t)value;
2361                 break;
2362
2363         case OD8_SETTING_GFXCLK_VOLTAGE1:
2364                 od_table->GfxclkVolt1 = (uint16_t)value;
2365                 break;
2366
2367         case OD8_SETTING_GFXCLK_FREQ2:
2368                 od_table->GfxclkFreq2 = (uint16_t)value;
2369                 break;
2370
2371         case OD8_SETTING_GFXCLK_VOLTAGE2:
2372                 od_table->GfxclkVolt2 = (uint16_t)value;
2373                 break;
2374
2375         case OD8_SETTING_GFXCLK_FREQ3:
2376                 od_table->GfxclkFreq3 = (uint16_t)value;
2377                 break;
2378
2379         case OD8_SETTING_GFXCLK_VOLTAGE3:
2380                 od_table->GfxclkVolt3 = (uint16_t)value;
2381                 break;
2382
2383         case OD8_SETTING_UCLK_FMAX:
2384                 if (value < od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].min_value ||
2385                     value > od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value)
2386                         return -EINVAL;
2387                 od_table->UclkFmax = (uint16_t)value;
2388                 break;
2389
2390         case OD8_SETTING_POWER_PERCENTAGE:
2391                 od_table->OverDrivePct = (int16_t)value;
2392                 break;
2393
2394         case OD8_SETTING_FAN_ACOUSTIC_LIMIT:
2395                 od_table->FanMaximumRpm = (uint16_t)value;
2396                 break;
2397
2398         case OD8_SETTING_FAN_MIN_SPEED:
2399                 od_table->FanMinimumPwm = (uint16_t)value;
2400                 break;
2401
2402         case OD8_SETTING_FAN_TARGET_TEMP:
2403                 od_table->FanTargetTemperature = (uint16_t)value;
2404                 break;
2405
2406         case OD8_SETTING_OPERATING_TEMP_MAX:
2407                 od_table->MaxOpTemp = (uint16_t)value;
2408                 break;
2409         }
2410
2411         return 0;
2412 }
2413
2414 static int vega20_set_od_percentage(struct smu_context *smu,
2415                                     enum pp_clock_type type,
2416                                     uint32_t value)
2417 {
2418         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
2419         struct vega20_dpm_table *dpm_table = NULL;
2420         struct vega20_dpm_table *golden_table = NULL;
2421         struct vega20_single_dpm_table *single_dpm_table;
2422         struct vega20_single_dpm_table *golden_dpm_table;
2423         uint32_t od_clk, index;
2424         int ret = 0;
2425         int feature_enabled;
2426         PPCLK_e clk_id;
2427
2428         mutex_lock(&(smu->mutex));
2429
2430         dpm_table = smu_dpm->dpm_context;
2431         golden_table = smu_dpm->golden_dpm_context;
2432
2433         switch (type) {
2434         case OD_SCLK:
2435                 single_dpm_table = &(dpm_table->gfx_table);
2436                 golden_dpm_table = &(golden_table->gfx_table);
2437                 feature_enabled = smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT);
2438                 clk_id = PPCLK_GFXCLK;
2439                 index = OD8_SETTING_GFXCLK_FMAX;
2440                 break;
2441         case OD_MCLK:
2442                 single_dpm_table = &(dpm_table->mem_table);
2443                 golden_dpm_table = &(golden_table->mem_table);
2444                 feature_enabled = smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT);
2445                 clk_id = PPCLK_UCLK;
2446                 index = OD8_SETTING_UCLK_FMAX;
2447                 break;
2448         default:
2449                 ret = -EINVAL;
2450                 break;
2451         }
2452
2453         if (ret)
2454                 goto set_od_failed;
2455
2456         od_clk = golden_dpm_table->dpm_levels[golden_dpm_table->count - 1].value * value;
2457         od_clk /= 100;
2458         od_clk += golden_dpm_table->dpm_levels[golden_dpm_table->count - 1].value;
2459
2460         ret = smu_update_od8_settings(smu, index, od_clk);
2461         if (ret) {
2462                 pr_err("[Setoverdrive] failed to set od clk!\n");
2463                 goto set_od_failed;
2464         }
2465
2466         if (feature_enabled) {
2467                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
2468                                                   clk_id);
2469                 if (ret) {
2470                         pr_err("[Setoverdrive] failed to refresh dpm table!\n");
2471                         goto set_od_failed;
2472                 }
2473         } else {
2474                 single_dpm_table->count = 1;
2475                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
2476         }
2477
2478         ret = smu_handle_task(smu, smu_dpm->dpm_level,
2479                               AMD_PP_TASK_READJUST_POWER_STATE);
2480
2481 set_od_failed:
2482         mutex_unlock(&(smu->mutex));
2483
2484         return ret;
2485 }
2486
2487 static int vega20_odn_edit_dpm_table(struct smu_context *smu,
2488                                      enum PP_OD_DPM_TABLE_COMMAND type,
2489                                      long *input, uint32_t size)
2490 {
2491         struct smu_table_context *table_context = &smu->smu_table;
2492         OverDriveTable_t *od_table =
2493                 (OverDriveTable_t *)(table_context->overdrive_table);
2494         struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
2495         struct vega20_dpm_table *dpm_table = NULL;
2496         struct vega20_single_dpm_table *single_dpm_table;
2497         struct vega20_od8_settings *od8_settings =
2498                 (struct vega20_od8_settings *)table_context->od8_settings;
2499         struct pp_clock_levels_with_latency clocks;
2500         int32_t input_index, input_clk, input_vol, i;
2501         int od8_id;
2502         int ret = 0;
2503
2504         dpm_table = smu_dpm->dpm_context;
2505
2506         if (!input) {
2507                 pr_warn("NULL user input for clock and voltage\n");
2508                 return -EINVAL;
2509         }
2510
2511         switch (type) {
2512         case PP_OD_EDIT_SCLK_VDDC_TABLE:
2513                 if (!(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id &&
2514                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id)) {
2515                         pr_info("Sclk min/max frequency overdrive not supported\n");
2516                         return -EOPNOTSUPP;
2517                 }
2518
2519                 for (i = 0; i < size; i += 2) {
2520                         if (i + 2 > size) {
2521                                 pr_info("invalid number of input parameters %d\n", size);
2522                                 return -EINVAL;
2523                         }
2524
2525                         input_index = input[i];
2526                         input_clk = input[i + 1];
2527
2528                         if (input_index != 0 && input_index != 1) {
2529                                 pr_info("Invalid index %d\n", input_index);
2530                                 pr_info("Support min/max sclk frequency settingonly which index by 0/1\n");
2531                                 return -EINVAL;
2532                         }
2533
2534                         if (input_clk < od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value ||
2535                             input_clk > od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value) {
2536                                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2537                                         input_clk,
2538                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value,
2539                                         od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value);
2540                                 return -EINVAL;
2541                         }
2542
2543                         if (input_index == 0 && od_table->GfxclkFmin != input_clk) {
2544                                 od_table->GfxclkFmin = input_clk;
2545                                 table_context->od_gfxclk_update = true;
2546                         } else if (input_index == 1 && od_table->GfxclkFmax != input_clk) {
2547                                 od_table->GfxclkFmax = input_clk;
2548                                 table_context->od_gfxclk_update = true;
2549                         }
2550                 }
2551
2552                 break;
2553
2554         case PP_OD_EDIT_MCLK_VDDC_TABLE:
2555                 if (!od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) {
2556                         pr_info("Mclk max frequency overdrive not supported\n");
2557                         return -EOPNOTSUPP;
2558                 }
2559
2560                 single_dpm_table = &(dpm_table->mem_table);
2561                 ret = vega20_get_clk_table(smu, &clocks, single_dpm_table);
2562                 if (ret) {
2563                         pr_err("Attempt to get memory clk levels Failed!");
2564                         return ret;
2565                 }
2566
2567                 for (i = 0; i < size; i += 2) {
2568                         if (i + 2 > size) {
2569                                 pr_info("invalid number of input parameters %d\n",
2570                                          size);
2571                                 return -EINVAL;
2572                         }
2573
2574                         input_index = input[i];
2575                         input_clk = input[i + 1];
2576
2577                         if (input_index != 1) {
2578                                 pr_info("Invalid index %d\n", input_index);
2579                                 pr_info("Support max Mclk frequency setting only which index by 1\n");
2580                                 return -EINVAL;
2581                         }
2582
2583                         if (input_clk < clocks.data[0].clocks_in_khz / 1000 ||
2584                             input_clk > od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value) {
2585                                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2586                                         input_clk,
2587                                         clocks.data[0].clocks_in_khz / 1000,
2588                                         od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value);
2589                                 return -EINVAL;
2590                         }
2591
2592                         if (input_index == 1 && od_table->UclkFmax != input_clk) {
2593                                 table_context->od_gfxclk_update = true;
2594                                 od_table->UclkFmax = input_clk;
2595                         }
2596                 }
2597
2598                 break;
2599
2600         case PP_OD_EDIT_VDDC_CURVE:
2601                 if (!(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id &&
2602                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id &&
2603                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id &&
2604                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
2605                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
2606                       od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id)) {
2607                         pr_info("Voltage curve calibrate not supported\n");
2608                         return -EOPNOTSUPP;
2609                 }
2610
2611                 for (i = 0; i < size; i += 3) {
2612                         if (i + 3 > size) {
2613                                 pr_info("invalid number of input parameters %d\n",
2614                                         size);
2615                                 return -EINVAL;
2616                         }
2617
2618                         input_index = input[i];
2619                         input_clk = input[i + 1];
2620                         input_vol = input[i + 2];
2621
2622                         if (input_index > 2) {
2623                                 pr_info("Setting for point %d is not supported\n",
2624                                         input_index + 1);
2625                                 pr_info("Three supported points index by 0, 1, 2\n");
2626                                 return -EINVAL;
2627                         }
2628
2629                         od8_id = OD8_SETTING_GFXCLK_FREQ1 + 2 * input_index;
2630                         if (input_clk < od8_settings->od8_settings_array[od8_id].min_value ||
2631                             input_clk > od8_settings->od8_settings_array[od8_id].max_value) {
2632                                 pr_info("clock freq %d is not within allowed range [%d - %d]\n",
2633                                         input_clk,
2634                                         od8_settings->od8_settings_array[od8_id].min_value,
2635                                         od8_settings->od8_settings_array[od8_id].max_value);
2636                                 return -EINVAL;
2637                         }
2638
2639                         od8_id = OD8_SETTING_GFXCLK_VOLTAGE1 + 2 * input_index;
2640                         if (input_vol < od8_settings->od8_settings_array[od8_id].min_value ||
2641                             input_vol > od8_settings->od8_settings_array[od8_id].max_value) {
2642                                 pr_info("clock voltage %d is not within allowed range [%d- %d]\n",
2643                                         input_vol,
2644                                         od8_settings->od8_settings_array[od8_id].min_value,
2645                                         od8_settings->od8_settings_array[od8_id].max_value);
2646                                 return -EINVAL;
2647                         }
2648
2649                         switch (input_index) {
2650                         case 0:
2651                                 od_table->GfxclkFreq1 = input_clk;
2652                                 od_table->GfxclkVolt1 = input_vol * VOLTAGE_SCALE;
2653                                 break;
2654                         case 1:
2655                                 od_table->GfxclkFreq2 = input_clk;
2656                                 od_table->GfxclkVolt2 = input_vol * VOLTAGE_SCALE;
2657                                 break;
2658                         case 2:
2659                                 od_table->GfxclkFreq3 = input_clk;
2660                                 od_table->GfxclkVolt3 = input_vol * VOLTAGE_SCALE;
2661                                 break;
2662                         }
2663                 }
2664
2665                 break;
2666
2667         case PP_OD_RESTORE_DEFAULT_TABLE:
2668                 ret = smu_update_table(smu, TABLE_OVERDRIVE, table_context->overdrive_table, false);
2669                 if (ret) {
2670                         pr_err("Failed to export over drive table!\n");
2671                         return ret;
2672                 }
2673
2674                 break;
2675
2676         case PP_OD_COMMIT_DPM_TABLE:
2677                 ret = smu_update_table(smu, TABLE_OVERDRIVE, table_context->overdrive_table, true);
2678                 if (ret) {
2679                         pr_err("Failed to import over drive table!\n");
2680                         return ret;
2681                 }
2682
2683                 /* retrieve updated gfxclk table */
2684                 if (table_context->od_gfxclk_update) {
2685                         table_context->od_gfxclk_update = false;
2686                         single_dpm_table = &(dpm_table->gfx_table);
2687
2688                         if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
2689                                 ret = vega20_set_single_dpm_table(smu, single_dpm_table,
2690                                                                   PPCLK_GFXCLK);
2691                                 if (ret) {
2692                                         pr_err("[Setoverdrive] failed to refresh dpm table!\n");
2693                                         return ret;
2694                                 }
2695                         } else {
2696                                 single_dpm_table->count = 1;
2697                                 single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
2698                         }
2699                 }
2700
2701                 break;
2702
2703         default:
2704                 return -EINVAL;
2705         }
2706
2707         if (type == PP_OD_COMMIT_DPM_TABLE) {
2708                 mutex_lock(&(smu->mutex));
2709                 ret = smu_handle_task(smu, smu_dpm->dpm_level,
2710                                       AMD_PP_TASK_READJUST_POWER_STATE);
2711                 mutex_unlock(&(smu->mutex));
2712         }
2713
2714         return ret;
2715 }
2716
2717 static int vega20_dpm_set_uvd_enable(struct smu_context *smu, bool enable)
2718 {
2719         if (!smu_feature_is_supported(smu, SMU_FEATURE_DPM_UVD_BIT))
2720                 return 0;
2721
2722         if (enable == smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT))
2723                 return 0;
2724
2725         return smu_feature_set_enabled(smu, SMU_FEATURE_DPM_UVD_BIT, enable);
2726 }
2727
2728 static int vega20_dpm_set_vce_enable(struct smu_context *smu, bool enable)
2729 {
2730         if (!smu_feature_is_supported(smu, SMU_FEATURE_DPM_VCE_BIT))
2731                 return 0;
2732
2733         if (enable == smu_feature_is_enabled(smu, SMU_FEATURE_DPM_VCE_BIT))
2734                 return 0;
2735
2736         return smu_feature_set_enabled(smu, SMU_FEATURE_DPM_VCE_BIT, enable);
2737 }
2738
2739 static int vega20_get_enabled_smc_features(struct smu_context *smu,
2740                 uint64_t *features_enabled)
2741 {
2742         uint32_t feature_mask[2] = {0, 0};
2743         int ret = 0;
2744
2745         ret = smu_feature_get_enabled_mask(smu, feature_mask, 2);
2746         if (ret)
2747                 return ret;
2748
2749         *features_enabled = ((((uint64_t)feature_mask[0] << SMU_FEATURES_LOW_SHIFT) & SMU_FEATURES_LOW_MASK) |
2750                         (((uint64_t)feature_mask[1] << SMU_FEATURES_HIGH_SHIFT) & SMU_FEATURES_HIGH_MASK));
2751
2752         return ret;
2753 }
2754
2755 static int vega20_enable_smc_features(struct smu_context *smu,
2756                 bool enable, uint64_t feature_mask)
2757 {
2758         uint32_t smu_features_low, smu_features_high;
2759         int ret = 0;
2760
2761         smu_features_low = (uint32_t)((feature_mask & SMU_FEATURES_LOW_MASK) >> SMU_FEATURES_LOW_SHIFT);
2762         smu_features_high = (uint32_t)((feature_mask & SMU_FEATURES_HIGH_MASK) >> SMU_FEATURES_HIGH_SHIFT);
2763
2764         if (enable) {
2765                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesLow,
2766                                                   smu_features_low);
2767                 if (ret)
2768                         return ret;
2769                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesHigh,
2770                                                   smu_features_high);
2771                 if (ret)
2772                         return ret;
2773         } else {
2774                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesLow,
2775                                                   smu_features_low);
2776                 if (ret)
2777                         return ret;
2778                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesHigh,
2779                                                   smu_features_high);
2780                 if (ret)
2781                         return ret;
2782         }
2783
2784         return 0;
2785
2786 }
2787
2788 static int vega20_get_ppfeature_status(struct smu_context *smu, char *buf)
2789 {
2790         static const char *ppfeature_name[] = {
2791                                 "DPM_PREFETCHER",
2792                                 "GFXCLK_DPM",
2793                                 "UCLK_DPM",
2794                                 "SOCCLK_DPM",
2795                                 "UVD_DPM",
2796                                 "VCE_DPM",
2797                                 "ULV",
2798                                 "MP0CLK_DPM",
2799                                 "LINK_DPM",
2800                                 "DCEFCLK_DPM",
2801                                 "GFXCLK_DS",
2802                                 "SOCCLK_DS",
2803                                 "LCLK_DS",
2804                                 "PPT",
2805                                 "TDC",
2806                                 "THERMAL",
2807                                 "GFX_PER_CU_CG",
2808                                 "RM",
2809                                 "DCEFCLK_DS",
2810                                 "ACDC",
2811                                 "VR0HOT",
2812                                 "VR1HOT",
2813                                 "FW_CTF",
2814                                 "LED_DISPLAY",
2815                                 "FAN_CONTROL",
2816                                 "GFX_EDC",
2817                                 "GFXOFF",
2818                                 "CG",
2819                                 "FCLK_DPM",
2820                                 "FCLK_DS",
2821                                 "MP1CLK_DS",
2822                                 "MP0CLK_DS",
2823                                 "XGMI",
2824                                 "ECC"};
2825         static const char *output_title[] = {
2826                                 "FEATURES",
2827                                 "BITMASK",
2828                                 "ENABLEMENT"};
2829         uint64_t features_enabled;
2830         int i;
2831         int ret = 0;
2832         int size = 0;
2833
2834         ret = vega20_get_enabled_smc_features(smu, &features_enabled);
2835         if (ret)
2836                 return ret;
2837
2838         size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", features_enabled);
2839         size += sprintf(buf + size, "%-19s %-22s %s\n",
2840                                 output_title[0],
2841                                 output_title[1],
2842                                 output_title[2]);
2843         for (i = 0; i < GNLD_FEATURES_MAX; i++) {
2844                 size += sprintf(buf + size, "%-19s 0x%016llx %6s\n",
2845                                         ppfeature_name[i],
2846                                         1ULL << i,
2847                                         (features_enabled & (1ULL << i)) ? "Y" : "N");
2848         }
2849
2850         return size;
2851 }
2852
2853 static int vega20_set_ppfeature_status(struct smu_context *smu, uint64_t new_ppfeature_masks)
2854 {
2855         uint64_t features_enabled;
2856         uint64_t features_to_enable;
2857         uint64_t features_to_disable;
2858         int ret = 0;
2859
2860         if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX))
2861                 return -EINVAL;
2862
2863         ret = vega20_get_enabled_smc_features(smu, &features_enabled);
2864         if (ret)
2865                 return ret;
2866
2867         features_to_disable =
2868                 features_enabled & ~new_ppfeature_masks;
2869         features_to_enable =
2870                 ~features_enabled & new_ppfeature_masks;
2871
2872         pr_debug("features_to_disable 0x%llx\n", features_to_disable);
2873         pr_debug("features_to_enable 0x%llx\n", features_to_enable);
2874
2875         if (features_to_disable) {
2876                 ret = vega20_enable_smc_features(smu, false, features_to_disable);
2877                 if (ret)
2878                         return ret;
2879         }
2880
2881         if (features_to_enable) {
2882                 ret = vega20_enable_smc_features(smu, true, features_to_enable);
2883                 if (ret)
2884                         return ret;
2885         }
2886
2887         return 0;
2888 }
2889
2890 static bool vega20_is_dpm_running(struct smu_context *smu)
2891 {
2892         int ret = 0;
2893         uint32_t feature_mask[2];
2894         unsigned long feature_enabled;
2895         ret = smu_feature_get_enabled_mask(smu, feature_mask, 2);
2896         feature_enabled = (unsigned long)((uint64_t)feature_mask[0] |
2897                            ((uint64_t)feature_mask[1] << 32));
2898         return !!(feature_enabled & SMC_DPM_FEATURE);
2899 }
2900
2901 static int vega20_set_thermal_fan_table(struct smu_context *smu)
2902 {
2903         int ret;
2904         struct smu_table_context *table_context = &smu->smu_table;
2905         PPTable_t *pptable = table_context->driver_pptable;
2906
2907         ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetFanTemperatureTarget,
2908                         (uint32_t)pptable->FanTargetTemperature);
2909
2910         return ret;
2911 }
2912
2913 static int vega20_get_fan_speed_percent(struct smu_context *smu,
2914                                         uint32_t *speed)
2915 {
2916         int ret = 0;
2917         uint32_t percent = 0;
2918         uint32_t current_rpm;
2919         PPTable_t *pptable = smu->smu_table.driver_pptable;
2920
2921         ret = smu_get_current_rpm(smu, &current_rpm);
2922         percent = current_rpm * 100 / pptable->FanMaximumRpm;
2923         *speed = percent > 100 ? 100 : percent;
2924
2925         return ret;
2926 }
2927
2928 static int vega20_get_gpu_power(struct smu_context *smu, uint32_t *value)
2929 {
2930         int ret = 0;
2931         SmuMetrics_t metrics;
2932
2933         if (!value)
2934                 return -EINVAL;
2935
2936         ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, (void *)&metrics,
2937                                false);
2938         if (ret)
2939                 return ret;
2940
2941         *value = metrics.CurrSocketPower << 8;
2942
2943         return 0;
2944 }
2945
2946 static int vega20_get_current_activity_percent(struct smu_context *smu,
2947                                                enum amd_pp_sensors sensor,
2948                                                uint32_t *value)
2949 {
2950         int ret = 0;
2951         SmuMetrics_t metrics;
2952
2953         if (!value)
2954                 return -EINVAL;
2955
2956         ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS,
2957                                (void *)&metrics, false);
2958         if (ret)
2959                 return ret;
2960
2961         switch (sensor) {
2962         case AMDGPU_PP_SENSOR_GPU_LOAD:
2963                 *value = metrics.AverageGfxActivity;
2964                 break;
2965         case AMDGPU_PP_SENSOR_MEM_LOAD:
2966                 *value = metrics.AverageUclkActivity;
2967                 break;
2968         default:
2969                 pr_err("Invalid sensor for retrieving clock activity\n");
2970                 return -EINVAL;
2971         }
2972
2973         return 0;
2974 }
2975
2976 static int vega20_read_sensor(struct smu_context *smu,
2977                                  enum amd_pp_sensors sensor,
2978                                  void *data, uint32_t *size)
2979 {
2980         int ret = 0;
2981         struct smu_table_context *table_context = &smu->smu_table;
2982         PPTable_t *pptable = table_context->driver_pptable;
2983
2984         switch (sensor) {
2985         case AMDGPU_PP_SENSOR_MAX_FAN_RPM:
2986                 *(uint32_t *)data = pptable->FanMaximumRpm;
2987                 *size = 4;
2988                 break;
2989         case AMDGPU_PP_SENSOR_MEM_LOAD:
2990         case AMDGPU_PP_SENSOR_GPU_LOAD:
2991                 ret = vega20_get_current_activity_percent(smu,
2992                                                 sensor,
2993                                                 (uint32_t *)data);
2994                 *size = 4;
2995                 break;
2996         case AMDGPU_PP_SENSOR_GPU_POWER:
2997                 ret = vega20_get_gpu_power(smu, (uint32_t *)data);
2998                 *size = 4;
2999                 break;
3000         default:
3001                 return -EINVAL;
3002         }
3003
3004         return ret;
3005 }
3006
3007 static int vega20_set_watermarks_table(struct smu_context *smu,
3008                                        void *watermarks, struct
3009                                        dm_pp_wm_sets_with_clock_ranges_soc15
3010                                        *clock_ranges)
3011 {
3012         int i;
3013         Watermarks_t *table = watermarks;
3014
3015         if (!table || !clock_ranges)
3016                 return -EINVAL;
3017
3018         if (clock_ranges->num_wm_dmif_sets > 4 ||
3019             clock_ranges->num_wm_mcif_sets > 4)
3020                 return -EINVAL;
3021
3022         for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) {
3023                 table->WatermarkRow[1][i].MinClock =
3024                         cpu_to_le16((uint16_t)
3025                         (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz /
3026                         1000));
3027                 table->WatermarkRow[1][i].MaxClock =
3028                         cpu_to_le16((uint16_t)
3029                         (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz /
3030                         1000));
3031                 table->WatermarkRow[1][i].MinUclk =
3032                         cpu_to_le16((uint16_t)
3033                         (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz /
3034                         1000));
3035                 table->WatermarkRow[1][i].MaxUclk =
3036                         cpu_to_le16((uint16_t)
3037                         (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz /
3038                         1000));
3039                 table->WatermarkRow[1][i].WmSetting = (uint8_t)
3040                                 clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id;
3041         }
3042
3043         for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) {
3044                 table->WatermarkRow[0][i].MinClock =
3045                         cpu_to_le16((uint16_t)
3046                         (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz /
3047                         1000));
3048                 table->WatermarkRow[0][i].MaxClock =
3049                         cpu_to_le16((uint16_t)
3050                         (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz /
3051                         1000));
3052                 table->WatermarkRow[0][i].MinUclk =
3053                         cpu_to_le16((uint16_t)
3054                         (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz /
3055                         1000));
3056                 table->WatermarkRow[0][i].MaxUclk =
3057                         cpu_to_le16((uint16_t)
3058                         (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz /
3059                         1000));
3060                 table->WatermarkRow[0][i].WmSetting = (uint8_t)
3061                                 clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
3062         }
3063
3064         return 0;
3065 }
3066
3067 static const struct pptable_funcs vega20_ppt_funcs = {
3068         .tables_init = vega20_tables_init,
3069         .alloc_dpm_context = vega20_allocate_dpm_context,
3070         .store_powerplay_table = vega20_store_powerplay_table,
3071         .check_powerplay_table = vega20_check_powerplay_table,
3072         .append_powerplay_table = vega20_append_powerplay_table,
3073         .get_smu_msg_index = vega20_get_smu_msg_index,
3074         .get_smu_clk_index = vega20_get_smu_clk_index,
3075         .get_smu_feature_index = vega20_get_smu_feature_index,
3076         .get_smu_table_index = vega20_get_smu_table_index,
3077         .get_smu_power_index = vega20_get_pwr_src_index,
3078         .get_workload_type = vega20_get_workload_type,
3079         .run_afll_btc = vega20_run_btc_afll,
3080         .get_allowed_feature_mask = vega20_get_allowed_feature_mask,
3081         .get_current_power_state = vega20_get_current_power_state,
3082         .set_default_dpm_table = vega20_set_default_dpm_table,
3083         .set_power_state = NULL,
3084         .populate_umd_state_clk = vega20_populate_umd_state_clk,
3085         .print_clk_levels = vega20_print_clk_levels,
3086         .force_clk_levels = vega20_force_clk_levels,
3087         .get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency,
3088         .set_default_od8_settings = vega20_set_default_od8_setttings,
3089         .get_od_percentage = vega20_get_od_percentage,
3090         .get_power_profile_mode = vega20_get_power_profile_mode,
3091         .set_power_profile_mode = vega20_set_power_profile_mode,
3092         .update_specified_od8_value = vega20_update_specified_od8_value,
3093         .set_od_percentage = vega20_set_od_percentage,
3094         .od_edit_dpm_table = vega20_odn_edit_dpm_table,
3095         .dpm_set_uvd_enable = vega20_dpm_set_uvd_enable,
3096         .dpm_set_vce_enable = vega20_dpm_set_vce_enable,
3097         .read_sensor = vega20_read_sensor,
3098         .pre_display_config_changed = vega20_pre_display_config_changed,
3099         .display_config_changed = vega20_display_config_changed,
3100         .apply_clocks_adjust_rules = vega20_apply_clocks_adjust_rules,
3101         .notify_smc_dispaly_config = vega20_notify_smc_dispaly_config,
3102         .force_dpm_limit_value = vega20_force_dpm_limit_value,
3103         .unforce_dpm_levels = vega20_unforce_dpm_levels,
3104         .get_profiling_clk_mask = vega20_get_profiling_clk_mask,
3105         .set_ppfeature_status = vega20_set_ppfeature_status,
3106         .get_ppfeature_status = vega20_get_ppfeature_status,
3107         .is_dpm_running = vega20_is_dpm_running,
3108         .set_thermal_fan_table = vega20_set_thermal_fan_table,
3109         .get_fan_speed_percent = vega20_get_fan_speed_percent,
3110         .set_watermarks_table = vega20_set_watermarks_table,
3111 };
3112
3113 void vega20_set_ppt_funcs(struct smu_context *smu)
3114 {
3115         struct smu_table_context *smu_table = &smu->smu_table;
3116
3117         smu->ppt_funcs = &vega20_ppt_funcs;
3118         smu->smc_if_version = SMU11_DRIVER_IF_VERSION;
3119         smu_table->table_count = TABLE_COUNT;
3120 }