diff options
author | Krzysztof Helt <krzysztof.h1@wp.pl> | 2008-07-23 21:31:04 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-24 10:47:36 -0700 |
commit | 34dec24317d6824b7db172bb0072b909a9c376f2 (patch) | |
tree | 41826b7aca0f0f7df800743acd42ee0d421c4494 | |
parent | 2c86a0c26fbe8ea218f7a267645679fb78aba8a3 (diff) |
tridentfb: various pixclock and timing improvements
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>
-rw-r--r-- | drivers/video/tridentfb.c | 35 |
1 files changed, 28 insertions, 7 deletions
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index d896dee7b48..ff82ec1e5e4 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c @@ -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); |