drm/i915: Support for Cougarpoint PCH display pipeline
authorZhenyu Wang <zhenyuw@linux.intel.com>
Wed, 7 Apr 2010 08:15:54 +0000 (16:15 +0800)
committerEric Anholt <eric@anholt.net>
Mon, 12 Apr 2010 16:23:40 +0000 (09:23 -0700)
Cougarpoint is the new PCH for Sandybridge CPU. This one resolves the
chipset change for display pipeline compared to previous Ibexpeak PCH.

Sandybridge/Cougarpoint has different FDI training parameters, so this also
makes seperate FDI training functions for IBX and CPT. Other change includes
new transcoder DPLL select function to set which DPLL for transcoder to pick
up.

And with another new transcoder C introduced in Cougarpoint, each connector
has new transcoder select bits. This one adds that change to light up VGA.

Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c

index cbbf59f..8de8194 100644 (file)
 #define   DP_LINK_TRAIN_MASK           (3 << 28)
 #define   DP_LINK_TRAIN_SHIFT          28
 
+/* CPT Link training mode */
+#define   DP_LINK_TRAIN_PAT_1_CPT      (0 << 8)
+#define   DP_LINK_TRAIN_PAT_2_CPT      (1 << 8)
+#define   DP_LINK_TRAIN_PAT_IDLE_CPT   (2 << 8)
+#define   DP_LINK_TRAIN_OFF_CPT                (3 << 8)
+#define   DP_LINK_TRAIN_MASK_CPT       (7 << 8)
+#define   DP_LINK_TRAIN_SHIFT_CPT      8
+
 /* Signal voltages. These are mostly controlled by the other end */
 #define   DP_VOLTAGE_0_4               (0 << 25)
 #define   DP_VOLTAGE_0_6               (1 << 25)
 #define SDE_PORTB_HOTPLUG       (1 << 8)
 #define SDE_SDVOB_HOTPLUG       (1 << 6)
 #define SDE_HOTPLUG_MASK       (0xf << 8)
+/* CPT */
+#define SDE_CRT_HOTPLUG_CPT    (1 << 19)
+#define SDE_PORTD_HOTPLUG_CPT  (1 << 23)
+#define SDE_PORTC_HOTPLUG_CPT  (1 << 22)
+#define SDE_PORTB_HOTPLUG_CPT  (1 << 21)
 
 #define SDEISR  0xc4000
 #define SDEIMR  0xc4004
 #define PCH_SSC4_PARMS          0xc6210
 #define PCH_SSC4_AUX_PARMS      0xc6214
 
+#define PCH_DPLL_SEL           0xc7000
+#define  TRANSA_DPLL_ENABLE    (1<<3)
+#define         TRANSA_DPLLB_SEL       (1<<0)
+#define         TRANSA_DPLLA_SEL       0
+#define  TRANSB_DPLL_ENABLE    (1<<7)
+#define         TRANSB_DPLLB_SEL       (1<<4)
+#define         TRANSB_DPLLA_SEL       (0)
+#define  TRANSC_DPLL_ENABLE    (1<<11)
+#define         TRANSC_DPLLB_SEL       (1<<8)
+#define         TRANSC_DPLLA_SEL       (0)
+
 /* transcoder */
 
 #define TRANS_HTOTAL_A          0xe0000
 #define  FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1<<22)
 #define  FDI_LINK_TRAIN_PRE_EMPHASIS_2X   (2<<22)
 #define  FDI_LINK_TRAIN_PRE_EMPHASIS_3X   (3<<22)
