]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/gpu/drm/i915/intel_display.c
drm/i915: wait for actual vblank, not just 20ms
[net-next-2.6.git] / drivers / gpu / drm / i915 / intel_display.c
index 5e21b31198249349dc5e69265dbe20c8b0a23d02..bdea9464b6783332a0437724a0a0aad85a78c631 100644 (file)
 #include <linux/i2c.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/vgaarb.h>
 #include "drmP.h"
 #include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include "i915_trace.h"
 #include "drm_dp_helper.h"
 
 #include "drm_crtc_helper.h"
@@ -42,6 +44,7 @@
 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);
 
 typedef struct {
     /* given values */
@@ -322,6 +325,9 @@ struct intel_limit {
 #define IRONLAKE_DP_P1_MIN             1
 #define IRONLAKE_DP_P1_MAX             2
 
+/* FDI */
+#define IRONLAKE_FDI_FREQ              2700000 /* in kHz for mode->clock */
+
 static bool
 intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                    int target, int refclk, intel_clock_t *best_clock);
@@ -971,11 +977,54 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
     return true;
 }
 
-void
-intel_wait_for_vblank(struct drm_device *dev)
+/**
+ * intel_wait_for_vblank - wait for vblank on a given pipe
+ * @dev: drm device
+ * @pipe: pipe to wait for
+ *
+ * Wait for vblank to occur on a given pipe.  Needed for various bits of
+ * mode setting code.
+ */
+void intel_wait_for_vblank(struct drm_device *dev, int pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipestat_reg = (pipe == 0 ? PIPEASTAT : PIPEBSTAT);
+
+       /* Wait for vblank interrupt bit to set */
+       if (wait_for((I915_READ(pipestat_reg) &
+                     PIPE_VBLANK_INTERRUPT_STATUS) == 0,
+                    50, 0))
+               DRM_DEBUG_KMS("vblank wait timed out\n");
+}
+
+/**
+ * intel_wait_for_vblank_off - wait for vblank after disabling a pipe
+ * @dev: drm device
+ * @pipe: pipe to wait for
+ *
+ * After disabling a pipe, we can't wait for vblank in the usual way,
+ * spinning on the vblank interrupt status bit, since we won't actually
+ * see an interrupt when the pipe is disabled.
+ *
+ * So this function waits for the display line value to settle (it
+ * usually ends up stopping at the start of the next frame).
+ */
+void intel_wait_for_vblank_off(struct drm_device *dev, int pipe)
 {
-       /* Wait for 20ms, i.e. one cycle at 50hz. */
-       msleep(20);
+       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;
+
+       /* Wait for the display line to settle */
+       do {
+               last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK;
+               mdelay(5);
+       } while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) &&
+                time_after(timeout, jiffies));
+
+       if (time_after(jiffies, timeout))
+               DRM_DEBUG_KMS("vblank wait timed out\n");
 }
 
 /* Parameters have changed, update FBC info */
@@ -1029,7 +1078,6 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 void i8xx_disable_fbc(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long timeout = jiffies + msecs_to_jiffies(1);
        u32 fbc_ctl;
 
        if (!I915_HAS_FBC(dev))
@@ -1044,16 +1092,11 @@ void i8xx_disable_fbc(struct drm_device *dev)
        I915_WRITE(FBC_CONTROL, fbc_ctl);
 
        /* Wait for compressing bit to clear */
-       while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) {
-               if (time_after(jiffies, timeout)) {
-                       DRM_DEBUG_DRIVER("FBC idle timed out\n");
-                       break;
-               }
-               ; /* do nothing */
+       if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) {
+               DRM_DEBUG_KMS("FBC idle timed out\n");
+               return;
        }
 
-       intel_wait_for_vblank(dev);
-
        DRM_DEBUG_KMS("disabled FBC\n");
 }
 
@@ -1110,7 +1153,6 @@ void g4x_disable_fbc(struct drm_device *dev)
        dpfc_ctl = I915_READ(DPFC_CONTROL);
        dpfc_ctl &= ~DPFC_CTL_EN;
        I915_WRITE(DPFC_CONTROL, dpfc_ctl);
-       intel_wait_for_vblank(dev);
 
        DRM_DEBUG_KMS("disabled FBC\n");
 }
@@ -1122,6 +1164,66 @@ static bool g4x_fbc_enabled(struct drm_device *dev)
        return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
 }
 
+static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_framebuffer *fb = crtc->fb;
+       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+       struct drm_i915_gem_object *obj_priv = 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;
+       unsigned long stall_watermark = 200;
+       u32 dpfc_ctl;
+
+       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;
+
+       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) {
+               dpfc_ctl |= (DPFC_CTL_FENCE_EN | dev_priv->cfb_fence);
+               I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
+       } else {
+               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);
+
+       DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
+}
+
+void ironlake_disable_fbc(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 dpfc_ctl;
+
+       /* Disable compression */
+       dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
+       dpfc_ctl &= ~DPFC_CTL_EN;
+       I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+
+       DRM_DEBUG_KMS("disabled FBC\n");
+}
+
+static bool ironlake_fbc_enabled(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
+}
+
 bool intel_fbc_enabled(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1248,6 +1350,10 @@ static void intel_update_fbc(struct drm_crtc *crtc,
                goto out_disable;
        }
 
+       /* If the kernel debugger is active, always disable compression */
+       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) ||
@@ -1279,7 +1385,12 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
 
        switch (obj_priv->tiling_mode) {
        case I915_TILING_NONE:
-               alignment = 64 * 1024;
+               if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
+                       alignment = 128 * 1024;
+               else if (IS_I965G(dev))
+                       alignment = 4 * 1024;
+               else
+                       alignment = 64 * 1024;
                break;
        case I915_TILING_X:
                /* pin() will align the object as required by fence */
@@ -1314,6 +1425,98 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
        return 0;
 }
 
+/* Assume fb object is pinned & idle & fenced and just update base pointers */
+static int
+intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+                          int x, int y)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_framebuffer *intel_fb;
+       struct drm_i915_gem_object *obj_priv;
+       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;
+
+       switch (plane) {
+       case 0:
+       case 1:
+               break;
+       default:
+               DRM_ERROR("Can't update plane %d in SAREA\n", plane);
+               return -EINVAL;
+       }
+
+       intel_fb = to_intel_framebuffer(fb);
+       obj = intel_fb->obj;
+       obj_priv = to_intel_bo(obj);
+
+       dspcntr = I915_READ(dspcntr_reg);
+       /* Mask out pixel format bits in case we change it */
+       dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
+       switch (fb->bits_per_pixel) {
+       case 8:
+               dspcntr |= DISPPLANE_8BPP;
+               break;
+       case 16:
+               if (fb->depth == 15)
+                       dspcntr |= DISPPLANE_15_16BPP;
+               else
+                       dspcntr |= DISPPLANE_16BPP;
+               break;
+       case 24:
+       case 32:
+               dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
+               break;
+       default:
+               DRM_ERROR("Unknown color depth\n");
+               return -EINVAL;
+       }
+       if (IS_I965G(dev)) {
+               if (obj_priv->tiling_mode != I915_TILING_NONE)
+                       dspcntr |= DISPPLANE_TILED;
+               else
+                       dspcntr &= ~DISPPLANE_TILED;
+       }
+
+       if (IS_IRONLAKE(dev))
+               /* must disable */
+               dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
+
+       I915_WRITE(dspcntr_reg, dspcntr);
+
+       Start = obj_priv->gtt_offset;
+       Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
+
+       DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y);
+       I915_WRITE(dspstride, fb->pitch);
+       if (IS_I965G(dev)) {
+               I915_WRITE(dspbase, Offset);
+               I915_READ(dspbase);
+               I915_WRITE(dspsurf, Start);
+               I915_READ(dspsurf);
+               I915_WRITE(dsptileoff, (y << 16) | x);
+       } else {
+               I915_WRITE(dspbase, Start + Offset);
+               I915_READ(dspbase);
+       }
+
+       if ((IS_I965G(dev) || plane == 0))
+               intel_update_fbc(crtc, &crtc->mode);
+
+       intel_wait_for_vblank(dev, intel_crtc->pipe);
+       intel_increase_pllclock(crtc, true);
+
+       return 0;
+}
+
 static int
 intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                    struct drm_framebuffer *old_fb)
@@ -1415,20 +1618,18 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                      Start, Offset, x, y, crtc->fb->pitch);
        I915_WRITE(dspstride, crtc->fb->pitch);
        if (IS_I965G(dev)) {
-               I915_WRITE(dspbase, Offset);
-               I915_READ(dspbase);
                I915_WRITE(dspsurf, Start);
-               I915_READ(dspsurf);
                I915_WRITE(dsptileoff, (y << 16) | x);
+               I915_WRITE(dspbase, Offset);
        } else {
                I915_WRITE(dspbase, Start + Offset);
-               I915_READ(dspbase);
        }
+       POSTING_READ(dspbase);
 
        if ((IS_I965G(dev) || plane == 0))
                intel_update_fbc(crtc, &crtc->mode);
 
-       intel_wait_for_vblank(dev);
+       intel_wait_for_vblank(dev, pipe);
 
        if (old_fb) {
                intel_fb = to_intel_framebuffer(old_fb);
@@ -1457,54 +1658,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        return 0;
 }
 
-/* Disable the VGA plane that we never use */
-static void i915_disable_vga (struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u8 sr1;
-       u32 vga_reg;
-
-       if (HAS_PCH_SPLIT(dev))
-               vga_reg = CPU_VGACNTRL;
-       else
-               vga_reg = VGACNTRL;
-
-       if (I915_READ(vga_reg) & VGA_DISP_DISABLE)
-               return;
-
-       I915_WRITE8(VGA_SR_INDEX, 1);
-       sr1 = I915_READ8(VGA_SR_DATA);
-       I915_WRITE8(VGA_SR_DATA, sr1 | (1 << 5));
-       udelay(100);
-
-       I915_WRITE(vga_reg, VGA_DISP_DISABLE);
-}
-
-static void ironlake_disable_pll_edp (struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 dpa_ctl;
-
-       DRM_DEBUG_KMS("\n");
-       dpa_ctl = I915_READ(DP_A);
-       dpa_ctl &= ~DP_PLL_ENABLE;
-       I915_WRITE(DP_A, dpa_ctl);
-}
-
-static void ironlake_enable_pll_edp (struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 dpa_ctl;
-
-       dpa_ctl = I915_READ(DP_A);
-       dpa_ctl |= DP_PLL_ENABLE;
-       I915_WRITE(DP_A, dpa_ctl);
-       udelay(200);
-}
-
-
 static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock)
 {
        struct drm_device *dev = crtc->dev;
@@ -1554,6 +1707,15 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
        int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
        u32 temp, tries = 0;
 
+       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+          for train result */
+       temp = I915_READ(fdi_rx_imr_reg);
+       temp &= ~FDI_RX_SYMBOL_LOCK;
+       temp &= ~FDI_RX_BIT_LOCK;
+       I915_WRITE(fdi_rx_imr_reg, temp);
+       I915_READ(fdi_rx_imr_reg);
+       udelay(150);
+
        /* enable CPU FDI TX and PCH FDI RX */
        temp = I915_READ(fdi_tx_reg);
        temp |= FDI_TX_ENABLE;
@@ -1571,16 +1733,7 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
        I915_READ(fdi_rx_reg);
        udelay(150);
 
-       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
-          for train result */
-       temp = I915_READ(fdi_rx_imr_reg);
-       temp &= ~FDI_RX_SYMBOL_LOCK;
-       temp &= ~FDI_RX_BIT_LOCK;
-       I915_WRITE(fdi_rx_imr_reg, temp);
-       I915_READ(fdi_rx_imr_reg);
-       udelay(150);
-
-       for (;;) {
+       for (tries = 0; tries < 5; tries++) {
                temp = I915_READ(fdi_rx_iir_reg);
                DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
@@ -1590,14 +1743,9 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
                                   temp | FDI_RX_BIT_LOCK);
                        break;
                }
-
-               tries++;
-
-               if (tries > 5) {
-                       DRM_DEBUG_KMS("FDI train 1 fail!\n");
-                       break;
-               }
        }
+       if (tries == 5)
+               DRM_DEBUG_KMS("FDI train 1 fail!\n");
 
        /* Train 2 */
        temp = I915_READ(fdi_tx_reg);
@@ -1613,7 +1761,7 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
 
        tries = 0;
 
-       for (;;) {
+       for (tries = 0; tries < 5; tries++) {
                temp = I915_READ(fdi_rx_iir_reg);
                DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
@@ -1623,14 +1771,9 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
                        DRM_DEBUG_KMS("FDI train 2 done.\n");
                        break;
                }
-
-               tries++;
-
-               if (tries > 5) {
-                       DRM_DEBUG_KMS("FDI train 2 fail!\n");
-                       break;
-               }
        }
+       if (tries == 5)
+               DRM_DEBUG_KMS("FDI train 2 fail!\n");
 
        DRM_DEBUG_KMS("FDI train done\n");
 }
@@ -1655,6 +1798,15 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
        u32 temp, i;
 
+       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+          for train result */
+       temp = I915_READ(fdi_rx_imr_reg);
+       temp &= ~FDI_RX_SYMBOL_LOCK;
+       temp &= ~FDI_RX_BIT_LOCK;
+       I915_WRITE(fdi_rx_imr_reg, temp);
+       I915_READ(fdi_rx_imr_reg);
+       udelay(150);
+
        /* enable CPU FDI TX and PCH FDI RX */
        temp = I915_READ(fdi_tx_reg);
        temp |= FDI_TX_ENABLE;
@@ -1680,15 +1832,6 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        I915_READ(fdi_rx_reg);
        udelay(150);
 
-       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
-          for train result */
-       temp = I915_READ(fdi_rx_imr_reg);
-       temp &= ~FDI_RX_SYMBOL_LOCK;
-       temp &= ~FDI_RX_BIT_LOCK;
-       I915_WRITE(fdi_rx_imr_reg, temp);
-       I915_READ(fdi_rx_imr_reg);
-       udelay(150);
-
        for (i = 0; i < 4; i++ ) {
                temp = I915_READ(fdi_tx_reg);
                temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
@@ -1785,7 +1928,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
        int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
        int trans_dpll_sel = (pipe == 0) ? 0 : 1;
        u32 temp;
-       int n;
        u32 pipe_bpc;
 
        temp = I915_READ(pipeconf_reg);
@@ -1798,7 +1940,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
        case DRM_MODE_DPMS_ON:
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
-               DRM_DEBUG_KMS("crtc %d dpms on\n", pipe);
+               DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
 
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
                        temp = I915_READ(PCH_LVDS);
@@ -1808,10 +1950,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        }
                }
 
