include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / gpu / drm / i915 / intel_display.c
index 2cc489b..e7e753b 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"
@@ -232,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).
  */
@@ -240,33 +241,86 @@ 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           6
-#define IRONLAKE_M_MIN           79
-#define IRONLAKE_M_MAX           127
 #define IRONLAKE_M1_MIN          12
 #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 */
 
-#define IRONLAKE_P_DISPLAY_PORT_MIN    10
-#define IRONLAKE_P_DISPLAY_PORT_MAX    20
-#define IRONLAKE_P2_DISPLAY_PORT_FAST  10
-#define IRONLAKE_P2_DISPLAY_PORT_SLOW  10
-#define IRONLAKE_P2_DISPLAY_PORT_LIMIT 0
-#define IRONLAKE_P1_DISPLAY_PORT_MIN   1
-#define IRONLAKE_P1_DISPLAY_PORT_MAX   2
+/* 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,
@@ -474,33 +528,78 @@ static const intel_limit_t intel_limits_pineview_lvds = {
        .find_pll = intel_find_best_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 },
+                .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 },
+                .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,
 };
 
@@ -509,34 +608,53 @@ static const intel_limit_t intel_limits_ironlake_display_port = {
                  .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_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_P_DISPLAY_PORT_MIN,
-                 .max = IRONLAKE_P_DISPLAY_PORT_MAX },
-        .p1  = { .min = IRONLAKE_P1_DISPLAY_PORT_MIN,
-                 .max = IRONLAKE_P1_DISPLAY_PORT_MAX},
-        .p2  = { .dot_limit = IRONLAKE_P2_DISPLAY_PORT_LIMIT,
-                 .p2_slow = IRONLAKE_P2_DISPLAY_PORT_SLOW,
-                 .p2_fast = IRONLAKE_P2_DISPLAY_PORT_FAST },
+        .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;
-       else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) ||
+       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;
 }
@@ -573,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);
@@ -769,7 +887,7 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
        if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
                int lvds_reg;
 
-               if (IS_IRONLAKE(dev))
+               if (HAS_PCH_SPLIT(dev))
                        lvds_reg = PCH_LVDS;
                else
                        lvds_reg = LVDS;
@@ -914,6 +1032,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)
@@ -1069,25 +1189,30 @@ 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;
        }
 
@@ -1247,7 +1372,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;
 
@@ -1308,7 +1433,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;
@@ -1992,7 +2117,7 @@ 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;
@@ -2520,6 +2645,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",
@@ -2563,6 +2692,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",
@@ -2630,7 +2763,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",
@@ -2836,7 +2984,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                        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;
@@ -2894,7 +3042,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        }
 
        /* FDI link */
-       if (IS_IRONLAKE(dev)) {
+       if (HAS_PCH_SPLIT(dev)) {
                int lane, link_bw, bpp;
                /* eDP doesn't require FDI link, so just set DP M/N
                   according to current link config */
@@ -2971,7 +3119,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;
@@ -3018,7 +3166,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)) {
@@ -3031,7 +3179,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)
@@ -3043,7 +3191,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;
@@ -3062,7 +3210,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) {
@@ -3096,7 +3244,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
@@ -3123,14 +3271,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;
        }
@@ -3151,7 +3299,7 @@ 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);
@@ -3173,12 +3321,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                /* set the dithering flag */
                if (IS_I965G(dev)) {
                        if (dev_priv->lvds_dither) {
-                               if (IS_IRONLAKE(dev))
+                               if (HAS_PCH_SPLIT(dev))
                                        pipeconf |= PIPE_ENABLE_DITHER;
                                else
                                        lvds |= LVDS_ENABLE_DITHER;
                        } else {
-                               if (IS_IRONLAKE(dev))
+                               if (HAS_PCH_SPLIT(dev))
                                        pipeconf &= ~PIPE_ENABLE_DITHER;
                                else
                                        lvds &= ~LVDS_ENABLE_DITHER;
@@ -3197,7 +3345,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) |
@@ -3244,14 +3392,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);
@@ -3307,7 +3455,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;
 
@@ -3422,11 +3570,10 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        intel_crtc->cursor_bo = bo;
 
        return 0;
-fail:
-       mutex_lock(&dev->struct_mutex);
 fail_locked:
-       drm_gem_object_unreference(bo);
        mutex_unlock(&dev->struct_mutex);
+fail:
+       drm_gem_object_unreference_unlocked(bo);
        return ret;
 }
 
@@ -3791,7 +3938,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)
@@ -3830,7 +3977,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)
@@ -3880,6 +4027,11 @@ static void intel_idle_update(struct work_struct *work)
 
        mutex_lock(&dev->struct_mutex);
 
+       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)
@@ -3913,9 +4065,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));
 
@@ -3927,6 +4087,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;
@@ -3950,7 +4118,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;
 };
@@ -3961,8 +4130,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);
 }
