[PATCH 10/20] drm/i915: Try to make bigjoiner work in atomic check.

Maarten Lankhorst maarten.lankhorst at linux.intel.com
Fri Aug 16 09:41:02 UTC 2019


When the clock is higher than the dotclock, try with 2 pipes enabled.
If we can enable 2, then we will go into big joiner mode, and steal
the adjacent crtc.

This only links the crtc's in software, no hardware or plane
programming is done yet. Blobs are also copied from the master's
crtc_state, so it doesn't depend at commit time on the other
crtc_state.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
---
 drivers/gpu/drm/i915/display/intel_atomic.c   |  15 +-
 drivers/gpu/drm/i915/display/intel_atomic.h   |   3 +-
 drivers/gpu/drm/i915/display/intel_display.c  | 222 +++++++++++++++++-
 .../drm/i915/display/intel_display_types.h    |   9 +
 drivers/gpu/drm/i915/display/intel_dp.c       |  26 +-
 5 files changed, 255 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c
index c442e9762ce7..e694b7157bbf 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic.c
@@ -228,25 +228,26 @@ void intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state)
 	intel_crtc_put_color_blobs(crtc_state);
 }
 
-void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state)
+void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state,
+				 const struct intel_crtc_state *from_crtc_state)
 {
 	intel_crtc_put_color_blobs(crtc_state);
 
-	if (crtc_state->uapi.degamma_lut)
+	if (from_crtc_state->uapi.degamma_lut)
 		crtc_state->hw.degamma_lut =
-			drm_property_blob_get(crtc_state->uapi.degamma_lut);
+			drm_property_blob_get(from_crtc_state->uapi.degamma_lut);
 	else
 		crtc_state->hw.degamma_lut = NULL;
 
-	if (crtc_state->uapi.gamma_lut)
+	if (from_crtc_state->uapi.gamma_lut)
 		crtc_state->hw.gamma_lut =
-			drm_property_blob_get(crtc_state->uapi.gamma_lut);
+			drm_property_blob_get(from_crtc_state->uapi.gamma_lut);
 	else
 		crtc_state->hw.gamma_lut = NULL;
 
-	if (crtc_state->uapi.ctm)
+	if (from_crtc_state->uapi.ctm)
 		crtc_state->hw.ctm =
-			drm_property_blob_get(crtc_state->uapi.ctm);
+			drm_property_blob_get(from_crtc_state->uapi.ctm);
 	else
 		crtc_state->hw.ctm = NULL;
 }
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.h b/drivers/gpu/drm/i915/display/intel_atomic.h
index 42be91e0772a..8da84d64aa04 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.h
+++ b/drivers/gpu/drm/i915/display/intel_atomic.h
@@ -36,7 +36,8 @@ struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc);
 void intel_crtc_destroy_state(struct drm_crtc *crtc,
 			       struct drm_crtc_state *state);
 void intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state);
-void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state);
+void intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state,
+				 const struct intel_crtc_state *from_crtc_state);
 struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev);
 void intel_atomic_state_clear(struct drm_atomic_state *state);
 
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 1a8e443240e0..2d06704a3951 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -7420,7 +7420,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
 				     struct intel_crtc_state *pipe_config)
 {
 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
+	struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
 	int clock_limit = dev_priv->max_dotclk_freq;
 
 	if (INTEL_GEN(dev_priv) < 4) {
@@ -7437,6 +7437,20 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
 		}
 	}
 
