amd_powerplay.c 29.1 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
/*
 * 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.
 *
 */
23
#include "pp_debug.h"
24 25 26
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/gfp.h>
27
#include <linux/slab.h>
28
#include <linux/firmware.h>
29 30
#include "amd_shared.h"
#include "amd_powerplay.h"
31
#include "power_state.h"
32
#include "amdgpu.h"
R
Rex Zhu 已提交
33
#include "hwmgr.h"
34

R
Rex Zhu 已提交
35

36
static const struct amd_pm_funcs pp_dpm_funcs;
37

38
static int amd_powerplay_create(struct amdgpu_device *adev)
39
{
40
	struct pp_hwmgr *hwmgr;
41

42
	if (adev == NULL)
43 44
		return -EINVAL;

45 46
	hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL);
	if (hwmgr == NULL)
47 48
		return -ENOMEM;

49
	hwmgr->adev = adev;
50 51
	hwmgr->not_vf = !amdgpu_sriov_vf(adev);
	hwmgr->pm_en = (amdgpu_dpm && hwmgr->not_vf) ? true : false;
52 53 54 55 56 57 58
	hwmgr->device = amdgpu_cgs_create_device(adev);
	mutex_init(&hwmgr->smu_lock);
	hwmgr->chip_family = adev->family;
	hwmgr->chip_id = adev->asic_type;
	hwmgr->feature_mask = amdgpu_pp_feature_mask;
	adev->powerplay.pp_handle = hwmgr;
	adev->powerplay.pp_funcs = &pp_dpm_funcs;
59 60 61
	return 0;
}

62

63
static void amd_powerplay_destroy(struct amdgpu_device *adev)
64
{
65
	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
66

67 68
	kfree(hwmgr->hardcode_pp_table);
	hwmgr->hardcode_pp_table = NULL;
69

70 71
	kfree(hwmgr);
	hwmgr = NULL;
72 73
}

74 75 76
static int pp_early_init(void *handle)
{
	int ret;
77
	struct amdgpu_device *adev = handle;
78

79
	ret = amd_powerplay_create(adev);
80

81 82 83
	if (ret != 0)
		return ret;

84
	ret = hwmgr_early_init(adev->powerplay.pp_handle);
85
	if (ret)
86
		return -EINVAL;
87

88
	return 0;
89 90
}

91
static int pp_sw_init(void *handle)
92
{
93 94
	struct amdgpu_device *adev = handle;
	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
95 96
	int ret = 0;

97
	ret = hwmgr_sw_init(hwmgr);
98

99
	pr_debug("powerplay sw init %s\n", ret ? "failed" : "successfully");
100

101 102
	return ret;
}
103

104 105
static int pp_sw_fini(void *handle)
{
106 107
	struct amdgpu_device *adev = handle;
	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
108

109
	hwmgr_sw_fini(hwmgr);
110

111 112 113
	if (adev->firmware.load_type == AMDGPU_FW_LOAD_SMU) {
		release_firmware(adev->pm.fw);
		adev->pm.fw = NULL;
114
		amdgpu_ucode_fini_bo(adev);
115
	}
116

117
	return 0;
118 119 120 121
}

static int pp_hw_init(void *handle)
{
122
	int ret = 0;
123 124
	struct amdgpu_device *adev = handle;
	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
125

126 127
	if (adev->firmware.load_type == AMDGPU_FW_LOAD_SMU)
		amdgpu_ucode_init_bo(adev);
128

129
	ret = hwmgr_hw_init(hwmgr);
130

131 132
	if (ret)
		pr_err("powerplay hw init failed\n");
133

134
	return ret;
135 136 137 138
}

static int pp_hw_fini(void *handle)
{
139 140
	struct amdgpu_device *adev = handle;
	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
141

142
	hwmgr_hw_fini(hwmgr);
143

144 145 146
	return 0;
}

R
Rex Zhu 已提交
147 148
static int pp_late_init(void *handle)
{
149 150 151
	struct amdgpu_device *adev = handle;
	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;

152 153 154
	if (hwmgr && hwmgr->pm_en) {
		mutex_lock(&hwmgr->smu_lock);
		hwmgr_handle_task(hwmgr,
155
					AMD_PP_TASK_COMPLETE_INIT, NULL);
156 157
		mutex_unlock(&hwmgr->smu_lock);
	}
R
Rex Zhu 已提交
158 159 160
	return 0;
}

161 162
static void pp_late_fini(void *handle)
{
163 164 165
	struct amdgpu_device *adev = handle;

	amd_powerplay_destroy(adev);
166 167 168
}


169 170
static bool pp_is_idle(void *handle)
{
171
	return false;
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
}

static int pp_wait_for_idle(void *handle)
{
	return 0;
}

static int pp_sw_reset(void *handle)
{
	return 0;
}

static int pp_set_powergating_state(void *handle,
				    enum amd_powergating_state state)
{
187 188
	struct amdgpu_device *adev = handle;
	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
189

190 191
	if (!hwmgr || !hwmgr->pm_en)
		return 0;
192

193
	if (hwmgr->hwmgr_func->enable_per_cu_power_gating == NULL) {
194
		pr_info("%s was not implemented.\n", __func__);
195 196
		return 0;
	}
197 198 199

