diff mbox

[v2,2/2] drm/i915/icl: Implement voltage swing programming sequence for MG PHY DDI

Message ID 1530225344-20373-2-git-send-email-manasi.d.navare@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Navare, Manasi June 28, 2018, 10:35 p.m. UTC
This sequence is used to setup voltage swing before enabling MG PHY DDI
as well as for changing the voltage during DisplayPort Link training.

For ICL, there are two types of DDIs. This sequence needs to be used
for MG PHY DDI which is ports C-F.

v6 (From Manasi):
* Add programming for MG_CLKHUB and MG_TX_DCC as per the
spec updates

v5 (from Paulo):
* Checkpatch.
v4 (from Paulo):
* Fix bogus error message
* Fix copy+paste bugs (missing s/TX1/TX2/ after copy+paste)
* Use the new mask names
* Stay under 80 columns
* Add some blank lines
v3:
* Clear the regs before writing (Paulo)
v2:
* Rename to MG PHY in the function def (Jani Nikula)
* Rebase on top of new revision of other patches in series

Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Jani Nikula <jani.nikula@linux.intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c | 135 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 129 insertions(+), 6 deletions(-)

Comments

Zanoni, Paulo R July 16, 2018, 11:48 p.m. UTC | #1
Em Qui, 2018-06-28 às 15:35 -0700, Manasi Navare escreveu:
> This sequence is used to setup voltage swing before enabling MG PHY
> DDI
> as well as for changing the voltage during DisplayPort Link training.
> 
> For ICL, there are two types of DDIs. This sequence needs to be used
> for MG PHY DDI which is ports C-F.

And our spec is still incomplete...

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>

