aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorMarek Szyprowski <m.szyprowski@samsung.com>2017-09-14 14:01:01 +0200
committerInki Dae <inki.dae@samsung.com>2017-09-19 19:50:44 +0900
commit6e8edf8a7d8d98e1734ff41e5c69439419319402 (patch)
tree7834cee31827d42a0619003666907ca1c2878406 /drivers/gpu
parentdrm/exynos: Fix locking in the suspend/resume paths (diff)
downloadlinux-dev-6e8edf8a7d8d98e1734ff41e5c69439419319402.tar.xz
linux-dev-6e8edf8a7d8d98e1734ff41e5c69439419319402.zip
drm/exynos: Fix suspend/resume support
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>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c40
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c20
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.h10
4 files changed, 43 insertions, 28 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 7f3cfc5dd320..e651a58c18cf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -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;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index cf131c2aa23e..f8bae4cb4823 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -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;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index c3a068409b48..dfb66ecf417b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -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();
+}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.h b/drivers/gpu/drm/exynos/exynos_drm_fbdev.h
index 330eef87f718..645d1bb7f665 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.h
@@ -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