drm/radeon/dpm: implement force performance levels for rv6xx

Allows you to limit the selected power levels via sysfs.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Alex Deucher 2013-07-25 20:07:25 -04:00
parent 2333a003a8
commit f4f85a8c94
3 changed files with 38 additions and 0 deletions

View File

@ -1161,6 +1161,7 @@ static struct radeon_asic rv6xx_asic = {
.get_mclk = &rv6xx_dpm_get_mclk,
.print_power_state = &rv6xx_dpm_print_power_state,
.debugfs_print_current_performance_level = &rv6xx_dpm_debugfs_print_current_performance_level,
.force_performance_level = &rv6xx_dpm_force_performance_level,
},
.pflip = {
.pre_page_flip = &rs600_pre_page_flip,

View File

@ -421,6 +421,8 @@ void rv6xx_dpm_print_power_state(struct radeon_device *rdev,
struct radeon_ps *ps);
void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
struct seq_file *m);
int rv6xx_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level);
/* rs780 dpm */
int rs780_dpm_init(struct radeon_device *rdev);
int rs780_dpm_enable(struct radeon_device *rdev);

View File

@ -1670,6 +1670,8 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
int ret;
pi->restricted_levels = 0;
rv6xx_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
rv6xx_clear_vc(rdev);
@ -1756,6 +1758,8 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
rv6xx_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
return 0;
}
@ -2085,3 +2089,34 @@ u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low)
else
return requested_state->high.mclk;
}
int rv6xx_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level)
{
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
pi->restricted_levels = 3;
} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
pi->restricted_levels = 2;
} else {
pi->restricted_levels = 0;
}
rv6xx_clear_vc(rdev);
r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW);
r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
rv6xx_enable_medium(rdev);
rv6xx_enable_high(rdev);
if (pi->restricted_levels == 3)
r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false);
rv6xx_program_vc(rdev);
rv6xx_program_at(rdev);
rdev->pm.dpm.forced_level = level;
return 0;
}