diff options
author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2015-10-02 11:10:42 +0300 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2016-03-03 17:38:20 +0200 |
commit | 92bf0f9e2a9f1ea99d86ab6b0c3a87183a67e63c (patch) | |
tree | 07dd215fe2d33e68f2f8f82866e8c85c0cf5babc /drivers/gpu/drm/omapdrm/omap_drv.c | |
parent | bfeece553335f9b9bf0d4dc9ea8a602a2248dfd6 (diff) | |
download | talos-op-linux-92bf0f9e2a9f1ea99d86ab6b0c3a87183a67e63c.tar.gz talos-op-linux-92bf0f9e2a9f1ea99d86ab6b0c3a87183a67e63c.zip |
drm/omap: fix suspend/resume handling
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>
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_drv.c')
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_drv.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index dfafdb602ad2..e21433c3fda4 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -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); |