On Sun, Sep 1, 2013 at 1:34 PM, Anthoine Bourgeois <anthoine.bourgeois@xxxxxxxxx> wrote: > 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@xxxxxxxxx> Patch looks good. Thanks for doing this. I'll add it to my queue. Alex > --- > drivers/gpu/drm/radeon/radeon_asic.c | 1 + > drivers/gpu/drm/radeon/radeon_asic.h | 2 + > 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 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 3d61d5a..0d81dbd 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..625d6ea 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) > WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000); > } > > -static void rs780_force_voltage_to_high(struct radeon_device *rdev) > +static void rs780_force_voltage(struct radeon_device *rdev, u16 voltage) > { > - struct igp_power_info *pi = rs780_get_pi(rdev); > struct igp_ps *current_state = > rs780_get_ps(rdev->pm.dpm.current_ps); > > if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) && > @@ -390,7 +389,7 @@ static void rs780_force_voltage_to_high(struct > radeon_device *rdev) > udelay(1); > > WREG32_P(FVTHROT_PWM_CTRL_REG0, > - STARTING_PWM_HIGHTIME(pi->max_voltage), > + STARTING_PWM_HIGHTIME(voltage), > ~STARTING_PWM_HIGHTIME_MASK); > > WREG32_P(FVTHROT_PWM_CTRL_REG0, > @@ -404,6 +403,26 @@ 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 == current_state->sclk_high) > + 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 +451,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, > @@ -649,7 +658,7 @@ int rs780_dpm_set_power_state(struct radeon_device > *rdev) > rs780_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); > > if (pi->voltage_control) { > - rs780_force_voltage_to_high(rdev); > + rs780_force_voltage(rdev, pi->max_voltage); > mdelay(5); > } > > @@ -986,3 +995,53 @@ 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 igp_power_info *pi = rs780_get_pi(rdev); > + struct radeon_ps *rps = rdev->pm.dpm.current_ps; > + struct igp_ps *ps = rs780_get_ps(rps); > + struct atom_clock_dividers dividers; > + int ret; > + > + rs780_clk_scaling_enable(rdev, false); > + rs780_voltage_scaling_enable(rdev, false); > + > + if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { > + if (pi->voltage_control) > + rs780_force_voltage(rdev, pi->max_voltage); > + > + ret = radeon_atom_get_clock_dividers(rdev, > COMPUTE_ENGINE_PLL_PARAM, > + ps->sclk_high, false, > ÷rs); > + if (ret) > + return ret; > + > + rs780_force_fbdiv(rdev, 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, > ÷rs); > + if (ret) > + return ret; > + > + rs780_force_fbdiv(rdev, dividers.fb_div); > + > + if (pi->voltage_control) > + rs780_force_voltage(rdev, pi->min_voltage); > + } else { > + if (pi->voltage_control) > + rs780_force_voltage(rdev, pi->max_voltage); > + > + WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV); > + rs780_clk_scaling_enable(rdev, true); > + > + if (pi->voltage_control) { > + rs780_voltage_scaling_enable(rdev, true); > + rs780_enable_voltage_scaling(rdev, rps); > + } > + } > + > + rdev->pm.dpm.forced_level = level; > + > + return 0; > +} > -- > 1.8.1.5 > > _______________________________________________ > dri-devel mailing list > dri-devel@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/dri-devel _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel