amd_powerplay.c 28.9 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 29
#include "amd_shared.h"
#include "amd_powerplay.h"
30
#include "pp_instance.h"
31 32
#include "power_state.h"
#include "eventmanager.h"
33

34

35
static inline int pp_check(struct pp_instance *handle)
36
{
37 38
	if (handle == NULL || handle->pp_valid != PP_VALID)
		return -EINVAL;
39

40
	if (handle->smu_mgr == NULL || handle->smu_mgr->smumgr_funcs == NULL)
41 42
		return -EINVAL;

43 44
	if (handle->pm_en == 0)
		return PP_DPM_DISABLED;
45

46 47 48
	if (handle->hwmgr == NULL || handle->hwmgr->hwmgr_func == NULL
		|| handle->eventmgr == NULL)
		return PP_DPM_DISABLED;
49

50 51
	return 0;
}
52

53 54 55 56
static int pp_early_init(void *handle)
{
	int ret;
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
57

58
	ret = smum_early_init(pp_handle);
59
	if (ret)
60 61 62 63 64
		return ret;

	if ((pp_handle->pm_en == 0)
		|| cgs_is_virtualization_enabled(pp_handle->device))
		return PP_DPM_DISABLED;
65

66 67 68 69
	ret = hwmgr_early_init(pp_handle);
	if (ret) {
		pp_handle->pm_en = 0;
		return PP_DPM_DISABLED;
70 71
	}

72 73 74 75 76 77 78
	ret = eventmgr_early_init(pp_handle);
	if (ret) {
		kfree(pp_handle->hwmgr);
		pp_handle->hwmgr = NULL;
		pp_handle->pm_en = 0;
		return PP_DPM_DISABLED;
	}
79 80

	return 0;
81 82
}

83
static int pp_sw_init(void *handle)
84
{
85
	struct pp_smumgr *smumgr;
86
	int ret = 0;
87
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
88

89
	ret = pp_check(pp_handle);
90

91 92
	if (ret == 0 || ret == PP_DPM_DISABLED) {
		smumgr = pp_handle->smu_mgr;
93

94 95
		if (smumgr->smumgr_funcs->smu_init == NULL)
			return -EINVAL;
96

97
		ret = smumgr->smumgr_funcs->smu_init(smumgr);
98

99 100 101 102
		pr_info("amdgpu: powerplay sw initialized\n");
	}
	return ret;
}
103

104 105 106 107 108 109 110 111 112
static int pp_sw_fini(void *handle)
{
	struct pp_smumgr *smumgr;
	int ret = 0;
	struct pp_instance *pp_handle = (struct pp_instance *)handle;

	ret = pp_check(pp_handle);
	if (ret == 0 || ret == PP_DPM_DISABLED) {
		smumgr = pp_handle->smu_mgr;
113

114 115 116 117 118
		if (smumgr->smumgr_funcs->smu_fini == NULL)
			return -EINVAL;

		ret = smumgr->smumgr_funcs->smu_fini(smumgr);
	}
119
	return ret;
120 121 122 123
}

static int pp_hw_init(void *handle)
{
124
	struct pp_smumgr *smumgr;
125
	struct pp_eventmgr *eventmgr;
126
	int ret = 0;
127
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
128

129
	ret = pp_check(pp_handle);
130

131 132
	if (ret == 0 || ret == PP_DPM_DISABLED) {
		smumgr = pp_handle->smu_mgr;
133

134 135
		if (smumgr->smumgr_funcs->start_smu == NULL)
			return -EINVAL;
136

137 138 139 140 141 142 143
		if(smumgr->smumgr_funcs->start_smu(smumgr)) {
			pr_err("smc start failed\n");
			smumgr->smumgr_funcs->smu_fini(smumgr);
			return -EINVAL;;
		}
		if (ret == PP_DPM_DISABLED)
			return PP_DPM_DISABLED;
144
	}
145

146 147 148
	ret = hwmgr_hw_init(pp_handle);
	if (ret)
		goto err;
149 150

	eventmgr = pp_handle->eventmgr;
151 152 153
	if (eventmgr->pp_eventmgr_init == NULL ||
		eventmgr->pp_eventmgr_init(eventmgr))
		goto err;
154

155
	return 0;
156 157 158 159 160 161 162
err:
	pp_handle->pm_en = 0;
	kfree(pp_handle->eventmgr);
	kfree(pp_handle->hwmgr);
	pp_handle->hwmgr = NULL;
	pp_handle->eventmgr = NULL;
	return PP_DPM_DISABLED;
163 164 165 166
}

static int pp_hw_fini(void *handle)
{
167
	struct pp_eventmgr *eventmgr;
168 169
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
170

171
	ret = pp_check(pp_handle);
172

173 174
	if (ret == 0) {
		eventmgr = pp_handle->eventmgr;
175

176 177
		if (eventmgr->pp_eventmgr_fini != NULL)
			eventmgr->pp_eventmgr_fini(eventmgr);
178

179 180
		hwmgr_hw_fini(pp_handle);
	}
181 182 183 184 185
	return 0;
}

static bool pp_is_idle(void *handle)
{
186
	return false;
187 188 189 190 191 192 193 194 195 196 197 198 199
}

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

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


200
int amd_set_clockgating_by_smu(void *handle, uint32_t msg_id)
201
{
202
	struct pp_hwmgr  *hwmgr;
203 204
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
205

206
	ret = pp_check(pp_handle);
207

208 209
	if (ret != 0)
		return ret;
210

211
	hwmgr = pp_handle->hwmgr;
212

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

218
	return hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
219 220 221 222 223
}

static int pp_set_powergating_state(void *handle,
				    enum amd_powergating_state state)
{
224
	struct pp_hwmgr  *hwmgr;
225 226
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
227

228
	ret = pp_check(pp_handle);
229

230 231
	if (ret != 0)
		return ret;
232

233
	hwmgr = pp_handle->hwmgr;
234 235

	if (hwmgr->hwmgr_func->enable_per_cu_power_gating == NULL) {
236
		pr_info("%s was not implemented.\n", __func__);
237 238
		return 0;
	}
239 240 241 242

	/* Enable/disable GFX per cu powergating through SMU */
	return hwmgr->hwmgr_func->enable_per_cu_power_gating(hwmgr,
			state == AMD_PG_STATE_GATE ? true : false);
243 244 245 246
}

static int pp_suspend(void *handle)
{
247 248
	struct pp_eventmgr *eventmgr;
	struct pem_event_data event_data = { {0} };
249 250
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
251

252 253 254 255
	ret = pp_check(pp_handle);

	if (ret != 0)
		return ret;
256 257

	eventmgr = pp_handle->eventmgr;
258
	pem_handle_event(eventmgr, AMD_PP_EVENT_SUSPEND, &event_data);
259

260 261 262 263 264
	return 0;
}

static int pp_resume(void *handle)
{
265 266
	struct pp_eventmgr *eventmgr;
	struct pem_event_data event_data = { {0} };
267
	struct pp_smumgr *smumgr;
268 269
	int ret, ret1;
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
270

271 272 273 274
	ret1 = pp_check(pp_handle);

	if (ret1 != 0 && ret1 != PP_DPM_DISABLED)
		return ret1;
275

276 277
	smumgr = pp_handle->smu_mgr;

278
	if (smumgr->smumgr_funcs->start_smu == NULL)
279 280 281 282
		return -EINVAL;

	ret = smumgr->smumgr_funcs->start_smu(smumgr);
	if (ret) {
283
		pr_err("smc start failed\n");
284 285 286 287
		smumgr->smumgr_funcs->smu_fini(smumgr);
		return ret;
	}

288
	if (ret1 == PP_DPM_DISABLED)
M
Monk Liu 已提交
289
		return 0;
290

291
	eventmgr = pp_handle->eventmgr;
292 293

	pem_handle_event(eventmgr, AMD_PP_EVENT_RESUME, &event_data);
294

295 296 297 298
	return 0;
}

const struct amd_ip_funcs pp_ip_funcs = {
299
	.name = "powerplay",
300 301 302 303 304 305 306 307 308 309 310
	.early_init = pp_early_init,
	.late_init = NULL,
	.sw_init = pp_sw_init,
	.sw_fini = pp_sw_fini,
	.hw_init = pp_hw_init,
	.hw_fini = pp_hw_fini,
	.suspend = pp_suspend,
	.resume = pp_resume,
	.is_idle = pp_is_idle,
	.wait_for_idle = pp_wait_for_idle,
	.soft_reset = pp_sw_reset,
311
	.set_clockgating_state = NULL,
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
	.set_powergating_state = pp_set_powergating_state,
};

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

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

static int pp_dpm_force_performance_level(void *handle,
					enum amd_dpm_forced_level level)
{
328
	struct pp_hwmgr  *hwmgr;
329 330
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
331

332
	ret = pp_check(pp_handle);
333

334 335
	if (ret != 0)
		return ret;
336 337 338

