Commit 06f66261 authored by Imre Deak's avatar Imre Deak

drm/i915/tc: Fix system resume MST mode restore for DP-alt sinks

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: default avatarImre Deak <imre.deak@intel.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230316131724.359612-5-imre.deak@intel.com
parent f2c7959d
...@@ -1783,6 +1783,7 @@ struct intel_digital_port { ...@@ -1783,6 +1783,7 @@ struct intel_digital_port {
bool tc_legacy_port:1; bool tc_legacy_port:1;
char tc_port_name[8]; char tc_port_name[8];
enum tc_port_mode tc_mode; enum tc_port_mode tc_mode;
enum tc_port_mode tc_init_mode;
enum phy_fia tc_phy_fia; enum phy_fia tc_phy_fia;
u8 tc_phy_fia_idx; u8 tc_phy_fia_idx;
......
...@@ -118,6 +118,24 @@ assert_tc_cold_blocked(struct intel_digital_port *dig_port) ...@@ -118,6 +118,24 @@ assert_tc_cold_blocked(struct intel_digital_port *dig_port)
drm_WARN_ON(&i915->drm, !enabled); 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) 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); 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) ...@@ -670,6 +688,16 @@ static void __intel_tc_port_put_link(struct intel_digital_port *dig_port)
dig_port->tc_link_refcount--; 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 * intel_tc_port_init_mode: Read out HW state and init the given port's TypeC mode
* @dig_port: digital port * @dig_port: digital port
...@@ -692,9 +720,23 @@ void intel_tc_port_init_mode(struct intel_digital_port *dig_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); tc_cold_wref = tc_cold_block(dig_port, &domain);
dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port); 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. */ /* Prevent changing dig_port->tc_mode until intel_tc_port_sanitize_mode() is called. */
__intel_tc_port_get_link(dig_port); __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); 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) ...@@ -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 * we'll just switch to disconnected mode from it here without
* a note. * 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, drm_dbg_kms(&i915->drm,
"Port %s: PHY left in %s mode on disabled port, disconnecting it\n", "Port %s: PHY left in %s mode on disabled port, disconnecting it\n",
dig_port->tc_port_name, dig_port->tc_port_name,
tc_port_mode_name(dig_port->tc_mode)); tc_port_mode_name(dig_port->tc_init_mode));
icl_tc_phy_disconnect(dig_port); icl_tc_phy_disconnect(dig_port);
__intel_tc_port_put_link(dig_port); __intel_tc_port_put_link(dig_port);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment