diff options
author | Antonino A. Daplas <adaplas@gmail.com> | 2005-09-09 16:04:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-09 16:57:59 -0400 |
commit | 13776711ce4b234b5ad153e55e8b5d6703c6b1ef (patch) | |
tree | 478de15a8709545fab36ca1d60cf7ab09018eacd /drivers/video | |
parent | 5e518d7672dea4cd7c60871e40d0490c52f01d13 (diff) |
[PATCH] savagefb: Driver updates
- 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>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/savage/savagefb-i2c.c | 16 | ||||
-rw-r--r-- | drivers/video/savage/savagefb.h | 13 | ||||
-rw-r--r-- | drivers/video/savage/savagefb_driver.c | 139 |
3 files changed, 147 insertions, 21 deletions
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index 847698b5cfe7..959404ad68f4 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c | |||
@@ -259,8 +259,9 @@ static u8 *savage_do_probe_i2c_edid(struct savagefb_i2c_chan *chan) | |||
259 | return buf; | 259 | return buf; |
260 | } | 260 | } |
261 | 261 | ||
262 | int savagefb_probe_i2c_connector(struct savagefb_par *par, u8 **out_edid) | 262 | int savagefb_probe_i2c_connector(struct fb_info *info, u8 **out_edid) |
263 | { | 263 | { |
264 | struct savagefb_par *par = info->par; | ||
264 | u8 *edid = NULL; | 265 | u8 *edid = NULL; |
265 | int i; | 266 | int i; |
266 | 267 | ||
@@ -270,12 +271,19 @@ int savagefb_probe_i2c_connector(struct savagefb_par *par, u8 **out_edid) | |||
270 | if (edid) | 271 | if (edid) |
271 | break; | 272 | break; |
272 | } | 273 | } |
274 | |||
275 | if (!edid) { | ||
276 | /* try to get from firmware */ | ||
277 | edid = kmalloc(EDID_LENGTH, GFP_KERNEL); | ||
278 | if (edid) | ||
279 | memcpy(edid, fb_firmware_edid(info->device), | ||
280 | EDID_LENGTH); | ||
281 | } | ||
282 | |||
273 | if (out_edid) | 283 | if (out_edid) |
274 | *out_edid = edid; | 284 | *out_edid = edid; |
275 | if (!edid) | ||
276 | return 1; | ||
277 | 285 | ||
278 | return 0; | 286 | return (edid) ? 0 : 1; |
279 | } | 287 | } |
280 | 288 | ||
281 | MODULE_LICENSE("GPL"); | 289 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h index 8594b1e42d71..d6f94742c9f2 100644 --- a/drivers/video/savage/savagefb.h +++ b/drivers/video/savage/savagefb.h | |||
@@ -60,6 +60,7 @@ | |||
60 | 60 | ||
61 | #define S3_SAVAGE_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000)) | 61 | #define S3_SAVAGE_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000)) |
62 | 62 | ||
63 | #define S3_MOBILE_TWISTER_SERIES(chip) ((chip==S3_TWISTER) || (chip == S3_PROSAVAGEDDR)) | ||
63 | 64 | ||
64 | /* Chip tags. These are used to group the adapters into | 65 | /* Chip tags. These are used to group the adapters into |
65 | * related families. | 66 | * related families. |
@@ -73,6 +74,8 @@ typedef enum { | |||
73 | S3_PROSAVAGE, | 74 | S3_PROSAVAGE, |
74 | S3_SUPERSAVAGE, | 75 | S3_SUPERSAVAGE, |
75 | S3_SAVAGE2000, | 76 | S3_SAVAGE2000, |
77 | S3_PROSAVAGEDDR, | ||
78 | S3_TWISTER, | ||
76 | S3_LAST | 79 | S3_LAST |
77 | } savage_chipset; | 80 | } savage_chipset; |
78 | 81 | ||
@@ -128,6 +131,10 @@ typedef enum { | |||
128 | #define BCI_CMD_SET_ROP(cmd, rop) ((cmd) |= ((rop & 0xFF) << 16)) | 131 | #define BCI_CMD_SET_ROP(cmd, rop) ((cmd) |= ((rop & 0xFF) << 16)) |
129 | #define BCI_CMD_SEND_COLOR 0x00008000 | 132 | #define BCI_CMD_SEND_COLOR 0x00008000 |
130 | 133 | ||
134 | #define DISP_CRT 1 | ||
135 | #define DISP_LCD 2 | ||
136 | #define DISP_DFP 3 | ||
137 | |||
131 | struct xtimings { | 138 | struct xtimings { |
132 | unsigned int Clock; | 139 | unsigned int Clock; |
133 | unsigned int HDisplay; | 140 | unsigned int HDisplay; |
@@ -166,6 +173,10 @@ struct savagefb_par { | |||
166 | struct savagefb_i2c_chan chan; | 173 | struct savagefb_i2c_chan chan; |
167 | unsigned char *edid; | 174 | unsigned char *edid; |
168 | u32 pseudo_palette[16]; | 175 | u32 pseudo_palette[16]; |
176 | int pm_state; | ||
177 | int display_type; | ||
178 | int dvi; | ||
179 | int crtonly; | ||
169 | int dacSpeedBpp; | 180 | int dacSpeedBpp; |
170 | int maxClock; | 181 | int maxClock; |
171 | int minClock; | 182 | int minClock; |
@@ -338,7 +349,7 @@ do { \ | |||
338 | } \ | 349 | } \ |
339 | } | 350 | } |
340 | 351 | ||
341 | extern int savagefb_probe_i2c_connector(struct savagefb_par *par, | 352 | extern int savagefb_probe_i2c_connector(struct fb_info *info, |
342 | u8 **out_edid); | 353 | u8 **out_edid); |
343 | extern void savagefb_create_i2c_busses(struct fb_info *info); | 354 | extern void savagefb_create_i2c_busses(struct fb_info *info); |
344 | extern void savagefb_delete_i2c_busses(struct fb_info *info); | 355 | extern void savagefb_delete_i2c_busses(struct fb_info *info); |
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 117ad42f120d..abad90a3702c 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c | |||
@@ -1400,6 +1400,58 @@ static int savagefb_pan_display (struct fb_var_screeninfo *var, | |||
1400 | return 0; | 1400 | return 0; |
1401 | } | 1401 | } |
1402 | 1402 | ||
1403 | static int savagefb_blank(int blank, struct fb_info *info) | ||
1404 | { | ||
1405 | struct savagefb_par *par = info->par; | ||
1406 | u8 sr8 = 0, srd = 0; | ||
1407 | |||
1408 | if (par->display_type == DISP_CRT) { | ||
1409 | vga_out8(0x3c4, 0x08); | ||
1410 | sr8 = vga_in8(0x3c5); | ||
1411 | sr8 |= 0x06; | ||
1412 | vga_out8(0x3c5, sr8); | ||
1413 | vga_out8(0x3c4, 0x0d); | ||
1414 | srd = vga_in8(0x3c5); | ||
1415 | srd &= 0x03; | ||
1416 | |||
1417 | switch (blank) { | ||
1418 | case FB_BLANK_UNBLANK: | ||
1419 | case FB_BLANK_NORMAL: | ||
1420 | break; | ||
1421 | case FB_BLANK_VSYNC_SUSPEND: | ||
1422 | srd |= 0x10; | ||
1423 | break; | ||
1424 | case FB_BLANK_HSYNC_SUSPEND: | ||
1425 | srd |= 0x40; | ||
1426 | break; | ||
1427 | case FB_BLANK_POWERDOWN: | ||
1428 | srd |= 0x50; | ||
1429 | break; | ||
1430 | } | ||
1431 | |||
1432 | vga_out8(0x3c4, 0x0d); | ||
1433 | vga_out8(0x3c5, srd); | ||
1434 | } | ||
1435 | |||
1436 | if (par->display_type == DISP_LCD || | ||
1437 | par->display_type == DISP_DFP) { | ||
1438 | switch(blank) { | ||
1439 | case FB_BLANK_UNBLANK: | ||
1440 | case FB_BLANK_NORMAL: | ||
1441 | vga_out8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */ | ||
1442 | vga_out8(0x3c5, vga_in8(0x3c5) | 0x10); | ||
1443 | break; | ||
1444 | case FB_BLANK_VSYNC_SUSPEND: | ||
1445 | case FB_BLANK_HSYNC_SUSPEND: | ||
1446 | case FB_BLANK_POWERDOWN: | ||
1447 | vga_out8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */ | ||
1448 | vga_out8(0x3c5, vga_in8(0x3c5) & ~0x10); | ||
1449 | break; | ||
1450 | } | ||
1451 | } | ||
1452 | |||
1453 | return (blank == FB_BLANK_NORMAL) ? 1 : 0; | ||
1454 | } | ||
1403 | 1455 | ||
1404 | static struct fb_ops savagefb_ops = { | 1456 | static struct fb_ops savagefb_ops = { |
1405 | .owner = THIS_MODULE, | 1457 | .owner = THIS_MODULE, |
@@ -1407,6 +1459,7 @@ static struct fb_ops savagefb_ops = { | |||
1407 | .fb_set_par = savagefb_set_par, | 1459 | .fb_set_par = savagefb_set_par, |
1408 | .fb_setcolreg = savagefb_setcolreg, | 1460 | .fb_setcolreg = savagefb_setcolreg, |
1409 | .fb_pan_display = savagefb_pan_display, | 1461 | .fb_pan_display = savagefb_pan_display, |
1462 | .fb_blank = savagefb_blank, | ||
1410 | #if defined(CONFIG_FB_SAVAGE_ACCEL) | 1463 | #if defined(CONFIG_FB_SAVAGE_ACCEL) |
1411 | .fb_fillrect = savagefb_fillrect, | 1464 | .fb_fillrect = savagefb_fillrect, |
1412 | .fb_copyarea = savagefb_copyarea, | 1465 | .fb_copyarea = savagefb_copyarea, |
@@ -1583,8 +1636,7 @@ static int __devinit savage_init_hw (struct savagefb_par *par) | |||
1583 | static unsigned char RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 }; | 1636 | static unsigned char RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 }; |
1584 | static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 }; | 1637 | static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 }; |
1585 | static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 2, 2 }; | 1638 | static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 2, 2 }; |
1586 | 1639 | int videoRam, videoRambytes, dvi; | |
1587 | int videoRam, videoRambytes; | ||
1588 | 1640 | ||
1589 | DBG("savage_init_hw"); | 1641 | DBG("savage_init_hw"); |
1590 | 1642 | ||
@@ -1705,6 +1757,30 @@ static int __devinit savage_init_hw (struct savagefb_par *par) | |||
1705 | printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n", | 1757 | printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n", |
1706 | par->MCLK); | 1758 | par->MCLK); |
1707 | 1759 | ||
1760 | /* check for DVI/flat panel */ | ||
1761 | dvi = 0; | ||
1762 | |||
1763 | if (par->chip == S3_SAVAGE4) { | ||
1764 | unsigned char sr30 = 0x00; | ||
1765 | |||
1766 | vga_out8(0x3c4, 0x30); | ||
1767 | /* clear bit 1 */ | ||
1768 | vga_out8(0x3c5, vga_in8(0x3c5) & ~0x02); | ||
1769 | sr30 = vga_in8(0x3c5); | ||
1770 | if (sr30 & 0x02 /*0x04 */) { | ||
1771 | dvi = 1; | ||
1772 | printk("savagefb: Digital Flat Panel Detected\n"); | ||
1773 | } | ||
1774 | } | ||
1775 | |||
1776 | if (S3_SAVAGE_MOBILE_SERIES(par->chip) || | ||
1777 | (S3_MOBILE_TWISTER_SERIES(par->chip) && !par->crtonly)) | ||
1778 | par->display_type = DISP_LCD; | ||
1779 | else if (dvi || (par->chip == S3_SAVAGE4 && par->dvi)) | ||
1780 | par->display_type = DISP_DFP; | ||
1781 | else | ||
1782 | par->display_type = DISP_CRT; | ||
1783 | |||
1708 | /* Check LCD panel parrmation */ | 1784 | /* Check LCD panel parrmation */ |
1709 | 1785 | ||
1710 | if (par->chip == S3_SAVAGE_MX) { | 1786 | if (par->chip == S3_SAVAGE_MX) { |
@@ -1759,7 +1835,8 @@ static int __devinit savage_init_hw (struct savagefb_par *par) | |||
1759 | par->SavagePanelWidth = panelX; | 1835 | par->SavagePanelWidth = panelX; |
1760 | par->SavagePanelHeight = panelY; | 1836 | par->SavagePanelHeight = panelY; |
1761 | 1837 | ||
1762 | } | 1838 | } else |
1839 | par->display_type = DISP_CRT; | ||
1763 | } | 1840 | } |
1764 | 1841 | ||
1765 | savage_get_default_par (par); | 1842 | savage_get_default_par (par); |
@@ -1845,15 +1922,15 @@ static int __devinit savage_init_fb_info (struct fb_info *info, | |||
1845 | snprintf (info->fix.id, 16, "ProSavageKM"); | 1922 | snprintf (info->fix.id, 16, "ProSavageKM"); |
1846 | break; | 1923 | break; |
1847 | case FB_ACCEL_S3TWISTER_P: | 1924 | case FB_ACCEL_S3TWISTER_P: |
1848 | par->chip = S3_PROSAVAGE; | 1925 | par->chip = S3_TWISTER; |
1849 | snprintf (info->fix.id, 16, "TwisterP"); | 1926 | snprintf (info->fix.id, 16, "TwisterP"); |
1850 | break; | 1927 | break; |
1851 | case FB_ACCEL_S3TWISTER_K: | 1928 | case FB_ACCEL_S3TWISTER_K: |
1852 | par->chip = S3_PROSAVAGE; | 1929 | par->chip = S3_TWISTER; |
1853 | snprintf (info->fix.id, 16, "TwisterK"); | 1930 | snprintf (info->fix.id, 16, "TwisterK"); |
1854 | break; | 1931 | break; |
1855 | case FB_ACCEL_PROSAVAGE_DDR: | 1932 | case FB_ACCEL_PROSAVAGE_DDR: |
1856 | par->chip = S3_PROSAVAGE; | 1933 | par->chip = S3_PROSAVAGEDDR; |
1857 | snprintf (info->fix.id, 16, "ProSavageDDR"); | 1934 | snprintf (info->fix.id, 16, "ProSavageDDR"); |
1858 | break; | 1935 | break; |
1859 | case FB_ACCEL_PROSAVAGE_DDRK: | 1936 | case FB_ACCEL_PROSAVAGE_DDRK: |
@@ -1959,7 +2036,8 @@ static int __devinit savagefb_probe (struct pci_dev* dev, | |||
1959 | INIT_LIST_HEAD(&info->modelist); | 2036 | INIT_LIST_HEAD(&info->modelist); |
1960 | #if defined(CONFIG_FB_SAVAGE_I2C) | 2037 | #if defined(CONFIG_FB_SAVAGE_I2C) |
1961 | savagefb_create_i2c_busses(info); | 2038 | savagefb_create_i2c_busses(info); |
1962 | savagefb_probe_i2c_connector(par, &par->edid); | 2039 | savagefb_probe_i2c_connector(info, &par->edid); |
2040 | kfree(par->edid); | ||
1963 | fb_edid_to_monspecs(par->edid, &info->monspecs); | 2041 | fb_edid_to_monspecs(par->edid, &info->monspecs); |
1964 | fb_videomode_to_modelist(info->monspecs.modedb, | 2042 | fb_videomode_to_modelist(info->monspecs.modedb, |
1965 | info->monspecs.modedb_len, | 2043 | info->monspecs.modedb_len, |
@@ -2111,13 +2189,30 @@ static int savagefb_suspend (struct pci_dev* dev, pm_message_t state) | |||
2111 | 2189 | ||
2112 | DBG("savagefb_suspend"); | 2190 | DBG("savagefb_suspend"); |
2113 | 2191 | ||
2192 | |||
2193 | par->pm_state = state.event; | ||
2194 | |||
2195 | /* | ||
2196 | * For PM_EVENT_FREEZE, do not power down so the console | ||
2197 | * can remain active. | ||
2198 | */ | ||
2199 | if (state.event == PM_EVENT_FREEZE) { | ||
2200 | dev->dev.power.power_state = state; | ||
2201 | return 0; | ||
2202 | } | ||
2203 | |||
2114 | acquire_console_sem(); | 2204 | acquire_console_sem(); |
2115 | fb_set_suspend(info, pci_choose_state(dev, state)); | 2205 | fb_set_suspend(info, 1); |
2116 | savage_disable_mmio(par); | ||
2117 | release_console_sem(); | ||
2118 | 2206 | ||
2207 | if (info->fbops->fb_sync) | ||
2208 | info->fbops->fb_sync(info); | ||
2209 | |||
2210 | savagefb_blank(FB_BLANK_POWERDOWN, info); | ||
2211 | savage_disable_mmio(par); | ||
2212 | pci_save_state(dev); | ||
2119 | pci_disable_device(dev); | 2213 | pci_disable_device(dev); |
2120 | pci_set_power_state(dev, pci_choose_state(dev, state)); | 2214 | pci_set_power_state(dev, pci_choose_state(dev, state)); |
2215 | release_console_sem(); | ||
2121 | 2216 | ||
2122 | return 0; | 2217 | return 0; |
2123 | } | 2218 | } |
@@ -2127,22 +2222,34 @@ static int savagefb_resume (struct pci_dev* dev) | |||
2127 | struct fb_info *info = | 2222 | struct fb_info *info = |
2128 | (struct fb_info *)pci_get_drvdata(dev); | 2223 | (struct fb_info *)pci_get_drvdata(dev); |
2129 | struct savagefb_par *par = (struct savagefb_par *)info->par; | 2224 | struct savagefb_par *par = (struct savagefb_par *)info->par; |
2225 | int cur_state = par->pm_state; | ||
2130 | 2226 | ||
2131 | DBG("savage_resume"); | 2227 | DBG("savage_resume"); |
2132 | 2228 | ||
2133 | pci_set_power_state(dev, 0); | 2229 | par->pm_state = PM_EVENT_ON; |
2134 | pci_restore_state(dev); | ||
2135 | if(pci_enable_device(dev)) | ||
2136 | DBG("err"); | ||
2137 | 2230 | ||
2138 | SavagePrintRegs(); | 2231 | /* |
2232 | * The adapter was not powered down coming back from a | ||
2233 | * PM_EVENT_FREEZE. | ||
2234 | */ | ||
2235 | if (cur_state == PM_EVENT_FREEZE) { | ||
2236 | pci_set_power_state(dev, PCI_D0); | ||
2237 | return 0; | ||
2238 | } | ||
2139 | 2239 | ||
2140 | acquire_console_sem(); | 2240 | acquire_console_sem(); |
2141 | 2241 | ||
2242 | pci_set_power_state(dev, PCI_D0); | ||
2243 | pci_restore_state(dev); | ||
2244 | |||
2245 | if(pci_enable_device(dev)) | ||
2246 | DBG("err"); | ||
2247 | |||
2248 | pci_set_master(dev); | ||
2142 | savage_enable_mmio(par); | 2249 | savage_enable_mmio(par); |
2143 | savage_init_hw(par); | 2250 | savage_init_hw(par); |
2144 | savagefb_set_par (info); | 2251 | savagefb_set_par (info); |
2145 | 2252 | savagefb_blank(FB_BLANK_UNBLANK, info); | |
2146 | fb_set_suspend (info, 0); | 2253 | fb_set_suspend (info, 0); |
2147 | release_console_sem(); | 2254 | release_console_sem(); |
2148 | 2255 | ||