Revert "drm/i915: Don't enable pipe/plane/VCO early (wait for DPMS on)."
[safe/jmp/linux-2.6] / drivers / gpu / drm / i915 / intel_display.c
index af61dd9..cc8131f 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/input.h>
 #include <linux/i2c.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include "drmP.h"
 #include "intel_drv.h"
 #include "i915_drm.h"
@@ -70,8 +71,6 @@ struct intel_limit {
     intel_p2_t     p2;
     bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
                      int, int, intel_clock_t *);
-    bool (* find_reduced_pll)(const intel_limit_t *, struct drm_crtc *,
-                             int, int, intel_clock_t *);
 };
 
 #define I8XX_DOT_MIN             25000
@@ -234,7 +233,7 @@ struct intel_limit {
 #define G4X_P2_DISPLAY_PORT_FAST           10
 #define G4X_P2_DISPLAY_PORT_LIMIT          0
 
-/* Ironlake */
+/* Ironlake / Sandybridge */
 /* as we calculate clock using (register_value + 2) for
    N/M1/M2, so here the range value for them is (actual_value-2).
  */
@@ -242,38 +241,93 @@ struct intel_limit {
 #define IRONLAKE_DOT_MAX         350000
 #define IRONLAKE_VCO_MIN         1760000
 #define IRONLAKE_VCO_MAX         3510000
-#define IRONLAKE_N_MIN           1
-#define IRONLAKE_N_MAX           5
-#define IRONLAKE_M_MIN           79
-#define IRONLAKE_M_MAX           118
 #define IRONLAKE_M1_MIN          12
-#define IRONLAKE_M1_MAX          23
+#define IRONLAKE_M1_MAX          22
 #define IRONLAKE_M2_MIN          5
 #define IRONLAKE_M2_MAX          9
-#define IRONLAKE_P_SDVO_DAC_MIN  5
-#define IRONLAKE_P_SDVO_DAC_MAX  80
-#define IRONLAKE_P_LVDS_MIN      28
-#define IRONLAKE_P_LVDS_MAX      112
-#define IRONLAKE_P1_MIN          1
-#define IRONLAKE_P1_MAX          8
-#define IRONLAKE_P2_SDVO_DAC_SLOW 10
-#define IRONLAKE_P2_SDVO_DAC_FAST 5
-#define IRONLAKE_P2_LVDS_SLOW    14 /* single channel */
-#define IRONLAKE_P2_LVDS_FAST    7  /* double channel */
 #define IRONLAKE_P2_DOT_LIMIT    225000 /* 225Mhz */
 
+/* We have parameter ranges for different type of outputs. */
+
+/* DAC & HDMI Refclk 120Mhz */
+#define IRONLAKE_DAC_N_MIN     1
+#define IRONLAKE_DAC_N_MAX     5
+#define IRONLAKE_DAC_M_MIN     79
+#define IRONLAKE_DAC_M_MAX     127
+#define IRONLAKE_DAC_P_MIN     5
+#define IRONLAKE_DAC_P_MAX     80
+#define IRONLAKE_DAC_P1_MIN    1
+#define IRONLAKE_DAC_P1_MAX    8
+#define IRONLAKE_DAC_P2_SLOW   10
+#define IRONLAKE_DAC_P2_FAST   5
+
+/* LVDS single-channel 120Mhz refclk */
+#define IRONLAKE_LVDS_S_N_MIN  1
+#define IRONLAKE_LVDS_S_N_MAX  3
+#define IRONLAKE_LVDS_S_M_MIN  79
+#define IRONLAKE_LVDS_S_M_MAX  118
+#define IRONLAKE_LVDS_S_P_MIN  28
+#define IRONLAKE_LVDS_S_P_MAX  112
+#define IRONLAKE_LVDS_S_P1_MIN 2
+#define IRONLAKE_LVDS_S_P1_MAX 8
+#define IRONLAKE_LVDS_S_P2_SLOW        14
+#define IRONLAKE_LVDS_S_P2_FAST        14
+
+/* LVDS dual-channel 120Mhz refclk */
+#define IRONLAKE_LVDS_D_N_MIN  1
+#define IRONLAKE_LVDS_D_N_MAX  3
+#define IRONLAKE_LVDS_D_M_MIN  79
+#define IRONLAKE_LVDS_D_M_MAX  127
+#define IRONLAKE_LVDS_D_P_MIN  14
+#define IRONLAKE_LVDS_D_P_MAX  56
+#define IRONLAKE_LVDS_D_P1_MIN 2
+#define IRONLAKE_LVDS_D_P1_MAX 8
+#define IRONLAKE_LVDS_D_P2_SLOW        7
+#define IRONLAKE_LVDS_D_P2_FAST        7
+
+/* LVDS single-channel 100Mhz refclk */
+#define IRONLAKE_LVDS_S_SSC_N_MIN      1
+#define IRONLAKE_LVDS_S_SSC_N_MAX      2
+#define IRONLAKE_LVDS_S_SSC_M_MIN      79
+#define IRONLAKE_LVDS_S_SSC_M_MAX      126
+#define IRONLAKE_LVDS_S_SSC_P_MIN      28
+#define IRONLAKE_LVDS_S_SSC_P_MAX      112
+#define IRONLAKE_LVDS_S_SSC_P1_MIN     2
+#define IRONLAKE_LVDS_S_SSC_P1_MAX     8
+#define IRONLAKE_LVDS_S_SSC_P2_SLOW    14
+#define IRONLAKE_LVDS_S_SSC_P2_FAST    14
+
+/* LVDS dual-channel 100Mhz refclk */
+#define IRONLAKE_LVDS_D_SSC_N_MIN      1
+#define IRONLAKE_LVDS_D_SSC_N_MAX      3
+#define IRONLAKE_LVDS_D_SSC_M_MIN      79
+#define IRONLAKE_LVDS_D_SSC_M_MAX      126
+#define IRONLAKE_LVDS_D_SSC_P_MIN      14
+#define IRONLAKE_LVDS_D_SSC_P_MAX      42
+#define IRONLAKE_LVDS_D_SSC_P1_MIN     2
+#define IRONLAKE_LVDS_D_SSC_P1_MAX     6
+#define IRONLAKE_LVDS_D_SSC_P2_SLOW    7
+#define IRONLAKE_LVDS_D_SSC_P2_FAST    7
+
+/* DisplayPort */
+#define IRONLAKE_DP_N_MIN              1
+#define IRONLAKE_DP_N_MAX              2
+#define IRONLAKE_DP_M_MIN              81
+#define IRONLAKE_DP_M_MAX              90
+#define IRONLAKE_DP_P_MIN              10
+#define IRONLAKE_DP_P_MAX              20
+#define IRONLAKE_DP_P2_FAST            10
+#define IRONLAKE_DP_P2_SLOW            10
+#define IRONLAKE_DP_P2_LIMIT           0
+#define IRONLAKE_DP_P1_MIN             1
+#define IRONLAKE_DP_P1_MAX             2
+
 static bool
 intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                    int target, int refclk, intel_clock_t *best_clock);
 static bool
-intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
-                           int target, int refclk, intel_clock_t *best_clock);
-static bool
 intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                        int target, int refclk, intel_clock_t *best_clock);
-static bool
-intel_ironlake_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
-                            int target, int refclk, intel_clock_t *best_clock);
 
 static bool
 intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
@@ -294,7 +348,6 @@ static const intel_limit_t intel_limits_i8xx_dvo = {
        .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
                 .p2_slow = I8XX_P2_SLOW,       .p2_fast = I8XX_P2_FAST },
        .find_pll = intel_find_best_PLL,
-       .find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
 static const intel_limit_t intel_limits_i8xx_lvds = {
@@ -309,7 +362,6 @@ static const intel_limit_t intel_limits_i8xx_lvds = {
        .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
                 .p2_slow = I8XX_P2_LVDS_SLOW,  .p2_fast = I8XX_P2_LVDS_FAST },
        .find_pll = intel_find_best_PLL,
-       .find_reduced_pll = intel_find_best_reduced_PLL,
 };
        
 static const intel_limit_t intel_limits_i9xx_sdvo = {
@@ -324,7 +376,6 @@ static const intel_limit_t intel_limits_i9xx_sdvo = {
        .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
        .find_pll = intel_find_best_PLL,
-       .find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
 static const intel_limit_t intel_limits_i9xx_lvds = {
@@ -342,7 +393,6 @@ static const intel_limit_t intel_limits_i9xx_lvds = {
        .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_FAST },
        .find_pll = intel_find_best_PLL,
-       .find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
     /* below parameter and function is for G4X Chipset Family*/
@@ -360,7 +410,6 @@ static const intel_limit_t intel_limits_g4x_sdvo = {
                 .p2_fast = G4X_P2_SDVO_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
-       .find_reduced_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_hdmi = {
@@ -377,7 +426,6 @@ static const intel_limit_t intel_limits_g4x_hdmi = {
                 .p2_fast = G4X_P2_HDMI_DAC_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
-       .find_reduced_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
@@ -402,7 +450,6 @@ static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
                 .p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
-       .find_reduced_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
@@ -427,7 +474,6 @@ static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
                 .p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
-       .find_reduced_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_display_port = {
@@ -465,7 +511,6 @@ static const intel_limit_t intel_limits_pineview_sdvo = {
        .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
        .find_pll = intel_find_best_PLL,
-       .find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
 static const intel_limit_t intel_limits_pineview_lvds = {
@@ -481,46 +526,135 @@ static const intel_limit_t intel_limits_pineview_lvds = {
        .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_SLOW },
        .find_pll = intel_find_best_PLL,
-       .find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
-static const intel_limit_t intel_limits_ironlake_sdvo = {
+static const intel_limit_t intel_limits_ironlake_dac = {
        .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
        .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
-       .n   = { .min = IRONLAKE_N_MIN,            .max = IRONLAKE_N_MAX },
-       .m   = { .min = IRONLAKE_M_MIN,            .max = IRONLAKE_M_MAX },
+       .n   = { .min = IRONLAKE_DAC_N_MIN,        .max = IRONLAKE_DAC_N_MAX },
+       .m   = { .min = IRONLAKE_DAC_M_MIN,        .max = IRONLAKE_DAC_M_MAX },
        .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
        .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
-       .p   = { .min = IRONLAKE_P_SDVO_DAC_MIN,   .max = IRONLAKE_P_SDVO_DAC_MAX },
-       .p1  = { .min = IRONLAKE_P1_MIN,           .max = IRONLAKE_P1_MAX },
+       .p   = { .min = IRONLAKE_DAC_P_MIN,        .max = IRONLAKE_DAC_P_MAX },
+       .p1  = { .min = IRONLAKE_DAC_P1_MIN,       .max = IRONLAKE_DAC_P1_MAX },
        .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
-                .p2_slow = IRONLAKE_P2_SDVO_DAC_SLOW,
-                .p2_fast = IRONLAKE_P2_SDVO_DAC_FAST },
-       .find_pll = intel_ironlake_find_best_PLL,
+                .p2_slow = IRONLAKE_DAC_P2_SLOW,
+                .p2_fast = IRONLAKE_DAC_P2_FAST },
+       .find_pll = intel_g4x_find_best_PLL,
 };
 
-static const intel_limit_t intel_limits_ironlake_lvds = {
+static const intel_limit_t intel_limits_ironlake_single_lvds = {
        .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
        .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
-       .n   = { .min = IRONLAKE_N_MIN,            .max = IRONLAKE_N_MAX },
-       .m   = { .min = IRONLAKE_M_MIN,            .max = IRONLAKE_M_MAX },
+       .n   = { .min = IRONLAKE_LVDS_S_N_MIN,     .max = IRONLAKE_LVDS_S_N_MAX },
+       .m   = { .min = IRONLAKE_LVDS_S_M_MIN,     .max = IRONLAKE_LVDS_S_M_MAX },
        .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
        .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
-       .p   = { .min = IRONLAKE_P_LVDS_MIN,       .max = IRONLAKE_P_LVDS_MAX },
-       .p1  = { .min = IRONLAKE_P1_MIN,           .max = IRONLAKE_P1_MAX },
+       .p   = { .min = IRONLAKE_LVDS_S_P_MIN,     .max = IRONLAKE_LVDS_S_P_MAX },
+       .p1  = { .min = IRONLAKE_LVDS_S_P1_MIN,    .max = IRONLAKE_LVDS_S_P1_MAX },
        .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
-                .p2_slow = IRONLAKE_P2_LVDS_SLOW,
-                .p2_fast = IRONLAKE_P2_LVDS_FAST },
-       .find_pll = intel_ironlake_find_best_PLL,
+                .p2_slow = IRONLAKE_LVDS_S_P2_SLOW,
+                .p2_fast = IRONLAKE_LVDS_S_P2_FAST },
+       .find_pll = intel_g4x_find_best_PLL,
+};
+
+static const intel_limit_t intel_limits_ironlake_dual_lvds = {
+       .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
+       .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
+       .n   = { .min = IRONLAKE_LVDS_D_N_MIN,     .max = IRONLAKE_LVDS_D_N_MAX },
+       .m   = { .min = IRONLAKE_LVDS_D_M_MIN,     .max = IRONLAKE_LVDS_D_M_MAX },
+       .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
+       .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
+       .p   = { .min = IRONLAKE_LVDS_D_P_MIN,     .max = IRONLAKE_LVDS_D_P_MAX },
+       .p1  = { .min = IRONLAKE_LVDS_D_P1_MIN,    .max = IRONLAKE_LVDS_D_P1_MAX },
+       .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
+                .p2_slow = IRONLAKE_LVDS_D_P2_SLOW,
+                .p2_fast = IRONLAKE_LVDS_D_P2_FAST },
+       .find_pll = intel_g4x_find_best_PLL,
+};
+
+static const intel_limit_t intel_limits_ironlake_single_lvds_100m = {
+       .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
+       .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
+       .n   = { .min = IRONLAKE_LVDS_S_SSC_N_MIN, .max = IRONLAKE_LVDS_S_SSC_N_MAX },
+       .m   = { .min = IRONLAKE_LVDS_S_SSC_M_MIN, .max = IRONLAKE_LVDS_S_SSC_M_MAX },
+       .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
+       .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
+       .p   = { .min = IRONLAKE_LVDS_S_SSC_P_MIN, .max = IRONLAKE_LVDS_S_SSC_P_MAX },
+       .p1  = { .min = IRONLAKE_LVDS_S_SSC_P1_MIN,.max = IRONLAKE_LVDS_S_SSC_P1_MAX },
+       .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
+                .p2_slow = IRONLAKE_LVDS_S_SSC_P2_SLOW,
+                .p2_fast = IRONLAKE_LVDS_S_SSC_P2_FAST },
+       .find_pll = intel_g4x_find_best_PLL,
+};
+
+static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = {
+       .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
+       .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
+       .n   = { .min = IRONLAKE_LVDS_D_SSC_N_MIN, .max = IRONLAKE_LVDS_D_SSC_N_MAX },
+       .m   = { .min = IRONLAKE_LVDS_D_SSC_M_MIN, .max = IRONLAKE_LVDS_D_SSC_M_MAX },
+       .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
+       .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
+       .p   = { .min = IRONLAKE_LVDS_D_SSC_P_MIN, .max = IRONLAKE_LVDS_D_SSC_P_MAX },
+       .p1  = { .min = IRONLAKE_LVDS_D_SSC_P1_MIN,.max = IRONLAKE_LVDS_D_SSC_P1_MAX },
+       .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
+                .p2_slow = IRONLAKE_LVDS_D_SSC_P2_SLOW,
+                .p2_fast = IRONLAKE_LVDS_D_SSC_P2_FAST },
+       .find_pll = intel_g4x_find_best_PLL,
+};
+
+static const intel_limit_t intel_limits_ironlake_display_port = {
+        .dot = { .min = IRONLAKE_DOT_MIN,
+                 .max = IRONLAKE_DOT_MAX },
+        .vco = { .min = IRONLAKE_VCO_MIN,
+                 .max = IRONLAKE_VCO_MAX},
+        .n   = { .min = IRONLAKE_DP_N_MIN,
+                 .max = IRONLAKE_DP_N_MAX },
+        .m   = { .min = IRONLAKE_DP_M_MIN,
+                 .max = IRONLAKE_DP_M_MAX },
+        .m1  = { .min = IRONLAKE_M1_MIN,
+                 .max = IRONLAKE_M1_MAX },
+        .m2  = { .min = IRONLAKE_M2_MIN,
+                 .max = IRONLAKE_M2_MAX },
+        .p   = { .min = IRONLAKE_DP_P_MIN,
+                 .max = IRONLAKE_DP_P_MAX },
+        .p1  = { .min = IRONLAKE_DP_P1_MIN,
+                 .max = IRONLAKE_DP_P1_MAX},
+        .p2  = { .dot_limit = IRONLAKE_DP_P2_LIMIT,
+                 .p2_slow = IRONLAKE_DP_P2_SLOW,
+                 .p2_fast = IRONLAKE_DP_P2_FAST },
+        .find_pll = intel_find_pll_ironlake_dp,
 };
 
 static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc)
 {
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        const intel_limit_t *limit;
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
-               limit = &intel_limits_ironlake_lvds;
+       int refclk = 120;
+
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+               if (dev_priv->lvds_use_ssc && dev_priv->lvds_ssc_freq == 100)
+                       refclk = 100;
+
+               if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
+                   LVDS_CLKB_POWER_UP) {
+                       /* LVDS dual channel */
+                       if (refclk == 100)
+                               limit = &intel_limits_ironlake_dual_lvds_100m;
+                       else
+                               limit = &intel_limits_ironlake_dual_lvds;
+               } else {
+                       if (refclk == 100)
+                               limit = &intel_limits_ironlake_single_lvds_100m;
+                       else
+                               limit = &intel_limits_ironlake_single_lvds;
+               }
+       } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) ||
+                       HAS_eDP)
+               limit = &intel_limits_ironlake_display_port;
        else
