On Mon, Mar 20, 2023 at 10:16:24PM +0200, Ville Syrjälä wrote: > On Thu, Mar 16, 2023 at 03:17:14PM +0200, Imre Deak wrote: > > At least restoring the MST topology during system resume needs to use > > AUX before the display HW readout->sanitization sequence is complete, > > but on TC ports the PHY may be in the wrong mode for this, resulting in > > the AUX transfers to fail. > > > > The initial TC port mode is kept fixed as BIOS left it for the above HW > > readout sequence (to prevent changing the mode on an enabled port). If > > the port is disabled this initial mode is TBT - as in any case the PHY > > ownership is not held - even if a DP-alt sink is connected. Thus, the > > AUX transfers during this time will use TBT mode instead of the expected > > DP-alt mode and so time out. > > > > Fix the above by connecting the PHY during port initialization if the > > port is disabled, which will switch to the expected mode (DP-alt in the > > above case). > > > > As the encoder/pipe HW state isn't read-out yet at this point, check if > > the port is enabled based on the DDI_BUF enabled flag. Save the read-out > > initial mode, so intel_tc_port_sanitize_mode() can check this wrt. the > > read-out encoder HW state. > > > > Signed-off-by: Imre Deak <imre.deak@xxxxxxxxx> > > --- > > .../drm/i915/display/intel_display_types.h | 1 + > > drivers/gpu/drm/i915/display/intel_tc.c | 48 +++++++++++++++++-- > > 2 files changed, 46 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h > > index c32bfba06ca1f..06bbfd426ac70 100644 > > --- a/drivers/gpu/drm/i915/display/intel_display_types.h > > +++ b/drivers/gpu/drm/i915/display/intel_display_types.h > > @@ -1783,6 +1783,7 @@ struct intel_digital_port { > > bool tc_legacy_port:1; > > char tc_port_name[8]; > > enum tc_port_mode tc_mode; > > + enum tc_port_mode tc_init_mode; > > enum phy_fia tc_phy_fia; > > u8 tc_phy_fia_idx; > > > > diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c > > index fd826b9657e93..e8cf3b506fb7f 100644 > > --- a/drivers/gpu/drm/i915/display/intel_tc.c > > +++ b/drivers/gpu/drm/i915/display/intel_tc.c > > @@ -118,6 +118,24 @@ assert_tc_cold_blocked(struct intel_digital_port *dig_port) > > drm_WARN_ON(&i915->drm, !enabled); > > } > > > > +static enum intel_display_power_domain > > +tc_port_power_domain(struct intel_digital_port *dig_port) > > +{ > > + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); > > + enum tc_port tc_port = intel_port_to_tc(i915, dig_port->base.port); > > + > > + return POWER_DOMAIN_PORT_DDI_LANES_TC1 + tc_port - TC_PORT_1; > > +} > > + > > +static void > > +assert_tc_port_power_enabled(struct intel_digital_port *dig_port) > > +{ > > + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); > > + > > + drm_WARN_ON(&i915->drm, > > + !intel_display_power_is_enabled(i915, tc_port_power_domain(dig_port))); > > +} > > + > > u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port) > > { > > struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); > > @@ -670,6 +688,16 @@ static void __intel_tc_port_put_link(struct intel_digital_port *dig_port) > > dig_port->tc_link_refcount--; > > } > > > > +static bool tc_port_is_enabled(struct intel_digital_port *dig_port) > > +{ > > + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); > > + > > + assert_tc_port_power_enabled(dig_port); > > + > > + return intel_de_read(i915, DDI_BUF_CTL(dig_port->base.port)) & > > + DDI_BUF_CTL_ENABLE; > > +} > > + > > /** > > * intel_tc_port_init_mode: Read out HW state and init the given port's TypeC mode > > * @dig_port: digital port > > @@ -692,9 +720,23 @@ void intel_tc_port_init_mode(struct intel_digital_port *dig_port) > > tc_cold_wref = tc_cold_block(dig_port, &domain); > > > > dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port); > > + /* > > + * Save the initial mode for the state check in > > + * intel_tc_port_sanitize_mode(). > > + */ > > + dig_port->tc_init_mode = dig_port->tc_mode; > > + dig_port->tc_lock_wakeref = tc_cold_block(dig_port, &dig_port->tc_lock_power_domain); > > + > > + /* > > + * The PHY needs to be connected for AUX to work during HW readout and > > + * MST topology resume, but the PHY mode can only be changed if the > > + * port is disabled. > > + */ > > + if (!tc_port_is_enabled(dig_port)) > > + intel_tc_port_update_mode(dig_port, 1, false); > > + > > /* Prevent changing dig_port->tc_mode until intel_tc_port_sanitize_mode() is called. */ > > __intel_tc_port_get_link(dig_port); > > - dig_port->tc_lock_wakeref = tc_cold_block(dig_port, &dig_port->tc_lock_power_domain); > > > > tc_cold_unblock(dig_port, domain, tc_cold_wref); > > > > @@ -741,11 +783,11 @@ void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port) > > * we'll just switch to disconnected mode from it here without > > * a note. > > */ > > - if (dig_port->tc_mode != TC_PORT_TBT_ALT) > > + if (dig_port->tc_init_mode != TC_PORT_TBT_ALT) > > drm_dbg_kms(&i915->drm, > > "Port %s: PHY left in %s mode on disabled port, disconnecting it\n", > > dig_port->tc_port_name, > > - tc_port_mode_name(dig_port->tc_mode)); > > + tc_port_mode_name(dig_port->tc_init_mode)); > > So we just have the tc_init_mode to get the debug correct, > or was it supposed be used elsewhere too? Yes, it's only used to keep the above check working. > > icl_tc_phy_disconnect(dig_port); > > __intel_tc_port_put_link(dig_port); > > > > -- > > 2.37.1 > > -- > Ville Syrjälä > Intel