Allows you to limit the selected power levels via sysfs.

Force the feedback divider to select a power level.

Signed-off-by: Anthoine Bourgeois <anthoine.bourge...@gmail.com>
---
drivers/gpu/drm/radeon/radeon_asic.c |  1 +
drivers/gpu/drm/radeon/radeon_asic.h |  2 ++
drivers/gpu/drm/radeon/rs780_dpm.c   | 67 ++++++++++++++++++++++++++++++------
3 files changed, 59 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_asic.c 
b/drivers/gpu/drm/radeon/radeon_asic.c
index f8f8b31..437d357 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1272,6 +1272,7 @@ static struct radeon_asic rs780_asic = {
                .get_mclk = &rs780_dpm_get_mclk,
                .print_power_state = &rs780_dpm_print_power_state,
                .debugfs_print_current_performance_level = 
&rs780_dpm_debugfs_print_current_performance_level,
+               .force_performance_level = &rs780_dpm_force_performance_level,
        },
        .pflip = {
                .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 902479f..09841fc 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -437,6 +437,8 @@ void rs780_dpm_print_power_state(struct radeon_device *rdev,
                                 struct radeon_ps *ps);
void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device 
*rdev,
                                                       struct seq_file *m);
+int rs780_dpm_force_performance_level(struct radeon_device *rdev,
+                                     enum radeon_dpm_forced_level level);

/* uvd */
int r600_uvd_init(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c 
b/drivers/gpu/drm/radeon/rs780_dpm.c
index d1a1ce7..df58e34 100644
--- a/drivers/gpu/drm/radeon/rs780_dpm.c
+++ b/drivers/gpu/drm/radeon/rs780_dpm.c
@@ -404,6 +404,27 @@ static void rs780_force_voltage_to_high(struct 
radeon_device *rdev)
        WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
}

+static void rs780_force_fbdiv(struct radeon_device *rdev, u32 fb_div)
+{
+       struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+
+       if ((current_state->sclk_low == fb_div) &&
+           (current_state->sclk_high == fb_div))
+               return;
+
+       WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
+
+       WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fb_div),
+                ~FORCED_FEEDBACK_DIV_MASK);
+       WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fb_div),
+                ~STARTING_FEEDBACK_DIV_MASK);
+       WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
+
+       udelay(100);
+
+       WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+}
+
static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
                                          struct radeon_ps *new_ps,
                                          struct radeon_ps *old_ps)
@@ -432,17 +453,7 @@ static int rs780_set_engine_clock_scaling(struct 
radeon_device *rdev,
        if (ret)
                return ret;

-       WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
-
-       WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
-                ~FORCED_FEEDBACK_DIV_MASK);
-       WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
-                ~STARTING_FEEDBACK_DIV_MASK);
-       WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
-
-       udelay(100);
-
-       WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+       rs780_force_fbdiv(rdev, max_dividers.fb_div);

        if (max_dividers.fb_div > min_dividers.fb_div) {
                WREG32_P(FVTHROT_FBDIV_REG0,
@@ -986,3 +997,37 @@ void 
rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
                seq_printf(m, "power level 1    sclk: %u vddc_index: %d\n",
                           ps->sclk_high, ps->max_voltage);
}
+
+int rs780_dpm_force_performance_level(struct radeon_device *rdev,
+                                     enum radeon_dpm_forced_level level)
+{
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct igp_ps *ps = rs780_get_ps(rps);
+       struct atom_clock_dividers min_dividers, max_dividers;
+       int ret;
+
+       rs780_clk_scaling_enable(rdev, false);
+
+       if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+               ret = radeon_atom_get_clock_dividers(rdev, 
COMPUTE_ENGINE_PLL_PARAM,
+                                                    ps->sclk_high, false, 
&max_dividers);
+               if (ret)
+                       return ret;
+
+               rs780_force_fbdiv(rdev, max_dividers.fb_div);
+       } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+               ret = radeon_atom_get_clock_dividers(rdev, 
COMPUTE_ENGINE_PLL_PARAM,
+                                                    ps->sclk_low, false, 
&min_dividers);
+               if (ret)
+                       return ret;
+
+               rs780_force_fbdiv(rdev, min_dividers.fb_div);
+       } else {
+               WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
+               rs780_clk_scaling_enable(rdev, true);
+       }
+
+       rdev->pm.dpm.forced_level = level;
+
+       return 0;
+}
--
1.8.1.5

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to