drm/radeon/kms: use lcd pll limits when available
Alex Deucher [Mon, 8 Mar 2010 17:55:16 +0000 (12:55 -0500)]
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>

drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_mode.h

index 0c67669..a8cd637 100644 (file)
@@ -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)
index 93783b1..e4540b2 100644 (file)
@@ -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;
index 69af81d..30a84ae 100644 (file)
@@ -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);
index ba8d806..ff5f099 100644 (file)
@@ -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;
index 1702b82..b868ffa 100644 (file)
@@ -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 */