smu10_hwmgr.c 31.6 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 24 25 26 27 28 29 30 31 32 33 34
/*
 * Copyright 2015 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.
 *
 */
#include "pp_debug.h"
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include "atom-types.h"
#include "atombios.h"
#include "processpptables.h"
#include "cgs_common.h"
#include "smumgr.h"
#include "hwmgr.h"
#include "hardwaremanager.h"
#include "rv_ppsmc.h"
R
Rex Zhu 已提交
35
#include "smu10_hwmgr.h"
36
#include "power_state.h"
37
#include "soc15_common.h"
38

R
Rex Zhu 已提交
39 40
#define SMU10_MAX_DEEPSLEEP_DIVIDER_ID     5
#define SMU10_MINIMUM_ENGINE_CLOCK         800   /* 8Mhz, the low boundary of engine clock allowed on this chip */
41
#define SCLK_MIN_DIV_INTV_SHIFT         12
R
Rex Zhu 已提交
42
#define SMU10_DISPCLK_BYPASS_THRESHOLD     10000 /* 100Mhz */
43 44
#define SMC_RAM_END                     0x40000

45 46 47 48 49 50 51
#define mmPWR_MISC_CNTL_STATUS					0x0183
#define mmPWR_MISC_CNTL_STATUS_BASE_IDX				0
#define PWR_MISC_CNTL_STATUS__PWR_GFX_RLC_CGPG_EN__SHIFT	0x0
#define PWR_MISC_CNTL_STATUS__PWR_GFXOFF_STATUS__SHIFT		0x1
#define PWR_MISC_CNTL_STATUS__PWR_GFX_RLC_CGPG_EN_MASK		0x00000001L
#define PWR_MISC_CNTL_STATUS__PWR_GFXOFF_STATUS_MASK		0x00000006L

R
Rex Zhu 已提交
52
static const unsigned long SMU10_Magic = (unsigned long) PHM_Rv_Magic;
53 54


R
Rex Zhu 已提交
55
static int smu10_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
56
		struct pp_display_clock_request *clock_req);
57 58


R
Rex Zhu 已提交
59
static struct smu10_power_state *cast_smu10_ps(struct pp_hw_power_state *hw_ps)
60
{
R
Rex Zhu 已提交
61
	if (SMU10_Magic != hw_ps->magic)
62 63
		return NULL;

R
Rex Zhu 已提交
64
	return (struct smu10_power_state *)hw_ps;
65 66
}

R
Rex Zhu 已提交
67
static const struct smu10_power_state *cast_const_smu10_ps(
68 69
				const struct pp_hw_power_state *hw_ps)
{
R
Rex Zhu 已提交
70
	if (SMU10_Magic != hw_ps->magic)
71 72
		return NULL;

R
Rex Zhu 已提交
73
	return (struct smu10_power_state *)hw_ps;
74 75
}

R
Rex Zhu 已提交
76
static int smu10_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
77
{
R
Rex Zhu 已提交
78
	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
79

R
Rex Zhu 已提交
80 81 82 83 84 85 86 87
	smu10_data->dce_slow_sclk_threshold = 30000;
	smu10_data->thermal_auto_throttling_treshold = 0;
	smu10_data->is_nb_dpm_enabled = 1;
	smu10_data->dpm_flags = 1;
	smu10_data->gfx_off_controled_by_driver = false;
	smu10_data->need_min_deep_sleep_dcefclk = true;
	smu10_data->num_active_display = 0;
	smu10_data->deep_sleep_dcefclk = 0;
88 89 90 91 92 93 94 95

	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
					PHM_PlatformCaps_SclkDeepSleep);

	phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
				PHM_PlatformCaps_SclkThrottleLowNotification);

	phm_cap_set(hwmgr->platform_descriptor.platformCaps,
96
				PHM_PlatformCaps_PowerPlaySupport);
97 98 99
	return 0;
}

R
Rex Zhu 已提交
100
static int smu10_construct_max_power_limits_table(struct pp_hwmgr *hwmgr,
101 102 103 104 105
			struct phm_clock_and_voltage_limits *table)
{
	return 0;
}

R
Rex Zhu 已提交
106
static int smu10_init_dynamic_state_adjustment_rule_settings(
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 141 142
							struct pp_hwmgr *hwmgr)
{
	uint32_t table_size =
		sizeof(struct phm_clock_voltage_dependency_table) +
		(7 * sizeof(struct phm_clock_voltage_dependency_record));

	struct phm_clock_voltage_dependency_table *table_clk_vlt =
					kzalloc(table_size, GFP_KERNEL);

	if (NULL == table_clk_vlt) {
		pr_err("Can not allocate memory!\n");
		return -ENOMEM;
	}

	table_clk_vlt->count = 8;
	table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_0;
	table_clk_vlt->entries[0].v = 0;
	table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_1;
	table_clk_vlt->entries[1].v = 1;
	table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_2;
	table_clk_vlt->entries[2].v = 2;
	table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_3;
	table_clk_vlt->entries[3].v = 3;
	table_clk_vlt->entries[4].clk = PP_DAL_POWERLEVEL_4;
	table_clk_vlt->entries[4].v = 4;
	table_clk_vlt->entries[5].clk = PP_DAL_POWERLEVEL_5;
	table_clk_vlt->entries[5].v = 5;
	table_clk_vlt->entries[6].clk = PP_DAL_POWERLEVEL_6;
	table_clk_vlt->entries[6].v = 6;
	table_clk_vlt->entries[7].clk = PP_DAL_POWERLEVEL_7;
	table_clk_vlt->entries[7].v = 7;
	hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;

	return 0;
}

R
Rex Zhu 已提交
143
static int smu10_get_system_info_data(struct pp_hwmgr *hwmgr)
144
{
R
Rex Zhu 已提交
145
	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)hwmgr->backend;
146

