amd_powerplay.c 24.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 23 24 25
/*
 * Copyright 2015 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 */
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/gfp.h>
26
#include <linux/slab.h>
27 28
#include "amd_shared.h"
#include "amd_powerplay.h"
29
#include "pp_instance.h"
30 31
#include "power_state.h"
#include "eventmanager.h"
32
#include "pp_debug.h"
33

34

35 36 37 38 39 40
#define PP_CHECK(handle)						\
	do {								\
		if ((handle) == NULL || (handle)->pp_valid != PP_VALID)	\
			return -EINVAL;					\
	} while (0)

41 42 43
#define PP_CHECK_HW(hwmgr)						\
	do {								\
		if ((hwmgr) == NULL || (hwmgr)->hwmgr_func == NULL)	\
44
			return 0;					\
45 46
	} while (0)

47 48 49 50 51 52 53
static int pp_early_init(void *handle)
{
	return 0;
}

static int pp_sw_init(void *handle)
{
54 55 56 57 58 59 60 61 62 63
	struct pp_instance *pp_handle;
	struct pp_hwmgr  *hwmgr;
	int ret = 0;

	if (handle == NULL)
		return -EINVAL;

	pp_handle = (struct pp_instance *)handle;
	hwmgr = pp_handle->hwmgr;

64 65 66
	PP_CHECK_HW(hwmgr);

	if (hwmgr->pptable_func == NULL ||
67 68 69 70 71
	    hwmgr->pptable_func->pptable_init == NULL ||
	    hwmgr->hwmgr_func->backend_init == NULL)
		return -EINVAL;

	ret = hwmgr->pptable_func->pptable_init(hwmgr);
72 73
	if (ret)
		goto err;
74

75
	ret = hwmgr->hwmgr_func->backend_init(hwmgr);
76
	if (ret)
77
		goto err1;
78

79 80 81
	pr_info("amdgpu: powerplay initialized\n");

	return 0;
82 83 84
err1:
	if (hwmgr->pptable_func->pptable_fini)
		hwmgr->pptable_func->pptable_fini(hwmgr);
85 86
err:
	pr_err("amdgpu: powerplay initialization failed\n");
87
	return ret;
88 89 90 91
}

static int pp_sw_fini(void *handle)
{
92 93 94 95 96 97 98 99 100 101
	struct pp_instance *pp_handle;
	struct pp_hwmgr  *hwmgr;
	int ret = 0;

	if (handle == NULL)
		return -EINVAL;

	pp_handle = (struct pp_instance *)handle;
	hwmgr = pp_handle->hwmgr;

102 103 104
	PP_CHECK_HW(hwmgr);

	if (hwmgr->hwmgr_func->backend_fini != NULL)
105 106
		ret = hwmgr->hwmgr_func->backend_fini(hwmgr);

107 108 109
	if (hwmgr->pptable_func->pptable_fini)
		hwmgr->pptable_func->pptable_fini(hwmgr);

110
	return ret;
111 112 113 114
}

static int pp_hw_init(void *handle)
{
115 116
	struct pp_instance *pp_handle;
	struct pp_smumgr *smumgr;
117
	struct pp_eventmgr *eventmgr;
118
	struct pp_hwmgr  *hwmgr;
119 120 121 122 123 124 125
	int ret = 0;

	if (handle == NULL)
		return -EINVAL;

	pp_handle = (struct pp_instance *)handle;
	smumgr = pp_handle->smu_mgr;
126
	hwmgr = pp_handle->hwmgr;
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

	if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
		smumgr->smumgr_funcs->smu_init == NULL ||
		smumgr->smumgr_funcs->start_smu == NULL)
		return -EINVAL;

	ret = smumgr->smumgr_funcs->smu_init(smumgr);
	if (ret) {
		printk(KERN_ERR "[ powerplay ] smc initialization failed\n");
		return ret;
	}

	ret = smumgr->smumgr_funcs->start_smu(smumgr);
	if (ret) {
		printk(KERN_ERR "[ powerplay ] smc start failed\n");
		smumgr->smumgr_funcs->smu_fini(smumgr);
		return ret;
	}
