drm/radeon/dpm: implement force performance levels for rv6xx
authorAlex Deucher <alexander.deucher@amd.com>
Fri, 26 Jul 2013 00:07:25 +0000 (20:07 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 26 Jul 2013 00:07:25 +0000 (20:07 -0400)
Allows you to limit the selected power levels via sysfs.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/rv6xx_dpm.c

index 78bec1a58ed1a70be65e9bd11bc235fcded90df6..f8f8b3113dddd140bb6bc51455dc86307cc267e3 100644 (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,
index ca1895709908b428bdc078c36abc5e40a19e6d73..902479fa737ff62c1b2917b4d0bfce0c34176d74 100644 (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);
index dde402340f229ad83eff46fa5dd006cac0a6ff1e..363018c60412c1d7374ee60a176abe2f5c49dce7 100644 (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;
+}