[PATCH 19/20] drm/i915: Add intel_update_bigjoiner handling.

Maarten Lankhorst maarten.lankhorst at linux.intel.com
Mon Aug 12 08:55:52 UTC 2019


Enabling is done in a special sequence and to be fair, so should
plane updates be. Ideally the end user never notices the second
pipe is used, so use the vblank evasion to cover both pipes.

This way ideally everything will be tear free, and updates are
really atomic as userspace expects it.

The disable sequence still needs some love, but otherwise bigjoiner
is close to ready now.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
---
 drivers/gpu/drm/i915/display/intel_display.c | 117 ++++++++++++++++---
 drivers/gpu/drm/i915/display/intel_sprite.c  |  22 +++-
 drivers/gpu/drm/i915/display/intel_sprite.h  |   2 +-
 3 files changed, 122 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 4d943cc10c63..3836f153c3c6 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -14211,13 +14211,63 @@ static void intel_update_crtc(struct intel_crtc *crtc,
 	else
 		i9xx_update_planes_on_crtc(state, crtc);
 
-	intel_pipe_update_end(new_crtc_state);
+	intel_pipe_update_end(new_crtc_state, NULL);
 
 	if (new_crtc_state->update_pipe && !modeset &&
 	    old_crtc_state->hw.mode.private_flags & I915_MODE_FLAG_INHERITED)
 		intel_crtc_arm_fifo_underrun(crtc, new_crtc_state);
 }
 
+static void intel_update_bigjoiner(struct intel_crtc *crtc,
+				   struct intel_atomic_state *state,
+				   struct intel_crtc_state *old_crtc_state,
+				   struct intel_crtc_state *new_crtc_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+	bool modeset = needs_modeset(new_crtc_state);
+	struct intel_crtc *slave = intel_get_crtc_for_pipe(dev_priv, crtc->pipe + 1);
+	struct intel_crtc_state *new_slave_crtc_state =
+		intel_atomic_get_new_crtc_state(state, slave);
+	struct intel_crtc_state *old_slave_crtc_state =
+		intel_atomic_get_old_crtc_state(state, slave);
+
+	if (modeset) {
+		/* Enable slave first */
+		update_scanline_offset(new_slave_crtc_state);
+		drm_calc_timestamping_constants(&slave->base, &new_slave_crtc_state->hw.adjusted_mode);
+		dev_priv->display.crtc_enable(new_slave_crtc_state, state);
+
+		/* Then master */
+		update_scanline_offset(new_crtc_state);
+		drm_calc_timestamping_constants(&crtc->base, &new_crtc_state->hw.adjusted_mode);
+		dev_priv->display.crtc_enable(new_crtc_state, state);
+
+		/* vblanks work again, re-enable pipe CRC. */
+		intel_crtc_enable_pipe_crc(crtc);
+
+	} else {
+		intel_pre_plane_update(old_crtc_state, new_crtc_state);
+		intel_pre_plane_update(old_slave_crtc_state, new_slave_crtc_state);
+
+		if (new_crtc_state->update_pipe)
+			intel_encoders_update_pipe(crtc, new_crtc_state, state);
+	}
+
+	/*
+	 * Perform vblank evasion around commit operation, and make sure to
+	 * commit both planes simultaneously for best results.
+	 */
+	intel_pipe_update_start(new_crtc_state);
+
+	commit_pipe_config(state, old_crtc_state, new_crtc_state);
+	commit_pipe_config(state, old_slave_crtc_state, new_slave_crtc_state);
+
+	skl_update_planes_on_crtc(state, crtc);
+	icl_update_bigjoiner_planes_on_crtc(state, slave);
+
+	intel_pipe_update_end(new_crtc_state, new_slave_crtc_state);
+}
+
 static void intel_update_crtcs(struct intel_atomic_state *state)
 {
 	struct intel_crtc *crtc;
@@ -14236,7 +14286,7 @@ static void intel_update_crtcs(struct intel_atomic_state *state)
 static void skl_update_crtcs(struct intel_atomic_state *state)
 {
 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
-	struct intel_crtc *crtc;
+	struct intel_crtc *crtc, *slave;
 	struct intel_crtc_state *old_crtc_state, *new_crtc_state;
 	unsigned int updated = 0;
 	bool progress;
@@ -14245,11 +14295,48 @@ static void skl_update_crtcs(struct intel_atomic_state *state)
 	u8 hw_enabled_slices = dev_priv->wm.skl_hw.ddb.enabled_slices;
 	u8 required_slices = state->wm_results.ddb.enabled_slices;
 	struct skl_ddb_entry entries[I915_MAX_PIPES] = {};
+	struct skl_ddb_entry new_entries[I915_MAX_PIPES] = {};
+	const struct intel_crtc_state *slave_crtc_state;
+
+	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+		if (new_crtc_state->bigjoiner_master_crtc) {
+			/* clear dirty bit, we're updated in master */
+			state->wm_results.dirty_pipes &= drm_crtc_mask(&crtc->base);
+			continue;
+		}
+
+		if (new_crtc_state->hw.active) {
+			if (new_crtc_state->bigjoiner) {
+				slave = intel_get_crtc_for_pipe(dev_priv,
+								crtc->pipe + 1);
+				slave_crtc_state =
+					intel_atomic_get_new_crtc_state(state,
+									slave);
+
+				/* put both entries in */
+				new_entries[i].start = new_crtc_state->wm.skl.ddb.start;
+				new_entries[i].end = slave_crtc_state->wm.skl.ddb.end;
+			} else {
+				new_entries[i] = new_crtc_state->wm.skl.ddb;
+			}
+		}
 
-	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i)
 		/* ignore allocations for crtc's that have been turned off. */
-		if (new_crtc_state->hw.active)
+		if (!new_crtc_state->hw.active || needs_modeset(new_crtc_state))
+			continue;
+
+		if (old_crtc_state->bigjoiner) {
+			slave = intel_get_crtc_for_pipe(dev_priv,
+							crtc->pipe + 1);
+			slave_crtc_state =
+				intel_atomic_get_old_crtc_state(state, slave);
+
+			entries[i].start = old_crtc_state->wm.skl.ddb.start;
+			entries[i].end = slave_crtc_state->wm.skl.ddb.end;
+		} else {
 			entries[i] = old_crtc_state->wm.skl.ddb;
+		}
+	}
 
 	/* If 2nd DBuf slice required, enable it here */
 	if (INTEL_GEN(dev_priv) >= 11 && required_slices > hw_enabled_slices)
@@ -14270,16 +14357,15 @@ static void skl_update_crtcs(struct intel_atomic_state *state)
 
 			pipe = crtc->pipe;
 
-			if (updated & cmask || !new_crtc_state->hw.active)
+			if (updated & cmask || !new_crtc_state->hw.active ||
+			    new_crtc_state->bigjoiner_master_crtc)
 				continue;
 