R
Rex Zhu 已提交
147 148
	smu10_data->sys_info.htc_hyst_lmt = 5;
	smu10_data->sys_info.htc_tmp_lmt = 203;
149

R
Rex Zhu 已提交
150 151
	if (smu10_data->thermal_auto_throttling_treshold == 0)
		 smu10_data->thermal_auto_throttling_treshold = 203;
152

R
Rex Zhu 已提交
153
	smu10_construct_max_power_limits_table (hwmgr,
154 155
				    &hwmgr->dyn_state.max_clock_voltage_on_ac);

R
Rex Zhu 已提交
156
	smu10_init_dynamic_state_adjustment_rule_settings(hwmgr);
157 158 159 160

	return 0;
}

R
Rex Zhu 已提交
161
static int smu10_construct_boot_state(struct pp_hwmgr *hwmgr)
162 163 164 165
{
	return 0;
}

R
Rex Zhu 已提交
166
static int smu10_set_clock_limit(struct pp_hwmgr *hwmgr, const void *input)
167
{
168 169 170
	struct PP_Clocks clocks = {0};
	struct pp_display_clock_request clock_req;

171
	clocks.dcefClock = hwmgr->display_config->min_dcef_set_clk;
172 173 174
	clock_req.clock_type = amd_pp_dcf_clock;
	clock_req.clock_freq_in_khz = clocks.dcefClock * 10;

R
Rex Zhu 已提交
175
	PP_ASSERT_WITH_CODE(!smu10_display_clock_voltage_request(hwmgr, &clock_req),
176 177
				"Attempt to set DCF Clock Failed!", return -EINVAL);

178 179 180
	return 0;
}

R
Rex Zhu 已提交
181
static int smu10_set_deep_sleep_dcefclk(struct pp_hwmgr *hwmgr, uint32_t clock)
182
{
R
Rex Zhu 已提交
183
	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
184

R
Rex Zhu 已提交
185 186
	if (smu10_data->need_min_deep_sleep_dcefclk && smu10_data->deep_sleep_dcefclk != clock/100) {
		smu10_data->deep_sleep_dcefclk = clock/100;
187
		smum_send_msg_to_smc_with_parameter(hwmgr,
188
					PPSMC_MSG_SetMinDeepSleepDcefclk,
R
Rex Zhu 已提交
189
					smu10_data->deep_sleep_dcefclk);
190 191 192 193
	}
	return 0;
}

R
Rex Zhu 已提交
194
static int smu10_set_active_display_count(struct pp_hwmgr *hwmgr, uint32_t count)
195
{
R
Rex Zhu 已提交
196
	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
197

R
Rex Zhu 已提交
198 199
	if (smu10_data->num_active_display != count) {
		smu10_data->num_active_display = count;
200
		smum_send_msg_to_smc_with_parameter(hwmgr,
201
				PPSMC_MSG_SetDisplayCount,
R
Rex Zhu 已提交
202
				smu10_data->num_active_display);
203
	}
204

205 206 207
	return 0;
}

R
Rex Zhu 已提交
208
static int smu10_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input)
209
{
R
Rex Zhu 已提交
210
	return smu10_set_clock_limit(hwmgr, input);
211
}
212

R
Rex Zhu 已提交
213
static int smu10_init_power_gate_state(struct pp_hwmgr *hwmgr)
214
{
R
Rex Zhu 已提交
215
	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
216
	struct amdgpu_device *adev = hwmgr->adev;
217

R
Rex Zhu 已提交
218 219 220
	smu10_data->vcn_power_gated = true;
	smu10_data->isp_tileA_power_gated = true;
	smu10_data->isp_tileB_power_gated = true;
221

222 223 224 225 226 227
	if (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)
		return smum_send_msg_to_smc_with_parameter(hwmgr,
							   PPSMC_MSG_SetGfxCGPG,
							   true);
	else
		return 0;
228 229 230
}


R
Rex Zhu 已提交
231
static int smu10_setup_asic_task(struct pp_hwmgr *hwmgr)
232
{
R
Rex Zhu 已提交
233
	return smu10_init_power_gate_state(hwmgr);
234
}
235

R
Rex Zhu 已提交
236
static int smu10_reset_cc6_data(struct pp_hwmgr *hwmgr)
237
{
R
Rex Zhu 已提交
238
	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
239

R
Rex Zhu 已提交
240 241 242 243
	smu10_data->separation_time = 0;
	smu10_data->cc6_disable = false;
	smu10_data->pstate_disable = false;
	smu10_data->cc6_setting_changed = false;
244 245 246 247

	return 0;
}

R
Rex Zhu 已提交
248
static int smu10_power_off_asic(struct pp_hwmgr *hwmgr)
249
{
R
Rex Zhu 已提交
250
	return smu10_reset_cc6_data(hwmgr);
251
}
252

253 254 255 256 257 258 259 260 261 262 263 264 265
static bool smu10_is_gfx_on(struct pp_hwmgr *hwmgr)
{
	uint32_t reg;
	struct amdgpu_device *adev = hwmgr->adev;

	reg = RREG32_SOC15(PWR, 0, mmPWR_MISC_CNTL_STATUS);
	if ((reg & PWR_MISC_CNTL_STATUS__PWR_GFXOFF_STATUS_MASK) ==
	    (0x2 << PWR_MISC_CNTL_STATUS__PWR_GFXOFF_STATUS__SHIFT))
		return true;

	return false;
}

R
Rex Zhu 已提交
266
static int smu10_disable_gfx_off(struct pp_hwmgr *hwmgr)
267
{
R
Rex Zhu 已提交
268
	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
269

270
	if (smu10_data->gfx_off_controled_by_driver) {
271
		smum_send_msg_to_smc(hwmgr, PPSMC_MSG_DisableGfxOff);
272

273 274 275 276 277
		/* confirm gfx is back to "on" state */
		while (!smu10_is_gfx_on(hwmgr))
			msleep(1);
	}

278 279 280
	return 0;
}