	hwmgr = pp_handle->hwmgr;

339
	if (hwmgr->hwmgr_func->force_dpm_level == NULL) {
340
		pr_info("%s was not implemented.\n", __func__);
341 342
		return 0;
	}
343 344 345

	hwmgr->hwmgr_func->force_dpm_level(hwmgr, level);

346 347
	return 0;
}
348

349 350 351
static enum amd_dpm_forced_level pp_dpm_get_performance_level(
								void *handle)
{
352
	struct pp_hwmgr  *hwmgr;
353 354
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
355

356
	ret = pp_check(pp_handle);
357

358 359
	if (ret != 0)
		return ret;
360

361
	hwmgr = pp_handle->hwmgr;
362

363
	return hwmgr->dpm_level;
364
}
365

366 367
static int pp_dpm_get_sclk(void *handle, bool low)
{
368
	struct pp_hwmgr  *hwmgr;
369 370
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
371

372
	ret = pp_check(pp_handle);
373

374 375
	if (ret != 0)
		return ret;
376

377
	hwmgr = pp_handle->hwmgr;
378 379

	if (hwmgr->hwmgr_func->get_sclk == NULL) {
380
		pr_info("%s was not implemented.\n", __func__);
381 382
		return 0;
	}
383 384

	return hwmgr->hwmgr_func->get_sclk(hwmgr, low);
385
}
386

387 388
static int pp_dpm_get_mclk(void *handle, bool low)
{
389
	struct pp_hwmgr  *hwmgr;
390 391
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
392

393
	ret = pp_check(pp_handle);
394

395 396
	if (ret != 0)
		return ret;
397

398
	hwmgr = pp_handle->hwmgr;
399 400

	if (hwmgr->hwmgr_func->get_mclk == NULL) {
401
		pr_info("%s was not implemented.\n", __func__);
402 403
		return 0;
	}
404 405

	return hwmgr->hwmgr_func->get_mclk(hwmgr, low);
406
}
407

408 409
static int pp_dpm_powergate_vce(void *handle, bool gate)
{
410
	struct pp_hwmgr  *hwmgr;
411 412
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
413

414
	ret = pp_check(pp_handle);
415

416 417
	if (ret != 0)
		return ret;
418

419
	hwmgr = pp_handle->hwmgr;
420 421

	if (hwmgr->hwmgr_func->powergate_vce == NULL) {
422
		pr_info("%s was not implemented.\n", __func__);
423 424
		return 0;
	}
425 426

	return hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
427
}
428

429 430
static int pp_dpm_powergate_uvd(void *handle, bool gate)
{
431
	struct pp_hwmgr  *hwmgr;
432 433
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
434

435
	ret = pp_check(pp_handle);
436

437 438
	if (ret != 0)
		return ret;
439

440
	hwmgr = pp_handle->hwmgr;
441 442

	if (hwmgr->hwmgr_func->powergate_uvd == NULL) {
443
		pr_info("%s was not implemented.\n", __func__);
444 445
		return 0;
	}
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461

	return hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate);
}

static enum PP_StateUILabel power_state_convert(enum amd_pm_state_type  state)
{
	switch (state) {
	case POWER_STATE_TYPE_BATTERY:
		return PP_StateUILabel_Battery;
	case POWER_STATE_TYPE_BALANCED:
		return PP_StateUILabel_Balanced;
	case POWER_STATE_TYPE_PERFORMANCE:
		return PP_StateUILabel_Performance;
	default:
		return PP_StateUILabel_None;
	}
462 463
}

464 465
static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_event event_id,
		void *input, void *output)
466
{
467 468
	int ret = 0;
	struct pem_event_data data = { {0} };
469
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
470

471
	ret = pp_check(pp_handle);
472

473 474
	if (ret != 0)
		return ret;
475

476 477 478 479 480 481 482 483 484 485 486 487 488 489
	switch (event_id) {
	case AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE:
		ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
		break;
	case AMD_PP_EVENT_ENABLE_USER_STATE:
	{
		enum amd_pm_state_type  ps;

		if (input == NULL)
			return -EINVAL;
		ps = *(unsigned long *)input;

		data.requested_ui_label = power_state_convert(ps);
		ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
490
		break;
491
	}
492 493 494
	case AMD_PP_EVENT_COMPLETE_INIT:
		ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
		break;
495 496 497
	case AMD_PP_EVENT_READJUST_POWER_STATE:
		ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
		break;
498 499 500 501
	default:
		break;
	}
	return ret;
502
}
503

