drm/i915: Update color management during vblank evasion.
[cascardo/linux.git] / drivers / gpu / drm / i915 / intel_display.c
index 46947ff..60bb486 100644 (file)
@@ -36,6 +36,7 @@
 #include "intel_drv.h"
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
+#include "intel_dsi.h"
 #include "i915_trace.h"
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
@@ -85,8 +86,6 @@ static const uint32_t intel_cursor_formats[] = {
        DRM_FORMAT_ARGB8888,
 };
 
-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_state *pipe_config);
 static void ironlake_pch_clock_get(struct intel_crtc *crtc,
@@ -98,12 +97,13 @@ static int intel_framebuffer_init(struct drm_device *dev,
                                  struct drm_i915_gem_object *obj);
 static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc);
 static void intel_set_pipe_timings(struct intel_crtc *intel_crtc);
+static void intel_set_pipe_src_size(struct intel_crtc *intel_crtc);
 static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
                                         struct intel_link_m_n *m_n,
                                         struct intel_link_m_n *m2_n2);
 static void ironlake_set_pipeconf(struct drm_crtc *crtc);
 static void haswell_set_pipeconf(struct drm_crtc *crtc);
-static void intel_set_pipe_csc(struct drm_crtc *crtc);
+static void haswell_set_pipemisc(struct drm_crtc *crtc);
 static void vlv_prepare_pll(struct intel_crtc *crtc,
                            const struct intel_crtc_state *pipe_config);
 static void chv_prepare_pll(struct intel_crtc *crtc,
@@ -112,13 +112,11 @@ static void intel_begin_crtc_commit(struct drm_crtc *, struct drm_crtc_state *);
 static void intel_finish_crtc_commit(struct drm_crtc *, struct drm_crtc_state *);
 static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_crtc,
        struct intel_crtc_state *crtc_state);
-static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state,
-                          int num_connectors);
 static void skylake_pfit_enable(struct intel_crtc *crtc);
 static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force);
 static void ironlake_pfit_enable(struct intel_crtc *crtc);
 static void intel_modeset_setup_hw_state(struct drm_device *dev);
-static void intel_pre_disable_primary(struct drm_crtc *crtc);
+static void intel_pre_disable_primary_noatomic(struct drm_crtc *crtc);
 
 typedef struct {
        int     min, max;
@@ -171,49 +169,62 @@ static int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv,
        return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, divider + 1);
 }
 
-int
-intel_pch_rawclk(struct drm_device *dev)
+static int
+intel_pch_rawclk(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       WARN_ON(!HAS_PCH_SPLIT(dev));
+       return (I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK) * 1000;
+}
 
-       return I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK;
+static int
+intel_vlv_hrawclk(struct drm_i915_private *dev_priv)
+{
+       return vlv_get_cck_clock_hpll(dev_priv, "hrawclk",
+                                     CCK_DISPLAY_REF_CLOCK_CONTROL);
 }
 
-/* hrawclock is 1/4 the FSB frequency */
-int intel_hrawclk(struct drm_device *dev)
+static int
+intel_g4x_hrawclk(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t clkcfg;
 
-       /* There is no CLKCFG reg in Valleyview. VLV hrawclk is 200 MHz */
-       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
-               return 200;
-
+       /* hrawclock is 1/4 the FSB frequency */
        clkcfg = I915_READ(CLKCFG);
        switch (clkcfg & CLKCFG_FSB_MASK) {
        case CLKCFG_FSB_400:
-               return 100;
+               return 100000;
        case CLKCFG_FSB_533:
-               return 133;
+               return 133333;
        case CLKCFG_FSB_667:
-               return 166;
+               return 166667;
        case CLKCFG_FSB_800:
-               return 200;
+               return 200000;
        case CLKCFG_FSB_1067:
-               return 266;
+               return 266667;
        case CLKCFG_FSB_1333:
-               return 333;
+               return 333333;
        /* these two are just a guess; one of them might be right */
        case CLKCFG_FSB_1600:
        case CLKCFG_FSB_1600_ALT:
-               return 400;
+               return 400000;
        default:
-               return 133;
+               return 133333;
        }
 }
 
+static void intel_update_rawclk(struct drm_i915_private *dev_priv)
+{
+       if (HAS_PCH_SPLIT(dev_priv))
+               dev_priv->rawclk_freq = intel_pch_rawclk(dev_priv);
+       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               dev_priv->rawclk_freq = intel_vlv_hrawclk(dev_priv);
+       else if (IS_G4X(dev_priv) || IS_PINEVIEW(dev_priv))
+               dev_priv->rawclk_freq = intel_g4x_hrawclk(dev_priv);
+       else
+               return; /* no rawclk on other platforms, or no need to know it */
+
+       DRM_DEBUG_DRIVER("rawclk rate: %d kHz\n", dev_priv->rawclk_freq);
+}
+
 static void intel_update_czclk(struct drm_i915_private *dev_priv)
 {
        if (!(IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)))
@@ -226,13 +237,15 @@ static void intel_update_czclk(struct drm_i915_private *dev_priv)
 }
 
 static inline u32 /* units of 100MHz */
-intel_fdi_link_freq(struct drm_device *dev)
+intel_fdi_link_freq(struct drm_i915_private *dev_priv,
+                   const struct intel_crtc_state *pipe_config)
 {
-       if (IS_GEN5(dev)) {
-               struct drm_i915_private *dev_priv = dev->dev_private;
-               return (I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2;
-       } else
-               return 27;
+       if (HAS_DDI(dev_priv))
+               return pipe_config->port_clock; /* SPLL */
+       else if (IS_GEN5(dev_priv))
+               return ((I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2) * 10000;
+       else
+               return 270000;
 }
 
 static const intel_limit_t intel_limits_i8xx_dac = {
@@ -552,89 +565,6 @@ static bool intel_pipe_will_have_type(const struct intel_crtc_state *crtc_state,
        return false;
 }
 
-static const intel_limit_t *
-intel_ironlake_limit(struct intel_crtc_state *crtc_state, int refclk)
-{
-       struct drm_device *dev = crtc_state->base.crtc->dev;
-       const intel_limit_t *limit;
-
-       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
-               if (intel_is_dual_link_lvds(dev)) {
-                       if (refclk == 100000)
-                               limit = &intel_limits_ironlake_dual_lvds_100m;
-                       else
-                               limit = &intel_limits_ironlake_dual_lvds;
-               } else {
-                       if (refclk == 100000)
-                               limit = &intel_limits_ironlake_single_lvds_100m;
-                       else
-                               limit = &intel_limits_ironlake_single_lvds;
-               }
-       } else
-               limit = &intel_limits_ironlake_dac;
-
-       return limit;
-}
-
-static const intel_limit_t *
-intel_g4x_limit(struct intel_crtc_state *crtc_state)
-{
-       struct drm_device *dev = crtc_state->base.crtc->dev;
-       const intel_limit_t *limit;
-
-       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
-               if (intel_is_dual_link_lvds(dev))
-                       limit = &intel_limits_g4x_dual_channel_lvds;
-               else
-                       limit = &intel_limits_g4x_single_channel_lvds;
-       } else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_HDMI) ||
-                  intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_ANALOG)) {
-               limit = &intel_limits_g4x_hdmi;
-       } else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_SDVO)) {
-               limit = &intel_limits_g4x_sdvo;
-       } else /* The option is for other outputs */
-               limit = &intel_limits_i9xx_sdvo;
-
-       return limit;
-}
-
-static const intel_limit_t *
-intel_limit(struct intel_crtc_state *crtc_state, int refclk)
-{
-       struct drm_device *dev = crtc_state->base.crtc->dev;
-       const intel_limit_t *limit;
-
-       if (IS_BROXTON(dev))
-               limit = &intel_limits_bxt;
-       else if (HAS_PCH_SPLIT(dev))
-               limit = intel_ironlake_limit(crtc_state, refclk);
-       else if (IS_G4X(dev)) {
-               limit = intel_g4x_limit(crtc_state);
-       } else if (IS_PINEVIEW(dev)) {
-               if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS))
-                       limit = &intel_limits_pineview_lvds;
-               else
-                       limit = &intel_limits_pineview_sdvo;
-       } else if (IS_CHERRYVIEW(dev)) {
-               limit = &intel_limits_chv;
-       } else if (IS_VALLEYVIEW(dev)) {
-               limit = &intel_limits_vlv;
-       } else if (!IS_GEN2(dev)) {
-               if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS))
-                       limit = &intel_limits_i9xx_lvds;
-               else
-                       limit = &intel_limits_i9xx_sdvo;
-       } else {
-               if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS))
-                       limit = &intel_limits_i8xx_lvds;
-               else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_DVO))
-                       limit = &intel_limits_i8xx_dvo;
-               else
-                       limit = &intel_limits_i8xx_dac;
-       }
-       return limit;
-}
-
 /*
  * Platform specific helpers to calculate the port PLL loopback- (clock.m),
  * and post-divider (clock.p) values, pre- (clock.vco) and post-divided fast
@@ -765,6 +695,16 @@ i9xx_select_p2_div(const intel_limit_t *limit,
        }
 }
 
+/*
+ * 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.
+ *
+ * Target and reference clocks are specified in kHz.
+ *
+ * If match_clock is provided, then best_clock P divider must match the P
+ * divider from @match_clock used for LVDS downclocking.
+ */
 static bool
 i9xx_find_best_dpll(const intel_limit_t *limit,
                    struct intel_crtc_state *crtc_state,
@@ -812,6 +752,16 @@ i9xx_find_best_dpll(const intel_limit_t *limit,
        return (err != target);
 }
 
+/*
+ * 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.
+ *
+ * Target and reference clocks are specified in kHz.
+ *
+ * If match_clock is provided, then best_clock P divider must match the P
+ * divider from @match_clock used for LVDS downclocking.
+ */
 static bool
 pnv_find_best_dpll(const intel_limit_t *limit,
                   struct intel_crtc_state *crtc_state,
@@ -857,6 +807,16 @@ pnv_find_best_dpll(const intel_limit_t *limit,
        return (err != target);
 }
 
+/*
+ * 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.
+ *
+ * Target and reference clocks are specified in kHz.
+ *
+ * If match_clock is provided, then best_clock P divider must match the P
+ * divider from @match_clock used for LVDS downclocking.
+ */
 static bool
 g4x_find_best_dpll(const intel_limit_t *limit,
                   struct intel_crtc_state *crtc_state,
@@ -945,6 +905,11 @@ static bool vlv_PLL_is_optimal(struct drm_device *dev, int target_freq,
        return *error_ppm + 10 < best_error_ppm;
 }
 
+/*
+ * 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.
+ */
 static bool
 vlv_find_best_dpll(const intel_limit_t *limit,
                   struct intel_crtc_state *crtc_state,
@@ -999,6 +964,11 @@ vlv_find_best_dpll(const intel_limit_t *limit,
        return found;
 }
 
+/*
+ * 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.
+ */
 static bool
 chv_find_best_dpll(const intel_limit_t *limit,
                   struct intel_crtc_state *crtc_state,
@@ -1060,9 +1030,10 @@ chv_find_best_dpll(const intel_limit_t *limit,
 bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state, int target_clock,
                        intel_clock_t *best_clock)
 {
-       int refclk = i9xx_get_refclk(crtc_state, 0);
+       int refclk = 100000;
+       const intel_limit_t *limit = &intel_limits_bxt;
 
-       return chv_find_best_dpll(intel_limit(crtc_state, refclk), crtc_state,
+       return chv_find_best_dpll(limit, crtc_state,
                                  target_clock, refclk, NULL, best_clock);
 }
 
@@ -1152,11 +1123,6 @@ static void intel_wait_for_pipe_off(struct intel_crtc *crtc)
        }
 }
 
-static const char *state_string(bool enabled)
-{
-       return enabled ? "on" : "off";
-}
-
 /* Only for pre-ILK configs */
 void assert_pll(struct drm_i915_private *dev_priv,
                enum pipe pipe, bool state)
@@ -1168,11 +1134,11 @@ void assert_pll(struct drm_i915_private *dev_priv,
        cur_state = !!(val & DPLL_VCO_ENABLE);
        I915_STATE_WARN(cur_state != state,
             "PLL state assertion failure (expected %s, current %s)\n",
-            state_string(state), state_string(cur_state));
+                       onoff(state), onoff(cur_state));
 }
 
 /* XXX: the dsi pll is shared between MIPI DSI ports */
-static void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state)
+void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state)
 {
        u32 val;
        bool cur_state;
@@ -1184,38 +1150,7 @@ static void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state)
        cur_state = val & DSI_PLL_VCO_EN;
        I915_STATE_WARN(cur_state != state,
             "DSI PLL state assertion failure (expected %s, current %s)\n",
-            state_string(state), state_string(cur_state));
-}
-#define assert_dsi_pll_enabled(d) assert_dsi_pll(d, true)
-#define assert_dsi_pll_disabled(d) assert_dsi_pll(d, false)
-
-struct intel_shared_dpll *
-intel_crtc_to_shared_dpll(struct intel_crtc *crtc)
-{
-       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
-
-       if (crtc->config->shared_dpll < 0)
-               return NULL;
-
-       return &dev_priv->shared_dplls[crtc->config->shared_dpll];
-}
-
-/* For ILK+ */
-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;
-
-       if (WARN (!pll,
-                 "asserting DPLL %s with no DPLL\n", state_string(state)))
-               return;
-
-       cur_state = pll->get_hw_state(dev_priv, pll, &hw_state);
-       I915_STATE_WARN(cur_state != state,
-            "%s assertion failure (expected %s, current %s)\n",
-            pll->name, state_string(state), state_string(cur_state));
+                       onoff(state), onoff(cur_state));
 }
 
 static void assert_fdi_tx(struct drm_i915_private *dev_priv,
@@ -1235,7 +1170,7 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv,
        }
        I915_STATE_WARN(cur_state != state,
             "FDI TX state assertion failure (expected %s, current %s)\n",
-            state_string(state), state_string(cur_state));
+                       onoff(state), onoff(cur_state));
 }
 #define assert_fdi_tx_enabled(d, p) assert_fdi_tx(d, p, true)
 #define assert_fdi_tx_disabled(d, p) assert_fdi_tx(d, p, false)
@@ -1250,7 +1185,7 @@ static void assert_fdi_rx(struct drm_i915_private *dev_priv,
        cur_state = !!(val & FDI_RX_ENABLE);
        I915_STATE_WARN(cur_state != state,
             "FDI RX state assertion failure (expected %s, current %s)\n",
-            state_string(state), state_string(cur_state));
+                       onoff(state), onoff(cur_state));
 }
 #define assert_fdi_rx_enabled(d, p) assert_fdi_rx(d, p, true)
 #define assert_fdi_rx_disabled(d, p) assert_fdi_rx(d, p, false)
@@ -1282,7 +1217,7 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
        cur_state = !!(val & FDI_RX_PLL_ENABLE);
        I915_STATE_WARN(cur_state != state,
             "FDI RX PLL assertion failure (expected %s, current %s)\n",
-            state_string(state), state_string(cur_state));
+                       onoff(state), onoff(cur_state));
 }
 
 void assert_panel_unlocked(struct drm_i915_private *dev_priv,
@@ -1340,7 +1275,7 @@ static void assert_cursor(struct drm_i915_private *dev_priv,
 
        I915_STATE_WARN(cur_state != state,
             "cursor on pipe %c assertion failure (expected %s, current %s)\n",
-            pipe_name(pipe), state_string(state), state_string(cur_state));
+                       pipe_name(pipe), onoff(state), onoff(cur_state));
 }
 #define assert_cursor_enabled(d, p) assert_cursor(d, p, true)
 #define assert_cursor_disabled(d, p) assert_cursor(d, p, false)
@@ -1370,7 +1305,7 @@ void assert_pipe(struct drm_i915_private *dev_priv,
 
        I915_STATE_WARN(cur_state != state,
             "pipe %c assertion failure (expected %s, current %s)\n",
-            pipe_name(pipe), state_string(state), state_string(cur_state));
+                       pipe_name(pipe), onoff(state), onoff(cur_state));
 }
 
 static void assert_plane(struct drm_i915_private *dev_priv,
@@ -1383,7 +1318,7 @@ static void assert_plane(struct drm_i915_private *dev_priv,
        cur_state = !!(val & DISPLAY_PLANE_ENABLE);
        I915_STATE_WARN(cur_state != state,
             "plane %c assertion failure (expected %s, current %s)\n",
-            plane_name(plane), state_string(state), state_string(cur_state));
+                       plane_name(plane), onoff(state), onoff(cur_state));
 }
 
 #define assert_plane_enabled(d, p) assert_plane(d, p, true)
@@ -1454,21 +1389,8 @@ static void assert_vblank_disabled(struct drm_crtc *crtc)
                drm_crtc_vblank_put(crtc);
 }
 
-static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
-{
-       u32 val;
-       bool enabled;
-
-       I915_STATE_WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev)));
-
-       val = I915_READ(PCH_DREF_CONTROL);
-       enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
-                           DREF_SUPERSPREAD_SOURCE_MASK));
-       I915_STATE_WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
-}
-
-static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
-                                          enum pipe pipe)
+void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
+                                   enum pipe pipe)
 {
        u32 val;
        bool enabled;
@@ -1864,100 +1786,6 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
                     port_name(dport->port), I915_READ(dpll_reg) & port_mask, expected_mask);
 }
 
-static void intel_prepare_shared_dpll(struct intel_crtc *crtc)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
-
-       if (WARN_ON(pll == NULL))
-               return;
-
-       WARN_ON(!pll->config.crtc_mask);
-       if (pll->active == 0) {
-               DRM_DEBUG_DRIVER("setting up %s\n", pll->name);
-               WARN_ON(pll->on);
-               assert_shared_dpll_disabled(dev_priv, pll);
-
-               pll->mode_set(dev_priv, pll);
-       }
-}
-
-/**
- * intel_enable_shared_dpll - enable PCH PLL
- * @dev_priv: i915 private structure
- * @pipe: pipe PLL to enable
- *
- * The PCH PLL needs to be enabled before the PCH transcoder, since it
- * drives the transcoder clock.
- */
-static void intel_enable_shared_dpll(struct intel_crtc *crtc)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
-
-       if (WARN_ON(pll == NULL))
-               return;
-
-       if (WARN_ON(pll->config.crtc_mask == 0))
-               return;
-
-       DRM_DEBUG_KMS("enable %s (active %d, on? %d) for crtc %d\n",
-                     pll->name, pll->active, pll->on,
-                     crtc->base.base.id);
-
-       if (pll->active++) {
-               WARN_ON(!pll->on);
-               assert_shared_dpll_enabled(dev_priv, pll);
-               return;
-       }
-       WARN_ON(pll->on);
-
-       intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
-
-       DRM_DEBUG_KMS("enabling %s\n", pll->name);
-       pll->enable(dev_priv, pll);
-       pll->on = true;
-}
-
-static void intel_disable_shared_dpll(struct intel_crtc *crtc)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
-
-       /* PCH only available on ILK+ */
-       if (INTEL_INFO(dev)->gen < 5)
-               return;
-
-       if (pll == NULL)
-               return;
-
-       if (WARN_ON(!(pll->config.crtc_mask & (1 << drm_crtc_index(&crtc->base)))))
-               return;
-
-       DRM_DEBUG_KMS("disable %s (active %d, on? %d) for crtc %d\n",
-                     pll->name, pll->active, pll->on,
-                     crtc->base.base.id);
-
-       if (WARN_ON(pll->active == 0)) {
-               assert_shared_dpll_disabled(dev_priv, pll);
-               return;
-       }
-
-       assert_shared_dpll_enabled(dev_priv, pll);
-       WARN_ON(!pll->on);
-       if (--pll->active)
-               return;
-
-       DRM_DEBUG_KMS("disabling %s\n", pll->name);
-       pll->disable(dev_priv, pll);
-       pll->on = false;
-
-       intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
-}
-
 static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
                                           enum pipe pipe)
 {
@@ -1971,8 +1799,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
        BUG_ON(!HAS_PCH_SPLIT(dev));
 
        /* Make sure PCH DPLL is enabled */
-       assert_shared_dpll_enabled(dev_priv,
-                                  intel_crtc_to_shared_dpll(intel_crtc));
+       assert_shared_dpll_enabled(dev_priv, intel_crtc->config->shared_dpll);
 
        /* FDI must be feeding us bits for PCH ports */
        assert_fdi_tx_enabled(dev_priv, pipe);
@@ -2156,6 +1983,17 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
 
        I915_WRITE(reg, val | PIPECONF_ENABLE);
        POSTING_READ(reg);
+
+       /*
+        * Until the pipe starts DSL will read as 0, which would cause
+        * an apparent vblank timestamp jump, which messes up also the
+        * frame count when it's derived from the timestamps. So let's
+        * wait for the pipe to start properly before we call
+        * drm_crtc_vblank_on()
+        */
+       if (dev->max_vblank_count == 0 &&
+           wait_for(intel_get_crtc_scanline(crtc) != crtc->scanline_offset, 50))
+               DRM_ERROR("pipe %c didn't start\n", pipe_name(pipe));
 }
 
 /**
@@ -2217,104 +2055,134 @@ static bool need_vtd_wa(struct drm_device *dev)
        return false;
 }
 
-unsigned int
-intel_tile_height(struct drm_device *dev, uint32_t pixel_format,
-                 uint64_t fb_format_modifier, unsigned int plane)
+static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv)
 {
-       unsigned int tile_height;
-       uint32_t pixel_bytes;
+       return IS_GEN2(dev_priv) ? 2048 : 4096;
+}
 
-       switch (fb_format_modifier) {
+static unsigned int intel_tile_width_bytes(const struct drm_i915_private *dev_priv,
+                                          uint64_t fb_modifier, unsigned int cpp)
+{
+       switch (fb_modifier) {
        case DRM_FORMAT_MOD_NONE:
-               tile_height = 1;
-               break;
+               return cpp;
        case I915_FORMAT_MOD_X_TILED:
-               tile_height = IS_GEN2(dev) ? 16 : 8;
-               break;
+               if (IS_GEN2(dev_priv))
+                       return 128;
+               else
+                       return 512;
        case I915_FORMAT_MOD_Y_TILED:
-               tile_height = 32;
-               break;
+               if (IS_GEN2(dev_priv) || HAS_128_BYTE_Y_TILING(dev_priv))
+                       return 128;
+               else
+                       return 512;
        case I915_FORMAT_MOD_Yf_TILED:
-               pixel_bytes = drm_format_plane_cpp(pixel_format, plane);
-               switch (pixel_bytes) {
-               default:
+               switch (cpp) {
                case 1:
-                       tile_height = 64;
-                       break;
+                       return 64;
                case 2:
                case 4:
-                       tile_height = 32;
-                       break;
+                       return 128;
                case 8:
-                       tile_height = 16;
-                       break;
                case 16:
-                       WARN_ONCE(1,
-                                 "128-bit pixels are not supported for display!");
-                       tile_height = 16;
-                       break;
+                       return 256;
+               default:
+                       MISSING_CASE(cpp);
+                       return cpp;
                }
                break;
        default:
-               MISSING_CASE(fb_format_modifier);
-               tile_height = 1;
-               break;
+               MISSING_CASE(fb_modifier);
+               return cpp;
        }
+}
+
+unsigned int intel_tile_height(const struct drm_i915_private *dev_priv,
+                              uint64_t fb_modifier, unsigned int cpp)
+{
+       if (fb_modifier == DRM_FORMAT_MOD_NONE)
+               return 1;
+       else
+               return intel_tile_size(dev_priv) /
+                       intel_tile_width_bytes(dev_priv, fb_modifier, cpp);
+}
+
+/* Return the tile dimensions in pixel units */
+static void intel_tile_dims(const struct drm_i915_private *dev_priv,
+                           unsigned int *tile_width,
+                           unsigned int *tile_height,
+                           uint64_t fb_modifier,
+                           unsigned int cpp)
+{
+       unsigned int tile_width_bytes =
+               intel_tile_width_bytes(dev_priv, fb_modifier, cpp);
 
-       return tile_height;
+       *tile_width = tile_width_bytes / cpp;
+       *tile_height = intel_tile_size(dev_priv) / tile_width_bytes;
 }
 
 unsigned int
 intel_fb_align_height(struct drm_device *dev, unsigned int height,
-                     uint32_t pixel_format, uint64_t fb_format_modifier)
+                     uint32_t pixel_format, uint64_t fb_modifier)
 {
-       return ALIGN(height, intel_tile_height(dev, pixel_format,
-                                              fb_format_modifier, 0));
+       unsigned int cpp = drm_format_plane_cpp(pixel_format, 0);
+       unsigned int tile_height = intel_tile_height(to_i915(dev), fb_modifier, cpp);
+
+       return ALIGN(height, tile_height);
 }
 
-static void
-intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb,
-                       const struct drm_plane_state *plane_state)
+unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info)
 {
-       struct intel_rotation_info *info = &view->params.rotation_info;
-       unsigned int tile_height, tile_pitch;
+       unsigned int size = 0;
+       int i;
 
-       *view = i915_ggtt_view_normal;
+       for (i = 0 ; i < ARRAY_SIZE(rot_info->plane); i++)
+               size += rot_info->plane[i].width * rot_info->plane[i].height;
 
-       if (!plane_state)
-               return;
+       return size;
+}
 
-       if (!intel_rotation_90_or_270(plane_state->rotation))
-               return;
+static void
+intel_fill_fb_ggtt_view(struct i915_ggtt_view *view,
+                       const struct drm_framebuffer *fb,
+                       unsigned int rotation)
+{
+       if (intel_rotation_90_or_270(rotation)) {
+               *view = i915_ggtt_view_rotated;
+               view->params.rotated = to_intel_framebuffer(fb)->rot_info;
+       } else {
+               *view = i915_ggtt_view_normal;
+       }
+}
+
+static void
+intel_fill_fb_info(struct drm_i915_private *dev_priv,
+                  struct drm_framebuffer *fb)
+{
+       struct intel_rotation_info *info = &to_intel_framebuffer(fb)->rot_info;
+       unsigned int tile_size, tile_width, tile_height, cpp;
 
-       *view = i915_ggtt_view_rotated;
+       tile_size = intel_tile_size(dev_priv);
 
-       info->height = fb->height;
-       info->pixel_format = fb->pixel_format;
-       info->pitch = fb->pitches[0];
-       info->uv_offset = fb->offsets[1];
-       info->fb_modifier = fb->modifier[0];
+       cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+       intel_tile_dims(dev_priv, &tile_width, &tile_height,
+                       fb->modifier[0], cpp);
 
-       tile_height = intel_tile_height(fb->dev, fb->pixel_format,
-                                       fb->modifier[0], 0);
-       tile_pitch = PAGE_SIZE / tile_height;
-       info->width_pages = DIV_ROUND_UP(fb->pitches[0], tile_pitch);
-       info->height_pages = DIV_ROUND_UP(fb->height, tile_height);
-       info->size = info->width_pages * info->height_pages * PAGE_SIZE;
+       info->plane[0].width = DIV_ROUND_UP(fb->pitches[0], tile_width * cpp);
+       info->plane[0].height = DIV_ROUND_UP(fb->height, tile_height);
 
        if (info->pixel_format == DRM_FORMAT_NV12) {
-               tile_height = intel_tile_height(fb->dev, fb->pixel_format,
-                                               fb->modifier[0], 1);
-               tile_pitch = PAGE_SIZE / tile_height;
-               info->width_pages_uv = DIV_ROUND_UP(fb->pitches[0], tile_pitch);
-               info->height_pages_uv = DIV_ROUND_UP(fb->height / 2,
-                                                    tile_height);
-               info->size_uv = info->width_pages_uv * info->height_pages_uv *
-                               PAGE_SIZE;
+               cpp = drm_format_plane_cpp(fb->pixel_format, 1);
+               intel_tile_dims(dev_priv, &tile_width, &tile_height,
+                               fb->modifier[1], cpp);
+
+               info->uv_offset = fb->offsets[1];
+               info->plane[1].width = DIV_ROUND_UP(fb->pitches[1], tile_width * cpp);
+               info->plane[1].height = DIV_ROUND_UP(fb->height / 2, tile_height);
        }
 }
 
-static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv)
+static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv)
 {
        if (INTEL_INFO(dev_priv)->gen >= 9)
                return 256 * 1024;
@@ -2327,10 +2195,28 @@ static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv)
                return 0;
 }
 
+static unsigned int intel_surf_alignment(const struct drm_i915_private *dev_priv,
+                                        uint64_t fb_modifier)
+{
+       switch (fb_modifier) {
+       case DRM_FORMAT_MOD_NONE:
+               return intel_linear_alignment(dev_priv);
+       case I915_FORMAT_MOD_X_TILED:
+               if (INTEL_INFO(dev_priv)->gen >= 9)
+                       return 256 * 1024;
+               return 0;
+       case I915_FORMAT_MOD_Y_TILED:
+       case I915_FORMAT_MOD_Yf_TILED:
+               return 1 * 1024 * 1024;
+       default:
+               MISSING_CASE(fb_modifier);
+               return 0;
+       }
+}
+
 int
