diff options
author | Anthoine Bourgeois <anthoine.bourgeois@gmail.com> | 2013-09-03 13:52:19 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2013-09-11 11:44:24 -0400 |
commit | 63580c3e48de1a35ec8847ea24f1acb5aef48608 (patch) | |
tree | 26717e89194100078c1f003f10bf3f7b3e68a257 | |
parent | 811e4d58edf98f1ff5d3478e2c5f61034d359ab3 (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.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rs780_dpm.c | 89 |
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); |
429 | void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, | 429 | void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
430 | struct seq_file *m); | 430 | struct seq_file *m); |
431 | int 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 | ||
379 | static void rs780_force_voltage_to_high(struct radeon_device *rdev) | 379 | static 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 | ||
406 | static 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 | |||
407 | static int rs780_set_engine_clock_scaling(struct radeon_device *rdev, | 426 | static 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 | |||
999 | int 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, ÷rs); | ||
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, ÷rs); | ||
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 | } | ||