[PATCH] savagefb: Driver updates
Antonino A. Daplas [Fri, 9 Sep 2005 20:04:35 +0000 (13:04 -0700)]
- Fallback to firmware EDID if chipset has no DDC/I2C support or if I2C
  probing failed

- Add fb_blank hook

- Fix savagefb_suspend/resume to enable driver to successfully suspend and
  resume from S3, memory or disk

Signed-off-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

drivers/video/savage/savagefb-i2c.c
drivers/video/savage/savagefb.h
drivers/video/savage/savagefb_driver.c

index 847698b..959404a 100644 (file)
@@ -259,8 +259,9 @@ static u8 *savage_do_probe_i2c_edid(struct savagefb_i2c_chan *chan)
        return buf;
 }
 
-int savagefb_probe_i2c_connector(struct savagefb_par *par, u8 **out_edid)
+int savagefb_probe_i2c_connector(struct fb_info *info, u8 **out_edid)
 {
+       struct savagefb_par *par = info->par;
        u8 *edid = NULL;
        int i;
 
@@ -270,12 +271,19 @@ int savagefb_probe_i2c_connector(struct savagefb_par *par, u8 **out_edid)
                if (edid)
                        break;
        }
+
+       if (!edid) {
+               /* try to get from firmware */
+               edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
+               if (edid)
+                       memcpy(edid, fb_firmware_edid(info->device),
+                              EDID_LENGTH);
+       }
+
        if (out_edid)
                *out_edid = edid;
-       if (!edid)
-               return 1;
 
-       return 0;
+       return (edid) ? 0 : 1;
 }
 
 MODULE_LICENSE("GPL");
index 8594b1e..d6f9474 100644 (file)
@@ -60,6 +60,7 @@
 
 #define S3_SAVAGE_SERIES(chip)    ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
 