R
Rex Zhu 已提交
281
static int smu10_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
282
{
R
Rex Zhu 已提交
283
	return smu10_disable_gfx_off(hwmgr);
284
}
285

R
Rex Zhu 已提交
286
static int smu10_enable_gfx_off(struct pp_hwmgr *hwmgr)
287
{
R
Rex Zhu 已提交
288
	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
289

R
Rex Zhu 已提交
290
	if (smu10_data->gfx_off_controled_by_driver)
291
		smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableGfxOff);
292 293 294 295

	return 0;
}

R
Rex Zhu 已提交
296
static int smu10_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
297
{
R
Rex Zhu 已提交
298
	return smu10_enable_gfx_off(hwmgr);
299
}
300

301 302 303 304 305 306 307 308
static int smu10_gfx_off_control(struct pp_hwmgr *hwmgr, bool enable)
{
	if (enable)
		return smu10_enable_gfx_off(hwmgr);
	else
		return smu10_disable_gfx_off(hwmgr);
}

R
Rex Zhu 已提交
309
static int smu10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
310 311 312 313 314 315 316
				struct pp_power_state  *prequest_ps,
			const struct pp_power_state *pcurrent_ps)
{
	return 0;
}

/* temporary hardcoded clock voltage breakdown tables */
317
static const DpmClock_t VddDcfClk[]= {
318 319 320 321 322
	{ 300, 2600},
	{ 600, 3200},
	{ 600, 3600},
};

323
static const DpmClock_t VddSocClk[]= {
324 325 326 327 328
	{ 478, 2600},
	{ 722, 3200},
	{ 722, 3600},
};

329
static const DpmClock_t VddFClk[]= {
330 331 332 333 334
	{ 400, 2600},
	{1200, 3200},
	{1200, 3600},
};

335
static const DpmClock_t VddDispClk[]= {
336 337 338 339 340
	{ 435, 2600},
	{ 661, 3200},
	{1086, 3600},
};

341
static const DpmClock_t VddDppClk[]= {
342 343 344 345 346
	{ 435, 2600},
	{ 661, 3200},
	{ 661, 3600},
};

347
static const DpmClock_t VddPhyClk[]= {
348 349 350 351 352
	{ 540, 2600},
	{ 810, 3200},
	{ 810, 3600},
};

R
Rex Zhu 已提交
353 354
static int smu10_get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr,
			struct smu10_voltage_dependency_table **pptable,
355
			uint32_t num_entry, const DpmClock_t *pclk_dependency_table)
356 357
{
	uint32_t table_size, i;
R
Rex Zhu 已提交
358
	struct smu10_voltage_dependency_table *ptable;
359

R
Rex Zhu 已提交
360
	table_size = sizeof(uint32_t) + sizeof(struct smu10_voltage_dependency_table) * num_entry;
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
	ptable = kzalloc(table_size, GFP_KERNEL);

	if (NULL == ptable)
		return -ENOMEM;

	ptable->count = num_entry;

	for (i = 0; i < ptable->count; i++) {
		ptable->entries[i].clk         = pclk_dependency_table->Freq * 100;
		ptable->entries[i].vol         = pclk_dependency_table->Vol;
		pclk_dependency_table++;
	}

	*pptable = ptable;

	return 0;
}


R
Rex Zhu 已提交
380
static int smu10_populate_clock_table(struct pp_hwmgr *hwmgr)
381 382 383
{
	int result;

R
Rex Zhu 已提交
384 385 386
	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
	DpmClocks_t  *table = &(smu10_data->clock_table);
	struct smu10_clock_voltage_information *pinfo = &(smu10_data->clock_vol_info);
387

388
	result = smum_smc_table_manager(hwmgr, (uint8_t *)table, SMU10_CLOCKTABLE, true);
389 390 391 392 393 394

	PP_ASSERT_WITH_CODE((0 == result),
			"Attempt to copy clock table from smc failed",
			return result);

	if (0 == result && table->DcefClocks[0].Freq != 0) {
R
Rex Zhu 已提交
395
		smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dcefclk,
396
						NUM_DCEFCLK_DPM_LEVELS,
R
Rex Zhu 已提交
397 398
						&smu10_data->clock_table.DcefClocks[0]);
		smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_socclk,
399
						NUM_SOCCLK_DPM_LEVELS,
R
Rex Zhu 已提交
400 401
						&smu10_data->clock_table.SocClocks[0]);
		smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_fclk,
402
						NUM_FCLK_DPM_LEVELS,
R
Rex Zhu 已提交
403 404
						&smu10_data->clock_table.FClocks[0]);
		smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_mclk,
405
						NUM_MEMCLK_DPM_LEVELS,
R
Rex Zhu 已提交
406
						&smu10_data->clock_table.MemClocks[0]);
407
	} else {
R
Rex Zhu 已提交
408
		smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dcefclk,
409 410
						ARRAY_SIZE(VddDcfClk),
						&VddDcfClk[0]);
R
Rex Zhu 已提交
411
		smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_socclk,
412 413
						ARRAY_SIZE(VddSocClk),
						&VddSocClk[0]);
R
Rex Zhu 已提交
414
		smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_fclk,
415 416
						ARRAY_SIZE(VddFClk),
						&VddFClk[0]);
417
	}
R
Rex Zhu 已提交
418
	smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dispclk,
419 420
					ARRAY_SIZE(VddDispClk),
					&VddDispClk[0]);
R
Rex Zhu 已提交
421
	smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dppclk,
422
					ARRAY_SIZE(VddDppClk), &VddDppClk[0]);
R
Rex Zhu 已提交
423
	smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_phyclk,
424
					ARRAY_SIZE(VddPhyClk), &VddPhyClk[0]);