	/* Enable/disable GFX per cu powergating through SMU */
	return hwmgr->hwmgr_func->enable_per_cu_power_gating(hwmgr,
200
			state == AMD_PG_STATE_GATE);
201 202 203 204
}

static int pp_suspend(void *handle)
{
205 206
	struct amdgpu_device *adev = handle;
	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
207

208
	return hwmgr_suspend(hwmgr);
209 210 211 212
}

static int pp_resume(void *handle)
{
213 214
	struct amdgpu_device *adev = handle;
	struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
215

216
	return hwmgr_resume(hwmgr);
217 218
}

219 220 221 222 223 224
static int pp_set_clockgating_state(void *handle,
					  enum amd_clockgating_state state)
{
	return 0;
}

225
static const struct amd_ip_funcs pp_ip_funcs = {
226
	.name = "powerplay",
227
	.early_init = pp_early_init,
R
Rex Zhu 已提交
228
	.late_init = pp_late_init,
229 230 231 232
	.sw_init = pp_sw_init,
	.sw_fini = pp_sw_fini,
	.hw_init = pp_hw_init,
	.hw_fini = pp_hw_fini,
233
	.late_fini = pp_late_fini,
234 235 236 237 238
	.suspend = pp_suspend,
	.resume = pp_resume,
	.is_idle = pp_is_idle,
	.wait_for_idle = pp_wait_for_idle,
	.soft_reset = pp_sw_reset,
239
	.set_clockgating_state = pp_set_clockgating_state,
240 241 242
	.set_powergating_state = pp_set_powergating_state,
};

243 244 245 246 247 248 249 250 251
const struct amdgpu_ip_block_version pp_smu_ip_block =
{
	.type = AMD_IP_BLOCK_TYPE_SMC,
	.major = 1,
	.minor = 0,
	.rev = 0,
	.funcs = &pp_ip_funcs,
};

252 253 254 255 256 257 258 259 260 261
static int pp_dpm_load_fw(void *handle)
{
	return 0;
}

static int pp_dpm_fw_loading_complete(void *handle)
{
	return 0;
}

262 263
static int pp_set_clockgating_by_smu(void *handle, uint32_t msg_id)
{
264
	struct pp_hwmgr *hwmgr = handle;
265

266 267
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
268 269 270 271 272 273 274 275 276

	if (hwmgr->hwmgr_func->update_clock_gatings == NULL) {
		pr_info("%s was not implemented.\n", __func__);
		return 0;
	}

	return hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
static void pp_dpm_en_umd_pstate(struct pp_hwmgr  *hwmgr,
						enum amd_dpm_forced_level *level)
{
	uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
					AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
					AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
					AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;

	if (!(hwmgr->dpm_level & profile_mode_mask)) {
		/* enter umd pstate, save current level, disable gfx cg*/
		if (*level & profile_mode_mask) {
			hwmgr->saved_dpm_level = hwmgr->dpm_level;
			hwmgr->en_umd_pstate = true;
			cgs_set_clockgating_state(hwmgr->device,
						AMD_IP_BLOCK_TYPE_GFX,
						AMD_CG_STATE_UNGATE);
			cgs_set_powergating_state(hwmgr->device,
					AMD_IP_BLOCK_TYPE_GFX,
					AMD_PG_STATE_UNGATE);
		}
	} else {
		/* exit umd pstate, restore level, enable gfx cg*/
		if (!(*level & profile_mode_mask)) {
			if (*level == AMD_DPM_FORCED_LEVEL_PROFILE_EXIT)
				*level = hwmgr->saved_dpm_level;
			hwmgr->en_umd_pstate = false;
			cgs_set_clockgating_state(hwmgr->device,
					AMD_IP_BLOCK_TYPE_GFX,
					AMD_CG_STATE_GATE);
			cgs_set_powergating_state(hwmgr->device,
					AMD_IP_BLOCK_TYPE_GFX,
					AMD_PG_STATE_GATE);
		}
	}
}

313 314 315
static int pp_dpm_force_performance_level(void *handle,
					enum amd_dpm_forced_level level)
{
316
	struct pp_hwmgr *hwmgr = handle;
317

318 319
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
320

321 322 323
	if (level == hwmgr->dpm_level)
		return 0;

324
	mutex_lock(&hwmgr->smu_lock);
325 326
	pp_dpm_en_umd_pstate(hwmgr, &level);
	hwmgr->request_dpm_level = level;
327 328
	hwmgr_handle_task(hwmgr, AMD_PP_TASK_READJUST_POWER_STATE, NULL);
	mutex_unlock(&hwmgr->smu_lock);
329

330 331
	return 0;
}
332

333 334 335
static enum amd_dpm_forced_level pp_dpm_get_performance_level(
								void *handle)
{
336
	struct pp_hwmgr *hwmgr = handle;
337
	enum amd_dpm_forced_level level;
338

339 340
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
341

342
	mutex_lock(&hwmgr->smu_lock);
343
	level = hwmgr->dpm_level;
344
	mutex_unlock(&hwmgr->smu_lock);
345
	return level;
346
}
347

348
static uint32_t pp_dpm_get_sclk(void *handle, bool low)
349
{
350
	struct pp_hwmgr *hwmgr = handle;
351
	uint32_t clk = 0;
352

353 354
	if (!hwmgr || !hwmgr->pm_en)
		return 0;
355

356
	if (hwmgr->hwmgr_func->get_sclk == NULL) {
357
		pr_info("%s was not implemented.\n", __func__);
358 359
		return 0;
	}
360
	mutex_lock(&hwmgr->smu_lock);
361
	clk = hwmgr->hwmgr_func->get_sclk(hwmgr, low);
362
	mutex_unlock(&hwmgr->smu_lock);
363
	return clk;
364
}
365

366
static uint32_t pp_dpm_get_mclk(void *handle, bool low)
367
{
368
	struct pp_hwmgr *hwmgr = handle;
369
	uint32_t clk = 0;
370

371 372
	if (!hwmgr || !hwmgr->pm_en)
		return 0;
373

374
	if (hwmgr->hwmgr_func->get_mclk == NULL) {
375
		pr_info("%s was not implemented.\n", __func__);
376 377
		return 0;
	}
378
	mutex_lock(&hwmgr->smu_lock);
379
	clk = hwmgr->hwmgr_func->get_mclk(hwmgr, low);
380
	mutex_unlock(&hwmgr->smu_lock);
381
	return clk;
382
}
383

384
static void pp_dpm_powergate_vce(void *handle, bool gate)
385
{
386
	struct pp_hwmgr *hwmgr = handle;
387

388
	if (!hwmgr || !hwmgr->pm_en)
389
		return;
390

391
	if (hwmgr->hwmgr_func->powergate_vce == NULL) {
392
		pr_info("%s was not implemented.\n", __func__);
393
		return;
394
	}
395
	mutex_lock(&hwmgr->smu_lock);
396
	hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
397
	mutex_unlock(&hwmgr->smu_lock);
398
}
399

400
static void pp_dpm_powergate_uvd(void *handle, bool gate)
401
{
402
	struct pp_hwmgr *hwmgr = handle;
403

404
	if (!hwmgr || !hwmgr->pm_en)
405
		return;
406

407
	if (hwmgr->hwmgr_func->powergate_uvd == NULL) {
408
		pr_info("%s was not implemented.\n", __func__);
409
		return;
410
	}
411
	mutex_lock(&hwmgr->smu_lock);
412
	hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate);
413
	mutex_unlock(&hwmgr->smu_lock);
414 415
}

416
static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_task task_id,
417
		enum amd_pm_state_type *user_state)
418
{
419
	int ret = 0;
420
	struct pp_hwmgr *hwmgr = handle;
421

422 423
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
424

425 426 427
	mutex_lock(&hwmgr->smu_lock);
	ret = hwmgr_handle_task(hwmgr, task_id, user_state);
	mutex_unlock(&hwmgr->smu_lock);
428

429
	return ret;
430
}
431

432
static enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
433
{
434
	struct pp_hwmgr *hwmgr = handle;
435
	struct pp_power_state *state;
436
	enum amd_pm_state_type pm_type;
437

438
	if (!hwmgr || !hwmgr->pm_en || !hwmgr->current_ps)
439 440
		return -EINVAL;

441
	mutex_lock(&hwmgr->smu_lock);
442

443 444 445 446
	state = hwmgr->current_ps;

	switch (state->classification.ui_label) {
	case PP_StateUILabel_Battery:
447
		pm_type = POWER_STATE_TYPE_BATTERY;
448
		break;
449
	case PP_StateUILabel_Balanced:
450
		pm_type = POWER_STATE_TYPE_BALANCED;
451
		break;
452
	case PP_StateUILabel_Performance:
453
		pm_type = POWER_STATE_TYPE_PERFORMANCE;
454
		break;
455
	default:
456
		if (state->classification.flags & PP_StateClassificationFlag_Boot)
457
			pm_type = POWER_STATE_TYPE_INTERNAL_BOOT;
458
		else
459
			pm_type = POWER_STATE_TYPE_DEFAULT;
460
		break;
461
	}
462
	mutex_unlock(&hwmgr->smu_lock);
463 464

	return pm_type;
465
}
466

467
static void pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
468
{
469
	struct pp_hwmgr *hwmgr = handle;
470

471
	if (!hwmgr || !hwmgr->pm_en)
472
		return;
473

474
	if (hwmgr->hwmgr_func->set_fan_control_mode == NULL) {
475
		pr_info("%s was not implemented.\n", __func__);
476
		return;
477
	}
478
	mutex_lock(&hwmgr->smu_lock);
479
	hwmgr->hwmgr_func->set_fan_control_mode(hwmgr, mode);
480
	mutex_unlock(&hwmgr->smu_lock);
481 482
}

483
static uint32_t pp_dpm_get_fan_control_mode(void *handle)
484
{
485
	struct pp_hwmgr *hwmgr = handle;
486
	uint32_t mode = 0;
487

488 489
	if (!hwmgr || !hwmgr->pm_en)
		return 0;
490

491
	if (hwmgr->hwmgr_func->get_fan_control_mode == NULL) {
492
		pr_info("%s was not implemented.\n", __func__);
493 494
		return 0;
	}
495
	mutex_lock(&hwmgr->smu_lock);
496
	mode = hwmgr->hwmgr_func->get_fan_control_mode(hwmgr);
497
	mutex_unlock(&hwmgr->smu_lock);
498
	return mode;
499 500 501 502
}

static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent)
{
503
	struct pp_hwmgr *hwmgr = handle;
504
	int ret = 0;
505

506 507
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
508

509
	if (hwmgr->hwmgr_func->set_fan_speed_percent == NULL) {
510
		pr_info("%s was not implemented.\n", __func__);
511 512
		return 0;
	}
513
	mutex_lock(&hwmgr->smu_lock);
514
	ret = hwmgr->hwmgr_func->set_fan_speed_percent(hwmgr, percent);
515
	mutex_unlock(&hwmgr->smu_lock);
516
	return ret;
517 518 519 520
}

static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed)
{
521
	struct pp_hwmgr *hwmgr = handle;
522
	int ret = 0;
523

524 525
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
526

527
	if (hwmgr->hwmgr_func->get_fan_speed_percent == NULL) {
528
		pr_info("%s was not implemented.\n", __func__);
529 530
		return 0;
	}
531

532
	mutex_lock(&hwmgr->smu_lock);
533
	ret = hwmgr->hwmgr_func->get_fan_speed_percent(hwmgr, speed);
534
	mutex_unlock(&hwmgr->smu_lock);
535
	return ret;
536 537
}

538 539
static int pp_dpm_get_fan_speed_rpm(void *handle, uint32_t *rpm)
{
540
	struct pp_hwmgr *hwmgr = handle;
541
	int ret = 0;
542

543 544
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
545 546 547 548

	if (hwmgr->hwmgr_func->get_fan_speed_rpm == NULL)
		return -EINVAL;

549
	mutex_lock(&hwmgr->smu_lock);
550
	ret = hwmgr->hwmgr_func->get_fan_speed_rpm(hwmgr, rpm);
551
	mutex_unlock(&hwmgr->smu_lock);
552
	return ret;
553 554
}

555 556 557
static int pp_dpm_get_pp_num_states(void *handle,
		struct pp_states_info *data)
{
558
	struct pp_hwmgr *hwmgr = handle;
559 560
	int i;

561 562
	memset(data, 0, sizeof(*data));

563
	if (!hwmgr || !hwmgr->pm_en ||!hwmgr->ps)
564 565
		return -EINVAL;

566
	mutex_lock(&hwmgr->smu_lock);
567

568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
	data->nums = hwmgr->num_ps;

	for (i = 0; i < hwmgr->num_ps; i++) {
		struct pp_power_state *state = (struct pp_power_state *)
				((unsigned long)hwmgr->ps + i * hwmgr->ps_size);
		switch (state->classification.ui_label) {
		case PP_StateUILabel_Battery:
			data->states[i] = POWER_STATE_TYPE_BATTERY;
			break;
		case PP_StateUILabel_Balanced:
			data->states[i] = POWER_STATE_TYPE_BALANCED;
			break;
		case PP_StateUILabel_Performance:
			data->states[i] = POWER_STATE_TYPE_PERFORMANCE;
			break;
		default:
			if (state->classification.flags & PP_StateClassificationFlag_Boot)
				data->states[i] = POWER_STATE_TYPE_INTERNAL_BOOT;
			else
				data->states[i] = POWER_STATE_TYPE_DEFAULT;
		}
	}
590
	mutex_unlock(&hwmgr->smu_lock);
591 592 593 594 595
	return 0;
}

static int pp_dpm_get_pp_table(void *handle, char **table)
{
596
	struct pp_hwmgr *hwmgr = handle;
597
	int size = 0;
598

599
	if (!hwmgr || !hwmgr->pm_en ||!hwmgr->soft_pp_table)
600 601
		return -EINVAL;

602
	mutex_lock(&hwmgr->smu_lock);
603
	*table = (char *)hwmgr->soft_pp_table;
604
	size = hwmgr->soft_pp_table_size;
605
	mutex_unlock(&hwmgr->smu_lock);
606
	return size;
607 608
}

609 610
static int amd_powerplay_reset(void *handle)
{
611
	struct pp_hwmgr *hwmgr = handle;
612 613
	int ret;

614
	ret = hwmgr_hw_fini(hwmgr);
615 616 617
	if (ret)
		return ret;

618
	ret = hwmgr_hw_init(hwmgr);
619 620 621
	if (ret)
		return ret;

622
	return hwmgr_handle_task(hwmgr, AMD_PP_TASK_COMPLETE_INIT, NULL);
623 624
}

625 626
static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
{
627
	struct pp_hwmgr *hwmgr = handle;
628
	int ret = -ENOMEM;
629

630 631
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
632

633
	mutex_lock(&hwmgr->smu_lock);
634
	if (!hwmgr->hardcode_pp_table) {
635 636 637
		hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table,
						   hwmgr->soft_pp_table_size,
						   GFP_KERNEL);
638 639
		if (!hwmgr->hardcode_pp_table)
			goto err;
640
	}
641

642 643 644 645
	memcpy(hwmgr->hardcode_pp_table, buf, size);

	hwmgr->soft_pp_table = hwmgr->hardcode_pp_table;

646 647
	ret = amd_powerplay_reset(handle);
	if (ret)
648
		goto err;
649 650 651 652

	if (hwmgr->hwmgr_func->avfs_control) {
		ret = hwmgr->hwmgr_func->avfs_control(hwmgr, false);
		if (ret)
653
			goto err;
654
	}
655
	mutex_unlock(&hwmgr->smu_lock);
656
	return 0;
657 658 659
err:
	mutex_unlock(&hwmgr->smu_lock);
	return ret;
