drm/exynos: Fix suspend/resume support
authorMarek Szyprowski <m.szyprowski@samsung.com>
Thu, 14 Sep 2017 12:01:01 +0000 (14:01 +0200)
committerInki Dae <inki.dae@samsung.com>
Tue, 19 Sep 2017 10:50:44 +0000 (19:50 +0900)
Commit 7d902c05b480 ("drm: Nuke drm_atomic_helper_connector_dpms")
removed drm_atomic_helper_connector_dpms() helper saying that it was a dead
code. It was however indirectly used by Exynos DRM driver for implementing
suspend/resume support. To fix this regression (after that patch Exynos DRM
suspend/resume functions became no-ops and hardware fails to suspend),
this patch rewrites them with drm_atomic_helper_suspend/resume() helpers.

Fixes: 7d902c05b480 ("drm: Nuke drm_atomic_helper_connector_dpms")
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.h

index 7f3cfc5dd320ba908770c48a3815d78bb196785e..e651a58c18cf2d5b743439776dd62d50b64f8a7a 100644 (file)
@@ -168,25 +168,19 @@ static struct drm_driver exynos_drm_driver = {
 static int exynos_drm_suspend(struct device *dev)
 {
        struct drm_device *drm_dev = dev_get_drvdata(dev);
-       struct drm_connector *connector;
-       struct drm_connector_list_iter conn_iter;
+       struct exynos_drm_private *private = drm_dev->dev_private;
 
        if (pm_runtime_suspended(dev) || !drm_dev)
                return 0;
 
-       drm_modeset_lock_all(drm_dev);
-       drm_connector_list_iter_begin(drm_dev, &conn_iter);
-       drm_for_each_connector_iter(connector, &conn_iter) {
-               int old_dpms = connector->dpms;
-
-               if (connector->funcs->dpms)
-                       connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
-
-               /* Set the old mode back to the connector for resume */
-               connector->dpms = old_dpms;
+       drm_kms_helper_poll_disable(drm_dev);
+       exynos_drm_fbdev_suspend(drm_dev);
+       private->suspend_state = drm_atomic_helper_suspend(drm_dev);
+       if (IS_ERR(private->suspend_state)) {
+               exynos_drm_fbdev_resume(drm_dev);
+               drm_kms_helper_poll_enable(drm_dev);
+               return PTR_ERR(private->suspend_state);
        }
-       drm_connector_list_iter_end(&conn_iter);
-       drm_modeset_unlock_all(drm_dev);
 
        return 0;
 }
@@ -194,24 +188,14 @@ static int exynos_drm_suspend(struct device *dev)
 static int exynos_drm_resume(struct device *dev)
 {
        struct drm_device *drm_dev = dev_get_drvdata(dev);
-       struct drm_connector *connector;
-       struct drm_connector_list_iter conn_iter;
+       struct exynos_drm_private *private = drm_dev->dev_private;
 
        if (pm_runtime_suspended(dev) || !drm_dev)
                return 0;
 
-       drm_modeset_lock_all(drm_dev);
-       drm_connector_list_iter_begin(drm_dev, &conn_iter);
-       drm_for_each_connector_iter(connector, &conn_iter) {
-               if (connector->funcs->dpms) {
-                       int dpms = connector->dpms;
-
-                       connector->dpms = DRM_MODE_DPMS_OFF;
-                       connector->funcs->dpms(connector, dpms);
-               }
-       }
-       drm_connector_list_iter_end(&conn_iter);
-       drm_modeset_unlock_all(drm_dev);
+       drm_atomic_helper_resume(drm_dev, private->suspend_state);
+       exynos_drm_fbdev_resume(drm_dev);
+       drm_kms_helper_poll_enable(drm_dev);
 
        return 0;
 }
index cf131c2aa23e431f13a44fe1985bad58c32da250..f8bae4cb4823653562de92a20bec51f87747d07f 100644 (file)
@@ -202,6 +202,7 @@ struct drm_exynos_file_private {
  */
 struct exynos_drm_private {
        struct drm_fb_helper *fb_helper;
+       struct drm_atomic_state *suspend_state;
 
        struct device *dma_dev;
        void *mapping;
index c3a068409b484fda04bbf837626f011beb875c1f..dfb66ecf417b5c8ba9bd26b8966a52a5f14b4aaa 100644 (file)
@@ -18,6 +18,8 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/exynos_drm.h>
 
+#include <linux/console.h>
+
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_fbdev.h"
@@ -285,3 +287,21 @@ void exynos_drm_output_poll_changed(struct drm_device *dev)
 
        drm_fb_helper_hotplug_event(fb_helper);
 }
+
+void exynos_drm_fbdev_suspend(struct drm_device *dev)
+{
+       struct exynos_drm_private *private = dev->dev_private;
+
+       console_lock();
+       drm_fb_helper_set_suspend(private->fb_helper, 1);
+       console_unlock();
+}
+
+void exynos_drm_fbdev_resume(struct drm_device *dev)
+{
+       struct exynos_drm_private *private = dev->dev_private;
+
+       console_lock();
+       drm_fb_helper_set_suspend(private->fb_helper, 0);
+       console_unlock();
+}
index 330eef87f7180b1b726ff41933874a6568b0474d..645d1bb7f665faed0dfa30bf3ab36c090a2c1c1f 100644 (file)
@@ -21,6 +21,8 @@ int exynos_drm_fbdev_init(struct drm_device *dev);
 void exynos_drm_fbdev_fini(struct drm_device *dev);
 void exynos_drm_fbdev_restore_mode(struct drm_device *dev);
 void exynos_drm_output_poll_changed(struct drm_device *dev);
+void exynos_drm_fbdev_suspend(struct drm_device *drm);
+void exynos_drm_fbdev_resume(struct drm_device *drm);
 
 #else
 
@@ -39,6 +41,14 @@ static inline void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
 
 #define exynos_drm_output_poll_changed (NULL)
 
+static inline void exynos_drm_fbdev_suspend(struct drm_device *drm)
+{
+}
+
+static inline void exynos_drm_fbdev_resume(struct drm_device *drm)
+{
+}
+
 #endif
 
 #endif