+	if (pipe_config->bigjoiner) {
+		/* Make sure the crtc config is halved horizontally */
+		adjusted_mode->crtc_clock /= 2;
+		adjusted_mode->crtc_hdisplay /= 2;
+		adjusted_mode->crtc_hblank_start /= 2;
+		adjusted_mode->crtc_hblank_end /= 2;
+		adjusted_mode->crtc_hsync_start /= 2;
+		adjusted_mode->crtc_hsync_end /= 2;
+		adjusted_mode->crtc_htotal /= 2;
+		adjusted_mode->crtc_hskew /= 2;
+
+		pipe_config->pipe_src_w /= 2;
+	}
+
 	if (adjusted_mode->crtc_clock > clock_limit) {
 		DRM_DEBUG_KMS("requested pixel clock (%d kHz) too high (max: %d kHz, double wide: %s)\n",
 			      adjusted_mode->crtc_clock, clock_limit,
@@ -8519,6 +8533,36 @@ static int vlv_crtc_compute_clock(struct intel_crtc *crtc,
 	return 0;
 }
 
+static int intel_crtc_compute_clock_bigjoiner(struct intel_atomic_state *state,
+					      struct intel_crtc_state *crtc_state)
+{
+	struct drm_connector *conn;
+	struct drm_connector_state *conn_state;
+	int i;
+	struct intel_crtc *master = crtc_state->bigjoiner_linked_crtc;
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+
+	for_each_new_connector_in_state(&state->base, conn, conn_state, i) {
+		struct intel_encoder *encoder =
+			to_intel_encoder(conn_state->best_encoder);
+
+		if (conn_state->crtc != &master->base)
+			continue;
+
+		if (!intel_reserve_shared_dplls(state, crtc, encoder)) {
+			DRM_DEBUG_KMS("[CRTC:%d:%s] Could not reserve shared dpll for bigjoiner\n",
+				      crtc->base.base.id, crtc->base.name);
+			return -EINVAL;
+		}
+
+		return 0;
+	}
+
+	DRM_ERROR("[CRTC:%d:%s] Could not find master encoder for calculating slave clock\n",
+		  crtc->base.base.id, crtc->base.name);
+	return -EINVAL;
+}
+
 static bool i9xx_has_pfit(struct drm_i915_private *dev_priv)
 {
 	if (IS_I830(dev_priv))
@@ -11760,6 +11804,8 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
 		to_intel_crtc_state(crtc_state);
 	int ret;
 	bool mode_changed = needs_modeset(pipe_config);
+	struct intel_atomic_state *state =
+		to_intel_atomic_state(pipe_config->uapi.state);
 
 	if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv) &&
 	    mode_changed && !pipe_config->hw.active)
@@ -11768,8 +11814,12 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
 	if (mode_changed && pipe_config->hw.enable &&
 	    dev_priv->display.crtc_compute_clock &&
 	    !WARN_ON(pipe_config->shared_dpll)) {
-		ret = dev_priv->display.crtc_compute_clock(intel_crtc,
-							   pipe_config);
+		if (pipe_config->bigjoiner_slave)
+			ret = intel_crtc_compute_clock_bigjoiner(state,
+								 pipe_config);
+		else
+			ret = dev_priv->display.crtc_compute_clock(intel_crtc,
+								   pipe_config);
 		if (ret)
 			return ret;
 	}
@@ -11783,8 +11833,15 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
 
 	if (mode_changed || pipe_config->update_pipe ||
 	    pipe_config->uapi.color_mgmt_changed) {
+		const struct intel_crtc_state *master_crtc_state = pipe_config;
+
+		if (pipe_config->bigjoiner_slave)
+			master_crtc_state =
+				intel_atomic_get_new_crtc_state(state,
+					pipe_config->bigjoiner_linked_crtc);
+
 		/* Copy color blobs to hw state */
-		intel_crtc_copy_color_blobs(pipe_config);
+		intel_crtc_copy_color_blobs(pipe_config, master_crtc_state);
 
 		ret = intel_color_check(pipe_config);
 		if (ret)
@@ -12241,6 +12298,47 @@ static void copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state)
 	crtc_state->uapi.adjusted_mode = crtc_state->hw.adjusted_mode;
 }
 
