File Index
Files and directories
Sign in
FILE

yellow_carp_ppt.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c C
   1/*
   2 * Copyright 2020 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#define SWSMU_CODE_LAYER_L2
  25
  26#include "amdgpu.h"
  27#include "amdgpu_smu.h"
  28#include "smu_v13_0.h"
  29#include "smu13_driver_if_yellow_carp.h"
  30#include "yellow_carp_ppt.h"
  31#include "smu_v13_0_1_ppsmc.h"
  32#include "smu_v13_0_1_pmfw.h"
  33#include "smu_cmn.h"
  34
  35/*
  36 * DO NOT use these for err/warn/info/debug messages.
  37 * Use dev_err, dev_warn, dev_info and dev_dbg instead.
  38 * They are more MGPU friendly.
  39 */
  40#undef pr_err
  41#undef pr_warn
  42#undef pr_info
  43#undef pr_debug
  44
  45#define regSMUIO_GFX_MISC_CNTL  						0x00c5
  46#define regSMUIO_GFX_MISC_CNTL_BASE_IDX					0
  47#define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK		0x00000006L
  48#define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT          0x1L
  49
  50#define SMU_13_0_8_UMD_PSTATE_GFXCLK                   533
  51#define SMU_13_0_8_UMD_PSTATE_SOCCLK                   533
  52#define SMU_13_0_8_UMD_PSTATE_FCLK                     800
  53
  54#define SMU_13_0_1_UMD_PSTATE_GFXCLK					700
  55#define SMU_13_0_1_UMD_PSTATE_SOCCLK		              678
  56#define SMU_13_0_1_UMD_PSTATE_FCLK			          1800
  57
  58#define FEATURE_MASK(feature) (1ULL << feature)
  59#define SMC_DPM_FEATURE ( \
  60	FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \
  61	FEATURE_MASK(FEATURE_VCN_DPM_BIT)	 | \
  62	FEATURE_MASK(FEATURE_FCLK_DPM_BIT)	 | \
  63	FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT)	 | \
  64	FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT)	 | \
  65	FEATURE_MASK(FEATURE_LCLK_DPM_BIT)	 | \
  66	FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT)	 | \
  67	FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \
  68	FEATURE_MASK(FEATURE_GFX_DPM_BIT))
  69
  70static struct cmn2asic_msg_mapping yellow_carp_message_map[SMU_MSG_MAX_COUNT] = {
  71	MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,			1),
  72	MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion,		1),
  73	MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion,		1),
  74	MSG_MAP(EnableGfxOff,                   PPSMC_MSG_EnableGfxOff,			1),
  75	MSG_MAP(AllowGfxOff,                    PPSMC_MSG_AllowGfxOff,			1),
  76	MSG_MAP(DisallowGfxOff,                 PPSMC_MSG_DisallowGfxOff,		1),
  77	MSG_MAP(PowerDownVcn,                   PPSMC_MSG_PowerDownVcn,			1),
  78	MSG_MAP(PowerUpVcn,                     PPSMC_MSG_PowerUpVcn,			1),
  79	MSG_MAP(SetHardMinVcn,                  PPSMC_MSG_SetHardMinVcn,		1),
  80	MSG_MAP(PrepareMp1ForUnload,            PPSMC_MSG_PrepareMp1ForUnload,      1),
  81	MSG_MAP(SetDriverDramAddrHigh,          PPSMC_MSG_SetDriverDramAddrHigh,	1),
  82	MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverDramAddrLow,		1),
  83	MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram,	1),
  84	MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu,	1),
  85	MSG_MAP(GfxDeviceDriverReset,           PPSMC_MSG_GfxDeviceDriverReset,		1),
  86	MSG_MAP(GetEnabledSmuFeatures,          PPSMC_MSG_GetEnabledSmuFeatures,	1),
  87	MSG_MAP(SetHardMinSocclkByFreq,         PPSMC_MSG_SetHardMinSocclkByFreq,	1),
  88	MSG_MAP(SetSoftMinVcn,                  PPSMC_MSG_SetSoftMinVcn,		1),
  89	MSG_MAP(GetGfxclkFrequency,             PPSMC_MSG_GetGfxclkFrequency,		1),
  90	MSG_MAP(GetFclkFrequency,               PPSMC_MSG_GetFclkFrequency,		1),
  91	MSG_MAP(SetSoftMaxGfxClk,               PPSMC_MSG_SetSoftMaxGfxClk,		1),
  92	MSG_MAP(SetHardMinGfxClk,               PPSMC_MSG_SetHardMinGfxClk,		1),
  93	MSG_MAP(SetSoftMaxSocclkByFreq,         PPSMC_MSG_SetSoftMaxSocclkByFreq,	1),
  94	MSG_MAP(SetSoftMaxFclkByFreq,           PPSMC_MSG_SetSoftMaxFclkByFreq,		1),
  95	MSG_MAP(SetSoftMaxVcn,                  PPSMC_MSG_SetSoftMaxVcn,		1),
  96	MSG_MAP(SetPowerLimitPercentage,        PPSMC_MSG_SetPowerLimitPercentage,	1),
  97	MSG_MAP(PowerDownJpeg,                  PPSMC_MSG_PowerDownJpeg,		1),
  98	MSG_MAP(PowerUpJpeg,                    PPSMC_MSG_PowerUpJpeg,			1),
  99	MSG_MAP(SetHardMinFclkByFreq,           PPSMC_MSG_SetHardMinFclkByFreq,		1),
 100	MSG_MAP(SetSoftMinSocclkByFreq,         PPSMC_MSG_SetSoftMinSocclkByFreq,	1),
 101};
 102
 103static struct cmn2asic_mapping yellow_carp_feature_mask_map[SMU_FEATURE_COUNT] = {
 104	FEA_MAP(CCLK_DPM),
 105	FEA_MAP(FAN_CONTROLLER),
 106	FEA_MAP(PPT),
 107	FEA_MAP(TDC),
 108	FEA_MAP(THERMAL),
 109	FEA_MAP(ULV),
 110	FEA_MAP(VCN_DPM),
 111	FEA_MAP_REVERSE(FCLK),
 112	FEA_MAP_REVERSE(SOCCLK),
 113	FEA_MAP(LCLK_DPM),
 114	FEA_MAP(SHUBCLK_DPM),
 115	FEA_MAP(DCFCLK_DPM),
 116	FEA_MAP_HALF_REVERSE(GFX),
 117	FEA_MAP(DS_GFXCLK),
 118	FEA_MAP(DS_SOCCLK),
 119	FEA_MAP(DS_LCLK),
 120	FEA_MAP(DS_DCFCLK),
 121	FEA_MAP(DS_FCLK),
 122	FEA_MAP(DS_MP1CLK),
 123	FEA_MAP(DS_MP0CLK),
 124	FEA_MAP(GFX_DEM),
 125	FEA_MAP(PSI),
 126	FEA_MAP(PROCHOT),
 127	FEA_MAP(CPUOFF),
 128	FEA_MAP(STAPM),
 129	FEA_MAP(S0I3),
 130	FEA_MAP(PERF_LIMIT),
 131	FEA_MAP(CORE_DLDO),
 132	FEA_MAP(RSMU_LOW_POWER),
 133	FEA_MAP(SMN_LOW_POWER),
 134	FEA_MAP(THM_LOW_POWER),
 135	FEA_MAP(SMUIO_LOW_POWER),
 136	FEA_MAP(MP1_LOW_POWER),
 137	FEA_MAP(DS_VCN),
 138	FEA_MAP(CPPC),
 139	FEA_MAP(DF_CSTATES),
 140	FEA_MAP(MSMU_LOW_POWER),
 141	FEA_MAP(ATHUB_PG),
 142};
 143
 144static struct cmn2asic_mapping yellow_carp_table_map[SMU_TABLE_COUNT] = {
 145	TAB_MAP_VALID(WATERMARKS),
 146	TAB_MAP_VALID(SMU_METRICS),
 147	TAB_MAP_VALID(CUSTOM_DPM),
 148	TAB_MAP_VALID(DPMCLOCKS),
 149};
 150	
 151static int yellow_carp_init_smc_tables(struct smu_context *smu)
 152{
 153	struct smu_table_context *smu_table = &smu->smu_table;
 154	struct smu_table *tables = smu_table->tables;
 155
 156	SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
 157		PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 158	SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
 159		PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 160	SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
 161		PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
 162
 163	smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
 164	if (!smu_table->clocks_table)
 165		goto err0_out;
 166
 167	smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
 168	if (!smu_table->metrics_table)
 169		goto err1_out;
 170	smu_table->metrics_time = 0;
 171
 172	smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
 173	if (!smu_table->watermarks_table)
 174		goto err2_out;
 175
 176	smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_1);
 177	smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
 178	if (!smu_table->gpu_metrics_table)
 179		goto err3_out;
 180
 181	return 0;
 182
 183err3_out:
 184	kfree(smu_table->watermarks_table);
 185err2_out:
 186	kfree(smu_table->metrics_table);
 187err1_out:
 188	kfree(smu_table->clocks_table);
 189err0_out:
 190	return -ENOMEM;
 191}
 192
 193static int yellow_carp_fini_smc_tables(struct smu_context *smu)
 194{
 195	struct smu_table_context *smu_table = &smu->smu_table;
 196
 197	kfree(smu_table->clocks_table);
 198	smu_table->clocks_table = NULL;
 199
 200	kfree(smu_table->metrics_table);
 201	smu_table->metrics_table = NULL;
 202
 203	kfree(smu_table->watermarks_table);
 204	smu_table->watermarks_table = NULL;
 205
 206	kfree(smu_table->gpu_metrics_table);
 207	smu_table->gpu_metrics_table = NULL;
 208
 209	return 0;
 210}
 211
 212static int yellow_carp_system_features_control(struct smu_context *smu, bool en)
 213{
 214	struct amdgpu_device *adev = smu->adev;
 215	int ret = 0;
 216
 217	if (!en && !adev->in_s0ix)
 218		ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL);
 219
 220	return ret;
 221}
 222
 223static int yellow_carp_dpm_set_vcn_enable(struct smu_context *smu,
 224					   bool enable,
 225					   int inst)
 226{
 227	int ret = 0;
 228
 229	/* vcn dpm on is a prerequisite for vcn power gate messages */
 230	if (enable)
 231		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn,
 232						      0, NULL);
 233	else
 234		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn,
 235						      0, NULL);
 236
 237	return ret;
 238}
 239
 240static int yellow_carp_dpm_set_jpeg_enable(struct smu_context *smu, bool enable)
 241{
 242	int ret = 0;
 243
 244	if (enable)
 245		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg,
 246						      0, NULL);
 247	else
 248		ret = smu_cmn_send_smc_msg_with_param(smu,
 249						      SMU_MSG_PowerDownJpeg, 0,
 250						      NULL);
 251
 252	return ret;
 253}
 254
 255
 256static bool yellow_carp_is_dpm_running(struct smu_context *smu)
 257{
 258	int ret = 0;
 259	uint64_t feature_enabled;
 260
 261	ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
 262
 263	if (ret)
 264		return false;
 265
 266	return !!(feature_enabled & SMC_DPM_FEATURE);
 267}
 268
 269static int yellow_carp_post_smu_init(struct smu_context *smu)
 270{
 271	struct amdgpu_device *adev = smu->adev;
 272	int ret = 0;
 273
 274	/* allow message will be sent after enable message on Yellow Carp*/
 275	ret = smu_cmn_send_smc_msg(smu, SMU_MSG_EnableGfxOff, NULL);
 276	if (ret)
 277		dev_err(adev->dev, "Failed to Enable GfxOff!\n");
 278	return ret;
 279}
 280
 281static int yellow_carp_mode_reset(struct smu_context *smu, int type)
 282{
 283	int ret = 0;
 284
 285	ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, type, NULL);
 286	if (ret)
 287		dev_err(smu->adev->dev, "Failed to mode reset!\n");
 288
 289	return ret;
 290}
 291
 292static int yellow_carp_mode2_reset(struct smu_context *smu)
 293{
 294	return yellow_carp_mode_reset(smu, SMU_RESET_MODE_2);
 295}
 296
 297
 298static void yellow_carp_get_ss_power_percent(SmuMetrics_t *metrics,
 299					uint32_t *apu_percent, uint32_t *dgpu_percent)
 300{
 301	uint32_t apu_boost = 0;
 302	uint32_t dgpu_boost = 0;
 303	uint16_t apu_limit = 0;
 304	uint16_t dgpu_limit = 0;
 305	uint16_t apu_power = 0;
 306	uint16_t dgpu_power = 0;
 307
 308	/* APU and dGPU power values are reported in milli Watts
 309	 * and STAPM power limits are in Watts */
 310	apu_power = metrics->ApuPower/1000;
 311	apu_limit = metrics->StapmOpnLimit;
 312	if (apu_power > apu_limit && apu_limit != 0)
 313		apu_boost =  ((apu_power - apu_limit) * 100) / apu_limit;
 314	apu_boost = (apu_boost > 100) ? 100 : apu_boost;
 315
 316	dgpu_power = metrics->dGpuPower/1000;
 317	if (metrics->StapmCurrentLimit > metrics->StapmOpnLimit)
 318		dgpu_limit = metrics->StapmCurrentLimit - metrics->StapmOpnLimit;
 319	if (dgpu_power > dgpu_limit && dgpu_limit != 0)
 320		dgpu_boost = ((dgpu_power - dgpu_limit) * 100) / dgpu_limit;
 321	dgpu_boost = (dgpu_boost > 100) ? 100 : dgpu_boost;
 322
 323	if (dgpu_boost >= apu_boost)
 324		apu_boost = 0;
 325	else
 326		dgpu_boost = 0;
 327
 328	*apu_percent = apu_boost;
 329	*dgpu_percent = dgpu_boost;
 330
 331}
 332
 333static int yellow_carp_get_smu_metrics_data(struct smu_context *smu,
 334							MetricsMember_t member,
 335							uint32_t *value)
 336{
 337	struct smu_table_context *smu_table = &smu->smu_table;
 338
 339	SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
 340	int ret = 0;
 341	uint32_t apu_percent = 0;
 342	uint32_t dgpu_percent = 0;
 343
 344	ret = smu_cmn_get_metrics_table(smu, NULL, false);
 345	if (ret)
 346		return ret;
 347
 348	switch (member) {
 349	case METRICS_AVERAGE_GFXCLK:
 350		*value = metrics->GfxclkFrequency;
 351		break;
 352	case METRICS_AVERAGE_SOCCLK:
 353		*value = metrics->SocclkFrequency;
 354		break;
 355	case METRICS_AVERAGE_VCLK:
 356		*value = metrics->VclkFrequency;
 357		break;
 358	case METRICS_AVERAGE_DCLK:
 359		*value = metrics->DclkFrequency;
 360		break;
 361	case METRICS_AVERAGE_UCLK:
 362		*value = metrics->MemclkFrequency;
 363		break;
 364	case METRICS_AVERAGE_GFXACTIVITY:
 365		*value = metrics->GfxActivity / 100;
 366		break;
 367	case METRICS_AVERAGE_VCNACTIVITY:
 368		*value = metrics->UvdActivity / 100;
 369		break;
 370	case METRICS_CURR_SOCKETPOWER:
 371		*value = (metrics->CurrentSocketPower << 8) / 1000;
 372		break;
 373	case METRICS_TEMPERATURE_EDGE:
 374		*value = metrics->GfxTemperature / 100 *
 375		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
 376		break;
 377	case METRICS_TEMPERATURE_HOTSPOT:
 378		*value = metrics->SocTemperature / 100 *
 379		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
 380		break;
 381	case METRICS_THROTTLER_STATUS:
 382		*value = metrics->ThrottlerStatus;
 383		break;
 384	case METRICS_VOLTAGE_VDDGFX:
 385		*value = metrics->Voltage[0];
 386		break;
 387	case METRICS_VOLTAGE_VDDSOC:
 388		*value = metrics->Voltage[1];
 389		break;
 390	case METRICS_SS_APU_SHARE:
 391		/* return the percentage of APU power boost
 392		 * with respect to APU's power limit.
 393		 */
 394		yellow_carp_get_ss_power_percent(metrics, &apu_percent, &dgpu_percent);
 395		*value = apu_percent;
 396		break;
 397	case METRICS_SS_DGPU_SHARE:
 398		/* return the percentage of dGPU power boost
 399		 * with respect to dGPU's power limit.
 400		 */
 401		yellow_carp_get_ss_power_percent(metrics, &apu_percent, &dgpu_percent);
 402		*value = dgpu_percent;
 403		break;
 404	default:
 405		*value = UINT_MAX;
 406		break;
 407	}
 408
 409	return ret;
 410}
 411
 412static int yellow_carp_read_sensor(struct smu_context *smu,
 413					enum amd_pp_sensors sensor,
 414					void *data, uint32_t *size)
 415{
 416	int ret = 0;
 417
 418	if (!data || !size)
 419		return -EINVAL;
 420
 421	switch (sensor) {
 422	case AMDGPU_PP_SENSOR_GPU_LOAD:
 423		ret = yellow_carp_get_smu_metrics_data(smu,
 424								METRICS_AVERAGE_GFXACTIVITY,
 425								(uint32_t *)data);
 426		*size = 4;
 427		break;
 428	case AMDGPU_PP_SENSOR_VCN_LOAD:
 429		ret = yellow_carp_get_smu_metrics_data(smu,
 430							METRICS_AVERAGE_VCNACTIVITY,
 431							(uint32_t *)data);
 432		*size = 4;
 433		break;
 434	case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
 435		ret = yellow_carp_get_smu_metrics_data(smu,
 436								METRICS_CURR_SOCKETPOWER,
 437								(uint32_t *)data);
 438		*size = 4;
 439		break;
 440	case AMDGPU_PP_SENSOR_EDGE_TEMP:
 441		ret = yellow_carp_get_smu_metrics_data(smu,
 442								METRICS_TEMPERATURE_EDGE,
 443								(uint32_t *)data);
 444		*size = 4;
 445		break;
 446	case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
 447		ret = yellow_carp_get_smu_metrics_data(smu,
 448								METRICS_TEMPERATURE_HOTSPOT,
 449								(uint32_t *)data);
 450		*size = 4;
 451		break;
 452	case AMDGPU_PP_SENSOR_GFX_MCLK:
 453		ret = yellow_carp_get_smu_metrics_data(smu,
 454								METRICS_AVERAGE_UCLK,
 455								(uint32_t *)data);
 456		*(uint32_t *)data *= 100;
 457		*size = 4;
 458		break;
 459	case AMDGPU_PP_SENSOR_GFX_SCLK:
 460		ret = yellow_carp_get_smu_metrics_data(smu,
 461								METRICS_AVERAGE_GFXCLK,
 462								(uint32_t *)data);
 463		*(uint32_t *)data *= 100;
 464		*size = 4;
 465		break;
 466	case AMDGPU_PP_SENSOR_VDDGFX:
 467		ret = yellow_carp_get_smu_metrics_data(smu,
 468								METRICS_VOLTAGE_VDDGFX,
 469								(uint32_t *)data);
 470		*size = 4;
 471		break;
 472	case AMDGPU_PP_SENSOR_VDDNB:
 473		ret = yellow_carp_get_smu_metrics_data(smu,
 474								METRICS_VOLTAGE_VDDSOC,
 475								(uint32_t *)data);
 476		*size = 4;
 477		break;
 478	case AMDGPU_PP_SENSOR_SS_APU_SHARE:
 479		ret = yellow_carp_get_smu_metrics_data(smu,
 480						       METRICS_SS_APU_SHARE,
 481						       (uint32_t *)data);
 482		*size = 4;
 483		break;
 484	case AMDGPU_PP_SENSOR_SS_DGPU_SHARE:
 485		ret = yellow_carp_get_smu_metrics_data(smu,
 486						       METRICS_SS_DGPU_SHARE,
 487						       (uint32_t *)data);
 488		*size = 4;
 489		break;
 490	case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
 491	default:
 492		ret = -EOPNOTSUPP;
 493		break;
 494	}
 495
 496	return ret;
 497}
 498
 499static int yellow_carp_set_watermarks_table(struct smu_context *smu,
 500				struct pp_smu_wm_range_sets *clock_ranges)
 501{
 502	int i;
 503	int ret = 0;
 504	Watermarks_t *table = smu->smu_table.watermarks_table;
 505
 506	if (!table || !clock_ranges)
 507		return -EINVAL;
 508
 509	if (clock_ranges) {
 510		if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES ||
 511			clock_ranges->num_writer_wm_sets > NUM_WM_RANGES)
 512			return -EINVAL;
 513
 514		for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) {
 515			table->WatermarkRow[WM_DCFCLK][i].MinClock =
 516				clock_ranges->reader_wm_sets[i].min_drain_clk_mhz;
 517			table->WatermarkRow[WM_DCFCLK][i].MaxClock =
 518				clock_ranges->reader_wm_sets[i].max_drain_clk_mhz;
 519			table->WatermarkRow[WM_DCFCLK][i].MinMclk =
 520				clock_ranges->reader_wm_sets[i].min_fill_clk_mhz;
 521			table->WatermarkRow[WM_DCFCLK][i].MaxMclk =
 522				clock_ranges->reader_wm_sets[i].max_fill_clk_mhz;
 523
 524			table->WatermarkRow[WM_DCFCLK][i].WmSetting =
 525				clock_ranges->reader_wm_sets[i].wm_inst;
 526		}
 527
 528		for (i = 0; i < clock_ranges->num_writer_wm_sets; i++) {
 529			table->WatermarkRow[WM_SOCCLK][i].MinClock =
 530				clock_ranges->writer_wm_sets[i].min_fill_clk_mhz;
 531			table->WatermarkRow[WM_SOCCLK][i].MaxClock =
 532				clock_ranges->writer_wm_sets[i].max_fill_clk_mhz;
 533			table->WatermarkRow[WM_SOCCLK][i].MinMclk =
 534				clock_ranges->writer_wm_sets[i].min_drain_clk_mhz;
 535			table->WatermarkRow[WM_SOCCLK][i].MaxMclk =
 536				clock_ranges->writer_wm_sets[i].max_drain_clk_mhz;
 537
 538			table->WatermarkRow[WM_SOCCLK][i].WmSetting =
 539				clock_ranges->writer_wm_sets[i].wm_inst;
 540		}
 541
 542		smu->watermarks_bitmap |= WATERMARKS_EXIST;
 543	}
 544
 545	/* pass data to smu controller */
 546	if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
 547	     !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
 548		ret = smu_cmn_write_watermarks_table(smu);
 549		if (ret) {
 550			dev_err(smu->adev->dev, "Failed to update WMTABLE!");
 551			return ret;
 552		}
 553		smu->watermarks_bitmap |= WATERMARKS_LOADED;
 554	}
 555
 556	return 0;
 557}
 558
 559static ssize_t yellow_carp_get_gpu_metrics(struct smu_context *smu,
 560						void **table)
 561{
 562	struct smu_table_context *smu_table = &smu->smu_table;
 563	struct gpu_metrics_v2_1 *gpu_metrics =
 564		(struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table;
 565	SmuMetrics_t metrics;
 566	int ret = 0;
 567
 568	ret = smu_cmn_get_metrics_table(smu, &metrics, true);
 569	if (ret)
 570		return ret;
 571
 572	smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 1);
 573
 574	gpu_metrics->temperature_gfx = metrics.GfxTemperature;
 575	gpu_metrics->temperature_soc = metrics.SocTemperature;
 576	memcpy(&gpu_metrics->temperature_core[0],
 577		&metrics.CoreTemperature[0],
 578		sizeof(uint16_t) * 8);
 579	gpu_metrics->temperature_l3[0] = metrics.L3Temperature;
 580
 581	gpu_metrics->average_gfx_activity = metrics.GfxActivity;
 582	gpu_metrics->average_mm_activity = metrics.UvdActivity;
 583
 584	gpu_metrics->average_socket_power = metrics.CurrentSocketPower;
 585	gpu_metrics->average_gfx_power = metrics.Power[0];
 586	gpu_metrics->average_soc_power = metrics.Power[1];
 587	memcpy(&gpu_metrics->average_core_power[0],
 588		&metrics.CorePower[0],
 589		sizeof(uint16_t) * 8);
 590
 591	gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency;
 592	gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency;
 593	gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency;
 594	gpu_metrics->average_fclk_frequency = metrics.MemclkFrequency;
 595	gpu_metrics->average_vclk_frequency = metrics.VclkFrequency;
 596	gpu_metrics->average_dclk_frequency = metrics.DclkFrequency;
 597
 598	memcpy(&gpu_metrics->current_coreclk[0],
 599		&metrics.CoreFrequency[0],
 600		sizeof(uint16_t) * 8);
 601	gpu_metrics->current_l3clk[0] = metrics.L3Frequency;
 602
 603	gpu_metrics->throttle_status = metrics.ThrottlerStatus;
 604
 605	gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
 606
 607	*table = (void *)gpu_metrics;
 608
 609	return sizeof(struct gpu_metrics_v2_1);
 610}
 611
 612/**
 613 * yellow_carp_get_gfxoff_status - get gfxoff status
 614 *
 615 * @smu: smu_context pointer
 616 *
 617 * This function will be used to get gfxoff status
 618 *
 619 * Returns 0=GFXOFF(default).
 620 * Returns 1=Transition out of GFX State.
 621 * Returns 2=Not in GFXOFF.
 622 * Returns 3=Transition into GFXOFF.
 623 */
 624static uint32_t yellow_carp_get_gfxoff_status(struct smu_context *smu)
 625{
 626	uint32_t reg;
 627	uint32_t gfxoff_status = 0;
 628	struct amdgpu_device *adev = smu->adev;
 629
 630	reg = RREG32_SOC15(SMUIO, 0, regSMUIO_GFX_MISC_CNTL);
 631	gfxoff_status = (reg & SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK)
 632		>> SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT;
 633
 634	return gfxoff_status;
 635}
 636
 637static int yellow_carp_set_default_dpm_tables(struct smu_context *smu)
 638{
 639	struct smu_table_context *smu_table = &smu->smu_table;
 640
 641	return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false);
 642}
 643
 644static int yellow_carp_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type,
 645					long input[], uint32_t size)
 646{
 647	struct smu_dpm_context *smu_dpm = &(smu->smu_dpm);
 648	int ret = 0;
 649
 650	/* Only allowed in manual mode */
 651	if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
 652		return -EINVAL;
 653
 654	switch (type) {
 655	case PP_OD_EDIT_SCLK_VDDC_TABLE:
 656		if (size != 2) {
 657			dev_err(smu->adev->dev, "Input parameter number not correct\n");
 658			return -EINVAL;
 659		}
 660
 661		if (input[0] == 0) {
 662			if (input[1] < smu->gfx_default_hard_min_freq) {
 663				dev_warn(smu->adev->dev,
 664					"Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
 665					input[1], smu->gfx_default_hard_min_freq);
 666				return -EINVAL;
 667			}
 668			smu->gfx_actual_hard_min_freq = input[1];
 669		} else if (input[0] == 1) {
 670			if (input[1] > smu->gfx_default_soft_max_freq) {
 671				dev_warn(smu->adev->dev,
 672					"Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
 673					input[1], smu->gfx_default_soft_max_freq);
 674				return -EINVAL;
 675			}
 676			smu->gfx_actual_soft_max_freq = input[1];
 677		} else {
 678			return -EINVAL;
 679		}
 680		break;
 681	case PP_OD_RESTORE_DEFAULT_TABLE:
 682		if (size != 0) {
 683			dev_err(smu->adev->dev, "Input parameter number not correct\n");
 684			return -EINVAL;
 685		} else {
 686			smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
 687			smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
 688		}
 689		break;
 690	case PP_OD_COMMIT_DPM_TABLE:
 691		if (size != 0) {
 692			dev_err(smu->adev->dev, "Input parameter number not correct\n");
 693			return -EINVAL;
 694		} else {
 695			if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) {
 696				dev_err(smu->adev->dev,
 697					"The setting minimum sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n",
 698					smu->gfx_actual_hard_min_freq,
 699					smu->gfx_actual_soft_max_freq);
 700				return -EINVAL;
 701			}
 702
 703			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
 704									smu->gfx_actual_hard_min_freq, NULL);
 705			if (ret) {
 706				dev_err(smu->adev->dev, "Set hard min sclk failed!");
 707				return ret;
 708			}
 709
 710			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
 711									smu->gfx_actual_soft_max_freq, NULL);
 712			if (ret) {
 713				dev_err(smu->adev->dev, "Set soft max sclk failed!");
 714				return ret;
 715			}
 716		}
 717		break;
 718	default:
 719		return -ENOSYS;
 720	}
 721
 722	return ret;
 723}
 724
 725static int yellow_carp_get_current_clk_freq(struct smu_context *smu,
 726						enum smu_clk_type clk_type,
 727						uint32_t *value)
 728{
 729	MetricsMember_t member_type;
 730
 731	switch (clk_type) {
 732	case SMU_SOCCLK:
 733		member_type = METRICS_AVERAGE_SOCCLK;
 734		break;
 735	case SMU_VCLK:
 736	    member_type = METRICS_AVERAGE_VCLK;
 737		break;
 738	case SMU_DCLK:
 739		member_type = METRICS_AVERAGE_DCLK;
 740		break;
 741	case SMU_MCLK:
 742		member_type = METRICS_AVERAGE_UCLK;
 743		break;
 744	case SMU_FCLK:
 745		return smu_cmn_send_smc_msg_with_param(smu,
 746				SMU_MSG_GetFclkFrequency, 0, value);
 747	case SMU_GFXCLK:
 748	case SMU_SCLK:
 749		return smu_cmn_send_smc_msg_with_param(smu,
 750				SMU_MSG_GetGfxclkFrequency, 0, value);
 751		break;
 752	default:
 753		return -EINVAL;
 754	}
 755
 756	return yellow_carp_get_smu_metrics_data(smu, member_type, value);
 757}
 758
 759static int yellow_carp_get_dpm_level_count(struct smu_context *smu,
 760						enum smu_clk_type clk_type,
 761						uint32_t *count)
 762{
 763	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
 764
 765	switch (clk_type) {
 766	case SMU_SOCCLK:
 767		*count = clk_table->NumSocClkLevelsEnabled;
 768		break;
 769	case SMU_VCLK:
 770		*count = clk_table->VcnClkLevelsEnabled;
 771		break;
 772	case SMU_DCLK:
 773		*count = clk_table->VcnClkLevelsEnabled;
 774		break;
 775	case SMU_MCLK:
 776		*count = clk_table->NumDfPstatesEnabled;
 777		break;
 778	case SMU_FCLK:
 779		*count = clk_table->NumDfPstatesEnabled;
 780		break;
 781	default:
 782		return -EINVAL;
 783	}
 784
 785	return 0;
 786}
 787
 788static int yellow_carp_get_dpm_freq_by_index(struct smu_context *smu,
 789						enum smu_clk_type clk_type,
 790						uint32_t dpm_level,
 791						uint32_t *freq)
 792{
 793	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
 794
 795	if (!clk_table || clk_type >= SMU_CLK_COUNT)
 796		return -EINVAL;
 797
 798	switch (clk_type) {
 799	case SMU_SOCCLK:
 800		if (dpm_level >= clk_table->NumSocClkLevelsEnabled)
 801			return -EINVAL;
 802		*freq = clk_table->SocClocks[dpm_level];
 803		break;
 804	case SMU_VCLK:
 805		if (dpm_level >= clk_table->VcnClkLevelsEnabled)
 806			return -EINVAL;
 807		*freq = clk_table->VClocks[dpm_level];
 808		break;
 809	case SMU_DCLK:
 810		if (dpm_level >= clk_table->VcnClkLevelsEnabled)
 811			return -EINVAL;
 812		*freq = clk_table->DClocks[dpm_level];
 813		break;
 814	case SMU_UCLK:
 815	case SMU_MCLK:
 816		if (dpm_level >= clk_table->NumDfPstatesEnabled)
 817			return -EINVAL;
 818		*freq = clk_table->DfPstateTable[dpm_level].MemClk;
 819		break;
 820	case SMU_FCLK:
 821		if (dpm_level >= clk_table->NumDfPstatesEnabled)
 822			return -EINVAL;
 823		*freq = clk_table->DfPstateTable[dpm_level].FClk;
 824		break;
 825	default:
 826		return -EINVAL;
 827	}
 828
 829	return 0;
 830}
 831
 832static bool yellow_carp_clk_dpm_is_enabled(struct smu_context *smu,
 833						enum smu_clk_type clk_type)
 834{
 835	enum smu_feature_mask feature_id = 0;
 836
 837	switch (clk_type) {
 838	case SMU_MCLK:
 839	case SMU_UCLK:
 840	case SMU_FCLK:
 841		feature_id = SMU_FEATURE_DPM_FCLK_BIT;
 842		break;
 843	case SMU_GFXCLK:
 844	case SMU_SCLK:
 845		feature_id = SMU_FEATURE_DPM_GFXCLK_BIT;
 846		break;
 847	case SMU_SOCCLK:
 848		feature_id = SMU_FEATURE_DPM_SOCCLK_BIT;
 849		break;
 850	case SMU_VCLK:
 851	case SMU_DCLK:
 852		feature_id = SMU_FEATURE_VCN_DPM_BIT;
 853		break;
 854	default:
 855		return true;
 856	}
 857
 858	return smu_cmn_feature_is_enabled(smu, feature_id);
 859}
 860
 861static int yellow_carp_get_dpm_ultimate_freq(struct smu_context *smu,
 862							enum smu_clk_type clk_type,
 863							uint32_t *min,
 864							uint32_t *max)
 865{
 866	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
 867	uint32_t clock_limit;
 868	uint32_t max_dpm_level, min_dpm_level;
 869	int ret = 0;
 870
 871	if (!yellow_carp_clk_dpm_is_enabled(smu, clk_type)) {
 872		ret = smu_v13_0_get_boot_freq_by_index(smu, clk_type, &clock_limit);
 873		if (ret)
 874			return ret;
 875
 876		/* clock in Mhz unit */
 877		if (min)
 878			*min = clock_limit / 100;
 879		if (max)
 880			*max = clock_limit / 100;
 881
 882		return 0;
 883	}
 884
 885	if (max) {
 886		switch (clk_type) {
 887		case SMU_GFXCLK:
 888		case SMU_SCLK:
 889			*max = clk_table->MaxGfxClk;
 890			break;
 891		case SMU_MCLK:
 892		case SMU_UCLK:
 893		case SMU_FCLK:
 894			max_dpm_level = 0;
 895			break;
 896		case SMU_SOCCLK:
 897			max_dpm_level = clk_table->NumSocClkLevelsEnabled - 1;
 898			break;
 899		case SMU_VCLK:
 900		case SMU_DCLK:
 901			max_dpm_level = clk_table->VcnClkLevelsEnabled - 1;
 902			break;
 903		default:
 904			ret = -EINVAL;
 905			goto failed;
 906		}
 907
 908		if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
 909			ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, max_dpm_level, max);
 910			if (ret)
 911				goto failed;
 912		}
 913	}
 914
 915	if (min) {
 916		switch (clk_type) {
 917		case SMU_GFXCLK:
 918		case SMU_SCLK:
 919			*min = clk_table->MinGfxClk;
 920			break;
 921		case SMU_MCLK:
 922		case SMU_UCLK:
 923		case SMU_FCLK:
 924			min_dpm_level = clk_table->NumDfPstatesEnabled - 1;
 925			break;
 926		case SMU_SOCCLK:
 927			min_dpm_level = 0;
 928			break;
 929		case SMU_VCLK:
 930		case SMU_DCLK:
 931			min_dpm_level = 0;
 932			break;
 933		default:
 934			ret = -EINVAL;
 935			goto failed;
 936		}
 937
 938		if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
 939			ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, min_dpm_level, min);
 940			if (ret)
 941				goto failed;
 942		}
 943	}
 944
 945failed:
 946	return ret;
 947}
 948
 949static int yellow_carp_set_soft_freq_limited_range(struct smu_context *smu,
 950						   enum smu_clk_type clk_type,
 951						   uint32_t min,
 952						   uint32_t max,
 953						   bool automatic)
 954{
 955	enum smu_message_type msg_set_min, msg_set_max;
 956	uint32_t min_clk = min;
 957	uint32_t max_clk = max;
 958
 959	int ret = 0;
 960
 961	if (!yellow_carp_clk_dpm_is_enabled(smu, clk_type))
 962		return -EINVAL;
 963
 964	switch (clk_type) {
 965	case SMU_GFXCLK:
 966	case SMU_SCLK:
 967		msg_set_min = SMU_MSG_SetHardMinGfxClk;
 968		msg_set_max = SMU_MSG_SetSoftMaxGfxClk;
 969		break;
 970	case SMU_FCLK:
 971		msg_set_min = SMU_MSG_SetHardMinFclkByFreq;
 972		msg_set_max = SMU_MSG_SetSoftMaxFclkByFreq;
 973		break;
 974	case SMU_SOCCLK:
 975		msg_set_min = SMU_MSG_SetHardMinSocclkByFreq;
 976		msg_set_max = SMU_MSG_SetSoftMaxSocclkByFreq;
 977		break;
 978	case SMU_VCLK:
 979	case SMU_DCLK:
 980		msg_set_min = SMU_MSG_SetHardMinVcn;
 981		msg_set_max = SMU_MSG_SetSoftMaxVcn;
 982		break;
 983	default:
 984		return -EINVAL;
 985	}
 986
 987	if (clk_type == SMU_VCLK) {
 988		min_clk = min << SMU_13_VCLK_SHIFT;
 989		max_clk = max << SMU_13_VCLK_SHIFT;
 990	}
 991
 992	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min_clk, NULL);
 993
 994	if (ret)
 995		goto out;
 996
 997	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max_clk, NULL);
 998	if (ret)
 999		goto out;