660 661 662
}

static int pp_dpm_force_clock_level(void *handle,
663
		enum pp_clock_type type, uint32_t mask)
664
{
665
	struct pp_hwmgr *hwmgr = handle;
666
	int ret = 0;
667

668 669
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
670

671
	if (hwmgr->hwmgr_func->force_clock_level == NULL) {
672
		pr_info("%s was not implemented.\n", __func__);
673 674
		return 0;
	}
675
	mutex_lock(&hwmgr->smu_lock);
676 677 678 679
	if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL)
		ret = hwmgr->hwmgr_func->force_clock_level(hwmgr, type, mask);
	else
		ret = -EINVAL;
680
	mutex_unlock(&hwmgr->smu_lock);
681
	return ret;
682 683 684 685 686
}

static int pp_dpm_print_clock_levels(void *handle,
		enum pp_clock_type type, char *buf)
{
687
	struct pp_hwmgr *hwmgr = handle;
688
	int ret = 0;
689

690 691
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
692

693
	if (hwmgr->hwmgr_func->print_clock_levels == NULL) {
694
		pr_info("%s was not implemented.\n", __func__);
695 696
		return 0;
	}
697
	mutex_lock(&hwmgr->smu_lock);
698
	ret = hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf);
699
	mutex_unlock(&hwmgr->smu_lock);
700
	return ret;
701 702
}

703 704
static int pp_dpm_get_sclk_od(void *handle)
{
705
	struct pp_hwmgr *hwmgr = handle;
706
	int ret = 0;
707

708 709
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
710 711

	if (hwmgr->hwmgr_func->get_sclk_od == NULL) {
712
		pr_info("%s was not implemented.\n", __func__);
713 714
		return 0;
	}
715
	mutex_lock(&hwmgr->smu_lock);
716
	ret = hwmgr->hwmgr_func->get_sclk_od(hwmgr);
717
	mutex_unlock(&hwmgr->smu_lock);
718
	return ret;
719 720 721 722
}

static int pp_dpm_set_sclk_od(void *handle, uint32_t value)
{
723
	struct pp_hwmgr *hwmgr = handle;
724
	int ret = 0;
725

726 727
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
728 729

	if (hwmgr->hwmgr_func->set_sclk_od == NULL) {
730
		pr_info("%s was not implemented.\n", __func__);
731 732 733
		return 0;
	}

734
	mutex_lock(&hwmgr->smu_lock);
735
	ret = hwmgr->hwmgr_func->set_sclk_od(hwmgr, value);
736
	mutex_unlock(&hwmgr->smu_lock);
737
	return ret;
738 739
}

740 741
static int pp_dpm_get_mclk_od(void *handle)
{
742
	struct pp_hwmgr *hwmgr = handle;
743
	int ret = 0;
744

745 746
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
747 748

	if (hwmgr->hwmgr_func->get_mclk_od == NULL) {
749
		pr_info("%s was not implemented.\n", __func__);
750 751
		return 0;
	}
752
	mutex_lock(&hwmgr->smu_lock);
753
	ret = hwmgr->hwmgr_func->get_mclk_od(hwmgr);
754
	mutex_unlock(&hwmgr->smu_lock);
755
	return ret;
756 757 758 759
}

static int pp_dpm_set_mclk_od(void *handle, uint32_t value)
{
760
	struct pp_hwmgr *hwmgr = handle;
761
	int ret = 0;
762

763 764
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
765 766

	if (hwmgr->hwmgr_func->set_mclk_od == NULL) {
767
		pr_info("%s was not implemented.\n", __func__);
768 769
		return 0;
	}
770
	mutex_lock(&hwmgr->smu_lock);
771
	ret = hwmgr->hwmgr_func->set_mclk_od(hwmgr, value);
772
	mutex_unlock(&hwmgr->smu_lock);
773
	return ret;
774 775
}

776 777
static int pp_dpm_read_sensor(void *handle, int idx,
			      void *value, int *size)
778
{
779
	struct pp_hwmgr *hwmgr = handle;
780
	int ret = 0;
781

782
	if (!hwmgr || !hwmgr->pm_en || !value)
783 784 785 786 787 788 789 790
		return -EINVAL;

	switch (idx) {
	case AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK:
		*((uint32_t *)value) = hwmgr->pstate_sclk;
		return 0;
	case AMDGPU_PP_SENSOR_STABLE_PSTATE_MCLK:
		*((uint32_t *)value) = hwmgr->pstate_mclk;
791
		return 0;
792
	default:
793
		mutex_lock(&hwmgr->smu_lock);
794
		ret = hwmgr->hwmgr_func->read_sensor(hwmgr, idx, value, size);
795
		mutex_unlock(&hwmgr->smu_lock);
796
		return ret;
797 798 799
	}
}

800 801 802
static struct amd_vce_state*
pp_dpm_get_vce_clock_state(void *handle, unsigned idx)
{
803
	struct pp_hwmgr *hwmgr = handle;
804

805
	if (!hwmgr || !hwmgr->pm_en)
806 807
		return NULL;

808
	if (idx < hwmgr->num_vce_state_tables)
809
		return &hwmgr->vce_states[idx];
810 811 812
	return NULL;
}

