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: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Alex Deucher 2010-09-29 11:37:41 -04:00 committed by Dave Airlie
parent f28488c282
commit 48dfaaeb66
7 changed files with 9 additions and 278 deletions

View File

@ -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;

View File

@ -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;

View File

@ -1112,8 +1112,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;
p1pll->pll_out_min = 64800;
}
p1pll->pll_in_min =
@ -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)

View File

@ -454,13 +454,13 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d)
return n;
}
static void radeon_compute_pll_legacy(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)
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)
{
uint32_t min_ref_div = pll->min_ref_div;
uint32_t max_ref_div = pll->max_ref_div;
@ -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);

View File

@ -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);

View File

@ -717,10 +717,6 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
pll = &rdev->clock.p1pll;
pll->flags = RADEON_PLL_LEGACY;
if (radeon_new_pll == 1)
pll->algo = PLL_ALGO_NEW;
else
pll->algo = PLL_ALGO_LEGACY;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc == crtc) {

View File

@ -144,12 +144,6 @@ struct radeon_tmds_pll {
#define RADEON_PLL_USE_POST_DIV (1 << 6)
#define RADEON_PLL_IS_LCD (1 << 7)
/* pll algo */
enum radeon_pll_algo {
PLL_ALGO_LEGACY,
PLL_ALGO_NEW
};
struct radeon_pll {
/* reference frequency */
uint32_t reference_freq;
@ -182,8 +176,6 @@ struct radeon_pll {
/* pll id */
uint32_t id;
/* pll algo */
enum radeon_pll_algo algo;
};
struct radeon_i2c_chan {
@ -346,7 +338,6 @@ struct radeon_encoder_atom_dig {
/* atom lvds */
uint32_t lvds_misc;
uint16_t panel_pwr_delay;
enum radeon_pll_algo pll_algo;
struct radeon_atom_ss *ss;
/* panel mode */
struct drm_display_mode native_mode;