-               if (HAS_eDP) {
-                       /* enable eDP PLL */
-                       ironlake_enable_pll_edp(crtc);
-               } else {
+               if (!HAS_eDP) {
 
                        /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
                        temp = I915_READ(fdi_rx_reg);
@@ -1843,16 +1982,15 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                }
 
                /* Enable panel fitting for LVDS */
-               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-                       temp = I915_READ(pf_ctl_reg);
-                       I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3);
-
-                       /* currently full aspect */
-                       I915_WRITE(pf_win_pos, 0);
-
-                       I915_WRITE(pf_win_size,
-                                  (dev_priv->panel_fixed_mode->hdisplay << 16) |
-                                  (dev_priv->panel_fixed_mode->vdisplay));
+               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)
+                   || HAS_eDP || intel_pch_has_edp(crtc)) {
+                       if (dev_priv->pch_pf_size) {
+                               temp = I915_READ(pf_ctl_reg);
+                               I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3);
+                               I915_WRITE(pf_win_pos, dev_priv->pch_pf_pos);
+                               I915_WRITE(pf_win_size, dev_priv->pch_pf_size);
+                       } else
+                               I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE);
                }
 
                /* Enable CPU pipe */
@@ -1936,11 +2074,15 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                                int reg;
 
                                reg = I915_READ(trans_dp_ctl);
-                               reg &= ~TRANS_DP_PORT_SEL_MASK;
-                               reg = TRANS_DP_OUTPUT_ENABLE |
-                                     TRANS_DP_ENH_FRAMING |
-                                     TRANS_DP_VSYNC_ACTIVE_HIGH |
-                                     TRANS_DP_HSYNC_ACTIVE_HIGH;
+                               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:
@@ -1973,16 +2115,17 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
                        I915_READ(transconf_reg);
 
-                       while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0)
-                               ;
-
+                       if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 10, 0))
+                               DRM_ERROR("failed to enable transcoder\n");
                }
 
                intel_crtc_load_lut(crtc);
 
-       break;
+               intel_update_fbc(crtc, &crtc->mode);
+               break;
+
        case DRM_MODE_DPMS_OFF:
-               DRM_DEBUG_KMS("crtc %d dpms off\n", pipe);
+               DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
 
                drm_vblank_off(dev, pipe);
                /* Disable display plane */
@@ -1994,26 +2137,18 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                        I915_READ(dspbase_reg);
                }
 
-               i915_disable_vga(dev);
+               if (dev_priv->cfb_plane == plane &&
+                   dev_priv->display.disable_fbc)
+                       dev_priv->display.disable_fbc(dev);
 
                /* 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);
-                       I915_READ(pipeconf_reg);
-                       n = 0;
+
                        /* wait for cpu pipe off, pipe state */
-                       while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) {
-                               n++;
-                               if (n < 60) {
-                                       udelay(500);
-                                       continue;
-                               } else {
-                                       DRM_DEBUG_KMS("pipe %d off delay\n",
-                                                               pipe);
-                                       break;
-                               }
-                       }
+                       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);
 
@@ -2074,20 +2209,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                temp = I915_READ(transconf_reg);
                if ((temp & TRANS_ENABLE) != 0) {
                        I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
-                       I915_READ(transconf_reg);
-                       n = 0;
+
                        /* wait for PCH transcoder off, transcoder state */
-                       while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) {
-                               n++;
-                               if (n < 60) {
-                                       udelay(500);
-                                       continue;
-                               } else {
-                                       DRM_DEBUG_KMS("transcoder %d off "
-                                                       "delay\n", pipe);
-                                       break;
-                               }
-                       }
+                       if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50, 1))
+                               DRM_ERROR("failed to disable transcoder\n");
                }
 
                temp = I915_READ(transconf_reg);
@@ -2124,10 +2249,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
                I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
                I915_READ(pch_dpll_reg);
 
-               if (HAS_eDP) {
-                       ironlake_disable_pll_edp(crtc);
-               }
-
                /* Switch from PCDclk to Rawclk */
                temp = I915_READ(fdi_rx_reg);
                temp &= ~FDI_SEL_PCDCLK;
@@ -2202,8 +2323,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
        case DRM_MODE_DPMS_ON:
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
-               intel_update_watermarks(dev);
-
                /* Enable the DPLL */
                temp = I915_READ(dpll_reg);
                if ((temp & DPLL_VCO_ENABLE) == 0) {
@@ -2243,8 +2362,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
                intel_crtc_dpms_overlay(intel_crtc, true);
        break;
        case DRM_MODE_DPMS_OFF:
-               intel_update_watermarks(dev);
-
                /* 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);
@@ -2253,9 +2370,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
                    dev_priv->display.disable_fbc)
                        dev_priv->display.disable_fbc(dev);
 
-               /* Disable the VGA plane that we never use */
-               i915_disable_vga(dev);
-
                /* Disable display plane */
                temp = I915_READ(dspcntr_reg);
                if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
@@ -2265,10 +2379,8 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
                        I915_READ(dspbase_reg);
                }
 
-               if (!IS_I9XX(dev)) {
-                       /* Wait for vblank for the disable to take effect */
-                       intel_wait_for_vblank(dev);
-               }
+               /* Wait for vblank for the disable to take effect */
+               intel_wait_for_vblank_off(dev, pipe);
 
                /* Don't disable pipe A or pipe A PLLs if needed */
                if (pipeconf_reg == PIPEACONF &&
@@ -2283,7 +2395,7 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
                }
 
                /* Wait for vblank for the disable to take effect. */
-               intel_wait_for_vblank(dev);
+               intel_wait_for_vblank_off(dev, pipe);
 
                temp = I915_READ(dpll_reg);
                if ((temp & DPLL_VCO_ENABLE) != 0) {
@@ -2299,9 +2411,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
 
 /**
  * Sets the power management mode of the pipe and plane.
- *
- * This code should probably grow support for turning the cursor off and back
- * on appropriately at the same time as we're turning the pipe off/on.
  */
 static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
@@ -2312,9 +2421,26 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
        int pipe = intel_crtc->pipe;
        bool enabled;
 
+       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);
 
-       intel_crtc->dpms_mode = mode;
+       if (mode == DRM_MODE_DPMS_ON)
+               intel_crtc_update_cursor(crtc);
+       else
+               intel_update_watermarks(dev);
 
        if (!dev->primary->master)
                return;
@@ -2366,6 +2492,20 @@ void intel_encoder_commit (struct drm_encoder *encoder)
        encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
 }
 
+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);
+
+       drm_encoder_cleanup(encoder);
+       kfree(intel_encoder);
+}
+
 static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
                                  struct drm_display_mode *mode,
                                  struct drm_display_mode *adjusted_mode)
@@ -2373,8 +2513,8 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        if (HAS_PCH_SPLIT(dev)) {
                /* FDI link clock is fixed at 2.7G */
-               if (mode->clock * 3 > 27000 * 4)
-                       return MODE_CLOCK_HIGH;
+               if (mode->clock * 3 > IRONLAKE_FDI_FREQ * 4)
+                       return false;
        }
        return true;
 }
@@ -2556,6 +2696,20 @@ static struct intel_watermark_params g4x_wm_info = {
        2,
        G4X_FIFO_LINE_SIZE,
 };
+static struct intel_watermark_params g4x_cursor_wm_info = {
+       I965_CURSOR_FIFO,
+       I965_CURSOR_MAX_WM,
+       I965_CURSOR_DFT_WM,
+       2,
+       G4X_FIFO_LINE_SIZE,
+};
+static struct intel_watermark_params i965_cursor_wm_info = {
+       I965_CURSOR_FIFO,
+       I965_CURSOR_MAX_WM,
+       I965_CURSOR_DFT_WM,
+       2,
+       I915_FIFO_LINE_SIZE,
+};
 static struct intel_watermark_params i945_wm_info = {
        I945_FIFO_SIZE,
        I915_MAX_WM,
@@ -2593,6 +2747,14 @@ static struct intel_watermark_params ironlake_display_wm_info = {
        ILK_FIFO_LINE_SIZE
 };
 
+static struct intel_watermark_params ironlake_cursor_wm_info = {
+       ILK_CURSOR_FIFO,
+       ILK_CURSOR_MAXWM,
+       ILK_CURSOR_DFTWM,
+       2,
+       ILK_FIFO_LINE_SIZE
+};
+
 static struct intel_watermark_params ironlake_display_srwm_info = {
        ILK_DISPLAY_SR_FIFO,
        ILK_DISPLAY_MAX_SRWM,
@@ -2642,7 +2804,7 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
         */
        entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) /
                1000;
-       entries_required /= wm->cacheline_size;
+       entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size);
 
        DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries_required);
 
@@ -2653,8 +2815,14 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
        /* Don't promote wm_size to unsigned... */
        if (wm_size > (long)wm->max_wm)
                wm_size = wm->max_wm;
-       if (wm_size <= 0)
+       if (wm_size <= 0) {
                wm_size = wm->default_wm;
+               DRM_ERROR("Insufficient FIFO for plane, expect flickering:"
+                         " entries required = %ld, available = %lu.\n",
+                         entries_required + wm->guard_size,
+                         wm->fifo_size);
+       }
+
        return wm_size;
 }
 
@@ -2669,7 +2837,7 @@ struct cxsr_latency {
        unsigned long cursor_hpll_disable;
 };
 
-static struct cxsr_latency cxsr_latency_table[] = {
+static const struct cxsr_latency cxsr_latency_table[] = {
        {1, 0, 800, 400, 3382, 33382, 3983, 33983},    /* DDR2-400 SC */
        {1, 0, 800, 667, 3354, 33354, 3807, 33807},    /* DDR2-667 SC */
        {1, 0, 800, 800, 3347, 33347, 3763, 33763},    /* DDR2-800 SC */
@@ -2707,11 +2875,13 @@ static struct cxsr_latency cxsr_latency_table[] = {
        {0, 1, 400, 800, 6042, 36042, 6584, 36584},    /* DDR3-800 SC */
 };
 
-static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int is_ddr3, 
-                                                  int fsb, int mem)
+static const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop,
+                                                        int is_ddr3,
+                                                        int fsb,
+                                                        int mem)
 {
+       const struct cxsr_latency *latency;
        int i;
-       struct cxsr_latency *latency;
 
        if (fsb == 0 || mem == 0)
                return NULL;
@@ -2732,13 +2902,9 @@ static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int is_ddr3,
 static void pineview_disable_cxsr(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 reg;
 
        /* deactivate cxsr */
-       reg = I915_READ(DSPFW3);
-       reg &= ~(PINEVIEW_SELF_REFRESH_EN);
-       I915_WRITE(DSPFW3, reg);
-       DRM_INFO("Big FIFO is disabled\n");
+       I915_WRITE(DSPFW3, I915_READ(DSPFW3) & ~PINEVIEW_SELF_REFRESH_EN);
 }
 
 /*
@@ -2763,11 +2929,9 @@ static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
        uint32_t dsparb = I915_READ(DSPARB);
        int size;
 
-       if (plane == 0)
-               size = dsparb & 0x7f;
-       else
-               size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) -
-                       (dsparb & 0x7f);
+       size = dsparb & 0x7f;
+       if (plane)
+               size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size;
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
                        plane ? "B" : "A", size);
@@ -2781,11 +2945,9 @@ static int i85x_get_fifo_size(struct drm_device *dev, int plane)
        uint32_t dsparb = I915_READ(DSPARB);
        int size;
 
-       if (plane == 0)
-               size = dsparb & 0x1ff;
-       else
-               size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) -
-                       (dsparb & 0x1ff);
+       size = dsparb & 0x1ff;
+       if (plane)
+               size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - size;
        size >>= 1; /* Convert to cachelines */
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
@@ -2826,15 +2988,16 @@ static int i830_get_fifo_size(struct drm_device *dev, int plane)
 }
 
 static void pineview_update_wm(struct drm_device *dev,  int planea_clock,
-                         int planeb_clock, int sr_hdisplay, 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;
        u32 reg;
        unsigned long wm;
-       struct cxsr_latency *latency;
        int sr_clock;
 
-       latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, 
+       latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3,
                                         dev_priv->fsb_freq, dev_priv->mem_freq);
        if (!latency) {
                DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
@@ -2880,9 +3043,8 @@ static void pineview_update_wm(struct drm_device *dev,  int planea_clock,
                DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg);
 
                /* activate cxsr */
-               reg = I915_READ(DSPFW3);
-               reg |= PINEVIEW_SELF_REFRESH_EN;
-               I915_WRITE(DSPFW3, reg);
+               I915_WRITE(DSPFW3,
+                          I915_READ(DSPFW3) | PINEVIEW_SELF_REFRESH_EN);
                DRM_DEBUG_KMS("Self-refresh is enabled\n");
        } else {
                pineview_disable_cxsr(dev);
@@ -2891,7 +3053,8 @@ static void pineview_update_wm(struct drm_device *dev,  int planea_clock,
 }
 
 static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
-                         int planeb_clock, int sr_hdisplay, int pixel_size)
+                         int planeb_clock, int sr_hdisplay, int sr_htotal,
+                         int pixel_size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int total_size, cacheline_size;
@@ -2915,12 +3078,12 @@ static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
         */
        entries_required = ((planea_clock / 1000) * pixel_size * latency_ns) /
                1000;
-       entries_required /= G4X_FIFO_LINE_SIZE;
+       entries_required = DIV_ROUND_UP(entries_required, G4X_FIFO_LINE_SIZE);
        planea_wm = entries_required + planea_params.guard_size;
 
        entries_required = ((planeb_clock / 1000) * pixel_size * latency_ns) /
                1000;
-       entries_required /= G4X_FIFO_LINE_SIZE;
+       entries_required = DIV_ROUND_UP(entries_required, G4X_FIFO_LINE_SIZE);
        planeb_wm = entries_required + planeb_params.guard_size;
 
        cursora_wm = cursorb_wm = 16;
@@ -2934,13 +3097,24 @@ static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
                static const int sr_latency_ns = 12000;
 
                sr_clock = planea_clock ? planea_clock : planeb_clock;
-               line_time_us = ((sr_hdisplay * 1000) / sr_clock);
+               line_time_us = ((sr_htotal * 1000) / sr_clock);
 
                /* Use ns/us then divide to preserve precision */
-               sr_entries = (((sr_latency_ns / line_time_us) + 1) *
-                             pixel_size * sr_hdisplay) / 1000;
-               sr_entries = roundup(sr_entries / cacheline_size, 1);
-               DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
+               sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
+                             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);
+               cursor_sr = entries_required + g4x_cursor_wm_info.guard_size;
+
+               if (cursor_sr > g4x_cursor_wm_info.max_wm)
+                       cursor_sr = g4x_cursor_wm_info.max_wm;
+               DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
+                             "cursor %d\n", sr_entries, cursor_sr);
+
                I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
        } else {
                /* Turn off self refresh if both pipes are enabled */
@@ -2965,11 +3139,13 @@ static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
 }
 
 static void i965_update_wm(struct drm_device *dev, int planea_clock,
-                          int planeb_clock, int sr_hdisplay, int pixel_size)
+                          int planeb_clock, int sr_hdisplay, int sr_htotal,
+                          int pixel_size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long line_time_us;
        int sr_clock, sr_entries, srwm = 1;