@@ -3985,6 +4155,12 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe)
        spin_lock_irqsave(&dev->event_lock, flags);
        work = intel_crtc->unpin_work;
        if (work == NULL || !work->pending) {
+               if (work && !work->pending) {
+                       obj_priv = work->pending_flip_obj->driver_private;
+                       DRM_DEBUG_DRIVER("flip finish: %p (%d) not pending?\n",
+                                        obj_priv,
+                                        atomic_read(&obj_priv->pending_flip));
+               }
                spin_unlock_irqrestore(&dev->event_lock, flags);
                return;
        }
@@ -4005,8 +4181,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 = work->pending_flip_obj->driver_private;
+
+       /* 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);
 }
@@ -4019,8 +4198,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);
 }
 
@@ -4036,7 +4218,8 @@ 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;
+       int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC;
+       int ret, pipesrc;
        RING_LOCALS;
 
        work = kzalloc(sizeof *work, GFP_KERNEL);
@@ -4048,12 +4231,13 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        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 */
        spin_lock_irqsave(&dev->event_lock, flags);
        if (intel_crtc->unpin_work) {
+               DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
                spin_unlock_irqrestore(&dev->event_lock, flags);
                kfree(work);
                mutex_unlock(&dev->struct_mutex);
@@ -4067,19 +4251,24 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
        ret = intel_pin_and_fence_fb_obj(dev, obj);
        if (ret != 0) {
+               DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n",
+                         obj->driver_private);
                kfree(work);
+               intel_crtc->unpin_work = NULL;
                mutex_unlock(&dev->struct_mutex);
                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;
        atomic_inc(&obj_priv->pending_flip);
+       work->pending_flip_obj = obj;
 
        BEGIN_LP_RING(4);
        OUT_RING(MI_DISPLAY_FLIP |
@@ -4087,7 +4276,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);
@@ -4229,7 +4419,7 @@ 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))
@@ -4298,7 +4488,7 @@ 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))
@@ -4323,9 +4513,7 @@ static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
                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);
 }
@@ -4388,9 +4576,7 @@ intel_user_framebuffer_create(struct drm_device *dev,
 
        ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj);
        if (ret) {
-               mutex_lock(&dev->struct_mutex);
-               drm_gem_object_unreference(obj);
-               mutex_unlock(&dev->struct_mutex);
+               drm_gem_object_unreference_unlocked(obj);
                return NULL;
        }
 
@@ -4438,6 +4624,91 @@ err_unref:
        return NULL;
 }
 
+void ironlake_enable_drps(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 rgvmodectl = I915_READ(MEMMODECTL), rgvswctl;
+       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;
+       vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
+               PXVFREQ_PX_SHIFT;
+
+       dev_priv->max_delay = fstart; /* can't go to fmax w/o IPS */
+       dev_priv->min_delay = fmin;
+       dev_priv->cur_delay = 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);
+
+       rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
+               (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
+       I915_WRITE(MEMSWCTL, rgvswctl);
+       POSTING_READ(MEMSWCTL);
+
+       rgvswctl |= MEMCTL_CMD_STS;
+       I915_WRITE(MEMSWCTL, rgvswctl);
+}
+
+void ironlake_disable_drps(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 rgvswctl;
+       u8 fstart;
+
+       /* 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 */
+       fstart = (I915_READ(MEMMODECTL) & MEMMODE_FSTART_MASK) >>
+               MEMMODE_FSTART_SHIFT;
+       rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
+               (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
+       I915_WRITE(MEMSWCTL, rgvswctl);
+       msleep(1);
+       rgvswctl |= MEMCTL_CMD_STS;
+       I915_WRITE(MEMSWCTL, rgvswctl);
+       msleep(1);
+
+}
+
 void intel_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4446,7 +4717,21 @@ 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);
                return;
        } else if (IS_G4X(dev)) {
                uint32_t dspclk_gate;
@@ -4519,7 +4804,7 @@ 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;
@@ -4562,7 +4847,7 @@ static void intel_init_display(struct drm_device *dev)
                        i830_get_display_clock_speed;
 
        /* For FIFO watermark updates */
-       if (IS_IRONLAKE(dev))
+       if (HAS_PCH_SPLIT(dev))
                dev_priv->display.update_wm = NULL;
        else if (IS_G4X(dev))
                dev_priv->display.update_wm = g4x_update_wm;
@@ -4621,11 +4906,6 @@ void intel_modeset_init(struct drm_device *dev)
        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);
-
        for (i = 0; i < num_pipe; i++) {
                intel_crtc_init(dev, i);
        }
@@ -4634,6 +4914,9 @@ void intel_modeset_init(struct drm_device *dev)
 
        intel_init_clock_gating(dev);
 
+       if (IS_IRONLAKE_M(dev))
+               ironlake_enable_drps(dev);
+
        INIT_WORK(&dev_priv->idle_work, intel_idle_update);
        setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
                    (unsigned long)dev);
@@ -4681,6 +4964,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
                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);