drm/omap: fix suspend/resume handling
authorTomi Valkeinen <tomi.valkeinen@ti.com>
Fri, 2 Oct 2015 08:10:42 +0000 (11:10 +0300)
committerTomi Valkeinen <tomi.valkeinen@ti.com>
Thu, 3 Mar 2016 15:38:20 +0000 (17:38 +0200)
For legacy reasons omapdss handles system suspend/resume via PM notifier
callback, where the driver disables/resumes all the outputs.

This doesn't work well with omapdrm. What happens on suspend is that the
omapdss disables the displays while omapdrm is still happily continuing
its work, possibly waiting for an vsync irq, which will never come if
the display output is disabled, leading to timeouts and errors sent to
userspace.

This patch moves the suspend/resume handling to omapdrm, and the
suspend/resume is now done safely inside modeset lock.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
drivers/gpu/drm/omapdrm/dss/core.c
drivers/gpu/drm/omapdrm/dss/display.c
drivers/gpu/drm/omapdrm/dss/dss.h
drivers/gpu/drm/omapdrm/omap_drv.c

index 54eeb507f9b379c4c494a4f4a5b5dcbe7e9b6ea7..1f55d0aae03d053193fbb67b7ec26ccc4b6f575d 100644 (file)
@@ -165,31 +165,6 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
 #endif /* CONFIG_OMAP2_DSS_DEBUGFS */
 
 /* PLATFORM DEVICE */
-static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
-{
-       DSSDBG("pm notif %lu\n", v);
-
-       switch (v) {
-       case PM_SUSPEND_PREPARE:
-       case PM_HIBERNATION_PREPARE:
-       case PM_RESTORE_PREPARE:
-               DSSDBG("suspending displays\n");
-               return dss_suspend_all_devices();
-
-       case PM_POST_SUSPEND:
-       case PM_POST_HIBERNATION:
-       case PM_POST_RESTORE:
-               DSSDBG("resuming displays\n");
-               return dss_resume_all_devices();
-
-       default:
-               return 0;
-       }
-}
-
-static struct notifier_block omap_dss_pm_notif_block = {
-       .notifier_call = omap_dss_pm_notif,
-};
 
 static int __init omap_dss_probe(struct platform_device *pdev)
 {
@@ -211,8 +186,6 @@ static int __init omap_dss_probe(struct platform_device *pdev)
        else if (pdata->default_device)
                core.default_display_name = pdata->default_device->name;
 
-       register_pm_notifier(&omap_dss_pm_notif_block);
-
        return 0;
 
 err_debugfs:
@@ -222,8 +195,6 @@ err_debugfs:
 
 static int omap_dss_remove(struct platform_device *pdev)
 {
-       unregister_pm_notifier(&omap_dss_pm_notif_block);
-
        dss_uninitialize_debugfs();
 
        return 0;
index ef5b9027985d63e50aecd7b91177e2b2030a61bb..24c2bffa0036b3c2100e28b1b6ebbdc10d7c98c9 100644 (file)
@@ -78,42 +78,6 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev,
 }
 EXPORT_SYMBOL(omapdss_default_get_timings);
 
-int dss_suspend_all_devices(void)
-{
-       struct omap_dss_device *dssdev = NULL;
-
-       for_each_dss_dev(dssdev) {
-               if (!dssdev->driver)
-                       continue;
-
-               if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
-                       dssdev->driver->disable(dssdev);
-                       dssdev->activate_after_resume = true;
-               } else {
-                       dssdev->activate_after_resume = false;
-               }
-       }
-
-       return 0;
-}
-
-int dss_resume_all_devices(void)
-{
-       struct omap_dss_device *dssdev = NULL;
-
-       for_each_dss_dev(dssdev) {
-               if (!dssdev->driver)
-                       continue;
-
-               if (dssdev->activate_after_resume) {
-                       dssdev->driver->enable(dssdev);
-                       dssdev->activate_after_resume = false;
-               }
-       }
-
-       return 0;
-}
-
 void dss_disable_all_devices(void)
 {
        struct omap_dss_device *dssdev = NULL;
index 9a6453235585bac50eb66768afc8c5f91c4b5740..a974d46672dba06eaa7782845d392b205119a86f 100644 (file)
@@ -206,8 +206,6 @@ int dss_set_min_bus_tput(struct device *dev, unsigned long tput);
 int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *));
 
 /* display */
-int dss_suspend_all_devices(void);
-int dss_resume_all_devices(void);
 void dss_disable_all_devices(void);
 
 int display_init_sysfs(struct platform_device *pdev);
index dfafdb602ad2a058cde0cf416bf32f4b53ccd7bf..e21433c3fda4b0cd01f4b62df5d06556f8c082eb 100644 (file)
@@ -900,12 +900,52 @@ static int pdev_remove(struct platform_device *device)
 }
 
 #ifdef CONFIG_PM_SLEEP
+static int omap_drm_suspend_all_displays(void)
+{
+       struct omap_dss_device *dssdev = NULL;
+
+       for_each_dss_dev(dssdev) {
+               if (!dssdev->driver)
+                       continue;
+
+               if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+                       dssdev->driver->disable(dssdev);
+                       dssdev->activate_after_resume = true;
+               } else {
+                       dssdev->activate_after_resume = false;
+               }
+       }
+
+       return 0;
+}
+
+static int omap_drm_resume_all_displays(void)
+{
+       struct omap_dss_device *dssdev = NULL;
+
+       for_each_dss_dev(dssdev) {
+               if (!dssdev->driver)
+                       continue;
+
+               if (dssdev->activate_after_resume) {
+                       dssdev->driver->enable(dssdev);
+                       dssdev->activate_after_resume = false;
+               }
+       }
+
+       return 0;
+}
+
 static int omap_drm_suspend(struct device *dev)
 {
        struct drm_device *drm_dev = dev_get_drvdata(dev);
 
        drm_kms_helper_poll_disable(drm_dev);
 
+       drm_modeset_lock_all(drm_dev);
+       omap_drm_suspend_all_displays();
+       drm_modeset_unlock_all(drm_dev);
+
        return 0;
 }
 
@@ -913,6 +953,10 @@ static int omap_drm_resume(struct device *dev)
 {
        struct drm_device *drm_dev = dev_get_drvdata(dev);
 
+       drm_modeset_lock_all(drm_dev);
+       omap_drm_resume_all_displays();
+       drm_modeset_unlock_all(drm_dev);
+
        drm_kms_helper_poll_enable(drm_dev);
 
        return omap_gem_resume(dev);