drm/i915: remove LP_RING&friends from modeset code
[cascardo/linux.git] / drivers / gpu / drm / i915 / intel_display.c
index bae38ac..278c0f0 100644 (file)
@@ -24,7 +24,7 @@
  *     Eric Anholt <eric@anholt.net>
  */
 
-#include <linux/cpufreq.h>
+#include <linux/dmi.h>
 #include <linux/module.h>
 #include <linux/input.h>
 #include <linux/i2c.h>
@@ -44,7 +44,6 @@
 #define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))
 
 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);
 static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
 
@@ -360,6 +359,110 @@ static const intel_limit_t intel_limits_ironlake_display_port = {
        .find_pll = intel_find_pll_ironlake_dp,
 };
 
+u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg)
+{
+       unsigned long flags;
+       u32 val = 0;
+
+       spin_lock_irqsave(&dev_priv->dpio_lock, flags);
+       if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) {
+               DRM_ERROR("DPIO idle wait timed out\n");
+               goto out_unlock;
+       }
+
+       I915_WRITE(DPIO_REG, reg);
+       I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_READ | DPIO_PORTID |
+                  DPIO_BYTE);
+       if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) {
+               DRM_ERROR("DPIO read wait timed out\n");
+               goto out_unlock;
+       }
+       val = I915_READ(DPIO_DATA);
+
+out_unlock:
+       spin_unlock_irqrestore(&dev_priv->dpio_lock, flags);
+       return val;
+}
+
+static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg,
+                            u32 val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->dpio_lock, flags);
+       if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) {
+               DRM_ERROR("DPIO idle wait timed out\n");
+               goto out_unlock;
+       }
+
+       I915_WRITE(DPIO_DATA, val);
+       I915_WRITE(DPIO_REG, reg);
+       I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_WRITE | DPIO_PORTID |
+                  DPIO_BYTE);
+       if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100))
+               DRM_ERROR("DPIO write wait timed out\n");
+
+out_unlock:
+       spin_unlock_irqrestore(&dev_priv->dpio_lock, flags);
+}
+
+static void vlv_init_dpio(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /* Reset the DPIO config */
+       I915_WRITE(DPIO_CTL, 0);
+       POSTING_READ(DPIO_CTL);
+       I915_WRITE(DPIO_CTL, 1);
+       POSTING_READ(DPIO_CTL);
+}
+
+static int intel_dual_link_lvds_callback(const struct dmi_system_id *id)
+{
+       DRM_INFO("Forcing lvds to dual link mode on %s\n", id->ident);
+       return 1;
+}
+
+static const struct dmi_system_id intel_dual_link_lvds[] = {
+       {
+               .callback = intel_dual_link_lvds_callback,
+               .ident = "Apple MacBook Pro (Core i5/i7 Series)",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"),
+               },
+       },
+       { }     /* terminating entry */
+};
+
+static bool is_dual_link_lvds(struct drm_i915_private *dev_priv,
+                             unsigned int reg)
+{
+       unsigned int val;
+
+       /* use the module option value if specified */
+       if (i915_lvds_channel_mode > 0)
+               return i915_lvds_channel_mode == 2;
+
+       if (dmi_check_system(intel_dual_link_lvds))
+               return true;
+
+       if (dev_priv->lvds_val)
+               val = dev_priv->lvds_val;
+       else {
+               /* BIOS should set the proper LVDS register value at boot, but
+                * in reality, it doesn't set the value when the lid is closed;
+                * we need to check "the value to be set" in VBT when LVDS
+                * register is uninitialized.
+                */
+               val = I915_READ(reg);
+               if (!(val & ~LVDS_DETECTED))
+                       val = dev_priv->bios_lvds_val;
+               dev_priv->lvds_val = val;
+       }
+       return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP;
+}
+
 static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
                                                int refclk)
 {
@@ -368,8 +471,7 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
        const intel_limit_t *limit;
 
        if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-               if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
-                   LVDS_CLKB_POWER_UP) {
+               if (is_dual_link_lvds(dev_priv, PCH_LVDS)) {
                        /* LVDS dual channel */
                        if (refclk == 100000)
                                limit = &intel_limits_ironlake_dual_lvds_100m;
@@ -397,8 +499,7 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
        const intel_limit_t *limit;
 
        if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-               if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
-                   LVDS_CLKB_POWER_UP)
+               if (is_dual_link_lvds(dev_priv, LVDS))
                        /* LVDS with dual channel */
                        limit = &intel_limits_g4x_dual_channel_lvds;
                else
@@ -536,8 +637,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                 * reliably set up different single/dual channel state, if we
                 * even can.
                 */
-               if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
-                   LVDS_CLKB_POWER_UP)
+               if (is_dual_link_lvds(dev_priv, LVDS))
                        clock.p2 = limit->p2.p2_fast;
                else
                        clock.p2 = limit->p2.p2_slow;
@@ -811,26 +911,28 @@ static void assert_pll(struct drm_i915_private *dev_priv,
 
 /* For ILK+ */
 static void assert_pch_pll(struct drm_i915_private *dev_priv,
-                          enum pipe pipe, bool state)
+                          struct intel_crtc *intel_crtc, bool state)
 {
        int reg;
        u32 val;
        bool cur_state;
 
+       if (!intel_crtc->pch_pll) {
+               WARN(1, "asserting PCH PLL enabled with no PLL\n");
+               return;
+       }
+
        if (HAS_PCH_CPT(dev_priv->dev)) {
                u32 pch_dpll;
 
                pch_dpll = I915_READ(PCH_DPLL_SEL);
 
                /* Make sure the selected PLL is enabled to the transcoder */
-               WARN(!((pch_dpll >> (4 * pipe)) & 8),
-                    "transcoder %d PLL not enabled\n", pipe);
-
-               /* Convert the transcoder pipe number to a pll pipe number */
-               pipe = (pch_dpll >> (4 * pipe)) & 1;
+               WARN(!((pch_dpll >> (4 * intel_crtc->pipe)) & 8),
+                    "transcoder %d PLL not enabled\n", intel_crtc->pipe);
        }
 
-       reg = PCH_DPLL(pipe);
+       reg = intel_crtc->pch_pll->pll_reg;
        val = I915_READ(reg);
        cur_state = !!(val & DPLL_VCO_ENABLE);
        WARN(cur_state != state,
@@ -1206,60 +1308,79 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
  * The PCH PLL needs to be enabled before the PCH transcoder, since it
  * drives the transcoder clock.
  */
-static void intel_enable_pch_pll(struct drm_i915_private *dev_priv,
-                                enum pipe pipe)
+static void intel_enable_pch_pll(struct intel_crtc *intel_crtc)
 {
+       struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
+       struct intel_pch_pll *pll = intel_crtc->pch_pll;
        int reg;
        u32 val;
 
-       if (pipe > 1)
-               return;
-
        /* PCH only available on ILK+ */
        BUG_ON(dev_priv->info->gen < 5);
+       BUG_ON(pll == NULL);
+       BUG_ON(pll->refcount == 0);
+
+       DRM_DEBUG_KMS("enable PCH PLL %x (active %d, on? %d)for crtc %d\n",
+                     pll->pll_reg, pll->active, pll->on,
+                     intel_crtc->base.base.id);
 
        /* PCH refclock must be enabled first */
        assert_pch_refclk_enabled(dev_priv);
 
-       reg = PCH_DPLL(pipe);
+       if (pll->active++ && pll->on) {
+               assert_pch_pll_enabled(dev_priv, intel_crtc);
+               return;
+       }
+
+       DRM_DEBUG_KMS("enabling PCH PLL %x\n", pll->pll_reg);
+
+       reg = pll->pll_reg;
        val = I915_READ(reg);
        val |= DPLL_VCO_ENABLE;
        I915_WRITE(reg, val);
        POSTING_READ(reg);
        udelay(200);
+
+       pll->on = true;
 }
 
-static void intel_disable_pch_pll(struct drm_i915_private *dev_priv,
-                                 enum pipe pipe)
+static void intel_disable_pch_pll(struct intel_crtc *intel_crtc)
 {
+       struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
+       struct intel_pch_pll *pll = intel_crtc->pch_pll;
        int reg;
-       u32 val, pll_mask = TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL,
-               pll_sel = TRANSC_DPLL_ENABLE;
-
-       if (pipe > 1)
-               return;
+       u32 val;
 
        /* PCH only available on ILK+ */
        BUG_ON(dev_priv->info->gen < 5);
+       if (pll == NULL)
+              return;
 
-       /* Make sure transcoder isn't still depending on us */
-       assert_transcoder_disabled(dev_priv, pipe);
-
-       if (pipe == 0)
-               pll_sel |= TRANSC_DPLLA_SEL;
-       else if (pipe == 1)
-               pll_sel |= TRANSC_DPLLB_SEL;
+       BUG_ON(pll->refcount == 0);
 
+       DRM_DEBUG_KMS("disable PCH PLL %x (active %d, on? %d) for crtc %d\n",
+                     pll->pll_reg, pll->active, pll->on,
+                     intel_crtc->base.base.id);
 
-       if ((I915_READ(PCH_DPLL_SEL) & pll_mask) == pll_sel)
+       BUG_ON(pll->active == 0);
+       if (--pll->active) {
+               assert_pch_pll_enabled(dev_priv, intel_crtc);
                return;
+       }
+
+       DRM_DEBUG_KMS("disabling PCH PLL %x\n", pll->pll_reg);
+
+       /* Make sure transcoder isn't still depending on us */
+       assert_transcoder_disabled(dev_priv, intel_crtc->pipe);
 
-       reg = PCH_DPLL(pipe);
+       reg = pll->pll_reg;
        val = I915_READ(reg);
        val &= ~DPLL_VCO_ENABLE;
        I915_WRITE(reg, val);
        POSTING_READ(reg);
        udelay(200);
+
+       pll->on = false;
 }
 
 static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
@@ -1273,7 +1394,7 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
        BUG_ON(dev_priv->info->gen < 5);
 
        /* Make sure PCH DPLL is enabled */
-       assert_pch_pll_enabled(dev_priv, pipe);
+       assert_pch_pll_enabled(dev_priv, to_intel_crtc(crtc));
 
        /* FDI must be feeding us bits for PCH ports */
        assert_fdi_tx_enabled(dev_priv, pipe);
@@ -1415,7 +1536,7 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv,
  * Plane regs are double buffered, going from enabled->disabled needs a
  * trigger in order to latch.  The display address reg provides this.
  */
-static void intel_flush_display_plane(struct drm_i915_private *dev_priv,
+void intel_flush_display_plane(struct drm_i915_private *dev_priv,
                                      enum plane plane)
 {
        I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane)));
@@ -1526,490 +1647,6 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
        disable_pch_hdmi(dev_priv, pipe, HDMID);
 }
 
-static void i8xx_disable_fbc(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 fbc_ctl;
-
-       /* Disable compression */
-       fbc_ctl = I915_READ(FBC_CONTROL);
-       if ((fbc_ctl & FBC_CTL_EN) == 0)
-               return;
-
-       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)) {
-               DRM_DEBUG_KMS("FBC idle timed out\n");
-               return;
-       }
-
-       DRM_DEBUG_KMS("disabled FBC\n");
-}
-
-static void i8xx_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 = intel_fb->obj;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int cfb_pitch;
-       int plane, i;
-       u32 fbc_ctl, fbc_ctl2;
-
-       cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
-       if (fb->pitches[0] < cfb_pitch)
-               cfb_pitch = fb->pitches[0];
-
-       /* FBC_CTL wants 64B units */
-       cfb_pitch = (cfb_pitch / 64) - 1;
-       plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB;
-
-       /* Clear old tags */
-       for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
-               I915_WRITE(FBC_TAG + (i * 4), 0);
-
-       /* Set it up... */
-       fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
-       fbc_ctl2 |= plane;
-       I915_WRITE(FBC_CONTROL2, fbc_ctl2);
-       I915_WRITE(FBC_FENCE_OFF, crtc->y);
-
-       /* enable it... */
-       fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC;
-       if (IS_I945GM(dev))
-               fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
-       fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
-       fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
-       fbc_ctl |= obj->fence_reg;
-       I915_WRITE(FBC_CONTROL, fbc_ctl);
-
-       DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %d, ",
-                     cfb_pitch, crtc->y, intel_crtc->plane);
-}
-
-static bool i8xx_fbc_enabled(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
-}
-
-static void g4x_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 = 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;
-
-       dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
-       dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
-       I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
-
-       I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
-                  (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
-                  (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
-       I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
-
-       /* enable it... */
-       I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN);
-
-       DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
-}
-
-static void g4x_disable_fbc(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 dpfc_ctl;
-
-       /* Disable compression */
-       dpfc_ctl = I915_READ(DPFC_CONTROL);
-       if (dpfc_ctl & DPFC_CTL_EN) {
-               dpfc_ctl &= ~DPFC_CTL_EN;
-               I915_WRITE(DPFC_CONTROL, dpfc_ctl);
-
-               DRM_DEBUG_KMS("disabled FBC\n");
-       }
-}
-
-static bool g4x_fbc_enabled(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
-}
-
-static void sandybridge_blit_fbc_update(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 blt_ecoskpd;
-
-       /* Make sure blitter notifies FBC of writes */
-       gen6_gt_force_wake_get(dev_priv);
-       blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
-       blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
-               GEN6_BLITTER_LOCK_SHIFT;
-       I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
-       blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
-       I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
-       blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
-                        GEN6_BLITTER_LOCK_SHIFT);
-       I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
-       POSTING_READ(GEN6_BLITTER_ECOSKPD);
-       gen6_gt_force_wake_put(dev_priv);
-}
-
-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 = 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;
-
-       dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
-       dpfc_ctl &= DPFC_RESERVED;
-       dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
-       /* Set persistent mode for front-buffer rendering, ala X. */
-       dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE;
-       dpfc_ctl |= (DPFC_CTL_FENCE_EN | obj->fence_reg);
-       I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
-
-       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->gtt_offset | ILK_FBC_RT_VALID);
-       /* enable it... */
-       I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
-
-       if (IS_GEN6(dev)) {
-               I915_WRITE(SNB_DPFC_CTL_SA,
-                          SNB_CPU_FENCE_ENABLE | obj->fence_reg);
-               I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
-               sandybridge_blit_fbc_update(dev);
-       }
-
-       DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
-}
-
-static 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);
-       if (dpfc_ctl & DPFC_CTL_EN) {
-               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;
-
-       if (!dev_priv->display.fbc_enabled)
-               return false;
-
-       return dev_priv->display.fbc_enabled(dev);
-}
-
-static void intel_fbc_work_fn(struct work_struct *__work)
-{
-       struct intel_fbc_work *work =
-               container_of(to_delayed_work(__work),
-                            struct intel_fbc_work, work);
-       struct drm_device *dev = work->crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       mutex_lock(&dev->struct_mutex);
-       if (work == dev_priv->fbc_work) {
-               /* Double check that we haven't switched fb without cancelling
-                * the prior work.
-                */
-               if (work->crtc->fb == work->fb) {
-                       dev_priv->display.enable_fbc(work->crtc,
-                                                    work->interval);
-
-                       dev_priv->cfb_plane = to_intel_crtc(work->crtc)->plane;
-                       dev_priv->cfb_fb = work->crtc->fb->base.id;
-                       dev_priv->cfb_y = work->crtc->y;
-               }
-
-               dev_priv->fbc_work = NULL;
-       }
-       mutex_unlock(&dev->struct_mutex);
-
-       kfree(work);
-}
-
-static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
-{
-       if (dev_priv->fbc_work == NULL)
-               return;
-
-       DRM_DEBUG_KMS("cancelling pending FBC enable\n");
-
-       /* Synchronisation is provided by struct_mutex and checking of
-        * dev_priv->fbc_work, so we can perform the cancellation
-        * entirely asynchronously.
-        */
-       if (cancel_delayed_work(&dev_priv->fbc_work->work))
-               /* tasklet was killed before being run, clean up */
-               kfree(dev_priv->fbc_work);
-
-       /* Mark the work as no longer wanted so that if it does
-        * wake-up (because the work was already running and waiting
-        * for our mutex), it will discover that is no longer
-        * necessary to run.
-        */
-       dev_priv->fbc_work = NULL;
-}
-
-static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
-{
-       struct intel_fbc_work *work;
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (!dev_priv->display.enable_fbc)
-               return;
-
-       intel_cancel_fbc_work(dev_priv);
-
-       work = kzalloc(sizeof *work, GFP_KERNEL);
-       if (work == NULL) {
-               dev_priv->display.enable_fbc(crtc, interval);
-               return;
-       }
-
-       work->crtc = crtc;
-       work->fb = crtc->fb;
-       work->interval = interval;
-       INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
-
-       dev_priv->fbc_work = work;
-
-       DRM_DEBUG_KMS("scheduling delayed FBC enable\n");
-
-       /* Delay the actual enabling to let pageflipping cease and the
-        * display to settle before starting the compression. Note that
-        * this delay also serves a second purpose: it allows for a
-        * vblank to pass after disabling the FBC before we attempt
-        * to modify the control registers.
-        *
-        * A more complicated solution would involve tracking vblanks
-        * following the termination of the page-flipping sequence
-        * and indeed performing the enable as a co-routine and not
-        * waiting synchronously upon the vblank.
-        */
-       schedule_delayed_work(&work->work, msecs_to_jiffies(50));
-}
-
-void intel_disable_fbc(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       intel_cancel_fbc_work(dev_priv);
-
-       if (!dev_priv->display.disable_fbc)
-               return;
-
-       dev_priv->display.disable_fbc(dev);
-       dev_priv->cfb_plane = -1;
-}
-
-/**
- * intel_update_fbc - enable/disable FBC as needed
- * @dev: the drm_device
- *
- * Set up the framebuffer compression hardware at mode set time.  We
- * enable it if possible:
- *   - plane A only (on pre-965)
- *   - no pixel mulitply/line duplication
- *   - no alpha buffer discard
- *   - no dual wide
- *   - framebuffer <= 2048 in width, 1536 in height
- *
- * We can't assume that any compression will take place (worst case),
- * so the compressed buffer has to be the same size as the uncompressed
- * one.  It also must reside (along with the line length buffer) in
- * stolen memory.
- *
- * We need to enable/disable FBC on a global basis.
- */
-static void intel_update_fbc(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       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;
-       int enable_fbc;
-
-       DRM_DEBUG_KMS("\n");
-
-       if (!i915_powersave)
-               return;
-
-       if (!I915_HAS_FBC(dev))
-               return;
-
-       /*
-        * If FBC is already on, we just have to verify that we can
-        * keep it that way...
-        * Need to disable if:
-        *   - more than one pipe is active
-        *   - changing FBC params (stride, fence, mode)
-        *   - new fb is too large to fit in compressed buffer
-        *   - 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 && tmp_crtc->fb) {
-                       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;
-               }
-       }
-
-       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 = intel_fb->obj;
-
-       enable_fbc = i915_enable_fbc;
-       if (enable_fbc < 0) {
-               DRM_DEBUG_KMS("fbc set to per-chip default\n");
-               enable_fbc = 1;
-               if (INTEL_INFO(dev)->gen <= 6)
-                       enable_fbc = 0;
-       }
-       if (!enable_fbc) {
-               DRM_DEBUG_KMS("fbc disabled per module param\n");
-               dev_priv->no_fbc_reason = FBC_MODULE_PARAM;
-               goto out_disable;
-       }
-       if (intel_fb->obj->base.size > dev_priv->cfb_size) {
-               DRM_DEBUG_KMS("framebuffer too large, disabling "
-                             "compression\n");
-               dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
-               goto out_disable;
-       }
-       if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
-           (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
-               DRM_DEBUG_KMS("mode incompatible with compression, "
-                             "disabling\n");
-               dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
-               goto out_disable;
-       }
-       if ((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)) && intel_crtc->plane != 0) {
-               DRM_DEBUG_KMS("plane not 0, disabling compression\n");
-               dev_priv->no_fbc_reason = FBC_BAD_PLANE;
-               goto out_disable;
-       }
-
-       /* The use of a CPU fence is mandatory in order to detect writes
-        * by the CPU to the scanout and trigger updates to the FBC.
-        */
-       if (obj->tiling_mode != I915_TILING_X ||
-           obj->fence_reg == I915_FENCE_REG_NONE) {
-               DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
-               dev_priv->no_fbc_reason = FBC_NOT_TILED;
-               goto out_disable;
-       }
-
-       /* If the kernel debugger is active, always disable compression */
-       if (in_dbg_master())
-               goto out_disable;
-
-       /* If the scanout has not changed, don't modify the FBC settings.
-        * Note that we make the fundamental assumption that the fb->obj
-        * cannot be unpinned (and have its GTT offset and fence revoked)
-        * without first being decoupled from the scanout and FBC disabled.
-        */
-       if (dev_priv->cfb_plane == intel_crtc->plane &&
-           dev_priv->cfb_fb == fb->base.id &&
-           dev_priv->cfb_y == crtc->y)
-               return;
-
-       if (intel_fbc_enabled(dev)) {
-               /* We update FBC along two paths, after changing fb/crtc
-                * configuration (modeswitching) and after page-flipping
-                * finishes. For the latter, we know that not only did
-                * we disable the FBC at the start of the page-flip
-                * sequence, but also more than one vblank has passed.
-                *
-                * For the former case of modeswitching, it is possible
-                * to switch between two FBC valid configurations
-                * instantaneously so we do need to disable the FBC
-                * before we can modify its control registers. We also
-                * have to wait for the next vblank for that to take
-                * effect. However, since we delay enabling FBC we can
-                * assume that a vblank has passed since disabling and
-                * that we can safely alter the registers in the deferred
-                * callback.
-                *
-                * In the scenario that we go from a valid to invalid
-                * and then back to valid FBC configuration we have
-                * no strict enforcement that a vblank occurred since
-                * disabling the FBC. However, along all current pipe
-                * disabling paths we do need to wait for a vblank at
-                * some point. And we wait before enabling FBC anyway.
-                */
-               DRM_DEBUG_KMS("disabling active FBC for update\n");
-               intel_disable_fbc(dev);
-       }
-
-       intel_enable_fbc(crtc, 500);
-       return;
-
-out_disable:
-       /* Multiple disables should be harmless */
-       if (intel_fbc_enabled(dev)) {
-               DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
-               intel_disable_fbc(dev);
-       }
-}
-
 int
 intel_pin_and_fence_fb_obj(struct drm_device *dev,
                           struct drm_i915_gem_object *obj,
@@ -2050,13 +1687,11 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
         * framebuffer compression.  For simplicity, we always install
         * a fence as the cost is not that onerous.
         */
-       if (obj->tiling_mode != I915_TILING_NONE) {
-               ret = i915_gem_object_get_fence(obj, pipelined);
-               if (ret)
-                       goto err_unpin;
+       ret = i915_gem_object_get_fence(obj);
+       if (ret)
+               goto err_unpin;
 
-               i915_gem_object_pin_fence(obj);
-       }
+       i915_gem_object_pin_fence(obj);
 
        dev_priv->mm.interruptible = true;
        return 0;
@@ -2137,7 +1772,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                      Start, Offset, x, y, fb->pitches[0]);
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        if (INTEL_INFO(dev)->gen >= 4) {
-               I915_WRITE(DSPSURF(plane), Start);
+               I915_MODIFY_DISPBASE(DSPSURF(plane), Start);
                I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
                I915_WRITE(DSPADDR(plane), Offset);
        } else
@@ -2217,7 +1852,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
        DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
                      Start, Offset, x, y, fb->pitches[0]);
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
-       I915_WRITE(DSPSURF(plane), Start);
+       I915_MODIFY_DISPBASE(DSPSURF(plane), Start);
        I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
        I915_WRITE(DSPADDR(plane), Offset);
        POSTING_READ(reg);
@@ -2232,16 +1867,12 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret;
-
-       ret = dev_priv->display.update_plane(crtc, fb, x, y);
-       if (ret)
-               return ret;
 
-       intel_update_fbc(dev);
+       if (dev_priv->display.disable_fbc)
+               dev_priv->display.disable_fbc(dev);
        intel_increase_pllclock(crtc);
 
-       return 0;
+       return dev_priv->display.update_plane(crtc, fb, x, y);
 }
 
 static int
@@ -2276,6 +1907,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                    struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int ret;
@@ -2312,8 +1944,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        if (old_fb)
                intel_finish_fb(old_fb);
 
-       ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
-                                        LEAVE_ATOMIC_MODE_SET);
+       ret = dev_priv->display.update_plane(crtc, crtc->fb, x, y);
        if (ret) {
                intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
                mutex_unlock(&dev->struct_mutex);
@@ -2326,6 +1957,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj);
        }
 
+       intel_update_fbc(dev);
        mutex_unlock(&dev->struct_mutex);
 
        if (!dev->primary->master)
@@ -2547,7 +2179,7 @@ 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;
-       u32 reg, temp, i;
+       u32 reg, temp, i, retry;
 
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
@@ -2599,15 +2231,19 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
                POSTING_READ(reg);
                udelay(500);
 
-               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(reg, temp | FDI_RX_BIT_LOCK);
-                       DRM_DEBUG_KMS("FDI train 1 done.\n");
-                       break;
+               for (retry = 0; retry < 5; retry++) {
+                       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(reg, temp | FDI_RX_BIT_LOCK);
+                               DRM_DEBUG_KMS("FDI train 1 done.\n");
+                               break;
+                       }
+                       udelay(50);
                }
+               if (retry < 5)
+                       break;
        }
        if (i == 4)
                DRM_ERROR("FDI train 1 fail!\n");
@@ -2648,15 +2284,19 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
                POSTING_READ(reg);
                udelay(500);
 
-               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(reg, temp | FDI_RX_SYMBOL_LOCK);
-                       DRM_DEBUG_KMS("FDI train 2 done.\n");
-                       break;
+               for (retry = 0; retry < 5; retry++) {
+                       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(reg, temp | FDI_RX_SYMBOL_LOCK);
+                               DRM_DEBUG_KMS("FDI train 2 done.\n");
+                               break;
+                       }
+                       udelay(50);
                }
+               if (retry < 5)
+                       break;
        }
        if (i == 4)
                DRM_ERROR("FDI train 2 fail!\n");
@@ -2910,16 +2550,14 @@ static void intel_clear_scanline_wait(struct drm_device *dev)
 
 static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 {
-       struct drm_i915_gem_object *obj;
-       struct drm_i915_private *dev_priv;
+       struct drm_device *dev = crtc->dev;
 
        if (crtc->fb == NULL)
                return;
 
-       obj = to_intel_framebuffer(crtc->fb)->obj;
-       dev_priv = crtc->dev->dev_private;
-       wait_event(dev_priv->pending_flip_queue,
-                  atomic_read(&obj->pending_flip) == 0);
+       mutex_lock(&dev->struct_mutex);
+       intel_finish_fb(crtc->fb);
+       mutex_unlock(&dev->struct_mutex);
 }
 
 static bool intel_crtc_driving_pch(struct drm_crtc *crtc)
@@ -2961,29 +2599,36 @@ static void ironlake_pch_enable(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;
-       u32 reg, temp, transc_sel;
+       u32 reg, temp;
 
        /* For PCH output, training FDI link */
        dev_priv->display.fdi_link_train(crtc);
 
-       intel_enable_pch_pll(dev_priv, pipe);
+       intel_enable_pch_pll(intel_crtc);
 
        if (HAS_PCH_CPT(dev)) {
-               transc_sel = intel_crtc->use_pll_a ? TRANSC_DPLLA_SEL :
-                       TRANSC_DPLLB_SEL;
+               u32 sel;
 
-               /* Be sure PCH DPLL SEL is set */
                temp = I915_READ(PCH_DPLL_SEL);
-               if (pipe == 0) {
-                       temp &= ~(TRANSA_DPLLB_SEL);
-                       temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
-               } else if (pipe == 1) {
-                       temp &= ~(TRANSB_DPLLB_SEL);
-                       temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
-               } else if (pipe == 2) {
-                       temp &= ~(TRANSC_DPLLB_SEL);
-                       temp |= (TRANSC_DPLL_ENABLE | transc_sel);
+               switch (pipe) {
+               default:
+               case 0:
+                       temp |= TRANSA_DPLL_ENABLE;
+                       sel = TRANSA_DPLLB_SEL;
+                       break;
+               case 1:
+                       temp |= TRANSB_DPLL_ENABLE;
+                       sel = TRANSB_DPLLB_SEL;
+                       break;
+               case 2:
+                       temp |= TRANSC_DPLL_ENABLE;
+                       sel = TRANSC_DPLLB_SEL;
+                       break;
                }
+               if (intel_crtc->pch_pll->pll_reg == _PCH_DPLL_B)
+                       temp |= sel;
+               else
+                       temp &= ~sel;
                I915_WRITE(PCH_DPLL_SEL, temp);
        }
 
@@ -3041,6 +2686,79 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
        intel_enable_transcoder(dev_priv, pipe);
 }
 
+static void intel_put_pch_pll(struct intel_crtc *intel_crtc)
+{
+       struct intel_pch_pll *pll = intel_crtc->pch_pll;
+
+       if (pll == NULL)
+               return;
+
+       if (pll->refcount == 0) {
+               WARN(1, "bad PCH PLL refcount\n");
+               return;
+       }
+
+       --pll->refcount;
+       intel_crtc->pch_pll = NULL;
+}
+
+static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u32 dpll, u32 fp)
+{
+       struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
+       struct intel_pch_pll *pll;
+       int i;
+
+       pll = intel_crtc->pch_pll;
+       if (pll) {
+               DRM_DEBUG_KMS("CRTC:%d reusing existing PCH PLL %x\n",
+                             intel_crtc->base.base.id, pll->pll_reg);
+               goto prepare;
+       }
+
+       for (i = 0; i < dev_priv->num_pch_pll; i++) {
+               pll = &dev_priv->pch_plls[i];
+
+               /* Only want to check enabled timings first */
+               if (pll->refcount == 0)
+                       continue;
+
+               if (dpll == (I915_READ(pll->pll_reg) & 0x7fffffff) &&
+                   fp == I915_READ(pll->fp0_reg)) {
+                       DRM_DEBUG_KMS("CRTC:%d sharing existing PCH PLL %x (refcount %d, ative %d)\n",
+                                     intel_crtc->base.base.id,
+                                     pll->pll_reg, pll->refcount, pll->active);
+
+                       goto found;
+               }
+       }
+
+       /* Ok no matching timings, maybe there's a free one? */
+       for (i = 0; i < dev_priv->num_pch_pll; i++) {
+               pll = &dev_priv->pch_plls[i];
+               if (pll->refcount == 0) {
+                       DRM_DEBUG_KMS("CRTC:%d allocated PCH PLL %x\n",
+                                     intel_crtc->base.base.id, pll->pll_reg);
+                       goto found;
+               }
+       }
+
+       return NULL;
+
+found:
+       intel_crtc->pch_pll = pll;
+       pll->refcount++;
+       DRM_DEBUG_DRIVER("using pll %d for pipe %d\n", i, intel_crtc->pipe);
+prepare: /* separate function? */
+       DRM_DEBUG_DRIVER("switching PLL %x off\n", pll->pll_reg);
+       I915_WRITE(pll->fp0_reg, fp);
+       I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE);
+
+       POSTING_READ(pll->pll_reg);
+       udelay(150);
+       pll->on = false;
+       return pll;
+}
+
 void intel_cpt_verify_modeset(struct drm_device *dev, int pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3185,8 +2903,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
        }
 
        /* disable PCH DPLL */
-       if (!intel_crtc->no_pll)
-               intel_disable_pch_pll(dev_priv, pipe);
+       intel_disable_pch_pll(intel_crtc);
 
        /* Switch from PCDclk to Rawclk */
        reg = FDI_RX_CTL(pipe);
@@ -3242,6 +2959,12 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
        }
 }
 
+static void ironlake_crtc_off(struct drm_crtc *crtc)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       intel_put_pch_pll(intel_crtc);
+}
+
 static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
 {
        if (!enable && intel_crtc->overlay) {
@@ -3333,6 +3056,10 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
        }
 }
 
+static void i9xx_crtc_off(struct drm_crtc *crtc)
+{
+}
+
 /**
  * Sets the power management mode of the pipe and plane.
  */
@@ -3380,25 +3107,11 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
 {
        struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
        struct drm_device *dev = crtc->dev;
-
-       /* Flush any pending WAITs before we disable the pipe. Note that
-        * we need to drop the struct_mutex in order to acquire it again
-        * during the lowlevel dpms routines around a couple of the
-        * operations. It does not look trivial nor desirable to move
-        * that locking higher. So instead we leave a window for the
-        * submission of further commands on the fb before we can actually
-        * disable it. This race with userspace exists anyway, and we can
-        * only rely on the pipe being disabled by userspace after it
-        * receives the hotplug notification and has flushed any pending
-        * batches.
-        */
-       if (crtc->fb) {
-               mutex_lock(&dev->struct_mutex);
-               intel_finish_fb(crtc->fb);
-               mutex_unlock(&dev->struct_mutex);
-       }
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+       dev_priv->display.off(crtc);
+
        assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane);
        assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe);
 
@@ -3484,6 +3197,11 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
        return true;
 }
 
+static int valleyview_get_display_clock_speed(struct drm_device *dev)
+{
+       return 400000; /* FIXME */
+}
+
 static int i945_get_display_clock_speed(struct drm_device *dev)
 {
        return 400000;
@@ -3581,5293 +3299,3152 @@ ironlake_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock,
        fdi_reduce_ratio(&m_n->link_m, &m_n->link_n);
 }
 
-
-struct intel_watermark_params {
-       unsigned long fifo_size;
-       unsigned long max_wm;
-       unsigned long default_wm;
-       unsigned long guard_size;
-       unsigned long cacheline_size;
-};
-
-/* Pineview has different values for various configs */
-static const struct intel_watermark_params pineview_display_wm = {
-       PINEVIEW_DISPLAY_FIFO,
-       PINEVIEW_MAX_WM,
-       PINEVIEW_DFT_WM,
-       PINEVIEW_GUARD_WM,
-       PINEVIEW_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params pineview_display_hplloff_wm = {
-       PINEVIEW_DISPLAY_FIFO,
-       PINEVIEW_MAX_WM,
-       PINEVIEW_DFT_HPLLOFF_WM,
-       PINEVIEW_GUARD_WM,
-       PINEVIEW_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params pineview_cursor_wm = {
-       PINEVIEW_CURSOR_FIFO,
-       PINEVIEW_CURSOR_MAX_WM,
-       PINEVIEW_CURSOR_DFT_WM,
-       PINEVIEW_CURSOR_GUARD_WM,
-       PINEVIEW_FIFO_LINE_SIZE,
-};
-static const struct intel_watermark_params pineview_cursor_hplloff_wm = {
-       PINEVIEW_CURSOR_FIFO,
-       PINEVIEW_CURSOR_MAX_WM,
-       PINEVIEW_CURSOR_DFT_WM,
-       PINEVIEW_CURSOR_GUARD_WM,
-       PINEVIEW_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params g4x_wm_info = {
-       G4X_FIFO_SIZE,
-       G4X_MAX_WM,
-       G4X_MAX_WM,
-       2,
-       G4X_FIFO_LINE_SIZE,
-};
-static const 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 const 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 const struct intel_watermark_params i945_wm_info = {
-       I945_FIFO_SIZE,
-       I915_MAX_WM,
-       1,
-       2,
-       I915_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params i915_wm_info = {
-       I915_FIFO_SIZE,
-       I915_MAX_WM,
-       1,
-       2,
-       I915_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params i855_wm_info = {
-       I855GM_FIFO_SIZE,
-       I915_MAX_WM,
-       1,
-       2,
-       I830_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params i830_wm_info = {
-       I830_FIFO_SIZE,
-       I915_MAX_WM,
-       1,
-       2,
-       I830_FIFO_LINE_SIZE
-};
-
-static const struct intel_watermark_params ironlake_display_wm_info = {
-       ILK_DISPLAY_FIFO,
-       ILK_DISPLAY_MAXWM,
-       ILK_DISPLAY_DFTWM,
-       2,
-       ILK_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params ironlake_cursor_wm_info = {
-       ILK_CURSOR_FIFO,
-       ILK_CURSOR_MAXWM,
-       ILK_CURSOR_DFTWM,
-       2,
-       ILK_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params ironlake_display_srwm_info = {
-       ILK_DISPLAY_SR_FIFO,
-       ILK_DISPLAY_MAX_SRWM,
-       ILK_DISPLAY_DFT_SRWM,
-       2,
-       ILK_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params ironlake_cursor_srwm_info = {
-       ILK_CURSOR_SR_FIFO,
-       ILK_CURSOR_MAX_SRWM,
-       ILK_CURSOR_DFT_SRWM,
-       2,
-       ILK_FIFO_LINE_SIZE
-};
-
-static const struct intel_watermark_params sandybridge_display_wm_info = {
-       SNB_DISPLAY_FIFO,
-       SNB_DISPLAY_MAXWM,
-       SNB_DISPLAY_DFTWM,
-       2,
-       SNB_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params sandybridge_cursor_wm_info = {
-       SNB_CURSOR_FIFO,
-       SNB_CURSOR_MAXWM,
-       SNB_CURSOR_DFTWM,
-       2,
-       SNB_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params sandybridge_display_srwm_info = {
-       SNB_DISPLAY_SR_FIFO,
-       SNB_DISPLAY_MAX_SRWM,
-       SNB_DISPLAY_DFT_SRWM,
-       2,
-       SNB_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params sandybridge_cursor_srwm_info = {
-       SNB_CURSOR_SR_FIFO,
-       SNB_CURSOR_MAX_SRWM,
-       SNB_CURSOR_DFT_SRWM,
-       2,
-       SNB_FIFO_LINE_SIZE
-};
-
+static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
+{
+       if (i915_panel_use_ssc >= 0)
+               return i915_panel_use_ssc != 0;
+       return dev_priv->lvds_use_ssc
+               && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
+}
 
 /**
- * intel_calculate_wm - calculate watermark level
- * @clock_in_khz: pixel clock
- * @wm: chip FIFO params
- * @pixel_size: display pixel size
- * @latency_ns: memory latency for the platform
+ * intel_choose_pipe_bpp_dither - figure out what color depth the pipe should send
+ * @crtc: CRTC structure
+ * @mode: requested mode
+ *
+ * A pipe may be connected to one or more outputs.  Based on the depth of the
+ * attached framebuffer, choose a good color depth to use on the pipe.
  *
- * Calculate the watermark level (the level at which the display plane will
- * start fetching from memory again).  Each chip has a different display
- * FIFO size and allocation, so the caller needs to figure that out and pass
- * in the correct intel_watermark_params structure.
+ * If possible, match the pipe depth to the fb depth.  In some cases, this
+ * isn't ideal, because the connected output supports a lesser or restricted
+ * set of depths.  Resolve that here:
+ *    LVDS typically supports only 6bpc, so clamp down in that case
+ *    HDMI supports only 8bpc or 12bpc, so clamp to 8bpc with dither for 10bpc
+ *    Displays may support a restricted set as well, check EDID and clamp as
+ *      appropriate.
+ *    DP may want to dither down to 6bpc to fit larger modes
  *
- * As the pixel clock runs, the FIFO will be drained at a rate that depends
- * on the pixel size.  When it reaches the watermark level, it'll start
- * fetching FIFO line sized based chunks from memory until the FIFO fills
- * past the watermark point.  If the FIFO drains completely, a FIFO underrun
- * will occur, and a display engine hang could result.
+ * RETURNS:
+ * Dithering requirement (i.e. false if display bpc and pipe bpc match,
+ * true if they don't match).
  */
-static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
-                                       const struct intel_watermark_params *wm,
-                                       int fifo_size,
-                                       int pixel_size,
-                                       unsigned long latency_ns)
+static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
+                                        unsigned int *pipe_bpp,
+                                        struct drm_display_mode *mode)
 {
-       long entries_required, wm_size;
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+       unsigned int display_bpc = UINT_MAX, bpc;
 
-       /*
-        * Note: we need to make sure we don't overflow for various clock &
-        * latency values.
-        * clocks go from a few thousand to several hundred thousand.
-        * latency is usually a few thousand
-        */
-       entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) /
-               1000;
-       entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size);
+       /* Walk the encoders & connectors on this crtc, get min bpc */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
 
-       DRM_DEBUG_KMS("FIFO entries required for mode: %ld\n", entries_required);
+               if (encoder->crtc != crtc)
+                       continue;
 
-       wm_size = fifo_size - (entries_required + wm->guard_size);
+               if (intel_encoder->type == INTEL_OUTPUT_LVDS) {
+                       unsigned int lvds_bpc;
 
-       DRM_DEBUG_KMS("FIFO watermark level: %ld\n", wm_size);
+                       if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) ==
+                           LVDS_A3_POWER_UP)
+                               lvds_bpc = 8;
+                       else
+                               lvds_bpc = 6;
 
-       /* Don't promote wm_size to unsigned... */
-       if (wm_size > (long)wm->max_wm)
-               wm_size = wm->max_wm;
-       if (wm_size <= 0)
-               wm_size = wm->default_wm;
-       return wm_size;
-}
+                       if (lvds_bpc < display_bpc) {
+                               DRM_DEBUG_KMS("clamping display bpc (was %d) to LVDS (%d)\n", display_bpc, lvds_bpc);
+                               display_bpc = lvds_bpc;
+                       }
+                       continue;
+               }
 
-struct cxsr_latency {
-       int is_desktop;
-       int is_ddr3;
-       unsigned long fsb_freq;
-       unsigned long mem_freq;
-       unsigned long display_sr;
-       unsigned long display_hpll_disable;
-       unsigned long cursor_sr;
-       unsigned long cursor_hpll_disable;
-};
+               if (intel_encoder->type == INTEL_OUTPUT_EDP) {
+                       /* Use VBT settings if we have an eDP panel */
+                       unsigned int edp_bpc = dev_priv->edp.bpp / 3;
 
-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 */
-       {1, 1, 800, 667, 6420, 36420, 6873, 36873},    /* DDR3-667 SC */
-       {1, 1, 800, 800, 5902, 35902, 6318, 36318},    /* DDR3-800 SC */
-
-       {1, 0, 667, 400, 3400, 33400, 4021, 34021},    /* DDR2-400 SC */
-       {1, 0, 667, 667, 3372, 33372, 3845, 33845},    /* DDR2-667 SC */
-       {1, 0, 667, 800, 3386, 33386, 3822, 33822},    /* DDR2-800 SC */
-       {1, 1, 667, 667, 6438, 36438, 6911, 36911},    /* DDR3-667 SC */
-       {1, 1, 667, 800, 5941, 35941, 6377, 36377},    /* DDR3-800 SC */
-
-       {1, 0, 400, 400, 3472, 33472, 4173, 34173},    /* DDR2-400 SC */
-       {1, 0, 400, 667, 3443, 33443, 3996, 33996},    /* DDR2-667 SC */
-       {1, 0, 400, 800, 3430, 33430, 3946, 33946},    /* DDR2-800 SC */
-       {1, 1, 400, 667, 6509, 36509, 7062, 37062},    /* DDR3-667 SC */
-       {1, 1, 400, 800, 5985, 35985, 6501, 36501},    /* DDR3-800 SC */
-
-       {0, 0, 800, 400, 3438, 33438, 4065, 34065},    /* DDR2-400 SC */
-       {0, 0, 800, 667, 3410, 33410, 3889, 33889},    /* DDR2-667 SC */
-       {0, 0, 800, 800, 3403, 33403, 3845, 33845},    /* DDR2-800 SC */
-       {0, 1, 800, 667, 6476, 36476, 6955, 36955},    /* DDR3-667 SC */
-       {0, 1, 800, 800, 5958, 35958, 6400, 36400},    /* DDR3-800 SC */
-
-       {0, 0, 667, 400, 3456, 33456, 4103, 34106},    /* DDR2-400 SC */
-       {0, 0, 667, 667, 3428, 33428, 3927, 33927},    /* DDR2-667 SC */
-       {0, 0, 667, 800, 3443, 33443, 3905, 33905},    /* DDR2-800 SC */
-       {0, 1, 667, 667, 6494, 36494, 6993, 36993},    /* DDR3-667 SC */
-       {0, 1, 667, 800, 5998, 35998, 6460, 36460},    /* DDR3-800 SC */
-
-       {0, 0, 400, 400, 3528, 33528, 4255, 34255},    /* DDR2-400 SC */
-       {0, 0, 400, 667, 3500, 33500, 4079, 34079},    /* DDR2-667 SC */
-       {0, 0, 400, 800, 3487, 33487, 4029, 34029},    /* DDR2-800 SC */
-       {0, 1, 400, 667, 6566, 36566, 7145, 37145},    /* DDR3-667 SC */
-       {0, 1, 400, 800, 6042, 36042, 6584, 36584},    /* DDR3-800 SC */
-};
+                       if (edp_bpc < display_bpc) {
+                               DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc);
+                               display_bpc = edp_bpc;
+                       }
+                       continue;
+               }
 
-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;
+               /* Not one of the known troublemakers, check the EDID */
+               list_for_each_entry(connector, &dev->mode_config.connector_list,
+                                   head) {
+                       if (connector->encoder != encoder)
+                               continue;
 
-       if (fsb == 0 || mem == 0)
-               return NULL;
+                       /* Don't use an invalid EDID bpc value */
+                       if (connector->display_info.bpc &&
+                           connector->display_info.bpc < display_bpc) {
+                               DRM_DEBUG_KMS("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc);
+                               display_bpc = connector->display_info.bpc;
+                       }
+               }
 
-       for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) {
-               latency = &cxsr_latency_table[i];
-               if (is_desktop == latency->is_desktop &&
-                   is_ddr3 == latency->is_ddr3 &&
-                   fsb == latency->fsb_freq && mem == latency->mem_freq)
-                       return latency;
+               /*
+                * HDMI is either 12 or 8, so if the display lets 10bpc sneak
+                * through, clamp it down.  (Note: >12bpc will be caught below.)
+                */
+               if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
+                       if (display_bpc > 8 && display_bpc < 12) {
+                               DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n");
+                               display_bpc = 12;
+                       } else {
+                               DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n");
+                               display_bpc = 8;
+                       }
+               }
        }
 
-       DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
+       if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
+               DRM_DEBUG_KMS("Dithering DP to 6bpc\n");
+               display_bpc = 6;
+       }
 
-       return NULL;
-}
+       /*
+        * We could just drive the pipe at the highest bpc all the time and
+        * enable dithering as needed, but that costs bandwidth.  So choose
+        * the minimum value that expresses the full color range of the fb but
+        * also stays within the max display bpc discovered above.
+        */
 
-static void pineview_disable_cxsr(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       switch (crtc->fb->depth) {
+       case 8:
+               bpc = 8; /* since we go through a colormap */
+               break;
+       case 15:
+       case 16:
+               bpc = 6; /* min is 18bpp */
+               break;
+       case 24:
+               bpc = 8;
+               break;
+       case 30:
+               bpc = 10;
+               break;
+       case 48:
+               bpc = 12;
+               break;
+       default:
+               DRM_DEBUG("unsupported depth, assuming 24 bits\n");
+               bpc = min((unsigned int)8, display_bpc);
+               break;
+       }
 
-       /* deactivate cxsr */
-       I915_WRITE(DSPFW3, I915_READ(DSPFW3) & ~PINEVIEW_SELF_REFRESH_EN);
-}
+       display_bpc = min(display_bpc, bpc);
 
-/*
- * Latency for FIFO fetches is dependent on several factors:
- *   - memory configuration (speed, channels)
- *   - chipset
- *   - current MCH state
- * It can be fairly high in some situations, so here we assume a fairly
- * pessimal value.  It's a tradeoff between extra memory fetches (if we
- * set this value too high, the FIFO will fetch frequently to stay full)
- * and power consumption (set it too low to save power and we might see
- * FIFO underruns and display "flicker").
- *
- * A value of 5us seems to be a good balance; safe for very low end
- * platforms but not overly aggressive on lower latency configs.
- */
-static const int latency_ns = 5000;
+       DRM_DEBUG_KMS("setting pipe bpc to %d (max display bpc %d)\n",
+                     bpc, display_bpc);
 
-static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t dsparb = I915_READ(DSPARB);
-       int size;
-
-       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);
+       *pipe_bpp = display_bpc * 3;
 
-       return size;
+       return display_bpc != bpc;
 }
 
-static int i85x_get_fifo_size(struct drm_device *dev, int plane)
+static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
 {
+       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t dsparb = I915_READ(DSPARB);
-       int size;
-
-       size = dsparb & 0x1ff;
-       if (plane)
-               size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - size;
-       size >>= 1; /* Convert to cachelines */
+       int refclk;
 
-       DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                     plane ? "B" : "A", size);
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+           intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
+               refclk = dev_priv->lvds_ssc_freq * 1000;
+               DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
+                             refclk / 1000);
+       } else if (!IS_GEN2(dev)) {
+               refclk = 96000;
+       } else {
+               refclk = 48000;
+       }
 
-       return size;
+       return refclk;
 }
 
-static int i845_get_fifo_size(struct drm_device *dev, int plane)
+static void i9xx_adjust_sdvo_tv_clock(struct drm_display_mode *adjusted_mode,
+                                     intel_clock_t *clock)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t dsparb = I915_READ(DSPARB);
-       int size;
-
-       size = dsparb & 0x7f;
-       size >>= 2; /* Convert to cachelines */
-
-       DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                     plane ? "B" : "A",
-                     size);
-
-       return size;
+       /* SDVO TV has fixed PLL values depend on its clock range,
+          this mirrors vbios setting. */
+       if (adjusted_mode->clock >= 100000
+           && 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) {
+               clock->p1 = 1;
+               clock->p2 = 10;
+               clock->n = 6;
+               clock->m1 = 12;
+               clock->m2 = 8;
+       }
 }
 
-static int i830_get_fifo_size(struct drm_device *dev, int plane)
+static void i9xx_update_pll_dividers(struct drm_crtc *crtc,
+                                    intel_clock_t *clock,
+                                    intel_clock_t *reduced_clock)
 {
+       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t dsparb = I915_READ(DSPARB);
-       int size;
-
-       size = dsparb & 0x7f;
-       size >>= 1; /* Convert to cachelines */
-
-       DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                     plane ? "B" : "A", size);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       u32 fp, fp2 = 0;
 
-       return size;
-}
+       if (IS_PINEVIEW(dev)) {
+               fp = (1 << clock->n) << 16 | clock->m1 << 8 | clock->m2;
+               if (reduced_clock)
+                       fp2 = (1 << reduced_clock->n) << 16 |
+                               reduced_clock->m1 << 8 | reduced_clock->m2;
+       } else {
+               fp = clock->n << 16 | clock->m1 << 8 | clock->m2;
+               if (reduced_clock)
+                       fp2 = reduced_clock->n << 16 | reduced_clock->m1 << 8 |
+                               reduced_clock->m2;
+       }
 
-static struct drm_crtc *single_enabled_crtc(struct drm_device *dev)
-{
-       struct drm_crtc *crtc, *enabled = NULL;
+       I915_WRITE(FP0(pipe), fp);
 
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               if (crtc->enabled && crtc->fb) {
-                       if (enabled)
-                               return NULL;
-                       enabled = crtc;
-               }
+       intel_crtc->lowfreq_avail = false;
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+           reduced_clock && i915_powersave) {
+               I915_WRITE(FP1(pipe), fp2);
+               intel_crtc->lowfreq_avail = true;
+       } else {
+               I915_WRITE(FP1(pipe), fp);
        }
-
-       return enabled;
 }
 
-static void pineview_update_wm(struct drm_device *dev)
+static void intel_update_lvds(struct drm_crtc *crtc, intel_clock_t *clock,
+                             struct drm_display_mode *adjusted_mode)
 {
+       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc;
-       const struct cxsr_latency *latency;
-       u32 reg;
-       unsigned long wm;
-
-       latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3,
-                                        dev_priv->fsb_freq, dev_priv->mem_freq);
-       if (!latency) {
-               DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
-               pineview_disable_cxsr(dev);
-               return;
-       }
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       u32 temp;
 
-       crtc = single_enabled_crtc(dev);
-       if (crtc) {
-               int clock = crtc->mode.clock;
-               int pixel_size = crtc->fb->bits_per_pixel / 8;
-
-               /* Display SR */
-               wm = intel_calculate_wm(clock, &pineview_display_wm,
-                                       pineview_display_wm.fifo_size,
-                                       pixel_size, latency->display_sr);
-               reg = I915_READ(DSPFW1);
-               reg &= ~DSPFW_SR_MASK;
-               reg |= wm << DSPFW_SR_SHIFT;
-               I915_WRITE(DSPFW1, reg);
-               DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg);
-
-               /* cursor SR */
-               wm = intel_calculate_wm(clock, &pineview_cursor_wm,
-                                       pineview_display_wm.fifo_size,
-                                       pixel_size, latency->cursor_sr);
-               reg = I915_READ(DSPFW3);
-               reg &= ~DSPFW_CURSOR_SR_MASK;
-               reg |= (wm & 0x3f) << DSPFW_CURSOR_SR_SHIFT;
-               I915_WRITE(DSPFW3, reg);
-
-               /* Display HPLL off SR */
-               wm = intel_calculate_wm(clock, &pineview_display_hplloff_wm,
-                                       pineview_display_hplloff_wm.fifo_size,
-                                       pixel_size, latency->display_hpll_disable);
-               reg = I915_READ(DSPFW3);
-               reg &= ~DSPFW_HPLL_SR_MASK;
-               reg |= wm & DSPFW_HPLL_SR_MASK;
-               I915_WRITE(DSPFW3, reg);
-
-               /* cursor HPLL off SR */
-               wm = intel_calculate_wm(clock, &pineview_cursor_hplloff_wm,
-                                       pineview_display_hplloff_wm.fifo_size,
-                                       pixel_size, latency->cursor_hpll_disable);
-               reg = I915_READ(DSPFW3);
-               reg &= ~DSPFW_HPLL_CURSOR_MASK;
-               reg |= (wm & 0x3f) << DSPFW_HPLL_CURSOR_SHIFT;
-               I915_WRITE(DSPFW3, reg);
-               DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg);
-
-               /* activate cxsr */
-               I915_WRITE(DSPFW3,
-                          I915_READ(DSPFW3) | PINEVIEW_SELF_REFRESH_EN);
-               DRM_DEBUG_KMS("Self-refresh is enabled\n");
+       temp = I915_READ(LVDS);
+       temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+       if (pipe == 1) {
+               temp |= LVDS_PIPEB_SELECT;
        } else {
-               pineview_disable_cxsr(dev);
-               DRM_DEBUG_KMS("Self-refresh is disabled\n");
+               temp &= ~LVDS_PIPEB_SELECT;
        }
-}
+       /* set the corresponsding LVDS_BORDER bit */
+       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)
+               temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+       else
+               temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
 
-static bool g4x_compute_wm0(struct drm_device *dev,
-                           int plane,
-                           const struct intel_watermark_params *display,
-                           int display_latency_ns,
-                           const struct intel_watermark_params *cursor,
-                           int cursor_latency_ns,
-                           int *plane_wm,
-                           int *cursor_wm)
-{
-       struct drm_crtc *crtc;
-       int htotal, hdisplay, clock, pixel_size;
-       int line_time_us, line_count;
-       int entries, tlb_miss;
-
-       crtc = intel_get_crtc_for_plane(dev, plane);
-       if (crtc->fb == NULL || !crtc->enabled) {
-               *cursor_wm = cursor->guard_size;
-               *plane_wm = display->guard_size;
-               return false;
+       /* 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 on LVDS as needed */
+       if (INTEL_INFO(dev)->gen >= 4) {
+               if (dev_priv->lvds_dither)
+                       temp |= LVDS_ENABLE_DITHER;
+               else
+                       temp &= ~LVDS_ENABLE_DITHER;
        }
-
-       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) * display_latency_ns) / 1000;
-       tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8;
-       if (tlb_miss > 0)
-               entries += tlb_miss;
-       entries = DIV_ROUND_UP(entries, display->cacheline_size);
-       *plane_wm = entries + display->guard_size;
-       if (*plane_wm > (int)display->max_wm)
-               *plane_wm = display->max_wm;
-
-       /* Use the large buffer method to calculate cursor watermark */
-       line_time_us = ((htotal * 1000) / clock);
-       line_count = (cursor_latency_ns / line_time_us + 1000) / 1000;
-       entries = line_count * 64 * pixel_size;
-       tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8;
-       if (tlb_miss > 0)
-               entries += tlb_miss;
-       entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
-       *cursor_wm = entries + cursor->guard_size;
-       if (*cursor_wm > (int)cursor->max_wm)
-               *cursor_wm = (int)cursor->max_wm;
-
-       return true;
+       temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
+       if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
+               temp |= LVDS_HSYNC_POLARITY;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+               temp |= LVDS_VSYNC_POLARITY;
+       I915_WRITE(LVDS, temp);
 }
 
-/*
- * Check the wm result.
- *
- * If any calculated watermark values is larger than the maximum value that
- * can be programmed into the associated watermark register, that watermark
- * must be disabled.
- */
-static bool g4x_check_srwm(struct drm_device *dev,
-                          int display_wm, int cursor_wm,
-                          const struct intel_watermark_params *display,
-                          const struct intel_watermark_params *cursor)
+static void i9xx_update_pll(struct drm_crtc *crtc,
+                           struct drm_display_mode *mode,
+                           struct drm_display_mode *adjusted_mode,
+                           intel_clock_t *clock, intel_clock_t *reduced_clock,
+                           int num_connectors)
 {
-       DRM_DEBUG_KMS("SR watermark: display plane %d, cursor %d\n",
-                     display_wm, cursor_wm);
+       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;
+       u32 dpll;
+       bool is_sdvo;
 
-       if (display_wm > display->max_wm) {
-               DRM_DEBUG_KMS("display watermark is too large(%d/%ld), disabling\n",
-                             display_wm, display->max_wm);
-               return false;
-       }
+       is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) ||
+               intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI);
 
-       if (cursor_wm > cursor->max_wm) {
-               DRM_DEBUG_KMS("cursor watermark is too large(%d/%ld), disabling\n",
-                             cursor_wm, cursor->max_wm);
-               return false;
-       }
+       dpll = DPLL_VGA_MODE_DIS;
 
-       if (!(display_wm || cursor_wm)) {
-               DRM_DEBUG_KMS("SR latency is 0, disabling\n");
-               return false;
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+               dpll |= DPLLB_MODE_LVDS;
+       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;
+               }
+               dpll |= DPLL_DVO_HIGH_SPEED;
        }
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
+               dpll |= DPLL_DVO_HIGH_SPEED;
 
-       return true;
-}
-
-static bool g4x_compute_srwm(struct drm_device *dev,
-                            int plane,
-                            int latency_ns,
-                            const struct intel_watermark_params *display,
-                            const struct intel_watermark_params *cursor,
-                            int *display_wm, int *cursor_wm)
-{
-       struct drm_crtc *crtc;
-       int hdisplay, htotal, pixel_size, clock;
-       unsigned long line_time_us;
-       int line_count, line_size;
-       int small, large;
-       int entries;
-
-       if (!latency_ns) {
-               *display_wm = *cursor_wm = 0;
-               return false;
+       /* compute bitmask from p1 value */
+       if (IS_PINEVIEW(dev))
+               dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
+       else {
+               dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+               if (IS_G4X(dev) && reduced_clock)
+                       dpll |= (1 << (reduced_clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
        }
+       switch (clock->p2) {
+       case 5:
+               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
+               break;
+       case 7:
+               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
+               break;
+       case 10:
+               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
+               break;
+       case 14:
+               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
+               break;
+       }
+       if (INTEL_INFO(dev)->gen >= 4)
+               dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
 
-       crtc = intel_get_crtc_for_plane(dev, plane);
-       hdisplay = crtc->mode.hdisplay;
-       htotal = crtc->mode.htotal;
-       clock = crtc->mode.clock;
-       pixel_size = crtc->fb->bits_per_pixel / 8;
-
-       line_time_us = (htotal * 1000) / clock;
-       line_count = (latency_ns / line_time_us + 1000) / 1000;
-       line_size = hdisplay * pixel_size;
+       if (is_sdvo && intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT))
+               dpll |= PLL_REF_INPUT_TVCLKINBC;
+       else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT))
+               /* XXX: just matching BIOS for now */
+               /*      dpll |= PLL_REF_INPUT_TVCLKINBC; */
+               dpll |= 3;
+       else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+                intel_panel_use_ssc(dev_priv) && num_connectors < 2)
+               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
+       else
+               dpll |= PLL_REF_INPUT_DREFCLK;
 
-       /* Use the minimum of the small and large buffer method for primary */
-       small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
-       large = line_count * line_size;
+       dpll |= DPLL_VCO_ENABLE;
+       I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
+       POSTING_READ(DPLL(pipe));
+       udelay(150);
 
-       entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
-       *display_wm = entries + display->guard_size;
+       /* 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.
+        */
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+               intel_update_lvds(crtc, clock, adjusted_mode);
 
-       /* calculate the self-refresh watermark for display cursor */
-       entries = line_count * pixel_size * 64;
-       entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
-       *cursor_wm = entries + cursor->guard_size;
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
+               intel_dp_set_m_n(crtc, mode, adjusted_mode);
 
-       return g4x_check_srwm(dev,
-                             *display_wm, *cursor_wm,
-                             display, cursor);
-}
+       I915_WRITE(DPLL(pipe), dpll);
 
-#define single_plane_enabled(mask) is_power_of_2(mask)
+       /* Wait for the clocks to stabilize. */
+       POSTING_READ(DPLL(pipe));
+       udelay(150);
 
-static void g4x_update_wm(struct drm_device *dev)
-{
-       static const int sr_latency_ns = 12000;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
-       int plane_sr, cursor_sr;
-       unsigned int enabled = 0;
-
-       if (g4x_compute_wm0(dev, 0,
-                           &g4x_wm_info, latency_ns,
-                           &g4x_cursor_wm_info, latency_ns,
-                           &planea_wm, &cursora_wm))
-               enabled |= 1;
-
-       if (g4x_compute_wm0(dev, 1,
-                           &g4x_wm_info, latency_ns,
-                           &g4x_cursor_wm_info, latency_ns,
-                           &planeb_wm, &cursorb_wm))
-               enabled |= 2;
-
-       plane_sr = cursor_sr = 0;
-       if (single_plane_enabled(enabled) &&
-           g4x_compute_srwm(dev, ffs(enabled) - 1,
-                            sr_latency_ns,
-                            &g4x_wm_info,
-                            &g4x_cursor_wm_info,
-                            &plane_sr, &cursor_sr))
-               I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
-       else
-               I915_WRITE(FW_BLC_SELF,
-                          I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN);
-
-       DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
-                     planea_wm, cursora_wm,
-                     planeb_wm, cursorb_wm,
-                     plane_sr, cursor_sr);
-
-       I915_WRITE(DSPFW1,
-                  (plane_sr << DSPFW_SR_SHIFT) |
-                  (cursorb_wm << DSPFW_CURSORB_SHIFT) |
-                  (planeb_wm << DSPFW_PLANEB_SHIFT) |
-                  planea_wm);
-       I915_WRITE(DSPFW2,
-                  (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) |
-                  (cursora_wm << DSPFW_CURSORA_SHIFT));
-       /* HPLL off in SR has some issues on G4x... disable it */
-       I915_WRITE(DSPFW3,
-                  (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) |
-                  (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
-}
-
-static void i965_update_wm(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc;
-       int srwm = 1;
-       int cursor_sr = 16;
-
-       /* Calc sr entries for one plane configs */
-       crtc = single_enabled_crtc(dev);
-       if (crtc) {
-               /* self-refresh has much higher latency */
-               static const int sr_latency_ns = 12000;
-               int clock = crtc->mode.clock;
-               int htotal = crtc->mode.htotal;
-               int hdisplay = crtc->mode.hdisplay;
-               int pixel_size = crtc->fb->bits_per_pixel / 8;
-               unsigned long line_time_us;
-               int entries;
-
-               line_time_us = ((htotal * 1000) / clock);
-
-               /* Use ns/us then divide to preserve precision */
-               entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                       pixel_size * hdisplay;
-               entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE);
-               srwm = I965_FIFO_SIZE - entries;
-               if (srwm < 0)
-                       srwm = 1;
-               srwm &= 0x1ff;
-               DRM_DEBUG_KMS("self-refresh entries: %d, wm: %d\n",
-                             entries, srwm);
-
-               entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                       pixel_size * 64;
-               entries = DIV_ROUND_UP(entries,
-                                         i965_cursor_wm_info.cacheline_size);
-               cursor_sr = i965_cursor_wm_info.fifo_size -
-                       (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_CRESTLINE(dev))
-                       I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
+       if (INTEL_INFO(dev)->gen >= 4) {
+               u32 temp = 0;
+               if (is_sdvo) {
+                       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 {
-               /* Turn off self refresh if both pipes are enabled */
-               if (IS_CRESTLINE(dev))
-                       I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
-                                  & ~FW_BLC_SELF_EN);
+               /* The pixel multiplier can only be updated once the
+                * DPLL is enabled and the clocks are stable.
+                *
+                * So write it again.
+                */
+               I915_WRITE(DPLL(pipe), dpll);
        }
-
-       DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n",
-                     srwm);
-
-       /* 965 has limitations... */
-       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)
+static void i8xx_update_pll(struct drm_crtc *crtc,
+                           struct drm_display_mode *adjusted_mode,
+                           intel_clock_t *clock,
+                           int num_connectors)
 {
+       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       const struct intel_watermark_params *wm_info;
-       uint32_t fwater_lo;
-       uint32_t fwater_hi;
-       int cwm, srwm = 1;
-       int fifo_size;
-       int planea_wm, planeb_wm;
-       struct drm_crtc *crtc, *enabled = NULL;
-
-       if (IS_I945GM(dev))
-               wm_info = &i945_wm_info;
-       else if (!IS_GEN2(dev))
-               wm_info = &i915_wm_info;
-       else
-               wm_info = &i855_wm_info;
-
-       fifo_size = dev_priv->display.get_fifo_size(dev, 0);
-       crtc = intel_get_crtc_for_plane(dev, 0);
-       if (crtc->enabled && crtc->fb) {
-               planea_wm = intel_calculate_wm(crtc->mode.clock,
-                                              wm_info, fifo_size,
-                                              crtc->fb->bits_per_pixel / 8,
-                                              latency_ns);
-               enabled = crtc;
-       } else
-               planea_wm = fifo_size - wm_info->guard_size;
-
-       fifo_size = dev_priv->display.get_fifo_size(dev, 1);
-       crtc = intel_get_crtc_for_plane(dev, 1);
-       if (crtc->enabled && crtc->fb) {
-               planeb_wm = intel_calculate_wm(crtc->mode.clock,
-                                              wm_info, fifo_size,
-                                              crtc->fb->bits_per_pixel / 8,
-                                              latency_ns);
-               if (enabled == NULL)
-                       enabled = crtc;
-               else
-                       enabled = NULL;
-       } else
-               planeb_wm = fifo_size - wm_info->guard_size;
-
-       DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       u32 dpll;
 
-       /*
-        * Overlay gets an aggressive default since video jitter is bad.
-        */
-       cwm = 2;
+       dpll = DPLL_VGA_MODE_DIS;
 
-       /* Play safe and disable self-refresh before adjusting watermarks. */
-       if (IS_I945G(dev) || IS_I945GM(dev))
-               I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | 0);
-       else if (IS_I915GM(dev))
-               I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN);
-
-       /* Calc sr entries for one plane configs */
-       if (HAS_FW_BLC(dev) && enabled) {
-               /* self-refresh has much higher latency */
-               static const int sr_latency_ns = 6000;
-               int clock = enabled->mode.clock;
-               int htotal = enabled->mode.htotal;
-               int hdisplay = enabled->mode.hdisplay;
-               int pixel_size = enabled->fb->bits_per_pixel / 8;
-               unsigned long line_time_us;
-               int entries;
-
-               line_time_us = (htotal * 1000) / clock;
-
-               /* Use ns/us then divide to preserve precision */
-               entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                       pixel_size * hdisplay;
-               entries = DIV_ROUND_UP(entries, wm_info->cacheline_size);
-               DRM_DEBUG_KMS("self-refresh entries: %d\n", entries);
-               srwm = wm_info->fifo_size - entries;
-               if (srwm < 0)
-                       srwm = 1;
-
-               if (IS_I945G(dev) || IS_I945GM(dev))
-                       I915_WRITE(FW_BLC_SELF,
-                                  FW_BLC_SELF_FIFO_MASK | (srwm & 0xff));
-               else if (IS_I915GM(dev))
-                       I915_WRITE(FW_BLC_SELF, srwm & 0x3f);
-       }
-
-       DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
-                     planea_wm, planeb_wm, cwm, srwm);
-
-       fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
-       fwater_hi = (cwm & 0x1f);
-
-       /* Set request length to 8 cachelines per fetch */
-       fwater_lo = fwater_lo | (1 << 24) | (1 << 8);
-       fwater_hi = fwater_hi | (1 << 8);
-
-       I915_WRITE(FW_BLC, fwater_lo);
-       I915_WRITE(FW_BLC2, fwater_hi);
-
-       if (HAS_FW_BLC(dev)) {
-               if (enabled) {
-                       if (IS_I945G(dev) || IS_I945GM(dev))
-                               I915_WRITE(FW_BLC_SELF,
-                                          FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
-                       else if (IS_I915GM(dev))
-                               I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN);
-                       DRM_DEBUG_KMS("memory self refresh enabled\n");
-               } else
-                       DRM_DEBUG_KMS("memory self refresh disabled\n");
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+               dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+       } else {
+               if (clock->p1 == 2)
+                       dpll |= PLL_P1_DIVIDE_BY_TWO;
+               else
+                       dpll |= (clock->p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+               if (clock->p2 == 4)
+                       dpll |= PLL_P2_DIVIDE_BY_4;
        }
-}
 
-static void i830_update_wm(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc;
-       uint32_t fwater_lo;
-       int planea_wm;
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT))
+               /* XXX: just matching BIOS for now */
+               /*      dpll |= PLL_REF_INPUT_TVCLKINBC; */
+               dpll |= 3;
+       else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+                intel_panel_use_ssc(dev_priv) && num_connectors < 2)
+               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
+       else
+               dpll |= PLL_REF_INPUT_DREFCLK;
 
-       crtc = single_enabled_crtc(dev);
-       if (crtc == NULL)
-               return;
+       dpll |= DPLL_VCO_ENABLE;
+       I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
+       POSTING_READ(DPLL(pipe));
+       udelay(150);
 
-       planea_wm = intel_calculate_wm(crtc->mode.clock, &i830_wm_info,
-                                      dev_priv->display.get_fifo_size(dev, 0),
-                                      crtc->fb->bits_per_pixel / 8,
-                                      latency_ns);
-       fwater_lo = I915_READ(FW_BLC) & ~0xfff;
-       fwater_lo |= (3<<8) | planea_wm;
+       I915_WRITE(DPLL(pipe), dpll);
 
-       DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d\n", planea_wm);
+       /* Wait for the clocks to stabilize. */
+       POSTING_READ(DPLL(pipe));
+       udelay(150);
 
-       I915_WRITE(FW_BLC, fwater_lo);
-}
+       /* 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.
+        */
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+               intel_update_lvds(crtc, clock, adjusted_mode);
 
-#define ILK_LP0_PLANE_LATENCY          700
-#define ILK_LP0_CURSOR_LATENCY         1300
+       /* The pixel multiplier can only be updated once the
+        * DPLL is enabled and the clocks are stable.
+        *
+        * So write it again.
+        */
+       I915_WRITE(DPLL(pipe), dpll);
+}
 
-/*
- * Check the wm result.
- *
- * If any calculated watermark values is larger than the maximum value that
- * can be programmed into the associated watermark register, that watermark
- * must be disabled.
- */
-static bool ironlake_check_srwm(struct drm_device *dev, int level,
-                               int fbc_wm, int display_wm, int cursor_wm,
-                               const struct intel_watermark_params *display,
-                               const struct intel_watermark_params *cursor)
+static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
+                             struct drm_display_mode *mode,
+                             struct drm_display_mode *adjusted_mode,
+                             int x, int y,
+                             struct drm_framebuffer *old_fb)
 {
+       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 refclk, num_connectors = 0;
+       intel_clock_t clock, reduced_clock;
+       u32 dspcntr, pipeconf, vsyncshift;
+       bool ok, has_reduced_clock = false, is_sdvo = false;
+       bool is_lvds = false, is_tv = false, is_dp = false;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
+       const intel_limit_t *limit;
+       int ret;
 
-       DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d,"
-                     " cursor %d\n", level, display_wm, fbc_wm, cursor_wm);
-
-       if (fbc_wm > SNB_FBC_MAX_SRWM) {
-               DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n",
-                             fbc_wm, SNB_FBC_MAX_SRWM, level);
-
-               /* fbc has it's own way to disable FBC WM */
-               I915_WRITE(DISP_ARB_CTL,
-                          I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS);
-               return false;
-       }
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               if (encoder->base.crtc != crtc)
+                       continue;
 