425

426
	smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency);
427
	result = smum_get_argument(hwmgr);
R
Rex Zhu 已提交
428
	smu10_data->gfx_min_freq_limit = result * 100;
429

430
	smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency);
431
	result = smum_get_argument(hwmgr);
R
Rex Zhu 已提交
432
	smu10_data->gfx_max_freq_limit = result * 100;
433

434 435 436
	return 0;
}

R
Rex Zhu 已提交
437
static int smu10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
438 439
{
	int result = 0;
R
Rex Zhu 已提交
440
	struct smu10_hwmgr *data;
441

R
Rex Zhu 已提交
442
	data = kzalloc(sizeof(struct smu10_hwmgr), GFP_KERNEL);
443 444 445 446 447
	if (data == NULL)
		return -ENOMEM;

	hwmgr->backend = data;

R
Rex Zhu 已提交
448
	result = smu10_initialize_dpm_defaults(hwmgr);
449
	if (result != 0) {
R
Rex Zhu 已提交
450
		pr_err("smu10_initialize_dpm_defaults failed\n");
451 452 453
		return result;
	}

R
Rex Zhu 已提交
454
	smu10_populate_clock_table(hwmgr);
455

R
Rex Zhu 已提交
456
	result = smu10_get_system_info_data(hwmgr);
457
	if (result != 0) {
R
Rex Zhu 已提交
458
		pr_err("smu10_get_system_info_data failed\n");
459 460 461
		return result;
	}

R
Rex Zhu 已提交
462
	smu10_construct_boot_state(hwmgr);
463 464

	hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
R
Rex Zhu 已提交
465
						SMU10_MAX_HARDWARE_POWERLEVELS;
466 467

	hwmgr->platform_descriptor.hardwarePerformanceLevels =
R
Rex Zhu 已提交
468
						SMU10_MAX_HARDWARE_POWERLEVELS;
469 470 471 472 473 474 475 476 477

	hwmgr->platform_descriptor.vbiosInterruptId = 0;

	hwmgr->platform_descriptor.clockStep.engineClock = 500;

	hwmgr->platform_descriptor.clockStep.memoryClock = 500;

	hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50;

R
Rex Zhu 已提交
478 479
	hwmgr->pstate_sclk = SMU10_UMD_PSTATE_GFXCLK;
	hwmgr->pstate_mclk = SMU10_UMD_PSTATE_FCLK;
R
Rex Zhu 已提交
480

481 482 483
	return result;
}

R
Rex Zhu 已提交
484
static int smu10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
485
{
R
Rex Zhu 已提交
486 487
	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
	struct smu10_clock_voltage_information *pinfo = &(smu10_data->clock_vol_info);
488

489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
	kfree(pinfo->vdd_dep_on_dcefclk);
	pinfo->vdd_dep_on_dcefclk = NULL;
	kfree(pinfo->vdd_dep_on_socclk);
	pinfo->vdd_dep_on_socclk = NULL;
	kfree(pinfo->vdd_dep_on_fclk);
	pinfo->vdd_dep_on_fclk = NULL;
	kfree(pinfo->vdd_dep_on_dispclk);
	pinfo->vdd_dep_on_dispclk = NULL;
	kfree(pinfo->vdd_dep_on_dppclk);
	pinfo->vdd_dep_on_dppclk = NULL;
	kfree(pinfo->vdd_dep_on_phyclk);
	pinfo->vdd_dep_on_phyclk = NULL;

	kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
	hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
504

505 506 507 508 509 510
	kfree(hwmgr->backend);
	hwmgr->backend = NULL;

	return 0;
}

R
Rex Zhu 已提交
511
static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
512 513
				enum amd_dpm_forced_level level)
{
514 515 516 517 518 519 520 521 522 523
	if (hwmgr->smu_version < 0x1E3700) {
		pr_info("smu firmware version too old, can not set dpm level\n");
		return 0;
	}

	switch (level) {
	case AMD_DPM_FORCED_LEVEL_HIGH:
	case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinGfxClk,
R
Rex Zhu 已提交
524
						SMU10_UMD_PSTATE_PEAK_GFXCLK);
525 526
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinFclkByFreq,
R
Rex Zhu 已提交
527
						SMU10_UMD_PSTATE_PEAK_FCLK);
528 529
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinSocclkByFreq,
R
Rex Zhu 已提交
530
						SMU10_UMD_PSTATE_PEAK_SOCCLK);
531 532
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinVcn,
R
Rex Zhu 已提交
533
						SMU10_UMD_PSTATE_VCE);
534 535 536

		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxGfxClk,
R
Rex Zhu 已提交
537
						SMU10_UMD_PSTATE_PEAK_GFXCLK);
538 539
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxFclkByFreq,
R
Rex Zhu 已提交
540
						SMU10_UMD_PSTATE_PEAK_FCLK);
541 542
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxSocclkByFreq,
R
Rex Zhu 已提交
543
						SMU10_UMD_PSTATE_PEAK_SOCCLK);
544 545
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxVcn,
R
Rex Zhu 已提交
546
						SMU10_UMD_PSTATE_VCE);
547 548 549 550
		break;
	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinGfxClk,
R
Rex Zhu 已提交
551
						SMU10_UMD_PSTATE_MIN_GFXCLK);
552 553
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxGfxClk,
R
Rex Zhu 已提交
554
						SMU10_UMD_PSTATE_MIN_GFXCLK);
555 556 557 558
		break;
	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinFclkByFreq,
R
Rex Zhu 已提交
559
						SMU10_UMD_PSTATE_MIN_FCLK);
560 561
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxFclkByFreq,
R
Rex Zhu 已提交
562
						SMU10_UMD_PSTATE_MIN_FCLK);
563 564 565 566
		break;
	case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinGfxClk,
R
Rex Zhu 已提交
567
						SMU10_UMD_PSTATE_GFXCLK);