145

146
	PP_CHECK_HW(hwmgr);
147

148 149 150
	hw_init_power_state_table(hwmgr);

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

	ret = eventmgr->pp_eventmgr_init(eventmgr);
155 156 157 158 159
	return 0;
}

static int pp_hw_fini(void *handle)
{
160 161
	struct pp_instance *pp_handle;
	struct pp_smumgr *smumgr;
162
	struct pp_eventmgr *eventmgr;
163 164 165 166 167

	if (handle == NULL)
		return -EINVAL;

	pp_handle = (struct pp_instance *)handle;
168 169
	eventmgr = pp_handle->eventmgr;

170
	if (eventmgr != NULL && eventmgr->pp_eventmgr_fini != NULL)
171 172
		eventmgr->pp_eventmgr_fini(eventmgr);

173 174
	smumgr = pp_handle->smu_mgr;

175
	if (smumgr != NULL && smumgr->smumgr_funcs != NULL &&
176 177 178
		smumgr->smumgr_funcs->smu_fini != NULL)
		smumgr->smumgr_funcs->smu_fini(smumgr);

179 180 181 182 183
	return 0;
}

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

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

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


198
int amd_set_clockgating_by_smu(void *handle, uint32_t msg_id)
199
{
200 201 202 203 204 205 206
	struct pp_hwmgr  *hwmgr;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

207
	PP_CHECK_HW(hwmgr);
208

209 210
	if (hwmgr->hwmgr_func->update_clock_gatings == NULL) {
		printk(KERN_INFO "%s was not implemented.\n", __func__);
211
		return 0;
212
	}
213

214
	return hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
215 216 217 218 219
}

static int pp_set_powergating_state(void *handle,
				    enum amd_powergating_state state)
{
220 221 222 223 224 225 226
	struct pp_hwmgr  *hwmgr;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

227 228 229 230 231 232
	PP_CHECK_HW(hwmgr);

	if (hwmgr->hwmgr_func->enable_per_cu_power_gating == NULL) {
		printk(KERN_INFO "%s was not implemented.\n", __func__);
		return 0;
	}
233 234 235 236

