drm/i915: Implement display w/a #1143
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Mon, 22 Jan 2018 17:41:31 +0000 (19:41 +0200)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 24 Jan 2018 18:09:29 +0000 (20:09 +0200)
Apparently SKL/KBL/CFL need some manual help to get the
programmed HDMI vswing to stick. Implement the relevant
workaround (display w/a #1143).

Note that the relevant chicken bits live in a transcoder register
even though the bits affect a specific DDI port rather than a
specific transcoder. Hence we must pick the correct transcoder
register instance based on the port rather than based on the
cpu_transcoder.

Also note that for completeness I included support for DDI A/E
in the code even though we never have HDMI on those ports.

v2: CFL needs the w/a as well (Rodrigo and Art)

Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Art Runyan <arthur.j.runyan@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180122174131.28046-1-ville.syrjala@linux.intel.com
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_ddi.c

index 9c56e2165b2abad5d2a2fefd2dd869b4b6d89d14..b06db954c79fc673e9a7b3026df24c8175618b14 100644 (file)
@@ -7079,8 +7079,12 @@ enum {
 #define CHICKEN_TRANS_A         0x420c0
 #define CHICKEN_TRANS_B         0x420c4
 #define CHICKEN_TRANS(trans) _MMIO_TRANS(trans, CHICKEN_TRANS_A, CHICKEN_TRANS_B)
-#define PSR2_VSC_ENABLE_PROG_HEADER    (1<<12)
-#define PSR2_ADD_VERTICAL_LINE_COUNT   (1<<15)
+#define  DDI_TRAINING_OVERRIDE_ENABLE  (1<<19)
+#define  DDI_TRAINING_OVERRIDE_VALUE   (1<<18)
+#define  DDIE_TRAINING_OVERRIDE_ENABLE (1<<17) /* CHICKEN_TRANS_A only */
+#define  DDIE_TRAINING_OVERRIDE_VALUE  (1<<16) /* CHICKEN_TRANS_A only */
+#define  PSR2_ADD_VERTICAL_LINE_COUNT   (1<<15)
+#define  PSR2_VSC_ENABLE_PROG_HEADER    (1<<12)
 
 #define DISP_ARB_CTL   _MMIO(0x45000)
 #define  DISP_FBC_MEMORY_WAKE          (1<<31)
index f51645a08dcaf489e0668af616fe39d421822a38..2756a69b6207608dde4d2cee947c9ae6b064e955 100644 (file)
@@ -2404,6 +2404,48 @@ static void intel_enable_ddi_hdmi(struct intel_encoder *encoder,
                                          crtc_state->hdmi_high_tmds_clock_ratio,
                                          crtc_state->hdmi_scrambling);
 
+       /* Display WA #1143: skl,kbl,cfl */
+       if (IS_GEN9_BC(dev_priv)) {
+               /*
+                * For some reason these chicken bits have been
+                * stuffed into a transcoder register, event though
+                * the bits affect a specific DDI port rather than
+                * a specific transcoder.
+                */
+               static const enum transcoder port_to_transcoder[] = {
+                       [PORT_A] = TRANSCODER_EDP,
+                       [PORT_B] = TRANSCODER_A,
+                       [PORT_C] = TRANSCODER_B,
+                       [PORT_D] = TRANSCODER_C,
+                       [PORT_E] = TRANSCODER_A,
+               };
+               enum transcoder transcoder = port_to_transcoder[port];
+               u32 val;
+
+               val = I915_READ(CHICKEN_TRANS(transcoder));
+
+               if (port == PORT_E)
+                       val |= DDIE_TRAINING_OVERRIDE_ENABLE |
+                               DDIE_TRAINING_OVERRIDE_VALUE;
+               else
+                       val |= DDI_TRAINING_OVERRIDE_ENABLE |
+                               DDI_TRAINING_OVERRIDE_VALUE;
+
+               I915_WRITE(CHICKEN_TRANS(transcoder), val);
+               POSTING_READ(CHICKEN_TRANS(transcoder));
+
+               udelay(1);
+
+               if (port == PORT_E)
+                       val &= ~(DDIE_TRAINING_OVERRIDE_ENABLE |
+                                DDIE_TRAINING_OVERRIDE_VALUE);
+               else
+                       val &= ~(DDI_TRAINING_OVERRIDE_ENABLE |
+                                DDI_TRAINING_OVERRIDE_VALUE);
+
+               I915_WRITE(CHICKEN_TRANS(transcoder), val);
+       }
+
        /* In HDMI/DVI mode, the port width, and swing/emphasis values
         * are ignored so nothing special needs to be done besides
         * enabling the port.