568 569
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinFclkByFreq,
R
Rex Zhu 已提交
570
						SMU10_UMD_PSTATE_FCLK);
571 572
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinSocclkByFreq,
R
Rex Zhu 已提交
573
						SMU10_UMD_PSTATE_SOCCLK);
574 575
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinVcn,
R
Rex Zhu 已提交
576
						SMU10_UMD_PSTATE_VCE);
577 578 579

		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxGfxClk,
R
Rex Zhu 已提交
580
						SMU10_UMD_PSTATE_GFXCLK);
581 582
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxFclkByFreq,
R
Rex Zhu 已提交
583
						SMU10_UMD_PSTATE_FCLK);
584 585
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxSocclkByFreq,
R
Rex Zhu 已提交
586
						SMU10_UMD_PSTATE_SOCCLK);
587 588
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxVcn,
R
Rex Zhu 已提交
589
						SMU10_UMD_PSTATE_VCE);
590 591 592 593
		break;
	case AMD_DPM_FORCED_LEVEL_AUTO:
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinGfxClk,
R
Rex Zhu 已提交
594
						SMU10_UMD_PSTATE_MIN_GFXCLK);
595 596
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinFclkByFreq,
R
Rex Zhu 已提交
597
						SMU10_UMD_PSTATE_MIN_FCLK);
598 599
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinSocclkByFreq,
R
Rex Zhu 已提交
600
						SMU10_UMD_PSTATE_MIN_SOCCLK);
601 602
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinVcn,
R
Rex Zhu 已提交
603
						SMU10_UMD_PSTATE_MIN_VCE);
604 605 606

		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxGfxClk,
R
Rex Zhu 已提交
607
						SMU10_UMD_PSTATE_PEAK_GFXCLK);
608 609
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxFclkByFreq,
R
Rex Zhu 已提交
610
						SMU10_UMD_PSTATE_PEAK_FCLK);
611 612
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxSocclkByFreq,
R
Rex Zhu 已提交
613
						SMU10_UMD_PSTATE_PEAK_SOCCLK);
614 615
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxVcn,
R
Rex Zhu 已提交
616
						SMU10_UMD_PSTATE_VCE);
617 618 619 620
		break;
	case AMD_DPM_FORCED_LEVEL_LOW:
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinGfxClk,
R
Rex Zhu 已提交
621
						SMU10_UMD_PSTATE_MIN_GFXCLK);
622 623
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxGfxClk,
R
Rex Zhu 已提交
624
						SMU10_UMD_PSTATE_MIN_GFXCLK);
625 626
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetHardMinFclkByFreq,
R
Rex Zhu 已提交
627
						SMU10_UMD_PSTATE_MIN_FCLK);
628 629
		smum_send_msg_to_smc_with_parameter(hwmgr,
						PPSMC_MSG_SetSoftMaxFclkByFreq,
R
Rex Zhu 已提交
630
						SMU10_UMD_PSTATE_MIN_FCLK);
631 632 633 634 635 636
		break;
	case AMD_DPM_FORCED_LEVEL_MANUAL:
	case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
	default:
		break;
	}
637 638 639
	return 0;
}

R
Rex Zhu 已提交
640
static uint32_t smu10_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
641
{
R
Rex Zhu 已提交
642
	struct smu10_hwmgr *data;
643 644 645 646

	if (hwmgr == NULL)
		return -EINVAL;

R
Rex Zhu 已提交
647
	data = (struct smu10_hwmgr *)(hwmgr->backend);
648 649 650 651 652 653

	if (low)
		return data->clock_vol_info.vdd_dep_on_fclk->entries[0].clk;
	else
		return data->clock_vol_info.vdd_dep_on_fclk->entries[
			data->clock_vol_info.vdd_dep_on_fclk->count - 1].clk;
654 655
}

R
Rex Zhu 已提交
656
static uint32_t smu10_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
657
{
R
Rex Zhu 已提交
658
	struct smu10_hwmgr *data;
659 660 661 662

	if (hwmgr == NULL)
		return -EINVAL;

R
Rex Zhu 已提交
663
	data = (struct smu10_hwmgr *)(hwmgr->backend);
664 665 666 667 668

	if (low)
		return data->gfx_min_freq_limit;
	else
		return data->gfx_max_freq_limit;
669 670
}

R
Rex Zhu 已提交
671
static int smu10_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
672 673 674 675 676
					struct pp_hw_power_state *hw_ps)
{
	return 0;
}

R
Rex Zhu 已提交
677
static int smu10_dpm_get_pp_table_entry_callback(
678 679 680 681 682
						     struct pp_hwmgr *hwmgr,
					   struct pp_hw_power_state *hw_ps,
							  unsigned int index,
						     const void *clock_info)
{
R
Rex Zhu 已提交
683
	struct smu10_power_state *smu10_ps = cast_smu10_ps(hw_ps);
684

R
Rex Zhu 已提交
685
	smu10_ps->levels[index].engine_clock = 0;
686

R
Rex Zhu 已提交
687 688
	smu10_ps->levels[index].vddc_index = 0;
	smu10_ps->level = index + 1;
689 690

	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
R
Rex Zhu 已提交
691 692
		smu10_ps->levels[index].ds_divider_index = 5;
		smu10_ps->levels[index].ss_divider_index = 5;
693 694 695 696 697
	}

	return 0;
}

R
Rex Zhu 已提交
698
static int smu10_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr)
699 700 701 702 703 704 705 706 707
{
	int result;
	unsigned long ret = 0;

	result = pp_tables_get_num_of_entries(hwmgr, &ret);

	return result ? 0 : ret;
}

