Merge branch 'drm-intel-fixes' into HEAD
[pandora-kernel.git] / drivers / gpu / drm / i915 / intel_display.c
index b5bf51a..1b5d878 100644 (file)
@@ -43,8 +43,8 @@
 
 bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
 static void intel_update_watermarks(struct drm_device *dev);
-static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule);
-static void intel_crtc_update_cursor(struct drm_crtc *crtc);
+static void intel_increase_pllclock(struct drm_crtc *crtc);
+static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
 
 typedef struct {
     /* given values */
@@ -342,6 +342,13 @@ static bool
 intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
                           int target, int refclk, intel_clock_t *best_clock);
 
+static inline u32 /* units of 100MHz */
+intel_fdi_link_freq(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       return (I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2;
+}
+
 static const intel_limit_t intel_limits_i8xx_dvo = {
         .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
         .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
@@ -744,20 +751,17 @@ static void intel_clock(struct drm_device *dev, int refclk, intel_clock_t *clock
 /**
  * Returns whether any output on the specified pipe is of the specified type
  */
-bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
+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_encoder *l_entry;
-
-    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_device *dev = crtc->dev;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
+
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+               if (encoder->base.crtc == crtc && encoder->type == type)
+                       return true;
+
+       return false;
 }
 
 #define INTELPllInvalid(s)   do { /* DRM_DEBUG(s); */ return false; } while (0)
@@ -955,26 +959,26 @@ static bool
 intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
                      int target, int refclk, intel_clock_t *best_clock)
 {
-    intel_clock_t clock;
-    if (target < 200000) {
-       clock.p1 = 2;
-       clock.p2 = 10;
-       clock.n = 2;
-       clock.m1 = 23;
-       clock.m2 = 8;
-    } else {
-       clock.p1 = 1;
-       clock.p2 = 10;
-       clock.n = 1;
-       clock.m1 = 14;
-       clock.m2 = 2;
-    }
-    clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
-    clock.p = (clock.p1 * clock.p2);
-    clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
-    clock.vco = 0;
-    memcpy(best_clock, &clock, sizeof(intel_clock_t));
-    return true;
+       intel_clock_t clock;
+       if (target < 200000) {
+               clock.p1 = 2;
+               clock.p2 = 10;
+               clock.n = 2;
+               clock.m1 = 23;
+               clock.m2 = 8;
+       } else {
+               clock.p1 = 1;
+               clock.p2 = 10;
+               clock.n = 1;
+               clock.m1 = 14;
+               clock.m2 = 2;
+       }
+       clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
+       clock.p = (clock.p1 * clock.p2);
+       clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
+       clock.vco = 0;
+       memcpy(best_clock, &clock, sizeof(intel_clock_t));
+       return true;
 }
 
 /**
@@ -1007,9 +1011,9 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
                   I915_READ(pipestat_reg) | PIPE_VBLANK_INTERRUPT_STATUS);
 
        /* Wait for vblank interrupt bit to set */
-       if (wait_for((I915_READ(pipestat_reg) &
-                     PIPE_VBLANK_INTERRUPT_STATUS),
-                    50, 0))
+       if (wait_for(I915_READ(pipestat_reg) &
+                    PIPE_VBLANK_INTERRUPT_STATUS,
+                    50))
                DRM_DEBUG_KMS("vblank wait timed out\n");
 }
 
@@ -1030,20 +1034,20 @@ void intel_wait_for_vblank_off(struct drm_device *dev, int pipe)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL);
        unsigned long timeout = jiffies + msecs_to_jiffies(100);
-       u32 last_line;
+       u32 last_line, line;
 
        /* Wait for the display line to settle */
+       line = I915_READ(pipedsl_reg) & DSL_LINEMASK;
        do {
-               last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK;
-               mdelay(5);
-       } while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) &&
-                time_after(timeout, jiffies));
+               last_line = line;
+               MSLEEP(5);
+               line = I915_READ(pipedsl_reg) & DSL_LINEMASK;
+       } while (line != last_line && time_after(timeout, jiffies));
 
-       if (time_after(jiffies, timeout))
+       if (line != last_line)
                DRM_DEBUG_KMS("vblank wait timed out\n");
 }
 
-/* Parameters have changed, update FBC info */
 static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 {
        struct drm_device *dev = crtc->dev;
@@ -1055,6 +1059,14 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        int plane, i;
        u32 fbc_ctl, fbc_ctl2;
 
+       if (fb->pitch == dev_priv->cfb_pitch &&
+           obj_priv->fence_reg == dev_priv->cfb_fence &&
+           intel_crtc->plane == dev_priv->cfb_plane &&
+           I915_READ(FBC_CONTROL) & FBC_CTL_EN)
+               return;
+
+       i8xx_disable_fbc(dev);
+
        dev_priv->cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
 
        if (fb->pitch < dev_priv->cfb_pitch)
@@ -1088,7 +1100,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        I915_WRITE(FBC_CONTROL, fbc_ctl);
 
        DRM_DEBUG_KMS("enabled FBC, pitch %ld, yoff %d, plane %d, ",
-                 dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
+                     dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
 }
 
 void i8xx_disable_fbc(struct drm_device *dev)
@@ -1096,19 +1108,13 @@ void i8xx_disable_fbc(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        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 */
-       if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) {
+       if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
                DRM_DEBUG_KMS("FBC idle timed out\n");
                return;
        }
@@ -1131,14 +1137,27 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
        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);
+       int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
        unsigned long stall_watermark = 200;
        u32 dpfc_ctl;
 
+       dpfc_ctl = I915_READ(DPFC_CONTROL);
+       if (dpfc_ctl & DPFC_CTL_EN) {
+               if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
+                   dev_priv->cfb_fence == obj_priv->fence_reg &&
+                   dev_priv->cfb_plane == intel_crtc->plane &&
+                   dev_priv->cfb_y == crtc->y)
+                       return;
+
+               I915_WRITE(DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
+               POSTING_READ(DPFC_CONTROL);
+               intel_wait_for_vblank(dev, intel_crtc->pipe);
+       }
+
        dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
        dev_priv->cfb_fence = obj_priv->fence_reg;
        dev_priv->cfb_plane = intel_crtc->plane;
+       dev_priv->cfb_y = crtc->y;
 
        dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
        if (obj_priv->tiling_mode != I915_TILING_NONE) {
@@ -1148,7 +1167,6 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
                I915_WRITE(DPFC_CHICKEN, ~DPFC_HT_MODIFY);
        }
 
-       I915_WRITE(DPFC_CONTROL, dpfc_ctl);
        I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
                   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
                   (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
@@ -1167,10 +1185,12 @@ void g4x_disable_fbc(struct drm_device *dev)
 
        /* Disable compression */
        dpfc_ctl = I915_READ(DPFC_CONTROL);
-       dpfc_ctl &= ~DPFC_CTL_EN;
-       I915_WRITE(DPFC_CONTROL, dpfc_ctl);
+       if (dpfc_ctl & DPFC_CTL_EN) {
+               dpfc_ctl &= ~DPFC_CTL_EN;
+               I915_WRITE(DPFC_CONTROL, dpfc_ctl);
 
-       DRM_DEBUG_KMS("disabled FBC\n");
+               DRM_DEBUG_KMS("disabled FBC\n");
+       }
 }
 
 static bool g4x_fbc_enabled(struct drm_device *dev)
@@ -1188,16 +1208,30 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
        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;
+       int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
        unsigned long stall_watermark = 200;
        u32 dpfc_ctl;
 
+       dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
+       if (dpfc_ctl & DPFC_CTL_EN) {
+               if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
+                   dev_priv->cfb_fence == obj_priv->fence_reg &&
+                   dev_priv->cfb_plane == intel_crtc->plane &&
+                   dev_priv->cfb_offset == obj_priv->gtt_offset &&
+                   dev_priv->cfb_y == crtc->y)
+                       return;
+
+               I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
+               POSTING_READ(ILK_DPFC_CONTROL);
+               intel_wait_for_vblank(dev, intel_crtc->pipe);
+       }
+
        dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
        dev_priv->cfb_fence = obj_priv->fence_reg;
        dev_priv->cfb_plane = intel_crtc->plane;
+       dev_priv->cfb_offset = obj_priv->gtt_offset;
+       dev_priv->cfb_y = crtc->y;
 
-       dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
        dpfc_ctl &= DPFC_RESERVED;
        dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
        if (obj_priv->tiling_mode != I915_TILING_NONE) {
@@ -1207,15 +1241,13 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
                I915_WRITE(ILK_DPFC_CHICKEN, ~DPFC_HT_MODIFY);
        }
 
-       I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
        I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
                   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
                   (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
        I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
        I915_WRITE(ILK_FBC_RT_BASE, obj_priv->gtt_offset | ILK_FBC_RT_VALID);
        /* enable it... */
-       I915_WRITE(ILK_DPFC_CONTROL, I915_READ(ILK_DPFC_CONTROL) |
-                  DPFC_CTL_EN);
+       I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 
        DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
 }
@@ -1227,10 +1259,12 @@ void ironlake_disable_fbc(struct drm_device *dev)
 
        /* Disable compression */
        dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
-       dpfc_ctl &= ~DPFC_CTL_EN;
-       I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+       if (dpfc_ctl & DPFC_CTL_EN) {
+               dpfc_ctl &= ~DPFC_CTL_EN;
+               I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
 
-       DRM_DEBUG_KMS("disabled FBC\n");
+               DRM_DEBUG_KMS("disabled FBC\n");
+       }
 }
 
 static bool ironlake_fbc_enabled(struct drm_device *dev)
@@ -1272,8 +1306,7 @@ void intel_disable_fbc(struct drm_device *dev)
 
 /**
  * intel_update_fbc - enable/disable FBC as needed
- * @crtc: CRTC to point the compressor at
- * @mode: mode in use
+ * @dev: the drm_device
  *
  * Set up the framebuffer compression hardware at mode set time.  We
  * enable it if possible:
@@ -1290,18 +1323,14 @@ void intel_disable_fbc(struct drm_device *dev)
  *
  * We need to enable/disable FBC on a global basis.
  */
