navi10_ppt.c 79.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Copyright 2019 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 */

24 25
#define SWSMU_CODE_LAYER_L2

26
#include <linux/firmware.h>
27
#include <linux/pci.h>
28
#include <linux/i2c.h>
29 30 31 32
#include "amdgpu.h"
#include "amdgpu_smu.h"
#include "atomfirmware.h"
#include "amdgpu_atomfirmware.h"
33
#include "amdgpu_atombios.h"
34
#include "soc15_common.h"
35
#include "smu_v11_0.h"
36
#include "smu11_driver_if_navi10.h"
37 38 39 40
#include "atom.h"
#include "navi10_ppt.h"
#include "smu_v11_0_pptable.h"
#include "smu_v11_0_ppsmc.h"
41 42
#include "nbio/nbio_2_3_offset.h"
#include "nbio/nbio_2_3_sh_mask.h"
43 44
#include "thm/thm_11_0_2_offset.h"
#include "thm/thm_11_0_2_sh_mask.h"
45

46
#include "asic_reg/mp/mp_11_0_sh_mask.h"
47
#include "smu_cmn.h"
48

49 50 51 52 53 54 55 56 57 58
/*
 * DO NOT use these for err/warn/info/debug messages.
 * Use dev_err, dev_warn, dev_info and dev_dbg instead.
 * They are more MGPU friendly.
 */
#undef pr_err
#undef pr_warn
#undef pr_info
#undef pr_debug

59 60
#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))

61
#define FEATURE_MASK(feature) (1ULL << feature)
62 63 64 65 66 67 68 69 70 71
#define SMC_DPM_FEATURE ( \
	FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \
	FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT)	 | \
	FEATURE_MASK(FEATURE_DPM_GFX_PACE_BIT)	 | \
	FEATURE_MASK(FEATURE_DPM_UCLK_BIT)	 | \
	FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT)	 | \
	FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT)	 | \
	FEATURE_MASK(FEATURE_DPM_LINK_BIT)	 | \
	FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT))

72
static struct cmn2asic_msg_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = {
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
	MSG_MAP(TestMessage,			PPSMC_MSG_TestMessage,			1),
	MSG_MAP(GetSmuVersion,			PPSMC_MSG_GetSmuVersion,		1),
	MSG_MAP(GetDriverIfVersion,		PPSMC_MSG_GetDriverIfVersion,		1),
	MSG_MAP(SetAllowedFeaturesMaskLow,	PPSMC_MSG_SetAllowedFeaturesMaskLow,	0),
	MSG_MAP(SetAllowedFeaturesMaskHigh,	PPSMC_MSG_SetAllowedFeaturesMaskHigh,	0),
	MSG_MAP(EnableAllSmuFeatures,		PPSMC_MSG_EnableAllSmuFeatures,		0),
	MSG_MAP(DisableAllSmuFeatures,		PPSMC_MSG_DisableAllSmuFeatures,	0),
	MSG_MAP(EnableSmuFeaturesLow,		PPSMC_MSG_EnableSmuFeaturesLow,		1),
	MSG_MAP(EnableSmuFeaturesHigh,		PPSMC_MSG_EnableSmuFeaturesHigh,	1),
	MSG_MAP(DisableSmuFeaturesLow,		PPSMC_MSG_DisableSmuFeaturesLow,	1),
	MSG_MAP(DisableSmuFeaturesHigh,		PPSMC_MSG_DisableSmuFeaturesHigh,	1),
	MSG_MAP(GetEnabledSmuFeaturesLow,	PPSMC_MSG_GetEnabledSmuFeaturesLow,	1),
	MSG_MAP(GetEnabledSmuFeaturesHigh,	PPSMC_MSG_GetEnabledSmuFeaturesHigh,	1),
	MSG_MAP(SetWorkloadMask,		PPSMC_MSG_SetWorkloadMask,		1),
	MSG_MAP(SetPptLimit,			PPSMC_MSG_SetPptLimit,			0),
	MSG_MAP(SetDriverDramAddrHigh,		PPSMC_MSG_SetDriverDramAddrHigh,	0),
	MSG_MAP(SetDriverDramAddrLow,		PPSMC_MSG_SetDriverDramAddrLow,		0),
	MSG_MAP(SetToolsDramAddrHigh,		PPSMC_MSG_SetToolsDramAddrHigh,		0),
	MSG_MAP(SetToolsDramAddrLow,		PPSMC_MSG_SetToolsDramAddrLow,		0),
	MSG_MAP(TransferTableSmu2Dram,		PPSMC_MSG_TransferTableSmu2Dram,	0),
	MSG_MAP(TransferTableDram2Smu,		PPSMC_MSG_TransferTableDram2Smu,	0),
	MSG_MAP(UseDefaultPPTable,		PPSMC_MSG_UseDefaultPPTable,		0),
	MSG_MAP(UseBackupPPTable,		PPSMC_MSG_UseBackupPPTable,		0),
	MSG_MAP(RunBtc,				PPSMC_MSG_RunBtc,			0),
	MSG_MAP(EnterBaco,			PPSMC_MSG_EnterBaco,			0),
	MSG_MAP(SetSoftMinByFreq,		PPSMC_MSG_SetSoftMinByFreq,		0),
	MSG_MAP(SetSoftMaxByFreq,		PPSMC_MSG_SetSoftMaxByFreq,		0),
	MSG_MAP(SetHardMinByFreq,		PPSMC_MSG_SetHardMinByFreq,		1),
	MSG_MAP(SetHardMaxByFreq,		PPSMC_MSG_SetHardMaxByFreq,		0),
	MSG_MAP(GetMinDpmFreq,			PPSMC_MSG_GetMinDpmFreq,		1),
	MSG_MAP(GetMaxDpmFreq,			PPSMC_MSG_GetMaxDpmFreq,		1),
	MSG_MAP(GetDpmFreqByIndex,		PPSMC_MSG_GetDpmFreqByIndex,		1),
	MSG_MAP(SetMemoryChannelConfig,		PPSMC_MSG_SetMemoryChannelConfig,	0),
	MSG_MAP(SetGeminiMode,			PPSMC_MSG_SetGeminiMode,		0),
	MSG_MAP(SetGeminiApertureHigh,		PPSMC_MSG_SetGeminiApertureHigh,	0),
	MSG_MAP(SetGeminiApertureLow,		PPSMC_MSG_SetGeminiApertureLow,		0),
	MSG_MAP(OverridePcieParameters,		PPSMC_MSG_OverridePcieParameters,	0),
	MSG_MAP(SetMinDeepSleepDcefclk,		PPSMC_MSG_SetMinDeepSleepDcefclk,	0),
	MSG_MAP(ReenableAcDcInterrupt,		PPSMC_MSG_ReenableAcDcInterrupt,	0),
	MSG_MAP(NotifyPowerSource,		PPSMC_MSG_NotifyPowerSource,		0),
	MSG_MAP(SetUclkFastSwitch,		PPSMC_MSG_SetUclkFastSwitch,		0),
	MSG_MAP(SetVideoFps,			PPSMC_MSG_SetVideoFps,			0),
	MSG_MAP(PrepareMp1ForUnload,		PPSMC_MSG_PrepareMp1ForUnload,		1),
	MSG_MAP(DramLogSetDramAddrHigh,		PPSMC_MSG_DramLogSetDramAddrHigh,	0),
	MSG_MAP(DramLogSetDramAddrLow,		PPSMC_MSG_DramLogSetDramAddrLow,	0),
	MSG_MAP(DramLogSetDramSize,		PPSMC_MSG_DramLogSetDramSize,		0),
	MSG_MAP(ConfigureGfxDidt,		PPSMC_MSG_ConfigureGfxDidt,		0),
	MSG_MAP(NumOfDisplays,			PPSMC_MSG_NumOfDisplays,		0),
	MSG_MAP(SetSystemVirtualDramAddrHigh,	PPSMC_MSG_SetSystemVirtualDramAddrHigh,	0),
	MSG_MAP(SetSystemVirtualDramAddrLow,	PPSMC_MSG_SetSystemVirtualDramAddrLow,	0),
	MSG_MAP(AllowGfxOff,			PPSMC_MSG_AllowGfxOff,			0),
	MSG_MAP(DisallowGfxOff,			PPSMC_MSG_DisallowGfxOff,		0),
	MSG_MAP(GetPptLimit,			PPSMC_MSG_GetPptLimit,			0),
	MSG_MAP(GetDcModeMaxDpmFreq,		PPSMC_MSG_GetDcModeMaxDpmFreq,		1),
	MSG_MAP(GetDebugData,			PPSMC_MSG_GetDebugData,			0),
	MSG_MAP(ExitBaco,			PPSMC_MSG_ExitBaco,			0),
	MSG_MAP(PrepareMp1ForReset,		PPSMC_MSG_PrepareMp1ForReset,		0),
	MSG_MAP(PrepareMp1ForShutdown,		PPSMC_MSG_PrepareMp1ForShutdown,	0),
	MSG_MAP(PowerUpVcn,			PPSMC_MSG_PowerUpVcn,			0),
	MSG_MAP(PowerDownVcn,			PPSMC_MSG_PowerDownVcn,			0),
	MSG_MAP(PowerUpJpeg,			PPSMC_MSG_PowerUpJpeg,			0),
	MSG_MAP(PowerDownJpeg,			PPSMC_MSG_PowerDownJpeg,		0),
	MSG_MAP(BacoAudioD3PME,			PPSMC_MSG_BacoAudioD3PME,		0),
	MSG_MAP(ArmD3,				PPSMC_MSG_ArmD3,			0),
	MSG_MAP(DAL_DISABLE_DUMMY_PSTATE_CHANGE,PPSMC_MSG_DALDisableDummyPstateChange,	0),
	MSG_MAP(DAL_ENABLE_DUMMY_PSTATE_CHANGE,	PPSMC_MSG_DALEnableDummyPstateChange,	0),
	MSG_MAP(GetVoltageByDpm,		PPSMC_MSG_GetVoltageByDpm,		0),
	MSG_MAP(GetVoltageByDpmOverdrive,	PPSMC_MSG_GetVoltageByDpmOverdrive,	0),
141 142
};

143
static struct cmn2asic_mapping navi10_clk_map[SMU_CLK_COUNT] = {
144
	CLK_MAP(GFXCLK, PPCLK_GFXCLK),
145
	CLK_MAP(SCLK,	PPCLK_GFXCLK),
146
	CLK_MAP(SOCCLK, PPCLK_SOCCLK),
147
	CLK_MAP(FCLK, PPCLK_SOCCLK),
148
	CLK_MAP(UCLK, PPCLK_UCLK),
149
	CLK_MAP(MCLK, PPCLK_UCLK),
150 151 152 153 154 155 156 157
	CLK_MAP(DCLK, PPCLK_DCLK),
	CLK_MAP(VCLK, PPCLK_VCLK),
	CLK_MAP(DCEFCLK, PPCLK_DCEFCLK),
	CLK_MAP(DISPCLK, PPCLK_DISPCLK),
	CLK_MAP(PIXCLK, PPCLK_PIXCLK),
	CLK_MAP(PHYCLK, PPCLK_PHYCLK),
};

158
static struct cmn2asic_mapping navi10_feature_mask_map[SMU_FEATURE_COUNT] = {
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
	FEA_MAP(DPM_PREFETCHER),
	FEA_MAP(DPM_GFXCLK),
	FEA_MAP(DPM_GFX_PACE),
	FEA_MAP(DPM_UCLK),
	FEA_MAP(DPM_SOCCLK),
	FEA_MAP(DPM_MP0CLK),
	FEA_MAP(DPM_LINK),
	FEA_MAP(DPM_DCEFCLK),
	FEA_MAP(MEM_VDDCI_SCALING),
	FEA_MAP(MEM_MVDD_SCALING),
	FEA_MAP(DS_GFXCLK),
	FEA_MAP(DS_SOCCLK),
	FEA_MAP(DS_LCLK),
	FEA_MAP(DS_DCEFCLK),
	FEA_MAP(DS_UCLK),
	FEA_MAP(GFX_ULV),
	FEA_MAP(FW_DSTATE),
	FEA_MAP(GFXOFF),
	FEA_MAP(BACO),
	FEA_MAP(VCN_PG),
	FEA_MAP(JPEG_PG),
	FEA_MAP(USB_PG),
	FEA_MAP(RSMU_SMN_CG),
	FEA_MAP(PPT),
	FEA_MAP(TDC),
	FEA_MAP(GFX_EDC),
	FEA_MAP(APCC_PLUS),
	FEA_MAP(GTHR),
	FEA_MAP(ACDC),
	FEA_MAP(VR0HOT),
	FEA_MAP(VR1HOT),
	FEA_MAP(FW_CTF),
	FEA_MAP(FAN_CONTROL),
	FEA_MAP(THERMAL),
	FEA_MAP(GFX_DCS),
	FEA_MAP(RM),
	FEA_MAP(LED_DISPLAY),
	FEA_MAP(GFX_SS),
	FEA_MAP(OUT_OF_BAND_MONITOR),
	FEA_MAP(TEMP_DEPENDENT_VMIN),
	FEA_MAP(MMHUB_PG),
	FEA_MAP(ATHUB_PG),
201
	FEA_MAP(APCC_DFLL),
202 203
};

204
static struct cmn2asic_mapping navi10_table_map[SMU_TABLE_COUNT] = {
205 206 207 208 209 210 211 212 213 214 215 216 217 218
	TAB_MAP(PPTABLE),
	TAB_MAP(WATERMARKS),
	TAB_MAP(AVFS),
	TAB_MAP(AVFS_PSM_DEBUG),
	TAB_MAP(AVFS_FUSE_OVERRIDE),
	TAB_MAP(PMSTATUSLOG),
	TAB_MAP(SMU_METRICS),
	TAB_MAP(DRIVER_SMU_CONFIG),
	TAB_MAP(ACTIVITY_MONITOR_COEFF),
	TAB_MAP(OVERDRIVE),
	TAB_MAP(I2C_COMMANDS),
	TAB_MAP(PACE),
};

219
static struct cmn2asic_mapping navi10_pwr_src_map[SMU_POWER_SOURCE_COUNT] = {
220 221 222 223
	PWR_MAP(AC),
	PWR_MAP(DC),
};

224
static struct cmn2asic_mapping navi10_workload_map[PP_SMC_POWER_PROFILE_COUNT] = {
225 226 227 228 229
	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT,	WORKLOAD_PPLIB_DEFAULT_BIT),
	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D,		WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT),
	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING,		WORKLOAD_PPLIB_POWER_SAVING_BIT),
	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO,		WORKLOAD_PPLIB_VIDEO_BIT),
	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR,			WORKLOAD_PPLIB_VR_BIT),
230
	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE,		WORKLOAD_PPLIB_COMPUTE_BIT),
231 232 233
	WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM,		WORKLOAD_PPLIB_CUSTOM_BIT),
};

234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
static bool is_asic_secure(struct smu_context *smu)
{
	struct amdgpu_device *adev = smu->adev;
	bool is_secure = true;
	uint32_t mp0_fw_intf;

	mp0_fw_intf = RREG32_PCIE(MP0_Public |
				   (smnMP0_FW_INTF & 0xffffffff));

	if (!(mp0_fw_intf & (1 << 19)))
		is_secure = false;

	return is_secure;
}

249
static int
250
navi10_get_allowed_feature_mask(struct smu_context *smu,
251 252
				  uint32_t *feature_mask, uint32_t num)
{
253 254
	struct amdgpu_device *adev = smu->adev;

255 256 257
	if (num > 2)
		return -EINVAL;

258 259
	memset(feature_mask, 0, sizeof(uint32_t) * num);

260
	*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT)
261 262
				| FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT)
				| FEATURE_MASK(FEATURE_RSMU_SMN_CG_BIT)
263
				| FEATURE_MASK(FEATURE_DS_SOCCLK_BIT)
264 265 266
				| FEATURE_MASK(FEATURE_PPT_BIT)
				| FEATURE_MASK(FEATURE_TDC_BIT)
				| FEATURE_MASK(FEATURE_GFX_EDC_BIT)
267
				| FEATURE_MASK(FEATURE_APCC_PLUS_BIT)
268 269 270 271
				| FEATURE_MASK(FEATURE_VR0HOT_BIT)
				| FEATURE_MASK(FEATURE_FAN_CONTROL_BIT)
				| FEATURE_MASK(FEATURE_THERMAL_BIT)
				| FEATURE_MASK(FEATURE_LED_DISPLAY_BIT)
272
				| FEATURE_MASK(FEATURE_DS_LCLK_BIT)
273
				| FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT)
274
				| FEATURE_MASK(FEATURE_FW_DSTATE_BIT)
275
				| FEATURE_MASK(FEATURE_BACO_BIT)
276 277
				| FEATURE_MASK(FEATURE_GFX_SS_BIT)
				| FEATURE_MASK(FEATURE_APCC_DFLL_BIT)
278 279
				| FEATURE_MASK(FEATURE_FW_CTF_BIT)
				| FEATURE_MASK(FEATURE_OUT_OF_BAND_MONITOR_BIT);
280

281 282 283 284 285 286 287 288 289 290 291 292
	if (adev->pm.pp_feature & PP_SOCCLK_DPM_MASK)
		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT);

	if (adev->pm.pp_feature & PP_SCLK_DPM_MASK)
		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT);

	if (adev->pm.pp_feature & PP_PCIE_DPM_MASK)
		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_LINK_BIT);

	if (adev->pm.pp_feature & PP_DCEFCLK_DPM_MASK)
		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT);

293 294 295 296 297
	if (adev->pm.pp_feature & PP_MCLK_DPM_MASK)
		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_UCLK_BIT)
				| FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT)
				| FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT);

298 299 300 301 302 303
	if (adev->pm.pp_feature & PP_ULV_MASK)
		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_ULV_BIT);

	if (adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK)
		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_GFXCLK_BIT);

304
	if (adev->pm.pp_feature & PP_GFXOFF_MASK)
305
		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXOFF_BIT);
306

307 308 309
	if (smu->adev->pg_flags & AMD_PG_SUPPORT_MMHUB)
		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MMHUB_PG_BIT);

310 311 312
	if (smu->adev->pg_flags & AMD_PG_SUPPORT_ATHUB)
		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_PG_BIT);

313
	if (smu->adev->pg_flags & AMD_PG_SUPPORT_VCN)
314 315 316 317
		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VCN_PG_BIT);

	if (smu->adev->pg_flags & AMD_PG_SUPPORT_JPEG)
		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_JPEG_PG_BIT);
318

319 320 321
	if (smu->dc_controlled_by_gpio)
		*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ACDC_BIT);

322 323 324 325 326 327
	/* disable DPM UCLK and DS SOCCLK on navi10 A0 secure board */
	if (is_asic_secure(smu)) {
		/* only for navi10 A0 */
		if ((adev->asic_type == CHIP_NAVI10) &&
			(adev->rev_id == 0)) {
			*(uint64_t *)feature_mask &=
328 329 330
					~(FEATURE_MASK(FEATURE_DPM_UCLK_BIT)
					  | FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT)
					  | FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT));
331 332 333 334 335
			*(uint64_t *)feature_mask &=
					~FEATURE_MASK(FEATURE_DS_SOCCLK_BIT);
		}
	}

336 337 338 339 340
	return 0;
}

static int navi10_check_powerplay_table(struct smu_context *smu)
{
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
	struct smu_table_context *table_context = &smu->smu_table;
	struct smu_11_0_powerplay_table *powerplay_table =
		table_context->power_play_table;
	struct smu_baco_context *smu_baco = &smu->smu_baco;

	if (powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_HARDWAREDC)
		smu->dc_controlled_by_gpio = true;

	mutex_lock(&smu_baco->mutex);
	if (powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_BACO ||
	    powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_MACO)
		smu_baco->platform_support = true;
	mutex_unlock(&smu_baco->mutex);

	table_context->thermal_controller_type =
		powerplay_table->thermal_controller_type;

	/*
	 * Instead of having its own buffer space and get overdrive_table copied,
	 * smu->od_settings just points to the actual overdrive_table
	 */
	smu->od_settings = &powerplay_table->overdrive_table;

364 365 366 367 368
	return 0;
}

static int navi10_append_powerplay_table(struct smu_context *smu)
{
369
	struct amdgpu_device *adev = smu->adev;
370 371 372
	struct smu_table_context *table_context = &smu->smu_table;
	PPTable_t *smc_pptable = table_context->driver_pptable;
	struct atom_smc_dpm_info_v4_5 *smc_dpm_table;
373
	struct atom_smc_dpm_info_v4_7 *smc_dpm_table_v4_7;
374 375 376 377 378
	int index, ret;

	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
					   smc_dpm_info);

379
	ret = amdgpu_atombios_get_data_table(adev, index, NULL, NULL, NULL,
380 381 382 383
				      (uint8_t **)&smc_dpm_table);
	if (ret)
		return ret;

384
	dev_info(adev->dev, "smc_dpm_info table revision(format.content): %d.%d\n",
385 386 387 388
			smc_dpm_table->table_header.format_revision,
			smc_dpm_table->table_header.content_revision);

	if (smc_dpm_table->table_header.format_revision != 4) {
389
		dev_err(adev->dev, "smc_dpm_info table format revision is not 4!\n");
390 391 392 393 394 395 396 397 398
		return -EINVAL;
	}

	switch (smc_dpm_table->table_header.content_revision) {
	case 5: /* nv10 and nv14 */
		memcpy(smc_pptable->I2cControllers, smc_dpm_table->I2cControllers,
			sizeof(*smc_dpm_table) - sizeof(smc_dpm_table->table_header));
		break;
	case 7: /* nv12 */
399
		ret = amdgpu_atombios_get_data_table(adev, index, NULL, NULL, NULL,
400 401 402 403 404 405 406
					      (uint8_t **)&smc_dpm_table_v4_7);
		if (ret)
			return ret;
		memcpy(smc_pptable->I2cControllers, smc_dpm_table_v4_7->I2cControllers,
			sizeof(*smc_dpm_table_v4_7) - sizeof(smc_dpm_table_v4_7->table_header));
		break;
	default:
407
		dev_err(smu->adev->dev, "smc_dpm_info with unsupported content revision %d!\n",
408 409 410
				smc_dpm_table->table_header.content_revision);
		return -EINVAL;
	}
411

412 413 414 415 416
	if (adev->pm.pp_feature & PP_GFXOFF_MASK) {
		/* TODO: remove it once SMU fw fix it */
		smc_pptable->DebugOverrides |= DPM_OVERRIDE_DISABLE_DFLL_PLL_SHUTDOWN;
	}

417 418 419 420 421 422
	return 0;
}

static int navi10_store_powerplay_table(struct smu_context *smu)
{
	struct smu_table_context *table_context = &smu->smu_table;
423 424
	struct smu_11_0_powerplay_table *powerplay_table =
		table_context->power_play_table;
425 426 427 428

	memcpy(table_context->driver_pptable, &powerplay_table->smc_pptable,
	       sizeof(PPTable_t));

429 430
	return 0;
}
431

432 433 434
static int navi10_setup_pptable(struct smu_context *smu)
{
	int ret = 0;
435

436 437 438
	ret = smu_v11_0_setup_pptable(smu);
	if (ret)
		return ret;
439

440 441 442 443 444 445 446 447 448 449 450 451 452
	ret = navi10_store_powerplay_table(smu);
	if (ret)
		return ret;

	ret = navi10_append_powerplay_table(smu);
	if (ret)
		return ret;

	ret = navi10_check_powerplay_table(smu);
	if (ret)
		return ret;

	return ret;
453 454
}

455
static int navi10_tables_init(struct smu_context *smu)
456
{
457
	struct smu_table_context *smu_table = &smu->smu_table;
458
	struct smu_table *tables = smu_table->tables;
459

460 461 462 463 464 465
	SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t),
		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
	SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
	SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
466 467
	SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t),
		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
468 469 470 471 472 473 474
	SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t),
		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
	SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE,
		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
	SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF,
		       sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE,
		       AMDGPU_GEM_DOMAIN_VRAM);
475

476 477 478 479 480
	smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
	if (!smu_table->metrics_table)
		return -ENOMEM;
	smu_table->metrics_time = 0;

481 482 483 484
	smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
	if (!smu_table->watermarks_table)
		return -ENOMEM;

485
	return 0;
486 487
}

488 489 490
static int navi10_get_smu_metrics_data(struct smu_context *smu,
				       MetricsMember_t member,
				       uint32_t *value)
491 492
{
	struct smu_table_context *smu_table= &smu->smu_table;
493
	SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
494 495
	int ret = 0;

496
	mutex_lock(&smu->metrics_lock);
497
	if (!smu_table->metrics_time ||
498
	     time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(1))) {
499
		ret = smu_cmn_update_table(smu,
500 501 502 503
				       SMU_TABLE_SMU_METRICS,
				       0,
				       smu_table->metrics_table,
				       false);
504
		if (ret) {
505
			dev_info(smu->adev->dev, "Failed to export SMU metrics table!\n");
506
			mutex_unlock(&smu->metrics_lock);
507 508 509 510 511
			return ret;
		}
		smu_table->metrics_time = jiffies;
	}

