drm: cirrus: add power management support
authorGerd Hoffmann <kraxel@redhat.com>
Mon, 14 Apr 2014 09:34:48 +0000 (11:34 +0200)
committerDave Airlie <airlied@redhat.com>
Fri, 18 Apr 2014 03:31:49 +0000 (13:31 +1000)
cirrus kms driver lacks power management support, thus
the vga display doesn't work any more after S3 resume.

Fix this by adding suspend and resume functions.
Also make the mode_set function unblank the screen.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/cirrus/cirrus_drv.c
drivers/gpu/drm/cirrus/cirrus_mode.c

index 953fc8aea69c141cf076dcccbc1c4ed2ec775321..08ce520f61a5aa4f43823a3cc8fa30ce47315067 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/console.h>
 #include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
 
 #include "cirrus_drv.h"
 
@@ -75,6 +76,41 @@ static void cirrus_pci_remove(struct pci_dev *pdev)
        drm_put_dev(dev);
 }
 
+static int cirrus_pm_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+       struct cirrus_device *cdev = drm_dev->dev_private;
+
+       drm_kms_helper_poll_disable(drm_dev);
+
+       if (cdev->mode_info.gfbdev) {
+               console_lock();
+               fb_set_suspend(cdev->mode_info.gfbdev->helper.fbdev, 1);
+               console_unlock();
+       }
+
+       return 0;
+}
+
+static int cirrus_pm_resume(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+       struct cirrus_device *cdev = drm_dev->dev_private;
+
+       drm_helper_resume_force_mode(drm_dev);
+
+       if (cdev->mode_info.gfbdev) {
+               console_lock();
+               fb_set_suspend(cdev->mode_info.gfbdev->helper.fbdev, 0);
+               console_unlock();
+       }
+
+       drm_kms_helper_poll_enable(drm_dev);
+       return 0;
+}
+
 static const struct file_operations cirrus_driver_fops = {
        .owner = THIS_MODULE,
        .open = drm_open,
@@ -103,11 +139,17 @@ static struct drm_driver driver = {
        .dumb_destroy = drm_gem_dumb_destroy,
 };
 
+static const struct dev_pm_ops cirrus_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(cirrus_pm_suspend,
+                               cirrus_pm_resume)
+};
+
 static struct pci_driver cirrus_pci_driver = {
        .name = DRIVER_NAME,
        .id_table = pciidlist,
        .probe = cirrus_pci_probe,
        .remove = cirrus_pci_remove,
+       .driver.pm = &cirrus_pm_ops,
 };
 
 static int __init cirrus_init(void)
index 2d64aea83df21a05a74c7470ab8054350063e8df..f59433b7610c560db846a9e330a3b3a1b87c1f0b 100644 (file)
@@ -308,6 +308,9 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
 
        WREG_HDR(hdr);
        cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0);
+
+       /* Unblank (needed on S3 resume, vgabios doesn't do it then) */
+       outb(0x20, 0x3c0);
        return 0;
 }