-               limit = &intel_limits_ironlake_sdvo;
+               limit = &intel_limits_ironlake_dac;
 
        return limit;
 }
@@ -557,7 +691,7 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        const intel_limit_t *limit;
 
-       if (IS_IRONLAKE(dev))
+       if (HAS_PCH_SPLIT(dev))
                limit = intel_ironlake_limit(crtc);
        else if (IS_G4X(dev)) {
                limit = intel_g4x_limit(crtc);
@@ -608,36 +742,18 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
 {
     struct drm_device *dev = crtc->dev;
     struct drm_mode_config *mode_config = &dev->mode_config;
-    struct drm_connector *l_entry;
+    struct drm_encoder *l_entry;
 
-    list_for_each_entry(l_entry, &mode_config->connector_list, head) {
-           if (l_entry->encoder &&
-               l_entry->encoder->crtc == crtc) {
-                   struct intel_output *intel_output = to_intel_output(l_entry);
-                   if (intel_output->type == type)
+    list_for_each_entry(l_entry, &mode_config->encoder_list, head) {
+           if (l_entry && l_entry->crtc == crtc) {
+                   struct intel_encoder *intel_encoder = enc_to_intel_encoder(l_entry);
+                   if (intel_encoder->type == type)
                            return true;
            }
     }
     return false;
 }
 
-struct drm_connector *
-intel_pipe_get_output (struct drm_crtc *crtc)
-{
-    struct drm_device *dev = crtc->dev;
-    struct drm_mode_config *mode_config = &dev->mode_config;
-    struct drm_connector *l_entry, *ret = NULL;
-
-    list_for_each_entry(l_entry, &mode_config->connector_list, head) {
-           if (l_entry->encoder &&
-               l_entry->encoder->crtc == crtc) {
-                   ret = l_entry;
-                   break;
-           }
-    }
-    return ret;
-}
-
 #define INTELPllInvalid(s)   do { /* DRM_DEBUG(s); */ return false; } while (0)
 /**
  * Returns whether the given set of divisors are valid for a given refclk with
@@ -737,46 +853,6 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
        return (err != target);
 }
 
-
-static bool
-intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
-                           int target, int refclk, intel_clock_t *best_clock)
-
-{
-       struct drm_device *dev = crtc->dev;
-       intel_clock_t clock;
-       int err = target;
-       bool found = false;
-
-       memcpy(&clock, best_clock, sizeof(intel_clock_t));
-
-       for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
-               for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++) {
-                       /* m1 is always 0 in Pineview */
-                       if (clock.m2 >= clock.m1 && !IS_PINEVIEW(dev))
-                               break;
-                       for (clock.n = limit->n.min; clock.n <= limit->n.max;
-                            clock.n++) {
-                               int this_err;
-
-                               intel_clock(dev, refclk, &clock);
-
-                               if (!intel_PLL_is_valid(crtc, &clock))
-                                       continue;
-
-                               this_err = abs(clock.dot - target);
-                               if (this_err < err) {
-                                       *best_clock = clock;
-                                       err = this_err;
-                                       found = true;
-                               }
-                       }
-               }
-       }
-
-       return found;
-}
-
 static bool
 intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                        int target, int refclk, intel_clock_t *best_clock)
@@ -791,7 +867,13 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
        found = false;
 
        if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-               if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
+               int lvds_reg;
+
+               if (HAS_PCH_SPLIT(dev))
+                       lvds_reg = PCH_LVDS;
+               else
+                       lvds_reg = LVDS;
+               if ((I915_READ(lvds_reg) & LVDS_CLKB_POWER_MASK) ==
                    LVDS_CLKB_POWER_UP)
                        clock.p2 = limit->p2.p2_fast;
                else
@@ -805,9 +887,9 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
 
        memset(best_clock, 0, sizeof(*best_clock));
        max_n = limit->n.max;
-       /* based on hardware requriment prefer smaller n to precision */
+       /* based on hardware requirement, prefer smaller n to precision */
        for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
-               /* based on hardware requirment prefere larger m1,m2 */
+               /* based on hardware requirement, prefere larger m1,m2 */
                for (clock.m1 = limit->m1.max;
                     clock.m1 >= limit->m1.min; clock.m1--) {
                        for (clock.m2 = limit->m2.max;
@@ -839,6 +921,11 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        intel_clock_t clock;
+
+       /* return directly when it is eDP */
+       if (HAS_eDP)
+               return true;
+
        if (target < 200000) {
                clock.n = 1;
                clock.p1 = 2;
@@ -857,68 +944,6 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
        return true;
 }
 
-static bool
-intel_ironlake_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
-                            int target, int refclk, intel_clock_t *best_clock)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       intel_clock_t clock;
-       int err_most = 47;
-       int err_min = 10000;
-
-       /* eDP has only 2 clock choice, no n/m/p setting */
-       if (HAS_eDP)
-               return true;
-
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
-               return intel_find_pll_ironlake_dp(limit, crtc, target,
-                                              refclk, best_clock);
-
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-               if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
-                   LVDS_CLKB_POWER_UP)
-                       clock.p2 = limit->p2.p2_fast;
-               else
-                       clock.p2 = limit->p2.p2_slow;
-       } else {
-               if (target < limit->p2.dot_limit)
-                       clock.p2 = limit->p2.p2_slow;
-               else
-                       clock.p2 = limit->p2.p2_fast;
-       }
-
-       memset(best_clock, 0, sizeof(*best_clock));
-       for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
-               /* based on hardware requriment prefer smaller n to precision */
-               for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) {
-                       /* based on hardware requirment prefere larger m1,m2 */
-                       for (clock.m1 = limit->m1.max;
-                            clock.m1 >= limit->m1.min; clock.m1--) {
-                               for (clock.m2 = limit->m2.max;
-                                    clock.m2 >= limit->m2.min; clock.m2--) {
-                                       int this_err;
-
-                                       intel_clock(dev, refclk, &clock);
-                                       if (!intel_PLL_is_valid(crtc, &clock))
-                                               continue;
-                                       this_err = abs((10000 - (target*10000/clock.dot)));
-                                       if (this_err < err_most) {
-                                               *best_clock = clock;
-                                               /* found on first matching */
-                                               goto out;
-                                       } else if (this_err < err_min) {
-                                               *best_clock = clock;
-                                               err_min = this_err;
-                                       }
-                               }
-                       }
-               }
-       }
-out:
-       return true;
-}
-
 /* DisplayPort has only two frequencies, 162MHz and 270MHz */
 static bool
 intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
@@ -960,7 +985,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_framebuffer *fb = crtc->fb;
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
-       struct drm_i915_gem_object *obj_priv = intel_fb->obj->driver_private;
+       struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int plane, i;
        u32 fbc_ctl, fbc_ctl2;
@@ -989,6 +1014,8 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 
        /* enable it... */
        fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC;
+       if (IS_I945GM(dev))
+               fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
        fbc_ctl |= (dev_priv->cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
        fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
        if (obj_priv->tiling_mode != I915_TILING_NONE)
@@ -1002,28 +1029,36 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 void i8xx_disable_fbc(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long timeout = jiffies + msecs_to_jiffies(1);
        u32 fbc_ctl;
 
        if (!I915_HAS_FBC(dev))
                return;
 
+       if (!(I915_READ(FBC_CONTROL) & FBC_CTL_EN))
+               return; /* Already off, just return */
+
        /* Disable compression */
        fbc_ctl = I915_READ(FBC_CONTROL);
        fbc_ctl &= ~FBC_CTL_EN;
        I915_WRITE(FBC_CONTROL, fbc_ctl);
 
        /* Wait for compressing bit to clear */
-       while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING)
-               ; /* nothing */
+       while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) {
+               if (time_after(jiffies, timeout)) {
+                       DRM_DEBUG_DRIVER("FBC idle timed out\n");
+                       break;
+               }
+               ; /* do nothing */
+       }
 
        intel_wait_for_vblank(dev);
 
        DRM_DEBUG_KMS("disabled FBC\n");
 }
 
