[Intel-gfx] [PATCH 6/9] drm/i915/mtl/display: Implement DisplayPort sequences

Imre Deak imre.deak at intel.com
Fri Apr 14 11:37:13 UTC 2023


On Thu, Apr 13, 2023 at 02:24:40PM -0700, Radhakrishna Sripada wrote:
> From: José Roberto de Souza <jose.souza at intel.com>
> 
> The differences between MTL and TGL DP sequences are big enough to
> MTL have its own functions.
> 
> Also it is much easier to follow MTL sequences against spec with
> its own functions.
> 
> One change worthy to mention is the move of
> 'intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain)'.
> This call is not necessary for MTL but we have _put() counter part in
> intel_ddi_post_disable_dp() that needs to balanced.
> We could add a display version check on it but instead here it is
> moving it to intel_ddi_pre_enable_dp() so it is executed for all
> platforms in a single place and this will not cause any harm in MTL
> and newer platforms.
> 
> v2:
>  - Fix logic to wait for buf idle.
>  - Use the right register to wait for ddi active.(RK)
> v3:
>  - Increase wait timeout for ddi buf active (Mika)
> v4:
>  - Increase idle timeout for ddi buf idle (Mika)
> v5: use rmw in mtl_disable_ddi_buf. Donot clear
>     link training mask(Imre)
> 
> BSpec: 65448 65505
> Cc: Matt Roper <matthew.d.roper at intel.com>
> Cc: Satyeshwar Singh <satyeshwar.singh at intel.com>
> Cc: Clint Taylor <clinton.a.taylor at intel.com>
> Cc: Ankit Nautiyal <ankit.k.nautiyal at intel.com>
> Cc: Imre Deak <imre.deak at intel.com>
> Signed-off-by: Radhakrishna Sripada <radhakrishna.sripada at intel.com>
> Signed-off-by: José Roberto de Souza <jose.souza at intel.com>
> Signed-off-by: Mika Kahola <mika.kahola at intel.com>

Reviewed-by: Imre Deak <imre.deak at intel.com>

