diff options
author | Andres Salomon <dilinger@queued.net> | 2008-04-28 13:15:02 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-28 19:58:36 +0400 |
commit | 46fb6f110dfc3fc99f44cf701f66ea3e790b6a81 (patch) | |
tree | f1fd3abed10ac35bed20670bb47b83c592293d07 /drivers/video/geode/gxfb_core.c | |
parent | d1b4cc3ec5f8ddbac57ada58cbab36f5a0be38eb (diff) | |
download | linux-46fb6f110dfc3fc99f44cf701f66ea3e790b6a81.tar.xz |
gxfb: add power management functionality
This adds the ability to suspend/resume the gxfb driver, which includes:
- The addition of a Graphics Processor register table in gxfb.h, and
associated GP handling.
- Register and palette saving code; registers are stored in gxfb_par.
A few MSR values are saved as well.
- gx_powerup and gx_powerdown functions which restore/save registers and
enable/disable graphic engines.
- gxfb_suspend/gxfb_resume
Originally based on a patch by Jordan Crouse.
Signed-off-by: Andres Salomon <dilinger@debian.org>
Cc: Jordan Crouse <jordan.crouse@amd.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/geode/gxfb_core.c')
-rw-r--r-- | drivers/video/geode/gxfb_core.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index fc56b8fc1a8b..151d964c025a 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -28,6 +28,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/fb.h> +#include <linux/console.h> #include <linux/init.h> #include <linux/pci.h> #include <asm/geode.h> @@ -222,6 +223,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 +305,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; @@ -357,6 +403,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 +429,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 +449,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 |