Merge commit 'Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux'
[linux.git] / drivers / gpu / drm / i915 / intel_display.c
index 5fb305840db89ecd80b5cd42b69ff9c35dd9432b..baaefd70cc67c814226e5879c9b427af07bc67ea 100644 (file)
@@ -45,6 +45,11 @@ bool intel_pipe_has_type(struct drm_crtc *crtc, int type);
 static void intel_increase_pllclock(struct drm_crtc *crtc);
 static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
 
+static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
+                               struct intel_crtc_config *pipe_config);
+static void ironlake_crtc_clock_get(struct intel_crtc *crtc,
+                                   struct intel_crtc_config *pipe_config);
+
 typedef struct {
        int     min, max;
 } intel_range_t;
@@ -84,7 +89,7 @@ intel_fdi_link_freq(struct drm_device *dev)
                return 27;
 }
 
-static const intel_limit_t intel_limits_i8xx_dvo = {
+static const intel_limit_t intel_limits_i8xx_dac = {
        .dot = { .min = 25000, .max = 350000 },
        .vco = { .min = 930000, .max = 1400000 },
        .n = { .min = 3, .max = 16 },
@@ -97,6 +102,19 @@ static const intel_limit_t intel_limits_i8xx_dvo = {
                .p2_slow = 4, .p2_fast = 2 },
 };
 
+static const intel_limit_t intel_limits_i8xx_dvo = {
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 930000, .max = 1400000 },
+       .n = { .min = 3, .max = 16 },
+       .m = { .min = 96, .max = 140 },
+       .m1 = { .min = 18, .max = 26 },
+       .m2 = { .min = 6, .max = 16 },
+       .p = { .min = 4, .max = 128 },
+       .p1 = { .min = 2, .max = 33 },
+       .p2 = { .dot_limit = 165000,
+               .p2_slow = 4, .p2_fast = 4 },
+};
+
 static const intel_limit_t intel_limits_i8xx_lvds = {
        .dot = { .min = 25000, .max = 350000 },
        .vco = { .min = 930000, .max = 1400000 },
@@ -405,8 +423,10 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc, int refclk)
        } else {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
                        limit = &intel_limits_i8xx_lvds;
-               else
+               else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DVO))
                        limit = &intel_limits_i8xx_dvo;
+               else
+                       limit = &intel_limits_i8xx_dac;
        }
        return limit;
 }
@@ -892,8 +912,8 @@ static const char *state_string(bool enabled)
 }
 
 /* Only for pre-ILK configs */
-static void assert_pll(struct drm_i915_private *dev_priv,
-                      enum pipe pipe, bool state)
+void assert_pll(struct drm_i915_private *dev_priv,
+               enum pipe pipe, bool state)
 {
        int reg;
        u32 val;
@@ -906,10 +926,8 @@ static void assert_pll(struct drm_i915_private *dev_priv,
             "PLL state assertion failure (expected %s, current %s)\n",
             state_string(state), state_string(cur_state));
 }
-#define assert_pll_enabled(d, p) assert_pll(d, p, true)
-#define assert_pll_disabled(d, p) assert_pll(d, p, false)
 
-static struct intel_shared_dpll *
+struct intel_shared_dpll *
 intel_crtc_to_shared_dpll(struct intel_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
@@ -921,9 +939,9 @@ intel_crtc_to_shared_dpll(struct intel_crtc *crtc)
 }
 
 /* For ILK+ */
-static void assert_shared_dpll(struct drm_i915_private *dev_priv,
-                              struct intel_shared_dpll *pll,
-                              bool state)
+void assert_shared_dpll(struct drm_i915_private *dev_priv,
+                       struct intel_shared_dpll *pll,
+                       bool state)
 {
        bool cur_state;
        struct intel_dpll_hw_state hw_state;
@@ -942,8 +960,6 @@ static void assert_shared_dpll(struct drm_i915_private *dev_priv,
             "%s assertion failure (expected %s, current %s)\n",
             pll->name, state_string(state), state_string(cur_state));
 }
-#define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true)
-#define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false)
 
 static void assert_fdi_tx(struct drm_i915_private *dev_priv,
                          enum pipe pipe, bool state)
@@ -1007,15 +1023,19 @@ static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv,
        WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n");
 }
 
-static void assert_fdi_rx_pll_enabled(struct drm_i915_private *dev_priv,
-                                     enum pipe pipe)
+void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
+                      enum pipe pipe, bool state)
 {
        int reg;
        u32 val;
+       bool cur_state;
 
        reg = FDI_RX_CTL(pipe);
        val = I915_READ(reg);
-       WARN(!(val & FDI_RX_PLL_ENABLE), "FDI RX PLL assertion failure, should be active but is disabled\n");
+       cur_state = !!(val & FDI_RX_PLL_ENABLE);
+       WARN(cur_state != state,
+            "FDI RX PLL assertion failure (expected %s, current %s)\n",
+            state_string(state), state_string(cur_state));
 }
 
 static void assert_panel_unlocked(struct drm_i915_private *dev_priv,
@@ -1111,7 +1131,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
        }
 
        /* Need to check both planes against the pipe */
-       for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) {
+       for_each_pipe(i) {
                reg = DSPCNTR(i);
                val = I915_READ(reg);
                cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
@@ -1301,51 +1321,92 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
        assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID);
 }
 
-/**
- * intel_enable_pll - enable a PLL
- * @dev_priv: i915 private structure
- * @pipe: pipe PLL to enable
- *
- * Enable @pipe's PLL so we can start pumping pixels from a plane.  Check to
- * make sure the PLL reg is writable first though, since the panel write
- * protect mechanism may be enabled.
- *
- * Note!  This is for pre-ILK only.
- *
- * Unfortunately needed by dvo_ns2501 since the dvo depends on it running.
- */
-static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
+static void vlv_enable_pll(struct intel_crtc *crtc)
 {
-       int reg;
-       u32 val;
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int reg = DPLL(crtc->pipe);
+       u32 dpll = crtc->config.dpll_hw_state.dpll;
 
-       assert_pipe_disabled(dev_priv, pipe);
+       assert_pipe_disabled(dev_priv, crtc->pipe);
 
        /* No really, not for ILK+ */
-       BUG_ON(!IS_VALLEYVIEW(dev_priv->dev) && dev_priv->info->gen >= 5);
+       BUG_ON(!IS_VALLEYVIEW(dev_priv->dev));
 
        /* PLL is protected by panel, make sure we can write it */
        if (IS_MOBILE(dev_priv->dev) && !IS_I830(dev_priv->dev))
-               assert_panel_unlocked(dev_priv, pipe);
+               assert_panel_unlocked(dev_priv, crtc->pipe);
 
-       reg = DPLL(pipe);
-       val = I915_READ(reg);
-       val |= DPLL_VCO_ENABLE;
+       I915_WRITE(reg, dpll);
+       POSTING_READ(reg);
+       udelay(150);
+
+       if (wait_for(((I915_READ(reg) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1))
+               DRM_ERROR("DPLL %d failed to lock\n", crtc->pipe);
+
+       I915_WRITE(DPLL_MD(crtc->pipe), crtc->config.dpll_hw_state.dpll_md);
+       POSTING_READ(DPLL_MD(crtc->pipe));
 
        /* We do this three times for luck */
-       I915_WRITE(reg, val);
+       I915_WRITE(reg, dpll);
        POSTING_READ(reg);
        udelay(150); /* wait for warmup */
-       I915_WRITE(reg, val);
+       I915_WRITE(reg, dpll);
        POSTING_READ(reg);
        udelay(150); /* wait for warmup */
-       I915_WRITE(reg, val);
+       I915_WRITE(reg, dpll);
+       POSTING_READ(reg);
+       udelay(150); /* wait for warmup */
+}
+
+static void i9xx_enable_pll(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int reg = DPLL(crtc->pipe);
+       u32 dpll = crtc->config.dpll_hw_state.dpll;
+
+       assert_pipe_disabled(dev_priv, crtc->pipe);
+
+       /* No really, not for ILK+ */
+       BUG_ON(dev_priv->info->gen >= 5);
+
+       /* PLL is protected by panel, make sure we can write it */
+       if (IS_MOBILE(dev) && !IS_I830(dev))
+               assert_panel_unlocked(dev_priv, crtc->pipe);
+
+       I915_WRITE(reg, dpll);
+
+       /* Wait for the clocks to stabilize. */
+       POSTING_READ(reg);
+       udelay(150);
+
+       if (INTEL_INFO(dev)->gen >= 4) {
+               I915_WRITE(DPLL_MD(crtc->pipe),
+                          crtc->config.dpll_hw_state.dpll_md);
+       } else {
+               /* The pixel multiplier can only be updated once the
+                * DPLL is enabled and the clocks are stable.
+                *
+                * So write it again.
+                */
+               I915_WRITE(reg, dpll);
+       }
+
+       /* We do this three times for luck */
+       I915_WRITE(reg, dpll);
+       POSTING_READ(reg);
+       udelay(150); /* wait for warmup */
+       I915_WRITE(reg, dpll);
+       POSTING_READ(reg);
+       udelay(150); /* wait for warmup */
+       I915_WRITE(reg, dpll);
        POSTING_READ(reg);
        udelay(150); /* wait for warmup */
 }
 
 /**
- * intel_disable_pll - disable a PLL
+ * i9xx_disable_pll - disable a PLL
  * @dev_priv: i915 private structure
  * @pipe: pipe PLL to disable
  *
@@ -1353,11 +1414,8 @@ static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
  *
  * Note!  This is for pre-ILK only.
  */
-static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
+static void i9xx_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
 {
-       int reg;
-       u32 val;
-
        /* Don't disable pipe A or pipe A PLLs if needed */
        if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
                return;
@@ -1365,11 +1423,8 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
        /* Make sure the pipe isn't still relying on us */
        assert_pipe_disabled(dev_priv, pipe);
 
-       reg = DPLL(pipe);
-       val = I915_READ(reg);
-       val &= ~DPLL_VCO_ENABLE;
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
+       I915_WRITE(DPLL(pipe), 0);
+       POSTING_READ(DPLL(pipe));
 }
 
 void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port)
@@ -1942,16 +1997,17 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                intel_crtc->dspaddr_offset = linear_offset;
        }
 
-       DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n",
-                     obj->gtt_offset, linear_offset, x, y, fb->pitches[0]);
+       DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
+                     i915_gem_obj_ggtt_offset(obj), linear_offset, x, y,
+                     fb->pitches[0]);
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        if (INTEL_INFO(dev)->gen >= 4) {
                I915_MODIFY_DISPBASE(DSPSURF(plane),
-                                    obj->gtt_offset + intel_crtc->dspaddr_offset);
+                                    i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
                I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
                I915_WRITE(DSPLINOFF(plane), linear_offset);
        } else
-               I915_WRITE(DSPADDR(plane), obj->gtt_offset + linear_offset);
+               I915_WRITE(DSPADDR(plane), i915_gem_obj_ggtt_offset(obj) + linear_offset);
        POSTING_READ(reg);
 
        return 0;
@@ -2031,11 +2087,12 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
                                               fb->pitches[0]);
        linear_offset -= intel_crtc->dspaddr_offset;
 
-       DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n",
-                     obj->gtt_offset, linear_offset, x, y, fb->pitches[0]);
+       DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
+                     i915_gem_obj_ggtt_offset(obj), linear_offset, x, y,
+                     fb->pitches[0]);
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        I915_MODIFY_DISPBASE(DSPSURF(plane),
-                            obj->gtt_offset + intel_crtc->dspaddr_offset);
+                            i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
        if (IS_HASWELL(dev)) {
                I915_WRITE(DSPOFFSET(plane), (y << 16) | x);
        } else {
@@ -2183,6 +2240,20 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                return ret;
        }
 
+       /* Update pipe size and adjust fitter if needed */
+       if (i915_fastboot) {
+               I915_WRITE(PIPESRC(intel_crtc->pipe),
+                          ((crtc->mode.hdisplay - 1) << 16) |
+                          (crtc->mode.vdisplay - 1));
+               if (!intel_crtc->config.pch_pfit.size &&
+                   (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
+                    intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
+                       I915_WRITE(PF_CTL(intel_crtc->pipe), 0);
+                       I915_WRITE(PF_WIN_POS(intel_crtc->pipe), 0);
+                       I915_WRITE(PF_WIN_SZ(intel_crtc->pipe), 0);
+               }
+       }
+
        ret = dev_priv->display.update_plane(crtc, fb, x, y);
        if (ret) {
                intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj);
@@ -2203,6 +2274,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        }
 
        intel_update_fbc(dev);
+       intel_edp_psr_update(dev);
        mutex_unlock(&dev->struct_mutex);
 
        intel_crtc_update_sarea_pos(crtc, x, y);
@@ -2927,15 +2999,8 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
        /* For PCH output, training FDI link */
        dev_priv->display.fdi_link_train(crtc);
 
-       /* XXX: pch pll's can be enabled any time before we enable the PCH
-        * transcoder, and we actually should do this to not upset any PCH
-        * transcoder that already use the clock when we share it.
-        *
-        * Note that enable_shared_dpll tries to do the right thing, but
-        * get_shared_dpll unconditionally resets the pll - we need that to have
-        * the right LVDS enable sequence. */
-       ironlake_enable_shared_dpll(intel_crtc);
-
+       /* We need to program the right clock selection before writing the pixel
+        * mutliplier into the DPLL. */
        if (HAS_PCH_CPT(dev)) {
                u32 sel;
 
@@ -2949,6 +3014,15 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
                I915_WRITE(PCH_DPLL_SEL, temp);
        }
 
+       /* XXX: pch pll's can be enabled any time before we enable the PCH
+        * transcoder, and we actually should do this to not upset any PCH
+        * transcoder that already use the clock when we share it.
+        *
+        * Note that enable_shared_dpll tries to do the right thing, but
+        * get_shared_dpll unconditionally resets the pll - we need that to have
+        * the right LVDS enable sequence. */
+       ironlake_enable_shared_dpll(intel_crtc);
+
        /* set transcoder timing, panel must allow it */
        assert_panel_unlocked(dev_priv, pipe);
        ironlake_pch_transcoder_set_timings(intel_crtc, pipe);
@@ -3031,7 +3105,7 @@ static void intel_put_shared_dpll(struct intel_crtc *crtc)
        crtc->config.shared_dpll = DPLL_ID_PRIVATE;
 }
 
-static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, u32 dpll, u32 fp)
+static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
        struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