+/* ILK always use 400mV 0dB for voltage swing and pre-emphasis level.
+   SNB has different settings. */
+/* SNB A-stepping */
+#define  FDI_LINK_TRAIN_400MV_0DB_SNB_A                (0x38<<22)
+#define  FDI_LINK_TRAIN_400MV_6DB_SNB_A                (0x02<<22)
+#define  FDI_LINK_TRAIN_600MV_3_5DB_SNB_A      (0x01<<22)
+#define  FDI_LINK_TRAIN_800MV_0DB_SNB_A                (0x0<<22)
+/* SNB B-stepping */
+#define  FDI_LINK_TRAIN_400MV_0DB_SNB_B                (0x0<<22)
+#define  FDI_LINK_TRAIN_400MV_6DB_SNB_B                (0x3a<<22)
+#define  FDI_LINK_TRAIN_600MV_3_5DB_SNB_B      (0x39<<22)
+#define  FDI_LINK_TRAIN_800MV_0DB_SNB_B                (0x38<<22)
+#define  FDI_LINK_TRAIN_VOL_EMP_MASK           (0x3f<<22)
 #define  FDI_DP_PORT_WIDTH_X1           (0<<19)
 #define  FDI_DP_PORT_WIDTH_X2           (1<<19)
 #define  FDI_DP_PORT_WIDTH_X3           (2<<19)
 #define  FDI_RX_ENHANCE_FRAME_ENABLE    (1<<6)
 #define  FDI_SEL_RAWCLK                 (0<<4)
 #define  FDI_SEL_PCDCLK                 (1<<4)
+/* CPT */
+#define  FDI_AUTO_TRAINING                     (1<<10)
+#define  FDI_LINK_TRAIN_PATTERN_1_CPT          (0<<8)
+#define  FDI_LINK_TRAIN_PATTERN_2_CPT          (1<<8)
+#define  FDI_LINK_TRAIN_PATTERN_IDLE_CPT       (2<<8)
+#define  FDI_LINK_TRAIN_NORMAL_CPT             (3<<8)
+#define  FDI_LINK_TRAIN_PATTERN_MASK_CPT       (3<<8)
 
 #define FDI_RXA_MISC            0xf0010
 #define FDI_RXB_MISC            0xf1010
 #define PCH_DPD_AUX_CH_DATA4   0xe4320
 #define PCH_DPD_AUX_CH_DATA5   0xe4324
 
+/* CPT */
+#define  PORT_TRANS_A_SEL_CPT  0
+#define  PORT_TRANS_B_SEL_CPT  (1<<29)
+#define  PORT_TRANS_C_SEL_CPT  (2<<29)
+#define  PORT_TRANS_SEL_MASK   (3<<29)
+
+#define TRANS_DP_CTL_A         0xe0300
+#define TRANS_DP_CTL_B         0xe1300
+#define TRANS_DP_CTL_C         0xe2300
+#define  TRANS_DP_OUTPUT_ENABLE        (1<<31)
+#define  TRANS_DP_PORT_SEL_B   (0<<29)
+#define  TRANS_DP_PORT_SEL_C   (1<<29)
+#define  TRANS_DP_PORT_SEL_D   (2<<29)
+#define  TRANS_DP_PORT_SEL_MASK        (3<<29)
+#define  TRANS_DP_AUDIO_ONLY   (1<<26)
+#define  TRANS_DP_ENH_FRAMING  (1<<18)
+#define  TRANS_DP_8BPC         (0<<9)
+#define  TRANS_DP_10BPC                (1<<9)
+#define  TRANS_DP_6BPC         (2<<9)
+#define  TRANS_DP_12BPC                (3<<9)
+#define  TRANS_DP_VSYNC_ACTIVE_HIGH    (1<<4)
+#define  TRANS_DP_VSYNC_ACTIVE_LOW     0
+#define  TRANS_DP_HSYNC_ACTIVE_HIGH    (1<<3)
+#define  TRANS_DP_HSYNC_ACTIVE_LOW     0
+
+/* SNB eDP training params */
+/* SNB A-stepping */
+#define  EDP_LINK_TRAIN_400MV_0DB_SNB_A                (0x38<<22)
+#define  EDP_LINK_TRAIN_400MV_6DB_SNB_A                (0x02<<22)
+#define  EDP_LINK_TRAIN_600MV_3_5DB_SNB_A      (0x01<<22)
+#define  EDP_LINK_TRAIN_800MV_0DB_SNB_A                (0x0<<22)
+/* SNB B-stepping */
+#define  EDP_LINK_TRAIN_400MV_0DB_SNB_B                (0x0<<22)
+#define  EDP_LINK_TRAIN_400MV_6DB_SNB_B                (0x3a<<22)
+#define  EDP_LINK_TRAIN_600MV_3_5DB_SNB_B      (0x39<<22)
+#define  EDP_LINK_TRAIN_800MV_0DB_SNB_B                (0x38<<22)
+#define  EDP_LINK_TRAIN_VOL_EMP_MASK_SNB       (0x3f<<22)
+
 #endif /* _I915_REG_H_ */
