[Intel-gfx] [PATCH 2/4] drm/i915: fix Haswell FDI link training code
Paulo Zanoni
przanoni at gmail.com
Thu Nov 1 23:17:58 CET 2012
This is wrong.... Ignore it. I messed up rebasing it against the new patches.
2012/11/1 Paulo Zanoni <przanoni at gmail.com>:
> From: Paulo Zanoni <paulo.r.zanoni at intel.com>
>
> This commit makes hsw_fdi_link_train responsible for implementing
> everything described in the "Enable and train FDI" section from the
> Hawell CRT mode set sequence documentation. We completely rewrite
> hsw_fdi_link_train to match the documentation and we also call it in
> the right place.
>
> This patch was initially sent as a series of tiny patches fixing every
> little problem of the function, but since there were too many patches
> fixing the same function it got a little difficult to get the "big
> picture" of how the function would be in the end, so here we amended
> all the patches into a single big patch fixing the whole function.
>
> Problems we fixed:
>
> 1 - Train Haswell FDI at the right time.
>
> We need to train the FDI before enabling the pipes and planes, so
> we're moving the call from lpt_pch_enable to haswell_crtc_enable
> directly.
>
> We are also removing ironlake_fdi_pll_enable since the PLL
> enablement on Haswell is completely different and is also done
> during the link training steps.
>
> 2 - Use the right FDI_RX_CTL register on Haswell
>
> There is only one PCH transcoder, so it's always _FDI_RXA_CTL.
> Using "pipe" here is wrong.
>
> 3 - Don't rely on DDI_BUF_CTL previous values
>
> Just set the bits we want, everything else is zero. Also
> POSTING_READ the register before sleeping.
>
> 4 - Program the FDI RX TUSIZE register on hsw_fdi_link_train
>
> According to the mode set sequence documentation, this is the
> right place. According to the FDI_RX_TUSIZE register description,
> this is the value we should set.
>
> Also remove the code that sets this register from the old
> location: lpt_pch_enable.
>
> 5 - Properly program FDI_RX_MISC pwrdn lane values on HSW
>
> 6 - Wait only 35us for the FDI link training
>
> First we wait 30us for the FDI receiver lane calibration, then we
> wait 5us for the FDI auto training time.
>
> 7 - Remove an useless indentation level on hsw_fdi_link_train
>
> We already "break" when the link training succeeds.
>
> 8 - Disable FDI_RX_ENABLE, not FDI_RX_PLL_ENABLE
>
> When we fail the training.
>
> 9 - Change Haswell FDI link training error messages
>
> We shouldn't call DRM_ERROR when still looping through voltage
> levels since this is expected and not really a failure. So in this
> commit we adjust the error path to only DRM_ERROR when we really
> fail after trying everything.
>
> While at it, replace DRM_DEBUG_DRIVER with DRM_DEBUG_KMS since
> it's what we use everywhere.
>
> 10 - Try each voltage twice at hsw_fdi_link_train
>
> Now with Daniel Vetter's suggestion to use "/2" instead of ">>1".
>
> Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com>
> ---
> drivers/gpu/drm/i915/i915_reg.h | 17 ++++--
> drivers/gpu/drm/i915/intel_ddi.c | 108 +++++++++++++++++++++--------------
> drivers/gpu/drm/i915/intel_display.c | 11 +---
> 3 files changed, 76 insertions(+), 60 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index d4520d5..a167d76 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -3924,16 +3924,21 @@
> #define FDI_PORT_WIDTH_2X_LPT (1<<19)
> #define FDI_PORT_WIDTH_1X_LPT (0<<19)
>
> -#define _FDI_RXA_MISC 0xf0010
> -#define _FDI_RXB_MISC 0xf1010
> +#define _FDI_RXA_MISC 0xf0010
> +#define _FDI_RXB_MISC 0xf1010
> +#define FDI_RX_PWRDN_LANE1_MASK (3<<26)
> +#define FDI_RX_PWRDN_LANE1_VAL(x) ((x)<<26)
> +#define FDI_RX_PWRDN_LANE0_MASK (3<<24)
> +#define FDI_RX_PWRDN_LANE0_VAL(x) ((x)<<24)
> +#define FDI_RX_TP1_TO_TP2_48 (2<<20)
> +#define FDI_RX_TP1_TO_TP2_64 (3<<20)
> +#define FDI_RX_FDI_DELAY_90 (0x90<<0)
> +#define FDI_RX_MISC(pipe) _PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC)
> +
> #define _FDI_RXA_TUSIZE1 0xf0030
> #define _FDI_RXA_TUSIZE2 0xf0038
> #define _FDI_RXB_TUSIZE1 0xf1030
> #define _FDI_RXB_TUSIZE2 0xf1038
> -#define FDI_RX_TP1_TO_TP2_48 (2<<20)
> -#define FDI_RX_TP1_TO_TP2_64 (3<<20)
> -#define FDI_RX_FDI_DELAY_90 (0x90<<0)
> -#define FDI_RX_MISC(pipe) _PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC)
> #define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE1, _FDI_RXB_TUSIZE1)
> #define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE2, _FDI_RXB_TUSIZE2)
>
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index a7a555f..92c2d61 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -153,11 +153,33 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
> struct drm_device *dev = crtc->dev;
> struct drm_i915_private *dev_priv = dev->dev_private;
> struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> - int pipe = intel_crtc->pipe;
> - u32 reg, temp, i;
> + u32 temp, i, rx_ctl_val;
> +
> + /* Set the FDI_RX_MISC pwrdn lanes and the 2 workarounds listed at the
> + * mode set "sequence for CRT port" document:
> + * - TP1 to TP2 time with the default value
> + * - FDI delay to 90h
> + */
> + I915_WRITE(_FDI_RXA_MISC, FDI_RX_PWRDN_LANE1_VAL(2) |
> + FDI_RX_PWRDN_LANE0_VAL(2) |
> + FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
> +
> + /* Enable the PCH Receiver FDI PLL */
> + rx_ctl_val = FDI_RX_PLL_ENABLE | FDI_RX_ENHANCE_FRAME_ENABLE |
> + ((intel_crtc->fdi_lanes - 1) << 19);
> + I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
> + POSTING_READ(_FDI_RXA_CTL);
> + udelay(220);
> +
> + /* Switch from Rawclk to PCDclk */
> + rx_ctl_val |= FDI_PCDCLK;
> + I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
> +
> + /* Configure Port Clock Select */
> + I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->ddi_pll_sel);
>
> /* Start the training iterating through available voltages and emphasis */
> - for (i=0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values); i++) {
> + for (i = 0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values) * 2; i++) {
> /* Configure DP_TP_CTL with auto-training */
> I915_WRITE(DP_TP_CTL(PORT_E),
> DP_TP_CTL_FDI_AUTOTRAIN |
> @@ -166,41 +188,37 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
> DP_TP_CTL_ENABLE);
>
> /* Configure and enable DDI_BUF_CTL for DDI E with next voltage */
> - temp = I915_READ(DDI_BUF_CTL(PORT_E));
> - temp = (temp & ~DDI_BUF_EMP_MASK);
> I915_WRITE(DDI_BUF_CTL(PORT_E),
> - temp |
> - DDI_BUF_CTL_ENABLE |
> - ((intel_crtc->fdi_lanes - 1) << 1) |
> - hsw_ddi_buf_ctl_values[i]);
> + DDI_BUF_CTL_ENABLE |
> + ((intel_crtc->fdi_lanes - 1) << 1) |
> + hsw_ddi_buf_ctl_values[i / 2]);
> + POSTING_READ(DDI_BUF_CTL(PORT_E));
>
> udelay(600);
>
> - /* We need to program FDI_RX_MISC with the default TP1 to TP2
> - * values before enabling the receiver, and configure the delay
> - * for the FDI timing generator to 90h. Luckily, all the other
> - * bits are supposed to be zeroed, so we can write those values
> - * directly.
> - */
> - I915_WRITE(FDI_RX_MISC(pipe), FDI_RX_TP1_TO_TP2_48 |
> - FDI_RX_FDI_DELAY_90);
> -
> - /* Enable CPU FDI Receiver with auto-training */
> - reg = FDI_RX_CTL(pipe);
> - I915_WRITE(reg,
> - I915_READ(reg) |
> - FDI_LINK_TRAIN_AUTO |
> - FDI_RX_ENABLE |
> - FDI_LINK_TRAIN_PATTERN_1_CPT |
> - FDI_RX_ENHANCE_FRAME_ENABLE |
> - ((intel_crtc->fdi_lanes - 1) << 19) |
> - FDI_RX_PLL_ENABLE);
> - POSTING_READ(reg);
> - udelay(100);
> + /* Program PCH FDI Receiver TU */
> + I915_WRITE(_FDI_RXA_TUSIZE1, TU_SIZE(64));
> +
> + /* Enable PCH FDI Receiver with auto-training */
> + rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO;
> + I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
> + POSTING_READ(_FDI_RXA_CTL);
> +
> + /* Wait for FDI receiver lane calibration */
> + udelay(30);
> +
> + /* Unset FDI_RX_MISC pwrdn lanes */
> + temp = I915_READ(_FDI_RXA_MISC);
> + temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
> + I915_WRITE(_FDI_RXA_MISC, temp);
> + POSTING_READ(_FDI_RXA_MISC);
> +
> + /* Wait for FDI auto training time */
> + udelay(5);
>
> temp = I915_READ(DP_TP_STATUS(PORT_E));
> if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) {
> - DRM_DEBUG_DRIVER("BUF_CTL training done on %d step\n", i);
> + DRM_DEBUG_KMS("FDI link training done on step %d\n", i);
>
> /* Enable normal pixel sending for FDI */
> I915_WRITE(DP_TP_CTL(PORT_E),
> @@ -209,22 +227,24 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
> DP_TP_CTL_ENHANCED_FRAME_ENABLE |
> DP_TP_CTL_ENABLE);
>
> - break;
> - } else {
> - DRM_ERROR("Error training BUF_CTL %d\n", i);
> -
> - /* Disable DP_TP_CTL and FDI_RX_CTL) and retry */
> - I915_WRITE(DP_TP_CTL(PORT_E),
> - I915_READ(DP_TP_CTL(PORT_E)) &
> - ~DP_TP_CTL_ENABLE);
> - I915_WRITE(FDI_RX_CTL(pipe),
> - I915_READ(FDI_RX_CTL(pipe)) &
> - ~FDI_RX_PLL_ENABLE);
> - continue;
> + return;
> }
> +
> + /* Disable DP_TP_CTL and FDI_RX_CTL and retry */
> + I915_WRITE(DP_TP_CTL(PORT_E),
> + I915_READ(DP_TP_CTL(PORT_E)) & ~DP_TP_CTL_ENABLE);
> +
> + rx_ctl_val &= ~FDI_RX_ENABLE;
> + I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
> +
> + /* Reset FDI_RX_MISC pwrdn lanes */
> + temp = I915_READ(_FDI_RXA_MISC);
> + temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
> + temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
> + I915_WRITE(_FDI_RXA_MISC, temp);
> }
>
> - DRM_DEBUG_KMS("FDI train done.\n");
> + DRM_ERROR("FDI link training failed!\n");
> }
>
> /* WRPLL clock dividers */
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 14ea479..69ed903 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3114,9 +3114,6 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
> I915_WRITE(FDI_RX_TUSIZE1(pipe),
> I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
>
> - /* For PCH output, training FDI link */
> - dev_priv->display.fdi_link_train(crtc);
> -
> /* XXX: pch pll's can be enabled any time before we enable the PCH
> * transcoder, and we actually should do this to not upset any PCH
> * transcoder that already use the clock when we share it.
> @@ -3209,16 +3206,10 @@ static void lpt_pch_enable(struct drm_crtc *crtc)
> struct drm_device *dev = crtc->dev;
> struct drm_i915_private *dev_priv = dev->dev_private;
> struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> - int pipe = intel_crtc->pipe;
> enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
>
> assert_transcoder_disabled(dev_priv, TRANSCODER_A);
>
> - /* Write the TU size bits before fdi link training, so that error
> - * detection works. */
> - I915_WRITE(FDI_RX_TUSIZE1(pipe),
> - I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
> -
> /* For PCH output, training FDI link */
> dev_priv->display.fdi_link_train(crtc);
>
> @@ -3451,7 +3442,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
> is_pch_port = haswell_crtc_driving_pch(crtc);
>
> if (is_pch_port)
> - ironlake_fdi_pll_enable(intel_crtc);
> + dev_priv->display.fdi_link_train(crtc);
>
> for_each_encoder_on_crtc(dev, crtc, encoder)
> if (encoder->pre_enable)
> --
> 1.7.11.4
>
--
Paulo Zanoni
More information about the Intel-gfx
mailing list