@@ -3045,7 +3119,7 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
 
        if (HAS_PCH_IBX(dev_priv->dev)) {
                /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
-               i = crtc->pipe;
+               i = (enum intel_dpll_id) crtc->pipe;
                pll = &dev_priv->shared_dplls[i];
 
                DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
@@ -3061,8 +3135,8 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
                if (pll->refcount == 0)
                        continue;
 
-               if (dpll == (I915_READ(PCH_DPLL(pll->id)) & 0x7fffffff) &&
-                   fp == I915_READ(PCH_FP0(pll->id))) {
+               if (memcmp(&crtc->config.dpll_hw_state, &pll->hw_state,
+                          sizeof(pll->hw_state)) == 0) {
                        DRM_DEBUG_KMS("CRTC:%d sharing existing %s (refcount %d, ative %d)\n",
                                      crtc->base.base.id,
                                      pll->name, pll->refcount, pll->active);
@@ -3096,13 +3170,7 @@ found:
                WARN_ON(pll->on);
                assert_shared_dpll_disabled(dev_priv, pll);
 
-               /* Wait for the clocks to stabilize before rewriting the regs */
-               I915_WRITE(PCH_DPLL(pll->id), dpll & ~DPLL_VCO_ENABLE);
-               POSTING_READ(PCH_DPLL(pll->id));
-               udelay(150);
-
-               I915_WRITE(PCH_FP0(pll->id), fp);
-               I915_WRITE(PCH_DPLL(pll->id), dpll & ~DPLL_VCO_ENABLE);
+               pll->mode_set(dev_priv, pll);
        }
        pll->refcount++;
 
@@ -3174,7 +3242,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
-       u32 temp;
 
        WARN_ON(!crtc->enabled);
 
@@ -3188,12 +3255,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 
        intel_update_watermarks(dev);
 
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-               temp = I915_READ(PCH_LVDS);
-               if ((temp & LVDS_PORT_EN) == 0)
-                       I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
-       }
-
+       for_each_encoder_on_crtc(dev, crtc, encoder)
+               if (encoder->pre_enable)
+                       encoder->pre_enable(encoder);
 
        if (intel_crtc->config.has_pch_encoder) {
                /* Note: FDI PLL enabling _must_ be done before we enable the
@@ -3205,10 +3269,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
                assert_fdi_rx_disabled(dev_priv, pipe);
        }
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               if (encoder->pre_enable)
-                       encoder->pre_enable(encoder);
-
        ironlake_pfit_enable(intel_crtc);
 
        /*
@@ -3389,7 +3449,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
        intel_crtc_wait_for_pending_flips(crtc);
        drm_vblank_off(dev, pipe);
 
-       if (dev_priv->cfb_plane == plane)
+       if (dev_priv->fbc.plane == plane)
                intel_disable_fbc(dev);
 
        intel_crtc_update_cursor(crtc, false);
@@ -3462,7 +3522,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
        drm_vblank_off(dev, pipe);
 
        /* FBC must be disabled before disabling the plane on HSW. */
-       if (dev_priv->cfb_plane == plane)
+       if (dev_priv->fbc.plane == plane)
                intel_disable_fbc(dev);
 
        hsw_disable_ips(intel_crtc);
@@ -3599,7 +3659,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
                if (encoder->pre_pll_enable)
                        encoder->pre_pll_enable(encoder);
 
-       intel_enable_pll(dev_priv, pipe);
+       vlv_enable_pll(intel_crtc);
 
        for_each_encoder_on_crtc(dev, crtc, encoder)
                if (encoder->pre_enable)
@@ -3640,12 +3700,12 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
        intel_crtc->active = true;
        intel_update_watermarks(dev);
 
-       intel_enable_pll(dev_priv, pipe);
-
        for_each_encoder_on_crtc(dev, crtc, encoder)
                if (encoder->pre_enable)
                        encoder->pre_enable(encoder);
 
+       i9xx_enable_pll(intel_crtc);
+
        i9xx_pfit_enable(intel_crtc);
 
        intel_crtc_load_lut(crtc);
@@ -3701,7 +3761,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
        intel_crtc_wait_for_pending_flips(crtc);
        drm_vblank_off(dev, pipe);
 
-       if (dev_priv->cfb_plane == plane)
+       if (dev_priv->fbc.plane == plane)
                intel_disable_fbc(dev);
 
        intel_crtc_dpms_overlay(intel_crtc, false);
@@ -3717,7 +3777,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
                if (encoder->post_disable)
                        encoder->post_disable(encoder);
 
-       intel_disable_pll(dev_priv, pipe);
+       i9xx_disable_pll(dev_priv, pipe);
 
        intel_crtc->active = false;
        intel_update_fbc(dev);
@@ -4266,14 +4326,17 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
        }
 
        I915_WRITE(FP0(pipe), fp);
+       crtc->config.dpll_hw_state.fp0 = fp;
 
        crtc->lowfreq_avail = false;
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
            reduced_clock && i915_powersave) {
                I915_WRITE(FP1(pipe), fp2);
+               crtc->config.dpll_hw_state.fp1 = fp2;
                crtc->lowfreq_avail = true;
        } else {
                I915_WRITE(FP1(pipe), fp);
+               crtc->config.dpll_hw_state.fp1 = fp;
        }
 }
 
@@ -4351,7 +4414,6 @@ static void vlv_update_pll(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *encoder;
        int pipe = crtc->pipe;
        u32 dpll, mdiv;
        u32 bestn, bestm1, bestm2, bestp1, bestp2;
@@ -4407,7 +4469,7 @@ static void vlv_update_pll(struct intel_crtc *crtc)
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) ||
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI))
                vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe),
-                                0x005f0021);
+                                0x009f0003);
        else
                vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe),
                                 0x00d0000f);
@@ -4440,10 +4502,6 @@ static void vlv_update_pll(struct intel_crtc *crtc)
 
        vlv_dpio_write(dev_priv, DPIO_PLL_CML(pipe), 0x87871000);
 
-       for_each_encoder_on_crtc(dev, &crtc->base, encoder)
-               if (encoder->pre_pll_enable)
-                       encoder->pre_pll_enable(encoder);
-
        /* Enable DPIO clock input */
        dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV |
                DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV;
@@ -4451,17 +4509,11 @@ static void vlv_update_pll(struct intel_crtc *crtc)
                dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
 
        dpll |= DPLL_VCO_ENABLE;
-       I915_WRITE(DPLL(pipe), dpll);
-       POSTING_READ(DPLL(pipe));
-       udelay(150);
-
-       if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1))
-               DRM_ERROR("DPLL %d failed to lock\n", pipe);
+       crtc->config.dpll_hw_state.dpll = dpll;
 
        dpll_md = (crtc->config.pixel_multiplier - 1)
                << DPLL_MD_UDI_MULTIPLIER_SHIFT;
-       I915_WRITE(DPLL_MD(pipe), dpll_md);
-       POSTING_READ(DPLL_MD(pipe));
+       crtc->config.dpll_hw_state.dpll_md = dpll_md;
 
        if (crtc->config.has_dp_encoder)
                intel_dp_set_m_n(crtc);
@@ -4475,8 +4527,6 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *encoder;
-       int pipe = crtc->pipe;
        u32 dpll;
        bool is_sdvo;
        struct dpll *clock = &crtc->config.dpll;
@@ -4499,10 +4549,10 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
        }
 
        if (is_sdvo)
-               dpll |= DPLL_DVO_HIGH_SPEED;
+               dpll |= DPLL_SDVO_HIGH_SPEED;
 
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT))
-               dpll |= DPLL_DVO_HIGH_SPEED;
+               dpll |= DPLL_SDVO_HIGH_SPEED;
 
        /* compute bitmask from p1 value */
        if (IS_PINEVIEW(dev))
@@ -4538,35 +4588,16 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
                dpll |= PLL_REF_INPUT_DREFCLK;
 
        dpll |= DPLL_VCO_ENABLE;
-       I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
-       POSTING_READ(DPLL(pipe));
-       udelay(150);
-
-       for_each_encoder_on_crtc(dev, &crtc->base, encoder)
-               if (encoder->pre_pll_enable)
-                       encoder->pre_pll_enable(encoder);
-
-       if (crtc->config.has_dp_encoder)
-               intel_dp_set_m_n(crtc);
-
-       I915_WRITE(DPLL(pipe), dpll);
-
-       /* Wait for the clocks to stabilize. */
-       POSTING_READ(DPLL(pipe));
-       udelay(150);
+       crtc->config.dpll_hw_state.dpll = dpll;
 
        if (INTEL_INFO(dev)->gen >= 4) {
                u32 dpll_md = (crtc->config.pixel_multiplier - 1)
                        << DPLL_MD_UDI_MULTIPLIER_SHIFT;
-               I915_WRITE(DPLL_MD(pipe), dpll_md);
-       } 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);
+               crtc->config.dpll_hw_state.dpll_md = dpll_md;
        }