-intel_pin_and_fence_fb_obj(struct drm_plane *plane,
-                          struct drm_framebuffer *fb,
-                          const struct drm_plane_state *plane_state)
+intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
+                          unsigned int rotation)
 {
        struct drm_device *dev = fb->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2341,31 +2227,9 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
-       switch (fb->modifier[0]) {
-       case DRM_FORMAT_MOD_NONE:
-               alignment = intel_linear_alignment(dev_priv);
-               break;
-       case I915_FORMAT_MOD_X_TILED:
-               if (INTEL_INFO(dev)->gen >= 9)
-                       alignment = 256 * 1024;
-               else {
-                       /* pin() will align the object as required by fence */
-                       alignment = 0;
-               }
-               break;
-       case I915_FORMAT_MOD_Y_TILED:
-       case I915_FORMAT_MOD_Yf_TILED:
-               if (WARN_ONCE(INTEL_INFO(dev)->gen < 9,
-                         "Y tiling bo slipped through, driver bug!\n"))
-                       return -EINVAL;
-               alignment = 1 * 1024 * 1024;
-               break;
-       default:
-               MISSING_CASE(fb->modifier[0]);
-               return -EINVAL;
-       }
+       alignment = intel_surf_alignment(dev_priv, fb->modifier[0]);
 
-       intel_fill_fb_ggtt_view(&view, fb, plane_state);
+       intel_fill_fb_ggtt_view(&view, fb, rotation);
 
        /* Note that the w/a also requires 64 PTE of padding following the
         * bo. We currently fill all unused PTE with the shadow page and so
@@ -2423,15 +2287,14 @@ err_pm:
        return ret;
 }
 
-static void intel_unpin_fb_obj(struct drm_framebuffer *fb,
-                              const struct drm_plane_state *plane_state)
+static void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
 {
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        struct i915_ggtt_view view;
 
        WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex));
 
-       intel_fill_fb_ggtt_view(&view, fb, plane_state);
+       intel_fill_fb_ggtt_view(&view, fb, rotation);
 
        if (view.type == I915_GGTT_VIEW_NORMAL)
                i915_gem_object_unpin_fence(obj);
@@ -2439,33 +2302,93 @@ static void intel_unpin_fb_obj(struct drm_framebuffer *fb,
        i915_gem_object_unpin_from_display_plane(obj, &view);
 }
 
-/* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel
- * is assumed to be a power-of-two. */
-unsigned long intel_gen4_compute_page_offset(struct drm_i915_private *dev_priv,
-                                            int *x, int *y,
-                                            unsigned int tiling_mode,
-                                            unsigned int cpp,
-                                            unsigned int pitch)
+/*
+ * Adjust the tile offset by moving the difference into
+ * the x/y offsets.
+ *
+ * Input tile dimensions and pitch must already be
+ * rotated to match x and y, and in pixel units.
+ */
+static u32 intel_adjust_tile_offset(int *x, int *y,
+                                   unsigned int tile_width,
+                                   unsigned int tile_height,
+                                   unsigned int tile_size,
+                                   unsigned int pitch_tiles,
+                                   u32 old_offset,
+                                   u32 new_offset)
 {
-       if (tiling_mode != I915_TILING_NONE) {
-               unsigned int tile_rows, tiles;
+       unsigned int tiles;
 
-               tile_rows = *y / 8;
-               *y %= 8;
+       WARN_ON(old_offset & (tile_size - 1));
+       WARN_ON(new_offset & (tile_size - 1));
+       WARN_ON(new_offset > old_offset);
 
-               tiles = *x / (512/cpp);
-               *x %= 512/cpp;
+       tiles = (old_offset - new_offset) / tile_size;
 
-               return tile_rows * pitch * 8 + tiles * 4096;
-       } else {
-               unsigned int alignment = intel_linear_alignment(dev_priv) - 1;
-               unsigned int offset;
+       *y += tiles / pitch_tiles * tile_height;
+       *x += tiles % pitch_tiles * tile_width;
+
+       return new_offset;
+}
+
+/*
+ * Computes the linear offset to the base tile and adjusts
+ * x, y. bytes per pixel is assumed to be a power-of-two.
+ *
+ * In the 90/270 rotated case, x and y are assumed
+ * to be already rotated to match the rotated GTT view, and
+ * pitch is the tile_height aligned framebuffer height.
+ */
+u32 intel_compute_tile_offset(int *x, int *y,
+                             const struct drm_framebuffer *fb, int plane,
+                             unsigned int pitch,
+                             unsigned int rotation)
+{
+       const struct drm_i915_private *dev_priv = to_i915(fb->dev);
+       uint64_t fb_modifier = fb->modifier[plane];
+       unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
+       u32 offset, offset_aligned, alignment;
+
+       alignment = intel_surf_alignment(dev_priv, fb_modifier);
+       if (alignment)
+               alignment--;
+
+       if (fb_modifier != DRM_FORMAT_MOD_NONE) {
+               unsigned int tile_size, tile_width, tile_height;
+               unsigned int tile_rows, tiles, pitch_tiles;
+
+               tile_size = intel_tile_size(dev_priv);
+               intel_tile_dims(dev_priv, &tile_width, &tile_height,
+                               fb_modifier, cpp);
+
+               if (intel_rotation_90_or_270(rotation)) {
+                       pitch_tiles = pitch / tile_height;
+                       swap(tile_width, tile_height);
+               } else {
+                       pitch_tiles = pitch / (tile_width * cpp);
+               }
+
+               tile_rows = *y / tile_height;
+               *y %= tile_height;
+
+               tiles = *x / tile_width;
+               *x %= tile_width;
+
+               offset = (tile_rows * pitch_tiles + tiles) * tile_size;
+               offset_aligned = offset & ~alignment;
 
+               intel_adjust_tile_offset(x, y, tile_width, tile_height,
+                                        tile_size, pitch_tiles,
+                                        offset, offset_aligned);
+       } else {
                offset = *y * pitch + *x * cpp;
+               offset_aligned = offset & ~alignment;
+
                *y = (offset & alignment) / pitch;
                *x = ((offset & alignment) - *y * pitch) / cpp;
-               return offset & ~alignment;
        }
+
+       return offset_aligned;
 }
 
 static int i9xx_format_to_fourcc(int format)
@@ -2536,15 +2459,19 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
        /* If the FB is too big, just don't use it since fbdev is not very
         * important and we should probably use that space with FBC or other
         * features. */
-       if (size_aligned * 2 > dev_priv->gtt.stolen_usable_size)
+       if (size_aligned * 2 > dev_priv->ggtt.stolen_usable_size)
                return false;
 
+       mutex_lock(&dev->struct_mutex);
+
        obj = i915_gem_object_create_stolen_for_preallocated(dev,
                                                             base_aligned,
                                                             base_aligned,
                                                             size_aligned);
-       if (!obj)
+       if (!obj) {
+               mutex_unlock(&dev->struct_mutex);
                return false;
+       }
 
        obj->tiling_mode = plane_config->tiling;
        if (obj->tiling_mode == I915_TILING_X)
@@ -2557,12 +2484,12 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
        mode_cmd.modifier[0] = fb->modifier[0];
        mode_cmd.flags = DRM_MODE_FB_MODIFIERS;
 
-       mutex_lock(&dev->struct_mutex);
        if (intel_framebuffer_init(dev, to_intel_framebuffer(fb),
                                   &mode_cmd, obj)) {
                DRM_DEBUG_KMS("intel fb init failed\n");
                goto out_unref_obj;
        }
+
        mutex_unlock(&dev->struct_mutex);
 
        DRM_DEBUG_KMS("initial plane fb obj %p\n", obj);
@@ -2601,6 +2528,8 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
        struct drm_plane_state *plane_state = primary->state;
        struct drm_crtc_state *crtc_state = intel_crtc->base.state;
        struct intel_plane *intel_plane = to_intel_plane(primary);
+       struct intel_plane_state *intel_state =
+               to_intel_plane_state(plane_state);
        struct drm_framebuffer *fb;
 
        if (!plane_config->fb)
@@ -2646,7 +2575,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
         */
        to_intel_plane_state(plane_state)->visible = false;
        crtc_state->plane_mask &= ~(1 << drm_plane_index(primary));
-       intel_pre_disable_primary(&intel_crtc->base);
+       intel_pre_disable_primary_noatomic(&intel_crtc->base);
        intel_plane->disable_plane(primary, &intel_crtc->base);
 
        return;
@@ -2662,6 +2591,15 @@ valid_fb:
        plane_state->crtc_w = fb->width;
        plane_state->crtc_h = fb->height;
 
+       intel_state->src.x1 = plane_state->src_x;
+       intel_state->src.y1 = plane_state->src_y;
+       intel_state->src.x2 = plane_state->src_x + plane_state->src_w;
+       intel_state->src.y2 = plane_state->src_y + plane_state->src_h;
+       intel_state->dst.x1 = plane_state->crtc_x;
+       intel_state->dst.y1 = plane_state->crtc_y;
+       intel_state->dst.x2 = plane_state->crtc_x + plane_state->crtc_w;
+       intel_state->dst.y2 = plane_state->crtc_y + plane_state->crtc_h;
+
        obj = intel_fb_obj(fb);
        if (obj->tiling_mode != I915_TILING_NONE)
                dev_priv->preserve_bios_swizzle = true;
@@ -2673,37 +2611,23 @@ valid_fb:
        obj->frontbuffer_bits |= to_intel_plane(primary)->frontbuffer_bit;
 }
 
-static void i9xx_update_primary_plane(struct drm_crtc *crtc,
-                                     struct drm_framebuffer *fb,
-                                     int x, int y)
+static void i9xx_update_primary_plane(struct drm_plane *primary,
+                                     const struct intel_crtc_state *crtc_state,
+                                     const struct intel_plane_state *plane_state)
 {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = primary->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct drm_plane *primary = crtc->primary;
-       bool visible = to_intel_plane_state(primary->state)->visible;
-       struct drm_i915_gem_object *obj;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_framebuffer *fb = plane_state->base.fb;
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int plane = intel_crtc->plane;
-       unsigned long linear_offset;
+       u32 linear_offset;
        u32 dspcntr;
        i915_reg_t reg = DSPCNTR(plane);
-       int pixel_size;
-
-       if (!visible || !fb) {
-               I915_WRITE(reg, 0);
-               if (INTEL_INFO(dev)->gen >= 4)
-                       I915_WRITE(DSPSURF(plane), 0);
-               else
-                       I915_WRITE(DSPADDR(plane), 0);
-               POSTING_READ(reg);
-               return;
-       }
-
-       obj = intel_fb_obj(fb);
-       if (WARN_ON(obj == NULL))
-               return;
-
-       pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+       unsigned int rotation = plane_state->base.rotation;
+       int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+       int x = plane_state->src.x1 >> 16;
+       int y = plane_state->src.y1 >> 16;
 
        dspcntr = DISPPLANE_GAMMA_ENABLE;
 
@@ -2717,13 +2641,13 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
                 * which should always be the user's requested size.
                 */
                I915_WRITE(DSPSIZE(plane),
-                          ((intel_crtc->config->pipe_src_h - 1) << 16) |
-                          (intel_crtc->config->pipe_src_w - 1));
+                          ((crtc_state->pipe_src_h - 1) << 16) |
+                          (crtc_state->pipe_src_w - 1));
                I915_WRITE(DSPPOS(plane), 0);
        } else if (IS_CHERRYVIEW(dev) && plane == PLANE_B) {
                I915_WRITE(PRIMSIZE(plane),
-                          ((intel_crtc->config->pipe_src_h - 1) << 16) |
-                          (intel_crtc->config->pipe_src_w - 1));
+                          ((crtc_state->pipe_src_h - 1) << 16) |
+                          (crtc_state->pipe_src_w - 1));
                I915_WRITE(PRIMPOS(plane), 0);
                I915_WRITE(PRIMCNSTALPHA(plane), 0);
        }
@@ -2761,30 +2685,28 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
        if (IS_G4X(dev))
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
-       linear_offset = y * fb->pitches[0] + x * pixel_size;
+       linear_offset = y * fb->pitches[0] + x * cpp;
 
        if (INTEL_INFO(dev)->gen >= 4) {
                intel_crtc->dspaddr_offset =
-                       intel_gen4_compute_page_offset(dev_priv,
-                                                      &x, &y, obj->tiling_mode,
-                                                      pixel_size,
-                                                      fb->pitches[0]);
+                       intel_compute_tile_offset(&x, &y, fb, 0,
+                                                 fb->pitches[0], rotation);
                linear_offset -= intel_crtc->dspaddr_offset;
        } else {
                intel_crtc->dspaddr_offset = linear_offset;
        }
 
-       if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180)) {
+       if (rotation == BIT(DRM_ROTATE_180)) {
                dspcntr |= DISPPLANE_ROTATE_180;
 
-               x += (intel_crtc->config->pipe_src_w - 1);
-               y += (intel_crtc->config->pipe_src_h - 1);
+               x += (crtc_state->pipe_src_w - 1);
+               y += (crtc_state->pipe_src_h - 1);
 
                /* Finding the last pixel of the last line of the display
                data and adding to linear_offset*/
                linear_offset +=
-                       (intel_crtc->config->pipe_src_h - 1) * fb->pitches[0] +
-                       (intel_crtc->config->pipe_src_w - 1) * pixel_size;
+                       (crtc_state->pipe_src_h - 1) * fb->pitches[0] +
+                       (crtc_state->pipe_src_w - 1) * cpp;
        }
 
        intel_crtc->adjusted_x = x;
@@ -2803,37 +2725,41 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
        POSTING_READ(reg);
 }
 
-static void ironlake_update_primary_plane(struct drm_crtc *crtc,
-                                         struct drm_framebuffer *fb,
-                                         int x, int y)
+static void i9xx_disable_primary_plane(struct drm_plane *primary,
+                                      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);
-       struct drm_plane *primary = crtc->primary;
-       bool visible = to_intel_plane_state(primary->state)->visible;
-       struct drm_i915_gem_object *obj;
        int plane = intel_crtc->plane;
-       unsigned long linear_offset;
-       u32 dspcntr;
-       i915_reg_t reg = DSPCNTR(plane);
-       int pixel_size;
 
-       if (!visible || !fb) {
-               I915_WRITE(reg, 0);
+       I915_WRITE(DSPCNTR(plane), 0);
+       if (INTEL_INFO(dev_priv)->gen >= 4)
                I915_WRITE(DSPSURF(plane), 0);
-               POSTING_READ(reg);
-               return;
-       }
-
-       obj = intel_fb_obj(fb);
-       if (WARN_ON(obj == NULL))
-               return;
+       else
+               I915_WRITE(DSPADDR(plane), 0);
+       POSTING_READ(DSPCNTR(plane));
+}
 
-       pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+static void ironlake_update_primary_plane(struct drm_plane *primary,
+                                         const struct intel_crtc_state *crtc_state,
+                                         const struct intel_plane_state *plane_state)
+{
+       struct drm_device *dev = primary->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_framebuffer *fb = plane_state->base.fb;
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       int plane = intel_crtc->plane;
+       u32 linear_offset;
+       u32 dspcntr;
+       i915_reg_t reg = DSPCNTR(plane);
+       unsigned int rotation = plane_state->base.rotation;
+       int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+       int x = plane_state->src.x1 >> 16;
+       int y = plane_state->src.y1 >> 16;
 
        dspcntr = DISPPLANE_GAMMA_ENABLE;
-
        dspcntr |= DISPLAY_PLANE_ENABLE;
 
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
@@ -2868,25 +2794,23 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
        if (!IS_HASWELL(dev) && !IS_BROADWELL(dev))
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
-       linear_offset = y * fb->pitches[0] + x * pixel_size;
+       linear_offset = y * fb->pitches[0] + x * cpp;
        intel_crtc->dspaddr_offset =
-               intel_gen4_compute_page_offset(dev_priv,
-                                              &x, &y, obj->tiling_mode,
-                                              pixel_size,
-                                              fb->pitches[0]);
+               intel_compute_tile_offset(&x, &y, fb, 0,
+                                         fb->pitches[0], rotation);
        linear_offset -= intel_crtc->dspaddr_offset;
-       if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180)) {
+       if (rotation == BIT(DRM_ROTATE_180)) {
                dspcntr |= DISPPLANE_ROTATE_180;
 
                if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
-                       x += (intel_crtc->config->pipe_src_w - 1);
-                       y += (intel_crtc->config->pipe_src_h - 1);
+                       x += (crtc_state->pipe_src_w - 1);
+                       y += (crtc_state->pipe_src_h - 1);
 
                        /* Finding the last pixel of the last line of the display
                        data and adding to linear_offset*/
                        linear_offset +=
-                               (intel_crtc->config->pipe_src_h - 1) * fb->pitches[0] +
-                               (intel_crtc->config->pipe_src_w - 1) * pixel_size;
+                               (crtc_state->pipe_src_h - 1) * fb->pitches[0] +
+                               (crtc_state->pipe_src_w - 1) * cpp;
                }
        }
 
@@ -2907,37 +2831,15 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
        POSTING_READ(reg);
 }
 
-u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier,
-                             uint32_t pixel_format)
+u32 intel_fb_stride_alignment(const struct drm_i915_private *dev_priv,
+                             uint64_t fb_modifier, uint32_t pixel_format)
 {
-       u32 bits_per_pixel = drm_format_plane_cpp(pixel_format, 0) * 8;
-
-       /*
-        * The stride is either expressed as a multiple of 64 bytes
-        * chunks for linear buffers or in number of tiles for tiled
-        * buffers.
-        */
-       switch (fb_modifier) {
-       case DRM_FORMAT_MOD_NONE:
-               return 64;
-       case I915_FORMAT_MOD_X_TILED:
-               if (INTEL_INFO(dev)->gen == 2)
-                       return 128;
-               return 512;
-       case I915_FORMAT_MOD_Y_TILED:
-               /* No need to check for old gens and Y tiling since this is
-                * about the display engine and those will be blocked before
-                * we get here.
-                */
-               return 128;
-       case I915_FORMAT_MOD_Yf_TILED:
-               if (bits_per_pixel == 8)
-                       return 64;
-               else
-                       return 128;
-       default:
-               MISSING_CASE(fb_modifier);
+       if (fb_modifier == DRM_FORMAT_MOD_NONE) {
                return 64;
+       } else {
+               int cpp = drm_format_plane_cpp(pixel_format, 0);
+
+               return intel_tile_width_bytes(dev_priv, fb_modifier, cpp);
        }
 }
 
@@ -2950,7 +2852,7 @@ u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
        u64 offset;
 
        intel_fill_fb_ggtt_view(&view, intel_plane->base.state->fb,
-                               intel_plane->base.state);
+                               intel_plane->base.state->rotation);
 
        vma = i915_gem_obj_to_ggtt_view(obj, &view);
        if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n",
@@ -2960,7 +2862,7 @@ u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
        offset = vma->node.start;
 
        if (plane == 1) {
-               offset += vma->ggtt_view.params.rotation_info.uv_start_page *
+               offset += vma->ggtt_view.params.rotated.uv_start_page *
                          PAGE_SIZE;
        }
 
@@ -3077,36 +2979,30 @@ u32 skl_plane_ctl_rotation(unsigned int rotation)
        return 0;
 }
 
-static void skylake_update_primary_plane(struct drm_crtc *crtc,
-                                        struct drm_framebuffer *fb,
-                                        int x, int y)
+static void skylake_update_primary_plane(struct drm_plane *plane,
+                                        const struct intel_crtc_state *crtc_state,
+                                        const struct intel_plane_state *plane_state)
 {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct drm_plane *plane = crtc->primary;
-       bool visible = to_intel_plane_state(plane->state)->visible;
-       struct drm_i915_gem_object *obj;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_framebuffer *fb = plane_state->base.fb;
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int pipe = intel_crtc->pipe;
        u32 plane_ctl, stride_div, stride;
        u32 tile_height, plane_offset, plane_size;
-       unsigned int rotation;
+       unsigned int rotation = plane_state->base.rotation;
        int x_offset, y_offset;
        u32 surf_addr;
-       struct intel_crtc_state *crtc_state = intel_crtc->config;
-       struct intel_plane_state *plane_state;
-       int src_x = 0, src_y = 0, src_w = 0, src_h = 0;
-       int dst_x = 0, dst_y = 0, dst_w = 0, dst_h = 0;
-       int scaler_id = -1;
-
-       plane_state = to_intel_plane_state(plane->state);
-
-       if (!visible || !fb) {
-               I915_WRITE(PLANE_CTL(pipe, 0), 0);
-               I915_WRITE(PLANE_SURF(pipe, 0), 0);
-               POSTING_READ(PLANE_CTL(pipe, 0));
-               return;
-       }
+       int scaler_id = plane_state->scaler_id;
+       int src_x = plane_state->src.x1 >> 16;
+       int src_y = plane_state->src.y1 >> 16;
+       int src_w = drm_rect_width(&plane_state->src) >> 16;
+       int src_h = drm_rect_height(&plane_state->src) >> 16;
+       int dst_x = plane_state->dst.x1;
+       int dst_y = plane_state->dst.y1;
+       int dst_w = drm_rect_width(&plane_state->dst);
+       int dst_h = drm_rect_height(&plane_state->dst);
 
        plane_ctl = PLANE_CTL_ENABLE |
                    PLANE_CTL_PIPE_GAMMA_ENABLE |
@@ -3115,41 +3011,27 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
        plane_ctl |= skl_plane_ctl_format(fb->pixel_format);
        plane_ctl |= skl_plane_ctl_tiling(fb->modifier[0]);
        plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
-
-       rotation = plane->state->rotation;
        plane_ctl |= skl_plane_ctl_rotation(rotation);
 
-       obj = intel_fb_obj(fb);
-       stride_div = intel_fb_stride_alignment(dev, fb->modifier[0],
+       stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0],
                                               fb->pixel_format);
        surf_addr = intel_plane_obj_offset(to_intel_plane(plane), obj, 0);
 
        WARN_ON(drm_rect_width(&plane_state->src) == 0);
 
-       scaler_id = plane_state->scaler_id;
-       src_x = plane_state->src.x1 >> 16;
-       src_y = plane_state->src.y1 >> 16;
-       src_w = drm_rect_width(&plane_state->src) >> 16;
-       src_h = drm_rect_height(&plane_state->src) >> 16;
-       dst_x = plane_state->dst.x1;
-       dst_y = plane_state->dst.y1;
-       dst_w = drm_rect_width(&plane_state->dst);
-       dst_h = drm_rect_height(&plane_state->dst);
-
-       WARN_ON(x != src_x || y != src_y);
-
        if (intel_rotation_90_or_270(rotation)) {
+               int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+
                /* stride = Surface height in tiles */
-               tile_height = intel_tile_height(dev, fb->pixel_format,
-                                               fb->modifier[0], 0);
+               tile_height = intel_tile_height(dev_priv, fb->modifier[0], cpp);
                stride = DIV_ROUND_UP(fb->height, tile_height);
-               x_offset = stride * tile_height - y - src_h;
-               y_offset = x;
+               x_offset = stride * tile_height - src_y - src_h;
+               y_offset = src_x;
                plane_size = (src_w - 1) << 16 | (src_h - 1);
        } else {
                stride = fb->pitches[0] / stride_div;
-               x_offset = x;
-               y_offset = y;
+               x_offset = src_x;
+               y_offset = src_y;
                plane_size = (src_h - 1) << 16 | (src_w - 1);
        }
        plane_offset = y_offset << 16 | x_offset;
@@ -3182,20 +3064,27 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
        POSTING_READ(PLANE_SURF(pipe, 0));
 }
 
-/* Assume fb object is pinned & idle & fenced and just update base pointers */
-static int
-intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
-                          int x, int y, enum mode_set_atomic state)
+static void skylake_disable_primary_plane(struct drm_plane *primary,
+                                         struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe = to_intel_crtc(crtc)->pipe;
 
-       if (dev_priv->fbc.deactivate)
-               dev_priv->fbc.deactivate(dev_priv);
+       I915_WRITE(PLANE_CTL(pipe, 0), 0);
+       I915_WRITE(PLANE_SURF(pipe, 0), 0);
+       POSTING_READ(PLANE_SURF(pipe, 0));
+}
 
-       dev_priv->display.update_primary_plane(crtc, fb, x, y);
+/* Assume fb object is pinned & idle & fenced and just update base pointers */
+static int
+intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+                          int x, int y, enum mode_set_atomic state)
+{
+       /* Support for kgdboc is disabled, this needs a major rework. */
+       DRM_ERROR("legacy panic handler not supported any more.\n");
 
-       return 0;
+       return -ENODEV;
 }
 
 static void intel_complete_page_flips(struct drm_device *dev)
@@ -3222,8 +3111,10 @@ static void intel_update_primary_planes(struct drm_device *dev)
                drm_modeset_lock_crtc(crtc, &plane->base);
                plane_state = to_intel_plane_state(plane->base.state);
 
-               if (crtc->state->active && plane_state->base.fb)
-                       plane->commit_plane(&plane->base, plane_state);
+               if (plane_state->visible)
+                       plane->update_plane(&plane->base,
+                                           to_intel_crtc_state(crtc->state),
+                                           plane_state);
 
                drm_modeset_unlock_crtc(crtc);
        }
@@ -3331,9 +3222,6 @@ static void intel_update_pipe_config(struct intel_crtc *crtc,
                      old_crtc_state->pipe_src_w, old_crtc_state->pipe_src_h,
                      pipe_config->pipe_src_w, pipe_config->pipe_src_h);
 
-       if (HAS_DDI(dev))
-               intel_set_pipe_csc(&crtc->base);
-
        /*
         * Update pipe size and adjust fitter if needed: the reason for this is
         * that in compute_mode_changes we check the native mode (not the pfit
@@ -3972,37 +3860,35 @@ static void lpt_disable_iclkip(struct drm_i915_private *dev_priv)
 /* Program iCLKIP clock to the desired frequency */
 static void lpt_program_iclkip(struct drm_crtc *crtc)
 {
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
        int clock = to_intel_crtc(crtc)->config->base.adjusted_mode.crtc_clock;
        u32 divsel, phaseinc, auxdiv, phasedir = 0;
        u32 temp;
 
        lpt_disable_iclkip(dev_priv);
 
-       /* 20MHz is a corner case which is out of range for the 7-bit divisor */
-       if (clock == 20000) {
-               auxdiv = 1;
-               divsel = 0x41;
-               phaseinc = 0x20;
-       } else {
-               /* The iCLK virtual clock root frequency is in MHz,
-                * but the adjusted_mode->crtc_clock in in KHz. To get the
-                * divisors, it is necessary to divide one by another, so we
-                * convert the virtual clock precision to KHz here for higher
-                * precision.
-                */
+       /* The iCLK virtual clock root frequency is in MHz,
+        * but the adjusted_mode->crtc_clock in in KHz. To get the
+        * divisors, it is necessary to divide one by another, so we
+        * convert the virtual clock precision to KHz here for higher
+        * precision.
+        */
+       for (auxdiv = 0; auxdiv < 2; auxdiv++) {
                u32 iclk_virtual_root_freq = 172800 * 1000;
                u32 iclk_pi_range = 64;
-               u32 desired_divisor, msb_divisor_value, pi_value;
+               u32 desired_divisor;
 
-               desired_divisor = DIV_ROUND_CLOSEST(iclk_virtual_root_freq, clock);
-               msb_divisor_value = desired_divisor / iclk_pi_range;
-               pi_value = desired_divisor % iclk_pi_range;
+               desired_divisor = DIV_ROUND_CLOSEST(iclk_virtual_root_freq,
+                                                   clock << auxdiv);
+               divsel = (desired_divisor / iclk_pi_range) - 2;
+               phaseinc = desired_divisor % iclk_pi_range;
 
-               auxdiv = 0;
-               divsel = msb_divisor_value - 2;
-               phaseinc = pi_value;
+               /*
+                * Near 20MHz is a corner case which is
+                * out of range for the 7-bit divisor
+                */
+               if (divsel <= 0x7f)
+                       break;
        }
 
        /* This should not happen with any sane values */
@@ -4049,6 +3935,43 @@ static void lpt_program_iclkip(struct drm_crtc *crtc)
        I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE);
 }
 
+int lpt_get_iclkip(struct drm_i915_private *dev_priv)
+{
+       u32 divsel, phaseinc, auxdiv;
+       u32 iclk_virtual_root_freq = 172800 * 1000;
+       u32 iclk_pi_range = 64;
+       u32 desired_divisor;
+       u32 temp;
+
+       if ((I915_READ(PIXCLK_GATE) & PIXCLK_GATE_UNGATE) == 0)
+               return 0;
+
+       mutex_lock(&dev_priv->sb_lock);
+
+       temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
+       if (temp & SBI_SSCCTL_DISABLE) {
+               mutex_unlock(&dev_priv->sb_lock);
+               return 0;
+       }
+
+       temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);
+       divsel = (temp & SBI_SSCDIVINTPHASE_DIVSEL_MASK) >>
+               SBI_SSCDIVINTPHASE_DIVSEL_SHIFT;
+       phaseinc = (temp & SBI_SSCDIVINTPHASE_INCVAL_MASK) >>
+               SBI_SSCDIVINTPHASE_INCVAL_SHIFT;
+
+       temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK);
+       auxdiv = (temp & SBI_SSCAUXDIV_FINALDIV2SEL_MASK) >>
+               SBI_SSCAUXDIV_FINALDIV2SEL_SHIFT;
+
+       mutex_unlock(&dev_priv->sb_lock);
+
+       desired_divisor = (divsel + 2) * iclk_pi_range + phaseinc;
+
+       return DIV_ROUND_CLOSEST(iclk_virtual_root_freq,
+                                desired_divisor << auxdiv);
+}
+
 static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc,
                                                enum pipe pch_transcoder)
 {
@@ -4176,7 +4099,8 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
                temp = I915_READ(PCH_DPLL_SEL);
                temp |= TRANS_DPLL_ENABLE(pipe);
                sel = TRANS_DPLLB_SEL(pipe);
-               if (intel_crtc->config->shared_dpll == DPLL_ID_PCH_PLL_B)
+               if (intel_crtc->config->shared_dpll ==
+                   intel_get_shared_dpll_by_id(dev_priv, DPLL_ID_PCH_PLL_B))
                        temp |= sel;
                else
                        temp &= ~sel;
@@ -4255,113 +4179,6 @@ static void lpt_pch_enable(struct drm_crtc *crtc)
        lpt_enable_pch_transcoder(dev_priv, cpu_transcoder);
 }
 
-struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
-                                               struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
-       struct intel_shared_dpll *pll;
-       struct intel_shared_dpll_config *shared_dpll;
-       enum intel_dpll_id i;
-       int max = dev_priv->num_shared_dpll;
-
-       shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
-
-       if (HAS_PCH_IBX(dev_priv->dev)) {
-               /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
-               i = (enum intel_dpll_id) crtc->pipe;
-               pll = &dev_priv->shared_dplls[i];
-
-               DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
-                             crtc->base.base.id, pll->name);
-
-               WARN_ON(shared_dpll[i].crtc_mask);
-
-               goto found;
-       }
-
-       if (IS_BROXTON(dev_priv->dev)) {
-               /* PLL is attached to port in bxt */
-               struct intel_encoder *encoder;
-               struct intel_digital_port *intel_dig_port;
-
-               encoder = intel_ddi_get_crtc_new_encoder(crtc_state);
-               if (WARN_ON(!encoder))
-                       return NULL;
-
-               intel_dig_port = enc_to_dig_port(&encoder->base);
-               /* 1:1 mapping between ports and PLLs */
-               i = (enum intel_dpll_id)intel_dig_port->port;
-               pll = &dev_priv->shared_dplls[i];
-               DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
-                       crtc->base.base.id, pll->name);
-               WARN_ON(shared_dpll[i].crtc_mask);
-
-               goto found;
-       } else if (INTEL_INFO(dev_priv)->gen < 9 && HAS_DDI(dev_priv))
-               /* Do not consider SPLL */
-               max = 2;
-
-       for (i = 0; i < max; i++) {
-               pll = &dev_priv->shared_dplls[i];
-
-               /* Only want to check enabled timings first */
-               if (shared_dpll[i].crtc_mask == 0)
-                       continue;
-
-               if (memcmp(&crtc_state->dpll_hw_state,
-                          &shared_dpll[i].hw_state,
-                          sizeof(crtc_state->dpll_hw_state)) == 0) {
-                       DRM_DEBUG_KMS("CRTC:%d sharing existing %s (crtc mask 0x%08x, ative %d)\n",
-                                     crtc->base.base.id, pll->name,
-                                     shared_dpll[i].crtc_mask,
-                                     pll->active);
-                       goto found;
-               }
-       }
-
-       /* Ok no matching timings, maybe there's a free one? */
-       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
-               pll = &dev_priv->shared_dplls[i];
-               if (shared_dpll[i].crtc_mask == 0) {
-                       DRM_DEBUG_KMS("CRTC:%d allocated %s\n",
-                                     crtc->base.base.id, pll->name);
-                       goto found;
-               }
-       }
-
-       return NULL;
-
-found:
-       if (shared_dpll[i].crtc_mask == 0)
-               shared_dpll[i].hw_state =
-                       crtc_state->dpll_hw_state;
-
-       crtc_state->shared_dpll = i;
-       DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name,
-                        pipe_name(crtc->pipe));
-
-       shared_dpll[i].crtc_mask |= 1 << crtc->pipe;
-
-       return pll;
-}
-
-static void intel_shared_dpll_commit(struct drm_atomic_state *state)
-{
-       struct drm_i915_private *dev_priv = to_i915(state->dev);
-       struct intel_shared_dpll_config *shared_dpll;
-       struct intel_shared_dpll *pll;
-       enum intel_dpll_id i;
-
-       if (!to_intel_atomic_state(state)->dpll_set)
-               return;
-
-       shared_dpll = to_intel_atomic_state(state)->shared_dpll;
-       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
-               pll = &dev_priv->shared_dplls[i];
-               pll->config = shared_dpll[i];
-       }
-}
-
 static void cpt_verify_modeset(struct drm_device *dev, int pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4455,7 +4272,7 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state)
                      intel_crtc->base.base.id, intel_crtc->pipe, SKL_CRTC_INDEX);
 
        return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX,
-               &state->scaler_state.scaler_id, DRM_ROTATE_0,
+               &state->scaler_state.scaler_id, BIT(DRM_ROTATE_0),
                state->pipe_src_w, state->pipe_src_h,
                adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_vdisplay);
 }
@@ -4593,8 +4410,11 @@ void hsw_enable_ips(struct intel_crtc *crtc)
        if (!crtc->config->ips_enabled)
                return;
 
-       /* We can only enable IPS after we enable a plane and wait for a vblank */
-       intel_wait_for_vblank(dev, crtc->pipe);
+       /*
+        * We can only enable IPS after we enable a plane and wait for a vblank
+        * This function is called from post_plane_update, which is run after
+        * a vblank wait.
+        */
 
        assert_plane_enabled(dev_priv, crtc->plane);
        if (IS_BROADWELL(dev)) {
@@ -4643,55 +4463,6 @@ void hsw_disable_ips(struct intel_crtc *crtc)
        intel_wait_for_vblank(dev, crtc->pipe);
 }
 
-/** Loads the palette/gamma unit for the CRTC with the prepared values */
-static 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);
-       enum pipe pipe = intel_crtc->pipe;
-       int i;
-       bool reenable_ips = false;
-
-       /* The clocks have to be on to load the palette. */
-       if (!crtc->state->active)
-               return;
-
-       if (HAS_GMCH_DISPLAY(dev_priv->dev)) {
-               if (intel_crtc->config->has_dsi_encoder)
-                       assert_dsi_pll_enabled(dev_priv);
-               else
-                       assert_pll_enabled(dev_priv, pipe);
-       }
-
-       /* Workaround : Do not read or write the pipe palette/gamma data while
-        * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
-        */
-       if (IS_HASWELL(dev) && intel_crtc->config->ips_enabled &&
-           ((I915_READ(GAMMA_MODE(pipe)) & GAMMA_MODE_MODE_MASK) ==
-            GAMMA_MODE_MODE_SPLIT)) {
-               hsw_disable_ips(intel_crtc);
-               reenable_ips = true;
-       }
-
-       for (i = 0; i < 256; i++) {
-               i915_reg_t palreg;
-
-               if (HAS_GMCH_DISPLAY(dev))
-                       palreg = PALETTE(pipe, i);
-               else
-                       palreg = LGC_PALETTE(pipe, i);
-
-               I915_WRITE(palreg,
-                          (intel_crtc->lut_r[i] << 16) |
-                          (intel_crtc->lut_g[i] << 8) |
-                          intel_crtc->lut_b[i]);
-       }
-
-       if (reenable_ips)
-               hsw_enable_ips(intel_crtc);
-}
-
 static void intel_crtc_dpms_overlay_disable(struct intel_crtc *intel_crtc)
 {
        if (intel_crtc->overlay) {
@@ -4751,16 +4522,7 @@ intel_post_enable_primary(struct drm_crtc *crtc)
        intel_check_pch_fifo_underruns(dev_priv);
 }
 
-/**
- * intel_pre_disable_primary - Perform operations before disabling primary plane
- * @crtc: the CRTC whose primary plane is to be disabled
- *
- * Performs potentially sleeping operations that must be done before the
- * primary plane is disabled, such as updating FBC and IPS.  Note that this may
- * be called due to an explicit primary plane update, or due to an implicit
- * disable that is caused when a sprite plane completely hides the primary
- * plane.
- */
+/* FIXME move all this to pre_plane_update() with proper state tracking */
 static void
 intel_pre_disable_primary(struct drm_crtc *crtc)
 {
@@ -4778,6 +4540,26 @@ intel_pre_disable_primary(struct drm_crtc *crtc)
        if (IS_GEN2(dev))
                intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
 
+       /*
+        * FIXME IPS should be fine as long as one plane is
+        * enabled, but in practice it seems to have problems
+        * when going from primary only to sprite only and vice
+        * versa.
+        */
+       hsw_disable_ips(intel_crtc);
+}
+
+/* FIXME get rid of this and use pre_plane_update */
+static void
+intel_pre_disable_primary_noatomic(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+
+       intel_pre_disable_primary(crtc);
+
        /*
         * Vblank time updates from the shadow to live plane control register
         * are blocked if the memory self-refresh mode is active at that
@@ -4792,71 +4574,128 @@ intel_pre_disable_primary(struct drm_crtc *crtc)
                dev_priv->wm.vlv.cxsr = false;
                intel_wait_for_vblank(dev, pipe);
        }
-
-       /*
-        * FIXME IPS should be fine as long as one plane is
-        * enabled, but in practice it seems to have problems
-        * when going from primary only to sprite only and vice
-        * versa.
-        */
-       hsw_disable_ips(intel_crtc);
 }
 
-static void intel_post_plane_update(struct intel_crtc *crtc)
+static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state)
 {
-       struct intel_crtc_atomic_commit *atomic = &crtc->atomic;
+       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
+       struct drm_atomic_state *old_state = old_crtc_state->base.state;
        struct intel_crtc_state *pipe_config =
                to_intel_crtc_state(crtc->base.state);
        struct drm_device *dev = crtc->base.dev;
+       struct drm_plane *primary = crtc->base.primary;
+       struct drm_plane_state *old_pri_state =
+               drm_atomic_get_existing_plane_state(old_state, primary);
 
-       if (atomic->wait_vblank)
-               intel_wait_for_vblank(dev, crtc->pipe);
-
-       intel_frontbuffer_flip(dev, atomic->fb_bits);
+       intel_frontbuffer_flip(dev, pipe_config->fb_bits);
 
        crtc->wm.cxsr_allowed = true;
 
-       if (pipe_config->wm_changed && pipe_config->base.active)
+       if (pipe_config->update_wm_post && pipe_config->base.active)
                intel_update_watermarks(&crtc->base);
 
-       if (atomic->update_fbc)
-               intel_fbc_update(crtc);
+       if (old_pri_state) {
+               struct intel_plane_state *primary_state =
+                       to_intel_plane_state(primary->state);
+               struct intel_plane_state *old_primary_state =
+                       to_intel_plane_state(old_pri_state);
 
-       if (atomic->post_enable_primary)
-               intel_post_enable_primary(&crtc->base);
+               intel_fbc_post_update(crtc);
 
-       memset(atomic, 0, sizeof(*atomic));
+               if (primary_state->visible &&
+                   (needs_modeset(&pipe_config->base) ||
+                    !old_primary_state->visible))
+                       intel_post_enable_primary(&crtc->base);
+       }
 }
 
-static void intel_pre_plane_update(struct intel_crtc *crtc)
+static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state)
 {
+       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc_atomic_commit *atomic = &crtc->atomic;
        struct intel_crtc_state *pipe_config =
                to_intel_crtc_state(crtc->base.state);
+       struct drm_atomic_state *old_state = old_crtc_state->base.state;
+       struct drm_plane *primary = crtc->base.primary;
+       struct drm_plane_state *old_pri_state =
+               drm_atomic_get_existing_plane_state(old_state, primary);
+       bool modeset = needs_modeset(&pipe_config->base);
 
-       if (atomic->disable_fbc)
-               intel_fbc_deactivate(crtc);
+       if (old_pri_state) {
+               struct intel_plane_state *primary_state =
+                       to_intel_plane_state(primary->state);
+               struct intel_plane_state *old_primary_state =
+                       to_intel_plane_state(old_pri_state);
 
-       if (crtc->atomic.disable_ips)
-               hsw_disable_ips(crtc);
+               intel_fbc_pre_update(crtc);
 
-       if (atomic->pre_disable_primary)
-               intel_pre_disable_primary(&crtc->base);
+               if (old_primary_state->visible &&
+                   (modeset || !primary_state->visible))
+                       intel_pre_disable_primary(&crtc->base);
+       }
 
        if (pipe_config->disable_cxsr) {
                crtc->wm.cxsr_allowed = false;
-               intel_set_memory_cxsr(dev_priv, false);
-       }
 
-       if (!needs_modeset(&pipe_config->base) && pipe_config->wm_changed)
-               intel_update_watermarks(&crtc->base);
-}
+               /*
+                * Vblank time updates from the shadow to live plane control register
+                * are blocked if the memory self-refresh mode is active at that
+                * moment. So to make sure the plane gets truly disabled, disable
+                * first the self-refresh mode. The self-refresh enable bit in turn
+                * will be checked/applied by the HW only at the next frame start
+                * event which is after the vblank start event, so we need to have a
+                * wait-for-vblank between disabling the plane and the pipe.
+                */
+               if (old_crtc_state->base.active) {
+                       intel_set_memory_cxsr(dev_priv, false);
+                       dev_priv->wm.vlv.cxsr = false;
+                       intel_wait_for_vblank(dev, crtc->pipe);
+               }
+       }
 
-static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask)
-{
-       struct drm_device *dev = crtc->dev;
+       /*
+        * IVB workaround: must disable low power watermarks for at least
+        * one frame before enabling scaling.  LP watermarks can be re-enabled
+        * when scaling is disabled.
+        *
+        * WaCxSRDisabledForSpriteScaling:ivb
+        */
+       if (pipe_config->disable_lp_wm) {
+               ilk_disable_lp_wm(dev);
+               intel_wait_for_vblank(dev, crtc->pipe);
+       }
+
+       /*
+        * If we're doing a modeset, we're done.  No need to do any pre-vblank
+        * watermark programming here.
+        */
+       if (needs_modeset(&pipe_config->base))
+               return;
+
+       /*
+        * For platforms that support atomic watermarks, program the
+        * 'intermediate' watermarks immediately.  On pre-gen9 platforms, these
+        * will be the intermediate values that are safe for both pre- and
+        * post- vblank; when vblank happens, the 'active' values will be set
+        * to the final 'target' values and we'll do this again to get the
+        * optimal watermarks.  For gen9+ platforms, the values we program here
+        * will be the final target values which will get automatically latched
+        * at vblank time; no further programming will be necessary.
+        *
+        * If a platform hasn't been transitioned to atomic watermarks yet,
+        * we'll continue to update watermarks the old way, if flags tell
+        * us to.
+        */
+       if (dev_priv->display.initial_watermarks != NULL)
+               dev_priv->display.initial_watermarks(pipe_config);
+       else if (pipe_config->update_wm_pre)
+               intel_update_watermarks(&crtc->base);
+}
+
+static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask)
+{
+       struct drm_device *dev = crtc->dev;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_plane *p;
        int pipe = intel_crtc->pipe;
@@ -4881,6 +4720,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
+       struct intel_crtc_state *pipe_config =
+               to_intel_crtc_state(crtc->state);
 
        if (WARN_ON(intel_crtc->active))
                return;
@@ -4895,6 +4736,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
                intel_dp_set_m_n(intel_crtc, M1_N1);
 
        intel_set_pipe_timings(intel_crtc);
+       intel_set_pipe_src_size(intel_crtc);
 
        if (intel_crtc->config->has_pch_encoder) {
                intel_cpu_transcoder_set_m_n(intel_crtc,
@@ -4927,9 +4769,10 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
         * On ILK+ LUT must be loaded before the pipe is running but with
         * clocks enabled
         */
-       intel_crtc_load_lut(crtc);
+       intel_color_load_luts(&pipe_config->base);
 
-       intel_update_watermarks(crtc);
+       if (dev_priv->display.initial_watermarks != NULL)
+               dev_priv->display.initial_watermarks(intel_crtc->config);
        intel_enable_pipe(intel_crtc);
 
        if (intel_crtc->config->has_pch_encoder)
@@ -4948,8 +4791,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        if (intel_crtc->config->has_pch_encoder)
                intel_wait_for_vblank(dev, pipe);
        intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
-
-       intel_fbc_enable(intel_crtc);
 }
 
 /* IPS only exists on ULT machines and is tied to pipe A. */
@@ -4965,6 +4806,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe, hsw_workaround_pipe;
+       enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
        struct intel_crtc_state *pipe_config =
                to_intel_crtc_state(crtc->state);
 
@@ -4975,16 +4817,20 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
                intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
                                                      false);
 
-       if (intel_crtc_to_shared_dpll(intel_crtc))
+       if (intel_crtc->config->shared_dpll)
                intel_enable_shared_dpll(intel_crtc);
 
        if (intel_crtc->config->has_dp_encoder)
                intel_dp_set_m_n(intel_crtc, M1_N1);
 
-       intel_set_pipe_timings(intel_crtc);
+       if (!intel_crtc->config->has_dsi_encoder)
+               intel_set_pipe_timings(intel_crtc);
 
-       if (intel_crtc->config->cpu_transcoder != TRANSCODER_EDP) {
-               I915_WRITE(PIPE_MULT(intel_crtc->config->cpu_transcoder),
+       intel_set_pipe_src_size(intel_crtc);
+
+       if (cpu_transcoder != TRANSCODER_EDP &&
+           !transcoder_is_dsi(cpu_transcoder)) {
+               I915_WRITE(PIPE_MULT(cpu_transcoder),
                           intel_crtc->config->pixel_multiplier - 1);
        }
 
@@ -4993,9 +4839,12 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
                                     &intel_crtc->config->fdi_m_n, NULL);
        }
 
-       haswell_set_pipeconf(crtc);
+       if (!intel_crtc->config->has_dsi_encoder)
+               haswell_set_pipeconf(crtc);
+
+       haswell_set_pipemisc(crtc);
 
-       intel_set_pipe_csc(crtc);
+       intel_color_set_csc(&pipe_config->base);
 
        intel_crtc->active = true;
 
@@ -5024,14 +4873,20 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
         * On ILK+ LUT must be loaded before the pipe is running but with
         * clocks enabled
         */
-       intel_crtc_load_lut(crtc);
+       intel_color_load_luts(&pipe_config->base);
 
        intel_ddi_set_pipe_settings(crtc);
        if (!intel_crtc->config->has_dsi_encoder)
                intel_ddi_enable_transcoder_func(crtc);
 
-       intel_update_watermarks(crtc);
-       intel_enable_pipe(intel_crtc);
+       if (dev_priv->display.initial_watermarks != NULL)
+               dev_priv->display.initial_watermarks(pipe_config);
+       else
+               intel_update_watermarks(crtc);
+
+       /* XXX: Do the pipe assertions at the right place for BXT DSI. */
+       if (!intel_crtc->config->has_dsi_encoder)
+               intel_enable_pipe(intel_crtc);
 
        if (intel_crtc->config->has_pch_encoder)
                lpt_pch_enable(crtc);
@@ -5062,8 +4917,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
                intel_wait_for_vblank(dev, hsw_workaround_pipe);
                intel_wait_for_vblank(dev, hsw_workaround_pipe);
        }
-
-       intel_fbc_enable(intel_crtc);
 }
 
 static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force)
@@ -5144,8 +4997,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
        }
 
        intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
-
-       intel_fbc_disable_crtc(intel_crtc);
 }
 
 static void haswell_crtc_disable(struct drm_crtc *crtc)
@@ -5168,7 +5019,9 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
        drm_crtc_vblank_off(crtc);
        assert_vblank_disabled(crtc);
 
-       intel_disable_pipe(intel_crtc);
+       /* XXX: Do the pipe assertions at the right place for BXT DSI. */
+       if (!intel_crtc->config->has_dsi_encoder)
+               intel_disable_pipe(intel_crtc);
 
        if (intel_crtc->config->dp_encoder_is_mst)
                intel_ddi_set_vc_payload_alloc(crtc, false);
@@ -5196,8 +5049,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
                intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
                                                      true);
        }
-
-       intel_fbc_disable_crtc(intel_crtc);
 }
 
 static void i9xx_pfit_enable(struct intel_crtc *crtc)
@@ -5320,31 +5171,40 @@ intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder)
        }
 }
 
-static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
+static unsigned long get_crtc_power_domains(struct drm_crtc *crtc,
+                                           struct intel_crtc_state *crtc_state)
 {
        struct drm_device *dev = crtc->dev;
-       struct intel_encoder *intel_encoder;
+       struct drm_encoder *encoder;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        enum pipe pipe = intel_crtc->pipe;
        unsigned long mask;
-       enum transcoder transcoder = intel_crtc->config->cpu_transcoder;
+       enum transcoder transcoder = crtc_state->cpu_transcoder;
 
-       if (!crtc->state->active)
+       if (!crtc_state->base.active)
                return 0;
 
        mask = BIT(POWER_DOMAIN_PIPE(pipe));
        mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder));
-       if (intel_crtc->config->pch_pfit.enabled ||
-           intel_crtc->config->pch_pfit.force_thru)
+       if (crtc_state->pch_pfit.enabled ||
+           crtc_state->pch_pfit.force_thru)
                mask |= BIT(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe));
 
-       for_each_encoder_on_crtc(dev, crtc, intel_encoder)
+       drm_for_each_encoder_mask(encoder, dev, crtc_state->base.encoder_mask) {
+               struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
+
                mask |= BIT(intel_display_port_power_domain(intel_encoder));
+       }
+
+       if (crtc_state->shared_dpll)
+               mask |= BIT(POWER_DOMAIN_PLLS);
 
        return mask;
 }
 
-static unsigned long modeset_get_crtc_power_domains(struct drm_crtc *crtc)
+static unsigned long
+modeset_get_crtc_power_domains(struct drm_crtc *crtc,
+                              struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *dev_priv = crtc->dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -5352,7 +5212,8 @@ static unsigned long modeset_get_crtc_power_domains(struct drm_crtc *crtc)
        unsigned long domains, new_domains, old_domains;
 
        old_domains = intel_crtc->enabled_power_domains;
-       intel_crtc->enabled_power_domains = new_domains = get_crtc_power_domains(crtc);
+       intel_crtc->enabled_power_domains = new_domains =
+               get_crtc_power_domains(crtc, crtc_state);
 
        domains = new_domains & ~old_domains;
 
@@ -5371,34 +5232,6 @@ static void modeset_put_power_domains(struct drm_i915_private *dev_priv,
                intel_display_power_put(dev_priv, domain);
 }
 
-static void modeset_update_crtc_power_domains(struct drm_atomic_state *state)
-{
-       struct drm_device *dev = state->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long put_domains[I915_MAX_PIPES] = {};
-       struct drm_crtc_state *crtc_state;
-       struct drm_crtc *crtc;
-       int i;
-
-       for_each_crtc_in_state(state, crtc, crtc_state, i) {
-               if (needs_modeset(crtc->state))
-                       put_domains[to_intel_crtc(crtc)->pipe] =
-                               modeset_get_crtc_power_domains(crtc);
-       }
-
-       if (dev_priv->display.modeset_commit_cdclk) {
-               unsigned int cdclk = to_intel_atomic_state(state)->cdclk;
-
-               if (cdclk != dev_priv->cdclk_freq &&
-                   !WARN_ON(!state->allow_modeset))
-                       dev_priv->display.modeset_commit_cdclk(state);
-       }
-
-       for (i = 0; i < I915_MAX_PIPES; i++)
-               if (put_domains[i])
-                       modeset_put_power_domains(dev_priv, put_domains[i]);
-}
-
 static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
 {
        int max_cdclk_freq = dev_priv->max_cdclk_freq;
@@ -6061,27 +5894,32 @@ static int broxton_calc_cdclk(struct drm_i915_private *dev_priv,
                return 144000;
 }
 
-/* Compute the max pixel clock for new configuration. Uses atomic state if
- * that's non-NULL, look at current state otherwise. */
+/* Compute the max pixel clock for new configuration. */
 static int intel_mode_max_pixclk(struct drm_device *dev,
                                 struct drm_atomic_state *state)
 {
-       struct intel_crtc *intel_crtc;
-       struct intel_crtc_state *crtc_state;
-       int max_pixclk = 0;
+       struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *crtc_state;
+       unsigned max_pixclk = 0, i;
+       enum pipe pipe;
 
-       for_each_intel_crtc(dev, intel_crtc) {
-               crtc_state = intel_atomic_get_crtc_state(state, intel_crtc);
-               if (IS_ERR(crtc_state))
-                       return PTR_ERR(crtc_state);
+       memcpy(intel_state->min_pixclk, dev_priv->min_pixclk,
+              sizeof(intel_state->min_pixclk));
 
-               if (!crtc_state->base.enable)
-                       continue;
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+               int pixclk = 0;
 
-               max_pixclk = max(max_pixclk,
-                                crtc_state->base.adjusted_mode.crtc_clock);
+               if (crtc_state->enable)
+                       pixclk = crtc_state->adjusted_mode.crtc_clock;
+
+               intel_state->min_pixclk[i] = pixclk;
        }
 
+       for_each_pipe(dev_priv, pipe)
+               max_pixclk = max(intel_state->min_pixclk[pipe], max_pixclk);
+
        return max_pixclk;
 }
 
@@ -6090,13 +5928,18 @@ static int valleyview_modeset_calc_cdclk(struct drm_atomic_state *state)
        struct drm_device *dev = state->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int max_pixclk = intel_mode_max_pixclk(dev, state);
+       struct intel_atomic_state *intel_state =
+               to_intel_atomic_state(state);
 
        if (max_pixclk < 0)
                return max_pixclk;
 
-       to_intel_atomic_state(state)->cdclk =
+       intel_state->cdclk = intel_state->dev_cdclk =
                valleyview_calc_cdclk(dev_priv, max_pixclk);
 
+       if (!intel_state->active_crtcs)
+               intel_state->dev_cdclk = valleyview_calc_cdclk(dev_priv, 0);
+
        return 0;
 }
 
@@ -6105,13 +5948,18 @@ static int broxton_modeset_calc_cdclk(struct drm_atomic_state *state)
        struct drm_device *dev = state->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int max_pixclk = intel_mode_max_pixclk(dev, state);
+       struct intel_atomic_state *intel_state =
+               to_intel_atomic_state(state);
 
        if (max_pixclk < 0)
                return max_pixclk;
 
-       to_intel_atomic_state(state)->cdclk =
+       intel_state->cdclk = intel_state->dev_cdclk =
                broxton_calc_cdclk(dev_priv, max_pixclk);
 
+       if (!intel_state->active_crtcs)
+               intel_state->dev_cdclk = broxton_calc_cdclk(dev_priv, 0);
+
        return 0;
 }
 
@@ -6154,8 +6002,10 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv)
 static void valleyview_modeset_commit_cdclk(struct drm_atomic_state *old_state)
 {
        struct drm_device *dev = old_state->dev;
-       unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_atomic_state *old_intel_state =
+               to_intel_atomic_state(old_state);
+       unsigned req_cdclk = old_intel_state->dev_cdclk;
 
        /*
         * FIXME: We can end up here with all power domains off, yet
@@ -6184,6 +6034,8 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
+       struct intel_crtc_state *pipe_config =
+               to_intel_crtc_state(crtc->state);
        int pipe = intel_crtc->pipe;
 
        if (WARN_ON(intel_crtc->active))
@@ -6193,6 +6045,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
                intel_dp_set_m_n(intel_crtc, M1_N1);
 
        intel_set_pipe_timings(intel_crtc);
+       intel_set_pipe_src_size(intel_crtc);
 
        if (IS_CHERRYVIEW(dev) && pipe == PIPE_B) {
                struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6227,8 +6080,9 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
 
        i9xx_pfit_enable(intel_crtc);
 
-       intel_crtc_load_lut(crtc);
+       intel_color_load_luts(&pipe_config->base);
 
+       intel_update_watermarks(crtc);
        intel_enable_pipe(intel_crtc);
 
        assert_vblank_disabled(crtc);
@@ -6253,6 +6107,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
+       struct intel_crtc_state *pipe_config =
+               to_intel_crtc_state(crtc->state);
        int pipe = intel_crtc->pipe;
 
        if (WARN_ON(intel_crtc->active))
@@ -6264,6 +6120,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
                intel_dp_set_m_n(intel_crtc, M1_N1);
 
        intel_set_pipe_timings(intel_crtc);
+       intel_set_pipe_src_size(intel_crtc);
 
        i9xx_set_pipeconf(intel_crtc);
 
@@ -6280,7 +6137,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
 
        i9xx_pfit_enable(intel_crtc);
 
-       intel_crtc_load_lut(crtc);
+       intel_color_load_luts(&pipe_config->base);
 
        intel_update_watermarks(crtc);
        intel_enable_pipe(intel_crtc);
@@ -6290,8 +6147,6 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
 
        for_each_encoder_on_crtc(dev, crtc, encoder)
                encoder->enable(encoder);
-
-       intel_fbc_enable(intel_crtc);
 }
 
 static void i9xx_pfit_disable(struct intel_crtc *crtc)
@@ -6320,10 +6175,9 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
        /*
         * On gen2 planes are double buffered but the pipe isn't, so we must
         * wait for planes to fully turn off before disabling the pipe.
-        * We also need to wait on all gmch platforms because of the
-        * self-refresh mode constraint explained above.
         */
-       intel_wait_for_vblank(dev, pipe);
+       if (IS_GEN2(dev))
+               intel_wait_for_vblank(dev, pipe);
 
        for_each_encoder_on_crtc(dev, crtc, encoder)
                encoder->disable(encoder);
@@ -6354,12 +6208,11 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
 
        if (!IS_GEN2(dev))
                intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
-
-       intel_fbc_disable_crtc(intel_crtc);
 }
 
 static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
 {
+       struct intel_encoder *encoder;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->dev);
        enum intel_display_power_domain domain;
@@ -6371,14 +6224,28 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
        if (to_intel_plane_state(crtc->primary->state)->visible) {
                WARN_ON(intel_crtc->unpin_work);
 
-               intel_pre_disable_primary(crtc);
+               intel_pre_disable_primary_noatomic(crtc);
 
                intel_crtc_disable_planes(crtc, 1 << drm_plane_index(crtc->primary));
                to_intel_plane_state(crtc->primary->state)->visible = false;
        }
 
        dev_priv->display.crtc_disable(crtc);
+
+       DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was enabled, now disabled\n",
+                     crtc->base.id);
+
+       WARN_ON(drm_atomic_set_mode_for_crtc(crtc->state, NULL) < 0);
+       crtc->state->active = false;
        intel_crtc->active = false;
+       crtc->enabled = false;
+       crtc->state->connector_mask = 0;
+       crtc->state->encoder_mask = 0;
+
+       for_each_encoder_on_crtc(crtc->dev, crtc, encoder)
+               encoder->base.crtc = NULL;
+
+       intel_fbc_disable(intel_crtc);
        intel_update_watermarks(crtc);
        intel_disable_shared_dpll(intel_crtc);
 
@@ -6386,6 +6253,9 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
        for_each_power_domain(domain, domains)
                intel_display_power_put(dev_priv, domain);
        intel_crtc->enabled_power_domains = 0;
+
+       dev_priv->active_crtcs &= ~(1 << intel_crtc->pipe);
+       dev_priv->min_pixclk[intel_crtc->pipe] = 0;
 }
 
 /*
@@ -6394,55 +6264,16 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
  */
 int intel_display_suspend(struct drm_device *dev)
 {
-       struct drm_mode_config *config = &dev->mode_config;
-       struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
+       struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_atomic_state *state;
-       struct drm_crtc *crtc;
-       unsigned crtc_mask = 0;
-       int ret = 0;
-
-       if (WARN_ON(!ctx))
-               return 0;
-
-       lockdep_assert_held(&ctx->ww_ctx);
-       state = drm_atomic_state_alloc(dev);
-       if (WARN_ON(!state))
-               return -ENOMEM;
-
-       state->acquire_ctx = ctx;
-       state->allow_modeset = true;
-
-       for_each_crtc(dev, crtc) {
-               struct drm_crtc_state *crtc_state =
-                       drm_atomic_get_crtc_state(state, crtc);
-
-               ret = PTR_ERR_OR_ZERO(crtc_state);
-               if (ret)
-                       goto free;
-
-               if (!crtc_state->active)
-                       continue;
-
-               crtc_state->active = false;
-               crtc_mask |= 1 << drm_crtc_index(crtc);
-       }
-
-       if (crtc_mask) {
-               ret = drm_atomic_commit(state);
-
-               if (!ret) {
-                       for_each_crtc(dev, crtc)
-                               if (crtc_mask & (1 << drm_crtc_index(crtc)))
-                                       crtc->state->active = true;
-
-                       return ret;
-               }
-       }
+       int ret;
 
-free:
+       state = drm_atomic_helper_suspend(dev);
+       ret = PTR_ERR_OR_ZERO(state);
        if (ret)
                DRM_ERROR("Suspending crtc's failed with %i\n", ret);
-       drm_atomic_state_free(state);
+       else
+               dev_priv->modeset_restore_state = state;
        return ret;
 }
 
