Linux Audio

Check our new training course

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