-static bool i8xx_fbc_enabled(struct drm_crtc *crtc)
+static bool i8xx_fbc_enabled(struct drm_device *dev)
 {
-       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
@@ -1035,7 +1070,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_framebuffer *fb = crtc->fb;
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
-       struct drm_i915_gem_object *obj_priv = intel_fb->obj->driver_private;
+       struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int plane = (intel_crtc->plane == 0 ? DPFC_CTL_PLANEA :
                     DPFC_CTL_PLANEB);
@@ -1080,14 +1115,43 @@ void g4x_disable_fbc(struct drm_device *dev)
        DRM_DEBUG_KMS("disabled FBC\n");
 }
 
-static bool g4x_fbc_enabled(struct drm_crtc *crtc)
+static bool g4x_fbc_enabled(struct drm_device *dev)
 {
-       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
 }
 
+bool intel_fbc_enabled(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!dev_priv->display.fbc_enabled)
+               return false;
+
+       return dev_priv->display.fbc_enabled(dev);
+}
+
+void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+{
+       struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+
+       if (!dev_priv->display.enable_fbc)
+               return;
+
+       dev_priv->display.enable_fbc(crtc, interval);
+}
+
+void intel_disable_fbc(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!dev_priv->display.disable_fbc)
+               return;
+
+       dev_priv->display.disable_fbc(dev);
+}
+
 /**
  * intel_update_fbc - enable/disable FBC as needed
  * @crtc: CRTC to point the compressor at
@@ -1122,16 +1186,14 @@ static void intel_update_fbc(struct drm_crtc *crtc,
        if (!i915_powersave)
                return;
 
-       if (!dev_priv->display.fbc_enabled ||
-           !dev_priv->display.enable_fbc ||
-           !dev_priv->display.disable_fbc)
+       if (!I915_HAS_FBC(dev))
                return;
 
        if (!crtc->fb)
                return;
 
        intel_fb = to_intel_framebuffer(fb);
-       obj_priv = intel_fb->obj->driver_private;
+       obj_priv = to_intel_bo(intel_fb->obj);
 
        /*
         * If FBC is already on, we just have to verify that we can
@@ -1144,56 +1206,59 @@ static void intel_update_fbc(struct drm_crtc *crtc,
        if (intel_fb->obj->size > dev_priv->cfb_size) {
                DRM_DEBUG_KMS("framebuffer too large, disabling "
                                "compression\n");
+               dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
                goto out_disable;
        }
        if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
            (mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
                DRM_DEBUG_KMS("mode incompatible with compression, "
                                "disabling\n");
+               dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
                goto out_disable;
        }
        if ((mode->hdisplay > 2048) ||
            (mode->vdisplay > 1536)) {
                DRM_DEBUG_KMS("mode too large for compression, disabling\n");
+               dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
                goto out_disable;
        }
        if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) {
                DRM_DEBUG_KMS("plane not 0, disabling compression\n");
+               dev_priv->no_fbc_reason = FBC_BAD_PLANE;
                goto out_disable;
        }
        if (obj_priv->tiling_mode != I915_TILING_X) {
                DRM_DEBUG_KMS("framebuffer not tiled, disabling compression\n");
+               dev_priv->no_fbc_reason = FBC_NOT_TILED;
                goto out_disable;
        }
 
-       if (dev_priv->display.fbc_enabled(crtc)) {
+       if (intel_fbc_enabled(dev)) {
                /* We can re-enable it in this case, but need to update pitch */
-               if (fb->pitch > dev_priv->cfb_pitch)
-                       dev_priv->display.disable_fbc(dev);
-               if (obj_priv->fence_reg != dev_priv->cfb_fence)
-                       dev_priv->display.disable_fbc(dev);
-               if (plane != dev_priv->cfb_plane)
-                       dev_priv->display.disable_fbc(dev);
+               if ((fb->pitch > dev_priv->cfb_pitch) ||
+                   (obj_priv->fence_reg != dev_priv->cfb_fence) ||
+                   (plane != dev_priv->cfb_plane))
+                       intel_disable_fbc(dev);
        }
 
-       if (!dev_priv->display.fbc_enabled(crtc)) {
-               /* Now try to turn it back on if possible */
-               dev_priv->display.enable_fbc(crtc, 500);
-       }
+       /* Now try to turn it back on if possible */
+       if (!intel_fbc_enabled(dev))
+               intel_enable_fbc(crtc, 500);
 
        return;
 
 out_disable:
-       DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
        /* Multiple disables should be harmless */
-       if (dev_priv->display.fbc_enabled(crtc))
-               dev_priv->display.disable_fbc(dev);
+       if (intel_fbc_enabled(dev)) {
+               DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
+               intel_disable_fbc(dev);
+       }
 }
 
 static int
 intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
 {
-       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        u32 alignment;
        int ret;
 
@@ -1273,7 +1338,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 
        intel_fb = to_intel_framebuffer(crtc->fb);
        obj = intel_fb->obj;
-       obj_priv = obj->driver_private;
+       obj_priv = to_intel_bo(obj);
 
        mutex_lock(&dev->struct_mutex);
        ret = intel_pin_and_fence_fb_obj(dev, obj);
@@ -1282,7 +1347,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                return ret;
        }
 
-       ret = i915_gem_object_set_to_gtt_domain(obj, 1);
+       ret = i915_gem_object_set_to_display_plane(obj);
        if (ret != 0) {
                i915_gem_object_unpin(obj);
                mutex_unlock(&dev->struct_mutex);
@@ -1322,7 +1387,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                        dspcntr &= ~DISPPLANE_TILED;
        }
 
-       if (IS_IRONLAKE(dev))
+       if (HAS_PCH_SPLIT(dev))
                /* must disable */
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
@@ -1331,7 +1396,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        Start = obj_priv->gtt_offset;
        Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8);
 
-       DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y);
+       DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
+                     Start, Offset, x, y, crtc->fb->pitch);
        I915_WRITE(dspstride, crtc->fb->pitch);
        if (IS_I965G(dev)) {
                I915_WRITE(dspbase, Offset);
@@ -1351,7 +1417,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 
        if (old_fb) {
                intel_fb = to_intel_framebuffer(old_fb);
-               obj_priv = intel_fb->obj->driver_private;
+               obj_priv = to_intel_bo(intel_fb->obj);
                i915_gem_object_unpin(intel_fb->obj);
        }
        intel_increase_pllclock(crtc, true);
@@ -1383,7 +1449,7 @@ static void i915_disable_vga (struct drm_device *dev)
        u8 sr1;
        u32 vga_reg;
 
-       if (IS_IRONLAKE(dev))
+       if (HAS_PCH_SPLIT(dev))
                vga_reg = CPU_VGACNTRL;
        else
                vga_reg = VGACNTRL;
@@ -1460,6 +1526,219 @@ 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 &= ~(7 << 19);
+       temp |= (intel_crtc->fdi_lanes - 1) << 19;
+       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 &= ~(7 << 19);
+       temp |= (intel_crtc->fdi_lanes - 1) << 19;
+       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;
@@ -1473,8 +1752,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;
@@ -1491,8 +1768,13 @@ 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);
+       pipe_bpc = temp & PIPE_BPC_MASK;
 
        /* XXX: When our outputs are all unaware of DPMS modes other than off
         * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
@@ -1515,18 +1797,24 @@ 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);
-                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE |
-                                       FDI_SEL_PCDCLK |
-                                       FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */
+                       /*
+                        * make the BPC in FDI Rx be consistent with that in
+                        * pipeconf reg.
+                        */
+                       temp &= ~(0x7 << 16);
+                       temp |= (pipe_bpc << 11);
+                       temp &= ~(7 << 19);
+                       temp |= (intel_crtc->fdi_lanes - 1) << 19;
+                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
+                       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);
 
@@ -1569,91 +1857,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));
@@ -1664,16 +1893,7 @@ 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 PCH transcoder */
-                       temp = I915_READ(transconf_reg);
-                       I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
-                       I915_READ(transconf_reg);
-
-                       while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0)
-                               ;
-
-                       /* enable normal */
-
+                       /* enable normal train */
                        temp = I915_READ(fdi_tx_reg);
                        temp &= ~FDI_LINK_TRAIN_NONE;
                        I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
@@ -1681,14 +1901,66 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        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);
+                       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);
 
+                       /* For PCH DP, enable TRANS_DP_CTL */
+                       if (HAS_PCH_CPT(dev) &&
+                           intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+                               int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
+                               int reg;
+
+                               reg = I915_READ(trans_dp_ctl);
+                               reg &= ~TRANS_DP_PORT_SEL_MASK;
+                               reg = TRANS_DP_OUTPUT_ENABLE |
+                                     TRANS_DP_ENH_FRAMING |
+                                     TRANS_DP_VSYNC_ACTIVE_HIGH |
+                                     TRANS_DP_HSYNC_ACTIVE_HIGH;
+
+                               switch (intel_trans_dp_port_sel(crtc)) {
+                               case PCH_DP_B:
+                                       reg |= TRANS_DP_PORT_SEL_B;
+                                       break;
+                               case PCH_DP_C:
+                                       reg |= TRANS_DP_PORT_SEL_C;
+                                       break;
+                               case PCH_DP_D:
+                                       reg |= TRANS_DP_PORT_SEL_D;
+                                       break;
+                               default:
+                                       DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
+                                       reg |= TRANS_DP_PORT_SEL_B;
+                                       break;
+                               }
+
+                               I915_WRITE(trans_dp_ctl, reg);
+                               POSTING_READ(trans_dp_ctl);
+                       }
+
+                       /* enable PCH transcoder */
+                       temp = I915_READ(transconf_reg);
+                       /*
+                        * make the BPC in transcoder be consistent with
+                        * that in pipeconf reg.
+                        */
+                       temp &= ~PIPE_BPC_MASK;
+                       temp |= pipe_bpc;
+                       I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
+                       I915_READ(transconf_reg);
+
+                       while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0)
+                               ;
+
                }
 
                intel_crtc_load_lut(crtc);
@@ -1697,6 +1969,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
        case DRM_MODE_DPMS_OFF:
                DRM_DEBUG_KMS("crtc %d dpms off\n", pipe);
 
+               drm_vblank_off(dev, pipe);
                /* Disable display plane */
                temp = I915_READ(dspcntr_reg);
                if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
@@ -1738,6 +2011,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);
@@ -1745,6 +2020,9 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                I915_READ(fdi_tx_reg);
 
                temp = I915_READ(fdi_rx_reg);
+               /* BPC in FDI rx is consistent with that in pipeconf */
+               temp &= ~(0x07 << 16);
+               temp |= (pipe_bpc << 11);
                I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE);
                I915_READ(fdi_rx_reg);
 
@@ -1755,11 +2033,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);
 
@@ -1790,37 +2075,61 @@ 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;
+               temp |= pipe_bpc;
+               I915_WRITE(transconf_reg, temp);
+               I915_READ(transconf_reg);
                udelay(100);
 
+               if (HAS_PCH_CPT(dev)) {
+                       /* disable TRANS_DP_CTL */
+                       int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
+                       int reg;
+
+                       reg = I915_READ(trans_dp_ctl);
+                       reg &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
+                       I915_WRITE(trans_dp_ctl, reg);
+                       POSTING_READ(trans_dp_ctl);
+
+                       /* 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;
@@ -2042,11 +2351,13 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
                                  struct drm_display_mode *adjusted_mode)
 {
        struct drm_device *dev = crtc->dev;
-       if (IS_IRONLAKE(dev)) {
+       if (HAS_PCH_SPLIT(dev)) {
                /* FDI link clock is fixed at 2.7G */
                if (mode->clock * 3 > 27000 * 4)
                        return MODE_CLOCK_HIGH;
        }
+
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
        return true;
 }
 
@@ -2256,6 +2567,30 @@ static struct intel_watermark_params i830_wm_info = {
        I830_FIFO_LINE_SIZE
 };
 
