aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnthoine Bourgeois <anthoine.bourgeois@gmail.com>2013-09-03 13:52:19 -0400
committerAlex Deucher <alexander.deucher@amd.com>2013-09-11 11:44:24 -0400
commit63580c3e48de1a35ec8847ea24f1acb5aef48608 (patch)
tree26717e89194100078c1f003f10bf3f7b3e68a257
parent811e4d58edf98f1ff5d3478e2c5f61034d359ab3 (diff)
drm/radeon/dpm: implement force performance levels for rs780 (v2)
Allows you to limit the selected power levels via sysfs. Force the feedback divider to select a power level. v2: fix checking in rs780_force_fbdiv, drop a duplicate divider structure in rs780_dpm_force_performance_level, Force the voltage level too. Signed-off-by: Anthoine Bourgeois <anthoine.bourgeois@gmail.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h2
-rw-r--r--drivers/gpu/drm/radeon/rs780_dpm.c89
3 files changed, 77 insertions, 15 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 630853b96841..40a9b4bc3291 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1141,6 +1141,7 @@ static struct radeon_asic rs780_asic = {
1141 .get_mclk = &rs780_dpm_get_mclk, 1141 .get_mclk = &rs780_dpm_get_mclk,
1142 .print_power_state = &rs780_dpm_print_power_state, 1142 .print_power_state = &rs780_dpm_print_power_state,
1143 .debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level, 1143 .debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level,
1144 .force_performance_level = &rs780_dpm_force_performance_level,
1144 }, 1145 },
1145 .pflip = { 1146 .pflip = {
1146 .pre_page_flip = &rs600_pre_page_flip, 1147 .pre_page_flip = &rs600_pre_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 818bbe6b884b..98a59f5d6edc 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -428,6 +428,8 @@ void rs780_dpm_print_power_state(struct radeon_device *rdev,
428 struct radeon_ps *ps); 428 struct radeon_ps *ps);
429void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, 429void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
430 struct seq_file *m); 430 struct seq_file *m);
431int rs780_dpm_force_performance_level(struct radeon_device *rdev,
432 enum radeon_dpm_forced_level level);
431 433
432/* 434/*
433 * rv770,rv730,rv710,rv740 435 * rv770,rv730,rv710,rv740
diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
index d1a1ce73bd45..625d6ea1f0d1 100644
--- a/drivers/gpu/drm/radeon/rs780_dpm.c
+++ b/drivers/gpu/drm/radeon/rs780_dpm.c
@@ -376,9 +376,8 @@ static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
376 WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000); 376 WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
377} 377}
378 378
379static void rs780_force_voltage_to_high(struct radeon_device *rdev) 379static void rs780_force_voltage(struct radeon_device *rdev, u16 voltage)
380{ 380{
381 struct igp_power_info *pi = rs780_get_pi(rdev);
382 struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps); 381 struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
383 382
384 if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) && 383 if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
@@ -390,7 +389,7 @@ static void rs780_force_voltage_to_high(struct radeon_device *rdev)
390 udelay(1); 389 udelay(1);
391 390
392 WREG32_P(FVTHROT_PWM_CTRL_REG0, 391 WREG32_P(FVTHROT_PWM_CTRL_REG0,
393 STARTING_PWM_HIGHTIME(pi->max_voltage), 392 STARTING_PWM_HIGHTIME(voltage),
394 ~STARTING_PWM_HIGHTIME_MASK); 393 ~STARTING_PWM_HIGHTIME_MASK);
395 394
396 WREG32_P(FVTHROT_PWM_CTRL_REG0, 395 WREG32_P(FVTHROT_PWM_CTRL_REG0,
@@ -404,6 +403,26 @@ static void rs780_force_voltage_to_high(struct radeon_device *rdev)
404 WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL); 403 WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
405} 404}
406 405
406static void rs780_force_fbdiv(struct radeon_device *rdev, u32 fb_div)
407{
408 struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
409
410 if (current_state->sclk_low == current_state->sclk_high)
411 return;
412
413 WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
414
415 WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fb_div),
416 ~FORCED_FEEDBACK_DIV_MASK);
417 WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fb_div),
418 ~STARTING_FEEDBACK_DIV_MASK);
419 WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
420
421 udelay(100);
422
423 WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
424}
425
407static int rs780_set_engine_clock_scaling(struct radeon_device *rdev, 426static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
408 struct radeon_ps *new_ps, 427 struct radeon_ps *new_ps,
409 struct radeon_ps *old_ps) 428 struct radeon_ps *old_ps)
@@ -432,17 +451,7 @@ static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
432 if (ret) 451 if (ret)
433 return ret; 452 return ret;
434 453
435 WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL); 454 rs780_force_fbdiv(rdev, max_dividers.fb_div);
436
437 WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
438 ~FORCED_FEEDBACK_DIV_MASK);
439 WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
440 ~STARTING_FEEDBACK_DIV_MASK);
441 WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
442
443 udelay(100);
444
445 WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
446 455
447 if (max_dividers.fb_div > min_dividers.fb_div) { 456 if (max_dividers.fb_div > min_dividers.fb_div) {
448 WREG32_P(FVTHROT_FBDIV_REG0, 457 WREG32_P(FVTHROT_FBDIV_REG0,
@@ -649,7 +658,7 @@ int rs780_dpm_set_power_state(struct radeon_device *rdev)
649 rs780_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); 658 rs780_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
650 659
651 if (pi->voltage_control) { 660 if (pi->voltage_control) {
652 rs780_force_voltage_to_high(rdev); 661 rs780_force_voltage(rdev, pi->max_voltage);
653 mdelay(5); 662 mdelay(5);
654 } 663 }
655 664
@@ -986,3 +995,53 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
986 seq_printf(m, "power level 1 sclk: %u vddc_index: %d\n", 995 seq_printf(m, "power level 1 sclk: %u vddc_index: %d\n",
987 ps->sclk_high, ps->max_voltage); 996 ps->sclk_high, ps->max_voltage);
988} 997}
998
999int rs780_dpm_force_performance_level(struct radeon_device *rdev,
1000 enum radeon_dpm_forced_level level)
1001{
1002 struct igp_power_info *pi = rs780_get_pi(rdev);
1003 struct radeon_ps *rps = rdev->pm.dpm.current_ps;
1004 struct igp_ps *ps = rs780_get_ps(rps);
1005 struct atom_clock_dividers dividers;
1006 int ret;
1007
1008 rs780_clk_scaling_enable(rdev, false);
1009 rs780_voltage_scaling_enable(rdev, false);
1010
1011 if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
1012 if (pi->voltage_control)
1013 rs780_force_voltage(rdev, pi->max_voltage);
1014
1015 ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
1016 ps->sclk_high, false, &dividers);
1017 if (ret)
1018 return ret;
1019
1020 rs780_force_fbdiv(rdev, dividers.fb_div);
1021 } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
1022 ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
1023 ps->sclk_low, false, &dividers);
1024 if (ret)
1025 return ret;
1026
1027 rs780_force_fbdiv(rdev, dividers.fb_div);
1028
1029 if (pi->voltage_control)
1030 rs780_force_voltage(rdev, pi->min_voltage);
1031 } else {
1032 if (pi->voltage_control)
1033 rs780_force_voltage(rdev, pi->max_voltage);
1034
1035 WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
1036 rs780_clk_scaling_enable(rdev, true);
1037
1038 if (pi->voltage_control) {
1039 rs780_voltage_scaling_enable(rdev, true);
1040 rs780_enable_voltage_scaling(rdev, rps);
1041 }
1042 }
1043
1044 rdev->pm.dpm.forced_level = level;
1045
1046 return 0;
1047}