[2/3] drm/i915/icl: Probe again type-c connectors that failed

Submitted by José Roberto de Souza on Feb. 9, 2019, 1 a.m.

Details

Message ID 20190209010005.14862-2-jose.souza@intel.com
State New
Headers show
Series "Series without cover letter" ( rev: 1 ) in Intel GFX - Try Bot

Not browsing as part of any series.

Commit Message

José Roberto de Souza Feb. 9, 2019, 1 a.m.
Unpowered type-c dongles can take some time to boot and be
responsible, causing the probe to fail and sink never be detected
without further actions from userspace.

It was not a issue for older platforms because there was a hardware
bridge between DDI/DP ports and type-c controller adding a implicit
delay that hid this issue but ICL have type-c controllers integrated
to the SOC bring this issue to users.

So here after the first probe interation over every connector with
a hotplug event set, it sleeps for half a second to give some time to
dongles to be ready and then try to probe again every type-c
connector that failed in the initial probe.

Cc: Imre Deak <imre.deak@intel.com>
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
---
 drivers/gpu/drm/i915/intel_dp.c      |  3 +++
 drivers/gpu/drm/i915/intel_drv.h     |  2 +-
 drivers/gpu/drm/i915/intel_hotplug.c | 39 +++++++++++++++++++++++-----
 3 files changed, 37 insertions(+), 7 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index cf709835fb9a..b91b9700755f 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -6968,6 +6968,9 @@  intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 		I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
 	}
 
+	if (intel_port_is_tc(dev_priv, port) && !intel_dig_port->tc_legacy_port)
+		intel_dig_port->tc_delay_wa_needed = true;
+
 	return true;
 
 fail:
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index fd50c962eaa3..3ae95679c2a9 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1257,7 +1257,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;
-	bool tc_legacy_port:1;
+	bool tc_legacy_port:1, tc_delay_wa_needed:1;
 	enum tc_port_type tc_type;
 
 	void (*write_infoframe)(struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c
index 72e0203bcbb2..eeac29f2dc70 100644
--- a/drivers/gpu/drm/i915/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/intel_hotplug.c
@@ -343,7 +343,7 @@  static void i915_digport_work_func(struct work_struct *work)
 }
 
 static bool
-i915_hotplug_iterate(struct drm_device *dev, u32 hpd_event_bits)
+i915_hotplug_iterate(struct drm_device *dev, u32 hpd_event_bits, u32 *hpd_tc_delay_wa)
 {
 	struct drm_connector_list_iter conn_iter;
 	struct drm_connector *connector;
@@ -356,16 +356,27 @@  i915_hotplug_iterate(struct drm_device *dev, u32 hpd_event_bits)
 
 		intel_connector = to_intel_connector(connector);
 		intel_encoder = intel_connector->encoder;
-
 		if (!intel_encoder)
 			continue;
 
 		if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) {
+			bool ret;
+
 			DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n",
 				      connector->name, intel_encoder->hpd_pin);
 
-			changed |= intel_encoder->hotplug(intel_encoder,
-							  intel_connector);
+			ret = intel_encoder->hotplug(intel_encoder,
+						     intel_connector);
+			changed |= ret;
+
+			if (hpd_tc_delay_wa && !ret &&
+			    connector->status != connector_status_connected) {
+				struct intel_digital_port *dig_port = enc_to_dig_port(&intel_encoder->base);
+
+				if (dig_port && dig_port->tc_delay_wa_needed &&
+				    !dig_port->dp.is_mst)
+					*hpd_tc_delay_wa |= (1 << intel_encoder->hpd_pin);
+			}
 		}
 	}
 	drm_connector_list_iter_end(&conn_iter);
@@ -382,7 +393,7 @@  static void i915_hotplug_work_func(struct work_struct *work)
 		container_of(work, struct drm_i915_private, hotplug.hotplug_work);
 	struct drm_device *dev = &dev_priv->drm;
 	bool changed;
-	u32 hpd_event_bits;
+	u32 hpd_event_bits, hpd_tc_delay_wa = 0;
 
 	mutex_lock(&dev->mode_config.mutex);
 	DRM_DEBUG_KMS("running encoder hotplug functions\n");
@@ -397,12 +408,28 @@  static void i915_hotplug_work_func(struct work_struct *work)
 
 	spin_unlock_irq(&dev_priv->irq_lock);
 
-	changed = i915_hotplug_iterate(dev, hpd_event_bits);
+	changed = i915_hotplug_iterate(dev, hpd_event_bits, &hpd_tc_delay_wa);
 
 	mutex_unlock(&dev->mode_config.mutex);
 
 	if (changed)
 		drm_kms_helper_hotplug_event(dev);
+
+	/*
+	 * Unpowered type-c dongles can take some time to boot and be
+	 * responsible, so here giving some type to those dongles to power up
+	 * and then probing again.
+	 */
+	if (hpd_tc_delay_wa) {
+		msleep(500);
+
+		mutex_lock(&dev->mode_config.mutex);
+		changed = i915_hotplug_iterate(dev, hpd_tc_delay_wa, NULL);
+		mutex_unlock(&dev->mode_config.mutex);
+
+		if (changed)
+			drm_kms_helper_hotplug_event(dev);
+	}
 }