+
+       if (crtc->config.has_dp_encoder)
+               intel_dp_set_m_n(crtc);
 }
 
 static void i8xx_update_pll(struct intel_crtc *crtc,
@@ -4575,8 +4606,6 @@ static void i8xx_update_pll(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *encoder;
-       int pipe = crtc->pipe;
        u32 dpll;
        struct dpll *clock = &crtc->config.dpll;
 
@@ -4595,6 +4624,9 @@ static void i8xx_update_pll(struct intel_crtc *crtc,
                        dpll |= PLL_P2_DIVIDE_BY_4;
        }
 
+       if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DVO))
+               dpll |= DPLL_DVO_2X_MODE;
+
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
                 intel_panel_use_ssc(dev_priv) && num_connectors < 2)
                dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
@@ -4602,26 +4634,7 @@ static void i8xx_update_pll(struct intel_crtc *crtc,
                dpll |= PLL_REF_INPUT_DREFCLK;
 
        dpll |= DPLL_VCO_ENABLE;
-       I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
-       POSTING_READ(DPLL(pipe));
-       udelay(150);
-
-       for_each_encoder_on_crtc(dev, &crtc->base, encoder)
-               if (encoder->pre_pll_enable)
-                       encoder->pre_pll_enable(encoder);
-
-       I915_WRITE(DPLL(pipe), dpll);
-
-       /* Wait for the clocks to stabilize. */
-       POSTING_READ(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(DPLL(pipe), dpll);
+       crtc->config.dpll_hw_state.dpll = dpll;
 }
 
 static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
@@ -4727,6 +4740,27 @@ static void intel_get_pipe_timings(struct intel_crtc *crtc,
        pipe_config->requested_mode.hdisplay = ((tmp >> 16) & 0xffff) + 1;
 }
 
+static void intel_crtc_mode_from_pipe_config(struct intel_crtc *intel_crtc,
+                                            struct intel_crtc_config *pipe_config)
+{
+       struct drm_crtc *crtc = &intel_crtc->base;
+
+       crtc->mode.hdisplay = pipe_config->adjusted_mode.crtc_hdisplay;
+       crtc->mode.htotal = pipe_config->adjusted_mode.crtc_htotal;
+       crtc->mode.hsync_start = pipe_config->adjusted_mode.crtc_hsync_start;
+       crtc->mode.hsync_end = pipe_config->adjusted_mode.crtc_hsync_end;
+
+       crtc->mode.vdisplay = pipe_config->adjusted_mode.crtc_vdisplay;
+       crtc->mode.vtotal = pipe_config->adjusted_mode.crtc_vtotal;
+       crtc->mode.vsync_start = pipe_config->adjusted_mode.crtc_vsync_start;
+       crtc->mode.vsync_end = pipe_config->adjusted_mode.crtc_vsync_end;
+
+       crtc->mode.flags = pipe_config->adjusted_mode.flags;
+
+       crtc->mode.clock = pipe_config->adjusted_mode.clock;
+       crtc->mode.flags |= pipe_config->adjusted_mode.flags;
+}
+
 static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
 {
        struct drm_device *dev = intel_crtc->base.dev;
@@ -4939,7 +4973,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t tmp;
 
-       pipe_config->cpu_transcoder = crtc->pipe;
+       pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
 
        tmp = I915_READ(PIPECONF(crtc->pipe));
@@ -4955,6 +4989,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
                pipe_config->pixel_multiplier =
                        ((tmp & DPLL_MD_UDI_MULTIPLIER_MASK)
                         >> DPLL_MD_UDI_MULTIPLIER_SHIFT) + 1;
+               pipe_config->dpll_hw_state.dpll_md = tmp;
        } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
                tmp = I915_READ(DPLL(crtc->pipe));
                pipe_config->pixel_multiplier =
@@ -4966,6 +5001,16 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
                 * function. */
                pipe_config->pixel_multiplier = 1;
        }
+       pipe_config->dpll_hw_state.dpll = I915_READ(DPLL(crtc->pipe));
+       if (!IS_VALLEYVIEW(dev)) {
+               pipe_config->dpll_hw_state.fp0 = I915_READ(FP0(crtc->pipe));
+               pipe_config->dpll_hw_state.fp1 = I915_READ(FP1(crtc->pipe));
+       } else {
+               /* Mask out read-only status bits. */
+               pipe_config->dpll_hw_state.dpll &= ~(DPLL_LOCK_VLV |
+                                                    DPLL_PORTC_READY_MASK |
+                                                    DPLL_PORTB_READY_MASK);
+       }
 
        return true;
 }
@@ -5119,74 +5164,37 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
        BUG_ON(val != final);
 }
 
-/* Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O. */
-static void lpt_init_pch_refclk(struct drm_device *dev)
+static void lpt_reset_fdi_mphy(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_mode_config *mode_config = &dev->mode_config;
-       struct intel_encoder *encoder;
-       bool has_vga = false;
-       bool is_sdv = false;
-       u32 tmp;
-
-       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
-               switch (encoder->type) {
-               case INTEL_OUTPUT_ANALOG:
-                       has_vga = true;
-                       break;
-               }
-       }
-
-       if (!has_vga)
-               return;
-
-       mutex_lock(&dev_priv->dpio_lock);
-
-       /* XXX: Rip out SDV support once Haswell ships for real. */
-       if (IS_HASWELL(dev) && (dev->pci_device & 0xFF00) == 0x0C00)
-               is_sdv = true;
-
-       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
-       tmp &= ~SBI_SSCCTL_DISABLE;
-       tmp |= SBI_SSCCTL_PATHALT;
-       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
-
-       udelay(24);
+       uint32_t tmp;
 
-       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
-       tmp &= ~SBI_SSCCTL_PATHALT;
-       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
+       tmp = I915_READ(SOUTH_CHICKEN2);
+       tmp |= FDI_MPHY_IOSFSB_RESET_CTL;
+       I915_WRITE(SOUTH_CHICKEN2, tmp);
 
-       if (!is_sdv) {
-               tmp = I915_READ(SOUTH_CHICKEN2);
-               tmp |= FDI_MPHY_IOSFSB_RESET_CTL;
-               I915_WRITE(SOUTH_CHICKEN2, tmp);
+       if (wait_for_atomic_us(I915_READ(SOUTH_CHICKEN2) &
+                              FDI_MPHY_IOSFSB_RESET_STATUS, 100))
+               DRM_ERROR("FDI mPHY reset assert timeout\n");
 
-               if (wait_for_atomic_us(I915_READ(SOUTH_CHICKEN2) &
-                                      FDI_MPHY_IOSFSB_RESET_STATUS, 100))
-                       DRM_ERROR("FDI mPHY reset assert timeout\n");
+       tmp = I915_READ(SOUTH_CHICKEN2);
+       tmp &= ~FDI_MPHY_IOSFSB_RESET_CTL;
+       I915_WRITE(SOUTH_CHICKEN2, tmp);
 
-               tmp = I915_READ(SOUTH_CHICKEN2);
-               tmp &= ~FDI_MPHY_IOSFSB_RESET_CTL;
-               I915_WRITE(SOUTH_CHICKEN2, tmp);
+       if (wait_for_atomic_us((I915_READ(SOUTH_CHICKEN2) &
+                               FDI_MPHY_IOSFSB_RESET_STATUS) == 0, 100))
+               DRM_ERROR("FDI mPHY reset de-assert timeout\n");
+}
 
-               if (wait_for_atomic_us((I915_READ(SOUTH_CHICKEN2) &
-                                       FDI_MPHY_IOSFSB_RESET_STATUS) == 0,
-                                      100))
-                       DRM_ERROR("FDI mPHY reset de-assert timeout\n");
-       }
+/* WaMPhyProgramming:hsw */
+static void lpt_program_fdi_mphy(struct drm_i915_private *dev_priv)
+{
+       uint32_t tmp;
 
        tmp = intel_sbi_read(dev_priv, 0x8008, SBI_MPHY);
        tmp &= ~(0xFF << 24);
        tmp |= (0x12 << 24);
        intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY);
 
