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

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

drm/radeon/kms: remove new pll algo

The recent changes to the old algo (prefer high post div)
coupled with the range and precision limitations of using
fixed point with the new algo make the new algo less
useful.  So drop the new algo.  This should work as well
or better than the old new/old combinations and simplifies
the code a lot.

Fixes:
https://bugs.freedesktop.org/show_bug.cgi?id=30218


among others.

Signed-off-by: default avatarAlex Deucher <alexdeucher@gmail.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent f28488c2
Loading
Loading
Loading
Loading
+1 −31
Original line number Diff line number Diff line
@@ -482,19 +482,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
	/* reset the pll flags */
	pll->flags = 0;

	/* select the PLL algo */
	if (ASIC_IS_AVIVO(rdev)) {
		if (radeon_new_pll == 0)
			pll->algo = PLL_ALGO_LEGACY;
		else
			pll->algo = PLL_ALGO_NEW;
	} else {
		if (radeon_new_pll == 1)
			pll->algo = PLL_ALGO_NEW;
		else
			pll->algo = PLL_ALGO_LEGACY;
	}

	if (ASIC_IS_AVIVO(rdev)) {
		if ((rdev->family == CHIP_RS600) ||
		    (rdev->family == CHIP_RS690) ||
@@ -523,25 +510,8 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
				/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
				if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
					adjusted_clock = mode->clock * 2;
				if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
					pll->algo = PLL_ALGO_LEGACY;
				if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
					pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
				}
				/* There is some evidence (often anecdotal) that RV515/RV620 LVDS
				 * (on some boards at least) prefers the legacy algo.  I'm not
				 * sure whether this should handled generically or on a
				 * case-by-case quirk basis.  Both algos should work fine in the
				 * majority of cases.
				 */
				if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) &&
				    ((rdev->family == CHIP_RV515) ||
				     (rdev->family == CHIP_RV620))) {
					/* allow the user to overrride just in case */
					if (radeon_new_pll == 1)
						pll->algo = PLL_ALGO_NEW;
					else
						pll->algo = PLL_ALGO_LEGACY;
				}
			} else {
				if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
					pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
+0 −1
Original line number Diff line number Diff line
@@ -88,7 +88,6 @@ extern int radeon_benchmarking;
extern int radeon_testing;
extern int radeon_connector_table;
extern int radeon_tv;
extern int radeon_new_pll;
extern int radeon_audio;
extern int radeon_disp_priority;
extern int radeon_hw_i2c;
+1 −14
Original line number Diff line number Diff line
@@ -1112,7 +1112,6 @@ 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;
		}

@@ -1390,18 +1389,6 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct

		lvds->ss = radeon_atombios_get_ss_info(encoder, lvds_info->info.ucSS_Id);

		if (ASIC_IS_AVIVO(rdev)) {
			if (radeon_new_pll == 0)
				lvds->pll_algo = PLL_ALGO_LEGACY;
			else
				lvds->pll_algo = PLL_ALGO_NEW;
		} else {
			if (radeon_new_pll == 1)
				lvds->pll_algo = PLL_ALGO_NEW;
			else
				lvds->pll_algo = PLL_ALGO_LEGACY;
		}

		encoder->native_mode = lvds->native_mode;

		if (encoder_enum == 2)
+7 −215
Original line number Diff line number Diff line
@@ -454,7 +454,7 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d)
	return n;
}

static void radeon_compute_pll_legacy(struct radeon_pll *pll,
void radeon_compute_pll(struct radeon_pll *pll,
			uint64_t freq,
			uint32_t *dot_clock_p,
			uint32_t *fb_div_p,
@@ -609,214 +609,6 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
	*post_div_p = best_post_div;
}

static bool
calc_fb_div(struct radeon_pll *pll,
	    uint32_t freq,
            uint32_t post_div,
            uint32_t ref_div,
            uint32_t *fb_div,
            uint32_t *fb_div_frac)
{
	fixed20_12 feedback_divider, a, b;
	u32 vco_freq;

	vco_freq = freq * post_div;
	/* feedback_divider = vco_freq * ref_div / pll->reference_freq; */
	a.full = dfixed_const(pll->reference_freq);
	feedback_divider.full = dfixed_const(vco_freq);
	feedback_divider.full = dfixed_div(feedback_divider, a);
	a.full = dfixed_const(ref_div);
	feedback_divider.full = dfixed_mul(feedback_divider, a);

	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
		/* feedback_divider = floor((feedback_divider * 10.0) + 0.5) * 0.1; */
		a.full = dfixed_const(10);
		feedback_divider.full = dfixed_mul(feedback_divider, a);
		feedback_divider.full += dfixed_const_half(0);
		feedback_divider.full = dfixed_floor(feedback_divider);
		feedback_divider.full = dfixed_div(feedback_divider, a);

		/* *fb_div = floor(feedback_divider); */
		a.full = dfixed_floor(feedback_divider);
		*fb_div = dfixed_trunc(a);
		/* *fb_div_frac = fmod(feedback_divider, 1.0) * 10.0; */
		a.full = dfixed_const(10);
		b.full = dfixed_mul(feedback_divider, a);

		feedback_divider.full = dfixed_floor(feedback_divider);
		feedback_divider.full = dfixed_mul(feedback_divider, a);
		feedback_divider.full = b.full - feedback_divider.full;
		*fb_div_frac = dfixed_trunc(feedback_divider);
	} else {
		/* *fb_div = floor(feedback_divider + 0.5); */
		feedback_divider.full += dfixed_const_half(0);
		feedback_divider.full = dfixed_floor(feedback_divider);

		*fb_div = dfixed_trunc(feedback_divider);
		*fb_div_frac = 0;
	}

	if (((*fb_div) < pll->min_feedback_div) || ((*fb_div) > pll->max_feedback_div))
		return false;
	else
		return true;
}

static bool
calc_fb_ref_div(struct radeon_pll *pll,
		uint32_t freq,
		uint32_t post_div,
		uint32_t *fb_div,
                uint32_t *fb_div_frac,
                uint32_t *ref_div)
{
	fixed20_12 ffreq, max_error, error, pll_out, a;
	u32 vco;
	u32 pll_out_min, pll_out_max;

	if (pll->flags & RADEON_PLL_IS_LCD) {
		pll_out_min = pll->lcd_pll_out_min;
		pll_out_max = pll->lcd_pll_out_max;
	} else {
		pll_out_min = pll->pll_out_min;
		pll_out_max = pll->pll_out_max;
	}

	ffreq.full = dfixed_const(freq);
	/* max_error = ffreq * 0.0025; */
	a.full = dfixed_const(400);
	max_error.full = dfixed_div(ffreq, a);

	for ((*ref_div) = pll->min_ref_div; (*ref_div) < pll->max_ref_div; ++(*ref_div)) {
		if (calc_fb_div(pll, freq, post_div, (*ref_div), fb_div, fb_div_frac)) {
			vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac));
			vco = vco / ((*ref_div) * 10);

			if ((vco < pll_out_min) || (vco > pll_out_max))
				continue;

			/* pll_out = vco / post_div; */
			a.full = dfixed_const(post_div);
			pll_out.full = dfixed_const(vco);
			pll_out.full = dfixed_div(pll_out, a);

			if (pll_out.full >= ffreq.full) {
				error.full = pll_out.full - ffreq.full;
				if (error.full <= max_error.full)
					return true;
			}
		}
	}
	return false;
}

static void radeon_compute_pll_new(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)
{
	u32 fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0;
	u32 best_freq = 0, vco_frequency;
	u32 pll_out_min, pll_out_max;

	if (pll->flags & RADEON_PLL_IS_LCD) {
		pll_out_min = pll->lcd_pll_out_min;
		pll_out_max = pll->lcd_pll_out_max;
	} else {
		pll_out_min = pll->pll_out_min;
		pll_out_max = pll->pll_out_max;
	}

	/* freq = freq / 10; */
	do_div(freq, 10);

	if (pll->flags & RADEON_PLL_USE_POST_DIV) {
		post_div = pll->post_div;
		if ((post_div < pll->min_post_div) || (post_div > pll->max_post_div))
			goto done;

		vco_frequency = freq * post_div;
		if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
			goto done;

		if (pll->flags & RADEON_PLL_USE_REF_DIV) {
			ref_div = pll->reference_div;
			if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
				goto done;
			if (!calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
				goto done;
		}
	} else {
		for (post_div = pll->max_post_div; post_div >= pll->min_post_div; --post_div) {
			if (pll->flags & RADEON_PLL_LEGACY) {
				if ((post_div == 5) ||
				    (post_div == 7) ||
				    (post_div == 9) ||
				    (post_div == 10) ||
				    (post_div == 11))
					continue;
			}

			if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
				continue;

			vco_frequency = freq * post_div;
			if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
				continue;
			if (pll->flags & RADEON_PLL_USE_REF_DIV) {
				ref_div = pll->reference_div;
				if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
					goto done;
				if (calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
					break;
			} else {
				if (calc_fb_ref_div(pll, freq, post_div, &fb_div, &fb_div_frac, &ref_div))
					break;
			}
		}
	}

	best_freq = pll->reference_freq * 10 * fb_div;
	best_freq += pll->reference_freq * fb_div_frac;
	best_freq = best_freq / (ref_div * post_div);

done:
	if (best_freq == 0)
		DRM_ERROR("Couldn't find valid PLL dividers\n");

	*dot_clock_p = best_freq / 10;
	*fb_div_p = fb_div;
	*frac_fb_div_p = fb_div_frac;
	*ref_div_p = ref_div;
	*post_div_p = post_div;

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

void radeon_compute_pll(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)
{
	switch (pll->algo) {
	case PLL_ALGO_NEW:
		radeon_compute_pll_new(pll, freq, dot_clock_p, fb_div_p,
				       frac_fb_div_p, ref_div_p, post_div_p);
		break;
	case PLL_ALGO_LEGACY:
	default:
		radeon_compute_pll_legacy(pll, freq, dot_clock_p, fb_div_p,
					  frac_fb_div_p, ref_div_p, post_div_p);
		break;
	}
}

static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
{
	struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
+0 −4
Original line number Diff line number Diff line
@@ -93,7 +93,6 @@ int radeon_benchmarking = 0;
int radeon_testing = 0;
int radeon_connector_table = 0;
int radeon_tv = 1;
int radeon_new_pll = -1;
int radeon_audio = 1;
int radeon_disp_priority = 0;
int radeon_hw_i2c = 0;
@@ -131,9 +130,6 @@ 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(new_pll, "Select new PLL code");
module_param_named(new_pll, radeon_new_pll, int, 0444);

MODULE_PARM_DESC(audio, "Audio enable (0 = disable)");
module_param_named(audio, radeon_audio, int, 0444);

Loading