504
static enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
505
{
506 507
	struct pp_hwmgr *hwmgr;
	struct pp_power_state *state;
508 509
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
510

511
	ret = pp_check(pp_handle);
512

513 514
	if (ret != 0)
		return ret;
515

516 517 518
	hwmgr = pp_handle->hwmgr;

	if (hwmgr->current_ps == NULL)
519 520 521 522 523 524 525 526 527 528 529 530
		return -EINVAL;

	state = hwmgr->current_ps;

	switch (state->classification.ui_label) {
	case PP_StateUILabel_Battery:
		return POWER_STATE_TYPE_BATTERY;
	case PP_StateUILabel_Balanced:
		return POWER_STATE_TYPE_BALANCED;
	case PP_StateUILabel_Performance:
		return POWER_STATE_TYPE_PERFORMANCE;
	default:
531 532 533 534
		if (state->classification.flags & PP_StateClassificationFlag_Boot)
			return  POWER_STATE_TYPE_INTERNAL_BOOT;
		else
			return POWER_STATE_TYPE_DEFAULT;
535
	}
536
}
537

538 539 540
static int pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
{
	struct pp_hwmgr  *hwmgr;
541 542
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
543

544
	ret = pp_check(pp_handle);
545

546 547
	if (ret != 0)
		return ret;
548

549
	hwmgr = pp_handle->hwmgr;
550 551

	if (hwmgr->hwmgr_func->set_fan_control_mode == NULL) {
552
		pr_info("%s was not implemented.\n", __func__);
553 554
		return 0;
	}
555 556 557 558 559 560 561

	return hwmgr->hwmgr_func->set_fan_control_mode(hwmgr, mode);
}

static int pp_dpm_get_fan_control_mode(void *handle)
{
	struct pp_hwmgr  *hwmgr;
562 563
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
564

565
	ret = pp_check(pp_handle);
566

567 568
	if (ret != 0)
		return ret;
569

570
	hwmgr = pp_handle->hwmgr;
571 572

	if (hwmgr->hwmgr_func->get_fan_control_mode == NULL) {
573
		pr_info("%s was not implemented.\n", __func__);
574 575
		return 0;
	}
576 577 578 579 580 581 582

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

static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent)
{
	struct pp_hwmgr  *hwmgr;
583 584
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
585

586
	ret = pp_check(pp_handle);
587

588 589
	if (ret != 0)
		return ret;
590

591
	hwmgr = pp_handle->hwmgr;
592 593

	if (hwmgr->hwmgr_func->set_fan_speed_percent == NULL) {
594
		pr_info("%s was not implemented.\n", __func__);
595 596
		return 0;
	}
597 598 599 600 601 602 603

	return hwmgr->hwmgr_func->set_fan_speed_percent(hwmgr, percent);
}

static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed)
{
	struct pp_hwmgr  *hwmgr;
604 605
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
606

607
	ret = pp_check(pp_handle);
608

609 610
	if (ret != 0)
		return ret;
611

612
	hwmgr = pp_handle->hwmgr;
613 614

	if (hwmgr->hwmgr_func->get_fan_speed_percent == NULL) {
615
		pr_info("%s was not implemented.\n", __func__);
616 617
		return 0;
	}
618 619 620 621

	return hwmgr->hwmgr_func->get_fan_speed_percent(hwmgr, speed);
}

622 623 624
static int pp_dpm_get_fan_speed_rpm(void *handle, uint32_t *rpm)
{
	struct pp_hwmgr *hwmgr;
625 626
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
627

628
	ret = pp_check(pp_handle);
629

630 631
	if (ret != 0)
		return ret;
632

633
	hwmgr = pp_handle->hwmgr;
634 635 636 637 638 639 640

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

	return hwmgr->hwmgr_func->get_fan_speed_rpm(hwmgr, rpm);
}

641 642 643
static int pp_dpm_get_temperature(void *handle)
{
	struct pp_hwmgr  *hwmgr;
644 645
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
646

647
	ret = pp_check(pp_handle);
648

649 650
	if (ret != 0)
		return ret;
651

652
	hwmgr = pp_handle->hwmgr;
653 654

	if (hwmgr->hwmgr_func->get_temperature == NULL) {
655
		pr_info("%s was not implemented.\n", __func__);
656 657
		return 0;
	}
658 659 660

	return hwmgr->hwmgr_func->get_temperature(hwmgr);
}
661

