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.d...@intel.com>
Signed-off-by: José Roberto de Souza <jose.so...@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(-)

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);
+       }
 }
 
 
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to