From 92bf0f9e2a9f1ea99d86ab6b0c3a87183a67e63c Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 2 Oct 2015 11:10:42 +0300 Subject: 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 --- drivers/gpu/drm/omapdrm/omap_drv.c | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'drivers/gpu/drm/omapdrm/omap_drv.c') 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); -- cgit From 179df15fc54118fc5c949138eeccc24c54f758a1 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 21 Oct 2015 16:17:23 +0300 Subject: drm/omap: remove use of omapdss_find_mgr_from_display() In order to remove uses of 'struct omap_overlay_manager' we need to get rid of using omapdss_find_mgr_from_display() when initializing omapdrm. Instead of using omapdss_find_mgr_from_display() and mgr->id to find the dispc channel used for the given display, we can instead use omapdss_find_output_from_display(), and get the output->dispc_channel from there. We can also remove omapdss_find_mgr_from_display() as it's no longer used. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/output.c | 18 ------------------ drivers/gpu/drm/omapdrm/omap_drv.c | 8 +++++--- 2 files changed, 5 insertions(+), 21 deletions(-) (limited to 'drivers/gpu/drm/omapdrm/omap_drv.c') diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index 16072159bd24..c1c099dfd621 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -169,24 +169,6 @@ struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device } EXPORT_SYMBOL(omapdss_find_output_from_display); -struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev) -{ - struct omap_dss_device *out; - struct omap_overlay_manager *mgr; - - out = omapdss_find_output_from_display(dssdev); - - if (out == NULL) - return NULL; - - mgr = out->manager; - - omap_dss_put_device(out); - - return mgr; -} -EXPORT_SYMBOL(omapdss_find_mgr_from_display); - static const struct dss_mgr_ops *dss_mgr_ops; int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops) diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index e21433c3fda4..c69a519f5d87 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -352,7 +352,7 @@ static int omap_modeset_init(struct drm_device *dev) struct drm_connector *connector; struct drm_encoder *encoder; enum omap_channel channel; - struct omap_overlay_manager *mgr; + struct omap_dss_device *out; if (!omapdss_device_is_connected(dssdev)) continue; @@ -399,8 +399,10 @@ static int omap_modeset_init(struct drm_device *dev) * not considered. */ - mgr = omapdss_find_mgr_from_display(dssdev); - channel = mgr->id; + out = omapdss_find_output_from_display(dssdev); + channel = out->dispc_channel; + omap_dss_put_device(out); + /* * if this channel hasn't already been taken by a previously * allocated crtc, we create a new crtc for it -- cgit