Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 63580c3e authored by Anthoine Bourgeois's avatar Anthoine Bourgeois Committed by Alex Deucher
Browse files

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: default avatarAnthoine Bourgeois <anthoine.bourgeois@gmail.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 811e4d58
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -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,
+2 −0
Original line number Original line Diff line number Diff line
@@ -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
+74 −15
Original line number Original line Diff line number Diff line
@@ -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, &dividers);
		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, &dividers);
		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;
}