drm/radeon/dpm: implement force performance levels for rs780 (v2)
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@gmail.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
811e4d58ed
commit
63580c3e48
@ -1141,6 +1141,7 @@ static struct radeon_asic rs780_asic = {
|
|||||||
.get_mclk = &rs780_dpm_get_mclk,
|
.get_mclk = &rs780_dpm_get_mclk,
|
||||||
.print_power_state = &rs780_dpm_print_power_state,
|
.print_power_state = &rs780_dpm_print_power_state,
|
||||||
.debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level,
|
.debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level,
|
||||||
|
.force_performance_level = &rs780_dpm_force_performance_level,
|
||||||
},
|
},
|
||||||
.pflip = {
|
.pflip = {
|
||||||
.pre_page_flip = &rs600_pre_page_flip,
|
.pre_page_flip = &rs600_pre_page_flip,
|
||||||
|
@ -428,6 +428,8 @@ void rs780_dpm_print_power_state(struct radeon_device *rdev,
|
|||||||
struct radeon_ps *ps);
|
struct radeon_ps *ps);
|
||||||
void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
|
void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
|
||||||
struct seq_file *m);
|
struct seq_file *m);
|
||||||
|
int rs780_dpm_force_performance_level(struct radeon_device *rdev,
|
||||||
|
enum radeon_dpm_forced_level level);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* rv770,rv730,rv710,rv740
|
* rv770,rv730,rv710,rv740
|
||||||
|
@ -376,9 +376,8 @@ static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
|
|||||||
WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
|
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);
|
struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
|
||||||
|
|
||||||
if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
|
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);
|
udelay(1);
|
||||||
|
|
||||||
WREG32_P(FVTHROT_PWM_CTRL_REG0,
|
WREG32_P(FVTHROT_PWM_CTRL_REG0,
|
||||||
STARTING_PWM_HIGHTIME(pi->max_voltage),
|
STARTING_PWM_HIGHTIME(voltage),
|
||||||
~STARTING_PWM_HIGHTIME_MASK);
|
~STARTING_PWM_HIGHTIME_MASK);
|
||||||
|
|
||||||
WREG32_P(FVTHROT_PWM_CTRL_REG0,
|
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);
|
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,
|
static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
|
||||||
struct radeon_ps *new_ps,
|
struct radeon_ps *new_ps,
|
||||||
struct radeon_ps *old_ps)
|
struct radeon_ps *old_ps)
|
||||||
@ -432,17 +451,7 @@ static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
|
rs780_force_fbdiv(rdev, max_dividers.fb_div);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (max_dividers.fb_div > min_dividers.fb_div) {
|
if (max_dividers.fb_div > min_dividers.fb_div) {
|
||||||
WREG32_P(FVTHROT_FBDIV_REG0,
|
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);
|
rs780_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
|
||||||
|
|
||||||
if (pi->voltage_control) {
|
if (pi->voltage_control) {
|
||||||
rs780_force_voltage_to_high(rdev);
|
rs780_force_voltage(rdev, pi->max_voltage);
|
||||||
mdelay(5);
|
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",
|
seq_printf(m, "power level 1 sclk: %u vddc_index: %d\n",
|
||||||
ps->sclk_high, ps->max_voltage);
|
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;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user