-static void intel_update_fbc(struct drm_crtc *crtc,
-                            struct drm_display_mode *mode)
+static void intel_update_fbc(struct drm_device *dev)
 {
-       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_framebuffer *fb = crtc->fb;
+       struct drm_crtc *crtc = NULL, *tmp_crtc;
+       struct intel_crtc *intel_crtc;
+       struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
        struct drm_i915_gem_object *obj_priv;
-       struct drm_crtc *tmp_crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int plane = intel_crtc->plane;
-       int crtcs_enabled = 0;
 
        DRM_DEBUG_KMS("\n");
 
@@ -1311,12 +1340,6 @@ static void intel_update_fbc(struct drm_crtc *crtc,
        if (!I915_HAS_FBC(dev))
                return;
 
-       if (!crtc->fb)
-               return;
-
-       intel_fb = to_intel_framebuffer(fb);
-       obj_priv = to_intel_bo(intel_fb->obj);
-
        /*
         * If FBC is already on, we just have to verify that we can
         * keep it that way...
@@ -1327,35 +1350,47 @@ static void intel_update_fbc(struct drm_crtc *crtc,
         *   - going to an unsupported config (interlace, pixel multiply, etc.)
         */
        list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
-               if (tmp_crtc->enabled)
-                       crtcs_enabled++;
+               if (tmp_crtc->enabled) {
+                       if (crtc) {
+                               DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
+                               dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+                               goto out_disable;
+                       }
+                       crtc = tmp_crtc;
+               }
        }
-       DRM_DEBUG_KMS("%d pipes active\n", crtcs_enabled);
-       if (crtcs_enabled > 1) {
-               DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
-               dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+
+       if (!crtc || crtc->fb == NULL) {
+               DRM_DEBUG_KMS("no output, disabling\n");
+               dev_priv->no_fbc_reason = FBC_NO_OUTPUT;
                goto out_disable;
        }
+
+       intel_crtc = to_intel_crtc(crtc);
+       fb = crtc->fb;
+       intel_fb = to_intel_framebuffer(fb);
+       obj_priv = to_intel_bo(intel_fb->obj);
+
        if (intel_fb->obj->size > dev_priv->cfb_size) {
                DRM_DEBUG_KMS("framebuffer too large, disabling "
-                               "compression\n");
+                             "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)) {
+       if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
+           (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
                DRM_DEBUG_KMS("mode incompatible with compression, "
-                               "disabling\n");
+                             "disabling\n");
                dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
                goto out_disable;
        }
-       if ((mode->hdisplay > 2048) ||
-           (mode->vdisplay > 1536)) {
+       if ((crtc->mode.hdisplay > 2048) ||
+           (crtc->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) {
+       if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) {
                DRM_DEBUG_KMS("plane not 0, disabling compression\n");
                dev_priv->no_fbc_reason = FBC_BAD_PLANE;
                goto out_disable;
@@ -1370,18 +1405,7 @@ static void intel_update_fbc(struct drm_crtc *crtc,
        if (in_dbg_master())
                goto out_disable;
 
-       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) ||
-                   (obj_priv->fence_reg != dev_priv->cfb_fence) ||
-                   (plane != dev_priv->cfb_plane))
-                       intel_disable_fbc(dev);
-       }
-
-       /* Now try to turn it back on if possible */
-       if (!intel_fbc_enabled(dev))
-               intel_enable_fbc(crtc, 500);
-
+       intel_enable_fbc(crtc, 500);
        return;
 
 out_disable:
@@ -1393,7 +1417,9 @@ out_disable:
 }
 
 int
-intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
+intel_pin_and_fence_fb_obj(struct drm_device *dev,
+                          struct drm_gem_object *obj,
+                          bool pipelined)
 {
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        u32 alignment;
@@ -1421,9 +1447,13 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
        }
 
        ret = i915_gem_object_pin(obj, alignment);
-       if (ret != 0)
+       if (ret)
                return ret;
 
+       ret = i915_gem_object_set_to_display_plane(obj, pipelined);
+       if (ret)
+               goto err_unpin;
+
        /* Install a fence for tiled scan-out. Pre-i965 always needs a
         * fence, whereas 965+ only requires a fence if using
         * framebuffer compression.  For simplicity, we always install
@@ -1431,14 +1461,16 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
         */
        if (obj_priv->fence_reg == I915_FENCE_REG_NONE &&
            obj_priv->tiling_mode != I915_TILING_NONE) {
-               ret = i915_gem_object_get_fence_reg(obj);
-               if (ret != 0) {
-                       i915_gem_object_unpin(obj);
-                       return ret;
-               }
+               ret = i915_gem_object_get_fence_reg(obj, false);
+               if (ret)
+                       goto err_unpin;
        }
 
        return 0;
+
+err_unpin:
+       i915_gem_object_unpin(obj);
+       return ret;
 }
 
 /* Assume fb object is pinned & idle & fenced and just update base pointers */
@@ -1454,12 +1486,8 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        struct drm_gem_object *obj;
        int plane = intel_crtc->plane;
        unsigned long Start, Offset;
-       int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR);
-       int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF);
-       int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
-       int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF);
-       int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
        u32 dspcntr;
+       u32 reg;
 
        switch (plane) {
        case 0:
@@ -1474,7 +1502,8 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        obj = intel_fb->obj;
        obj_priv = to_intel_bo(obj);
 
-       dspcntr = I915_READ(dspcntr_reg);
+       reg = DSPCNTR(plane);
+       dspcntr = I915_READ(reg);
        /* Mask out pixel format bits in case we change it */
        dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
        switch (fb->bits_per_pixel) {
@@ -1506,28 +1535,24 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                /* must disable */
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
-       I915_WRITE(dspcntr_reg, dspcntr);
+       I915_WRITE(reg, dspcntr);
 
        Start = obj_priv->gtt_offset;
        Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
 
        DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
                      Start, Offset, x, y, fb->pitch);
-       I915_WRITE(dspstride, fb->pitch);
+       I915_WRITE(DSPSTRIDE(plane), fb->pitch);
        if (IS_I965G(dev)) {
-               I915_WRITE(dspsurf, Start);
-               I915_WRITE(dsptileoff, (y << 16) | x);
-               I915_WRITE(dspbase, Offset);
-       } else {
-               I915_WRITE(dspbase, Start + Offset);
-       }
-       POSTING_READ(dspbase);
-
-       if (IS_I965G(dev) || plane == 0)
-               intel_update_fbc(crtc, &crtc->mode);
+               I915_WRITE(DSPSURF(plane), Start);
+               I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
+               I915_WRITE(DSPADDR(plane), Offset);
+       } else
+               I915_WRITE(DSPADDR(plane), Start + Offset);
+       POSTING_READ(reg);
 
-       intel_wait_for_vblank(dev, intel_crtc->pipe);
-       intel_increase_pllclock(crtc, true);
+       intel_update_fbc(dev);
+       intel_increase_pllclock(crtc);
 
        return 0;
 }
@@ -1566,15 +1591,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        obj_priv = to_intel_bo(obj);
 
        mutex_lock(&dev->struct_mutex);
-       ret = intel_pin_and_fence_fb_obj(dev, obj);
-       if (ret != 0) {
-               mutex_unlock(&dev->struct_mutex);
-               return ret;
-       }
-
-       ret = i915_gem_object_set_to_display_plane(obj);
+       ret = intel_pin_and_fence_fb_obj(dev, obj, false);
        if (ret != 0) {
-               i915_gem_object_unpin(obj);
                mutex_unlock(&dev->struct_mutex);
                return ret;
        }
@@ -1612,7 +1630,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        return 0;
 }
 
-static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock)
+static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1645,6 +1663,7 @@ static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock)
        }
        I915_WRITE(DP_A, dpa_ctl);
 
+       POSTING_READ(DP_A);
        udelay(500);
 }
 
@@ -1655,84 +1674,84 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
        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;
+       u32 reg, temp, tries;
 
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
-       temp = I915_READ(fdi_rx_imr_reg);
+       reg = FDI_RX_IMR(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_RX_SYMBOL_LOCK;
        temp &= ~FDI_RX_BIT_LOCK;
-       I915_WRITE(fdi_rx_imr_reg, temp);
-       I915_READ(fdi_rx_imr_reg);
+       I915_WRITE(reg, temp);
+       I915_READ(reg);
        udelay(150);
 
        /* enable CPU FDI TX and PCH FDI RX */
-       temp = I915_READ(fdi_tx_reg);
-       temp |= FDI_TX_ENABLE;
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
        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);
+       I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
-       temp = I915_READ(fdi_rx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(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);
+       I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+       POSTING_READ(reg);
        udelay(150);
 
+       reg = FDI_RX_IIR(pipe);
        for (tries = 0; tries < 5; tries++) {
-               temp = I915_READ(fdi_rx_iir_reg);
+               temp = I915_READ(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);
+                       I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
                        break;
                }
        }
        if (tries == 5)
-               DRM_DEBUG_KMS("FDI train 1 fail!\n");
+               DRM_ERROR("FDI train 1 fail!\n");
 
        /* Train 2 */
-       temp = I915_READ(fdi_tx_reg);
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_LINK_TRAIN_NONE;
        temp |= FDI_LINK_TRAIN_PATTERN_2;
-       I915_WRITE(fdi_tx_reg, temp);
+       I915_WRITE(reg, temp);
 
-       temp = I915_READ(fdi_rx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_LINK_TRAIN_NONE;
        temp |= FDI_LINK_TRAIN_PATTERN_2;
-       I915_WRITE(fdi_rx_reg, temp);
-       udelay(150);
+       I915_WRITE(reg, temp);
 
-       tries = 0;
+       POSTING_READ(reg);
+       udelay(150);
 
+       reg = FDI_RX_IIR(pipe);
        for (tries = 0; tries < 5; tries++) {
-               temp = I915_READ(fdi_rx_iir_reg);
+               temp = I915_READ(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);
+                       I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
                        DRM_DEBUG_KMS("FDI train 2 done.\n");
                        break;
                }
        }
        if (tries == 5)
-               DRM_DEBUG_KMS("FDI train 2 fail!\n");
+               DRM_ERROR("FDI train 2 fail!\n");
 
        DRM_DEBUG_KMS("FDI train done\n");
 }
 
-static int snb_b_fdi_train_param [] = {
+static const int const 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,
@@ -1746,24 +1765,22 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        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;
+       u32 reg, temp, i;
 
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
-       temp = I915_READ(fdi_rx_imr_reg);
+       reg = FDI_RX_IMR(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_RX_SYMBOL_LOCK;
        temp &= ~FDI_RX_BIT_LOCK;
-       I915_WRITE(fdi_rx_imr_reg, temp);
-       I915_READ(fdi_rx_imr_reg);
+       I915_WRITE(reg, temp);
+
+       POSTING_READ(reg);
        udelay(150);
 
        /* enable CPU FDI TX and PCH FDI RX */
-       temp = I915_READ(fdi_tx_reg);
-       temp |= FDI_TX_ENABLE;
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~(7 << 19);
        temp |= (intel_crtc->fdi_lanes - 1) << 19;
        temp &= ~FDI_LINK_TRAIN_NONE;
@@ -1771,10 +1788,10 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        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);
+       I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
-       temp = I915_READ(fdi_rx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
        if (HAS_PCH_CPT(dev)) {
                temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
                temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
@@ -1782,32 +1799,37 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
                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);
+       I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+       POSTING_READ(reg);
        udelay(150);
 
        for (i = 0; i < 4; i++ ) {
-               temp = I915_READ(fdi_tx_reg);
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
                temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
                temp |= snb_b_fdi_train_param[i];
-               I915_WRITE(fdi_tx_reg, temp);
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
                udelay(500);
 
-               temp = I915_READ(fdi_rx_iir_reg);
+               reg = FDI_RX_IIR(pipe);
+               temp = I915_READ(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);
+                       I915_WRITE(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");
+               DRM_ERROR("FDI train 1 fail!\n");
 
        /* Train 2 */
-       temp = I915_READ(fdi_tx_reg);
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_LINK_TRAIN_NONE;
        temp |= FDI_LINK_TRAIN_PATTERN_2;
        if (IS_GEN6(dev)) {
@@ -1815,9 +1837,10 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
                /* SNB-B */
                temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
        }
-       I915_WRITE(fdi_tx_reg, temp);
+       I915_WRITE(reg, temp);
 
-       temp = I915_READ(fdi_rx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
        if (HAS_PCH_CPT(dev)) {
                temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
                temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
@@ -1825,535 +1848,595 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
                temp &= ~FDI_LINK_TRAIN_NONE;
                temp |= FDI_LINK_TRAIN_PATTERN_2;
        }
-       I915_WRITE(fdi_rx_reg, temp);
+       I915_WRITE(reg, temp);
+
+       POSTING_READ(reg);
        udelay(150);
 
        for (i = 0; i < 4; i++ ) {
-               temp = I915_READ(fdi_tx_reg);
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
                temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
                temp |= snb_b_fdi_train_param[i];
-               I915_WRITE(fdi_tx_reg, temp);
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
                udelay(500);
 
-               temp = I915_READ(fdi_rx_iir_reg);
+               reg = FDI_RX_IIR(pipe);
+               temp = I915_READ(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);
+                       I915_WRITE(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_ERROR("FDI train 2 fail!\n");
 
        DRM_DEBUG_KMS("FDI train done.\n");
 }
 
-static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
+static void ironlake_fdi_enable(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 plane = intel_crtc->plane;
-       int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
-       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-       int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-       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 transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
-       int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
-       int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
-       int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
-       int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
-       int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
-       int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
-       int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B;
-       int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B;
-       int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B;
-       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;
-       u32 pipe_bpc;
-
-       temp = I915_READ(pipeconf_reg);
-       pipe_bpc = temp & PIPE_BPC_MASK;
+       u32 reg, temp;
 
-       /* 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.
-        */
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-               DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
+       /* Write the TU size bits so error detection works */
+       I915_WRITE(FDI_RX_TUSIZE1(pipe),
+                  I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
 
-               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-                       temp = I915_READ(PCH_LVDS);
-                       if ((temp & LVDS_PORT_EN) == 0) {
-                               I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
-                               POSTING_READ(PCH_LVDS);
-                       }
-               }
+       /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~((0x7 << 19) | (0x7 << 16));
+       temp |= (intel_crtc->fdi_lanes - 1) << 19;
+       temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+       I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
 
-               if (!HAS_eDP) {
+       POSTING_READ(reg);
+       udelay(200);
 
-                       /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
-                       temp = I915_READ(fdi_rx_reg);
-                       /*
-                        * 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(reg);
+       I915_WRITE(reg, temp | FDI_PCDCLK);
 
-                       /* 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);
+       POSTING_READ(reg);
+       udelay(200);
 
-                       /* Enable CPU FDI TX PLL, always on for Ironlake */
-                       temp = I915_READ(fdi_tx_reg);
-                       if ((temp & FDI_TX_PLL_ENABLE) == 0) {
-                               I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
-                               I915_READ(fdi_tx_reg);
-                               udelay(100);
-                       }
-               }
+       /* Enable CPU FDI TX PLL, always on for Ironlake */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       if ((temp & FDI_TX_PLL_ENABLE) == 0) {
+               I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
 
-               /* Enable panel fitting for LVDS */
-               if (dev_priv->pch_pf_size &&
-                   (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)
-                   || HAS_eDP || intel_pch_has_edp(crtc))) {
-                       /* Force use of hard-coded filter coefficients
-                        * as some pre-programmed values are broken,
-                        * e.g. x201.
-                        */
-                       I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
-                                  PF_ENABLE | PF_FILTER_MED_3x3);
-                       I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
-                                  dev_priv->pch_pf_pos);
-                       I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
-                                  dev_priv->pch_pf_size);
-               }
+               POSTING_READ(reg);
+               udelay(100);
+       }
+}
 
-               /* Enable CPU pipe */
-               temp = I915_READ(pipeconf_reg);
-               if ((temp & PIPEACONF_ENABLE) == 0) {
-                       I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
-                       I915_READ(pipeconf_reg);
-                       udelay(100);
-               }
+static void intel_flush_display_plane(struct drm_device *dev,
+                                     int plane)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg = DSPADDR(plane);
+       I915_WRITE(reg, I915_READ(reg));
+}
 
-               /* configure and enable CPU plane */
-               temp = I915_READ(dspcntr_reg);
-               if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
-                       I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
-                       /* Flush the plane changes */
-                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-               }
+/*
+ * When we disable a pipe, we need to clear any pending scanline wait events
+ * to avoid hanging the ring, which we assume we are waiting on.
+ */
+static void intel_clear_scanline_wait(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 tmp;
 
-               if (!HAS_eDP) {
-                       /* For PCH output, training FDI link */
-                       if (IS_GEN6(dev))
-                               gen6_fdi_link_train(crtc);
-                       else
-                               ironlake_fdi_link_train(crtc);
+       if (IS_GEN2(dev))
+               /* Can't break the hang on i8xx */
+               return;
 
-                       /* 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);
-                       }
-                       udelay(200);
+       tmp = I915_READ(PRB0_CTL);
+       if (tmp & RING_WAIT) {
+               I915_WRITE(PRB0_CTL, tmp);
+               POSTING_READ(PRB0_CTL);
+       }
+}
 
-                       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);
-                       }
+static void ironlake_crtc_enable(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 plane = intel_crtc->plane;
+       u32 reg, temp;
 
-                       /* set transcoder timing */
-                       I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
-                       I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg));
-                       I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg));
-
-                       I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg));
-                       I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
-                       I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
-
-                       /* enable normal train */
-                       temp = I915_READ(fdi_tx_reg);
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
-                                       FDI_TX_ENHANCE_FRAME_ENABLE);
-                       I915_READ(fdi_tx_reg);
-
-                       temp = I915_READ(fdi_rx_reg);
-                       if (HAS_PCH_CPT(dev)) {
-                               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-                               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
-                       } else {
-                               temp &= ~FDI_LINK_TRAIN_NONE;
-                               temp |= FDI_LINK_TRAIN_NONE;
-                       }
-                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
-                       I915_READ(fdi_rx_reg);
+       if (intel_crtc->active)
+               return;
 
-                       /* wait one idle pattern time */
-                       udelay(100);
+       intel_crtc->active = true;
+       intel_update_watermarks(dev);
 
-                       /* 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 |
-                                        TRANS_DP_SYNC_MASK);
-                               reg |= (TRANS_DP_OUTPUT_ENABLE |
-                                       TRANS_DP_ENH_FRAMING);
-
-                               if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
-                                     reg |= TRANS_DP_HSYNC_ACTIVE_HIGH;
-                               if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
-                                     reg |= TRANS_DP_VSYNC_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;
-                               }
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+               temp = I915_READ(PCH_LVDS);
+               if ((temp & LVDS_PORT_EN) == 0)
+                       I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
+       }
 
-                               I915_WRITE(trans_dp_ctl, reg);
-                               POSTING_READ(trans_dp_ctl);
-                       }
+       ironlake_fdi_enable(crtc);
 
-                       /* 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);
+       /* Enable panel fitting for LVDS */
+       if (dev_priv->pch_pf_size &&
+           (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)
+            || HAS_eDP || intel_pch_has_edp(crtc))) {
+               /* Force use of hard-coded filter coefficients
+                * as some pre-programmed values are broken,
+                * e.g. x201.
+                */
+               I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
+                          PF_ENABLE | PF_FILTER_MED_3x3);
+               I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
+                          dev_priv->pch_pf_pos);
+               I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
+                          dev_priv->pch_pf_size);
+       }
+
+       /* Enable CPU pipe */
+       reg = PIPECONF(pipe);
+       temp = I915_READ(reg);
+       if ((temp & PIPECONF_ENABLE) == 0) {
+               I915_WRITE(reg, temp | PIPECONF_ENABLE);
+               POSTING_READ(reg);
+               udelay(100);
+       }
 
-                       if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100, 1))
-                               DRM_ERROR("failed to enable transcoder\n");
-               }
+       /* configure and enable CPU plane */
+       reg = DSPCNTR(plane);
+       temp = I915_READ(reg);
+       if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+               I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
+               intel_flush_display_plane(dev, plane);
+       }
 
-               intel_crtc_load_lut(crtc);
+       /* For PCH output, training FDI link */
+       if (IS_GEN6(dev))
+               gen6_fdi_link_train(crtc);
+       else
+               ironlake_fdi_link_train(crtc);
+
+       /* enable PCH DPLL */
+       reg = PCH_DPLL(pipe);
+       temp = I915_READ(reg);
+       if ((temp & DPLL_VCO_ENABLE) == 0) {
+               I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+               POSTING_READ(reg);
+               udelay(200);
+       }
 
-               intel_update_fbc(crtc, &crtc->mode);
-               break;
+       if (HAS_PCH_CPT(dev)) {
+               /* Be sure PCH DPLL SEL is set */
+               temp = I915_READ(PCH_DPLL_SEL);
+               if (pipe == 0 && (temp & TRANSA_DPLL_ENABLE) == 0)
+                       temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+               else if (pipe == 1 && (temp & TRANSB_DPLL_ENABLE) == 0)
+                       temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+               I915_WRITE(PCH_DPLL_SEL, temp);
+       }
 
-       case DRM_MODE_DPMS_OFF:
-               DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
+       /* set transcoder timing */
+       I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(pipe)));
+       I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(pipe)));
+       I915_WRITE(TRANS_HSYNC(pipe),  I915_READ(HSYNC(pipe)));
 
-               drm_vblank_off(dev, pipe);
-               /* Disable display plane */
-               temp = I915_READ(dspcntr_reg);
-               if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
-                       I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
-                       /* Flush the plane changes */
-                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-                       I915_READ(dspbase_reg);
+       I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe)));
+       I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
+       I915_WRITE(TRANS_VSYNC(pipe),  I915_READ(VSYNC(pipe)));
+
+       /* enable normal train */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+       I915_WRITE(reg, temp);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       if (HAS_PCH_CPT(dev)) {
+               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
+       } else {
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_NONE;
+       }
+       I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
+
+       /* wait one idle pattern time */
+       POSTING_READ(reg);
+       udelay(100);
+
+       /* For PCH DP, enable TRANS_DP_CTL */
+       if (HAS_PCH_CPT(dev) &&
+           intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+               reg = TRANS_DP_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~(TRANS_DP_PORT_SEL_MASK |
+                         TRANS_DP_SYNC_MASK);
+               temp |= (TRANS_DP_OUTPUT_ENABLE |
+                        TRANS_DP_ENH_FRAMING);
+
+               if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
+                       temp |= TRANS_DP_HSYNC_ACTIVE_HIGH;
+               if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
+                       temp |= TRANS_DP_VSYNC_ACTIVE_HIGH;
+
+               switch (intel_trans_dp_port_sel(crtc)) {
+               case PCH_DP_B:
+                       temp |= TRANS_DP_PORT_SEL_B;
+                       break;
+               case PCH_DP_C:
+                       temp |= TRANS_DP_PORT_SEL_C;
+                       break;
+               case PCH_DP_D:
+                       temp |= TRANS_DP_PORT_SEL_D;
+                       break;
+               default:
+                       DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
+                       temp |= TRANS_DP_PORT_SEL_B;
+                       break;
                }
 
-               if (dev_priv->cfb_plane == plane &&
-                   dev_priv->display.disable_fbc)
-                       dev_priv->display.disable_fbc(dev);
+               I915_WRITE(reg, temp);
+       }
 
-               /* disable cpu pipe, disable after all planes disabled */
-               temp = I915_READ(pipeconf_reg);
-               if ((temp & PIPEACONF_ENABLE) != 0) {
-                       I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+       /* enable PCH transcoder */
+       reg = TRANSCONF(pipe);
+       temp = I915_READ(reg);
+       /*
+        * make the BPC in transcoder be consistent with
+        * that in pipeconf reg.
+        */
+       temp &= ~PIPE_BPC_MASK;
+       temp |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK;
+       I915_WRITE(reg, temp | TRANS_ENABLE);
+       if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
+               DRM_ERROR("failed to enable transcoder\n");
 
-                       /* wait for cpu pipe off, pipe state */
-                       if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50, 1))
-                               DRM_ERROR("failed to turn off cpu pipe\n");
-               } else
-                       DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
+       intel_crtc_load_lut(crtc);
+       intel_update_fbc(dev);
+       intel_crtc_update_cursor(crtc, true);
+}
 
-               udelay(100);
+static void ironlake_crtc_disable(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 plane = intel_crtc->plane;
+       u32 reg, temp;
 
-               /* Disable PF */
-               I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0);
-               I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0);
+       if (!intel_crtc->active)
+               return;
 
-               /* disable CPU FDI tx and PCH FDI rx */
-               temp = I915_READ(fdi_tx_reg);
-               I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE);
-               I915_READ(fdi_tx_reg);
+       drm_vblank_off(dev, pipe);
+       intel_crtc_update_cursor(crtc, false);
 
-               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);
+       /* Disable display plane */
+       reg = DSPCNTR(plane);
+       temp = I915_READ(reg);
+       if (temp & DISPLAY_PLANE_ENABLE) {
+               I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
+               intel_flush_display_plane(dev, plane);
+       }
 
-               udelay(100);
+       if (dev_priv->cfb_plane == plane &&
+           dev_priv->display.disable_fbc)
+               dev_priv->display.disable_fbc(dev);
 
-               /* still set train pattern 1 */
-               temp = I915_READ(fdi_tx_reg);
+       /* disable cpu pipe, disable after all planes disabled */
+       reg = PIPECONF(pipe);
+       temp = I915_READ(reg);
+       if (temp & PIPECONF_ENABLE) {
+               I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
+               /* wait for cpu pipe off, pipe state */
+               if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0, 50))
+                       DRM_ERROR("failed to turn off cpu pipe\n");
+       }
+
+       /* Disable PF */
+       I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0);
+       I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0);
+
+       /* disable CPU FDI tx and PCH FDI rx */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_TX_ENABLE);
+       POSTING_READ(reg);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~(0x7 << 16);
+       temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+       I915_WRITE(reg, temp & ~FDI_RX_ENABLE);
+
+       POSTING_READ(reg);
+       udelay(100);
+
+       /* still set train pattern 1 */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_1;
+       I915_WRITE(reg, temp);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(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_tx_reg, temp);
-               POSTING_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);
-               POSTING_READ(fdi_rx_reg);
+       }
+       /* BPC in FDI rx is consistent with that in PIPECONF */
+       temp &= ~(0x07 << 16);
+       temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+       I915_WRITE(reg, temp);
 
-               udelay(100);
+       POSTING_READ(reg);
+       udelay(100);
 
-               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-                       temp = I915_READ(PCH_LVDS);
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+               temp = I915_READ(PCH_LVDS);
+               if (temp & LVDS_PORT_EN) {
                        I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN);
-                       I915_READ(PCH_LVDS);
+                       POSTING_READ(PCH_LVDS);
                        udelay(100);
                }
+       }
 
-               /* disable PCH transcoder */
-               temp = I915_READ(transconf_reg);
-               if ((temp & TRANS_ENABLE) != 0) {
-                       I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
+       /* disable PCH transcoder */
+       reg = TRANSCONF(plane);
+       temp = I915_READ(reg);
+       if (temp & TRANS_ENABLE) {
+               I915_WRITE(reg, temp & ~TRANS_ENABLE);
+               /* wait for PCH transcoder off, transcoder state */
+               if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
+                       DRM_ERROR("failed to disable transcoder\n");
+       }
 
-                       /* wait for PCH transcoder off, transcoder state */
-                       if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50, 1))
-                               DRM_ERROR("failed to disable transcoder\n");
-               }
+       if (HAS_PCH_CPT(dev)) {
+               /* disable TRANS_DP_CTL */
+               reg = TRANS_DP_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
+               I915_WRITE(reg, temp);
 
-               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);
+               /* disable DPLL_SEL */
+               temp = I915_READ(PCH_DPLL_SEL);
+               if (pipe == 0)
+                       temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
+               else
+                       temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+               I915_WRITE(PCH_DPLL_SEL, temp);
+       }
 
-               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;
+       /* disable PCH DPLL */
+       reg = PCH_DPLL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
 
-                       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);
+       /* Switch from PCDclk to Rawclk */
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_PCDCLK);
 
-                       /* 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 CPU FDI TX PLL */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE);
 
-               }
+       POSTING_READ(reg);
+       udelay(100);
 
-               /* disable PCH DPLL */
-               temp = I915_READ(pch_dpll_reg);
-               I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
-               I915_READ(pch_dpll_reg);
-
-               /* 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);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE);
+
+       /* Wait for the clocks to turn off. */
+       POSTING_READ(reg);
+       udelay(100);
+
+       intel_crtc->active = false;
+       intel_update_watermarks(dev);
+       intel_update_fbc(dev);
+       intel_clear_scanline_wait(dev);
+}
+
+static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+
+       /* 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.
+        */
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+               DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
+               ironlake_crtc_enable(crtc);
+               break;
+
+       case DRM_MODE_DPMS_OFF:
+               DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
+               ironlake_crtc_disable(crtc);
+               break;
+       }
+}
+
+static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
+{
+       if (!enable && intel_crtc->overlay) {
+               struct drm_device *dev = intel_crtc->base.dev;
+
+               mutex_lock(&dev->struct_mutex);
+               (void) intel_overlay_switch_off(intel_crtc->overlay, false);
+               mutex_unlock(&dev->struct_mutex);
+       }
+
+       /* Let userspace switch the overlay on again. In most cases userspace
+        * has to recompute where to put it anyway.
+        */
+}
+
+static void i9xx_crtc_enable(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 plane = intel_crtc->plane;
+       u32 reg, temp;
+
+       if (intel_crtc->active)
+               return;
+
+       intel_crtc->active = true;
+       intel_update_watermarks(dev);
+
+       /* Enable the DPLL */
+       reg = DPLL(pipe);
+       temp = I915_READ(reg);
+       if ((temp & DPLL_VCO_ENABLE) == 0) {
+               I915_WRITE(reg, temp);
+
+               /* Wait for the clocks to stabilize. */
+               POSTING_READ(reg);
+               udelay(150);
+
+               I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+
+               /* Wait for the clocks to stabilize. */
+               POSTING_READ(reg);
+               udelay(150);
 
-               temp = I915_READ(fdi_rx_reg);
-               temp &= ~FDI_RX_PLL_ENABLE;
-               I915_WRITE(fdi_rx_reg, temp);
-               I915_READ(fdi_rx_reg);
+               I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
 
-               /* Wait for the clocks to turn off. */
-               udelay(100);
-               break;
+               /* Wait for the clocks to stabilize. */
+               POSTING_READ(reg);
+               udelay(150);
        }
-}
-
-static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
-{
-       struct intel_overlay *overlay;
-       int ret;
 
-       if (!enable && intel_crtc->overlay) {
-               overlay = intel_crtc->overlay;
-               mutex_lock(&overlay->dev->struct_mutex);
-               for (;;) {
-                       ret = intel_overlay_switch_off(overlay);
-                       if (ret == 0)
-                               break;
+       /* Enable the pipe */
+       reg = PIPECONF(pipe);
+       temp = I915_READ(reg);
+       if ((temp & PIPECONF_ENABLE) == 0)
+               I915_WRITE(reg, temp | PIPECONF_ENABLE);
 
-                       ret = intel_overlay_recover_from_interrupt(overlay, 0);
-                       if (ret != 0) {
-                               /* overlay doesn't react anymore. Usually
-                                * results in a black screen and an unkillable
-                                * X server. */
-                               BUG();
-                               overlay->hw_wedged = HW_WEDGED;
-                               break;
-                       }
-               }
-               mutex_unlock(&overlay->dev->struct_mutex);
+       /* Enable the plane */
+       reg = DSPCNTR(plane);
+       temp = I915_READ(reg);
+       if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+               I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
+               intel_flush_display_plane(dev, plane);
        }
-       /* Let userspace switch the overlay on again. In most cases userspace
-        * has to recompute where to put it anyway. */
 
-       return;
+       intel_crtc_load_lut(crtc);
+       intel_update_fbc(dev);
+
+       /* Give the overlay scaler a chance to enable if it's on this pipe */
+       intel_crtc_dpms_overlay(intel_crtc, true);
+       intel_crtc_update_cursor(crtc, true);
 }
 
-static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
+static void i9xx_crtc_disable(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 plane = intel_crtc->plane;
-       int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
-       int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-       int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
-       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-       u32 temp;
-
-       /* 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.
-        */
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-               /* Enable the DPLL */
-               temp = I915_READ(dpll_reg);
-               if ((temp & DPLL_VCO_ENABLE) == 0) {
-                       I915_WRITE(dpll_reg, temp);
-                       I915_READ(dpll_reg);
-                       /* Wait for the clocks to stabilize. */
-                       udelay(150);
-                       I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
-                       I915_READ(dpll_reg);
-                       /* Wait for the clocks to stabilize. */
-                       udelay(150);
-                       I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
-                       I915_READ(dpll_reg);
-                       /* Wait for the clocks to stabilize. */
-                       udelay(150);
-               }
+       u32 reg, temp;
 
-               /* Enable the pipe */
-               temp = I915_READ(pipeconf_reg);
-               if ((temp & PIPEACONF_ENABLE) == 0)
-                       I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
-
-               /* Enable the plane */
-               temp = I915_READ(dspcntr_reg);
-               if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
-                       I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
-                       /* Flush the plane changes */
-                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-               }
+       if (!intel_crtc->active)
+               return;
 
-               intel_crtc_load_lut(crtc);
+       /* Give the overlay scaler a chance to disable if it's on this pipe */
+       intel_crtc_dpms_overlay(intel_crtc, false);
+       intel_crtc_update_cursor(crtc, false);
+       drm_vblank_off(dev, pipe);
 
-               if ((IS_I965G(dev) || plane == 0))
-                       intel_update_fbc(crtc, &crtc->mode);
+       if (dev_priv->cfb_plane == plane &&
+           dev_priv->display.disable_fbc)
+               dev_priv->display.disable_fbc(dev);
 
-               /* Give the overlay scaler a chance to enable if it's on this pipe */
-               intel_crtc_dpms_overlay(intel_crtc, true);
-       break;
-       case DRM_MODE_DPMS_OFF:
-               /* Give the overlay scaler a chance to disable if it's on this pipe */
-               intel_crtc_dpms_overlay(intel_crtc, false);
-               drm_vblank_off(dev, pipe);
-
-               if (dev_priv->cfb_plane == plane &&
-                   dev_priv->display.disable_fbc)
-                       dev_priv->display.disable_fbc(dev);
-
-               /* Disable display plane */
-               temp = I915_READ(dspcntr_reg);
-               if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
-                       I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
-                       /* Flush the plane changes */
-                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-                       I915_READ(dspbase_reg);
-               }
+       /* Disable display plane */
+       reg = DSPCNTR(plane);
+       temp = I915_READ(reg);
+       if (temp & DISPLAY_PLANE_ENABLE) {
+               I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
+               /* Flush the plane changes */
+               intel_flush_display_plane(dev, plane);
 
                /* Wait for vblank for the disable to take effect */
-               intel_wait_for_vblank_off(dev, pipe);
+               if (!IS_I9XX(dev))
+                       intel_wait_for_vblank_off(dev, pipe);
+       }
 
-               /* Don't disable pipe A or pipe A PLLs if needed */
-               if (pipeconf_reg == PIPEACONF &&
-                   (dev_priv->quirks & QUIRK_PIPEA_FORCE))
-                       goto skip_pipe_off;
+       /* Don't disable pipe A or pipe A PLLs if needed */
+       if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
+               goto done;
 
-               /* Next, disable display pipes */
-               temp = I915_READ(pipeconf_reg);
-               if ((temp & PIPEACONF_ENABLE) != 0) {
-                       I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
-                       I915_READ(pipeconf_reg);
-               }
+       /* Next, disable display pipes */
+       reg = PIPECONF(pipe);
+       temp = I915_READ(reg);
+       if (temp & PIPECONF_ENABLE) {
+               I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
 
                /* Wait for vblank for the disable to take effect. */
+               POSTING_READ(reg);
                intel_wait_for_vblank_off(dev, pipe);
+       }
+
+       reg = DPLL(pipe);
+       temp = I915_READ(reg);
+       if (temp & DPLL_VCO_ENABLE) {
+               I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
 
-               temp = I915_READ(dpll_reg);
-               if ((temp & DPLL_VCO_ENABLE) != 0) {
-                       I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
-                       I915_READ(dpll_reg);
-               }
-       skip_pipe_off:
                /* Wait for the clocks to turn off. */
+               POSTING_READ(reg);
                udelay(150);
+       }
+
+done:
+       intel_crtc->active = false;
+       intel_update_fbc(dev);
+       intel_update_watermarks(dev);
+       intel_clear_scanline_wait(dev);
+}
+
+static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       /* 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.
+        */
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+               i9xx_crtc_enable(crtc);
+               break;
+       case DRM_MODE_DPMS_OFF:
+               i9xx_crtc_disable(crtc);
                break;
        }
 }
@@ -2374,26 +2457,9 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
                return;
 
        intel_crtc->dpms_mode = mode;
-       intel_crtc->cursor_on = mode == DRM_MODE_DPMS_ON;
-
-       /* When switching on the display, ensure that SR is disabled
-        * with multiple pipes prior to enabling to new pipe.
-        *
-        * When switching off the display, make sure the cursor is
-        * properly hidden prior to disabling the pipe.
-        */
-       if (mode == DRM_MODE_DPMS_ON)
-               intel_update_watermarks(dev);
-       else
-               intel_crtc_update_cursor(crtc);
 
        dev_priv->display.dpms(crtc, mode);
 
-       if (mode == DRM_MODE_DPMS_ON)
-               intel_crtc_update_cursor(crtc);
-       else
-               intel_update_watermarks(dev);
-
        if (!dev->primary->master)
                return;
 
@@ -2418,16 +2484,32 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
        }
 }
 
-static void intel_crtc_prepare (struct drm_crtc *crtc)
+/* Prepare for a mode set.
+ *
+ * Note we could be a lot smarter here.  We need to figure out which outputs
+ * will be enabled, which disabled (in short, how the config will changes)
+ * and perform the minimum necessary steps to accomplish that, e.g. updating
+ * watermarks, FBC configuration, making sure PLLs are programmed correctly,
+ * panel fitting is in the proper state, etc.
+ */
+static void i9xx_crtc_prepare(struct drm_crtc *crtc)
 {
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+       i9xx_crtc_disable(crtc);
 }
 
-static void intel_crtc_commit (struct drm_crtc *crtc)
+static void i9xx_crtc_commit(struct drm_crtc *crtc)
 {
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+       i9xx_crtc_enable(crtc);
+}
+
+static void ironlake_crtc_prepare(struct drm_crtc *crtc)
+{
+       ironlake_crtc_disable(crtc);
+}
+
+static void ironlake_crtc_commit(struct drm_crtc *crtc)
+{
+       ironlake_crtc_enable(crtc);
 }
 
 void intel_encoder_prepare (struct drm_encoder *encoder)
@@ -2446,13 +2528,7 @@ void intel_encoder_commit (struct drm_encoder *encoder)
 
 void intel_encoder_destroy(struct drm_encoder *encoder)
 {
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-
-       if (intel_encoder->ddc_bus)
-               intel_i2c_destroy(intel_encoder->ddc_bus);
-
-       if (intel_encoder->i2c_bus)
-               intel_i2c_destroy(intel_encoder->i2c_bus);
+       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
 
        drm_encoder_cleanup(encoder);
        kfree(intel_encoder);
@@ -2543,33 +2619,6 @@ static int i830_get_display_clock_speed(struct drm_device *dev)
        return 133000;
 }
 
-/**
- * Return the pipe currently connected to the panel fitter,
- * or -1 if the panel fitter is not present or not in use
- */
-int intel_panel_fitter_pipe (struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32  pfit_control;
-
-       /* i830 doesn't have a panel fitter */
-       if (IS_I830(dev))
-               return -1;
-
-       pfit_control = I915_READ(PFIT_CONTROL);
-
-       /* See if the panel fitter is in use */
-       if ((pfit_control & PFIT_ENABLE) == 0)
-               return -1;
-
-       /* 965 can place panel fitter on either pipe */
-       if (IS_I965G(dev))
-               return (pfit_control >> 29) & 0x3;
-
-       /* older chips can only use pipe 1 */
-       return 1;
-}
-
 struct fdi_m_n {
        u32        tu;
        u32        gmch_m;
@@ -2888,7 +2937,7 @@ static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
                size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size;
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                       plane ? "B" : "A", size);
+                     plane ? "B" : "A", size);
 
        return size;
 }
@@ -2905,7 +2954,7 @@ static int i85x_get_fifo_size(struct drm_device *dev, int plane)
        size >>= 1; /* Convert to cachelines */
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                       plane ? "B" : "A", size);
+                     plane ? "B" : "A", size);
 
        return size;
 }
@@ -2920,8 +2969,8 @@ static int i845_get_fifo_size(struct drm_device *dev, int plane)
        size >>= 2; /* Convert to cachelines */
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                       plane ? "B" : "A",
-                 size);
+                     plane ? "B" : "A",
+                     size);
 
        return size;
 }
@@ -2936,14 +2985,14 @@ static int i830_get_fifo_size(struct drm_device *dev, int plane)
        size >>= 1; /* Convert to cachelines */
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                       plane ? "B" : "A", size);
+                     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 unused,
-                         int pixel_size)
+                              int planeb_clock, int sr_hdisplay, int unused,
+                              int pixel_size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        const struct cxsr_latency *latency;
@@ -3055,13 +3104,13 @@ static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
 
                /* Use ns/us then divide to preserve precision */
                sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                             pixel_size * sr_hdisplay;
+                       pixel_size * sr_hdisplay;
                sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
 
                entries_required = (((sr_latency_ns / line_time_us) +
                                     1000) / 1000) * pixel_size * 64;
                entries_required = DIV_ROUND_UP(entries_required,
-                                          g4x_cursor_wm_info.cacheline_size);
+                                               g4x_cursor_wm_info.cacheline_size);
                cursor_sr = entries_required + g4x_cursor_wm_info.guard_size;
 
                if (cursor_sr > g4x_cursor_wm_info.max_wm)
@@ -3073,7 +3122,7 @@ static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
        } else {
                /* Turn off self refresh if both pipes are enabled */
                I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
-                                       & ~FW_BLC_SELF_EN);
+                          & ~FW_BLC_SELF_EN);
        }
 
        DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n",
@@ -3111,7 +3160,7 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
 
                /* Use ns/us then divide to preserve precision */
                sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                             pixel_size * sr_hdisplay;
+                       pixel_size * sr_hdisplay;
                sr_entries = DIV_ROUND_UP(sr_entries, I915_FIFO_LINE_SIZE);
                DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
                srwm = I965_FIFO_SIZE - sr_entries;
@@ -3120,11 +3169,11 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
                srwm &= 0x1ff;
 
                sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                            pixel_size * 64;
+                       pixel_size * 64;
                sr_entries = DIV_ROUND_UP(sr_entries,
                                          i965_cursor_wm_info.cacheline_size);
                cursor_sr = i965_cursor_wm_info.fifo_size -
-                           (sr_entries + i965_cursor_wm_info.guard_size);
+                       (sr_entries + i965_cursor_wm_info.guard_size);
 
                if (cursor_sr > i965_cursor_wm_info.max_wm)
                        cursor_sr = i965_cursor_wm_info.max_wm;
@@ -3203,7 +3252,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
 
                /* Use ns/us then divide to preserve precision */
                sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                             pixel_size * sr_hdisplay;
+                       pixel_size * sr_hdisplay;
                sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
                DRM_DEBUG_KMS("self-refresh entries: %d\n", sr_entries);
                srwm = total_size - sr_entries;
@@ -3228,7 +3277,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
        }
 
        DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
-                 planea_wm, planeb_wm, cwm, srwm);
+                     planea_wm, planeb_wm, cwm, srwm);
 
        fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
        fwater_hi = (cwm & 0x1f);
@@ -3262,146 +3311,130 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused,
 #define ILK_LP0_PLANE_LATENCY          700
 #define ILK_LP0_CURSOR_LATENCY         1300
 
-static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
-                      int planeb_clock, int sr_hdisplay, int sr_htotal,
-                      int pixel_size)
+static bool ironlake_compute_wm0(struct drm_device *dev,
+                                int pipe,
+                                int *plane_wm,
+                                int *cursor_wm)
 {
-       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;
-       int line_count;
-       int planea_htotal = 0, planeb_htotal = 0;
        struct drm_crtc *crtc;
+       int htotal, hdisplay, clock, pixel_size = 0;
+       int line_time_us, line_count, entries;
 
-       /* Need htotal for all active display plane */
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-               if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) {
-                       if (intel_crtc->plane == 0)
-                               planea_htotal = crtc->mode.htotal;
-                       else
-                               planeb_htotal = crtc->mode.htotal;
-               }
-       }
-
-       /* 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;
-
-               /* Use the large buffer method to calculate cursor watermark */
-               line_time_us = (planea_htotal * 1000) / planea_clock;
-
-               /* Use ns/us then divide to preserve precision */
-               line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
-
-               /* calculate the cursor watermark for cursor A */
-               entries_required = line_count * 64 * pixel_size;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_cursor_wm_info.cacheline_size);
-               cursora_wm = entries_required + ironlake_cursor_wm_info.guard_size;
-               if (cursora_wm > ironlake_cursor_wm_info.max_wm)
-                       cursora_wm = ironlake_cursor_wm_info.max_wm;
-
-               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;
+       crtc = intel_get_crtc_for_pipe(dev, pipe);
+       if (crtc->fb == NULL || !crtc->enabled)
+               return false;
 
-               /* Use the large buffer method to calculate cursor watermark */
-               line_time_us = (planeb_htotal * 1000) / planeb_clock;
+       htotal = crtc->mode.htotal;
+       hdisplay = crtc->mode.hdisplay;
+       clock = crtc->mode.clock;
+       pixel_size = crtc->fb->bits_per_pixel / 8;
+
+       /* Use the small buffer method to calculate plane watermark */
+       entries = ((clock * pixel_size / 1000) * ILK_LP0_PLANE_LATENCY) / 1000;
+       entries = DIV_ROUND_UP(entries,
+                              ironlake_display_wm_info.cacheline_size);
+       *plane_wm = entries + ironlake_display_wm_info.guard_size;
+       if (*plane_wm > (int)ironlake_display_wm_info.max_wm)
+               *plane_wm = ironlake_display_wm_info.max_wm;
+
+       /* Use the large buffer method to calculate cursor watermark */
+       line_time_us = ((htotal * 1000) / clock);
+       line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+       entries = line_count * 64 * pixel_size;
+       entries = DIV_ROUND_UP(entries,
+                              ironlake_cursor_wm_info.cacheline_size);
+       *cursor_wm = entries + ironlake_cursor_wm_info.guard_size;
+       if (*cursor_wm > ironlake_cursor_wm_info.max_wm)
+               *cursor_wm = ironlake_cursor_wm_info.max_wm;
 
