Signed-off-by: Maarten Lankhorst <maarten.lankho...@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 109 +++++++++++++++++++++++++----------
 drivers/gpu/drm/i915/intel_drv.h     |   2 +
 2 files changed, 81 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index 7bc78b49f9f4..7a79659dca00 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4848,35 +4848,6 @@ static bool hsw_crtc_supports_ips(struct intel_crtc 
*crtc)
        return HAS_IPS(crtc->base.dev) && crtc->pipe == PIPE_A;
 }
 
-/*
- * This implements the workaround described in the "notes" section of the mode
- * set sequence documentation. When going from no pipes or single pipe to
- * multiple pipes, and planes are enabled after the pipe, we need to wait at
- * least 2 vblanks on the first pipe before enabling planes on the second pipe.
- */
-static void haswell_mode_set_planes_workaround(struct intel_crtc *crtc)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct intel_crtc *crtc_it, *other_active_crtc = NULL;
-
-       /* We want to get the other_active_crtc only if there's only 1 other
-        * active crtc. */
-       for_each_intel_crtc(dev, crtc_it) {
-               if (!crtc_it->active || crtc_it == crtc)
-                       continue;
-
-               if (other_active_crtc)
-                       return;
-
-               other_active_crtc = crtc_it;
-       }
-       if (!other_active_crtc)
-               return;
-
-       intel_wait_for_vblank(dev, other_active_crtc->pipe);
-       intel_wait_for_vblank(dev, other_active_crtc->pipe);
-}
-
 static void haswell_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -4967,7 +4938,10 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
 
        /* If we change the relative order between pipe/planes enabling, we need
         * to change the workaround. */
-       haswell_mode_set_planes_workaround(intel_crtc);
+       if (pipe_config->hsw_workaround_pipe != INVALID_PIPE) {
+               intel_wait_for_vblank(dev, pipe_config->hsw_workaround_pipe);
+               intel_wait_for_vblank(dev, pipe_config->hsw_workaround_pipe);
+       }
 }
 
 static void ironlake_pfit_disable(struct intel_crtc *crtc)
@@ -12147,6 +12121,74 @@ done:
        return ret;
 }
 
+/*
+ * This implements the workaround described in the "notes" section of the mode
+ * set sequence documentation. When going from no pipes or single pipe to
+ * multiple pipes, and planes are enabled after the pipe, we need to wait at
+ * least 2 vblanks on the first pipe before enabling planes on the second pipe.
+ */
+static int haswell_mode_set_planes_workaround(struct drm_atomic_state *state)
+{
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *crtc_state;
+       struct intel_crtc_state *first_crtc_state = NULL, *other_crtc_state = 
NULL;
+       struct intel_crtc *intel_crtc, *first_crtc = NULL, *enabled_crtc;
+       int enabled_crtcs = 0, ret, i;
+
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+               struct intel_crtc_state *pipe_config =
+                       to_intel_crtc_state(crtc_state);
+
+               pipe_config->hsw_workaround_pipe = INVALID_PIPE;
+
+               if (!crtc_state->active)
+                       continue;
+
+               if (!needs_modeset(crtc_state)) {
+                       enabled_crtcs++;
+                       enabled_crtc = to_intel_crtc(crtc);
+                       continue;
+               }
+
+               if (first_crtc) {
+                       other_crtc_state = pipe_config;
+                       break;
+               }
+               first_crtc = to_intel_crtc(crtc);
+               first_crtc_state = pipe_config;
+       }
+
+       /* No workaround needed? */
+       if (!first_crtc || enabled_crtcs > 1)
+               return 0;
+
+       for_each_intel_crtc(state->dev, intel_crtc) {
+               if (state->crtcs[drm_crtc_index(&intel_crtc->base)])
+                       continue;
+
+               ret = drm_modeset_lock(&intel_crtc->base.mutex,
+                                      state->acquire_ctx);
+               if (ret)
+                       return ret;
+
+               if (!intel_crtc->base.state->active)
+                       continue;
+
+               /* 2 enabled crtcs means no need for w/a */
+               if (++enabled_crtcs >= 2)
+                       return 0;
+
+               enabled_crtc = intel_crtc;
+       }
+
+       if (enabled_crtcs == 1)
+               first_crtc_state->hsw_workaround_pipe = enabled_crtc->pipe;
+       else if (other_crtc_state)
+               other_crtc_state->hsw_workaround_pipe = first_crtc->pipe;
+
+       return 0;
+}
+
 /* Code that should eventually be part of atomic_check() */
 static int __intel_set_mode_checks(struct drm_atomic_state *state)
 {
@@ -12158,6 +12200,13 @@ static int __intel_set_mode_checks(struct 
drm_atomic_state *state)
                return -EINVAL;
        }
 
+       if (IS_HASWELL(state->dev)) {
+               ret = haswell_mode_set_planes_workaround(state);
+
+               if (ret)
+                       return ret;
+       }
+
        /*
         * See if the config requires any additional preparation, e.g.
         * to adjust global state with pipes off.  We need to do this
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index eb87f82b5aff..6c2ba5dbcd79 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -437,6 +437,8 @@ struct intel_crtc_state {
        int pbn;
 
        struct intel_crtc_scaler_state scaler_state;
+
+       enum pipe hsw_workaround_pipe;
 };
 
 struct intel_pipe_wm {
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to