662 663 664 665 666
static int pp_dpm_get_pp_num_states(void *handle,
		struct pp_states_info *data)
{
	struct pp_hwmgr *hwmgr;
	int i;
667 668
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
669

670
	ret = pp_check(pp_handle);
671

672 673 674 675
	if (ret != 0)
		return ret;

	hwmgr = pp_handle->hwmgr;
676

677
	if (hwmgr->ps == NULL)
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
		return -EINVAL;

	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;
		}
	}

	return 0;
}

static int pp_dpm_get_pp_table(void *handle, char **table)
{
	struct pp_hwmgr *hwmgr;
709 710
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
711

712
	ret = pp_check(pp_handle);
713

714 715
	if (ret != 0)
		return ret;
716

717
	hwmgr = pp_handle->hwmgr;
718

719 720 721 722
	if (!hwmgr->soft_pp_table)
		return -EINVAL;

	*table = (char *)hwmgr->soft_pp_table;
723

724
	return hwmgr->soft_pp_table_size;
725 726 727 728 729
}

static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
{
	struct pp_hwmgr *hwmgr;
730 731
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
732

733
	ret = pp_check(pp_handle);
734

735 736
	if (ret != 0)
		return ret;
737

738
	hwmgr = pp_handle->hwmgr;
739

740
	if (!hwmgr->hardcode_pp_table) {
741 742 743
		hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table,
						   hwmgr->soft_pp_table_size,
						   GFP_KERNEL);
744 745 746

		if (!hwmgr->hardcode_pp_table)
			return -ENOMEM;
747
	}
748

749 750 751 752 753
	memcpy(hwmgr->hardcode_pp_table, buf, size);

	hwmgr->soft_pp_table = hwmgr->hardcode_pp_table;

	return amd_powerplay_reset(handle);
754 755 756
}

static int pp_dpm_force_clock_level(void *handle,
757
		enum pp_clock_type type, uint32_t mask)
758 759
{
	struct pp_hwmgr *hwmgr;
760 761
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
762

763
	ret = pp_check(pp_handle);
764

765 766
	if (ret != 0)
		return ret;
767

768
	hwmgr = pp_handle->hwmgr;
769 770

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

775
	return hwmgr->hwmgr_func->force_clock_level(hwmgr, type, mask);
776 777 778 779 780 781
}

static int pp_dpm_print_clock_levels(void *handle,
		enum pp_clock_type type, char *buf)
{
	struct pp_hwmgr *hwmgr;
782 783
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
784

785
	ret = pp_check(pp_handle);
786

787 788
	if (ret != 0)
		return ret;
789

790
	hwmgr = pp_handle->hwmgr;
791

792
	if (hwmgr->hwmgr_func->print_clock_levels == NULL) {
793
		pr_info("%s was not implemented.\n", __func__);
794 795
		return 0;
	}
796 797 798
	return hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf);
}