512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
	switch (member) {
	case METRICS_CURR_GFXCLK:
		*value = metrics->CurrClock[PPCLK_GFXCLK];
		break;
	case METRICS_CURR_SOCCLK:
		*value = metrics->CurrClock[PPCLK_SOCCLK];
		break;
	case METRICS_CURR_UCLK:
		*value = metrics->CurrClock[PPCLK_UCLK];
		break;
	case METRICS_CURR_VCLK:
		*value = metrics->CurrClock[PPCLK_VCLK];
		break;
	case METRICS_CURR_DCLK:
		*value = metrics->CurrClock[PPCLK_DCLK];
		break;
528 529 530
	case METRICS_CURR_DCEFCLK:
		*value = metrics->CurrClock[PPCLK_DCEFCLK];
		break;
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
	case METRICS_AVERAGE_GFXCLK:
		*value = metrics->AverageGfxclkFrequency;
		break;
	case METRICS_AVERAGE_SOCCLK:
		*value = metrics->AverageSocclkFrequency;
		break;
	case METRICS_AVERAGE_UCLK:
		*value = metrics->AverageUclkFrequency;
		break;
	case METRICS_AVERAGE_GFXACTIVITY:
		*value = metrics->AverageGfxActivity;
		break;
	case METRICS_AVERAGE_MEMACTIVITY:
		*value = metrics->AverageUclkActivity;
		break;
	case METRICS_AVERAGE_SOCKETPOWER:
		*value = metrics->AverageSocketPower << 8;
		break;
	case METRICS_TEMPERATURE_EDGE:
		*value = metrics->TemperatureEdge *
			SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
		break;
	case METRICS_TEMPERATURE_HOTSPOT:
		*value = metrics->TemperatureHotspot *
			SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
		break;
	case METRICS_TEMPERATURE_MEM:
		*value = metrics->TemperatureMem *
			SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
		break;
	case METRICS_TEMPERATURE_VRGFX:
		*value = metrics->TemperatureVrGfx *
			SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
		break;
	case METRICS_TEMPERATURE_VRSOC:
		*value = metrics->TemperatureVrSoc *
			SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
		break;
	case METRICS_THROTTLER_STATUS:
		*value = metrics->ThrottlerStatus;
		break;
	case METRICS_CURR_FANSPEED:
		*value = metrics->CurrFanSpeed;
		break;
	default:
		*value = UINT_MAX;
		break;
	}

580
	mutex_unlock(&smu->metrics_lock);
581 582 583 584

	return ret;
}

585 586 587 588 589 590 591 592 593 594 595 596 597 598
static int navi10_allocate_dpm_context(struct smu_context *smu)
{
	struct smu_dpm_context *smu_dpm = &smu->smu_dpm;

	smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context),
				       GFP_KERNEL);
	if (!smu_dpm->dpm_context)
		return -ENOMEM;

	smu_dpm->dpm_context_size = sizeof(struct smu_11_0_dpm_context);

	return 0;
}

599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
static int navi10_init_smc_tables(struct smu_context *smu)
{
	int ret = 0;

	ret = navi10_tables_init(smu);
	if (ret)
		return ret;

	ret = navi10_allocate_dpm_context(smu);
	if (ret)
		return ret;

	return smu_v11_0_init_smc_tables(smu);
}

614 615
static int navi10_set_default_dpm_table(struct smu_context *smu)
{
616 617 618 619
	struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
	PPTable_t *driver_ppt = smu->smu_table.driver_pptable;
	struct smu_11_0_dpm_table *dpm_table;
	int ret = 0;
620

621 622
	/* socclk dpm table setup */
	dpm_table = &dpm_context->dpm_tables.soc_table;
623
	if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
624 625 626 627 628 629 630 631 632 633 634 635 636 637
		ret = smu_v11_0_set_single_dpm_table(smu,
						     SMU_SOCCLK,
						     dpm_table);
		if (ret)
			return ret;
		dpm_table->is_fine_grained =
			!driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete;
	} else {
		dpm_table->count = 1;
		dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100;
		dpm_table->dpm_levels[0].enabled = true;
		dpm_table->min = dpm_table->dpm_levels[0].value;
		dpm_table->max = dpm_table->dpm_levels[0].value;
	}
638

639 640
	/* gfxclk dpm table setup */
	dpm_table = &dpm_context->dpm_tables.gfx_table;
641
	if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
642 643 644 645 646 647 648 649 650 651 652 653 654 655
		ret = smu_v11_0_set_single_dpm_table(smu,
						     SMU_GFXCLK,
						     dpm_table);
		if (ret)
			return ret;
		dpm_table->is_fine_grained =
			!driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete;
	} else {
		dpm_table->count = 1;
		dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
		dpm_table->dpm_levels[0].enabled = true;
		dpm_table->min = dpm_table->dpm_levels[0].value;
		dpm_table->max = dpm_table->dpm_levels[0].value;
	}
656

657 658
	/* uclk dpm table setup */
	dpm_table = &dpm_context->dpm_tables.uclk_table;
659
	if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
660 661 662 663 664 665 666 667 668 669 670 671 672 673
		ret = smu_v11_0_set_single_dpm_table(smu,
						     SMU_UCLK,
						     dpm_table);
		if (ret)
			return ret;
		dpm_table->is_fine_grained =
			!driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete;
	} else {
		dpm_table->count = 1;
		dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100;
		dpm_table->dpm_levels[0].enabled = true;
		dpm_table->min = dpm_table->dpm_levels[0].value;
		dpm_table->max = dpm_table->dpm_levels[0].value;
	}
674

675 676
	/* vclk dpm table setup */
	dpm_table = &dpm_context->dpm_tables.vclk_table;
677
	if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
678 679 680 681 682 683 684 685 686 687 688 689 690 691
		ret = smu_v11_0_set_single_dpm_table(smu,
						     SMU_VCLK,
						     dpm_table);
		if (ret)
			return ret;
		dpm_table->is_fine_grained =
			!driver_ppt->DpmDescriptor[PPCLK_VCLK].SnapToDiscrete;
	} else {
		dpm_table->count = 1;
		dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100;
		dpm_table->dpm_levels[0].enabled = true;
		dpm_table->min = dpm_table->dpm_levels[0].value;
		dpm_table->max = dpm_table->dpm_levels[0].value;
	}
692

693 694
	/* dclk dpm table setup */
	dpm_table = &dpm_context->dpm_tables.dclk_table;
695
	if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
696 697 698 699 700 701 702 703 704 705 706 707 708 709
		ret = smu_v11_0_set_single_dpm_table(smu,
						     SMU_DCLK,
						     dpm_table);
		if (ret)
			return ret;
		dpm_table->is_fine_grained =
			!driver_ppt->DpmDescriptor[PPCLK_DCLK].SnapToDiscrete;
	} else {
		dpm_table->count = 1;
		dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100;
		dpm_table->dpm_levels[0].enabled = true;
		dpm_table->min = dpm_table->dpm_levels[0].value;
		dpm_table->max = dpm_table->dpm_levels[0].value;
	}
710

711 712
	/* dcefclk dpm table setup */
	dpm_table = &dpm_context->dpm_tables.dcef_table;
713
	if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
714 715 716 717 718 719 720 721 722 723 724 725 726 727
		ret = smu_v11_0_set_single_dpm_table(smu,
						     SMU_DCEFCLK,
						     dpm_table);
		if (ret)
			return ret;
		dpm_table->is_fine_grained =
			!driver_ppt->DpmDescriptor[PPCLK_DCEFCLK].SnapToDiscrete;
	} else {
		dpm_table->count = 1;
		dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
		dpm_table->dpm_levels[0].enabled = true;
		dpm_table->min = dpm_table->dpm_levels[0].value;
		dpm_table->max = dpm_table->dpm_levels[0].value;
	}
728

729 730
	/* pixelclk dpm table setup */
	dpm_table = &dpm_context->dpm_tables.pixel_table;
731
	if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
732 733 734 735 736 737 738 739 740 741 742 743 744 745
		ret = smu_v11_0_set_single_dpm_table(smu,
						     SMU_PIXCLK,
						     dpm_table);
		if (ret)
			return ret;
		dpm_table->is_fine_grained =
			!driver_ppt->DpmDescriptor[PPCLK_PIXCLK].SnapToDiscrete;
	} else {
		dpm_table->count = 1;
		dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
		dpm_table->dpm_levels[0].enabled = true;
		dpm_table->min = dpm_table->dpm_levels[0].value;
		dpm_table->max = dpm_table->dpm_levels[0].value;
	}
746

747 748
	/* displayclk dpm table setup */
	dpm_table = &dpm_context->dpm_tables.display_table;
749
	if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
750 751 752 753 754 755 756 757 758 759 760 761 762 763
		ret = smu_v11_0_set_single_dpm_table(smu,
						     SMU_DISPCLK,
						     dpm_table);
		if (ret)
			return ret;
		dpm_table->is_fine_grained =
			!driver_ppt->DpmDescriptor[PPCLK_DISPCLK].SnapToDiscrete;
	} else {
		dpm_table->count = 1;
		dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
		dpm_table->dpm_levels[0].enabled = true;
		dpm_table->min = dpm_table->dpm_levels[0].value;
		dpm_table->max = dpm_table->dpm_levels[0].value;
	}
764

765 766
	/* phyclk dpm table setup */
	dpm_table = &dpm_context->dpm_tables.phy_table;
767
	if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
768 769 770 771 772 773 774 775 776 777 778 779 780 781
		ret = smu_v11_0_set_single_dpm_table(smu,
						     SMU_PHYCLK,
						     dpm_table);
		if (ret)
			return ret;
		dpm_table->is_fine_grained =
			!driver_ppt->DpmDescriptor[PPCLK_PHYCLK].SnapToDiscrete;
	} else {
		dpm_table->count = 1;
		dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
		dpm_table->dpm_levels[0].enabled = true;
		dpm_table->min = dpm_table->dpm_levels[0].value;
		dpm_table->max = dpm_table->dpm_levels[0].value;
	}
782 783 784 785

	return 0;
}

786
static int navi10_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
787
{
788 789
	struct smu_power_context *smu_power = &smu->smu_power;
	struct smu_power_gate *power_gate = &smu_power->power_gate;
790
	int ret = 0;
791 792

	if (enable) {
793
		/* vcn dpm on is a prerequisite for vcn power gate messages */
794
		if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
795
			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 1, NULL);
796 797 798 799
			if (ret)
				return ret;
		}
		power_gate->vcn_gated = false;
800
	} else {
801
		if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
802
			ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerDownVcn, NULL);
803 804 805 806
			if (ret)
				return ret;
		}
		power_gate->vcn_gated = true;
807 808
	}

809
	return ret;
810 811
}

812 813 814 815 816 817 818
static int navi10_dpm_set_jpeg_enable(struct smu_context *smu, bool enable)
{
	struct smu_power_context *smu_power = &smu->smu_power;
	struct smu_power_gate *power_gate = &smu_power->power_gate;
	int ret = 0;

	if (enable) {
819
		if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) {
820
			ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerUpJpeg, NULL);
821 822 823 824 825
			if (ret)
				return ret;
		}
		power_gate->jpeg_gated = false;
	} else {
826
		if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) {
827
			ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerDownJpeg, NULL);
828 829 830 831 832 833 834 835 836
			if (ret)
				return ret;
		}
		power_gate->jpeg_gated = true;
	}

	return ret;
}

837 838 839 840
static int navi10_get_current_clk_freq_by_table(struct smu_context *smu,
				       enum smu_clk_type clk_type,
				       uint32_t *value)
{
841 842
	MetricsMember_t member_type;
	int clk_id = 0;
843

844 845 846
	clk_id = smu_cmn_to_asic_specific_index(smu,
						CMN2ASIC_MAPPING_CLK,
						clk_type);
847 848 849
	if (clk_id < 0)
		return clk_id;

850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
	switch (clk_id) {
	case PPCLK_GFXCLK:
		member_type = METRICS_CURR_GFXCLK;
		break;
	case PPCLK_UCLK:
		member_type = METRICS_CURR_UCLK;
		break;
	case PPCLK_SOCCLK:
		member_type = METRICS_CURR_SOCCLK;
		break;
	case PPCLK_VCLK:
		member_type = METRICS_CURR_VCLK;
		break;
	case PPCLK_DCLK:
		member_type = METRICS_CURR_DCLK;
		break;
	case PPCLK_DCEFCLK:
		member_type = METRICS_CURR_DCEFCLK;
		break;
	default:
		return -EINVAL;
	}
872

873 874 875
	return navi10_get_smu_metrics_data(smu,
					   member_type,
					   value);
876 877
}

878 879 880 881 882 883
static bool navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu_clk_type clk_type)
{
	PPTable_t *pptable = smu->smu_table.driver_pptable;
	DpmDescriptor_t *dpm_desc = NULL;
	uint32_t clk_index = 0;

884 885 886
	clk_index = smu_cmn_to_asic_specific_index(smu,
						   CMN2ASIC_MAPPING_CLK,
						   clk_type);
887 888 889 890 891 892
	dpm_desc = &pptable->DpmDescriptor[clk_index];

	/* 0 - Fine grained DPM, 1 - Discrete DPM */
	return dpm_desc->SnapToDiscrete == 0 ? true : false;
}