-       if (display_wm > display->max_wm) {
-               DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n",
-                             display_wm, SNB_DISPLAY_MAX_SRWM, level);
-               return false;
-       }
+               switch (encoder->type) {
+               case INTEL_OUTPUT_LVDS:
+                       is_lvds = true;
+                       break;
+               case INTEL_OUTPUT_SDVO:
+               case INTEL_OUTPUT_HDMI:
+                       is_sdvo = true;
+                       if (encoder->needs_tv_clock)
+                               is_tv = true;
+                       break;
+               case INTEL_OUTPUT_TVOUT:
+                       is_tv = true;
+                       break;
+               case INTEL_OUTPUT_DISPLAYPORT:
+                       is_dp = true;
+                       break;
+               }
 
-       if (cursor_wm > cursor->max_wm) {
-               DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n",
-                             cursor_wm, SNB_CURSOR_MAX_SRWM, level);
-               return false;
+               num_connectors++;
        }
 
-       if (!(fbc_wm || display_wm || cursor_wm)) {
-               DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level);
-               return false;
+       refclk = i9xx_get_refclk(crtc, num_connectors);
+
+       /*
+        * Returns a set of divisors for the desired target clock with the given
+        * refclk, or FALSE.  The returned values represent the clock equation:
+        * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+        */
+       limit = intel_limit(crtc, refclk);
+       ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
+                            &clock);
+       if (!ok) {
+               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               return -EINVAL;
        }
 
-       return true;
-}
+       /* Ensure that the cursor is valid for the new mode before changing... */
+       intel_crtc_update_cursor(crtc, true);
 
-/*
- * Compute watermark values of WM[1-3],
- */
-static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane,
-                                 int latency_ns,
-                                 const struct intel_watermark_params *display,
-                                 const struct intel_watermark_params *cursor,
-                                 int *fbc_wm, int *display_wm, int *cursor_wm)
-{
-       struct drm_crtc *crtc;
-       unsigned long line_time_us;
-       int hdisplay, htotal, pixel_size, clock;
-       int line_count, line_size;
-       int small, large;
-       int entries;
-
-       if (!latency_ns) {
-               *fbc_wm = *display_wm = *cursor_wm = 0;
-               return false;
+       if (is_lvds && dev_priv->lvds_downclock_avail) {
+               /*
+                * Ensure we match the reduced clock's P to the target clock.
+                * If the clocks don't match, we can't switch the display clock
+                * by using the FP0/FP1. In such case we will disable the LVDS
+                * downclock feature.
+               */
+               has_reduced_clock = limit->find_pll(limit, crtc,
+                                                   dev_priv->lvds_downclock,
+                                                   refclk,
+                                                   &clock,
+                                                   &reduced_clock);
        }
 
-       crtc = intel_get_crtc_for_plane(dev, plane);
-       hdisplay = crtc->mode.hdisplay;
-       htotal = crtc->mode.htotal;
-       clock = crtc->mode.clock;
-       pixel_size = crtc->fb->bits_per_pixel / 8;
-
-       line_time_us = (htotal * 1000) / clock;
-       line_count = (latency_ns / line_time_us + 1000) / 1000;
-       line_size = hdisplay * pixel_size;
+       if (is_sdvo && is_tv)
+               i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock);
 
-       /* Use the minimum of the small and large buffer method for primary */
-       small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
-       large = line_count * line_size;
+       i9xx_update_pll_dividers(crtc, &clock, has_reduced_clock ?
+                                &reduced_clock : NULL);
 
-       entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
-       *display_wm = entries + display->guard_size;
+       if (IS_GEN2(dev))
+               i8xx_update_pll(crtc, adjusted_mode, &clock, num_connectors);
+       else
+               i9xx_update_pll(crtc, mode, adjusted_mode, &clock,
+                               has_reduced_clock ? &reduced_clock : NULL,
+                               num_connectors);
 
-       /*
-        * Spec says:
-        * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2
-        */
-       *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2;
+       /* setup pipeconf */
+       pipeconf = I915_READ(PIPECONF(pipe));
 
-       /* calculate the self-refresh watermark for display cursor */
-       entries = line_count * pixel_size * 64;
-       entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
-       *cursor_wm = entries + cursor->guard_size;
+       /* Set up the display plane register */
+       dspcntr = DISPPLANE_GAMMA_ENABLE;
 
-       return ironlake_check_srwm(dev, level,
-                                  *fbc_wm, *display_wm, *cursor_wm,
-                                  display, cursor);
-}
+       if (pipe == 0)
+               dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
+       else
+               dspcntr |= DISPPLANE_SEL_PIPE_B;
 
-static void ironlake_update_wm(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int fbc_wm, plane_wm, cursor_wm;
-       unsigned int enabled;
-
-       enabled = 0;
-       if (g4x_compute_wm0(dev, 0,
-                           &ironlake_display_wm_info,
-                           ILK_LP0_PLANE_LATENCY,
-                           &ironlake_cursor_wm_info,
-                           ILK_LP0_CURSOR_LATENCY,
-                           &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 |= 1;
-       }
-
-       if (g4x_compute_wm0(dev, 1,
-                           &ironlake_display_wm_info,
-                           ILK_LP0_PLANE_LATENCY,
-                           &ironlake_cursor_wm_info,
-                           ILK_LP0_CURSOR_LATENCY,
-                           &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 |= 2;
+       if (pipe == 0 && INTEL_INFO(dev)->gen < 4) {
+               /* Enable pixel doubling when the dot clock is > 90% of the (display)
+                * core speed.
+                *
+                * XXX: No double-wide on 915GM pipe B. Is that the only reason for the
+                * pipe == 0 check?
+                */
+               if (mode->clock >
+                   dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
+                       pipeconf |= PIPECONF_DOUBLE_WIDE;
+               else
+                       pipeconf &= ~PIPECONF_DOUBLE_WIDE;
        }
 
-       /*
-        * Calculate and update the self-refresh watermark only when one
-        * display plane is used.
-        */
-       I915_WRITE(WM3_LP_ILK, 0);
-       I915_WRITE(WM2_LP_ILK, 0);
-       I915_WRITE(WM1_LP_ILK, 0);
-
-       if (!single_plane_enabled(enabled))
-               return;
-       enabled = ffs(enabled) - 1;
-
-       /* WM1 */
-       if (!ironlake_compute_srwm(dev, 1, enabled,
-                                  ILK_READ_WM1_LATENCY() * 500,
-                                  &ironlake_display_srwm_info,
-                                  &ironlake_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &cursor_wm))
-               return;
-
-       I915_WRITE(WM1_LP_ILK,
-                  WM1_LP_SR_EN |
-                  (ILK_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
-                  (fbc_wm << WM1_LP_FBC_SHIFT) |
-                  (plane_wm << WM1_LP_SR_SHIFT) |
-                  cursor_wm);
-
-       /* WM2 */
-       if (!ironlake_compute_srwm(dev, 2, enabled,
-                                  ILK_READ_WM2_LATENCY() * 500,
-                                  &ironlake_display_srwm_info,
-                                  &ironlake_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &cursor_wm))
-               return;
+       /* default to 8bpc */
+       pipeconf &= ~(PIPECONF_BPP_MASK | PIPECONF_DITHER_EN);
+       if (is_dp) {
+               if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
+                       pipeconf |= PIPECONF_BPP_6 |
+                                   PIPECONF_DITHER_EN |
+                                   PIPECONF_DITHER_TYPE_SP;
+               }
+       }
 
-       I915_WRITE(WM2_LP_ILK,
-                  WM2_LP_EN |
-                  (ILK_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
-                  (fbc_wm << WM1_LP_FBC_SHIFT) |
-                  (plane_wm << WM1_LP_SR_SHIFT) |
-                  cursor_wm);
+       DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
+       drm_mode_debug_printmodeline(mode);
 
-       /*
-        * WM3 is unsupported on ILK, probably because we don't have latency
-        * data for that power state
-        */
-}
+       if (HAS_PIPE_CXSR(dev)) {
+               if (intel_crtc->lowfreq_avail) {
+                       DRM_DEBUG_KMS("enabling CxSR downclocking\n");
+                       pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
+               } else {
+                       DRM_DEBUG_KMS("disabling CxSR downclocking\n");
+                       pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
+               }
+       }
 
-void sandybridge_update_wm(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int latency = SNB_READ_WM0_LATENCY() * 100;     /* In unit 0.1us */
-       u32 val;
-       int fbc_wm, plane_wm, cursor_wm;
-       unsigned int enabled;
-
-       enabled = 0;
-       if (g4x_compute_wm0(dev, 0,
-                           &sandybridge_display_wm_info, latency,
-                           &sandybridge_cursor_wm_info, latency,
-                           &plane_wm, &cursor_wm)) {
-               val = I915_READ(WM0_PIPEA_ILK);
-               val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-               I915_WRITE(WM0_PIPEA_ILK, val |
-                          ((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 |= 1;
-       }
-
-       if (g4x_compute_wm0(dev, 1,
-                           &sandybridge_display_wm_info, latency,
-                           &sandybridge_cursor_wm_info, latency,
-                           &plane_wm, &cursor_wm)) {
-               val = I915_READ(WM0_PIPEB_ILK);
-               val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-               I915_WRITE(WM0_PIPEB_ILK, val |
-                          ((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 |= 2;
-       }
-
-       /* IVB has 3 pipes */
-       if (IS_IVYBRIDGE(dev) &&
-           g4x_compute_wm0(dev, 2,
-                           &sandybridge_display_wm_info, latency,
-                           &sandybridge_cursor_wm_info, latency,
-                           &plane_wm, &cursor_wm)) {
-               val = I915_READ(WM0_PIPEC_IVB);
-               val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-               I915_WRITE(WM0_PIPEC_IVB, val |
-                          ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
-               DRM_DEBUG_KMS("FIFO watermarks For pipe C -"
-                             " plane %d, cursor: %d\n",
-                             plane_wm, cursor_wm);
-               enabled |= 3;
+       pipeconf &= ~PIPECONF_INTERLACE_MASK;
+       if (!IS_GEN2(dev) &&
+           adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+               pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+               /* the chip adds 2 halflines automatically */
+               adjusted_mode->crtc_vtotal -= 1;
+               adjusted_mode->crtc_vblank_end -= 1;
+               vsyncshift = adjusted_mode->crtc_hsync_start
+                            - adjusted_mode->crtc_htotal/2;
+       } else {
+               pipeconf |= PIPECONF_PROGRESSIVE;
+               vsyncshift = 0;
        }
 
-       /*
-        * Calculate and update the self-refresh watermark only when one
-        * display plane is used.
-        *
-        * SNB support 3 levels of watermark.
-        *
-        * WM1/WM2/WM2 watermarks have to be enabled in the ascending order,
-        * and disabled in the descending order
-        *
-        */
-       I915_WRITE(WM3_LP_ILK, 0);
-       I915_WRITE(WM2_LP_ILK, 0);
-       I915_WRITE(WM1_LP_ILK, 0);
+       if (!IS_GEN3(dev))
+               I915_WRITE(VSYNCSHIFT(pipe), vsyncshift);
 
-       if (!single_plane_enabled(enabled) ||
-           dev_priv->sprite_scaling_enabled)
-               return;
-       enabled = ffs(enabled) - 1;
-
-       /* WM1 */
-       if (!ironlake_compute_srwm(dev, 1, enabled,
-                                  SNB_READ_WM1_LATENCY() * 500,
-                                  &sandybridge_display_srwm_info,
-                                  &sandybridge_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &cursor_wm))
-               return;
+       I915_WRITE(HTOTAL(pipe),
+                  (adjusted_mode->crtc_hdisplay - 1) |
+                  ((adjusted_mode->crtc_htotal - 1) << 16));
+       I915_WRITE(HBLANK(pipe),
+                  (adjusted_mode->crtc_hblank_start - 1) |
+                  ((adjusted_mode->crtc_hblank_end - 1) << 16));
+       I915_WRITE(HSYNC(pipe),
+                  (adjusted_mode->crtc_hsync_start - 1) |
+                  ((adjusted_mode->crtc_hsync_end - 1) << 16));
 
-       I915_WRITE(WM1_LP_ILK,
-                  WM1_LP_SR_EN |
-                  (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
-                  (fbc_wm << WM1_LP_FBC_SHIFT) |
-                  (plane_wm << WM1_LP_SR_SHIFT) |
-                  cursor_wm);
-
-       /* WM2 */
-       if (!ironlake_compute_srwm(dev, 2, enabled,
-                                  SNB_READ_WM2_LATENCY() * 500,
-                                  &sandybridge_display_srwm_info,
-                                  &sandybridge_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &cursor_wm))
-               return;
+       I915_WRITE(VTOTAL(pipe),
+                  (adjusted_mode->crtc_vdisplay - 1) |
+                  ((adjusted_mode->crtc_vtotal - 1) << 16));
+       I915_WRITE(VBLANK(pipe),
+                  (adjusted_mode->crtc_vblank_start - 1) |
+                  ((adjusted_mode->crtc_vblank_end - 1) << 16));
+       I915_WRITE(VSYNC(pipe),
+                  (adjusted_mode->crtc_vsync_start - 1) |
+                  ((adjusted_mode->crtc_vsync_end - 1) << 16));
 
-       I915_WRITE(WM2_LP_ILK,
-                  WM2_LP_EN |
-                  (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
-                  (fbc_wm << WM1_LP_FBC_SHIFT) |
-                  (plane_wm << WM1_LP_SR_SHIFT) |
-                  cursor_wm);
-
-       /* WM3 */
-       if (!ironlake_compute_srwm(dev, 3, enabled,
-                                  SNB_READ_WM3_LATENCY() * 500,
-                                  &sandybridge_display_srwm_info,
-                                  &sandybridge_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &cursor_wm))
-               return;
+       /* pipesrc and dspsize control the size that is scaled from,
+        * which should always be the user's requested size.
+        */
+       I915_WRITE(DSPSIZE(plane),
+                  ((mode->vdisplay - 1) << 16) |
+                  (mode->hdisplay - 1));
+       I915_WRITE(DSPPOS(plane), 0);
+       I915_WRITE(PIPESRC(pipe),
+                  ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
 
-       I915_WRITE(WM3_LP_ILK,
-                  WM3_LP_EN |
-                  (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) |
-                  (fbc_wm << WM1_LP_FBC_SHIFT) |
-                  (plane_wm << WM1_LP_SR_SHIFT) |
-                  cursor_wm);
-}
+       I915_WRITE(PIPECONF(pipe), pipeconf);
+       POSTING_READ(PIPECONF(pipe));
+       intel_enable_pipe(dev_priv, pipe, false);
 
-static bool
-sandybridge_compute_sprite_wm(struct drm_device *dev, int plane,
-                             uint32_t sprite_width, int pixel_size,
-                             const struct intel_watermark_params *display,
-                             int display_latency_ns, int *sprite_wm)
-{
-       struct drm_crtc *crtc;
-       int clock;
-       int entries, tlb_miss;
+       intel_wait_for_vblank(dev, pipe);
 
-       crtc = intel_get_crtc_for_plane(dev, plane);
-       if (crtc->fb == NULL || !crtc->enabled) {
-               *sprite_wm = display->guard_size;
-               return false;
-       }
+       I915_WRITE(DSPCNTR(plane), dspcntr);
+       POSTING_READ(DSPCNTR(plane));
 
-       clock = crtc->mode.clock;
+       ret = intel_pipe_set_base(crtc, x, y, old_fb);
 
-       /* Use the small buffer method to calculate the sprite watermark */
-       entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
-       tlb_miss = display->fifo_size*display->cacheline_size -
-               sprite_width * 8;
-       if (tlb_miss > 0)
-               entries += tlb_miss;
-       entries = DIV_ROUND_UP(entries, display->cacheline_size);
-       *sprite_wm = entries + display->guard_size;
-       if (*sprite_wm > (int)display->max_wm)
-               *sprite_wm = display->max_wm;
+       intel_update_watermarks(dev);
 
-       return true;
+       return ret;
 }
 
-static bool
-sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane,
-                               uint32_t sprite_width, int pixel_size,
-                               const struct intel_watermark_params *display,
-                               int latency_ns, int *sprite_wm)
+/*
+ * Initialize reference clocks when the driver loads
+ */
+void ironlake_init_pch_refclk(struct drm_device *dev)
 {
-       struct drm_crtc *crtc;
-       unsigned long line_time_us;
-       int clock;
-       int line_count, line_size;
-       int small, large;
-       int entries;
-
-       if (!latency_ns) {
-               *sprite_wm = 0;
-               return false;
-       }
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
+       u32 temp;
+       bool has_lvds = false;
+       bool has_cpu_edp = false;
+       bool has_pch_edp = false;
+       bool has_panel = false;
+       bool has_ck505 = false;
+       bool can_ssc = false;
 
-       crtc = intel_get_crtc_for_plane(dev, plane);
-       clock = crtc->mode.clock;
-       if (!clock) {
-               *sprite_wm = 0;
-               return false;
+       /* We need to take the global config into account */
+       list_for_each_entry(encoder, &mode_config->encoder_list,
+                           base.head) {
+               switch (encoder->type) {
+               case INTEL_OUTPUT_LVDS:
+                       has_panel = true;
+                       has_lvds = true;
+                       break;
+               case INTEL_OUTPUT_EDP:
+                       has_panel = true;
+                       if (intel_encoder_is_pch_edp(&encoder->base))
+                               has_pch_edp = true;
+                       else
+                               has_cpu_edp = true;
+                       break;
+               }
        }
 
-       line_time_us = (sprite_width * 1000) / clock;
-       if (!line_time_us) {
-               *sprite_wm = 0;
-               return false;
+       if (HAS_PCH_IBX(dev)) {
+               has_ck505 = dev_priv->display_clock_mode;
+               can_ssc = has_ck505;
+       } else {
+               has_ck505 = false;
+               can_ssc = true;
        }
 
-       line_count = (latency_ns / line_time_us + 1000) / 1000;
-       line_size = sprite_width * pixel_size;
+       DRM_DEBUG_KMS("has_panel %d has_lvds %d has_pch_edp %d has_cpu_edp %d has_ck505 %d\n",
+                     has_panel, has_lvds, has_pch_edp, has_cpu_edp,
+                     has_ck505);
 
-       /* Use the minimum of the small and large buffer method for primary */
-       small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
-       large = line_count * line_size;
+       /* Ironlake: try to setup display ref clock before DPLL
+        * enabling. This is only under driver's control after
+        * PCH B stepping, previous chipset stepping should be
+        * ignoring this setting.
+        */
+       temp = I915_READ(PCH_DREF_CONTROL);
+       /* Always enable nonspread source */
+       temp &= ~DREF_NONSPREAD_SOURCE_MASK;
 
-       entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
-       *sprite_wm = entries + display->guard_size;
+       if (has_ck505)
+               temp |= DREF_NONSPREAD_CK505_ENABLE;
+       else
+               temp |= DREF_NONSPREAD_SOURCE_ENABLE;
 
-       return *sprite_wm > 0x3ff ? false : true;
-}
+       if (has_panel) {
+               temp &= ~DREF_SSC_SOURCE_MASK;
+               temp |= DREF_SSC_SOURCE_ENABLE;
 
-static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
-                                        uint32_t sprite_width, int pixel_size)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int latency = SNB_READ_WM0_LATENCY() * 100;     /* In unit 0.1us */
-       u32 val;
-       int sprite_wm, reg;
-       int ret;
+               /* SSC must be turned on before enabling the CPU output  */
+               if (intel_panel_use_ssc(dev_priv) && can_ssc) {
+                       DRM_DEBUG_KMS("Using SSC on panel\n");
+                       temp |= DREF_SSC1_ENABLE;
+               } else
+                       temp &= ~DREF_SSC1_ENABLE;
 
-       switch (pipe) {
-       case 0:
-               reg = WM0_PIPEA_ILK;
-               break;
-       case 1:
-               reg = WM0_PIPEB_ILK;
-               break;
-       case 2:
-               reg = WM0_PIPEC_IVB;
-               break;
-       default:
-               return; /* bad pipe */
-       }
-
-       ret = sandybridge_compute_sprite_wm(dev, pipe, sprite_width, pixel_size,
-                                           &sandybridge_display_wm_info,
-                                           latency, &sprite_wm);
-       if (!ret) {
-               DRM_DEBUG_KMS("failed to compute sprite wm for pipe %d\n",
-                             pipe);
-               return;
-       }
+               /* Get SSC going before enabling the outputs */
+               I915_WRITE(PCH_DREF_CONTROL, temp);
+               POSTING_READ(PCH_DREF_CONTROL);
+               udelay(200);
 
-       val = I915_READ(reg);
-       val &= ~WM0_PIPE_SPRITE_MASK;
-       I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT));
-       DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm);
-
-
-       ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
-                                             pixel_size,
-                                             &sandybridge_display_srwm_info,
-                                             SNB_READ_WM1_LATENCY() * 500,
-                                             &sprite_wm);
-       if (!ret) {
-               DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %d\n",
-                             pipe);
-               return;
-       }
-       I915_WRITE(WM1S_LP_ILK, sprite_wm);
+               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 
-       /* Only IVB has two more LP watermarks for sprite */
-       if (!IS_IVYBRIDGE(dev))
-               return;
+               /* Enable CPU source on CPU attached eDP */
+               if (has_cpu_edp) {
+                       if (intel_panel_use_ssc(dev_priv) && can_ssc) {
+                               DRM_DEBUG_KMS("Using SSC on eDP\n");
+                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                       }
+                       else
+                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+               } else
+                       temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
 
-       ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
-                                             pixel_size,
-                                             &sandybridge_display_srwm_info,
-                                             SNB_READ_WM2_LATENCY() * 500,
-                                             &sprite_wm);
-       if (!ret) {
-               DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %d\n",
-                             pipe);
-               return;
-       }
-       I915_WRITE(WM2S_LP_IVB, sprite_wm);
+               I915_WRITE(PCH_DREF_CONTROL, temp);
+               POSTING_READ(PCH_DREF_CONTROL);
+               udelay(200);
+       } else {
+               DRM_DEBUG_KMS("Disabling SSC entirely\n");
 
-       ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
-                                             pixel_size,
-                                             &sandybridge_display_srwm_info,
-                                             SNB_READ_WM3_LATENCY() * 500,
-                                             &sprite_wm);
-       if (!ret) {
-               DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %d\n",
-                             pipe);
-               return;
-       }
-       I915_WRITE(WM3S_LP_IVB, sprite_wm);
-}
+               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 
-/**
- * intel_update_watermarks - update FIFO watermark values based on current modes
- *
- * Calculate watermark values for the various WM regs based on current mode
- * and plane configuration.
- *
- * There are several cases to deal with here:
- *   - normal (i.e. non-self-refresh)
- *   - self-refresh (SR) mode
- *   - lines are large relative to FIFO size (buffer can hold up to 2)
- *   - lines are small relative to FIFO size (buffer can hold more than 2
- *     lines), so need to account for TLB latency
- *
- *   The normal calculation is:
- *     watermark = dotclock * bytes per pixel * latency
- *   where latency is platform & configuration dependent (we assume pessimal
- *   values here).
- *
- *   The SR calculation is:
- *     watermark = (trunc(latency/line time)+1) * surface width *
- *       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,
- * and include an extra 2 entries to account for clock crossings.
- *
- * 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;
+               /* Turn off CPU output */
+               temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
 
-       if (dev_priv->display.update_wm)
-               dev_priv->display.update_wm(dev);
-}
+               I915_WRITE(PCH_DREF_CONTROL, temp);
+               POSTING_READ(PCH_DREF_CONTROL);
+               udelay(200);
 
-void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
-                                   uint32_t sprite_width, int pixel_size)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
+               /* Turn off the SSC source */
+               temp &= ~DREF_SSC_SOURCE_MASK;
+               temp |= DREF_SSC_SOURCE_DISABLE;
 
-       if (dev_priv->display.update_sprite_wm)
-               dev_priv->display.update_sprite_wm(dev, pipe, sprite_width,
-                                                  pixel_size);
-}
+               /* Turn off SSC1 */
+               temp &= ~ DREF_SSC1_ENABLE;
 
-static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
-{
-       if (i915_panel_use_ssc >= 0)
-               return i915_panel_use_ssc != 0;
-       return dev_priv->lvds_use_ssc
-               && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
+               I915_WRITE(PCH_DREF_CONTROL, temp);
+               POSTING_READ(PCH_DREF_CONTROL);
+               udelay(200);
+       }
 }
 
-/**
- * intel_choose_pipe_bpp_dither - figure out what color depth the pipe should send
- * @crtc: CRTC structure
- * @mode: requested mode
- *
- * A pipe may be connected to one or more outputs.  Based on the depth of the
- * attached framebuffer, choose a good color depth to use on the pipe.
- *
- * If possible, match the pipe depth to the fb depth.  In some cases, this
- * isn't ideal, because the connected output supports a lesser or restricted
- * set of depths.  Resolve that here:
- *    LVDS typically supports only 6bpc, so clamp down in that case
- *    HDMI supports only 8bpc or 12bpc, so clamp to 8bpc with dither for 10bpc
- *    Displays may support a restricted set as well, check EDID and clamp as
- *      appropriate.
- *    DP may want to dither down to 6bpc to fit larger modes
- *
- * RETURNS:
- * Dithering requirement (i.e. false if display bpc and pipe bpc match,
- * true if they don't match).
- */
-static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
-                                        unsigned int *pipe_bpp,
-                                        struct drm_display_mode *mode)
+static int ironlake_get_refclk(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_encoder *encoder;
-       struct drm_connector *connector;
-       unsigned int display_bpc = UINT_MAX, bpc;
-
-       /* Walk the encoders & connectors on this crtc, get min bpc */
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
+       struct intel_encoder *encoder;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *edp_encoder = NULL;
+       int num_connectors = 0;
+       bool is_lvds = false;
 
-               if (encoder->crtc != crtc)
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               if (encoder->base.crtc != crtc)
                        continue;
 
-               if (intel_encoder->type == INTEL_OUTPUT_LVDS) {
-                       unsigned int lvds_bpc;
+               switch (encoder->type) {
+               case INTEL_OUTPUT_LVDS:
+                       is_lvds = true;
+                       break;
+               case INTEL_OUTPUT_EDP:
+                       edp_encoder = encoder;
+                       break;
+               }
+               num_connectors++;
+       }
 
-                       if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) ==
-                           LVDS_A3_POWER_UP)
-                               lvds_bpc = 8;
-                       else
-                               lvds_bpc = 6;
+       if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
+               DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
+                             dev_priv->lvds_ssc_freq);
+               return dev_priv->lvds_ssc_freq * 1000;
+       }
 
-                       if (lvds_bpc < display_bpc) {
-                               DRM_DEBUG_KMS("clamping display bpc (was %d) to LVDS (%d)\n", display_bpc, lvds_bpc);
-                               display_bpc = lvds_bpc;
-                       }
-                       continue;
-               }
+       return 120000;
+}
 
-               if (intel_encoder->type == INTEL_OUTPUT_EDP) {
-                       /* Use VBT settings if we have an eDP panel */
-                       unsigned int edp_bpc = dev_priv->edp.bpp / 3;
+static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode,
+                                 int x, int y,
+                                 struct drm_framebuffer *old_fb)
+{
+       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 refclk, num_connectors = 0;
+       intel_clock_t clock, reduced_clock;
+       u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
+       bool ok, has_reduced_clock = false, is_sdvo = false;
+       bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder, *edp_encoder = NULL;
+       const intel_limit_t *limit;
+       int ret;
+       struct fdi_m_n m_n = {0};
+       u32 temp;
+       int target_clock, pixel_multiplier, lane, link_bw, factor;
+       unsigned int pipe_bpp;
+       bool dither;
+       bool is_cpu_edp = false, is_pch_edp = false;
 
-                       if (edp_bpc < display_bpc) {
-                               DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc);
-                               display_bpc = edp_bpc;
-                       }
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               if (encoder->base.crtc != crtc)
                        continue;
-               }
-
-               /* Not one of the known troublemakers, check the EDID */
-               list_for_each_entry(connector, &dev->mode_config.connector_list,
-                                   head) {
-                       if (connector->encoder != encoder)
-                               continue;
 
-                       /* Don't use an invalid EDID bpc value */
-                       if (connector->display_info.bpc &&
-                           connector->display_info.bpc < display_bpc) {
-                               DRM_DEBUG_KMS("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc);
-                               display_bpc = connector->display_info.bpc;
-                       }
+               switch (encoder->type) {
+               case INTEL_OUTPUT_LVDS:
+                       is_lvds = true;
+                       break;
+               case INTEL_OUTPUT_SDVO:
+               case INTEL_OUTPUT_HDMI:
+                       is_sdvo = true;
+                       if (encoder->needs_tv_clock)
+                               is_tv = true;
+                       break;
+               case INTEL_OUTPUT_TVOUT:
+                       is_tv = true;
+                       break;
+               case INTEL_OUTPUT_ANALOG:
+                       is_crt = true;
+                       break;
+               case INTEL_OUTPUT_DISPLAYPORT:
+                       is_dp = true;
+                       break;
+               case INTEL_OUTPUT_EDP:
+                       is_dp = true;
+                       if (intel_encoder_is_pch_edp(&encoder->base))
+                               is_pch_edp = true;
+                       else
+                               is_cpu_edp = true;
+                       edp_encoder = encoder;
+                       break;
                }
 
-               /*
-                * HDMI is either 12 or 8, so if the display lets 10bpc sneak
-                * through, clamp it down.  (Note: >12bpc will be caught below.)
-                */
-               if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
-                       if (display_bpc > 8 && display_bpc < 12) {
-                               DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n");
-                               display_bpc = 12;
-                       } else {
-                               DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n");
-                               display_bpc = 8;
-                       }
-               }
+               num_connectors++;
        }
 
-       if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
-               DRM_DEBUG_KMS("Dithering DP to 6bpc\n");
-               display_bpc = 6;
-       }
+       refclk = ironlake_get_refclk(crtc);
 
        /*
-        * We could just drive the pipe at the highest bpc all the time and
-        * enable dithering as needed, but that costs bandwidth.  So choose
-        * the minimum value that expresses the full color range of the fb but
-        * also stays within the max display bpc discovered above.
+        * Returns a set of divisors for the desired target clock with the given
+        * refclk, or FALSE.  The returned values represent the clock equation:
+        * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
         */
+       limit = intel_limit(crtc, refclk);
+       ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
+                            &clock);
+       if (!ok) {
+               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               return -EINVAL;
+       }
 