799 800 801
static int pp_dpm_get_sclk_od(void *handle)
{
	struct pp_hwmgr *hwmgr;
802 803
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
804

805
	ret = pp_check(pp_handle);
806

807 808
	if (ret != 0)
		return ret;
809

810
	hwmgr = pp_handle->hwmgr;
811 812

	if (hwmgr->hwmgr_func->get_sclk_od == NULL) {
813
		pr_info("%s was not implemented.\n", __func__);
814 815 816 817 818 819 820 821 822
		return 0;
	}

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

static int pp_dpm_set_sclk_od(void *handle, uint32_t value)
{
	struct pp_hwmgr *hwmgr;
823 824
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
825

826
	ret = pp_check(pp_handle);
827

828 829
	if (ret != 0)
		return ret;
830

831
	hwmgr = pp_handle->hwmgr;
832 833

	if (hwmgr->hwmgr_func->set_sclk_od == NULL) {
834
		pr_info("%s was not implemented.\n", __func__);
835 836 837 838 839 840
		return 0;
	}

	return hwmgr->hwmgr_func->set_sclk_od(hwmgr, value);
}

841 842 843
static int pp_dpm_get_mclk_od(void *handle)
{
	struct pp_hwmgr *hwmgr;
844 845
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
846

847
	ret = pp_check(pp_handle);
848

849 850
	if (ret != 0)
		return ret;
851

852
	hwmgr = pp_handle->hwmgr;
853 854

	if (hwmgr->hwmgr_func->get_mclk_od == NULL) {
855
		pr_info("%s was not implemented.\n", __func__);
856 857 858 859 860 861 862 863 864
		return 0;
	}

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

static int pp_dpm_set_mclk_od(void *handle, uint32_t value)
{
	struct pp_hwmgr *hwmgr;
865 866
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
867

868
	ret = pp_check(pp_handle);
869

870 871
	if (ret != 0)
		return ret;
872

873
	hwmgr = pp_handle->hwmgr;
874 875

	if (hwmgr->hwmgr_func->set_mclk_od == NULL) {
876
		pr_info("%s was not implemented.\n", __func__);
877 878 879 880 881 882
		return 0;
	}

	return hwmgr->hwmgr_func->set_mclk_od(hwmgr, value);
}

883
static int pp_dpm_read_sensor(void *handle, int idx, void *value)
884 885
{
	struct pp_hwmgr *hwmgr;
886 887
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
888

889
	ret = pp_check(pp_handle);
890

891 892
	if (ret != 0)
		return ret;
893

894
	hwmgr = pp_handle->hwmgr;
895 896

	if (hwmgr->hwmgr_func->read_sensor == NULL) {
897
		pr_info("%s was not implemented.\n", __func__);
898 899 900 901 902 903
		return 0;
	}

	return hwmgr->hwmgr_func->read_sensor(hwmgr, idx, value);
}

904 905 906 907
static struct amd_vce_state*
pp_dpm_get_vce_clock_state(void *handle, unsigned idx)
{
	struct pp_hwmgr *hwmgr;
908 909
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
910

911
	ret = pp_check(pp_handle);
912

913 914 915 916 917 918 919
	if (ret != 0)
		return NULL;

	hwmgr = pp_handle->hwmgr;

	if (hwmgr && idx < hwmgr->num_vce_state_tables)
		return &hwmgr->vce_states[idx];
920 921 922
	return NULL;
}

923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
static int pp_dpm_reset_power_profile_state(void *handle,
		struct amd_pp_profile *request)
{
	struct pp_hwmgr *hwmgr;
	struct pp_instance *pp_handle = (struct pp_instance *)handle;

	if (!request || pp_check(pp_handle))
		return -EINVAL;

	hwmgr = pp_handle->hwmgr;

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

	if (request->type == AMD_PP_GFX_PROFILE) {
		hwmgr->gfx_power_profile = hwmgr->default_gfx_power_profile;
		return hwmgr->hwmgr_func->set_power_profile_state(hwmgr,
				&hwmgr->gfx_power_profile);
	} else if (request->type == AMD_PP_COMPUTE_PROFILE) {
		hwmgr->compute_power_profile =
				hwmgr->default_compute_power_profile;
		return hwmgr->hwmgr_func->set_power_profile_state(hwmgr,
				&hwmgr->compute_power_profile);
	} else
		return -EINVAL;
}

static int pp_dpm_get_power_profile_state(void *handle,
		struct amd_pp_profile *query)
{
	struct pp_hwmgr *hwmgr;
	struct pp_instance *pp_handle = (struct pp_instance *)handle;

	if (!query || pp_check(pp_handle))
		return -EINVAL;

	hwmgr = pp_handle->hwmgr;

	if (query->type == AMD_PP_GFX_PROFILE)
		memcpy(query, &hwmgr->gfx_power_profile,
				sizeof(struct amd_pp_profile));
	else if (query->type == AMD_PP_COMPUTE_PROFILE)
		memcpy(query, &hwmgr->compute_power_profile,
				sizeof(struct amd_pp_profile));
	else
		return -EINVAL;

	return 0;
}

static int pp_dpm_set_power_profile_state(void *handle,
		struct amd_pp_profile *request)
{
	struct pp_hwmgr *hwmgr;
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = -1;

	if (!request || pp_check(pp_handle))
		return -EINVAL;

	hwmgr = pp_handle->hwmgr;

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

	if (request->min_sclk ||
		request->min_mclk ||
		request->activity_threshold ||
		request->up_hyst ||
		request->down_hyst) {
		if (request->type == AMD_PP_GFX_PROFILE)
			memcpy(&hwmgr->gfx_power_profile, request,
					sizeof(struct amd_pp_profile));
		else if (request->type == AMD_PP_COMPUTE_PROFILE)
			memcpy(&hwmgr->compute_power_profile, request,
					sizeof(struct amd_pp_profile));
		else
			return -EINVAL;

		if (request->type == hwmgr->current_power_profile)
			ret = hwmgr->hwmgr_func->set_power_profile_state(
					hwmgr,
					request);
	} else {
		/* set power profile if it exists */
		switch (request->type) {
		case AMD_PP_GFX_PROFILE:
			ret = hwmgr->hwmgr_func->set_power_profile_state(
					hwmgr,
					&hwmgr->gfx_power_profile);
			break;
		case AMD_PP_COMPUTE_PROFILE:
			ret = hwmgr->hwmgr_func->set_power_profile_state(
					hwmgr,
					&hwmgr->compute_power_profile);
			break;
		default:
			return -EINVAL;
		}
	}

	if (!ret)
		hwmgr->current_power_profile = request->type;

	return 0;
}

static int pp_dpm_switch_power_profile(void *handle,
		enum amd_pp_profile_type type)
{
	struct pp_hwmgr *hwmgr;
	struct amd_pp_profile request = {0};
	struct pp_instance *pp_handle = (struct pp_instance *)handle;

	if (pp_check(pp_handle))
		return -EINVAL;

	hwmgr = pp_handle->hwmgr;

	if (hwmgr->current_power_profile != type) {
		request.type = type;
		pp_dpm_set_power_profile_state(handle, &request);
	}

	return 0;
}

1054
const struct amd_powerplay_funcs pp_dpm_funcs = {
1055
	.get_temperature = pp_dpm_get_temperature,
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
	.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,
	.get_sclk = pp_dpm_get_sclk,
	.get_mclk = pp_dpm_get_mclk,
	.powergate_vce = pp_dpm_powergate_vce,
	.powergate_uvd = pp_dpm_powergate_uvd,
	.dispatch_tasks = pp_dpm_dispatch_tasks,
1066 1067 1068 1069
	.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,
1070
	.get_fan_speed_rpm = pp_dpm_get_fan_speed_rpm,
1071 1072 1073 1074 1075
	.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,
1076 1077
	.get_sclk_od = pp_dpm_get_sclk_od,
	.set_sclk_od = pp_dpm_set_sclk_od,
1078 1079
	.get_mclk_od = pp_dpm_get_mclk_od,
	.set_mclk_od = pp_dpm_set_mclk_od,
1080
	.read_sensor = pp_dpm_read_sensor,
1081
	.get_vce_clock_state = pp_dpm_get_vce_clock_state,
1082 1083 1084 1085
	.reset_power_profile_state = pp_dpm_reset_power_profile_state,
	.get_power_profile_state = pp_dpm_get_power_profile_state,
	.set_power_profile_state = pp_dpm_set_power_profile_state,
	.switch_power_profile = pp_dpm_switch_power_profile,
1086 1087
};

1088 1089
int amd_powerplay_create(struct amd_pp_init *pp_init,
				void **handle)
1090
{
1091
	struct pp_instance *instance;
1092

1093 1094
	if (pp_init == NULL || handle == NULL)
		return -EINVAL;
1095

1096 1097 1098
	instance = kzalloc(sizeof(struct pp_instance), GFP_KERNEL);
	if (instance == NULL)
		return -ENOMEM;
1099

1100 1101 1102 1103 1104 1105 1106
	instance->pp_valid = PP_VALID;
	instance->chip_family = pp_init->chip_family;
	instance->chip_id = pp_init->chip_id;
	instance->pm_en = pp_init->pm_en;
	instance->feature_mask = pp_init->feature_mask;
	instance->device = pp_init->device;
	*handle = instance;
1107

1108 1109 1110
	return 0;
}

1111
int amd_powerplay_destroy(void *handle)
1112 1113
{
	struct pp_instance *instance = (struct pp_instance *)handle;
1114

1115 1116 1117 1118 1119
	if (instance->pm_en) {
		kfree(instance->eventmgr);
		kfree(instance->hwmgr);
		instance->hwmgr = NULL;
		instance->eventmgr = NULL;
1120
	}
1121

1122 1123 1124 1125
	kfree(instance->smu_mgr);
	instance->smu_mgr = NULL;
	kfree(instance);
	instance = NULL;
1126 1127
	return 0;
}
1128

1129 1130 1131 1132 1133 1134 1135
int amd_powerplay_reset(void *handle)
{
	struct pp_instance *instance = (struct pp_instance *)handle;
	struct pp_eventmgr *eventmgr;
	struct pem_event_data event_data = { {0} };
	int ret;

1136 1137
	if (cgs_is_virtualization_enabled(instance->smu_mgr->device))
		return PP_DPM_DISABLED;
1138

1139 1140
	ret = pp_check(instance);
	if (ret != 0)
1141 1142
		return ret;

1143
	ret = pp_hw_fini(handle);
1144 1145 1146
	if (ret)
		return ret;

1147 1148 1149
	ret = hwmgr_hw_init(instance);
	if (ret)
		return PP_DPM_DISABLED;
1150

1151
	eventmgr = instance->eventmgr;
1152

1153 1154
	if (eventmgr->pp_eventmgr_init == NULL)
		return PP_DPM_DISABLED;
1155 1156 1157 1158 1159 1160 1161 1162

	ret = eventmgr->pp_eventmgr_init(eventmgr);
	if (ret)
		return ret;

	return pem_handle_event(eventmgr, AMD_PP_EVENT_COMPLETE_INIT, &event_data);
}

1163 1164
/* export this function to DAL */

1165 1166
int amd_powerplay_display_configuration_change(void *handle,
	const struct amd_pp_display_configuration *display_config)
1167 1168
{
	struct pp_hwmgr  *hwmgr;
1169 1170
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
1171

1172
	ret = pp_check(pp_handle);
1173

1174 1175
	if (ret != 0)
		return ret;
1176

1177
	hwmgr = pp_handle->hwmgr;
1178

1179
	phm_store_dal_configuration_data(hwmgr, display_config);
1180

1181 1182
	return 0;
}
1183

1184
int amd_powerplay_get_display_power_level(void *handle,
R
Rex Zhu 已提交
1185
		struct amd_pp_simple_clock_info *output)
1186 1187
{
	struct pp_hwmgr  *hwmgr;
1188 1189
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
1190

1191
	ret = pp_check(pp_handle);
1192

1193 1194
	if (ret != 0)
		return ret;
1195

1196
	hwmgr = pp_handle->hwmgr;
1197

1198 1199
	if (output == NULL)
		return -EINVAL;
1200

1201
	return phm_get_dal_power_level(hwmgr, output);
1202
}
1203 1204

int amd_powerplay_get_current_clocks(void *handle,
1205
		struct amd_pp_clock_info *clocks)
1206 1207 1208
{
	struct amd_pp_simple_clock_info simple_clocks;
	struct pp_clock_info hw_clocks;
1209 1210 1211
	struct pp_hwmgr  *hwmgr;
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
1212

1213
	ret = pp_check(pp_handle);
1214

1215 1216
	if (ret != 0)
		return ret;
1217

1218
	hwmgr = pp_handle->hwmgr;
1219

1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
	phm_get_dal_power_level(hwmgr, &simple_clocks);

	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PowerContainment)) {
		if (0 != phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks, PHM_PerformanceLevelDesignation_PowerContainment))
			PP_ASSERT_WITH_CODE(0, "Error in PHM_GetPowerContainmentClockInfo", return -1);
	} else {
		if (0 != phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks, PHM_PerformanceLevelDesignation_Activity))
			PP_ASSERT_WITH_CODE(0, "Error in PHM_GetClockInfo", return -1);
	}

	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;
	}

	return 0;

}

int amd_powerplay_get_clock_by_type(void *handle, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks)
{
	int result = -1;
1254 1255 1256
	struct pp_hwmgr  *hwmgr;
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
1257

1258
	ret = pp_check(pp_handle);
1259

1260 1261 1262 1263
	if (ret != 0)
		return ret;

	hwmgr = pp_handle->hwmgr;
1264 1265

	if (clocks == NULL)
1266 1267 1268 1269 1270 1271 1272
		return -EINVAL;

	result = phm_get_clock_by_type(hwmgr, type, clocks);

	return result;
}

1273 1274
int amd_powerplay_get_display_mode_validation_clocks(void *handle,
		struct amd_pp_simple_clock_info *clocks)
1275 1276
{
	struct pp_hwmgr  *hwmgr;
1277 1278
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
1279

1280
	ret = pp_check(pp_handle);
1281

1282 1283 1284 1285
	if (ret != 0)
		return ret;

	hwmgr = pp_handle->hwmgr;
1286 1287


1288 1289
	if (clocks == NULL)
		return -EINVAL;
1290

1291
	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
1292
		ret = phm_get_max_high_clocks(hwmgr, clocks);
1293

1294
	return ret;
1295 1296
}