-       if (is_sdv) {
-               tmp = intel_sbi_read(dev_priv, 0x800C, SBI_MPHY);
-               tmp |= 0x7FFF;
-               intel_sbi_write(dev_priv, 0x800C, tmp, SBI_MPHY);
-       }
-
        tmp = intel_sbi_read(dev_priv, 0x2008, SBI_MPHY);
        tmp |= (1 << 11);
        intel_sbi_write(dev_priv, 0x2008, tmp, SBI_MPHY);
@@ -5195,24 +5203,6 @@ static void lpt_init_pch_refclk(struct drm_device *dev)
        tmp |= (1 << 11);
        intel_sbi_write(dev_priv, 0x2108, tmp, SBI_MPHY);
 
-       if (is_sdv) {
-               tmp = intel_sbi_read(dev_priv, 0x2038, SBI_MPHY);
-               tmp |= (0x3F << 24) | (0xF << 20) | (0xF << 16);
-               intel_sbi_write(dev_priv, 0x2038, tmp, SBI_MPHY);
-
-               tmp = intel_sbi_read(dev_priv, 0x2138, SBI_MPHY);
-               tmp |= (0x3F << 24) | (0xF << 20) | (0xF << 16);
-               intel_sbi_write(dev_priv, 0x2138, tmp, SBI_MPHY);
-
-               tmp = intel_sbi_read(dev_priv, 0x203C, SBI_MPHY);
-               tmp |= (0x3F << 8);
-               intel_sbi_write(dev_priv, 0x203C, tmp, SBI_MPHY);
-
-               tmp = intel_sbi_read(dev_priv, 0x213C, SBI_MPHY);
-               tmp |= (0x3F << 8);
-               intel_sbi_write(dev_priv, 0x213C, tmp, SBI_MPHY);
-       }
-
        tmp = intel_sbi_read(dev_priv, 0x206C, SBI_MPHY);
        tmp |= (1 << 24) | (1 << 21) | (1 << 18);
        intel_sbi_write(dev_priv, 0x206C, tmp, SBI_MPHY);
@@ -5221,17 +5211,15 @@ static void lpt_init_pch_refclk(struct drm_device *dev)
        tmp |= (1 << 24) | (1 << 21) | (1 << 18);
        intel_sbi_write(dev_priv, 0x216C, tmp, SBI_MPHY);
 
-       if (!is_sdv) {
-               tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY);
-               tmp &= ~(7 << 13);
-               tmp |= (5 << 13);
-               intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY);
+       tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY);
+       tmp &= ~(7 << 13);
+       tmp |= (5 << 13);
+       intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY);
 
-               tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY);
-               tmp &= ~(7 << 13);
-               tmp |= (5 << 13);
-               intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY);
-       }
+       tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY);
+       tmp &= ~(7 << 13);
+       tmp |= (5 << 13);
+       intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY);
 
        tmp = intel_sbi_read(dev_priv, 0x208C, SBI_MPHY);
        tmp &= ~0xFF;
@@ -5253,34 +5241,120 @@ static void lpt_init_pch_refclk(struct drm_device *dev)
        tmp |= (0x1C << 16);
        intel_sbi_write(dev_priv, 0x2198, tmp, SBI_MPHY);
 
-       if (!is_sdv) {
-               tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY);
-               tmp |= (1 << 27);
-               intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY);
+       tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY);
+       tmp |= (1 << 27);
+       intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY);
+       tmp |= (1 << 27);
+       intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY);
 
-               tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY);
-               tmp |= (1 << 27);
-               intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY);
+       tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY);
+       tmp &= ~(0xF << 28);
+       tmp |= (4 << 28);
+       intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY);
+       tmp &= ~(0xF << 28);
+       tmp |= (4 << 28);
+       intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY);
+}
 
-               tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY);
-               tmp &= ~(0xF << 28);
-               tmp |= (4 << 28);
-               intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY);
+/* Implements 3 different sequences from BSpec chapter "Display iCLK
+ * Programming" based on the parameters passed:
+ * - Sequence to enable CLKOUT_DP
+ * - Sequence to enable CLKOUT_DP without spread
+ * - Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O
+ */
+static void lpt_enable_clkout_dp(struct drm_device *dev, bool with_spread,
+                                bool with_fdi)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t reg, tmp;
 
-               tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY);
-               tmp &= ~(0xF << 28);
-               tmp |= (4 << 28);
-               intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY);
+       if (WARN(with_fdi && !with_spread, "FDI requires downspread\n"))
+               with_spread = true;
+       if (WARN(dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE &&
+                with_fdi, "LP PCH doesn't have FDI\n"))
+               with_fdi = false;
+
+       mutex_lock(&dev_priv->dpio_lock);
+
+       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
+       tmp &= ~SBI_SSCCTL_DISABLE;
+       tmp |= SBI_SSCCTL_PATHALT;
+       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
+
+       udelay(24);
+
+       if (with_spread) {
+               tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
+               tmp &= ~SBI_SSCCTL_PATHALT;
+               intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
+
+               if (with_fdi) {
+                       lpt_reset_fdi_mphy(dev_priv);
+                       lpt_program_fdi_mphy(dev_priv);
+               }
        }
 
-       /* ULT uses SBI_GEN0, but ULT doesn't have VGA, so we don't care. */
-       tmp = intel_sbi_read(dev_priv, SBI_DBUFF0, SBI_ICLK);
-       tmp |= SBI_DBUFF0_ENABLE;
-       intel_sbi_write(dev_priv, SBI_DBUFF0, tmp, SBI_ICLK);
+       reg = (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) ?
+              SBI_GEN0 : SBI_DBUFF0;
+       tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
+       tmp |= SBI_GEN0_CFG_BUFFENABLE_DISABLE;
+       intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
+
+       mutex_unlock(&dev_priv->dpio_lock);
+}
+
+/* Sequence to disable CLKOUT_DP */
+static void lpt_disable_clkout_dp(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t reg, tmp;
+
+       mutex_lock(&dev_priv->dpio_lock);
+
+       reg = (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) ?
+              SBI_GEN0 : SBI_DBUFF0;
+       tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
+       tmp &= ~SBI_GEN0_CFG_BUFFENABLE_DISABLE;
+       intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
+
+       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
+       if (!(tmp & SBI_SSCCTL_DISABLE)) {
+               if (!(tmp & SBI_SSCCTL_PATHALT)) {
+                       tmp |= SBI_SSCCTL_PATHALT;
+                       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
+                       udelay(32);
+               }
+               tmp |= SBI_SSCCTL_DISABLE;
+               intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
+       }
 
        mutex_unlock(&dev_priv->dpio_lock);
 }
 
+static void lpt_init_pch_refclk(struct drm_device *dev)
+{
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
+       bool has_vga = false;
+
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               switch (encoder->type) {
+               case INTEL_OUTPUT_ANALOG:
+                       has_vga = true;
+                       break;
+               }
+       }
+
+       if (has_vga)
+               lpt_enable_clkout_dp(dev, true, true);
+       else
+               lpt_disable_clkout_dp(dev);
+}
+
 /*
  * Initialize reference clocks when the driver loads
  */
@@ -5610,9 +5684,9 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
                << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
 
        if (is_sdvo)
-               dpll |= DPLL_DVO_HIGH_SPEED;
+               dpll |= DPLL_SDVO_HIGH_SPEED;
        if (intel_crtc->config.has_dp_encoder)
