include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / video / geode / gxfb_core.c
index fc56b8f..76e7dac 100644 (file)
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/mm.h>
-#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>
+#include <linux/cs5535.h>
 
 #include "gxfb.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 +107,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)
@@ -139,13 +170,10 @@ static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 
 static int gxfb_set_par(struct fb_info *info)
 {
-       if (info->var.bits_per_pixel > 8) {
+       if (info->var.bits_per_pixel > 8)
                info->fix.visual = FB_VISUAL_TRUECOLOR;
-               fb_dealloc_cmap(&info->cmap);
-       } else {
+       else
                info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
-               fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
-       }
 
        info->fix.line_length = gx_line_delta(info->var.xres, info->var.bits_per_pixel);
 
@@ -210,18 +238,25 @@ static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *de
        ret = pci_request_region(dev, 3, "gxfb (video processor)");
        if (ret < 0)
                return ret;
-       par->vid_regs = ioremap(pci_resource_start(dev, 3),
-                               pci_resource_len(dev, 3));
+       par->vid_regs = pci_ioremap_bar(dev, 3);
        if (!par->vid_regs)
                return -ENOMEM;
 
        ret = pci_request_region(dev, 2, "gxfb (display controller)");
        if (ret < 0)
                return ret;
-       par->dc_regs = ioremap(pci_resource_start(dev, 2), pci_resource_len(dev, 2));
+       par->dc_regs = pci_ioremap_bar(dev, 2);
        if (!par->dc_regs)
                return -ENOMEM;
 
+       ret = pci_request_region(dev, 1, "gxfb (graphics processor)");
+       if (ret < 0)
+               return ret;
+       par->gp_regs = pci_ioremap_bar(dev, 1);
+
+       if (!par->gp_regs)
+               return -ENOMEM;
+
        ret = pci_request_region(dev, 0, "gxfb (framebuffer)");
        if (ret < 0)
                return ret;
@@ -292,9 +327,50 @@ static struct fb_info * __init gxfb_init_fbinfo(struct device *dev)
 
        info->var.grayscale     = 0;
 
+       if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+               framebuffer_release(info);
+               return NULL;
+       }
+
        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 +378,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 +400,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 +416,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,9 +439,15 @@ 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)
+       if (info) {
+               fb_dealloc_cmap(&info->cmap);
                framebuffer_release(info);
+       }
        return ret;
 }
 
@@ -379,6 +467,10 @@ 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);
+
+       fb_dealloc_cmap(&info->cmap);
        pci_set_drvdata(pdev, NULL);
 
        framebuffer_release(info);
@@ -396,6 +488,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 +541,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");