> ---
>  .../gpu/drm/i915/display/intel_cx0_phy_regs.h |   8 +
>  drivers/gpu/drm/i915/display/intel_ddi.c      | 344 +++++++++++++++++-
>  drivers/gpu/drm/i915/i915_reg.h               |   5 +
>  3 files changed, 345 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h
> index 9cfa7f508c90..fe2e3edef69b 100644
> --- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h
> +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h
> @@ -59,8 +59,16 @@
>  										 _XELPDP_PORT_BUF_CTL1_LN0_B, \
>  										 _XELPDP_PORT_BUF_CTL1_LN0_USBC1, \
>  										 _XELPDP_PORT_BUF_CTL1_LN0_USBC2))
> +#define   XELPDP_PORT_BUF_D2D_LINK_ENABLE		REG_BIT(29)
> +#define   XELPDP_PORT_BUF_D2D_LINK_STATE		REG_BIT(28)
>  #define   XELPDP_PORT_BUF_SOC_PHY_READY			REG_BIT(24)
> +#define   XELPDP_PORT_BUF_PORT_DATA_WIDTH_MASK		REG_GENMASK(19, 18)
> +#define   XELPDP_PORT_BUF_PORT_DATA_10BIT		REG_FIELD_PREP(XELPDP_PORT_BUF_PORT_DATA_WIDTH_MASK, 0)
> +#define   XELPDP_PORT_BUF_PORT_DATA_20BIT		REG_FIELD_PREP(XELPDP_PORT_BUF_PORT_DATA_WIDTH_MASK, 1)
> +#define   XELPDP_PORT_BUF_PORT_DATA_40BIT		REG_FIELD_PREP(XELPDP_PORT_BUF_PORT_DATA_WIDTH_MASK, 2)
>  #define   XELPDP_PORT_REVERSAL				REG_BIT(16)
> +#define   XELPDP_PORT_BUF_IO_SELECT_TBT			REG_BIT(11)
> +#define   XELPDP_PORT_BUF_PHY_IDLE			REG_BIT(7)
>  #define   XELPDP_TC_PHY_OWNERSHIP			REG_BIT(6)
>  #define   XELPDP_TCSS_POWER_REQUEST			REG_BIT(5)
>  #define   XELPDP_TCSS_POWER_STATE			REG_BIT(4)
> diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
> index 21a86cb7b2dc..c0283829823f 100644
> --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> @@ -40,6 +40,7 @@
>  #include "intel_connector.h"
>  #include "intel_crtc.h"
>  #include "intel_cx0_phy.h"
> +#include "intel_cx0_phy_regs.h"
>  #include "intel_ddi.h"
>  #include "intel_ddi_buf_trans.h"
>  #include "intel_de.h"
> @@ -169,6 +170,18 @@ static void hsw_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder,
>  		       trans->entries[level].hsw.trans2);
>  }
>  
> +static void mtl_wait_ddi_buf_idle(struct drm_i915_private *i915, enum port port)
> +{
> +	int ret;
> +
> +	/* FIXME: find out why Bspec's 100us timeout is too short */
> +	ret = wait_for_us((intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port)) &
> +			   XELPDP_PORT_BUF_PHY_IDLE), 10000);
> +	if (ret)
> +		drm_err(&i915->drm, "Timeout waiting for DDI BUF %c to get idle\n",
> +			port_name(port));
> +}
> +
>  void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
>  			     enum port port)
>  {
> @@ -196,7 +209,9 @@ static void intel_wait_ddi_buf_active(struct drm_i915_private *dev_priv,
>  		return;
>  	}
>  
> -	if (IS_DG2(dev_priv)) {
> +	if (DISPLAY_VER(dev_priv) >= 14) {
> +		timeout_us = 10000;
> +	} else if (IS_DG2(dev_priv)) {
>  		timeout_us = 1200;
>  	} else if (DISPLAY_VER(dev_priv) >= 12) {
>  		if (intel_phy_is_tc(dev_priv, phy))
> @@ -207,8 +222,12 @@ static void intel_wait_ddi_buf_active(struct drm_i915_private *dev_priv,
>  		timeout_us = 500;
>  	}
>  
> -	ret = _wait_for(!(intel_de_read(dev_priv, DDI_BUF_CTL(port)) &
> -			  DDI_BUF_IS_IDLE), timeout_us, 10, 10);
> +	if (DISPLAY_VER(dev_priv) >= 14)
> +		ret = _wait_for(!(intel_de_read(dev_priv, XELPDP_PORT_BUF_CTL1(port)) & XELPDP_PORT_BUF_PHY_IDLE),
> +				timeout_us, 10, 10);
> +	else
> +		ret = _wait_for(!(intel_de_read(dev_priv, DDI_BUF_CTL(port)) & DDI_BUF_IS_IDLE),
> +				timeout_us, 10, 10);
>  
>  	if (ret)
>  		drm_err(&dev_priv->drm, "Timeout waiting for DDI BUF %c to get active\n",
> @@ -313,6 +332,13 @@ static void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder,
>  		DDI_PORT_WIDTH(crtc_state->lane_count) |
>  		DDI_BUF_TRANS_SELECT(0);
>  
> +	if (DISPLAY_VER(i915) >= 14) {
> +		if (intel_dp_is_uhbr(crtc_state))
> +			intel_dp->DP |= DDI_BUF_PORT_DATA_40BIT;
> +		else
> +			intel_dp->DP |= DDI_BUF_PORT_DATA_10BIT;
> +	}
> +
>  	if (IS_ALDERLAKE_P(i915) && intel_phy_is_tc(i915, phy)) {
>  		intel_dp->DP |= ddi_buf_phy_link_rate(crtc_state->port_clock);
>  		if (!intel_tc_port_in_tbt_alt_mode(dig_port))
> @@ -2309,6 +2335,179 @@ static void intel_ddi_mso_configure(const struct intel_crtc_state *crtc_state)
>  		     OVERLAP_PIXELS_MASK, dss1);
>  }
>  
> +static u8 mtl_get_port_width(u8 lane_count)
> +{
> +	switch (lane_count) {
> +	case 1:
> +		return 0;
> +	case 2:
> +		return 1;
> +	case 3:
> +		return 4;
> +	case 4:
> +		return 3;
> +	default:
> +		MISSING_CASE(lane_count);
> +		return 4;
> +	}
> +}
> +
> +static void
> +mtl_ddi_enable_d2d(struct intel_encoder *encoder)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	enum port port = encoder->port;
> +
> +	intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(port), 0,
> +		     XELPDP_PORT_BUF_D2D_LINK_ENABLE);
> +
> +	if (wait_for_us((intel_de_read(dev_priv, XELPDP_PORT_BUF_CTL1(port)) &
> +			 XELPDP_PORT_BUF_D2D_LINK_STATE), 100)) {
> +		drm_err(&dev_priv->drm, "Timeout waiting for D2D Link enable for PORT_BUF_CTL %c\n",
> +			port_name(port));
> +	}
> +}
> +
> +static void mtl_port_buf_ctl_program(struct intel_encoder *encoder,
> +				     const struct intel_crtc_state *crtc_state)
> +{
> +	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
> +	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> +	enum port port = encoder->port;
> +	u32 val;
> +
> +	val = intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port));
> +	val &= ~XELPDP_PORT_WIDTH_MASK;
> +	val |= XELPDP_PORT_WIDTH(mtl_get_port_width(crtc_state->lane_count));
> +
> +	val &= ~XELPDP_PORT_BUF_PORT_DATA_WIDTH_MASK;
> +	if (intel_dp_is_uhbr(crtc_state))
> +		val |= XELPDP_PORT_BUF_PORT_DATA_40BIT;
> +	else
> +		val |= XELPDP_PORT_BUF_PORT_DATA_10BIT;
> +
> +	if (dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL)
> +		val |= XELPDP_PORT_REVERSAL;
> +
> +	intel_de_write(i915, XELPDP_PORT_BUF_CTL1(port), val);
> +}
> +
> +static void mtl_port_buf_ctl_io_selection(struct intel_encoder *encoder)
> +{
> +	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
> +	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> +	u32 val;
> +
> +	val = intel_tc_port_in_tbt_alt_mode(dig_port) ?
> +	      XELPDP_PORT_BUF_IO_SELECT_TBT : 0;
> +	intel_de_rmw(i915, XELPDP_PORT_BUF_CTL1(encoder->port),
> +		     XELPDP_PORT_BUF_IO_SELECT_TBT, val);
> +}
> +
> +static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state,
> +				  struct intel_encoder *encoder,
> +				  const struct intel_crtc_state *crtc_state,
> +				  const struct drm_connector_state *conn_state)
> +{
> +	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
> +	bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
> +
> +	intel_dp_set_link_params(intel_dp,
> +				 crtc_state->port_clock,
> +				 crtc_state->lane_count);
> +
> +	/*
> +	 * We only configure what the register value will be here.  Actual
> +	 * enabling happens during link training farther down.
> +	 */
> +	intel_ddi_init_dp_buf_reg(encoder, crtc_state);
> +
> +	/*
> +	 * 1. Enable Power Wells
> +	 *
> +	 * This was handled at the beginning of intel_atomic_commit_tail(),
> +	 * before we called down into this function.
> +	 */
> +
> +	/* 2. PMdemand was already set */
> +
> +	/* 3. Select Thunderbolt */
> +	mtl_port_buf_ctl_io_selection(encoder);
> +
> +	/* 4. Enable Panel Power if PPS is required */
> +	intel_pps_on(intel_dp);
> +
> +	/* 5. Enable the port PLL */
> +	intel_ddi_enable_clock(encoder, crtc_state);
> +
> +	/*
> +	 * 6.a Configure Transcoder Clock Select to direct the Port clock to the
> +	 * Transcoder.
> +	 */
> +	intel_ddi_enable_transcoder_clock(encoder, crtc_state);
> +
> +	/*
> +	 * 6.b If DP v2.0/128b mode - Configure TRANS_DP2_CTL register settings.
> +	 */
> +	intel_ddi_config_transcoder_dp2(encoder, crtc_state);
> +
> +	/*
> +	 * 6.c Configure TRANS_DDI_FUNC_CTL DDI Select, DDI Mode Select & MST
> +	 * Transport Select
> +	 */
> +	intel_ddi_config_transcoder_func(encoder, crtc_state);
> +
> +	/*
> +	 * 6.e Program CoG/MSO configuration bits in DSS_CTL1 if selected.
> +	 */
> +	intel_ddi_mso_configure(crtc_state);
> +
> +	if (!is_mst)
> +		intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
> +
> +	intel_dp_configure_protocol_converter(intel_dp, crtc_state);
> +	intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true);
> +	/*
> +	 * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit
> +	 * in the FEC_CONFIGURATION register to 1 before initiating link
> +	 * training
> +	 */
> +	intel_dp_sink_set_fec_ready(intel_dp, crtc_state);
> +
> +	intel_dp_check_frl_training(intel_dp);
> +	intel_dp_pcon_dsc_configure(intel_dp, crtc_state);
> +
> +	/*
> +	 * 6. The rest of the below are substeps under the bspec's "Enable and
> +	 * Train Display Port" step.  Note that steps that are specific to
> +	 * MST will be handled by intel_mst_pre_enable_dp() before/after it
> +	 * calls into this function.  Also intel_mst_pre_enable_dp() only calls
> +	 * us when active_mst_links==0, so any steps designated for "single
> +	 * stream or multi-stream master transcoder" can just be performed
> +	 * unconditionally here.
> +	 *
> +	 * mtl_ddi_prepare_link_retrain() that is called by
> +	 * intel_dp_start_link_train() will execute steps: 6.d, 6.f, 6.g, 6.h,
> +	 * 6.i and 6.j
> +	 *
> +	 * 6.k Follow DisplayPort specification training sequence (see notes for
> +	 *     failure handling)
> +	 * 6.m If DisplayPort multi-stream - Set DP_TP_CTL link training to Idle
> +	 *     Pattern, wait for 5 idle patterns (DP_TP_STATUS Min_Idles_Sent)
> +	 *     (timeout after 800 us)
> +	 */
> +	intel_dp_start_link_train(intel_dp, crtc_state);
> +
> +	/* 6.n Set DP_TP_CTL link training to Normal */
> +	if (!is_trans_port_sync_mode(crtc_state))
> +		intel_dp_stop_link_train(intel_dp, crtc_state);
> +
> +	/* 6.o Configure and enable FEC if needed */
> +	intel_ddi_enable_fec(encoder, crtc_state);
> +
> +	intel_dsc_dp_pps_write(encoder, crtc_state);
> +}
> +
>  static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
>  				  struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *crtc_state,
> @@ -2523,7 +2722,9 @@ static void intel_ddi_pre_enable_dp(struct intel_atomic_state *state,
>  		intel_dp_128b132b_sdp_crc16(enc_to_intel_dp(encoder),
>  					    crtc_state);
>  
> -	if (DISPLAY_VER(dev_priv) >= 12)
> +	if (DISPLAY_VER(dev_priv) >= 14)
> +		mtl_ddi_pre_enable_dp(state, encoder, crtc_state, conn_state);
> +	else if (DISPLAY_VER(dev_priv) >= 12)
>  		tgl_ddi_pre_enable_dp(state, encoder, crtc_state, conn_state);
>  	else
>  		hsw_ddi_pre_enable_dp(state, encoder, crtc_state, conn_state);
> @@ -2604,8 +2805,50 @@ static void intel_ddi_pre_enable(struct intel_atomic_state *state,
>  	}
>  }
>  
> -static void intel_disable_ddi_buf(struct intel_encoder *encoder,
> -				  const struct intel_crtc_state *crtc_state)
> +static void
> +mtl_ddi_disable_d2d_link(struct intel_encoder *encoder)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	enum port port = encoder->port;
> +
> +	intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(port),
> +		     XELPDP_PORT_BUF_D2D_LINK_ENABLE, 0);
> +
> +	if (wait_for_us(!(intel_de_read(dev_priv, XELPDP_PORT_BUF_CTL1(port)) &
> +			  XELPDP_PORT_BUF_D2D_LINK_STATE), 100))
> +		drm_err(&dev_priv->drm, "Timeout waiting for D2D Link disable for PORT_BUF_CTL %c\n",
> +			port_name(port));
> +}
> +
> +static void mtl_disable_ddi_buf(struct intel_encoder *encoder,
> +				const struct intel_crtc_state *crtc_state)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	enum port port = encoder->port;
> +	u32 val;
> +
> +	/* 3.b Clear DDI_CTL_DE Enable to 0. */
> +	val = intel_de_read(dev_priv, DDI_BUF_CTL(port));
> +	if (val & DDI_BUF_CTL_ENABLE) {
> +		val &= ~DDI_BUF_CTL_ENABLE;
> +		intel_de_write(dev_priv, DDI_BUF_CTL(port), val);
> +
> +		/* 3.c Poll for PORT_BUF_CTL Idle Status == 1, timeout after 100us */
> +		mtl_wait_ddi_buf_idle(dev_priv, port);
> +	}
> +
> +	/* 3.d Disable D2D Link */
> +	mtl_ddi_disable_d2d_link(encoder);
> +
> +	/* 3.e Disable DP_TP_CTL */
> +	if (intel_crtc_has_dp_encoder(crtc_state)) {
> +		intel_de_rmw(dev_priv, dp_tp_ctl_reg(encoder, crtc_state),
> +			     DP_TP_CTL_ENABLE, 0);
> +	}
> +}
> +
> +static void disable_ddi_buf(struct intel_encoder *encoder,
> +			    const struct intel_crtc_state *crtc_state)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	enum port port = encoder->port;
> @@ -2630,6 +2873,21 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder,
>  		intel_wait_ddi_buf_idle(dev_priv, port);
>  }
>  
> +static void intel_disable_ddi_buf(struct intel_encoder *encoder,
> +				  const struct intel_crtc_state *crtc_state)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +
> +	if (DISPLAY_VER(dev_priv) >= 14) {
> +		mtl_disable_ddi_buf(encoder, crtc_state);
> +
> +		/* 3.f Disable DP_TP_CTL FEC Enable if it is needed */
> +		intel_ddi_disable_fec_state(encoder, crtc_state);
> +	} else {
> +		disable_ddi_buf(encoder, crtc_state);
> +	}
> +}
> +
>  static void intel_ddi_post_disable_dp(struct intel_atomic_state *state,
>  				      struct intel_encoder *encoder,
>  				      const struct intel_crtc_state *old_crtc_state,
> @@ -2638,6 +2896,7 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state,
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
>  	struct intel_dp *intel_dp = &dig_port->dp;
> +	intel_wakeref_t wakeref;
>  	bool is_mst = intel_crtc_has_type(old_crtc_state,
>  					  INTEL_OUTPUT_DP_MST);
>  
> @@ -2677,12 +2936,19 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state,
>  	intel_pps_vdd_on(intel_dp);
>  	intel_pps_off(intel_dp);
>  
> -	if (!intel_tc_port_in_tbt_alt_mode(dig_port))
> +	wakeref = fetch_and_zero(&dig_port->ddi_io_wakeref);
> +
> +	if (wakeref)
>  		intel_display_power_put(dev_priv,
>  					dig_port->ddi_io_power_domain,
> -					fetch_and_zero(&dig_port->ddi_io_wakeref));
> +					wakeref);
>  
>  	intel_ddi_disable_clock(encoder);
> +
> +	/* De-select Thunderbolt */
> +	if (DISPLAY_VER(dev_priv) >= 14)
> +		intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(encoder->port),
> +			     XELPDP_PORT_BUF_IO_SELECT_TBT, 0);
>  }
>  
>  static void intel_ddi_post_disable_hdmi(struct intel_atomic_state *state,
> @@ -2693,6 +2959,7 @@ static void intel_ddi_post_disable_hdmi(struct intel_atomic_state *state,
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
>  	struct intel_hdmi *intel_hdmi = &dig_port->hdmi;
> +	intel_wakeref_t wakeref;
>  
>  	dig_port->set_infoframes(encoder, false,
>  				 old_crtc_state, old_conn_state);
> @@ -2705,9 +2972,11 @@ static void intel_ddi_post_disable_hdmi(struct intel_atomic_state *state,
>  	if (DISPLAY_VER(dev_priv) >= 12)
>  		intel_ddi_disable_transcoder_clock(old_crtc_state);
>  
> -	intel_display_power_put(dev_priv,
> -				dig_port->ddi_io_power_domain,
> -				fetch_and_zero(&dig_port->ddi_io_wakeref));
> +	wakeref = fetch_and_zero(&dig_port->ddi_io_wakeref);
> +	if (wakeref)
> +		intel_display_power_put(dev_priv,
> +					dig_port->ddi_io_power_domain,
> +					wakeref);
>  
>  	intel_ddi_disable_clock(encoder);
>  
> @@ -3104,6 +3373,53 @@ static void adlp_tbt_to_dp_alt_switch_wa(struct intel_encoder *encoder)
>  		intel_dkl_phy_rmw(i915, DKL_PCS_DW5(tc_port, ln), DKL_PCS_DW5_CORE_SOFTRESET, 0);
>  }
>  
> +static void mtl_ddi_prepare_link_retrain(struct intel_dp *intel_dp,
> +					 const struct intel_crtc_state *crtc_state)
> +{
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	struct intel_encoder *encoder = &dig_port->base;
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	enum port port = encoder->port;
> +	u32 dp_tp_ctl;
> +
> +	/*
> +	 * TODO: To train with only a different voltage swing entry is not
> +	 * necessary disable and enable port
> +	 */
> +	dp_tp_ctl = intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
> +	if (dp_tp_ctl & DP_TP_CTL_ENABLE)
> +		mtl_disable_ddi_buf(encoder, crtc_state);
> +
> +	/* 6.d Configure and enable DP_TP_CTL with link training pattern 1 selected */
> +	dp_tp_ctl = DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_PAT1;
> +	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) {
> +		dp_tp_ctl |= DP_TP_CTL_MODE_MST;
> +	} else {
> +		dp_tp_ctl |= DP_TP_CTL_MODE_SST;
> +		if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
> +			dp_tp_ctl |= DP_TP_CTL_ENHANCED_FRAME_ENABLE;
> +	}
> +	intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), dp_tp_ctl);
> +	intel_de_posting_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state));
> +
> +	/* 6.f Enable D2D Link */
> +	mtl_ddi_enable_d2d(encoder);
> +
> +	/* 6.g Configure voltage swing and related IO settings */
> +	encoder->set_signal_levels(encoder, crtc_state);
> +
> +	/* 6.h Configure PORT_BUF_CTL1 */
> +	mtl_port_buf_ctl_program(encoder, crtc_state);
> +
> +	/* 6.i Configure and enable DDI_CTL_DE to start sending valid data to port slice */
> +	intel_dp->DP |= DDI_BUF_CTL_ENABLE;
> +	intel_de_write(dev_priv, DDI_BUF_CTL(port), intel_dp->DP);
> +	intel_de_posting_read(dev_priv, DDI_BUF_CTL(port));
> +
> +	/* 6.j Poll for PORT_BUF_CTL Idle Status == 0, timeout after 100 us */
> +	intel_wait_ddi_buf_active(dev_priv, port);
> +}
> +
>  static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp,
>  					   const struct intel_crtc_state *crtc_state)
>  {
> @@ -3871,6 +4187,7 @@ static const struct drm_encoder_funcs intel_ddi_funcs = {
>  static struct intel_connector *
>  intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
>  {
> +	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
>  	struct intel_connector *connector;
>  	enum port port = dig_port->base.port;
>  
> @@ -3879,7 +4196,10 @@ intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
>  		return NULL;
>  
>  	dig_port->dp.output_reg = DDI_BUF_CTL(port);
> -	dig_port->dp.prepare_link_retrain = intel_ddi_prepare_link_retrain;
> +	if (DISPLAY_VER(i915) >= 14)
> +		dig_port->dp.prepare_link_retrain = mtl_ddi_prepare_link_retrain;
> +	else
> +		dig_port->dp.prepare_link_retrain = intel_ddi_prepare_link_retrain;
>  	dig_port->dp.set_link_train = intel_ddi_set_link_train;
>  	dig_port->dp.set_idle_link_train = intel_ddi_set_idle_link_train;
>  
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 531c0ea68c05..df29ab301326 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -5655,11 +5655,16 @@ enum skl_power_gate {
>  /* DDI Buffer Control */
>  #define _DDI_BUF_CTL_A				0x64000
>  #define _DDI_BUF_CTL_B				0x64100
> +/* Known as DDI_CTL_DE in MTL+ */
>  #define DDI_BUF_CTL(port) _MMIO_PORT(port, _DDI_BUF_CTL_A, _DDI_BUF_CTL_B)
>  #define  DDI_BUF_CTL_ENABLE			(1 << 31)
>  #define  DDI_BUF_TRANS_SELECT(n)	((n) << 24)
>  #define  DDI_BUF_EMP_MASK			(0xf << 24)
>  #define  DDI_BUF_PHY_LINK_RATE(r)		((r) << 20)
> +#define  DDI_BUF_PORT_DATA_MASK			REG_GENMASK(19, 18)
> +#define  DDI_BUF_PORT_DATA_10BIT		REG_FIELD_PREP(DDI_BUF_PORT_DATA_MASK, 0)
> +#define  DDI_BUF_PORT_DATA_20BIT		REG_FIELD_PREP(DDI_BUF_PORT_DATA_MASK, 1)
> +#define  DDI_BUF_PORT_DATA_40BIT		REG_FIELD_PREP(DDI_BUF_PORT_DATA_MASK, 2)
>  #define  DDI_BUF_PORT_REVERSAL			(1 << 16)
>  #define  DDI_BUF_IS_IDLE			(1 << 7)
>  #define  DDI_BUF_CTL_TC_PHY_OWNERSHIP		REG_BIT(6)
> -- 
> 2.34.1
> 


More information about the Intel-gfx mailing list