With drivers supporting runtime pm it's generally not a good idea to
touch the hardware when it's off. Add an option to the commit_planes
helper to support this case.

Note that the helpers already add all planes on a crtc when a modeset
happens, hence plane updates will not be lost if drivers set this to
true.

v2: Check for NULL state->crtc before chasing the pointer. Also check
both old and new crtc if there's a switch. Finally just outright
disallow switching crtcs for a plane if the plane is in active use, on
most hardware that doesn't make sense.

Cc: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
Cc: Thierry Reding <treding at nvidia.com>
Cc: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
Cc: Laurent Pinchart <laurent.pinchart+renesas at ideasonboard.com>
Signed-off-by: Daniel Vetter <daniel.vetter at intel.com>
---
 drivers/gpu/drm/drm_atomic_helper.c    | 29 +++++++++++++++++++++++++++--
 drivers/gpu/drm/exynos/exynos_drm_fb.c |  2 +-
 drivers/gpu/drm/msm/msm_atomic.c       |  2 +-
 drivers/gpu/drm/omapdrm/omap_drv.c     |  2 +-
 drivers/gpu/drm/rcar-du/rcar_du_kms.c  |  2 +-
 drivers/gpu/drm/sti/sti_drm_drv.c      |  2 +-
 drivers/gpu/drm/tegra/drm.c            |  2 +-
 include/drm/drm_atomic_helper.h        |  3 ++-
 8 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c 
b/drivers/gpu/drm/drm_atomic_helper.c
index 99656815641d..2122c2b844da 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -471,6 +471,14 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
                if (!funcs || !funcs->atomic_check)
                        continue;

