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 884
static int pp_dpm_read_sensor(void *handle, int idx,
			      void *value, int *size)
885 886
{
	struct pp_hwmgr *hwmgr;
887 888
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
889

890
	ret = pp_check(pp_handle);
891

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

895
	hwmgr = pp_handle->hwmgr;
896 897

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

902
	return hwmgr->hwmgr_func->read_sensor(hwmgr, idx, value, size);
903 904
}

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

912
	ret = pp_check(pp_handle);
913

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

	hwmgr = pp_handle->hwmgr;

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

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

1055
const struct amd_powerplay_funcs pp_dpm_funcs = {
1056
	.get_temperature = pp_dpm_get_temperature,
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
	.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,
1067 1068 1069 1070
	.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,
1071
	.get_fan_speed_rpm = pp_dpm_get_fan_speed_rpm,
1072 1073 1074 1075 1076
	.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,
1077 1078
	.get_sclk_od = pp_dpm_get_sclk_od,
	.set_sclk_od = pp_dpm_set_sclk_od,
1079 1080
	.get_mclk_od = pp_dpm_get_mclk_od,
	.set_mclk_od = pp_dpm_set_mclk_od,
1081
	.read_sensor = pp_dpm_read_sensor,
1082
	.get_vce_clock_state = pp_dpm_get_vce_clock_state,
1083 1084 1085 1086
	.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,
1087 1088
};

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

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

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

1101 1102 1103 1104 1105 1106 1107
	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;
1108

1109 1110 1111
	return 0;
}

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

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

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

1130 1131 1132 1133 1134 1135 1136
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;

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

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

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

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

1152
	eventmgr = instance->eventmgr;
1153

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

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

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

1164 1165
/* export this function to DAL */

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

1173
	ret = pp_check(pp_handle);
1174

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

1178
	hwmgr = pp_handle->hwmgr;
1179

1180
	phm_store_dal_configuration_data(hwmgr, display_config);
1181

1182 1183
	return 0;
}
1184

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

1192
	ret = pp_check(pp_handle);
1193

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

1197
	hwmgr = pp_handle->hwmgr;
1198

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

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

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

1214
	ret = pp_check(pp_handle);
1215

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

1219
	hwmgr = pp_handle->hwmgr;
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 1254
	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;
1255 1256 1257
	struct pp_hwmgr  *hwmgr;
	struct pp_instance *pp_handle = (struct pp_instance *)handle;
	int ret = 0;
1258

1259
	ret = pp_check(pp_handle);
1260

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

	hwmgr = pp_handle->hwmgr;
1265 1266

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

	result = phm_get_clock_by_type(hwmgr, type, clocks);

	return result;
}

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

1281
	ret = pp_check(pp_handle);
1282

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

	hwmgr = pp_handle->hwmgr;
1287 1288


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

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

1295
	return ret;
1296 1297
}