R
Rex Zhu 已提交
708
static int smu10_dpm_get_pp_table_entry(struct pp_hwmgr *hwmgr,
709 710 711
		    unsigned long entry, struct pp_power_state *ps)
{
	int result;
R
Rex Zhu 已提交
712
	struct smu10_power_state *smu10_ps;
713

R
Rex Zhu 已提交
714
	ps->hardware.magic = SMU10_Magic;
715

R
Rex Zhu 已提交
716
	smu10_ps = cast_smu10_ps(&(ps->hardware));
717 718

	result = pp_tables_get_entry(hwmgr, entry, ps,
R
Rex Zhu 已提交
719
			smu10_dpm_get_pp_table_entry_callback);
720

R
Rex Zhu 已提交
721 722
	smu10_ps->uvd_clocks.vclk = ps->uvd_clocks.VCLK;
	smu10_ps->uvd_clocks.dclk = ps->uvd_clocks.DCLK;
723 724 725 726

	return result;
}

R
Rex Zhu 已提交
727
static int smu10_get_power_state_size(struct pp_hwmgr *hwmgr)
728
{
R
Rex Zhu 已提交
729
	return sizeof(struct smu10_power_state);
730 731
}

R
Rex Zhu 已提交
732
static int smu10_set_cpu_power_state(struct pp_hwmgr *hwmgr)
733 734 735 736 737
{
	return 0;
}


R
Rex Zhu 已提交
738
static int smu10_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time,
739 740
			bool cc6_disable, bool pstate_disable, bool pstate_switch_disable)
{
741 742 743 744 745 746 747 748 749 750
	struct smu10_hwmgr *data = (struct smu10_hwmgr *)(hwmgr->backend);

	if (separation_time != data->separation_time ||
			cc6_disable != data->cc6_disable ||
			pstate_disable != data->pstate_disable) {
		data->separation_time = separation_time;
		data->cc6_disable = cc6_disable;
		data->pstate_disable = pstate_disable;
		data->cc6_setting_changed = true;
	}
751 752 753
	return 0;
}

R
Rex Zhu 已提交
754
static int smu10_get_dal_power_level(struct pp_hwmgr *hwmgr,
755 756 757 758 759
		struct amd_pp_simple_clock_info *info)
{
	return -EINVAL;
}

R
Rex Zhu 已提交
760
static int smu10_force_clock_level(struct pp_hwmgr *hwmgr,
761 762 763 764 765
		enum pp_clock_type type, uint32_t mask)
{
	return 0;
}

R
Rex Zhu 已提交
766
static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
767 768
		enum pp_clock_type type, char *buf)
{
R
Rex Zhu 已提交
769 770
	struct smu10_hwmgr *data = (struct smu10_hwmgr *)(hwmgr->backend);
	struct smu10_voltage_dependency_table *mclk_table =
771 772 773 774 775
			data->clock_vol_info.vdd_dep_on_fclk;
	int i, now, size = 0;

	switch (type) {
	case PP_SCLK:
776
		smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetGfxclkFrequency);
777
		now = smum_get_argument(hwmgr);
778 779 780 781 782 783 784 785 786 787 788

		size += sprintf(buf + size, "0: %uMhz %s\n",
				data->gfx_min_freq_limit / 100,
				((data->gfx_min_freq_limit / 100)
				 == now) ? "*" : "");
		size += sprintf(buf + size, "1: %uMhz %s\n",
				data->gfx_max_freq_limit / 100,
				((data->gfx_max_freq_limit / 100)
				 == now) ? "*" : "");
		break;
	case PP_MCLK:
789
		smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency);
790
		now = smum_get_argument(hwmgr);
791 792 793 794 795 796 797 798 799 800 801 802 803

		for (i = 0; i < mclk_table->count; i++)
			size += sprintf(buf + size, "%d: %uMhz %s\n",
					i,
					mclk_table->entries[i].clk / 100,
					((mclk_table->entries[i].clk / 100)
					 == now) ? "*" : "");
		break;
	default:
		break;
	}

	return size;
804 805
}

R
Rex Zhu 已提交
806
static int smu10_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state,
807 808 809
				PHM_PerformanceLevelDesignation designation, uint32_t index,
				PHM_PerformanceLevel *level)
{
R
Rex Zhu 已提交
810
	struct smu10_hwmgr *data;
811 812 813 814

	if (level == NULL || hwmgr == NULL || state == NULL)
		return -EINVAL;

R
Rex Zhu 已提交
815
	data = (struct smu10_hwmgr *)(hwmgr->backend);
816

817
	if (index == 0) {
818
		level->memory_clock = data->clock_vol_info.vdd_dep_on_fclk->entries[0].clk;
819 820 821 822 823
		level->coreClock = data->gfx_min_freq_limit;
	} else {
		level->memory_clock = data->clock_vol_info.vdd_dep_on_fclk->entries[
			data->clock_vol_info.vdd_dep_on_fclk->count - 1].clk;
		level->coreClock = data->gfx_max_freq_limit;
824
	}
825

826 827 828 829 830 831
	level->nonLocalMemoryFreq = 0;
	level->nonLocalMemoryWidth = 0;

	return 0;
}

R
Rex Zhu 已提交
832
static int smu10_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr,
833 834
	const struct pp_hw_power_state *state, struct pp_clock_info *clock_info)
{
R
Rex Zhu 已提交
835
	const struct smu10_power_state *ps = cast_const_smu10_ps(state);
836 837 838 839 840 841 842 843 844 845 846 847 848 849

	clock_info->min_eng_clk = ps->levels[0].engine_clock / (1 << (ps->levels[0].ss_divider_index));
	clock_info->max_eng_clk = ps->levels[ps->level - 1].engine_clock / (1 << (ps->levels[ps->level - 1].ss_divider_index));

	return 0;
}

#define MEM_FREQ_LOW_LATENCY        25000
#define MEM_FREQ_HIGH_LATENCY       80000
#define MEM_LATENCY_HIGH            245
#define MEM_LATENCY_LOW             35
#define MEM_LATENCY_ERR             0xFFFF