	/* 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);
237 238 239 240
}

static int pp_suspend(void *handle)
{
241 242 243 244 245 246 247 248 249
	struct pp_instance *pp_handle;
	struct pp_eventmgr *eventmgr;
	struct pem_event_data event_data = { {0} };

	if (handle == NULL)
		return -EINVAL;

	pp_handle = (struct pp_instance *)handle;
	eventmgr = pp_handle->eventmgr;
250 251 252

	if (eventmgr != NULL)
		pem_handle_event(eventmgr, AMD_PP_EVENT_SUSPEND, &event_data);
253 254 255 256 257
	return 0;
}

static int pp_resume(void *handle)
{
258 259 260
	struct pp_instance *pp_handle;
	struct pp_eventmgr *eventmgr;
	struct pem_event_data event_data = { {0} };
261 262
	struct pp_smumgr *smumgr;
	int ret;
263 264 265 266 267

	if (handle == NULL)
		return -EINVAL;

	pp_handle = (struct pp_instance *)handle;
268 269 270 271 272 273 274 275 276 277 278 279 280
	smumgr = pp_handle->smu_mgr;

	if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
		smumgr->smumgr_funcs->start_smu == NULL)
		return -EINVAL;

	ret = smumgr->smumgr_funcs->start_smu(smumgr);
	if (ret) {
		printk(KERN_ERR "[ powerplay ] smc start failed\n");
		smumgr->smumgr_funcs->smu_fini(smumgr);
		return ret;
	}

281
	eventmgr = pp_handle->eventmgr;
282 283
	if (eventmgr != NULL)
		pem_handle_event(eventmgr, AMD_PP_EVENT_RESUME, &event_data);
284

285 286 287 288
	return 0;
}

const struct amd_ip_funcs pp_ip_funcs = {
289
	.name = "powerplay",
290 291 292 293 294 295 296 297 298 299 300
	.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,
301
	.set_clockgating_state = NULL,
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
	.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)
{
318 319 320 321 322 323 324 325 326 327
	struct pp_instance *pp_handle;
	struct pp_hwmgr  *hwmgr;

	if (handle == NULL)
		return -EINVAL;

	pp_handle = (struct pp_instance *)handle;

	hwmgr = pp_handle->hwmgr;

328 329 330 331 332 333
	PP_CHECK_HW(hwmgr);

	if (hwmgr->hwmgr_func->force_dpm_level == NULL) {
		printk(KERN_INFO "%s was not implemented.\n", __func__);
		return 0;
	}
334 335 336

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

337 338
	return 0;
}
339

340 341 342
static enum amd_dpm_forced_level pp_dpm_get_performance_level(
								void *handle)
{
343 344 345 346 347 348 349
	struct pp_hwmgr  *hwmgr;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

350
	PP_CHECK_HW(hwmgr);
351 352

	return (((struct pp_instance *)handle)->hwmgr->dpm_level);
353
}
354

355 356
static int pp_dpm_get_sclk(void *handle, bool low)
{
357 358 359 360 361 362 363
	struct pp_hwmgr  *hwmgr;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

364 365 366 367 368 369
	PP_CHECK_HW(hwmgr);

	if (hwmgr->hwmgr_func->get_sclk == NULL) {
		printk(KERN_INFO "%s was not implemented.\n", __func__);
		return 0;
	}
370 371

	return hwmgr->hwmgr_func->get_sclk(hwmgr, low);
372
}
373

374 375
static int pp_dpm_get_mclk(void *handle, bool low)
{
376 377 378 379 380 381 382
	struct pp_hwmgr  *hwmgr;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

383 384 385 386 387 388
	PP_CHECK_HW(hwmgr);

	if (hwmgr->hwmgr_func->get_mclk == NULL) {
		printk(KERN_INFO "%s was not implemented.\n", __func__);
		return 0;
	}
389 390

	return hwmgr->hwmgr_func->get_mclk(hwmgr, low);
391
}
392

393 394
static int pp_dpm_powergate_vce(void *handle, bool gate)
{
395 396 397 398 399 400 401
	struct pp_hwmgr  *hwmgr;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

402 403 404 405 406 407
	PP_CHECK_HW(hwmgr);

	if (hwmgr->hwmgr_func->powergate_vce == NULL) {
		printk(KERN_INFO "%s was not implemented.\n", __func__);
		return 0;
	}
408 409

	return hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
410
}
411

412 413
static int pp_dpm_powergate_uvd(void *handle, bool gate)
{
414 415 416 417 418 419 420
	struct pp_hwmgr  *hwmgr;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

421 422 423 424 425 426
	PP_CHECK_HW(hwmgr);

	if (hwmgr->hwmgr_func->powergate_uvd == NULL) {
		printk(KERN_INFO "%s was not implemented.\n", __func__);
		return 0;
	}
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442

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

445 446
static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_event event_id,
		void *input, void *output)
447
{
448 449 450 451 452 453 454 455 456
	int ret = 0;
	struct pp_instance *pp_handle;
	struct pem_event_data data = { {0} };

	pp_handle = (struct pp_instance *)handle;

	if (pp_handle == NULL)
		return -EINVAL;

457 458 459
	if (pp_handle->eventmgr == NULL)
		return 0;

460 461 462 463 464 465 466 467 468 469 470 471 472 473
	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);
474
		break;
475
	}
476 477 478
	case AMD_PP_EVENT_COMPLETE_INIT:
		ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
		break;
479 480 481
	case AMD_PP_EVENT_READJUST_POWER_STATE:
		ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
		break;
482 483 484 485
	default:
		break;
	}
	return ret;
486
}
487

488
static enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
489
{
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
	struct pp_hwmgr *hwmgr;
	struct pp_power_state *state;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

	if (hwmgr == NULL || hwmgr->current_ps == NULL)
		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:
511 512 513 514
		if (state->classification.flags & PP_StateClassificationFlag_Boot)
			return  POWER_STATE_TYPE_INTERNAL_BOOT;
		else
			return POWER_STATE_TYPE_DEFAULT;
515
	}
516
}
517

518 519 520 521 522 523 524 525 526
static int pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
{
	struct pp_hwmgr  *hwmgr;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

527 528 529 530 531 532
	PP_CHECK_HW(hwmgr);

	if (hwmgr->hwmgr_func->set_fan_control_mode == NULL) {
		printk(KERN_INFO "%s was not implemented.\n", __func__);
		return 0;
	}
533 534 535 536 537 538 539 540 541 542 543 544 545

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

static int pp_dpm_get_fan_control_mode(void *handle)
{
	struct pp_hwmgr  *hwmgr;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

546 547 548 549 550 551
	PP_CHECK_HW(hwmgr);

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

	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;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

565 566 567 568 569 570
	PP_CHECK_HW(hwmgr);

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

	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;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

584 585 586 587 588 589
	PP_CHECK_HW(hwmgr);

	if (hwmgr->hwmgr_func->get_fan_speed_percent == NULL) {
		printk(KERN_INFO "%s was not implemented.\n", __func__);
		return 0;
	}
590 591 592 593

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

594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
static int pp_dpm_get_fan_speed_rpm(void *handle, uint32_t *rpm)
{
	struct pp_hwmgr *hwmgr;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

	PP_CHECK_HW(hwmgr);

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

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

611 612 613 614 615 616 617 618 619
static int pp_dpm_get_temperature(void *handle)
{
	struct pp_hwmgr  *hwmgr;

	if (handle == NULL)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

620 621 622 623 624 625
	PP_CHECK_HW(hwmgr);

	if (hwmgr->hwmgr_func->get_temperature == NULL) {
		printk(KERN_INFO "%s was not implemented.\n", __func__);
		return 0;
	}
626 627 628

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

630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
static int pp_dpm_get_pp_num_states(void *handle,
		struct pp_states_info *data)
{
	struct pp_hwmgr *hwmgr;
	int i;

	if (!handle)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

	if (hwmgr == NULL || hwmgr->ps == NULL)
		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;

	if (!handle)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

679 680
	PP_CHECK_HW(hwmgr);

681 682 683 684
	if (!hwmgr->soft_pp_table)
		return -EINVAL;

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

686
	return hwmgr->soft_pp_table_size;
687 688 689 690 691 692 693 694 695 696 697
}

static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
{
	struct pp_hwmgr *hwmgr;

	if (!handle)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

698 699
	PP_CHECK_HW(hwmgr);

700
	if (!hwmgr->hardcode_pp_table) {
701 702 703
		hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table,
						   hwmgr->soft_pp_table_size,
						   GFP_KERNEL);
704 705 706

		if (!hwmgr->hardcode_pp_table)
			return -ENOMEM;
707
	}
708

709 710 711 712 713
	memcpy(hwmgr->hardcode_pp_table, buf, size);

	hwmgr->soft_pp_table = hwmgr->hardcode_pp_table;

	return amd_powerplay_reset(handle);
714 715 716
}

static int pp_dpm_force_clock_level(void *handle,
717
		enum pp_clock_type type, uint32_t mask)
718 719 720 721 722 723 724 725
{
	struct pp_hwmgr *hwmgr;

	if (!handle)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

726 727 728 729 730 731
	PP_CHECK_HW(hwmgr);

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

733
	return hwmgr->hwmgr_func->force_clock_level(hwmgr, type, mask);
734 735 736 737 738 739 740 741 742 743 744 745
}

static int pp_dpm_print_clock_levels(void *handle,
		enum pp_clock_type type, char *buf)
{
	struct pp_hwmgr *hwmgr;

	if (!handle)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

746
	PP_CHECK_HW(hwmgr);
747

748 749 750 751
	if (hwmgr->hwmgr_func->print_clock_levels == NULL) {
		printk(KERN_INFO "%s was not implemented.\n", __func__);
		return 0;
	}
752 753 754
	return hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf);
}

755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
static int pp_dpm_get_sclk_od(void *handle)
{
	struct pp_hwmgr *hwmgr;

	if (!handle)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

	PP_CHECK_HW(hwmgr);

	if (hwmgr->hwmgr_func->get_sclk_od == NULL) {
		printk(KERN_INFO "%s was not implemented.\n", __func__);
		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;

	if (!handle)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

	PP_CHECK_HW(hwmgr);

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

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

793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
static int pp_dpm_get_mclk_od(void *handle)
{
	struct pp_hwmgr *hwmgr;

	if (!handle)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

	PP_CHECK_HW(hwmgr);

	if (hwmgr->hwmgr_func->get_mclk_od == NULL) {
		printk(KERN_INFO "%s was not implemented.\n", __func__);
		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;

	if (!handle)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

	PP_CHECK_HW(hwmgr);

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

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

831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
static int pp_dpm_read_sensor(void *handle, int idx, int32_t *value)
{
	struct pp_hwmgr *hwmgr;

	if (!handle)
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

	PP_CHECK_HW(hwmgr);

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

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

850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
static struct amd_vce_state*
pp_dpm_get_vce_clock_state(void *handle, unsigned idx)
{
	struct pp_hwmgr *hwmgr;

	if (handle) {
		hwmgr = ((struct pp_instance *)handle)->hwmgr;

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

	return NULL;
}

865
const struct amd_powerplay_funcs pp_dpm_funcs = {
866
	.get_temperature = pp_dpm_get_temperature,
867 868 869 870 871 872 873 874 875 876
	.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,
877 878 879 880
	.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,
881
	.get_fan_speed_rpm = pp_dpm_get_fan_speed_rpm,
882 883 884 885 886
	.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,
887 888
	.get_sclk_od = pp_dpm_get_sclk_od,
	.set_sclk_od = pp_dpm_set_sclk_od,
889 890
	.get_mclk_od = pp_dpm_get_mclk_od,
	.set_mclk_od = pp_dpm_set_mclk_od,
891
	.read_sensor = pp_dpm_read_sensor,
892
	.get_vce_clock_state = pp_dpm_get_vce_clock_state,
893 894
};

895 896 897 898 899 900 901 902 903 904
static int amd_pp_instance_init(struct amd_pp_init *pp_init,
				struct amd_powerplay *amd_pp)
{
	int ret;
	struct pp_instance *handle;

	handle = kzalloc(sizeof(struct pp_instance), GFP_KERNEL);
	if (handle == NULL)
		return -ENOMEM;

905 906
	handle->pp_valid = PP_VALID;

907 908
	ret = smum_init(pp_init, handle);
	if (ret)
909 910
		goto fail_smum;

911 912 913

	amd_pp->pp_handle = handle;

914 915
	if ((amdgpu_dpm == 0)
		|| cgs_is_virtualization_enabled(pp_init->device))
916 917
		return 0;

918 919 920
	ret = hwmgr_init(pp_init, handle);
	if (ret)
		goto fail_hwmgr;
921

922 923 924 925
	ret = eventmgr_init(handle);
	if (ret)
		goto fail_eventmgr;

926
	return 0;
927

928 929
fail_eventmgr:
	hwmgr_fini(handle->hwmgr);
930 931 932 933 934
fail_hwmgr:
	smum_fini(handle->smu_mgr);
fail_smum:
	kfree(handle);
	return ret;
935 936 937 938 939
}

static int amd_pp_instance_fini(void *handle)
{
	struct pp_instance *instance = (struct pp_instance *)handle;
940

941 942 943
	if (instance == NULL)
		return -EINVAL;

944 945
	if ((amdgpu_dpm != 0)
		&& !cgs_is_virtualization_enabled(instance->smu_mgr->device)) {
946 947 948
		eventmgr_fini(instance->eventmgr);
		hwmgr_fini(instance->hwmgr);
	}
949

950 951 952 953 954
	smum_fini(instance->smu_mgr);
	kfree(handle);
	return 0;
}

955 956 957
int amd_powerplay_init(struct amd_pp_init *pp_init,
		       struct amd_powerplay *amd_pp)
{
958 959
	int ret;

960 961 962
	if (pp_init == NULL || amd_pp == NULL)
		return -EINVAL;

963 964 965 966 967
	ret = amd_pp_instance_init(pp_init, amd_pp);

	if (ret)
		return ret;

968 969 970 971 972 973 974 975
	amd_pp->ip_funcs = &pp_ip_funcs;
	amd_pp->pp_funcs = &pp_dpm_funcs;

	return 0;
}

int amd_powerplay_fini(void *handle)
{
976 977
	amd_pp_instance_fini(handle);

978 979
	return 0;
}
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
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;

	if (instance == NULL)
		return -EINVAL;

	eventmgr = instance->eventmgr;
	if (!eventmgr || !eventmgr->pp_eventmgr_fini)
		return -EINVAL;

	eventmgr->pp_eventmgr_fini(eventmgr);

	ret = pp_sw_fini(handle);
	if (ret)
		return ret;

	kfree(instance->hwmgr->ps);

	ret = pp_sw_init(handle);
	if (ret)
		return ret;

1007 1008
	if ((amdgpu_dpm == 0)
		|| cgs_is_virtualization_enabled(instance->smu_mgr->device))
1009 1010
		return 0;

1011 1012
	hw_init_power_state_table(instance->hwmgr);

1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
	if (eventmgr == NULL || eventmgr->pp_eventmgr_init == NULL)
		return -EINVAL;

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

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

1023 1024
/* export this function to DAL */

1025 1026
int amd_powerplay_display_configuration_change(void *handle,
	const struct amd_pp_display_configuration *display_config)
1027 1028 1029
{
	struct pp_hwmgr  *hwmgr;

1030
	PP_CHECK((struct pp_instance *)handle);
1031 1032 1033

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

1034 1035
	PP_CHECK_HW(hwmgr);

1036
	phm_store_dal_configuration_data(hwmgr, display_config);
1037

1038 1039
	return 0;
}
1040

1041
int amd_powerplay_get_display_power_level(void *handle,
R
Rex Zhu 已提交
1042
		struct amd_pp_simple_clock_info *output)
1043 1044 1045
{
	struct pp_hwmgr  *hwmgr;

1046 1047 1048
	PP_CHECK((struct pp_instance *)handle);

	if (output == NULL)
1049 1050 1051 1052
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

1053 1054
	PP_CHECK_HW(hwmgr);

1055
	return phm_get_dal_power_level(hwmgr, output);
1056
}
1057 1058

int amd_powerplay_get_current_clocks(void *handle,
1059
		struct amd_pp_clock_info *clocks)
1060 1061 1062 1063 1064
{
	struct pp_hwmgr  *hwmgr;
	struct amd_pp_simple_clock_info simple_clocks;
	struct pp_clock_info hw_clocks;

1065 1066 1067
	PP_CHECK((struct pp_instance *)handle);

	if (clocks == NULL)
1068 1069 1070 1071
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

1072 1073
	PP_CHECK_HW(hwmgr);

1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
	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;

	struct pp_hwmgr *hwmgr;

1111 1112 1113
	PP_CHECK((struct pp_instance *)handle);

	if (clocks == NULL)
1114 1115 1116 1117
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

1118 1119
	PP_CHECK_HW(hwmgr);

1120 1121 1122 1123 1124
	result = phm_get_clock_by_type(hwmgr, type, clocks);

	return result;
}

1125 1126
int amd_powerplay_get_display_mode_validation_clocks(void *handle,
		struct amd_pp_simple_clock_info *clocks)
1127 1128 1129 1130
{
	int result = -1;
	struct pp_hwmgr  *hwmgr;

1131 1132 1133
	PP_CHECK((struct pp_instance *)handle);

	if (clocks == NULL)
1134 1135 1136 1137
		return -EINVAL;

	hwmgr = ((struct pp_instance *)handle)->hwmgr;

1138 1139
	PP_CHECK_HW(hwmgr);

1140 1141 1142 1143 1144 1145
	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
		result = phm_get_max_high_clocks(hwmgr, clocks);

	return result;
}