+       int cursor_sr = 16;
 
        /* Calc sr entries for one plane configs */
        if (sr_hdisplay && (!planea_clock || !planeb_clock)) {
@@ -2977,17 +3153,31 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
                static const int sr_latency_ns = 12000;
 
                sr_clock = planea_clock ? planea_clock : planeb_clock;
-               line_time_us = ((sr_hdisplay * 1000) / sr_clock);
+               line_time_us = ((sr_htotal * 1000) / sr_clock);
 
                /* Use ns/us then divide to preserve precision */
-               sr_entries = (((sr_latency_ns / line_time_us) + 1) *
-                             pixel_size * sr_hdisplay) / 1000;
-               sr_entries = roundup(sr_entries / I915_FIFO_LINE_SIZE, 1);
+               sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
+                             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 = I945_FIFO_SIZE - sr_entries;
+               srwm = I965_FIFO_SIZE - sr_entries;
                if (srwm < 0)
                        srwm = 1;
-               srwm &= 0x3f;
+               srwm &= 0x1ff;
+
+               sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
+                            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);
+
+               if (cursor_sr > i965_cursor_wm_info.max_wm)
+                       cursor_sr = i965_cursor_wm_info.max_wm;
+
+               DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
+                             "cursor %d\n", srwm, cursor_sr);
+
                if (IS_I965GM(dev))
                        I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
        } else {
@@ -3004,10 +3194,13 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
        I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) | (8 << 16) | (8 << 8) |
                   (8 << 0));
        I915_WRITE(DSPFW2, (8 << 8) | (8 << 0));
+       /* update cursor SR watermark */
+       I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
 }
 
 static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
-                          int planeb_clock, int sr_hdisplay, int pixel_size)
+                          int planeb_clock, int sr_hdisplay, int sr_htotal,
+                          int pixel_size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t fwater_lo;
@@ -3052,12 +3245,12 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
                static const int sr_latency_ns = 6000;
 
                sr_clock = planea_clock ? planea_clock : planeb_clock;
-               line_time_us = ((sr_hdisplay * 1000) / sr_clock);
+               line_time_us = ((sr_htotal * 1000) / sr_clock);
 
                /* Use ns/us then divide to preserve precision */
-               sr_entries = (((sr_latency_ns / line_time_us) + 1) *
-                             pixel_size * sr_hdisplay) / 1000;
-               sr_entries = roundup(sr_entries / cacheline_size, 1);
+               sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
+                             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;
                if (srwm < 0)
@@ -3095,7 +3288,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
 }
 
 static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused,
-                          int unused2, int pixel_size)
+                          int unused2, int unused3, int pixel_size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t fwater_lo = I915_READ(FW_BLC) & ~0xfff;
@@ -3113,9 +3306,11 @@ 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 pixel_size)
+                      int planeb_clock, int sr_hdisplay, int sr_htotal,
+                      int pixel_size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
@@ -3123,20 +3318,47 @@ static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
        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;
+
+       /* 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);
+                                               ironlake_display_wm_info.cacheline_size);
                planea_wm = entries_required +
                            ironlake_display_wm_info.guard_size;
 
                if (planea_wm > (int)ironlake_display_wm_info.max_wm)
                        planea_wm = ironlake_display_wm_info.max_wm;
 
-               cursora_wm = 16;
+               /* 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) |
@@ -3150,14 +3372,27 @@ static void ironlake_update_wm(struct drm_device *dev,  int planea_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);
+                                               ironlake_display_wm_info.cacheline_size);
                planeb_wm = entries_required +
                            ironlake_display_wm_info.guard_size;
 
                if (planeb_wm > (int)ironlake_display_wm_info.max_wm)
                        planeb_wm = ironlake_display_wm_info.max_wm;
 
-               cursorb_wm = 16;
+               /* Use the large buffer method to calculate cursor watermark */
+               line_time_us = (planeb_htotal * 1000) / planeb_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 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;
+
                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) |
@@ -3172,12 +3407,12 @@ static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
         * display plane is used.
         */
        if (!planea_clock || !planeb_clock) {
-               int line_count;
+
                /* Read the self-refresh latency. The unit is 0.5us */
                int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK;
 
                sr_clock = planea_clock ? planea_clock : planeb_clock;
-               line_time_us = ((sr_hdisplay * 1000) / sr_clock);
+               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)
@@ -3186,14 +3421,14 @@ static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
                /* 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);
+                                               ironlake_display_srwm_info.cacheline_size);
                sr_wm = entries_required +
                        ironlake_display_srwm_info.guard_size;
 
                /* calculate the self-refresh watermark for display cursor */
                entries_required = line_count * pixel_size * 64;
                entries_required = DIV_ROUND_UP(entries_required,
-                                  ironlake_cursor_srwm_info.cacheline_size);
+                                               ironlake_cursor_srwm_info.cacheline_size);
                cursor_wm = entries_required +
                            ironlake_cursor_srwm_info.guard_size;
 
@@ -3237,6 +3472,7 @@ static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
  *       bytes per pixel
  *   where
  *     line time = htotal / dotclock
+ *     surface width = hdisplay for normal plane and 64 for cursor
  *   and latency is assumed to be high, as above.
  *
  * The final value programmed to the register should always be rounded up,