-               /* Use ns/us then divide to preserve precision */
-               line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+       return true;
+}
 
-               /* calculate the cursor watermark for cursor B */
-               entries_required = line_count * 64 * pixel_size;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_cursor_wm_info.cacheline_size);
-               cursorb_wm = entries_required + ironlake_cursor_wm_info.guard_size;
-               if (cursorb_wm > ironlake_cursor_wm_info.max_wm)
-                       cursorb_wm = ironlake_cursor_wm_info.max_wm;
+static void ironlake_update_wm(struct drm_device *dev,
+                              int planea_clock, int planeb_clock,
+                              int sr_hdisplay, int sr_htotal,
+                              int pixel_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int plane_wm, cursor_wm, enabled;
+       int tmp;
+
+       enabled = 0;
+       if (ironlake_compute_wm0(dev, 0, &plane_wm, &cursor_wm)) {
+               I915_WRITE(WM0_PIPEA_ILK,
+                          (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+               DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
+                             " plane %d, " "cursor: %d\n",
+                             plane_wm, cursor_wm);
+               enabled++;
+       }
 
-               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);
+       if (ironlake_compute_wm0(dev, 1, &plane_wm, &cursor_wm)) {
+               I915_WRITE(WM0_PIPEB_ILK,
+                          (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+               DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
+                             " plane %d, cursor: %d\n",
+                             plane_wm, cursor_wm);
+               enabled++;
        }
 
        /*
         * Calculate and update the self-refresh watermark only when one
         * display plane is used.
         */
-       if (!planea_clock || !planeb_clock) {
-
+       tmp = 0;
+       if (enabled == 1 && /* XXX disabled due to buggy implmentation? */ 0) {
+               unsigned long line_time_us;
+               int small, large, plane_fbc;
+               int sr_clock, entries;
+               int line_count, line_size;
                /* 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_htotal * 1000) / sr_clock);
+               line_time_us = (sr_htotal * 1000) / sr_clock;
 
                /* Use ns/us then divide to preserve precision */
                line_count = ((ilk_sr_latency * 500) / line_time_us + 1000)
-                              / 1000;
+                       / 1000;
+               line_size = sr_hdisplay * pixel_size;
 
-               /* 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;
+               /* Use the minimum of the small and large buffer method for primary */
+               small = ((sr_clock * pixel_size / 1000) * (ilk_sr_latency * 500)) / 1000;
+               large = line_count * line_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;
+               entries = DIV_ROUND_UP(min(small, large),
+                                      ironlake_display_srwm_info.cacheline_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 |= (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
-                            (sr_wm << WM1_LP_SR_SHIFT) | cursor_wm;
+               plane_fbc = entries * 64;
+               plane_fbc = DIV_ROUND_UP(plane_fbc, line_size);
 
-               I915_WRITE(WM1_LP_ILK, reg_value);
-               DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
-                               "cursor %d\n", sr_wm, cursor_wm);
+               plane_wm = entries + ironlake_display_srwm_info.guard_size;
+               if (plane_wm > (int)ironlake_display_srwm_info.max_wm)
+                       plane_wm = ironlake_display_srwm_info.max_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);
-       }
+               /* calculate the self-refresh watermark for display cursor */
+               entries = line_count * pixel_size * 64;
+               entries = DIV_ROUND_UP(entries,
+                                      ironlake_cursor_srwm_info.cacheline_size);
+
+               cursor_wm = entries + ironlake_cursor_srwm_info.guard_size;
+               if (cursor_wm > (int)ironlake_cursor_srwm_info.max_wm)
+                       cursor_wm = ironlake_cursor_srwm_info.max_wm;
+
+               /* configure watermark and enable self-refresh */
+               tmp = (WM1_LP_SR_EN |
+                      (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
+                      (plane_fbc << WM1_LP_FBC_SHIFT) |
+                      (plane_wm << WM1_LP_SR_SHIFT) |
+                      cursor_wm);
+               DRM_DEBUG_KMS("self-refresh watermark: display plane %d, fbc lines %d,"
+                             " cursor %d\n", plane_wm, plane_fbc, cursor_wm);
+       }
+       I915_WRITE(WM1_LP_ILK, tmp);
+       /* XXX setup WM2 and WM3 */
 }
+
 /**
  * intel_update_watermarks - update FIFO watermark values based on current modes
  *
@@ -3433,7 +3466,7 @@ static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
  *
  * We don't use the sprite, so we can ignore that.  And on Crestline we have
  * to set the non-SR watermarks to 8.
 */
+ */
 static void intel_update_watermarks(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3449,15 +3482,15 @@ static void intel_update_watermarks(struct drm_device *dev)
        /* Get the clock config from both planes */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-               if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) {
+               if (intel_crtc->active) {
                        enabled++;
                        if (intel_crtc->plane == 0) {
                                DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n",
-                                         intel_crtc->pipe, crtc->mode.clock);
+                                             intel_crtc->pipe, crtc->mode.clock);
                                planea_clock = crtc->mode.clock;
                        } else {
                                DRM_DEBUG_KMS("plane B (pipe %d) clock: %d\n",
-                                         intel_crtc->pipe, crtc->mode.clock);
+                                             intel_crtc->pipe, crtc->mode.clock);
                                planeb_clock = crtc->mode.clock;
                        }
                        sr_hdisplay = crtc->mode.hdisplay;
@@ -3488,62 +3521,35 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
-       int fp_reg = (pipe == 0) ? FPA0 : FPB0;
-       int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
-       int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
-       int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-       int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
-       int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
-       int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
-       int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
-       int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
-       int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
-       int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE;
-       int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS;
-       int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
+       u32 fp_reg, dpll_reg;
        int refclk, num_connectors = 0;
        intel_clock_t clock, reduced_clock;
-       u32 dpll = 0, fp = 0, fp2 = 0, dspcntr, pipeconf;
+       u32 dpll, 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;
        struct intel_encoder *has_edp_encoder = NULL;
        struct drm_mode_config *mode_config = &dev->mode_config;
-       struct drm_encoder *encoder;
+       struct intel_encoder *encoder;
        const intel_limit_t *limit;
        int ret;
        struct fdi_m_n m_n = {0};
-       int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1;
-       int data_n1_reg = (pipe == 0) ? PIPEA_DATA_N1 : PIPEB_DATA_N1;
-       int link_m1_reg = (pipe == 0) ? PIPEA_LINK_M1 : PIPEB_LINK_M1;
-       int link_n1_reg = (pipe == 0) ? PIPEA_LINK_N1 : PIPEB_LINK_N1;
-       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;
+       u32 reg, temp;
        int target_clock;
 
        drm_vblank_pre_modeset(dev, pipe);
 
-       list_for_each_entry(encoder, &mode_config->encoder_list, head) {
-               struct intel_encoder *intel_encoder;
-
-               if (encoder->crtc != crtc)
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               if (encoder->base.crtc != crtc)
                        continue;
 
-               intel_encoder = enc_to_intel_encoder(encoder);
-               switch (intel_encoder->type) {
+               switch (encoder->type) {
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
                        break;
                case INTEL_OUTPUT_SDVO:
                case INTEL_OUTPUT_HDMI:
                        is_sdvo = true;
-                       if (intel_encoder->needs_tv_clock)
+                       if (encoder->needs_tv_clock)
                                is_tv = true;
                        break;
                case INTEL_OUTPUT_DVO:
@@ -3559,7 +3565,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        is_dp = true;
                        break;
                case INTEL_OUTPUT_EDP:
-                       has_edp_encoder = intel_encoder;
+                       has_edp_encoder = encoder;
                        break;
                }
 
@@ -3569,7 +3575,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        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);
+                             refclk / 1000);
        } else if (IS_I9XX(dev)) {
                refclk = 96000;
                if (HAS_PCH_SPLIT(dev))
@@ -3577,7 +3583,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        } else {
                refclk = 48000;
        }
-       
 
        /*
         * Returns a set of divisors for the desired target clock with the given
@@ -3593,13 +3598,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        }
 
        /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc);
+       intel_crtc_update_cursor(crtc, true);
 
        if (is_lvds && dev_priv->lvds_downclock_avail) {
                has_reduced_clock = limit->find_pll(limit, crtc,
-                                                           dev_priv->lvds_downclock,
-                                                           refclk,
-                                                           &reduced_clock);
+                                                   dev_priv->lvds_downclock,
+                                                   refclk,
+                                                   &reduced_clock);
                if (has_reduced_clock && (clock.p != reduced_clock.p)) {
                        /*
                         * If the different P is found, it means that we can't
@@ -3608,7 +3613,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                         * feature.
                         */
                        DRM_DEBUG_KMS("Different P is found for "
-                                               "LVDS clock/downclock\n");
+                                     "LVDS clock/downclock\n");
                        has_reduced_clock = 0;
                }
        }
@@ -3616,14 +3621,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
           this mirrors vbios setting. */
        if (is_sdvo && is_tv) {
                if (adjusted_mode->clock >= 100000
-                               && adjusted_mode->clock < 140500) {
+                   && adjusted_mode->clock < 140500) {
                        clock.p1 = 2;
                        clock.p2 = 10;
                        clock.n = 3;
                        clock.m1 = 16;
                        clock.m2 = 8;
                } else if (adjusted_mode->clock >= 140500
-                               && adjusted_mode->clock <= 200000) {
+                          && adjusted_mode->clock <= 200000) {
                        clock.p1 = 1;
                        clock.p2 = 10;
                        clock.n = 6;
@@ -3648,16 +3653,23 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                target_clock = mode->clock;
                        else
                                target_clock = adjusted_mode->clock;
-                       link_bw = 270000;
+
+                       /* FDI is a binary signal running at ~2.7GHz, encoding
+                        * each output octet as 10 bits. The actual frequency
+                        * is stored as a divider into a 100MHz clock, and the
+                        * mode pixel clock is stored in units of 1KHz.
+                        * Hence the bw of each lane in terms of the mode signal
+                        * is:
+                        */
+                       link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
                }
 
                /* determine panel color depth */
-               temp = I915_READ(pipeconf_reg);
+               temp = I915_READ(PIPECONF(pipe));
                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)
+                       if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
                                temp |= PIPE_8BPC;
                        else
                                temp |= PIPE_6BPC;
@@ -3678,8 +3690,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        }
                } else
                        temp |= PIPE_8BPC;
-               I915_WRITE(pipeconf_reg, temp);
-               I915_READ(pipeconf_reg);
+               I915_WRITE(PIPECONF(pipe), temp);
 
                switch (temp & PIPE_BPC_MASK) {
                case PIPE_8BPC:
@@ -3724,33 +3735,27 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                /* Always enable nonspread source */
                temp &= ~DREF_NONSPREAD_SOURCE_MASK;
                temp |= DREF_NONSPREAD_SOURCE_ENABLE;
-               I915_WRITE(PCH_DREF_CONTROL, temp);
-               POSTING_READ(PCH_DREF_CONTROL);
-
                temp &= ~DREF_SSC_SOURCE_MASK;
                temp |= DREF_SSC_SOURCE_ENABLE;
                I915_WRITE(PCH_DREF_CONTROL, temp);
-               POSTING_READ(PCH_DREF_CONTROL);
 
+               POSTING_READ(PCH_DREF_CONTROL);
                udelay(200);
 
                if (has_edp_encoder) {
                        if (dev_priv->lvds_use_ssc) {
                                temp |= DREF_SSC1_ENABLE;
                                I915_WRITE(PCH_DREF_CONTROL, temp);
-                               POSTING_READ(PCH_DREF_CONTROL);
 
+                               POSTING_READ(PCH_DREF_CONTROL);
                                udelay(200);
 
                                temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
                                temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
-                               I915_WRITE(PCH_DREF_CONTROL, temp);
-                               POSTING_READ(PCH_DREF_CONTROL);
                        } else {
                                temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
-                               I915_WRITE(PCH_DREF_CONTROL, temp);
-                               POSTING_READ(PCH_DREF_CONTROL);
                        }
+                       I915_WRITE(PCH_DREF_CONTROL, temp);
                }
        }
 