893
static inline bool navi10_od_feature_is_supported(struct smu_11_0_overdrive_table *od_table, enum SMU_11_0_ODFEATURE_CAP cap)
894
{
895
	return od_table->cap[cap];
896 897
}

898 899 900 901 902 903 904 905 906
static void navi10_od_setting_get_range(struct smu_11_0_overdrive_table *od_table,
					enum SMU_11_0_ODSETTING_ID setting,
					uint32_t *min, uint32_t *max)
{
	if (min)
		*min = od_table->min[setting];
	if (max)
		*max = od_table->max[setting];
}
907

908 909 910
static int navi10_print_clk_levels(struct smu_context *smu,
			enum smu_clk_type clk_type, char *buf)
{
911
	uint16_t *curve_settings;
912 913
	int i, size = 0, ret = 0;
	uint32_t cur_value = 0, value = 0, count = 0;
914 915
	uint32_t freq_values[3] = {0};
	uint32_t mark_index = 0;
916
	struct smu_table_context *table_context = &smu->smu_table;
917 918 919 920 921 922 923 924
	uint32_t gen_speed, lane_width;
	struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
	struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context;
	struct amdgpu_device *adev = smu->adev;
	PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable;
	OverDriveTable_t *od_table =
		(OverDriveTable_t *)table_context->overdrive_table;
	struct smu_11_0_overdrive_table *od_settings = smu->od_settings;
925
	uint32_t min_value, max_value;
926 927 928 929 930 931 932 933 934

	switch (clk_type) {
	case SMU_GFXCLK:
	case SMU_SCLK:
	case SMU_SOCCLK:
	case SMU_MCLK:
	case SMU_UCLK:
	case SMU_FCLK:
	case SMU_DCEFCLK:
935
		ret = navi10_get_current_clk_freq_by_table(smu, clk_type, &cur_value);
936 937
		if (ret)
			return size;
938

939
		ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &count);
940 941 942
		if (ret)
			return size;

943 944
		if (!navi10_is_support_fine_grained_dpm(smu, clk_type)) {
			for (i = 0; i < count; i++) {
945
				ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &value);
946 947 948 949 950 951 952
				if (ret)
					return size;

				size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
						cur_value == value ? "*" : "");
			}
		} else {
953
			ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, 0, &freq_values[0]);
954 955
			if (ret)
				return size;
956
			ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, count - 1, &freq_values[2]);
957 958 959
			if (ret)
				return size;

960 961 962 963 964 965 966 967 968 969 970
			freq_values[1] = cur_value;
			mark_index = cur_value == freq_values[0] ? 0 :
				     cur_value == freq_values[2] ? 2 : 1;
			if (mark_index != 1)
				freq_values[1] = (freq_values[0] + freq_values[2]) / 2;

			for (i = 0; i < 3; i++) {
				size += sprintf(buf + size, "%d: %uMhz %s\n", i, freq_values[i],
						i == mark_index ? "*" : "");
			}

971 972
		}
		break;
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
	case SMU_PCIE:
		gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) &
			     PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK)
			>> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
		lane_width = (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) &
			      PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK)
			>> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT;
		for (i = 0; i < NUM_LINK_LEVELS; i++)
			size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
					(dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," :
					(dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 1) ? "5.0GT/s," :
					(dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 2) ? "8.0GT/s," :
					(dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 3) ? "16.0GT/s," : "",
					(dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 1) ? "x1" :
					(dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 2) ? "x2" :
					(dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 3) ? "x4" :
					(dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 4) ? "x8" :
					(dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 5) ? "x12" :
					(dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 6) ? "x16" : "",
					pptable->LclkFreq[i],
					(gen_speed == dpm_context->dpm_tables.pcie_table.pcie_gen[i]) &&
					(lane_width == dpm_context->dpm_tables.pcie_table.pcie_lane[i]) ?
					"*" : "");
		break;
997 998 999
	case SMU_OD_SCLK:
		if (!smu->od_enabled || !od_table || !od_settings)
			break;
1000
		if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS))
1001 1002 1003 1004 1005 1006 1007
			break;
		size += sprintf(buf + size, "OD_SCLK:\n");
		size += sprintf(buf + size, "0: %uMhz\n1: %uMhz\n", od_table->GfxclkFmin, od_table->GfxclkFmax);
		break;
	case SMU_OD_MCLK:
		if (!smu->od_enabled || !od_table || !od_settings)
			break;
1008
		if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX))
1009 1010
			break;
		size += sprintf(buf + size, "OD_MCLK:\n");
1011
		size += sprintf(buf + size, "1: %uMHz\n", od_table->UclkFmax);
1012 1013 1014 1015
		break;
	case SMU_OD_VDDC_CURVE:
		if (!smu->od_enabled || !od_table || !od_settings)
			break;
1016
		if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE))
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
			break;
		size += sprintf(buf + size, "OD_VDDC_CURVE:\n");
		for (i = 0; i < 3; i++) {
			switch (i) {
			case 0:
				curve_settings = &od_table->GfxclkFreq1;
				break;
			case 1:
				curve_settings = &od_table->GfxclkFreq2;
				break;
			case 2:
				curve_settings = &od_table->GfxclkFreq3;
				break;
			default:
				break;
			}
1033
			size += sprintf(buf + size, "%d: %uMHz %umV\n", i, curve_settings[0], curve_settings[1] / NAVI10_VOLTAGE_SCALE);
1034
		}
1035 1036 1037 1038 1039 1040
		break;
	case SMU_OD_RANGE:
		if (!smu->od_enabled || !od_table || !od_settings)
			break;
		size = sprintf(buf, "%s:\n", "OD_RANGE");

1041
		if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) {
1042 1043 1044 1045 1046 1047 1048 1049
			navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_GFXCLKFMIN,
						    &min_value, NULL);
			navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_GFXCLKFMAX,
						    NULL, &max_value);
			size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
					min_value, max_value);
		}

1050
		if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) {
1051 1052 1053 1054 1055 1056
			navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_UCLKFMAX,
						    &min_value, &max_value);
			size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
					min_value, max_value);
		}

1057
		if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) {
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
			navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P1,
						    &min_value, &max_value);
			size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
					min_value, max_value);
			navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P1,
						    &min_value, &max_value);
			size += sprintf(buf + size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n",
					min_value, max_value);
			navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P2,
						    &min_value, &max_value);
			size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
					min_value, max_value);
			navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P2,
						    &min_value, &max_value);
			size += sprintf(buf + size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n",
					min_value, max_value);
			navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P3,
						    &min_value, &max_value);
			size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
					min_value, max_value);
			navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P3,
						    &min_value, &max_value);
			size += sprintf(buf + size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
					min_value, max_value);
		}

1084
		break;
1085 1086 1087 1088 1089 1090 1091
	default:
		break;
	}

	return size;
}

1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
static int navi10_force_clk_levels(struct smu_context *smu,
				   enum smu_clk_type clk_type, uint32_t mask)
{

	int ret = 0, size = 0;
	uint32_t soft_min_level = 0, soft_max_level = 0, min_freq = 0, max_freq = 0;

	soft_min_level = mask ? (ffs(mask) - 1) : 0;
	soft_max_level = mask ? (fls(mask) - 1) : 0;

	switch (clk_type) {
	case SMU_GFXCLK:
1104
	case SMU_SCLK:
1105 1106 1107 1108 1109
	case SMU_SOCCLK:
	case SMU_MCLK:
	case SMU_UCLK:
	case SMU_DCEFCLK:
	case SMU_FCLK:
1110 1111 1112 1113 1114 1115
		/* There is only 2 levels for fine grained DPM */
		if (navi10_is_support_fine_grained_dpm(smu, clk_type)) {
			soft_max_level = (soft_max_level >= 1 ? 1 : 0);
			soft_min_level = (soft_min_level >= 1 ? 1 : 0);
		}

1116
		ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq);
1117 1118 1119
		if (ret)
			return size;

1120
		ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq);
1121 1122 1123
		if (ret)
			return size;

1124
		ret = smu_v11_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq);
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
		if (ret)
			return size;
		break;
	default:
		break;
	}

	return size;
}

1135 1136
static int navi10_populate_umd_state_clk(struct smu_context *smu)
{
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221
	struct smu_11_0_dpm_context *dpm_context =
				smu->smu_dpm.dpm_context;
	struct smu_11_0_dpm_table *gfx_table =
				&dpm_context->dpm_tables.gfx_table;
	struct smu_11_0_dpm_table *mem_table =
				&dpm_context->dpm_tables.uclk_table;
	struct smu_11_0_dpm_table *soc_table =
				&dpm_context->dpm_tables.soc_table;
	struct smu_umd_pstate_table *pstate_table =
				&smu->pstate_table;
	struct amdgpu_device *adev = smu->adev;
	uint32_t sclk_freq;

	pstate_table->gfxclk_pstate.min = gfx_table->min;
	switch (adev->asic_type) {
	case CHIP_NAVI10:
		switch (adev->pdev->revision) {
		case 0xf0: /* XTX */
		case 0xc0:
			sclk_freq = NAVI10_PEAK_SCLK_XTX;
			break;
		case 0xf1: /* XT */
		case 0xc1:
			sclk_freq = NAVI10_PEAK_SCLK_XT;
			break;
		default: /* XL */
			sclk_freq = NAVI10_PEAK_SCLK_XL;
			break;
		}
		break;
	case CHIP_NAVI14:
		switch (adev->pdev->revision) {
		case 0xc7: /* XT */
		case 0xf4:
			sclk_freq = NAVI14_UMD_PSTATE_PEAK_XT_GFXCLK;
			break;
		case 0xc1: /* XTM */
		case 0xf2:
			sclk_freq = NAVI14_UMD_PSTATE_PEAK_XTM_GFXCLK;
			break;
		case 0xc3: /* XLM */
		case 0xf3:
			sclk_freq = NAVI14_UMD_PSTATE_PEAK_XLM_GFXCLK;
			break;
		case 0xc5: /* XTX */
		case 0xf6:
			sclk_freq = NAVI14_UMD_PSTATE_PEAK_XLM_GFXCLK;
			break;
		default: /* XL */
			sclk_freq = NAVI14_UMD_PSTATE_PEAK_XL_GFXCLK;
			break;
		}
		break;
	case CHIP_NAVI12:
		sclk_freq = NAVI12_UMD_PSTATE_PEAK_GFXCLK;
		break;
	default:
		sclk_freq = gfx_table->dpm_levels[gfx_table->count - 1].value;
		break;
	}
	pstate_table->gfxclk_pstate.peak = sclk_freq;

	pstate_table->uclk_pstate.min = mem_table->min;
	pstate_table->uclk_pstate.peak = mem_table->max;

	pstate_table->socclk_pstate.min = soc_table->min;
	pstate_table->socclk_pstate.peak = soc_table->max;

	if (gfx_table->max > NAVI10_UMD_PSTATE_PROFILING_GFXCLK &&
	    mem_table->max > NAVI10_UMD_PSTATE_PROFILING_MEMCLK &&
	    soc_table->max > NAVI10_UMD_PSTATE_PROFILING_SOCCLK) {
		pstate_table->gfxclk_pstate.standard =
			NAVI10_UMD_PSTATE_PROFILING_GFXCLK;
		pstate_table->uclk_pstate.standard =
			NAVI10_UMD_PSTATE_PROFILING_MEMCLK;
		pstate_table->socclk_pstate.standard =
			NAVI10_UMD_PSTATE_PROFILING_SOCCLK;
	} else {
		pstate_table->gfxclk_pstate.standard =
			pstate_table->gfxclk_pstate.min;
		pstate_table->uclk_pstate.standard =
			pstate_table->uclk_pstate.min;
		pstate_table->socclk_pstate.standard =
			pstate_table->socclk_pstate.min;
	}
1222

1223
	return 0;
1224 1225
}

1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
static int navi10_get_clock_by_type_with_latency(struct smu_context *smu,
						 enum smu_clk_type clk_type,
						 struct pp_clock_levels_with_latency *clocks)
{
	int ret = 0, i = 0;
	uint32_t level_count = 0, freq = 0;

	switch (clk_type) {
	case SMU_GFXCLK:
	case SMU_DCEFCLK:
	case SMU_SOCCLK:
1237 1238
	case SMU_MCLK:
	case SMU_UCLK:
1239
		ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &level_count);
1240 1241 1242 1243 1244 1245 1246
		if (ret)
			return ret;

		level_count = min(level_count, (uint32_t)MAX_NUM_CLOCKS);
		clocks->num_levels = level_count;

		for (i = 0; i < level_count; i++) {
1247
			ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &freq);
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
			if (ret)
				return ret;

			clocks->data[i].clocks_in_khz = freq * 1000;
			clocks->data[i].latency_in_us = 0;
		}
		break;
	default:
		break;
	}

	return ret;
}

1262 1263 1264 1265 1266
static int navi10_pre_display_config_changed(struct smu_context *smu)
{
	int ret = 0;
	uint32_t max_freq = 0;

1267
	ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, 0, NULL);