@@ -3249,18 +3485,18 @@ static void intel_update_watermarks(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc;
-       struct intel_crtc *intel_crtc;
        int sr_hdisplay = 0;
        unsigned long planea_clock = 0, planeb_clock = 0, sr_clock = 0;
        int enabled = 0, pixel_size = 0;
+       int sr_htotal = 0;
 
        if (!dev_priv->display.update_wm)
                return;
 
        /* Get the clock config from both planes */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               intel_crtc = to_intel_crtc(crtc);
-               if (crtc->enabled) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) {
                        enabled++;
                        if (intel_crtc->plane == 0) {
                                DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n",
@@ -3273,6 +3509,7 @@ static void intel_update_watermarks(struct drm_device *dev)
                        }
                        sr_hdisplay = crtc->mode.hdisplay;
                        sr_clock = crtc->mode.clock;
+                       sr_htotal = crtc->mode.htotal;
                        if (crtc->fb)
                                pixel_size = crtc->fb->bits_per_pixel / 8;
                        else
@@ -3284,7 +3521,7 @@ static void intel_update_watermarks(struct drm_device *dev)
                return;
 
        dev_priv->display.update_wm(dev, planea_clock, planeb_clock,
-                                   sr_hdisplay, pixel_size);
+                                   sr_hdisplay, sr_htotal, pixel_size);
 }
 
 static int intel_crtc_mode_set(struct drm_crtc *crtc,
@@ -3403,6 +3640,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
+       /* Ensure that the cursor is valid for the new mode before changing... */
+       intel_crtc_update_cursor(crtc);
+
        if (is_lvds && dev_priv->lvds_downclock_avail) {
                has_reduced_clock = limit->find_pll(limit, crtc,
                                                            dev_priv->lvds_downclock,
@@ -3469,7 +3709,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                temp |= PIPE_8BPC;
                        else
                                temp |= PIPE_6BPC;
-               } else if (is_edp) {
+               } else if (is_edp || (is_dp && intel_pch_has_edp(crtc))) {
                        switch (dev_priv->edp_bpp/3) {
                        case 8:
                                temp |= PIPE_8BPC;
@@ -3691,9 +3931,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                dpll_reg = pch_dpll_reg;
        }
 
-       if (is_edp) {
-               ironlake_disable_pll_edp(crtc);
-       } else if ((dpll & DPLL_VCO_ENABLE)) {
+       if (!is_edp) {
                I915_WRITE(fp_reg, fp);
                I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
                I915_READ(dpll_reg);
@@ -3712,6 +3950,11 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                udelay(150);
        }
 
+       if (HAS_PCH_SPLIT(dev)) {
+               pipeconf &= ~PIPE_ENABLE_DITHER;
+               pipeconf &= ~PIPE_DITHER_TYPE_MASK;
+       }
+
        /* The LVDS pin pair needs to be on before the DPLLs are enabled.
         * This is an exception to the general rule that mode_set doesn't turn
         * things on.
@@ -3754,16 +3997,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        if (dev_priv->lvds_dither) {
                                if (HAS_PCH_SPLIT(dev)) {
                                        pipeconf |= PIPE_ENABLE_DITHER;
-                                       pipeconf &= ~PIPE_DITHER_TYPE_MASK;
                                        pipeconf |= PIPE_DITHER_TYPE_ST01;
                                } else
                                        lvds |= LVDS_ENABLE_DITHER;
                        } else {
-                               if (HAS_PCH_SPLIT(dev)) {
-                                       pipeconf &= ~PIPE_ENABLE_DITHER;
-                                       pipeconf &= ~PIPE_DITHER_TYPE_MASK;
-                               } else
+                               if (!HAS_PCH_SPLIT(dev)) {
                                        lvds &= ~LVDS_ENABLE_DITHER;
+                               }
                        }
                }
                I915_WRITE(lvds_reg, lvds);
@@ -3890,7 +4130,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        I915_WRITE(pipeconf_reg, pipeconf);
        I915_READ(pipeconf_reg);
 
-       intel_wait_for_vblank(dev);
+       intel_wait_for_vblank(dev, pipe);
 
        if (IS_IRONLAKE(dev)) {
                /* enable address swizzle for tiling buffer */
@@ -3903,9 +4143,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        /* Flush the plane changes */
        ret = intel_pipe_set_base(crtc, x, y, old_fb);
 
-       if ((IS_I965G(dev) || plane == 0))
-               intel_update_fbc(crtc, &crtc->mode);
-
        intel_update_watermarks(dev);
 
        drm_vblank_post_modeset(dev, pipe);
@@ -3939,6 +4176,118 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
        }
 }
 
+static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       bool visible = base != 0;
+       u32 cntl;
+
+       if (intel_crtc->cursor_visible == visible)
+               return;
+
+       cntl = I915_READ(CURACNTR);
+       if (visible) {
+               /* On these chipsets we can only modify the base whilst
+                * the cursor is disabled.
+                */
+               I915_WRITE(CURABASE, base);
+
+               cntl &= ~(CURSOR_FORMAT_MASK);
+               /* XXX width must be 64, stride 256 => 0x00 << 28 */
+               cntl |= CURSOR_ENABLE |
+                       CURSOR_GAMMA_ENABLE |
+                       CURSOR_FORMAT_ARGB;
+       } else
+               cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE);
+       I915_WRITE(CURACNTR, cntl);
+
+       intel_crtc->cursor_visible = visible;
+}
+
+static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
+{
+       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;
+       bool visible = base != 0;
+
+       if (intel_crtc->cursor_visible != visible) {
+               uint32_t cntl = I915_READ(pipe == 0 ? CURACNTR : CURBCNTR);
+               if (base) {
+                       cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
+                       cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
+                       cntl |= pipe << 28; /* Connect to correct pipe */
+               } else {
+                       cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
+                       cntl |= CURSOR_MODE_DISABLE;
+               }
+               I915_WRITE(pipe == 0 ? CURACNTR : CURBCNTR, cntl);
+
+               intel_crtc->cursor_visible = visible;
+       }
+       /* and commit changes on next vblank */
+       I915_WRITE(pipe == 0 ? CURABASE : CURBBASE, 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)
+{
+       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 x = intel_crtc->cursor_x;
+       int y = intel_crtc->cursor_y;
+       u32 base, pos;
+       bool visible;
+
+       pos = 0;
+
+       if (intel_crtc->cursor_on && crtc->fb) {
+               base = intel_crtc->cursor_addr;
+               if (x > (int) crtc->fb->width)
+                       base = 0;
+
+               if (y > (int) crtc->fb->height)
+                       base = 0;
+       } else
+               base = 0;
+
+       if (x < 0) {
+               if (x + intel_crtc->cursor_width < 0)
+                       base = 0;
+
+               pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
+               x = -x;
+       }
+       pos |= x << CURSOR_X_SHIFT;
+
+       if (y < 0) {
+               if (y + intel_crtc->cursor_height < 0)
+                       base = 0;
+
+               pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
+               y = -y;
+       }
+       pos |= y << CURSOR_Y_SHIFT;
+
+       visible = base != 0;
+       if (!visible && !intel_crtc->cursor_visible)
+               return;
+
+       I915_WRITE(pipe == 0 ? CURAPOS : CURBPOS, pos);
+       if (IS_845G(dev) || IS_I865G(dev))
+               i845_update_cursor(crtc, base);
+       else
+               i9xx_update_cursor(crtc, base);
+
+       if (visible)
+               intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj);
+}
+
 static int intel_crtc_cursor_set(struct drm_crtc *crtc,
                                 struct drm_file *file_priv,
                                 uint32_t handle,
@@ -3949,11 +4298,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_gem_object *bo;
        struct drm_i915_gem_object *obj_priv;
-       int pipe = intel_crtc->pipe;
-       uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
-       uint32_t base = (pipe == 0) ? CURABASE : CURBBASE;
-       uint32_t temp = I915_READ(control);
-       size_t addr;
+       uint32_t addr;
        int ret;
 
        DRM_DEBUG_KMS("\n");
@@ -3961,12 +4306,6 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        /* if we want to turn off the cursor ignore width and height */
        if (!handle) {
                DRM_DEBUG_KMS("cursor off\n");
-               if (IS_MOBILE(dev) || IS_I9XX(dev)) {
-                       temp &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
-                       temp |= CURSOR_MODE_DISABLE;
-               } else {
-                       temp &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE);
-               }
                addr = 0;
                bo = NULL;
                mutex_lock(&dev->struct_mutex);
@@ -4008,7 +4347,10 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
 
                addr = obj_priv->gtt_offset;
        } else {
-               ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
+               int align = IS_I830(dev) ? 16 * 1024 : 256;
+               ret = i915_gem_attach_phys_object(dev, bo,
+                                                 (intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1,
+                                                 align);
                if (ret) {
                        DRM_ERROR("failed to attach phys object\n");
                        goto fail_locked;
@@ -4019,21 +4361,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        if (!IS_I9XX(dev))
                I915_WRITE(CURSIZE, (height << 12) | width);
 
-       /* Hooray for CUR*CNTR differences */
-       if (IS_MOBILE(dev) || IS_I9XX(dev)) {
-               temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
-               temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
-               temp |= (pipe << 28); /* Connect to correct pipe */
-       } else {
-               temp &= ~(CURSOR_FORMAT_MASK);
-               temp |= CURSOR_ENABLE;
-               temp |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE;
-       }
-
  finish:
-       I915_WRITE(control, temp);
-       I915_WRITE(base, addr);
-
        if (intel_crtc->cursor_bo) {
                if (dev_priv->info->cursor_needs_physical) {
                        if (intel_crtc->cursor_bo != bo)
@@ -4047,6 +4375,10 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
 
        intel_crtc->cursor_addr = addr;
        intel_crtc->cursor_bo = bo;
+       intel_crtc->cursor_width = width;
+       intel_crtc->cursor_height = height;
+
+       intel_crtc_update_cursor(crtc);
 
        return 0;
 fail_unpin:
@@ -4060,34 +4392,12 @@ fail:
 
 static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
 {
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_framebuffer *intel_fb;
-       int pipe = intel_crtc->pipe;
-       uint32_t temp = 0;
-       uint32_t adder;
 
-       if (crtc->fb) {
-               intel_fb = to_intel_framebuffer(crtc->fb);
-               intel_mark_busy(dev, intel_fb->obj);
-       }
+       intel_crtc->cursor_x = x;
+       intel_crtc->cursor_y = y;
 
-       if (x < 0) {
-               temp |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
-               x = -x;
-       }
-       if (y < 0) {
-               temp |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
-               y = -y;
-       }
-
-       temp |= x << CURSOR_X_SHIFT;
-       temp |= y << CURSOR_Y_SHIFT;
-
-       adder = intel_crtc->cursor_addr;
-       I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp);
-       I915_WRITE((pipe == 0) ? CURABASE : CURBBASE, adder);
+       intel_crtc_update_cursor(crtc);
 
        return 0;
 }
@@ -4232,7 +4542,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
                encoder_funcs->commit(encoder);
        }
        /* let the connector get through one full cycle before testing */
-       intel_wait_for_vblank(dev);
+       intel_wait_for_vblank(dev, intel_crtc->pipe);
 
        return crtc;
 }
@@ -4437,7 +4747,7 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
                dpll &= ~DISPLAY_RATE_SELECT_FPA1;
                I915_WRITE(dpll_reg, dpll);
                dpll = I915_READ(dpll_reg);
-               intel_wait_for_vblank(dev);
+               intel_wait_for_vblank(dev, pipe);
                dpll = I915_READ(dpll_reg);
                if (dpll & DISPLAY_RATE_SELECT_FPA1)
                        DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
@@ -4481,7 +4791,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
                dpll |= DISPLAY_RATE_SELECT_FPA1;
                I915_WRITE(dpll_reg, dpll);
                dpll = I915_READ(dpll_reg);
-               intel_wait_for_vblank(dev);
+               intel_wait_for_vblank(dev, pipe);
                dpll = I915_READ(dpll_reg);
                if (!(dpll & DISPLAY_RATE_SELECT_FPA1))
                        DRM_DEBUG_DRIVER("failed to downclock LVDS!\n");
@@ -4671,6 +4981,8 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
            atomic_dec_and_test(&obj_priv->pending_flip))
                DRM_WAKEUP(&dev_priv->pending_flip_queue);
        schedule_work(&work->work);
+
+       trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
 }
 
 void intel_finish_page_flip(struct drm_device *dev, int pipe)
