[Intel-gfx] [PATCH] drm/i915/icl+: Prevent using non-TypeC AUX channels on TypeC ports

Imre Deak imre.deak at intel.com
Thu Apr 23 18:19:37 UTC 2020


Using an AUX channel which by default belongs to a non-TypeC PHY won't
work on a TypeC PHY, since - as a side-effect besides providing an AUX
channel - the AUX channel power well affects power manangement specific
to the TypeC subsystem. Using a TypeC AUX channel on a non-TypeC PHY
would probably also cause problems, so for simplicity prevent both.

This fixes at least an ICL-Y machine in CI, which has a buggy VBT
setting AUX-B as an alternative channel for port C.

Signed-off-by: Imre Deak <imre.deak at intel.com>
---
 drivers/gpu/drm/i915/display/intel_bios.c | 84 +++++++++++++++--------
 1 file changed, 57 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 839124647202..10d463723d12 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -1538,11 +1538,38 @@ static enum port get_port_by_aux_ch(struct drm_i915_private *i915, u8 aux_ch)
 	return PORT_NONE;
 }
 
+static enum aux_ch
+intel_bios_port_info_aux_ch(const struct ddi_vbt_port_info *info)
+{
+	switch (info->alternate_aux_channel) {
+	case DP_AUX_A:
+		return AUX_CH_A;
+	case DP_AUX_B:
+		return AUX_CH_B;
+	case DP_AUX_C:
+		return AUX_CH_C;
+	case DP_AUX_D:
+		return AUX_CH_D;
+	case DP_AUX_E:
+		return AUX_CH_E;
+	case DP_AUX_F:
+		return AUX_CH_F;
+	case DP_AUX_G:
+		return AUX_CH_G;
+	default:
+		MISSING_CASE(info->alternate_aux_channel);
+		return AUX_CH_A;
+	}
+}
+
 static void sanitize_aux_ch(struct drm_i915_private *dev_priv,
 			    enum port port)
 {
 	struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port];
 	enum port p;
+	enum aux_ch aux_ch;
+	bool aux_is_tc;
+	bool phy_is_tc;
 
 	if (!info->alternate_aux_channel)
 		return;
@@ -1571,6 +1598,35 @@ static void sanitize_aux_ch(struct drm_i915_private *dev_priv,
 
 		info->supports_dp = false;
 		info->alternate_aux_channel = 0;
+
+		return;
+	}
+
+	aux_ch = intel_bios_port_info_aux_ch(info);
+	/* The AUX CH -> default port is a 1:1 mapping. */
+	aux_is_tc = intel_phy_is_tc(dev_priv,
+				    intel_port_to_phy(dev_priv,
+						      (enum port)aux_ch));
+	phy_is_tc = intel_phy_is_tc(dev_priv,
+				    intel_port_to_phy(dev_priv, port));
+	if (aux_is_tc != phy_is_tc) {
+		/*
+		 * Using an AUX channel which by default belongs to a TypeC
+		 * PHY can't be used for non-TypeC PHYs and vice-versa. The
+		 * reason is that TypeC AUX power wells can only be enabled in
+		 * the current TypeC mode of the PHY and have an effect on power
+		 * management specific to the TypeC subsystem.
+		 */
+		drm_dbg_kms(&dev_priv->drm,
+			    "Port %c on a %s PHY is trying to use the %s AUX CH %c, "
+			    "disabling DP support on this port.\n",
+			    port_name(port),
+			    phy_is_tc ? "TypeC" : "non-TypeC",
+			    aux_is_tc ? "TypeC" : "non-TypeC",
+			    aux_ch_name(aux_ch));
+
+		info->supports_dp = false;
+		info->alternate_aux_channel = 0;
 	}
 }
 
@@ -2595,33 +2651,7 @@ enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *dev_priv,
 		return aux_ch;
 	}
 
-	switch (info->alternate_aux_channel) {
-	case DP_AUX_A:
-		aux_ch = AUX_CH_A;
-		break;
-	case DP_AUX_B:
-		aux_ch = AUX_CH_B;
-		break;
-	case DP_AUX_C:
-		aux_ch = AUX_CH_C;
-		break;
-	case DP_AUX_D:
-		aux_ch = AUX_CH_D;
-		break;
-	case DP_AUX_E:
-		aux_ch = AUX_CH_E;
-		break;
-	case DP_AUX_F:
-		aux_ch = AUX_CH_F;
-		break;
-	case DP_AUX_G:
-		aux_ch = AUX_CH_G;
-		break;
-	default:
-		MISSING_CASE(info->alternate_aux_channel);
-		aux_ch = AUX_CH_A;
-		break;
-	}
+	aux_ch = intel_bios_port_info_aux_ch(info);
 
 	drm_dbg_kms(&dev_priv->drm, "using AUX %c for port %c (VBT)\n",
 		    aux_ch_name(aux_ch), port_name(port));
-- 
2.23.1



More information about the Intel-gfx mailing list