]> err.no Git - linux-2.6/blobdiff - drivers/video/geode/gxfb_core.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/tglx/linux-2.6-hrt
[linux-2.6] / drivers / video / geode / gxfb_core.c
index fc56b8fc1a8ba1b932436475dfc7f598b89b63ea..de2b8f9876a5398b1534aa77ac9c269c38e67408 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/suspend.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <asm/geode.h>
 
 static char *mode_option;
 static int vram;
+static int vt_switch;
 
 /* Modes relevant to the GX (taken from modedb.c) */
-static const struct fb_videomode gx_modedb[] __initdata = {
+static struct fb_videomode gx_modedb[] __initdata = {
        /* 640x480-60 VESA */
        { NULL, 60, 640, 480, 39682,  48, 16, 33, 10, 96, 2,
          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
@@ -105,6 +108,35 @@ static const struct fb_videomode gx_modedb[] __initdata = {
          FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 };
 
+#ifdef CONFIG_OLPC
+#include <asm/olpc.h>
+
+static struct fb_videomode gx_dcon_modedb[] __initdata = {
+       /* The only mode the DCON has is 1200x900 */
+       { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, 0 }
+};
+
+static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
+{
+       if (olpc_has_dcon()) {
+               *modedb = (struct fb_videomode *) gx_dcon_modedb;
+               *size = ARRAY_SIZE(gx_dcon_modedb);
+       } else {
+               *modedb = (struct fb_videomode *) gx_modedb;
+               *size = ARRAY_SIZE(gx_modedb);
+       }
+}
+
+#else
+static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
+{
+       *modedb = (struct fb_videomode *) gx_modedb;
+       *size = ARRAY_SIZE(gx_modedb);
+}
+#endif
+
 static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
        if (var->xres > 1600 || var->yres > 1200)
@@ -222,6 +254,15 @@ static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *de
        if (!par->dc_regs)
                return -ENOMEM;
 
+       ret = pci_request_region(dev, 1, "gxfb (graphics processor)");
+       if (ret < 0)
+               return ret;
+       par->gp_regs = ioremap(pci_resource_start(dev, 1),
+       pci_resource_len(dev, 1));
+
+       if (!par->gp_regs)
+               return -ENOMEM;
+
        ret = pci_request_region(dev, 0, "gxfb (framebuffer)");
        if (ret < 0)
                return ret;
@@ -295,6 +336,42 @@ static struct fb_info * __init gxfb_init_fbinfo(struct device *dev)
        return info;
 }
 
+#ifdef CONFIG_PM
+static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct fb_info *info = pci_get_drvdata(pdev);
+
+       if (state.event == PM_EVENT_SUSPEND) {
+               acquire_console_sem();
+               gx_powerdown(info);
+               fb_set_suspend(info, 1);
+               release_console_sem();
+       }
+
+       /* there's no point in setting PCI states; we emulate PCI, so
+        * we don't end up getting power savings anyways */
+
+       return 0;
+}
+
+static int gxfb_resume(struct pci_dev *pdev)
+{
+       struct fb_info *info = pci_get_drvdata(pdev);
+       int ret;
+
+       acquire_console_sem();
+       ret = gx_powerup(info);
+       if (ret) {
+               printk(KERN_ERR "gxfb:  power up failed!\n");
+               return ret;
+       }
+
+       fb_set_suspend(info, 0);
+       release_console_sem();
+       return 0;
+}
+#endif
+
 static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct gxfb_par *par;
@@ -302,6 +379,9 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
        int ret;
        unsigned long val;
 
+       struct fb_videomode *modedb_ptr;
+       unsigned int modedb_size;
+
        info = gxfb_init_fbinfo(&pdev->dev);
        if (!info)
                return -ENOMEM;
@@ -321,8 +401,9 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
        else
                par->enable_crt = 1;
 
+       get_modedb(&modedb_ptr, &modedb_size);
        ret = fb_find_mode(&info->var, info, mode_option,
-                          gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16);
+                          modedb_ptr, modedb_size, NULL, 16);
        if (ret == 0 || ret == 4) {
                dev_err(&pdev->dev, "could not find valid video mode\n");
                ret = -EINVAL;
@@ -336,6 +417,8 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
        gxfb_check_var(&info->var, info);
        gxfb_set_par(info);
 
+       pm_set_vt_switch(vt_switch);
+
        if (register_framebuffer(info) < 0) {
                ret = -EINVAL;
                goto err;
@@ -357,6 +440,10 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
                iounmap(par->dc_regs);
                pci_release_region(pdev, 2);
        }
+       if (par->gp_regs) {
+               iounmap(par->gp_regs);
+               pci_release_region(pdev, 1);
+       }
 
        if (info)
                framebuffer_release(info);
@@ -379,6 +466,9 @@ static void gxfb_remove(struct pci_dev *pdev)
        iounmap(par->dc_regs);
        pci_release_region(pdev, 2);
 
+       iounmap(par->gp_regs);
+       pci_release_region(pdev, 1);
+
        pci_set_drvdata(pdev, NULL);
 
        framebuffer_release(info);
@@ -396,6 +486,10 @@ static struct pci_driver gxfb_driver = {
        .id_table       = gxfb_id_table,
        .probe          = gxfb_probe,
        .remove         = gxfb_remove,
+#ifdef CONFIG_PM
+       .suspend        = gxfb_suspend,
+       .resume         = gxfb_resume,
+#endif
 };
 
 #ifndef MODULE
@@ -445,5 +539,8 @@ MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])");
 module_param(vram, int, 0);
 MODULE_PARM_DESC(vram, "video memory size");
 
+module_param(vt_switch, int, 0);
+MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume");
+
 MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX");
 MODULE_LICENSE("GPL");