@@ -4748,40 +5060,37 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
        mutex_lock(&dev->struct_mutex);
        ret = intel_pin_and_fence_fb_obj(dev, obj);
-       if (ret != 0) {
-               mutex_unlock(&dev->struct_mutex);
-
-               spin_lock_irqsave(&dev->event_lock, flags);
-               intel_crtc->unpin_work = NULL;
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-
-               kfree(work);
-
-               DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n",
-                                to_intel_bo(obj));
-               return ret;
-       }
+       if (ret)
+               goto cleanup_work;
 
        /* Reference the objects for the scheduled work. */
        drm_gem_object_reference(work->old_fb_obj);
        drm_gem_object_reference(obj);
 
        crtc->fb = fb;
-       i915_gem_object_flush_write_domain(obj);
-       drm_vblank_get(dev, intel_crtc->pipe);
+       ret = i915_gem_object_flush_write_domain(obj);
+       if (ret)
+               goto cleanup_objs;
+
+       ret = drm_vblank_get(dev, intel_crtc->pipe);
+       if (ret)
+               goto cleanup_objs;
+
        obj_priv = to_intel_bo(obj);
        atomic_inc(&obj_priv->pending_flip);
        work->pending_flip_obj = obj;
 
        if (intel_crtc->plane)
-               flip_mask = I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
+               flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
        else
-               flip_mask = I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT;
+               flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
 
-       /* Wait for any previous flip to finish */
-       if (IS_GEN3(dev))
-               while (I915_READ(ISR) & flip_mask)
-                       ;
+       if (IS_GEN3(dev) || IS_GEN2(dev)) {
+               BEGIN_LP_RING(2);
+               OUT_RING(MI_WAIT_FOR_EVENT | flip_mask);
+               OUT_RING(0);
+               ADVANCE_LP_RING();
+       }
 
        /* Offset into the new buffer for cases of shared fbs between CRTCs */
        offset = obj_priv->gtt_offset;
@@ -4795,18 +5104,40 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                OUT_RING(offset | obj_priv->tiling_mode);
                pipesrc = I915_READ(pipesrc_reg); 
                OUT_RING(pipesrc & 0x0fff0fff);
