[14/23] drm/i915: Keep the TypeC port mode fixed for detect/AUX transfers

Submitted by Imre Deak on June 4, 2019, 2:58 p.m.

Details

Message ID 20190604145826.16424-15-imre.deak@intel.com
State New
Headers show
Series "drm/i915: Fix TypeC port mode switching" ( rev: 2 1 ) in Intel GFX

Not browsing as part of any series.

Commit Message

Imre Deak June 4, 2019, 2:58 p.m.
We must keep the TypeC port mode fixed for the duration of the connector
detection and each AUX transfers. Add a new TypeC lock holding it around
these two sequences. For consistency also hold the lock during the port
mode sanitization.

Whenever resetting the port mode (only during the detection for now) the
port's AUX power domain must be disabled already. Flush the async power
domain disabling work to ensure this.

A follow-up patch will make the port mode changing more robust by
postponing the change for active ports.

Cc: José Roberto de Souza <jose.souza@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c |  9 ++++++---
 drivers/gpu/drm/i915/intel_dp.c  |  7 +++++++
 drivers/gpu/drm/i915/intel_drv.h |  1 +
 drivers/gpu/drm/i915/intel_tc.c  | 34 +++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_tc.h  |  4 ++++
 5 files changed, 51 insertions(+), 4 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 2bc3b4f2c9a5..ad2f7bb2f50b 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -4235,9 +4235,12 @@  void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
 	intel_dig_port->max_lanes = intel_ddi_max_lanes(intel_dig_port);
 	intel_dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port);
 
-	intel_dig_port->tc_legacy_port = intel_port_is_tc(dev_priv, port) &&
-					 !port_info->supports_typec_usb &&
-					 !port_info->supports_tbt;
+	if (intel_port_is_tc(dev_priv, port)) {
+		bool is_legacy = !port_info->supports_typec_usb &&
+				 !port_info->supports_tbt;
+
+		intel_tc_port_init(intel_dig_port, is_legacy);
+	}
 
 	switch (port) {
 	case PORT_A:
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index e1e27662aa6d..b984410f41a4 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1190,6 +1190,7 @@  intel_dp_aux_xfer(struct intel_dp *intel_dp,
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	struct drm_i915_private *dev_priv =
 			to_i915(intel_dig_port->base.base.dev);
+	bool is_tc_port = intel_port_is_tc(dev_priv, intel_dig_port->base.port);
 	i915_reg_t ch_ctl, ch_data[5];
 	u32 aux_clock_divider;
 	enum intel_display_power_domain aux_domain =
@@ -1205,6 +1206,9 @@  intel_dp_aux_xfer(struct intel_dp *intel_dp,
 	for (i = 0; i < ARRAY_SIZE(ch_data); i++)
 		ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
 
+	if (is_tc_port)
+		intel_tc_port_lock(intel_dig_port);
+
 	aux_wakeref = intel_display_power_get(dev_priv, aux_domain);
 	pps_wakeref = pps_lock(intel_dp);
 
@@ -1355,6 +1359,9 @@  intel_dp_aux_xfer(struct intel_dp *intel_dp,
 	pps_unlock(intel_dp, pps_wakeref);
 	intel_display_power_put_async(dev_priv, aux_domain, aux_wakeref);
 
+	if (is_tc_port)
+		intel_tc_port_unlock(intel_dig_port);
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 30cd49dbd0d8..18d292dd0d9c 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1224,6 +1224,7 @@  struct intel_digital_port {
 	/* Used for DP and ICL+ TypeC/DP and TypeC/HDMI ports. */
 	enum aux_ch aux_ch;
 	enum intel_display_power_domain ddi_io_power_domain;
+	struct mutex tc_lock;
 	bool tc_legacy_port:1;
 	enum tc_port_mode tc_mode;
 
diff --git a/drivers/gpu/drm/i915/intel_tc.c b/drivers/gpu/drm/i915/intel_tc.c
index 9ebf25d7931c..fc0341dc50c5 100644
--- a/drivers/gpu/drm/i915/intel_tc.c
+++ b/drivers/gpu/drm/i915/intel_tc.c
@@ -322,6 +322,8 @@  static void intel_tc_port_reset_mode(struct intel_digital_port *dig_port)
 	enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port);
 	enum tc_port_mode old_tc_mode = dig_port->tc_mode;
 
+	intel_display_power_flush_work(dev_priv);
+
 	icl_tc_phy_disconnect(dig_port);
 	icl_tc_phy_connect(dig_port);
 
@@ -338,6 +340,8 @@  void intel_tc_port_sanitize(struct intel_digital_port *dig_port)
 	enum tc_port tc_port = intel_port_to_tc(dev_priv, encoder->port);
 	int active_links = 0;
 
+	mutex_lock(&dig_port->tc_lock);
+
 	dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port);
 	if (dig_port->dp.is_mst)
 		active_links = intel_dp_mst_encoder_active_links(dig_port);
@@ -359,6 +363,8 @@  void intel_tc_port_sanitize(struct intel_digital_port *dig_port)
 	DRM_DEBUG_DRIVER("Port %s: sanitize mode (%s)\n",
 			 tc_port_name(dev_priv, tc_port),
 			 tc_port_mode_name(dig_port->tc_mode));
+
+	mutex_unlock(&dig_port->tc_lock);
 }
 
 static bool
@@ -379,9 +385,35 @@  intel_tc_port_needs_reset(struct intel_digital_port *dig_port)
  */
 bool intel_tc_port_connected(struct intel_digital_port *dig_port)
 {
+	bool is_connected;
+
+	mutex_lock(&dig_port->tc_lock);
+
 	if (intel_tc_port_needs_reset(dig_port))
 		intel_tc_port_reset_mode(dig_port);
 
-	return tc_port_live_status_mask(dig_port) & BIT(dig_port->tc_mode);
+	is_connected = tc_port_live_status_mask(dig_port) &
+		       BIT(dig_port->tc_mode);
+
+	mutex_unlock(&dig_port->tc_lock);
+
+	return is_connected;
 }
 
+void intel_tc_port_lock(struct intel_digital_port *dig_port)
+{
+	mutex_lock(&dig_port->tc_lock);
+	/* TODO: reset the TypeC port mode if needed */
+}
+
+void intel_tc_port_unlock(struct intel_digital_port *dig_port)
+{
+	mutex_unlock(&dig_port->tc_lock);
+}
+
+void
+intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy)
+{
+	mutex_init(&dig_port->tc_lock);
+	dig_port->tc_legacy_port = is_legacy;
+}
diff --git a/drivers/gpu/drm/i915/intel_tc.h b/drivers/gpu/drm/i915/intel_tc.h
index 10f0f0d81ee4..91c6e7459cc9 100644
--- a/drivers/gpu/drm/i915/intel_tc.h
+++ b/drivers/gpu/drm/i915/intel_tc.h
@@ -12,5 +12,9 @@  u32 intel_tc_port_get_lane_info(struct intel_digital_port *dig_port);
 int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port);
 
 void intel_tc_port_sanitize(struct intel_digital_port *dig_port);
+void intel_tc_port_lock(struct intel_digital_port *dig_port);
+void intel_tc_port_unlock(struct intel_digital_port *dig_port);
+
+void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy);
 
 #endif /* __INTEL_TC_H__ */