Hi 2012/11/1 Daniel Vetter <daniel.vetter at ffwll.ch>: > We need to set the timing override chicken bit after fdi link training > has completed and before we enable the dp transcoder. We also have to > clear that bit again after disabling the pch dp transcoder. > > See "Graphics BSpec: vol4g North Display Engine Registers [IVB], > Display Mode Set Sequence" and "Graphics BSpec: vol4h South Display > Engine Registers [CPT, PPT], South Display Engine Transcoder and FDI > Control, Transcoder Debug and DFT, TRANS_CHICKEN_2" bit 31: > > "Workaround : Enable the override prior to enabling the transcoder. > Disable the override after disabling the transcoder." > > While at it, use the _PIPE macro for the other TRANS_DP register. > > v2: Keep the w/a as-is, but kill the original (but wrongly placed) > workaround introduced in > > commit 3bcf603f6d5d18bd9d076dc280de71f48add4101 > Author: Jesse Barnes <jbarnes at virtuousgeek.org> > Date: Wed Jul 27 11:51:40 2011 -0700 > > drm/i915: apply timing generator bug workaround on CPT and PPT > > and > > commit d4270e57efe9e2536798c59e1ed2fd0a1e5cdfcf > Author: Jesse Barnes <jbarnes at virtuousgeek.org> > Date: Tue Oct 11 10:43:02 2011 -0700 > > drm/i915: export a CPT mode set verification function > > Note that this old code has unconditionally set the w/a, which might > explain why fdi link training sometimes silently fails, and especially > why the auto-train did not seem to work properly. > > v3: Paulo Zanoni pointed out that this workaround is also required on > the LPT PCH. And Arthur Ranyan confirmed that this workaround is > requierd for all ports on the pch, not just DP: The important part s/requierd/required/ > is that the bit is set whenever the pch transcoder is enabled, and > that it is _not_ set while the fdi link is trained. It is also > important that the pch transcoder is fully disabled, i.e. we have to > wait for bit 30 to clear before clearing the w/a bit. > > Hence move to workaround into enable/disable_transcoder, where the pch > transcoder gets enabled/disabled. > > v4: Whitespace changes dropped. > > v5: Don't run the w/a on IBX, we only need it on CPT/PPT and LPT. > > Cc: Jesse Barnes <jbarnes at virtuousgeek.org> > Cc: Paulo Zanoni <przanoni at gmail.com> > Cc: Arthur Ranyan <arthur.j.runyan at intel.com> > Signed-off-by: Daniel Vetter <daniel.vetter at ffwll.ch> For me, it doesn't matter if you do !HAS_PCH_IBX or HAS_PCH_CPT, I will have to fork the functions for LPT anyway, so I will fix that, independently of what you do here. Reviewed-by: Paulo Zanoni <paulo.r.zanoni at intel.com> > --- > drivers/gpu/drm/i915/i915_reg.h | 5 +++-- > drivers/gpu/drm/i915/intel_display.c | 32 +++++++++++++++++++++++--------- > drivers/gpu/drm/i915/intel_pm.c | 4 ---- > 3 files changed, 26 insertions(+), 15 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > index 2dd880f..f1fe3a0 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -3806,7 +3806,8 @@ > #define _TRANSA_CHICKEN2 0xf0064 > #define _TRANSB_CHICKEN2 0xf1064 > #define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) > -#define TRANS_AUTOTRAIN_GEN_STALL_DIS (1<<31) > +#define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31) > + > > #define SOUTH_CHICKEN1 0xc2000 > #define FDIA_PHASE_SYNC_SHIFT_OVR 19 > @@ -4064,7 +4065,7 @@ > #define TRANS_DP_CTL_A 0xe0300 > #define TRANS_DP_CTL_B 0xe1300 > #define TRANS_DP_CTL_C 0xe2300 > -#define TRANS_DP_CTL(pipe) (TRANS_DP_CTL_A + (pipe) * 0x01000) > +#define TRANS_DP_CTL(pipe) _PIPE(pipe, TRANS_DP_CTL_A, TRANS_DP_CTL_B) > #define TRANS_DP_OUTPUT_ENABLE (1<<31) > #define TRANS_DP_PORT_SEL_B (0<<29) > #define TRANS_DP_PORT_SEL_C (1<<29) > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c > index 129059b..675079a 100644 > --- a/drivers/gpu/drm/i915/intel_display.c > +++ b/drivers/gpu/drm/i915/intel_display.c > @@ -1673,9 +1673,9 @@ static void intel_disable_pch_pll(struct intel_crtc *intel_crtc) > static void intel_enable_transcoder(struct drm_i915_private *dev_priv, > enum pipe pipe) > { > - int reg; > - u32 val, pipeconf_val; > + struct drm_device *dev = dev_priv->dev; > struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; > + uint32_t reg, val, pipeconf_val; > > /* PCH only available on ILK+ */ > BUG_ON(dev_priv->info->gen < 5); > @@ -1693,6 +1693,16 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv, > DRM_ERROR("Attempting to enable transcoder on Haswell with pipe > 0\n"); > return; > } > + > + if (!HAS_PCH_IBX(dev)) { > + /* Workaround: Set the timing override bit before enabling the > + * pch transcoder. */ > + reg = TRANS_CHICKEN2(pipe); > + val = I915_READ(reg); > + val |= TRANS_CHICKEN2_TIMING_OVERRIDE; > + I915_WRITE(reg, val); > + } > + > reg = TRANSCONF(pipe); > val = I915_READ(reg); > pipeconf_val = I915_READ(PIPECONF(pipe)); > @@ -1724,8 +1734,8 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv, > static void intel_disable_transcoder(struct drm_i915_private *dev_priv, > enum pipe pipe) > { > - int reg; > - u32 val; > + struct drm_device *dev = dev_priv->dev; > + uint32_t reg, val; > > /* FDI relies on the transcoder */ > assert_fdi_tx_disabled(dev_priv, pipe); > @@ -1741,6 +1751,14 @@ static void intel_disable_transcoder(struct drm_i915_private *dev_priv, > /* wait for PCH transcoder off, transcoder state */ > if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50)) > DRM_ERROR("failed to disable transcoder %d\n", pipe); > + > + if (!HAS_PCH_IBX(dev)) { > + /* Workaround: Clear the timing override chicken bit again. */ > + reg = TRANS_CHICKEN2(pipe); > + val = I915_READ(reg); > + val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE; > + I915_WRITE(reg, val); > + } > } > > /** > @@ -3217,16 +3235,12 @@ prepare: /* separate function? */ > void intel_cpt_verify_modeset(struct drm_device *dev, int pipe) > { > struct drm_i915_private *dev_priv = dev->dev_private; > - int dslreg = PIPEDSL(pipe), tc2reg = TRANS_CHICKEN2(pipe); > + int dslreg = PIPEDSL(pipe); > u32 temp; > > temp = I915_READ(dslreg); > udelay(500); > if (wait_for(I915_READ(dslreg) != temp, 5)) { > - /* Without this, mode sets may fail silently on FDI */ > - I915_WRITE(tc2reg, TRANS_AUTOTRAIN_GEN_STALL_DIS); > - udelay(250); > - I915_WRITE(tc2reg, 0); > if (wait_for(I915_READ(dslreg) != temp, 5)) > DRM_ERROR("mode set failed: pipe %d stuck\n", pipe); > } > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c > index a04b336..3469fbd 100644 > --- a/drivers/gpu/drm/i915/intel_pm.c > +++ b/drivers/gpu/drm/i915/intel_pm.c > @@ -3786,7 +3786,6 @@ static void ibx_init_clock_gating(struct drm_device *dev) > static void cpt_init_clock_gating(struct drm_device *dev) > { > struct drm_i915_private *dev_priv = dev->dev_private; > - int pipe; > > /* > * On Ibex Peak and Cougar Point, we need to disable clock > @@ -3796,9 +3795,6 @@ static void cpt_init_clock_gating(struct drm_device *dev) > I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); > I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) | > DPLS_EDP_PPS_FIX_DIS); > - /* Without this, mode sets may fail silently on FDI */ > - for_each_pipe(pipe) > - I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS); > } > > void intel_init_clock_gating(struct drm_device *dev) > -- > 1.7.11.4 > -- Paulo Zanoni