index 4dd5daa..1f732ba 100644 (file)
@@ -135,11 +135,17 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
                adpa |= ADPA_VSYNC_ACTIVE_HIGH;
 
        if (intel_crtc->pipe == 0) {
-               adpa |= ADPA_PIPE_A_SELECT;
+               if (HAS_PCH_CPT(dev))
+                       adpa |= PORT_TRANS_A_SEL_CPT;
+               else
+                       adpa |= ADPA_PIPE_A_SELECT;
                if (!HAS_PCH_SPLIT(dev))
                        I915_WRITE(BCLRPAT_A, 0);
        } else {
-               adpa |= ADPA_PIPE_B_SELECT;
+               if (HAS_PCH_CPT(dev))
+                       adpa |= PORT_TRANS_B_SEL_CPT;
+               else
+                       adpa |= ADPA_PIPE_B_SELECT;
                if (!HAS_PCH_SPLIT(dev))
                        I915_WRITE(BCLRPAT_B, 0);
        }
index 9b59979..716ab9e 100644 (file)
@@ -1508,6 +1508,217 @@ static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock)
        udelay(500);
 }
 
+/* The FDI link training functions for ILK/Ibexpeak. */
+static void ironlake_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;
+       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
+       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
+       int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
+       int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
+       u32 temp, tries = 0;
+
+       /* enable CPU FDI TX and PCH FDI RX */
+       temp = I915_READ(fdi_tx_reg);
+       temp |= FDI_TX_ENABLE;
+       temp |= FDI_DP_PORT_WIDTH_X4; /* default */
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_1;
+       I915_WRITE(fdi_tx_reg, temp);
+       I915_READ(fdi_tx_reg);
+
+       temp = I915_READ(fdi_rx_reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_1;
+       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
+       I915_READ(fdi_rx_reg);
+       udelay(150);
+
+       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+          for train result */
+       temp = I915_READ(fdi_rx_imr_reg);
+       temp &= ~FDI_RX_SYMBOL_LOCK;
+       temp &= ~FDI_RX_BIT_LOCK;
+       I915_WRITE(fdi_rx_imr_reg, temp);
+       I915_READ(fdi_rx_imr_reg);
+       udelay(150);
+
+       for (;;) {
+               temp = I915_READ(fdi_rx_iir_reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if ((temp & FDI_RX_BIT_LOCK)) {
+                       DRM_DEBUG_KMS("FDI train 1 done.\n");
+                       I915_WRITE(fdi_rx_iir_reg,
+                                  temp | FDI_RX_BIT_LOCK);
+                       break;
+               }
+
+               tries++;
+
+               if (tries > 5) {
+                       DRM_DEBUG_KMS("FDI train 1 fail!\n");
+                       break;
+               }
+       }
+
+       /* Train 2 */
+       temp = I915_READ(fdi_tx_reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_2;
+       I915_WRITE(fdi_tx_reg, temp);
+
+       temp = I915_READ(fdi_rx_reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_2;
+       I915_WRITE(fdi_rx_reg, temp);
+       udelay(150);
+
+       tries = 0;
+
+       for (;;) {
+               temp = I915_READ(fdi_rx_iir_reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if (temp & FDI_RX_SYMBOL_LOCK) {
+                       I915_WRITE(fdi_rx_iir_reg,
+                                  temp | FDI_RX_SYMBOL_LOCK);
+                       DRM_DEBUG_KMS("FDI train 2 done.\n");
+                       break;
+               }
+
+               tries++;
+
+               if (tries > 5) {
+                       DRM_DEBUG_KMS("FDI train 2 fail!\n");
+                       break;
+               }
+       }
+
+       DRM_DEBUG_KMS("FDI train done\n");
+}
+
+static int snb_b_fdi_train_param [] = {
+       FDI_LINK_TRAIN_400MV_0DB_SNB_B,
+       FDI_LINK_TRAIN_400MV_6DB_SNB_B,
+       FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
+       FDI_LINK_TRAIN_800MV_0DB_SNB_B,
+};
+
+/* The FDI link training functions for SNB/Cougarpoint. */
+static void gen6_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;
+       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
+       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
+       int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
+       int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
+       u32 temp, i;
+
+       /* enable CPU FDI TX and PCH FDI RX */
+       temp = I915_READ(fdi_tx_reg);
+       temp |= FDI_TX_ENABLE;
+       temp |= FDI_DP_PORT_WIDTH_X4; /* default */
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_1;
+       temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+       /* SNB-B */
+       temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+       I915_WRITE(fdi_tx_reg, temp);
+       I915_READ(fdi_tx_reg);
+
+       temp = I915_READ(fdi_rx_reg);
+       if (HAS_PCH_CPT(dev)) {
+               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+               temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+       } else {
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_PATTERN_1;
+       }
+       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
+       I915_READ(fdi_rx_reg);
+       udelay(150);
+
+       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+          for train result */
+       temp = I915_READ(fdi_rx_imr_reg);
+       temp &= ~FDI_RX_SYMBOL_LOCK;
+       temp &= ~FDI_RX_BIT_LOCK;
+       I915_WRITE(fdi_rx_imr_reg, temp);
+       I915_READ(fdi_rx_imr_reg);
+       udelay(150);
+
+       for (i = 0; i < 4; i++ ) {
+               temp = I915_READ(fdi_tx_reg);
+               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+               temp |= snb_b_fdi_train_param[i];
+               I915_WRITE(fdi_tx_reg, temp);
+               udelay(500);
+
+               temp = I915_READ(fdi_rx_iir_reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if (temp & FDI_RX_BIT_LOCK) {
+                       I915_WRITE(fdi_rx_iir_reg,
+                                  temp | FDI_RX_BIT_LOCK);
+                       DRM_DEBUG_KMS("FDI train 1 done.\n");
+                       break;
+               }
+       }
+       if (i == 4)
+               DRM_DEBUG_KMS("FDI train 1 fail!\n");
+
+       /* Train 2 */
+       temp = I915_READ(fdi_tx_reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_2;
+       if (IS_GEN6(dev)) {
+               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+               /* SNB-B */
+               temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+       }
+       I915_WRITE(fdi_tx_reg, temp);
+
+       temp = I915_READ(fdi_rx_reg);
+       if (HAS_PCH_CPT(dev)) {
+               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+               temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
+       } else {
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_PATTERN_2;
+       }
+       I915_WRITE(fdi_rx_reg, temp);
+       udelay(150);
+
+       for (i = 0; i < 4; i++ ) {
+               temp = I915_READ(fdi_tx_reg);
+               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+               temp |= snb_b_fdi_train_param[i];
+               I915_WRITE(fdi_tx_reg, temp);
+               udelay(500);
+
+               temp = I915_READ(fdi_rx_iir_reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if (temp & FDI_RX_SYMBOL_LOCK) {
+                       I915_WRITE(fdi_rx_iir_reg,
+                                  temp | FDI_RX_SYMBOL_LOCK);
+                       DRM_DEBUG_KMS("FDI train 2 done.\n");
+                       break;
+               }
+       }
+       if (i == 4)
+               DRM_DEBUG_KMS("FDI train 2 fail!\n");
+
+       DRM_DEBUG_KMS("FDI train done.\n");
+}
+
 static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
        struct drm_device *dev = crtc->dev;
@@ -1521,8 +1732,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
        int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
        int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
        int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-       int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
-       int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
        int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
        int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1;
        int pf_win_size = (pipe == 0) ? PFA_WIN_SZ : PFB_WIN_SZ;
@@ -1539,8 +1748,9 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
        int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B;
        int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
        int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
+       int trans_dpll_sel = (pipe == 0) ? 0 : 1;
        u32 temp;
-       int tries = 5, j, n;
+       int n;
        u32 pipe_bpc;
 
        temp = I915_READ(pipeconf_reg);
@@ -1567,12 +1777,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        /* enable eDP PLL */
                        ironlake_enable_pll_edp(crtc);
                } else {
-                       /* enable PCH DPLL */
-                       temp = I915_READ(pch_dpll_reg);
-                       if ((temp & DPLL_VCO_ENABLE) == 0) {
-                               I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
-                               I915_READ(pch_dpll_reg);
-                       }
 
                        /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
                        temp = I915_READ(fdi_rx_reg);
@@ -1583,11 +1787,16 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        temp &= ~(0x7 << 16);
                        temp |= (pipe_bpc << 11);
                        I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE |
-                                       FDI_SEL_PCDCLK |
                                        FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */
                        I915_READ(fdi_rx_reg);
                        udelay(200);
 
+                       /* Switch from Rawclk to PCDclk */
+                       temp = I915_READ(fdi_rx_reg);
+                       I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
+                       I915_READ(fdi_rx_reg);
+                       udelay(200);
+
                        /* Enable CPU FDI TX PLL, always on for Ironlake */
                        temp = I915_READ(fdi_tx_reg);
                        if ((temp & FDI_TX_PLL_ENABLE) == 0) {
@@ -1627,91 +1836,32 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                }
 
                if (!HAS_eDP) {
-                       /* enable CPU FDI TX and PCH FDI RX */
-                       temp = I915_READ(fdi_tx_reg);
-                       temp |= FDI_TX_ENABLE;
-                       temp |= FDI_DP_PORT_WIDTH_X4; /* default */
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       temp |= FDI_LINK_TRAIN_PATTERN_1;
-                       I915_WRITE(fdi_tx_reg, temp);
-                       I915_READ(fdi_tx_reg);
-
-                       temp = I915_READ(fdi_rx_reg);
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       temp |= FDI_LINK_TRAIN_PATTERN_1;
-                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
-                       I915_READ(fdi_rx_reg);
-
-                       udelay(150);
-
-                       /* Train FDI. */
-                       /* umask FDI RX Interrupt symbol_lock and bit_lock bit
-                          for train result */
-                       temp = I915_READ(fdi_rx_imr_reg);
-                       temp &= ~FDI_RX_SYMBOL_LOCK;
-                       temp &= ~FDI_RX_BIT_LOCK;
-                       I915_WRITE(fdi_rx_imr_reg, temp);
-                       I915_READ(fdi_rx_imr_reg);
-                       udelay(150);
+                       /* For PCH output, training FDI link */
+                       if (IS_GEN6(dev))
+                               gen6_fdi_link_train(crtc);
+                       else
+                               ironlake_fdi_link_train(crtc);
 
-                       temp = I915_READ(fdi_rx_iir_reg);
-                       DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
-
-                       if ((temp & FDI_RX_BIT_LOCK) == 0) {
-                               for (j = 0; j < tries; j++) {
-                                       temp = I915_READ(fdi_rx_iir_reg);
-                                       DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n",
-                                                               temp);
-                                       if (temp & FDI_RX_BIT_LOCK)
-                                               break;
-                                       udelay(200);
-                               }
-                               if (j != tries)
-                                       I915_WRITE(fdi_rx_iir_reg,
-                                                       temp | FDI_RX_BIT_LOCK);
-                               else
-                                       DRM_DEBUG_KMS("train 1 fail\n");
-                       } else {
-                               I915_WRITE(fdi_rx_iir_reg,
-                                               temp | FDI_RX_BIT_LOCK);
-                               DRM_DEBUG_KMS("train 1 ok 2!\n");
+                       /* enable PCH DPLL */
+                       temp = I915_READ(pch_dpll_reg);
+                       if ((temp & DPLL_VCO_ENABLE) == 0) {
+                               I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
+                               I915_READ(pch_dpll_reg);
                        }
-                       temp = I915_READ(fdi_tx_reg);
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       temp |= FDI_LINK_TRAIN_PATTERN_2;
-                       I915_WRITE(fdi_tx_reg, temp);
-
-                       temp = I915_READ(fdi_rx_reg);
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       temp |= FDI_LINK_TRAIN_PATTERN_2;
-                       I915_WRITE(fdi_rx_reg, temp);
-
-                       udelay(150);
+                       udelay(200);
 
-                       temp = I915_READ(fdi_rx_iir_reg);
-                       DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
-
-                       if ((temp & FDI_RX_SYMBOL_LOCK) == 0) {
-                               for (j = 0; j < tries; j++) {
-                                       temp = I915_READ(fdi_rx_iir_reg);
-                                       DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n",
-                                                               temp);
-                                       if (temp & FDI_RX_SYMBOL_LOCK)
-                                               break;
-                                       udelay(200);
-                               }
-                               if (j != tries) {
-                                       I915_WRITE(fdi_rx_iir_reg,
-                                                       temp | FDI_RX_SYMBOL_LOCK);
-                                       DRM_DEBUG_KMS("train 2 ok 1!\n");
-                               } else
-                                       DRM_DEBUG_KMS("train 2 fail\n");
-                       } else {
-                               I915_WRITE(fdi_rx_iir_reg,
-                                               temp | FDI_RX_SYMBOL_LOCK);
-                               DRM_DEBUG_KMS("train 2 ok 2!\n");
+                       if (HAS_PCH_CPT(dev)) {
+                               /* Be sure PCH DPLL SEL is set */
+                               temp = I915_READ(PCH_DPLL_SEL);
+                               if (trans_dpll_sel == 0 &&
+                                               (temp & TRANSA_DPLL_ENABLE) == 0)
+                                       temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+                               else if (trans_dpll_sel == 1 &&
+                                               (temp & TRANSB_DPLL_ENABLE) == 0)
+                                       temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+                               I915_WRITE(PCH_DPLL_SEL, temp);
+                               I915_READ(PCH_DPLL_SEL);
                        }
-                       DRM_DEBUG_KMS("train done\n");
 
                        /* set transcoder timing */
                        I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
@@ -1722,6 +1872,27 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
                        I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
 
+                       /* enable normal train */
+                       temp = I915_READ(fdi_tx_reg);
+                       temp &= ~FDI_LINK_TRAIN_NONE;
+                       I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
+                                       FDI_TX_ENHANCE_FRAME_ENABLE);
+                       I915_READ(fdi_tx_reg);
+
+                       temp = I915_READ(fdi_rx_reg);
+                       if (HAS_PCH_CPT(dev)) {
+                               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+                               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
+                       } else {
+                               temp &= ~FDI_LINK_TRAIN_NONE;
+                               temp |= FDI_LINK_TRAIN_NONE;
+                       }
+                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
+                       I915_READ(fdi_rx_reg);
+
+                       /* wait one idle pattern time */
+                       udelay(100);
+
                        /* enable PCH transcoder */
                        temp = I915_READ(transconf_reg);
                        /*
@@ -1736,23 +1907,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0)
                                ;
 
-                       /* enable normal */
-
-                       temp = I915_READ(fdi_tx_reg);
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
-                                       FDI_TX_ENHANCE_FRAME_ENABLE);
-                       I915_READ(fdi_tx_reg);
-
-                       temp = I915_READ(fdi_rx_reg);
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE |
-                                       FDI_RX_ENHANCE_FRAME_ENABLE);
-                       I915_READ(fdi_rx_reg);
-
-                       /* wait one idle pattern time */
-                       udelay(100);
-
                }
 
                intel_crtc_load_lut(crtc);
@@ -1803,6 +1957,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        I915_READ(pf_ctl_reg);
                }
                I915_WRITE(pf_win_size, 0);
+               POSTING_READ(pf_win_size);
+
 
                /* disable CPU FDI tx and PCH FDI rx */
                temp = I915_READ(fdi_tx_reg);
@@ -1823,11 +1979,18 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                temp &= ~FDI_LINK_TRAIN_NONE;
                temp |= FDI_LINK_TRAIN_PATTERN_1;
                I915_WRITE(fdi_tx_reg, temp);
+               POSTING_READ(fdi_tx_reg);
 
                temp = I915_READ(fdi_rx_reg);
-               temp &= ~FDI_LINK_TRAIN_NONE;
-               temp |= FDI_LINK_TRAIN_PATTERN_1;
+               if (HAS_PCH_CPT(dev)) {
+                       temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+                       temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+               } else {
+                       temp &= ~FDI_LINK_TRAIN_NONE;
+                       temp |= FDI_LINK_TRAIN_PATTERN_1;
+               }
                I915_WRITE(fdi_rx_reg, temp);
+               POSTING_READ(fdi_rx_reg);
 
                udelay(100);
 
@@ -1857,6 +2020,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                                }
                        }
                }