-               dpll |= DPLL_DVO_HIGH_SPEED;
+               dpll |= DPLL_SDVO_HIGH_SPEED;
 
        /* compute bitmask from p1 value */
        dpll |= (1 << (intel_crtc->config.dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
@@ -5708,7 +5782,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                else
                        intel_crtc->config.dpll_hw_state.fp1 = fp;
 
-               pll = intel_get_shared_dpll(intel_crtc, dpll, fp);
+               pll = intel_get_shared_dpll(intel_crtc);
                if (pll == NULL) {
                        DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
                                         pipe_name(pipe));
@@ -5720,10 +5794,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        if (intel_crtc->config.has_dp_encoder)
                intel_dp_set_m_n(intel_crtc);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               if (encoder->pre_pll_enable)
-                       encoder->pre_pll_enable(encoder);
-
        if (is_lvds && has_reduced_clock && i915_powersave)
                intel_crtc->lowfreq_avail = true;
        else
@@ -5732,23 +5802,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        if (intel_crtc->config.has_pch_encoder) {
                pll = intel_crtc_to_shared_dpll(intel_crtc);
 
-               I915_WRITE(PCH_DPLL(pll->id), dpll);
-
-               /* Wait for the clocks to stabilize. */
-               POSTING_READ(PCH_DPLL(pll->id));
-               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(pll->id), dpll);
-
-               if (has_reduced_clock)
-                       I915_WRITE(PCH_FP1(pll->id), fp2);
-               else
-                       I915_WRITE(PCH_FP1(pll->id), fp);
        }
 
        intel_set_pipe_timings(intel_crtc);
@@ -5820,7 +5873,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t tmp;
 
-       pipe_config->cpu_transcoder = crtc->pipe;
+       pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
 
        tmp = I915_READ(PIPECONF(crtc->pipe));
@@ -5838,12 +5891,9 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
 
                ironlake_get_fdi_m_n_config(crtc, pipe_config);
 
-               /* XXX: Can't properly read out the pch dpll pixel multiplier
-                * since we don't have state tracking for pch clocks yet. */
-               pipe_config->pixel_multiplier = 1;
-
                if (HAS_PCH_IBX(dev_priv->dev)) {
-                       pipe_config->shared_dpll = crtc->pipe;
+                       pipe_config->shared_dpll =
+                               (enum intel_dpll_id) crtc->pipe;
                } else {
                        tmp = I915_READ(PCH_DPLL_SEL);
                        if (tmp & TRANS_DPLLB_SEL(crtc->pipe))
@@ -5856,6 +5906,11 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
 
                WARN_ON(!pll->get_hw_state(dev_priv, pll,
                                           &pipe_config->dpll_hw_state));
+
+               tmp = pipe_config->dpll_hw_state.dpll;
+               pipe_config->pixel_multiplier =
+                       ((tmp & PLL_REF_SDVO_HDMI_MULTIPLIER_MASK)
+                        >> PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT) + 1;
        } else {
                pipe_config->pixel_multiplier = 1;
        }
@@ -5867,6 +5922,142 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
        return true;
 }
 
+static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct intel_ddi_plls *plls = &dev_priv->ddi_plls;
+       struct intel_crtc *crtc;
+       unsigned long irqflags;
+       uint32_t val, pch_hpd_mask;
+
+       pch_hpd_mask = SDE_PORTB_HOTPLUG_CPT | SDE_PORTC_HOTPLUG_CPT;
+       if (!(dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE))
+               pch_hpd_mask |= SDE_PORTD_HOTPLUG_CPT | SDE_CRT_HOTPLUG_CPT;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head)
+               WARN(crtc->base.enabled, "CRTC for pipe %c enabled\n",
+                    pipe_name(crtc->pipe));
+
+       WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n");
+       WARN(plls->spll_refcount, "SPLL enabled\n");
+       WARN(plls->wrpll1_refcount, "WRPLL1 enabled\n");
+       WARN(plls->wrpll2_refcount, "WRPLL2 enabled\n");
+       WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n");
+       WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
+            "CPU PWM1 enabled\n");
+       WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
+            "CPU PWM2 enabled\n");
+       WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
+            "PCH PWM1 enabled\n");
+       WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
+            "Utility pin enabled\n");
+       WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n");
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       val = I915_READ(DEIMR);
+       WARN((val & ~DE_PCH_EVENT_IVB) != val,
+            "Unexpected DEIMR bits enabled: 0x%x\n", val);
+       val = I915_READ(SDEIMR);
+       WARN((val & ~pch_hpd_mask) != val,
+            "Unexpected SDEIMR bits enabled: 0x%x\n", val);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+/*
+ * This function implements pieces of two sequences from BSpec:
+ * - Sequence for display software to disable LCPLL
+ * - Sequence for display software to allow package C8+
+ * The steps implemented here are just the steps that actually touch the LCPLL
+ * register. Callers should take care of disabling all the display engine
+ * functions, doing the mode unset, fixing interrupts, etc.
+ */
+void hsw_disable_lcpll(struct drm_i915_private *dev_priv,
+                      bool switch_to_fclk, bool allow_power_down)
+{
+       uint32_t val;
+
+       assert_can_disable_lcpll(dev_priv);
+
+       val = I915_READ(LCPLL_CTL);
+
+       if (switch_to_fclk) {
+               val |= LCPLL_CD_SOURCE_FCLK;
+               I915_WRITE(LCPLL_CTL, val);
+
+               if (wait_for_atomic_us(I915_READ(LCPLL_CTL) &
+                                      LCPLL_CD_SOURCE_FCLK_DONE, 1))
+                       DRM_ERROR("Switching to FCLK failed\n");
+
+               val = I915_READ(LCPLL_CTL);
+       }
+
+       val |= LCPLL_PLL_DISABLE;
+       I915_WRITE(LCPLL_CTL, val);
+       POSTING_READ(LCPLL_CTL);
+
+       if (wait_for((I915_READ(LCPLL_CTL) & LCPLL_PLL_LOCK) == 0, 1))
+               DRM_ERROR("LCPLL still locked\n");
+
+       val = I915_READ(D_COMP);
+       val |= D_COMP_COMP_DISABLE;
+       I915_WRITE(D_COMP, val);
+       POSTING_READ(D_COMP);
+       ndelay(100);
+
+       if (wait_for((I915_READ(D_COMP) & D_COMP_RCOMP_IN_PROGRESS) == 0, 1))
+               DRM_ERROR("D_COMP RCOMP still in progress\n");
+
+       if (allow_power_down) {
+               val = I915_READ(LCPLL_CTL);
+               val |= LCPLL_POWER_DOWN_ALLOW;
+               I915_WRITE(LCPLL_CTL, val);
+               POSTING_READ(LCPLL_CTL);
+       }
+}
+
+/*
+ * Fully restores LCPLL, disallowing power down and switching back to LCPLL
+ * source.
+ */
+void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
+{
+       uint32_t val;
+
+       val = I915_READ(LCPLL_CTL);
+
+       if ((val & (LCPLL_PLL_LOCK | LCPLL_PLL_DISABLE | LCPLL_CD_SOURCE_FCLK |
+                   LCPLL_POWER_DOWN_ALLOW)) == LCPLL_PLL_LOCK)
+               return;
+
+       if (val & LCPLL_POWER_DOWN_ALLOW) {
+               val &= ~LCPLL_POWER_DOWN_ALLOW;
+               I915_WRITE(LCPLL_CTL, val);
+       }
+
+       val = I915_READ(D_COMP);
+       val |= D_COMP_COMP_FORCE;
+       val &= ~D_COMP_COMP_DISABLE;
+       I915_WRITE(D_COMP, val);
+       I915_READ(D_COMP);
+
+       val = I915_READ(LCPLL_CTL);
+       val &= ~LCPLL_PLL_DISABLE;
+       I915_WRITE(LCPLL_CTL, val);
+
+       if (wait_for(I915_READ(LCPLL_CTL) & LCPLL_PLL_LOCK, 5))
+               DRM_ERROR("LCPLL not locked yet\n");
+
+       if (val & LCPLL_CD_SOURCE_FCLK) {
+               val = I915_READ(LCPLL_CTL);
+               val &= ~LCPLL_CD_SOURCE_FCLK;
+               I915_WRITE(LCPLL_CTL, val);
+
+               if (wait_for_atomic_us((I915_READ(LCPLL_CTL) &
+                                       LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1))
+                       DRM_ERROR("Switching back to LCPLL failed\n");
+       }
+}
+
 static void haswell_modeset_global_resources(struct drm_device *dev)
 {
        bool enable = false;
@@ -5935,7 +6126,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
        enum intel_display_power_domain pfit_domain;
        uint32_t tmp;
 
-       pipe_config->cpu_transcoder = crtc->pipe;
+       pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
 
        tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
@@ -6548,7 +6739,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
                        goto fail_unpin;
                }
 
-               addr = obj->gtt_offset;
+               addr = i915_gem_obj_ggtt_offset(obj);
        } else {
                int align = IS_I830(dev) ? 16 * 1024 : 256;
                ret = i915_gem_attach_phys_object(dev, obj,
@@ -6875,11 +7066,12 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
 }
 
 /* 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)
+static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
+                               struct intel_crtc_config *pipe_config)
 {
+       struct drm_device *dev = crtc->base.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 pipe = pipe_config->cpu_transcoder;
        u32 dpll = I915_READ(DPLL(pipe));
        u32 fp;
        intel_clock_t clock;
@@ -6918,7 +7110,8 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
                default:
                        DRM_DEBUG_KMS("Unknown DPLL mode %08x in programmed "
                                  "mode\n", (int)(dpll & DPLL_MODE_MASK));
-                       return 0;
+                       pipe_config->adjusted_mode.clock = 0;
+                       return;
                }
 
                if (IS_PINEVIEW(dev))
@@ -6955,12 +7148,55 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
                }
        }
 
-       /* 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.
+       pipe_config->adjusted_mode.clock = clock.dot *
+               pipe_config->pixel_multiplier;
+}
+
+static void ironlake_crtc_clock_get(struct intel_crtc *crtc,
+                                   struct intel_crtc_config *pipe_config)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
+       int link_freq, repeat;
+       u64 clock;
+       u32 link_m, link_n;
+
+       repeat = pipe_config->pixel_multiplier;
+
+       /*
+        * The calculation for the data clock is:
+        * pixel_clock = ((m/n)*(link_clock * nr_lanes * repeat))/bpp
+        * But we want to avoid losing precison if possible, so:
+        * pixel_clock = ((m * link_clock * nr_lanes * repeat)/(n*bpp))
+        *
+        * and the link clock is simpler:
+        * link_clock = (m * link_clock * repeat) / n
         */
 
-       return clock.dot;
+       /*
+        * We need to get the FDI or DP link clock here to derive
+        * the M/N dividers.
+        *
+        * For FDI, we read it from the BIOS or use a fixed 2.7GHz.
+        * For DP, it's either 1.62GHz or 2.7GHz.
+        * We do our calculations in 10*MHz since we don't need much precison.
+        */
+       if (pipe_config->has_pch_encoder)
+               link_freq = intel_fdi_link_freq(dev) * 10000;
+       else
+               link_freq = pipe_config->port_clock;
+
+       link_m = I915_READ(PIPE_LINK_M1(cpu_transcoder));
+       link_n = I915_READ(PIPE_LINK_N1(cpu_transcoder));
+
+       if (!link_m || !link_n)
+               return;
+
+       clock = ((u64)link_m * (u64)link_freq * (u64)repeat);
+       do_div(clock, link_n);
+
+       pipe_config->adjusted_mode.clock = clock;
 }
 
 /** Returns the currently programmed mode of the given pipe. */
