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

Commit b27b6375 authored by Alex Deucher's avatar Alex Deucher Committed by Dave Airlie
Browse files

drm/radeon/kms/avivo: add support for new pll selection algo



Supported on all AVIVO-based asics.
Can be disabled via the new_pll module parameter:
new_pll=0 - disable
new_pll=1 - enable
enabled by default

[airlied: fixed to use do_div]
Signed-off-by: default avatarAlex Deucher <alexdeucher@gmail.com>
Signed-off-by: default avatarDave Airlie <airlied@linux.ie>
parent 69b3b5e5
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -499,6 +499,16 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
	else
		pll = &rdev->clock.p2pll;

	if (ASIC_IS_AVIVO(rdev)) {
		if (radeon_new_pll)
			radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock,
						 &fb_div, &frac_fb_div,
						 &ref_div, &post_div, pll_flags);
		else
			radeon_compute_pll(pll, adjusted_clock, &pll_clock,
					   &fb_div, &frac_fb_div,
					   &ref_div, &post_div, pll_flags);
	} else
		radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
				   &ref_div, &post_div, pll_flags);

+1 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ extern int radeon_benchmarking;
extern int radeon_testing;
extern int radeon_connector_table;
extern int radeon_tv;
extern int radeon_new_pll;

/*
 * Copy from radeon_drv.h so we don't have to include both and have conflicting
+2 −1
Original line number Diff line number Diff line
@@ -871,6 +871,7 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
			 * pre-DCE 3.0 r6xx hardware.  This might need to be adjusted per
			 * family.
			 */
			if (!radeon_new_pll)
				p1pll->pll_out_min = 64800;
		}

+92 −0
Original line number Diff line number Diff line
@@ -560,6 +560,98 @@ void radeon_compute_pll(struct radeon_pll *pll,
	*post_div_p = best_post_div;
}

void radeon_compute_pll_avivo(struct radeon_pll *pll,
			      uint64_t freq,
			      uint32_t *dot_clock_p,
			      uint32_t *fb_div_p,
			      uint32_t *frac_fb_div_p,
			      uint32_t *ref_div_p,
			      uint32_t *post_div_p,
			      int flags)
{
	fixed20_12 m, n, frac_n, p, f_vco, f_pclk, best_freq;
	fixed20_12 pll_out_max, pll_out_min;
	fixed20_12 pll_in_max, pll_in_min;
	fixed20_12 reference_freq;
	fixed20_12 error, ffreq, a, b;

	pll_out_max.full = rfixed_const(pll->pll_out_max);
	pll_out_min.full = rfixed_const(pll->pll_out_min);
	pll_in_max.full = rfixed_const(pll->pll_in_max);
	pll_in_min.full = rfixed_const(pll->pll_in_min);
	reference_freq.full = rfixed_const(pll->reference_freq);
	do_div(freq, 10);
	ffreq.full = rfixed_const(freq);
	error.full = rfixed_const(100 * 100);

	/* max p */
	p.full = rfixed_div(pll_out_max, ffreq);
	p.full = rfixed_floor(p);

	/* min m */
	m.full = rfixed_div(reference_freq, pll_in_max);
	m.full = rfixed_ceil(m);

	while (1) {
		n.full = rfixed_div(ffreq, reference_freq);
		n.full = rfixed_mul(n, m);
		n.full = rfixed_mul(n, p);

		f_vco.full = rfixed_div(n, m);
		f_vco.full = rfixed_mul(f_vco, reference_freq);

		f_pclk.full = rfixed_div(f_vco, p);

		if (f_pclk.full > ffreq.full)
			error.full = f_pclk.full - ffreq.full;
		else
			error.full = ffreq.full - f_pclk.full;
		error.full = rfixed_div(error, f_pclk);
		a.full = rfixed_const(100 * 100);
		error.full = rfixed_mul(error, a);

		a.full = rfixed_mul(m, p);
		a.full = rfixed_div(n, a);
		best_freq.full = rfixed_mul(reference_freq, a);

		if (rfixed_trunc(error) < 25)
			break;

		a.full = rfixed_const(1);
		m.full = m.full + a.full;
		a.full = rfixed_div(reference_freq, m);
		if (a.full >= pll_in_min.full)
			continue;

		m.full = rfixed_div(reference_freq, pll_in_max);
		m.full = rfixed_ceil(m);
		a.full= rfixed_const(1);
		p.full = p.full - a.full;
		a.full = rfixed_mul(p, ffreq);
		if (a.full >= pll_out_min.full)
			continue;
		else {
			DRM_ERROR("Unable to find pll dividers\n");
			break;
		}
	}

	a.full = rfixed_const(10);
	b.full = rfixed_mul(n, a);

	frac_n.full = rfixed_floor(n);
	frac_n.full = rfixed_mul(frac_n, a);
	frac_n.full = b.full - frac_n.full;

	*dot_clock_p = rfixed_trunc(best_freq);
	*fb_div_p = rfixed_trunc(n);
	*frac_fb_div_p = rfixed_trunc(frac_n);
	*ref_div_p = rfixed_trunc(m);
	*post_div_p = rfixed_trunc(p);

	DRM_DEBUG("%u %d.%d, %d, %d\n", *dot_clock_p * 10, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p);
}

static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
{
	struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
+4 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ int radeon_benchmarking = 0;
int radeon_testing = 0;
int radeon_connector_table = 0;
int radeon_tv = 1;
int radeon_new_pll = 1;

MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -120,6 +121,9 @@ module_param_named(connector_table, radeon_connector_table, int, 0444);
MODULE_PARM_DESC(tv, "TV enable (0 = disable)");
module_param_named(tv, radeon_tv, int, 0444);

MODULE_PARM_DESC(r4xx_atom, "Select new PLL code for AVIVO chips");
module_param_named(new_pll, radeon_new_pll, int, 0444);

static int radeon_suspend(struct drm_device *dev, pm_message_t state)
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
Loading