+
                temp = I915_READ(transconf_reg);
                /* BPC in transcoder is consistent with that in pipeconf */
                temp &= ~PIPE_BPC_MASK;
@@ -1865,35 +2029,45 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                I915_READ(transconf_reg);
                udelay(100);
 
+               if (HAS_PCH_CPT(dev)) {
+
+                       /* disable DPLL_SEL */
+                       temp = I915_READ(PCH_DPLL_SEL);
+                       if (trans_dpll_sel == 0)
+                               temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
+                       else
+                               temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+                       I915_WRITE(PCH_DPLL_SEL, temp);
+                       I915_READ(PCH_DPLL_SEL);
+
+               }
+
                /* disable PCH DPLL */
                temp = I915_READ(pch_dpll_reg);
-               if ((temp & DPLL_VCO_ENABLE) != 0) {
-                       I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
-                       I915_READ(pch_dpll_reg);
-               }
+               I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
+               I915_READ(pch_dpll_reg);
 
                if (HAS_eDP) {
                        ironlake_disable_pll_edp(crtc);
                }
 
+               /* Switch from PCDclk to Rawclk */
                temp = I915_READ(fdi_rx_reg);
                temp &= ~FDI_SEL_PCDCLK;
                I915_WRITE(fdi_rx_reg, temp);
                I915_READ(fdi_rx_reg);
 