@@ -6626,7 +6457,7 @@ retry:
         * 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;
+       link_bw = intel_fdi_link_freq(to_i915(dev), pipe_config);
 
        fdi_dotclock = adjusted_mode->crtc_clock;
 
@@ -6638,8 +6469,7 @@ retry:
        intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock,
                               link_bw, &pipe_config->fdi_m_n);
 
-       ret = ironlake_check_fdi_lanes(intel_crtc->base.dev,
-                                      intel_crtc->pipe, pipe_config);
+       ret = ironlake_check_fdi_lanes(dev, intel_crtc->pipe, pipe_config);
        if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
                pipe_config->pipe_bpp -= 2*3;
                DRM_DEBUG_KMS("fdi link bw constraint, reducing pipe bpp to %i\n",
@@ -7191,30 +7021,6 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
                && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
 }
 
-static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state,
-                          int num_connectors)
-{
-       struct drm_device *dev = crtc_state->base.crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int refclk;
-
-       WARN_ON(!crtc_state->base.state);
-
-       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev) || IS_BROXTON(dev)) {
-               refclk = 100000;
-       } else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
-           intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
-               refclk = dev_priv->vbt.lvds_ssc_freq;
-               DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk);
-       } else if (!IS_GEN2(dev)) {
-               refclk = 96000;
-       } else {
-               refclk = 48000;
-       }
-
-       return refclk;
-}
-
 static uint32_t pnv_dpll_compute_fp(struct dpll *dpll)
 {
        return (1 << dpll->n) << 16 | dpll->m2;
@@ -7596,26 +7402,34 @@ static void chv_prepare_pll(struct intel_crtc *crtc,
  * in cases where we need the PLL enabled even when @pipe is not going to
  * be enabled.
  */
-void vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
-                     const struct dpll *dpll)
+int vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
+                    const struct dpll *dpll)
 {
        struct intel_crtc *crtc =
                to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
-       struct intel_crtc_state pipe_config = {
-               .base.crtc = &crtc->base,
-               .pixel_multiplier = 1,
-               .dpll = *dpll,
-       };
+       struct intel_crtc_state *pipe_config;
+
+       pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL);
+       if (!pipe_config)
+               return -ENOMEM;
+
+       pipe_config->base.crtc = &crtc->base;
+       pipe_config->pixel_multiplier = 1;
+       pipe_config->dpll = *dpll;
 
        if (IS_CHERRYVIEW(dev)) {
-               chv_compute_dpll(crtc, &pipe_config);
-               chv_prepare_pll(crtc, &pipe_config);
-               chv_enable_pll(crtc, &pipe_config);
+               chv_compute_dpll(crtc, pipe_config);
+               chv_prepare_pll(crtc, pipe_config);
+               chv_enable_pll(crtc, pipe_config);
        } else {
-               vlv_compute_dpll(crtc, &pipe_config);
-               vlv_prepare_pll(crtc, &pipe_config);
-               vlv_enable_pll(crtc, &pipe_config);
+               vlv_compute_dpll(crtc, pipe_config);
+               vlv_prepare_pll(crtc, pipe_config);
+               vlv_enable_pll(crtc, pipe_config);
        }
+
+       kfree(pipe_config);
+
+       return 0;
 }
 
 /**
@@ -7636,8 +7450,7 @@ void vlv_force_pll_off(struct drm_device *dev, enum pipe pipe)
 
 static void i9xx_compute_dpll(struct intel_crtc *crtc,
                              struct intel_crtc_state *crtc_state,
-                             intel_clock_t *reduced_clock,
-                             int num_connectors)
+                             intel_clock_t *reduced_clock)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7696,7 +7509,7 @@ static void i9xx_compute_dpll(struct intel_crtc *crtc,
        if (crtc_state->sdvo_tv_clock)
                dpll |= PLL_REF_INPUT_TVCLKINBC;
        else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
-                intel_panel_use_ssc(dev_priv) && num_connectors < 2)
+                intel_panel_use_ssc(dev_priv))
                dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
        else
                dpll |= PLL_REF_INPUT_DREFCLK;
@@ -7713,8 +7526,7 @@ static void i9xx_compute_dpll(struct intel_crtc *crtc,
 
 static void i8xx_compute_dpll(struct intel_crtc *crtc,
                              struct intel_crtc_state *crtc_state,
-                             intel_clock_t *reduced_clock,
-                             int num_connectors)
+                             intel_clock_t *reduced_clock)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7740,7 +7552,7 @@ static void i8xx_compute_dpll(struct intel_crtc *crtc,
                dpll |= DPLL_DVO_2X_MODE;
 
        if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
-                intel_panel_use_ssc(dev_priv) && num_connectors < 2)
+           intel_panel_use_ssc(dev_priv))
                dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
        else
                dpll |= PLL_REF_INPUT_DREFCLK;
@@ -7809,6 +7621,14 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
            (pipe == PIPE_B || pipe == PIPE_C))
                I915_WRITE(VTOTAL(pipe), I915_READ(VTOTAL(cpu_transcoder)));
 
+}
+
+static void intel_set_pipe_src_size(struct intel_crtc *intel_crtc)
+{
+       struct drm_device *dev = intel_crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe pipe = intel_crtc->pipe;
+
        /* pipesrc controls the size that is scaled from, which should
         * always be the user's requested size.
         */
@@ -7850,6 +7670,14 @@ static void intel_get_pipe_timings(struct intel_crtc *crtc,
                pipe_config->base.adjusted_mode.crtc_vtotal += 1;
                pipe_config->base.adjusted_mode.crtc_vblank_end += 1;
        }
+}
+
+static void intel_get_pipe_src_size(struct intel_crtc *crtc,
+                                   struct intel_crtc_state *pipe_config)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 tmp;
 
        tmp = I915_READ(PIPESRC(crtc->pipe));
        pipe_config->pipe_src_h = (tmp & 0xffff) + 1;
@@ -7947,119 +7775,248 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
        POSTING_READ(PIPECONF(intel_crtc->pipe));
 }
 
-static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
+static int i8xx_crtc_compute_clock(struct intel_crtc *crtc,
                                   struct intel_crtc_state *crtc_state)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int refclk, num_connectors = 0;
-       intel_clock_t clock;
-       bool ok;
        const intel_limit_t *limit;
-       struct drm_atomic_state *state = crtc_state->base.state;
-       struct drm_connector *connector;
-       struct drm_connector_state *connector_state;
-       int i;
+       int refclk = 48000;
 
        memset(&crtc_state->dpll_hw_state, 0,
               sizeof(crtc_state->dpll_hw_state));
 
-       if (crtc_state->has_dsi_encoder)
-               return 0;
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
+               if (intel_panel_use_ssc(dev_priv)) {
+                       refclk = dev_priv->vbt.lvds_ssc_freq;
+                       DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk);
+               }
 
-       for_each_connector_in_state(state, connector, connector_state, i) {
-               if (connector_state->crtc == &crtc->base)
-                       num_connectors++;
+               limit = &intel_limits_i8xx_lvds;
+       } else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_DVO)) {
+               limit = &intel_limits_i8xx_dvo;
+       } else {
+               limit = &intel_limits_i8xx_dac;
        }
 
-       if (!crtc_state->clock_set) {
-               refclk = i9xx_get_refclk(crtc_state, num_connectors);
+       if (!crtc_state->clock_set &&
+           !i9xx_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+                                refclk, NULL, &crtc_state->dpll)) {
+               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               return -EINVAL;
+       }
 
-               /*
-                * 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_state, refclk);
-               ok = dev_priv->display.find_dpll(limit, crtc_state,
-                                                crtc_state->port_clock,
-                                                refclk, NULL, &clock);
-               if (!ok) {
-                       DRM_ERROR("Couldn't find PLL settings for mode!\n");
-                       return -EINVAL;
+       i8xx_compute_dpll(crtc, crtc_state, NULL);
+
+       return 0;
+}
+
+static int g4x_crtc_compute_clock(struct intel_crtc *crtc,
+                                 struct intel_crtc_state *crtc_state)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       const intel_limit_t *limit;
+       int refclk = 96000;
+
+       memset(&crtc_state->dpll_hw_state, 0,
+              sizeof(crtc_state->dpll_hw_state));
+
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
+               if (intel_panel_use_ssc(dev_priv)) {
+                       refclk = dev_priv->vbt.lvds_ssc_freq;
+                       DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk);
                }
 
-               /* Compat-code for transition, will disappear. */
-               crtc_state->dpll.n = clock.n;
-               crtc_state->dpll.m1 = clock.m1;
-               crtc_state->dpll.m2 = clock.m2;
-               crtc_state->dpll.p1 = clock.p1;
-               crtc_state->dpll.p2 = clock.p2;
+               if (intel_is_dual_link_lvds(dev))
+                       limit = &intel_limits_g4x_dual_channel_lvds;
+               else
+                       limit = &intel_limits_g4x_single_channel_lvds;
+       } else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_HDMI) ||
+                  intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_ANALOG)) {
+               limit = &intel_limits_g4x_hdmi;
+       } else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_SDVO)) {
+               limit = &intel_limits_g4x_sdvo;
+       } else {
+               /* The option is for other outputs */
+               limit = &intel_limits_i9xx_sdvo;
        }
 
-       if (IS_GEN2(dev)) {
-               i8xx_compute_dpll(crtc, crtc_state, NULL,
-                                 num_connectors);
-       } else if (IS_CHERRYVIEW(dev)) {
-               chv_compute_dpll(crtc, crtc_state);
-       } else if (IS_VALLEYVIEW(dev)) {
-               vlv_compute_dpll(crtc, crtc_state);
-       } else {
-               i9xx_compute_dpll(crtc, crtc_state, NULL,
-                                 num_connectors);
+       if (!crtc_state->clock_set &&
+           !g4x_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+                               refclk, NULL, &crtc_state->dpll)) {
+               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               return -EINVAL;
        }
 
+       i9xx_compute_dpll(crtc, crtc_state, NULL);
+
        return 0;
 }
 
-static void i9xx_get_pfit_config(struct intel_crtc *crtc,
-                                struct intel_crtc_state *pipe_config)
+static int pnv_crtc_compute_clock(struct intel_crtc *crtc,
+                                 struct intel_crtc_state *crtc_state)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t tmp;
+       const intel_limit_t *limit;
+       int refclk = 96000;
 
-       if (INTEL_INFO(dev)->gen <= 3 && (IS_I830(dev) || !IS_MOBILE(dev)))
-               return;
+       memset(&crtc_state->dpll_hw_state, 0,
+              sizeof(crtc_state->dpll_hw_state));
 
-       tmp = I915_READ(PFIT_CONTROL);
-       if (!(tmp & PFIT_ENABLE))
-               return;
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
+               if (intel_panel_use_ssc(dev_priv)) {
+                       refclk = dev_priv->vbt.lvds_ssc_freq;
+                       DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk);
+               }
 
-       /* Check whether the pfit is attached to our pipe. */
-       if (INTEL_INFO(dev)->gen < 4) {
-               if (crtc->pipe != PIPE_B)
-                       return;
+               limit = &intel_limits_pineview_lvds;
        } else {
-               if ((tmp & PFIT_PIPE_MASK) != (crtc->pipe << PFIT_PIPE_SHIFT))
-                       return;
+               limit = &intel_limits_pineview_sdvo;
        }
 
-       pipe_config->gmch_pfit.control = tmp;
-       pipe_config->gmch_pfit.pgm_ratios = I915_READ(PFIT_PGM_RATIOS);
-       if (INTEL_INFO(dev)->gen < 5)
-               pipe_config->gmch_pfit.lvds_border_bits =
-                       I915_READ(LVDS) & LVDS_BORDER_ENABLE;
+       if (!crtc_state->clock_set &&
+           !pnv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+                               refclk, NULL, &crtc_state->dpll)) {
+               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               return -EINVAL;
+       }
+
+       i9xx_compute_dpll(crtc, crtc_state, NULL);
+
+       return 0;
 }
 
-static void vlv_crtc_clock_get(struct intel_crtc *crtc,
-                              struct intel_crtc_state *pipe_config)
+static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
+                                  struct intel_crtc_state *crtc_state)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int pipe = pipe_config->cpu_transcoder;
-       intel_clock_t clock;
-       u32 mdiv;
-       int refclk = 100000;
+       const intel_limit_t *limit;
+       int refclk = 96000;
 
-       /* In case of MIPI DPLL will not even be used */
-       if (!(pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE))
-               return;
+       memset(&crtc_state->dpll_hw_state, 0,
+              sizeof(crtc_state->dpll_hw_state));
 
-       mutex_lock(&dev_priv->sb_lock);
-       mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe));
-       mutex_unlock(&dev_priv->sb_lock);
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
+               if (intel_panel_use_ssc(dev_priv)) {
+                       refclk = dev_priv->vbt.lvds_ssc_freq;
+                       DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk);
+               }
+
+               limit = &intel_limits_i9xx_lvds;
+       } else {
+               limit = &intel_limits_i9xx_sdvo;
+       }
+
+       if (!crtc_state->clock_set &&
+           !i9xx_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+                                refclk, NULL, &crtc_state->dpll)) {
+               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               return -EINVAL;
+       }
+
+       i9xx_compute_dpll(crtc, crtc_state, NULL);
+
+       return 0;
+}
+
+static int chv_crtc_compute_clock(struct intel_crtc *crtc,
+                                 struct intel_crtc_state *crtc_state)
+{
+       int refclk = 100000;
+       const intel_limit_t *limit = &intel_limits_chv;
+
+       memset(&crtc_state->dpll_hw_state, 0,
+              sizeof(crtc_state->dpll_hw_state));
+
+       if (crtc_state->has_dsi_encoder)
+               return 0;
+
+       if (!crtc_state->clock_set &&
+           !chv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+                               refclk, NULL, &crtc_state->dpll)) {
+               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               return -EINVAL;
+       }
+
+       chv_compute_dpll(crtc, crtc_state);
+
+       return 0;
+}
+
+static int vlv_crtc_compute_clock(struct intel_crtc *crtc,
+                                 struct intel_crtc_state *crtc_state)
+{
+       int refclk = 100000;
+       const intel_limit_t *limit = &intel_limits_vlv;
+
+       memset(&crtc_state->dpll_hw_state, 0,
+              sizeof(crtc_state->dpll_hw_state));
+
+       if (crtc_state->has_dsi_encoder)
+               return 0;
+
+       if (!crtc_state->clock_set &&
+           !vlv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+                               refclk, NULL, &crtc_state->dpll)) {
+               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               return -EINVAL;
+       }
+
+       vlv_compute_dpll(crtc, crtc_state);
+
+       return 0;
+}
+
+static void i9xx_get_pfit_config(struct intel_crtc *crtc,
+                                struct intel_crtc_state *pipe_config)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t tmp;
+
+       if (INTEL_INFO(dev)->gen <= 3 && (IS_I830(dev) || !IS_MOBILE(dev)))
+               return;
+
+       tmp = I915_READ(PFIT_CONTROL);
+       if (!(tmp & PFIT_ENABLE))
+               return;
+
+       /* Check whether the pfit is attached to our pipe. */
+       if (INTEL_INFO(dev)->gen < 4) {
+               if (crtc->pipe != PIPE_B)
+                       return;
+       } else {
+               if ((tmp & PFIT_PIPE_MASK) != (crtc->pipe << PFIT_PIPE_SHIFT))
+                       return;
+       }
+
+       pipe_config->gmch_pfit.control = tmp;
+       pipe_config->gmch_pfit.pgm_ratios = I915_READ(PFIT_PGM_RATIOS);
+       if (INTEL_INFO(dev)->gen < 5)
+               pipe_config->gmch_pfit.lvds_border_bits =
+                       I915_READ(LVDS) & LVDS_BORDER_ENABLE;
+}
+
+static void vlv_crtc_clock_get(struct intel_crtc *crtc,
+                              struct intel_crtc_state *pipe_config)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe = pipe_config->cpu_transcoder;
+       intel_clock_t clock;
+       u32 mdiv;
+       int refclk = 100000;
+
+       /* In case of MIPI DPLL will not even be used */
+       if (!(pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE))
+               return;
+
+       mutex_lock(&dev_priv->sb_lock);
+       mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe));
+       mutex_unlock(&dev_priv->sb_lock);
 
        clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7;
        clock.m2 = mdiv & DPIO_M2DIV_MASK;
@@ -8183,7 +8140,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
                return false;
 
        pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
-       pipe_config->shared_dpll = DPLL_ID_PRIVATE;
+       pipe_config->shared_dpll = NULL;
 
        ret = false;
 
@@ -8215,6 +8172,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
                pipe_config->double_wide = tmp & PIPECONF_DOUBLE_WIDE;
 
        intel_get_pipe_timings(crtc, pipe_config);
+       intel_get_pipe_src_size(crtc, pipe_config);
 
        i9xx_get_pfit_config(crtc, pipe_config);
 
@@ -8688,42 +8646,6 @@ void intel_init_pch_refclk(struct drm_device *dev)
                lpt_init_pch_refclk(dev);
 }
 
-static int ironlake_get_refclk(struct intel_crtc_state *crtc_state)
-{
-       struct drm_device *dev = crtc_state->base.crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_atomic_state *state = crtc_state->base.state;
-       struct drm_connector *connector;
-       struct drm_connector_state *connector_state;
-       struct intel_encoder *encoder;
-       int num_connectors = 0, i;
-       bool is_lvds = false;
-
-       for_each_connector_in_state(state, connector, connector_state, i) {
-               if (connector_state->crtc != crtc_state->base.crtc)
-                       continue;
-
-               encoder = to_intel_encoder(connector_state->best_encoder);
-
-               switch (encoder->type) {
-               case INTEL_OUTPUT_LVDS:
-                       is_lvds = true;
-                       break;
-               default:
-                       break;
-               }
-               num_connectors++;
-       }
-
-       if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
-               DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n",
-                             dev_priv->vbt.lvds_ssc_freq);
-               return dev_priv->vbt.lvds_ssc_freq;
-       }
-
-       return 120000;
-}
-
 static void ironlake_set_pipeconf(struct drm_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = crtc->dev->dev_private;
@@ -8766,82 +8688,14 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc)
        POSTING_READ(PIPECONF(pipe));
 }
 
-/*
- * Set up the pipe CSC unit.
- *
- * Currently only full range RGB to limited range RGB conversion
- * is supported, but eventually this should handle various
- * RGB<->YCbCr scenarios as well.
- */
-static void intel_set_pipe_csc(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
-       uint16_t coeff = 0x7800; /* 1.0 */
-
-       /*
-        * TODO: Check what kind of values actually come out of the pipe
-        * with these coeff/postoff values and adjust to get the best
-        * accuracy. Perhaps we even need to take the bpc value into
-        * consideration.
-        */
-
-       if (intel_crtc->config->limited_color_range)
-               coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */
-
-       /*
-        * GY/GU and RY/RU should be the other way around according
-        * to BSpec, but reality doesn't agree. Just set them up in
-        * a way that results in the correct picture.
-        */
-       I915_WRITE(PIPE_CSC_COEFF_RY_GY(pipe), coeff << 16);
-       I915_WRITE(PIPE_CSC_COEFF_BY(pipe), 0);
-
-       I915_WRITE(PIPE_CSC_COEFF_RU_GU(pipe), coeff);
-       I915_WRITE(PIPE_CSC_COEFF_BU(pipe), 0);
-
-       I915_WRITE(PIPE_CSC_COEFF_RV_GV(pipe), 0);
-       I915_WRITE(PIPE_CSC_COEFF_BV(pipe), coeff << 16);
-
-       I915_WRITE(PIPE_CSC_PREOFF_HI(pipe), 0);
-       I915_WRITE(PIPE_CSC_PREOFF_ME(pipe), 0);
-       I915_WRITE(PIPE_CSC_PREOFF_LO(pipe), 0);
-
-       if (INTEL_INFO(dev)->gen > 6) {
-               uint16_t postoff = 0;
-
-               if (intel_crtc->config->limited_color_range)
-                       postoff = (16 * (1 << 12) / 255) & 0x1fff;
-
-               I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff);
-               I915_WRITE(PIPE_CSC_POSTOFF_ME(pipe), postoff);
-               I915_WRITE(PIPE_CSC_POSTOFF_LO(pipe), postoff);
-
-               I915_WRITE(PIPE_CSC_MODE(pipe), 0);
-       } else {
-               uint32_t mode = CSC_MODE_YUV_TO_RGB;
-
-               if (intel_crtc->config->limited_color_range)
-                       mode |= CSC_BLACK_SCREEN_OFFSET;
-
-               I915_WRITE(PIPE_CSC_MODE(pipe), mode);
-       }
-}
-
 static void haswell_set_pipeconf(struct drm_crtc *crtc)
 {
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = crtc->dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       enum pipe pipe = intel_crtc->pipe;
        enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
-       uint32_t val;
-
-       val = 0;
+       u32 val = 0;
 
-       if (IS_HASWELL(dev) && intel_crtc->config->dither)
+       if (IS_HASWELL(dev_priv) && intel_crtc->config->dither)
                val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
 
        if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
@@ -8851,12 +8705,15 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc)
 
        I915_WRITE(PIPECONF(cpu_transcoder), val);
        POSTING_READ(PIPECONF(cpu_transcoder));
+}
 
-       I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT);
-       POSTING_READ(GAMMA_MODE(intel_crtc->pipe));
+static void haswell_set_pipemisc(struct drm_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       if (IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9) {
-               val = 0;
+       if (IS_BROADWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 9) {
+               u32 val = 0;
 
                switch (intel_crtc->config->pipe_bpp) {
                case 18:
@@ -8879,39 +8736,10 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc)
                if (intel_crtc->config->dither)
                        val |= PIPEMISC_DITHER_ENABLE | PIPEMISC_DITHER_TYPE_SP;
 
-               I915_WRITE(PIPEMISC(pipe), val);
+               I915_WRITE(PIPEMISC(intel_crtc->pipe), val);
        }
 }
 
-static bool ironlake_compute_clocks(struct drm_crtc *crtc,
-                                   struct intel_crtc_state *crtc_state,
-                                   intel_clock_t *clock,
-                                   bool *has_reduced_clock,
-                                   intel_clock_t *reduced_clock)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int refclk;
-       const intel_limit_t *limit;
-       bool ret;
-
-       refclk = ironlake_get_refclk(crtc_state);
-
-       /*
-        * 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_state, refclk);
-       ret = dev_priv->display.find_dpll(limit, crtc_state,
-                                         crtc_state->port_clock,
-                                         refclk, NULL, clock);
-       if (!ret)
-               return false;
-
-       return true;
-}
-
 int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp)
 {
        /*
@@ -8928,10 +8756,9 @@ static bool ironlake_needs_fb_cb_tune(struct dpll *dpll, int factor)
        return i9xx_dpll_compute_m(dpll) < factor * dpll->n;
 }
 
-static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
-                                     struct intel_crtc_state *crtc_state,
-                                     u32 *fp,
-                                     intel_clock_t *reduced_clock, u32 *fp2)
+static void ironlake_compute_dpll(struct intel_crtc *intel_crtc,
+                                 struct intel_crtc_state *crtc_state,
+                                 intel_clock_t *reduced_clock)
 {
        struct drm_crtc *crtc = &intel_crtc->base;
        struct drm_device *dev = crtc->dev;
@@ -8940,8 +8767,8 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
        struct drm_connector *connector;
        struct drm_connector_state *connector_state;
        struct intel_encoder *encoder;
-       uint32_t dpll;
-       int factor, num_connectors = 0, i;
+       u32 dpll, fp, fp2;
+       int factor, i;
        bool is_lvds = false, is_sdvo = false;
 
        for_each_connector_in_state(state, connector, connector_state, i) {
@@ -8961,8 +8788,6 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
                default:
                        break;
                }
-
-               num_connectors++;
        }
 
        /* Enable autotuning of the PLL clock (if permissible) */
@@ -8975,11 +8800,19 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
        } else if (crtc_state->sdvo_tv_clock)
                factor = 20;
 
+       fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
+
        if (ironlake_needs_fb_cb_tune(&crtc_state->dpll, factor))
-               *fp |= FP_CB_TUNE;
+               fp |= FP_CB_TUNE;
+
+       if (reduced_clock) {
+               fp2 = i9xx_dpll_compute_fp(reduced_clock);
 
-       if (fp2 && (reduced_clock->m < factor * reduced_clock->n))
-               *fp2 |= FP_CB_TUNE;
+               if (reduced_clock->m < factor * reduced_clock->n)
+                       fp2 |= FP_CB_TUNE;
+       } else {
+               fp2 = fp;
+       }
 
        dpll = 0;
 
@@ -9016,76 +8849,80 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
                break;
        }
 
-       if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
+       if (is_lvds && intel_panel_use_ssc(dev_priv))
                dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
        else
                dpll |= PLL_REF_INPUT_DREFCLK;
 
-       return dpll | DPLL_VCO_ENABLE;
+       dpll |= DPLL_VCO_ENABLE;
+
+       crtc_state->dpll_hw_state.dpll = dpll;
+       crtc_state->dpll_hw_state.fp0 = fp;
+       crtc_state->dpll_hw_state.fp1 = fp2;
 }
 
 static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
                                       struct intel_crtc_state *crtc_state)
 {
        struct drm_device *dev = crtc->base.dev;
-       intel_clock_t clock, reduced_clock;
-       u32 dpll = 0, fp = 0, fp2 = 0;
-       bool ok, has_reduced_clock = false;
-       bool is_lvds = false;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       intel_clock_t reduced_clock;
+       bool has_reduced_clock = false;
        struct intel_shared_dpll *pll;
+       const intel_limit_t *limit;
+       int refclk = 120000;
 
        memset(&crtc_state->dpll_hw_state, 0,
               sizeof(crtc_state->dpll_hw_state));
 
-       is_lvds = intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS);
+       crtc->lowfreq_avail = false;
+
+       /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
+       if (!crtc_state->has_pch_encoder)
+               return 0;
+
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) {
+               if (intel_panel_use_ssc(dev_priv)) {
+                       DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n",
+                                     dev_priv->vbt.lvds_ssc_freq);
+                       refclk = dev_priv->vbt.lvds_ssc_freq;
+               }
 
-       WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)),
-            "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev));
+               if (intel_is_dual_link_lvds(dev)) {
+                       if (refclk == 100000)
+                               limit = &intel_limits_ironlake_dual_lvds_100m;
+                       else
+                               limit = &intel_limits_ironlake_dual_lvds;
+               } else {
+                       if (refclk == 100000)
+                               limit = &intel_limits_ironlake_single_lvds_100m;
+                       else
+                               limit = &intel_limits_ironlake_single_lvds;
+               }
+       } else {
+               limit = &intel_limits_ironlake_dac;
+       }
 
-       ok = ironlake_compute_clocks(&crtc->base, crtc_state, &clock,
-                                    &has_reduced_clock, &reduced_clock);
-       if (!ok && !crtc_state->clock_set) {
+       if (!crtc_state->clock_set &&
+           !g4x_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+                               refclk, NULL, &crtc_state->dpll)) {
                DRM_ERROR("Couldn't find PLL settings for mode!\n");
                return -EINVAL;
        }
-       /* Compat-code for transition, will disappear. */
-       if (!crtc_state->clock_set) {
-               crtc_state->dpll.n = clock.n;
-               crtc_state->dpll.m1 = clock.m1;
-               crtc_state->dpll.m2 = clock.m2;
-               crtc_state->dpll.p1 = clock.p1;
-               crtc_state->dpll.p2 = clock.p2;
-       }
-
-       /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
-       if (crtc_state->has_pch_encoder) {
-               fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
-               if (has_reduced_clock)
-                       fp2 = i9xx_dpll_compute_fp(&reduced_clock);
-
-               dpll = ironlake_compute_dpll(crtc, crtc_state,
-                                            &fp, &reduced_clock,
-                                            has_reduced_clock ? &fp2 : NULL);
 
-               crtc_state->dpll_hw_state.dpll = dpll;
-               crtc_state->dpll_hw_state.fp0 = fp;
-               if (has_reduced_clock)
-                       crtc_state->dpll_hw_state.fp1 = fp2;
-               else
-                       crtc_state->dpll_hw_state.fp1 = fp;
+       ironlake_compute_dpll(crtc, crtc_state,
+                             has_reduced_clock ? &reduced_clock : NULL);
 
-               pll = intel_get_shared_dpll(crtc, crtc_state);
-               if (pll == NULL) {
-                       DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
-                                        pipe_name(crtc->pipe));
-                       return -EINVAL;
-               }
+       pll = intel_get_shared_dpll(crtc, crtc_state, NULL);
+       if (pll == NULL) {
+               DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
+                                pipe_name(crtc->pipe));
+               return -EINVAL;
        }
 
-       if (is_lvds && has_reduced_clock)
+       if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
+           has_reduced_clock)
                crtc->lowfreq_avail = true;
-       else
-               crtc->lowfreq_avail = false;
 
        return 0;
 }
@@ -9258,7 +9095,7 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
        fb->width = ((val >> 0) & 0x1fff) + 1;
 
        val = I915_READ(PLANE_STRIDE(pipe, 0));
-       stride_mult = intel_fb_stride_alignment(dev, fb->modifier[0],
+       stride_mult = intel_fb_stride_alignment(dev_priv, fb->modifier[0],
                                                fb->pixel_format);
        fb->pitches[0] = (val & 0x3ff) * stride_mult;
 
@@ -9387,7 +9224,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
                return false;
 
        pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
-       pipe_config->shared_dpll = DPLL_ID_PRIVATE;
+       pipe_config->shared_dpll = NULL;
 
        ret = false;
        tmp = I915_READ(PIPECONF(crtc->pipe));
@@ -9416,6 +9253,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
 
        if (I915_READ(PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) {
                struct intel_shared_dpll *pll;
+               enum intel_dpll_id pll_id;
 
                pipe_config->has_pch_encoder = true;
 
@@ -9426,20 +9264,21 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
                ironlake_get_fdi_m_n_config(crtc, pipe_config);
 
                if (HAS_PCH_IBX(dev_priv->dev)) {
-                       pipe_config->shared_dpll =
-                               (enum intel_dpll_id) crtc->pipe;
+                       pll_id = (enum intel_dpll_id) crtc->pipe;
                } else {
                        tmp = I915_READ(PCH_DPLL_SEL);
                        if (tmp & TRANS_DPLLB_SEL(crtc->pipe))
-                               pipe_config->shared_dpll = DPLL_ID_PCH_PLL_B;
+                               pll_id = DPLL_ID_PCH_PLL_B;
                        else
-                               pipe_config->shared_dpll = DPLL_ID_PCH_PLL_A;
+                               pll_id= DPLL_ID_PCH_PLL_A;
                }
 
-               pll = &dev_priv->shared_dplls[pipe_config->shared_dpll];
+               pipe_config->shared_dpll =
+                       intel_get_shared_dpll_by_id(dev_priv, pll_id);
+               pll = pipe_config->shared_dpll;
 
-               WARN_ON(!pll->get_hw_state(dev_priv, pll,
-                                          &pipe_config->dpll_hw_state));
+               WARN_ON(!pll->funcs.get_hw_state(dev_priv, pll,
+                                                &pipe_config->dpll_hw_state));
 
                tmp = pipe_config->dpll_hw_state.dpll;
                pipe_config->pixel_multiplier =
@@ -9452,6 +9291,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
        }
 
        intel_get_pipe_timings(crtc, pipe_config);
+       intel_get_pipe_src_size(crtc, pipe_config);
 
        ironlake_get_pfit_config(crtc, pipe_config);
 
@@ -9682,14 +9522,14 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv)
                val |= PCH_LP_PARTITION_LEVEL_DISABLE;
                I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
        }