+static struct intel_watermark_params ironlake_display_wm_info = {
+       ILK_DISPLAY_FIFO,
+       ILK_DISPLAY_MAXWM,
+       ILK_DISPLAY_DFTWM,
+       2,
+       ILK_FIFO_LINE_SIZE
+};
+
+static struct intel_watermark_params ironlake_display_srwm_info = {
+       ILK_DISPLAY_SR_FIFO,
+       ILK_DISPLAY_MAX_SRWM,
+       ILK_DISPLAY_DFT_SRWM,
+       2,
+       ILK_FIFO_LINE_SIZE
+};
+
+static struct intel_watermark_params ironlake_cursor_srwm_info = {
+       ILK_CURSOR_SR_FIFO,
+       ILK_CURSOR_MAX_SRWM,
+       ILK_CURSOR_DFT_SRWM,
+       2,
+       ILK_FIFO_LINE_SIZE
+};
+
 /**
  * intel_calculate_wm - calculate watermark level
  * @clock_in_khz: pixel clock
@@ -2307,6 +2642,7 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
 
 struct cxsr_latency {
        int is_desktop;
+       int is_ddr3;
        unsigned long fsb_freq;
        unsigned long mem_freq;
        unsigned long display_sr;
@@ -2316,33 +2652,45 @@ struct cxsr_latency {
 };
 
 static struct cxsr_latency cxsr_latency_table[] = {
-       {1, 800, 400, 3382, 33382, 3983, 33983},    /* DDR2-400 SC */
-       {1, 800, 667, 3354, 33354, 3807, 33807},    /* DDR2-667 SC */
-       {1, 800, 800, 3347, 33347, 3763, 33763},    /* DDR2-800 SC */
-
-       {1, 667, 400, 3400, 33400, 4021, 34021},    /* DDR2-400 SC */
-       {1, 667, 667, 3372, 33372, 3845, 33845},    /* DDR2-667 SC */
-       {1, 667, 800, 3386, 33386, 3822, 33822},    /* DDR2-800 SC */
-
-       {1, 400, 400, 3472, 33472, 4173, 34173},    /* DDR2-400 SC */
-       {1, 400, 667, 3443, 33443, 3996, 33996},    /* DDR2-667 SC */
-       {1, 400, 800, 3430, 33430, 3946, 33946},    /* DDR2-800 SC */
-
-       {0, 800, 400, 3438, 33438, 4065, 34065},    /* DDR2-400 SC */
-       {0, 800, 667, 3410, 33410, 3889, 33889},    /* DDR2-667 SC */
-       {0, 800, 800, 3403, 33403, 3845, 33845},    /* DDR2-800 SC */
-
-       {0, 667, 400, 3456, 33456, 4103, 34106},    /* DDR2-400 SC */
-       {0, 667, 667, 3428, 33428, 3927, 33927},    /* DDR2-667 SC */
-       {0, 667, 800, 3443, 33443, 3905, 33905},    /* DDR2-800 SC */
-
-       {0, 400, 400, 3528, 33528, 4255, 34255},    /* DDR2-400 SC */
-       {0, 400, 667, 3500, 33500, 4079, 34079},    /* DDR2-667 SC */
-       {0, 400, 800, 3487, 33487, 4029, 34029},    /* DDR2-800 SC */
+       {1, 0, 800, 400, 3382, 33382, 3983, 33983},    /* DDR2-400 SC */
+       {1, 0, 800, 667, 3354, 33354, 3807, 33807},    /* DDR2-667 SC */
+       {1, 0, 800, 800, 3347, 33347, 3763, 33763},    /* DDR2-800 SC */
+       {1, 1, 800, 667, 6420, 36420, 6873, 36873},    /* DDR3-667 SC */
+       {1, 1, 800, 800, 5902, 35902, 6318, 36318},    /* DDR3-800 SC */
+
+       {1, 0, 667, 400, 3400, 33400, 4021, 34021},    /* DDR2-400 SC */
+       {1, 0, 667, 667, 3372, 33372, 3845, 33845},    /* DDR2-667 SC */
+       {1, 0, 667, 800, 3386, 33386, 3822, 33822},    /* DDR2-800 SC */
+       {1, 1, 667, 667, 6438, 36438, 6911, 36911},    /* DDR3-667 SC */
+       {1, 1, 667, 800, 5941, 35941, 6377, 36377},    /* DDR3-800 SC */
+
+       {1, 0, 400, 400, 3472, 33472, 4173, 34173},    /* DDR2-400 SC */
+       {1, 0, 400, 667, 3443, 33443, 3996, 33996},    /* DDR2-667 SC */
+       {1, 0, 400, 800, 3430, 33430, 3946, 33946},    /* DDR2-800 SC */
+       {1, 1, 400, 667, 6509, 36509, 7062, 37062},    /* DDR3-667 SC */
+       {1, 1, 400, 800, 5985, 35985, 6501, 36501},    /* DDR3-800 SC */
+
+       {0, 0, 800, 400, 3438, 33438, 4065, 34065},    /* DDR2-400 SC */
+       {0, 0, 800, 667, 3410, 33410, 3889, 33889},    /* DDR2-667 SC */
+       {0, 0, 800, 800, 3403, 33403, 3845, 33845},    /* DDR2-800 SC */
+       {0, 1, 800, 667, 6476, 36476, 6955, 36955},    /* DDR3-667 SC */
+       {0, 1, 800, 800, 5958, 35958, 6400, 36400},    /* DDR3-800 SC */
+
+       {0, 0, 667, 400, 3456, 33456, 4103, 34106},    /* DDR2-400 SC */
+       {0, 0, 667, 667, 3428, 33428, 3927, 33927},    /* DDR2-667 SC */
+       {0, 0, 667, 800, 3443, 33443, 3905, 33905},    /* DDR2-800 SC */
+       {0, 1, 667, 667, 6494, 36494, 6993, 36993},    /* DDR3-667 SC */
+       {0, 1, 667, 800, 5998, 35998, 6460, 36460},    /* DDR3-800 SC */
+
+       {0, 0, 400, 400, 3528, 33528, 4255, 34255},    /* DDR2-400 SC */
+       {0, 0, 400, 667, 3500, 33500, 4079, 34079},    /* DDR2-667 SC */
+       {0, 0, 400, 800, 3487, 33487, 4029, 34029},    /* DDR2-800 SC */
+       {0, 1, 400, 667, 6566, 36566, 7145, 37145},    /* DDR3-667 SC */
+       {0, 1, 400, 800, 6042, 36042, 6584, 36584},    /* DDR3-800 SC */
 };
 
-static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int fsb,
-                                                  int mem)
+static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int is_ddr3, 
+                                                  int fsb, int mem)
 {
        int i;
        struct cxsr_latency *latency;
@@ -2353,6 +2701,7 @@ static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int fsb,
        for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) {
                latency = &cxsr_latency_table[i];
                if (is_desktop == latency->is_desktop &&
+                   is_ddr3 == latency->is_ddr3 &&
                    fsb == latency->fsb_freq && mem == latency->mem_freq)
                        return latency;
        }
@@ -2374,66 +2723,6 @@ static void pineview_disable_cxsr(struct drm_device *dev)
        DRM_INFO("Big FIFO is disabled\n");
 }
 
-static void pineview_enable_cxsr(struct drm_device *dev, unsigned long clock,
-                                int pixel_size)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 reg;
-       unsigned long wm;
-       struct cxsr_latency *latency;
-
-       latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->fsb_freq,
-               dev_priv->mem_freq);
-       if (!latency) {
-               DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
-               pineview_disable_cxsr(dev);
-               return;
-       }
-
-       /* Display SR */
-       wm = intel_calculate_wm(clock, &pineview_display_wm, pixel_size,
-                               latency->display_sr);
-       reg = I915_READ(DSPFW1);
-       reg &= 0x7fffff;
-       reg |= wm << 23;
-       I915_WRITE(DSPFW1, reg);
-       DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg);
-
-       /* cursor SR */
-       wm = intel_calculate_wm(clock, &pineview_cursor_wm, pixel_size,
-                               latency->cursor_sr);
-       reg = I915_READ(DSPFW3);
-       reg &= ~(0x3f << 24);
-       reg |= (wm & 0x3f) << 24;
-       I915_WRITE(DSPFW3, reg);
-
-       /* Display HPLL off SR */
-       wm = intel_calculate_wm(clock, &pineview_display_hplloff_wm,
-               latency->display_hpll_disable, I915_FIFO_LINE_SIZE);
-       reg = I915_READ(DSPFW3);
-       reg &= 0xfffffe00;
-       reg |= wm & 0x1ff;
-       I915_WRITE(DSPFW3, reg);
-
-       /* cursor HPLL off SR */
-       wm = intel_calculate_wm(clock, &pineview_cursor_hplloff_wm, pixel_size,
-                               latency->cursor_hpll_disable);
-       reg = I915_READ(DSPFW3);
-       reg &= ~(0x3f << 16);
-       reg |= (wm & 0x3f) << 16;
-       I915_WRITE(DSPFW3, reg);
-       DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg);
-
-       /* activate cxsr */
-       reg = I915_READ(DSPFW3);
-       reg |= PINEVIEW_SELF_REFRESH_EN;
-       I915_WRITE(DSPFW3, reg);
-
-       DRM_INFO("Big FIFO is enabled\n");
-
-       return;
-}
-
 /*
  * Latency for FIFO fetches is dependent on several factors:
  *   - memory configuration (speed, channels)
@@ -2506,16 +2795,81 @@ static int i845_get_fifo_size(struct drm_device *dev, int plane)
 static int i830_get_fifo_size(struct drm_device *dev, int plane)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t dsparb = I915_READ(DSPARB);
-       int size;
+       uint32_t dsparb = I915_READ(DSPARB);
+       int size;
+
+       size = dsparb & 0x7f;
+       size >>= 1; /* Convert to cachelines */
+
+       DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
+                       plane ? "B" : "A", size);
+
+       return size;
+}
+
+static void pineview_update_wm(struct drm_device *dev,  int planea_clock,
+                         int planeb_clock, int sr_hdisplay, int pixel_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg;
+       unsigned long wm;
+       struct cxsr_latency *latency;
+       int sr_clock;
 
-       size = dsparb & 0x7f;
-       size >>= 1; /* Convert to cachelines */
+       latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, 
+                                        dev_priv->fsb_freq, dev_priv->mem_freq);
+       if (!latency) {
+               DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
+               pineview_disable_cxsr(dev);
+               return;
+       }
 
-       DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                       plane ? "B" : "A", size);
+       if (!planea_clock || !planeb_clock) {
+               sr_clock = planea_clock ? planea_clock : planeb_clock;
 
-       return size;
+               /* Display SR */
+               wm = intel_calculate_wm(sr_clock, &pineview_display_wm,
+                                       pixel_size, latency->display_sr);
+               reg = I915_READ(DSPFW1);
+               reg &= ~DSPFW_SR_MASK;
+               reg |= wm << DSPFW_SR_SHIFT;
+               I915_WRITE(DSPFW1, reg);
+               DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg);
+
+               /* cursor SR */
+               wm = intel_calculate_wm(sr_clock, &pineview_cursor_wm,
+                                       pixel_size, latency->cursor_sr);
+               reg = I915_READ(DSPFW3);
+               reg &= ~DSPFW_CURSOR_SR_MASK;
+               reg |= (wm & 0x3f) << DSPFW_CURSOR_SR_SHIFT;
+               I915_WRITE(DSPFW3, reg);
+
+               /* Display HPLL off SR */
+               wm = intel_calculate_wm(sr_clock, &pineview_display_hplloff_wm,
+                                       pixel_size, latency->display_hpll_disable);
+               reg = I915_READ(DSPFW3);
+               reg &= ~DSPFW_HPLL_SR_MASK;
+               reg |= wm & DSPFW_HPLL_SR_MASK;
+               I915_WRITE(DSPFW3, reg);
+
+               /* cursor HPLL off SR */
+               wm = intel_calculate_wm(sr_clock, &pineview_cursor_hplloff_wm,
+                                       pixel_size, latency->cursor_hpll_disable);
+               reg = I915_READ(DSPFW3);
+               reg &= ~DSPFW_HPLL_CURSOR_MASK;
+               reg |= (wm & 0x3f) << DSPFW_HPLL_CURSOR_SHIFT;
+               I915_WRITE(DSPFW3, reg);
+               DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg);
+
+               /* activate cxsr */
+               reg = I915_READ(DSPFW3);
+               reg |= PINEVIEW_SELF_REFRESH_EN;
+               I915_WRITE(DSPFW3, reg);
+               DRM_DEBUG_KMS("Self-refresh is enabled\n");
+       } else {
+               pineview_disable_cxsr(dev);
+               DRM_DEBUG_KMS("Self-refresh is disabled\n");
+       }
 }
 
 static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
@@ -2570,6 +2924,10 @@ static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
                sr_entries = roundup(sr_entries / cacheline_size, 1);
                DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
                I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
+       } else {
+               /* Turn off self refresh if both pipes are enabled */
+               I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
+                                       & ~FW_BLC_SELF_EN);
        }
 
        DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n",
@@ -2613,6 +2971,10 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
                        srwm = 1;
                srwm &= 0x3f;
                I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
+       } else {
+               /* Turn off self refresh if both pipes are enabled */
+               I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
+                                       & ~FW_BLC_SELF_EN);
        }
 
        DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n",
@@ -2680,7 +3042,22 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
                srwm = total_size - sr_entries;
                if (srwm < 0)
                        srwm = 1;
-               I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f));
+
+               if (IS_I945G(dev) || IS_I945GM(dev))
+                       I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_FIFO_MASK | (srwm & 0xff));
+               else if (IS_I915GM(dev)) {
+                       /* 915M has a smaller SRWM field */
+                       I915_WRITE(FW_BLC_SELF, srwm & 0x3f);
+                       I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN);
+               }
+       } else {
+               /* Turn off self refresh if both pipes are enabled */
+               if (IS_I945G(dev) || IS_I945GM(dev)) {
+                       I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
+                                  & ~FW_BLC_SELF_EN);
+               } else if (IS_I915GM(dev)) {
+                       I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN);
+               }
        }
 
        DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