1268 1269 1270
	if (ret)
		return ret;

1271
	if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
1272
		ret = smu_v11_0_get_dpm_ultimate_freq(smu, SMU_UCLK, NULL, &max_freq);
1273 1274
		if (ret)
			return ret;
1275
		ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, 0, max_freq);
1276 1277 1278 1279 1280 1281 1282
		if (ret)
			return ret;
	}

	return ret;
}

1283 1284 1285 1286 1287
static int navi10_display_config_changed(struct smu_context *smu)
{
	int ret = 0;

	if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
1288 1289
	    smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
	    smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
1290
		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays,
1291 1292
						  smu->display_config->num_display,
						  NULL);
1293 1294 1295 1296 1297 1298
		if (ret)
			return ret;
	}

	return ret;
}
1299

1300 1301 1302 1303 1304
static int navi10_get_gpu_power(struct smu_context *smu, uint32_t *value)
{
	if (!value)
		return -EINVAL;

1305 1306 1307
	return navi10_get_smu_metrics_data(smu,
					   METRICS_AVERAGE_SOCKETPOWER,
					   value);
1308 1309
}

1310
static int navi10_get_current_activity_percent(struct smu_context *smu,
1311
					       enum amd_pp_sensors sensor,
1312 1313 1314 1315 1316 1317 1318
					       uint32_t *value)
{
	int ret = 0;

	if (!value)
		return -EINVAL;

1319 1320
	switch (sensor) {
	case AMDGPU_PP_SENSOR_GPU_LOAD:
1321 1322 1323
		ret = navi10_get_smu_metrics_data(smu,
						  METRICS_AVERAGE_GFXACTIVITY,
						  value);
1324 1325
		break;
	case AMDGPU_PP_SENSOR_MEM_LOAD:
1326 1327 1328
		ret = navi10_get_smu_metrics_data(smu,
						  METRICS_AVERAGE_MEMACTIVITY,
						  value);
1329 1330
		break;
	default:
1331
		dev_err(smu->adev->dev, "Invalid sensor for retrieving clock activity\n");
1332 1333
		return -EINVAL;
	}
1334

1335
	return ret;
1336 1337
}

1338 1339 1340 1341 1342
static bool navi10_is_dpm_running(struct smu_context *smu)
{
	int ret = 0;
	uint32_t feature_mask[2];
	unsigned long feature_enabled;
1343
	ret = smu_cmn_get_enabled_mask(smu, feature_mask, 2);
1344 1345 1346 1347 1348
	feature_enabled = (unsigned long)((uint64_t)feature_mask[0] |
			   ((uint64_t)feature_mask[1] << 32));
	return !!(feature_enabled & SMC_DPM_FEATURE);
}

1349 1350
static int navi10_get_fan_speed_rpm(struct smu_context *smu,
				    uint32_t *speed)
1351
{
1352
	if (!speed)
1353 1354
		return -EINVAL;

1355 1356 1357
	return navi10_get_smu_metrics_data(smu,
					   METRICS_CURR_FANSPEED,
					   speed);
1358 1359
}

1360 1361 1362 1363 1364
static int navi10_get_fan_speed_percent(struct smu_context *smu,
					uint32_t *speed)
{
	int ret = 0;
	uint32_t percent = 0;
1365
	uint32_t current_rpm;
1366 1367
	PPTable_t *pptable = smu->smu_table.driver_pptable;

1368
	ret = navi10_get_fan_speed_rpm(smu, &current_rpm);
1369 1370 1371 1372 1373 1374 1375 1376 1377
	if (ret)
		return ret;

	percent = current_rpm * 100 / pptable->FanMaximumRpm;
	*speed = percent > 100 ? 100 : percent;

	return ret;
}

1378 1379 1380 1381
static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
{
	DpmActivityMonitorCoeffInt_t activity_monitor;
	uint32_t i, size = 0;
1382
	int16_t workload_type = 0;
1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413
	static const char *profile_name[] = {
					"BOOTUP_DEFAULT",
					"3D_FULL_SCREEN",
					"POWER_SAVING",
					"VIDEO",
					"VR",
					"COMPUTE",
					"CUSTOM"};
	static const char *title[] = {
			"PROFILE_INDEX(NAME)",
			"CLOCK_TYPE(NAME)",
			"FPS",
			"MinFreqType",
			"MinActiveFreqType",
			"MinActiveFreq",
			"BoosterFreqType",
			"BoosterFreq",
			"PD_Data_limit_c",
			"PD_Data_error_coeff",
			"PD_Data_error_rate_coeff"};
	int result = 0;

	if (!buf)
		return -EINVAL;

	size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
			title[0], title[1], title[2], title[3], title[4], title[5],
			title[6], title[7], title[8], title[9], title[10]);

	for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
		/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
1414 1415 1416
		workload_type = smu_cmn_to_asic_specific_index(smu,
							       CMN2ASIC_MAPPING_WORKLOAD,
							       i);
1417 1418 1419
		if (workload_type < 0)
			return -EINVAL;

1420
		result = smu_cmn_update_table(smu,
1421
					  SMU_TABLE_ACTIVITY_MONITOR_COEFF, workload_type,
1422 1423
					  (void *)(&activity_monitor), false);
		if (result) {
1424
			dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484
			return result;
		}

		size += sprintf(buf + size, "%2d %14s%s:\n",
			i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");

		size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
			" ",
			0,
			"GFXCLK",
			activity_monitor.Gfx_FPS,
			activity_monitor.Gfx_MinFreqStep,
			activity_monitor.Gfx_MinActiveFreqType,
			activity_monitor.Gfx_MinActiveFreq,
			activity_monitor.Gfx_BoosterFreqType,
			activity_monitor.Gfx_BoosterFreq,
			activity_monitor.Gfx_PD_Data_limit_c,
			activity_monitor.Gfx_PD_Data_error_coeff,
			activity_monitor.Gfx_PD_Data_error_rate_coeff);

		size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
			" ",
			1,
			"SOCCLK",
			activity_monitor.Soc_FPS,
			activity_monitor.Soc_MinFreqStep,
			activity_monitor.Soc_MinActiveFreqType,
			activity_monitor.Soc_MinActiveFreq,
			activity_monitor.Soc_BoosterFreqType,
			activity_monitor.Soc_BoosterFreq,
			activity_monitor.Soc_PD_Data_limit_c,
			activity_monitor.Soc_PD_Data_error_coeff,
			activity_monitor.Soc_PD_Data_error_rate_coeff);

		size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
			" ",
			2,
			"MEMLK",
			activity_monitor.Mem_FPS,
			activity_monitor.Mem_MinFreqStep,
			activity_monitor.Mem_MinActiveFreqType,
			activity_monitor.Mem_MinActiveFreq,
			activity_monitor.Mem_BoosterFreqType,
			activity_monitor.Mem_BoosterFreq,
			activity_monitor.Mem_PD_Data_limit_c,
			activity_monitor.Mem_PD_Data_error_coeff,
			activity_monitor.Mem_PD_Data_error_rate_coeff);
	}

	return size;
}

static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
{
	DpmActivityMonitorCoeffInt_t activity_monitor;
	int workload_type, ret = 0;

	smu->power_profile_mode = input[size];

	if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
1485
		dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
1486 1487 1488 1489 1490
		return -EINVAL;
	}

	if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {

1491
		ret = smu_cmn_update_table(smu,
1492
				       SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
1493 1494
				       (void *)(&activity_monitor), false);
		if (ret) {
1495
			dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534
			return ret;
		}

		switch (input[0]) {
		case 0: /* Gfxclk */
			activity_monitor.Gfx_FPS = input[1];
			activity_monitor.Gfx_MinFreqStep = input[2];
			activity_monitor.Gfx_MinActiveFreqType = input[3];
			activity_monitor.Gfx_MinActiveFreq = input[4];
			activity_monitor.Gfx_BoosterFreqType = input[5];
			activity_monitor.Gfx_BoosterFreq = input[6];
			activity_monitor.Gfx_PD_Data_limit_c = input[7];
			activity_monitor.Gfx_PD_Data_error_coeff = input[8];
			activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
			break;
		case 1: /* Socclk */
			activity_monitor.Soc_FPS = input[1];
			activity_monitor.Soc_MinFreqStep = input[2];
			activity_monitor.Soc_MinActiveFreqType = input[3];
			activity_monitor.Soc_MinActiveFreq = input[4];
			activity_monitor.Soc_BoosterFreqType = input[5];
			activity_monitor.Soc_BoosterFreq = input[6];
			activity_monitor.Soc_PD_Data_limit_c = input[7];
			activity_monitor.Soc_PD_Data_error_coeff = input[8];
			activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
			break;
		case 2: /* Memlk */
			activity_monitor.Mem_FPS = input[1];
			activity_monitor.Mem_MinFreqStep = input[2];
			activity_monitor.Mem_MinActiveFreqType = input[3];
			activity_monitor.Mem_MinActiveFreq = input[4];
			activity_monitor.Mem_BoosterFreqType = input[5];
			activity_monitor.Mem_BoosterFreq = input[6];
			activity_monitor.Mem_PD_Data_limit_c = input[7];
			activity_monitor.Mem_PD_Data_error_coeff = input[8];
			activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
			break;
		}

1535
		ret = smu_cmn_update_table(smu,
1536
				       SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
1537 1538
				       (void *)(&activity_monitor), true);
		if (ret) {
1539
			dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
1540 1541 1542 1543 1544
			return ret;
		}
	}

	/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
1545 1546 1547
	workload_type = smu_cmn_to_asic_specific_index(smu,
						       CMN2ASIC_MAPPING_WORKLOAD,
						       smu->power_profile_mode);
1548 1549
	if (workload_type < 0)
		return -EINVAL;
1550
	smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
1551
				    1 << workload_type, NULL);
1552 1553 1554 1555

	return ret;
}

A
Alex Deucher 已提交
1556
static int navi10_notify_smc_display_config(struct smu_context *smu)
1557 1558 1559 1560 1561 1562 1563 1564 1565
{
	struct smu_clocks min_clocks = {0};
	struct pp_display_clock_request clock_req;
	int ret = 0;

	min_clocks.dcef_clock = smu->display_config->min_dcef_set_clk;
	min_clocks.dcef_clock_in_sr = smu->display_config->min_dcef_deep_sleep_set_clk;
	min_clocks.memory_clock = smu->display_config->min_mem_set_clock;

1566
	if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
1567 1568
		clock_req.clock_type = amd_pp_dcef_clock;
		clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10;
1569

1570
		ret = smu_v11_0_display_clock_voltage_request(smu, &clock_req);
1571
		if (!ret) {
1572
			if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_DCEFCLK_BIT)) {
1573
				ret = smu_cmn_send_smc_msg_with_param(smu,
1574
								  SMU_MSG_SetMinDeepSleepDcefclk,
1575 1576
								  min_clocks.dcef_clock_in_sr/100,
								  NULL);
1577
				if (ret) {
1578
					dev_err(smu->adev->dev, "Attempt to set divider for DCEFCLK Failed!");
1579 1580 1581 1582
					return ret;
				}
			}
		} else {
1583
			dev_info(smu->adev->dev, "Attempt to set Hard Min for DCEFCLK Failed!");
1584 1585 1586
		}
	}

1587
	if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
1588
		ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, min_clocks.memory_clock/100, 0);
1589
		if (ret) {
1590
			dev_err(smu->adev->dev, "[%s] Set hard min uclk failed!", __func__);
1591 1592 1593 1594 1595 1596 1597
			return ret;
		}
	}

	return 0;
}

1598
static int navi10_set_watermarks_table(struct smu_context *smu,
1599
				       struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges)
1600
{
1601
	Watermarks_t *table = smu->smu_table.watermarks_table;
1602
	int ret = 0;
1603
	int i;
1604

1605 1606 1607 1608
	if (clock_ranges) {
		if (clock_ranges->num_wm_dmif_sets > 4 ||
		    clock_ranges->num_wm_mcif_sets > 4)
			return -EINVAL;
1609

1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629
		for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) {
			table->WatermarkRow[1][i].MinClock =
				cpu_to_le16((uint16_t)
				(clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz /
				1000));
			table->WatermarkRow[1][i].MaxClock =
				cpu_to_le16((uint16_t)
				(clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz /
				1000));
			table->WatermarkRow[1][i].MinUclk =
				cpu_to_le16((uint16_t)
				(clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz /
				1000));
			table->WatermarkRow[1][i].MaxUclk =
				cpu_to_le16((uint16_t)
				(clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz /
				1000));
			table->WatermarkRow[1][i].WmSetting = (uint8_t)
					clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id;
		}
1630

1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650
		for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) {
			table->WatermarkRow[0][i].MinClock =
				cpu_to_le16((uint16_t)
				(clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz /
				1000));
			table->WatermarkRow[0][i].MaxClock =
				cpu_to_le16((uint16_t)
				(clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz /
				1000));
			table->WatermarkRow[0][i].MinUclk =
				cpu_to_le16((uint16_t)
				(clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz /
				1000));
			table->WatermarkRow[0][i].MaxUclk =
				cpu_to_le16((uint16_t)
				(clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz /
				1000));
			table->WatermarkRow[0][i].WmSetting = (uint8_t)
					clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
		}