-
-       intel_prepare_ddi(dev);
 }
 
 static void broxton_modeset_commit_cdclk(struct drm_atomic_state *old_state)
 {
        struct drm_device *dev = old_state->dev;
-       unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk;
+       struct intel_atomic_state *old_intel_state =
+               to_intel_atomic_state(old_state);
+       unsigned int req_cdclk = old_intel_state->dev_cdclk;
 
        broxton_set_cdclk(dev, req_cdclk);
 }
@@ -9697,29 +9537,38 @@ static void broxton_modeset_commit_cdclk(struct drm_atomic_state *old_state)
 /* compute the max rate for new configuration */
 static int ilk_max_pixel_rate(struct drm_atomic_state *state)
 {
-       struct intel_crtc *intel_crtc;
+       struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+       struct drm_i915_private *dev_priv = state->dev->dev_private;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *cstate;
        struct intel_crtc_state *crtc_state;
-       int max_pixel_rate = 0;
+       unsigned max_pixel_rate = 0, i;
+       enum pipe pipe;
 
-       for_each_intel_crtc(state->dev, intel_crtc) {
-               int pixel_rate;
+       memcpy(intel_state->min_pixclk, dev_priv->min_pixclk,
+              sizeof(intel_state->min_pixclk));
 
-               crtc_state = intel_atomic_get_crtc_state(state, intel_crtc);
-               if (IS_ERR(crtc_state))
-                       return PTR_ERR(crtc_state);
+       for_each_crtc_in_state(state, crtc, cstate, i) {
+               int pixel_rate;
 
-               if (!crtc_state->base.enable)
+               crtc_state = to_intel_crtc_state(cstate);
+               if (!crtc_state->base.enable) {
+                       intel_state->min_pixclk[i] = 0;
                        continue;
+               }
 
                pixel_rate = ilk_pipe_pixel_rate(crtc_state);
 
                /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */
-               if (IS_BROADWELL(state->dev) && crtc_state->ips_enabled)
+               if (IS_BROADWELL(dev_priv) && crtc_state->ips_enabled)
                        pixel_rate = DIV_ROUND_UP(pixel_rate * 100, 95);
 
-               max_pixel_rate = max(max_pixel_rate, pixel_rate);
+               intel_state->min_pixclk[i] = pixel_rate;
        }
 
+       for_each_pipe(dev_priv, pipe)
+               max_pixel_rate = max(intel_state->min_pixclk[pipe], max_pixel_rate);
+
        return max_pixel_rate;
 }
 
@@ -9750,8 +9599,8 @@ static void broadwell_set_cdclk(struct drm_device *dev, int cdclk)
        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))
+       if (wait_for_us(I915_READ(LCPLL_CTL) &
+                       LCPLL_CD_SOURCE_FCLK_DONE, 1))
                DRM_ERROR("Switching to FCLK failed\n");
 
        val = I915_READ(LCPLL_CTL);
@@ -9785,8 +9634,8 @@ static void broadwell_set_cdclk(struct drm_device *dev, int cdclk)
        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))
+       if (wait_for_us((I915_READ(LCPLL_CTL) &
+                       LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1))
                DRM_ERROR("Switching back to LCPLL failed\n");
 
        mutex_lock(&dev_priv->rps.hw_lock);
@@ -9803,6 +9652,7 @@ static void broadwell_set_cdclk(struct drm_device *dev, int cdclk)
 static int broadwell_modeset_calc_cdclk(struct drm_atomic_state *state)
 {
        struct drm_i915_private *dev_priv = to_i915(state->dev);
+       struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
        int max_pixclk = ilk_max_pixel_rate(state);
        int cdclk;
 
@@ -9825,7 +9675,9 @@ static int broadwell_modeset_calc_cdclk(struct drm_atomic_state *state)
                return -EINVAL;
        }
 
-       to_intel_atomic_state(state)->cdclk = cdclk;
+       intel_state->cdclk = intel_state->dev_cdclk = cdclk;
+       if (!intel_state->active_crtcs)
+               intel_state->dev_cdclk = 337500;
 
        return 0;
 }
@@ -9833,7 +9685,9 @@ static int broadwell_modeset_calc_cdclk(struct drm_atomic_state *state)
 static void broadwell_modeset_commit_cdclk(struct drm_atomic_state *old_state)
 {
        struct drm_device *dev = old_state->dev;
-       unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk;
+       struct intel_atomic_state *old_intel_state =
+               to_intel_atomic_state(old_state);
+       unsigned req_cdclk = old_intel_state->dev_cdclk;
 
        broadwell_set_cdclk(dev, req_cdclk);
 }
@@ -9841,8 +9695,13 @@ static void broadwell_modeset_commit_cdclk(struct drm_atomic_state *old_state)
 static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
                                      struct intel_crtc_state *crtc_state)
 {
-       if (!intel_ddi_pll_select(crtc, crtc_state))
-               return -EINVAL;
+       struct intel_encoder *intel_encoder =
+               intel_ddi_get_crtc_new_encoder(crtc_state);
+
+       if (intel_encoder->type != INTEL_OUTPUT_DSI) {
+               if (!intel_ddi_pll_select(crtc, crtc_state))
+                       return -EINVAL;
+       }
 
        crtc->lowfreq_avail = false;
 
@@ -9853,72 +9712,193 @@ static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv,
                                enum port port,
                                struct intel_crtc_state *pipe_config)
 {
+       enum intel_dpll_id id;
+
        switch (port) {
        case PORT_A:
                pipe_config->ddi_pll_sel = SKL_DPLL0;
-               pipe_config->shared_dpll = DPLL_ID_SKL_DPLL1;
+               id = DPLL_ID_SKL_DPLL0;
                break;
        case PORT_B:
                pipe_config->ddi_pll_sel = SKL_DPLL1;
-               pipe_config->shared_dpll = DPLL_ID_SKL_DPLL2;
+               id = DPLL_ID_SKL_DPLL1;
                break;
        case PORT_C:
                pipe_config->ddi_pll_sel = SKL_DPLL2;
-               pipe_config->shared_dpll = DPLL_ID_SKL_DPLL3;
+               id = DPLL_ID_SKL_DPLL2;
                break;
        default:
                DRM_ERROR("Incorrect port type\n");
+               return;
        }
+
+       pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
 }
 
 static void skylake_get_ddi_pll(struct drm_i915_private *dev_priv,
                                enum port port,
                                struct intel_crtc_state *pipe_config)
 {
-       u32 temp, dpll_ctl1;
+       enum intel_dpll_id id;
+       u32 temp;
 
        temp = I915_READ(DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
        pipe_config->ddi_pll_sel = temp >> (port * 3 + 1);
 
        switch (pipe_config->ddi_pll_sel) {
        case SKL_DPLL0:
-               /*
-                * On SKL the eDP DPLL (DPLL0 as we don't use SSC) is not part
-                * of the shared DPLL framework and thus needs to be read out
-                * separately
-                */
-               dpll_ctl1 = I915_READ(DPLL_CTRL1);
-               pipe_config->dpll_hw_state.ctrl1 = dpll_ctl1 & 0x3f;
+               id = DPLL_ID_SKL_DPLL0;
                break;
        case SKL_DPLL1:
-               pipe_config->shared_dpll = DPLL_ID_SKL_DPLL1;
+               id = DPLL_ID_SKL_DPLL1;
                break;
        case SKL_DPLL2:
-               pipe_config->shared_dpll = DPLL_ID_SKL_DPLL2;
+               id = DPLL_ID_SKL_DPLL2;
                break;
        case SKL_DPLL3:
-               pipe_config->shared_dpll = DPLL_ID_SKL_DPLL3;
+               id = DPLL_ID_SKL_DPLL3;
                break;
+       default:
+               MISSING_CASE(pipe_config->ddi_pll_sel);
+               return;
        }
+
+       pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
 }
 
 static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
                                enum port port,
                                struct intel_crtc_state *pipe_config)
 {
+       enum intel_dpll_id id;
+
        pipe_config->ddi_pll_sel = I915_READ(PORT_CLK_SEL(port));
 
        switch (pipe_config->ddi_pll_sel) {
        case PORT_CLK_SEL_WRPLL1:
-               pipe_config->shared_dpll = DPLL_ID_WRPLL1;
+               id = DPLL_ID_WRPLL1;
                break;
        case PORT_CLK_SEL_WRPLL2:
-               pipe_config->shared_dpll = DPLL_ID_WRPLL2;
+               id = DPLL_ID_WRPLL2;
                break;
        case PORT_CLK_SEL_SPLL:
-               pipe_config->shared_dpll = DPLL_ID_SPLL;
+               id = DPLL_ID_SPLL;
+               break;
+       case PORT_CLK_SEL_LCPLL_810:
+               id = DPLL_ID_LCPLL_810;
                break;
+       case PORT_CLK_SEL_LCPLL_1350:
+               id = DPLL_ID_LCPLL_1350;
+               break;
+       case PORT_CLK_SEL_LCPLL_2700:
+               id = DPLL_ID_LCPLL_2700;
+               break;
+       default:
+               MISSING_CASE(pipe_config->ddi_pll_sel);
+               /* fall through */
+       case PORT_CLK_SEL_NONE:
+               return;
        }
+
+       pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
+}
+
+static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
+                                    struct intel_crtc_state *pipe_config,
+                                    unsigned long *power_domain_mask)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_display_power_domain power_domain;
+       u32 tmp;
+
+       pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
+
+       /*
+        * XXX: Do intel_display_power_get_if_enabled before reading this (for
+        * consistency and less surprising code; it's in always on power).
+        */
+       tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
+       if (tmp & TRANS_DDI_FUNC_ENABLE) {
+               enum pipe trans_edp_pipe;
+               switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
+               default:
+                       WARN(1, "unknown pipe linked to edp transcoder\n");
+               case TRANS_DDI_EDP_INPUT_A_ONOFF:
+               case TRANS_DDI_EDP_INPUT_A_ON:
+                       trans_edp_pipe = PIPE_A;
+                       break;
+               case TRANS_DDI_EDP_INPUT_B_ONOFF:
+                       trans_edp_pipe = PIPE_B;
+                       break;
+               case TRANS_DDI_EDP_INPUT_C_ONOFF:
+                       trans_edp_pipe = PIPE_C;
+                       break;
+               }
+
+               if (trans_edp_pipe == crtc->pipe)
+                       pipe_config->cpu_transcoder = TRANSCODER_EDP;
+       }
+
+       power_domain = POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder);
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+               return false;
+       *power_domain_mask |= BIT(power_domain);
+
+       tmp = I915_READ(PIPECONF(pipe_config->cpu_transcoder));
+
+       return tmp & PIPECONF_ENABLE;
+}
+
+static bool bxt_get_dsi_transcoder_state(struct intel_crtc *crtc,
+                                        struct intel_crtc_state *pipe_config,
+                                        unsigned long *power_domain_mask)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_display_power_domain power_domain;
+       enum port port;
+       enum transcoder cpu_transcoder;
+       u32 tmp;
+
+       pipe_config->has_dsi_encoder = false;
+
+       for_each_port_masked(port, BIT(PORT_A) | BIT(PORT_C)) {
+               if (port == PORT_A)
+                       cpu_transcoder = TRANSCODER_DSI_A;
+               else
+                       cpu_transcoder = TRANSCODER_DSI_C;
+
+               power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder);
+               if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+                       continue;
+               *power_domain_mask |= BIT(power_domain);
+
+               /*
+                * The PLL needs to be enabled with a valid divider
+                * configuration, otherwise accessing DSI registers will hang
+                * the machine. See BSpec North Display Engine
+                * registers/MIPI[BXT]. We can break out here early, since we
+                * need the same DSI PLL to be enabled for both DSI ports.
+                */
+               if (!intel_dsi_pll_is_enabled(dev_priv))
+                       break;
+
+               /* XXX: this works for video mode only */
+               tmp = I915_READ(BXT_MIPI_PORT_CTRL(port));
+               if (!(tmp & DPI_ENABLE))
+                       continue;
+
+               tmp = I915_READ(MIPI_CTRL(port));
+               if ((tmp & BXT_PIPE_SELECT_MASK) != BXT_PIPE_SELECT(crtc->pipe))
+                       continue;
+
+               pipe_config->cpu_transcoder = cpu_transcoder;
+               pipe_config->has_dsi_encoder = true;
+               break;
+       }
+
+       return pipe_config->has_dsi_encoder;
 }
 
 static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
@@ -9941,11 +9921,10 @@ static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
        else
                haswell_get_ddi_pll(dev_priv, port, pipe_config);
 
-       if (pipe_config->shared_dpll >= 0) {
-               pll = &dev_priv->shared_dplls[pipe_config->shared_dpll];
-
-               WARN_ON(!pll->get_hw_state(dev_priv, pll,
-                                          &pipe_config->dpll_hw_state));
+       pll = pipe_config->shared_dpll;
+       if (pll) {
+               WARN_ON(!pll->funcs.get_hw_state(dev_priv, pll,
+                                                &pipe_config->dpll_hw_state));
        }
 
        /*
@@ -9972,53 +9951,37 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum intel_display_power_domain power_domain;
        unsigned long power_domain_mask;
-       uint32_t tmp;
-       bool ret;
+       bool active;
 
        power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
        if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
        power_domain_mask = BIT(power_domain);
 
-       ret = false;
+       pipe_config->shared_dpll = NULL;
 
-       pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
-       pipe_config->shared_dpll = DPLL_ID_PRIVATE;
-
-       tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
-       if (tmp & TRANS_DDI_FUNC_ENABLE) {
-               enum pipe trans_edp_pipe;
-               switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
-               default:
-                       WARN(1, "unknown pipe linked to edp transcoder\n");
-               case TRANS_DDI_EDP_INPUT_A_ONOFF:
-               case TRANS_DDI_EDP_INPUT_A_ON:
-                       trans_edp_pipe = PIPE_A;
-                       break;
-               case TRANS_DDI_EDP_INPUT_B_ONOFF:
-                       trans_edp_pipe = PIPE_B;
-                       break;
-               case TRANS_DDI_EDP_INPUT_C_ONOFF:
-                       trans_edp_pipe = PIPE_C;
-                       break;
-               }
+       active = hsw_get_transcoder_state(crtc, pipe_config, &power_domain_mask);
 
-               if (trans_edp_pipe == crtc->pipe)
-                       pipe_config->cpu_transcoder = TRANSCODER_EDP;
+       if (IS_BROXTON(dev_priv)) {
+               bxt_get_dsi_transcoder_state(crtc, pipe_config,
+                                            &power_domain_mask);
+               WARN_ON(active && pipe_config->has_dsi_encoder);
+               if (pipe_config->has_dsi_encoder)
+                       active = true;
        }
 
-       power_domain = POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder);
-       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+       if (!active)
                goto out;
-       power_domain_mask |= BIT(power_domain);
 
-       tmp = I915_READ(PIPECONF(pipe_config->cpu_transcoder));
-       if (!(tmp & PIPECONF_ENABLE))
-               goto out;
+       if (!pipe_config->has_dsi_encoder) {
+               haswell_get_ddi_port_state(crtc, pipe_config);
+               intel_get_pipe_timings(crtc, pipe_config);
+       }
 
-       haswell_get_ddi_port_state(crtc, pipe_config);
+       intel_get_pipe_src_size(crtc, pipe_config);
 
-       intel_get_pipe_timings(crtc, pipe_config);
+       pipe_config->gamma_mode =
+               I915_READ(GAMMA_MODE(crtc->pipe)) & GAMMA_MODE_MODE_MASK;
 
        if (INTEL_INFO(dev)->gen >= 9) {
                skl_init_scalers(dev, crtc, pipe_config);
@@ -10042,32 +10005,32 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
                pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) &&
                        (I915_READ(IPS_CTL) & IPS_ENABLE);
 
-       if (pipe_config->cpu_transcoder != TRANSCODER_EDP) {
+       if (pipe_config->cpu_transcoder != TRANSCODER_EDP &&
+           !transcoder_is_dsi(pipe_config->cpu_transcoder)) {
                pipe_config->pixel_multiplier =
                        I915_READ(PIPE_MULT(pipe_config->cpu_transcoder)) + 1;
        } else {
                pipe_config->pixel_multiplier = 1;
        }
 
-       ret = true;
-
 out:
        for_each_power_domain(power_domain, power_domain_mask)
                intel_display_power_put(dev_priv, power_domain);
 
-       return ret;
+       return active;
 }
 
-static void i845_update_cursor(struct drm_crtc *crtc, u32 base, bool on)
+static void i845_update_cursor(struct drm_crtc *crtc, u32 base,
+                              const struct intel_plane_state *plane_state)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        uint32_t cntl = 0, size = 0;
 
-       if (on) {
-               unsigned int width = intel_crtc->base.cursor->state->crtc_w;
-               unsigned int height = intel_crtc->base.cursor->state->crtc_h;
+       if (plane_state && plane_state->visible) {
+               unsigned int width = plane_state->base.crtc_w;
+               unsigned int height = plane_state->base.crtc_h;
                unsigned int stride = roundup_pow_of_two(width) * 4;
 
                switch (stride) {
@@ -10120,7 +10083,8 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base, bool on)
        }
 }
 
-static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base, bool on)
+static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base,
+                              const struct intel_plane_state *plane_state)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -10128,9 +10092,9 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base, bool on)
        int pipe = intel_crtc->pipe;
        uint32_t cntl = 0;
 
-       if (on) {
+       if (plane_state && plane_state->visible) {
                cntl = MCURSOR_GAMMA_ENABLE;
-               switch (intel_crtc->base.cursor->state->crtc_w) {
+               switch (plane_state->base.crtc_w) {
                        case 64:
                                cntl |= CURSOR_MODE_64_ARGB_AX;
                                break;
@@ -10141,17 +10105,17 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base, bool on)
                                cntl |= CURSOR_MODE_256_ARGB_AX;
                                break;
                        default:
-                               MISSING_CASE(intel_crtc->base.cursor->state->crtc_w);
+                               MISSING_CASE(plane_state->base.crtc_w);
                                return;
                }
                cntl |= pipe << 28; /* Connect to correct pipe */
 
                if (HAS_DDI(dev))
                        cntl |= CURSOR_PIPE_CSC_ENABLE;
-       }
 
-       if (crtc->cursor->state->rotation == BIT(DRM_ROTATE_180))
-               cntl |= CURSOR_ROTATE_180;
+               if (plane_state->base.rotation == BIT(DRM_ROTATE_180))
+                       cntl |= CURSOR_ROTATE_180;
+       }
 
        if (intel_crtc->cursor_cntl != cntl) {
                I915_WRITE(CURCNTR(pipe), cntl);
@@ -10168,56 +10132,45 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base, bool on)
 
 /* 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)
+                                    const struct intel_plane_state *plane_state)
 {
        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_plane_state *cursor_state = crtc->cursor->state;
-       int x = cursor_state->crtc_x;
-       int y = cursor_state->crtc_y;
-       u32 base = 0, pos = 0;
-
-       base = intel_crtc->cursor_addr;
-
-       if (x >= intel_crtc->config->pipe_src_w)
-               on = false;
-
-       if (y >= intel_crtc->config->pipe_src_h)
-               on = false;
+       u32 base = intel_crtc->cursor_addr;
+       u32 pos = 0;
 
-       if (x < 0) {
-               if (x + cursor_state->crtc_w <= 0)
-                       on = false;
+       if (plane_state) {
+               int x = plane_state->base.crtc_x;
+               int y = plane_state->base.crtc_y;
 
-               pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
-               x = -x;
-       }
-       pos |= x << CURSOR_X_SHIFT;
+               if (x < 0) {
+                       pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
+                       x = -x;
+               }
+               pos |= x << CURSOR_X_SHIFT;
 
-       if (y < 0) {
-               if (y + cursor_state->crtc_h <= 0)
-                       on = false;
+               if (y < 0) {
+                       pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
+                       y = -y;
+               }
+               pos |= y << CURSOR_Y_SHIFT;
 
-               pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
-               y = -y;
+               /* ILK+ do this automagically */
+               if (HAS_GMCH_DISPLAY(dev) &&
+                   plane_state->base.rotation == BIT(DRM_ROTATE_180)) {
+                       base += (plane_state->base.crtc_h *
+                                plane_state->base.crtc_w - 1) * 4;
+               }
        }
-       pos |= y << CURSOR_Y_SHIFT;
 
        I915_WRITE(CURPOS(pipe), pos);
 
-       /* ILK+ do this automagically */
-       if (HAS_GMCH_DISPLAY(dev) &&
-           crtc->cursor->state->rotation == BIT(DRM_ROTATE_180)) {
-               base += (cursor_state->crtc_h *
-                        cursor_state->crtc_w - 1) * 4;
-       }
-
        if (IS_845G(dev) || IS_I865G(dev))
-               i845_update_cursor(crtc, base, on);
+               i845_update_cursor(crtc, base, plane_state);
        else
-               i9xx_update_cursor(crtc, base, on);
+               i9xx_update_cursor(crtc, base, plane_state);
 }
 
 static bool cursor_size_ok(struct drm_device *dev,
@@ -10257,21 +10210,6 @@ static bool cursor_size_ok(struct drm_device *dev,
        return true;
 }
 
-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);
-
-       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_load_lut(crtc);
-}
-
 /* 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,
@@ -10385,6 +10323,7 @@ mode_fits_in_fbdev(struct drm_device *dev,
        if (obj->base.size < mode->vdisplay * fb->pitches[0])
                return NULL;
 
+       drm_framebuffer_reference(fb);
        return fb;
 #else
        return NULL;
@@ -10440,7 +10379,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
        struct drm_device *dev = encoder->dev;
        struct drm_framebuffer *fb;
        struct drm_mode_config *config = &dev->mode_config;
-       struct drm_atomic_state *state = NULL;
+       struct drm_atomic_state *state = NULL, *restore_state = NULL;
        struct drm_connector_state *connector_state;
        struct intel_crtc_state *crtc_state;
        int ret, i = -1;
@@ -10449,6 +10388,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
                      connector->base.id, connector->name,
                      encoder->base.id, encoder->name);
 
+       old->restore_state = NULL;
+
 retry:
        ret = drm_modeset_lock(&config->connection_mutex, ctx);
        if (ret)
@@ -10465,24 +10406,15 @@ retry:
         */
 
        /* See if we already have a CRTC for this connector */
-       if (encoder->crtc) {
-               crtc = encoder->crtc;
+       if (connector->state->crtc) {
+               crtc = connector->state->crtc;
 
                ret = drm_modeset_lock(&crtc->mutex, ctx);
                if (ret)
                        goto fail;
-               ret = drm_modeset_lock(&crtc->primary->mutex, ctx);
-               if (ret)
-                       goto fail;
-
-               old->dpms_mode = connector->dpms;
-               old->load_detect_temp = false;
 
                /* Make sure the crtc and connector are running */
-               if (connector->dpms != DRM_MODE_DPMS_ON)
-                       connector->funcs->dpms(connector, DRM_MODE_DPMS_ON);
-
-               return true;
+               goto found;
        }
 
        /* Find an unused one (if possible) */
@@ -10490,8 +10422,15 @@ retry:
                i++;
                if (!(encoder->possible_crtcs & (1 << i)))
                        continue;
-               if (possible_crtc->state->enable)
+
+               ret = drm_modeset_lock(&possible_crtc->mutex, ctx);
+               if (ret)
+                       goto fail;
+
+               if (possible_crtc->state->enable) {
+                       drm_modeset_unlock(&possible_crtc->mutex);
                        continue;
+               }
 
                crtc = possible_crtc;
                break;
@@ -10505,23 +10444,22 @@ retry:
                goto fail;
        }
 
-       ret = drm_modeset_lock(&crtc->mutex, ctx);
-       if (ret)
-               goto fail;
+found:
+       intel_crtc = to_intel_crtc(crtc);
+
        ret = drm_modeset_lock(&crtc->primary->mutex, ctx);
        if (ret)
                goto fail;
 
-       intel_crtc = to_intel_crtc(crtc);
-       old->dpms_mode = connector->dpms;
-       old->load_detect_temp = true;
-       old->release_fb = NULL;
-
        state = drm_atomic_state_alloc(dev);
-       if (!state)
-               return false;
+       restore_state = drm_atomic_state_alloc(dev);
+       if (!state || !restore_state) {
+               ret = -ENOMEM;
+               goto fail;
+       }
 
        state->acquire_ctx = ctx;
+       restore_state->acquire_ctx = ctx;
 
        connector_state = drm_atomic_get_connector_state(state, connector);
        if (IS_ERR(connector_state)) {
@@ -10529,8 +10467,9 @@ retry:
                goto fail;
        }
 