@@ -2715,6 +3092,108 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused,
        I915_WRITE(FW_BLC, fwater_lo);
 }
 
+#define ILK_LP0_PLANE_LATENCY          700
+
+static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
+                      int planeb_clock, int sr_hdisplay, int pixel_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
+       int sr_wm, cursor_wm;
+       unsigned long line_time_us;
+       int sr_clock, entries_required;
+       u32 reg_value;
+
+       /* Calculate and update the watermark for plane A */
+       if (planea_clock) {
+               entries_required = ((planea_clock / 1000) * pixel_size *
+                                    ILK_LP0_PLANE_LATENCY) / 1000;
+               entries_required = DIV_ROUND_UP(entries_required,
+                                  ironlake_display_wm_info.cacheline_size);
+               planea_wm = entries_required +
+                           ironlake_display_wm_info.guard_size;
+
+               if (planea_wm > (int)ironlake_display_wm_info.max_wm)
+                       planea_wm = ironlake_display_wm_info.max_wm;
+
+               cursora_wm = 16;
+               reg_value = I915_READ(WM0_PIPEA_ILK);
+               reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+               reg_value |= (planea_wm << WM0_PIPE_PLANE_SHIFT) |
+                            (cursora_wm & WM0_PIPE_CURSOR_MASK);
+               I915_WRITE(WM0_PIPEA_ILK, reg_value);
+               DRM_DEBUG_KMS("FIFO watermarks For pipe A - plane %d, "
+                               "cursor: %d\n", planea_wm, cursora_wm);
+       }
+       /* Calculate and update the watermark for plane B */
+       if (planeb_clock) {
+               entries_required = ((planeb_clock / 1000) * pixel_size *
+                                    ILK_LP0_PLANE_LATENCY) / 1000;
+               entries_required = DIV_ROUND_UP(entries_required,
+                                  ironlake_display_wm_info.cacheline_size);
+               planeb_wm = entries_required +
+                           ironlake_display_wm_info.guard_size;
+
+               if (planeb_wm > (int)ironlake_display_wm_info.max_wm)
+                       planeb_wm = ironlake_display_wm_info.max_wm;
+
+               cursorb_wm = 16;
+               reg_value = I915_READ(WM0_PIPEB_ILK);
+               reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+               reg_value |= (planeb_wm << WM0_PIPE_PLANE_SHIFT) |
+                            (cursorb_wm & WM0_PIPE_CURSOR_MASK);
+               I915_WRITE(WM0_PIPEB_ILK, reg_value);
+               DRM_DEBUG_KMS("FIFO watermarks For pipe B - plane %d, "
+                               "cursor: %d\n", planeb_wm, cursorb_wm);
+       }
+
+       /*
+        * Calculate and update the self-refresh watermark only when one
+        * display plane is used.
+        */
+       if (!planea_clock || !planeb_clock) {
+               int line_count;
+               /* Read the self-refresh latency. The unit is 0.5us */
+               int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK;
+
+               sr_clock = planea_clock ? planea_clock : planeb_clock;
+               line_time_us = ((sr_hdisplay * 1000) / sr_clock);
+
+               /* Use ns/us then divide to preserve precision */
+               line_count = ((ilk_sr_latency * 500) / line_time_us + 1000)
+                              / 1000;
+
+               /* calculate the self-refresh watermark for display plane */
+               entries_required = line_count * sr_hdisplay * pixel_size;
+               entries_required = DIV_ROUND_UP(entries_required,
+                                  ironlake_display_srwm_info.cacheline_size);
+               sr_wm = entries_required +
+                       ironlake_display_srwm_info.guard_size;
+
+               /* calculate the self-refresh watermark for display cursor */
+               entries_required = line_count * pixel_size * 64;
+               entries_required = DIV_ROUND_UP(entries_required,
+                                  ironlake_cursor_srwm_info.cacheline_size);
+               cursor_wm = entries_required +
+                           ironlake_cursor_srwm_info.guard_size;
+
+               /* configure watermark and enable self-refresh */
+               reg_value = I915_READ(WM1_LP_ILK);
+               reg_value &= ~(WM1_LP_LATENCY_MASK | WM1_LP_SR_MASK |
+                              WM1_LP_CURSOR_MASK);
+               reg_value |= WM1_LP_SR_EN |
+                            (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
+                            (sr_wm << WM1_LP_SR_SHIFT) | cursor_wm;
+
+               I915_WRITE(WM1_LP_ILK, reg_value);
+               DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
+                               "cursor %d\n", sr_wm, cursor_wm);
+
+       } else {
+               /* Turn off self refresh if both pipes are enabled */
+               I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN);
+       }
+}
 /**
  * intel_update_watermarks - update FIFO watermark values based on current modes
  *
@@ -2784,12 +3263,6 @@ static void intel_update_watermarks(struct drm_device *dev)
        if (enabled <= 0)
                return;
 
-       /* Single plane configs can enable self refresh */
-       if (enabled == 1 && IS_PINEVIEW(dev))
-               pineview_enable_cxsr(dev, sr_clock, pixel_size);
-       else if (IS_PINEVIEW(dev))
-               pineview_disable_cxsr(dev);
-
        dev_priv->display.update_wm(dev, planea_clock, planeb_clock,
                                    sr_hdisplay, pixel_size);
 }
@@ -2819,14 +3292,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE;
        int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS;
        int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
-       int refclk, num_outputs = 0;
+       int refclk, num_connectors = 0;
        intel_clock_t clock, reduced_clock;
        u32 dpll = 0, fp = 0, fp2 = 0, dspcntr, pipeconf;
        bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
        bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
        bool is_edp = false;
        struct drm_mode_config *mode_config = &dev->mode_config;
-       struct drm_connector *connector;
+       struct drm_encoder *encoder;
+       struct intel_encoder *intel_encoder = NULL;
        const intel_limit_t *limit;
        int ret;
        struct fdi_m_n m_n = {0};
@@ -2837,6 +3311,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;
@@ -2844,20 +3320,21 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        drm_vblank_pre_modeset(dev, pipe);
 
