tridentfb: various pixclock and timing improvements
authorKrzysztof Helt <krzysztof.h1@wp.pl>
Thu, 24 Jul 2008 04:31:04 +0000 (21:31 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 24 Jul 2008 17:47:36 +0000 (10:47 -0700)
This patch fixes few issues related to timings and pixclock generation:

 - disallow the pixclocks with numerator lower than
   double denominator. This fixes display instability
   for some modes.
 - choose the pixelclock with the highest
   numerator and denominator values. This improve
   image quality and fixes display instability
   for some modes.
 - make interlaced modes work.
 - set synchronization pulses polarization
   correctly.
 - horizontal synchronization timing are now
   the same as generated by X.

Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/video/tridentfb.c

index d896dee7b487b7fb90b28d48aa55031014e99a24..ff82ec1e5e4d02e3b00faa1a12c1d652973e1b3d 100644 (file)
@@ -680,10 +680,12 @@ static void set_vclk(struct tridentfb_par *par, unsigned long freq)
 
        d = 20000;
        for (k = 1; k >= 0; k--)
-               for (m = 0; m < 32; m++)
-                       for (n = 0; n < 122; n++) {
+               for (m = 0; m < 32; m++) {
+                       n = 2 * (m + 2) - 8;
+                       for (n = (n < 0 ? 0 : n); n < 122; n++) {
                                fi = ((14318l * (n + 8)) / (m + 2)) >> k;
-                               if ((di = abs(fi - freq)) < d) {
+                               di = abs(fi - freq);
+                               if (di <= d) {
                                        d = di;
                                        best_n = n;
                                        best_m = m;
@@ -692,6 +694,7 @@ static void set_vclk(struct tridentfb_par *par, unsigned long freq)
                                if (fi > freq)
                                        break;
                        }
+               }
 
        if (is_oldclock(par->chip_id)) {
                lo = best_n | (best_m << 7);
@@ -977,8 +980,8 @@ static int tridentfb_set_par(struct fb_info *info)
 
        debug("enter\n");
        hdispend = var->xres / 8 - 1;
-       hsyncstart = (var->xres + var->right_margin) / 8 - 1;
-       hsyncend = (var->xres + var->right_margin + var->hsync_len) / 8 - 1;
+       hsyncstart = (var->xres + var->right_margin) / 8;
+       hsyncend = (var->xres + var->right_margin + var->hsync_len) / 8;
        htotal = (var->xres + var->left_margin + var->right_margin +
                  var->hsync_len) / 8 - 5;
        hblankstart = hdispend + 1;
@@ -991,8 +994,22 @@ static int tridentfb_set_par(struct fb_info *info)
        vblankstart = vdispend + 1;
        vblankend = vtotal;
 
+       if (info->var.vmode & FB_VMODE_INTERLACED) {
+               vtotal /= 2;
+               vdispend /= 2;
+               vsyncstart /= 2;
+               vsyncend /= 2;
+               vblankstart /= 2;
+               vblankend /= 2;
+       }
+
        crtc_unlock(par);
        write3CE(par, CyberControl, 8);
+       tmp = 0xEB;
+       if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+               tmp &= ~0x40;
+       if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+               tmp &= ~0x80;
 
        if (par->flatpanel && var->xres < nativex) {
                /*
@@ -1000,7 +1017,7 @@ static int tridentfb_set_par(struct fb_info *info)
                 * than requested resolution decide whether
                 * we stretch or center
                 */
-               t_outb(par, 0xEB, VGA_MIS_W);
+               t_outb(par, tmp | 0xC0, VGA_MIS_W);
 
                shadowmode_on(par);
 
@@ -1010,7 +1027,7 @@ static int tridentfb_set_par(struct fb_info *info)
                        screen_stretch(par);
 
        } else {
-               t_outb(par, 0x2B, VGA_MIS_W);
+               t_outb(par, tmp, VGA_MIS_W);
                write3CE(par, CyberControl, 8);
        }
 
@@ -1071,6 +1088,10 @@ static int tridentfb_set_par(struct fb_info *info)
        tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80;
        /* enable access extended memory */
        write3X4(par, CRTCModuleTest, tmp);
+       tmp = read3CE(par, MiscIntContReg) & ~0x4;
+       if (info->var.vmode & FB_VMODE_INTERLACED)
+               tmp |= 0x4;
+       write3CE(par, MiscIntContReg, tmp);
 
        /* enable GE for text acceleration */
        write3X4(par, GraphEngReg, 0x80);