[PATCH 5/6] drm/i915: Reset TypeC port mode if needed before detect

Imre Deak imre.deak at intel.com
Tue Mar 24 17:23:02 UTC 2020


Signed-off-by: Imre Deak <imre.deak at intel.com>
---
 drivers/gpu/drm/i915/display/intel_ddi.c | 84 ++++++++++++++++++++----
 drivers/gpu/drm/i915/display/intel_tc.c  | 15 ++++-
 drivers/gpu/drm/i915/display/intel_tc.h  |  1 +
 3 files changed, 84 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 47ca23ef4fe3..2c21f02311bf 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -4287,27 +4287,62 @@ static int intel_hdmi_reset_link(struct intel_encoder *encoder,
 	return modeset_pipe(&crtc->base, ctx);
 }
 
-static enum intel_hotplug_state
-intel_ddi_hotplug(struct intel_encoder *encoder,
-		  struct intel_connector *connector)
+static int intel_tc_dp_reset_link(struct intel_encoder *encoder,
+				  struct drm_modeset_acquire_ctx *ctx)
 {
 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
 	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
-	enum phy phy = intel_port_to_phy(i915, encoder->port);
-	bool is_tc = intel_phy_is_tc(i915, phy);
-	struct drm_modeset_acquire_ctx ctx;
-	enum intel_hotplug_state state;
+	struct intel_dp *dp = &dig_port->dp;
+	struct intel_connector *connector = dp->attached_connector;
+	struct drm_connector_state *conn_state;
+	struct intel_crtc_state *crtc_state;
+	struct intel_crtc *crtc;
 	int ret;
 
-	state = intel_encoder_hotplug(encoder, connector);
+	if (!connector)
+		return 0;
+
+	ret = drm_modeset_lock(&i915->drm.mode_config.connection_mutex, ctx);
+	if (ret)
+		return ret;
+
+	conn_state = connector->base.state;
+
+	crtc = to_intel_crtc(conn_state->crtc);
+	if (!crtc)
+		return 0;
+
+	ret = drm_modeset_lock(&crtc->base.mutex, ctx);
+	if (ret)
+		return ret;
+
+	crtc_state = to_intel_crtc_state(crtc->base.state);
+
+	drm_WARN_ON(&i915->drm,
+		    !intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP));
+
+	if (!crtc_state->hw.active)
+		return 0;
+
+	if (conn_state->commit &&
+	    !try_wait_for_completion(&conn_state->commit->hw_done))
+		return 0;
+
+	return modeset_pipe(&crtc->base, ctx);
+}
+
+static void
+intel_ddi_reset_link(struct intel_encoder *encoder,
+		     int (*reset_fn)(struct intel_encoder *encoder,
+				     struct drm_modeset_acquire_ctx *ctx))
+{
+	struct drm_modeset_acquire_ctx ctx;
+	int ret;
 
 	drm_modeset_acquire_init(&ctx, 0);
 
 	for (;;) {
-		if (connector->base.connector_type == DRM_MODE_CONNECTOR_HDMIA)
-			ret = intel_hdmi_reset_link(encoder, &ctx);
-		else
-			ret = intel_dp_retrain_link(encoder, &ctx);
+		ret = reset_fn(encoder, &ctx);
 
 		if (ret == -EDEADLK) {
 			drm_modeset_backoff(&ctx);
@@ -4319,8 +4354,29 @@ intel_ddi_hotplug(struct intel_encoder *encoder,
 
 	drm_modeset_drop_locks(&ctx);
 	drm_modeset_acquire_fini(&ctx);
-	drm_WARN(encoder->base.dev, ret,
-		 "Acquiring modeset locks failed with %i\n", ret);
+	drm_WARN(encoder->base.dev, ret, "Resetting link failed (%i)\n", ret);
+}
+
+static enum intel_hotplug_state
+intel_ddi_hotplug(struct intel_encoder *encoder,
+		  struct intel_connector *connector)
+{
+	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+	enum phy phy = intel_port_to_phy(i915, encoder->port);
+	bool is_tc = intel_phy_is_tc(i915, phy);
+	enum intel_hotplug_state state;
+
+	if (!dig_port->dp.is_mst &&
+	    is_tc && intel_tc_port_needs_reset(dig_port))
+		intel_ddi_reset_link(encoder, intel_tc_dp_reset_link);
+
+	state = intel_encoder_hotplug(encoder, connector);
+
+	if (connector->base.connector_type == DRM_MODE_CONNECTOR_HDMIA)
+		intel_ddi_reset_link(encoder, intel_hdmi_reset_link);
+	else
+		intel_ddi_reset_link(encoder, intel_dp_retrain_link);
 
 	/*
 	 * Unpowered type-c dongles can take some time to boot and be
diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c
index 869822b4c0a3..0e349eee12c7 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.c
+++ b/drivers/gpu/drm/i915/display/intel_tc.c
@@ -478,11 +478,22 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port)
 	mutex_unlock(&dig_port->tc_lock);
 }
 
-static bool intel_tc_port_needs_reset(struct intel_digital_port *dig_port)
+static bool __intel_tc_port_needs_reset(struct intel_digital_port *dig_port)
 {
 	return intel_tc_port_get_target_mode(dig_port) != dig_port->tc_mode;
 }
 
+bool intel_tc_port_needs_reset(struct intel_digital_port *dig_port)
+{
+	bool ret;
+
+	mutex_lock(&dig_port->tc_lock);
+	ret = __intel_tc_port_needs_reset(dig_port);
+	mutex_unlock(&dig_port->tc_lock);
+
+	return ret;
+}
+
 /*
  * The type-C ports are different because even when they are connected, they may
  * not be available/usable by the graphics driver: see the comment on
@@ -516,7 +527,7 @@ static void __intel_tc_port_lock(struct intel_digital_port *dig_port,
 	mutex_lock(&dig_port->tc_lock);
 
 	if (!dig_port->tc_link_refcount &&
-	    intel_tc_port_needs_reset(dig_port))
+	    __intel_tc_port_needs_reset(dig_port))
 		intel_tc_port_reset_mode(dig_port, required_lanes);
 
 	drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref);
diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h
index 463f1b3c836f..d00d2bb43405 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.h
+++ b/drivers/gpu/drm/i915/display/intel_tc.h
@@ -25,6 +25,7 @@ void intel_tc_port_get_link(struct intel_digital_port *dig_port,
 			    int required_lanes);
 void intel_tc_port_put_link(struct intel_digital_port *dig_port);
 bool intel_tc_port_ref_held(struct intel_digital_port *dig_port);
+bool intel_tc_port_needs_reset(struct intel_digital_port *dig_port);
 
 void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy);
 
-- 
2.23.1



More information about the Intel-gfx-trybot mailing list