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