[Intel-gfx] [PATCH 32/42] drm/i915: Calculate haswell plane workaround.

Maarten Lankhorst maarten.lankhorst at linux.intel.com
Mon May 11 07:25:08 PDT 2015


Signed-off-by: Maarten Lankhorst <maarten.lankhorst at 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



More information about the Intel-gfx mailing list