813 814
static int pp_get_power_profile_mode(void *handle, char *buf)
{
815
	struct pp_hwmgr *hwmgr = handle;
816

817
	if (!hwmgr || !hwmgr->pm_en || !buf)
818 819 820 821 822 823 824 825 826 827 828 829
		return -EINVAL;

	if (hwmgr->hwmgr_func->get_power_profile_mode == NULL) {
		pr_info("%s was not implemented.\n", __func__);
		return snprintf(buf, PAGE_SIZE, "\n");
	}

	return hwmgr->hwmgr_func->get_power_profile_mode(hwmgr, buf);
}

static int pp_set_power_profile_mode(void *handle, long *input, uint32_t size)
{
830
	struct pp_hwmgr *hwmgr = handle;
831
	int ret = -EINVAL;
832

833 834
	if (!hwmgr || !hwmgr->pm_en)
		return ret;
835 836 837

	if (hwmgr->hwmgr_func->set_power_profile_mode == NULL) {
		pr_info("%s was not implemented.\n", __func__);
838
		return ret;
839
	}
840
	mutex_lock(&hwmgr->smu_lock);
841 842
	if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL)
		ret = hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, input, size);
843
	mutex_unlock(&hwmgr->smu_lock);
844
	return ret;
845 846
}

847 848
static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint32_t size)
{
849
	struct pp_hwmgr *hwmgr = handle;
850

851
	if (!hwmgr || !hwmgr->pm_en)
852 853 854 855 856 857 858 859 860 861
		return -EINVAL;

	if (hwmgr->hwmgr_func->odn_edit_dpm_table == NULL) {
		pr_info("%s was not implemented.\n", __func__);
		return -EINVAL;
	}

	return hwmgr->hwmgr_func->odn_edit_dpm_table(hwmgr, type, input, size);
}

862
static int pp_dpm_switch_power_profile(void *handle,
863
		enum PP_SMC_POWER_PROFILE type, bool en)
864
{
865
	struct pp_hwmgr *hwmgr = handle;
866 867
	long workload;
	uint32_t index;
868

869
	if (!hwmgr || !hwmgr->pm_en)
870 871
		return -EINVAL;

872 873 874 875 876 877 878 879
	if (hwmgr->hwmgr_func->set_power_profile_mode == NULL) {
		pr_info("%s was not implemented.\n", __func__);
		return -EINVAL;
	}

	if (!(type < PP_SMC_POWER_PROFILE_CUSTOM))
		return -EINVAL;

880
	mutex_lock(&hwmgr->smu_lock);
881 882 883 884 885 886 887 888 889 890 891

	if (!en) {
		hwmgr->workload_mask &= ~(1 << hwmgr->workload_prority[type]);
		index = fls(hwmgr->workload_mask);
		index = index > 0 && index <= Workload_Policy_Max ? index - 1 : 0;
		workload = hwmgr->workload_setting[index];
	} else {
		hwmgr->workload_mask |= (1 << hwmgr->workload_prority[type]);
		index = fls(hwmgr->workload_mask);
		index = index <= Workload_Policy_Max ? index - 1 : 0;
		workload = hwmgr->workload_setting[index];
892 893
	}

894 895
	if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
		hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, &workload, 0);
896
	mutex_unlock(&hwmgr->smu_lock);
897

898 899 900
	return 0;
}

901 902 903 904 905 906 907
static int pp_dpm_notify_smu_memory_info(void *handle,
					uint32_t virtual_addr_low,
					uint32_t virtual_addr_hi,
					uint32_t mc_addr_low,
					uint32_t mc_addr_hi,
					uint32_t size)
{
908
	struct pp_hwmgr *hwmgr = handle;
909 910
	int ret = 0;

911 912
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
913 914 915 916 917 918

	if (hwmgr->hwmgr_func->notify_cac_buffer_info == NULL) {
		pr_info("%s was not implemented.\n", __func__);
		return -EINVAL;
	}

919
	mutex_lock(&hwmgr->smu_lock);
920 921 922 923 924

	ret = hwmgr->hwmgr_func->notify_cac_buffer_info(hwmgr, virtual_addr_low,
					virtual_addr_hi, mc_addr_low, mc_addr_hi,
					size);

925
	mutex_unlock(&hwmgr->smu_lock);
926 927 928 929

	return ret;
}

930 931
static int pp_set_power_limit(void *handle, uint32_t limit)
{
932
	struct pp_hwmgr *hwmgr = handle;
933

934 935
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
936 937 938 939 940 941 942 943 944 945 946 947

	if (hwmgr->hwmgr_func->set_power_limit == NULL) {
		pr_info("%s was not implemented.\n", __func__);
		return -EINVAL;
	}

	if (limit == 0)
		limit = hwmgr->default_power_limit;

	if (limit > hwmgr->default_power_limit)
		return -EINVAL;

948
	mutex_lock(&hwmgr->smu_lock);
949 950
	hwmgr->hwmgr_func->set_power_limit(hwmgr, limit);
	hwmgr->power_limit = limit;
951
	mutex_unlock(&hwmgr->smu_lock);
952
	return 0;
953 954 955 956
}

static int pp_get_power_limit(void *handle, uint32_t *limit, bool default_limit)
{
957
	struct pp_hwmgr *hwmgr = handle;
958

959
	if (!hwmgr || !hwmgr->pm_en ||!limit)
960 961
		return -EINVAL;

962
	mutex_lock(&hwmgr->smu_lock);
963 964 965 966 967 968

	if (default_limit)
		*limit = hwmgr->default_power_limit;
	else
		*limit = hwmgr->power_limit;

969
	mutex_unlock(&hwmgr->smu_lock);
970

971
	return 0;
972 973
}