+#define S3_MOBILE_TWISTER_SERIES(chip) ((chip==S3_TWISTER) || (chip == S3_PROSAVAGEDDR))
 
 /* Chip tags.  These are used to group the adapters into
  * related families.
@@ -73,6 +74,8 @@ typedef enum {
   S3_PROSAVAGE,
   S3_SUPERSAVAGE,
   S3_SAVAGE2000,
+  S3_PROSAVAGEDDR,
+  S3_TWISTER,
   S3_LAST
 } savage_chipset;
 
@@ -128,6 +131,10 @@ typedef enum {
 #define BCI_CMD_SET_ROP(cmd, rop)    ((cmd) |= ((rop & 0xFF) << 16))
 #define BCI_CMD_SEND_COLOR           0x00008000
 
+#define DISP_CRT     1
+#define DISP_LCD     2
+#define DISP_DFP     3
+
 struct xtimings {
        unsigned int Clock;
        unsigned int HDisplay;
@@ -166,6 +173,10 @@ struct savagefb_par {
        struct savagefb_i2c_chan chan;
        unsigned char   *edid;
        u32 pseudo_palette[16];
+       int pm_state;
+       int display_type;
+       int dvi;
+       int crtonly;
        int dacSpeedBpp;
        int maxClock;
        int minClock;
@@ -338,7 +349,7 @@ do {                       \
        } \
 }
 
-extern int savagefb_probe_i2c_connector(struct savagefb_par *par,
+extern int savagefb_probe_i2c_connector(struct fb_info *info,
                                        u8 **out_edid);
 extern void savagefb_create_i2c_busses(struct fb_info *info);
 extern void savagefb_delete_i2c_busses(struct fb_info *info);
index 117ad42..abad90a 100644 (file)
@@ -1400,6 +1400,58 @@ static int savagefb_pan_display (struct fb_var_screeninfo *var,
        return 0;
 }
 
+static int savagefb_blank(int blank, struct fb_info *info)
+{
+       struct savagefb_par *par = info->par;
+       u8 sr8 = 0, srd = 0;
+
+       if (par->display_type == DISP_CRT) {
+               vga_out8(0x3c4, 0x08);
+               sr8 = vga_in8(0x3c5);
+               sr8 |= 0x06;
+               vga_out8(0x3c5, sr8);
+               vga_out8(0x3c4, 0x0d);
+               srd = vga_in8(0x3c5);
+               srd &= 0x03;
+
+               switch (blank) {
+               case FB_BLANK_UNBLANK:
+               case FB_BLANK_NORMAL:
+                       break;
+               case FB_BLANK_VSYNC_SUSPEND:
+                       srd |= 0x10;
+                       break;
+               case FB_BLANK_HSYNC_SUSPEND:
+                       srd |= 0x40;
+                       break;
+               case FB_BLANK_POWERDOWN:
+                       srd |= 0x50;
+                       break;
+               }
+
+               vga_out8(0x3c4, 0x0d);
+               vga_out8(0x3c5, srd);
+       }
+
+       if (par->display_type == DISP_LCD ||
+           par->display_type == DISP_DFP) {
+               switch(blank) {
+               case FB_BLANK_UNBLANK:
+               case FB_BLANK_NORMAL:
+                       vga_out8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */
+                       vga_out8(0x3c5, vga_in8(0x3c5) | 0x10);
+                       break;
+               case FB_BLANK_VSYNC_SUSPEND:
+               case FB_BLANK_HSYNC_SUSPEND:
+               case FB_BLANK_POWERDOWN:
+                       vga_out8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */
+                       vga_out8(0x3c5, vga_in8(0x3c5) & ~0x10);
+                       break;
+               }
+       }
+
+       return (blank == FB_BLANK_NORMAL) ? 1 : 0;
+}
 
 static struct fb_ops savagefb_ops = {
        .owner          = THIS_MODULE,
@@ -1407,6 +1459,7 @@ static struct fb_ops savagefb_ops = {
        .fb_set_par     = savagefb_set_par,
        .fb_setcolreg   = savagefb_setcolreg,
        .fb_pan_display = savagefb_pan_display,
+       .fb_blank       = savagefb_blank,
 #if defined(CONFIG_FB_SAVAGE_ACCEL)
        .fb_fillrect    = savagefb_fillrect,
        .fb_copyarea    = savagefb_copyarea,
@@ -1583,8 +1636,7 @@ static int __devinit savage_init_hw (struct savagefb_par *par)
        static unsigned char RamSavage4[] =  { 2, 4, 8, 12, 16, 32, 64, 32 };
        static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
        static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 2, 2 };
-
-       int videoRam, videoRambytes;
+       int videoRam, videoRambytes, dvi;
 
        DBG("savage_init_hw");
 
@@ -1705,6 +1757,30 @@ static int __devinit savage_init_hw (struct savagefb_par *par)
        printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n",
                par->MCLK);
 
+       /* check for DVI/flat panel */
+       dvi = 0;
+
+       if (par->chip == S3_SAVAGE4) {
+               unsigned char sr30 = 0x00;
+
+               vga_out8(0x3c4, 0x30);
+               /* clear bit 1 */
+               vga_out8(0x3c5, vga_in8(0x3c5) & ~0x02);
+               sr30 = vga_in8(0x3c5);
+               if (sr30 & 0x02 /*0x04 */) {
+                       dvi = 1;
+                       printk("savagefb: Digital Flat Panel Detected\n");
+               }
+       }
+
+       if (S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+           (S3_MOBILE_TWISTER_SERIES(par->chip) && !par->crtonly))
+               par->display_type = DISP_LCD;
+       else if (dvi || (par->chip == S3_SAVAGE4 && par->dvi))
+               par->display_type = DISP_DFP;
+       else
+               par->display_type = DISP_CRT;
+
        /* Check LCD panel parrmation */
 
        if (par->chip == S3_SAVAGE_MX) {
@@ -1759,7 +1835,8 @@ static int __devinit savage_init_hw (struct savagefb_par *par)
                        par->SavagePanelWidth = panelX;
                        par->SavagePanelHeight = panelY;
 
-               }
+               } else
+                       par->display_type = DISP_CRT;
        }
 
        savage_get_default_par (par);