-			if (skl_ddb_allocation_overlaps(&new_crtc_state->wm.skl.ddb,
-							entries,
+			if (skl_ddb_allocation_overlaps(&new_entries[i], entries,
 							INTEL_INFO(dev_priv)->num_pipes, i))
 				continue;
 
 			updated |= cmask;
-			entries[i] = new_crtc_state->wm.skl.ddb;
 
 			/*
 			 * If this is an already active pipe, it's DDB changed,
@@ -14287,18 +14373,23 @@ static void skl_update_crtcs(struct intel_atomic_state *state)
 			 * then we need to wait for a vblank to pass for the
 			 * new ddb allocation to take effect.
 			 */
-			if (!skl_ddb_entry_equal(&new_crtc_state->wm.skl.ddb,
-						 &old_crtc_state->wm.skl.ddb) &&
-			    !new_crtc_state->uapi.active_changed &&
+			if (!skl_ddb_entry_equal(&entries[i], &new_entries[i]) &&
+			    !needs_modeset(new_crtc_state) &&
 			    state->wm_results.dirty_pipes != updated)
 				vbl_wait = true;
 
-			intel_update_crtc(crtc, state, old_crtc_state,
-					  new_crtc_state);
+			if (new_crtc_state->bigjoiner)
+				intel_update_bigjoiner(crtc, state,
+						       old_crtc_state,
+						       new_crtc_state);
+			else
+				intel_update_crtc(crtc, state, old_crtc_state,
+						  new_crtc_state);
 
 			if (vbl_wait)
 				intel_wait_for_vblank(dev_priv, pipe);
 
+			entries[i] = new_entries[i];
 			progress = true;
 		}
 	} while (progress);
diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c
index c6ea4d5a8e85..660894488928 100644
--- a/drivers/gpu/drm/i915/display/intel_sprite.c
+++ b/drivers/gpu/drm/i915/display/intel_sprite.c
@@ -98,6 +98,8 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
 
 	/* FIXME needs to be calibrated sensibly */
 	min = vblank_start - intel_usecs_to_scanlines(adjusted_mode,
+						      new_crtc_state->bigjoiner ?
+						      2 * VBLANK_EVASION_TIME_US :
 						      VBLANK_EVASION_TIME_US);
 	max = vblank_start - 1;
 
@@ -188,7 +190,8 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
  * re-enables interrupts and verifies the update was actually completed
  * before a vblank.
  */
-void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state)
+void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state,
+			   struct intel_crtc_state *slave_crtc_state)
 {
 	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
 	enum pipe pipe = crtc->pipe;
@@ -203,15 +206,24 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state)
 	 * Would be slightly nice to just grab the vblank count and arm the
 	 * event outside of the critical section - the spinlock might spin for a
 	 * while ... */
-	if (new_crtc_state->uapi.event) {
-		WARN_ON(drm_crtc_vblank_get(&crtc->base) != 0);
+	if (new_crtc_state->uapi.event || (slave_crtc_state && slave_crtc_state->uapi.event)) {
+		if (new_crtc_state->uapi.event)
+			WARN_ON(drm_crtc_vblank_get(&crtc->base) != 0);
+		if (slave_crtc_state && slave_crtc_state->uapi.event)
+			WARN_ON(drm_crtc_vblank_get(&crtc->base) != 0);
 
 		spin_lock(&crtc->base.dev->event_lock);
-		drm_crtc_arm_vblank_event(&crtc->base,
-				          new_crtc_state->uapi.event);
+		if (new_crtc_state->uapi.event)
+			drm_crtc_arm_vblank_event(&crtc->base,
+						  new_crtc_state->uapi.event);
+		if (slave_crtc_state && slave_crtc_state->uapi.event)
+			drm_crtc_arm_vblank_event(&crtc->base,
+						  slave_crtc_state->uapi.event);
 		spin_unlock(&crtc->base.dev->event_lock);
 
 		new_crtc_state->uapi.event = NULL;
+		if (slave_crtc_state)
+			slave_crtc_state->uapi.event = NULL;
 	}
 
 	local_irq_enable();
diff --git a/drivers/gpu/drm/i915/display/intel_sprite.h b/drivers/gpu/drm/i915/display/intel_sprite.h
index 202e2fc58e6c..10ffdf834cdd 100644
--- a/drivers/gpu/drm/i915/display/intel_sprite.h
+++ b/drivers/gpu/drm/i915/display/intel_sprite.h
@@ -24,7 +24,7 @@ struct intel_plane *intel_sprite_plane_create(struct drm_i915_private *dev_priv,
 int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
 				    struct drm_file *file_priv);
 void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state);
-void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state);
+void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state, struct intel_crtc_state *slave_crtc_state);
 int intel_plane_check_stride(const struct intel_plane_state *master_plane_state,
 			     const struct intel_plane_state *plane_state);
 int intel_plane_check_src_coordinates(const struct intel_plane_state *master_plane_state,
-- 
2.20.1



More information about the Intel-gfx-trybot mailing list