-       connector_state->crtc = crtc;
-       connector_state->best_encoder = &intel_encoder->base;
+       ret = drm_atomic_set_crtc_for_connector(connector_state, crtc);
+       if (ret)
+               goto fail;
 
        crtc_state = intel_atomic_get_crtc_state(state, intel_crtc);
        if (IS_ERR(crtc_state)) {
@@ -10554,7 +10493,6 @@ retry:
        if (fb == NULL) {
                DRM_DEBUG_KMS("creating tmp fb for load-detection\n");
                fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32);
-               old->release_fb = fb;
        } else
                DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
        if (IS_ERR(fb)) {
@@ -10566,15 +10504,29 @@ retry:
        if (ret)
                goto fail;
 
-       drm_mode_copy(&crtc_state->base.mode, mode);
+       drm_framebuffer_unreference(fb);
 
-       if (drm_atomic_commit(state)) {
+       ret = drm_atomic_set_mode_for_crtc(&crtc_state->base, mode);
+       if (ret)
+               goto fail;
+
+       ret = PTR_ERR_OR_ZERO(drm_atomic_get_connector_state(restore_state, connector));
+       if (!ret)
+               ret = PTR_ERR_OR_ZERO(drm_atomic_get_crtc_state(restore_state, crtc));
+       if (!ret)
+               ret = PTR_ERR_OR_ZERO(drm_atomic_get_plane_state(restore_state, crtc->primary));
+       if (ret) {
+               DRM_DEBUG_KMS("Failed to create a copy of old state to restore: %i\n", ret);
+               goto fail;
+       }
+
+       ret = drm_atomic_commit(state);
+       if (ret) {
                DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
-               if (old->release_fb)
-                       old->release_fb->funcs->destroy(old->release_fb);
                goto fail;
        }
-       crtc->primary->crtc = crtc;
+
+       old->restore_state = restore_state;
 
        /* let the connector get through one full cycle before testing */
        intel_wait_for_vblank(dev, intel_crtc->pipe);
@@ -10582,7 +10534,8 @@ retry:
 
 fail:
        drm_atomic_state_free(state);
-       state = NULL;
+       drm_atomic_state_free(restore_state);
+       restore_state = state = NULL;
 
        if (ret == -EDEADLK) {
                drm_modeset_backoff(ctx);
@@ -10596,66 +10549,24 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
                                    struct intel_load_detect_pipe *old,
                                    struct drm_modeset_acquire_ctx *ctx)
 {
-       struct drm_device *dev = connector->dev;
        struct intel_encoder *intel_encoder =
                intel_attached_encoder(connector);
        struct drm_encoder *encoder = &intel_encoder->base;
-       struct drm_crtc *crtc = encoder->crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct drm_atomic_state *state;
-       struct drm_connector_state *connector_state;
-       struct intel_crtc_state *crtc_state;
+       struct drm_atomic_state *state = old->restore_state;
        int ret;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
                      connector->base.id, connector->name,
                      encoder->base.id, encoder->name);
 
-       if (old->load_detect_temp) {
-               state = drm_atomic_state_alloc(dev);
-               if (!state)
-                       goto fail;
-
-               state->acquire_ctx = ctx;
-
-               connector_state = drm_atomic_get_connector_state(state, connector);
-               if (IS_ERR(connector_state))
-                       goto fail;
-
-               crtc_state = intel_atomic_get_crtc_state(state, intel_crtc);
-               if (IS_ERR(crtc_state))
-                       goto fail;
-
-               connector_state->best_encoder = NULL;
-               connector_state->crtc = NULL;
-
-               crtc_state->base.enable = crtc_state->base.active = false;
-
-               ret = intel_modeset_setup_plane_state(state, crtc, NULL, NULL,
-                                                     0, 0);
-               if (ret)
-                       goto fail;
-
-               ret = drm_atomic_commit(state);
-               if (ret)
-                       goto fail;
-
-               if (old->release_fb) {
-                       drm_framebuffer_unregister_private(old->release_fb);
-                       drm_framebuffer_unreference(old->release_fb);
-               }
-
+       if (!state)
                return;
-       }
 
-       /* Switch crtc and encoder back off if necessary */
-       if (old->dpms_mode != DRM_MODE_DPMS_ON)
-               connector->funcs->dpms(connector, old->dpms_mode);
-
-       return;
-fail:
-       DRM_DEBUG_KMS("Couldn't release load detect pipe.\n");
-       drm_atomic_state_free(state);
+       ret = drm_atomic_commit(state);
+       if (ret) {
+               DRM_DEBUG_KMS("Couldn't release load detect pipe: %i\n", ret);
+               drm_atomic_state_free(state);
+       }
 }
 
 static int i9xx_pll_refclk(struct drm_device *dev,
@@ -10786,19 +10697,18 @@ int intel_dotclock_calculate(int link_freq,
 static void ironlake_pch_clock_get(struct intel_crtc *crtc,
                                   struct intel_crtc_state *pipe_config)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
        /* read out port_clock from the DPLL */
        i9xx_crtc_clock_get(crtc, pipe_config);
 
        /*
-        * This value does not include pixel_multiplier.
-        * We will check that port_clock and adjusted_mode.crtc_clock
-        * agree once we know their relationship in the encoder's
-        * get_config() function.
+        * In case there is an active pipe without active ports,
+        * we may need some idea for the dotclock anyway.
+        * Calculate one based on the FDI configuration.
         */
        pipe_config->base.adjusted_mode.crtc_clock =
-               intel_dotclock_calculate(intel_fdi_link_freq(dev) * 10000,
+               intel_dotclock_calculate(intel_fdi_link_freq(dev_priv, pipe_config),
                                         &pipe_config->fdi_m_n);
 }
 
@@ -10810,7 +10720,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_state pipe_config;
+       struct intel_crtc_state *pipe_config;
        int htot = I915_READ(HTOTAL(cpu_transcoder));
        int hsync = I915_READ(HSYNC(cpu_transcoder));
        int vtot = I915_READ(VTOTAL(cpu_transcoder));
@@ -10821,6 +10731,12 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
        if (!mode)
                return NULL;
 
+       pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL);
+       if (!pipe_config) {
+               kfree(mode);
+               return NULL;
+       }
+
        /*
         * Construct a pipe_config sufficient for getting the clock info
         * back out of crtc_clock_get.
@@ -10828,14 +10744,14 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
         * 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) pipe;
-       pipe_config.pixel_multiplier = 1;
-       pipe_config.dpll_hw_state.dpll = I915_READ(DPLL(pipe));
-       pipe_config.dpll_hw_state.fp0 = I915_READ(FP0(pipe));
-       pipe_config.dpll_hw_state.fp1 = I915_READ(FP1(pipe));
-       i9xx_crtc_clock_get(intel_crtc, &pipe_config);
-
-       mode->clock = pipe_config.port_clock / pipe_config.pixel_multiplier;
+       pipe_config->cpu_transcoder = (enum transcoder) pipe;
+       pipe_config->pixel_multiplier = 1;
+       pipe_config->dpll_hw_state.dpll = I915_READ(DPLL(pipe));
+       pipe_config->dpll_hw_state.fp0 = I915_READ(FP0(pipe));
+       pipe_config->dpll_hw_state.fp1 = I915_READ(FP1(pipe));
+       i9xx_crtc_clock_get(intel_crtc, pipe_config);
+
+       mode->clock = pipe_config->port_clock / pipe_config->pixel_multiplier;
        mode->hdisplay = (htot & 0xffff) + 1;
        mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
        mode->hsync_start = (hsync & 0xffff) + 1;
@@ -10847,6 +10763,8 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
 
        drm_mode_set_name(mode);
 
+       kfree(pipe_config);
+
        return mode;
 }
 
@@ -10909,7 +10827,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
        struct drm_plane *primary = crtc->base.primary;
 
        mutex_lock(&dev->struct_mutex);
-       intel_unpin_fb_obj(work->old_fb, primary->state);
+       intel_unpin_fb_obj(work->old_fb, primary->state->rotation);
        drm_gem_object_unreference(&work->pending_flip_obj->base);
 
        if (work->flip_queued_req)
@@ -10917,6 +10835,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
        mutex_unlock(&dev->struct_mutex);
 
        intel_frontbuffer_flip_complete(dev, to_intel_plane(primary)->frontbuffer_bit);
+       intel_fbc_post_update(crtc);
        drm_framebuffer_unreference(work->old_fb);
 
        BUG_ON(atomic_read(&crtc->unpin_work_count) == 0);
@@ -10997,6 +10916,12 @@ static bool page_flip_finished(struct intel_crtc *crtc)
        if (INTEL_INFO(dev)->gen < 5 && !IS_G4X(dev))
                return true;
 
+       /*
+        * BDW signals flip done immediately if the plane
+        * is disabled, even if the plane enable is already
+        * armed to occur at the next vblank :(
+        */
+
        /*
         * A DSPSURFLIVE check isn't enough in case the mmio and CS flips
         * used the same base address. In that case the mmio flip might
@@ -11056,7 +10981,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
                                 struct drm_i915_gem_request *req,
                                 uint32_t flags)
 {
-       struct intel_engine_cs *ring = req->ring;
+       struct intel_engine_cs *engine = req->engine;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        u32 flip_mask;
        int ret;
@@ -11072,13 +10997,13 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
                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 |
+       intel_ring_emit(engine, MI_WAIT_FOR_EVENT | flip_mask);
+       intel_ring_emit(engine, MI_NOOP);
+       intel_ring_emit(engine, MI_DISPLAY_FLIP |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       intel_ring_emit(ring, fb->pitches[0]);
-       intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
-       intel_ring_emit(ring, 0); /* aux display base address, unused */
+       intel_ring_emit(engine, fb->pitches[0]);
+       intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
+       intel_ring_emit(engine, 0); /* aux display base address, unused */
 
        intel_mark_page_flip_active(intel_crtc->unpin_work);
        return 0;
@@ -11091,7 +11016,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
                                 struct drm_i915_gem_request *req,
                                 uint32_t flags)
 {
-       struct intel_engine_cs *ring = req->ring;
+       struct intel_engine_cs *engine = req->engine;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        u32 flip_mask;
        int ret;
@@ -11104,13 +11029,13 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
                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 |
+       intel_ring_emit(engine, MI_WAIT_FOR_EVENT | flip_mask);
+       intel_ring_emit(engine, MI_NOOP);
+       intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       intel_ring_emit(ring, fb->pitches[0]);
-       intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
-       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_emit(engine, fb->pitches[0]);
+       intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
+       intel_ring_emit(engine, MI_NOOP);
 
        intel_mark_page_flip_active(intel_crtc->unpin_work);
        return 0;
@@ -11123,7 +11048,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
                                 struct drm_i915_gem_request *req,
                                 uint32_t flags)
 {
-       struct intel_engine_cs *ring = req->ring;
+       struct intel_engine_cs *engine = req->engine;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        uint32_t pf, pipesrc;
@@ -11137,10 +11062,10 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
         * 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 |
+       intel_ring_emit(engine, MI_DISPLAY_FLIP |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       intel_ring_emit(ring, fb->pitches[0]);
-       intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset |
+       intel_ring_emit(engine, fb->pitches[0]);
+       intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset |
                        obj->tiling_mode);
 
        /* XXX Enabling the panel-fitter across page-flip is so far
@@ -11149,7 +11074,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
         */
        pf = 0;
        pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
-       intel_ring_emit(ring, pf | pipesrc);
+       intel_ring_emit(engine, pf | pipesrc);
 
        intel_mark_page_flip_active(intel_crtc->unpin_work);
        return 0;
@@ -11162,7 +11087,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
                                 struct drm_i915_gem_request *req,
                                 uint32_t flags)
 {
-       struct intel_engine_cs *ring = req->ring;
+       struct intel_engine_cs *engine = req->engine;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        uint32_t pf, pipesrc;
@@ -11172,10 +11097,10 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
        if (ret)
                return ret;
 
-       intel_ring_emit(ring, MI_DISPLAY_FLIP |
+       intel_ring_emit(engine, MI_DISPLAY_FLIP |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       intel_ring_emit(ring, fb->pitches[0] | obj->tiling_mode);
-       intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
+       intel_ring_emit(engine, fb->pitches[0] | obj->tiling_mode);
+       intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
 
        /* Contrary to the suggestions in the documentation,
         * "Enable Panel Fitter" does not seem to be required when page
@@ -11185,7 +11110,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
         */
        pf = 0;
        pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
-       intel_ring_emit(ring, pf | pipesrc);
+       intel_ring_emit(engine, pf | pipesrc);
 
        intel_mark_page_flip_active(intel_crtc->unpin_work);
        return 0;
@@ -11198,7 +11123,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
                                 struct drm_i915_gem_request *req,
                                 uint32_t flags)
 {
-       struct intel_engine_cs *ring = req->ring;
+       struct intel_engine_cs *engine = req->engine;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        uint32_t plane_bit = 0;
        int len, ret;
@@ -11219,7 +11144,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
        }
 
        len = 4;
-       if (ring->id == RCS) {
+       if (engine->id == RCS) {
                len += 6;
                /*
                 * On Gen 8, SRM is now taking an extra dword to accommodate
@@ -11257,36 +11182,36 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
         * for the RCS also doesn't appear to drop events. Setting the DERRMR
         * to zero does lead to lockups within MI_DISPLAY_FLIP.
         */
-       if (ring->id == RCS) {
-               intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
-               intel_ring_emit_reg(ring, DERRMR);
-               intel_ring_emit(ring, ~(DERRMR_PIPEA_PRI_FLIP_DONE |
-                                       DERRMR_PIPEB_PRI_FLIP_DONE |
-                                       DERRMR_PIPEC_PRI_FLIP_DONE));
+       if (engine->id == RCS) {
+               intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(1));
+               intel_ring_emit_reg(engine, DERRMR);
+               intel_ring_emit(engine, ~(DERRMR_PIPEA_PRI_FLIP_DONE |
+                                         DERRMR_PIPEB_PRI_FLIP_DONE |
+                                         DERRMR_PIPEC_PRI_FLIP_DONE));
                if (IS_GEN8(dev))
-                       intel_ring_emit(ring, MI_STORE_REGISTER_MEM_GEN8 |
+                       intel_ring_emit(engine, MI_STORE_REGISTER_MEM_GEN8 |
                                              MI_SRM_LRM_GLOBAL_GTT);
                else
-                       intel_ring_emit(ring, MI_STORE_REGISTER_MEM |
+                       intel_ring_emit(engine, MI_STORE_REGISTER_MEM |
                                              MI_SRM_LRM_GLOBAL_GTT);
-               intel_ring_emit_reg(ring, DERRMR);
-               intel_ring_emit(ring, ring->scratch.gtt_offset + 256);
+               intel_ring_emit_reg(engine, DERRMR);
+               intel_ring_emit(engine, engine->scratch.gtt_offset + 256);
                if (IS_GEN8(dev)) {
-                       intel_ring_emit(ring, 0);
-                       intel_ring_emit(ring, MI_NOOP);
+                       intel_ring_emit(engine, 0);
+                       intel_ring_emit(engine, MI_NOOP);
                }
        }
 
-       intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit);
-       intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode));
-       intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
-       intel_ring_emit(ring, (MI_NOOP));
+       intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 | plane_bit);
+       intel_ring_emit(engine, (fb->pitches[0] | obj->tiling_mode));
+       intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
+       intel_ring_emit(engine, (MI_NOOP));
 
        intel_mark_page_flip_active(intel_crtc->unpin_work);
        return 0;
 }
 
-static bool use_mmio_flip(struct intel_engine_cs *ring,
+static bool use_mmio_flip(struct intel_engine_cs *engine,
                          struct drm_i915_gem_object *obj)
 {
        /*
@@ -11297,10 +11222,10 @@ static bool use_mmio_flip(struct intel_engine_cs *ring,
         * So using MMIO flips there would disrupt this mechanism.
         */
 
-       if (ring == NULL)
+       if (engine == NULL)
                return true;
 
-       if (INTEL_INFO(ring->dev)->gen < 5)
+       if (INTEL_INFO(engine->dev)->gen < 5)
                return false;
 
        if (i915.use_mmio_flip < 0)
@@ -11314,7 +11239,7 @@ static bool use_mmio_flip(struct intel_engine_cs *ring,
                                                       false))
                return true;
        else
-               return ring != i915_gem_request_get_ring(obj->last_write_req);
+               return engine != i915_gem_request_get_engine(obj->last_write_req);
 }
 
 static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
@@ -11351,13 +11276,12 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
         */
        if (intel_rotation_90_or_270(rotation)) {
                /* stride = Surface height in tiles */
-               tile_height = intel_tile_height(dev, fb->pixel_format,
-                                               fb->modifier[0], 0);
+               tile_height = intel_tile_height(dev_priv, fb->modifier[0], 0);
                stride = DIV_ROUND_UP(fb->height, tile_height);
        } else {
                stride = fb->pitches[0] /
-                               intel_fb_stride_alignment(dev, fb->modifier[0],
-                                                         fb->pixel_format);
+                       intel_fb_stride_alignment(dev_priv, fb->modifier[0],
+                                                 fb->pixel_format);
        }
 
        /*
@@ -11561,7 +11485,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        struct drm_plane *primary = crtc->primary;
        enum pipe pipe = intel_crtc->pipe;
        struct intel_unpin_work *work;
-       struct intel_engine_cs *ring;
+       struct intel_engine_cs *engine;
        bool mmio_flip;
        struct drm_i915_gem_request *request = NULL;
        int ret;
@@ -11633,6 +11557,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
        crtc->primary->fb = fb;
        update_state_fb(crtc->primary);
+       intel_fbc_pre_update(intel_crtc);
 
        work->pending_flip_obj = obj;
 
@@ -11647,21 +11572,21 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                work->flip_count = I915_READ(PIPE_FLIPCOUNT_G4X(pipe)) + 1;
 
        if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
-               ring = &dev_priv->ring[BCS];
+               engine = &dev_priv->engine[BCS];
                if (obj->tiling_mode != intel_fb_obj(work->old_fb)->tiling_mode)
                        /* vlv: DISPLAY_FLIP fails to change tiling */
-                       ring = NULL;
+                       engine = NULL;
        } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
-               ring = &dev_priv->ring[BCS];
+               engine = &dev_priv->engine[BCS];
        } else if (INTEL_INFO(dev)->gen >= 7) {
-               ring = i915_gem_request_get_ring(obj->last_write_req);
-               if (ring == NULL || ring->id != RCS)
-                       ring = &dev_priv->ring[BCS];
+               engine = i915_gem_request_get_engine(obj->last_write_req);
+               if (engine == NULL || engine->id != RCS)
+                       engine = &dev_priv->engine[BCS];
        } else {
-               ring = &dev_priv->ring[RCS];
+               engine = &dev_priv->engine[RCS];
        }
 
-       mmio_flip = use_mmio_flip(ring, obj);
+       mmio_flip = use_mmio_flip(engine, obj);
 
        /* When using CS flips, we want to emit semaphores between rings.
         * However, when using mmio flips we will create a task to do the
@@ -11669,13 +11594,12 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
         * into the display plane and skip any waits.
         */
        if (!mmio_flip) {
-               ret = i915_gem_object_sync(obj, ring, &request);
+               ret = i915_gem_object_sync(obj, engine, &request);
                if (ret)
                        goto cleanup_pending;
        }
 
-       ret = intel_pin_and_fence_fb_obj(crtc->primary, fb,
-                                        crtc->primary->state);
+       ret = intel_pin_and_fence_fb_obj(fb, primary->state->rotation);
        if (ret)
                goto cleanup_pending;
 
@@ -11692,9 +11616,11 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                                        obj->last_write_req);
        } else {
                if (!request) {
-                       ret = i915_gem_request_alloc(ring, ring->default_context, &request);
-                       if (ret)
+                       request = i915_gem_request_alloc(engine, NULL);
+                       if (IS_ERR(request)) {
+                               ret = PTR_ERR(request);
                                goto cleanup_unpin;
+                       }
                }
 
                ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request,
@@ -11715,7 +11641,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                          to_intel_plane(primary)->frontbuffer_bit);
        mutex_unlock(&dev->struct_mutex);
 
-       intel_fbc_deactivate(intel_crtc);
        intel_frontbuffer_flip_prepare(dev,
                                       to_intel_plane(primary)->frontbuffer_bit);
 
@@ -11724,9 +11649,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        return 0;
 
 cleanup_unpin:
-       intel_unpin_fb_obj(fb, crtc->primary->state);
+       intel_unpin_fb_obj(fb, crtc->primary->state->rotation);
 cleanup_pending:
-       if (request)
+       if (!IS_ERR_OR_NULL(request))
                i915_gem_request_cancel(request);
        atomic_dec(&intel_crtc->unpin_work_count);
        mutex_unlock(&dev->struct_mutex);
@@ -11837,11 +11762,10 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_plane *plane = plane_state->plane;
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_plane_state *old_plane_state =
                to_intel_plane_state(plane->state);
        int idx = intel_crtc->base.base.id, ret;
-       int i = drm_plane_index(plane);
        bool mode_changed = needs_modeset(crtc_state);
        bool was_crtc_enabled = crtc->state->active;
        bool is_crtc_enabled = crtc_state->active;
@@ -11863,12 +11787,20 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
        if (!was_crtc_enabled && WARN_ON(was_visible))
                was_visible = false;
 
-       if (!is_crtc_enabled && WARN_ON(visible))
-               visible = false;
+       /*
+        * Visibility is calculated as if the crtc was on, but
+        * after scaler setup everything depends on it being off
+        * when the crtc isn't active.
+        */
+       if (!is_crtc_enabled)
+               to_intel_plane_state(plane_state)->visible = visible = false;
 
        if (!was_visible && !visible)
                return 0;
 
+       if (fb != old_plane_state->base.fb)
+               pipe_config->fb_changed = true;
+
        turn_off = was_visible && (!visible || mode_changed);
        turn_on = visible && (!was_visible || mode_changed);
 
@@ -11879,90 +11811,43 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
                         plane->base.id, was_visible, visible,
                         turn_off, turn_on, mode_changed);
 
-       if (turn_on || turn_off) {
-               pipe_config->wm_changed = true;
+       if (turn_on) {
+               pipe_config->update_wm_pre = true;
 
                /* must disable cxsr around plane enable/disable */
-               if (plane->type != DRM_PLANE_TYPE_CURSOR) {
-                       if (is_crtc_enabled)
-                               intel_crtc->atomic.wait_vblank = true;
+               if (plane->type != DRM_PLANE_TYPE_CURSOR)
+                       pipe_config->disable_cxsr = true;
+       } else if (turn_off) {
+               pipe_config->update_wm_post = true;
+
+               /* must disable cxsr around plane enable/disable */
+               if (plane->type != DRM_PLANE_TYPE_CURSOR)
                        pipe_config->disable_cxsr = true;
-               }
        } else if (intel_wm_need_update(plane, plane_state)) {
-               pipe_config->wm_changed = true;
+               /* FIXME bollocks */
+               pipe_config->update_wm_pre = true;
+               pipe_config->update_wm_post = true;
        }
 
-       if (visible || was_visible)
-               intel_crtc->atomic.fb_bits |=
-                       to_intel_plane(plane)->frontbuffer_bit;
+       /* Pre-gen9 platforms need two-step watermark updates */
+       if ((pipe_config->update_wm_pre || pipe_config->update_wm_post) &&
+           INTEL_INFO(dev)->gen < 9 && dev_priv->display.optimize_watermarks)
+               to_intel_crtc_state(crtc_state)->wm.need_postvbl_update = true;
 
-       switch (plane->type) {
-       case DRM_PLANE_TYPE_PRIMARY:
-               intel_crtc->atomic.pre_disable_primary = turn_off;
-               intel_crtc->atomic.post_enable_primary = turn_on;
-
-               if (turn_off) {
-                       /*
-                        * FIXME: Actually if we will still have any other
-                        * plane enabled on the pipe we could let IPS enabled
-                        * still, but for now lets consider that when we make
-                        * primary invisible by setting DSPCNTR to 0 on
-                        * update_primary_plane function IPS needs to be
-                        * disable.
-                        */
-                       intel_crtc->atomic.disable_ips = true;
-
-                       intel_crtc->atomic.disable_fbc = true;
-               }
-
-               /*
-                * FBC does not work on some platforms for rotated
-                * planes, so disable it when rotation is not 0 and
-                * update it when rotation is set back to 0.
-                *
-                * FIXME: This is redundant with the fbc update done in
-                * the primary plane enable function except that that
-                * one is done too late. We eventually need to unify
-                * this.
-                */
-
-               if (visible &&
-                   INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
-                   dev_priv->fbc.crtc == intel_crtc &&
-                   plane_state->rotation != BIT(DRM_ROTATE_0))
-                       intel_crtc->atomic.disable_fbc = true;
-
-               /*
-                * BDW signals flip done immediately if the plane
-                * is disabled, even if the plane enable is already
-                * armed to occur at the next vblank :(
-                */
-               if (turn_on && IS_BROADWELL(dev))
-                       intel_crtc->atomic.wait_vblank = true;
+       if (visible || was_visible)
+               pipe_config->fb_bits |= to_intel_plane(plane)->frontbuffer_bit;
 
-               intel_crtc->atomic.update_fbc |= visible || mode_changed;
-               break;
-       case DRM_PLANE_TYPE_CURSOR:
-               break;
-       case DRM_PLANE_TYPE_OVERLAY:
-               /*
-                * WaCxSRDisabledForSpriteScaling:ivb
-                *
-                * cstate->update_wm was already set above, so this flag will
-                * take effect when we commit and program watermarks.
-                */
-               if (IS_IVYBRIDGE(dev) &&
-                   needs_scaling(to_intel_plane_state(plane_state)) &&
-                   !needs_scaling(old_plane_state)) {
-                       to_intel_crtc_state(crtc_state)->disable_lp_wm = true;
-               } else if (turn_off && !mode_changed) {
-                       intel_crtc->atomic.wait_vblank = true;
-                       intel_crtc->atomic.update_sprite_watermarks |=
-                               1 << i;
-               }
+       /*
+        * WaCxSRDisabledForSpriteScaling:ivb
+        *
+        * cstate->update_wm was already set above, so this flag will
+        * take effect when we commit and program watermarks.
+        */
+       if (plane->type == DRM_PLANE_TYPE_OVERLAY && IS_IVYBRIDGE(dev) &&
+           needs_scaling(to_intel_plane_state(plane_state)) &&
+           !needs_scaling(old_plane_state))
+               pipe_config->disable_lp_wm = true;
 
-               break;
-       }
        return 0;
 }
 
@@ -12034,22 +11919,49 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
        }
 
        if (mode_changed && !crtc_state->active)
-               pipe_config->wm_changed = true;
+               pipe_config->update_wm_post = true;
 
        if (mode_changed && crtc_state->enable &&
            dev_priv->display.crtc_compute_clock &&
-           !WARN_ON(pipe_config->shared_dpll != DPLL_ID_PRIVATE)) {
+           !WARN_ON(pipe_config->shared_dpll)) {
                ret = dev_priv->display.crtc_compute_clock(intel_crtc,
                                                           pipe_config);
                if (ret)
                        return ret;
        }
 