+               if (plane->state->crtc && plane_state->crtc &&
+                   plane->state->crtc != plane_state->crtc &&
+                   plane->state->crtc->state->active) {
+                       DRM_DEBUG_ATOMIC("[PLANE:%d] changing crtc while still 
active\n",
+                                        plane->base.id);
+                       return -EINVAL;
+               }
+
                ret = funcs->atomic_check(plane, plane_state);
                if (ret) {
                        DRM_DEBUG_ATOMIC("[PLANE:%d] atomic driver check 
failed\n",
@@ -995,7 +1003,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,

        drm_atomic_helper_commit_modeset_disables(dev, state);

-       drm_atomic_helper_commit_planes(dev, state);
+       drm_atomic_helper_commit_planes(dev, state, false);

        drm_atomic_helper_commit_modeset_enables(dev, state);

@@ -1110,10 +1118,16 @@ fail:
 }
 EXPORT_SYMBOL(drm_atomic_helper_prepare_planes);

+bool plane_crtc_active(struct drm_plane_state *state)
+{
+       return state->crtc && state->crtc->state->active;
+}
+
 /**
  * drm_atomic_helper_commit_planes - commit plane state
  * @dev: DRM device
  * @old_state: atomic state object with old state structures
+ * @active_only: Only commit on active CRTC if set
  *
  * This function commits the new plane state using the plane and atomic helper
  * functions for planes and crtcs. It assumes that the atomic state has already
@@ -1128,7 +1142,8 @@ EXPORT_SYMBOL(drm_atomic_helper_prepare_planes);
  * drm_atomic_helper_commit_planes_on_crtc() instead.
  */
 void drm_atomic_helper_commit_planes(struct drm_device *dev,
-                                    struct drm_atomic_state *old_state)
+                                    struct drm_atomic_state *old_state,
+                                    bool active_only)
 {
        struct drm_crtc *crtc;
        struct drm_crtc_state *old_crtc_state;
@@ -1144,6 +1159,9 @@ void drm_atomic_helper_commit_planes(struct drm_device 
*dev,
                if (!funcs || !funcs->atomic_begin)
                        continue;

+               if (active_only && !crtc->state->active)
+                       continue;
+
                funcs->atomic_begin(crtc);
        }

@@ -1155,6 +1173,10 @@ void drm_atomic_helper_commit_planes(struct drm_device 
*dev,
                if (!funcs)
                        continue;

+               if (active_only && !plane_crtc_active(plane->state) &&
+                   !plane_crtc_active(old_plane_state))
+                       continue;
+
                /*
                 * Special-case disabling the plane if drivers support it.
                 */
@@ -1174,6 +1196,9 @@ void drm_atomic_helper_commit_planes(struct drm_device 
*dev,
                if (!funcs || !funcs->atomic_flush)
                        continue;

+               if (active_only && !crtc->state->active)
+                       continue;
+
                funcs->atomic_flush(crtc);
        }
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c 
b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 2b6320e6eae2..7b383acbb5af 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -293,7 +293,7 @@ static int exynos_atomic_commit(struct drm_device *dev,
         * have the relevant clocks enabled to perform the update.
         */

-       drm_atomic_helper_commit_planes(dev, state);
+       drm_atomic_helper_commit_planes(dev, state, false);

        drm_atomic_helper_cleanup_planes(dev, state);

diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index 1b22d8bfe142..0709b97251bf 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -125,7 +125,7 @@ static void complete_commit(struct msm_commit *c)

        drm_atomic_helper_commit_modeset_disables(dev, state);

-       drm_atomic_helper_commit_planes(dev, state);
+       drm_atomic_helper_commit_planes(dev, state, false);

        drm_atomic_helper_commit_modeset_enables(dev, state);

diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c 
b/drivers/gpu/drm/omapdrm/omap_drv.c
index e888a831dd3c..0ecce79fc782 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -96,7 +96,7 @@ static void omap_atomic_complete(struct 
omap_atomic_state_commit *commit)
        dispc_runtime_get();

        drm_atomic_helper_commit_modeset_disables(dev, old_state);
-       drm_atomic_helper_commit_planes(dev, old_state);
+       drm_atomic_helper_commit_planes(dev, old_state, false);
        drm_atomic_helper_commit_modeset_enables(dev, old_state);

        omap_atomic_wait_for_completion(dev, old_state);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c 
b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index 56518eb1269a..ca12e8ca5552 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -456,7 +456,7 @@ static void rcar_du_atomic_complete(struct rcar_du_commit 
*commit)
        /* Apply the atomic update. */
        drm_atomic_helper_commit_modeset_disables(dev, old_state);
        drm_atomic_helper_commit_modeset_enables(dev, old_state);
-       drm_atomic_helper_commit_planes(dev, old_state);
+       drm_atomic_helper_commit_planes(dev, old_state, false);

        drm_atomic_helper_wait_for_vblanks(dev, old_state);

diff --git a/drivers/gpu/drm/sti/sti_drm_drv.c 
b/drivers/gpu/drm/sti/sti_drm_drv.c
index 59d558b400b3..123f1408d508 100644
--- a/drivers/gpu/drm/sti/sti_drm_drv.c
+++ b/drivers/gpu/drm/sti/sti_drm_drv.c
@@ -59,7 +59,7 @@ static void sti_drm_atomic_complete(struct sti_drm_private 
*private,
         */

        drm_atomic_helper_commit_modeset_disables(drm, state);
-       drm_atomic_helper_commit_planes(drm, state);
+       drm_atomic_helper_commit_planes(drm, state, false);
        drm_atomic_helper_commit_modeset_enables(drm, state);

        drm_atomic_helper_wait_for_vblanks(drm, state);
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index c6276aebfec3..783edc242648 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -56,7 +56,7 @@ static void tegra_atomic_complete(struct tegra_drm *tegra,
         */

        drm_atomic_helper_commit_modeset_disables(drm, state);
-       drm_atomic_helper_commit_planes(drm, state);
+       drm_atomic_helper_commit_planes(drm, state, false);
        drm_atomic_helper_commit_modeset_enables(drm, state);

        drm_atomic_helper_wait_for_vblanks(drm, state);
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index cc1fee8a12d0..c7b6aa54be37 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -55,7 +55,8 @@ void drm_atomic_helper_commit_modeset_enables(struct 
drm_device *dev,
 int drm_atomic_helper_prepare_planes(struct drm_device *dev,
                                     struct drm_atomic_state *state);
 void drm_atomic_helper_commit_planes(struct drm_device *dev,
-                                    struct drm_atomic_state *state);
+                                    struct drm_atomic_state *state,
+                                    bool active_only);
 void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
                                      struct drm_atomic_state *old_state);
 void drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state 
*old_crtc_state);
-- 
2.1.4

Reply via email to