-       list_for_each_entry(connector, &mode_config->connector_list, head) {
-               struct intel_output *intel_output = to_intel_output(connector);
+       list_for_each_entry(encoder, &mode_config->encoder_list, head) {
 
-               if (!connector->encoder || connector->encoder->crtc != crtc)
+               if (!encoder || encoder->crtc != crtc)
                        continue;
 
-               switch (intel_output->type) {
+               intel_encoder = enc_to_intel_encoder(encoder);
+
+               switch (intel_encoder->type) {
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
                        break;
                case INTEL_OUTPUT_SDVO:
                case INTEL_OUTPUT_HDMI:
                        is_sdvo = true;
-                       if (intel_output->needs_tv_clock)
+                       if (intel_encoder->needs_tv_clock)
                                is_tv = true;
                        break;
                case INTEL_OUTPUT_DVO:
@@ -2877,16 +3354,16 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        break;
                }
 
-               num_outputs++;
+               num_connectors++;
        }
 
-       if (is_lvds && dev_priv->lvds_use_ssc && num_outputs < 2) {
+       if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) {
                refclk = dev_priv->lvds_ssc_freq * 1000;
                DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
                                        refclk / 1000);
        } else if (IS_I9XX(dev)) {
                refclk = 96000;
-               if (IS_IRONLAKE(dev))
+               if (HAS_PCH_SPLIT(dev))
                        refclk = 120000; /* 120Mhz refclk */
        } else {
                refclk = 48000;
@@ -2906,10 +3383,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
-       if (is_lvds && limit->find_reduced_pll &&
-                       dev_priv->lvds_downclock_avail) {
-               memcpy(&reduced_clock, &clock, sizeof(intel_clock_t));
-               has_reduced_clock = limit->find_reduced_pll(limit, crtc,
+       if (is_lvds && dev_priv->lvds_downclock_avail) {
+               has_reduced_clock = limit->find_pll(limit, crtc,
                                                            dev_priv->lvds_downclock,
                                                            refclk,
                                                            &reduced_clock);
@@ -2946,15 +3421,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        }
 
        /* FDI link */
-       if (IS_IRONLAKE(dev)) {
-               int lane, link_bw, bpp;
+       if (HAS_PCH_SPLIT(dev)) {
+               int lane = 0, link_bw, bpp;
                /* eDP doesn't require FDI link, so just set DP M/N
                   according to current link config */
                if (is_edp) {
-                       struct drm_connector *edp;
                        target_clock = mode->clock;
-                       edp = intel_pipe_get_output(crtc);
-                       intel_edp_link_config(to_intel_output(edp),
+                       intel_edp_link_config(intel_encoder,
                                        &lane, &link_bw);
                } else {
                        /* DP over FDI requires target mode clock
@@ -2963,12 +3436,38 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                target_clock = mode->clock;
                        else
                                target_clock = adjusted_mode->clock;
-                       lane = 4;
                        link_bw = 270000;
                }
 
                /* determine panel color depth */
                temp = I915_READ(pipeconf_reg);
+               temp &= ~PIPE_BPC_MASK;
+               if (is_lvds) {
+                       int lvds_reg = I915_READ(PCH_LVDS);
+                       /* the BPC will be 6 if it is 18-bit LVDS panel */
+                       if ((lvds_reg & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
+                               temp |= PIPE_8BPC;
+                       else
+                               temp |= PIPE_6BPC;
+               } else if (is_edp) {
+                       switch (dev_priv->edp_bpp/3) {
+                       case 8:
+                               temp |= PIPE_8BPC;
+                               break;
+                       case 10:
+                               temp |= PIPE_10BPC;
+                               break;
+                       case 6:
+                               temp |= PIPE_6BPC;
+                               break;
+                       case 12:
+                               temp |= PIPE_12BPC;
+                               break;
+                       }
+               } else
+                       temp |= PIPE_8BPC;
+               I915_WRITE(pipeconf_reg, temp);
+               I915_READ(pipeconf_reg);
 
                switch (temp & PIPE_BPC_MASK) {
                case PIPE_8BPC:
@@ -2988,6 +3487,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        bpp = 24;
                }
 
+               if (!lane) {
+                       /* 
+                        * Account for spread spectrum to avoid
+                        * oversubscribing the link. Max center spread
+                        * is 2.5%; use 5% for safety's sake.
+                        */
+                       u32 bps = target_clock * bpp * 21 / 20;
+                       lane = bps / (link_bw * 8) + 1;
+               }
+
+               intel_crtc->fdi_lanes = lane;
+
                ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n);
        }
 
@@ -2996,7 +3507,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
         * PCH B stepping, previous chipset stepping should be
         * ignoring this setting.
         */
-       if (IS_IRONLAKE(dev)) {
+       if (HAS_PCH_SPLIT(dev)) {
                temp = I915_READ(PCH_DREF_CONTROL);
                /* Always enable nonspread source */
                temp &= ~DREF_NONSPREAD_SOURCE_MASK;
@@ -3043,7 +3554,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                reduced_clock.m2;
        }
 
-       if (!IS_IRONLAKE(dev))
+       if (!HAS_PCH_SPLIT(dev))
                dpll = DPLL_VGA_MODE_DIS;
 
        if (IS_I9XX(dev)) {
@@ -3056,7 +3567,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
                        if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
                                dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
-                       else if (IS_IRONLAKE(dev))
+                       else if (HAS_PCH_SPLIT(dev))
                                dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
                }
                if (is_dp)
@@ -3068,7 +3579,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                else {
                        dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
                        /* also FPA1 */
-                       if (IS_IRONLAKE(dev))
+                       if (HAS_PCH_SPLIT(dev))
                                dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
                        if (IS_G4X(dev) && has_reduced_clock)
                                dpll |= (1 << (reduced_clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
@@ -3087,7 +3598,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
                        break;
                }
-               if (IS_I965G(dev) && !IS_IRONLAKE(dev))
+               if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
                        dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
        } else {
                if (is_lvds) {
@@ -3108,7 +3619,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                /* XXX: just matching BIOS for now */
                /*      dpll |= PLL_REF_INPUT_TVCLKINBC; */
                dpll |= 3;
-       else if (is_lvds && dev_priv->lvds_use_ssc && num_outputs < 2)
+       else if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2)
                dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
        else
                dpll |= PLL_REF_INPUT_DREFCLK;
@@ -3121,7 +3632,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        /* Ironlake's plane is forced to pipe, bit 24 is to
           enable color space conversion */
-       if (!IS_IRONLAKE(dev)) {
+       if (!HAS_PCH_SPLIT(dev)) {
                if (pipe == 0)
                        dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
                else
@@ -3148,14 +3659,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
 
        /* Disable the panel fitter if it was on our pipe */
-       if (!IS_IRONLAKE(dev) && intel_panel_fitter_pipe(dev) == pipe)
+       if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe)
                I915_WRITE(PFIT_CONTROL, 0);
 
        DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
        drm_mode_debug_printmodeline(mode);
 
        /* assign to Ironlake registers */
-       if (IS_IRONLAKE(dev)) {
+       if (HAS_PCH_SPLIT(dev)) {
                fp_reg = pch_fp_reg;
                dpll_reg = pch_dpll_reg;
        }
@@ -3169,6 +3680,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.
@@ -3176,11 +3699,22 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        if (is_lvds) {
                u32 lvds;
 
-               if (IS_IRONLAKE(dev))
+               if (HAS_PCH_SPLIT(dev))
                        lvds_reg = PCH_LVDS;
 
                lvds = I915_READ(lvds_reg);
-               lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT;
+               lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+               if (pipe == 1) {
+                       if (HAS_PCH_CPT(dev))
+                               lvds |= PORT_TRANS_B_SEL_CPT;
+                       else
+                               lvds |= LVDS_PIPEB_SELECT;
+               } else {
+                       if (HAS_PCH_CPT(dev))
+                               lvds &= ~PORT_TRANS_SEL_MASK;
+                       else
+                               lvds &= ~LVDS_PIPEB_SELECT;
+               }
                /* set the corresponsding LVDS_BORDER bit */
                lvds |= dev_priv->lvds_border_bits;
                /* Set the B0-B3 data pairs corresponding to whether we're going to
@@ -3195,12 +3729,41 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                 * appropriately here, but we need to look more thoroughly into how
                 * panels behave in the two modes.
                 */
-
+               /* set the dithering flag */
+               if (IS_I965G(dev)) {
+                       if (dev_priv->lvds_dither) {
+                               if (HAS_PCH_SPLIT(dev)) {
+                                       pipeconf |= PIPE_ENABLE_DITHER;
+                                       pipeconf |= PIPE_DITHER_TYPE_ST01;
+                               } else
+                                       lvds |= LVDS_ENABLE_DITHER;
+                       } else {
+                               if (HAS_PCH_SPLIT(dev)) {
+                                       pipeconf &= ~PIPE_ENABLE_DITHER;
+                                       pipeconf &= ~PIPE_DITHER_TYPE_MASK;
+                               } else
+                                       lvds &= ~LVDS_ENABLE_DITHER;
+                       }
+               }
                I915_WRITE(lvds_reg, lvds);
                I915_READ(lvds_reg);
        }
        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);
@@ -3209,7 +3772,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                /* Wait for the clocks to stabilize. */
                udelay(150);
 
-               if (IS_I965G(dev) && !IS_IRONLAKE(dev)) {
+               if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
                        if (is_sdvo) {
                                sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
                                I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
@@ -3241,6 +3804,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                }
        }
 
+       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+               pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+               /* the chip adds 2 halflines automatically */
+               adjusted_mode->crtc_vdisplay -= 1;
+               adjusted_mode->crtc_vtotal -= 1;
+               adjusted_mode->crtc_vblank_start -= 1;
+               adjusted_mode->crtc_vblank_end -= 1;
+               adjusted_mode->crtc_vsync_end -= 1;
+               adjusted_mode->crtc_vsync_start -= 1;
+       } else
+               pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */
+
        I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
                   ((adjusted_mode->crtc_htotal - 1) << 16));
        I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
@@ -3256,14 +3831,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        /* pipesrc and dspsize control the size that is scaled from, which should
         * always be the user's requested size.
         */
-       if (!IS_IRONLAKE(dev)) {
+       if (!HAS_PCH_SPLIT(dev)) {
                I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) |
                                (mode->hdisplay - 1));
                I915_WRITE(dsppos_reg, 0);
        }
        I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
 
-       if (IS_IRONLAKE(dev)) {
+       if (HAS_PCH_SPLIT(dev)) {
                I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m);
                I915_WRITE(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n);
                I915_WRITE(link_m1_reg, m_n.link_m);
@@ -3275,6 +3850,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);
                }
        }
@@ -3319,7 +3906,7 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
                return;
 
        /* use legacy palette for Ironlake */
-       if (IS_IRONLAKE(dev))
+       if (HAS_PCH_SPLIT(dev))
                palreg = (intel_crtc->pipe == 0) ? LGC_PALETTE_A :
                                                   LGC_PALETTE_B;
 
@@ -3375,7 +3962,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        if (!bo)
                return -ENOENT;
 
-       obj_priv = bo->driver_private;
+       obj_priv = to_intel_bo(bo);
 
        if (bo->size < width * height * 4) {
                DRM_ERROR("buffer is to small\n");
@@ -3391,6 +3978,13 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
                        DRM_ERROR("failed to pin cursor bo\n");
                        goto fail_locked;
                }
+
+               ret = i915_gem_object_set_to_gtt_domain(bo, 0);
+               if (ret) {
+                       DRM_ERROR("failed to move cursor bo into the GTT\n");
+                       goto fail_unpin;
+               }
+
                addr = obj_priv->gtt_offset;
        } else {
                ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
@@ -3434,11 +4028,12 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        intel_crtc->cursor_bo = bo;
 
        return 0;
-fail:
-       mutex_lock(&dev->struct_mutex);
+fail_unpin:
+       i915_gem_object_unpin(bo);
 fail_locked:
-       drm_gem_object_unreference(bo);
        mutex_unlock(&dev->struct_mutex);
+fail:
+       drm_gem_object_unreference_unlocked(bo);
        return ret;
 }
 
@@ -3520,9 +4115,9 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
  * detection.
  *
  * It will be up to the load-detect code to adjust the pipe as appropriate for
- * its requirements.  The pipe will be connected to no other outputs.
+ * its requirements.  The pipe will be connected to no other encoders.
  *
- * Currently this code will only succeed if there is a pipe with no outputs
+ * Currently this code will only succeed if there is a pipe with no encoders
  * configured for it.  In the future, it could choose to temporarily disable
  * some outputs to free up a pipe for its use.
  *
@@ -3535,14 +4130,15 @@ static struct drm_display_mode load_detect_mode = {
                 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
 };
 
-struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output,
+struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+                                           struct drm_connector *connector,
                                            struct drm_display_mode *mode,
                                            int *dpms_mode)
 {
        struct intel_crtc *intel_crtc;
        struct drm_crtc *possible_crtc;
        struct drm_crtc *supported_crtc =NULL;
-       struct drm_encoder *encoder = &intel_output->enc;
+       struct drm_encoder *encoder = &intel_encoder->enc;
        struct drm_crtc *crtc = NULL;
        struct drm_device *dev = encoder->dev;
        struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -3594,8 +4190,8 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output,
        }
 
        encoder->crtc = crtc;
-       intel_output->base.encoder = encoder;
-       intel_output->load_detect_temp = true;
+       connector->encoder = encoder;
+       intel_encoder->load_detect_temp = true;
 
        intel_crtc = to_intel_crtc(crtc);
        *dpms_mode = intel_crtc->dpms_mode;
@@ -3620,23 +4216,24 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output,
        return crtc;
 }
 
-void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_mode)
+void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
+                                   struct drm_connector *connector, int dpms_mode)
 {
-       struct drm_encoder *encoder = &intel_output->enc;
+       struct drm_encoder *encoder = &intel_encoder->enc;
        struct drm_device *dev = encoder->dev;
        struct drm_crtc *crtc = encoder->crtc;
        struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
        struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
 
-       if (intel_output->load_detect_temp) {
+       if (intel_encoder->load_detect_temp) {
                encoder->crtc = NULL;
-               intel_output->base.encoder = NULL;
-               intel_output->load_detect_temp = false;
+               connector->encoder = NULL;
+               intel_encoder->load_detect_temp = false;
                crtc->enabled = drm_helper_crtc_in_use(crtc);
                drm_helper_disable_unused_functions(dev);
        }
 
-       /* Switch crtc and output back off if necessary */
+       /* Switch crtc and encoder back off if necessary */
        if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) {
                if (encoder->crtc == crtc)
                        encoder_funcs->dpms(encoder, dpms_mode);
@@ -3803,7 +4400,7 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
        int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
        int dpll = I915_READ(dpll_reg);
 
-       if (IS_IRONLAKE(dev))
+       if (HAS_PCH_SPLIT(dev))
                return;
 
        if (!dev_priv->lvds_downclock_avail)
@@ -3842,7 +4439,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
        int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
        int dpll = I915_READ(dpll_reg);
 
-       if (IS_IRONLAKE(dev))
+       if (HAS_PCH_SPLIT(dev))
                return;
 
        if (!dev_priv->lvds_downclock_avail)
@@ -3892,6 +4489,13 @@ static void intel_idle_update(struct work_struct *work)
 
        mutex_lock(&dev->struct_mutex);
 
+       i915_update_gfx_val(dev_priv);
+
+       if (IS_I945G(dev) || IS_I945GM(dev)) {
+               DRM_DEBUG_DRIVER("enable memory self refresh on 945\n");
+               I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
+       }
+
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                /* Skip inactive CRTCs */
                if (!crtc->fb)
@@ -3925,9 +4529,17 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return;
 
-       if (!dev_priv->busy)
+       if (!dev_priv->busy) {
+               if (IS_I945G(dev) || IS_I945GM(dev)) {
+                       u32 fw_blc_self;
+
+                       DRM_DEBUG_DRIVER("disable memory self refresh on 945\n");
+                       fw_blc_self = I915_READ(FW_BLC_SELF);
+                       fw_blc_self &= ~FW_BLC_SELF_EN;
+                       I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
+               }
                dev_priv->busy = true;
-       else
+       else
                mod_timer(&dev_priv->idle_timer, jiffies +
                          msecs_to_jiffies(GPU_IDLE_TIMEOUT));
 
@@ -3939,6 +4551,14 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
                intel_fb = to_intel_framebuffer(crtc->fb);
                if (intel_fb->obj == obj) {
                        if (!intel_crtc->busy) {
+                               if (IS_I945G(dev) || IS_I945GM(dev)) {
+                                       u32 fw_blc_self;
+
+                                       DRM_DEBUG_DRIVER("disable memory self refresh on 945\n");
+                                       fw_blc_self = I915_READ(FW_BLC_SELF);
+                                       fw_blc_self &= ~FW_BLC_SELF_EN;
+                                       I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
+                               }
                                /* Non-busy -> busy, upclock */
                                intel_increase_pllclock(crtc, true);
                                intel_crtc->busy = true;
@@ -3962,7 +4582,8 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
 struct intel_unpin_work {
        struct work_struct work;
        struct drm_device *dev;
-       struct drm_gem_object *obj;
+       struct drm_gem_object *old_fb_obj;
+       struct drm_gem_object *pending_flip_obj;
        struct drm_pending_vblank_event *event;
        int pending;
 };
@@ -3973,8 +4594,9 @@ static void intel_unpin_work_fn(struct work_struct *__work)
                container_of(__work, struct intel_unpin_work, work);
 
        mutex_lock(&work->dev->struct_mutex);
-       i915_gem_object_unpin(work->obj);
-       drm_gem_object_unreference(work->obj);
+       i915_gem_object_unpin(work->old_fb_obj);
+       drm_gem_object_unreference(work->pending_flip_obj);
+       drm_gem_object_unreference(work->old_fb_obj);
        mutex_unlock(&work->dev->struct_mutex);
        kfree(work);
 }
@@ -4017,8 +4639,11 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe)
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
-       obj_priv = work->obj->driver_private;
-       if (atomic_dec_and_test(&obj_priv->pending_flip))
+       obj_priv = to_intel_bo(work->pending_flip_obj);
+
+       /* Initial scanout buffer will have a 0 pending flip count */
+       if ((atomic_read(&obj_priv->pending_flip) == 0) ||
+           atomic_dec_and_test(&obj_priv->pending_flip))
                DRM_WAKEUP(&dev_priv->pending_flip_queue);
        schedule_work(&work->work);
 }
@@ -4031,8 +4656,11 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane)
        unsigned long flags;
 
        spin_lock_irqsave(&dev->event_lock, flags);
-       if (intel_crtc->unpin_work)
+       if (intel_crtc->unpin_work) {
                intel_crtc->unpin_work->pending = 1;
+       } else {
+               DRM_DEBUG_DRIVER("preparing flip with no unpin work?\n");
+       }
        spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
@@ -4048,19 +4676,17 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_unpin_work *work;
        unsigned long flags;
-       int ret;
-       RING_LOCALS;
+       int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC;
+       int ret, pipesrc;
 
        work = kzalloc(sizeof *work, GFP_KERNEL);
        if (work == NULL)
                return -ENOMEM;
 
-       mutex_lock(&dev->struct_mutex);
-
        work->event = event;
        work->dev = crtc->dev;
        intel_fb = to_intel_framebuffer(crtc->fb);
-       work->obj = intel_fb->obj;
+       work->old_fb_obj = intel_fb->obj;
        INIT_WORK(&work->work, intel_unpin_work_fn);
 
        /* We borrow the event spin lock for protecting unpin_work */
@@ -4068,7 +4694,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        if (intel_crtc->unpin_work) {
                spin_unlock_irqrestore(&dev->event_lock, flags);
                kfree(work);
-               mutex_unlock(&dev->struct_mutex);
+
+               DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
                return -EBUSY;
        }
        intel_crtc->unpin_work = work;
@@ -4077,21 +4704,32 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        intel_fb = to_intel_framebuffer(fb);
        obj = intel_fb->obj;
 
+       mutex_lock(&dev->struct_mutex);
        ret = intel_pin_and_fence_fb_obj(dev, obj);
        if (ret != 0) {
-               kfree(work);
                mutex_unlock(&dev->struct_mutex);
+
+               spin_lock_irqsave(&dev->event_lock, flags);
+               intel_crtc->unpin_work = NULL;
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+
+               kfree(work);
+
+               DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n",
+                                to_intel_bo(obj));
                return ret;
        }
 
-       /* Reference the old fb object for the scheduled work. */
-       drm_gem_object_reference(work->obj);
+       /* Reference the objects for the scheduled work. */
+       drm_gem_object_reference(work->old_fb_obj);
+       drm_gem_object_reference(obj);
 
        crtc->fb = fb;
        i915_gem_object_flush_write_domain(obj);
        drm_vblank_get(dev, intel_crtc->pipe);
-       obj_priv = obj->driver_private;
+       obj_priv = to_intel_bo(obj);
        atomic_inc(&obj_priv->pending_flip);
+       work->pending_flip_obj = obj;
 
        BEGIN_LP_RING(4);
        OUT_RING(MI_DISPLAY_FLIP |
@@ -4099,7 +4737,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        OUT_RING(fb->pitch);
        if (IS_I965G(dev)) {
                OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode);
-               OUT_RING((fb->width << 16) | fb->height);
+               pipesrc = I915_READ(pipesrc_reg); 
+               OUT_RING(pipesrc & 0x0fff0fff);
        } else {
                OUT_RING(obj_priv->gtt_offset);
                OUT_RING(MI_NOOP);
@@ -4214,15 +4853,15 @@ struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
        return crtc;
 }
 
-static int intel_connector_clones(struct drm_device *dev, int type_mask)
+static int intel_encoder_clones(struct drm_device *dev, int type_mask)
 {
        int index_mask = 0;
-       struct drm_connector *connector;
+       struct drm_encoder *encoder;
        int entry = 0;
 
-        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               struct intel_output *intel_output = to_intel_output(connector);
-               if (type_mask & intel_output->clone_mask)
+        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+               if (type_mask & intel_encoder->clone_mask)
                        index_mask |= (1 << entry);
                entry++;
        }
@@ -4233,7 +4872,7 @@ static int intel_connector_clones(struct drm_device *dev, int type_mask)
 static void intel_setup_outputs(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_connector *connector;
+       struct drm_encoder *encoder;
 
        intel_crt_init(dev);
 
@@ -4241,16 +4880,15 @@ static void intel_setup_outputs(struct drm_device *dev)
        if (IS_MOBILE(dev) && !IS_I830(dev))
                intel_lvds_init(dev);
 
-       if (IS_IRONLAKE(dev)) {
+       if (HAS_PCH_SPLIT(dev)) {
                int found;
 
                if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED))
                        intel_dp_init(dev, DP_A);
 
                if (I915_READ(HDMIB) & PORT_DETECTED) {
-                       /* check SDVOB */
-                       /* found = intel_sdvo_init(dev, HDMIB); */
-                       found = 0;
+                       /* PCH SDVOB multiplex with HDMIB */
+                       found = intel_sdvo_init(dev, PCH_SDVOB);
                        if (!found)
                                intel_hdmi_init(dev, HDMIB);
                        if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
@@ -4310,34 +4948,27 @@ static void intel_setup_outputs(struct drm_device *dev)
                        DRM_DEBUG_KMS("probing DP_D\n");
                        intel_dp_init(dev, DP_D);
                }
-       } else if (IS_I8XX(dev))
+       } else if (IS_GEN2(dev))
                intel_dvo_init(dev);
 
        if (SUPPORTS_TV(dev))
                intel_tv_init(dev);
 
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               struct intel_output *intel_output = to_intel_output(connector);
-               struct drm_encoder *encoder = &intel_output->enc;
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
 
-               encoder->possible_crtcs = intel_output->crtc_mask;
-               encoder->possible_clones = intel_connector_clones(dev,
-                                               intel_output->clone_mask);
+               encoder->possible_crtcs = intel_encoder->crtc_mask;
+               encoder->possible_clones = intel_encoder_clones(dev,
+                                               intel_encoder->clone_mask);
        }
 }
 
 static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
 {
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
-       struct drm_device *dev = fb->dev;
-
-       if (fb->fbdev)
-               intelfb_remove(dev, fb);
 
        drm_framebuffer_cleanup(fb);
-       mutex_lock(&dev->struct_mutex);
-       drm_gem_object_unreference(intel_fb->obj);
-       mutex_unlock(&dev->struct_mutex);
+       drm_gem_object_unreference_unlocked(intel_fb->obj);
 
        kfree(intel_fb);
 }
