From 46fb6f110dfc3fc99f44cf701f66ea3e790b6a81 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Mon, 28 Apr 2008 02:15:02 -0700 Subject: 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 Cc: Jordan Crouse Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/geode/gxfb_core.c | 57 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'drivers/video/geode/gxfb_core.c') diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index fc56b8fc1a8..151d964c025 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -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 -- cgit v1.2.3