-       switch (crtc->fb->depth) {
-       case 8:
-               bpc = 8; /* since we go through a colormap */
-               break;
-       case 15:
-       case 16:
-               bpc = 6; /* min is 18bpp */
-               break;
-       case 24:
-               bpc = 8;
-               break;
-       case 30:
-               bpc = 10;
-               break;
-       case 48:
-               bpc = 12;
-               break;
-       default:
-               DRM_DEBUG("unsupported depth, assuming 24 bits\n");
-               bpc = min((unsigned int)8, display_bpc);
-               break;
-       }
-
-       display_bpc = min(display_bpc, bpc);
-
-       DRM_DEBUG_KMS("setting pipe bpc to %d (max display bpc %d)\n",
-                     bpc, display_bpc);
-
-       *pipe_bpp = display_bpc * 3;
-
-       return display_bpc != bpc;
-}
-
-static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int refclk;
-
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
-           intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
-               refclk = dev_priv->lvds_ssc_freq * 1000;
-               DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
-                             refclk / 1000);
-       } else if (!IS_GEN2(dev)) {
-               refclk = 96000;
-       } else {
-               refclk = 48000;
-       }
-
-       return refclk;
-}
-
-static void i9xx_adjust_sdvo_tv_clock(struct drm_display_mode *adjusted_mode,
-                                     intel_clock_t *clock)
-{
-       /* SDVO TV has fixed PLL values depend on its clock range,
-          this mirrors vbios setting. */
-       if (adjusted_mode->clock >= 100000
-           && 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) {
-               clock->p1 = 1;
-               clock->p2 = 10;
-               clock->n = 6;
-               clock->m1 = 12;
-               clock->m2 = 8;
-       }
-}
-
-static void i9xx_update_pll_dividers(struct drm_crtc *crtc,
-                                    intel_clock_t *clock,
-                                    intel_clock_t *reduced_clock)
-{
-       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;
-       u32 fp, fp2 = 0;
-
-       if (IS_PINEVIEW(dev)) {
-               fp = (1 << clock->n) << 16 | clock->m1 << 8 | clock->m2;
-               if (reduced_clock)
-                       fp2 = (1 << reduced_clock->n) << 16 |
-                               reduced_clock->m1 << 8 | reduced_clock->m2;
-       } else {
-               fp = clock->n << 16 | clock->m1 << 8 | clock->m2;
-               if (reduced_clock)
-                       fp2 = reduced_clock->n << 16 | reduced_clock->m1 << 8 |
-                               reduced_clock->m2;
-       }
-
-       I915_WRITE(FP0(pipe), fp);
-
-       intel_crtc->lowfreq_avail = false;
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
-           reduced_clock && i915_powersave) {
-               I915_WRITE(FP1(pipe), fp2);
-               intel_crtc->lowfreq_avail = true;
-       } else {
-               I915_WRITE(FP1(pipe), fp);
-       }
-}
-
-static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
-                             struct drm_display_mode *mode,
-                             struct drm_display_mode *adjusted_mode,
-                             int x, int y,
-                             struct drm_framebuffer *old_fb)
-{
-       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 refclk, num_connectors = 0;
-       intel_clock_t clock, reduced_clock;
-       u32 dpll, dspcntr, pipeconf, vsyncshift;
-       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 drm_mode_config *mode_config = &dev->mode_config;
-       struct intel_encoder *encoder;
-       const intel_limit_t *limit;
-       int ret;
-       u32 temp;
-       u32 lvds_sync = 0;
-
-       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
-               if (encoder->base.crtc != crtc)
-                       continue;
-
-               switch (encoder->type) {
-               case INTEL_OUTPUT_LVDS:
-                       is_lvds = true;
-                       break;
-               case INTEL_OUTPUT_SDVO:
-               case INTEL_OUTPUT_HDMI:
-                       is_sdvo = true;
-                       if (encoder->needs_tv_clock)
-                               is_tv = true;
-                       break;
-               case INTEL_OUTPUT_DVO:
-                       is_dvo = true;
-                       break;
-               case INTEL_OUTPUT_TVOUT:
-                       is_tv = true;
-                       break;
-               case INTEL_OUTPUT_ANALOG:
-                       is_crt = true;
-                       break;
-               case INTEL_OUTPUT_DISPLAYPORT:
-                       is_dp = true;
-                       break;
-               }
-
-               num_connectors++;
-       }
-
-       refclk = i9xx_get_refclk(crtc, num_connectors);
-
-       /*
-        * Returns a set of divisors for the desired target clock with the given
-        * refclk, or FALSE.  The returned values represent the clock equation:
-        * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
-        */
-       limit = intel_limit(crtc, refclk);
-       ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
-                            &clock);
-       if (!ok) {
-               DRM_ERROR("Couldn't find PLL settings for mode!\n");
-               return -EINVAL;
-       }
-
-       /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc, true);
-
-       if (is_lvds && dev_priv->lvds_downclock_avail) {
-               /*
-                * Ensure we match the reduced clock's P to the target clock.
-                * If the clocks don't match, we can't switch the display clock
-                * by using the FP0/FP1. In such case we will disable the LVDS
-                * downclock feature.
-               */
-               has_reduced_clock = limit->find_pll(limit, crtc,
-                                                   dev_priv->lvds_downclock,
-                                                   refclk,
-                                                   &clock,
-                                                   &reduced_clock);
-       }
-
-       if (is_sdvo && is_tv)
-               i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock);
-
-       i9xx_update_pll_dividers(crtc, &clock, has_reduced_clock ?
-                                &reduced_clock : NULL);
-
-       dpll = DPLL_VGA_MODE_DIS;
-
-       if (!IS_GEN2(dev)) {
-               if (is_lvds)
-                       dpll |= DPLLB_MODE_LVDS;
-               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;
-                       }
-                       dpll |= DPLL_DVO_HIGH_SPEED;
-               }
-               if (is_dp)
-                       dpll |= DPLL_DVO_HIGH_SPEED;
-
-               /* compute bitmask from p1 value */
-               if (IS_PINEVIEW(dev))
-                       dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
-               else {
-                       dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
-                       if (IS_G4X(dev) && has_reduced_clock)
-                               dpll |= (1 << (reduced_clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
-               }
-               switch (clock.p2) {
-               case 5:
-                       dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
-                       break;
-               case 7:
-                       dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
-                       break;
-               case 10:
-                       dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
-                       break;
-               case 14:
-                       dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
-                       break;
-               }
-               if (INTEL_INFO(dev)->gen >= 4)
-                       dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
-       } else {
-               if (is_lvds) {
-                       dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
-               } else {
-                       if (clock.p1 == 2)
-                               dpll |= PLL_P1_DIVIDE_BY_TWO;
-                       else
-                               dpll |= (clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT;
-                       if (clock.p2 == 4)
-                               dpll |= PLL_P2_DIVIDE_BY_4;
-               }
-       }
-
-       if (is_sdvo && is_tv)
-               dpll |= PLL_REF_INPUT_TVCLKINBC;
-       else if (is_tv)
-               /* XXX: just matching BIOS for now */
-               /*      dpll |= PLL_REF_INPUT_TVCLKINBC; */
-               dpll |= 3;
-       else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
-               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
-       else
-               dpll |= PLL_REF_INPUT_DREFCLK;
-
-       /* setup pipeconf */
-       pipeconf = I915_READ(PIPECONF(pipe));
-
-       /* Set up the display plane register */
-       dspcntr = DISPPLANE_GAMMA_ENABLE;
-
-       if (pipe == 0)
-               dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
-       else
-               dspcntr |= DISPPLANE_SEL_PIPE_B;
-
-       if (pipe == 0 && INTEL_INFO(dev)->gen < 4) {
-               /* Enable pixel doubling when the dot clock is > 90% of the (display)
-                * core speed.
-                *
-                * XXX: No double-wide on 915GM pipe B. Is that the only reason for the
-                * pipe == 0 check?
-                */
-               if (mode->clock >
-                   dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
-                       pipeconf |= PIPECONF_DOUBLE_WIDE;
-               else
-                       pipeconf &= ~PIPECONF_DOUBLE_WIDE;
-       }
-
-       /* default to 8bpc */
-       pipeconf &= ~(PIPECONF_BPP_MASK | PIPECONF_DITHER_EN);
-       if (is_dp) {
-               if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
-                       pipeconf |= PIPECONF_BPP_6 |
-                                   PIPECONF_DITHER_EN |
-                                   PIPECONF_DITHER_TYPE_SP;
-               }
-       }
-
-       dpll |= DPLL_VCO_ENABLE;
-
-       DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
-       drm_mode_debug_printmodeline(mode);
-
-       I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
-
-       POSTING_READ(DPLL(pipe));
-       udelay(150);
-
-       /* The LVDS pin pair needs to be on before the DPLLs are enabled.
-        * This is an exception to the general rule that mode_set doesn't turn
-        * things on.
-        */
-       if (is_lvds) {
-               temp = I915_READ(LVDS);
-               temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
-               if (pipe == 1) {
-                       temp |= LVDS_PIPEB_SELECT;
-               } else {
-                       temp &= ~LVDS_PIPEB_SELECT;
-               }
-               /* set the corresponsding LVDS_BORDER bit */
-               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)
-                       temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
-               else
-                       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 on LVDS as needed */
-               if (INTEL_INFO(dev)->gen >= 4) {
-                       if (dev_priv->lvds_dither)
-                               temp |= LVDS_ENABLE_DITHER;
-                       else
-                               temp &= ~LVDS_ENABLE_DITHER;
-               }
-               if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
-                       lvds_sync |= LVDS_HSYNC_POLARITY;
-               if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
-                       lvds_sync |= LVDS_VSYNC_POLARITY;
-               if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY))
-                   != lvds_sync) {
-                       char flags[2] = "-+";
-                       DRM_INFO("Changing LVDS panel from "
-                                "(%chsync, %cvsync) to (%chsync, %cvsync)\n",
-                                flags[!(temp & LVDS_HSYNC_POLARITY)],
-                                flags[!(temp & LVDS_VSYNC_POLARITY)],
-                                flags[!(lvds_sync & LVDS_HSYNC_POLARITY)],
-                                flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]);
-                       temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
-                       temp |= lvds_sync;
-               }
-               I915_WRITE(LVDS, temp);
-       }
-
-       if (is_dp) {
-               intel_dp_set_m_n(crtc, mode, adjusted_mode);
-       }
-
-       I915_WRITE(DPLL(pipe), dpll);
-
-       /* Wait for the clocks to stabilize. */
-       POSTING_READ(DPLL(pipe));
-       udelay(150);
-
-       if (INTEL_INFO(dev)->gen >= 4) {
-               temp = 0;
-               if (is_sdvo) {
-                       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 {
-               /* The pixel multiplier can only be updated once the
-                * DPLL is enabled and the clocks are stable.
-                *
-                * So write it again.
-                */
-               I915_WRITE(DPLL(pipe), dpll);
-       }
-
-       if (HAS_PIPE_CXSR(dev)) {
-               if (intel_crtc->lowfreq_avail) {
-                       DRM_DEBUG_KMS("enabling CxSR downclocking\n");
-                       pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
-               } else {
-                       DRM_DEBUG_KMS("disabling CxSR downclocking\n");
-                       pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
-               }
-       }
-
-       pipeconf &= ~PIPECONF_INTERLACE_MASK;
-       if (!IS_GEN2(dev) &&
-           adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
-               pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
-               /* the chip adds 2 halflines automatically */
-               adjusted_mode->crtc_vtotal -= 1;
-               adjusted_mode->crtc_vblank_end -= 1;
-               vsyncshift = adjusted_mode->crtc_hsync_start
-                            - adjusted_mode->crtc_htotal/2;
-       } else {
-               pipeconf |= PIPECONF_PROGRESSIVE;
-               vsyncshift = 0;
-       }
-
-       if (!IS_GEN3(dev))
-               I915_WRITE(VSYNCSHIFT(pipe), vsyncshift);
-
-       I915_WRITE(HTOTAL(pipe),
-                  (adjusted_mode->crtc_hdisplay - 1) |
-                  ((adjusted_mode->crtc_htotal - 1) << 16));
-       I915_WRITE(HBLANK(pipe),
-                  (adjusted_mode->crtc_hblank_start - 1) |
-                  ((adjusted_mode->crtc_hblank_end - 1) << 16));
-       I915_WRITE(HSYNC(pipe),
-                  (adjusted_mode->crtc_hsync_start - 1) |
-                  ((adjusted_mode->crtc_hsync_end - 1) << 16));
-
-       I915_WRITE(VTOTAL(pipe),
-                  (adjusted_mode->crtc_vdisplay - 1) |
-                  ((adjusted_mode->crtc_vtotal - 1) << 16));
-       I915_WRITE(VBLANK(pipe),
-                  (adjusted_mode->crtc_vblank_start - 1) |
-                  ((adjusted_mode->crtc_vblank_end - 1) << 16));
-       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.
-        */
-       I915_WRITE(DSPSIZE(plane),
-                  ((mode->vdisplay - 1) << 16) |
-                  (mode->hdisplay - 1));
-       I915_WRITE(DSPPOS(plane), 0);
-       I915_WRITE(PIPESRC(pipe),
-                  ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
-
-       I915_WRITE(PIPECONF(pipe), pipeconf);
-       POSTING_READ(PIPECONF(pipe));
-       intel_enable_pipe(dev_priv, pipe, false);
-
-       intel_wait_for_vblank(dev, pipe);
-
-       I915_WRITE(DSPCNTR(plane), dspcntr);
-       POSTING_READ(DSPCNTR(plane));
-       intel_enable_plane(dev_priv, plane, pipe);
-
-       ret = intel_pipe_set_base(crtc, x, y, old_fb);
-
-       intel_update_watermarks(dev);
-
-       return ret;
-}
-
-/*
- * Initialize reference clocks when the driver loads
- */
-void ironlake_init_pch_refclk(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_mode_config *mode_config = &dev->mode_config;
-       struct intel_encoder *encoder;
-       u32 temp;
-       bool has_lvds = false;
-       bool has_cpu_edp = false;
-       bool has_pch_edp = false;
-       bool has_panel = false;
-       bool has_ck505 = false;
-       bool can_ssc = false;
-
-       /* We need to take the global config into account */
-       list_for_each_entry(encoder, &mode_config->encoder_list,
-                           base.head) {
-               switch (encoder->type) {
-               case INTEL_OUTPUT_LVDS:
-                       has_panel = true;
-                       has_lvds = true;
-                       break;
-               case INTEL_OUTPUT_EDP:
-                       has_panel = true;
-                       if (intel_encoder_is_pch_edp(&encoder->base))
-                               has_pch_edp = true;
-                       else
-                               has_cpu_edp = true;
-                       break;
-               }
-       }
-
-       if (HAS_PCH_IBX(dev)) {
-               has_ck505 = dev_priv->display_clock_mode;
-               can_ssc = has_ck505;
-       } else {
-               has_ck505 = false;
-               can_ssc = true;
-       }
-
-       DRM_DEBUG_KMS("has_panel %d has_lvds %d has_pch_edp %d has_cpu_edp %d has_ck505 %d\n",
-                     has_panel, has_lvds, has_pch_edp, has_cpu_edp,
-                     has_ck505);
-
-       /* Ironlake: try to setup display ref clock before DPLL
-        * enabling. This is only under driver's control after
-        * PCH B stepping, previous chipset stepping should be
-        * ignoring this setting.
-        */
-       temp = I915_READ(PCH_DREF_CONTROL);
-       /* Always enable nonspread source */
-       temp &= ~DREF_NONSPREAD_SOURCE_MASK;
-
-       if (has_ck505)
-               temp |= DREF_NONSPREAD_CK505_ENABLE;
-       else
-               temp |= DREF_NONSPREAD_SOURCE_ENABLE;
-
-       if (has_panel) {
-               temp &= ~DREF_SSC_SOURCE_MASK;
-               temp |= DREF_SSC_SOURCE_ENABLE;
-
-               /* SSC must be turned on before enabling the CPU output  */
-               if (intel_panel_use_ssc(dev_priv) && can_ssc) {
-                       DRM_DEBUG_KMS("Using SSC on panel\n");
-                       temp |= DREF_SSC1_ENABLE;
-               } else
-                       temp &= ~DREF_SSC1_ENABLE;
-
-               /* Get SSC going before enabling the outputs */
-               I915_WRITE(PCH_DREF_CONTROL, temp);
-               POSTING_READ(PCH_DREF_CONTROL);
-               udelay(200);
-
-               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
-
-               /* Enable CPU source on CPU attached eDP */
-               if (has_cpu_edp) {
-                       if (intel_panel_use_ssc(dev_priv) && can_ssc) {
-                               DRM_DEBUG_KMS("Using SSC on eDP\n");
-                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
-                       }
-                       else
-                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
-               } else
-                       temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
-
-               I915_WRITE(PCH_DREF_CONTROL, temp);
-               POSTING_READ(PCH_DREF_CONTROL);
-               udelay(200);
-       } else {
-               DRM_DEBUG_KMS("Disabling SSC entirely\n");
-
-               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
-
-               /* Turn off CPU output */
-               temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
-
-               I915_WRITE(PCH_DREF_CONTROL, temp);
-               POSTING_READ(PCH_DREF_CONTROL);
-               udelay(200);
-
-               /* Turn off the SSC source */
-               temp &= ~DREF_SSC_SOURCE_MASK;
-               temp |= DREF_SSC_SOURCE_DISABLE;
-
-               /* Turn off SSC1 */
-               temp &= ~ DREF_SSC1_ENABLE;
-
-               I915_WRITE(PCH_DREF_CONTROL, temp);
-               POSTING_READ(PCH_DREF_CONTROL);
-               udelay(200);
-       }
-}
-
-static int ironlake_get_refclk(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *encoder;
-       struct drm_mode_config *mode_config = &dev->mode_config;
-       struct intel_encoder *edp_encoder = NULL;
-       int num_connectors = 0;
-       bool is_lvds = false;
-
-       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
-               if (encoder->base.crtc != crtc)
-                       continue;
-
-               switch (encoder->type) {
-               case INTEL_OUTPUT_LVDS:
-                       is_lvds = true;
-                       break;
-               case INTEL_OUTPUT_EDP:
-                       edp_encoder = encoder;
-                       break;
-               }
-               num_connectors++;
-       }
-
-       if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
-               DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
-                             dev_priv->lvds_ssc_freq);
-               return dev_priv->lvds_ssc_freq * 1000;
-       }
-
-       return 120000;
-}
-
-static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
-                                 struct drm_display_mode *mode,
-                                 struct drm_display_mode *adjusted_mode,
-                                 int x, int y,
-                                 struct drm_framebuffer *old_fb)
-{
-       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 refclk, num_connectors = 0;
-       intel_clock_t clock, reduced_clock;
-       u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
-       bool ok, has_reduced_clock = false, is_sdvo = 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 intel_encoder *encoder;
-       const intel_limit_t *limit;
-       int ret;
-       struct fdi_m_n m_n = {0};
-       u32 temp;
-       u32 lvds_sync = 0;
-       int target_clock, pixel_multiplier, lane, link_bw, factor;
-       unsigned int pipe_bpp;
-       bool dither;
-
-       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
-               if (encoder->base.crtc != crtc)
-                       continue;
-
-               switch (encoder->type) {
-               case INTEL_OUTPUT_LVDS:
-                       is_lvds = true;
-                       break;
-               case INTEL_OUTPUT_SDVO:
-               case INTEL_OUTPUT_HDMI:
-                       is_sdvo = true;
-                       if (encoder->needs_tv_clock)
-                               is_tv = true;
-                       break;
-               case INTEL_OUTPUT_TVOUT:
-                       is_tv = true;
-                       break;
-               case INTEL_OUTPUT_ANALOG:
-                       is_crt = true;
-                       break;
-               case INTEL_OUTPUT_DISPLAYPORT:
-                       is_dp = true;
-                       break;
-               case INTEL_OUTPUT_EDP:
-                       has_edp_encoder = encoder;
-                       break;
-               }
-
-               num_connectors++;
-       }
-
-       refclk = ironlake_get_refclk(crtc);
-
-       /*
-        * Returns a set of divisors for the desired target clock with the given
-        * refclk, or FALSE.  The returned values represent the clock equation:
-        * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
-        */
-       limit = intel_limit(crtc, refclk);
-       ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
-                            &clock);
-       if (!ok) {
-               DRM_ERROR("Couldn't find PLL settings for mode!\n");
-               return -EINVAL;
-       }
-
-       /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc, true);
-
-       if (is_lvds && dev_priv->lvds_downclock_avail) {
-               /*
-                * Ensure we match the reduced clock's P to the target clock.
-                * If the clocks don't match, we can't switch the display clock
-                * by using the FP0/FP1. In such case we will disable the LVDS
-                * downclock feature.
-               */
-               has_reduced_clock = limit->find_pll(limit, crtc,
-                                                   dev_priv->lvds_downclock,
-                                                   refclk,
-                                                   &clock,
-                                                   &reduced_clock);
-       }
-       /* SDVO TV has fixed PLL values depend on its clock range,
-          this mirrors vbios setting. */
-       if (is_sdvo && is_tv) {
-               if (adjusted_mode->clock >= 100000
-                   && 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) {
-                       clock.p1 = 1;
-                       clock.p2 = 10;
-                       clock.n = 6;
-                       clock.m1 = 12;
-                       clock.m2 = 8;
-               }
-       }
-
-       /* FDI link */
-       pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
-       lane = 0;
-       /* CPU eDP doesn't require FDI link, so just set DP M/N
-          according to current link config */
-       if (has_edp_encoder &&
-           !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-               target_clock = mode->clock;
-               intel_edp_link_config(has_edp_encoder,
-                                     &lane, &link_bw);
-       } else {
-               /* [e]DP over FDI requires target mode clock
-                  instead of link clock */
-               if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
-                       target_clock = mode->clock;
-               else
-                       target_clock = adjusted_mode->clock;
-
-               /* 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(pipe));
-       temp &= ~PIPE_BPC_MASK;
-       dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, mode);
-       switch (pipe_bpp) {
-       case 18:
-               temp |= PIPE_6BPC;
-               break;
-       case 24:
-               temp |= PIPE_8BPC;
-               break;
-       case 30:
-               temp |= PIPE_10BPC;
-               break;
-       case 36:
-               temp |= PIPE_12BPC;
-               break;
-       default:
-               WARN(1, "intel_choose_pipe_bpp returned invalid value %d\n",
-                       pipe_bpp);
-               temp |= PIPE_8BPC;
-               pipe_bpp = 24;
-               break;
-       }
-
-       intel_crtc->bpp = pipe_bpp;
-       I915_WRITE(PIPECONF(pipe), temp);
-
-       if (!lane) {
-               /*
-                * Account for spread spectrum to avoid
-                * oversubscribing the link. Max center spread
-                * is 2.5%; use 5% for safety's sake.
-                */
-               u32 bps = target_clock * intel_crtc->bpp * 21 / 20;
-               lane = bps / (link_bw * 8) + 1;
-       }
-
-       intel_crtc->fdi_lanes = lane;
-
-       if (pixel_multiplier > 1)
-               link_bw *= pixel_multiplier;
-       ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw,
-                            &m_n);
-
-       fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
-       if (has_reduced_clock)
-               fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
-                       reduced_clock.m2;
-
-       /* Enable autotuning of the PLL clock (if permissible) */
-       factor = 21;
-       if (is_lvds) {
-               if ((intel_panel_use_ssc(dev_priv) &&
-                    dev_priv->lvds_ssc_freq == 100) ||
-                   (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
-                       factor = 25;
-       } else if (is_sdvo && is_tv)
-               factor = 20;
-
-       if (clock.m < factor * clock.n)
-               fp |= FP_CB_TUNE;
-
-       dpll = 0;
-
-       if (is_lvds)
-               dpll |= DPLLB_MODE_LVDS;
-       else
-               dpll |= DPLLB_MODE_DAC_SERIAL;
-       if (is_sdvo) {
-               int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
-               if (pixel_multiplier > 1) {
-                       dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
-               }
-               dpll |= DPLL_DVO_HIGH_SPEED;
-       }
-       if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
-               dpll |= DPLL_DVO_HIGH_SPEED;
-
-       /* compute bitmask from p1 value */
-       dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
-       /* also FPA1 */
-       dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
-
-       switch (clock.p2) {
-       case 5:
-               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
-               break;
-       case 7:
-               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
-               break;
-       case 10:
-               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
-               break;
-       case 14:
-               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
-               break;
-       }
-
-       if (is_sdvo && is_tv)
-               dpll |= PLL_REF_INPUT_TVCLKINBC;
-       else if (is_tv)
-               /* XXX: just matching BIOS for now */
-               /*      dpll |= PLL_REF_INPUT_TVCLKINBC; */
-               dpll |= 3;
-       else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
-               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
-       else
-               dpll |= PLL_REF_INPUT_DREFCLK;
-
-       /* setup pipeconf */
-       pipeconf = I915_READ(PIPECONF(pipe));
-
-       /* Set up the display plane register */
-       dspcntr = DISPPLANE_GAMMA_ENABLE;
-
-       DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
-       drm_mode_debug_printmodeline(mode);
-
-       /* PCH eDP needs FDI, but CPU eDP does not */
-       if (!intel_crtc->no_pll) {
-               if (!has_edp_encoder ||
-                   intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-                       I915_WRITE(PCH_FP0(pipe), fp);
-                       I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
-
-                       POSTING_READ(PCH_DPLL(pipe));
-                       udelay(150);
-               }
-       } else {
-               if (dpll == (I915_READ(PCH_DPLL(0)) & 0x7fffffff) &&
-                   fp == I915_READ(PCH_FP0(0))) {
-                       intel_crtc->use_pll_a = true;
-                       DRM_DEBUG_KMS("using pipe a dpll\n");
-               } else if (dpll == (I915_READ(PCH_DPLL(1)) & 0x7fffffff) &&
-                          fp == I915_READ(PCH_FP0(1))) {
-                       intel_crtc->use_pll_a = false;
-                       DRM_DEBUG_KMS("using pipe b dpll\n");
-               } else {
-                       DRM_DEBUG_KMS("no matching PLL configuration for pipe 2\n");
-                       return -EINVAL;
-               }
-       }
-
-       /* 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.
-        */
-       if (is_lvds) {
-               temp = I915_READ(PCH_LVDS);
-               temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
-               if (HAS_PCH_CPT(dev)) {
-                       temp &= ~PORT_TRANS_SEL_MASK;
-                       temp |= PORT_TRANS_SEL_CPT(pipe);
-               } else {
-                       if (pipe == 1)
-                               temp |= LVDS_PIPEB_SELECT;
-                       else
-                               temp &= ~LVDS_PIPEB_SELECT;
-               }
-
-               /* set the corresponsding LVDS_BORDER bit */
-               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)
-                       temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
-               else
-                       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.
-                */
-               if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
-                       lvds_sync |= LVDS_HSYNC_POLARITY;
-               if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
-                       lvds_sync |= LVDS_VSYNC_POLARITY;
-               if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY))
-                   != lvds_sync) {
-                       char flags[2] = "-+";
-                       DRM_INFO("Changing LVDS panel from "
-                                "(%chsync, %cvsync) to (%chsync, %cvsync)\n",
-                                flags[!(temp & LVDS_HSYNC_POLARITY)],
-                                flags[!(temp & LVDS_VSYNC_POLARITY)],
-                                flags[!(lvds_sync & LVDS_HSYNC_POLARITY)],
-                                flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]);
-                       temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
-                       temp |= lvds_sync;
-               }
-               I915_WRITE(PCH_LVDS, temp);
-       }
-
-       pipeconf &= ~PIPECONF_DITHER_EN;
-       pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
-       if ((is_lvds && dev_priv->lvds_dither) || dither) {
-               pipeconf |= PIPECONF_DITHER_EN;
-               pipeconf |= PIPECONF_DITHER_TYPE_SP;
-       }
-       if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-               intel_dp_set_m_n(crtc, mode, adjusted_mode);
-       } else {
-               /* For non-DP output, clear any trans DP clock recovery setting.*/
-               I915_WRITE(TRANSDATA_M1(pipe), 0);
-               I915_WRITE(TRANSDATA_N1(pipe), 0);
-               I915_WRITE(TRANSDPLINK_M1(pipe), 0);
-               I915_WRITE(TRANSDPLINK_N1(pipe), 0);
-       }
-
-       if (!intel_crtc->no_pll &&
-           (!has_edp_encoder ||
-            intel_encoder_is_pch_edp(&has_edp_encoder->base))) {
-               I915_WRITE(PCH_DPLL(pipe), dpll);
-
-               /* Wait for the clocks to stabilize. */
-               POSTING_READ(PCH_DPLL(pipe));
-               udelay(150);
-
-               /* The pixel multiplier can only be updated once the
-                * DPLL is enabled and the clocks are stable.
-                *
-                * So write it again.
-                */
-               I915_WRITE(PCH_DPLL(pipe), dpll);
-       }
-
-       intel_crtc->lowfreq_avail = false;
-       if (!intel_crtc->no_pll) {
-               if (is_lvds && has_reduced_clock && i915_powersave) {
-                       I915_WRITE(PCH_FP1(pipe), fp2);
-                       intel_crtc->lowfreq_avail = true;
-                       if (HAS_PIPE_CXSR(dev)) {
-                               DRM_DEBUG_KMS("enabling CxSR downclocking\n");
-                               pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
-                       }
-               } else {
-                       I915_WRITE(PCH_FP1(pipe), fp);
-                       if (HAS_PIPE_CXSR(dev)) {
-                               DRM_DEBUG_KMS("disabling CxSR downclocking\n");
-                               pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
-                       }
-               }
-       }
-
-       pipeconf &= ~PIPECONF_INTERLACE_MASK;
-       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
-               pipeconf |= PIPECONF_INTERLACED_ILK;
-               /* the chip adds 2 halflines automatically */
-               adjusted_mode->crtc_vtotal -= 1;
-               adjusted_mode->crtc_vblank_end -= 1;
-               I915_WRITE(VSYNCSHIFT(pipe),
-                          adjusted_mode->crtc_hsync_start
-                          - adjusted_mode->crtc_htotal/2);
-       } else {
-               pipeconf |= PIPECONF_PROGRESSIVE;
-               I915_WRITE(VSYNCSHIFT(pipe), 0);
-       }
-
-       I915_WRITE(HTOTAL(pipe),
-                  (adjusted_mode->crtc_hdisplay - 1) |
-                  ((adjusted_mode->crtc_htotal - 1) << 16));
-       I915_WRITE(HBLANK(pipe),
-                  (adjusted_mode->crtc_hblank_start - 1) |
-                  ((adjusted_mode->crtc_hblank_end - 1) << 16));
-       I915_WRITE(HSYNC(pipe),
-                  (adjusted_mode->crtc_hsync_start - 1) |
-                  ((adjusted_mode->crtc_hsync_end - 1) << 16));
-
-       I915_WRITE(VTOTAL(pipe),
-                  (adjusted_mode->crtc_vdisplay - 1) |
-                  ((adjusted_mode->crtc_vtotal - 1) << 16));
-       I915_WRITE(VBLANK(pipe),
-                  (adjusted_mode->crtc_vblank_start - 1) |
-                  ((adjusted_mode->crtc_vblank_end - 1) << 16));
-       I915_WRITE(VSYNC(pipe),
-                  (adjusted_mode->crtc_vsync_start - 1) |
-                  ((adjusted_mode->crtc_vsync_end - 1) << 16));
-
-       /* pipesrc controls the size that is scaled from, which should
-        * always be the user's requested size.
-        */
-       I915_WRITE(PIPESRC(pipe),
-                  ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
-
-       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 &&
-           !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-               ironlake_set_pll_edp(crtc, adjusted_mode->clock);
-       }
-
-       I915_WRITE(PIPECONF(pipe), pipeconf);
-       POSTING_READ(PIPECONF(pipe));
-
-       intel_wait_for_vblank(dev, pipe);
-
-       I915_WRITE(DSPCNTR(plane), dspcntr);
-       POSTING_READ(DSPCNTR(plane));
-
-       ret = intel_pipe_set_base(crtc, x, y, old_fb);
-
-       intel_update_watermarks(dev);
-
-       return ret;
-}
-
-static int intel_crtc_mode_set(struct drm_crtc *crtc,
-                              struct drm_display_mode *mode,
-                              struct drm_display_mode *adjusted_mode,
-                              int x, int y,
-                              struct drm_framebuffer *old_fb)
-{
-       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 ret;
-
-       drm_vblank_pre_modeset(dev, pipe);
-
-       ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode,
-                                             x, y, old_fb);
-       drm_vblank_post_modeset(dev, pipe);
-
-       if (ret)
-               intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF;
-       else
-               intel_crtc->dpms_mode = DRM_MODE_DPMS_ON;
-
-       return ret;
-}
-
-static bool intel_eld_uptodate(struct drm_connector *connector,
-                              int reg_eldv, uint32_t bits_eldv,
-                              int reg_elda, uint32_t bits_elda,
-                              int reg_edid)
-{
-       struct drm_i915_private *dev_priv = connector->dev->dev_private;
-       uint8_t *eld = connector->eld;
-       uint32_t i;
-
-       i = I915_READ(reg_eldv);
-       i &= bits_eldv;
-
-       if (!eld[0])
-               return !i;
-
-       if (!i)
-               return false;
-
-       i = I915_READ(reg_elda);
-       i &= ~bits_elda;
-       I915_WRITE(reg_elda, i);
-
-       for (i = 0; i < eld[2]; i++)
-               if (I915_READ(reg_edid) != *((uint32_t *)eld + i))
-                       return false;
-
-       return true;
-}
-
-static void g4x_write_eld(struct drm_connector *connector,
-                         struct drm_crtc *crtc)
-{
-       struct drm_i915_private *dev_priv = connector->dev->dev_private;
-       uint8_t *eld = connector->eld;
-       uint32_t eldv;
-       uint32_t len;
-       uint32_t i;
-
-       i = I915_READ(G4X_AUD_VID_DID);
-
-       if (i == INTEL_AUDIO_DEVBLC || i == INTEL_AUDIO_DEVCL)
-               eldv = G4X_ELDV_DEVCL_DEVBLC;
-       else
-               eldv = G4X_ELDV_DEVCTG;
-
-       if (intel_eld_uptodate(connector,
-                              G4X_AUD_CNTL_ST, eldv,
-                              G4X_AUD_CNTL_ST, G4X_ELD_ADDR,
-                              G4X_HDMIW_HDMIEDID))
-               return;
-
-       i = I915_READ(G4X_AUD_CNTL_ST);
-       i &= ~(eldv | G4X_ELD_ADDR);
-       len = (i >> 9) & 0x1f;          /* ELD buffer size */
-       I915_WRITE(G4X_AUD_CNTL_ST, i);
-
-       if (!eld[0])
-               return;
-
-       len = min_t(uint8_t, eld[2], len);
-       DRM_DEBUG_DRIVER("ELD size %d\n", len);
-       for (i = 0; i < len; i++)
-               I915_WRITE(G4X_HDMIW_HDMIEDID, *((uint32_t *)eld + i));
-
-       i = I915_READ(G4X_AUD_CNTL_ST);
-       i |= eldv;
-       I915_WRITE(G4X_AUD_CNTL_ST, i);
-}
-
-static void ironlake_write_eld(struct drm_connector *connector,
-                                    struct drm_crtc *crtc)
-{
-       struct drm_i915_private *dev_priv = connector->dev->dev_private;
-       uint8_t *eld = connector->eld;
-       uint32_t eldv;
-       uint32_t i;
-       int len;
-       int hdmiw_hdmiedid;
-       int aud_config;
-       int aud_cntl_st;
-       int aud_cntrl_st2;
-
-       if (HAS_PCH_IBX(connector->dev)) {
-               hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID_A;
-               aud_config = IBX_AUD_CONFIG_A;
-               aud_cntl_st = IBX_AUD_CNTL_ST_A;
-               aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
-       } else {
-               hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID_A;
-               aud_config = CPT_AUD_CONFIG_A;
-               aud_cntl_st = CPT_AUD_CNTL_ST_A;
-               aud_cntrl_st2 = CPT_AUD_CNTRL_ST2;
-       }
-
-       i = to_intel_crtc(crtc)->pipe;
-       hdmiw_hdmiedid += i * 0x100;
-       aud_cntl_st += i * 0x100;
-       aud_config += i * 0x100;
-
-       DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(i));
-
-       i = I915_READ(aud_cntl_st);
-       i = (i >> 29) & 0x3;            /* DIP_Port_Select, 0x1 = PortB */
-       if (!i) {
-               DRM_DEBUG_DRIVER("Audio directed to unknown port\n");
-               /* operate blindly on all ports */
-               eldv = IBX_ELD_VALIDB;
-               eldv |= IBX_ELD_VALIDB << 4;
-               eldv |= IBX_ELD_VALIDB << 8;
-       } else {
-               DRM_DEBUG_DRIVER("ELD on port %c\n", 'A' + i);
-               eldv = IBX_ELD_VALIDB << ((i - 1) * 4);
-       }
-
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
-               DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n");
-               eld[5] |= (1 << 2);     /* Conn_Type, 0x1 = DisplayPort */
-               I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */
-       } else
-               I915_WRITE(aud_config, 0);
-
-       if (intel_eld_uptodate(connector,
-                              aud_cntrl_st2, eldv,
-                              aud_cntl_st, IBX_ELD_ADDRESS,
-                              hdmiw_hdmiedid))
-               return;
-
-       i = I915_READ(aud_cntrl_st2);
-       i &= ~eldv;
-       I915_WRITE(aud_cntrl_st2, i);
-
-       if (!eld[0])
-               return;
-
-       i = I915_READ(aud_cntl_st);
-       i &= ~IBX_ELD_ADDRESS;
-       I915_WRITE(aud_cntl_st, i);
-
-       len = min_t(uint8_t, eld[2], 21);       /* 84 bytes of hw ELD buffer */
-       DRM_DEBUG_DRIVER("ELD size %d\n", len);
-       for (i = 0; i < len; i++)
-               I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i));
-
-       i = I915_READ(aud_cntrl_st2);
-       i |= eldv;
-       I915_WRITE(aud_cntrl_st2, i);
-}
-
-void intel_write_eld(struct drm_encoder *encoder,
-                    struct drm_display_mode *mode)
-{
-       struct drm_crtc *crtc = encoder->crtc;
-       struct drm_connector *connector;
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       connector = drm_select_eld(encoder, mode);
-       if (!connector)
-               return;
-
-       DRM_DEBUG_DRIVER("ELD on [CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
-                        connector->base.id,
-                        drm_get_connector_name(connector),
-                        connector->encoder->base.id,
-                        drm_get_encoder_name(connector->encoder));
-
-       connector->eld[6] = drm_av_sync_delay(connector, mode) / 2;
-
-       if (dev_priv->display.write_eld)
-               dev_priv->display.write_eld(connector, crtc);
-}
-
-/** Loads the palette/gamma unit for the CRTC with the prepared values */
-void intel_crtc_load_lut(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 palreg = PALETTE(intel_crtc->pipe);
-       int i;
-
-       /* The clocks have to be on to load the palette. */
-       if (!crtc->enabled || !intel_crtc->active)
-               return;
-
-       /* use legacy palette for Ironlake */
-       if (HAS_PCH_SPLIT(dev))
-               palreg = LGC_PALETTE(intel_crtc->pipe);
-
-       for (i = 0; i < 256; i++) {
-               I915_WRITE(palreg + 4 * i,
-                          (intel_crtc->lut_r[i] << 16) |
-                          (intel_crtc->lut_g[i] << 8) |
-                          intel_crtc->lut_b[i]);
-       }
-}
-
-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(CURCNTR(pipe));
-               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(CURCNTR(pipe), cntl);
-
-               intel_crtc->cursor_visible = visible;
-       }
-       /* and commit changes on next vblank */
-       I915_WRITE(CURBASE(pipe), base);
-}
-
-static void ivb_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(CURCNTR_IVB(pipe));
-               if (base) {
-                       cntl &= ~CURSOR_MODE;
-                       cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
-               } else {
-                       cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
-                       cntl |= CURSOR_MODE_DISABLE;
-               }
-               I915_WRITE(CURCNTR_IVB(pipe), cntl);
-
-               intel_crtc->cursor_visible = visible;
-       }
-       /* and commit changes on next vblank */
-       I915_WRITE(CURBASE_IVB(pipe), 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,
-                                    bool on)
-{
-       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 (on && crtc->enabled && 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;
+       /* Ensure that the cursor is valid for the new mode before changing... */
+       intel_crtc_update_cursor(crtc, true);
 
-               pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
-               x = -x;
+       if (is_lvds && dev_priv->lvds_downclock_avail) {
+               /*
+                * Ensure we match the reduced clock's P to the target clock.
+                * If the clocks don't match, we can't switch the display clock
+                * by using the FP0/FP1. In such case we will disable the LVDS
+                * downclock feature.
+               */
+               has_reduced_clock = limit->find_pll(limit, crtc,
+                                                   dev_priv->lvds_downclock,
+                                                   refclk,
+                                                   &clock,
+                                                   &reduced_clock);
        }
-       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;
+       /* SDVO TV has fixed PLL values depend on its clock range,
+          this mirrors vbios setting. */
+       if (is_sdvo && is_tv) {
+               if (adjusted_mode->clock >= 100000
+                   && 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) {
+                       clock.p1 = 1;
+                       clock.p2 = 10;
+                       clock.n = 6;
+                       clock.m1 = 12;
+                       clock.m2 = 8;
+               }
        }
-       pos |= y << CURSOR_Y_SHIFT;
-
-       visible = base != 0;
-       if (!visible && !intel_crtc->cursor_visible)
-               return;
 
-       if (IS_IVYBRIDGE(dev)) {
-               I915_WRITE(CURPOS_IVB(pipe), pos);
-               ivb_update_cursor(crtc, base);
+       /* FDI link */
+       pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+       lane = 0;
+       /* CPU eDP doesn't require FDI link, so just set DP M/N
+          according to current link config */
+       if (is_cpu_edp) {
+               target_clock = mode->clock;
+               intel_edp_link_config(edp_encoder, &lane, &link_bw);
        } else {
-               I915_WRITE(CURPOS(pipe), pos);
-               if (IS_845G(dev) || IS_I865G(dev))
-                       i845_update_cursor(crtc, base);
+               /* [e]DP over FDI requires target mode clock
+                  instead of link clock */
+               if (is_dp)
+                       target_clock = mode->clock;
                else
-                       i9xx_update_cursor(crtc, base);
-       }
+                       target_clock = adjusted_mode->clock;
 
-       if (visible)
-               intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj);
-}
+               /* 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;
+       }
 
-static int intel_crtc_cursor_set(struct drm_crtc *crtc,
-                                struct drm_file *file,
-                                uint32_t handle,
-                                uint32_t width, uint32_t height)
-{
-       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 drm_i915_gem_object *obj;
-       uint32_t addr;
-       int ret;
+       /* determine panel color depth */
+       temp = I915_READ(PIPECONF(pipe));
+       temp &= ~PIPE_BPC_MASK;
+       dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, mode);
+       switch (pipe_bpp) {
+       case 18:
+               temp |= PIPE_6BPC;
+               break;
+       case 24:
+               temp |= PIPE_8BPC;
+               break;
+       case 30:
+               temp |= PIPE_10BPC;
+               break;
+       case 36:
+               temp |= PIPE_12BPC;
+               break;
+       default:
+               WARN(1, "intel_choose_pipe_bpp returned invalid value %d\n",
+                       pipe_bpp);
+               temp |= PIPE_8BPC;
+               pipe_bpp = 24;
+               break;
+       }
 
-       DRM_DEBUG_KMS("\n");
+       intel_crtc->bpp = pipe_bpp;
+       I915_WRITE(PIPECONF(pipe), temp);
 
-       /* if we want to turn off the cursor ignore width and height */
-       if (!handle) {
-               DRM_DEBUG_KMS("cursor off\n");
-               addr = 0;
-               obj = NULL;
-               mutex_lock(&dev->struct_mutex);
-               goto finish;
+       if (!lane) {
+               /*
+                * Account for spread spectrum to avoid
+                * oversubscribing the link. Max center spread
+                * is 2.5%; use 5% for safety's sake.
+                */
+               u32 bps = target_clock * intel_crtc->bpp * 21 / 20;
+               lane = bps / (link_bw * 8) + 1;
        }
 
-       /* Currently we only support 64x64 cursors */
-       if (width != 64 || height != 64) {
-               DRM_ERROR("we currently only support 64x64 cursors\n");
-               return -EINVAL;
-       }
+       intel_crtc->fdi_lanes = lane;
 
-       obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle));
-       if (&obj->base == NULL)
-               return -ENOENT;
+       if (pixel_multiplier > 1)
+               link_bw *= pixel_multiplier;
+       ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw,
+                            &m_n);
 
-       if (obj->base.size < width * height * 4) {
-               DRM_ERROR("buffer is to small\n");
-               ret = -ENOMEM;
-               goto fail;
-       }
+       fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
+       if (has_reduced_clock)
+               fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
+                       reduced_clock.m2;
 
-       /* we only need to pin inside GTT if cursor is non-phy */
-       mutex_lock(&dev->struct_mutex);
-       if (!dev_priv->info->cursor_needs_physical) {
-               if (obj->tiling_mode) {
-                       DRM_ERROR("cursor cannot be tiled\n");
-                       ret = -EINVAL;
-                       goto fail_locked;
-               }
+       /* Enable autotuning of the PLL clock (if permissible) */
+       factor = 21;
+       if (is_lvds) {
+               if ((intel_panel_use_ssc(dev_priv) &&
+                    dev_priv->lvds_ssc_freq == 100) ||
+                   (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
+                       factor = 25;
+       } else if (is_sdvo && is_tv)
+               factor = 20;
 
-               ret = i915_gem_object_pin_to_display_plane(obj, 0, NULL);
-               if (ret) {
-                       DRM_ERROR("failed to move cursor bo into the GTT\n");
-                       goto fail_locked;
-               }
+       if (clock.m < factor * clock.n)
+               fp |= FP_CB_TUNE;
 
-               ret = i915_gem_object_put_fence(obj);
-               if (ret) {
-                       DRM_ERROR("failed to release fence for cursor");
-                       goto fail_unpin;
-               }
+       dpll = 0;
 
-               addr = obj->gtt_offset;
-       } else {
-               int align = IS_I830(dev) ? 16 * 1024 : 256;
-               ret = i915_gem_attach_phys_object(dev, obj,
-                                                 (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;
+       if (is_lvds)
+               dpll |= DPLLB_MODE_LVDS;
+       else
+               dpll |= DPLLB_MODE_DAC_SERIAL;
+       if (is_sdvo) {
+               int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+               if (pixel_multiplier > 1) {
+                       dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
                }
-               addr = obj->phys_obj->handle->busaddr;
+               dpll |= DPLL_DVO_HIGH_SPEED;
        }
+       if (is_dp && !is_cpu_edp)
+               dpll |= DPLL_DVO_HIGH_SPEED;
 
-       if (IS_GEN2(dev))
-               I915_WRITE(CURSIZE, (height << 12) | width);
+       /* compute bitmask from p1 value */
+       dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+       /* also FPA1 */
+       dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
 
- finish:
-       if (intel_crtc->cursor_bo) {
-               if (dev_priv->info->cursor_needs_physical) {
-                       if (intel_crtc->cursor_bo != obj)
-                               i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
-               } else
-                       i915_gem_object_unpin(intel_crtc->cursor_bo);
-               drm_gem_object_unreference(&intel_crtc->cursor_bo->base);
+       switch (clock.p2) {
+       case 5:
+               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
+               break;
+       case 7:
+               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
+               break;
+       case 10:
+               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
+               break;
+       case 14:
+               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
+               break;
        }
 
-       mutex_unlock(&dev->struct_mutex);
-
-       intel_crtc->cursor_addr = addr;
-       intel_crtc->cursor_bo = obj;
-       intel_crtc->cursor_width = width;
-       intel_crtc->cursor_height = height;
-
-       intel_crtc_update_cursor(crtc, true);
+       if (is_sdvo && is_tv)
+               dpll |= PLL_REF_INPUT_TVCLKINBC;
+       else if (is_tv)
+               /* XXX: just matching BIOS for now */
+               /*      dpll |= PLL_REF_INPUT_TVCLKINBC; */
+               dpll |= 3;
+       else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
+               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
+       else
+               dpll |= PLL_REF_INPUT_DREFCLK;
 
-       return 0;
-fail_unpin:
-       i915_gem_object_unpin(obj);
-fail_locked:
-       mutex_unlock(&dev->struct_mutex);
-fail:
-       drm_gem_object_unreference_unlocked(&obj->base);
-       return ret;
-}
+       /* setup pipeconf */
+       pipeconf = I915_READ(PIPECONF(pipe));
 
-static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
-{
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       /* Set up the display plane register */
+       dspcntr = DISPPLANE_GAMMA_ENABLE;
 
-       intel_crtc->cursor_x = x;
-       intel_crtc->cursor_y = y;
+       DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
+       drm_mode_debug_printmodeline(mode);
 
-       intel_crtc_update_cursor(crtc, true);
+       /* CPU eDP is the only output that doesn't need a PCH PLL of its own */
+       if (!is_cpu_edp) {
+               struct intel_pch_pll *pll;
 
-       return 0;
-}
+               pll = intel_get_pch_pll(intel_crtc, dpll, fp);
+               if (pll == NULL) {
+                       DRM_DEBUG_DRIVER("failed to find PLL for pipe %d\n",
+                                        pipe);
+                       return -EINVAL;
+               }
+       } else
+               intel_put_pch_pll(intel_crtc);
 
-/** Sets the color ramps on behalf of RandR */
-void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
-                                u16 blue, int regno)
-{
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       /* 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.
+        */
+       if (is_lvds) {
+               temp = I915_READ(PCH_LVDS);
+               temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+               if (HAS_PCH_CPT(dev)) {
+                       temp &= ~PORT_TRANS_SEL_MASK;
+                       temp |= PORT_TRANS_SEL_CPT(pipe);
+               } else {
+                       if (pipe == 1)
+                               temp |= LVDS_PIPEB_SELECT;
+                       else
+                               temp &= ~LVDS_PIPEB_SELECT;
+               }
 
-       intel_crtc->lut_r[regno] = red >> 8;
-       intel_crtc->lut_g[regno] = green >> 8;
-       intel_crtc->lut_b[regno] = blue >> 8;
-}
+               /* set the corresponsding LVDS_BORDER bit */
+               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)
+                       temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+               else
+                       temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
 
-void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
-                            u16 *blue, int regno)
-{
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               /* 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.
+                */
+               temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
+               if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
+                       temp |= LVDS_HSYNC_POLARITY;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+                       temp |= LVDS_VSYNC_POLARITY;
+               I915_WRITE(PCH_LVDS, temp);
+       }
 
-       *red = intel_crtc->lut_r[regno] << 8;
-       *green = intel_crtc->lut_g[regno] << 8;
-       *blue = intel_crtc->lut_b[regno] << 8;
-}
+       pipeconf &= ~PIPECONF_DITHER_EN;
+       pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
+       if ((is_lvds && dev_priv->lvds_dither) || dither) {
+               pipeconf |= PIPECONF_DITHER_EN;
+               pipeconf |= PIPECONF_DITHER_TYPE_SP;
+       }
+       if (is_dp && !is_cpu_edp) {
+               intel_dp_set_m_n(crtc, mode, adjusted_mode);
+       } else {
+               /* For non-DP output, clear any trans DP clock recovery setting.*/
+               I915_WRITE(TRANSDATA_M1(pipe), 0);
+               I915_WRITE(TRANSDATA_N1(pipe), 0);
+               I915_WRITE(TRANSDPLINK_M1(pipe), 0);
+               I915_WRITE(TRANSDPLINK_N1(pipe), 0);
+       }
 
-static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
-                                u16 *blue, uint32_t start, uint32_t size)
-{
-       int end = (start + size > 256) ? 256 : start + size, i;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       if (intel_crtc->pch_pll) {
+               I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll);
 
-       for (i = start; i < end; i++) {
-               intel_crtc->lut_r[i] = red[i] >> 8;
-               intel_crtc->lut_g[i] = green[i] >> 8;
-               intel_crtc->lut_b[i] = blue[i] >> 8;
+               /* Wait for the clocks to stabilize. */
+               POSTING_READ(intel_crtc->pch_pll->pll_reg);
+               udelay(150);
+
+               /* The pixel multiplier can only be updated once the
+                * DPLL is enabled and the clocks are stable.
+                *
+                * So write it again.
+                */
+               I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll);
        }
 
-       intel_crtc_load_lut(crtc);
-}
+       intel_crtc->lowfreq_avail = false;
+       if (intel_crtc->pch_pll) {
+               if (is_lvds && has_reduced_clock && i915_powersave) {
+                       I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2);
+                       intel_crtc->lowfreq_avail = true;
+                       if (HAS_PIPE_CXSR(dev)) {
+                               DRM_DEBUG_KMS("enabling CxSR downclocking\n");
+                               pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
+                       }
+               } else {
+                       I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp);
+                       if (HAS_PIPE_CXSR(dev)) {
+                               DRM_DEBUG_KMS("disabling CxSR downclocking\n");
+                               pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
+                       }
+               }
+       }
 
-/**
- * Get a pipe with a simple mode set on it for doing load-based monitor
- * detection.
- *
- * It will be up to the load-detect code to adjust the pipe as appropriate for
- * its requirements.  The pipe will be connected to no other encoders.
- *
- * Currently this code will only succeed if there is a pipe with no encoders
- * configured for it.  In the future, it could choose to temporarily disable
- * some outputs to free up a pipe for its use.
- *
- * \return crtc, or NULL if no pipes are available.
- */
+       pipeconf &= ~PIPECONF_INTERLACE_MASK;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+               pipeconf |= PIPECONF_INTERLACED_ILK;
+               /* the chip adds 2 halflines automatically */
+               adjusted_mode->crtc_vtotal -= 1;
+               adjusted_mode->crtc_vblank_end -= 1;
+               I915_WRITE(VSYNCSHIFT(pipe),
+                          adjusted_mode->crtc_hsync_start
+                          - adjusted_mode->crtc_htotal/2);
+       } else {
+               pipeconf |= PIPECONF_PROGRESSIVE;
+               I915_WRITE(VSYNCSHIFT(pipe), 0);
+       }
 
-/* VESA 640x480x72Hz mode to set on the pipe */
-static struct drm_display_mode load_detect_mode = {
-       DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664,
-                704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-};
+       I915_WRITE(HTOTAL(pipe),
+                  (adjusted_mode->crtc_hdisplay - 1) |
+                  ((adjusted_mode->crtc_htotal - 1) << 16));
+       I915_WRITE(HBLANK(pipe),
+                  (adjusted_mode->crtc_hblank_start - 1) |
+                  ((adjusted_mode->crtc_hblank_end - 1) << 16));
+       I915_WRITE(HSYNC(pipe),
+                  (adjusted_mode->crtc_hsync_start - 1) |
+                  ((adjusted_mode->crtc_hsync_end - 1) << 16));
 
-static struct drm_framebuffer *
-intel_framebuffer_create(struct drm_device *dev,
-                        struct drm_mode_fb_cmd2 *mode_cmd,
-                        struct drm_i915_gem_object *obj)
-{
-       struct intel_framebuffer *intel_fb;
-       int ret;
+       I915_WRITE(VTOTAL(pipe),
+                  (adjusted_mode->crtc_vdisplay - 1) |
+                  ((adjusted_mode->crtc_vtotal - 1) << 16));
+       I915_WRITE(VBLANK(pipe),
+                  (adjusted_mode->crtc_vblank_start - 1) |
+                  ((adjusted_mode->crtc_vblank_end - 1) << 16));
+       I915_WRITE(VSYNC(pipe),
+                  (adjusted_mode->crtc_vsync_start - 1) |
+                  ((adjusted_mode->crtc_vsync_end - 1) << 16));
 
-       intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
-       if (!intel_fb) {
-               drm_gem_object_unreference_unlocked(&obj->base);
-               return ERR_PTR(-ENOMEM);
-       }
+       /* pipesrc controls the size that is scaled from, which should
+        * always be the user's requested size.
+        */
+       I915_WRITE(PIPESRC(pipe),
+                  ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
 
-       ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
-       if (ret) {
-               drm_gem_object_unreference_unlocked(&obj->base);
-               kfree(intel_fb);
-               return ERR_PTR(ret);
-       }
+       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);
 
-       return &intel_fb->base;
-}
+       if (is_cpu_edp)
+               ironlake_set_pll_edp(crtc, adjusted_mode->clock);
 
-static u32
-intel_framebuffer_pitch_for_width(int width, int bpp)
-{
-       u32 pitch = DIV_ROUND_UP(width * bpp, 8);
-       return ALIGN(pitch, 64);
-}
+       I915_WRITE(PIPECONF(pipe), pipeconf);
+       POSTING_READ(PIPECONF(pipe));
 
-static u32
-intel_framebuffer_size_for_mode(struct drm_display_mode *mode, int bpp)
-{
-       u32 pitch = intel_framebuffer_pitch_for_width(mode->hdisplay, bpp);
-       return ALIGN(pitch * mode->vdisplay, PAGE_SIZE);
-}
+       intel_wait_for_vblank(dev, pipe);
 
-static struct drm_framebuffer *
-intel_framebuffer_create_for_mode(struct drm_device *dev,
-                                 struct drm_display_mode *mode,
-                                 int depth, int bpp)
-{
-       struct drm_i915_gem_object *obj;
-       struct drm_mode_fb_cmd2 mode_cmd;
+       I915_WRITE(DSPCNTR(plane), dspcntr);
+       POSTING_READ(DSPCNTR(plane));
 
-       obj = i915_gem_alloc_object(dev,
-                                   intel_framebuffer_size_for_mode(mode, bpp));
-       if (obj == NULL)
-               return ERR_PTR(-ENOMEM);
+       ret = intel_pipe_set_base(crtc, x, y, old_fb);
 
-       mode_cmd.width = mode->hdisplay;
-       mode_cmd.height = mode->vdisplay;
-       mode_cmd.pitches[0] = intel_framebuffer_pitch_for_width(mode_cmd.width,
-                                                               bpp);
-       mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
+       intel_update_watermarks(dev);
 
-       return intel_framebuffer_create(dev, &mode_cmd, obj);
+       return ret;
 }
 
-static struct drm_framebuffer *
-mode_fits_in_fbdev(struct drm_device *dev,
-                  struct drm_display_mode *mode)
+static int intel_crtc_mode_set(struct drm_crtc *crtc,
+                              struct drm_display_mode *mode,
+                              struct drm_display_mode *adjusted_mode,
+                              int x, int y,
+                              struct drm_framebuffer *old_fb)
 {
+       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_i915_gem_object *obj;
-       struct drm_framebuffer *fb;
-
-       if (dev_priv->fbdev == NULL)
-               return NULL;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int ret;
 
-       obj = dev_priv->fbdev->ifb.obj;
-       if (obj == NULL)
-               return NULL;
+       drm_vblank_pre_modeset(dev, pipe);
 
-       fb = &dev_priv->fbdev->ifb.base;
-       if (fb->pitches[0] < intel_framebuffer_pitch_for_width(mode->hdisplay,
-                                                              fb->bits_per_pixel))
-               return NULL;
+       ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode,
+                                             x, y, old_fb);
+       drm_vblank_post_modeset(dev, pipe);
 
-       if (obj->base.size < mode->vdisplay * fb->pitches[0])
-               return NULL;
+       if (ret)
+               intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF;
+       else
+               intel_crtc->dpms_mode = DRM_MODE_DPMS_ON;
 
-       return fb;
+       return ret;
 }
 
-bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
-                               struct drm_connector *connector,
-                               struct drm_display_mode *mode,
-                               struct intel_load_detect_pipe *old)
+static bool intel_eld_uptodate(struct drm_connector *connector,
+                              int reg_eldv, uint32_t bits_eldv,
+                              int reg_elda, uint32_t bits_elda,
+                              int reg_edid)
 {
-       struct intel_crtc *intel_crtc;
-       struct drm_crtc *possible_crtc;
-       struct drm_encoder *encoder = &intel_encoder->base;
-       struct drm_crtc *crtc = NULL;
-       struct drm_device *dev = encoder->dev;
-       struct drm_framebuffer *old_fb;
-       int i = -1;
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       uint8_t *eld = connector->eld;
+       uint32_t i;
 
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
-                     connector->base.id, drm_get_connector_name(connector),
-                     encoder->base.id, drm_get_encoder_name(encoder));
+       i = I915_READ(reg_eldv);
+       i &= bits_eldv;
 
-       /*
-        * Algorithm gets a little messy:
-        *
-        *   - if the connector already has an assigned crtc, use it (but make
-        *     sure it's on first)
-        *
-        *   - try to find the first unused crtc that can drive this connector,
-        *     and use that if we find one
-        */
+       if (!eld[0])
+               return !i;
 
-       /* See if we already have a CRTC for this connector */
-       if (encoder->crtc) {
-               crtc = encoder->crtc;
+       if (!i)
+               return false;
 
-               intel_crtc = to_intel_crtc(crtc);
-               old->dpms_mode = intel_crtc->dpms_mode;
-               old->load_detect_temp = false;
+       i = I915_READ(reg_elda);
+       i &= ~bits_elda;
+       I915_WRITE(reg_elda, i);
 
-               /* Make sure the crtc and connector are running */
-               if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
-                       struct drm_encoder_helper_funcs *encoder_funcs;
-                       struct drm_crtc_helper_funcs *crtc_funcs;
+       for (i = 0; i < eld[2]; i++)
+               if (I915_READ(reg_edid) != *((uint32_t *)eld + i))
+                       return false;
 
-                       crtc_funcs = crtc->helper_private;
-                       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+       return true;
+}
 
-                       encoder_funcs = encoder->helper_private;
-                       encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
-               }
+static void g4x_write_eld(struct drm_connector *connector,
+                         struct drm_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       uint8_t *eld = connector->eld;
+       uint32_t eldv;
+       uint32_t len;
+       uint32_t i;
 
-               return true;
-       }
+       i = I915_READ(G4X_AUD_VID_DID);
 
-       /* Find an unused one (if possible) */
-       list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) {
-               i++;
-               if (!(encoder->possible_crtcs & (1 << i)))
-                       continue;
-               if (!possible_crtc->enabled) {
-                       crtc = possible_crtc;
-                       break;
-               }
-       }
+       if (i == INTEL_AUDIO_DEVBLC || i == INTEL_AUDIO_DEVCL)
+               eldv = G4X_ELDV_DEVCL_DEVBLC;
+       else
+               eldv = G4X_ELDV_DEVCTG;
 
-       /*
-        * If we didn't find an unused CRTC, don't use any.
-        */
-       if (!crtc) {
-               DRM_DEBUG_KMS("no pipe available for load-detect\n");
-               return false;
-       }
+       if (intel_eld_uptodate(connector,
+                              G4X_AUD_CNTL_ST, eldv,
+                              G4X_AUD_CNTL_ST, G4X_ELD_ADDR,
+                              G4X_HDMIW_HDMIEDID))
+               return;
 
-       encoder->crtc = crtc;
-       connector->encoder = encoder;
+       i = I915_READ(G4X_AUD_CNTL_ST);
+       i &= ~(eldv | G4X_ELD_ADDR);
+       len = (i >> 9) & 0x1f;          /* ELD buffer size */
+       I915_WRITE(G4X_AUD_CNTL_ST, i);
 
-       intel_crtc = to_intel_crtc(crtc);
-       old->dpms_mode = intel_crtc->dpms_mode;
-       old->load_detect_temp = true;
-       old->release_fb = NULL;
+       if (!eld[0])
+               return;
 
-       if (!mode)
-               mode = &load_detect_mode;
+       len = min_t(uint8_t, eld[2], len);
+       DRM_DEBUG_DRIVER("ELD size %d\n", len);
+       for (i = 0; i < len; i++)
+               I915_WRITE(G4X_HDMIW_HDMIEDID, *((uint32_t *)eld + i));
 
-       old_fb = crtc->fb;
+       i = I915_READ(G4X_AUD_CNTL_ST);
+       i |= eldv;
+       I915_WRITE(G4X_AUD_CNTL_ST, i);
+}
 
-       /* We need a framebuffer large enough to accommodate all accesses
-        * that the plane may generate whilst we perform load detection.
-        * We can not rely on the fbcon either being present (we get called
-        * during its initialisation to detect all boot displays, or it may
-        * not even exist) or that it is large enough to satisfy the
-        * requested mode.
-        */
-       crtc->fb = mode_fits_in_fbdev(dev, mode);
-       if (crtc->fb == NULL) {
-               DRM_DEBUG_KMS("creating tmp fb for load-detection\n");
-               crtc->fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32);
-               old->release_fb = crtc->fb;
-       } else
-               DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
-       if (IS_ERR(crtc->fb)) {
-               DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
-               crtc->fb = old_fb;
-               return false;
-       }
+static void ironlake_write_eld(struct drm_connector *connector,
+                                    struct drm_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       uint8_t *eld = connector->eld;
+       uint32_t eldv;
+       uint32_t i;
+       int len;
+       int hdmiw_hdmiedid;
+       int aud_config;
+       int aud_cntl_st;
+       int aud_cntrl_st2;
 
-       if (!drm_crtc_helper_set_mode(crtc, mode, 0, 0, old_fb)) {
-               DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
-               if (old->release_fb)
-                       old->release_fb->funcs->destroy(old->release_fb);
-               crtc->fb = old_fb;
-               return false;
+       if (HAS_PCH_IBX(connector->dev)) {
+               hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID_A;
+               aud_config = IBX_AUD_CONFIG_A;
+               aud_cntl_st = IBX_AUD_CNTL_ST_A;
+               aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
+       } else {
+               hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID_A;
+               aud_config = CPT_AUD_CONFIG_A;
+               aud_cntl_st = CPT_AUD_CNTL_ST_A;
+               aud_cntrl_st2 = CPT_AUD_CNTRL_ST2;
        }
 
-       /* let the connector get through one full cycle before testing */
-       intel_wait_for_vblank(dev, intel_crtc->pipe);
+       i = to_intel_crtc(crtc)->pipe;
+       hdmiw_hdmiedid += i * 0x100;
+       aud_cntl_st += i * 0x100;
+       aud_config += i * 0x100;
 
-       return true;
-}
+       DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(i));
 
-void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
-                                   struct drm_connector *connector,
-                                   struct intel_load_detect_pipe *old)
-{
-       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;
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       i = I915_READ(aud_cntl_st);
+       i = (i >> 29) & 0x3;            /* DIP_Port_Select, 0x1 = PortB */
+       if (!i) {
+               DRM_DEBUG_DRIVER("Audio directed to unknown port\n");
+               /* operate blindly on all ports */
+               eldv = IBX_ELD_VALIDB;
+               eldv |= IBX_ELD_VALIDB << 4;
+               eldv |= IBX_ELD_VALIDB << 8;
+       } else {
+               DRM_DEBUG_DRIVER("ELD on port %c\n", 'A' + i);
+               eldv = IBX_ELD_VALIDB << ((i - 1) * 4);
+       }
 
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
-                     connector->base.id, drm_get_connector_name(connector),
-                     encoder->base.id, drm_get_encoder_name(encoder));
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+               DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n");
+               eld[5] |= (1 << 2);     /* Conn_Type, 0x1 = DisplayPort */
+               I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */
+       } else
+               I915_WRITE(aud_config, 0);
 
-       if (old->load_detect_temp) {
-               connector->encoder = NULL;
-               drm_helper_disable_unused_functions(dev);
+       if (intel_eld_uptodate(connector,
+                              aud_cntrl_st2, eldv,
+                              aud_cntl_st, IBX_ELD_ADDRESS,
+                              hdmiw_hdmiedid))
+               return;
 
-               if (old->release_fb)
-                       old->release_fb->funcs->destroy(old->release_fb);
+       i = I915_READ(aud_cntrl_st2);
+       i &= ~eldv;
+       I915_WRITE(aud_cntrl_st2, i);
 
+       if (!eld[0])
                return;
-       }
 
-       /* Switch crtc and encoder back off if necessary */
-       if (old->dpms_mode != DRM_MODE_DPMS_ON) {
-               encoder_funcs->dpms(encoder, old->dpms_mode);
-               crtc_funcs->dpms(crtc, old->dpms_mode);
-       }
+       i = I915_READ(aud_cntl_st);
+       i &= ~IBX_ELD_ADDRESS;
+       I915_WRITE(aud_cntl_st, i);
+
+       len = min_t(uint8_t, eld[2], 21);       /* 84 bytes of hw ELD buffer */
+       DRM_DEBUG_DRIVER("ELD size %d\n", len);
+       for (i = 0; i < len; i++)
+               I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i));
+
+       i = I915_READ(aud_cntrl_st2);
+       i |= eldv;
+       I915_WRITE(aud_cntrl_st2, i);
 }
 
-/* Returns the clock of the currently programmed mode of the given pipe. */
-static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
+void intel_write_eld(struct drm_encoder *encoder,
+                    struct drm_display_mode *mode)
 {
+       struct drm_crtc *crtc = encoder->crtc;
+       struct drm_connector *connector;
+       struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
-       u32 dpll = I915_READ(DPLL(pipe));
-       u32 fp;
-       intel_clock_t clock;
 
-       if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
-               fp = I915_READ(FP0(pipe));
-       else
-               fp = I915_READ(FP1(pipe));
+       connector = drm_select_eld(encoder, mode);
+       if (!connector)
+               return;
 
-       clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
-       if (IS_PINEVIEW(dev)) {
-               clock.n = ffs((fp & FP_N_PINEVIEW_DIV_MASK) >> FP_N_DIV_SHIFT) - 1;
-               clock.m2 = (fp & FP_M2_PINEVIEW_DIV_MASK) >> FP_M2_DIV_SHIFT;
-       } else {
-               clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT;
-               clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
-       }
+       DRM_DEBUG_DRIVER("ELD on [CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
+                        connector->base.id,
+                        drm_get_connector_name(connector),
+                        connector->encoder->base.id,
+                        drm_get_encoder_name(connector->encoder));
 
-       if (!IS_GEN2(dev)) {
-               if (IS_PINEVIEW(dev))
-                       clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >>
-                               DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW);
-               else
-                       clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >>
-                              DPLL_FPA01_P1_POST_DIV_SHIFT);
+       connector->eld[6] = drm_av_sync_delay(connector, mode) / 2;
 
-               switch (dpll & DPLL_MODE_MASK) {
-               case DPLLB_MODE_DAC_SERIAL:
-                       clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ?
-                               5 : 10;
-                       break;
-               case DPLLB_MODE_LVDS:
-                       clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ?
-                               7 : 14;
-                       break;
-               default:
-                       DRM_DEBUG_KMS("Unknown DPLL mode %08x in programmed "
-                                 "mode\n", (int)(dpll & DPLL_MODE_MASK));
-                       return 0;
-               }
+       if (dev_priv->display.write_eld)
+               dev_priv->display.write_eld(connector, crtc);
+}
 
-               /* XXX: Handle the 100Mhz refclk */
-               intel_clock(dev, 96000, &clock);
-       } else {
-               bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN);
+/** Loads the palette/gamma unit for the CRTC with the prepared values */
+void intel_crtc_load_lut(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 palreg = PALETTE(intel_crtc->pipe);
+       int i;
 
-               if (is_lvds) {
-                       clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >>
-                                      DPLL_FPA01_P1_POST_DIV_SHIFT);
-                       clock.p2 = 14;
+       /* The clocks have to be on to load the palette. */
+       if (!crtc->enabled || !intel_crtc->active)
+               return;
 
-                       if ((dpll & PLL_REF_INPUT_MASK) ==
-                           PLLB_REF_INPUT_SPREADSPECTRUMIN) {
-                               /* XXX: might not be 66MHz */
-                               intel_clock(dev, 66000, &clock);
-                       } else
-                               intel_clock(dev, 48000, &clock);
-               } else {
-                       if (dpll & PLL_P1_DIVIDE_BY_TWO)
-                               clock.p1 = 2;
-                       else {
-                               clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >>
-                                           DPLL_FPA01_P1_POST_DIV_SHIFT) + 2;
-                       }
-                       if (dpll & PLL_P2_DIVIDE_BY_4)
-                               clock.p2 = 4;
-                       else
-                               clock.p2 = 2;
+       /* use legacy palette for Ironlake */
+       if (HAS_PCH_SPLIT(dev))
+               palreg = LGC_PALETTE(intel_crtc->pipe);
 
-                       intel_clock(dev, 48000, &clock);
-               }
+       for (i = 0; i < 256; i++) {
+               I915_WRITE(palreg + 4 * i,
+                          (intel_crtc->lut_r[i] << 16) |
+                          (intel_crtc->lut_g[i] << 8) |
+                          intel_crtc->lut_b[i]);
        }
-
-       /* XXX: It would be nice to validate the clocks, but we can't reuse
-        * i830PllIsValid() because it relies on the xf86_config connector
-        * configuration being accurate, which it isn't necessarily.
-        */
-
-       return clock.dot;
 }
 
-/** Returns the currently programmed mode of the given pipe. */
-struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
-                                            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);
-       int pipe = intel_crtc->pipe;
-       struct drm_display_mode *mode;
-       int htot = I915_READ(HTOTAL(pipe));
-       int hsync = I915_READ(HSYNC(pipe));
-       int vtot = I915_READ(VTOTAL(pipe));
-       int vsync = I915_READ(VSYNC(pipe));
+       bool visible = base != 0;
+       u32 cntl;
 
-       mode = kzalloc(sizeof(*mode), GFP_KERNEL);
-       if (!mode)
-               return NULL;
+       if (intel_crtc->cursor_visible == visible)
+               return;
 
-       mode->clock = intel_crtc_clock_get(dev, crtc);
-       mode->hdisplay = (htot & 0xffff) + 1;
-       mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
-       mode->hsync_start = (hsync & 0xffff) + 1;
-       mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1;
-       mode->vdisplay = (vtot & 0xffff) + 1;
-       mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1;
-       mode->vsync_start = (vsync & 0xffff) + 1;
-       mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1;
+       cntl = I915_READ(_CURACNTR);
+       if (visible) {
+               /* On these chipsets we can only modify the base whilst
+                * the cursor is disabled.
+                */
+               I915_WRITE(_CURABASE, base);
 
-       drm_mode_set_name(mode);
-       drm_mode_set_crtcinfo(mode, 0);
+               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);
 
-       return mode;
+       intel_crtc->cursor_visible = visible;
 }
 
-#define GPU_IDLE_TIMEOUT 500 /* ms */
-
-/* When this timer fires, we've been idle for awhile */
-static void intel_gpu_idle_timer(unsigned long arg)
+static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
 {
-       struct drm_device *dev = (struct drm_device *)arg;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       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 (!list_empty(&dev_priv->mm.active_list)) {
-               /* Still processing requests, so just re-arm the timer. */
-               mod_timer(&dev_priv->idle_timer, jiffies +
-                         msecs_to_jiffies(GPU_IDLE_TIMEOUT));
-               return;
-       }
+       if (intel_crtc->cursor_visible != visible) {
+               uint32_t cntl = I915_READ(CURCNTR(pipe));
+               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(CURCNTR(pipe), cntl);
 
-       dev_priv->busy = false;
-       queue_work(dev_priv->wq, &dev_priv->idle_work);
+               intel_crtc->cursor_visible = visible;
+       }
+       /* and commit changes on next vblank */
+       I915_WRITE(CURBASE(pipe), base);
 }
 
-#define CRTC_IDLE_TIMEOUT 1000 /* ms */
-
-static void intel_crtc_idle_timer(unsigned long arg)
+static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
 {
-       struct intel_crtc *intel_crtc = (struct intel_crtc *)arg;
-       struct drm_crtc *crtc = &intel_crtc->base;
-       drm_i915_private_t *dev_priv = crtc->dev->dev_private;
-       struct intel_framebuffer *intel_fb;
+       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;
 
-       intel_fb = to_intel_framebuffer(crtc->fb);
-       if (intel_fb && intel_fb->obj->active) {
-               /* The framebuffer is still being accessed by the GPU. */
-               mod_timer(&intel_crtc->idle_timer, jiffies +
-                         msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
-               return;
-       }
+       if (intel_crtc->cursor_visible != visible) {
+               uint32_t cntl = I915_READ(CURCNTR_IVB(pipe));
+               if (base) {
+                       cntl &= ~CURSOR_MODE;
+                       cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
+               } else {
+                       cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
+                       cntl |= CURSOR_MODE_DISABLE;
+               }
+               I915_WRITE(CURCNTR_IVB(pipe), cntl);
 
-       intel_crtc->busy = false;
-       queue_work(dev_priv->wq, &dev_priv->idle_work);
+               intel_crtc->cursor_visible = visible;
+       }
+       /* and commit changes on next vblank */
+       I915_WRITE(CURBASE_IVB(pipe), base);
 }
 
-static void intel_increase_pllclock(struct drm_crtc *crtc)
+/* 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,
+                                    bool on)
 {
        struct drm_device *dev = crtc->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       int dpll_reg = DPLL(pipe);
-       int dpll;
+       int x = intel_crtc->cursor_x;
+       int y = intel_crtc->cursor_y;
+       u32 base, pos;
+       bool visible;
+
+       pos = 0;
+
+       if (on && crtc->enabled && crtc->fb) {
+               base = intel_crtc->cursor_addr;
+               if (x > (int) crtc->fb->width)
+                       base = 0;
 
-       if (HAS_PCH_SPLIT(dev))
-               return;
+               if (y > (int) crtc->fb->height)
+                       base = 0;
+       } else
+               base = 0;
 
-       if (!dev_priv->lvds_downclock_avail)
-               return;
+       if (x < 0) {
+               if (x + intel_crtc->cursor_width < 0)
+                       base = 0;
 
-       dpll = I915_READ(dpll_reg);
-       if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) {
-               DRM_DEBUG_DRIVER("upclocking LVDS\n");
+               pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
+               x = -x;
+       }
+       pos |= x << CURSOR_X_SHIFT;
 
-               assert_panel_unlocked(dev_priv, pipe);
+       if (y < 0) {
+               if (y + intel_crtc->cursor_height < 0)
+                       base = 0;
 
-               dpll &= ~DISPLAY_RATE_SELECT_FPA1;
-               I915_WRITE(dpll_reg, dpll);
-               intel_wait_for_vblank(dev, pipe);
+               pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
+               y = -y;
+       }
+       pos |= y << CURSOR_Y_SHIFT;
 
-               dpll = I915_READ(dpll_reg);
-               if (dpll & DISPLAY_RATE_SELECT_FPA1)
-                       DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
+       visible = base != 0;
+       if (!visible && !intel_crtc->cursor_visible)
+               return;
+
+       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
+               I915_WRITE(CURPOS_IVB(pipe), pos);
+               ivb_update_cursor(crtc, base);
+       } else {
+               I915_WRITE(CURPOS(pipe), pos);
+               if (IS_845G(dev) || IS_I865G(dev))
+                       i845_update_cursor(crtc, base);
+               else
+                       i9xx_update_cursor(crtc, base);
        }
 
-       /* Schedule downclock */
-       mod_timer(&intel_crtc->idle_timer, jiffies +
-                 msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+       if (visible)
+               intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj);
 }
 