@@ -1845,15 +1922,15 @@ static int __devinit savage_init_fb_info (struct fb_info *info,
                snprintf (info->fix.id, 16, "ProSavageKM");
                break;
        case FB_ACCEL_S3TWISTER_P:
-               par->chip = S3_PROSAVAGE;
+               par->chip = S3_TWISTER;
                snprintf (info->fix.id, 16, "TwisterP");
                break;
        case FB_ACCEL_S3TWISTER_K:
-               par->chip = S3_PROSAVAGE;
+               par->chip = S3_TWISTER;
                snprintf (info->fix.id, 16, "TwisterK");
                break;
        case FB_ACCEL_PROSAVAGE_DDR:
-               par->chip = S3_PROSAVAGE;
+               par->chip = S3_PROSAVAGEDDR;
                snprintf (info->fix.id, 16, "ProSavageDDR");
                break;
        case FB_ACCEL_PROSAVAGE_DDRK:
@@ -1959,7 +2036,8 @@ static int __devinit savagefb_probe (struct pci_dev* dev,
        INIT_LIST_HEAD(&info->modelist);
 #if defined(CONFIG_FB_SAVAGE_I2C)
        savagefb_create_i2c_busses(info);
-       savagefb_probe_i2c_connector(par, &par->edid);
+       savagefb_probe_i2c_connector(info, &par->edid);
+       kfree(par->edid);
        fb_edid_to_monspecs(par->edid, &info->monspecs);
        fb_videomode_to_modelist(info->monspecs.modedb,
                                 info->monspecs.modedb_len,
@@ -2111,13 +2189,30 @@ static int savagefb_suspend (struct pci_dev* dev, pm_message_t state)
 
        DBG("savagefb_suspend");
 
+
+       par->pm_state = state.event;
+
+       /*
+        * For PM_EVENT_FREEZE, do not power down so the console
+        * can remain active.
+        */
+       if (state.event == PM_EVENT_FREEZE) {
+               dev->dev.power.power_state = state;
+               return 0;
+       }
+
        acquire_console_sem();
-       fb_set_suspend(info, pci_choose_state(dev, state));
-       savage_disable_mmio(par);
-       release_console_sem();
+       fb_set_suspend(info, 1);
 
+       if (info->fbops->fb_sync)
+               info->fbops->fb_sync(info);
+
+       savagefb_blank(FB_BLANK_POWERDOWN, info);
+       savage_disable_mmio(par);
+       pci_save_state(dev);
        pci_disable_device(dev);
        pci_set_power_state(dev, pci_choose_state(dev, state));
+       release_console_sem();
 
        return 0;
 }
@@ -2127,22 +2222,34 @@ static int savagefb_resume (struct pci_dev* dev)
        struct fb_info *info =
                (struct fb_info *)pci_get_drvdata(dev);
        struct savagefb_par *par = (struct savagefb_par *)info->par;
+       int cur_state = par->pm_state;
 
        DBG("savage_resume");
 
-       pci_set_power_state(dev, 0);
-       pci_restore_state(dev);
-       if(pci_enable_device(dev))
-               DBG("err");
+       par->pm_state = PM_EVENT_ON;
 
-       SavagePrintRegs();
+       /*
+        * The adapter was not powered down coming back from a
+        * PM_EVENT_FREEZE.
+        */
+       if (cur_state == PM_EVENT_FREEZE) {
+               pci_set_power_state(dev, PCI_D0);
+               return 0;
+       }
 
        acquire_console_sem();
 
+       pci_set_power_state(dev, PCI_D0);
+       pci_restore_state(dev);
+
+       if(pci_enable_device(dev))
+               DBG("err");
+
+       pci_set_master(dev);
        savage_enable_mmio(par);
        savage_init_hw(par);
        savagefb_set_par (info);
-
+       savagefb_blank(FB_BLANK_UNBLANK, info);
        fb_set_suspend (info, 0);
        release_console_sem();