R
Rex Zhu 已提交
850
static uint32_t smu10_get_mem_latency(struct pp_hwmgr *hwmgr,
851 852 853 854 855 856 857 858 859 860 861
		uint32_t clock)
{
	if (clock >= MEM_FREQ_LOW_LATENCY &&
			clock < MEM_FREQ_HIGH_LATENCY)
		return MEM_LATENCY_HIGH;
	else if (clock >= MEM_FREQ_HIGH_LATENCY)
		return MEM_LATENCY_LOW;
	else
		return MEM_LATENCY_ERR;
}

R
Rex Zhu 已提交
862
static int smu10_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr,
863
		enum amd_pp_clock_type type,
864 865 866
		struct pp_clock_levels_with_latency *clocks)
{
	uint32_t i;
R
Rex Zhu 已提交
867 868 869
	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
	struct smu10_clock_voltage_information *pinfo = &(smu10_data->clock_vol_info);
	struct smu10_voltage_dependency_table *pclk_vol_table;
870
	bool latency_required = false;
871

872 873
	if (pinfo == NULL)
		return -EINVAL;
874 875 876

	switch (type) {
	case amd_pp_mem_clock:
877 878
		pclk_vol_table = pinfo->vdd_dep_on_mclk;
		latency_required = true;
879
		break;
880 881 882
	case amd_pp_f_clock:
		pclk_vol_table = pinfo->vdd_dep_on_fclk;
		latency_required = true;
883
		break;
884 885
	case amd_pp_dcf_clock:
		pclk_vol_table = pinfo->vdd_dep_on_dcefclk;
886
		break;
887 888 889 890 891 892 893 894
	case amd_pp_disp_clock:
		pclk_vol_table = pinfo->vdd_dep_on_dispclk;
		break;
	case amd_pp_phy_clock:
		pclk_vol_table = pinfo->vdd_dep_on_phyclk;
		break;
	case amd_pp_dpp_clock:
		pclk_vol_table = pinfo->vdd_dep_on_dppclk;
895
	default:
896 897 898 899 900 901 902 903 904 905
		return -EINVAL;
	}

	if (pclk_vol_table == NULL || pclk_vol_table->count == 0)
		return -EINVAL;

	clocks->num_levels = 0;
	for (i = 0; i < pclk_vol_table->count; i++) {
		clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk;
		clocks->data[i].latency_in_us = latency_required ?
R
Rex Zhu 已提交
906
						smu10_get_mem_latency(hwmgr,
907 908 909
						pclk_vol_table->entries[i].clk) :
						0;
		clocks->num_levels++;
910 911 912 913 914
	}

	return 0;
}

R
Rex Zhu 已提交
915
static int smu10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr,
916 917 918 919
		enum amd_pp_clock_type type,
		struct pp_clock_levels_with_voltage *clocks)
{
	uint32_t i;
R
Rex Zhu 已提交
920 921 922
	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
	struct smu10_clock_voltage_information *pinfo = &(smu10_data->clock_vol_info);
	struct smu10_voltage_dependency_table *pclk_vol_table = NULL;
923 924 925

	if (pinfo == NULL)
		return -EINVAL;
926 927 928 929 930

	switch (type) {
	case amd_pp_mem_clock:
		pclk_vol_table = pinfo->vdd_dep_on_mclk;
		break;
931 932
	case amd_pp_f_clock:
		pclk_vol_table = pinfo->vdd_dep_on_fclk;
933
		break;
934 935
	case amd_pp_dcf_clock:
		pclk_vol_table = pinfo->vdd_dep_on_dcefclk;
936
		break;
937 938
	case amd_pp_soc_clock:
		pclk_vol_table = pinfo->vdd_dep_on_socclk;
939 940 941 942 943
		break;
	default:
		return -EINVAL;
	}

944
	if (pclk_vol_table == NULL || pclk_vol_table->count == 0)
945 946
		return -EINVAL;

947
	clocks->num_levels = 0;
948 949 950 951 952 953 954 955 956
	for (i = 0; i < pclk_vol_table->count; i++) {
		clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk;
		clocks->data[i].voltage_in_mv = pclk_vol_table->entries[i].vol;
		clocks->num_levels++;
	}

	return 0;
}

R
Rex Zhu 已提交
957
static int smu10_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
958 959
		struct pp_display_clock_request *clock_req)
{
R
Rex Zhu 已提交
960
	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
961
	enum amd_pp_clock_type clk_type = clock_req->clock_type;
962
	uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
963 964 965
	PPSMC_Msg        msg;

	switch (clk_type) {
966
	case amd_pp_dcf_clock:
R
Rex Zhu 已提交
967
		if (clk_freq == smu10_data->dcf_actual_hard_min_freq)
968
			return 0;
969
		msg =  PPSMC_MSG_SetHardMinDcefclkByFreq;
R
Rex Zhu 已提交
970
		smu10_data->dcf_actual_hard_min_freq = clk_freq;
971 972 973 974
		break;
	case amd_pp_soc_clock:
		 msg = PPSMC_MSG_SetHardMinSocclkByFreq;
		break;
975
	case amd_pp_f_clock:
R
Rex Zhu 已提交
976
		if (clk_freq == smu10_data->f_actual_hard_min_freq)
977
			return 0;
R
Rex Zhu 已提交
978
		smu10_data->f_actual_hard_min_freq = clk_freq;
979 980 981 982 983 984 985
		msg = PPSMC_MSG_SetHardMinFclkByFreq;
		break;
	default:
		pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!");
		return -EINVAL;
	}

986
	smum_send_msg_to_smc_with_parameter(hwmgr, msg, clk_freq);
987

988
	return 0;
989 990
}

R
Rex Zhu 已提交
991
static int smu10_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks)
992
{
993 994
	clocks->engine_max_clock = 80000; /* driver can't get engine clock, temp hard code to 800MHz */
	return 0;
995 996
}

R
Rex Zhu 已提交
997
static int smu10_thermal_get_temperature(struct pp_hwmgr *hwmgr)
998
{
999 1000
	struct amdgpu_device *adev = hwmgr->adev;
	uint32_t reg_value = RREG32_SOC15(THM, 0, mmTHM_TCON_CUR_TMP);
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
	int cur_temp =
		(reg_value & THM_TCON_CUR_TMP__CUR_TEMP_MASK) >> THM_TCON_CUR_TMP__CUR_TEMP__SHIFT;

	if (cur_temp & THM_TCON_CUR_TMP__CUR_TEMP_RANGE_SEL_MASK)
		cur_temp = ((cur_temp / 8) - 49) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
	else
		cur_temp = (cur_temp / 8) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;

	return cur_temp;
}

R
Rex Zhu 已提交
1012
static int smu10_read_sensor(struct pp_hwmgr *hwmgr, int idx,
1013 1014
			  void *value, int *size)
{
1015 1016 1017
	uint32_t sclk, mclk;
	int ret = 0;

1018
	switch (idx) {
1019
	case AMDGPU_PP_SENSOR_GFX_SCLK:
1020
		smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetGfxclkFrequency);
1021
		sclk = smum_get_argument(hwmgr);
1022
			/* in units of 10KHZ */
1023 1024
		*((uint32_t *)value) = sclk * 100;
		*size = 4;
1025 1026
		break;
	case AMDGPU_PP_SENSOR_GFX_MCLK:
1027
		smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency);
1028
		mclk = smum_get_argument(hwmgr);
1029
			/* in units of 10KHZ */
1030 1031
		*((uint32_t *)value) = mclk * 100;
		*size = 4;
1032
		break;
1033
	case AMDGPU_PP_SENSOR_GPU_TEMP:
R
Rex Zhu 已提交
1034
		*((uint32_t *)value) = smu10_thermal_get_temperature(hwmgr);
1035
		break;
1036
	default:
1037 1038
		ret = -EINVAL;
		break;
1039
	}
1040 1041

	return ret;
1042 1043
}

1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
static int smu10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr,
		struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges)
{
	struct smu10_hwmgr *data = hwmgr->backend;
	Watermarks_t *table = &(data->water_marks_table);
	int result = 0;

	smu_set_watermarks_for_clocks_ranges(table,wm_with_clock_ranges);
	smum_smc_table_manager(hwmgr, (uint8_t *)table, (uint16_t)SMU10_WMTABLE, false);
	data->water_marks_exist = true;
	return result;
}
R
Rex Zhu 已提交
1056
static int smu10_set_mmhub_powergating_by_smu(struct pp_hwmgr *hwmgr)
1057 1058 1059 1060
{
	return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_PowerGateMmHub);
}

R
Rex Zhu 已提交
1061 1062 1063
static const struct pp_hwmgr_func smu10_hwmgr_funcs = {
	.backend_init = smu10_hwmgr_backend_init,
	.backend_fini = smu10_hwmgr_backend_fini,
1064
	.asic_setup = NULL,
R
Rex Zhu 已提交
1065 1066 1067
	.apply_state_adjust_rules = smu10_apply_state_adjust_rules,
	.force_dpm_level = smu10_dpm_force_dpm_level,
	.get_power_state_size = smu10_get_power_state_size,
1068 1069 1070
	.powerdown_uvd = NULL,
	.powergate_uvd = NULL,
	.powergate_vce = NULL,
R
Rex Zhu 已提交
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
	.get_mclk = smu10_dpm_get_mclk,
	.get_sclk = smu10_dpm_get_sclk,
	.patch_boot_state = smu10_dpm_patch_boot_state,
	.get_pp_table_entry = smu10_dpm_get_pp_table_entry,
	.get_num_of_pp_table_entries = smu10_dpm_get_num_of_pp_table_entries,
	.set_cpu_power_state = smu10_set_cpu_power_state,
	.store_cc6_data = smu10_store_cc6_data,
	.force_clock_level = smu10_force_clock_level,
	.print_clock_levels = smu10_print_clock_levels,
	.get_dal_power_level = smu10_get_dal_power_level,
	.get_performance_level = smu10_get_performance_level,
	.get_current_shallow_sleep_clocks = smu10_get_current_shallow_sleep_clocks,
	.get_clock_by_type_with_latency = smu10_get_clock_by_type_with_latency,
	.get_clock_by_type_with_voltage = smu10_get_clock_by_type_with_voltage,
1085
	.set_watermarks_for_clocks_ranges = smu10_set_watermarks_for_clocks_ranges,
R
Rex Zhu 已提交
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
	.get_max_high_clocks = smu10_get_max_high_clocks,
	.read_sensor = smu10_read_sensor,
	.set_active_display_count = smu10_set_active_display_count,
	.set_deep_sleep_dcefclk = smu10_set_deep_sleep_dcefclk,
	.dynamic_state_management_enable = smu10_enable_dpm_tasks,
	.power_off_asic = smu10_power_off_asic,
	.asic_setup = smu10_setup_asic_task,
	.power_state_set = smu10_set_power_state_tasks,
	.dynamic_state_management_disable = smu10_disable_dpm_tasks,
	.set_mmhub_powergating_by_smu = smu10_set_mmhub_powergating_by_smu,
1096
	.gfx_off_control = smu10_gfx_off_control,
1097 1098
};

R
Rex Zhu 已提交
1099
int smu10_init_function_pointers(struct pp_hwmgr *hwmgr)
1100
{
R
Rex Zhu 已提交
1101
	hwmgr->hwmgr_func = &smu10_hwmgr_funcs;
1102 1103 1104
	hwmgr->pptable_func = &pptable_funcs;
	return 0;
}