1651

1652
		smu->watermarks_bitmap |= WATERMARKS_EXIST;
1653 1654
	}

1655
	/* pass data to smu controller */
1656 1657
	if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
	     !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
1658
		ret = smu_cmn_write_watermarks_table(smu);
1659
		if (ret) {
1660
			dev_err(smu->adev->dev, "Failed to update WMTABLE!");
1661 1662 1663 1664 1665
			return ret;
		}
		smu->watermarks_bitmap |= WATERMARKS_LOADED;
	}

1666 1667 1668
	return 0;
}

1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679
static int navi10_thermal_get_temperature(struct smu_context *smu,
					     enum amd_pp_sensors sensor,
					     uint32_t *value)
{
	int ret = 0;

	if (!value)
		return -EINVAL;

	switch (sensor) {
	case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
1680 1681 1682
		ret = navi10_get_smu_metrics_data(smu,
						  METRICS_TEMPERATURE_HOTSPOT,
						  value);
1683 1684
		break;
	case AMDGPU_PP_SENSOR_EDGE_TEMP:
1685 1686 1687
		ret = navi10_get_smu_metrics_data(smu,
						  METRICS_TEMPERATURE_EDGE,
						  value);
1688 1689
		break;
	case AMDGPU_PP_SENSOR_MEM_TEMP:
1690 1691 1692
		ret = navi10_get_smu_metrics_data(smu,
						  METRICS_TEMPERATURE_MEM,
						  value);
1693 1694
		break;
	default:
1695
		dev_err(smu->adev->dev, "Invalid sensor for retrieving temp\n");
1696 1697 1698
		return -EINVAL;
	}

1699
	return ret;
1700 1701
}

1702 1703 1704 1705 1706 1707 1708 1709
static int navi10_read_sensor(struct smu_context *smu,
				 enum amd_pp_sensors sensor,
				 void *data, uint32_t *size)
{
	int ret = 0;
	struct smu_table_context *table_context = &smu->smu_table;
	PPTable_t *pptable = table_context->driver_pptable;

1710 1711 1712
	if(!data || !size)
		return -EINVAL;

1713
	mutex_lock(&smu->sensor_lock);
1714 1715 1716 1717 1718
	switch (sensor) {
	case AMDGPU_PP_SENSOR_MAX_FAN_RPM:
		*(uint32_t *)data = pptable->FanMaximumRpm;
		*size = 4;
		break;
1719
	case AMDGPU_PP_SENSOR_MEM_LOAD:
1720
	case AMDGPU_PP_SENSOR_GPU_LOAD:
1721
		ret = navi10_get_current_activity_percent(smu, sensor, (uint32_t *)data);
1722 1723
		*size = 4;
		break;
1724 1725 1726 1727
	case AMDGPU_PP_SENSOR_GPU_POWER:
		ret = navi10_get_gpu_power(smu, (uint32_t *)data);
		*size = 4;
		break;
1728 1729 1730 1731 1732 1733
	case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
	case AMDGPU_PP_SENSOR_EDGE_TEMP:
	case AMDGPU_PP_SENSOR_MEM_TEMP:
		ret = navi10_thermal_get_temperature(smu, sensor, (uint32_t *)data);
		*size = 4;
		break;
1734 1735 1736 1737 1738 1739 1740 1741 1742 1743
	case AMDGPU_PP_SENSOR_GFX_MCLK:
		ret = navi10_get_current_clk_freq_by_table(smu, SMU_UCLK, (uint32_t *)data);
		*(uint32_t *)data *= 100;
		*size = 4;
		break;
	case AMDGPU_PP_SENSOR_GFX_SCLK:
		ret = navi10_get_current_clk_freq_by_table(smu, SMU_GFXCLK, (uint32_t *)data);
		*(uint32_t *)data *= 100;
		*size = 4;
		break;
1744 1745 1746 1747
	case AMDGPU_PP_SENSOR_VDDGFX:
		ret = smu_v11_0_get_gfx_vdd(smu, (uint32_t *)data);
		*size = 4;
		break;
1748
	default:
1749 1750
		ret = -EOPNOTSUPP;
		break;
1751
	}
1752
	mutex_unlock(&smu->sensor_lock);
1753 1754 1755 1756

	return ret;
}

1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785
static int navi10_get_uclk_dpm_states(struct smu_context *smu, uint32_t *clocks_in_khz, uint32_t *num_states)
{
	uint32_t num_discrete_levels = 0;
	uint16_t *dpm_levels = NULL;
	uint16_t i = 0;
	struct smu_table_context *table_context = &smu->smu_table;
	PPTable_t *driver_ppt = NULL;

	if (!clocks_in_khz || !num_states || !table_context->driver_pptable)
		return -EINVAL;

	driver_ppt = table_context->driver_pptable;
	num_discrete_levels = driver_ppt->DpmDescriptor[PPCLK_UCLK].NumDiscreteLevels;
	dpm_levels = driver_ppt->FreqTableUclk;

	if (num_discrete_levels == 0 || dpm_levels == NULL)
		return -EINVAL;

	*num_states = num_discrete_levels;
	for (i = 0; i < num_discrete_levels; i++) {
		/* convert to khz */
		*clocks_in_khz = (*dpm_levels) * 1000;
		clocks_in_khz++;
		dpm_levels++;
	}

	return 0;
}

1786 1787 1788
static int navi10_get_thermal_temperature_range(struct smu_context *smu,
						struct smu_temperature_range *range)
{
1789 1790 1791
	struct smu_table_context *table_context = &smu->smu_table;
	struct smu_11_0_powerplay_table *powerplay_table =
				table_context->power_play_table;
1792
	PPTable_t *pptable = smu->smu_table.driver_pptable;
1793

1794
	if (!range)
1795 1796
		return -EINVAL;

1797 1798
	memcpy(range, &smu11_thermal_policy[0], sizeof(struct smu_temperature_range));

1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809
	range->max = pptable->TedgeLimit *
		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
	range->edge_emergency_max = (pptable->TedgeLimit + CTF_OFFSET_EDGE) *
		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
	range->hotspot_crit_max = pptable->ThotspotLimit *
		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
	range->hotspot_emergency_max = (pptable->ThotspotLimit + CTF_OFFSET_HOTSPOT) *
		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
	range->mem_crit_max = pptable->TmemLimit *
		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
	range->mem_emergency_max = (pptable->TmemLimit + CTF_OFFSET_MEM)*
1810
		SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
1811
	range->software_shutdown_temp = powerplay_table->software_shutdown_temp;
1812 1813 1814 1815

	return 0;
}

1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829
static int navi10_display_disable_memory_clock_switch(struct smu_context *smu,
						bool disable_memory_clock_switch)
{
	int ret = 0;
	struct smu_11_0_max_sustainable_clocks *max_sustainable_clocks =
		(struct smu_11_0_max_sustainable_clocks *)
			smu->smu_table.max_sustainable_clocks;
	uint32_t min_memory_clock = smu->hard_min_uclk_req_from_dal;
	uint32_t max_memory_clock = max_sustainable_clocks->uclock;

	if(smu->disable_uclk_switch == disable_memory_clock_switch)
		return 0;

	if(disable_memory_clock_switch)
1830
		ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, max_memory_clock, 0);
1831
	else
1832
		ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, min_memory_clock, 0);
1833 1834 1835 1836 1837 1838 1839

	if(!ret)
		smu->disable_uclk_switch = disable_memory_clock_switch;

	return ret;
}

1840
static int navi10_get_power_limit(struct smu_context *smu)
1841
{
1842 1843
	struct smu_11_0_powerplay_table *powerplay_table =
		(struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table;
1844
	struct smu_11_0_overdrive_table *od_settings = smu->od_settings;
1845
	PPTable_t *pptable = smu->smu_table.driver_pptable;
1846 1847 1848 1849 1850 1851 1852
	uint32_t power_limit, od_percent;

	if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
		/* the last hope to figure out the ppt limit */
		if (!pptable) {
			dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!");
			return -EINVAL;
1853
		}
1854 1855 1856 1857
		power_limit =
			pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
	}
	smu->current_power_limit = power_limit;
1858

1859 1860
	if (smu->od_enabled &&
	    navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) {
1861 1862 1863 1864 1865 1866
		od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]);

		dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_percent, power_limit);

		power_limit *= (100 + od_percent);
		power_limit /= 100;
1867
	}
1868
	smu->max_power_limit = power_limit;
1869 1870 1871 1872

	return 0;
}

1873 1874 1875 1876
static int navi10_update_pcie_parameters(struct smu_context *smu,
				     uint32_t pcie_gen_cap,
				     uint32_t pcie_width_cap)
{
1877
	struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
1878 1879
	PPTable_t *pptable = smu->smu_table.driver_pptable;
	uint32_t smu_pcie_arg;
1880
	int ret, i;
1881

1882 1883 1884 1885 1886
	/* lclk dpm table setup */
	for (i = 0; i < MAX_PCIE_CONF; i++) {
		dpm_context->dpm_tables.pcie_table.pcie_gen[i] = pptable->PcieGenSpeed[i];
		dpm_context->dpm_tables.pcie_table.pcie_lane[i] = pptable->PcieLaneCount[i];
	}
1887

1888 1889 1890 1891 1892
	for (i = 0; i < NUM_LINK_LEVELS; i++) {
		smu_pcie_arg = (i << 16) |
			((pptable->PcieGenSpeed[i] <= pcie_gen_cap) ? (pptable->PcieGenSpeed[i] << 8) :
				(pcie_gen_cap << 8)) | ((pptable->PcieLaneCount[i] <= pcie_width_cap) ?
					pptable->PcieLaneCount[i] : pcie_width_cap);
1893
		ret = smu_cmn_send_smc_msg_with_param(smu,
1894
					  SMU_MSG_OverridePcieParameters,
1895 1896
					  smu_pcie_arg,
					  NULL);
1897 1898 1899 1900 1901 1902 1903 1904

		if (ret)
			return ret;

		if (pptable->PcieGenSpeed[i] > pcie_gen_cap)
			dpm_context->dpm_tables.pcie_table.pcie_gen[i] = pcie_gen_cap;
		if (pptable->PcieLaneCount[i] > pcie_width_cap)
			dpm_context->dpm_tables.pcie_table.pcie_lane[i] = pcie_width_cap;
1905
	}
1906 1907

	return 0;
1908 1909
}

1910 1911 1912 1913 1914 1915 1916 1917 1918
static inline void navi10_dump_od_table(struct smu_context *smu,
					OverDriveTable_t *od_table)
{
	dev_dbg(smu->adev->dev, "OD: Gfxclk: (%d, %d)\n", od_table->GfxclkFmin, od_table->GfxclkFmax);
	dev_dbg(smu->adev->dev, "OD: Gfx1: (%d, %d)\n", od_table->GfxclkFreq1, od_table->GfxclkVolt1);
	dev_dbg(smu->adev->dev, "OD: Gfx2: (%d, %d)\n", od_table->GfxclkFreq2, od_table->GfxclkVolt2);
	dev_dbg(smu->adev->dev, "OD: Gfx3: (%d, %d)\n", od_table->GfxclkFreq3, od_table->GfxclkVolt3);
	dev_dbg(smu->adev->dev, "OD: UclkFmax: %d\n", od_table->UclkFmax);
	dev_dbg(smu->adev->dev, "OD: OverDrivePct: %d\n", od_table->OverDrivePct);
1919 1920
}

1921 1922 1923 1924
static int navi10_od_setting_check_range(struct smu_context *smu,
					 struct smu_11_0_overdrive_table *od_table,
					 enum SMU_11_0_ODSETTING_ID setting,
					 uint32_t value)
1925 1926
{
	if (value < od_table->min[setting]) {
1927
		dev_warn(smu->adev->dev, "OD setting (%d, %d) is less than the minimum allowed (%d)\n", setting, value, od_table->min[setting]);
1928 1929 1930
		return -EINVAL;
	}
	if (value > od_table->max[setting]) {
1931
		dev_warn(smu->adev->dev, "OD setting (%d, %d) is greater than the maximum allowed (%d)\n", setting, value, od_table->max[setting]);
1932 1933 1934 1935 1936
		return -EINVAL;
	}
	return 0;
}