-static void intel_decrease_pllclock(struct drm_crtc *crtc)
+static int intel_crtc_cursor_set(struct drm_crtc *crtc,
+                                struct drm_file *file,
+                                uint32_t handle,
+                                uint32_t width, uint32_t height)
 {
        struct drm_device *dev = crtc->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
-       int dpll_reg = DPLL(pipe);
-       int dpll = I915_READ(dpll_reg);
-
-       if (HAS_PCH_SPLIT(dev))
-               return;
-
-       if (!dev_priv->lvds_downclock_avail)
-               return;
-
-       /*
-        * Since this is called by a timer, we should never get here in
-        * the manual case.
-        */
-       if (!HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) {
-               DRM_DEBUG_DRIVER("downclocking LVDS\n");
+       struct drm_i915_gem_object *obj;
+       uint32_t addr;
+       int ret;
 
-               assert_panel_unlocked(dev_priv, pipe);
+       DRM_DEBUG_KMS("\n");
 
-               dpll |= DISPLAY_RATE_SELECT_FPA1;
-               I915_WRITE(dpll_reg, dpll);
-               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");
+       /* if we want to turn off the cursor ignore width and height */
+       if (!handle) {
+               DRM_DEBUG_KMS("cursor off\n");
+               addr = 0;
+               obj = NULL;
+               mutex_lock(&dev->struct_mutex);
+               goto finish;
        }
 
-}
+       /* Currently we only support 64x64 cursors */
+       if (width != 64 || height != 64) {
+               DRM_ERROR("we currently only support 64x64 cursors\n");
+               return -EINVAL;
+       }
 
-/**
- * intel_idle_update - adjust clocks for idleness
- * @work: work struct
- *
- * Either the GPU or display (or both) went idle.  Check the busy status
- * here and adjust the CRTC and GPU clocks as necessary.
- */
-static void intel_idle_update(struct work_struct *work)
-{
-       drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
-                                                   idle_work);
-       struct drm_device *dev = dev_priv->dev;
-       struct drm_crtc *crtc;
-       struct intel_crtc *intel_crtc;
+       obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle));
+       if (&obj->base == NULL)
+               return -ENOENT;
 
-       if (!i915_powersave)
-               return;
+       if (obj->base.size < width * height * 4) {
+               DRM_ERROR("buffer is to small\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
 
+       /* we only need to pin inside GTT if cursor is non-phy */
        mutex_lock(&dev->struct_mutex);
+       if (!dev_priv->info->cursor_needs_physical) {
+               if (obj->tiling_mode) {
+                       DRM_ERROR("cursor cannot be tiled\n");
+                       ret = -EINVAL;
+                       goto fail_locked;
+               }
 
-       i915_update_gfx_val(dev_priv);
+               ret = i915_gem_object_pin_to_display_plane(obj, 0, NULL);
+               if (ret) {
+                       DRM_ERROR("failed to move cursor bo into the GTT\n");
+                       goto fail_locked;
+               }
 
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               /* Skip inactive CRTCs */
-               if (!crtc->fb)
-                       continue;
+               ret = i915_gem_object_put_fence(obj);
+               if (ret) {
+                       DRM_ERROR("failed to release fence for cursor");
+                       goto fail_unpin;
+               }
 
-               intel_crtc = to_intel_crtc(crtc);
-               if (!intel_crtc->busy)
-                       intel_decrease_pllclock(crtc);
+               addr = obj->gtt_offset;
+       } else {
+               int align = IS_I830(dev) ? 16 * 1024 : 256;
+               ret = i915_gem_attach_phys_object(dev, obj,
+                                                 (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;
+               }
+               addr = obj->phys_obj->handle->busaddr;
        }
 
+       if (IS_GEN2(dev))
+               I915_WRITE(CURSIZE, (height << 12) | width);
 
-       mutex_unlock(&dev->struct_mutex);
-}
-
-/**
- * intel_mark_busy - mark the GPU and possibly the display busy
- * @dev: drm device
- * @obj: object we're operating on
- *
- * Callers can use this function to indicate that the GPU is busy processing
- * commands.  If @obj matches one of the CRTC objects (i.e. it's a scanout
- * buffer), we'll also mark the display as busy, so we know to increase its
- * clock frequency.
- */
-void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc = NULL;
-       struct intel_framebuffer *intel_fb;
-       struct intel_crtc *intel_crtc;
+ finish:
+       if (intel_crtc->cursor_bo) {
+               if (dev_priv->info->cursor_needs_physical) {
+                       if (intel_crtc->cursor_bo != obj)
+                               i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
+               } else
+                       i915_gem_object_unpin(intel_crtc->cursor_bo);
+               drm_gem_object_unreference(&intel_crtc->cursor_bo->base);
+       }
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return;
+       mutex_unlock(&dev->struct_mutex);
 
-       if (!dev_priv->busy)
-               dev_priv->busy = true;
-       else
-               mod_timer(&dev_priv->idle_timer, jiffies +
-                         msecs_to_jiffies(GPU_IDLE_TIMEOUT));
+       intel_crtc->cursor_addr = addr;
+       intel_crtc->cursor_bo = obj;
+       intel_crtc->cursor_width = width;
+       intel_crtc->cursor_height = height;
 
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               if (!crtc->fb)
-                       continue;
+       intel_crtc_update_cursor(crtc, true);
 
-               intel_crtc = to_intel_crtc(crtc);
-               intel_fb = to_intel_framebuffer(crtc->fb);
-               if (intel_fb->obj == obj) {
-                       if (!intel_crtc->busy) {
-                               /* Non-busy -> busy, upclock */
-                               intel_increase_pllclock(crtc);
-                               intel_crtc->busy = true;
-                       } else {
-                               /* Busy -> busy, put off timer */
-                               mod_timer(&intel_crtc->idle_timer, jiffies +
-                                         msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
-                       }
-               }
-       }
+       return 0;
+fail_unpin:
+       i915_gem_object_unpin(obj);
+fail_locked:
+       mutex_unlock(&dev->struct_mutex);
+fail:
+       drm_gem_object_unreference_unlocked(&obj->base);
+       return ret;
 }
 
-static void intel_crtc_destroy(struct drm_crtc *crtc)
+static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
 {
        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);
-       }
+       intel_crtc->cursor_x = x;
+       intel_crtc->cursor_y = y;
 
-       drm_crtc_cleanup(crtc);
+       intel_crtc_update_cursor(crtc, true);
 
-       kfree(intel_crtc);
+       return 0;
 }
 
-static void intel_unpin_work_fn(struct work_struct *__work)
+/** Sets the color ramps on behalf of RandR */
+void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+                                u16 blue, int regno)
 {
-       struct intel_unpin_work *work =
-               container_of(__work, struct intel_unpin_work, work);
-
-       mutex_lock(&work->dev->struct_mutex);
-       intel_unpin_fb_obj(work->old_fb_obj);
-       drm_gem_object_unreference(&work->pending_flip_obj->base);
-       drm_gem_object_unreference(&work->old_fb_obj->base);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       intel_update_fbc(work->dev);
-       mutex_unlock(&work->dev->struct_mutex);
-       kfree(work);
+       intel_crtc->lut_r[regno] = red >> 8;
+       intel_crtc->lut_g[regno] = green >> 8;
+       intel_crtc->lut_b[regno] = blue >> 8;
 }
 
-static void do_intel_finish_page_flip(struct drm_device *dev,
-                                     struct drm_crtc *crtc)
+void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+                            u16 *blue, int regno)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_unpin_work *work;
-       struct drm_i915_gem_object *obj;
-       struct drm_pending_vblank_event *e;
-       struct timeval tnow, tvbl;
-       unsigned long flags;
 
-       /* Ignore early vblank irqs */
-       if (intel_crtc == NULL)
-               return;
+       *red = intel_crtc->lut_r[regno] << 8;
+       *green = intel_crtc->lut_g[regno] << 8;
+       *blue = intel_crtc->lut_b[regno] << 8;
+}
 
-       do_gettimeofday(&tnow);
+static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+                                u16 *blue, uint32_t start, uint32_t size)
+{
+       int end = (start + size > 256) ? 256 : start + size, i;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       spin_lock_irqsave(&dev->event_lock, flags);
-       work = intel_crtc->unpin_work;
-       if (work == NULL || !work->pending) {
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-               return;
+       for (i = start; i < end; i++) {
+               intel_crtc->lut_r[i] = red[i] >> 8;
+               intel_crtc->lut_g[i] = green[i] >> 8;
+               intel_crtc->lut_b[i] = blue[i] >> 8;
        }
 
-       intel_crtc->unpin_work = NULL;
+       intel_crtc_load_lut(crtc);
+}
 
-       if (work->event) {
-               e = work->event;
-               e->event.sequence = drm_vblank_count_and_time(dev, intel_crtc->pipe, &tvbl);
+/**
+ * Get a pipe with a simple mode set on it for doing load-based monitor
+ * detection.
+ *
+ * It will be up to the load-detect code to adjust the pipe as appropriate for
+ * its requirements.  The pipe will be connected to no other encoders.
+ *
+ * Currently this code will only succeed if there is a pipe with no encoders
+ * configured for it.  In the future, it could choose to temporarily disable
+ * some outputs to free up a pipe for its use.
+ *
+ * \return crtc, or NULL if no pipes are available.
+ */
 
-               /* Called before vblank count and timestamps have
-                * been updated for the vblank interval of flip
-                * completion? Need to increment vblank count and
-                * add one videorefresh duration to returned timestamp
-                * to account for this. We assume this happened if we
-                * get called over 0.9 frame durations after the last
-                * timestamped vblank.
-                *
-                * This calculation can not be used with vrefresh rates
-                * below 5Hz (10Hz to be on the safe side) without
-                * promoting to 64 integers.
-                */
-               if (10 * (timeval_to_ns(&tnow) - timeval_to_ns(&tvbl)) >
-                   9 * crtc->framedur_ns) {
-                       e->event.sequence++;
-                       tvbl = ns_to_timeval(timeval_to_ns(&tvbl) +
-                                            crtc->framedur_ns);
-               }
+/* VESA 640x480x72Hz mode to set on the pipe */
+static struct drm_display_mode load_detect_mode = {
+       DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664,
+                704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+};
 
-               e->event.tv_sec = tvbl.tv_sec;
-               e->event.tv_usec = tvbl.tv_usec;
+static struct drm_framebuffer *
+intel_framebuffer_create(struct drm_device *dev,
+                        struct drm_mode_fb_cmd2 *mode_cmd,
+                        struct drm_i915_gem_object *obj)
+{
+       struct intel_framebuffer *intel_fb;
+       int ret;
 
-               list_add_tail(&e->base.link,
-                             &e->base.file_priv->event_list);
-               wake_up_interruptible(&e->base.file_priv->event_wait);
+       intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+       if (!intel_fb) {
+               drm_gem_object_unreference_unlocked(&obj->base);
+               return ERR_PTR(-ENOMEM);
        }
 
-       drm_vblank_put(dev, intel_crtc->pipe);
-
-       spin_unlock_irqrestore(&dev->event_lock, flags);
-
-       obj = work->old_fb_obj;
-
-       atomic_clear_mask(1 << intel_crtc->plane,
-                         &obj->pending_flip.counter);
-       if (atomic_read(&obj->pending_flip) == 0)
-               wake_up(&dev_priv->pending_flip_queue);
-
-       schedule_work(&work->work);
+       ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
+       if (ret) {
+               drm_gem_object_unreference_unlocked(&obj->base);
+               kfree(intel_fb);
+               return ERR_PTR(ret);
+       }
 
-       trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
+       return &intel_fb->base;
 }
 
-void intel_finish_page_flip(struct drm_device *dev, int pipe)
+static u32
+intel_framebuffer_pitch_for_width(int width, int bpp)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
-
-       do_intel_finish_page_flip(dev, crtc);
+       u32 pitch = DIV_ROUND_UP(width * bpp, 8);
+       return ALIGN(pitch, 64);
 }
 
-void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
+static u32
+intel_framebuffer_size_for_mode(struct drm_display_mode *mode, int bpp)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane];
-
-       do_intel_finish_page_flip(dev, crtc);
+       u32 pitch = intel_framebuffer_pitch_for_width(mode->hdisplay, bpp);
+       return ALIGN(pitch * mode->vdisplay, PAGE_SIZE);
 }
 
-void intel_prepare_page_flip(struct drm_device *dev, int plane)
+static struct drm_framebuffer *
+intel_framebuffer_create_for_mode(struct drm_device *dev,
+                                 struct drm_display_mode *mode,
+                                 int depth, int bpp)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc =
-               to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]);
-       unsigned long flags;
+       struct drm_i915_gem_object *obj;
+       struct drm_mode_fb_cmd2 mode_cmd;
 
-       spin_lock_irqsave(&dev->event_lock, flags);
-       if (intel_crtc->unpin_work) {
-               if ((++intel_crtc->unpin_work->pending) > 1)
-                       DRM_ERROR("Prepared flip multiple times\n");
-       } else {
-               DRM_DEBUG_DRIVER("preparing flip with no unpin work?\n");
-       }
-       spin_unlock_irqrestore(&dev->event_lock, flags);
+       obj = i915_gem_alloc_object(dev,
+                                   intel_framebuffer_size_for_mode(mode, bpp));
+       if (obj == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       mode_cmd.width = mode->hdisplay;
+       mode_cmd.height = mode->vdisplay;
+       mode_cmd.pitches[0] = intel_framebuffer_pitch_for_width(mode_cmd.width,
+                                                               bpp);
+       mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
+
+       return intel_framebuffer_create(dev, &mode_cmd, obj);
 }
 
-static int intel_gen2_queue_flip(struct drm_device *dev,
-                                struct drm_crtc *crtc,
-                                struct drm_framebuffer *fb,
-                                struct drm_i915_gem_object *obj)
+static struct drm_framebuffer *
+mode_fits_in_fbdev(struct drm_device *dev,
+                  struct drm_display_mode *mode)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       unsigned long offset;
-       u32 flip_mask;
-       int ret;
+       struct drm_i915_gem_object *obj;
+       struct drm_framebuffer *fb;
 
-       ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv));
-       if (ret)
-               goto out;
+       if (dev_priv->fbdev == NULL)
+               return NULL;
 
-       /* Offset into the new buffer for cases of shared fbs between CRTCs */
-       offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8;
+       obj = dev_priv->fbdev->ifb.obj;
+       if (obj == NULL)
+               return NULL;
 
-       ret = BEGIN_LP_RING(6);
-       if (ret)
-               goto out;
+       fb = &dev_priv->fbdev->ifb.base;
+       if (fb->pitches[0] < intel_framebuffer_pitch_for_width(mode->hdisplay,
+                                                              fb->bits_per_pixel))
+               return NULL;
 
-       /* Can't queue multiple flips, so wait for the previous
-        * one to finish before executing the next.
-        */
-       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);
-       OUT_RING(MI_NOOP);
-       OUT_RING(MI_DISPLAY_FLIP |
-                MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       OUT_RING(fb->pitches[0]);
-       OUT_RING(obj->gtt_offset + offset);
-       OUT_RING(0); /* aux display base address, unused */
-       ADVANCE_LP_RING();
-out:
-       return ret;
+       if (obj->base.size < mode->vdisplay * fb->pitches[0])
+               return NULL;
+
+       return fb;
 }
 
-static int intel_gen3_queue_flip(struct drm_device *dev,
-                                struct drm_crtc *crtc,
-                                struct drm_framebuffer *fb,
-                                struct drm_i915_gem_object *obj)
+bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+                               struct drm_connector *connector,
+                               struct drm_display_mode *mode,
+                               struct intel_load_detect_pipe *old)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       unsigned long offset;
-       u32 flip_mask;
-       int ret;
+       struct intel_crtc *intel_crtc;
+       struct drm_crtc *possible_crtc;
+       struct drm_encoder *encoder = &intel_encoder->base;
+       struct drm_crtc *crtc = NULL;
+       struct drm_device *dev = encoder->dev;
+       struct drm_framebuffer *old_fb;
+       int i = -1;
 
-       ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv));
-       if (ret)
-               goto out;
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
+                     connector->base.id, drm_get_connector_name(connector),
+                     encoder->base.id, drm_get_encoder_name(encoder));
 
-       /* Offset into the new buffer for cases of shared fbs between CRTCs */
-       offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8;
+       /*
+        * Algorithm gets a little messy:
+        *
+        *   - if the connector already has an assigned crtc, use it (but make
+        *     sure it's on first)
+        *
+        *   - try to find the first unused crtc that can drive this connector,
+        *     and use that if we find one
+        */
 
-       ret = BEGIN_LP_RING(6);
-       if (ret)
-               goto out;
+       /* See if we already have a CRTC for this connector */
+       if (encoder->crtc) {
+               crtc = encoder->crtc;
 
-       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);
-       OUT_RING(MI_NOOP);
-       OUT_RING(MI_DISPLAY_FLIP_I915 |
-                MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       OUT_RING(fb->pitches[0]);
-       OUT_RING(obj->gtt_offset + offset);
-       OUT_RING(MI_NOOP);
-
-       ADVANCE_LP_RING();
-out:
-       return ret;
-}
+               intel_crtc = to_intel_crtc(crtc);
+               old->dpms_mode = intel_crtc->dpms_mode;
+               old->load_detect_temp = false;
+
+               /* Make sure the crtc and connector are running */
+               if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
+                       struct drm_encoder_helper_funcs *encoder_funcs;
+                       struct drm_crtc_helper_funcs *crtc_funcs;
 
-static int intel_gen4_queue_flip(struct drm_device *dev,
-                                struct drm_crtc *crtc,
-                                struct drm_framebuffer *fb,
-                                struct drm_i915_gem_object *obj)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       uint32_t pf, pipesrc;
-       int ret;
+                       crtc_funcs = crtc->helper_private;
+                       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
 
-       ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv));
-       if (ret)
-               goto out;
+                       encoder_funcs = encoder->helper_private;
+                       encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
+               }
 
-       ret = BEGIN_LP_RING(4);
-       if (ret)
-               goto out;
+               return true;
+       }
 
-       /* i965+ uses the linear or tiled offsets from the
-        * Display Registers (which do not change across a page-flip)
-        * so we need only reprogram the base address.
-        */
-       OUT_RING(MI_DISPLAY_FLIP |
-                MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       OUT_RING(fb->pitches[0]);
-       OUT_RING(obj->gtt_offset | obj->tiling_mode);
+       /* Find an unused one (if possible) */
+       list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) {
+               i++;
+               if (!(encoder->possible_crtcs & (1 << i)))
+                       continue;
+               if (!possible_crtc->enabled) {
+                       crtc = possible_crtc;
+                       break;
+               }
+       }
 
-       /* XXX Enabling the panel-fitter across page-flip is so far
-        * untested on non-native modes, so ignore it for now.
-        * pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE;
+       /*
+        * If we didn't find an unused CRTC, don't use any.
         */
-       pf = 0;
-       pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
-       OUT_RING(pf | pipesrc);
-       ADVANCE_LP_RING();
-out:
-       return ret;
-}
+       if (!crtc) {
+               DRM_DEBUG_KMS("no pipe available for load-detect\n");
+               return false;
+       }
 
-static int intel_gen6_queue_flip(struct drm_device *dev,
-                                struct drm_crtc *crtc,
-                                struct drm_framebuffer *fb,
-                                struct drm_i915_gem_object *obj)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       uint32_t pf, pipesrc;
-       int ret;
+       encoder->crtc = crtc;
+       connector->encoder = encoder;
 
-       ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv));
-       if (ret)
-               goto out;
+       intel_crtc = to_intel_crtc(crtc);
+       old->dpms_mode = intel_crtc->dpms_mode;
+       old->load_detect_temp = true;
+       old->release_fb = NULL;
 
-       ret = BEGIN_LP_RING(4);
-       if (ret)
-               goto out;
+       if (!mode)
+               mode = &load_detect_mode;
 
-       OUT_RING(MI_DISPLAY_FLIP |
-                MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       OUT_RING(fb->pitches[0] | obj->tiling_mode);
-       OUT_RING(obj->gtt_offset);
+       old_fb = crtc->fb;
 
-       pf = I915_READ(PF_CTL(intel_crtc->pipe)) & PF_ENABLE;
-       pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
-       OUT_RING(pf | pipesrc);
-       ADVANCE_LP_RING();
-out:
-       return ret;
+       /* We need a framebuffer large enough to accommodate all accesses
+        * that the plane may generate whilst we perform load detection.
+        * We can not rely on the fbcon either being present (we get called
+        * during its initialisation to detect all boot displays, or it may
+        * not even exist) or that it is large enough to satisfy the
+        * requested mode.
+        */
+       crtc->fb = mode_fits_in_fbdev(dev, mode);
+       if (crtc->fb == NULL) {
+               DRM_DEBUG_KMS("creating tmp fb for load-detection\n");
+               crtc->fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32);
+               old->release_fb = crtc->fb;
+       } else
+               DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
+       if (IS_ERR(crtc->fb)) {
+               DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
+               crtc->fb = old_fb;
+               return false;
+       }
+
+       if (!drm_crtc_helper_set_mode(crtc, mode, 0, 0, old_fb)) {
+               DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
+               if (old->release_fb)
+                       old->release_fb->funcs->destroy(old->release_fb);
+               crtc->fb = old_fb;
+               return false;
+       }
+
+       /* let the connector get through one full cycle before testing */
+       intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+       return true;
 }
 
-/*
- * On gen7 we currently use the blit ring because (in early silicon at least)
- * the render ring doesn't give us interrpts for page flip completion, which
- * means clients will hang after the first flip is queued.  Fortunately the
- * blit ring generates interrupts properly, so use it instead.
- */
-static int intel_gen7_queue_flip(struct drm_device *dev,
-                                struct drm_crtc *crtc,
-                                struct drm_framebuffer *fb,
-                                struct drm_i915_gem_object *obj)
+void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
+                                   struct drm_connector *connector,
+                                   struct intel_load_detect_pipe *old)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_ring_buffer *ring = &dev_priv->ring[BCS];
-       int ret;
+       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;
+       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
 
-       ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
-       if (ret)
-               goto out;
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
+                     connector->base.id, drm_get_connector_name(connector),
+                     encoder->base.id, drm_get_encoder_name(encoder));
 
-       ret = intel_ring_begin(ring, 4);
-       if (ret)
-               goto out;
+       if (old->load_detect_temp) {
+               connector->encoder = NULL;
+               drm_helper_disable_unused_functions(dev);
 
-       intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | (intel_crtc->plane << 19));
-       intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode));
-       intel_ring_emit(ring, (obj->gtt_offset));
-       intel_ring_emit(ring, (MI_NOOP));
-       intel_ring_advance(ring);
-out:
-       return ret;
-}
+               if (old->release_fb)
+                       old->release_fb->funcs->destroy(old->release_fb);
 
-static int intel_default_queue_flip(struct drm_device *dev,
-                                   struct drm_crtc *crtc,
-                                   struct drm_framebuffer *fb,
-                                   struct drm_i915_gem_object *obj)
-{
-       return -ENODEV;
+               return;
+       }
+
+       /* Switch crtc and encoder back off if necessary */
+       if (old->dpms_mode != DRM_MODE_DPMS_ON) {
+               encoder_funcs->dpms(encoder, old->dpms_mode);
+               crtc_funcs->dpms(crtc, old->dpms_mode);
+       }
 }
 
-static int intel_crtc_page_flip(struct drm_crtc *crtc,
-                               struct drm_framebuffer *fb,
-                               struct drm_pending_vblank_event *event)
+/* Returns the clock of the currently programmed mode of the given pipe. */
+static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
 {
-       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_framebuffer *intel_fb;
-       struct drm_i915_gem_object *obj;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_unpin_work *work;
-       unsigned long flags;
-       int ret;
-
-       work = kzalloc(sizeof *work, GFP_KERNEL);
-       if (work == NULL)
-               return -ENOMEM;
+       int pipe = intel_crtc->pipe;
+       u32 dpll = I915_READ(DPLL(pipe));
+       u32 fp;
+       intel_clock_t clock;
 
-       work->event = event;
-       work->dev = crtc->dev;
-       intel_fb = to_intel_framebuffer(crtc->fb);
-       work->old_fb_obj = intel_fb->obj;
-       INIT_WORK(&work->work, intel_unpin_work_fn);
+       if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
+               fp = I915_READ(FP0(pipe));
+       else
+               fp = I915_READ(FP1(pipe));
 
-       ret = drm_vblank_get(dev, intel_crtc->pipe);
-       if (ret)
-               goto free_work;
+       clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
+       if (IS_PINEVIEW(dev)) {
+               clock.n = ffs((fp & FP_N_PINEVIEW_DIV_MASK) >> FP_N_DIV_SHIFT) - 1;
+               clock.m2 = (fp & FP_M2_PINEVIEW_DIV_MASK) >> FP_M2_DIV_SHIFT;
+       } else {
+               clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT;
+               clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
+       }
 
-       /* We borrow the event spin lock for protecting unpin_work */
-       spin_lock_irqsave(&dev->event_lock, flags);
-       if (intel_crtc->unpin_work) {
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-               kfree(work);
-               drm_vblank_put(dev, intel_crtc->pipe);
+       if (!IS_GEN2(dev)) {
+               if (IS_PINEVIEW(dev))
+                       clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >>
+                               DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW);
+               else
+                       clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >>
+                              DPLL_FPA01_P1_POST_DIV_SHIFT);
 
-               DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
-               return -EBUSY;
-       }
-       intel_crtc->unpin_work = work;
-       spin_unlock_irqrestore(&dev->event_lock, flags);
+               switch (dpll & DPLL_MODE_MASK) {
+               case DPLLB_MODE_DAC_SERIAL:
+                       clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ?
+                               5 : 10;
+                       break;
+               case DPLLB_MODE_LVDS:
+                       clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ?
+                               7 : 14;
+                       break;
+               default:
+                       DRM_DEBUG_KMS("Unknown DPLL mode %08x in programmed "
+                                 "mode\n", (int)(dpll & DPLL_MODE_MASK));
+                       return 0;
+               }
 
-       intel_fb = to_intel_framebuffer(fb);
-       obj = intel_fb->obj;
+               /* XXX: Handle the 100Mhz refclk */
+               intel_clock(dev, 96000, &clock);
+       } else {
+               bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN);
 
-       mutex_lock(&dev->struct_mutex);
+               if (is_lvds) {
+                       clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >>
+                                      DPLL_FPA01_P1_POST_DIV_SHIFT);
+                       clock.p2 = 14;
 
-       /* Reference the objects for the scheduled work. */
-       drm_gem_object_reference(&work->old_fb_obj->base);
-       drm_gem_object_reference(&obj->base);
+                       if ((dpll & PLL_REF_INPUT_MASK) ==
+                           PLLB_REF_INPUT_SPREADSPECTRUMIN) {
+                               /* XXX: might not be 66MHz */
+                               intel_clock(dev, 66000, &clock);
+                       } else
+                               intel_clock(dev, 48000, &clock);
+               } else {
+                       if (dpll & PLL_P1_DIVIDE_BY_TWO)
+                               clock.p1 = 2;
+                       else {
+                               clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >>
+                                           DPLL_FPA01_P1_POST_DIV_SHIFT) + 2;
+                       }
+                       if (dpll & PLL_P2_DIVIDE_BY_4)
+                               clock.p2 = 4;
+                       else
+                               clock.p2 = 2;
 
-       crtc->fb = fb;
+                       intel_clock(dev, 48000, &clock);
+               }
+       }
 
-       work->pending_flip_obj = obj;
+       /* XXX: It would be nice to validate the clocks, but we can't reuse
+        * i830PllIsValid() because it relies on the xf86_config connector
+        * configuration being accurate, which it isn't necessarily.
+        */
 
-       work->enable_stall_check = true;
+       return clock.dot;
+}
 
-       /* Block clients from rendering to the new back buffer until
-        * the flip occurs and the object is no longer visible.
-        */
-       atomic_add(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip);
+/** Returns the currently programmed mode of the given pipe. */
+struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
+                                            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;
+       struct drm_display_mode *mode;
+       int htot = I915_READ(HTOTAL(pipe));
+       int hsync = I915_READ(HSYNC(pipe));
+       int vtot = I915_READ(VTOTAL(pipe));
+       int vsync = I915_READ(VSYNC(pipe));
 
-       ret = dev_priv->display.queue_flip(dev, crtc, fb, obj);
-       if (ret)
-               goto cleanup_pending;
+       mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+       if (!mode)
+               return NULL;
 
-       intel_disable_fbc(dev);
-       mutex_unlock(&dev->struct_mutex);
+       mode->clock = intel_crtc_clock_get(dev, crtc);
+       mode->hdisplay = (htot & 0xffff) + 1;
+       mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
+       mode->hsync_start = (hsync & 0xffff) + 1;
+       mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1;
+       mode->vdisplay = (vtot & 0xffff) + 1;
+       mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1;
+       mode->vsync_start = (vsync & 0xffff) + 1;
+       mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1;
 
-       trace_i915_flip_request(intel_crtc->plane, obj);
+       drm_mode_set_name(mode);
+       drm_mode_set_crtcinfo(mode, 0);
 
-       return 0;
+       return mode;
+}
 
-cleanup_pending:
-       atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip);
-       drm_gem_object_unreference(&work->old_fb_obj->base);
-       drm_gem_object_unreference(&obj->base);
-       mutex_unlock(&dev->struct_mutex);
+#define GPU_IDLE_TIMEOUT 500 /* ms */
 
-       spin_lock_irqsave(&dev->event_lock, flags);
-       intel_crtc->unpin_work = NULL;
-       spin_unlock_irqrestore(&dev->event_lock, flags);
+/* When this timer fires, we've been idle for awhile */
+static void intel_gpu_idle_timer(unsigned long arg)
+{
+       struct drm_device *dev = (struct drm_device *)arg;
+       drm_i915_private_t *dev_priv = dev->dev_private;
 
-       drm_vblank_put(dev, intel_crtc->pipe);
-free_work:
-       kfree(work);
+       if (!list_empty(&dev_priv->mm.active_list)) {
+               /* Still processing requests, so just re-arm the timer. */
+               mod_timer(&dev_priv->idle_timer, jiffies +
+                         msecs_to_jiffies(GPU_IDLE_TIMEOUT));
+               return;
+       }
 
-       return ret;
+       dev_priv->busy = false;
+       queue_work(dev_priv->wq, &dev_priv->idle_work);
 }
 
-static void intel_sanitize_modesetting(struct drm_device *dev,
-                                      int pipe, int plane)
+#define CRTC_IDLE_TIMEOUT 1000 /* ms */
+
+static void intel_crtc_idle_timer(unsigned long arg)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 reg, val;
+       struct intel_crtc *intel_crtc = (struct intel_crtc *)arg;
+       struct drm_crtc *crtc = &intel_crtc->base;
+       drm_i915_private_t *dev_priv = crtc->dev->dev_private;
+       struct intel_framebuffer *intel_fb;
 
-       /* Clear any frame start delays used for debugging left by the BIOS */
-       for_each_pipe(pipe) {
-               reg = PIPECONF(pipe);
-               I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
+       intel_fb = to_intel_framebuffer(crtc->fb);
+       if (intel_fb && intel_fb->obj->active) {
+               /* The framebuffer is still being accessed by the GPU. */
+               mod_timer(&intel_crtc->idle_timer, jiffies +
+                         msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+               return;
        }
 
+       intel_crtc->busy = false;
+       queue_work(dev_priv->wq, &dev_priv->idle_work);
+}
+
+static void intel_increase_pllclock(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int dpll_reg = DPLL(pipe);
+       int dpll;
+
        if (HAS_PCH_SPLIT(dev))
                return;
 
-       /* Who knows what state these registers were left in by the BIOS or
-        * grub?
-        *
-        * If we leave the registers in a conflicting state (e.g. with the
-        * display plane reading from the other pipe than the one we intend
-        * to use) then when we attempt to teardown the active mode, we will
-        * not disable the pipes and planes in the correct order -- leaving
-        * a plane reading from a disabled pipe and possibly leading to
-        * undefined behaviour.
-        */
+       if (!dev_priv->lvds_downclock_avail)
+               return;
 
-       reg = DSPCNTR(plane);
-       val = I915_READ(reg);
+       dpll = I915_READ(dpll_reg);
+       if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) {
+               DRM_DEBUG_DRIVER("upclocking LVDS\n");
 
-       if ((val & DISPLAY_PLANE_ENABLE) == 0)
-               return;
-       if (!!(val & DISPPLANE_SEL_PIPE_MASK) == pipe)
-               return;
+               assert_panel_unlocked(dev_priv, pipe);
 
-       /* This display plane is active and attached to the other CPU pipe. */
-       pipe = !pipe;
+               dpll &= ~DISPLAY_RATE_SELECT_FPA1;
+               I915_WRITE(dpll_reg, dpll);
+               intel_wait_for_vblank(dev, pipe);
 
-       /* Disable the plane and wait for it to stop reading from the pipe. */
-       intel_disable_plane(dev_priv, plane, pipe);
-       intel_disable_pipe(dev_priv, pipe);
+               dpll = I915_READ(dpll_reg);
+               if (dpll & DISPLAY_RATE_SELECT_FPA1)
+                       DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
+       }
+
+       /* Schedule downclock */
+       mod_timer(&intel_crtc->idle_timer, jiffies +
+                 msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
 }
 
-static void intel_crtc_reset(struct drm_crtc *crtc)
+static void intel_decrease_pllclock(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int dpll_reg = DPLL(pipe);
+       int dpll = I915_READ(dpll_reg);
 
-       /* Reset flags back to the 'unknown' status so that they
-        * will be correctly set on the initial modeset.
-        */
-       intel_crtc->dpms_mode = -1;
+       if (HAS_PCH_SPLIT(dev))
+               return;
 
-       /* We need to fix up any BIOS configuration that conflicts with
-        * our expectations.
+       if (!dev_priv->lvds_downclock_avail)
+               return;
+
+       /*
+        * Since this is called by a timer, we should never get here in
+        * the manual case.
         */
-       intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane);
-}
+       if (!HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) {
+               DRM_DEBUG_DRIVER("downclocking LVDS\n");
 
-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,
-       .load_lut = intel_crtc_load_lut,
-       .disable = intel_crtc_disable,
-};
+               assert_panel_unlocked(dev_priv, pipe);
 
-static const struct drm_crtc_funcs intel_crtc_funcs = {
-       .reset = intel_crtc_reset,
-       .cursor_set = intel_crtc_cursor_set,
-       .cursor_move = intel_crtc_cursor_move,
-       .gamma_set = intel_crtc_gamma_set,
-       .set_config = drm_crtc_helper_set_config,
-       .destroy = intel_crtc_destroy,
-       .page_flip = intel_crtc_page_flip,
-};
+               dpll |= DISPLAY_RATE_SELECT_FPA1;
+               I915_WRITE(dpll_reg, dpll);
+               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");
+       }
 
-static void intel_crtc_init(struct drm_device *dev, int pipe)
+}
+
+/**
+ * intel_idle_update - adjust clocks for idleness
+ * @work: work struct
+ *
+ * Either the GPU or display (or both) went idle.  Check the busy status
+ * here and adjust the CRTC and GPU clocks as necessary.
+ */
+static void intel_idle_update(struct work_struct *work)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+                                                   idle_work);
+       struct drm_device *dev = dev_priv->dev;
+       struct drm_crtc *crtc;
        struct intel_crtc *intel_crtc;
-       int i;
 
-       intel_crtc = kzalloc(sizeof(struct intel_crtc) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
-       if (intel_crtc == NULL)
+       if (!i915_powersave)
                return;
 
-       drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
-
-       drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
-       for (i = 0; i < 256; i++) {
-               intel_crtc->lut_r[i] = i;
-               intel_crtc->lut_g[i] = i;
-               intel_crtc->lut_b[i] = i;
-       }
-
-       /* Swap pipes & planes for FBC on pre-965 */
-       intel_crtc->pipe = pipe;
-       intel_crtc->plane = pipe;
-       if (IS_MOBILE(dev) && IS_GEN3(dev)) {
-               DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
-               intel_crtc->plane = !pipe;
-       }
-
-       BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
-              dev_priv->plane_to_crtc_mapping[intel_crtc->plane] != NULL);
-       dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
-       dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
+       mutex_lock(&dev->struct_mutex);
 