@@ -3766,6 +3771,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                reduced_clock.m2;
        }
 
+       dpll = 0;
        if (!HAS_PCH_SPLIT(dev))
                dpll = DPLL_VGA_MODE_DIS;
 
@@ -3775,12 +3781,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                else
                        dpll |= DPLLB_MODE_DAC_SERIAL;
                if (is_sdvo) {
+                       int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+                       if (pixel_multiplier > 1) {
+                               if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+                                       dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
+                               else if (HAS_PCH_SPLIT(dev))
+                                       dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+                       }
                        dpll |= DPLL_DVO_HIGH_SPEED;
-                       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 (HAS_PCH_SPLIT(dev))
-                               dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
                }
                if (is_dp)
                        dpll |= DPLL_DVO_HIGH_SPEED;
@@ -3837,7 +3845,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                dpll |= PLL_REF_INPUT_DREFCLK;
 
        /* setup pipeconf */
-       pipeconf = I915_READ(pipeconf_reg);
+       pipeconf = I915_READ(PIPECONF(pipe));
 
        /* Set up the display plane register */
        dspcntr = DISPPLANE_GAMMA_ENABLE;
@@ -3860,51 +3868,46 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                 */
                if (mode->clock >
                    dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
-                       pipeconf |= PIPEACONF_DOUBLE_WIDE;
+                       pipeconf |= PIPECONF_DOUBLE_WIDE;
                else
-                       pipeconf &= ~PIPEACONF_DOUBLE_WIDE;
+                       pipeconf &= ~PIPECONF_DOUBLE_WIDE;
        }
 
        dspcntr |= DISPLAY_PLANE_ENABLE;
-       pipeconf |= PIPEACONF_ENABLE;
+       pipeconf |= PIPECONF_ENABLE;
        dpll |= DPLL_VCO_ENABLE;
 
-
-       /* Disable the panel fitter if it was on our 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 (HAS_PCH_SPLIT(dev)) {
-               fp_reg = pch_fp_reg;
-               dpll_reg = pch_dpll_reg;
+               fp_reg = PCH_FP0(pipe);
+               dpll_reg = PCH_DPLL(pipe);
+       } else {
+               fp_reg = FP0(pipe);
+               dpll_reg = DPLL(pipe);
        }
 
        if (!has_edp_encoder) {
                I915_WRITE(fp_reg, fp);
                I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
-               I915_READ(dpll_reg);
+
+               POSTING_READ(dpll_reg);
                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);
+               if (pipe == 0)
+                       temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL;
                else
-                       temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+                       temp |= TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL;
                I915_WRITE(PCH_DPLL_SEL, temp);
-               I915_READ(PCH_DPLL_SEL);
-               udelay(150);
-       }
 
-       if (HAS_PCH_SPLIT(dev)) {
-               pipeconf &= ~PIPE_ENABLE_DITHER;
-               pipeconf &= ~PIPE_DITHER_TYPE_MASK;
+               POSTING_READ(PCH_DPLL_SEL);
+               udelay(150);
        }
 
        /* The LVDS pin pair needs to be on before the DPLLs are enabled.
@@ -3912,55 +3915,57 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
         * things on.
         */
        if (is_lvds) {
-               u32 lvds;
-
+               reg = LVDS;
                if (HAS_PCH_SPLIT(dev))
-                       lvds_reg = PCH_LVDS;
+                       reg = PCH_LVDS;
 
-               lvds = I915_READ(lvds_reg);
-               lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+               temp = I915_READ(reg);
+               temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
                if (pipe == 1) {
                        if (HAS_PCH_CPT(dev))
-                               lvds |= PORT_TRANS_B_SEL_CPT;
+                               temp |= PORT_TRANS_B_SEL_CPT;
                        else
-                               lvds |= LVDS_PIPEB_SELECT;
+                               temp |= LVDS_PIPEB_SELECT;
                } else {
                        if (HAS_PCH_CPT(dev))
-                               lvds &= ~PORT_TRANS_SEL_MASK;
+                               temp &= ~PORT_TRANS_SEL_MASK;
                        else
-                               lvds &= ~LVDS_PIPEB_SELECT;
+                               temp &= ~LVDS_PIPEB_SELECT;
                }
                /* set the corresponsding LVDS_BORDER bit */
-               lvds |= dev_priv->lvds_border_bits;
+               temp |= dev_priv->lvds_border_bits;
                /* Set the B0-B3 data pairs corresponding to whether we're going to
                 * set the DPLLs for dual-channel mode or not.
                 */
                if (clock.p2 == 7)
-                       lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+                       temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
                else
-                       lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
+                       temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
 
                /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
                 * 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)) {
-                                       lvds &= ~LVDS_ENABLE_DITHER;
-                               }
-                       }
+               /* set the dithering flag on non-PCH LVDS as needed */
+               if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+                       if (dev_priv->lvds_dither)
+                               temp |= LVDS_ENABLE_DITHER;
+                       else
+                               temp &= ~LVDS_ENABLE_DITHER;
+               }
+               I915_WRITE(reg, temp);
+       }
+
+       /* set the dithering flag and clear for anything other than a panel. */
+       if (HAS_PCH_SPLIT(dev)) {
+               pipeconf &= ~PIPECONF_DITHER_EN;
+               pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
+               if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) {
+                       pipeconf |= PIPECONF_DITHER_EN;
+                       pipeconf |= PIPECONF_DITHER_TYPE_ST1;
                }
-               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)) {
@@ -3981,26 +3986,32 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        if (!has_edp_encoder) {
                I915_WRITE(fp_reg, fp);
                I915_WRITE(dpll_reg, dpll);
-               I915_READ(dpll_reg);
+
                /* Wait for the clocks to stabilize. */
+               POSTING_READ(dpll_reg);
                udelay(150);
 
                if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+                       temp = 0;
                        if (is_sdvo) {
-                               sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
-                               I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
-                                       ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
-                       } else
-                               I915_WRITE(dpll_md_reg, 0);
+                               temp = intel_mode_get_pixel_multiplier(adjusted_mode);
+                               if (temp > 1)
+                                       temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+                               else
+                                       temp = 0;
+                       }
+                       I915_WRITE(DPLL_MD(pipe), temp);
                } else {
                        /* write it again -- the BIOS does, after all */
                        I915_WRITE(dpll_reg, dpll);
                }
-               I915_READ(dpll_reg);
+
                /* Wait for the clocks to stabilize. */
+               POSTING_READ(dpll_reg);
                udelay(150);
        }
 
+       intel_crtc->lowfreq_avail = false;
        if (is_lvds && has_reduced_clock && i915_powersave) {
                I915_WRITE(fp_reg + 4, fp2);
                intel_crtc->lowfreq_avail = true;
@@ -4010,7 +4021,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                }
        } else {
                I915_WRITE(fp_reg + 4, fp);
-               intel_crtc->lowfreq_avail = false;
                if (HAS_PIPE_CXSR(dev)) {
                        DRM_DEBUG_KMS("disabling CxSR downclocking\n");
                        pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
@@ -4029,58 +4039,72 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        } else
                pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */
 
-       I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+       I915_WRITE(HTOTAL(pipe),
+                  (adjusted_mode->crtc_hdisplay - 1) |
                   ((adjusted_mode->crtc_htotal - 1) << 16));
-       I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+       I915_WRITE(HBLANK(pipe),
+                  (adjusted_mode->crtc_hblank_start - 1) |
                   ((adjusted_mode->crtc_hblank_end - 1) << 16));
-       I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+       I915_WRITE(HSYNC(pipe),
+                  (adjusted_mode->crtc_hsync_start - 1) |
                   ((adjusted_mode->crtc_hsync_end - 1) << 16));
-       I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+
+       I915_WRITE(VTOTAL(pipe),
+                  (adjusted_mode->crtc_vdisplay - 1) |
                   ((adjusted_mode->crtc_vtotal - 1) << 16));
-       I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+       I915_WRITE(VBLANK(pipe),
+                  (adjusted_mode->crtc_vblank_start - 1) |
                   ((adjusted_mode->crtc_vblank_end - 1) << 16));
-       I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+       I915_WRITE(VSYNC(pipe),
+                  (adjusted_mode->crtc_vsync_start - 1) |
                   ((adjusted_mode->crtc_vsync_end - 1) << 16));
-       /* pipesrc and dspsize control the size that is scaled from, which should
-        * always be the user's requested size.
+
+       /* pipesrc and dspsize control the size that is scaled from,
+        * which should always be the user's requested size.
         */
        if (!HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) |
-                               (mode->hdisplay - 1));
-               I915_WRITE(dsppos_reg, 0);
+               I915_WRITE(DSPSIZE(plane),
+                          ((mode->vdisplay - 1) << 16) |
+                          (mode->hdisplay - 1));
+               I915_WRITE(DSPPOS(plane), 0);
        }
-       I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+       I915_WRITE(PIPESRC(pipe),
+                  ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
 
        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);
-               I915_WRITE(link_n1_reg, m_n.link_n);
+               I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
+               I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
+               I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
+               I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
 
                if (has_edp_encoder) {
                        ironlake_set_pll_edp(crtc, adjusted_mode->clock);
                } else {
                        /* 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);
+                       reg = FDI_RX_CTL(pipe);
+                       temp = I915_READ(reg);
+                       I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
+
+                       POSTING_READ(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);
+                       reg = FDI_TX_CTL(pipe);
+                       temp = I915_READ(reg);
+                       I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
 
                        /* enable FDI RX PCDCLK */
-                       temp = I915_READ(fdi_rx_reg);
-                       I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
-                       I915_READ(fdi_rx_reg);
+                       reg = FDI_RX_CTL(pipe);
+                       temp = I915_READ(reg);
+                       I915_WRITE(reg, temp | FDI_PCDCLK);
+
+                       POSTING_READ(reg);
                        udelay(200);
                }
        }
 
-       I915_WRITE(pipeconf_reg, pipeconf);
-       I915_READ(pipeconf_reg);
+       I915_WRITE(PIPECONF(pipe), pipeconf);
+       POSTING_READ(PIPECONF(pipe));
 
        intel_wait_for_vblank(dev, pipe);
 
@@ -4090,9 +4114,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
        }
 
-       I915_WRITE(dspcntr_reg, dspcntr);
+       I915_WRITE(DSPCNTR(plane), dspcntr);
 
-       /* Flush the plane changes */
        ret = intel_pipe_set_base(crtc, x, y, old_fb);
 
        intel_update_watermarks(dev);
@@ -4185,7 +4208,8 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
 }
 
 /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
-static void intel_crtc_update_cursor(struct drm_crtc *crtc)
+static void intel_crtc_update_cursor(struct drm_crtc *crtc,
+                                    bool on)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4198,7 +4222,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc)
 
        pos = 0;
 
