summaryrefslogtreecommitdiff
path: root/drivers/video/fbmon.c
diff options
context:
space:
mode:
authorAntonino A. Daplas <adaplas@gmail.com>2006-06-26 07:26:29 (GMT)
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 16:58:29 (GMT)
commit3007683144b2d53008363f5a7b36a78c53710db4 (patch)
treedc738feee436ec164fb841f82d015f33e9d36e83 /drivers/video/fbmon.c
parent22f4a00fd5207a107fb81984f7b4cc09e5047b45 (diff)
downloadlinux-3007683144b2d53008363f5a7b36a78c53710db4.tar.xz
[PATCH] fbdev: More accurate sync range extrapolation
The EDID block should specify the display's operating limits (vertical and horizontal sync ranges, and maximum dot clock). If not given by the EDID block, the ranges are extrapolated from the modelist. However, the computation used is only a rough approximation, and the resulting values may not reflect the actual capability of the display. This problem is frequently encountered when the EDID block has a single entry, the single mode entry will fail validation. To prevent this, calculate the values based on the same method used in fb_validate_mode(). Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/video/fbmon.c')
-rw-r--r--drivers/video/fbmon.c28
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index fbbcb71..87b0224d 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -605,6 +605,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
DPRINTK(" Monitor Operating Limits: ");
+
for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
if (edid_is_limits_block(block)) {
specs->hfmin = H_MIN_RATE * 1000;
@@ -618,11 +619,12 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
break;
}
}
-
+
/* estimate monitor limits based on modes supported */
if (retval) {
- struct fb_videomode *modes;
+ struct fb_videomode *modes, *mode;
int num_modes, i, hz, hscan, pixclock;
+ int vtotal, htotal;
modes = fb_create_modedb(edid, &num_modes);
if (!modes) {
@@ -632,20 +634,38 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
retval = 0;
for (i = 0; i < num_modes; i++) {
- hz = modes[i].refresh;
+ mode = &modes[i];
pixclock = PICOS2KHZ(modes[i].pixclock) * 1000;
- hscan = (modes[i].yres * 105 * hz + 5000)/100;
+ htotal = mode->xres + mode->right_margin + mode->hsync_len
+ + mode->left_margin;
+ vtotal = mode->yres + mode->lower_margin + mode->vsync_len
+ + mode->upper_margin;
+
+ if (mode->vmode & FB_VMODE_INTERLACED)
+ vtotal /= 2;
+
+ if (mode->vmode & FB_VMODE_DOUBLE)
+ vtotal *= 2;
+
+ hscan = (pixclock + htotal / 2) / htotal;
+ hscan = (hscan + 500) / 1000 * 1000;
+ hz = (hscan + vtotal / 2) / vtotal;
if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
specs->dclkmax = pixclock;
+
if (specs->dclkmin == 0 || specs->dclkmin > pixclock)
specs->dclkmin = pixclock;
+
if (specs->hfmax == 0 || specs->hfmax < hscan)
specs->hfmax = hscan;
+
if (specs->hfmin == 0 || specs->hfmin > hscan)
specs->hfmin = hscan;
+
if (specs->vfmax == 0 || specs->vfmax < hz)
specs->vfmax = hz;
+
if (specs->vfmin == 0 || specs->vfmin > hz)
specs->vfmin = hz;
}