]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/video/tdfxfb.c
tdfxfb: make use of DDC information about connected monitor
[linux-2.6-omap-h63xx.git] / drivers / video / tdfxfb.c
index bc6f916c53be14a25397aa85a9fa4a2d017f0f3c..89f231dc443f0b191701cae247aca0f29c4785f2 100644 (file)
@@ -487,6 +487,12 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
                return -EINVAL;
        }
 
+       if (info->monspecs.hfmax && info->monspecs.vfmax &&
+           info->monspecs.dclkmax && fb_validate_mode(var, info) < 0) {
+               DPRINTK("mode outside monitor's specs\n");
+               return -EINVAL;
+       }
+
        var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
        lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
 
@@ -1355,6 +1361,23 @@ static void tdfxfb_delete_i2c_busses(struct tdfx_par *par)
                i2c_del_adapter(&par->chan[1].adapter);
        par->chan[1].par = NULL;
 }
+
+static int tdfxfb_probe_i2c_connector(struct tdfx_par *par,
+                                     struct fb_monspecs *specs)
+{
+       u8 *edid = NULL;
+
+       DPRINTK("Probe DDC Bus\n");
+       if (par->chan[0].par)
+               edid = fb_ddc_read(&par->chan[0].adapter);
+
+       if (edid) {
+               fb_edid_to_monspecs(edid, specs);
+               kfree(edid);
+               return 0;
+       }
+       return 1;
+}
 #endif /* CONFIG_FB_3DFX_I2C */
 
 /**
@@ -1372,6 +1395,8 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
        struct tdfx_par *default_par;
        struct fb_info *info;
        int err, lpitch;
+       struct fb_monspecs *specs;
+       bool found;
 
        err = pci_enable_device(pdev);
        if (err) {
@@ -1474,15 +1499,49 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
        if (hwcursor)
                info->fix.smem_len = (info->fix.smem_len - 1024) &
                                        (PAGE_MASK << 1);
+       specs = &info->monspecs;
+       found = false;
+       info->var.bits_per_pixel = 8;
 #ifdef CONFIG_FB_3DFX_I2C
        tdfxfb_create_i2c_busses(info);
+       err = tdfxfb_probe_i2c_connector(default_par, specs);
+
+       if (!err) {
+               if (specs->modedb == NULL)
+                       DPRINTK("Unable to get Mode Database\n");
+               else {
+                       const struct fb_videomode *m;
+
+                       fb_videomode_to_modelist(specs->modedb,
+                                                specs->modedb_len,
+                                                &info->modelist);
+                       m = fb_find_best_display(specs, &info->modelist);
+                       if (m) {
+                               fb_videomode_to_var(&info->var, m);
+                               /* fill all other info->var's fields */
+                               if (tdfxfb_check_var(&info->var, info) < 0)
+                                       info->var = tdfx_var;
+                               else
+                                       found = true;
+                       }
+               }
+       }
 #endif
-       if (!mode_option)
+       if (!mode_option && !found)
                mode_option = "640x480@60";
 
-       err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
-       if (!err || err == 4)
-               info->var = tdfx_var;
+       if (mode_option) {
+               err = fb_find_mode(&info->var, info, mode_option,
+                                  specs->modedb, specs->modedb_len,
+                                  NULL, info->var.bits_per_pixel);
+               if (!err || err == 4)
+                       info->var = tdfx_var;
+       }
+
+       if (found) {
+               fb_destroy_modedb(specs->modedb);
+               specs->modedb = NULL;
+       }
 
        /* maximize virtual vertical length */
        lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3);