+               /* Disable CPU FDI TX PLL */
+               temp = I915_READ(fdi_tx_reg);
+               I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE);
+               I915_READ(fdi_tx_reg);
+               udelay(100);
+
                temp = I915_READ(fdi_rx_reg);
                temp &= ~FDI_RX_PLL_ENABLE;
                I915_WRITE(fdi_rx_reg, temp);
                I915_READ(fdi_rx_reg);
 
-               /* Disable CPU FDI TX PLL */
-               temp = I915_READ(fdi_tx_reg);
-               if ((temp & FDI_TX_PLL_ENABLE) != 0) {
-                       I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE);
-                       I915_READ(fdi_tx_reg);
-                       udelay(100);
-               }
-
                /* Wait for the clocks to turn off. */
                udelay(100);
                break;
@@ -2934,6 +3108,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0;
        int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
        int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
+       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
+       int trans_dpll_sel = (pipe == 0) ? 0 : 1;
        int lvds_reg = LVDS;
        u32 temp;
        int sdvo_pixel_multiply;
@@ -3292,6 +3468,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                udelay(150);
        }
 
+       /* enable transcoder DPLL */
+       if (HAS_PCH_CPT(dev)) {
+               temp = I915_READ(PCH_DPLL_SEL);
+               if (trans_dpll_sel == 0)
+                       temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+               else
+                       temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+               I915_WRITE(PCH_DPLL_SEL, temp);
+               I915_READ(PCH_DPLL_SEL);
+               udelay(150);
+       }
+
        /* The LVDS pin pair needs to be on before the DPLLs are enabled.
         * This is an exception to the general rule that mode_set doesn't turn
         * things on.
@@ -3341,6 +3529,20 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        }
        if (is_dp)
                intel_dp_set_m_n(crtc, mode, adjusted_mode);
+       else if (HAS_PCH_SPLIT(dev)) {
+               /* For non-DP output, clear any trans DP clock recovery setting.*/
+               if (pipe == 0) {
+                       I915_WRITE(TRANSA_DATA_M1, 0);
+                       I915_WRITE(TRANSA_DATA_N1, 0);
+                       I915_WRITE(TRANSA_DP_LINK_M1, 0);
+                       I915_WRITE(TRANSA_DP_LINK_N1, 0);
+               } else {
+                       I915_WRITE(TRANSB_DATA_M1, 0);
+                       I915_WRITE(TRANSB_DATA_N1, 0);
+                       I915_WRITE(TRANSB_DP_LINK_M1, 0);
+                       I915_WRITE(TRANSB_DP_LINK_N1, 0);
+               }
+       }
 
        if (!is_edp) {
                I915_WRITE(fp_reg, fp);
@@ -3415,6 +3617,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        /* enable FDI RX PLL too */
                        temp = I915_READ(fdi_rx_reg);
                        I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
+                       I915_READ(fdi_rx_reg);
+                       udelay(200);
+
+                       /* enable FDI TX PLL too */
+                       temp = I915_READ(fdi_tx_reg);
+                       I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
+                       I915_READ(fdi_tx_reg);
+
+                       /* enable FDI RX PCDCLK */
+                       temp = I915_READ(fdi_rx_reg);
+                       I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
+                       I915_READ(fdi_rx_reg);
                        udelay(200);
                }
        }