1937 1938 1939 1940 1941 1942 1943 1944
static int navi10_overdrive_get_gfx_clk_base_voltage(struct smu_context *smu,
						     uint16_t *voltage,
						     uint32_t freq)
{
	uint32_t param = (freq & 0xFFFF) | (PPCLK_GFXCLK << 16);
	uint32_t value = 0;
	int ret;

1945
	ret = smu_cmn_send_smc_msg_with_param(smu,
1946
					  SMU_MSG_GetVoltageByDpm,
1947 1948
					  param,
					  &value);
1949
	if (ret) {
1950
		dev_err(smu->adev->dev, "[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!");
1951 1952 1953 1954 1955 1956 1957 1958
		return ret;
	}

	*voltage = (uint16_t)value;

	return 0;
}

1959 1960 1961 1962 1963
static bool navi10_is_baco_supported(struct smu_context *smu)
{
	struct amdgpu_device *adev = smu->adev;
	uint32_t val;

W
Wenhui Sheng 已提交
1964
	if (amdgpu_sriov_vf(adev) || (!smu_v11_0_baco_is_support(smu)))
1965 1966 1967 1968 1969 1970
		return false;

	val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0);
	return (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) ? true : false;
}

1971 1972 1973 1974 1975 1976
static int navi10_set_default_od_settings(struct smu_context *smu)
{
	OverDriveTable_t *od_table =
		(OverDriveTable_t *)smu->smu_table.overdrive_table;
	OverDriveTable_t *boot_od_table =
		(OverDriveTable_t *)smu->smu_table.boot_overdrive_table;
1977 1978
	int ret = 0;

1979
	ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, false);
1980
	if (ret) {
1981
		dev_err(smu->adev->dev, "Failed to get overdrive table!\n");
1982
		return ret;
1983
	}
1984

1985 1986 1987 1988 1989 1990 1991
	if (!od_table->GfxclkVolt1) {
		ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
								&od_table->GfxclkVolt1,
								od_table->GfxclkFreq1);
		if (ret)
			return ret;
	}
1992

1993 1994 1995 1996 1997 1998
	if (!od_table->GfxclkVolt2) {
		ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
								&od_table->GfxclkVolt2,
								od_table->GfxclkFreq2);
		if (ret)
			return ret;
1999 2000
	}

2001 2002 2003 2004 2005 2006
	if (!od_table->GfxclkVolt3) {
		ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
								&od_table->GfxclkVolt3,
								od_table->GfxclkFreq3);
		if (ret)
			return ret;
2007
	}
2008

2009 2010
	memcpy(boot_od_table, od_table, sizeof(OverDriveTable_t));

2011
	navi10_dump_od_table(smu, od_table);
2012 2013

	return 0;
2014 2015
}

2016 2017 2018 2019 2020 2021
static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, long input[], uint32_t size) {
	int i;
	int ret = 0;
	struct smu_table_context *table_context = &smu->smu_table;
	OverDriveTable_t *od_table;
	struct smu_11_0_overdrive_table *od_settings;
2022 2023
	enum SMU_11_0_ODSETTING_ID freq_setting, voltage_setting;
	uint16_t *freq_ptr, *voltage_ptr;
2024 2025 2026
	od_table = (OverDriveTable_t *)table_context->overdrive_table;

	if (!smu->od_enabled) {
2027
		dev_warn(smu->adev->dev, "OverDrive is not enabled!\n");
2028 2029 2030 2031
		return -EINVAL;
	}

	if (!smu->od_settings) {
2032
		dev_err(smu->adev->dev, "OD board limits are not set!\n");
2033 2034 2035 2036 2037 2038 2039
		return -ENOENT;
	}

	od_settings = smu->od_settings;

	switch (type) {
	case PP_OD_EDIT_SCLK_VDDC_TABLE:
2040
		if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) {
2041
			dev_warn(smu->adev->dev, "GFXCLK_LIMITS not supported!\n");
2042 2043 2044
			return -ENOTSUPP;
		}
		if (!table_context->overdrive_table) {
2045
			dev_err(smu->adev->dev, "Overdrive is not initialized\n");
2046 2047 2048 2049
			return -EINVAL;
		}
		for (i = 0; i < size; i += 2) {
			if (i + 2 > size) {
2050
				dev_info(smu->adev->dev, "invalid number of input parameters %d\n", size);
2051 2052 2053 2054 2055 2056 2057
				return -EINVAL;
			}
			switch (input[i]) {
			case 0:
				freq_setting = SMU_11_0_ODSETTING_GFXCLKFMIN;
				freq_ptr = &od_table->GfxclkFmin;
				if (input[i + 1] > od_table->GfxclkFmax) {
2058
					dev_info(smu->adev->dev, "GfxclkFmin (%ld) must be <= GfxclkFmax (%u)!\n",
2059 2060 2061 2062 2063 2064 2065 2066 2067
						input[i + 1],
						od_table->GfxclkFmin);
					return -EINVAL;
				}
				break;
			case 1:
				freq_setting = SMU_11_0_ODSETTING_GFXCLKFMAX;
				freq_ptr = &od_table->GfxclkFmax;
				if (input[i + 1] < od_table->GfxclkFmin) {
2068
					dev_info(smu->adev->dev, "GfxclkFmax (%ld) must be >= GfxclkFmin (%u)!\n",
2069 2070 2071 2072 2073 2074
						input[i + 1],
						od_table->GfxclkFmax);
					return -EINVAL;
				}
				break;
			default:
2075 2076
				dev_info(smu->adev->dev, "Invalid SCLK_VDDC_TABLE index: %ld\n", input[i]);
				dev_info(smu->adev->dev, "Supported indices: [0:min,1:max]\n");
2077 2078
				return -EINVAL;
			}
2079
			ret = navi10_od_setting_check_range(smu, od_settings, freq_setting, input[i + 1]);
2080 2081 2082 2083 2084 2085
			if (ret)
				return ret;
			*freq_ptr = input[i + 1];
		}
		break;
	case PP_OD_EDIT_MCLK_VDDC_TABLE:
2086
		if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) {
2087
			dev_warn(smu->adev->dev, "UCLK_MAX not supported!\n");
2088 2089 2090
			return -ENOTSUPP;
		}
		if (size < 2) {
2091
			dev_info(smu->adev->dev, "invalid number of parameters: %d\n", size);
2092 2093 2094
			return -EINVAL;
		}
		if (input[0] != 1) {
2095 2096
			dev_info(smu->adev->dev, "Invalid MCLK_VDDC_TABLE index: %ld\n", input[0]);
			dev_info(smu->adev->dev, "Supported indices: [1:max]\n");
2097 2098
			return -EINVAL;
		}
2099
		ret = navi10_od_setting_check_range(smu, od_settings, SMU_11_0_ODSETTING_UCLKFMAX, input[1]);
2100 2101 2102 2103
		if (ret)
			return ret;
		od_table->UclkFmax = input[1];
		break;
2104 2105
	case PP_OD_RESTORE_DEFAULT_TABLE:
		if (!(table_context->overdrive_table && table_context->boot_overdrive_table)) {
2106
			dev_err(smu->adev->dev, "Overdrive table was not initialized!\n");
2107 2108 2109 2110
			return -EINVAL;
		}
		memcpy(table_context->overdrive_table, table_context->boot_overdrive_table, sizeof(OverDriveTable_t));
		break;
2111
	case PP_OD_COMMIT_DPM_TABLE:
2112
		navi10_dump_od_table(smu, od_table);
2113
		ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, true);
2114
		if (ret) {
2115
			dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
2116 2117 2118 2119
			return ret;
		}
		break;
	case PP_OD_EDIT_VDDC_CURVE:
2120
		if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) {
2121
			dev_warn(smu->adev->dev, "GFXCLK_CURVE not supported!\n");
2122 2123 2124
			return -ENOTSUPP;
		}
		if (size < 3) {
2125
			dev_info(smu->adev->dev, "invalid number of parameters: %d\n", size);
2126 2127 2128
			return -EINVAL;
		}
		if (!od_table) {
2129
			dev_info(smu->adev->dev, "Overdrive is not initialized\n");
2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152
			return -EINVAL;
		}

		switch (input[0]) {
		case 0:
			freq_setting = SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P1;
			voltage_setting = SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P1;
			freq_ptr = &od_table->GfxclkFreq1;
			voltage_ptr = &od_table->GfxclkVolt1;
			break;
		case 1:
			freq_setting = SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P2;
			voltage_setting = SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P2;
			freq_ptr = &od_table->GfxclkFreq2;
			voltage_ptr = &od_table->GfxclkVolt2;
			break;
		case 2:
			freq_setting = SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P3;
			voltage_setting = SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P3;
			freq_ptr = &od_table->GfxclkFreq3;
			voltage_ptr = &od_table->GfxclkVolt3;
			break;
		default:
2153 2154
			dev_info(smu->adev->dev, "Invalid VDDC_CURVE index: %ld\n", input[0]);
			dev_info(smu->adev->dev, "Supported indices: [0, 1, 2]\n");
2155 2156
			return -EINVAL;
		}
2157
		ret = navi10_od_setting_check_range(smu, od_settings, freq_setting, input[1]);
2158 2159 2160 2161
		if (ret)
			return ret;
		// Allow setting zero to disable the OverDrive VDDC curve
		if (input[2] != 0) {
2162
			ret = navi10_od_setting_check_range(smu, od_settings, voltage_setting, input[2]);
2163 2164 2165 2166
			if (ret)
				return ret;
			*freq_ptr = input[1];
			*voltage_ptr = ((uint16_t)input[2]) * NAVI10_VOLTAGE_SCALE;
2167
			dev_dbg(smu->adev->dev, "OD: set curve %ld: (%d, %d)\n", input[0], *freq_ptr, *voltage_ptr);
2168 2169 2170 2171 2172 2173
		} else {
			// If setting 0, disable all voltage curve settings
			od_table->GfxclkVolt1 = 0;
			od_table->GfxclkVolt2 = 0;
			od_table->GfxclkVolt3 = 0;
		}
2174
		navi10_dump_od_table(smu, od_table);
2175
		break;
2176 2177 2178 2179 2180
	default:
		return -ENOSYS;
	}
	return ret;
}
2181

2182 2183 2184 2185
static int navi10_run_btc(struct smu_context *smu)
{
	int ret = 0;

2186
	ret = smu_cmn_send_smc_msg(smu, SMU_MSG_RunBtc, NULL);
2187
	if (ret)
2188
		dev_err(smu->adev->dev, "RunBtc failed!\n");
2189 2190 2191 2192

	return ret;
}

2193 2194 2195 2196 2197
static int navi10_dummy_pstate_control(struct smu_context *smu, bool enable)
{
	int result = 0;

	if (!enable)
2198
		result = smu_cmn_send_smc_msg(smu, SMU_MSG_DAL_DISABLE_DUMMY_PSTATE_CHANGE, NULL);
2199
	else
2200
		result = smu_cmn_send_smc_msg(smu, SMU_MSG_DAL_ENABLE_DUMMY_PSTATE_CHANGE, NULL);
2201 2202 2203 2204

	return result;
}

2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219
static inline bool navi10_need_umc_cdr_12gbps_workaround(struct amdgpu_device *adev)
{
	if (adev->asic_type != CHIP_NAVI10)
		return false;

	if (adev->pdev->device == 0x731f &&
	    (adev->pdev->revision == 0xc2 ||
	     adev->pdev->revision == 0xc3 ||
	     adev->pdev->revision == 0xca ||
	     adev->pdev->revision == 0xcb))
		return true;
	else
		return false;
}

2220 2221 2222 2223 2224 2225
static int navi10_disable_umc_cdr_12gbps_workaround(struct smu_context *smu)
{
	uint32_t uclk_count, uclk_min, uclk_max;
	uint32_t smu_version;
	int ret = 0;

2226 2227 2228
	if (!navi10_need_umc_cdr_12gbps_workaround(smu->adev))
		return 0;

2229
	ret = smu_cmn_get_smc_version(smu, NULL, &smu_version);
2230 2231 2232 2233 2234 2235 2236
	if (ret)
		return ret;

	/* This workaround is available only for 42.50 or later SMC firmwares */
	if (smu_version < 0x2A3200)
		return 0;

2237
	ret = smu_v11_0_get_dpm_level_count(smu, SMU_UCLK, &uclk_count);
2238 2239 2240
	if (ret)
		return ret;

2241
	ret = smu_v11_0_get_dpm_freq_by_index(smu, SMU_UCLK, (uint16_t)0, &uclk_min);
2242 2243 2244
	if (ret)
		return ret;

2245
	ret = smu_v11_0_get_dpm_freq_by_index(smu, SMU_UCLK, (uint16_t)(uclk_count - 1), &uclk_max);
2246 2247 2248 2249
	if (ret)
		return ret;

	/* Force UCLK out of the highest DPM */
2250
	ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, 0, uclk_min);
2251 2252 2253 2254
	if (ret)
		return ret;

	/* Revert the UCLK Hardmax */
2255
	ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, 0, uclk_max);
2256 2257 2258 2259 2260 2261 2262 2263 2264 2265
	if (ret)
		return ret;

	/*
	 * In this case, SMU already disabled dummy pstate during enablement
	 * of UCLK DPM, we have to re-enabled it.
	 * */
	return navi10_dummy_pstate_control(smu, true);
}