@@ -6971,6 +7207,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
        struct drm_display_mode *mode;
+       struct intel_crtc_config pipe_config;
        int htot = I915_READ(HTOTAL(cpu_transcoder));
        int hsync = I915_READ(HSYNC(cpu_transcoder));
        int vtot = I915_READ(VTOTAL(cpu_transcoder));
@@ -6980,7 +7217,18 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
        if (!mode)
                return NULL;
 
-       mode->clock = intel_crtc_clock_get(dev, crtc);
+       /*
+        * Construct a pipe_config sufficient for getting the clock info
+        * back out of crtc_clock_get.
+        *
+        * Note, if LVDS ever uses a non-1 pixel multiplier, we'll need
+        * to use a real value here instead.
+        */
+       pipe_config.cpu_transcoder = (enum transcoder) intel_crtc->pipe;
+       pipe_config.pixel_multiplier = 1;
+       i9xx_crtc_clock_get(intel_crtc, &pipe_config);
+
+       mode->clock = pipe_config.adjusted_mode.clock;
        mode->hdisplay = (htot & 0xffff) + 1;
        mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
        mode->hsync_start = (hsync & 0xffff) + 1;
@@ -7263,7 +7511,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
        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 + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
        intel_ring_emit(ring, 0); /* aux display base address, unused */
 
        intel_mark_page_flip_active(intel_crtc);
@@ -7304,7 +7552,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
        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 + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
        intel_ring_emit(ring, MI_NOOP);
 
        intel_mark_page_flip_active(intel_crtc);
@@ -7344,7 +7592,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
        intel_ring_emit(ring, fb->pitches[0]);
        intel_ring_emit(ring,
-                       (obj->gtt_offset + intel_crtc->dspaddr_offset) |
+                       (i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset) |
                        obj->tiling_mode);
 
        /* XXX Enabling the panel-fitter across page-flip is so far
@@ -7387,7 +7635,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
        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 + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
 
        /* Contrary to the suggestions in the documentation,
         * "Enable Panel Fitter" does not seem to be required when page
@@ -7452,7 +7700,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 
        intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit);
        intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode));
-       intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
        intel_ring_emit(ring, (MI_NOOP));
 
        intel_mark_page_flip_active(intel_crtc);
@@ -7806,7 +8054,8 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
 
        drm_mode_copy(&pipe_config->adjusted_mode, mode);
        drm_mode_copy(&pipe_config->requested_mode, mode);
-       pipe_config->cpu_transcoder = to_intel_crtc(crtc)->pipe;
+       pipe_config->cpu_transcoder =
+               (enum transcoder) to_intel_crtc(crtc)->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
 
        /* Compute a starting value for pipe_config->pipe_bpp taking the source
@@ -8041,6 +8290,28 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
 
 }
 
+static bool intel_fuzzy_clock_check(struct intel_crtc_config *cur,
+                                   struct intel_crtc_config *new)
+{
+       int clock1, clock2, diff;
+
+       clock1 = cur->adjusted_mode.clock;
+       clock2 = new->adjusted_mode.clock;
+
+       if (clock1 == clock2)
+               return true;
+
+       if (!clock1 || !clock2)
+               return false;
+
+       diff = abs(clock1 - clock2);
+
+       if (((((diff + clock1 + clock2) * 100)) / (clock1 + clock2)) < 105)
+               return true;
+
+       return false;
+}
+
 #define for_each_intel_crtc_masked(dev, mask, intel_crtc) \
        list_for_each_entry((intel_crtc), \
                            &(dev)->mode_config.crtc_list, \
@@ -8072,7 +8343,7 @@ intel_pipe_config_compare(struct drm_device *dev,
 
 #define PIPE_CONF_CHECK_FLAGS(name, mask)      \
        if ((current_config->name ^ pipe_config->name) & (mask)) { \
-               DRM_ERROR("mismatch in " #name " " \
+               DRM_ERROR("mismatch in " #name "(" #mask ") "      \
                          "(expected %i, found %i)\n", \
                          current_config->name & (mask), \
                          pipe_config->name & (mask)); \
@@ -8106,8 +8377,7 @@ intel_pipe_config_compare(struct drm_device *dev,
        PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_start);
        PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_end);
 
-       if (!HAS_PCH_SPLIT(dev))
-               PIPE_CONF_CHECK_I(pixel_multiplier);
+       PIPE_CONF_CHECK_I(pixel_multiplier);
 
        PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
                              DRM_MODE_FLAG_INTERLACE);
@@ -8138,6 +8408,7 @@ intel_pipe_config_compare(struct drm_device *dev,
 
        PIPE_CONF_CHECK_I(shared_dpll);
        PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
+       PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md);
        PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
        PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
 
@@ -8146,6 +8417,15 @@ intel_pipe_config_compare(struct drm_device *dev,
 #undef PIPE_CONF_CHECK_FLAGS
 #undef PIPE_CONF_QUIRK
 
+       if (!IS_HASWELL(dev)) {
+               if (!intel_fuzzy_clock_check(current_config, pipe_config)) {
+                       DRM_ERROR("mismatch in clock (expected %d, found %d)\n",
+                                 current_config->adjusted_mode.clock,
+                                 pipe_config->adjusted_mode.clock);
+                       return false;
+               }
+       }
+
        return true;
 }
 
@@ -8275,6 +8555,9 @@ check_crtc_state(struct drm_device *dev)
                                encoder->get_config(encoder, &pipe_config);
                }
 
+               if (dev_priv->display.get_clock)
+                       dev_priv->display.get_clock(crtc, &pipe_config);
+
                WARN(crtc->active != active,
                     "crtc active state doesn't match with hw state "
                     "(expected %i, found %i)\n", crtc->active, active);
@@ -8571,8 +8854,16 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
        } else if (set->crtc->fb != set->fb) {
                /* If we have no fb then treat it as a full mode set */
                if (set->crtc->fb == NULL) {
-                       DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
-                       config->mode_changed = true;
+                       struct intel_crtc *intel_crtc =
+                               to_intel_crtc(set->crtc);
+
+                       if (intel_crtc->active && i915_fastboot) {
+                               DRM_DEBUG_KMS("crtc has no fb, will flip\n");
+                               config->fb_changed = true;
+                       } else {
+                               DRM_DEBUG_KMS("inactive crtc, full mode set\n");
+                               config->mode_changed = true;
+                       }
                } else if (set->fb == NULL) {
                        config->mode_changed = true;
                } else if (set->fb->pixel_format !=
@@ -8802,19 +9093,32 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
        return val & DPLL_VCO_ENABLE;
 }
 
