forked from Minki/linux
drm/radeon/kms: use lcd pll limits when available
The bios has alternate pll output limits for LCD panels. If available, use these for pll divider calculations. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
parent
b792210e7d
commit
86cb2bbfda
@ -525,6 +525,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
|
||||
if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) {
|
||||
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
|
||||
pll->algo = dig->pll_algo;
|
||||
pll->flags |= RADEON_PLL_IS_LCD;
|
||||
}
|
||||
} else {
|
||||
if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
|
||||
|
@ -887,6 +887,20 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
|
||||
p1pll->pll_out_max =
|
||||
le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);
|
||||
|
||||
if (crev >= 4) {
|
||||
p1pll->lcd_pll_out_min =
|
||||
le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;
|
||||
if (p1pll->lcd_pll_out_min == 0)
|
||||
p1pll->lcd_pll_out_min = p1pll->pll_out_min;
|
||||
p1pll->lcd_pll_out_max =
|
||||
le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100;
|
||||
if (p1pll->lcd_pll_out_max == 0)
|
||||
p1pll->lcd_pll_out_max = p1pll->pll_out_max;
|
||||
} else {
|
||||
p1pll->lcd_pll_out_min = p1pll->pll_out_min;
|
||||
p1pll->lcd_pll_out_max = p1pll->pll_out_max;
|
||||
}
|
||||
|
||||
if (p1pll->pll_out_min == 0) {
|
||||
if (ASIC_IS_AVIVO(rdev))
|
||||
p1pll->pll_out_min = 64800;
|
||||
|
@ -633,6 +633,8 @@ bool radeon_combios_get_clock_info(struct drm_device *dev)
|
||||
p1pll->reference_div = RBIOS16(pll_info + 0x10);
|
||||
p1pll->pll_out_min = RBIOS32(pll_info + 0x12);
|
||||
p1pll->pll_out_max = RBIOS32(pll_info + 0x16);
|
||||
p1pll->lcd_pll_out_min = p1pll->pll_out_min;
|
||||
p1pll->lcd_pll_out_max = p1pll->pll_out_max;
|
||||
|
||||
if (rev > 9) {
|
||||
p1pll->pll_in_min = RBIOS32(pll_info + 0x36);
|
||||
|
@ -469,10 +469,19 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
|
||||
uint32_t best_error = 0xffffffff;
|
||||
uint32_t best_vco_diff = 1;
|
||||
uint32_t post_div;
|
||||
u32 pll_out_min, pll_out_max;
|
||||
|
||||
DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div);
|
||||
freq = freq * 1000;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (pll->flags & RADEON_PLL_USE_REF_DIV)
|
||||
min_ref_div = max_ref_div = pll->reference_div;
|
||||
else {
|
||||
@ -536,10 +545,10 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
|
||||
tmp = (uint64_t)pll->reference_freq * feedback_div;
|
||||
vco = radeon_div(tmp, ref_div);
|
||||
|
||||
if (vco < pll->pll_out_min) {
|
||||
if (vco < pll_out_min) {
|
||||
min_feed_div = feedback_div + 1;
|
||||
continue;
|
||||
} else if (vco > pll->pll_out_max) {
|
||||
} else if (vco > pll_out_max) {
|
||||
max_feed_div = feedback_div;
|
||||
continue;
|
||||
}
|
||||
@ -675,6 +684,15 @@ calc_fb_ref_div(struct radeon_pll *pll,
|
||||
{
|
||||
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 = rfixed_const(freq);
|
||||
/* max_error = ffreq * 0.0025; */
|
||||
@ -686,7 +704,7 @@ calc_fb_ref_div(struct radeon_pll *pll,
|
||||
vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac));
|
||||
vco = vco / ((*ref_div) * 10);
|
||||
|
||||
if ((vco < pll->pll_out_min) || (vco > pll->pll_out_max))
|
||||
if ((vco < pll_out_min) || (vco > pll_out_max))
|
||||
continue;
|
||||
|
||||
/* pll_out = vco / post_div; */
|
||||
@ -714,6 +732,15 @@ static void radeon_compute_pll_new(struct radeon_pll *pll,
|
||||
{
|
||||
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);
|
||||
@ -724,7 +751,7 @@ static void radeon_compute_pll_new(struct radeon_pll *pll,
|
||||
goto done;
|
||||
|
||||
vco_frequency = freq * post_div;
|
||||
if ((vco_frequency < pll->pll_out_min) || (vco_frequency > pll->pll_out_max))
|
||||
if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
|
||||
goto done;
|
||||
|
||||
if (pll->flags & RADEON_PLL_USE_REF_DIV) {
|
||||
@ -749,7 +776,7 @@ static void radeon_compute_pll_new(struct radeon_pll *pll,
|
||||
continue;
|
||||
|
||||
vco_frequency = freq * post_div;
|
||||
if ((vco_frequency < pll->pll_out_min) || (vco_frequency > pll->pll_out_max))
|
||||
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;
|
||||
|
@ -129,6 +129,7 @@ struct radeon_tmds_pll {
|
||||
#define RADEON_PLL_USE_FRAC_FB_DIV (1 << 10)
|
||||
#define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11)
|
||||
#define RADEON_PLL_USE_POST_DIV (1 << 12)
|
||||
#define RADEON_PLL_IS_LCD (1 << 13)
|
||||
|
||||
/* pll algo */
|
||||
enum radeon_pll_algo {
|
||||
@ -149,6 +150,8 @@ struct radeon_pll {
|
||||
uint32_t pll_in_max;
|
||||
uint32_t pll_out_min;
|
||||
uint32_t pll_out_max;
|
||||
uint32_t lcd_pll_out_min;
|
||||
uint32_t lcd_pll_out_max;
|
||||
uint32_t best_vco;
|
||||
|
||||
/* divider limits */
|
||||
|
Loading…
Reference in New Issue
Block a user