@@ -4357,18 +4988,13 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = {
        .create_handle = intel_user_framebuffer_create_handle,
 };
 
-int intel_framebuffer_create(struct drm_device *dev,
-                            struct drm_mode_fb_cmd *mode_cmd,
-                            struct drm_framebuffer **fb,
-                            struct drm_gem_object *obj)
+int intel_framebuffer_init(struct drm_device *dev,
+                          struct intel_framebuffer *intel_fb,
+                          struct drm_mode_fb_cmd *mode_cmd,
+                          struct drm_gem_object *obj)
 {
-       struct intel_framebuffer *intel_fb;
        int ret;
 
-       intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
-       if (!intel_fb)
-               return -ENOMEM;
-
        ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
        if (ret) {
                DRM_ERROR("framebuffer init failed %d\n", ret);
@@ -4376,44 +5002,275 @@ int intel_framebuffer_create(struct drm_device *dev,
        }
 
        drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
-
        intel_fb->obj = obj;
-
-       *fb = &intel_fb->base;
-
        return 0;
 }
 
-
 static struct drm_framebuffer *
 intel_user_framebuffer_create(struct drm_device *dev,
                              struct drm_file *filp,
                              struct drm_mode_fb_cmd *mode_cmd)
 {
        struct drm_gem_object *obj;
-       struct drm_framebuffer *fb;
+       struct intel_framebuffer *intel_fb;
        int ret;
 
        obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle);
        if (!obj)
                return NULL;
 
-       ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj);
+       intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+       if (!intel_fb)
+               return NULL;
+
+       ret = intel_framebuffer_init(dev, intel_fb,
+                                    mode_cmd, obj);
        if (ret) {
-               mutex_lock(&dev->struct_mutex);
-               drm_gem_object_unreference(obj);
-               mutex_unlock(&dev->struct_mutex);
+               drm_gem_object_unreference_unlocked(obj);
+               kfree(intel_fb);
                return NULL;
        }
 
-       return fb;
+       return &intel_fb->base;
 }
 
 static const struct drm_mode_config_funcs intel_mode_funcs = {
        .fb_create = intel_user_framebuffer_create,
-       .fb_changed = intelfb_probe,
+       .output_poll_changed = intel_fb_output_poll_changed,
 };
 
+static struct drm_gem_object *
+intel_alloc_power_context(struct drm_device *dev)
+{
+       struct drm_gem_object *pwrctx;
+       int ret;
+
+       pwrctx = i915_gem_alloc_object(dev, 4096);
+       if (!pwrctx) {
+               DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
+               return NULL;
+       }
+
+       mutex_lock(&dev->struct_mutex);
+       ret = i915_gem_object_pin(pwrctx, 4096);
+       if (ret) {
+               DRM_ERROR("failed to pin power context: %d\n", ret);
+               goto err_unref;
+       }
+
+       ret = i915_gem_object_set_to_gtt_domain(pwrctx, 1);
+       if (ret) {
+               DRM_ERROR("failed to set-domain on power context: %d\n", ret);
+               goto err_unpin;
+       }
+       mutex_unlock(&dev->struct_mutex);
+
+       return pwrctx;
+
+err_unpin:
+       i915_gem_object_unpin(pwrctx);
+err_unref:
+       drm_gem_object_unreference(pwrctx);
+       mutex_unlock(&dev->struct_mutex);
+       return NULL;
+}
+
+bool ironlake_set_drps(struct drm_device *dev, u8 val)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u16 rgvswctl;
+
+       rgvswctl = I915_READ16(MEMSWCTL);
+       if (rgvswctl & MEMCTL_CMD_STS) {
+               DRM_DEBUG("gpu busy, RCS change rejected\n");
+               return false; /* still busy with another command */
+       }
+
+       rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
+               (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
+       I915_WRITE16(MEMSWCTL, rgvswctl);
+       POSTING_READ16(MEMSWCTL);
+
+       rgvswctl |= MEMCTL_CMD_STS;
+       I915_WRITE16(MEMSWCTL, rgvswctl);
+
+       return true;
+}
+
+void ironlake_enable_drps(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 rgvmodectl = I915_READ(MEMMODECTL);
+       u8 fmax, fmin, fstart, vstart;
+       int i = 0;
+
+       /* 100ms RC evaluation intervals */
+       I915_WRITE(RCUPEI, 100000);
+       I915_WRITE(RCDNEI, 100000);
+
+       /* Set max/min thresholds to 90ms and 80ms respectively */
+       I915_WRITE(RCBMAXAVG, 90000);
+       I915_WRITE(RCBMINAVG, 80000);
+
+       I915_WRITE(MEMIHYST, 1);
+
+       /* Set up min, max, and cur for interrupt handling */
+       fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT;
+       fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
+       fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
+               MEMMODE_FSTART_SHIFT;
+       fstart = fmax;
+
+       vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
+               PXVFREQ_PX_SHIFT;
+
+       dev_priv->fmax = fstart; /* IPS callback will increase this */
+       dev_priv->fstart = fstart;
+
+       dev_priv->max_delay = fmax;
+       dev_priv->min_delay = fmin;
+       dev_priv->cur_delay = fstart;
+
+       DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", fmax, fmin,
+                        fstart);
+
+       I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
+
+       /*
+        * Interrupts will be enabled in ironlake_irq_postinstall
+        */
+
+       I915_WRITE(VIDSTART, vstart);
+       POSTING_READ(VIDSTART);
+
+       rgvmodectl |= MEMMODE_SWMODE_EN;
+       I915_WRITE(MEMMODECTL, rgvmodectl);
+
+       while (I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) {
+               if (i++ > 100) {
+                       DRM_ERROR("stuck trying to change perf mode\n");
+                       break;
+               }
+               msleep(1);
+       }
+       msleep(1);
+
+       ironlake_set_drps(dev, fstart);
+
+       dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) +
+               I915_READ(0x112e0);
+       dev_priv->last_time1 = jiffies_to_msecs(jiffies);
+       dev_priv->last_count2 = I915_READ(0x112f4);
+       getrawmonotonic(&dev_priv->last_time2);
+}
+
+void ironlake_disable_drps(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u16 rgvswctl = I915_READ16(MEMSWCTL);
+
+       /* Ack interrupts, disable EFC interrupt */
+       I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
+       I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG);
+       I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT);
+       I915_WRITE(DEIIR, DE_PCU_EVENT);
+       I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
+
+       /* Go back to the starting frequency */
+       ironlake_set_drps(dev, dev_priv->fstart);
+       msleep(1);
+       rgvswctl |= MEMCTL_CMD_STS;
+       I915_WRITE(MEMSWCTL, rgvswctl);
+       msleep(1);
+
+}
+
+static unsigned long intel_pxfreq(u32 vidfreq)
+{
+       unsigned long freq;
+       int div = (vidfreq & 0x3f0000) >> 16;
+       int post = (vidfreq & 0x3000) >> 12;
+       int pre = (vidfreq & 0x7);
+
+       if (!pre)
+               return 0;
+
+       freq = ((div * 133333) / ((1<<post) * pre));
+
+       return freq;
+}
+
+void intel_init_emon(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 lcfuse;
+       u8 pxw[16];
+       int i;
+
+       /* Disable to program */
+       I915_WRITE(ECR, 0);
+       POSTING_READ(ECR);
+
+       /* Program energy weights for various events */
+       I915_WRITE(SDEW, 0x15040d00);
+       I915_WRITE(CSIEW0, 0x007f0000);
+       I915_WRITE(CSIEW1, 0x1e220004);
+       I915_WRITE(CSIEW2, 0x04000004);
+
+       for (i = 0; i < 5; i++)
+               I915_WRITE(PEW + (i * 4), 0);
+       for (i = 0; i < 3; i++)
+               I915_WRITE(DEW + (i * 4), 0);
+
+       /* Program P-state weights to account for frequency power adjustment */
+       for (i = 0; i < 16; i++) {
+               u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4));
+               unsigned long freq = intel_pxfreq(pxvidfreq);
+               unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >>
+                       PXVFREQ_PX_SHIFT;
+               unsigned long val;
+
+               val = vid * vid;
+               val *= (freq / 1000);
+               val *= 255;
+               val /= (127*127*900);
+               if (val > 0xff)
+                       DRM_ERROR("bad pxval: %ld\n", val);
+               pxw[i] = val;
+       }
+       /* Render standby states get 0 weight */
+       pxw[14] = 0;
+       pxw[15] = 0;
+
+       for (i = 0; i < 4; i++) {
+               u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) |
+                       (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]);
+               I915_WRITE(PXW + (i * 4), val);
+       }
+
+       /* Adjust magic regs to magic values (more experimental results) */
+       I915_WRITE(OGW0, 0);
+       I915_WRITE(OGW1, 0);
+       I915_WRITE(EG0, 0x00007f00);
+       I915_WRITE(EG1, 0x0000000e);
+       I915_WRITE(EG2, 0x000e0000);
+       I915_WRITE(EG3, 0x68000300);
+       I915_WRITE(EG4, 0x42000000);
+       I915_WRITE(EG5, 0x00140031);
+       I915_WRITE(EG6, 0);
+       I915_WRITE(EG7, 0);
+
+       for (i = 0; i < 8; i++)
+               I915_WRITE(PXWL + (i * 4), 0);
+
+       /* Enable PMON + select events */
+       I915_WRITE(ECR, 0x80000019);
+
+       lcfuse = I915_READ(LCFUSE02);
+
+       dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
+}
+
 void intel_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4422,7 +5279,40 @@ void intel_init_clock_gating(struct drm_device *dev)
         * Disable clock gating reported to work incorrectly according to the
         * specs, but enable as much else as we can.
         */
-       if (IS_IRONLAKE(dev)) {
+       if (HAS_PCH_SPLIT(dev)) {
+               uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+               if (IS_IRONLAKE(dev)) {
+                       /* Required for FBC */
+                       dspclk_gate |= DPFDUNIT_CLOCK_GATE_DISABLE;
+                       /* Required for CxSR */
+                       dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
+
+                       I915_WRITE(PCH_3DCGDIS0,
+                                  MARIUNIT_CLOCK_GATE_DISABLE |
+                                  SVSMUNIT_CLOCK_GATE_DISABLE);
+               }
+
+               I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+               /*
+                * According to the spec the following bits should be set in
+                * order to enable memory self-refresh
+                * The bit 22/21 of 0x42004
+                * The bit 5 of 0x42020
+                * The bit 15 of 0x45000
+                */
+               if (IS_IRONLAKE(dev)) {
+                       I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                                       (I915_READ(ILK_DISPLAY_CHICKEN2) |
+                                       ILK_DPARB_GATE | ILK_VSDPFD_FULL));
+                       I915_WRITE(ILK_DSPCLK_GATE,
+                                       (I915_READ(ILK_DSPCLK_GATE) |
+                                               ILK_DPARB_CLK_GATE));
+                       I915_WRITE(DISP_ARB_CTL,
+                                       (I915_READ(DISP_ARB_CTL) |
+                                               DISP_FBC_WM_DIS));
+               }
                return;
        } else if (IS_G4X(dev)) {
                uint32_t dspclk_gate;
@@ -4467,41 +5357,26 @@ void intel_init_clock_gating(struct drm_device *dev)
         * to save state.
         */
        if (I915_HAS_RC6(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) {
-               struct drm_gem_object *pwrctx;
-               struct drm_i915_gem_object *obj_priv;
-               int ret;
+               struct drm_i915_gem_object *obj_priv = NULL;
 
                if (dev_priv->pwrctx) {
-                       obj_priv = dev_priv->pwrctx->driver_private;
+                       obj_priv = to_intel_bo(dev_priv->pwrctx);
                } else {
-                       pwrctx = drm_gem_object_alloc(dev, 4096);
-                       if (!pwrctx) {
-                               DRM_DEBUG("failed to alloc power context, "
-                                         "RC6 disabled\n");
-                               goto out;
-                       }
+                       struct drm_gem_object *pwrctx;
 
-                       ret = i915_gem_object_pin(pwrctx, 4096);
-                       if (ret) {
-                               DRM_ERROR("failed to pin power context: %d\n",
-                                         ret);
-                               drm_gem_object_unreference(pwrctx);
-                               goto out;
+                       pwrctx = intel_alloc_power_context(dev);
+                       if (pwrctx) {
+                               dev_priv->pwrctx = pwrctx;
+                               obj_priv = to_intel_bo(pwrctx);
                        }
-
-                       i915_gem_object_set_to_gtt_domain(pwrctx, 1);
-
-                       dev_priv->pwrctx = pwrctx;
-                       obj_priv = pwrctx->driver_private;
                }
 
-               I915_WRITE(PWRCTXA, obj_priv->gtt_offset | PWRCTX_EN);
-               I915_WRITE(MCHBAR_RENDER_STANDBY,
-                          I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT);
+               if (obj_priv) {
+                       I915_WRITE(PWRCTXA, obj_priv->gtt_offset | PWRCTX_EN);
+                       I915_WRITE(MCHBAR_RENDER_STANDBY,
+                                  I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT);
+               }
        }
-
-out:
-       return;
 }
 
 /* Set up chip specific display functions */
@@ -4510,18 +5385,17 @@ static void intel_init_display(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        /* We always want a DPMS function */
-       if (IS_IRONLAKE(dev))
+       if (HAS_PCH_SPLIT(dev))
                dev_priv->display.dpms = ironlake_crtc_dpms;
        else
                dev_priv->display.dpms = i9xx_crtc_dpms;
 
-       /* Only mobile has FBC, leave pointers NULL for other chips */
-       if (IS_MOBILE(dev)) {
+       if (I915_HAS_FBC(dev)) {
                if (IS_GM45(dev)) {
                        dev_priv->display.fbc_enabled = g4x_fbc_enabled;
                        dev_priv->display.enable_fbc = g4x_enable_fbc;
                        dev_priv->display.disable_fbc = g4x_disable_fbc;
-               } else if (IS_I965GM(dev) || IS_I945GM(dev) || IS_I915GM(dev)) {
+               } else if (IS_I965GM(dev)) {
                        dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
                        dev_priv->display.enable_fbc = i8xx_enable_fbc;
                        dev_priv->display.disable_fbc = i8xx_disable_fbc;
@@ -4553,30 +5427,54 @@ static void intel_init_display(struct drm_device *dev)
                        i830_get_display_clock_speed;
 
        /* For FIFO watermark updates */
-       if (IS_IRONLAKE(dev))
-               dev_priv->display.update_wm = NULL;
-       else if (IS_G4X(dev))
+       if (HAS_PCH_SPLIT(dev)) {
+               if (IS_IRONLAKE(dev)) {
+                       if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
+                               dev_priv->display.update_wm = ironlake_update_wm;
+                       else {
+                               DRM_DEBUG_KMS("Failed to get proper latency. "
+                                             "Disable CxSR\n");
+                               dev_priv->display.update_wm = NULL;
+                       }
+               } else
+                       dev_priv->display.update_wm = NULL;
+       } else if (IS_PINEVIEW(dev)) {
+               if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev),
+                                           dev_priv->is_ddr3,
+                                           dev_priv->fsb_freq,
+                                           dev_priv->mem_freq)) {
+                       DRM_INFO("failed to find known CxSR latency "
+                                "(found ddr%s fsb freq %d, mem freq %d), "
+                                "disabling CxSR\n",
+                                (dev_priv->is_ddr3 == 1) ? "3": "2",
+                                dev_priv->fsb_freq, dev_priv->mem_freq);
+                       /* Disable CxSR and never update its watermark again */
+                       pineview_disable_cxsr(dev);
+                       dev_priv->display.update_wm = NULL;
+               } else
+                       dev_priv->display.update_wm = pineview_update_wm;
+       } else if (IS_G4X(dev))
                dev_priv->display.update_wm = g4x_update_wm;
        else if (IS_I965G(dev))
                dev_priv->display.update_wm = i965_update_wm;
-       else if (IS_I9XX(dev) || IS_MOBILE(dev)) {
+       else if (IS_I9XX(dev)) {
                dev_priv->display.update_wm = i9xx_update_wm;
                dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
+       } else if (IS_I85X(dev)) {
+               dev_priv->display.update_wm = i9xx_update_wm;
+               dev_priv->display.get_fifo_size = i85x_get_fifo_size;
        } else {
-               if (IS_I85X(dev))
-                       dev_priv->display.get_fifo_size = i85x_get_fifo_size;
-               else if (IS_845G(dev))
+               dev_priv->display.update_wm = i830_update_wm;
+               if (IS_845G(dev))
                        dev_priv->display.get_fifo_size = i845_get_fifo_size;
                else
                        dev_priv->display.get_fifo_size = i830_get_fifo_size;
-               dev_priv->display.update_wm = i830_update_wm;
        }
 }
 
 void intel_modeset_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int num_pipe;
        int i;
 
        drm_mode_config_init(dev);
@@ -4606,18 +5504,13 @@ void intel_modeset_init(struct drm_device *dev)
                dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0);
 
        if (IS_MOBILE(dev) || IS_I9XX(dev))
-               num_pipe = 2;
+               dev_priv->num_pipe = 2;
        else
-               num_pipe = 1;
+               dev_priv->num_pipe = 1;
        DRM_DEBUG_KMS("%d display pipe%s available.\n",
-                 num_pipe, num_pipe > 1 ? "s" : "");
-
-       if (IS_I85X(dev))
-               pci_read_config_word(dev->pdev, HPLLCC, &dev_priv->orig_clock);
-       else if (IS_I9XX(dev) || IS_G4X(dev))
-               pci_read_config_word(dev->pdev, GCFGC, &dev_priv->orig_clock);
+                     dev_priv->num_pipe, dev_priv->num_pipe > 1 ? "s" : "");
 
-       for (i = 0; i < num_pipe; i++) {
+       for (i = 0; i < dev_priv->num_pipe; i++) {
                intel_crtc_init(dev, i);
        }
 
@@ -4625,18 +5518,16 @@ void intel_modeset_init(struct drm_device *dev)
 
        intel_init_clock_gating(dev);
 
+       if (IS_IRONLAKE_M(dev)) {
+               ironlake_enable_drps(dev);
+               intel_init_emon(dev);
+       }
+
        INIT_WORK(&dev_priv->idle_work, intel_idle_update);
        setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
                    (unsigned long)dev);
 
        intel_setup_overlay(dev);
-
-       if (IS_PINEVIEW(dev) && !intel_get_cxsr_latency(IS_PINEVIEW_G(dev),
-                                                       dev_priv->fsb_freq,
-                                                       dev_priv->mem_freq))
-               DRM_INFO("failed to find known CxSR latency "
-                        "(found fsb freq %d, mem freq %d), disabling CxSR\n",
-                        dev_priv->fsb_freq, dev_priv->mem_freq);
 }
 
 void intel_modeset_cleanup(struct drm_device *dev)
@@ -4647,6 +5538,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        mutex_lock(&dev->struct_mutex);
 
+       drm_kms_helper_poll_fini(dev);
+       intel_fbdev_fini(dev);
+
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                /* Skip inactive CRTCs */
                if (!crtc->fb)
@@ -4665,27 +5559,45 @@ void intel_modeset_cleanup(struct drm_device *dev)
        if (dev_priv->pwrctx) {
                struct drm_i915_gem_object *obj_priv;
 
-               obj_priv = dev_priv->pwrctx->driver_private;
+               obj_priv = to_intel_bo(dev_priv->pwrctx);
                I915_WRITE(PWRCTXA, obj_priv->gtt_offset &~ PWRCTX_EN);
                I915_READ(PWRCTXA);
                i915_gem_object_unpin(dev_priv->pwrctx);
                drm_gem_object_unreference(dev_priv->pwrctx);
        }
 
+       if (IS_IRONLAKE_M(dev))
+               ironlake_disable_drps(dev);
+
        mutex_unlock(&dev->struct_mutex);
 
        drm_mode_config_cleanup(dev);
 }
 
 
-/* current intel driver doesn't take advantage of encoders
-   always give back the encoder for the connector
-*/
-struct drm_encoder *intel_best_encoder(struct drm_connector *connector)
+/*
+ * Return which encoder is currently attached for connector.
+ */
+struct drm_encoder *intel_attached_encoder (struct drm_connector *connector)
 {
-       struct intel_output *intel_output = to_intel_output(connector);
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+       int i;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == 0)
+                       break;
 
-       return &intel_output->enc;
+               obj = drm_mode_object_find(connector->dev,
+                                           connector->encoder_ids[i],
+                                           DRM_MODE_OBJECT_ENCODER);
+               if (!obj)
+                       continue;
+
+               encoder = obj_to_encoder(obj);
+               return encoder;
+       }
+       return NULL;
 }
 
 /*