+static int
+copy_bigjoiner_crtc_state(struct intel_crtc_state *crtc_state,
+			  const struct intel_crtc_state *from_crtc_state)
+{
+	struct intel_crtc_state *saved_state;
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+
+	saved_state = kmemdup(from_crtc_state, sizeof(*saved_state), GFP_KERNEL);
+	if (!saved_state)
+		return -ENOMEM;
+
+	saved_state->uapi = crtc_state->uapi;
+	saved_state->scaler_state = crtc_state->scaler_state;
+	saved_state->shared_dpll = crtc_state->shared_dpll;
+	saved_state->dpll_hw_state = crtc_state->dpll_hw_state;
+	saved_state->crc_enabled = crtc_state->crc_enabled;
+
+	intel_crtc_free_hw_state(crtc_state);
+	memcpy(crtc_state, saved_state, sizeof(*crtc_state));
+	kfree(saved_state);
+
+	/* Re-init hw state */
+	memset(&crtc_state->hw, 0, sizeof(saved_state->hw));
+	crtc_state->hw.enable = from_crtc_state->hw.enable;
+	crtc_state->hw.active = from_crtc_state->hw.active;
+	crtc_state->hw.mode = from_crtc_state->hw.mode;
+	crtc_state->hw.adjusted_mode = from_crtc_state->hw.adjusted_mode;
+
+	/* Some fixups */
+	crtc_state->uapi.mode_changed = from_crtc_state->uapi.mode_changed;
+	crtc_state->uapi.connectors_changed = from_crtc_state->uapi.connectors_changed;
+	crtc_state->uapi.active_changed = from_crtc_state->uapi.active_changed;
+	crtc_state->nv12_planes = crtc_state->c8_planes = crtc_state->update_planes = 0;
+	crtc_state->bigjoiner_linked_crtc = to_intel_crtc(from_crtc_state->uapi.crtc);
+	crtc_state->bigjoiner_slave = true;
+	crtc_state->cpu_transcoder = (enum transcoder)crtc->pipe;
+	crtc_state->has_audio = false;
+
+	return 0;
+}
+
 static int
 clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
 {
@@ -13617,6 +13715,109 @@ static void intel_crtc_check_fastset(const struct intel_crtc_state *old_crtc_sta
 	new_crtc_state->has_drrs = old_crtc_state->has_drrs;
 }
 
+static int intel_atomic_check_bigjoiner(struct intel_atomic_state *state)
+{
+	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+	struct intel_crtc_state *old_crtc_state, *new_crtc_state, *slave_crtc_state, *master_crtc_state;
+	struct intel_crtc *crtc, *slave, *master;
+	int i, ret = 0;
+
+	if (INTEL_GEN(dev_priv) < 11)
+		return 0;
+
+	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
+					    new_crtc_state, i) {
+		if (!old_crtc_state->bigjoiner_slave)
+			continue;
+
+		if (crtc->pipe == PIPE_A) {
+			DRM_ERROR("Bigjoiner slave on pipe A?\n");
+			return -EINVAL;
+		}
+
+		/* crtc staying in slave mode? */
+		if (!new_crtc_state->uapi.enable)
+			continue;
+
+		if (needs_modeset(new_crtc_state) || new_crtc_state->update_pipe) {
+			master = old_crtc_state->bigjoiner_linked_crtc;
+			master_crtc_state = intel_atomic_get_crtc_state(&state->base, master);
+			if (IS_ERR(master_crtc_state))
+				return PTR_ERR(master_crtc_state);
+
+			/*
+			 * Force modeset on master, to recalculate bigjoiner
+			 * state.
+			 *
+			 * If master_crtc_state was not part of the atomic commit,
+			 * we will fail because the master was not deconfigured,
+			 * but at least fail below to unify the checks.
+			 */
+			master_crtc_state->uapi.mode_changed = true;
+
+			ret = drm_atomic_add_affected_planes(&state->base, &crtc->base);
+			if (ret)
+				return ret;
+
+			ret = drm_atomic_add_affected_connectors(&state->base, &crtc->base);
+			if (ret)
+				return ret;
+		}
+	}
+
+	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
+					    new_crtc_state, i) {
+		if (!new_crtc_state->uapi.enable || !new_crtc_state->bigjoiner) {
+			if (!old_crtc_state->bigjoiner)
+				continue;
+		}
+
+		if (!needs_modeset(new_crtc_state) && !new_crtc_state->update_pipe)
+			continue;
+
+		if (new_crtc_state->bigjoiner && !new_crtc_state->bigjoiner_slave) {
+			if (1 + crtc->pipe >= INTEL_INFO(dev_priv)->num_pipes) {
+				DRM_DEBUG_KMS("Big joiner configuration requires CRTC + 1 to be used, doesn't exist\n");
+				return -EINVAL;
+			}
+
+			slave = new_crtc_state->bigjoiner_linked_crtc =
+				intel_get_crtc_for_pipe(dev_priv, crtc->pipe + 1);
+			slave_crtc_state = intel_atomic_get_crtc_state(&state->base, slave);
+			if (IS_ERR(slave_crtc_state))
+				return PTR_ERR(slave_crtc_state);
+
+			if (slave_crtc_state->uapi.enable) {
+				DRM_DEBUG_KMS("[CRTC:%d:%s] Big joiner configuration requires this CRTC to be unconfigured\n",
+					      slave->base.base.id, slave->base.name);
+				return -EINVAL;
+			} else {
+				DRM_DEBUG_KMS("[CRTC:%d:%s] Used as slave for big joiner\n",
+					      slave->base.base.id, slave->base.name);
+				ret = copy_bigjoiner_crtc_state(slave_crtc_state, new_crtc_state);
+			}
+		} else {
+			master = new_crtc_state->bigjoiner_linked_crtc;
+			if (!master)
+				continue;
+
+			master_crtc_state = intel_atomic_get_crtc_state(&state->base, master);
+			if (IS_ERR(master_crtc_state))
+				return PTR_ERR(master_crtc_state);
+
+			if (!master_crtc_state->uapi.enable && !slave_crtc_state->uapi.enable) {
+				DRM_DEBUG_KMS("[CRTC:%d:%s] Disabling slave from big joiner\n",
+					      slave->base.base.id, slave->base.name);
+				ret = clear_intel_crtc_state(slave_crtc_state);
+			}
+		}
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 /**
  * intel_atomic_check - validate state object
  * @dev: drm device
@@ -13651,7 +13852,10 @@ static int intel_atomic_check(struct drm_device *dev,
 
 		if (!new_crtc_state->uapi.enable) {
 			any_ms = true;
-			clear_intel_crtc_state(new_crtc_state);
+
+			/* big joiner slave is cleared in intel_atomic_check_bigjoiner() */
+			if (!new_crtc_state->bigjoiner_slave)
+				clear_intel_crtc_state(new_crtc_state);
 			continue;
 		}
 
