On Tue, 2018-10-30 at 19:52 +0200, Ville Syrjälä wrote: > On Wed, Oct 10, 2018 at 02:35:07PM -0700, José Roberto de Souza > wrote: > > Some USB type-C dongles requires some time to power on before being > > able to process aux channel transactions. > > It was not a problem for older gens because there was a bridge > > between DP port and USB-C controller adding some delay but ICL > > handles type-C native. > > > > So here trying to do a aux channel transaction at each 150ms for up > > 5 > > times, before giving up. > > > > Cc: Paulo Zanoni <paulo.r.zanoni@xxxxxxxxx> > > Signed-off-by: José Roberto de Souza <jose.souza@xxxxxxxxx> > > --- > > drivers/gpu/drm/i915/i915_drv.h | 1 + > > drivers/gpu/drm/i915/intel_dp.c | 7 ++++ > > drivers/gpu/drm/i915/intel_drv.h | 6 ++- > > drivers/gpu/drm/i915/intel_hotplug.c | 58 > > ++++++++++++++++++++++++++++ > > 4 files changed, 71 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/gpu/drm/i915/i915_drv.h > > b/drivers/gpu/drm/i915/i915_drv.h > > index 3017ef037fed..b3f1fc865366 100644 > > --- a/drivers/gpu/drm/i915/i915_drv.h > > +++ b/drivers/gpu/drm/i915/i915_drv.h > > @@ -2810,6 +2810,7 @@ enum hpd_pin intel_hpd_pin_default(struct > > drm_i915_private *dev_priv, > > enum port port); > > bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum > > hpd_pin pin); > > void intel_hpd_enable(struct drm_i915_private *dev_priv, enum > > hpd_pin pin); > > +void intel_hotplug_tc_wa_work(struct work_struct *__work); > > > > /* i915_irq.c */ > > static inline void i915_queue_hangcheck(struct drm_i915_private > > *dev_priv) > > diff --git a/drivers/gpu/drm/i915/intel_dp.c > > b/drivers/gpu/drm/i915/intel_dp.c > > index 60e62a3c1e22..b945385cd5bc 100644 > > --- a/drivers/gpu/drm/i915/intel_dp.c > > +++ b/drivers/gpu/drm/i915/intel_dp.c > > @@ -5289,6 +5289,7 @@ void intel_dp_encoder_destroy(struct > > drm_encoder *encoder) > > { > > struct intel_digital_port *intel_dig_port = > > enc_to_dig_port(encoder); > > struct intel_dp *intel_dp = &intel_dig_port->dp; > > + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); > > > > intel_dp_mst_encoder_cleanup(intel_dig_port); > > if (intel_dp_is_edp(intel_dp)) { > > @@ -5305,6 +5306,8 @@ void intel_dp_encoder_destroy(struct > > drm_encoder *encoder) > > unregister_reboot_notifier(&intel_dp- > > >edp_notifier); > > intel_dp->edp_notifier.notifier_call = NULL; > > } > > + } else if (IS_ICELAKE(dev_priv)) { > > + cancel_delayed_work_sync(&intel_dp->tc_wa_work); > > } > > > > intel_dp_aux_fini(intel_dp); > > @@ -6663,6 +6666,10 @@ intel_dp_init_connector(struct > > intel_digital_port *intel_dig_port, > > I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); > > } > > > > + if (IS_ICELAKE(dev_priv) && !intel_dp_is_edp(intel_dp)) > > + INIT_DELAYED_WORK(&intel_dp->tc_wa_work, > > + intel_hotplug_tc_wa_work); > > + > > return true; > > > > fail: > > diff --git a/drivers/gpu/drm/i915/intel_drv.h > > b/drivers/gpu/drm/i915/intel_drv.h > > index 3dea7a1bda7f..174a54aa966a 100644 > > --- a/drivers/gpu/drm/i915/intel_drv.h > > +++ b/drivers/gpu/drm/i915/intel_drv.h > > @@ -1100,7 +1100,11 @@ struct intel_dp { > > int panel_power_cycle_delay; > > int backlight_on_delay; > > int backlight_off_delay; > > - struct delayed_work panel_vdd_work; > > + union { > > + struct delayed_work panel_vdd_work; > > + struct delayed_work tc_wa_work; > > + }; > > + u8 tc_wa_count; > > bool want_panel_vdd; > > unsigned long last_power_on; > > unsigned long last_backlight_off; > > diff --git a/drivers/gpu/drm/i915/intel_hotplug.c > > b/drivers/gpu/drm/i915/intel_hotplug.c > > index 648a13c6043c..96546067f832 100644 > > --- a/drivers/gpu/drm/i915/intel_hotplug.c > > +++ b/drivers/gpu/drm/i915/intel_hotplug.c > > @@ -323,6 +323,45 @@ static void i915_digport_work_func(struct > > work_struct *work) > > } > > } > > > > +#define TC_WA_DELAY_MSEC 150 > > +#define TC_WA_TRIES 5 > > + > > +void intel_hotplug_tc_wa_work(struct work_struct *__work) > > +{ > > + struct intel_dp *intel_dp = > > container_of(to_delayed_work(__work), > > + struct intel_dp, > > tc_wa_work); > > + struct intel_digital_port *intel_dig_port = > > dp_to_dig_port(intel_dp); > > + struct intel_encoder *intel_encoder = &intel_dig_port->base; > > + struct intel_connector *intel_connector = intel_dp- > > >attached_connector; > > + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); > > + struct drm_device *dev = &dev_priv->drm; > > + u8 val; > > + > > + if (!intel_port_is_tc(dev_priv, intel_encoder->port) || > > + !intel_digital_port_connected(intel_encoder)) > > + return; > > + > > + if (drm_dp_dpcd_read(&intel_dp->aux, DP_DPCD_REV, &val, 1) < 1) > > { > > + intel_dp->tc_wa_count++; > > + > > + if (intel_dp->tc_wa_count < TC_WA_TRIES) { > > + unsigned long delay; > > + > > + delay = msecs_to_jiffies(TC_WA_DELAY_MSEC); > > + schedule_delayed_work(&intel_dp->tc_wa_work, > > delay); > > + } else { > > + DRM_DEBUG_KMS("TC not responsive, giving > > up\n"); > > + } > > + } else { > > + mutex_lock(&dev->mode_config.mutex); > > + val = intel_encoder->hotplug(intel_encoder, > > intel_connector); > > + mutex_unlock(&dev->mode_config.mutex); > > + > > + if (val) > > + drm_kms_helper_hotplug_event(dev); > > + } > > +} > > + > > /* > > * Handle hotplug events outside the interrupt handler proper. > > */ > > @@ -361,6 +400,25 @@ static void i915_hotplug_work_func(struct > > work_struct *work) > > DRM_DEBUG_KMS("Connector %s (pin %i) received > > hotplug event.\n", > > connector->name, intel_encoder- > > >hpd_pin); > > > > + /* > > + * TC WA: TC dongles takes some type to be > > + * responsible > > + */ > > + if (IS_ICELAKE(dev_priv) && > > + intel_port_is_tc(dev_priv, intel_encoder- > > >port) && > > + intel_digital_port_connected(intel_encoder) > > ) { > > + struct intel_dp *intel_dp; > > + unsigned long delay; > > + > > + intel_dp = > > enc_to_intel_dp(&intel_encoder->base); > > + > > + intel_dp->tc_wa_count = 0; > > + delay = > > msecs_to_jiffies(TC_WA_DELAY_MSEC); > > + schedule_delayed_work(&intel_dp- > > >tc_wa_work, > > + delay); > > + continue; > > + } > > + > > changed |= intel_encoder- > > >hotplug(intel_encoder, > > intel_connect > > or); > > I think if we need such duct-tape we should just stuff it into the > .hotplug() hook. The problem of moving it to intel_encoder_hotplug() is avoid infinite tries in case the transaction inside of intel_encoder_hotplug() fails after the one in intel_hotplug_tc_wa_work() works: intel_hotplug_tc_wa_work() { ... intel_dp->tc_wa_count++ if (drm_dp_dpcd_read() == 1) intel_encoder_hotplug() ... } intel_encoder_hotplug() { ... if (drm_dp_dpcd_read() < 1) if (IS_ICELAKE() && intel_port_is_tc() && intel_digital_port_connected()) intel_dp->tc_wa_count = 0; schedule_delayed_work() ... } I'm still thinking about other solutions but I guess the safest place is i915_hotplug_work_func(), any other tip? > > > } > > -- > > 2.19.1 > > > > _______________________________________________ > > Intel-gfx mailing list > > Intel-gfx@xxxxxxxxxxxxxxxxxxxxx > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx