[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