@@ -13665,6 +13869,10 @@ static int intel_atomic_check(struct drm_device *dev,
 			any_ms = true;
 	}
 
+	ret = intel_atomic_check_bigjoiner(state);
+	if (ret)
+		return ret;
+
 	ret = drm_dp_mst_atomic_check(&state->base);
 	if (ret)
 		goto fail;
@@ -13815,7 +14023,9 @@ static void intel_update_crtc(struct intel_crtc *crtc,
 
 	commit_pipe_config(state, old_crtc_state, new_crtc_state);
 
-	if (INTEL_GEN(dev_priv) >= 9)
+	if (new_crtc_state->bigjoiner)
+		{/* Not supported yet */}
+	else if (INTEL_GEN(dev_priv) >= 9)
 		skl_update_planes_on_crtc(state, crtc);
 	else
 		i9xx_update_planes_on_crtc(state, crtc);
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 59461d6bc238..827f5ed213f7 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -997,6 +997,15 @@ struct intel_crtc_state {
 	/* enable pipe csc? */
 	bool csc_enable;
 
+	/* enable pipe big joiner? */
+	bool bigjoiner;
+
+	/* big joiner slave crtc? */
+	bool bigjoiner_slave;
+
+	/* linked crtc for bigjoiner, either slave or master */
+	struct intel_crtc *bigjoiner_linked_crtc;
+
 	/* Display Stream compression state */
 	struct {
 		bool compression_enable;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 62a20c9e4b09..599c5fd2c804 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -2054,6 +2054,15 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
 	pipe_config->port_clock = intel_dp->common_rates[limits->max_clock];
 	pipe_config->lane_count = limits->max_lane_count;
 
+	if (adjusted_mode->crtc_clock > intel_dp_downstream_max_dotclock(intel_dp, false)) {
+		if (adjusted_mode->crtc_clock > intel_dp_downstream_max_dotclock(intel_dp, true)) {
+			DRM_DEBUG_KMS("Clock rate too high for big joiner\n");
+			return -EINVAL;
+		}
+		pipe_config->bigjoiner = true;
+		DRM_DEBUG_KMS("Using bigjoiner configuration\n");
+	}
+
 	if (intel_dp_is_edp(intel_dp)) {
 		pipe_config->dsc_params.compressed_bpp =
 			min_t(u16, drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4,
@@ -2061,6 +2070,11 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
 		pipe_config->dsc_params.slice_count =
 			drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
 							true);
+
+		if (pipe_config->bigjoiner && pipe_config->dsc_params.slice_count < 4) {
+			DRM_DEBUG_KMS("Cannot split eDP stream in bigjoiner configuration.\n");
+			return -EINVAL;
+		}
 	} else {
 		u16 dsc_max_output_bpp;
 		u8 dsc_dp_slice_count;
@@ -2070,12 +2084,12 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
 						    pipe_config->lane_count,
 						    adjusted_mode->crtc_clock,
 						    adjusted_mode->crtc_hdisplay,
-						    false);
+						    pipe_config->bigjoiner);
 		dsc_dp_slice_count =
 			intel_dp_dsc_get_slice_count(intel_dp,
 						     adjusted_mode->crtc_clock,
 						     adjusted_mode->crtc_hdisplay,
-						     false);
+						     pipe_config->bigjoiner);
 		if (!dsc_max_output_bpp || !dsc_dp_slice_count) {
 			DRM_DEBUG_KMS("Compressed BPP/Slice Count not supported\n");
 			return -EINVAL;
@@ -2090,13 +2104,13 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
 	 * is greater than the maximum Cdclock and if slice count is even
 	 * then we need to use 2 VDSC instances.
 	 */
-	if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq) {
-		if (pipe_config->dsc_params.slice_count > 1) {
-			pipe_config->dsc_params.dsc_split = true;
-		} else {
+	if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq || pipe_config->bigjoiner) {
+		if (pipe_config->dsc_params.slice_count < 2) {
 			DRM_DEBUG_KMS("Cannot split stream to use 2 VDSC instances\n");
 			return -EINVAL;
 		}
+
+		pipe_config->dsc_params.dsc_split = true;
 	}
 
 	ret = intel_dp_compute_dsc_params(intel_dp, pipe_config);
-- 
2.20.1



More information about the Intel-gfx-trybot mailing list