Very strictly speaking this is possible if you have special hw and
genlocked CRTCs. In general switching a plane between two active CRTC
just won't work so well and is probably not tested at all. Just forbid
it.

The exception is when both CRTC do a full modeset, then it should be
no problem at all to move the planes around (presuming a correct
implementation) so allow that case.

I've put this into the core since I really couldn't come up with a
case where we don't want to enforce that. But if that ever happens it
would be easy to move this check into helpers.

Cc: Thierry Reding <thierry.reding at gmail.com>
Cc: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter at intel.com>
---
 drivers/gpu/drm/drm_atomic.c        | 38 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_atomic_helper.c |  1 +
 2 files changed, 39 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 434915448ea0..422183e7ee7d 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -663,6 +663,38 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
        return 0;
 }

+/* checks whether a plane has its CRTC switched while being in active use. */
+static bool
+active_plane_switching(struct drm_atomic_state *state,
+                      struct drm_plane *plane,
+                      struct drm_plane_state *plane_state)
+{
+       struct drm_crtc_state *crtc_state, *curr_crtc_state;
+
+       if (!plane->state->crtc || !plane_state->crtc)
+               return false;
+
+       if (plane->state->crtc == plane_state->crtc)
+               return false;
+
+       curr_crtc_state = plane->state->crtc->state;
+       if (!curr_crtc_state->active)
+               return false;
+
+       crtc_state = drm_atomic_get_existing_crtc_state(state,
+                                                       plane_state->crtc);
+       if (!crtc_state->active)
+               return false;
+
+       /* plane switching CRTC and both CRTC are active. This is only ok if
+        * both CRTC do a full modeset. */
+       if (drm_atomic_crtc_needs_modeset(curr_crtc_state) &&
+           drm_atomic_crtc_needs_modeset(crtc_state))
+               return false;
+
+       return true;
+}
+
 /**
  * drm_atomic_plane_check - check plane state
  * @plane: plane to check
@@ -734,6 +766,12 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
                return -ENOSPC;
        }

+       if (active_plane_switching(state->state, plane, state)) {
+               DRM_DEBUG_ATOMIC("[PLANE:%d] switching active CRTC without 
modeset\n",
+                                plane->base.id);
+               return -EINVAL;
+       }
+
        return 0;
 }

diff --git a/drivers/gpu/drm/drm_atomic_helper.c 
b/drivers/gpu/drm/drm_atomic_helper.c
index 6be0adb5a0e9..54c59ddc59a5 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -497,6 +497,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
                                         plane->base.id);
                        return ret;
                }
+
        }

        for_each_crtc_in_state(state, crtc, crtc_state, i) {
-- 
2.5.0

Reply via email to