1000
1001out:
1002	return ret;
1003}
1004
1005static uint32_t yellow_carp_get_umd_pstate_clk_default(struct smu_context *smu,
1006					enum smu_clk_type clk_type)
1007{
1008	uint32_t clk_limit = 0;
1009	struct amdgpu_device *adev = smu->adev;
1010
1011	switch (clk_type) {
1012	case SMU_GFXCLK:
1013	case SMU_SCLK:
1014		if ((amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 8))
1015			clk_limit = SMU_13_0_8_UMD_PSTATE_GFXCLK;
1016		if ((amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 1) ||
1017			(amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 3))
1018			clk_limit = SMU_13_0_1_UMD_PSTATE_GFXCLK;
1019		break;
1020	case SMU_SOCCLK:
1021		if ((amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 8))
1022			clk_limit = SMU_13_0_8_UMD_PSTATE_SOCCLK;
1023		if ((amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 1) ||
1024			(amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 3))
1025			clk_limit = SMU_13_0_1_UMD_PSTATE_SOCCLK;
1026		break;
1027	case SMU_FCLK:
1028		if ((amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 8))
1029			clk_limit = SMU_13_0_8_UMD_PSTATE_FCLK;
1030		if ((amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 1) ||
1031			(amdgpu_ip_version(adev, MP1_HWIP, 0)) == IP_VERSION(13, 0, 3))
1032			clk_limit = SMU_13_0_1_UMD_PSTATE_FCLK;
1033		break;
1034	default:
1035		break;
1036	}
1037
1038	return clk_limit;
1039}
1040
1041static int yellow_carp_print_clk_levels(struct smu_context *smu,
1042				enum smu_clk_type clk_type, char *buf)
1043{
1044	int i, idx, size = 0, ret = 0, start_offset = 0;
1045	uint32_t cur_value = 0, value = 0, count = 0;
1046	uint32_t min, max;
1047	uint32_t clk_limit = 0;
1048
1049	smu_cmn_get_sysfs_buf(&buf, &size);
1050	start_offset = size;
1051
1052	switch (clk_type) {
1053	case SMU_OD_SCLK:
1054		size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
1055		size += sysfs_emit_at(buf, size, "0: %10uMhz\n",
1056		(smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);
1057		size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
1058		(smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq);
1059		break;
1060	case SMU_OD_RANGE:
1061		size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
1062		size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
1063						smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);
1064		break;
1065	case SMU_SOCCLK:
1066	case SMU_VCLK:
1067	case SMU_DCLK:
1068	case SMU_MCLK:
1069	case SMU_FCLK:
1070		ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value);
1071		if (ret)
1072			goto print_clk_out;
1073
1074		ret = yellow_carp_get_dpm_level_count(smu, clk_type, &count);
1075		if (ret)
1076			goto print_clk_out;
1077
1078		for (i = 0; i < count; i++) {
1079			idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i;
1080			ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, idx, &value);
1081			if (ret)
1082				goto print_clk_out;
1083
1084			size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value,
1085					cur_value == value ? "*" : "");
1086		}
1087		break;
1088	case SMU_GFXCLK:
1089	case SMU_SCLK:
1090		clk_limit = yellow_carp_get_umd_pstate_clk_default(smu, clk_type);
1091		ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value);
1092		if (ret)
1093			goto print_clk_out;
1094		min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq;
1095		max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq;
1096		if (cur_value  == max)
1097			i = 2;
1098		else if (cur_value == min)
1099			i = 0;
1100		else
1101			i = 1;
1102		size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min,
1103				i == 0 ? "*" : "");
1104		size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
1105				i == 1 ? cur_value : clk_limit,
1106				i == 1 ? "*" : "");
1107		size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max,
1108				i == 2 ? "*" : "");
1109		break;
1110	default:
1111		break;
1112	}
1113
1114print_clk_out:
1115	return size - start_offset;
1116}
1117
1118static int yellow_carp_force_clk_levels(struct smu_context *smu,
1119				enum smu_clk_type clk_type, uint32_t mask)
1120{
1121	uint32_t soft_min_level = 0, soft_max_level = 0;
1122	uint32_t min_freq = 0, max_freq = 0;
1123	int ret = 0;
1124
1125	soft_min_level = mask ? (ffs(mask) - 1) : 0;
1126	soft_max_level = mask ? (fls(mask) - 1) : 0;
1127
1128	switch (clk_type) {
1129	case SMU_SOCCLK:
1130	case SMU_FCLK:
1131	case SMU_VCLK:
1132	case SMU_DCLK:
1133		ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq);
1134		if (ret)
1135			goto force_level_out;
1136
1137		ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq);
1138		if (ret)
1139			goto force_level_out;
1140
1141		ret = yellow_carp_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq, false);
1142		if (ret)
1143			goto force_level_out;
1144		break;
1145	default:
1146		ret = -EINVAL;
1147		break;
1148	}
1149
1150force_level_out:
1151	return ret;
1152}
1153
1154static int yellow_carp_get_dpm_profile_freq(struct smu_context *smu,
1155					enum amd_dpm_forced_level level,
1156					enum smu_clk_type clk_type,
1157					uint32_t *min_clk,
1158					uint32_t *max_clk)
1159{
1160	int ret = 0;
1161	uint32_t clk_limit = 0;
1162
1163	clk_limit = yellow_carp_get_umd_pstate_clk_default(smu, clk_type);
1164
1165	switch (clk_type) {
1166	case SMU_GFXCLK:
1167	case SMU_SCLK:
1168		if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
1169			yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &clk_limit);
1170		else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK)
1171			yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &clk_limit, NULL);
1172		break;
1173	case SMU_SOCCLK:
1174		if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
1175			yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &clk_limit);
1176		break;
1177	case SMU_FCLK:
1178		if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
1179			yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &clk_limit);
1180		else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK)
1181			yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &clk_limit, NULL);
1182		break;
1183	case SMU_VCLK:
1184		yellow_carp_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &clk_limit);
1185		break;
1186	case SMU_DCLK:
1187		yellow_carp_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &clk_limit);
1188		break;
1189	default:
1190		ret = -EINVAL;
1191		break;
1192	}
1193	*min_clk = *max_clk = clk_limit;
1194	return ret;
1195}
1196
1197static int yellow_carp_set_performance_level(struct smu_context *smu,
1198						enum amd_dpm_forced_level level)
1199{
1200	struct amdgpu_device *adev = smu->adev;
1201	uint32_t sclk_min = 0, sclk_max = 0;
1202	uint32_t fclk_min = 0, fclk_max = 0;
1203	uint32_t socclk_min = 0, socclk_max = 0;
1204	uint32_t vclk_min = 0, vclk_max = 0;
1205	uint32_t dclk_min = 0, dclk_max = 0;
1206
1207	int ret = 0;
1208
1209	switch (level) {
1210	case AMD_DPM_FORCED_LEVEL_HIGH:
1211		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_max);
1212		yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_max);
1213		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_max);
1214		yellow_carp_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &vclk_max);
1215		yellow_carp_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &dclk_max);
1216		sclk_min = sclk_max;
1217		fclk_min = fclk_max;
1218		socclk_min = socclk_max;
1219		vclk_min = vclk_max;
1220		dclk_min = dclk_max;
1221		break;
1222	case AMD_DPM_FORCED_LEVEL_LOW:
1223		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, NULL);
1224		yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, NULL);
1225		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, NULL);
1226		yellow_carp_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, NULL);
1227		yellow_carp_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, NULL);
1228		sclk_max = sclk_min;
1229		fclk_max = fclk_min;
1230		socclk_max = socclk_min;
1231		vclk_max = vclk_min;
1232		dclk_max = dclk_min;
1233		break;
1234	case AMD_DPM_FORCED_LEVEL_AUTO:
1235		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, &sclk_max);
1236		yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, &fclk_max);
1237		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, &socclk_max);
1238		yellow_carp_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, &vclk_max);
1239		yellow_carp_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, &dclk_max);
1240		break;
1241	case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
1242	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
1243	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
1244	case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
1245		yellow_carp_get_dpm_profile_freq(smu, level, SMU_SCLK, &sclk_min, &sclk_max);
1246		yellow_carp_get_dpm_profile_freq(smu, level, SMU_FCLK, &fclk_min, &fclk_max);
1247		yellow_carp_get_dpm_profile_freq(smu, level, SMU_SOCCLK, &socclk_min, &socclk_max);
1248		yellow_carp_get_dpm_profile_freq(smu, level, SMU_VCLK, &vclk_min, &vclk_max);
1249		yellow_carp_get_dpm_profile_freq(smu, level, SMU_DCLK, &dclk_min, &dclk_max);
1250		break;
1251	case AMD_DPM_FORCED_LEVEL_MANUAL:
1252	case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
1253		return 0;
1254	default:
1255		dev_err(adev->dev, "Invalid performance level %d\n", level);
1256		return -EINVAL;
1257	}
1258
1259	if (sclk_min && sclk_max) {
1260		ret = yellow_carp_set_soft_freq_limited_range(smu,
1261							      SMU_SCLK,
1262							      sclk_min,
1263							      sclk_max,
1264							      false);
1265		if (ret)
1266			return ret;
1267
1268		smu->gfx_actual_hard_min_freq = sclk_min;
1269		smu->gfx_actual_soft_max_freq = sclk_max;
1270	}
1271
1272	if (fclk_min && fclk_max) {
1273		ret = yellow_carp_set_soft_freq_limited_range(smu,
1274							      SMU_FCLK,
1275							      fclk_min,
1276							      fclk_max,
1277							      false);
1278		if (ret)
1279			return ret;
1280	}
1281
1282	if (socclk_min && socclk_max) {
1283		ret = yellow_carp_set_soft_freq_limited_range(smu,
1284							      SMU_SOCCLK,
1285							      socclk_min,
1286							      socclk_max,
1287							      false);
1288		if (ret)
1289			return ret;
1290	}
1291
1292	if (vclk_min && vclk_max) {
1293		ret = yellow_carp_set_soft_freq_limited_range(smu,
1294							      SMU_VCLK,
1295							      vclk_min,
1296							      vclk_max,
1297							      false);
1298		if (ret)
1299			return ret;
1300	}
1301
1302	if (dclk_min && dclk_max) {
1303		ret = yellow_carp_set_soft_freq_limited_range(smu,
1304							      SMU_DCLK,
1305							      dclk_min,
1306							      dclk_max,
1307							      false);
1308		if (ret)
1309			return ret;
1310	}
1311
1312	return ret;
1313}
1314
1315static int yellow_carp_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
1316{
1317	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
1318
1319	smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
1320	smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
1321	smu->gfx_actual_hard_min_freq = 0;
1322	smu->gfx_actual_soft_max_freq = 0;
1323
1324	return 0;
1325}
1326
1327static const struct pptable_funcs yellow_carp_ppt_funcs = {
1328	.check_fw_status = smu_v13_0_check_fw_status,
1329	.check_fw_version = smu_v13_0_check_fw_version,
1330	.init_smc_tables = yellow_carp_init_smc_tables,
1331	.fini_smc_tables = yellow_carp_fini_smc_tables,
1332	.get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values,
1333	.system_features_control = yellow_carp_system_features_control,
1334	.send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
1335	.send_smc_msg = smu_cmn_send_smc_msg,
1336	.dpm_set_vcn_enable = yellow_carp_dpm_set_vcn_enable,
1337	.dpm_set_jpeg_enable = yellow_carp_dpm_set_jpeg_enable,
1338	.set_default_dpm_table = yellow_carp_set_default_dpm_tables,
1339	.read_sensor = yellow_carp_read_sensor,
1340	.is_dpm_running = yellow_carp_is_dpm_running,
1341	.set_watermarks_table = yellow_carp_set_watermarks_table,
1342	.get_gpu_metrics = yellow_carp_get_gpu_metrics,
1343	.get_enabled_mask = smu_cmn_get_enabled_mask,
1344	.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
1345	.set_driver_table_location = smu_v13_0_set_driver_table_location,
1346	.gfx_off_control = smu_v13_0_gfx_off_control,
1347	.get_gfx_off_status = yellow_carp_get_gfxoff_status,
1348	.post_init = yellow_carp_post_smu_init,
1349	.mode2_reset = yellow_carp_mode2_reset,
1350	.get_dpm_ultimate_freq = yellow_carp_get_dpm_ultimate_freq,
1351	.od_edit_dpm_table = yellow_carp_od_edit_dpm_table,
1352	.print_clk_levels = yellow_carp_print_clk_levels,
1353	.force_clk_levels = yellow_carp_force_clk_levels,
1354	.set_performance_level = yellow_carp_set_performance_level,
1355	.set_fine_grain_gfx_freq_parameters = yellow_carp_set_fine_grain_gfx_freq_parameters,
1356};
1357
1358void yellow_carp_set_ppt_funcs(struct smu_context *smu)
1359{
1360	smu->ppt_funcs = &yellow_carp_ppt_funcs;
1361	smu->message_map = yellow_carp_message_map;
1362	smu->feature_map = yellow_carp_feature_mask_map;
1363	smu->table_map = yellow_carp_table_map;
1364	smu->is_apu = true;
1365	smu->smc_driver_if_version = SMU13_YELLOW_CARP_DRIVER_IF_VERSION;
1366	smu_v13_0_set_smu_mailbox_registers(smu);
1367}
~/ Read-only file preview.