+       if (crtc_state->color_mgmt_changed) {
+               ret = intel_color_check(crtc, crtc_state);
+               if (ret)
+                       return ret;
+       }
+
        ret = 0;
        if (dev_priv->display.compute_pipe_wm) {
-               ret = dev_priv->display.compute_pipe_wm(intel_crtc, state);
-               if (ret)
+               ret = dev_priv->display.compute_pipe_wm(pipe_config);
+               if (ret) {
+                       DRM_DEBUG_KMS("Target pipe watermarks are invalid\n");
                        return ret;
+               }
+       }
+
+       if (dev_priv->display.compute_intermediate_wm &&
+           !to_intel_atomic_state(state)->skip_intermediate_wm) {
+               if (WARN_ON(!dev_priv->display.compute_pipe_wm))
+                       return 0;
+
+               /*
+                * Calculate 'intermediate' watermarks that satisfy both the
+                * old state and the new state.  We can program these
+                * immediately.
+                */
+               ret = dev_priv->display.compute_intermediate_wm(crtc->dev,
+                                                               intel_crtc,
+                                                               pipe_config);
+               if (ret) {
+                       DRM_DEBUG_KMS("No valid intermediate pipe watermarks are possible\n");
+                       return ret;
+               }
        }
 
        if (INTEL_INFO(dev)->gen >= 9) {
@@ -12066,7 +11978,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
 
 static const struct drm_crtc_helper_funcs intel_helper_funcs = {
        .mode_set_base_atomic = intel_pipe_set_base_atomic,
-       .load_lut = intel_crtc_load_lut,
        .atomic_begin = intel_begin_crtc_commit,
        .atomic_flush = intel_finish_crtc_commit,
        .atomic_check = intel_crtc_atomic_check,
@@ -12183,7 +12094,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
        DRM_DEBUG_KMS("[CRTC:%d]%s config %p for pipe %c\n", crtc->base.base.id,
                      context, pipe_config, pipe_name(crtc->pipe));
 
-       DRM_DEBUG_KMS("cpu_transcoder: %c\n", transcoder_name(pipe_config->cpu_transcoder));
+       DRM_DEBUG_KMS("cpu_transcoder: %s\n", transcoder_name(pipe_config->cpu_transcoder));
        DRM_DEBUG_KMS("pipe bpp: %i, dithering: %i\n",
                      pipe_config->pipe_bpp, pipe_config->dither);
        DRM_DEBUG_KMS("fdi/pch: %i, lanes: %i, gmch_m: %u, gmch_n: %u, link_m: %u, link_n: %u, tu: %u\n",
@@ -12259,7 +12170,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
                              pipe_config->dpll_hw_state.cfgcr1,
                              pipe_config->dpll_hw_state.cfgcr2);
        } else if (HAS_DDI(dev)) {
-               DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
+               DRM_DEBUG_KMS("ddi_pll_sel: 0x%x; dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
                              pipe_config->ddi_pll_sel,
                              pipe_config->dpll_hw_state.wrpll,
                              pipe_config->dpll_hw_state.spll);
@@ -12362,7 +12273,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
        struct drm_crtc_state tmp_state;
        struct intel_crtc_scaler_state scaler_state;
        struct intel_dpll_hw_state dpll_hw_state;
-       enum intel_dpll_id shared_dpll;
+       struct intel_shared_dpll *shared_dpll;
        uint32_t ddi_pll_sel;
        bool force_thru;
 
@@ -12561,19 +12472,22 @@ intel_compare_m_n(unsigned int m, unsigned int n,
 
        BUILD_BUG_ON(DATA_LINK_M_N_MASK > INT_MAX);
 
-       if (m > m2) {
-               while (m > m2) {
+       if (n > n2) {
+               while (n > n2) {
                        m2 <<= 1;
                        n2 <<= 1;
                }
-       } else if (m < m2) {
-               while (m < m2) {
+       } else if (n < n2) {
+               while (n < n2) {
                        m <<= 1;
                        n <<= 1;
                }
        }
 
-       return m == m2 && n == n2;
+       if (n != n2)
+               return false;
+
+       return intel_fuzzy_clock_check(m, m2);
 }
 
 static bool
@@ -12629,6 +12543,15 @@ intel_pipe_config_compare(struct drm_device *dev,
                ret = false; \
        }
 
+#define PIPE_CONF_CHECK_P(name)        \
+       if (current_config->name != pipe_config->name) { \
+               INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \
+                         "(expected %p, found %p)\n", \
+                         current_config->name, \
+                         pipe_config->name); \
+               ret = false; \
+       }
+
 #define PIPE_CONF_CHECK_M_N(name) \
        if (!intel_compare_link_m_n(&current_config->name, \
                                    &pipe_config->name,\
@@ -12649,6 +12572,11 @@ intel_pipe_config_compare(struct drm_device *dev,
                ret = false; \
        }
 
+/* This is required for BDW+ where there is only one set of registers for
+ * switching between high and low RR.
+ * This macro can be used whenever a comparison has to be made between one
+ * hw state and multiple sw state variables.
+ */
 #define PIPE_CONF_CHECK_M_N_ALT(name, alt_name) \
        if (!intel_compare_link_m_n(&current_config->name, \
                                    &pipe_config->name, adjust) && \
@@ -12676,22 +12604,6 @@ intel_pipe_config_compare(struct drm_device *dev,
                ret = false; \
        }
 
-/* This is required for BDW+ where there is only one set of registers for
- * switching between high and low RR.
- * This macro can be used whenever a comparison has to be made between one
- * hw state and multiple sw state variables.
- */
-#define PIPE_CONF_CHECK_I_ALT(name, alt_name) \
-       if ((current_config->name != pipe_config->name) && \
-               (current_config->alt_name != pipe_config->name)) { \
-                       INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \
-                                 "(expected %i or %i, found %i)\n", \
-                                 current_config->name, \
-                                 current_config->alt_name, \
-                                 pipe_config->name); \
-                       ret = false; \
-       }
-
 #define PIPE_CONF_CHECK_FLAGS(name, mask)      \
        if ((current_config->name ^ pipe_config->name) & (mask)) { \
                INTEL_ERR_OR_DBG_KMS("mismatch in " #name "(" #mask ") " \
@@ -12796,7 +12708,7 @@ intel_pipe_config_compare(struct drm_device *dev,
 
        PIPE_CONF_CHECK_X(ddi_pll_sel);
 
-       PIPE_CONF_CHECK_I(shared_dpll);
+       PIPE_CONF_CHECK_P(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);
@@ -12815,7 +12727,7 @@ intel_pipe_config_compare(struct drm_device *dev,
 
 #undef PIPE_CONF_CHECK_X
 #undef PIPE_CONF_CHECK_I
-#undef PIPE_CONF_CHECK_I_ALT
+#undef PIPE_CONF_CHECK_P
 #undef PIPE_CONF_CHECK_FLAGS
 #undef PIPE_CONF_CHECK_CLOCK_FUZZY
 #undef PIPE_CONF_QUIRK
@@ -12824,6 +12736,24 @@ intel_pipe_config_compare(struct drm_device *dev,
        return ret;
 }
 
+static void intel_pipe_config_sanity_check(struct drm_i915_private *dev_priv,
+                                          const struct intel_crtc_state *pipe_config)
+{
+       if (pipe_config->has_pch_encoder) {
+               int fdi_dotclock = intel_dotclock_calculate(intel_fdi_link_freq(dev_priv, pipe_config),
+                                                           &pipe_config->fdi_m_n);
+               int dotclock = pipe_config->base.adjusted_mode.crtc_clock;
+
+               /*
+                * FDI already provided one idea for the dotclock.
+                * Yell if the encoder disagrees.
+                */
+               WARN(!intel_fuzzy_clock_check(fdi_dotclock, dotclock),
+                    "FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n",
+                    fdi_dotclock, dotclock);
+       }
+}
+
 static void check_wm_state(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -12997,6 +12927,8 @@ check_crtc_state(struct drm_device *dev, struct drm_atomic_state *old_state)
                if (!crtc->state->active)
                        continue;
 
+               intel_pipe_config_sanity_check(dev_priv, pipe_config);
+
                sw_config = to_intel_crtc_state(crtc->state);
                if (!intel_pipe_config_compare(dev, sw_config,
                                               pipe_config, false)) {
@@ -13018,39 +12950,44 @@ check_shared_dpll_state(struct drm_device *dev)
        int i;
 
        for (i = 0; i < dev_priv->num_shared_dpll; i++) {
-               struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
-               int enabled_crtcs = 0, active_crtcs = 0;
+               struct intel_shared_dpll *pll =
+                       intel_get_shared_dpll_by_id(dev_priv, i);
+               unsigned enabled_crtcs = 0, active_crtcs = 0;
                bool active;
 
                memset(&dpll_hw_state, 0, sizeof(dpll_hw_state));
 
                DRM_DEBUG_KMS("%s\n", pll->name);
 
-               active = pll->get_hw_state(dev_priv, pll, &dpll_hw_state);
+               active = pll->funcs.get_hw_state(dev_priv, pll, &dpll_hw_state);
 
-               I915_STATE_WARN(pll->active > hweight32(pll->config.crtc_mask),
-                    "more active pll users than references: %i vs %i\n",
-                    pll->active, hweight32(pll->config.crtc_mask));
-               I915_STATE_WARN(pll->active && !pll->on,
-                    "pll in active use but not on in sw tracking\n");
-               I915_STATE_WARN(pll->on && !pll->active,
-                    "pll in on but not on in use in sw tracking\n");
-               I915_STATE_WARN(pll->on != active,
-                    "pll on state mismatch (expected %i, found %i)\n",
-                    pll->on, active);
+               I915_STATE_WARN(pll->active_mask & ~pll->config.crtc_mask,
+                    "more active pll users than references: %x vs %x\n",
+                    pll->active_mask, pll->config.crtc_mask);
+
+               if (!(pll->flags & INTEL_DPLL_ALWAYS_ON)) {
+                       I915_STATE_WARN(!pll->on && pll->active_mask,
+                            "pll in active use but not on in sw tracking\n");
+                       I915_STATE_WARN(pll->on && !pll->active_mask,
+                            "pll is on but not used by any active crtc\n");
+                       I915_STATE_WARN(pll->on != active,
+                            "pll on state mismatch (expected %i, found %i)\n",
+                            pll->on, active);
+               }
 
                for_each_intel_crtc(dev, crtc) {
-                       if (crtc->base.state->enable && intel_crtc_to_shared_dpll(crtc) == pll)
-                               enabled_crtcs++;
-                       if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll)
-                               active_crtcs++;
-               }
-               I915_STATE_WARN(pll->active != active_crtcs,
-                    "pll active crtcs mismatch (expected %i, found %i)\n",
-                    pll->active, active_crtcs);
-               I915_STATE_WARN(hweight32(pll->config.crtc_mask) != enabled_crtcs,
-                    "pll enabled crtcs mismatch (expected %i, found %i)\n",
-                    hweight32(pll->config.crtc_mask), enabled_crtcs);
+                       if (crtc->base.state->enable && crtc->config->shared_dpll == pll)
+                               enabled_crtcs |= 1 << drm_crtc_index(&crtc->base);
+                       if (crtc->base.state->active && crtc->config->shared_dpll == pll)
+                               active_crtcs |= 1 << drm_crtc_index(&crtc->base);
+               }
+
+               I915_STATE_WARN(pll->active_mask != active_crtcs,
+                    "pll active crtcs mismatch (expected %x, found %x)\n",
+                    pll->active_mask, active_crtcs);
+               I915_STATE_WARN(pll->config.crtc_mask != enabled_crtcs,
+                    "pll enabled crtcs mismatch (expected %x, found %x)\n",
+                    pll->config.crtc_mask, enabled_crtcs);
 
                I915_STATE_WARN(pll->on && memcmp(&pll->config.hw_state, &dpll_hw_state,
                                       sizeof(dpll_hw_state)),
@@ -13069,18 +13006,6 @@ intel_modeset_check_state(struct drm_device *dev,
        check_shared_dpll_state(dev);
 }
 
-void ironlake_check_encoder_dotclock(const struct intel_crtc_state *pipe_config,
-                                    int dotclock)
-{
-       /*
-        * FDI already provided one idea for the dotclock.
-        * Yell if the encoder disagrees.
-        */
-       WARN(!intel_fuzzy_clock_check(pipe_config->base.adjusted_mode.crtc_clock, dotclock),
-            "FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n",
-            pipe_config->base.adjusted_mode.crtc_clock, dotclock);
-}
-
 static void update_scanline_offset(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
@@ -13124,8 +13049,6 @@ static void intel_modeset_clear_plls(struct drm_atomic_state *state)
        struct drm_device *dev = state->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_shared_dpll_config *shared_dpll = NULL;
-       struct intel_crtc *intel_crtc;
-       struct intel_crtc_state *intel_crtc_state;
        struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
        int i;
@@ -13134,21 +13057,22 @@ static void intel_modeset_clear_plls(struct drm_atomic_state *state)
                return;
 
        for_each_crtc_in_state(state, crtc, crtc_state, i) {
-               int dpll;
-
-               intel_crtc = to_intel_crtc(crtc);
-               intel_crtc_state = to_intel_crtc_state(crtc_state);
-               dpll = intel_crtc_state->shared_dpll;
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               struct intel_shared_dpll *old_dpll =
+                       to_intel_crtc_state(crtc->state)->shared_dpll;
 
-               if (!needs_modeset(crtc_state) || dpll == DPLL_ID_PRIVATE)
+               if (!needs_modeset(crtc_state))
                        continue;
 
-               intel_crtc_state->shared_dpll = DPLL_ID_PRIVATE;
+               to_intel_crtc_state(crtc_state)->shared_dpll = NULL;
+
+               if (!old_dpll)
+                       continue;
 
                if (!shared_dpll)
                        shared_dpll = intel_atomic_get_shared_dpll_state(state);
 
-               shared_dpll[dpll].crtc_mask &= ~(1 << intel_crtc->pipe);
+               intel_shared_dpll_config_put(shared_dpll, old_dpll, intel_crtc);
        }
 }
 
@@ -13248,15 +13172,27 @@ static int intel_modeset_all_pipes(struct drm_atomic_state *state)
 
 static int intel_modeset_checks(struct drm_atomic_state *state)
 {
-       struct drm_device *dev = state->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret;
+       struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+       struct drm_i915_private *dev_priv = state->dev->dev_private;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *crtc_state;
+       int ret = 0, i;
 
        if (!check_digital_port_conflicts(state)) {
                DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n");
                return -EINVAL;
        }
 
+       intel_state->modeset = true;
+       intel_state->active_crtcs = dev_priv->active_crtcs;
+
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+               if (crtc_state->active)
+                       intel_state->active_crtcs |= 1 << i;
+               else
+                       intel_state->active_crtcs &= ~(1 << i);
+       }
+
        /*
         * See if the config requires any additional preparation, e.g.
         * to adjust global state with pipes off.  We need to do this
@@ -13265,22 +13201,22 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
         * adjusted_mode bits in the crtc directly.
         */
        if (dev_priv->display.modeset_calc_cdclk) {
-               unsigned int cdclk;
-
                ret = dev_priv->display.modeset_calc_cdclk(state);
 
-               cdclk = to_intel_atomic_state(state)->cdclk;
-               if (!ret && cdclk != dev_priv->cdclk_freq)
+               if (!ret && intel_state->dev_cdclk != dev_priv->cdclk_freq)
                        ret = intel_modeset_all_pipes(state);
 
                if (ret < 0)
                        return ret;
+
+               DRM_DEBUG_KMS("New cdclk calculated to be atomic %u, actual %u\n",
+                             intel_state->cdclk, intel_state->dev_cdclk);
        } else
-               to_intel_atomic_state(state)->cdclk = dev_priv->cdclk_freq;
+               to_intel_atomic_state(state)->cdclk = dev_priv->atomic_cdclk_freq;
 
        intel_modeset_clear_plls(state);
 
-       if (IS_HASWELL(dev))
+       if (IS_HASWELL(dev_priv))
                return haswell_mode_set_planes_workaround(state);
 
        return 0;
@@ -13333,6 +13269,7 @@ static void calc_watermark_data(struct drm_atomic_state *state)
 static int intel_atomic_check(struct drm_device *dev,
                              struct drm_atomic_state *state)
 {
+       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
        struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
@@ -13347,9 +13284,6 @@ static int intel_atomic_check(struct drm_device *dev,
                struct intel_crtc_state *pipe_config =
                        to_intel_crtc_state(crtc_state);
 
-               memset(&to_intel_crtc(crtc)->atomic, 0,
-                      sizeof(struct intel_crtc_atomic_commit));
-
                /* Catch I915_MODE_FLAG_INHERITED */
                if (crtc_state->mode.private_flags != crtc->state->mode.private_flags)
                        crtc_state->mode_changed = true;
@@ -13375,7 +13309,7 @@ static int intel_atomic_check(struct drm_device *dev,
                        return ret;
 
                if (i915.fastboot &&
-                   intel_pipe_config_compare(state->dev,
+                   intel_pipe_config_compare(dev,
                                        to_intel_crtc_state(crtc->state),
                                        pipe_config, true)) {
                        crtc_state->mode_changed = false;
@@ -13401,12 +13335,13 @@ static int intel_atomic_check(struct drm_device *dev,
                if (ret)
                        return ret;
        } else
-               intel_state->cdclk = to_i915(state->dev)->cdclk_freq;
+               intel_state->cdclk = dev_priv->cdclk_freq;
 
-       ret = drm_atomic_helper_check_planes(state->dev, state);
+       ret = drm_atomic_helper_check_planes(dev, state);
        if (ret)
                return ret;
 
+       intel_fbc_choose_crtc(dev_priv, state);
        calc_watermark_data(state);
 
        return 0;
@@ -13478,6 +13413,71 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
        return ret;
 }
 
+static void intel_atomic_wait_for_vblanks(struct drm_device *dev,
+                                         struct drm_i915_private *dev_priv,
+                                         unsigned crtc_mask)
+{
+       unsigned last_vblank_count[I915_MAX_PIPES];
+       enum pipe pipe;
+       int ret;
+
+       if (!crtc_mask)
+               return;
+
+       for_each_pipe(dev_priv, pipe) {
+               struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+
+               if (!((1 << pipe) & crtc_mask))
+                       continue;
+
+               ret = drm_crtc_vblank_get(crtc);
+               if (WARN_ON(ret != 0)) {
+                       crtc_mask &= ~(1 << pipe);
+                       continue;
+               }
+
+               last_vblank_count[pipe] = drm_crtc_vblank_count(crtc);
+       }
+
+       for_each_pipe(dev_priv, pipe) {
+               struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+               long lret;
+
+               if (!((1 << pipe) & crtc_mask))
+                       continue;
+
+               lret = wait_event_timeout(dev->vblank[pipe].queue,
+                               last_vblank_count[pipe] !=
+                                       drm_crtc_vblank_count(crtc),
+                               msecs_to_jiffies(50));
+
+               WARN_ON(!lret);
+
+               drm_crtc_vblank_put(crtc);
+       }
+}
+
+static bool needs_vblank_wait(struct intel_crtc_state *crtc_state)
+{
+       /* fb updated, need to unpin old fb */
+       if (crtc_state->fb_changed)
+               return true;
+
+       /* wm changes, need vblank before final wm's */
+       if (crtc_state->update_wm_post)
+               return true;
+
+       /*
+        * cxsr is re-enabled after vblank.
+        * This is already handled by crtc_state->update_wm_post,
+        * but added for clarity.
+        */
+       if (crtc_state->disable_cxsr)
+               return true;
+
+       return false;
+}
+
 /**
  * intel_atomic_commit - commit validated state object
  * @dev: DRM device
@@ -13498,12 +13498,15 @@ static int intel_atomic_commit(struct drm_device *dev,
                               struct drm_atomic_state *state,
                               bool async)
 {
+       struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_crtc_state *crtc_state;
+       struct drm_crtc_state *old_crtc_state;
        struct drm_crtc *crtc;
-       int ret = 0;
-       int i;
-       bool any_ms = false;
+       struct intel_crtc_state *intel_cstate;
+       int ret = 0, i;
+       bool hw_check = intel_state->modeset;
+       unsigned long put_domains[I915_MAX_PIPES] = {};
+       unsigned crtc_vblank_mask = 0;
 
        ret = intel_atomic_prepare_commit(dev, state, async);
        if (ret) {
@@ -13512,21 +13515,40 @@ static int intel_atomic_commit(struct drm_device *dev,
        }
 
        drm_atomic_helper_swap_state(dev, state);
-       dev_priv->wm.config = to_intel_atomic_state(state)->wm_config;
+       dev_priv->wm.config = intel_state->wm_config;
+       intel_shared_dpll_commit(state);
 
-       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+       if (intel_state->modeset) {
+               memcpy(dev_priv->min_pixclk, intel_state->min_pixclk,
+                      sizeof(intel_state->min_pixclk));
+               dev_priv->active_crtcs = intel_state->active_crtcs;
+               dev_priv->atomic_cdclk_freq = intel_state->cdclk;
+
+               intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
+       }
+
+       for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
                struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
+               if (needs_modeset(crtc->state) ||
+                   to_intel_crtc_state(crtc->state)->update_pipe) {
+                       hw_check = true;
+
+                       put_domains[to_intel_crtc(crtc)->pipe] =
+                               modeset_get_crtc_power_domains(crtc,
+                                       to_intel_crtc_state(crtc->state));
+               }
+
                if (!needs_modeset(crtc->state))
                        continue;
 
-               any_ms = true;
-               intel_pre_plane_update(intel_crtc);
+               intel_pre_plane_update(to_intel_crtc_state(old_crtc_state));
 
-               if (crtc_state->active) {
-                       intel_crtc_disable_planes(crtc, crtc_state->plane_mask);
+               if (old_crtc_state->active) {
+                       intel_crtc_disable_planes(crtc, old_crtc_state->plane_mask);
                        dev_priv->display.crtc_disable(crtc);
                        intel_crtc->active = false;
+                       intel_fbc_disable(intel_crtc);
                        intel_disable_shared_dpll(intel_crtc);
 
                        /*
@@ -13545,65 +13567,93 @@ static int intel_atomic_commit(struct drm_device *dev,
         * update the the output configuration. */
        intel_modeset_update_crtc_state(state);
 
-       if (any_ms) {
-               intel_shared_dpll_commit(state);
-
+       if (intel_state->modeset) {
                drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
-               modeset_update_crtc_power_domains(state);
+
+               if (dev_priv->display.modeset_commit_cdclk &&
+                   intel_state->dev_cdclk != dev_priv->cdclk_freq)
+                       dev_priv->display.modeset_commit_cdclk(state);
        }
 
        /* Now enable the clocks, plane, pipe, and connectors that we set up. */
-       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+       for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
                struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
                bool modeset = needs_modeset(crtc->state);
-               bool update_pipe = !modeset &&
-                       to_intel_crtc_state(crtc->state)->update_pipe;
-               unsigned long put_domains = 0;
-
-               if (modeset)
-                       intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
+               struct intel_crtc_state *pipe_config =
+                       to_intel_crtc_state(crtc->state);
+               bool update_pipe = !modeset && pipe_config->update_pipe;
 
                if (modeset && crtc->state->active) {
                        update_scanline_offset(to_intel_crtc(crtc));
                        dev_priv->display.crtc_enable(crtc);
                }
 
-               if (update_pipe) {
-                       put_domains = modeset_get_crtc_power_domains(crtc);
-
-                       /* make sure intel_modeset_check_state runs */
-                       any_ms = true;
-               }
-
                if (!modeset)
-                       intel_pre_plane_update(intel_crtc);
+                       intel_pre_plane_update(to_intel_crtc_state(old_crtc_state));
+
+               if (crtc->state->active &&
+                   drm_atomic_get_existing_plane_state(state, crtc->primary))
+                       intel_fbc_enable(intel_crtc);
 
                if (crtc->state->active &&
                    (crtc->state->planes_changed || update_pipe))
-                       drm_atomic_helper_commit_planes_on_crtc(crtc_state);
+                       drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
 
-               if (put_domains)
-                       modeset_put_power_domains(dev_priv, put_domains);
+               if (pipe_config->base.active && needs_vblank_wait(pipe_config))
+                       crtc_vblank_mask |= 1 << i;
+       }
+
+       /* FIXME: add subpixel order */
+
+       if (!state->legacy_cursor_update)
+               intel_atomic_wait_for_vblanks(dev, dev_priv, crtc_vblank_mask);
 
-               intel_post_plane_update(intel_crtc);
+       /*
+        * Now that the vblank has passed, we can go ahead and program the
+        * optimal watermarks on platforms that need two-step watermark
+        * programming.
+        *
+        * TODO: Move this (and other cleanup) to an async worker eventually.
+        */
+       for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
+               intel_cstate = to_intel_crtc_state(crtc->state);
 
-               if (modeset)
-                       intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
+               if (dev_priv->display.optimize_watermarks)
+                       dev_priv->display.optimize_watermarks(intel_cstate);
        }
 
-       /* FIXME: add subpixel order */
+       for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
+               intel_post_plane_update(to_intel_crtc_state(old_crtc_state));
 
-       drm_atomic_helper_wait_for_vblanks(dev, state);
+               if (put_domains[i])
+                       modeset_put_power_domains(dev_priv, put_domains[i]);
+       }
+
+       if (intel_state->modeset)
+               intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
 
        mutex_lock(&dev->struct_mutex);
        drm_atomic_helper_cleanup_planes(dev, state);
        mutex_unlock(&dev->struct_mutex);
 
-       if (any_ms)
+       if (hw_check)
                intel_modeset_check_state(dev, state);
 
        drm_atomic_state_free(state);
 
+       /* As one of the primary mmio accessors, KMS has a high likelihood
+        * of triggering bugs in unclaimed access. After we finish
+        * modesetting, see if an error has been flagged, and if so
+        * enable debugging for the next modeset - and hope we catch
+        * the culprit.
+        *
+        * XXX note that we assume display power is on at this point.
+        * This might hold true now but we need to add pm helper to check
+        * unclaimed only when the hardware is on, as atomic commits
+        * can happen also when the device is completely off.
+        */
+       intel_uncore_arm_unclaimed_mmio_detection(dev_priv);
+
        return 0;
 }
 
@@ -13631,132 +13681,31 @@ retry:
                        goto out;
 
                crtc_state->mode_changed = true;
-               ret = drm_atomic_commit(state);
-       }
-
-       if (ret == -EDEADLK) {
-               drm_atomic_state_clear(state);
-               drm_modeset_backoff(state->acquire_ctx);
-               goto retry;
-       }
-
-       if (ret)
-out:
-               drm_atomic_state_free(state);
-}
-
-#undef for_each_intel_crtc_masked
-
-static const struct drm_crtc_funcs intel_crtc_funcs = {
-       .gamma_set = intel_crtc_gamma_set,
-       .set_config = drm_atomic_helper_set_config,
-       .destroy = intel_crtc_destroy,
-       .page_flip = intel_crtc_page_flip,
-       .atomic_duplicate_state = intel_crtc_duplicate_state,
-       .atomic_destroy_state = intel_crtc_destroy_state,
-};
-
-static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
-                                     struct intel_shared_dpll *pll,
-                                     struct intel_dpll_hw_state *hw_state)
-{
-       uint32_t val;
-
-       if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
-               return false;
-
-       val = I915_READ(PCH_DPLL(pll->id));
-       hw_state->dpll = val;
-       hw_state->fp0 = I915_READ(PCH_FP0(pll->id));
-       hw_state->fp1 = I915_READ(PCH_FP1(pll->id));
-
-       intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
-
-       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->config.hw_state.fp0);
-       I915_WRITE(PCH_FP1(pll->id), pll->config.hw_state.fp1);
-}
-
-static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
-                               struct intel_shared_dpll *pll)
-{
-       /* PCH refclock must be enabled first */
-       ibx_assert_pch_refclk_enabled(dev_priv);
-
-       I915_WRITE(PCH_DPLL(pll->id), pll->config.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->config.hw_state.dpll);
-       POSTING_READ(PCH_DPLL(pll->id));
-       udelay(200);
-}
-
-static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
-                                struct intel_shared_dpll *pll)
-{
-       struct drm_device *dev = dev_priv->dev;
-       struct intel_crtc *crtc;
-
-       /* Make sure no transcoder isn't still depending on us. */
-       for_each_intel_crtc(dev, crtc) {
-               if (intel_crtc_to_shared_dpll(crtc) == pll)
-                       assert_pch_transcoder_disabled(dev_priv, crtc->pipe);
-       }
-
-       I915_WRITE(PCH_DPLL(pll->id), 0);
-       POSTING_READ(PCH_DPLL(pll->id));
-       udelay(200);
-}
-
-static char *ibx_pch_dpll_names[] = {
-       "PCH DPLL A",
-       "PCH DPLL B",
-};
-
-static void ibx_pch_dpll_init(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
-
-       dev_priv->num_shared_dpll = 2;
+               ret = drm_atomic_commit(state);
+       }
 
-       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 =
-                       ibx_pch_dpll_get_hw_state;
+       if (ret == -EDEADLK) {
+               drm_atomic_state_clear(state);
+               drm_modeset_backoff(state->acquire_ctx);
+               goto retry;
        }
-}
 
-static void intel_shared_dpll_init(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       if (ret)
+out:
+               drm_atomic_state_free(state);
+}
 
-       if (HAS_DDI(dev))
-               intel_ddi_pll_init(dev);
-       else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
-               ibx_pch_dpll_init(dev);
-       else
-               dev_priv->num_shared_dpll = 0;
+#undef for_each_intel_crtc_masked
 
-       BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
-}
+static const struct drm_crtc_funcs intel_crtc_funcs = {
+       .gamma_set = drm_atomic_helper_legacy_gamma_set,
+       .set_config = drm_atomic_helper_set_config,
+       .set_property = drm_atomic_helper_crtc_set_property,
+       .destroy = intel_crtc_destroy,
+       .page_flip = intel_crtc_page_flip,
+       .atomic_duplicate_state = intel_crtc_duplicate_state,
+       .atomic_destroy_state = intel_crtc_destroy_state,
+};
 
 /**
  * intel_prepare_plane_fb - Prepare fb for usage on plane
@@ -13831,7 +13780,7 @@ intel_prepare_plane_fb(struct drm_plane *plane,
                if (ret)
                        DRM_DEBUG_KMS("failed to attach phys object\n");
        } else {
-               ret = intel_pin_and_fence_fb_obj(plane, fb, new_state);
+               ret = intel_pin_and_fence_fb_obj(fb, new_state->rotation);
        }
 
        if (ret == 0) {
@@ -13875,7 +13824,7 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
 
        if (old_obj && (plane->type != DRM_PLANE_TYPE_CURSOR ||
            !INTEL_INFO(dev)->cursor_needs_physical))
-               intel_unpin_fb_obj(old_state->fb, old_state);
+               intel_unpin_fb_obj(old_state->fb, old_state->rotation);
 
        /* prepare_fb aborted? */
        if ((old_obj && (old_obj->frontbuffer_bits & intel_plane->frontbuffer_bit)) ||
@@ -13883,7 +13832,6 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
                i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
 
        i915_gem_request_assign(&old_intel_state->wait_req, NULL);
-
 }
 
 int
@@ -13894,7 +13842,7 @@ skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state
        struct drm_i915_private *dev_priv;
        int crtc_clock, cdclk;
 
-       if (!intel_crtc || !crtc_state)
+       if (!intel_crtc || !crtc_state->base.enable)
                return DRM_PLANE_HELPER_NO_SCALING;
 
        dev = intel_crtc->base.dev;
@@ -13943,32 +13891,6 @@ intel_check_primary_plane(struct drm_plane *plane,
                                             &state->visible);
 }
 
-static void
-intel_commit_primary_plane(struct drm_plane *plane,
-                          struct intel_plane_state *state)
-{
-       struct drm_crtc *crtc = state->base.crtc;
-       struct drm_framebuffer *fb = state->base.fb;
-       struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       crtc = crtc ? crtc : plane->crtc;
-
-       dev_priv->display.update_primary_plane(crtc, fb,
-                                              state->src.x1 >> 16,
-                                              state->src.y1 >> 16);
-}
-
-static void
-intel_disable_primary_plane(struct drm_plane *plane,
-                           struct drm_crtc *crtc)
-{
-       struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       dev_priv->display.update_primary_plane(crtc, NULL, 0, 0);
-}
-
 static void intel_begin_crtc_commit(struct drm_crtc *crtc,
                                    struct drm_crtc_state *old_crtc_state)
 {
@@ -13984,6 +13906,11 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
        if (modeset)
                return;
 
+       if (crtc->state->color_mgmt_changed || to_intel_crtc_state(crtc->state)->update_pipe) {
+               intel_color_set_csc(crtc->state);
+               intel_color_load_luts(crtc->state);
+       }
+
        if (to_intel_crtc_state(crtc->state)->update_pipe)
                intel_update_pipe_config(intel_crtc, old_intel_state);
        else if (INTEL_INFO(dev)->gen >= 9)
@@ -14053,20 +13980,33 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
        primary->plane = pipe;
        primary->frontbuffer_bit = INTEL_FRONTBUFFER_PRIMARY(pipe);
        primary->check_plane = intel_check_primary_plane;
-       primary->commit_plane = intel_commit_primary_plane;
-       primary->disable_plane = intel_disable_primary_plane;
        if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4)
                primary->plane = !pipe;
 
        if (INTEL_INFO(dev)->gen >= 9) {
                intel_primary_formats = skl_primary_formats;
                num_formats = ARRAY_SIZE(skl_primary_formats);
+
+               primary->update_plane = skylake_update_primary_plane;
+               primary->disable_plane = skylake_disable_primary_plane;
+       } else if (HAS_PCH_SPLIT(dev)) {
+               intel_primary_formats = i965_primary_formats;
+               num_formats = ARRAY_SIZE(i965_primary_formats);
+
+               primary->update_plane = ironlake_update_primary_plane;
+               primary->disable_plane = i9xx_disable_primary_plane;
        } else if (INTEL_INFO(dev)->gen >= 4) {
                intel_primary_formats = i965_primary_formats;
                num_formats = ARRAY_SIZE(i965_primary_formats);
+
+               primary->update_plane = i9xx_update_primary_plane;
+               primary->disable_plane = i9xx_disable_primary_plane;
        } else {
                intel_primary_formats = i8xx_primary_formats;
                num_formats = ARRAY_SIZE(i8xx_primary_formats);
+
+               primary->update_plane = i9xx_update_primary_plane;
+               primary->disable_plane = i9xx_disable_primary_plane;
        }
 
        drm_universal_plane_init(dev, &primary->base, 0,
@@ -14165,22 +14105,23 @@ static void
 intel_disable_cursor_plane(struct drm_plane *plane,
                           struct drm_crtc *crtc)
 {
-       intel_crtc_update_cursor(crtc, false);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       intel_crtc->cursor_addr = 0;
+       intel_crtc_update_cursor(crtc, NULL);
 }
 
 static void
-intel_commit_cursor_plane(struct drm_plane *plane,
-                         struct intel_plane_state *state)
+intel_update_cursor_plane(struct drm_plane *plane,
+                         const struct intel_crtc_state *crtc_state,
+                         const struct intel_plane_state *state)
 {
-       struct drm_crtc *crtc = state->base.crtc;
+       struct drm_crtc *crtc = crtc_state->base.crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_device *dev = plane->dev;
-       struct intel_crtc *intel_crtc;
        struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb);
        uint32_t addr;
 
-       crtc = crtc ? crtc : plane->crtc;
-       intel_crtc = to_intel_crtc(crtc);
-
        if (!obj)
                addr = 0;
        else if (!INTEL_INFO(dev)->cursor_needs_physical)
@@ -14189,9 +14130,7 @@ intel_commit_cursor_plane(struct drm_plane *plane,
                addr = obj->phys_handle->busaddr;
 
        intel_crtc->cursor_addr = addr;
-
-       if (crtc->state->active)
-               intel_crtc_update_cursor(crtc, state->visible);
+       intel_crtc_update_cursor(crtc, state);
 }
 
 static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
@@ -14217,7 +14156,7 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
        cursor->plane = pipe;
        cursor->frontbuffer_bit = INTEL_FRONTBUFFER_CURSOR(pipe);
        cursor->check_plane = intel_check_cursor_plane;
-       cursor->commit_plane = intel_commit_cursor_plane;
+       cursor->update_plane = intel_update_cursor_plane;
        cursor->disable_plane = intel_disable_cursor_plane;
 
        drm_universal_plane_init(dev, &cursor->base, 0,
@@ -14269,7 +14208,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        struct intel_crtc_state *crtc_state = NULL;
        struct drm_plane *primary = NULL;
        struct drm_plane *cursor = NULL;
-       int i, ret;
+       int ret;
 
        intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
        if (intel_crtc == NULL)
@@ -14305,13 +14244,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        if (ret)
                goto fail;
 
-       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;
-       }
-
        /*
         * On gen2/3 only plane A can do fbc, but the panel fitter and lvds port
         * is hooked to pipe B. Hence we want plane A feeding pipe B.
@@ -14336,6 +14268,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 
        drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
 
+       intel_color_init(&intel_crtc->base);
+
        WARN_ON(drm_crtc_index(&intel_crtc->base) != intel_crtc->pipe);
        return;
 
@@ -14460,6 +14394,8 @@ static void intel_setup_outputs(struct drm_device *dev)
                intel_ddi_init(dev, PORT_A);
                intel_ddi_init(dev, PORT_B);
                intel_ddi_init(dev, PORT_C);
+
+               intel_dsi_init(dev);
        } else if (HAS_DDI(dev)) {
                int found;
 
@@ -14664,10 +14600,12 @@ u32 intel_fb_pitch_limit(struct drm_device *dev, uint64_t fb_modifier,
        u32 gen = INTEL_INFO(dev)->gen;
 
        if (gen >= 9) {
+               int cpp = drm_format_plane_cpp(pixel_format, 0);
+
                /* "The stride in bytes must not exceed the of the size of 8K
                 *  pixels and 32K bytes."
                 */
-                return min(8192*drm_format_plane_cpp(pixel_format, 0), 32768);
+               return min(8192 * cpp, 32768);
        } else if (gen >= 5 && !IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
                return 32*1024;
        } else if (gen >= 4) {
@@ -14691,6 +14629,7 @@ static int intel_framebuffer_init(struct drm_device *dev,
                                  struct drm_mode_fb_cmd2 *mode_cmd,
                                  struct drm_i915_gem_object *obj)
 {
+       struct drm_i915_private *dev_priv = to_i915(dev);
        unsigned int aligned_height;
        int ret;
        u32 pitch_limit, stride_alignment;
@@ -14732,7 +14671,8 @@ static int intel_framebuffer_init(struct drm_device *dev,
                return -EINVAL;
        }
 
-       stride_alignment = intel_fb_stride_alignment(dev, mode_cmd->modifier[0],
+       stride_alignment = intel_fb_stride_alignment(dev_priv,
+                                                    mode_cmd->modifier[0],
                                                     mode_cmd->pixel_format);
        if (mode_cmd->pitches[0] & (stride_alignment - 1)) {
                DRM_DEBUG("pitch (%d) must be at least %u byte aligned\n",
@@ -14824,7 +14764,8 @@ static int intel_framebuffer_init(struct drm_device *dev,
 
        drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
        intel_fb->obj = obj;
-       intel_fb->obj->framebuffer_references++;
+
+       intel_fill_fb_info(dev_priv, &intel_fb->base);
 
        ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
        if (ret) {
@@ -14832,6 +14773,8 @@ static int intel_framebuffer_init(struct drm_device *dev,
                return ret;
        }
 
+       intel_fb->obj->framebuffer_references++;
+
        return 0;
 }
 
@@ -14871,23 +14814,13 @@ static const struct drm_mode_config_funcs intel_mode_funcs = {
        .atomic_state_clear = intel_atomic_state_clear,
 };
 
-/* Set up chip specific display functions */
-static void intel_init_display(struct drm_device *dev)
+/**
+ * intel_init_display_hooks - initialize the display modesetting hooks
+ * @dev_priv: device private
+ */
+void intel_init_display_hooks(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (HAS_PCH_SPLIT(dev) || IS_G4X(dev))
-               dev_priv->display.find_dpll = g4x_find_best_dpll;
-       else if (IS_CHERRYVIEW(dev))
-               dev_priv->display.find_dpll = chv_find_best_dpll;
-       else if (IS_VALLEYVIEW(dev))
-               dev_priv->display.find_dpll = vlv_find_best_dpll;
-       else if (IS_PINEVIEW(dev))
-               dev_priv->display.find_dpll = pnv_find_best_dpll;
-       else
-               dev_priv->display.find_dpll = i9xx_find_best_dpll;
-
-       if (INTEL_INFO(dev)->gen >= 9) {
+       if (INTEL_INFO(dev_priv)->gen >= 9) {
                dev_priv->display.get_pipe_config = haswell_get_pipe_config;
                dev_priv->display.get_initial_plane_config =
                        skylake_get_initial_plane_config;
@@ -14895,9 +14828,7 @@ static void intel_init_display(struct drm_device *dev)
                        haswell_crtc_compute_clock;
                dev_priv->display.crtc_enable = haswell_crtc_enable;
                dev_priv->display.crtc_disable = haswell_crtc_disable;
-               dev_priv->display.update_primary_plane =
-                       skylake_update_primary_plane;
-       } else if (HAS_DDI(dev)) {
+       } else if (HAS_DDI(dev_priv)) {
                dev_priv->display.get_pipe_config = haswell_get_pipe_config;
                dev_priv->display.get_initial_plane_config =
                        ironlake_get_initial_plane_config;
@@ -14905,9 +14836,7 @@ static void intel_init_display(struct drm_device *dev)
                        haswell_crtc_compute_clock;
                dev_priv->display.crtc_enable = haswell_crtc_enable;
                dev_priv->display.crtc_disable = haswell_crtc_disable;
-               dev_priv->display.update_primary_plane =
-                       ironlake_update_primary_plane;
-       } else if (HAS_PCH_SPLIT(dev)) {
+       } else if (HAS_PCH_SPLIT(dev_priv)) {
                dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
                dev_priv->display.get_initial_plane_config =
                        ironlake_get_initial_plane_config;
@@ -14915,112 +14844,134 @@ static void intel_init_display(struct drm_device *dev)
                        ironlake_crtc_compute_clock;
                dev_priv->display.crtc_enable = ironlake_crtc_enable;
                dev_priv->display.crtc_disable = ironlake_crtc_disable;
-               dev_priv->display.update_primary_plane =
-                       ironlake_update_primary_plane;
-       } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
+       } else if (IS_CHERRYVIEW(dev_priv)) {
                dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
                dev_priv->display.get_initial_plane_config =
                        i9xx_get_initial_plane_config;
-               dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock;
+               dev_priv->display.crtc_compute_clock = chv_crtc_compute_clock;
                dev_priv->display.crtc_enable = valleyview_crtc_enable;
                dev_priv->display.crtc_disable = i9xx_crtc_disable;
-               dev_priv->display.update_primary_plane =
-                       i9xx_update_primary_plane;
-       } else {
+       } else if (IS_VALLEYVIEW(dev_priv)) {
+               dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
+               dev_priv->display.get_initial_plane_config =
+                       i9xx_get_initial_plane_config;
+               dev_priv->display.crtc_compute_clock = vlv_crtc_compute_clock;
+               dev_priv->display.crtc_enable = valleyview_crtc_enable;
+               dev_priv->display.crtc_disable = i9xx_crtc_disable;
+       } else if (IS_G4X(dev_priv)) {
+               dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
+               dev_priv->display.get_initial_plane_config =
+                       i9xx_get_initial_plane_config;
+               dev_priv->display.crtc_compute_clock = g4x_crtc_compute_clock;
+               dev_priv->display.crtc_enable = i9xx_crtc_enable;
+               dev_priv->display.crtc_disable = i9xx_crtc_disable;
+       } else if (IS_PINEVIEW(dev_priv)) {
+               dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
+               dev_priv->display.get_initial_plane_config =
+                       i9xx_get_initial_plane_config;
+               dev_priv->display.crtc_compute_clock = pnv_crtc_compute_clock;
+               dev_priv->display.crtc_enable = i9xx_crtc_enable;
+               dev_priv->display.crtc_disable = i9xx_crtc_disable;
+       } else if (!IS_GEN2(dev_priv)) {
                dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
                dev_priv->display.get_initial_plane_config =
                        i9xx_get_initial_plane_config;
                dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock;
                dev_priv->display.crtc_enable = i9xx_crtc_enable;
                dev_priv->display.crtc_disable = i9xx_crtc_disable;
-               dev_priv->display.update_primary_plane =
-                       i9xx_update_primary_plane;
+       } else {
+               dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
+               dev_priv->display.get_initial_plane_config =
+                       i9xx_get_initial_plane_config;
+               dev_priv->display.crtc_compute_clock = i8xx_crtc_compute_clock;
+               dev_priv->display.crtc_enable = i9xx_crtc_enable;
+               dev_priv->display.crtc_disable = i9xx_crtc_disable;
        }
 
        /* Returns the core display clock speed */
-       if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
+       if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        skylake_get_display_clock_speed;
-       else if (IS_BROXTON(dev))
+       else if (IS_BROXTON(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        broxton_get_display_clock_speed;
-       else if (IS_BROADWELL(dev))
+       else if (IS_BROADWELL(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        broadwell_get_display_clock_speed;
-       else if (IS_HASWELL(dev))
+       else if (IS_HASWELL(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        haswell_get_display_clock_speed;
-       else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
+       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        valleyview_get_display_clock_speed;
-       else if (IS_GEN5(dev))
+       else if (IS_GEN5(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        ilk_get_display_clock_speed;
-       else if (IS_I945G(dev) || IS_BROADWATER(dev) ||
-                IS_GEN6(dev) || IS_IVYBRIDGE(dev))
+       else if (IS_I945G(dev_priv) || IS_BROADWATER(dev_priv) ||
+                IS_GEN6(dev_priv) || IS_IVYBRIDGE(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        i945_get_display_clock_speed;
-       else if (IS_GM45(dev))
+       else if (IS_GM45(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        gm45_get_display_clock_speed;
-       else if (IS_CRESTLINE(dev))
+       else if (IS_CRESTLINE(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        i965gm_get_display_clock_speed;
-       else if (IS_PINEVIEW(dev))
+       else if (IS_PINEVIEW(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        pnv_get_display_clock_speed;
-       else if (IS_G33(dev) || IS_G4X(dev))
+       else if (IS_G33(dev_priv) || IS_G4X(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        g33_get_display_clock_speed;
-       else if (IS_I915G(dev))
+       else if (IS_I915G(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        i915_get_display_clock_speed;
-       else if (IS_I945GM(dev) || IS_845G(dev))
+       else if (IS_I945GM(dev_priv) || IS_845G(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        i9xx_misc_get_display_clock_speed;
-       else if (IS_I915GM(dev))
+       else if (IS_I915GM(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        i915gm_get_display_clock_speed;
-       else if (IS_I865G(dev))
+       else if (IS_I865G(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        i865_get_display_clock_speed;
-       else if (IS_I85X(dev))
+       else if (IS_I85X(dev_priv))
                dev_priv->display.get_display_clock_speed =
                        i85x_get_display_clock_speed;
        else { /* 830 */
-               WARN(!IS_I830(dev), "Unknown platform. Assuming 133 MHz CDCLK\n");
+               WARN(!IS_I830(dev_priv), "Unknown platform. Assuming 133 MHz CDCLK\n");
                dev_priv->display.get_display_clock_speed =
                        i830_get_display_clock_speed;
        }
 
-       if (IS_GEN5(dev)) {
+       if (IS_GEN5(dev_priv)) {
                dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
-       } else if (IS_GEN6(dev)) {
+       } else if (IS_GEN6(dev_priv)) {
                dev_priv->display.fdi_link_train = gen6_fdi_link_train;
-       } else if (IS_IVYBRIDGE(dev)) {
+       } else if (IS_IVYBRIDGE(dev_priv)) {
                /* FIXME: detect B0+ stepping and use auto training */
                dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
-       } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+       } else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
                dev_priv->display.fdi_link_train = hsw_fdi_link_train;
-               if (IS_BROADWELL(dev)) {
+               if (IS_BROADWELL(dev_priv)) {
                        dev_priv->display.modeset_commit_cdclk =
                                broadwell_modeset_commit_cdclk;
                        dev_priv->display.modeset_calc_cdclk =
                                broadwell_modeset_calc_cdclk;
                }
-       } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
+       } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
                dev_priv->display.modeset_commit_cdclk =
                        valleyview_modeset_commit_cdclk;
                dev_priv->display.modeset_calc_cdclk =
                        valleyview_modeset_calc_cdclk;
-       } else if (IS_BROXTON(dev)) {
+       } else if (IS_BROXTON(dev_priv)) {
                dev_priv->display.modeset_commit_cdclk =
                        broxton_modeset_commit_cdclk;
                dev_priv->display.modeset_calc_cdclk =
                        broxton_modeset_calc_cdclk;
        }
 
-       switch (INTEL_INFO(dev)->gen) {
+       switch (INTEL_INFO(dev_priv)->gen) {
        case 2:
                dev_priv->display.queue_flip = intel_gen2_queue_flip;
                break;
@@ -15047,8 +14998,6 @@ static void intel_init_display(struct drm_device *dev)
                /* Default just returns -ENODEV to indicate unsupported */
                dev_priv->display.queue_flip = intel_default_queue_flip;
        }
-
-       mutex_init(&dev_priv->pps_mutex);
 }
 
 /*
@@ -15240,12 +15189,97 @@ static void i915_disable_vga(struct drm_device *dev)
 
 void intel_modeset_init_hw(struct drm_device *dev)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
        intel_update_cdclk(dev);
-       intel_prepare_ddi(dev);
+
+       dev_priv->atomic_cdclk_freq = dev_priv->cdclk_freq;
+
        intel_init_clock_gating(dev);
        intel_enable_gt_powersave(dev);
 }
 
+/*
+ * Calculate what we think the watermarks should be for the state we've read
+ * out of the hardware and then immediately program those watermarks so that
+ * we ensure the hardware settings match our internal state.
+ *
+ * We can calculate what we think WM's should be by creating a duplicate of the
+ * current state (which was constructed during hardware readout) and running it
+ * through the atomic check code to calculate new watermark values in the
+ * state object.
+ */
+static void sanitize_watermarks(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_atomic_state *state;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *cstate;
+       struct drm_modeset_acquire_ctx ctx;
+       int ret;
+       int i;
+
+       /* Only supported on platforms that use atomic watermark design */
+       if (!dev_priv->display.optimize_watermarks)
+               return;
+
+       /*
+        * We need to hold connection_mutex before calling duplicate_state so
+        * that the connector loop is protected.
+        */
+       drm_modeset_acquire_init(&ctx, 0);
+retry:
+       ret = drm_modeset_lock_all_ctx(dev, &ctx);
+       if (ret == -EDEADLK) {
+               drm_modeset_backoff(&ctx);
+               goto retry;
+       } else if (WARN_ON(ret)) {
+               goto fail;
+       }
+
+       state = drm_atomic_helper_duplicate_state(dev, &ctx);
+       if (WARN_ON(IS_ERR(state)))
+               goto fail;
+
+       /*
+        * Hardware readout is the only time we don't want to calculate
+        * intermediate watermarks (since we don't trust the current
+        * watermarks).
+        */
+       to_intel_atomic_state(state)->skip_intermediate_wm = true;
+
+       ret = intel_atomic_check(dev, state);
+       if (ret) {
+               /*
+                * If we fail here, it means that the hardware appears to be
+                * programmed in a way that shouldn't be possible, given our
+                * understanding of watermark requirements.  This might mean a
+                * mistake in the hardware readout code or a mistake in the
+                * watermark calculations for a given platform.  Raise a WARN
+                * so that this is noticeable.
+                *
+                * If this actually happens, we'll have to just leave the
+                * BIOS-programmed watermarks untouched and hope for the best.
+                */
+               WARN(true, "Could not determine valid watermarks for inherited state\n");
+               goto fail;
+       }
+
+       /* Write calculated watermark values back */
+       to_i915(dev)->wm.config = to_intel_atomic_state(state)->wm_config;
+       for_each_crtc_in_state(state, crtc, cstate, i) {
+               struct intel_crtc_state *cs = to_intel_crtc_state(cstate);
+
+               cs->wm.need_postvbl_update = true;
+               dev_priv->display.optimize_watermarks(cs);
+       }
+
+       drm_atomic_state_free(state);
+fail:
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+}
+
 void intel_modeset_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -15290,9 +15324,6 @@ void intel_modeset_init(struct drm_device *dev)
                }
        }
 
-       intel_init_display(dev);
-       intel_init_audio(dev);
-
        if (IS_GEN2(dev)) {
                dev->mode_config.max_width = 2048;
                dev->mode_config.max_height = 2048;
@@ -15315,7 +15346,7 @@ void intel_modeset_init(struct drm_device *dev)
                dev->mode_config.cursor_height = MAX_CURSOR_HEIGHT;
        }
 
-       dev->mode_config.fb_base = dev_priv->gtt.mappable_base;
+       dev->mode_config.fb_base = dev_priv->ggtt.mappable_base;
 
        DRM_DEBUG_KMS("%d display pipe%s available.\n",
                      INTEL_INFO(dev)->num_pipes,
@@ -15332,6 +15363,7 @@ void intel_modeset_init(struct drm_device *dev)
        }
 
        intel_update_czclk(dev_priv);
+       intel_update_rawclk(dev_priv);
        intel_update_cdclk(dev);
 
        intel_shared_dpll_init(dev);
@@ -15366,6 +15398,13 @@ void intel_modeset_init(struct drm_device *dev)
                 */
                intel_find_initial_plane_obj(crtc, &plane_config);
        }
+
+       /*
+        * Make sure hardware watermarks really match the state we read out.
+        * Note that we need to do this after reconstructing the BIOS fb's
+        * since the watermark calculation done here will use pstate->fb.
+        */
+       sanitize_watermarks(dev);
 }
 
 static void intel_enable_pipe_a(struct drm_device *dev)
@@ -15422,14 +15461,30 @@ static bool intel_crtc_has_encoders(struct intel_crtc *crtc)
        return false;
 }
 
+static bool intel_encoder_has_connectors(struct intel_encoder *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct intel_connector *connector;
+
+       for_each_connector_on_encoder(dev, &encoder->base, connector)
+               return true;
+
+       return false;
+}
+
 static void intel_sanitize_crtc(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       i915_reg_t reg = PIPECONF(crtc->config->cpu_transcoder);
+       enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
 
        /* Clear any frame start delays used for debugging left by the BIOS */
-       I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
+       if (!transcoder_is_dsi(cpu_transcoder)) {
+               i915_reg_t reg = PIPECONF(cpu_transcoder);
+
+               I915_WRITE(reg,
+                          I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
+       }
 
        /* restore vblank interrupts to correct state */
        drm_crtc_vblank_reset(&crtc->base);
@@ -15477,37 +15532,9 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
 
        /* Adjust the state of the output pipe according to whether we
         * have active connectors/encoders. */
-       if (!intel_crtc_has_encoders(crtc))
+       if (crtc->active && !intel_crtc_has_encoders(crtc))
                intel_crtc_disable_noatomic(&crtc->base);
 
-       if (crtc->active != crtc->base.state->active) {
-               struct intel_encoder *encoder;
-
-               /* This can happen either due to bugs in the get_hw_state
-                * functions or because of calls to intel_crtc_disable_noatomic,
-                * or because the pipe is force-enabled due to the
-                * pipe A quirk. */
-               DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was %s, now %s\n",
-                             crtc->base.base.id,
-                             crtc->base.state->enable ? "enabled" : "disabled",
-                             crtc->active ? "enabled" : "disabled");
-
-               WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, NULL) < 0);
-               crtc->base.state->active = crtc->active;
-               crtc->base.enabled = crtc->active;
-               crtc->base.state->connector_mask = 0;
-
-               /* Because we only establish the connector -> encoder ->
-                * crtc links if something is active, this means the
-                * crtc is now deactivated. Break the links. connector
-                * -> encoder links are only establish when things are
-                *  actually up, hence no need to break them. */
-               WARN_ON(crtc->active);
-
-               for_each_encoder_on_crtc(dev, &crtc->base, encoder)
-                       encoder->base.crtc = NULL;
-       }
-
        if (crtc->active || HAS_GMCH_DISPLAY(dev)) {
                /*
                 * We start out with underrun reporting disabled to avoid races.
@@ -15531,7 +15558,6 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
 {
        struct intel_connector *connector;
        struct drm_device *dev = encoder->base.dev;
-       bool active = false;
 
        /* We need to check both for a crtc link (meaning that the
         * encoder is active and trying to read from a pipe) and the
@@ -15539,15 +15565,7 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
        bool has_active_crtc = encoder->base.crtc &&
                to_intel_crtc(encoder->base.crtc)->active;
 
-       for_each_intel_connector(dev, connector) {
-               if (connector->base.encoder != &encoder->base)
-                       continue;
-
-               active = true;
-               break;
-       }
-
-       if (active && !has_active_crtc) {
+       if (intel_encoder_has_connectors(encoder) && !has_active_crtc) {
                DRM_DEBUG_KMS("[ENCODER:%d:%s] has active connectors but no active pipe!\n",
                              encoder->base.base.id,
                              encoder->base.name);
@@ -15640,16 +15658,40 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
        struct intel_connector *connector;
        int i;
 
+       dev_priv->active_crtcs = 0;
+
        for_each_intel_crtc(dev, crtc) {
-               __drm_atomic_helper_crtc_destroy_state(&crtc->base, crtc->base.state);
-               memset(crtc->config, 0, sizeof(*crtc->config));
-               crtc->config->base.crtc = &crtc->base;
+               struct intel_crtc_state *crtc_state = crtc->config;
+               int pixclk = 0;
+
+               __drm_atomic_helper_crtc_destroy_state(&crtc->base, &crtc_state->base);
+               memset(crtc_state, 0, sizeof(*crtc_state));
+               crtc_state->base.crtc = &crtc->base;
+
+               crtc_state->base.active = crtc_state->base.enable =
+                       dev_priv->display.get_pipe_config(crtc, crtc_state);
+
+               crtc->base.enabled = crtc_state->base.enable;
+               crtc->active = crtc_state->base.active;
 
-               crtc->active = dev_priv->display.get_pipe_config(crtc,
-                                                                crtc->config);
+               if (crtc_state->base.active) {
+                       dev_priv->active_crtcs |= 1 << crtc->pipe;
+
+                       if (IS_BROADWELL(dev_priv)) {
+                               pixclk = ilk_pipe_pixel_rate(crtc_state);
+
+                               /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */
+                               if (crtc_state->ips_enabled)
+                                       pixclk = DIV_ROUND_UP(pixclk * 100, 95);
+                       } else if (IS_VALLEYVIEW(dev_priv) ||
+                                  IS_CHERRYVIEW(dev_priv) ||
+                                  IS_BROXTON(dev_priv))
+                               pixclk = crtc_state->base.adjusted_mode.crtc_clock;
+                       else
+                               WARN_ON(dev_priv->display.modeset_calc_cdclk);
+               }
 
-               crtc->base.state->active = crtc->active;
-               crtc->base.enabled = crtc->active;
+               dev_priv->min_pixclk[crtc->pipe] = pixclk;
 
                readout_plane_state(crtc);
 
@@ -15661,22 +15703,17 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
        for (i = 0; i < dev_priv->num_shared_dpll; i++) {
                struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
 
-               pll->on = pll->get_hw_state(dev_priv, pll,
-                                           &pll->config.hw_state);
-               pll->active = 0;
+               pll->on = pll->funcs.get_hw_state(dev_priv, pll,
+                                                 &pll->config.hw_state);
                pll->config.crtc_mask = 0;
                for_each_intel_crtc(dev, crtc) {
-                       if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) {
-                               pll->active++;
+                       if (crtc->active && crtc->config->shared_dpll == pll)
                                pll->config.crtc_mask |= 1 << crtc->pipe;
-                       }
                }
+               pll->active_mask = pll->config.crtc_mask;
 
                DRM_DEBUG_KMS("%s hw state readout: crtc_mask 0x%08x, on %i\n",
                              pll->name, pll->config.crtc_mask, pll->on);
-
-               if (pll->config.crtc_mask)
-                       intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
        }
 
        for_each_intel_encoder(dev, encoder) {
@@ -15713,6 +15750,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                                 */
                                encoder->base.crtc->state->connector_mask |=
                                        1 << drm_connector_index(&connector->base);
+                               encoder->base.crtc->state->encoder_mask |=
+                                       1 << drm_encoder_index(&encoder->base);
                        }
 
                } else {
@@ -15756,6 +15795,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                        drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode);
                        update_scanline_offset(crtc);
                }
+
+               intel_pipe_config_sanity_check(dev_priv, crtc->config);
        }
 }
 
@@ -15790,12 +15831,12 @@ intel_modeset_setup_hw_state(struct drm_device *dev)
        for (i = 0; i < dev_priv->num_shared_dpll; i++) {
                struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
 
-               if (!pll->on || pll->active)
+               if (!pll->on || pll->active_mask)
                        continue;
 
                DRM_DEBUG_KMS("%s enabled but not in use, disabling\n", pll->name);
 
-               pll->disable(dev_priv, pll);
+               pll->funcs.disable(dev_priv, pll);
                pll->on = false;
        }
 
@@ -15809,63 +15850,76 @@ intel_modeset_setup_hw_state(struct drm_device *dev)
        for_each_intel_crtc(dev, crtc) {
                unsigned long put_domains;
 
-               put_domains = modeset_get_crtc_power_domains(&crtc->base);
+               put_domains = modeset_get_crtc_power_domains(&crtc->base, crtc->config);
                if (WARN_ON(put_domains))
                        modeset_put_power_domains(dev_priv, put_domains);
        }
        intel_display_set_init_power(dev_priv, false);
+
+       intel_fbc_init_pipe_state(dev_priv);
 }
 
 void intel_display_resume(struct drm_device *dev)
 {
-       struct drm_atomic_state *state = drm_atomic_state_alloc(dev);
-       struct intel_connector *conn;
-       struct intel_plane *plane;
-       struct drm_crtc *crtc;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_atomic_state *state = dev_priv->modeset_restore_state;
+       struct drm_modeset_acquire_ctx ctx;
        int ret;
+       bool setup = false;
 
-       if (!state)
-               return;
-
-       state->acquire_ctx = dev->mode_config.acquire_ctx;
+       dev_priv->modeset_restore_state = NULL;
 
-       /* preserve complete old state, including dpll */
-       intel_atomic_get_shared_dpll_state(state);
+       /*
+        * This is a cludge because with real atomic modeset mode_config.mutex
+        * won't be taken. Unfortunately some probed state like
+        * audio_codec_enable is still protected by mode_config.mutex, so lock
+        * it here for now.
+        */
+       mutex_lock(&dev->mode_config.mutex);
+       drm_modeset_acquire_init(&ctx, 0);
 
-       for_each_crtc(dev, crtc) {
-               struct drm_crtc_state *crtc_state =
-                       drm_atomic_get_crtc_state(state, crtc);
+retry:
+       ret = drm_modeset_lock_all_ctx(dev, &ctx);
 
-               ret = PTR_ERR_OR_ZERO(crtc_state);
-               if (ret)
-                       goto err;
+       if (ret == 0 && !setup) {
+               setup = true;
 
-               /* force a restore */
-               crtc_state->mode_changed = true;
+               intel_modeset_setup_hw_state(dev);
+               i915_redisable_vga(dev);
        }
 
-       for_each_intel_plane(dev, plane) {
-               ret = PTR_ERR_OR_ZERO(drm_atomic_get_plane_state(state, &plane->base));
-               if (ret)
-                       goto err;
-       }
+       if (ret == 0 && state) {
+               struct drm_crtc_state *crtc_state;
+               struct drm_crtc *crtc;
+               int i;
 
-       for_each_intel_connector(dev, conn) {
-               ret = PTR_ERR_OR_ZERO(drm_atomic_get_connector_state(state, &conn->base));
-               if (ret)
-                       goto err;
+               state->acquire_ctx = &ctx;
+
+               for_each_crtc_in_state(state, crtc, crtc_state, i) {
+                       /*
+                        * Force recalculation even if we restore
+                        * current state. With fast modeset this may not result
+                        * in a modeset when the state is compatible.
+                        */
+                       crtc_state->mode_changed = true;
+               }
+
+               ret = drm_atomic_commit(state);
        }
 
-       intel_modeset_setup_hw_state(dev);
+       if (ret == -EDEADLK) {
+               drm_modeset_backoff(&ctx);
+               goto retry;
+       }
 
-       i915_redisable_vga(dev);
-       ret = drm_atomic_commit(state);
-       if (!ret)
-               return;
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+       mutex_unlock(&dev->mode_config.mutex);
 
-err:
-       DRM_ERROR("Restoring old state failed with %i\n", ret);
-       drm_atomic_state_free(state);
+       if (ret) {
+               DRM_ERROR("Restoring old state failed with %i\n", ret);
+               drm_atomic_state_free(state);
+       }
 }
 
 void intel_modeset_gem_init(struct drm_device *dev)
@@ -15874,9 +15928,7 @@ void intel_modeset_gem_init(struct drm_device *dev)
        struct drm_i915_gem_object *obj;
        int ret;
 
-       mutex_lock(&dev->struct_mutex);
        intel_init_gt_powersave(dev);
-       mutex_unlock(&dev->struct_mutex);
 
        intel_modeset_init_hw(dev);
 
@@ -15893,9 +15945,8 @@ void intel_modeset_gem_init(struct drm_device *dev)
                        continue;
 
                mutex_lock(&dev->struct_mutex);
-               ret = intel_pin_and_fence_fb_obj(c->primary,
-                                                c->primary->fb,
-                                                c->primary->state);
+               ret = intel_pin_and_fence_fb_obj(c->primary->fb,
+                                                c->primary->state->rotation);
                mutex_unlock(&dev->struct_mutex);
                if (ret) {
                        DRM_ERROR("failed to pin boot fb on pipe %d\n",
@@ -15943,7 +15994,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        intel_unregister_dsm_handler();
 
-       intel_fbc_disable(dev_priv);
+       intel_fbc_global_disable(dev_priv);
 
        /* flush any delayed tasks or pending work */
        flush_scheduled_work();
@@ -15956,9 +16007,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        intel_cleanup_overlay(dev);
 
-       mutex_lock(&dev->struct_mutex);
        intel_cleanup_gt_powersave(dev);
-       mutex_unlock(&dev->struct_mutex);
 
        intel_teardown_gmbus(dev);
 }
@@ -16106,6 +16155,7 @@ intel_display_capture_error_state(struct drm_device *dev)
                        error->pipe[i].stat = I915_READ(PIPESTAT(i));
        }
 
+       /* Note: this does not include DSI transcoders. */
        error->num_transcoders = INTEL_INFO(dev)->num_pipes;
        if (HAS_DDI(dev_priv->dev))
                error->num_transcoders++; /* Account for eDP. */
@@ -16153,7 +16203,7 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
        for_each_pipe(dev_priv, i) {
                err_printf(m, "Pipe [%d]:\n", i);
                err_printf(m, "  Power: %s\n",
-                          error->pipe[i].power_domain_on ? "on" : "off");
+                          onoff(error->pipe[i].power_domain_on));
                err_printf(m, "  SRC: %08x\n", error->pipe[i].source);
                err_printf(m, "  STAT: %08x\n", error->pipe[i].stat);
 
@@ -16178,10 +16228,10 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
        }
 
        for (i = 0; i < error->num_transcoders; i++) {
-               err_printf(m, "CPU transcoder: %c\n",
+               err_printf(m, "CPU transcoder: %s\n",
                           transcoder_name(error->transcoder[i].cpu_transcoder));
                err_printf(m, "  Power: %s\n",
-                          error->transcoder[i].power_domain_on ? "on" : "off");
+                          onoff(error->transcoder[i].power_domain_on));
                err_printf(m, "  CONF: %08x\n", error->transcoder[i].conf);
                err_printf(m, "  HTOTAL: %08x\n", error->transcoder[i].htotal);
                err_printf(m, "  HBLANK: %08x\n", error->transcoder[i].hblank);
@@ -16191,24 +16241,3 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
                err_printf(m, "  VSYNC: %08x\n", error->transcoder[i].vsync);
        }
 }
-
-void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file)
-{
-       struct intel_crtc *crtc;
-
-       for_each_intel_crtc(dev, crtc) {
-               struct intel_unpin_work *work;
-
-               spin_lock_irq(&dev->event_lock);
-
-               work = crtc->unpin_work;
-
-               if (work && work->event &&
-                   work->event->base.file_priv == file) {
-                       kfree(work->event);
-                       work->event = NULL;
-               }
-
-               spin_unlock_irq(&dev->event_lock);
-       }
-}