2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483
static void navi10_fill_i2c_req(SwI2cRequest_t  *req, bool write,
				  uint8_t address, uint32_t numbytes,
				  uint8_t *data)
{
	int i;

	BUG_ON(numbytes > MAX_SW_I2C_COMMANDS);

	req->I2CcontrollerPort = 0;
	req->I2CSpeed = 2;
	req->SlaveAddress = address;
	req->NumCmds = numbytes;

	for (i = 0; i < numbytes; i++) {
		SwI2cCmd_t *cmd =  &req->SwI2cCmds[i];

		/* First 2 bytes are always write for lower 2b EEPROM address */
		if (i < 2)
			cmd->Cmd = 1;
		else
			cmd->Cmd = write;


		/* Add RESTART for read  after address filled */
		cmd->CmdConfig |= (i == 2 && !write) ? CMDCONFIG_RESTART_MASK : 0;

		/* Add STOP in the end */
		cmd->CmdConfig |= (i == (numbytes - 1)) ? CMDCONFIG_STOP_MASK : 0;

		/* Fill with data regardless if read or write to simplify code */
		cmd->RegisterAddr = data[i];
	}
}

static int navi10_i2c_read_data(struct i2c_adapter *control,
					       uint8_t address,
					       uint8_t *data,
					       uint32_t numbytes)
{
	uint32_t  i, ret = 0;
	SwI2cRequest_t req;
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct smu_table_context *smu_table = &adev->smu.smu_table;
	struct smu_table *table = &smu_table->driver_table;

	memset(&req, 0, sizeof(req));
	navi10_fill_i2c_req(&req, false, address, numbytes, data);

	mutex_lock(&adev->smu.mutex);
	/* Now read data starting with that address */
	ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req,
				   true);
	mutex_unlock(&adev->smu.mutex);

	if (!ret) {
		SwI2cRequest_t *res = (SwI2cRequest_t *)table->cpu_addr;

		/* Assume SMU  fills res.SwI2cCmds[i].Data with read bytes */
		for (i = 0; i < numbytes; i++)
			data[i] = res->SwI2cCmds[i].Data;

		dev_dbg(adev->dev, "navi10_i2c_read_data, address = %x, bytes = %d, data :",
				  (uint16_t)address, numbytes);

		print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE,
			       8, 1, data, numbytes, false);
	} else
		dev_err(adev->dev, "navi10_i2c_read_data - error occurred :%x", ret);

	return ret;
}

static int navi10_i2c_write_data(struct i2c_adapter *control,
						uint8_t address,
						uint8_t *data,
						uint32_t numbytes)
{
	uint32_t ret;
	SwI2cRequest_t req;
	struct amdgpu_device *adev = to_amdgpu_device(control);

	memset(&req, 0, sizeof(req));
	navi10_fill_i2c_req(&req, true, address, numbytes, data);

	mutex_lock(&adev->smu.mutex);
	ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true);
	mutex_unlock(&adev->smu.mutex);

	if (!ret) {
		dev_dbg(adev->dev, "navi10_i2c_write(), address = %x, bytes = %d , data: ",
					 (uint16_t)address, numbytes);

		print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE,
			       8, 1, data, numbytes, false);
		/*
		 * According to EEPROM spec there is a MAX of 10 ms required for
		 * EEPROM to flush internal RX buffer after STOP was issued at the
		 * end of write transaction. During this time the EEPROM will not be
		 * responsive to any more commands - so wait a bit more.
		 */
		msleep(10);

	} else
		dev_err(adev->dev, "navi10_i2c_write- error occurred :%x", ret);

	return ret;
}

static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap,
			      struct i2c_msg *msgs, int num)
{
	uint32_t  i, j, ret, data_size, data_chunk_size, next_eeprom_addr = 0;
	uint8_t *data_ptr, data_chunk[MAX_SW_I2C_COMMANDS] = { 0 };

	for (i = 0; i < num; i++) {
		/*
		 * SMU interface allows at most MAX_SW_I2C_COMMANDS bytes of data at
		 * once and hence the data needs to be spliced into chunks and sent each
		 * chunk separately
		 */
		data_size = msgs[i].len - 2;
		data_chunk_size = MAX_SW_I2C_COMMANDS - 2;
		next_eeprom_addr = (msgs[i].buf[0] << 8 & 0xff00) | (msgs[i].buf[1] & 0xff);
		data_ptr = msgs[i].buf + 2;

		for (j = 0; j < data_size / data_chunk_size; j++) {
			/* Insert the EEPROM dest addess, bits 0-15 */
			data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff);
			data_chunk[1] = (next_eeprom_addr & 0xff);

			if (msgs[i].flags & I2C_M_RD) {
				ret = navi10_i2c_read_data(i2c_adap,
							     (uint8_t)msgs[i].addr,
							     data_chunk, MAX_SW_I2C_COMMANDS);

				memcpy(data_ptr, data_chunk + 2, data_chunk_size);
			} else {

				memcpy(data_chunk + 2, data_ptr, data_chunk_size);

				ret = navi10_i2c_write_data(i2c_adap,
							      (uint8_t)msgs[i].addr,
							      data_chunk, MAX_SW_I2C_COMMANDS);
			}

			if (ret) {
				num = -EIO;
				goto fail;
			}

			next_eeprom_addr += data_chunk_size;
			data_ptr += data_chunk_size;
		}

		if (data_size % data_chunk_size) {
			data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff);
			data_chunk[1] = (next_eeprom_addr & 0xff);

			if (msgs[i].flags & I2C_M_RD) {
				ret = navi10_i2c_read_data(i2c_adap,
							     (uint8_t)msgs[i].addr,
							     data_chunk, (data_size % data_chunk_size) + 2);

				memcpy(data_ptr, data_chunk + 2, data_size % data_chunk_size);
			} else {
				memcpy(data_chunk + 2, data_ptr, data_size % data_chunk_size);

				ret = navi10_i2c_write_data(i2c_adap,
							      (uint8_t)msgs[i].addr,
							      data_chunk, (data_size % data_chunk_size) + 2);
			}

			if (ret) {
				num = -EIO;
				goto fail;
			}
		}
	}

fail:
	return num;
}

static u32 navi10_i2c_func(struct i2c_adapter *adap)
{
	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}


static const struct i2c_algorithm navi10_i2c_algo = {
	.master_xfer = navi10_i2c_xfer,
	.functionality = navi10_i2c_func,
};

static int navi10_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	int res;

	control->owner = THIS_MODULE;
	control->class = I2C_CLASS_SPD;
	control->dev.parent = &adev->pdev->dev;
	control->algo = &navi10_i2c_algo;
	snprintf(control->name, sizeof(control->name), "AMDGPU SMU");

	res = i2c_add_adapter(control);
	if (res)
		DRM_ERROR("Failed to register hw i2c, err: %d\n", res);

	return res;
}

static void navi10_i2c_control_fini(struct smu_context *smu, struct i2c_adapter *control)
{
	i2c_del_adapter(control);
}


2484
static const struct pptable_funcs navi10_ppt_funcs = {
2485
	.get_allowed_feature_mask = navi10_get_allowed_feature_mask,
2486
	.set_default_dpm_table = navi10_set_default_dpm_table,
2487
	.dpm_set_vcn_enable = navi10_dpm_set_vcn_enable,
2488
	.dpm_set_jpeg_enable = navi10_dpm_set_jpeg_enable,
2489 2490
	.i2c_init = navi10_i2c_control_init,
	.i2c_fini = navi10_i2c_control_fini,
2491
	.print_clk_levels = navi10_print_clk_levels,
2492
	.force_clk_levels = navi10_force_clk_levels,
2493
	.populate_umd_state_clk = navi10_populate_umd_state_clk,
2494
	.get_clock_by_type_with_latency = navi10_get_clock_by_type_with_latency,
2495
	.pre_display_config_changed = navi10_pre_display_config_changed,
2496
	.display_config_changed = navi10_display_config_changed,
A
Alex Deucher 已提交
2497
	.notify_smc_display_config = navi10_notify_smc_display_config,
2498
	.is_dpm_running = navi10_is_dpm_running,
2499
	.get_fan_speed_percent = navi10_get_fan_speed_percent,
2500
	.get_fan_speed_rpm = navi10_get_fan_speed_rpm,
2501 2502
	.get_power_profile_mode = navi10_get_power_profile_mode,
	.set_power_profile_mode = navi10_set_power_profile_mode,
2503
	.set_watermarks_table = navi10_set_watermarks_table,
2504
	.read_sensor = navi10_read_sensor,
2505
	.get_uclk_dpm_states = navi10_get_uclk_dpm_states,
2506
	.set_performance_level = smu_v11_0_set_performance_level,
2507
	.get_thermal_temperature_range = navi10_get_thermal_temperature_range,
2508
	.display_disable_memory_clock_switch = navi10_display_disable_memory_clock_switch,
2509
	.get_power_limit = navi10_get_power_limit,
2510
	.update_pcie_parameters = navi10_update_pcie_parameters,
2511 2512
	.init_microcode = smu_v11_0_init_microcode,
	.load_microcode = smu_v11_0_load_microcode,
2513
	.fini_microcode = smu_v11_0_fini_microcode,
2514
	.init_smc_tables = navi10_init_smc_tables,
2515 2516 2517 2518
	.fini_smc_tables = smu_v11_0_fini_smc_tables,
	.init_power = smu_v11_0_init_power,
	.fini_power = smu_v11_0_fini_power,
	.check_fw_status = smu_v11_0_check_fw_status,
2519
	.setup_pptable = navi10_setup_pptable,
2520 2521
	.get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values,
	.check_fw_version = smu_v11_0_check_fw_version,
2522
	.write_pptable = smu_cmn_write_pptable,
2523
	.set_driver_table_location = smu_v11_0_set_driver_table_location,
2524 2525 2526
	.set_tool_table_location = smu_v11_0_set_tool_table_location,
	.notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
	.system_features_control = smu_v11_0_system_features_control,
2527 2528
	.send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
	.send_smc_msg = smu_cmn_send_smc_msg,
2529 2530
	.init_display_count = smu_v11_0_init_display_count,
	.set_allowed_mask = smu_v11_0_set_allowed_mask,
2531
	.get_enabled_mask = smu_cmn_get_enabled_mask,
2532
	.feature_is_enabled = smu_cmn_feature_is_enabled,
2533
	.disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception,
2534 2535 2536
	.notify_display_change = smu_v11_0_notify_display_change,
	.set_power_limit = smu_v11_0_set_power_limit,
	.init_max_sustainable_clocks = smu_v11_0_init_max_sustainable_clocks,
2537 2538
	.enable_thermal_alert = smu_v11_0_enable_thermal_alert,
	.disable_thermal_alert = smu_v11_0_disable_thermal_alert,
2539
	.set_min_dcef_deep_sleep = smu_v11_0_set_min_deep_sleep_dcefclk,
2540 2541 2542 2543 2544 2545 2546 2547 2548 2549
	.display_clock_voltage_request = smu_v11_0_display_clock_voltage_request,
	.get_fan_control_mode = smu_v11_0_get_fan_control_mode,
	.set_fan_control_mode = smu_v11_0_set_fan_control_mode,
	.set_fan_speed_percent = smu_v11_0_set_fan_speed_percent,
	.set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm,
	.set_xgmi_pstate = smu_v11_0_set_xgmi_pstate,
	.gfx_off_control = smu_v11_0_gfx_off_control,
	.register_irq_handler = smu_v11_0_register_irq_handler,
	.set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme,
	.get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc,
2550
	.baco_is_support= navi10_is_baco_supported,
2551 2552
	.baco_get_state = smu_v11_0_baco_get_state,
	.baco_set_state = smu_v11_0_baco_set_state,
2553 2554
	.baco_enter = smu_v11_0_baco_enter,
	.baco_exit = smu_v11_0_baco_exit,
2555 2556
	.get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq,
	.set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range,
2557 2558
	.set_default_od_settings = navi10_set_default_od_settings,
	.od_edit_dpm_table = navi10_od_edit_dpm_table,
2559
	.run_btc = navi10_run_btc,
2560
	.disable_umc_cdr_12gbps_workaround = navi10_disable_umc_cdr_12gbps_workaround,
2561
	.set_power_source = smu_v11_0_set_power_source,
2562 2563
	.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
	.set_pp_feature_mask = smu_cmn_set_pp_feature_mask,
2564 2565 2566 2567 2568
};

void navi10_set_ppt_funcs(struct smu_context *smu)
{
	smu->ppt_funcs = &navi10_ppt_funcs;
2569 2570 2571 2572 2573 2574
	smu->message_map = navi10_message_map;
	smu->clock_map = navi10_clk_map;
	smu->feature_map = navi10_feature_mask_map;
	smu->table_map = navi10_table_map;
	smu->pwr_src_map = navi10_pwr_src_map;
	smu->workload_map = navi10_workload_map;
2575
}