-       intel_crtc_reset(&intel_crtc->base);
-       intel_crtc->active = true; /* force the pipe off on setup_init_config */
-       intel_crtc->bpp = 24; /* default for pre-Ironlake */
+       i915_update_gfx_val(dev_priv);
 
-       if (HAS_PCH_SPLIT(dev)) {
-               if (pipe == 2 && IS_IVYBRIDGE(dev))
-                       intel_crtc->no_pll = true;
-               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;
-       }
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               /* Skip inactive CRTCs */
+               if (!crtc->fb)
+                       continue;
 
-       drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
+               intel_crtc = to_intel_crtc(crtc);
+               if (!intel_crtc->busy)
+                       intel_decrease_pllclock(crtc);
+       }
 
-       intel_crtc->busy = false;
 
-       setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
-                   (unsigned long)intel_crtc);
+       mutex_unlock(&dev->struct_mutex);
 }
 
-int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
-                               struct drm_file *file)
+/**
+ * intel_mark_busy - mark the GPU and possibly the display busy
+ * @dev: drm device
+ * @obj: object we're operating on
+ *
+ * Callers can use this function to indicate that the GPU is busy processing
+ * commands.  If @obj matches one of the CRTC objects (i.e. it's a scanout
+ * buffer), we'll also mark the display as busy, so we know to increase its
+ * clock frequency.
+ */
+void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_i915_get_pipe_from_crtc_id *pipe_from_crtc_id = data;
-       struct drm_mode_object *drmmode_obj;
-       struct intel_crtc *crtc;
-
-       if (!dev_priv) {
-               DRM_ERROR("called with no initialization\n");
-               return -EINVAL;
-       }
+       struct drm_crtc *crtc = NULL;
+       struct intel_framebuffer *intel_fb;
+       struct intel_crtc *intel_crtc;
 
-       drmmode_obj = drm_mode_object_find(dev, pipe_from_crtc_id->crtc_id,
-                       DRM_MODE_OBJECT_CRTC);
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return;
 
-       if (!drmmode_obj) {
-               DRM_ERROR("no such CRTC id\n");
-               return -EINVAL;
-       }
+       if (!dev_priv->busy)
+               dev_priv->busy = true;
+       else
+               mod_timer(&dev_priv->idle_timer, jiffies +
+                         msecs_to_jiffies(GPU_IDLE_TIMEOUT));
 
-       crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
-       pipe_from_crtc_id->pipe = crtc->pipe;
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (!crtc->fb)
+                       continue;
 
-       return 0;
+               intel_crtc = to_intel_crtc(crtc);
+               intel_fb = to_intel_framebuffer(crtc->fb);
+               if (intel_fb->obj == obj) {
+                       if (!intel_crtc->busy) {
+                               /* Non-busy -> busy, upclock */
+                               intel_increase_pllclock(crtc);
+                               intel_crtc->busy = true;
+                       } else {
+                               /* Busy -> busy, put off timer */
+                               mod_timer(&intel_crtc->idle_timer, jiffies +
+                                         msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+                       }
+               }
+       }
 }
 
-static int intel_encoder_clones(struct drm_device *dev, int type_mask)
+static void intel_crtc_destroy(struct drm_crtc *crtc)
 {
-       struct intel_encoder *encoder;
-       int index_mask = 0;
-       int entry = 0;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct intel_unpin_work *work;
+       unsigned long flags;
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
-               if (type_mask & encoder->clone_mask)
-                       index_mask |= (1 << entry);
-               entry++;
+       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);
        }
 
-       return index_mask;
+       drm_crtc_cleanup(crtc);
+
+       kfree(intel_crtc);
 }
 
-static bool has_edp_a(struct drm_device *dev)
+static void intel_unpin_work_fn(struct work_struct *__work)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (!IS_MOBILE(dev))
-               return false;
-
-       if ((I915_READ(DP_A) & DP_DETECTED) == 0)
-               return false;
+       struct intel_unpin_work *work =
+               container_of(__work, struct intel_unpin_work, work);
 
-       if (IS_GEN5(dev) &&
-           (I915_READ(ILK_DISPLAY_CHICKEN_FUSES) & ILK_eDP_A_DISABLE))
-               return false;
+       mutex_lock(&work->dev->struct_mutex);
+       intel_unpin_fb_obj(work->old_fb_obj);
+       drm_gem_object_unreference(&work->pending_flip_obj->base);
+       drm_gem_object_unreference(&work->old_fb_obj->base);
 
-       return true;
+       intel_update_fbc(work->dev);
+       mutex_unlock(&work->dev->struct_mutex);
+       kfree(work);
 }
 
-static void intel_setup_outputs(struct drm_device *dev)
+static void do_intel_finish_page_flip(struct drm_device *dev,
+                                     struct drm_crtc *crtc)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *encoder;
-       bool dpd_is_edp = false;
-       bool has_lvds;
-
-       has_lvds = intel_lvds_init(dev);
-       if (!has_lvds && !HAS_PCH_SPLIT(dev)) {
-               /* disable the panel fitter on everything but LVDS */
-               I915_WRITE(PFIT_CONTROL, 0);
-       }
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_unpin_work *work;
+       struct drm_i915_gem_object *obj;
+       struct drm_pending_vblank_event *e;
+       struct timeval tnow, tvbl;
+       unsigned long flags;
 
-       if (HAS_PCH_SPLIT(dev)) {
-               dpd_is_edp = intel_dpd_is_edp(dev);
+       /* Ignore early vblank irqs */
+       if (intel_crtc == NULL)
+               return;
 
-               if (has_edp_a(dev))
-                       intel_dp_init(dev, DP_A);
+       do_gettimeofday(&tnow);
 
-               if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
-                       intel_dp_init(dev, PCH_DP_D);
+       spin_lock_irqsave(&dev->event_lock, flags);
+       work = intel_crtc->unpin_work;
+       if (work == NULL || !work->pending) {
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+               return;
        }
 
-       intel_crt_init(dev);
+       intel_crtc->unpin_work = NULL;
 
-       if (HAS_PCH_SPLIT(dev)) {
-               int found;
+       if (work->event) {
+               e = work->event;
+               e->event.sequence = drm_vblank_count_and_time(dev, intel_crtc->pipe, &tvbl);
 
-               if (I915_READ(HDMIB) & PORT_DETECTED) {
-                       /* PCH SDVOB multiplex with HDMIB */
-                       found = intel_sdvo_init(dev, PCH_SDVOB);
-                       if (!found)
-                               intel_hdmi_init(dev, HDMIB);
-                       if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
-                               intel_dp_init(dev, PCH_DP_B);
+               /* Called before vblank count and timestamps have
+                * been updated for the vblank interval of flip
+                * completion? Need to increment vblank count and
+                * add one videorefresh duration to returned timestamp
+                * to account for this. We assume this happened if we
+                * get called over 0.9 frame durations after the last
+                * timestamped vblank.
+                *
+                * This calculation can not be used with vrefresh rates
+                * below 5Hz (10Hz to be on the safe side) without
+                * promoting to 64 integers.
+                */
+               if (10 * (timeval_to_ns(&tnow) - timeval_to_ns(&tvbl)) >
+                   9 * crtc->framedur_ns) {
+                       e->event.sequence++;
+                       tvbl = ns_to_timeval(timeval_to_ns(&tvbl) +
+                                            crtc->framedur_ns);
                }
 
-               if (I915_READ(HDMIC) & PORT_DETECTED)
-                       intel_hdmi_init(dev, HDMIC);
-
-               if (I915_READ(HDMID) & PORT_DETECTED)
-                       intel_hdmi_init(dev, HDMID);
-
-               if (I915_READ(PCH_DP_C) & DP_DETECTED)
-                       intel_dp_init(dev, PCH_DP_C);
-
-               if (!dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
-                       intel_dp_init(dev, PCH_DP_D);
-
-       } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) {
-               bool found = false;
-
-               if (I915_READ(SDVOB) & SDVO_DETECTED) {
-                       DRM_DEBUG_KMS("probing SDVOB\n");
-                       found = intel_sdvo_init(dev, SDVOB);
-                       if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) {
-                               DRM_DEBUG_KMS("probing HDMI on SDVOB\n");
-                               intel_hdmi_init(dev, SDVOB);
-                       }
-
-                       if (!found && SUPPORTS_INTEGRATED_DP(dev)) {
-                               DRM_DEBUG_KMS("probing DP_B\n");
-                               intel_dp_init(dev, DP_B);
-                       }
-               }
+               e->event.tv_sec = tvbl.tv_sec;
+               e->event.tv_usec = tvbl.tv_usec;
 
-               /* Before G4X SDVOC doesn't have its own detect register */
+               list_add_tail(&e->base.link,
+                             &e->base.file_priv->event_list);
+               wake_up_interruptible(&e->base.file_priv->event_wait);
+       }
 
-               if (I915_READ(SDVOB) & SDVO_DETECTED) {
-                       DRM_DEBUG_KMS("probing SDVOC\n");
-                       found = intel_sdvo_init(dev, SDVOC);
-               }
+       drm_vblank_put(dev, intel_crtc->pipe);
 
-               if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) {
+       spin_unlock_irqrestore(&dev->event_lock, flags);
 
-                       if (SUPPORTS_INTEGRATED_HDMI(dev)) {
-                               DRM_DEBUG_KMS("probing HDMI on SDVOC\n");
-                               intel_hdmi_init(dev, SDVOC);
-                       }
-                       if (SUPPORTS_INTEGRATED_DP(dev)) {
-                               DRM_DEBUG_KMS("probing DP_C\n");
-                               intel_dp_init(dev, DP_C);
-                       }
-               }
+       obj = work->old_fb_obj;
 
-               if (SUPPORTS_INTEGRATED_DP(dev) &&
-                   (I915_READ(DP_D) & DP_DETECTED)) {
-                       DRM_DEBUG_KMS("probing DP_D\n");
-                       intel_dp_init(dev, DP_D);
-               }
-       } else if (IS_GEN2(dev))
-               intel_dvo_init(dev);
+       atomic_clear_mask(1 << intel_crtc->plane,
+                         &obj->pending_flip.counter);
+       if (atomic_read(&obj->pending_flip) == 0)
+               wake_up(&dev_priv->pending_flip_queue);
 
-       if (SUPPORTS_TV(dev))
-               intel_tv_init(dev);
+       schedule_work(&work->work);
 
-       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);
-       }
+       trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
+}
 
-       /* disable all the possible outputs/crtcs before entering KMS mode */
-       drm_helper_disable_unused_functions(dev);
+void intel_finish_page_flip(struct drm_device *dev, int pipe)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
 
-       if (HAS_PCH_SPLIT(dev))
-               ironlake_init_pch_refclk(dev);
+       do_intel_finish_page_flip(dev, crtc);
 }
 
-static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
+void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
 {
-       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
-
-       drm_framebuffer_cleanup(fb);
-       drm_gem_object_unreference_unlocked(&intel_fb->obj->base);
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane];
 
-       kfree(intel_fb);
+       do_intel_finish_page_flip(dev, crtc);
 }
 
-static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb,
-                                               struct drm_file *file,
-                                               unsigned int *handle)
+void intel_prepare_page_flip(struct drm_device *dev, int plane)
 {
-       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
-       struct drm_i915_gem_object *obj = intel_fb->obj;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc =
+               to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]);
+       unsigned long flags;
 
-       return drm_gem_handle_create(file, &obj->base, handle);
+       spin_lock_irqsave(&dev->event_lock, flags);
+       if (intel_crtc->unpin_work) {
+               if ((++intel_crtc->unpin_work->pending) > 1)
+                       DRM_ERROR("Prepared flip multiple times\n");
+       } else {
+               DRM_DEBUG_DRIVER("preparing flip with no unpin work?\n");
+       }
+       spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
-static const struct drm_framebuffer_funcs intel_fb_funcs = {
-       .destroy = intel_user_framebuffer_destroy,
-       .create_handle = intel_user_framebuffer_create_handle,
-};
-
-int intel_framebuffer_init(struct drm_device *dev,
-                          struct intel_framebuffer *intel_fb,
-                          struct drm_mode_fb_cmd2 *mode_cmd,
-                          struct drm_i915_gem_object *obj)
+static int intel_gen2_queue_flip(struct drm_device *dev,
+                                struct drm_crtc *crtc,
+                                struct drm_framebuffer *fb,
+                                struct drm_i915_gem_object *obj)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       unsigned long offset;
+       u32 flip_mask;
+       struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
        int ret;
 
-       if (obj->tiling_mode == I915_TILING_Y)
-               return -EINVAL;
-
-       if (mode_cmd->pitches[0] & 63)
-               return -EINVAL;
+       ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
+       if (ret)
+               goto err;
 
-       switch (mode_cmd->pixel_format) {
-       case DRM_FORMAT_RGB332:
-       case DRM_FORMAT_RGB565:
-       case DRM_FORMAT_XRGB8888:
-       case DRM_FORMAT_XBGR8888:
-       case DRM_FORMAT_ARGB8888:
-       case DRM_FORMAT_XRGB2101010:
-       case DRM_FORMAT_ARGB2101010:
-               /* RGB formats are common across chipsets */
-               break;
-       case DRM_FORMAT_YUYV:
-       case DRM_FORMAT_UYVY:
-       case DRM_FORMAT_YVYU:
-       case DRM_FORMAT_VYUY:
-               break;
-       default:
-               DRM_DEBUG_KMS("unsupported pixel format %u\n",
-                               mode_cmd->pixel_format);
-               return -EINVAL;
-       }
+       /* Offset into the new buffer for cases of shared fbs between CRTCs */
+       offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8;
 
-       ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
-       if (ret) {
-               DRM_ERROR("framebuffer init failed %d\n", ret);
-               return ret;
-       }
+       ret = intel_ring_begin(ring, 6);
+       if (ret)
+               goto err_unpin;
 
-       drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
-       intel_fb->obj = obj;
+       /* Can't queue multiple flips, so wait for the previous
+        * one to finish before executing the next.
+        */
+       if (intel_crtc->plane)
+               flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
+       else
+               flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
+       intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_emit(ring, MI_DISPLAY_FLIP |
+                       MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+       intel_ring_emit(ring, fb->pitches[0]);
+       intel_ring_emit(ring, obj->gtt_offset + offset);
+       intel_ring_emit(ring, 0); /* aux display base address, unused */
+       intel_ring_advance(ring);
        return 0;
+
+err_unpin:
+       intel_unpin_fb_obj(obj);
+err:
+       return ret;
 }
 
-static struct drm_framebuffer *
-intel_user_framebuffer_create(struct drm_device *dev,
-                             struct drm_file *filp,
-                             struct drm_mode_fb_cmd2 *mode_cmd)
+static int intel_gen3_queue_flip(struct drm_device *dev,
+                                struct drm_crtc *crtc,
+                                struct drm_framebuffer *fb,
+                                struct drm_i915_gem_object *obj)
 {
-       struct drm_i915_gem_object *obj;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       unsigned long offset;
+       u32 flip_mask;
+       struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
+       int ret;
 
-       obj = to_intel_bo(drm_gem_object_lookup(dev, filp,
-                                               mode_cmd->handles[0]));
-       if (&obj->base == NULL)
-               return ERR_PTR(-ENOENT);
+       ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
+       if (ret)
+               goto err;
 
-       return intel_framebuffer_create(dev, mode_cmd, obj);
-}
+       /* Offset into the new buffer for cases of shared fbs between CRTCs */
+       offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8;
 
-static const struct drm_mode_config_funcs intel_mode_funcs = {
-       .fb_create = intel_user_framebuffer_create,
-       .output_poll_changed = intel_fb_output_poll_changed,
-};
+       ret = intel_ring_begin(ring, 6);
+       if (ret)
+               goto err_unpin;
+
+       if (intel_crtc->plane)
+               flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
+       else
+               flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
+       intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 |
+                       MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+       intel_ring_emit(ring, fb->pitches[0]);
+       intel_ring_emit(ring, obj->gtt_offset + offset);
+       intel_ring_emit(ring, MI_NOOP);
+
+       intel_ring_advance(ring);
+       return 0;
+
+err_unpin:
+       intel_unpin_fb_obj(obj);
+err:
+       return ret;
+}
 
-static struct drm_i915_gem_object *
-intel_alloc_context_page(struct drm_device *dev)
+static int intel_gen4_queue_flip(struct drm_device *dev,
+                                struct drm_crtc *crtc,
+                                struct drm_framebuffer *fb,
+                                struct drm_i915_gem_object *obj)
 {
-       struct drm_i915_gem_object *ctx;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       uint32_t pf, pipesrc;
+       struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
        int ret;
 
-       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+       ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
+       if (ret)
+               goto err;
 
-       ctx = i915_gem_alloc_object(dev, 4096);
-       if (!ctx) {
-               DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
-               return NULL;
-       }
+       ret = intel_ring_begin(ring, 4);
+       if (ret)
+               goto err_unpin;
 
-       ret = i915_gem_object_pin(ctx, 4096, true);
-       if (ret) {
-               DRM_ERROR("failed to pin power context: %d\n", ret);
-               goto err_unref;
-       }
+       /* i965+ uses the linear or tiled offsets from the
+        * Display Registers (which do not change across a page-flip)
+        * so we need only reprogram the base address.
+        */
+       intel_ring_emit(ring, MI_DISPLAY_FLIP |
+                       MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+       intel_ring_emit(ring, fb->pitches[0]);
+       intel_ring_emit(ring, obj->gtt_offset | obj->tiling_mode);
 
-       ret = i915_gem_object_set_to_gtt_domain(ctx, 1);
-       if (ret) {
-               DRM_ERROR("failed to set-domain on power context: %d\n", ret);
+       /* XXX Enabling the panel-fitter across page-flip is so far
+        * untested on non-native modes, so ignore it for now.
+        * pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE;
+        */
+       pf = 0;
+       pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
+       intel_ring_emit(ring, pf | pipesrc);
+       intel_ring_advance(ring);
+       return 0;
+
+err_unpin:
+       intel_unpin_fb_obj(obj);
+err:
+       return ret;
+}
+
+static int intel_gen6_queue_flip(struct drm_device *dev,
+                                struct drm_crtc *crtc,
+                                struct drm_framebuffer *fb,
+                                struct drm_i915_gem_object *obj)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
+       uint32_t pf, pipesrc;
+       int ret;
+
+       ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
+       if (ret)
+               goto err;
+
+       ret = intel_ring_begin(ring, 4);
+       if (ret)
                goto err_unpin;
-       }
 
-       return ctx;
+       intel_ring_emit(ring, MI_DISPLAY_FLIP |
+                       MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+       intel_ring_emit(ring, fb->pitches[0] | obj->tiling_mode);
+       intel_ring_emit(ring, obj->gtt_offset);
+
+       pf = I915_READ(PF_CTL(intel_crtc->pipe)) & PF_ENABLE;
+       pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
+       intel_ring_emit(ring, pf | pipesrc);
+       intel_ring_advance(ring);
+       return 0;
 
 err_unpin:
-       i915_gem_object_unpin(ctx);
-err_unref:
-       drm_gem_object_unreference(&ctx->base);
-       mutex_unlock(&dev->struct_mutex);
-       return NULL;
+       intel_unpin_fb_obj(obj);
+err:
+       return ret;
 }
 
-bool ironlake_set_drps(struct drm_device *dev, u8 val)
+/*
+ * On gen7 we currently use the blit ring because (in early silicon at least)
+ * the render ring doesn't give us interrpts for page flip completion, which
+ * means clients will hang after the first flip is queued.  Fortunately the
+ * blit ring generates interrupts properly, so use it instead.
+ */
+static int intel_gen7_queue_flip(struct drm_device *dev,
+                                struct drm_crtc *crtc,
+                                struct drm_framebuffer *fb,
+                                struct drm_i915_gem_object *obj)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u16 rgvswctl;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_ring_buffer *ring = &dev_priv->ring[BCS];
+       int ret;
 
-       rgvswctl = I915_READ16(MEMSWCTL);
-       if (rgvswctl & MEMCTL_CMD_STS) {
-               DRM_DEBUG("gpu busy, RCS change rejected\n");
-               return false; /* still busy with another command */
-       }
+       ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
+       if (ret)
+               goto err;
 
-       rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
-               (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
-       I915_WRITE16(MEMSWCTL, rgvswctl);
-       POSTING_READ16(MEMSWCTL);
+       ret = intel_ring_begin(ring, 4);
+       if (ret)
+               goto err_unpin;
 
-       rgvswctl |= MEMCTL_CMD_STS;
-       I915_WRITE16(MEMSWCTL, rgvswctl);
+       intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | (intel_crtc->plane << 19));
+       intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode));
+       intel_ring_emit(ring, (obj->gtt_offset));
+       intel_ring_emit(ring, (MI_NOOP));
+       intel_ring_advance(ring);
+       return 0;
 
-       return true;
+err_unpin:
+       intel_unpin_fb_obj(obj);
+err:
+       return ret;
 }
 
-void ironlake_enable_drps(struct drm_device *dev)
+static int intel_default_queue_flip(struct drm_device *dev,
+                                   struct drm_crtc *crtc,
+                                   struct drm_framebuffer *fb,
+                                   struct drm_i915_gem_object *obj)
+{
+       return -ENODEV;
+}
+
+static int intel_crtc_page_flip(struct drm_crtc *crtc,
+                               struct drm_framebuffer *fb,
+                               struct drm_pending_vblank_event *event)
 {
+       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 rgvmodectl = I915_READ(MEMMODECTL);
-       u8 fmax, fmin, fstart, vstart;
+       struct intel_framebuffer *intel_fb;
+       struct drm_i915_gem_object *obj;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_unpin_work *work;
+       unsigned long flags;
+       int ret;
+
+       work = kzalloc(sizeof *work, GFP_KERNEL);
+       if (work == NULL)
+               return -ENOMEM;
 
-       /* Enable temp reporting */
-       I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN);
-       I915_WRITE16(TSC1, I915_READ(TSC1) | TSE);
+       work->event = event;
+       work->dev = crtc->dev;
+       intel_fb = to_intel_framebuffer(crtc->fb);
+       work->old_fb_obj = intel_fb->obj;
+       INIT_WORK(&work->work, intel_unpin_work_fn);
 
-       /* 100ms RC evaluation intervals */
-       I915_WRITE(RCUPEI, 100000);
-       I915_WRITE(RCDNEI, 100000);
+       ret = drm_vblank_get(dev, intel_crtc->pipe);
+       if (ret)
+               goto free_work;
 
-       /* Set max/min thresholds to 90ms and 80ms respectively */
-       I915_WRITE(RCBMAXAVG, 90000);
-       I915_WRITE(RCBMINAVG, 80000);
+       /* We borrow the event spin lock for protecting unpin_work */
+       spin_lock_irqsave(&dev->event_lock, flags);
+       if (intel_crtc->unpin_work) {
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+               kfree(work);
+               drm_vblank_put(dev, intel_crtc->pipe);
 
-       I915_WRITE(MEMIHYST, 1);
+               DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
+               return -EBUSY;
+       }
+       intel_crtc->unpin_work = work;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
 
-       /* Set up min, max, and cur for interrupt handling */
-       fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT;
-       fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
-       fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
-               MEMMODE_FSTART_SHIFT;
+       intel_fb = to_intel_framebuffer(fb);
+       obj = intel_fb->obj;
 
-       vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
-               PXVFREQ_PX_SHIFT;
+       mutex_lock(&dev->struct_mutex);
 
-       dev_priv->fmax = fmax; /* IPS callback will increase this */
-       dev_priv->fstart = fstart;
+       /* Reference the objects for the scheduled work. */
+       drm_gem_object_reference(&work->old_fb_obj->base);
+       drm_gem_object_reference(&obj->base);
 
-       dev_priv->max_delay = fstart;
-       dev_priv->min_delay = fmin;
-       dev_priv->cur_delay = fstart;
+       crtc->fb = fb;
 
-       DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n",
-                        fmax, fmin, fstart);
+       work->pending_flip_obj = obj;
 
-       I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
+       work->enable_stall_check = true;
 
-       /*
-        * Interrupts will be enabled in ironlake_irq_postinstall
+       /* Block clients from rendering to the new back buffer until
+        * the flip occurs and the object is no longer visible.
         */
+       atomic_add(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip);
 
-       I915_WRITE(VIDSTART, vstart);
-       POSTING_READ(VIDSTART);
-
-       rgvmodectl |= MEMMODE_SWMODE_EN;
-       I915_WRITE(MEMMODECTL, rgvmodectl);
-
-       if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
-               DRM_ERROR("stuck trying to change perf mode\n");
-       msleep(1);
-
-       ironlake_set_drps(dev, fstart);
+       ret = dev_priv->display.queue_flip(dev, crtc, fb, obj);
+       if (ret)
+               goto cleanup_pending;
 
-       dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) +
-               I915_READ(0x112e0);
-       dev_priv->last_time1 = jiffies_to_msecs(jiffies);
-       dev_priv->last_count2 = I915_READ(0x112f4);
-       getrawmonotonic(&dev_priv->last_time2);
-}
+       intel_disable_fbc(dev);
+       mutex_unlock(&dev->struct_mutex);
 
-void ironlake_disable_drps(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u16 rgvswctl = I915_READ16(MEMSWCTL);
+       trace_i915_flip_request(intel_crtc->plane, obj);
 
-       /* Ack interrupts, disable EFC interrupt */
-       I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
-       I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG);
-       I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT);
-       I915_WRITE(DEIIR, DE_PCU_EVENT);
-       I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
+       return 0;
 
-       /* Go back to the starting frequency */
-       ironlake_set_drps(dev, dev_priv->fstart);
-       msleep(1);
-       rgvswctl |= MEMCTL_CMD_STS;
-       I915_WRITE(MEMSWCTL, rgvswctl);
-       msleep(1);
+cleanup_pending:
+       atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip);
+       drm_gem_object_unreference(&work->old_fb_obj->base);
+       drm_gem_object_unreference(&obj->base);
+       mutex_unlock(&dev->struct_mutex);
 
-}
+       spin_lock_irqsave(&dev->event_lock, flags);
+       intel_crtc->unpin_work = NULL;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
 
-void gen6_set_rps(struct drm_device *dev, u8 val)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 swreq;
+       drm_vblank_put(dev, intel_crtc->pipe);
+free_work:
+       kfree(work);
 
-       swreq = (val & 0x3ff) << 25;
-       I915_WRITE(GEN6_RPNSWREQ, swreq);
+       return ret;
 }
 
-void gen6_disable_rps(struct drm_device *dev)
+static void intel_sanitize_modesetting(struct drm_device *dev,
+                                      int pipe, int plane)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg, val;
 
-       I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
-       I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
-       I915_WRITE(GEN6_PMIER, 0);
-       /* Complete PM interrupt masking here doesn't race with the rps work
-        * item again unmasking PM interrupts because that is using a different
-        * register (PMIMR) to mask PM interrupts. The only risk is in leaving
-        * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
+       /* Clear any frame start delays used for debugging left by the BIOS */
+       for_each_pipe(pipe) {
+               reg = PIPECONF(pipe);
+               I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
+       }
 
-       spin_lock_irq(&dev_priv->rps_lock);
-       dev_priv->pm_iir = 0;
-       spin_unlock_irq(&dev_priv->rps_lock);
+       if (HAS_PCH_SPLIT(dev))
+               return;
 
-       I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
-}
+       /* Who knows what state these registers were left in by the BIOS or
+        * grub?
+        *
+        * If we leave the registers in a conflicting state (e.g. with the
+        * display plane reading from the other pipe than the one we intend
+        * to use) then when we attempt to teardown the active mode, we will
+        * not disable the pipes and planes in the correct order -- leaving
+        * a plane reading from a disabled pipe and possibly leading to
+        * undefined behaviour.
+        */
 
-static unsigned long intel_pxfreq(u32 vidfreq)
-{
-       unsigned long freq;
-       int div = (vidfreq & 0x3f0000) >> 16;
-       int post = (vidfreq & 0x3000) >> 12;
-       int pre = (vidfreq & 0x7);
+       reg = DSPCNTR(plane);
+       val = I915_READ(reg);
 
-       if (!pre)
-               return 0;
+       if ((val & DISPLAY_PLANE_ENABLE) == 0)
+               return;
+       if (!!(val & DISPPLANE_SEL_PIPE_MASK) == pipe)
+               return;
 
-       freq = ((div * 133333) / ((1<<post) * pre));
+       /* This display plane is active and attached to the other CPU pipe. */
+       pipe = !pipe;
 
-       return freq;
+       /* Disable the plane and wait for it to stop reading from the pipe. */
+       intel_disable_plane(dev_priv, plane, pipe);
+       intel_disable_pipe(dev_priv, pipe);
 }
 
-void intel_init_emon(struct drm_device *dev)
+static void intel_crtc_reset(struct drm_crtc *crtc)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 lcfuse;
-       u8 pxw[16];
-       int i;
-
-       /* Disable to program */
-       I915_WRITE(ECR, 0);
-       POSTING_READ(ECR);
-
-       /* Program energy weights for various events */
-       I915_WRITE(SDEW, 0x15040d00);
-       I915_WRITE(CSIEW0, 0x007f0000);
-       I915_WRITE(CSIEW1, 0x1e220004);
-       I915_WRITE(CSIEW2, 0x04000004);
-
-       for (i = 0; i < 5; i++)
-               I915_WRITE(PEW + (i * 4), 0);
-       for (i = 0; i < 3; i++)
-               I915_WRITE(DEW + (i * 4), 0);
-
-       /* Program P-state weights to account for frequency power adjustment */
-       for (i = 0; i < 16; i++) {
-               u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4));
-               unsigned long freq = intel_pxfreq(pxvidfreq);
-               unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >>
-                       PXVFREQ_PX_SHIFT;
-               unsigned long val;
-
-               val = vid * vid;
-               val *= (freq / 1000);
-               val *= 255;
-               val /= (127*127*900);
-               if (val > 0xff)
-                       DRM_ERROR("bad pxval: %ld\n", val);
-               pxw[i] = val;
-       }
-       /* Render standby states get 0 weight */
-       pxw[14] = 0;
-       pxw[15] = 0;
-
-       for (i = 0; i < 4; i++) {
-               u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) |
-                       (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]);
-               I915_WRITE(PXW + (i * 4), val);
-       }
-
-       /* Adjust magic regs to magic values (more experimental results) */
-       I915_WRITE(OGW0, 0);
-       I915_WRITE(OGW1, 0);
-       I915_WRITE(EG0, 0x00007f00);
-       I915_WRITE(EG1, 0x0000000e);
-       I915_WRITE(EG2, 0x000e0000);
-       I915_WRITE(EG3, 0x68000300);
-       I915_WRITE(EG4, 0x42000000);
-       I915_WRITE(EG5, 0x00140031);
-       I915_WRITE(EG6, 0);
-       I915_WRITE(EG7, 0);
+       struct drm_device *dev = crtc->dev;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       for (i = 0; i < 8; i++)
-               I915_WRITE(PXWL + (i * 4), 0);
+       /* Reset flags back to the 'unknown' status so that they
+        * will be correctly set on the initial modeset.
+        */
+       intel_crtc->dpms_mode = -1;
 
-       /* Enable PMON + select events */
-       I915_WRITE(ECR, 0x80000019);
+       /* We need to fix up any BIOS configuration that conflicts with
+        * our expectations.
+        */
+       intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane);
+}
 
-       lcfuse = I915_READ(LCFUSE02);
+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,
+       .load_lut = intel_crtc_load_lut,
+       .disable = intel_crtc_disable,
+};
 
-       dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
-}
+static const struct drm_crtc_funcs intel_crtc_funcs = {
+       .reset = intel_crtc_reset,
+       .cursor_set = intel_crtc_cursor_set,
+       .cursor_move = intel_crtc_cursor_move,
+       .gamma_set = intel_crtc_gamma_set,
+       .set_config = drm_crtc_helper_set_config,
+       .destroy = intel_crtc_destroy,
+       .page_flip = intel_crtc_page_flip,
+};
 
-static int intel_enable_rc6(struct drm_device *dev)
+static void intel_pch_pll_init(struct drm_device *dev)
 {
-       /*
-        * Respect the kernel parameter if it is set
-        */
-       if (i915_enable_rc6 >= 0)
-               return i915_enable_rc6;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int i;
 
-       /*
-        * Disable RC6 on Ironlake
-        */
-       if (INTEL_INFO(dev)->gen == 5)
-               return 0;
+       if (dev_priv->num_pch_pll == 0) {
+               DRM_DEBUG_KMS("No PCH PLLs on this hardware, skipping initialisation\n");
+               return;
+       }
 
-       /*
-        * Disable rc6 on Sandybridge
-        */
-       if (INTEL_INFO(dev)->gen == 6) {
-               DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n");
-               return INTEL_RC6_ENABLE;
+       for (i = 0; i < dev_priv->num_pch_pll; i++) {
+               dev_priv->pch_plls[i].pll_reg = _PCH_DPLL(i);
+               dev_priv->pch_plls[i].fp0_reg = _PCH_FP0(i);
+               dev_priv->pch_plls[i].fp1_reg = _PCH_FP1(i);
        }
-       DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n");
-       return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
 }
 
-void gen6_enable_rps(struct drm_i915_private *dev_priv)
+static void intel_crtc_init(struct drm_device *dev, int pipe)
 {
-       u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
-       u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
-       u32 pcu_mbox, rc6_mask = 0;
-       u32 gtfifodbg;
-       int cur_freq, min_freq, max_freq;
-       int rc6_mode;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc;
        int i;
 
-       /* Here begins a magic sequence of register writes to enable
-        * auto-downclocking.
-        *
-        * Perhaps there might be some value in exposing these to
-        * userspace...
-        */
-       I915_WRITE(GEN6_RC_STATE, 0);
-       mutex_lock(&dev_priv->dev->struct_mutex);
-
-       /* Clear the DBG now so we don't confuse earlier errors */
-       if ((gtfifodbg = I915_READ(GTFIFODBG))) {
-               DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg);
-               I915_WRITE(GTFIFODBG, gtfifodbg);
-       }
-
-       gen6_gt_force_wake_get(dev_priv);
-
-       /* disable the counters and set deterministic thresholds */
-       I915_WRITE(GEN6_RC_CONTROL, 0);
-
-       I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16);
-       I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30);
-       I915_WRITE(GEN6_RC6pp_WAKE_RATE_LIMIT, 30);
-       I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
-       I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25);
-
-       for (i = 0; i < I915_NUM_RINGS; i++)
-               I915_WRITE(RING_MAX_IDLE(dev_priv->ring[i].mmio_base), 10);
-
-       I915_WRITE(GEN6_RC_SLEEP, 0);
-       I915_WRITE(GEN6_RC1e_THRESHOLD, 1000);
-       I915_WRITE(GEN6_RC6_THRESHOLD, 50000);
-       I915_WRITE(GEN6_RC6p_THRESHOLD, 100000);
-       I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
-
-       rc6_mode = intel_enable_rc6(dev_priv->dev);
-       if (rc6_mode & INTEL_RC6_ENABLE)
-               rc6_mask |= GEN6_RC_CTL_RC6_ENABLE;
-
-       if (rc6_mode & INTEL_RC6p_ENABLE)
-               rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE;
-
-       if (rc6_mode & INTEL_RC6pp_ENABLE)
-               rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE;
-
-       DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n",
-                       (rc6_mode & INTEL_RC6_ENABLE) ? "on" : "off",
-                       (rc6_mode & INTEL_RC6p_ENABLE) ? "on" : "off",
-                       (rc6_mode & INTEL_RC6pp_ENABLE) ? "on" : "off");
-
-       I915_WRITE(GEN6_RC_CONTROL,
-                  rc6_mask |
-                  GEN6_RC_CTL_EI_MODE(1) |
-                  GEN6_RC_CTL_HW_ENABLE);
-
-       I915_WRITE(GEN6_RPNSWREQ,
-                  GEN6_FREQUENCY(10) |
-                  GEN6_OFFSET(0) |
-                  GEN6_AGGRESSIVE_TURBO);
-       I915_WRITE(GEN6_RC_VIDEO_FREQ,
-                  GEN6_FREQUENCY(12));
-
-       I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
-       I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
-                  18 << 24 |
-                  6 << 16);
-       I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000);
-       I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000);
-       I915_WRITE(GEN6_RP_UP_EI, 100000);
-       I915_WRITE(GEN6_RP_DOWN_EI, 5000000);
-       I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
-       I915_WRITE(GEN6_RP_CONTROL,
-                  GEN6_RP_MEDIA_TURBO |
-                  GEN6_RP_MEDIA_HW_MODE |
-                  GEN6_RP_MEDIA_IS_GFX |
-                  GEN6_RP_ENABLE |
-                  GEN6_RP_UP_BUSY_AVG |
-                  GEN6_RP_DOWN_IDLE_CONT);
-
-       if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
-                    500))
-               DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
-
-       I915_WRITE(GEN6_PCODE_DATA, 0);
-       I915_WRITE(GEN6_PCODE_MAILBOX,
-                  GEN6_PCODE_READY |
-                  GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
-       if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
-                    500))
-               DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
-
-       min_freq = (rp_state_cap & 0xff0000) >> 16;
-       max_freq = rp_state_cap & 0xff;
-       cur_freq = (gt_perf_status & 0xff00) >> 8;
-
-       /* Check for overclock support */
-       if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
-                    500))
-               DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
-       I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS);
-       pcu_mbox = I915_READ(GEN6_PCODE_DATA);
-       if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
-                    500))
-               DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
-       if (pcu_mbox & (1<<31)) { /* OC supported */
-               max_freq = pcu_mbox & 0xff;
-               DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
-       }
-
-       /* In units of 100MHz */
-       dev_priv->max_delay = max_freq;
-       dev_priv->min_delay = min_freq;
-       dev_priv->cur_delay = cur_freq;
-
-       /* requires MSI enabled */
-       I915_WRITE(GEN6_PMIER,
-                  GEN6_PM_MBOX_EVENT |
-                  GEN6_PM_THERMAL_EVENT |
-                  GEN6_PM_RP_DOWN_TIMEOUT |
-                  GEN6_PM_RP_UP_THRESHOLD |
-                  GEN6_PM_RP_DOWN_THRESHOLD |
-                  GEN6_PM_RP_UP_EI_EXPIRED |
-                  GEN6_PM_RP_DOWN_EI_EXPIRED);
-       spin_lock_irq(&dev_priv->rps_lock);
-       WARN_ON(dev_priv->pm_iir != 0);
-       I915_WRITE(GEN6_PMIMR, 0);
-       spin_unlock_irq(&dev_priv->rps_lock);
-       /* enable all PM interrupts */
-       I915_WRITE(GEN6_PMINTRMSK, 0);
-
-       gen6_gt_force_wake_put(dev_priv);
-       mutex_unlock(&dev_priv->dev->struct_mutex);
-}
-
-void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
-{
-       int min_freq = 15;
-       int gpu_freq, ia_freq, max_ia_freq;
-       int scaling_factor = 180;
-
-       max_ia_freq = cpufreq_quick_get_max(0);
-       /*
-        * Default to measured freq if none found, PCU will ensure we don't go
-        * over
-        */
-       if (!max_ia_freq)
-               max_ia_freq = tsc_khz;
-
-       /* Convert from kHz to MHz */
-       max_ia_freq /= 1000;
-
-       mutex_lock(&dev_priv->dev->struct_mutex);
+       intel_crtc = kzalloc(sizeof(struct intel_crtc) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
+       if (intel_crtc == NULL)
+               return;
 
-       /*
-        * For each potential GPU frequency, load a ring frequency we'd like
-        * to use for memory access.  We do this by specifying the IA frequency
-        * the PCU should use as a reference to determine the ring frequency.
-        */
-       for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay;
-            gpu_freq--) {
-               int diff = dev_priv->max_delay - gpu_freq;
+       drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
 
-               /*
-                * For GPU frequencies less than 750MHz, just use the lowest
-                * ring freq.
-                */
-               if (gpu_freq < min_freq)
-                       ia_freq = 800;
-               else
-                       ia_freq = max_ia_freq - ((diff * scaling_factor) / 2);
-               ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
-
-               I915_WRITE(GEN6_PCODE_DATA,
-                          (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) |
-                          gpu_freq);
-               I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
-                          GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
-               if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
-                             GEN6_PCODE_READY) == 0, 10)) {
-                       DRM_ERROR("pcode write of freq table timed out\n");
-                       continue;
-               }
+       drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
+       for (i = 0; i < 256; i++) {
+               intel_crtc->lut_r[i] = i;
+               intel_crtc->lut_g[i] = i;
+               intel_crtc->lut_b[i] = i;
        }
 
-       mutex_unlock(&dev_priv->dev->struct_mutex);
-}
-
-static void ironlake_init_clock_gating(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+       /* Swap pipes & planes for FBC on pre-965 */
+       intel_crtc->pipe = pipe;
+       intel_crtc->plane = pipe;
+       if (IS_MOBILE(dev) && IS_GEN3(dev)) {
+               DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
+               intel_crtc->plane = !pipe;
+       }
 
-       /* Required for FBC */
-       dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE |
-               DPFCRUNIT_CLOCK_GATE_DISABLE |
-               DPFDUNIT_CLOCK_GATE_DISABLE;
-       /* Required for CxSR */
-       dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
+       BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
+              dev_priv->plane_to_crtc_mapping[intel_crtc->plane] != NULL);
+       dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
+       dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
 
-       I915_WRITE(PCH_3DCGDIS0,
-                  MARIUNIT_CLOCK_GATE_DISABLE |
-                  SVSMUNIT_CLOCK_GATE_DISABLE);
-       I915_WRITE(PCH_3DCGDIS1,
-                  VFMUNIT_CLOCK_GATE_DISABLE);
+       intel_crtc_reset(&intel_crtc->base);
+       intel_crtc->active = true; /* force the pipe off on setup_init_config */
+       intel_crtc->bpp = 24; /* default for pre-Ironlake */
 
-       I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+       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;
+       }
 
-       /*
-        * According to the spec the following bits should be set in
-        * order to enable memory self-refresh
-        * The bit 22/21 of 0x42004
-        * The bit 5 of 0x42020
-        * The bit 15 of 0x45000
-        */
-       I915_WRITE(ILK_DISPLAY_CHICKEN2,
-                  (I915_READ(ILK_DISPLAY_CHICKEN2) |
-                   ILK_DPARB_GATE | ILK_VSDPFD_FULL));
-       I915_WRITE(ILK_DSPCLK_GATE,
-                  (I915_READ(ILK_DSPCLK_GATE) |
-                   ILK_DPARB_CLK_GATE));
-       I915_WRITE(DISP_ARB_CTL,
-                  (I915_READ(DISP_ARB_CTL) |
-                   DISP_FBC_WM_DIS));
-       I915_WRITE(WM3_LP_ILK, 0);
-       I915_WRITE(WM2_LP_ILK, 0);
-       I915_WRITE(WM1_LP_ILK, 0);
+       drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
 
-       /*
-        * 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);
-       }
+       intel_crtc->busy = false;
 
-       I915_WRITE(ILK_DISPLAY_CHICKEN2,
-                  I915_READ(ILK_DISPLAY_CHICKEN2) |
-                  ILK_ELPIN_409_SELECT);
-       I915_WRITE(_3D_CHICKEN2,
-                  _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
-                  _3D_CHICKEN2_WM_READ_PIPELINED);
+       setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
+                   (unsigned long)intel_crtc);
 }
 
-static void gen6_init_clock_gating(struct drm_device *dev)
+int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
+                               struct drm_file *file)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int pipe;
-       uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+       struct drm_i915_get_pipe_from_crtc_id *pipe_from_crtc_id = data;
+       struct drm_mode_object *drmmode_obj;
+       struct intel_crtc *crtc;
 
-       I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -ENODEV;
 
-       I915_WRITE(ILK_DISPLAY_CHICKEN2,
-                  I915_READ(ILK_DISPLAY_CHICKEN2) |
-                  ILK_ELPIN_409_SELECT);
+       drmmode_obj = drm_mode_object_find(dev, pipe_from_crtc_id->crtc_id,
+                       DRM_MODE_OBJECT_CRTC);
 
-       I915_WRITE(WM3_LP_ILK, 0);
-       I915_WRITE(WM2_LP_ILK, 0);
-       I915_WRITE(WM1_LP_ILK, 0);
+       if (!drmmode_obj) {
+               DRM_ERROR("no such CRTC id\n");
+               return -EINVAL;
+       }
 
-       I915_WRITE(GEN6_UCGCTL1,
-                  I915_READ(GEN6_UCGCTL1) |
-                  GEN6_BLBUNIT_CLOCK_GATE_DISABLE);
+       crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
+       pipe_from_crtc_id->pipe = crtc->pipe;
 
-       /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
-        * gating disable must be set.  Failure to set it results in
-        * flickering pixels due to Z write ordering failures after
-        * some amount of runtime in the Mesa "fire" demo, and Unigine
-        * Sanctuary and Tropics, and apparently anything else with
-        * alpha test or pixel discard.
-        *
-        * According to the spec, bit 11 (RCCUNIT) must also be set,
-        * but we didn't debug actual testcases to find it out.
-        */
-       I915_WRITE(GEN6_UCGCTL2,
-                  GEN6_RCPBUNIT_CLOCK_GATE_DISABLE |
-                  GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
+       return 0;
+}
 
-       /*
-        * According to the spec the following bits should be
-        * set in order to enable memory self-refresh and fbc:
-        * The bit21 and bit22 of 0x42000
-        * The bit21 and bit22 of 0x42004
-        * The bit5 and bit7 of 0x42020
-        * The bit14 of 0x70180
-        * The bit14 of 0x71180
-        */
-       I915_WRITE(ILK_DISPLAY_CHICKEN1,
-                  I915_READ(ILK_DISPLAY_CHICKEN1) |
-                  ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
-       I915_WRITE(ILK_DISPLAY_CHICKEN2,
-                  I915_READ(ILK_DISPLAY_CHICKEN2) |
-                  ILK_DPARB_GATE | ILK_VSDPFD_FULL);
-       I915_WRITE(ILK_DSPCLK_GATE,
-                  I915_READ(ILK_DSPCLK_GATE) |
-                  ILK_DPARB_CLK_GATE  |
-                  ILK_DPFD_CLK_GATE);
+static int intel_encoder_clones(struct drm_device *dev, int type_mask)
+{
+       struct intel_encoder *encoder;
+       int index_mask = 0;
+       int entry = 0;
 
-       for_each_pipe(pipe) {
-               I915_WRITE(DSPCNTR(pipe),
-                          I915_READ(DSPCNTR(pipe)) |
-                          DISPPLANE_TRICKLE_FEED_DISABLE);
-               intel_flush_display_plane(dev_priv, pipe);
+       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 ivybridge_init_clock_gating(struct drm_device *dev)
+static bool has_edp_a(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int pipe;
-       uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
-
-       I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
 
-       I915_WRITE(WM3_LP_ILK, 0);
-       I915_WRITE(WM2_LP_ILK, 0);
-       I915_WRITE(WM1_LP_ILK, 0);
+       if (!IS_MOBILE(dev))
+               return false;
 
-       /* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
-        * This implements the WaDisableRCZUnitClockGating workaround.
-        */
-       I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
+       if ((I915_READ(DP_A) & DP_DETECTED) == 0)
+               return false;
 
-       I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);
+       if (IS_GEN5(dev) &&
+           (I915_READ(ILK_DISPLAY_CHICKEN_FUSES) & ILK_eDP_A_DISABLE))
+               return false;
 
-       I915_WRITE(IVB_CHICKEN3,
-                  CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
-                  CHICKEN3_DGMG_DONE_FIX_DISABLE);
+       return true;
+}
 
-       /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
-       I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
-                  GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
+static void intel_setup_outputs(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_encoder *encoder;
+       bool dpd_is_edp = false;
+       bool has_lvds;
 
-       /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
-       I915_WRITE(GEN7_L3CNTLREG1,
-                       GEN7_WA_FOR_GEN7_L3_CONTROL);
-       I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER,
-                       GEN7_WA_L3_CHICKEN_MODE);
+       has_lvds = intel_lvds_init(dev);
+       if (!has_lvds && !HAS_PCH_SPLIT(dev)) {
+               /* disable the panel fitter on everything but LVDS */
+               I915_WRITE(PFIT_CONTROL, 0);
+       }
 
-       /* This is required by WaCatErrorRejectionIssue */
-       I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
-                       I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
-                       GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
+       if (HAS_PCH_SPLIT(dev)) {
+               dpd_is_edp = intel_dpd_is_edp(dev);
 
-       for_each_pipe(pipe) {
-               I915_WRITE(DSPCNTR(pipe),
-                          I915_READ(DSPCNTR(pipe)) |
-                          DISPPLANE_TRICKLE_FEED_DISABLE);
-               intel_flush_display_plane(dev_priv, pipe);
-       }
-}
+               if (has_edp_a(dev))
+                       intel_dp_init(dev, DP_A);
 
-static void g4x_init_clock_gating(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t dspclk_gate;
+               if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
+                       intel_dp_init(dev, PCH_DP_D);
+       }
 
-       I915_WRITE(RENCLK_GATE_D1, 0);
-       I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
-                  GS_UNIT_CLOCK_GATE_DISABLE |
-                  CL_UNIT_CLOCK_GATE_DISABLE);
-       I915_WRITE(RAMCLK_GATE_D, 0);
-       dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
-               OVRUNIT_CLOCK_GATE_DISABLE |
-               OVCUNIT_CLOCK_GATE_DISABLE;
-       if (IS_GM45(dev))
-               dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
-       I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
-}
+       intel_crt_init(dev);
 
-static void crestline_init_clock_gating(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       if (HAS_PCH_SPLIT(dev)) {
+               int found;
 
-       I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
-       I915_WRITE(RENCLK_GATE_D2, 0);
-       I915_WRITE(DSPCLK_GATE_D, 0);
-       I915_WRITE(RAMCLK_GATE_D, 0);
-       I915_WRITE16(DEUC, 0);
-}
+               if (I915_READ(HDMIB) & PORT_DETECTED) {
+                       /* PCH SDVOB multiplex with HDMIB */
+                       found = intel_sdvo_init(dev, PCH_SDVOB, true);
+                       if (!found)
+                               intel_hdmi_init(dev, HDMIB);
+                       if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
+                               intel_dp_init(dev, PCH_DP_B);
+               }
 
-static void broadwater_init_clock_gating(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
+               if (I915_READ(HDMIC) & PORT_DETECTED)
+                       intel_hdmi_init(dev, HDMIC);
 
-       I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
-                  I965_RCC_CLOCK_GATE_DISABLE |
-                  I965_RCPB_CLOCK_GATE_DISABLE |
-                  I965_ISC_CLOCK_GATE_DISABLE |
-                  I965_FBC_CLOCK_GATE_DISABLE);
-       I915_WRITE(RENCLK_GATE_D2, 0);
-}
+               if (I915_READ(HDMID) & PORT_DETECTED)
+                       intel_hdmi_init(dev, HDMID);
 
-static void gen3_init_clock_gating(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 dstate = I915_READ(D_STATE);
+               if (I915_READ(PCH_DP_C) & DP_DETECTED)
+                       intel_dp_init(dev, PCH_DP_C);
 
-       dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
-               DSTATE_DOT_CLOCK_GATING;
-       I915_WRITE(D_STATE, dstate);
-}
+               if (!dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
+                       intel_dp_init(dev, PCH_DP_D);
 
-static void i85x_init_clock_gating(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) {
+               bool found = false;
 
-       I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
-}
+               if (I915_READ(SDVOB) & SDVO_DETECTED) {
+                       DRM_DEBUG_KMS("probing SDVOB\n");
+                       found = intel_sdvo_init(dev, SDVOB, true);
+                       if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) {
+                               DRM_DEBUG_KMS("probing HDMI on SDVOB\n");
+                               intel_hdmi_init(dev, SDVOB);
+                       }
 
-static void i830_init_clock_gating(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
+                       if (!found && SUPPORTS_INTEGRATED_DP(dev)) {
+                               DRM_DEBUG_KMS("probing DP_B\n");
+                               intel_dp_init(dev, DP_B);
+                       }
+               }
 
-       I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
-}
+               /* Before G4X SDVOC doesn't have its own detect register */
 
-static void ibx_init_clock_gating(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
+               if (I915_READ(SDVOB) & SDVO_DETECTED) {
+                       DRM_DEBUG_KMS("probing SDVOC\n");
+                       found = intel_sdvo_init(dev, SDVOC, false);
+               }
 
-       /*
-        * On Ibex Peak and Cougar Point, we need to disable clock
-        * gating for the panel power sequencer or it will fail to
-        * start up when no ports are active.
-        */
-       I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
-}
+               if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) {
 
-static void cpt_init_clock_gating(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int pipe;
+                       if (SUPPORTS_INTEGRATED_HDMI(dev)) {
+                               DRM_DEBUG_KMS("probing HDMI on SDVOC\n");
+                               intel_hdmi_init(dev, SDVOC);
+                       }
+                       if (SUPPORTS_INTEGRATED_DP(dev)) {
+                               DRM_DEBUG_KMS("probing DP_C\n");
+                               intel_dp_init(dev, DP_C);
+                       }
+               }
 
-       /*
-        * On Ibex Peak and Cougar Point, we need to disable clock
-        * gating for the panel power sequencer or it will fail to
-        * start up when no ports are active.
-        */
-       I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
-       I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) |
-                  DPLS_EDP_PPS_FIX_DIS);
-       /* Without this, mode sets may fail silently on FDI */
-       for_each_pipe(pipe)
-               I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS);
-}
+               if (SUPPORTS_INTEGRATED_DP(dev) &&
+                   (I915_READ(DP_D) & DP_DETECTED)) {
+                       DRM_DEBUG_KMS("probing DP_D\n");
+                       intel_dp_init(dev, DP_D);
+               }
+       } else if (IS_GEN2(dev))
+               intel_dvo_init(dev);
 
-static void ironlake_teardown_rc6(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       if (SUPPORTS_TV(dev))
+               intel_tv_init(dev);
 
-       if (dev_priv->renderctx) {
-               i915_gem_object_unpin(dev_priv->renderctx);
-               drm_gem_object_unreference(&dev_priv->renderctx->base);
-               dev_priv->renderctx = NULL;
+       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);
        }
 
-       if (dev_priv->pwrctx) {
-               i915_gem_object_unpin(dev_priv->pwrctx);
-               drm_gem_object_unreference(&dev_priv->pwrctx->base);
-               dev_priv->pwrctx = NULL;
-       }
+       /* disable all the possible outputs/crtcs before entering KMS mode */
+       drm_helper_disable_unused_functions(dev);
+
+       if (HAS_PCH_SPLIT(dev))
+               ironlake_init_pch_refclk(dev);
 }
 
-static void ironlake_disable_rc6(struct drm_device *dev)
+static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (I915_READ(PWRCTXA)) {
-               /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
-               I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
-               wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
-                        50);
-
-               I915_WRITE(PWRCTXA, 0);
-               POSTING_READ(PWRCTXA);
+       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 
-               I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
-               POSTING_READ(RSTDBYCTL);
-       }
+       drm_framebuffer_cleanup(fb);
+       drm_gem_object_unreference_unlocked(&intel_fb->obj->base);
 
-       ironlake_teardown_rc6(dev);
+       kfree(intel_fb);
 }
 
-static int ironlake_setup_rc6(struct drm_device *dev)
+static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb,
+                                               struct drm_file *file,
+                                               unsigned int *handle)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->renderctx == NULL)
-               dev_priv->renderctx = intel_alloc_context_page(dev);
-       if (!dev_priv->renderctx)
-               return -ENOMEM;
-
-       if (dev_priv->pwrctx == NULL)
-               dev_priv->pwrctx = intel_alloc_context_page(dev);
-       if (!dev_priv->pwrctx) {
-               ironlake_teardown_rc6(dev);
-               return -ENOMEM;
-       }
+       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+       struct drm_i915_gem_object *obj = intel_fb->obj;
 
-       return 0;
+       return drm_gem_handle_create(file, &obj->base, handle);
 }
 
-void ironlake_enable_rc6(struct drm_device *dev)
+static const struct drm_framebuffer_funcs intel_fb_funcs = {
+       .destroy = intel_user_framebuffer_destroy,
+       .create_handle = intel_user_framebuffer_create_handle,
+};
+
+int intel_framebuffer_init(struct drm_device *dev,
+                          struct intel_framebuffer *intel_fb,
+                          struct drm_mode_fb_cmd2 *mode_cmd,
+                          struct drm_i915_gem_object *obj)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
-       /* rc6 disabled by default due to repeated reports of hanging during
-        * boot and resume.
-        */
-       if (!intel_enable_rc6(dev))
-               return;
+       if (obj->tiling_mode == I915_TILING_Y)
+               return -EINVAL;
 
-       mutex_lock(&dev->struct_mutex);
-       ret = ironlake_setup_rc6(dev);
-       if (ret) {
-               mutex_unlock(&dev->struct_mutex);
-               return;
-       }
+       if (mode_cmd->pitches[0] & 63)
+               return -EINVAL;
 
-       /*
-        * GPU can automatically power down the render unit if given a page
-        * to save state.
-        */
-       ret = BEGIN_LP_RING(6);
-       if (ret) {
-               ironlake_teardown_rc6(dev);
-               mutex_unlock(&dev->struct_mutex);
-               return;
+       switch (mode_cmd->pixel_format) {
+       case DRM_FORMAT_RGB332:
+       case DRM_FORMAT_RGB565:
+       case DRM_FORMAT_XRGB8888:
+       case DRM_FORMAT_XBGR8888:
+       case DRM_FORMAT_ARGB8888:
+       case DRM_FORMAT_XRGB2101010:
+       case DRM_FORMAT_ARGB2101010:
+               /* RGB formats are common across chipsets */
+               break;
+       case DRM_FORMAT_YUYV:
+       case DRM_FORMAT_UYVY:
+       case DRM_FORMAT_YVYU:
+       case DRM_FORMAT_VYUY:
+               break;
+       default:
+               DRM_DEBUG_KMS("unsupported pixel format %u\n",
+                               mode_cmd->pixel_format);
+               return -EINVAL;
        }
 
-       OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
-       OUT_RING(MI_SET_CONTEXT);
-       OUT_RING(dev_priv->renderctx->gtt_offset |
-                MI_MM_SPACE_GTT |
-                MI_SAVE_EXT_STATE_EN |
-                MI_RESTORE_EXT_STATE_EN |
-                MI_RESTORE_INHIBIT);
-       OUT_RING(MI_SUSPEND_FLUSH);
-       OUT_RING(MI_NOOP);
-       OUT_RING(MI_FLUSH);
-       ADVANCE_LP_RING();
-
-       /*
-        * Wait for the command parser to advance past MI_SET_CONTEXT. The HW
-        * does an implicit flush, combined with MI_FLUSH above, it should be
-        * safe to assume that renderctx is valid
-        */
-       ret = intel_wait_ring_idle(LP_RING(dev_priv));
+       ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
        if (ret) {
-               DRM_ERROR("failed to enable ironlake power power savings\n");
-               ironlake_teardown_rc6(dev);
-               mutex_unlock(&dev->struct_mutex);
-               return;
+               DRM_ERROR("framebuffer init failed %d\n", ret);
+               return ret;
        }
 
-       I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN);
-       I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
-       mutex_unlock(&dev->struct_mutex);
+       drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
+       intel_fb->obj = obj;
+       return 0;
 }
 
-void intel_init_clock_gating(struct drm_device *dev)
+static struct drm_framebuffer *
+intel_user_framebuffer_create(struct drm_device *dev,
+                             struct drm_file *filp,
+                             struct drm_mode_fb_cmd2 *mode_cmd)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj;
 
-       dev_priv->display.init_clock_gating(dev);
+       obj = to_intel_bo(drm_gem_object_lookup(dev, filp,
+                                               mode_cmd->handles[0]));
+       if (&obj->base == NULL)
+               return ERR_PTR(-ENOENT);
 
-       if (dev_priv->display.init_pch_clock_gating)
-               dev_priv->display.init_pch_clock_gating(dev);
+       return intel_framebuffer_create(dev, mode_cmd, obj);
 }
 
+static const struct drm_mode_config_funcs intel_mode_funcs = {
+       .fb_create = intel_user_framebuffer_create,
+       .output_poll_changed = intel_fb_output_poll_changed,
+};
+
 /* Set up chip specific display functions */
 static void intel_init_display(struct drm_device *dev)
 {
@@ -8877,32 +6454,20 @@ static void intel_init_display(struct drm_device *dev)
        if (HAS_PCH_SPLIT(dev)) {
                dev_priv->display.dpms = ironlake_crtc_dpms;
                dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
+               dev_priv->display.off = ironlake_crtc_off;
                dev_priv->display.update_plane = ironlake_update_plane;
        } else {
                dev_priv->display.dpms = i9xx_crtc_dpms;
                dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
+               dev_priv->display.off = i9xx_crtc_off;
                dev_priv->display.update_plane = i9xx_update_plane;
        }
 
-       if (I915_HAS_FBC(dev)) {
-               if (HAS_PCH_SPLIT(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;
-               } else if (IS_CRESTLINE(dev)) {
-                       dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
-                       dev_priv->display.enable_fbc = i8xx_enable_fbc;
-                       dev_priv->display.disable_fbc = i8xx_disable_fbc;
-               }
-               /* 855GM needs testing */
-       }
-
        /* Returns the core display clock speed */
-       if (IS_I945G(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev)))
+       if (IS_VALLEYVIEW(dev))
+               dev_priv->display.get_display_clock_speed =
+                       valleyview_get_display_clock_speed;
+       else if (IS_I945G(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev)))
                dev_priv->display.get_display_clock_speed =
                        i945_get_display_clock_speed;
        else if (IS_I915G(dev))
@@ -8924,124 +6489,24 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.get_display_clock_speed =
                        i830_get_display_clock_speed;
 
-       /* For FIFO watermark updates */
        if (HAS_PCH_SPLIT(dev)) {
-               dev_priv->display.force_wake_get = __gen6_gt_force_wake_get;
-               dev_priv->display.force_wake_put = __gen6_gt_force_wake_put;
-
-               /* IVB configs may use multi-threaded forcewake */
-               if (IS_IVYBRIDGE(dev)) {
-                       u32     ecobus;
-
-                       /* A small trick here - if the bios hasn't configured MT forcewake,
-                        * and if the device is in RC6, then force_wake_mt_get will not wake
-                        * the device and the ECOBUS read will return zero. Which will be
-                        * (correctly) interpreted by the test below as MT forcewake being
-                        * disabled.
-                        */
-                       mutex_lock(&dev->struct_mutex);
-                       __gen6_gt_force_wake_mt_get(dev_priv);
-                       ecobus = I915_READ_NOTRACE(ECOBUS);
-                       __gen6_gt_force_wake_mt_put(dev_priv);
-                       mutex_unlock(&dev->struct_mutex);
-
-                       if (ecobus & FORCEWAKE_MT_ENABLE) {
-                               DRM_DEBUG_KMS("Using MT version of forcewake\n");
-                               dev_priv->display.force_wake_get =
-                                       __gen6_gt_force_wake_mt_get;
-                               dev_priv->display.force_wake_put =
-                                       __gen6_gt_force_wake_mt_put;
-                       }
-               }
-
-               if (HAS_PCH_IBX(dev))
-                       dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating;
-               else if (HAS_PCH_CPT(dev))
-                       dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating;
-
                if (IS_GEN5(dev)) {
-                       if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
-                               dev_priv->display.update_wm = ironlake_update_wm;
-                       else {
-                               DRM_DEBUG_KMS("Failed to get proper latency. "
-                                             "Disable CxSR\n");
-                               dev_priv->display.update_wm = NULL;
-                       }
                        dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
-                       dev_priv->display.init_clock_gating = ironlake_init_clock_gating;
                        dev_priv->display.write_eld = ironlake_write_eld;
                } else if (IS_GEN6(dev)) {
-                       if (SNB_READ_WM0_LATENCY()) {
-                               dev_priv->display.update_wm = sandybridge_update_wm;
-                               dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
-                       } else {
-                               DRM_DEBUG_KMS("Failed to read display plane latency. "
-                                             "Disable CxSR\n");
-                               dev_priv->display.update_wm = NULL;
-                       }
                        dev_priv->display.fdi_link_train = gen6_fdi_link_train;
-                       dev_priv->display.init_clock_gating = gen6_init_clock_gating;
                        dev_priv->display.write_eld = ironlake_write_eld;
                } else if (IS_IVYBRIDGE(dev)) {
                        /* FIXME: detect B0+ stepping and use auto training */
                        dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
-                       if (SNB_READ_WM0_LATENCY()) {
-                               dev_priv->display.update_wm = sandybridge_update_wm;
-                               dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
-                       } else {
-                               DRM_DEBUG_KMS("Failed to read display plane latency. "
-                                             "Disable CxSR\n");
-                               dev_priv->display.update_wm = NULL;
-                       }
-                       dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
                        dev_priv->display.write_eld = ironlake_write_eld;
                } else
                        dev_priv->display.update_wm = NULL;
-       } else if (IS_PINEVIEW(dev)) {
-               if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev),
-                                           dev_priv->is_ddr3,
-                                           dev_priv->fsb_freq,
-                                           dev_priv->mem_freq)) {
-                       DRM_INFO("failed to find known CxSR latency "
-                                "(found ddr%s fsb freq %d, mem freq %d), "
-                                "disabling CxSR\n",
-                                (dev_priv->is_ddr3 == 1) ? "3" : "2",
-                                dev_priv->fsb_freq, dev_priv->mem_freq);
-                       /* Disable CxSR and never update its watermark again */
-                       pineview_disable_cxsr(dev);
-                       dev_priv->display.update_wm = NULL;
-               } else
-                       dev_priv->display.update_wm = pineview_update_wm;
-               dev_priv->display.init_clock_gating = gen3_init_clock_gating;
+       } else if (IS_VALLEYVIEW(dev)) {
+               dev_priv->display.force_wake_get = vlv_force_wake_get;
+               dev_priv->display.force_wake_put = vlv_force_wake_put;
        } else if (IS_G4X(dev)) {
                dev_priv->display.write_eld = g4x_write_eld;
-               dev_priv->display.update_wm = g4x_update_wm;
-               dev_priv->display.init_clock_gating = g4x_init_clock_gating;
-       } else if (IS_GEN4(dev)) {
-               dev_priv->display.update_wm = i965_update_wm;
-               if (IS_CRESTLINE(dev))
-                       dev_priv->display.init_clock_gating = crestline_init_clock_gating;
-               else if (IS_BROADWATER(dev))
-                       dev_priv->display.init_clock_gating = broadwater_init_clock_gating;
-       } else if (IS_GEN3(dev)) {
-               dev_priv->display.update_wm = i9xx_update_wm;
-               dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
-               dev_priv->display.init_clock_gating = gen3_init_clock_gating;
-       } else if (IS_I865G(dev)) {
-               dev_priv->display.update_wm = i830_update_wm;
-               dev_priv->display.init_clock_gating = i85x_init_clock_gating;
-               dev_priv->display.get_fifo_size = i830_get_fifo_size;
-       } else if (IS_I85X(dev)) {
-               dev_priv->display.update_wm = i9xx_update_wm;
-               dev_priv->display.get_fifo_size = i85x_get_fifo_size;
-               dev_priv->display.init_clock_gating = i85x_init_clock_gating;
-       } else {
-               dev_priv->display.update_wm = i830_update_wm;
-               dev_priv->display.init_clock_gating = i830_init_clock_gating;
-               if (IS_845G(dev))
-                       dev_priv->display.get_fifo_size = i845_get_fifo_size;
-               else
-                       dev_priv->display.get_fifo_size = i830_get_fifo_size;
        }
 
        /* Default just returns -ENODEV to indicate unsupported */
@@ -9080,7 +6545,7 @@ static void quirk_pipea_force(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        dev_priv->quirks |= QUIRK_PIPEA_FORCE;
-       DRM_DEBUG_DRIVER("applying pipe a force quirk\n");
+       DRM_INFO("applying pipe a force quirk\n");
 }
 
 /*
@@ -9090,6 +6555,18 @@ static void quirk_ssc_force_disable(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        dev_priv->quirks |= QUIRK_LVDS_SSC_DISABLE;
+       DRM_INFO("applying lvds SSC disable quirk\n");
+}
+
+/*
+ * A machine (e.g. Acer Aspire 5734Z) may need to invert the panel backlight
+ * brightness value
+ */
+static void quirk_invert_brightness(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       dev_priv->quirks |= QUIRK_INVERT_BRIGHTNESS;
+       DRM_INFO("applying inverted panel brightness quirk\n");
 }
 
 struct intel_quirk {
@@ -9099,7 +6576,7 @@ struct intel_quirk {
        void (*hook)(struct drm_device *dev);
 };
 
-struct intel_quirk intel_quirks[] = {
+static struct intel_quirk intel_quirks[] = {
        /* HP Mini needs pipe A force quirk (LP: #322104) */
        { 0x27ae, 0x103c, 0x361a, quirk_pipea_force },
 
@@ -9124,6 +6601,9 @@ struct intel_quirk intel_quirks[] = {
 
        /* Sony Vaio Y cannot use SSC on LVDS */
        { 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable },
+
+       /* Acer Aspire 5734Z must invert backlight brightness */
+       { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness },
 };
 
 static void intel_init_quirks(struct drm_device *dev)
@@ -9156,7 +6636,7 @@ static void i915_disable_vga(struct drm_device *dev)
                vga_reg = VGACNTRL;
 
        vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
-       outb(1, VGA_SR_INDEX);
+       outb(SR01, VGA_SR_INDEX);
        sr1 = inb(VGA_SR_DATA);
        outb(sr1 | 1<<5, VGA_SR_DATA);
        vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
@@ -9166,6 +6646,39 @@ static void i915_disable_vga(struct drm_device *dev)
        POSTING_READ(vga_reg);
 }
 
+static void ivb_pch_pwm_override(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /*
+        * IVB has CPU eDP backlight regs too, set things up to let the
+        * PCH regs control the backlight
+        */
+       I915_WRITE(BLC_PWM_CPU_CTL2, PWM_ENABLE);
+       I915_WRITE(BLC_PWM_CPU_CTL, 0);
+       I915_WRITE(BLC_PWM_PCH_CTL1, PWM_ENABLE | (1<<30));
+}
+
+void intel_modeset_init_hw(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       intel_init_clock_gating(dev);
+
+       if (IS_IRONLAKE_M(dev)) {
+               ironlake_enable_drps(dev);
+               intel_init_emon(dev);
+       }
+
+       if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) {
+               gen6_enable_rps(dev_priv);
+               gen6_update_ring_freq(dev_priv);
+       }
+
+       if (IS_IVYBRIDGE(dev))
+               ivb_pch_pwm_override(dev);
+}
+
 void intel_modeset_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -9183,6 +6696,8 @@ void intel_modeset_init(struct drm_device *dev)
 
        intel_init_quirks(dev);
 
+       intel_init_pm(dev);
+
        intel_init_display(dev);
 
        if (IS_GEN2(dev)) {
@@ -9207,21 +6722,13 @@ void intel_modeset_init(struct drm_device *dev)
                        DRM_DEBUG_KMS("plane %d init failed: %d\n", i, ret);
        }
 
+       intel_pch_pll_init(dev);
+
        /* Just disable it once at startup */
        i915_disable_vga(dev);
        intel_setup_outputs(dev);
 
-       intel_init_clock_gating(dev);
-
-       if (IS_IRONLAKE_M(dev)) {
-               ironlake_enable_drps(dev);
-               intel_init_emon(dev);
-       }
-
-       if (IS_GEN6(dev) || IS_GEN7(dev)) {
-               gen6_enable_rps(dev_priv);
-               gen6_update_ring_freq(dev_priv);
-       }
+       intel_modeset_init_hw(dev);
 
        INIT_WORK(&dev_priv->idle_work, intel_idle_update);
        setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
@@ -9261,12 +6768,15 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        if (IS_IRONLAKE_M(dev))
                ironlake_disable_drps(dev);
-       if (IS_GEN6(dev) || IS_GEN7(dev))
+       if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev))
                gen6_disable_rps(dev);
 
        if (IS_IRONLAKE_M(dev))
                ironlake_disable_rc6(dev);
 
+       if (IS_VALLEYVIEW(dev))
+               vlv_init_dpio(dev);
+
        mutex_unlock(&dev->struct_mutex);
 
        /* Disable the irq before mode object teardown, for the irq might