2013/8/1 Deucher, Alexander Alexander.Deucher@amd.com
-----Original Message----- From: Anthoine Bourgeois [mailto:anthoine.bourgeois@gmail.com] Sent: Wednesday, July 31, 2013 6:34 PM To: Deucher, Alexander; Koenig, Christian; Jerome Glisse; Anthoine Bourgeois Cc: dri-devel@lists.freedesktop.org Subject: [PATCH] drm/radeon/dpm: implement force performance levels for rs780
Allows you to limit the selected power levels via sysfs.
Force the feedback divider to select a power level.
Nice work. A few comments below.
Alex
Signed-off-by: Anthoine Bourgeois anthoine.bourgeois@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;
I'm not quite sure what you are checking here.
Oh yes, my mistake, fb_div shouldn't be in that condition. In my memory, I just wanted to check that sclk_low is equal to sclk_high. In that case, no need to force the fbdiv because there are the same.
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;
You can drop the separate min and max and just use a single dividers struct.
OK.
Also, You are only forcing the sclk. It would probably also be a good idea to force the voltage levels.
OK, I'm working on it but I can't test it, my board (RS880) doesn't seem to support the voltage scaling. I'll do my best.
Anthoine
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