]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
drm/i915/tc: Fix system resume MST mode restore for DP-alt sinks
authorImre Deak <imre.deak@intel.com>
Thu, 16 Mar 2023 13:17:14 +0000 (15:17 +0200)
committerImre Deak <imre.deak@intel.com>
Wed, 22 Mar 2023 18:31:06 +0000 (20:31 +0200)
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@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230316131724.359612-5-imre.deak@intel.com
drivers/gpu/drm/i915/display/intel_display_types.h
drivers/gpu/drm/i915/display/intel_tc.c

index c32bfba06ca1f21a4d661fbfba000b92d463cdb3..06bbfd426ac700050b8fb93879f0dabed1bb9d83 100644 (file)
@@ -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;
 
index fd826b9657e9302694fbbea0d31404233eafa804..e8cf3b506fb7f89fe2c61c7b2d89353aaef97497 100644 (file)
@@ -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));
                icl_tc_phy_disconnect(dig_port);
                __intel_tc_port_put_link(dig_port);