974
static int pp_display_configuration_change(void *handle,
975
	const struct amd_pp_display_configuration *display_config)
976
{
977
	struct pp_hwmgr *hwmgr = handle;
978

979 980
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
981

982
	mutex_lock(&hwmgr->smu_lock);
983
	phm_store_dal_configuration_data(hwmgr, display_config);
984
	mutex_unlock(&hwmgr->smu_lock);
985 986
	return 0;
}
987

988
static int pp_get_display_power_level(void *handle,
R
Rex Zhu 已提交
989
		struct amd_pp_simple_clock_info *output)
990
{
991
	struct pp_hwmgr *hwmgr = handle;
992
	int ret = 0;
993

994
	if (!hwmgr || !hwmgr->pm_en ||!output)
995
		return -EINVAL;
996

997
	mutex_lock(&hwmgr->smu_lock);
998
	ret = phm_get_dal_power_level(hwmgr, output);
999
	mutex_unlock(&hwmgr->smu_lock);
1000
	return ret;
1001
}
1002

1003
static int pp_get_current_clocks(void *handle,
1004
		struct amd_pp_clock_info *clocks)
1005 1006 1007
{
	struct amd_pp_simple_clock_info simple_clocks;
	struct pp_clock_info hw_clocks;
1008
	struct pp_hwmgr *hwmgr = handle;
1009
	int ret = 0;
1010

1011 1012
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
1013

1014
	mutex_lock(&hwmgr->smu_lock);
1015

1016 1017
	phm_get_dal_power_level(hwmgr, &simple_clocks);

1018 1019 1020 1021 1022 1023 1024 1025
	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
					PHM_PlatformCaps_PowerContainment))
		ret = phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware,
					&hw_clocks, PHM_PerformanceLevelDesignation_PowerContainment);
	else
		ret = phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware,
					&hw_clocks, PHM_PerformanceLevelDesignation_Activity);

1026
	if (ret) {
1027
		pr_info("Error in phm_get_clock_info \n");
1028
		mutex_unlock(&hwmgr->smu_lock);
1029
		return -EINVAL;
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
	}

	clocks->min_engine_clock = hw_clocks.min_eng_clk;
	clocks->max_engine_clock = hw_clocks.max_eng_clk;
	clocks->min_memory_clock = hw_clocks.min_mem_clk;
	clocks->max_memory_clock = hw_clocks.max_mem_clk;
	clocks->min_bus_bandwidth = hw_clocks.min_bus_bandwidth;
	clocks->max_bus_bandwidth = hw_clocks.max_bus_bandwidth;

	clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
	clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;

	clocks->max_clocks_state = simple_clocks.level;

	if (0 == phm_get_current_shallow_sleep_clocks(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks)) {
		clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
		clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
	}
1048
	mutex_unlock(&hwmgr->smu_lock);
1049 1050 1051
	return 0;
}

1052
static int pp_get_clock_by_type(void *handle, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks)
1053
{
1054
	struct pp_hwmgr *hwmgr = handle;
1055
	int ret = 0;
1056

1057 1058
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
1059

1060
	if (clocks == NULL)
1061 1062
		return -EINVAL;

1063
	mutex_lock(&hwmgr->smu_lock);
1064
	ret = phm_get_clock_by_type(hwmgr, type, clocks);
1065
	mutex_unlock(&hwmgr->smu_lock);
1066
	return ret;
1067 1068
}

1069
static int pp_get_clock_by_type_with_latency(void *handle,
1070 1071 1072
		enum amd_pp_clock_type type,
		struct pp_clock_levels_with_latency *clocks)
{
1073
	struct pp_hwmgr *hwmgr = handle;
1074 1075
	int ret = 0;

1076
	if (!hwmgr || !hwmgr->pm_en ||!clocks)
1077 1078
		return -EINVAL;

1079
	mutex_lock(&hwmgr->smu_lock);
1080
	ret = phm_get_clock_by_type_with_latency(hwmgr, type, clocks);
1081
	mutex_unlock(&hwmgr->smu_lock);
1082 1083 1084
	return ret;
}

1085
static int pp_get_clock_by_type_with_voltage(void *handle,
1086 1087 1088
		enum amd_pp_clock_type type,
		struct pp_clock_levels_with_voltage *clocks)
{
1089
	struct pp_hwmgr *hwmgr = handle;
1090 1091
	int ret = 0;

1092
	if (!hwmgr || !hwmgr->pm_en ||!clocks)
1093 1094
		return -EINVAL;

1095
	mutex_lock(&hwmgr->smu_lock);
1096 1097 1098

	ret = phm_get_clock_by_type_with_voltage(hwmgr, type, clocks);

1099
	mutex_unlock(&hwmgr->smu_lock);
1100 1101 1102
	return ret;
}

1103
static int pp_set_watermarks_for_clocks_ranges(void *handle,
1104 1105
		struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges)
{
1106
	struct pp_hwmgr *hwmgr = handle;
1107 1108
	int ret = 0;

1109
	if (!hwmgr || !hwmgr->pm_en ||!wm_with_clock_ranges)
1110 1111
		return -EINVAL;

1112
	mutex_lock(&hwmgr->smu_lock);
1113 1114
	ret = phm_set_watermarks_for_clocks_ranges(hwmgr,
			wm_with_clock_ranges);
1115
	mutex_unlock(&hwmgr->smu_lock);
1116 1117 1118 1119

	return ret;
}

1120
static int pp_display_clock_voltage_request(void *handle,
1121 1122
		struct pp_display_clock_request *clock)
{
1123
	struct pp_hwmgr *hwmgr = handle;
1124 1125
	int ret = 0;

1126
	if (!hwmgr || !hwmgr->pm_en ||!clock)
1127 1128
		return -EINVAL;

1129
	mutex_lock(&hwmgr->smu_lock);
1130
	ret = phm_display_clock_voltage_request(hwmgr, clock);
1131
	mutex_unlock(&hwmgr->smu_lock);
1132 1133 1134 1135

	return ret;
}

1136
static int pp_get_display_mode_validation_clocks(void *handle,
1137
		struct amd_pp_simple_clock_info *clocks)
1138
{
1139
	struct pp_hwmgr *hwmgr = handle;
1140
	int ret = 0;
1141

1142
	if (!hwmgr || !hwmgr->pm_en ||!clocks)
1143
		return -EINVAL;
1144

1145
	mutex_lock(&hwmgr->smu_lock);
1146

1147
	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
1148
		ret = phm_get_max_high_clocks(hwmgr, clocks);
1149

1150
	mutex_unlock(&hwmgr->smu_lock);
1151
	return ret;
1152 1153
}

1154 1155
static int pp_set_mmhub_powergating_by_smu(void *handle)
{
1156
	struct pp_hwmgr *hwmgr = handle;
1157

1158 1159
	if (!hwmgr || !hwmgr->pm_en)
		return -EINVAL;
1160 1161 1162 1163 1164 1165 1166 1167 1168

	if (hwmgr->hwmgr_func->set_mmhub_powergating_by_smu == NULL) {
		pr_info("%s was not implemented.\n", __func__);
		return 0;
	}

	return hwmgr->hwmgr_func->set_mmhub_powergating_by_smu(hwmgr);
}

1169
static const struct amd_pm_funcs pp_dpm_funcs = {
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
	.load_firmware = pp_dpm_load_fw,
	.wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
	.force_performance_level = pp_dpm_force_performance_level,
	.get_performance_level = pp_dpm_get_performance_level,
	.get_current_power_state = pp_dpm_get_current_power_state,
	.powergate_vce = pp_dpm_powergate_vce,
	.powergate_uvd = pp_dpm_powergate_uvd,
	.dispatch_tasks = pp_dpm_dispatch_tasks,
	.set_fan_control_mode = pp_dpm_set_fan_control_mode,
	.get_fan_control_mode = pp_dpm_get_fan_control_mode,
	.set_fan_speed_percent = pp_dpm_set_fan_speed_percent,
	.get_fan_speed_percent = pp_dpm_get_fan_speed_percent,
	.get_fan_speed_rpm = pp_dpm_get_fan_speed_rpm,
	.get_pp_num_states = pp_dpm_get_pp_num_states,
	.get_pp_table = pp_dpm_get_pp_table,
	.set_pp_table = pp_dpm_set_pp_table,
	.force_clock_level = pp_dpm_force_clock_level,
	.print_clock_levels = pp_dpm_print_clock_levels,
	.get_sclk_od = pp_dpm_get_sclk_od,
	.set_sclk_od = pp_dpm_set_sclk_od,
	.get_mclk_od = pp_dpm_get_mclk_od,
	.set_mclk_od = pp_dpm_set_mclk_od,
	.read_sensor = pp_dpm_read_sensor,
	.get_vce_clock_state = pp_dpm_get_vce_clock_state,
	.switch_power_profile = pp_dpm_switch_power_profile,
	.set_clockgating_by_smu = pp_set_clockgating_by_smu,
1196
	.notify_smu_memory_info = pp_dpm_notify_smu_memory_info,
1197 1198
	.get_power_profile_mode = pp_get_power_profile_mode,
	.set_power_profile_mode = pp_set_power_profile_mode,
1199
	.odn_edit_dpm_table = pp_odn_edit_dpm_table,
1200 1201
	.set_power_limit = pp_set_power_limit,
	.get_power_limit = pp_get_power_limit,
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
/* export to DC */
	.get_sclk = pp_dpm_get_sclk,
	.get_mclk = pp_dpm_get_mclk,
	.display_configuration_change = pp_display_configuration_change,
	.get_display_power_level = pp_get_display_power_level,
	.get_current_clocks = pp_get_current_clocks,
	.get_clock_by_type = pp_get_clock_by_type,
	.get_clock_by_type_with_latency = pp_get_clock_by_type_with_latency,
	.get_clock_by_type_with_voltage = pp_get_clock_by_type_with_voltage,
	.set_watermarks_for_clocks_ranges = pp_set_watermarks_for_clocks_ranges,
	.display_clock_voltage_request = pp_display_clock_voltage_request,
	.get_display_mode_validation_clocks = pp_get_display_mode_validation_clocks,
1214
	.set_mmhub_powergating_by_smu = pp_set_mmhub_powergating_by_smu,
1215
};