-       } else {
+       } else if (IS_GEN3(dev)) {
                OUT_RING(MI_DISPLAY_FLIP_I915 |
                         MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
                OUT_RING(fb->pitch);
                OUT_RING(offset);
                OUT_RING(MI_NOOP);
+       } else {
+               OUT_RING(MI_DISPLAY_FLIP |
+                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+               OUT_RING(fb->pitch);
+               OUT_RING(offset);
+               OUT_RING(MI_NOOP);
        }
        ADVANCE_LP_RING();
 
        mutex_unlock(&dev->struct_mutex);
 
+       trace_i915_flip_request(intel_crtc->plane, obj);
+
        return 0;
+
+cleanup_objs:
+       drm_gem_object_unreference(work->old_fb_obj);
+       drm_gem_object_unreference(obj);
+cleanup_work:
+       mutex_unlock(&dev->struct_mutex);
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       intel_crtc->unpin_work = NULL;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       kfree(work);
+
+       return ret;
 }
 
 static const struct drm_crtc_helper_funcs intel_helper_funcs = {
@@ -4814,6 +5145,7 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = {
        .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,
@@ -4932,19 +5264,26 @@ static void intel_setup_outputs(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_encoder *encoder;
+       bool dpd_is_edp = false;
 
-       intel_crt_init(dev);
-
-       /* Set up integrated LVDS */
        if (IS_MOBILE(dev) && !IS_I830(dev))
                intel_lvds_init(dev);
 
        if (HAS_PCH_SPLIT(dev)) {
-               int found;
+               dpd_is_edp = intel_dpd_is_edp(dev);
 
                if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED))
                        intel_dp_init(dev, DP_A);
 
+               if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
+                       intel_dp_init(dev, PCH_DP_D);
+       }
+
+       intel_crt_init(dev);
+
+       if (HAS_PCH_SPLIT(dev)) {
+               int found;
+
                if (I915_READ(HDMIB) & PORT_DETECTED) {
                        /* PCH SDVOB multiplex with HDMIB */
                        found = intel_sdvo_init(dev, PCH_SDVOB);
@@ -4963,7 +5302,7 @@ static void intel_setup_outputs(struct drm_device *dev)
                if (I915_READ(PCH_DP_C) & DP_DETECTED)
                        intel_dp_init(dev, PCH_DP_C);
 
-               if (I915_READ(PCH_DP_D) & DP_DETECTED)
+               if (!dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
                        intel_dp_init(dev, PCH_DP_D);
 
        } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) {
@@ -5099,37 +5438,37 @@ static const struct drm_mode_config_funcs intel_mode_funcs = {
 };
 
 static struct drm_gem_object *
-intel_alloc_power_context(struct drm_device *dev)
+intel_alloc_context_page(struct drm_device *dev)
 {
-       struct drm_gem_object *pwrctx;
+       struct drm_gem_object *ctx;
        int ret;
 
-       pwrctx = i915_gem_alloc_object(dev, 4096);
-       if (!pwrctx) {
+       ctx = i915_gem_alloc_object(dev, 4096);
+       if (!ctx) {
                DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
                return NULL;
        }
 
        mutex_lock(&dev->struct_mutex);
-       ret = i915_gem_object_pin(pwrctx, 4096);
+       ret = i915_gem_object_pin(ctx, 4096);
        if (ret) {
                DRM_ERROR("failed to pin power context: %d\n", ret);
                goto err_unref;
        }
 
-       ret = i915_gem_object_set_to_gtt_domain(pwrctx, 1);
+       ret = i915_gem_object_set_to_gtt_domain(ctx, 1);
        if (ret) {
                DRM_ERROR("failed to set-domain on power context: %d\n", ret);
                goto err_unpin;
        }
        mutex_unlock(&dev->struct_mutex);
 
-       return pwrctx;
+       return ctx;
 
 err_unpin:
-       i915_gem_object_unpin(pwrctx);
+       i915_gem_object_unpin(ctx);
 err_unref:
-       drm_gem_object_unreference(pwrctx);
+       drm_gem_object_unreference(ctx);
        mutex_unlock(&dev->struct_mutex);
        return NULL;
 }
@@ -5161,7 +5500,6 @@ void ironlake_enable_drps(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 rgvmodectl = I915_READ(MEMMODECTL);
        u8 fmax, fmin, fstart, vstart;
-       int i = 0;
 
        /* 100ms RC evaluation intervals */
        I915_WRITE(RCUPEI, 100000);
@@ -5205,13 +5543,8 @@ void ironlake_enable_drps(struct drm_device *dev)
        rgvmodectl |= MEMMODE_SWMODE_EN;
        I915_WRITE(MEMMODECTL, rgvmodectl);
 
-       while (I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) {
-               if (i++ > 100) {
-                       DRM_ERROR("stuck trying to change perf mode\n");
-                       break;
-               }
-               msleep(1);
-       }
+       if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 1, 0))
+               DRM_ERROR("stuck trying to change perf mode\n");
        msleep(1);
 
        ironlake_set_drps(dev, fstart);
@@ -5372,7 +5705,28 @@ void intel_init_clock_gating(struct drm_device *dev)
                                        (I915_READ(DISP_ARB_CTL) |
                                                DISP_FBC_WM_DIS));
                }
-               return;
+               /*
+                * Based on the document from hardware guys the following bits
+                * should be set unconditionally in order to enable FBC.
+                * The bit 22 of 0x42000
+                * The bit 22 of 0x42004
+                * The bit 7,8,9 of 0x42020.
+                */
+               if (IS_IRONLAKE_M(dev)) {
+                       I915_WRITE(ILK_DISPLAY_CHICKEN1,
+                                  I915_READ(ILK_DISPLAY_CHICKEN1) |
+                                  ILK_FBCQ_DIS);
+                       I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                                  I915_READ(ILK_DISPLAY_CHICKEN2) |
+                                  ILK_DPARB_GATE);
+                       I915_WRITE(ILK_DSPCLK_GATE,
+                                  I915_READ(ILK_DSPCLK_GATE) |
+                                  ILK_DPFC_DIS1 |
+                                  ILK_DPFC_DIS2 |
+                                  ILK_CLK_FBC);
+               }
+               if (IS_GEN6(dev))
+                       return;
        } else if (IS_G4X(dev)) {
                uint32_t dspclk_gate;
                I915_WRITE(RENCLK_GATE_D1, 0);
@@ -5415,6 +5769,31 @@ void intel_init_clock_gating(struct drm_device *dev)
         * GPU can automatically power down the render unit if given a page
         * to save state.
         */
+       if (IS_IRONLAKE_M(dev)) {
+               if (dev_priv->renderctx == NULL)
+                       dev_priv->renderctx = intel_alloc_context_page(dev);
+               if (dev_priv->renderctx) {
+                       struct drm_i915_gem_object *obj_priv;
+                       obj_priv = to_intel_bo(dev_priv->renderctx);
+                       if (obj_priv) {
+                               BEGIN_LP_RING(4);
+                               OUT_RING(MI_SET_CONTEXT);
+                               OUT_RING(obj_priv->gtt_offset |
+                                               MI_MM_SPACE_GTT |
+                                               MI_SAVE_EXT_STATE_EN |
+                                               MI_RESTORE_EXT_STATE_EN |
+                                               MI_RESTORE_INHIBIT);
+                               OUT_RING(MI_NOOP);
+                               OUT_RING(MI_FLUSH);
+                               ADVANCE_LP_RING();
+                       }
+               } else {
+                       DRM_DEBUG_KMS("Failed to allocate render context."
+                                     "Disable RC6\n");
+                       return;
+               }
+       }
+
        if (I915_HAS_RC6(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) {
                struct drm_i915_gem_object *obj_priv = NULL;
 
@@ -5423,7 +5802,7 @@ void intel_init_clock_gating(struct drm_device *dev)
                } else {
                        struct drm_gem_object *pwrctx;
 
-                       pwrctx = intel_alloc_power_context(dev);
+                       pwrctx = intel_alloc_context_page(dev);
                        if (pwrctx) {
                                dev_priv->pwrctx = pwrctx;
                                obj_priv = to_intel_bo(pwrctx);
@@ -5450,7 +5829,11 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.dpms = i9xx_crtc_dpms;
 
        if (I915_HAS_FBC(dev)) {
-               if (IS_GM45(dev)) {
+               if (IS_IRONLAKE_M(dev)) {
+                       dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
+                       dev_priv->display.enable_fbc = ironlake_enable_fbc;
+                       dev_priv->display.disable_fbc = ironlake_disable_fbc;
+               } else if (IS_GM45(dev)) {
                        dev_priv->display.fbc_enabled = g4x_fbc_enabled;
                        dev_priv->display.enable_fbc = g4x_enable_fbc;
                        dev_priv->display.disable_fbc = g4x_disable_fbc;
@@ -5591,6 +5974,29 @@ static void intel_init_quirks(struct drm_device *dev)
        }
 }
 
+/* Disable the VGA plane that we never use */
+static void i915_disable_vga(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u8 sr1;
+       u32 vga_reg;
+
+       if (HAS_PCH_SPLIT(dev))
+               vga_reg = CPU_VGACNTRL;
+       else
+               vga_reg = VGACNTRL;
+
+       vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
+       outb(1, VGA_SR_INDEX);
+       sr1 = inb(VGA_SR_DATA);
+       outb(sr1 | 1<<5, VGA_SR_DATA);
+       vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
+       udelay(300);
+
+       I915_WRITE(vga_reg, VGA_DISP_DISABLE);
+       POSTING_READ(vga_reg);
+}
+
 void intel_modeset_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5639,6 +6045,9 @@ void intel_modeset_init(struct drm_device *dev)
 
        intel_init_clock_gating(dev);
 
+       /* Just disable it once at startup */
+       i915_disable_vga(dev);
+
        if (IS_IRONLAKE_M(dev)) {
                ironlake_enable_drps(dev);
                intel_init_emon(dev);
@@ -5677,6 +6086,16 @@ void intel_modeset_cleanup(struct drm_device *dev)
        if (dev_priv->display.disable_fbc)
                dev_priv->display.disable_fbc(dev);
 
+       if (dev_priv->renderctx) {
+               struct drm_i915_gem_object *obj_priv;
+
+               obj_priv = to_intel_bo(dev_priv->renderctx);
+               I915_WRITE(CCID, obj_priv->gtt_offset &~ CCID_EN);
+               I915_READ(CCID);
+               i915_gem_object_unpin(dev_priv->renderctx);
+               drm_gem_object_unreference(dev_priv->renderctx);
+       }
+
        if (dev_priv->pwrctx) {
                struct drm_i915_gem_object *obj_priv;