+static void ibx_pch_dpll_mode_set(struct drm_i915_private *dev_priv,
+                                 struct intel_shared_dpll *pll)
+{
+       I915_WRITE(PCH_FP0(pll->id), pll->hw_state.fp0);
+       I915_WRITE(PCH_FP1(pll->id), pll->hw_state.fp1);
+}
+
 static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
                                struct intel_shared_dpll *pll)
 {
-       uint32_t reg, val;
-
        /* PCH refclock must be enabled first */
        assert_pch_refclk_enabled(dev_priv);
 
-       reg = PCH_DPLL(pll->id);
-       val = I915_READ(reg);
-       val |= DPLL_VCO_ENABLE;
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
+       I915_WRITE(PCH_DPLL(pll->id), pll->hw_state.dpll);
+
+       /* Wait for the clocks to stabilize. */
+       POSTING_READ(PCH_DPLL(pll->id));
+       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(pll->id), pll->hw_state.dpll);
+       POSTING_READ(PCH_DPLL(pll->id));
        udelay(200);
 }
 
@@ -8823,7 +9127,6 @@ static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
 {
        struct drm_device *dev = dev_priv->dev;
        struct intel_crtc *crtc;
-       uint32_t reg, val;
 
        /* Make sure no transcoder isn't still depending on us. */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
@@ -8831,11 +9134,8 @@ static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
                        assert_pch_transcoder_disabled(dev_priv, crtc->pipe);
        }
 
-       reg = PCH_DPLL(pll->id);
-       val = I915_READ(reg);
-       val &= ~DPLL_VCO_ENABLE;
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
+       I915_WRITE(PCH_DPLL(pll->id), 0);
+       POSTING_READ(PCH_DPLL(pll->id));
        udelay(200);
 }
 
@@ -8854,6 +9154,7 @@ static void ibx_pch_dpll_init(struct drm_device *dev)
        for (i = 0; i < dev_priv->num_shared_dpll; i++) {
                dev_priv->shared_dplls[i].id = i;
                dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i];
+               dev_priv->shared_dplls[i].mode_set = ibx_pch_dpll_mode_set;
                dev_priv->shared_dplls[i].enable = ibx_pch_dpll_enable;
                dev_priv->shared_dplls[i].disable = ibx_pch_dpll_disable;
                dev_priv->shared_dplls[i].get_hw_state =
@@ -9270,6 +9571,7 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.update_plane = ironlake_update_plane;
        } else if (HAS_PCH_SPLIT(dev)) {
                dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
+               dev_priv->display.get_clock = ironlake_crtc_clock_get;
                dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
                dev_priv->display.crtc_enable = ironlake_crtc_enable;
                dev_priv->display.crtc_disable = ironlake_crtc_disable;
@@ -9277,6 +9579,7 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.update_plane = ironlake_update_plane;
        } else if (IS_VALLEYVIEW(dev)) {
                dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
+               dev_priv->display.get_clock = i9xx_crtc_clock_get;
                dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
                dev_priv->display.crtc_enable = valleyview_crtc_enable;
                dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@ -9284,6 +9587,7 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.update_plane = i9xx_update_plane;
        } else {
                dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
+               dev_priv->display.get_clock = i9xx_crtc_clock_get;
                dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
                dev_priv->display.crtc_enable = i9xx_crtc_enable;
                dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@ -9584,7 +9888,7 @@ void intel_modeset_init(struct drm_device *dev)
                      INTEL_INFO(dev)->num_pipes,
                      INTEL_INFO(dev)->num_pipes > 1 ? "s" : "");
 
-       for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) {
+       for_each_pipe(i) {
                intel_crtc_init(dev, i);
                for (j = 0; j < dev_priv->num_plane; j++) {
                        ret = intel_plane_init(dev, i, j);
@@ -9860,6 +10164,15 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                              pipe);
        }
 
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+                           base.head) {
+               if (!crtc->active)
+                       continue;
+               if (dev_priv->display.get_clock)
+                       dev_priv->display.get_clock(crtc,
+                                                   &crtc->config);
+       }
+
        list_for_each_entry(connector, &dev->mode_config.connector_list,
                            base.head) {
                if (connector->get_hw_state(connector)) {
@@ -9891,6 +10204,22 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
 
        intel_modeset_readout_hw_state(dev);
 
+       /*
+        * Now that we have the config, copy it to each CRTC struct
+        * Note that this could go away if we move to using crtc_config
+        * checking everywhere.
+        */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+                           base.head) {
+               if (crtc->active && i915_fastboot) {
+                       intel_crtc_mode_from_pipe_config(crtc, &crtc->config);
+
+                       DRM_DEBUG_KMS("[CRTC:%d] found active mode: ",
+                                     crtc->base.base.id);
+                       drm_mode_debug_printmodeline(&crtc->base.mode);
+               }
+       }
+
        /* HW state is read out, now we need to sanitize this mess. */
        list_for_each_entry(encoder, &dev->mode_config.encoder_list,
                            base.head) {
@@ -10033,9 +10362,6 @@ int intel_modeset_vga_set_state(struct drm_device *dev, bool state)
        return 0;
 }
 
-#ifdef CONFIG_DEBUG_FS
-#include <linux/seq_file.h>
-
 struct intel_display_error_state {
 
        u32 power_well_driver;
@@ -10179,4 +10505,3 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
                err_printf(m, "  BASE: %08x\n", error->cursor[i].base);
        }
 }
-#endif