> 
> v6 (From Manasi):
> * Add programming for MG_CLKHUB and MG_TX_DCC as per the
> spec updates
> 
> v5 (from Paulo):
> * Checkpatch.
> v4 (from Paulo):
> * Fix bogus error message
> * Fix copy+paste bugs (missing s/TX1/TX2/ after copy+paste)
> * Use the new mask names
> * Stay under 80 columns
> * Add some blank lines
> v3:
> * Clear the regs before writing (Paulo)
> v2:
> * Rename to MG PHY in the function def (Jani Nikula)
> * Rebase on top of new revision of other patches in series
> 
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Cc: Jani Nikula <jani.nikula@linux.intel.com>
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c | 135
> +++++++++++++++++++++++++++++++++++++--
>  1 file changed, 129 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> b/drivers/gpu/drm/i915/intel_ddi.c
> index 0319825..c91e96e 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -2459,7 +2459,128 @@ static void
> icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
>  	I915_WRITE(ICL_PORT_TX_DW5_GRP(port), val);
>  }
>  
> -static void icl_ddi_vswing_sequence(struct intel_encoder *encoder,
> u32 level,
> +static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder
> *encoder,
> +					   int link_clock,
> +					   u32 level)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder-
> >base.dev);
> +	enum port port = encoder->port;
> +	const struct icl_mg_phy_ddi_buf_trans *ddi_translations;
> +	u32 n_entries, val;
> +	int ln;
> +
> +	n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations);
> +	ddi_translations = icl_mg_phy_ddi_translations;
> +	/* The table does not have values for level 3 and level 9.
> */
> +	if (level >= n_entries || level == 3 || level == 9) {
> +		DRM_DEBUG_KMS("DDI translation not found for level
> %d. Using %d instead.",
> +			      level, n_entries - 2);
> +		level = n_entries - 2;
> +	}
> +
> +	/* Set MG_TX_LINK_PARAMS cri_use_fs32 to 0. */
> +	for (ln = 0; ln < 2; ln++) {
> +		val = I915_READ(MG_TX1_LINK_PARAMS(port, ln));
> +		val &= ~CRI_USE_FS32;
> +		I915_WRITE(MG_TX1_LINK_PARAMS(port, ln), val);
> +
> +		val = I915_READ(MG_TX2_LINK_PARAMS(port, ln));
> +		val &= ~CRI_USE_FS32;
> +		I915_WRITE(MG_TX2_LINK_PARAMS(port, ln), val);
> +	}
> +
> +	/* Program MG_TX_SWINGCTRL with values from vswing table */
> +	for (ln = 0; ln < 2; ln++) {
> +		val = I915_READ(MG_TX1_SWINGCTRL(port, ln));
> +		val &= ~CRI_TXDEEMPH_OVERRIDE_17_12_MASK;
> +		val |= CRI_TXDEEMPH_OVERRIDE_17_12(
> +			ddi_translations[level].cri_txdeemph_overrid
> e_17_12);
> +		I915_WRITE(MG_TX1_SWINGCTRL(port, ln), val);
> +
> +		val = I915_READ(MG_TX2_SWINGCTRL(port, ln));
> +		val &= ~CRI_TXDEEMPH_OVERRIDE_17_12_MASK;
> +		val |= CRI_TXDEEMPH_OVERRIDE_17_12(
> +			ddi_translations[level].cri_txdeemph_overrid
> e_17_12);
> +		I915_WRITE(MG_TX2_SWINGCTRL(port, ln), val);
> +	}
> +
> +	/* Program MG_TX_DRVCTRL with values from vswing table */
> +	for (ln = 0; ln < 2; ln++) {
> +		val = I915_READ(MG_TX1_DRVCTRL(port, ln));
> +		val &= ~(CRI_TXDEEMPH_OVERRIDE_11_6_MASK |
> +			 CRI_TXDEEMPH_OVERRIDE_5_0_MASK);
> +		val |= CRI_TXDEEMPH_OVERRIDE_5_0(
> +			ddi_translations[level].cri_txdeemph_overrid
> e_5_0) |
> +			CRI_TXDEEMPH_OVERRIDE_11_6(
> +				ddi_translations[level].cri_txdeemph
> _override_11_6) |
> +			CRI_TXDEEMPH_OVERRIDE_EN;
> +		I915_WRITE(MG_TX1_DRVCTRL(port, ln), val);
> +
> +		val = I915_READ(MG_TX2_DRVCTRL(port, ln));
> +		val &= ~(CRI_TXDEEMPH_OVERRIDE_11_6_MASK |
> +			 CRI_TXDEEMPH_OVERRIDE_5_0_MASK);
> +		val |= CRI_TXDEEMPH_OVERRIDE_5_0(
> +			ddi_translations[level].cri_txdeemph_overrid
> e_5_0) |
> +			CRI_TXDEEMPH_OVERRIDE_11_6(
> +				ddi_translations[level].cri_txdeemph
> _override_11_6) |
> +			CRI_TXDEEMPH_OVERRIDE_EN;
> +		I915_WRITE(MG_TX2_DRVCTRL(port, ln), val);
> +
> +		/* FIXME: Program CRI_LOADGEN_SEL after the spec is
> updated */
> +	}
> +
> +	/*
> +	 * Program MG_CLKHUB<LN, port being used> with value from
> frequency table
> +	 * In case of Legacy mode on MG PHY, both TX1 and TX2
> enabled so use the
> +	 * values from table for which TX1 and TX2 enabled.
> +	 */
> +	for (ln = 0; ln < 2; ln++) {
> +		val = I915_READ(MG_CLKHUB(port, ln));
> +		if (link_clock < 300000)
> +			val |= CFG_LOW_RATE_LKREN_EN;
> +		else
> +			val &= ~CFG_LOW_RATE_LKREN_EN;
> +		I915_WRITE(MG_CLKHUB(port, ln), val);
> +	}
> +
> +	/* Program the MG_TX_DCC<LN, port being used> based on the
> link frequency */
> +	for (ln = 0; ln < 2; ln++) {
> +		val = I915_READ(MG_TX1_DCC(port, ln));
> +		val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK;
> +		if (link_clock <= 500000) {
> +			val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN;
> +		} else {
> +			val |= CFG_AMI_CK_DIV_OVERRIDE_EN |
> +				CFG_AMI_CK_DIV_OVERRIDE_VAL(1);
> +		}
> +		I915_WRITE(MG_TX1_DCC(port, ln), val);
> +
> +		val = I915_READ(MG_TX2_DCC(port, ln));
> +		val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK;
> +		if (link_clock <= 500000) {
> +			val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN;
> +		} else {
> +			val |= CFG_AMI_CK_DIV_OVERRIDE_EN |
> +				CFG_AMI_CK_DIV_OVERRIDE_VAL(1);
> +		}
> +		I915_WRITE(MG_TX2_DCC(port, ln), val);
> +	}
> +
> +	/* Program MG_TX_PISO_READLOAD with values from vswing table
> */
> +	for (ln = 0; ln < 2; ln++) {
> +		val = I915_READ(MG_TX1_PISO_READLOAD(port, ln));
> +		val |= CRI_CALCINIT;
> +		I915_WRITE(MG_TX1_PISO_READLOAD(port, ln), val);
> +
> +		val = I915_READ(MG_TX2_PISO_READLOAD(port, ln));
> +		val |= CRI_CALCINIT;
> +		I915_WRITE(MG_TX2_PISO_READLOAD(port, ln), val);
> +	}
> +}
> +
> +static void icl_ddi_vswing_sequence(struct intel_encoder *encoder,
> +				    int link_clock,
> +				    u32 level,
>  				    enum intel_output_type type)
>  {
>  	enum port port = encoder->port;
> @@ -2467,8 +2588,7 @@ static void icl_ddi_vswing_sequence(struct
> intel_encoder *encoder, u32 level,
>  	if (port == PORT_A || port == PORT_B)
>  		icl_combo_phy_ddi_vswing_sequence(encoder, level,
> type);
>  	else
> -		/* Not Implemented Yet */
> -		WARN_ON(1);
> +		icl_mg_phy_ddi_vswing_sequence(encoder, link_clock,
> level);
>  }
>  
>  static uint32_t translate_signal_level(int signal_levels)
> @@ -2503,7 +2623,8 @@ u32 bxt_signal_levels(struct intel_dp
> *intel_dp)
>  	int level = intel_ddi_dp_level(intel_dp);
>  
>  	if (IS_ICELAKE(dev_priv))
> -		icl_ddi_vswing_sequence(encoder, level, encoder-
> >type);
> +		icl_ddi_vswing_sequence(encoder, intel_dp-
> >link_rate,
> +					level, encoder->type);
>  	else if (IS_CANNONLAKE(dev_priv))
>  		cnl_ddi_vswing_sequence(encoder, level, encoder-
> >type);
>  	else
> @@ -2684,7 +2805,8 @@ static void intel_ddi_pre_enable_dp(struct
> intel_encoder *encoder,
>  	intel_display_power_get(dev_priv, dig_port-
> >ddi_io_power_domain);
>  
>  	if (IS_ICELAKE(dev_priv))
> -		icl_ddi_vswing_sequence(encoder, level, encoder-
> >type);
> +		icl_ddi_vswing_sequence(encoder, crtc_state-
> >port_clock,
> +					level, encoder->type);
>  	else if (IS_CANNONLAKE(dev_priv))
>  		cnl_ddi_vswing_sequence(encoder, level, encoder-
> >type);
>  	else if (IS_GEN9_LP(dev_priv))
> @@ -2719,7 +2841,8 @@ static void intel_ddi_pre_enable_hdmi(struct
> intel_encoder *encoder,
>  	intel_display_power_get(dev_priv, dig_port-
> >ddi_io_power_domain);
>  
>  	if (IS_ICELAKE(dev_priv))
> -		icl_ddi_vswing_sequence(encoder, level,
> INTEL_OUTPUT_HDMI);
> +		icl_ddi_vswing_sequence(encoder, crtc_state-
> >port_clock,
> +					level, INTEL_OUTPUT_HDMI);
>  	else if (IS_CANNONLAKE(dev_priv))
>  		cnl_ddi_vswing_sequence(encoder, level,
> INTEL_OUTPUT_HDMI);
>  	else if (IS_GEN9_LP(dev_priv))
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 0319825..c91e96e 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -2459,7 +2459,128 @@  static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
 	I915_WRITE(ICL_PORT_TX_DW5_GRP(port), val);
 }
 
-static void icl_ddi_vswing_sequence(struct intel_encoder *encoder, u32 level,
+static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
+					   int link_clock,
+					   u32 level)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	enum port port = encoder->port;
+	const struct icl_mg_phy_ddi_buf_trans *ddi_translations;
+	u32 n_entries, val;
+	int ln;
+
+	n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations);
+	ddi_translations = icl_mg_phy_ddi_translations;
+	/* The table does not have values for level 3 and level 9. */
+	if (level >= n_entries || level == 3 || level == 9) {
+		DRM_DEBUG_KMS("DDI translation not found for level %d. Using %d instead.",
+			      level, n_entries - 2);
+		level = n_entries - 2;
+	}
+
+	/* Set MG_TX_LINK_PARAMS cri_use_fs32 to 0. */
+	for (ln = 0; ln < 2; ln++) {
+		val = I915_READ(MG_TX1_LINK_PARAMS(port, ln));
+		val &= ~CRI_USE_FS32;
+		I915_WRITE(MG_TX1_LINK_PARAMS(port, ln), val);
+
+		val = I915_READ(MG_TX2_LINK_PARAMS(port, ln));
+		val &= ~CRI_USE_FS32;
+		I915_WRITE(MG_TX2_LINK_PARAMS(port, ln), val);
+	}
+
+	/* Program MG_TX_SWINGCTRL with values from vswing table */
+	for (ln = 0; ln < 2; ln++) {
+		val = I915_READ(MG_TX1_SWINGCTRL(port, ln));
+		val &= ~CRI_TXDEEMPH_OVERRIDE_17_12_MASK;
+		val |= CRI_TXDEEMPH_OVERRIDE_17_12(
+			ddi_translations[level].cri_txdeemph_override_17_12);
+		I915_WRITE(MG_TX1_SWINGCTRL(port, ln), val);
+
+		val = I915_READ(MG_TX2_SWINGCTRL(port, ln));
+		val &= ~CRI_TXDEEMPH_OVERRIDE_17_12_MASK;
+		val |= CRI_TXDEEMPH_OVERRIDE_17_12(
+			ddi_translations[level].cri_txdeemph_override_17_12);
+		I915_WRITE(MG_TX2_SWINGCTRL(port, ln), val);
+	}
+
+	/* Program MG_TX_DRVCTRL with values from vswing table */
+	for (ln = 0; ln < 2; ln++) {
+		val = I915_READ(MG_TX1_DRVCTRL(port, ln));
+		val &= ~(CRI_TXDEEMPH_OVERRIDE_11_6_MASK |
+			 CRI_TXDEEMPH_OVERRIDE_5_0_MASK);
+		val |= CRI_TXDEEMPH_OVERRIDE_5_0(
+			ddi_translations[level].cri_txdeemph_override_5_0) |
+			CRI_TXDEEMPH_OVERRIDE_11_6(
+				ddi_translations[level].cri_txdeemph_override_11_6) |
+			CRI_TXDEEMPH_OVERRIDE_EN;
+		I915_WRITE(MG_TX1_DRVCTRL(port, ln), val);
+
+		val = I915_READ(MG_TX2_DRVCTRL(port, ln));
+		val &= ~(CRI_TXDEEMPH_OVERRIDE_11_6_MASK |
+			 CRI_TXDEEMPH_OVERRIDE_5_0_MASK);
+		val |= CRI_TXDEEMPH_OVERRIDE_5_0(
+			ddi_translations[level].cri_txdeemph_override_5_0) |
+			CRI_TXDEEMPH_OVERRIDE_11_6(
+				ddi_translations[level].cri_txdeemph_override_11_6) |
+			CRI_TXDEEMPH_OVERRIDE_EN;
+		I915_WRITE(MG_TX2_DRVCTRL(port, ln), val);
+
+		/* FIXME: Program CRI_LOADGEN_SEL after the spec is updated */
+	}
+
+	/*
+	 * Program MG_CLKHUB<LN, port being used> with value from frequency table
+	 * In case of Legacy mode on MG PHY, both TX1 and TX2 enabled so use the
+	 * values from table for which TX1 and TX2 enabled.
+	 */
+	for (ln = 0; ln < 2; ln++) {
+		val = I915_READ(MG_CLKHUB(port, ln));
+		if (link_clock < 300000)
+			val |= CFG_LOW_RATE_LKREN_EN;
+		else
+			val &= ~CFG_LOW_RATE_LKREN_EN;
+		I915_WRITE(MG_CLKHUB(port, ln), val);
+	}
+
+	/* Program the MG_TX_DCC<LN, port being used> based on the link frequency */
+	for (ln = 0; ln < 2; ln++) {
+		val = I915_READ(MG_TX1_DCC(port, ln));
+		val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK;
+		if (link_clock <= 500000) {
+			val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN;
+		} else {
+			val |= CFG_AMI_CK_DIV_OVERRIDE_EN |
+				CFG_AMI_CK_DIV_OVERRIDE_VAL(1);
+		}
+		I915_WRITE(MG_TX1_DCC(port, ln), val);
+
+		val = I915_READ(MG_TX2_DCC(port, ln));
+		val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK;
+		if (link_clock <= 500000) {
+			val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN;
+		} else {
+			val |= CFG_AMI_CK_DIV_OVERRIDE_EN |
+				CFG_AMI_CK_DIV_OVERRIDE_VAL(1);
+		}
+		I915_WRITE(MG_TX2_DCC(port, ln), val);
+	}
+
+	/* Program MG_TX_PISO_READLOAD with values from vswing table */
+	for (ln = 0; ln < 2; ln++) {
+		val = I915_READ(MG_TX1_PISO_READLOAD(port, ln));
+		val |= CRI_CALCINIT;
+		I915_WRITE(MG_TX1_PISO_READLOAD(port, ln), val);
+
+		val = I915_READ(MG_TX2_PISO_READLOAD(port, ln));
+		val |= CRI_CALCINIT;
+		I915_WRITE(MG_TX2_PISO_READLOAD(port, ln), val);
+	}
+}
+
+static void icl_ddi_vswing_sequence(struct intel_encoder *encoder,
+				    int link_clock,
+				    u32 level,
 				    enum intel_output_type type)
 {
 	enum port port = encoder->port;
@@ -2467,8 +2588,7 @@  static void icl_ddi_vswing_sequence(struct intel_encoder *encoder, u32 level,
 	if (port == PORT_A || port == PORT_B)
 		icl_combo_phy_ddi_vswing_sequence(encoder, level, type);
 	else
-		/* Not Implemented Yet */
-		WARN_ON(1);
+		icl_mg_phy_ddi_vswing_sequence(encoder, link_clock, level);
 }
 
 static uint32_t translate_signal_level(int signal_levels)
@@ -2503,7 +2623,8 @@  u32 bxt_signal_levels(struct intel_dp *intel_dp)
 	int level = intel_ddi_dp_level(intel_dp);
 
 	if (IS_ICELAKE(dev_priv))
-		icl_ddi_vswing_sequence(encoder, level, encoder->type);
+		icl_ddi_vswing_sequence(encoder, intel_dp->link_rate,
+					level, encoder->type);
 	else if (IS_CANNONLAKE(dev_priv))
 		cnl_ddi_vswing_sequence(encoder, level, encoder->type);
 	else
@@ -2684,7 +2805,8 @@  static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
 	intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain);
 
 	if (IS_ICELAKE(dev_priv))
-		icl_ddi_vswing_sequence(encoder, level, encoder->type);
+		icl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
+					level, encoder->type);
 	else if (IS_CANNONLAKE(dev_priv))
 		cnl_ddi_vswing_sequence(encoder, level, encoder->type);
 	else if (IS_GEN9_LP(dev_priv))
@@ -2719,7 +2841,8 @@  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
 	intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain);
 
 	if (IS_ICELAKE(dev_priv))
-		icl_ddi_vswing_sequence(encoder, level, INTEL_OUTPUT_HDMI);
+		icl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
+					level, INTEL_OUTPUT_HDMI);
 	else if (IS_CANNONLAKE(dev_priv))
 		cnl_ddi_vswing_sequence(encoder, level, INTEL_OUTPUT_HDMI);
 	else if (IS_GEN9_LP(dev_priv))