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: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@linux.ie>
This commit is contained in:
parent
69b3b5e59b
commit
b27b63750d
|
@ -499,8 +499,18 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
|
|||
else
|
||||
pll = &rdev->clock.p2pll;
|
||||
|
||||
radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
|
||||
&ref_div, &post_div, pll_flags);
|
||||
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);
|
||||
|
||||
index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
|
||||
atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -871,7 +871,8 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
|
|||
* pre-DCE 3.0 r6xx hardware. This might need to be adjusted per
|
||||
* family.
|
||||
*/
|
||||
p1pll->pll_out_min = 64800;
|
||||
if (!radeon_new_pll)
|
||||
p1pll->pll_out_min = 64800;
|
||||
}
|
||||
|
||||
p1pll->pll_in_min =
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -437,6 +437,15 @@ extern void radeon_compute_pll(struct radeon_pll *pll,
|
|||
uint32_t *post_div_p,
|
||||
int flags);
|
||||
|
||||
extern 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);
|
||||
|
||||
extern void radeon_setup_encoder_clones(struct drm_device *dev);
|
||||
|
||||
struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index);
|
||||
|
|
Loading…
Reference in New Issue