-       if (intel_crtc->cursor_on && crtc->fb) {
+       if (on && crtc->enabled && crtc->fb) {
                base = intel_crtc->cursor_addr;
                if (x > (int) crtc->fb->width)
                        base = 0;
@@ -4330,7 +4354,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        intel_crtc->cursor_width = width;
        intel_crtc->cursor_height = height;
 
-       intel_crtc_update_cursor(crtc);
+       intel_crtc_update_cursor(crtc, true);
 
        return 0;
 fail_unpin:
@@ -4349,7 +4373,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        intel_crtc->cursor_x = x;
        intel_crtc->cursor_y = y;
 
-       intel_crtc_update_cursor(crtc);
+       intel_crtc_update_cursor(crtc, true);
 
        return 0;
 }
@@ -4418,7 +4442,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
        struct intel_crtc *intel_crtc;
        struct drm_crtc *possible_crtc;
        struct drm_crtc *supported_crtc =NULL;
-       struct drm_encoder *encoder = &intel_encoder->enc;
+       struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_crtc *crtc = NULL;
        struct drm_device *dev = encoder->dev;
        struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -4499,7 +4523,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
 void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
                                    struct drm_connector *connector, int dpms_mode)
 {
-       struct drm_encoder *encoder = &intel_encoder->enc;
+       struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_device *dev = encoder->dev;
        struct drm_crtc *crtc = encoder->crtc;
        struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -4671,7 +4695,7 @@ static void intel_crtc_idle_timer(unsigned long arg)
        queue_work(dev_priv->wq, &dev_priv->idle_work);
 }
 
-static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
+static void intel_increase_pllclock(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -4706,9 +4730,8 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
        }
 
        /* Schedule downclock */
-       if (schedule)
-               mod_timer(&intel_crtc->idle_timer, jiffies +
-                         msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+       mod_timer(&intel_crtc->idle_timer, jiffies +
+                 msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
 }
 
 static void intel_decrease_pllclock(struct drm_crtc *crtc)
@@ -4844,7 +4867,7 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
                                        I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
                                }
                                /* Non-busy -> busy, upclock */
-                               intel_increase_pllclock(crtc, true);
+                               intel_increase_pllclock(crtc);
                                intel_crtc->busy = true;
                        } else {
                                /* Busy -> busy, put off timer */
@@ -4858,8 +4881,22 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
 static void intel_crtc_destroy(struct drm_crtc *crtc)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct intel_unpin_work *work;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       work = intel_crtc->unpin_work;
+       intel_crtc->unpin_work = NULL;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       if (work) {
+               cancel_work_sync(&work->work);
+               kfree(work);
+       }
 
        drm_crtc_cleanup(crtc);
+
        kfree(intel_crtc);
 }
 
@@ -4971,7 +5008,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        struct intel_unpin_work *work;
        unsigned long flags, offset;
        int pipe = intel_crtc->pipe;
-       u32 pf, pipesrc;
+       u32 was_dirty, pf, pipesrc;
        int ret;
 
        work = kzalloc(sizeof *work, GFP_KERNEL);
@@ -5000,7 +5037,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        obj = intel_fb->obj;
 
        mutex_lock(&dev->struct_mutex);
-       ret = intel_pin_and_fence_fb_obj(dev, obj);
+       was_dirty = obj->write_domain & I915_GEM_GPU_DOMAINS;
+       ret = intel_pin_and_fence_fb_obj(dev, obj, true);
        if (ret)
                goto cleanup_work;
 
@@ -5009,9 +5047,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        drm_gem_object_reference(obj);
 
        crtc->fb = fb;
-       ret = i915_gem_object_flush_write_domain(obj);
-       if (ret)
-               goto cleanup_objs;
 
        ret = drm_vblank_get(dev, intel_crtc->pipe);
        if (ret)
@@ -5021,17 +5056,24 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        atomic_inc(&obj_priv->pending_flip);
        work->pending_flip_obj = obj;
 
-       if (IS_GEN3(dev) || IS_GEN2(dev)) {
-               u32 flip_mask;
+       if (was_dirty || IS_GEN3(dev) || IS_GEN2(dev)) {
+               BEGIN_LP_RING(2);
+               if (IS_GEN3(dev) || IS_GEN2(dev)) {
+                       u32 flip_mask;
 
-               if (intel_crtc->plane)
-                       flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
-               else
-                       flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
+                       /* Can't queue multiple flips, so wait for the previous
+                        * one to finish before executing the next.
+                        */
 
-               BEGIN_LP_RING(2);
-               OUT_RING(MI_WAIT_FOR_EVENT | flip_mask);
-               OUT_RING(0);
+                       if (intel_crtc->plane)
+                               flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
+                       else
+                               flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
+
+                       OUT_RING(MI_WAIT_FOR_EVENT | flip_mask);
+               } else
+                       OUT_RING(MI_NOOP);
+               OUT_RING(MI_FLUSH);
                ADVANCE_LP_RING();
        }
 
@@ -5112,14 +5154,12 @@ cleanup_work:
        return ret;
 }
 
-static const struct drm_crtc_helper_funcs intel_helper_funcs = {
+static struct drm_crtc_helper_funcs intel_helper_funcs = {
        .dpms = intel_crtc_dpms,
        .mode_fixup = intel_crtc_mode_fixup,
        .mode_set = intel_crtc_mode_set,
        .mode_set_base = intel_pipe_set_base,
        .mode_set_base_atomic = intel_pipe_set_base_atomic,
-       .prepare = intel_crtc_prepare,
-       .commit = intel_crtc_commit,
        .load_lut = intel_crtc_load_lut,
 };
 
@@ -5146,8 +5186,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
 
        drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
-       intel_crtc->pipe = pipe;
-       intel_crtc->plane = pipe;
        for (i = 0; i < 256; i++) {
                intel_crtc->lut_r[i] = i;
                intel_crtc->lut_g[i] = i;
@@ -5157,9 +5195,9 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        /* Swap pipes & planes for FBC on pre-965 */
        intel_crtc->pipe = pipe;
        intel_crtc->plane = pipe;
-       if (IS_MOBILE(dev) && (IS_I9XX(dev) && !IS_I965G(dev))) {
+       if (IS_MOBILE(dev) && IS_GEN3(dev)) {
                DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
-               intel_crtc->plane = ((pipe == 0) ? 1 : 0);
+               intel_crtc->plane = !pipe;
        }
 
        BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
@@ -5169,6 +5207,16 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 
        intel_crtc->cursor_addr = 0;
        intel_crtc->dpms_mode = -1;
+       intel_crtc->active = true; /* force the pipe off on setup_init_config */
+
+       if (HAS_PCH_SPLIT(dev)) {
+               intel_helper_funcs.prepare = ironlake_crtc_prepare;
+               intel_helper_funcs.commit = ironlake_crtc_commit;
+       } else {
+               intel_helper_funcs.prepare = i9xx_crtc_prepare;
+               intel_helper_funcs.commit = i9xx_crtc_commit;
+       }
+
        drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
 
        intel_crtc->busy = false;
@@ -5204,38 +5252,25 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
        return 0;
 }
 
-struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
-{
-       struct drm_crtc *crtc = NULL;
-
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-               if (intel_crtc->pipe == pipe)
-                       break;
-       }
-       return crtc;
-}
-
 static int intel_encoder_clones(struct drm_device *dev, int type_mask)
 {
+       struct intel_encoder *encoder;
        int index_mask = 0;
-       struct drm_encoder *encoder;
        int entry = 0;
 
-        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)
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+               if (type_mask & encoder->clone_mask)
                        index_mask |= (1 << entry);
                entry++;
        }
+
        return index_mask;
 }
 
-
 static void intel_setup_outputs(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_encoder *encoder;
+       struct intel_encoder *encoder;
        bool dpd_is_edp = false;
 
        if (IS_MOBILE(dev) && !IS_I830(dev))
@@ -5324,12 +5359,10 @@ static void intel_setup_outputs(struct drm_device *dev)
        if (SUPPORTS_TV(dev))
                intel_tv_init(dev);
 
-       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_encoder->crtc_mask;
-               encoder->possible_clones = intel_encoder_clones(dev,
-                                               intel_encoder->clone_mask);
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+               encoder->base.possible_crtcs = encoder->crtc_mask;
+               encoder->base.possible_clones =
+                       intel_encoder_clones(dev, encoder->clone_mask);
        }
 }
 
@@ -5363,8 +5396,25 @@ int intel_framebuffer_init(struct drm_device *dev,
                           struct drm_mode_fb_cmd *mode_cmd,
                           struct drm_gem_object *obj)
 {
+       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        int ret;
 
+       if (obj_priv->tiling_mode == I915_TILING_Y)
+               return -EINVAL;
+
+       if (mode_cmd->pitch & 63)
+               return -EINVAL;
+
+       switch (mode_cmd->bpp) {
+       case 8:
+       case 16:
+       case 24:
+       case 32:
+               break;
+       default:
+               return -EINVAL;
+       }
+
        ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
        if (ret) {
                DRM_ERROR("framebuffer init failed %d\n", ret);
@@ -5473,6 +5523,10 @@ void ironlake_enable_drps(struct drm_device *dev)
        u32 rgvmodectl = I915_READ(MEMMODECTL);
        u8 fmax, fmin, fstart, vstart;
 
+       /* Enable temp reporting */
+       I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN);
+       I915_WRITE16(TSC1, I915_READ(TSC1) | TSE);
+
        /* 100ms RC evaluation intervals */
        I915_WRITE(RCUPEI, 100000);
        I915_WRITE(RCDNEI, 100000);
@@ -5515,7 +5569,7 @@ void ironlake_enable_drps(struct drm_device *dev)
        rgvmodectl |= MEMMODE_SWMODE_EN;
        I915_WRITE(MEMMODECTL, rgvmodectl);
 
-       if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
+       if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
                DRM_ERROR("stuck trying to change perf mode\n");
        msleep(1);
 
@@ -6049,12 +6103,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
                        continue;
 
                intel_crtc = to_intel_crtc(crtc);
-               intel_increase_pllclock(crtc, false);
-               del_timer_sync(&intel_crtc->idle_timer);
+               intel_increase_pllclock(crtc);
        }
 
-       del_timer_sync(&dev_priv->idle_timer);
-
        if (dev_priv->display.disable_fbc)
                dev_priv->display.disable_fbc(dev);
 
@@ -6083,33 +6134,36 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        mutex_unlock(&dev->struct_mutex);
 
+       /* Disable the irq before mode object teardown, for the irq might
+        * enqueue unpin/hotplug work. */
+       drm_irq_uninstall(dev);
+       cancel_work_sync(&dev_priv->hotplug_work);
+
+       /* Shut off idle work before the crtcs get freed. */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               intel_crtc = to_intel_crtc(crtc);
+               del_timer_sync(&intel_crtc->idle_timer);
+       }
+       del_timer_sync(&dev_priv->idle_timer);
+       cancel_work_sync(&dev_priv->idle_work);
+
        drm_mode_config_cleanup(dev);
 }
 
-
 /*
  * Return which encoder is currently attached for connector.
  */
-struct drm_encoder *intel_attached_encoder (struct drm_connector *connector)
+struct drm_encoder *intel_best_encoder(struct drm_connector *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;
-
-               obj = drm_mode_object_find(connector->dev,
-                                           connector->encoder_ids[i],
-                                           DRM_MODE_OBJECT_ENCODER);
-               if (!obj)
-                       continue;
+       return &intel_attached_encoder(connector)->base;
+}
 
-               encoder = obj_to_encoder(obj);
-               return encoder;
-       }
-       return NULL;
+void intel_connector_attach_encoder(struct intel_connector *connector,
+                                   struct intel_encoder *encoder)
+{
+       connector->encoder = encoder;
+       drm_mode_connector_attach_encoder(&connector->base,
+                                         &encoder->base);
 }
 
 /*