]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/gpu/drm/i915/intel_display.c
drm/i915: Remove crtc->config dereferences in intel_sanitize_crtc
[linux.git] / drivers / gpu / drm / i915 / intel_display.c
index ed3fa1c8a98342d549ec8bf5b027b3b783affa08..6ea31ed81789c616179c328dd482512b83071120 100644 (file)
@@ -46,6 +46,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_atomic_uapi.h>
 #include <linux/dma_remapping.h>
 #include <linux/reservation.h>
 
@@ -73,55 +74,6 @@ static const uint64_t i9xx_format_modifiers[] = {
        DRM_FORMAT_MOD_INVALID
 };
 
-static const uint32_t skl_primary_formats[] = {
-       DRM_FORMAT_C8,
-       DRM_FORMAT_RGB565,
-       DRM_FORMAT_XRGB8888,
-       DRM_FORMAT_XBGR8888,
-       DRM_FORMAT_ARGB8888,
-       DRM_FORMAT_ABGR8888,
-       DRM_FORMAT_XRGB2101010,
-       DRM_FORMAT_XBGR2101010,
-       DRM_FORMAT_YUYV,
-       DRM_FORMAT_YVYU,
-       DRM_FORMAT_UYVY,
-       DRM_FORMAT_VYUY,
-};
-
-static const uint32_t skl_pri_planar_formats[] = {
-       DRM_FORMAT_C8,
-       DRM_FORMAT_RGB565,
-       DRM_FORMAT_XRGB8888,
-       DRM_FORMAT_XBGR8888,
-       DRM_FORMAT_ARGB8888,
-       DRM_FORMAT_ABGR8888,
-       DRM_FORMAT_XRGB2101010,
-       DRM_FORMAT_XBGR2101010,
-       DRM_FORMAT_YUYV,
-       DRM_FORMAT_YVYU,
-       DRM_FORMAT_UYVY,
-       DRM_FORMAT_VYUY,
-       DRM_FORMAT_NV12,
-};
-
-static const uint64_t skl_format_modifiers_noccs[] = {
-       I915_FORMAT_MOD_Yf_TILED,
-       I915_FORMAT_MOD_Y_TILED,
-       I915_FORMAT_MOD_X_TILED,
-       DRM_FORMAT_MOD_LINEAR,
-       DRM_FORMAT_MOD_INVALID
-};
-
-static const uint64_t skl_format_modifiers_ccs[] = {
-       I915_FORMAT_MOD_Yf_TILED_CCS,
-       I915_FORMAT_MOD_Y_TILED_CCS,
-       I915_FORMAT_MOD_Yf_TILED,
-       I915_FORMAT_MOD_Y_TILED,
-       I915_FORMAT_MOD_X_TILED,
-       DRM_FORMAT_MOD_LINEAR,
-       DRM_FORMAT_MOD_INVALID
-};
-
 /* Cursor formats */
 static const uint32_t intel_cursor_formats[] = {
        DRM_FORMAT_ARGB8888,
@@ -140,15 +92,15 @@ static void ironlake_pch_clock_get(struct intel_crtc *crtc,
 static int intel_framebuffer_init(struct intel_framebuffer *ifb,
                                  struct drm_i915_gem_object *obj,
                                  struct drm_mode_fb_cmd2 *mode_cmd);
-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 haswell_set_pipemisc(struct drm_crtc *crtc);
+static void intel_set_pipe_timings(const struct intel_crtc_state *crtc_state);
+static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state);
+static void intel_cpu_transcoder_set_m_n(const struct intel_crtc_state *crtc_state,
+                                        const struct intel_link_m_n *m_n,
+                                        const struct intel_link_m_n *m2_n2);
+static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state);
+static void ironlake_set_pipeconf(const struct intel_crtc_state *crtc_state);
+static void haswell_set_pipeconf(const struct intel_crtc_state *crtc_state);
+static void haswell_set_pipemisc(const struct intel_crtc_state *crtc_state);
 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,
@@ -157,9 +109,9 @@ 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 intel_crtc_init_scalers(struct intel_crtc *crtc,
                                    struct intel_crtc_state *crtc_state);
-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 skylake_pfit_enable(const struct intel_crtc_state *crtc_state);
+static void ironlake_pfit_disable(const struct intel_crtc_state *old_crtc_state);
+static void ironlake_pfit_enable(const struct intel_crtc_state *crtc_state);
 static void intel_modeset_setup_hw_state(struct drm_device *dev,
                                         struct drm_modeset_acquire_ctx *ctx);
 static void intel_pre_disable_primary_noatomic(struct drm_crtc *crtc);
@@ -1564,14 +1516,15 @@ static void i9xx_enable_pll(struct intel_crtc *crtc,
        }
 }
 
-static void i9xx_disable_pll(struct intel_crtc *crtc)
+static void i9xx_disable_pll(const struct intel_crtc_state *crtc_state)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        enum pipe pipe = crtc->pipe;
 
        /* Disable DVO 2x clock on both PLLs if necessary */
        if (IS_I830(dev_priv) &&
-           intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DVO) &&
+           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DVO) &&
            !intel_num_dvo_pipes(dev_priv)) {
                I915_WRITE(DPLL(PIPE_B),
                           I915_READ(DPLL(PIPE_B)) & ~DPLL_DVO_2X_MODE);
@@ -1665,16 +1618,16 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
                     I915_READ(dpll_reg) & port_mask, expected_mask);
 }
 
-static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
-                                          enum pipe pipe)
+static void ironlake_enable_pch_transcoder(const struct intel_crtc_state *crtc_state)
 {
-       struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv,
-                                                               pipe);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
        i915_reg_t reg;
        uint32_t val, pipeconf_val;
 
        /* Make sure PCH DPLL is enabled */
-       assert_shared_dpll_enabled(dev_priv, intel_crtc->config->shared_dpll);
+       assert_shared_dpll_enabled(dev_priv, crtc_state->shared_dpll);
 
        /* FDI must be feeding us bits for PCH ports */
        assert_fdi_tx_enabled(dev_priv, pipe);
@@ -1700,7 +1653,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
                 * here for both 8bpc and 12bpc.
                 */
                val &= ~PIPECONF_BPC_MASK;
-               if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_HDMI))
+               if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
                        val |= PIPECONF_8BPC;
                else
                        val |= pipeconf_val & PIPECONF_BPC_MASK;
@@ -1709,7 +1662,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
        val &= ~TRANS_INTERLACE_MASK;
        if ((pipeconf_val & PIPECONF_INTERLACE_MASK) == PIPECONF_INTERLACED_ILK)
                if (HAS_PCH_IBX(dev_priv) &&
-                   intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_SDVO))
+                   intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO))
                        val |= TRANS_LEGACY_INTERLACED_ILK;
                else
                        val |= TRANS_INTERLACED;
@@ -1916,10 +1869,10 @@ static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv)
 }
 
 static unsigned int
-intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane)
+intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
 {
        struct drm_i915_private *dev_priv = to_i915(fb->dev);
-       unsigned int cpp = fb->format->cpp[plane];
+       unsigned int cpp = fb->format->cpp[color_plane];
 
        switch (fb->modifier) {
        case DRM_FORMAT_MOD_LINEAR:
@@ -1930,7 +1883,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane)
                else
                        return 512;
        case I915_FORMAT_MOD_Y_TILED_CCS:
-               if (plane == 1)
+               if (color_plane == 1)
                        return 128;
                /* fall through */
        case I915_FORMAT_MOD_Y_TILED:
@@ -1939,7 +1892,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane)
                else
                        return 512;
        case I915_FORMAT_MOD_Yf_TILED_CCS:
-               if (plane == 1)
+               if (color_plane == 1)
                        return 128;
                /* fall through */
        case I915_FORMAT_MOD_Yf_TILED:
@@ -1964,22 +1917,22 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane)
 }
 
 static unsigned int
-intel_tile_height(const struct drm_framebuffer *fb, int plane)
+intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
 {
        if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
                return 1;
        else
                return intel_tile_size(to_i915(fb->dev)) /
-                       intel_tile_width_bytes(fb, plane);
+                       intel_tile_width_bytes(fb, color_plane);
 }
 
 /* Return the tile dimensions in pixel units */
-static void intel_tile_dims(const struct drm_framebuffer *fb, int plane,
+static void intel_tile_dims(const struct drm_framebuffer *fb, int color_plane,
                            unsigned int *tile_width,
                            unsigned int *tile_height)
 {
-       unsigned int tile_width_bytes = intel_tile_width_bytes(fb, plane);
-       unsigned int cpp = fb->format->cpp[plane];
+       unsigned int tile_width_bytes = intel_tile_width_bytes(fb, color_plane);
+       unsigned int cpp = fb->format->cpp[color_plane];
 
        *tile_width = tile_width_bytes / cpp;
        *tile_height = intel_tile_size(to_i915(fb->dev)) / tile_width_bytes;
@@ -1987,9 +1940,9 @@ static void intel_tile_dims(const struct drm_framebuffer *fb, int plane,
 
 unsigned int
 intel_fb_align_height(const struct drm_framebuffer *fb,
-                     int plane, unsigned int height)
+                     int color_plane, unsigned int height)
 {
-       unsigned int tile_height = intel_tile_height(fb, plane);
+       unsigned int tile_height = intel_tile_height(fb, color_plane);
 
        return ALIGN(height, tile_height);
 }
@@ -2043,12 +1996,12 @@ static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_pr
 }
 
 static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
-                                        int plane)
+                                        int color_plane)
 {
        struct drm_i915_private *dev_priv = to_i915(fb->dev);
 
        /* AUX_DIST needs only 4K alignment */
-       if (plane == 1)
+       if (color_plane == 1)
                return 4096;
 
        switch (fb->modifier) {
@@ -2079,14 +2032,13 @@ static bool intel_plane_uses_fence(const struct intel_plane_state *plane_state)
 
 struct i915_vma *
 intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
-                          unsigned int rotation,
+                          const struct i915_ggtt_view *view,
                           bool uses_fence,
                           unsigned long *out_flags)
 {
        struct drm_device *dev = fb->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-       struct i915_ggtt_view view;
        struct i915_vma *vma;
        unsigned int pinctl;
        u32 alignment;
@@ -2095,8 +2047,6 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
 
        alignment = intel_surf_alignment(fb, 0);
 
-       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
         * we should always have valid PTE following the scanout preventing
@@ -2129,7 +2079,7 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
                pinctl |= PIN_MAPPABLE;
 
        vma = i915_gem_object_pin_to_display_plane(obj,
-                                                  alignment, &view, pinctl);
+                                                  alignment, view, pinctl);
        if (IS_ERR(vma))
                goto err;
 
@@ -2181,13 +2131,13 @@ void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags)
        i915_vma_put(vma);
 }
 
-static int intel_fb_pitch(const struct drm_framebuffer *fb, int plane,
+static int intel_fb_pitch(const struct drm_framebuffer *fb, int color_plane,
                          unsigned int rotation)
 {
        if (drm_rotation_90_or_270(rotation))
-               return to_intel_framebuffer(fb)->rotated[plane].pitch;
+               return to_intel_framebuffer(fb)->rotated[color_plane].pitch;
        else
-               return fb->pitches[plane];
+               return fb->pitches[color_plane];
 }
 
 /*
@@ -2198,11 +2148,11 @@ static int intel_fb_pitch(const struct drm_framebuffer *fb, int plane,
  */
 u32 intel_fb_xy_to_linear(int x, int y,
                          const struct intel_plane_state *state,
-                         int plane)
+                         int color_plane)
 {
        const struct drm_framebuffer *fb = state->base.fb;
-       unsigned int cpp = fb->format->cpp[plane];
-       unsigned int pitch = fb->pitches[plane];
+       unsigned int cpp = fb->format->cpp[color_plane];
+       unsigned int pitch = state->color_plane[color_plane].stride;
 
        return y * pitch + x * cpp;
 }
@@ -2214,28 +2164,28 @@ u32 intel_fb_xy_to_linear(int x, int y,
  */
 void intel_add_fb_offsets(int *x, int *y,
                          const struct intel_plane_state *state,
-                         int plane)
+                         int color_plane)
 
 {
        const struct intel_framebuffer *intel_fb = to_intel_framebuffer(state->base.fb);
        unsigned int rotation = state->base.rotation;
 
        if (drm_rotation_90_or_270(rotation)) {
-               *x += intel_fb->rotated[plane].x;
-               *y += intel_fb->rotated[plane].y;
+               *x += intel_fb->rotated[color_plane].x;
+               *y += intel_fb->rotated[color_plane].y;
        } else {
-               *x += intel_fb->normal[plane].x;
-               *y += intel_fb->normal[plane].y;
+               *x += intel_fb->normal[color_plane].x;
+               *y += intel_fb->normal[color_plane].y;
        }
 }
 
-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)
+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)
 {
        unsigned int pitch_pixels = pitch_tiles * tile_width;
        unsigned int tiles;
@@ -2256,14 +2206,15 @@ static u32 __intel_adjust_tile_offset(int *x, int *y,
        return new_offset;
 }
 
-static u32 _intel_adjust_tile_offset(int *x, int *y,
-                                    const struct drm_framebuffer *fb, int plane,
-                                    unsigned int rotation,
-                                    u32 old_offset, u32 new_offset)
+static u32 intel_adjust_aligned_offset(int *x, int *y,
+                                      const struct drm_framebuffer *fb,
+                                      int color_plane,
+                                      unsigned int rotation,
+                                      unsigned int pitch,
+                                      u32 old_offset, u32 new_offset)
 {
-       const struct drm_i915_private *dev_priv = to_i915(fb->dev);
-       unsigned int cpp = fb->format->cpp[plane];
-       unsigned int pitch = intel_fb_pitch(fb, plane, rotation);
+       struct drm_i915_private *dev_priv = to_i915(fb->dev);
+       unsigned int cpp = fb->format->cpp[color_plane];
 
        WARN_ON(new_offset > old_offset);
 
@@ -2272,7 +2223,7 @@ static u32 _intel_adjust_tile_offset(int *x, int *y,
                unsigned int pitch_tiles;
 
                tile_size = intel_tile_size(dev_priv);
-               intel_tile_dims(fb, plane, &tile_width, &tile_height);
+               intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
 
                if (drm_rotation_90_or_270(rotation)) {
                        pitch_tiles = pitch / tile_height;
@@ -2281,9 +2232,9 @@ static u32 _intel_adjust_tile_offset(int *x, int *y,
                        pitch_tiles = pitch / (tile_width * cpp);
                }
 
-               __intel_adjust_tile_offset(x, y, tile_width, tile_height,
-                                          tile_size, pitch_tiles,
-                                          old_offset, new_offset);
+               intel_adjust_tile_offset(x, y, tile_width, tile_height,
+                                        tile_size, pitch_tiles,
+                                        old_offset, new_offset);
        } else {
                old_offset += *y * pitch + *x * cpp;
 
@@ -2298,17 +2249,19 @@ static u32 _intel_adjust_tile_offset(int *x, int *y,
  * Adjust the tile offset by moving the difference into
  * the x/y offsets.
  */
-static u32 intel_adjust_tile_offset(int *x, int *y,
-                                   const struct intel_plane_state *state, int plane,
-                                   u32 old_offset, u32 new_offset)
-{
-       return _intel_adjust_tile_offset(x, y, state->base.fb, plane,
-                                        state->base.rotation,
-                                        old_offset, new_offset);
+static u32 intel_plane_adjust_aligned_offset(int *x, int *y,
+                                            const struct intel_plane_state *state,
+                                            int color_plane,
+                                            u32 old_offset, u32 new_offset)
+{
+       return intel_adjust_aligned_offset(x, y, state->base.fb, color_plane,
+                                          state->base.rotation,
+                                          state->color_plane[color_plane].stride,
+                                          old_offset, new_offset);
 }
 
 /*
- * Computes the linear offset to the base tile and adjusts
+ * Computes the aligned 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
@@ -2321,15 +2274,16 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
  * used. This is why the user has to pass in the pitch since it
  * is specified in the rotated orientation.
  */
-static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv,
-                                     int *x, int *y,
-                                     const struct drm_framebuffer *fb, int plane,
-                                     unsigned int pitch,
-                                     unsigned int rotation,
-                                     u32 alignment)
+static u32 intel_compute_aligned_offset(struct drm_i915_private *dev_priv,
+                                       int *x, int *y,
+                                       const struct drm_framebuffer *fb,
+                                       int color_plane,
+                                       unsigned int pitch,
+                                       unsigned int rotation,
+                                       u32 alignment)
 {
        uint64_t fb_modifier = fb->modifier;
-       unsigned int cpp = fb->format->cpp[plane];
+       unsigned int cpp = fb->format->cpp[color_plane];
        u32 offset, offset_aligned;
 
        if (alignment)
@@ -2340,7 +2294,7 @@ static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv,
                unsigned int tile_rows, tiles, pitch_tiles;
 
                tile_size = intel_tile_size(dev_priv);
-               intel_tile_dims(fb, plane, &tile_width, &tile_height);
+               intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
 
                if (drm_rotation_90_or_270(rotation)) {
                        pitch_tiles = pitch / tile_height;
@@ -2358,9 +2312,9 @@ static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv,
                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);
+               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;
@@ -2372,42 +2326,44 @@ static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv,
        return offset_aligned;
 }
 
-u32 intel_compute_tile_offset(int *x, int *y,
-                             const struct intel_plane_state *state,
-                             int plane)
+static u32 intel_plane_compute_aligned_offset(int *x, int *y,
+                                             const struct intel_plane_state *state,
+                                             int color_plane)
 {
        struct intel_plane *intel_plane = to_intel_plane(state->base.plane);
        struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev);
        const struct drm_framebuffer *fb = state->base.fb;
        unsigned int rotation = state->base.rotation;
-       int pitch = intel_fb_pitch(fb, plane, rotation);
+       int pitch = state->color_plane[color_plane].stride;
        u32 alignment;
 
        if (intel_plane->id == PLANE_CURSOR)
                alignment = intel_cursor_alignment(dev_priv);
        else
-               alignment = intel_surf_alignment(fb, plane);
+               alignment = intel_surf_alignment(fb, color_plane);
 
-       return _intel_compute_tile_offset(dev_priv, x, y, fb, plane, pitch,
-                                         rotation, alignment);
+       return intel_compute_aligned_offset(dev_priv, x, y, fb, color_plane,
+                                           pitch, rotation, alignment);
 }
 
 /* Convert the fb->offset[] into x/y offsets */
 static int intel_fb_offset_to_xy(int *x, int *y,
-                                const struct drm_framebuffer *fb, int plane)
+                                const struct drm_framebuffer *fb,
+                                int color_plane)
 {
        struct drm_i915_private *dev_priv = to_i915(fb->dev);
 
        if (fb->modifier != DRM_FORMAT_MOD_LINEAR &&
-           fb->offsets[plane] % intel_tile_size(dev_priv))
+           fb->offsets[color_plane] % intel_tile_size(dev_priv))
                return -EINVAL;
 
        *x = 0;
        *y = 0;
 
-       _intel_adjust_tile_offset(x, y,
-                                 fb, plane, DRM_MODE_ROTATE_0,
-                                 fb->offsets[plane], 0);
+       intel_adjust_aligned_offset(x, y,
+                                   fb, color_plane, DRM_MODE_ROTATE_0,
+                                   fb->pitches[color_plane],
+                                   fb->offsets[color_plane], 0);
 
        return 0;
 }
@@ -2474,6 +2430,12 @@ intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
        }
 }
 
+bool is_ccs_modifier(u64 modifier)
+{
+       return modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
+              modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
+}
+
 static int
 intel_fill_fb_info(struct drm_i915_private *dev_priv,
                   struct drm_framebuffer *fb)
@@ -2504,8 +2466,7 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
                        return ret;
                }
 
-               if ((fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
-                    fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) && i == 1) {
+               if (is_ccs_modifier(fb->modifier) && i == 1) {
                        int hsub = fb->format->hsub;
                        int vsub = fb->format->vsub;
                        int tile_width, tile_height;
@@ -2559,9 +2520,10 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
                intel_fb->normal[i].x = x;
                intel_fb->normal[i].y = y;
 
-               offset = _intel_compute_tile_offset(dev_priv, &x, &y,
-                                                   fb, i, fb->pitches[i],
-                                                   DRM_MODE_ROTATE_0, tile_size);
+               offset = intel_compute_aligned_offset(dev_priv, &x, &y, fb, i,
+                                                     fb->pitches[i],
+                                                     DRM_MODE_ROTATE_0,
+                                                     tile_size);
                offset /= tile_size;
 
                if (fb->modifier != DRM_FORMAT_MOD_LINEAR) {
@@ -2608,10 +2570,10 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
                         * We only keep the x/y offsets, so push all of the
                         * gtt offset into the x/y offsets.
                         */
-                       __intel_adjust_tile_offset(&x, &y,
-                                                  tile_width, tile_height,
-                                                  tile_size, pitch_tiles,
-                                                  gtt_offset_rotated * tile_size, 0);
+                       intel_adjust_tile_offset(&x, &y,
+                                                tile_width, tile_height,
+                                                tile_size, pitch_tiles,
+                                                gtt_offset_rotated * tile_size, 0);
 
                        gtt_offset_rotated += rot_info->plane[i].width * rot_info->plane[i].height;
 
@@ -2630,9 +2592,9 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
                max_size = max(max_size, offset + size);
        }
 
-       if (max_size * tile_size > obj->base.size) {
-               DRM_DEBUG_KMS("fb too big for bo (need %u bytes, have %zu bytes)\n",
-                             max_size * tile_size, obj->base.size);
+       if (mul_u32_u32(max_size, tile_size) > obj->base.size) {
+               DRM_DEBUG_KMS("fb too big for bo (need %llu bytes, have %zu bytes)\n",
+                             mul_u32_u32(max_size, tile_size), obj->base.size);
                return -EINVAL;
        }
 
@@ -2754,18 +2716,27 @@ intel_set_plane_visible(struct intel_crtc_state *crtc_state,
 
        plane_state->base.visible = visible;
 
-       /* FIXME pre-g4x don't work like this */
-       if (visible) {
+       if (visible)
                crtc_state->base.plane_mask |= drm_plane_mask(&plane->base);
-               crtc_state->active_planes |= BIT(plane->id);
-       } else {
+       else
                crtc_state->base.plane_mask &= ~drm_plane_mask(&plane->base);
-               crtc_state->active_planes &= ~BIT(plane->id);
-       }
+}
+
+static void fixup_active_planes(struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
+       struct drm_plane *plane;
+
+       /*
+        * Active_planes aliases if multiple "primary" or cursor planes
+        * have been used on the same (or wrong) pipe. plane_mask uses
+        * unique ids, hence we can use that to reconstruct active_planes.
+        */
+       crtc_state->active_planes = 0;
 
-       DRM_DEBUG_KMS("%s active planes 0x%x\n",
-                     crtc_state->base.crtc->name,
-                     crtc_state->active_planes);
+       drm_for_each_plane_mask(plane, &dev_priv->drm,
+                               crtc_state->base.plane_mask)
+               crtc_state->active_planes |= BIT(to_intel_plane(plane)->id);
 }
 
 static void intel_plane_disable_noatomic(struct intel_crtc *crtc,
@@ -2776,7 +2747,12 @@ static void intel_plane_disable_noatomic(struct intel_crtc *crtc,
        struct intel_plane_state *plane_state =
                to_intel_plane_state(plane->base.state);
 
+       DRM_DEBUG_KMS("Disabling [PLANE:%d:%s] on [CRTC:%d:%s]\n",
+                     plane->base.base.id, plane->base.name,
+                     crtc->base.base.id, crtc->base.name);
+
        intel_set_plane_visible(crtc_state, plane_state, false);
+       fixup_active_planes(crtc_state);
 
        if (plane->id == PLANE_PRIMARY)
                intel_pre_disable_primary_noatomic(&crtc->base);
@@ -2795,7 +2771,6 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
        struct drm_i915_gem_object *obj;
        struct drm_plane *primary = intel_crtc->base.primary;
        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);
@@ -2847,10 +2822,15 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
        return;
 
 valid_fb:
+       intel_fill_fb_ggtt_view(&intel_state->view, fb,
+                               intel_state->base.rotation);
+       intel_state->color_plane[0].stride =
+               intel_fb_pitch(fb, 0, intel_state->base.rotation);
+
        mutex_lock(&dev->struct_mutex);
        intel_state->vma =
                intel_pin_and_fence_fb_obj(fb,
-                                          primary->state->rotation,
+                                          &intel_state->view,
                                           intel_plane_uses_fence(intel_state),
                                           &intel_state->flags);
        mutex_unlock(&dev->struct_mutex);
@@ -2885,18 +2865,15 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
        plane_state->fb = fb;
        plane_state->crtc = &intel_crtc->base;
 
-       intel_set_plane_visible(to_intel_crtc_state(crtc_state),
-                               to_intel_plane_state(plane_state),
-                               true);
-
        atomic_or(to_intel_plane(primary)->frontbuffer_bit,
                  &obj->frontbuffer_bits);
 }
 
-static int skl_max_plane_width(const struct drm_framebuffer *fb, int plane,
+static int skl_max_plane_width(const struct drm_framebuffer *fb,
+                              int color_plane,
                               unsigned int rotation)
 {
-       int cpp = fb->format->cpp[plane];
+       int cpp = fb->format->cpp[color_plane];
 
        switch (fb->modifier) {
        case DRM_FORMAT_MOD_LINEAR:
@@ -2944,9 +2921,9 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
        const struct drm_framebuffer *fb = plane_state->base.fb;
        int hsub = fb->format->hsub;
        int vsub = fb->format->vsub;
-       int aux_x = plane_state->aux.x;
-       int aux_y = plane_state->aux.y;
-       u32 aux_offset = plane_state->aux.offset;
+       int aux_x = plane_state->color_plane[1].x;
+       int aux_y = plane_state->color_plane[1].y;
+       u32 aux_offset = plane_state->color_plane[1].offset;
        u32 alignment = intel_surf_alignment(fb, 1);
 
        while (aux_offset >= main_offset && aux_y <= main_y) {
@@ -2960,8 +2937,8 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
 
                x = aux_x / hsub;
                y = aux_y / vsub;
-               aux_offset = intel_adjust_tile_offset(&x, &y, plane_state, 1,
-                                                     aux_offset, aux_offset - alignment);
+               aux_offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
+                                                              aux_offset, aux_offset - alignment);
                aux_x = x * hsub + aux_x % hsub;
                aux_y = y * vsub + aux_y % vsub;
        }
@@ -2969,29 +2946,24 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
        if (aux_x != main_x || aux_y != main_y)
                return false;
 
-       plane_state->aux.offset = aux_offset;
-       plane_state->aux.x = aux_x;
-       plane_state->aux.y = aux_y;
+       plane_state->color_plane[1].offset = aux_offset;
+       plane_state->color_plane[1].x = aux_x;
+       plane_state->color_plane[1].y = aux_y;
 
        return true;
 }
 
-static int skl_check_main_surface(const struct intel_crtc_state *crtc_state,
-                                 struct intel_plane_state *plane_state)
+static int skl_check_main_surface(struct intel_plane_state *plane_state)
 {
-       struct drm_i915_private *dev_priv =
-               to_i915(plane_state->base.plane->dev);
        const struct drm_framebuffer *fb = plane_state->base.fb;
        unsigned int rotation = plane_state->base.rotation;
        int x = plane_state->base.src.x1 >> 16;
        int y = plane_state->base.src.y1 >> 16;
        int w = drm_rect_width(&plane_state->base.src) >> 16;
        int h = drm_rect_height(&plane_state->base.src) >> 16;
-       int dst_x = plane_state->base.dst.x1;
-       int pipe_src_w = crtc_state->pipe_src_w;
        int max_width = skl_max_plane_width(fb, 0, rotation);
        int max_height = 4096;
-       u32 alignment, offset, aux_offset = plane_state->aux.offset;
+       u32 alignment, offset, aux_offset = plane_state->color_plane[1].offset;
 
        if (w > max_width || h > max_height) {
                DRM_DEBUG_KMS("requested Y/RGB source size %dx%d too big (limit %dx%d)\n",
@@ -2999,26 +2971,8 @@ static int skl_check_main_surface(const struct intel_crtc_state *crtc_state,
                return -EINVAL;
        }
 
-       /*
-        * Display WA #1175: cnl,glk
-        * Planes other than the cursor may cause FIFO underflow and display
-        * corruption if starting less than 4 pixels from the right edge of
-        * the screen.
-        * Besides the above WA fix the similar problem, where planes other
-        * than the cursor ending less than 4 pixels from the left edge of the
-        * screen may cause FIFO underflow and display corruption.
-        */
-       if ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) &&
-           (dst_x + w < 4 || dst_x > pipe_src_w - 4)) {
-               DRM_DEBUG_KMS("requested plane X %s position %d invalid (valid range %d-%d)\n",
-                             dst_x + w < 4 ? "end" : "start",
-                             dst_x + w < 4 ? dst_x + w : dst_x,
-                             4, pipe_src_w - 4);
-               return -ERANGE;
-       }
-
        intel_add_fb_offsets(&x, &y, plane_state, 0);
-       offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
+       offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 0);
        alignment = intel_surf_alignment(fb, 0);
 
        /*
@@ -3027,8 +2981,8 @@ static int skl_check_main_surface(const struct intel_crtc_state *crtc_state,
         * sure that is what we will get.
         */
        if (offset > aux_offset)
-               offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
-                                                 offset, aux_offset & ~(alignment - 1));
+               offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0,
+                                                          offset, aux_offset & ~(alignment - 1));
 
        /*
         * When using an X-tiled surface, the plane blows up
@@ -3039,14 +2993,14 @@ static int skl_check_main_surface(const struct intel_crtc_state *crtc_state,
        if (fb->modifier == I915_FORMAT_MOD_X_TILED) {
                int cpp = fb->format->cpp[0];
 
-               while ((x + w) * cpp > fb->pitches[0]) {
+               while ((x + w) * cpp > plane_state->color_plane[0].stride) {
                        if (offset == 0) {
                                DRM_DEBUG_KMS("Unable to find suitable display surface offset due to X-tiling\n");
                                return -EINVAL;
                        }
 
-                       offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
-                                                         offset, offset - alignment);
+                       offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0,
+                                                                  offset, offset - alignment);
                }
        }
 
@@ -3054,32 +3008,30 @@ static int skl_check_main_surface(const struct intel_crtc_state *crtc_state,
         * CCS AUX surface doesn't have its own x/y offsets, we must make sure
         * they match with the main surface x/y offsets.
         */
-       if (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
-           fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) {
+       if (is_ccs_modifier(fb->modifier)) {
                while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset)) {
                        if (offset == 0)
                                break;
 
-                       offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
-                                                         offset, offset - alignment);
+                       offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0,
+                                                                  offset, offset - alignment);
                }
 
-               if (x != plane_state->aux.x || y != plane_state->aux.y) {
+               if (x != plane_state->color_plane[1].x || y != plane_state->color_plane[1].y) {
                        DRM_DEBUG_KMS("Unable to find suitable display surface offset due to CCS\n");
                        return -EINVAL;
                }
        }
 
-       plane_state->main.offset = offset;
-       plane_state->main.x = x;
-       plane_state->main.y = y;
+       plane_state->color_plane[0].offset = offset;
+       plane_state->color_plane[0].x = x;
+       plane_state->color_plane[0].y = y;
 
        return 0;
 }
 
 static int
-skl_check_nv12_surface(const struct intel_crtc_state *crtc_state,
-                      struct intel_plane_state *plane_state)
+skl_check_nv12_surface(struct intel_plane_state *plane_state)
 {
        /* Display WA #1106 */
        if (plane_state->base.rotation !=
@@ -3113,7 +3065,7 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
        u32 offset;
 
        intel_add_fb_offsets(&x, &y, plane_state, 1);
-       offset = intel_compute_tile_offset(&x, &y, plane_state, 1);
+       offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 1);
 
        /* FIXME not quite sure how/if these apply to the chroma plane */
        if (w > max_width || h > max_height) {
@@ -3122,9 +3074,9 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
                return -EINVAL;
        }
 
-       plane_state->aux.offset = offset;
-       plane_state->aux.x = x;
-       plane_state->aux.y = y;
+       plane_state->color_plane[1].offset = offset;
+       plane_state->color_plane[1].x = x;
+       plane_state->color_plane[1].y = y;
 
        return 0;
 }
@@ -3140,34 +3092,33 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
        int y = src_y / vsub;
        u32 offset;
 
-       if (plane_state->base.rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180)) {
-               DRM_DEBUG_KMS("RC support only with 0/180 degree rotation %x\n",
-                             plane_state->base.rotation);
-               return -EINVAL;
-       }
-
        intel_add_fb_offsets(&x, &y, plane_state, 1);
-       offset = intel_compute_tile_offset(&x, &y, plane_state, 1);
+       offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 1);
 
-       plane_state->aux.offset = offset;
-       plane_state->aux.x = x * hsub + src_x % hsub;
-       plane_state->aux.y = y * vsub + src_y % vsub;
+       plane_state->color_plane[1].offset = offset;
+       plane_state->color_plane[1].x = x * hsub + src_x % hsub;
+       plane_state->color_plane[1].y = y * vsub + src_y % vsub;
 
        return 0;
 }
 
-int skl_check_plane_surface(const struct intel_crtc_state *crtc_state,
-                           struct intel_plane_state *plane_state)
+int skl_check_plane_surface(struct intel_plane_state *plane_state)
 {
        const struct drm_framebuffer *fb = plane_state->base.fb;
        unsigned int rotation = plane_state->base.rotation;
        int ret;
 
-       if (rotation & DRM_MODE_REFLECT_X &&
-           fb->modifier == DRM_FORMAT_MOD_LINEAR) {
-               DRM_DEBUG_KMS("horizontal flip is not supported with linear surface formats\n");
-               return -EINVAL;
-       }
+       intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation);
+       plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation);
+       plane_state->color_plane[1].stride = intel_fb_pitch(fb, 1, rotation);
+
+       ret = intel_plane_check_stride(plane_state);
+       if (ret)
+               return ret;
+
+       /* HW only has 8 bits pixel precision, disable plane if invisible */
+       if (!(plane_state->base.alpha >> 8))
+               plane_state->base.visible = false;
 
        if (!plane_state->base.visible)
                return 0;
@@ -3183,30 +3134,56 @@ int skl_check_plane_surface(const struct intel_crtc_state *crtc_state,
         * the main surface setup depends on it.
         */
        if (fb->format->format == DRM_FORMAT_NV12) {
-               ret = skl_check_nv12_surface(crtc_state, plane_state);
+               ret = skl_check_nv12_surface(plane_state);
                if (ret)
                        return ret;
                ret = skl_check_nv12_aux_surface(plane_state);
                if (ret)
                        return ret;
-       } else if (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
-                  fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) {
+       } else if (is_ccs_modifier(fb->modifier)) {
                ret = skl_check_ccs_aux_surface(plane_state);
                if (ret)
                        return ret;
        } else {
-               plane_state->aux.offset = ~0xfff;
-               plane_state->aux.x = 0;
-               plane_state->aux.y = 0;
+               plane_state->color_plane[1].offset = ~0xfff;
+               plane_state->color_plane[1].x = 0;
+               plane_state->color_plane[1].y = 0;
        }
 
-       ret = skl_check_main_surface(crtc_state, plane_state);
+       ret = skl_check_main_surface(plane_state);
        if (ret)
                return ret;
 
        return 0;
 }
 
+unsigned int
+i9xx_plane_max_stride(struct intel_plane *plane,
+                     u32 pixel_format, u64 modifier,
+                     unsigned int rotation)
+{
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+
+       if (!HAS_GMCH_DISPLAY(dev_priv)) {
+               return 32*1024;
+       } else if (INTEL_GEN(dev_priv) >= 4) {
+               if (modifier == I915_FORMAT_MOD_X_TILED)
+                       return 16*1024;
+               else
+                       return 32*1024;
+       } else if (INTEL_GEN(dev_priv) >= 3) {
+               if (modifier == I915_FORMAT_MOD_X_TILED)
+                       return 8*1024;
+               else
+                       return 16*1024;
+       } else {
+               if (plane->i9xx_plane == PLANE_C)
+                       return 4*1024;
+               else
+                       return 8*1024;
+       }
+}
+
 static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
                          const struct intel_plane_state *plane_state)
 {
@@ -3273,21 +3250,30 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
 {
        struct drm_i915_private *dev_priv =
                to_i915(plane_state->base.plane->dev);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       unsigned int rotation = plane_state->base.rotation;
        int src_x = plane_state->base.src.x1 >> 16;
        int src_y = plane_state->base.src.y1 >> 16;
        u32 offset;
+       int ret;
+
+       intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation);
+       plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation);
+
+       ret = intel_plane_check_stride(plane_state);
+       if (ret)
+               return ret;
 
        intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
 
        if (INTEL_GEN(dev_priv) >= 4)
-               offset = intel_compute_tile_offset(&src_x, &src_y,
-                                                  plane_state, 0);
+               offset = intel_plane_compute_aligned_offset(&src_x, &src_y,
+                                                           plane_state, 0);
        else
                offset = 0;
 
        /* HSW/BDW do this automagically in hardware */
        if (!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)) {
-               unsigned int rotation = plane_state->base.rotation;
                int src_w = drm_rect_width(&plane_state->base.src) >> 16;
                int src_h = drm_rect_height(&plane_state->base.src) >> 16;
 
@@ -3299,9 +3285,43 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
                }
        }
 
-       plane_state->main.offset = offset;
-       plane_state->main.x = src_x;
-       plane_state->main.y = src_y;
+       plane_state->color_plane[0].offset = offset;
+       plane_state->color_plane[0].x = src_x;
+       plane_state->color_plane[0].y = src_y;
+
+       return 0;
+}
+
+static int
+i9xx_plane_check(struct intel_crtc_state *crtc_state,
+                struct intel_plane_state *plane_state)
+{
+       int ret;
+
+       ret = chv_plane_check_rotation(plane_state);
+       if (ret)
+               return ret;
+
+       ret = drm_atomic_helper_check_plane_state(&plane_state->base,
+                                                 &crtc_state->base,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 false, true);
+       if (ret)
+               return ret;
+
+       if (!plane_state->base.visible)
+               return 0;
+
+       ret = intel_plane_check_src_coordinates(plane_state);
+       if (ret)
+               return ret;
+
+       ret = i9xx_check_plane_surface(plane_state);
+       if (ret)
+               return ret;
+
+       plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state);
 
        return 0;
 }
@@ -3311,20 +3331,19 @@ static void i9xx_update_plane(struct intel_plane *plane,
                              const struct intel_plane_state *plane_state)
 {
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-       const struct drm_framebuffer *fb = plane_state->base.fb;
        enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
        u32 linear_offset;
        u32 dspcntr = plane_state->ctl;
        i915_reg_t reg = DSPCNTR(i9xx_plane);
-       int x = plane_state->main.x;
-       int y = plane_state->main.y;
+       int x = plane_state->color_plane[0].x;
+       int y = plane_state->color_plane[0].y;
        unsigned long irqflags;
        u32 dspaddr_offset;
 
        linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
 
        if (INTEL_GEN(dev_priv) >= 4)
-               dspaddr_offset = plane_state->main.offset;
+               dspaddr_offset = plane_state->color_plane[0].offset;
        else
                dspaddr_offset = linear_offset;
 
@@ -3348,7 +3367,7 @@ static void i9xx_update_plane(struct intel_plane *plane,
 
        I915_WRITE_FW(reg, dspcntr);
 
-       I915_WRITE_FW(DSPSTRIDE(i9xx_plane), fb->pitches[0]);
+       I915_WRITE_FW(DSPSTRIDE(i9xx_plane), plane_state->color_plane[0].stride);
        if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
                I915_WRITE_FW(DSPSURF(i9xx_plane),
                              intel_plane_ggtt_offset(plane_state) +
@@ -3423,12 +3442,12 @@ static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
 }
 
 static u32
-intel_fb_stride_alignment(const struct drm_framebuffer *fb, int plane)
+intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
 {
        if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
                return 64;
        else
-               return intel_tile_width_bytes(fb, plane);
+               return intel_tile_width_bytes(fb, color_plane);
 }
 
 static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
@@ -3444,13 +3463,13 @@ static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
 /*
  * This function detaches (aka. unbinds) unused scalers in hardware
  */
-static void skl_detach_scalers(struct intel_crtc *intel_crtc)
+static void skl_detach_scalers(const struct intel_crtc_state *crtc_state)
 {
-       struct intel_crtc_scaler_state *scaler_state;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       const struct intel_crtc_scaler_state *scaler_state =
+               &crtc_state->scaler_state;
        int i;
 
-       scaler_state = &intel_crtc->config->scaler_state;
-
        /* loop through and disable scalers that aren't in use */
        for (i = 0; i < intel_crtc->num_scalers; i++) {
                if (!scaler_state->scalers[i].in_use)
@@ -3458,24 +3477,24 @@ static void skl_detach_scalers(struct intel_crtc *intel_crtc)
        }
 }
 
-u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane,
-                    unsigned int rotation)
+u32 skl_plane_stride(const struct intel_plane_state *plane_state,
+                    int color_plane)
 {
-       u32 stride;
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       unsigned int rotation = plane_state->base.rotation;
+       u32 stride = plane_state->color_plane[color_plane].stride;
 
-       if (plane >= fb->format->num_planes)
+       if (color_plane >= fb->format->num_planes)
                return 0;
 
-       stride = intel_fb_pitch(fb, plane, rotation);
-
        /*
         * The stride is either expressed as a multiple of 64 bytes chunks for
         * linear buffers or in number of tiles for tiled buffers.
         */
        if (drm_rotation_90_or_270(rotation))
-               stride /= intel_tile_height(fb, plane);
+               stride /= intel_tile_height(fb, color_plane);
        else
-               stride /= intel_fb_stride_alignment(fb, plane);
+               stride /= intel_fb_stride_alignment(fb, color_plane);
 
        return stride;
 }
@@ -3514,29 +3533,38 @@ static u32 skl_plane_ctl_format(uint32_t pixel_format)
        return 0;
 }
 
-/*
- * XXX: For ARBG/ABGR formats we default to expecting scanout buffers
- * to be already pre-multiplied. We need to add a knob (or a different
- * DRM_FORMAT) for user-space to configure that.
- */
-static u32 skl_plane_ctl_alpha(uint32_t pixel_format)
+static u32 skl_plane_ctl_alpha(const struct intel_plane_state *plane_state)
 {
-       switch (pixel_format) {
-       case DRM_FORMAT_ABGR8888:
-       case DRM_FORMAT_ARGB8888:
+       if (!plane_state->base.fb->format->has_alpha)
+               return PLANE_CTL_ALPHA_DISABLE;
+
+       switch (plane_state->base.pixel_blend_mode) {
+       case DRM_MODE_BLEND_PIXEL_NONE:
+               return PLANE_CTL_ALPHA_DISABLE;
+       case DRM_MODE_BLEND_PREMULTI:
                return PLANE_CTL_ALPHA_SW_PREMULTIPLY;
+       case DRM_MODE_BLEND_COVERAGE:
+               return PLANE_CTL_ALPHA_HW_PREMULTIPLY;
        default:
+               MISSING_CASE(plane_state->base.pixel_blend_mode);
                return PLANE_CTL_ALPHA_DISABLE;
        }
 }
 
-static u32 glk_plane_color_ctl_alpha(uint32_t pixel_format)
+static u32 glk_plane_color_ctl_alpha(const struct intel_plane_state *plane_state)
 {
-       switch (pixel_format) {
-       case DRM_FORMAT_ABGR8888:
-       case DRM_FORMAT_ARGB8888:
+       if (!plane_state->base.fb->format->has_alpha)
+               return PLANE_COLOR_ALPHA_DISABLE;
+
+       switch (plane_state->base.pixel_blend_mode) {
+       case DRM_MODE_BLEND_PIXEL_NONE:
+               return PLANE_COLOR_ALPHA_DISABLE;
+       case DRM_MODE_BLEND_PREMULTI:
                return PLANE_COLOR_ALPHA_SW_PREMULTIPLY;
+       case DRM_MODE_BLEND_COVERAGE:
+               return PLANE_COLOR_ALPHA_HW_PREMULTIPLY;
        default:
+               MISSING_CASE(plane_state->base.pixel_blend_mode);
                return PLANE_COLOR_ALPHA_DISABLE;
        }
 }
@@ -3551,11 +3579,11 @@ static u32 skl_plane_ctl_tiling(uint64_t fb_modifier)
        case I915_FORMAT_MOD_Y_TILED:
                return PLANE_CTL_TILED_Y;
        case I915_FORMAT_MOD_Y_TILED_CCS:
-               return PLANE_CTL_TILED_Y | PLANE_CTL_DECOMPRESSION_ENABLE;
+               return PLANE_CTL_TILED_Y | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
        case I915_FORMAT_MOD_Yf_TILED:
                return PLANE_CTL_TILED_YF;
        case I915_FORMAT_MOD_Yf_TILED_CCS:
-               return PLANE_CTL_TILED_YF | PLANE_CTL_DECOMPRESSION_ENABLE;
+               return PLANE_CTL_TILED_YF | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
        default:
                MISSING_CASE(fb_modifier);
        }
@@ -3613,7 +3641,7 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
        plane_ctl = PLANE_CTL_ENABLE;
 
        if (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) {
-               plane_ctl |= skl_plane_ctl_alpha(fb->format->format);
+               plane_ctl |= skl_plane_ctl_alpha(plane_state);
                plane_ctl |=
                        PLANE_CTL_PIPE_GAMMA_ENABLE |
                        PLANE_CTL_PIPE_CSC_ENABLE |
@@ -3655,7 +3683,7 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
                plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE;
        }
        plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE;
-       plane_color_ctl |= glk_plane_color_ctl_alpha(fb->format->format);
+       plane_color_ctl |= glk_plane_color_ctl_alpha(plane_state);
 
        if (fb->format->is_yuv) {
                if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709)
@@ -3849,15 +3877,15 @@ static void intel_update_pipe_config(const struct intel_crtc_state *old_crtc_sta
 
        /* on skylake this is done by detaching scalers */
        if (INTEL_GEN(dev_priv) >= 9) {
-               skl_detach_scalers(crtc);
+               skl_detach_scalers(new_crtc_state);
 
                if (new_crtc_state->pch_pfit.enabled)
-                       skylake_pfit_enable(crtc);
+                       skylake_pfit_enable(new_crtc_state);
        } else if (HAS_PCH_SPLIT(dev_priv)) {
                if (new_crtc_state->pch_pfit.enabled)
-                       ironlake_pfit_enable(crtc);
+                       ironlake_pfit_enable(new_crtc_state);
                else if (old_crtc_state->pch_pfit.enabled)
-                       ironlake_pfit_disable(crtc, true);
+                       ironlake_pfit_disable(old_crtc_state);
        }
 }
 
@@ -4256,10 +4284,10 @@ static void ivb_manual_fdi_link_train(struct intel_crtc *crtc,
        DRM_DEBUG_KMS("FDI train done.\n");
 }
 
-static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
+static void ironlake_fdi_pll_enable(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = intel_crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
        int pipe = intel_crtc->pipe;
        i915_reg_t reg;
        u32 temp;
@@ -4268,7 +4296,7 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
        reg = FDI_RX_CTL(pipe);
        temp = I915_READ(reg);
        temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16));
-       temp |= FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
+       temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
        temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
        I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
 
@@ -4531,12 +4559,12 @@ int lpt_get_iclkip(struct drm_i915_private *dev_priv)
                                 desired_divisor << auxdiv);
 }
 
-static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc,
+static void ironlake_pch_transcoder_set_timings(const struct intel_crtc_state *crtc_state,
                                                enum pipe pch_transcoder)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
 
        I915_WRITE(PCH_TRANS_HTOTAL(pch_transcoder),
                   I915_READ(HTOTAL(cpu_transcoder)));
@@ -4681,11 +4709,11 @@ static void ironlake_pch_enable(const struct intel_atomic_state *state,
         * Note that enable_shared_dpll tries to do the right thing, but
         * get_shared_dpll unconditionally resets the pll - we need that to have
         * the right LVDS enable sequence. */
-       intel_enable_shared_dpll(crtc);
+       intel_enable_shared_dpll(crtc_state);
 
        /* set transcoder timing, panel must allow it */
        assert_panel_unlocked(dev_priv, pipe);
-       ironlake_pch_transcoder_set_timings(crtc, pipe);
+       ironlake_pch_transcoder_set_timings(crtc_state, pipe);
 
        intel_fdi_normal_train(crtc);
 
@@ -4717,7 +4745,7 @@ static void ironlake_pch_enable(const struct intel_atomic_state *state,
                I915_WRITE(reg, temp);
        }
 
-       ironlake_enable_pch_transcoder(dev_priv, pipe);
+       ironlake_enable_pch_transcoder(crtc_state);
 }
 
 static void lpt_pch_enable(const struct intel_atomic_state *state,
@@ -4732,7 +4760,7 @@ static void lpt_pch_enable(const struct intel_atomic_state *state,
        lpt_program_iclkip(crtc);
 
        /* Set transcoder timing. */
-       ironlake_pch_transcoder_set_timings(crtc, PIPE_A);
+       ironlake_pch_transcoder_set_timings(crtc_state, PIPE_A);
 
        lpt_enable_pch_transcoder(dev_priv, cpu_transcoder);
 }
@@ -4811,7 +4839,8 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
                if (pixel_format == DRM_FORMAT_NV12)
                        need_scaling = true;
 
-       if (crtc_state->ycbcr420 && scaler_user == SKL_CRTC_INDEX)
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 &&
+           scaler_user == SKL_CRTC_INDEX)
                need_scaling = true;
 
        /*
@@ -4974,19 +5003,19 @@ static void skylake_scaler_disable(struct intel_crtc *crtc)
                skl_detach_scaler(crtc, i);
 }
 
-static void skylake_pfit_enable(struct intel_crtc *crtc)
+static void skylake_pfit_enable(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int pipe = crtc->pipe;
-       struct intel_crtc_scaler_state *scaler_state =
-               &crtc->config->scaler_state;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+       const struct intel_crtc_scaler_state *scaler_state =
+               &crtc_state->scaler_state;
 
-       if (crtc->config->pch_pfit.enabled) {
+       if (crtc_state->pch_pfit.enabled) {
                u16 uv_rgb_hphase, uv_rgb_vphase;
                int id;
 
-               if (WARN_ON(crtc->config->scaler_state.scaler_id < 0))
+               if (WARN_ON(crtc_state->scaler_state.scaler_id < 0))
                        return;
 
                uv_rgb_hphase = skl_scaler_calc_phase(1, false);
@@ -4999,18 +5028,18 @@ static void skylake_pfit_enable(struct intel_crtc *crtc)
                              PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase));
                I915_WRITE_FW(SKL_PS_HPHASE(pipe, id),
                              PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_hphase));
-               I915_WRITE(SKL_PS_WIN_POS(pipe, id), crtc->config->pch_pfit.pos);
-               I915_WRITE(SKL_PS_WIN_SZ(pipe, id), crtc->config->pch_pfit.size);
+               I915_WRITE(SKL_PS_WIN_POS(pipe, id), crtc_state->pch_pfit.pos);
+               I915_WRITE(SKL_PS_WIN_SZ(pipe, id), crtc_state->pch_pfit.size);
        }
 }
 
-static void ironlake_pfit_enable(struct intel_crtc *crtc)
+static void ironlake_pfit_enable(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        int pipe = crtc->pipe;
 
-       if (crtc->config->pch_pfit.enabled) {
+       if (crtc_state->pch_pfit.enabled) {
                /* Force use of hard-coded filter coefficients
                 * as some pre-programmed values are broken,
                 * e.g. x201.
@@ -5020,8 +5049,8 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc)
                                                 PF_PIPE_SEL_IVB(pipe));
                else
                        I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3);
-               I915_WRITE(PF_WIN_POS(pipe), crtc->config->pch_pfit.pos);
-               I915_WRITE(PF_WIN_SZ(pipe), crtc->config->pch_pfit.size);
+               I915_WRITE(PF_WIN_POS(pipe), crtc_state->pch_pfit.pos);
+               I915_WRITE(PF_WIN_SZ(pipe), crtc_state->pch_pfit.size);
        }
 }
 
@@ -5078,10 +5107,14 @@ void hsw_disable_ips(const struct intel_crtc_state *crtc_state)
                mutex_lock(&dev_priv->pcu_lock);
                WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 0));
                mutex_unlock(&dev_priv->pcu_lock);
-               /* wait for pcode to finish disabling IPS, which may take up to 42ms */
+               /*
+                * Wait for PCODE to finish disabling IPS. The BSpec specified
+                * 42ms timeout value leads to occasional timeouts so use 100ms
+                * instead.
+                */
                if (intel_wait_for_register(dev_priv,
                                            IPS_CTL, IPS_ENABLE, 0,
-                                           42))
+                                           100))
                        DRM_ERROR("Timed out waiting for IPS disable\n");
        } else {
                I915_WRITE(IPS_CTL, 0);
@@ -5322,7 +5355,8 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
         *
         * WaCxSRDisabledForSpriteScaling:ivb
         */
-       if (pipe_config->disable_lp_wm && ilk_disable_lp_wm(dev))
+       if (pipe_config->disable_lp_wm && ilk_disable_lp_wm(dev) &&
+           old_crtc_state->base.active)
                intel_wait_for_vblank(dev_priv, crtc->pipe);
 
        /*
@@ -5353,24 +5387,23 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
                intel_update_watermarks(crtc);
 }
 
-static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask)
+static void intel_crtc_disable_planes(struct intel_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;
+       struct drm_device *dev = crtc->base.dev;
+       struct intel_plane *plane;
+       unsigned fb_bits = 0;
 
-       intel_crtc_dpms_overlay_disable(intel_crtc);
+       intel_crtc_dpms_overlay_disable(crtc);
 
-       drm_for_each_plane_mask(p, dev, plane_mask)
-               to_intel_plane(p)->disable_plane(to_intel_plane(p), intel_crtc);
+       for_each_intel_plane_on_crtc(dev, crtc, plane) {
+               if (plane_mask & BIT(plane->id)) {
+                       plane->disable_plane(plane, crtc);
 
-       /*
-        * FIXME: Once we grow proper nuclear flip support out of this we need
-        * to compute the mask of flip planes precisely. For the time being
-        * consider this a flip to a NULL plane.
-        */
-       intel_frontbuffer_flip(to_i915(dev), INTEL_FRONTBUFFER_ALL_MASK(pipe));
+                       fb_bits |= plane->frontbuffer_bit;
+               }
+       }
+
+       intel_frontbuffer_flip(to_i915(dev), fb_bits);
 }
 
 static void intel_encoders_pre_pll_enable(struct drm_crtc *crtc,
@@ -5520,37 +5553,37 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
        intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
        intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
 
-       if (intel_crtc->config->has_pch_encoder)
-               intel_prepare_shared_dpll(intel_crtc);
+       if (pipe_config->has_pch_encoder)
+               intel_prepare_shared_dpll(pipe_config);
 
-       if (intel_crtc_has_dp_encoder(intel_crtc->config))
-               intel_dp_set_m_n(intel_crtc, M1_N1);
+       if (intel_crtc_has_dp_encoder(pipe_config))
+               intel_dp_set_m_n(pipe_config, M1_N1);
 
-       intel_set_pipe_timings(intel_crtc);
-       intel_set_pipe_src_size(intel_crtc);
+       intel_set_pipe_timings(pipe_config);
+       intel_set_pipe_src_size(pipe_config);
 
-       if (intel_crtc->config->has_pch_encoder) {
-               intel_cpu_transcoder_set_m_n(intel_crtc,
-                                    &intel_crtc->config->fdi_m_n, NULL);
+       if (pipe_config->has_pch_encoder) {
+               intel_cpu_transcoder_set_m_n(pipe_config,
+                                            &pipe_config->fdi_m_n, NULL);
        }
 
-       ironlake_set_pipeconf(crtc);
+       ironlake_set_pipeconf(pipe_config);
 
        intel_crtc->active = true;
 
        intel_encoders_pre_enable(crtc, pipe_config, old_state);
 
-       if (intel_crtc->config->has_pch_encoder) {
+       if (pipe_config->has_pch_encoder) {
                /* Note: FDI PLL enabling _must_ be done before we enable the
                 * cpu pipes, hence this is separate from all the other fdi/pch
                 * enabling. */
-               ironlake_fdi_pll_enable(intel_crtc);
+               ironlake_fdi_pll_enable(pipe_config);
        } else {
                assert_fdi_tx_disabled(dev_priv, pipe);
                assert_fdi_rx_disabled(dev_priv, pipe);
        }
 
-       ironlake_pfit_enable(intel_crtc);
+       ironlake_pfit_enable(pipe_config);
 
        /*
         * On ILK+ LUT must be loaded before the pipe is running but with
@@ -5559,10 +5592,10 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
        intel_color_load_luts(&pipe_config->base);
 
        if (dev_priv->display.initial_watermarks != NULL)
-               dev_priv->display.initial_watermarks(old_intel_state, intel_crtc->config);
+               dev_priv->display.initial_watermarks(old_intel_state, pipe_config);
        intel_enable_pipe(pipe_config);
 
-       if (intel_crtc->config->has_pch_encoder)
+       if (pipe_config->has_pch_encoder)
                ironlake_pch_enable(old_intel_state, pipe_config);
 
        assert_vblank_disabled(crtc);
@@ -5579,7 +5612,7 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
         * some interlaced HDMI modes. Let's do the double wait always
         * in case there are more corner cases we don't know about.
         */
-       if (intel_crtc->config->has_pch_encoder) {
+       if (pipe_config->has_pch_encoder) {
                intel_wait_for_vblank(dev_priv, pipe);
                intel_wait_for_vblank(dev_priv, pipe);
        }
@@ -5613,10 +5646,9 @@ static void icl_pipe_mbus_enable(struct intel_crtc *crtc)
        enum pipe pipe = crtc->pipe;
        uint32_t val;
 
-       val = MBUS_DBOX_BW_CREDIT(1) | MBUS_DBOX_A_CREDIT(2);
-
-       /* Program B credit equally to all pipes */
-       val |= MBUS_DBOX_B_CREDIT(24 / INTEL_INFO(dev_priv)->num_pipes);
+       val = MBUS_DBOX_A_CREDIT(2);
+       val |= MBUS_DBOX_BW_CREDIT(1);
+       val |= MBUS_DBOX_B_CREDIT(8);
 
        I915_WRITE(PIPE_MBUS_DBOX_CTL(pipe), val);
 }
@@ -5628,7 +5660,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
        struct drm_i915_private *dev_priv = to_i915(crtc->dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe, hsw_workaround_pipe;
-       enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
+       enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
        struct intel_atomic_state *old_intel_state =
                to_intel_atomic_state(old_state);
        bool psl_clkgate_wa;
@@ -5639,37 +5671,37 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
 
        intel_encoders_pre_pll_enable(crtc, pipe_config, old_state);
 
-       if (intel_crtc->config->shared_dpll)
-               intel_enable_shared_dpll(intel_crtc);
+       if (pipe_config->shared_dpll)
+               intel_enable_shared_dpll(pipe_config);
 
        if (INTEL_GEN(dev_priv) >= 11)
                icl_map_plls_to_ports(crtc, pipe_config, old_state);
 
        intel_encoders_pre_enable(crtc, pipe_config, old_state);
 
-       if (intel_crtc_has_dp_encoder(intel_crtc->config))
-               intel_dp_set_m_n(intel_crtc, M1_N1);
+       if (intel_crtc_has_dp_encoder(pipe_config))
+               intel_dp_set_m_n(pipe_config, M1_N1);
 
        if (!transcoder_is_dsi(cpu_transcoder))
-               intel_set_pipe_timings(intel_crtc);
+               intel_set_pipe_timings(pipe_config);
 
-       intel_set_pipe_src_size(intel_crtc);
+       intel_set_pipe_src_size(pipe_config);
 
        if (cpu_transcoder != TRANSCODER_EDP &&
            !transcoder_is_dsi(cpu_transcoder)) {
                I915_WRITE(PIPE_MULT(cpu_transcoder),
-                          intel_crtc->config->pixel_multiplier - 1);
+                          pipe_config->pixel_multiplier - 1);
        }
 
-       if (intel_crtc->config->has_pch_encoder) {
-               intel_cpu_transcoder_set_m_n(intel_crtc,
-                                    &intel_crtc->config->fdi_m_n, NULL);
+       if (pipe_config->has_pch_encoder) {
+               intel_cpu_transcoder_set_m_n(pipe_config,
+                                            &pipe_config->fdi_m_n, NULL);
        }
 
        if (!transcoder_is_dsi(cpu_transcoder))
-               haswell_set_pipeconf(crtc);
+               haswell_set_pipeconf(pipe_config);
 
-       haswell_set_pipemisc(crtc);
+       haswell_set_pipemisc(pipe_config);
 
        intel_color_set_csc(&pipe_config->base);
 
@@ -5677,14 +5709,14 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
 
        /* Display WA #1180: WaDisableScalarClockGating: glk, cnl */
        psl_clkgate_wa = (IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) &&
-                        intel_crtc->config->pch_pfit.enabled;
+                        pipe_config->pch_pfit.enabled;
        if (psl_clkgate_wa)
                glk_pipe_scaler_clock_gating_wa(dev_priv, pipe, true);
 
        if (INTEL_GEN(dev_priv) >= 9)
-               skylake_pfit_enable(intel_crtc);
+               skylake_pfit_enable(pipe_config);
        else
-               ironlake_pfit_enable(intel_crtc);
+               ironlake_pfit_enable(pipe_config);
 
        /*
         * On ILK+ LUT must be loaded before the pipe is running but with
@@ -5717,10 +5749,10 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
        if (!transcoder_is_dsi(cpu_transcoder))
                intel_enable_pipe(pipe_config);
 
-       if (intel_crtc->config->has_pch_encoder)
+       if (pipe_config->has_pch_encoder)
                lpt_pch_enable(old_intel_state, pipe_config);
 
-       if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DP_MST))
+       if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST))
                intel_ddi_set_vc_payload_alloc(pipe_config, true);
 
        assert_vblank_disabled(crtc);
@@ -5742,15 +5774,15 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
        }
 }
 
-static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force)
+static void ironlake_pfit_disable(const struct intel_crtc_state *old_crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int pipe = crtc->pipe;
+       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
 
        /* To avoid upsetting the power well on haswell only disable the pfit if
         * it's in use. The hw state code will make sure we get this right. */
-       if (force || crtc->config->pch_pfit.enabled) {
+       if (old_crtc_state->pch_pfit.enabled) {
                I915_WRITE(PF_CTL(pipe), 0);
                I915_WRITE(PF_WIN_POS(pipe), 0);
                I915_WRITE(PF_WIN_SZ(pipe), 0);
@@ -5781,14 +5813,14 @@ static void ironlake_crtc_disable(struct intel_crtc_state *old_crtc_state,
 
        intel_disable_pipe(old_crtc_state);
 
-       ironlake_pfit_disable(intel_crtc, false);
+       ironlake_pfit_disable(old_crtc_state);
 
-       if (intel_crtc->config->has_pch_encoder)
+       if (old_crtc_state->has_pch_encoder)
                ironlake_fdi_disable(crtc);
 
        intel_encoders_post_disable(crtc, old_crtc_state, old_state);
 
-       if (intel_crtc->config->has_pch_encoder) {
+       if (old_crtc_state->has_pch_encoder) {
                ironlake_disable_pch_transcoder(dev_priv, pipe);
 
                if (HAS_PCH_CPT(dev_priv)) {
@@ -5842,7 +5874,7 @@ static void haswell_crtc_disable(struct intel_crtc_state *old_crtc_state,
        if (INTEL_GEN(dev_priv) >= 9)
                skylake_scaler_disable(intel_crtc);
        else
-               ironlake_pfit_disable(intel_crtc, false);
+               ironlake_pfit_disable(old_crtc_state);
 
        intel_encoders_post_disable(crtc, old_crtc_state, old_state);
 
@@ -5850,13 +5882,12 @@ static void haswell_crtc_disable(struct intel_crtc_state *old_crtc_state,
                icl_unmap_plls_to_ports(crtc, old_crtc_state, old_state);
 }
 
-static void i9xx_pfit_enable(struct intel_crtc *crtc)
+static void i9xx_pfit_enable(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc_state *pipe_config = crtc->config;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
-       if (!pipe_config->gmch_pfit.control)
+       if (!crtc_state->gmch_pfit.control)
                return;
 
        /*
@@ -5866,8 +5897,8 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc)
        WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE);
        assert_pipe_disabled(dev_priv, crtc->pipe);
 
-       I915_WRITE(PFIT_PGM_RATIOS, pipe_config->gmch_pfit.pgm_ratios);
-       I915_WRITE(PFIT_CONTROL, pipe_config->gmch_pfit.control);
+       I915_WRITE(PFIT_PGM_RATIOS, crtc_state->gmch_pfit.pgm_ratios);
+       I915_WRITE(PFIT_CONTROL, crtc_state->gmch_pfit.control);
 
        /* Border color in case we don't scale up to the full screen. Black by
         * default, change to something else for debugging. */
@@ -5990,20 +6021,20 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
        if (WARN_ON(intel_crtc->active))
                return;
 
-       if (intel_crtc_has_dp_encoder(intel_crtc->config))
-               intel_dp_set_m_n(intel_crtc, M1_N1);
+       if (intel_crtc_has_dp_encoder(pipe_config))
+               intel_dp_set_m_n(pipe_config, M1_N1);
 
-       intel_set_pipe_timings(intel_crtc);
-       intel_set_pipe_src_size(intel_crtc);
+       intel_set_pipe_timings(pipe_config);
+       intel_set_pipe_src_size(pipe_config);
 
        if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
-               struct drm_i915_private *dev_priv = to_i915(dev);
-
                I915_WRITE(CHV_BLEND(pipe), CHV_BLEND_LEGACY);
                I915_WRITE(CHV_CANVAS(pipe), 0);
        }
 
-       i9xx_set_pipeconf(intel_crtc);
+       i9xx_set_pipeconf(pipe_config);
+
+       intel_color_set_csc(&pipe_config->base);
 
        intel_crtc->active = true;
 
@@ -6012,16 +6043,16 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
        intel_encoders_pre_pll_enable(crtc, pipe_config, old_state);
 
        if (IS_CHERRYVIEW(dev_priv)) {
-               chv_prepare_pll(intel_crtc, intel_crtc->config);
-               chv_enable_pll(intel_crtc, intel_crtc->config);
+               chv_prepare_pll(intel_crtc, pipe_config);
+               chv_enable_pll(intel_crtc, pipe_config);
        } else {
-               vlv_prepare_pll(intel_crtc, intel_crtc->config);
-               vlv_enable_pll(intel_crtc, intel_crtc->config);
+               vlv_prepare_pll(intel_crtc, pipe_config);
+               vlv_enable_pll(intel_crtc, pipe_config);
        }
 
        intel_encoders_pre_enable(crtc, pipe_config, old_state);
 
-       i9xx_pfit_enable(intel_crtc);
+       i9xx_pfit_enable(pipe_config);
 
        intel_color_load_luts(&pipe_config->base);
 
@@ -6035,13 +6066,13 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
        intel_encoders_enable(crtc, pipe_config, old_state);
 }
 
-static void i9xx_set_pll_dividers(struct intel_crtc *crtc)
+static void i9xx_set_pll_dividers(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
-       I915_WRITE(FP0(crtc->pipe), crtc->config->dpll_hw_state.fp0);
-       I915_WRITE(FP1(crtc->pipe), crtc->config->dpll_hw_state.fp1);
+       I915_WRITE(FP0(crtc->pipe), crtc_state->dpll_hw_state.fp0);
+       I915_WRITE(FP1(crtc->pipe), crtc_state->dpll_hw_state.fp1);
 }
 
 static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
@@ -6058,15 +6089,15 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
        if (WARN_ON(intel_crtc->active))
                return;
 
-       i9xx_set_pll_dividers(intel_crtc);
+       i9xx_set_pll_dividers(pipe_config);
 
-       if (intel_crtc_has_dp_encoder(intel_crtc->config))
-               intel_dp_set_m_n(intel_crtc, M1_N1);
+       if (intel_crtc_has_dp_encoder(pipe_config))
+               intel_dp_set_m_n(pipe_config, M1_N1);
 
-       intel_set_pipe_timings(intel_crtc);
-       intel_set_pipe_src_size(intel_crtc);
+       intel_set_pipe_timings(pipe_config);
+       intel_set_pipe_src_size(pipe_config);
 
-       i9xx_set_pipeconf(intel_crtc);
+       i9xx_set_pipeconf(pipe_config);
 
        intel_crtc->active = true;
 
@@ -6077,13 +6108,13 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
 
        i9xx_enable_pll(intel_crtc, pipe_config);
 
-       i9xx_pfit_enable(intel_crtc);
+       i9xx_pfit_enable(pipe_config);
 
        intel_color_load_luts(&pipe_config->base);
 
        if (dev_priv->display.initial_watermarks != NULL)
                dev_priv->display.initial_watermarks(old_intel_state,
-                                                    intel_crtc->config);
+                                                    pipe_config);
        else
                intel_update_watermarks(intel_crtc);
        intel_enable_pipe(pipe_config);
@@ -6094,18 +6125,18 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
        intel_encoders_enable(crtc, pipe_config, old_state);
 }
 
-static void i9xx_pfit_disable(struct intel_crtc *crtc)
+static void i9xx_pfit_disable(const struct intel_crtc_state *old_crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
-       if (!crtc->config->gmch_pfit.control)
+       if (!old_crtc_state->gmch_pfit.control)
                return;
 
        assert_pipe_disabled(dev_priv, crtc->pipe);
 
-       DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n",
-                        I915_READ(PFIT_CONTROL));
+       DRM_DEBUG_KMS("disabling pfit, current: 0x%08x\n",
+                     I915_READ(PFIT_CONTROL));
        I915_WRITE(PFIT_CONTROL, 0);
 }
 
@@ -6132,17 +6163,17 @@ static void i9xx_crtc_disable(struct intel_crtc_state *old_crtc_state,
 
        intel_disable_pipe(old_crtc_state);
 
-       i9xx_pfit_disable(intel_crtc);
+       i9xx_pfit_disable(old_crtc_state);
 
        intel_encoders_post_disable(crtc, old_crtc_state, old_state);
 
-       if (!intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DSI)) {
+       if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DSI)) {
                if (IS_CHERRYVIEW(dev_priv))
                        chv_disable_pll(dev_priv, pipe);
                else if (IS_VALLEYVIEW(dev_priv))
                        vlv_disable_pll(dev_priv, pipe);
                else
-                       i9xx_disable_pll(intel_crtc);
+                       i9xx_disable_pll(old_crtc_state);
        }
 
        intel_encoders_post_pll_disable(crtc, old_crtc_state, old_state);
@@ -6216,7 +6247,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc,
 
        intel_fbc_disable(intel_crtc);
        intel_update_watermarks(intel_crtc);
-       intel_disable_shared_dpll(intel_crtc);
+       intel_disable_shared_dpll(to_intel_crtc_state(crtc->state));
 
        domains = intel_crtc->enabled_power_domains;
        for_each_power_domain(domain, domains)
@@ -6294,66 +6325,6 @@ static void intel_connector_verify_state(struct drm_crtc_state *crtc_state,
        }
 }
 
-int intel_connector_init(struct intel_connector *connector)
-{
-       struct intel_digital_connector_state *conn_state;
-
-       /*
-        * Allocate enough memory to hold intel_digital_connector_state,
-        * This might be a few bytes too many, but for connectors that don't
-        * need it we'll free the state and allocate a smaller one on the first
-        * succesful commit anyway.
-        */
-       conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
-       if (!conn_state)
-               return -ENOMEM;
-
-       __drm_atomic_helper_connector_reset(&connector->base,
-                                           &conn_state->base);
-
-       return 0;
-}
-
-struct intel_connector *intel_connector_alloc(void)
-{
-       struct intel_connector *connector;
-
-       connector = kzalloc(sizeof *connector, GFP_KERNEL);
-       if (!connector)
-               return NULL;
-
-       if (intel_connector_init(connector) < 0) {
-               kfree(connector);
-               return NULL;
-       }
-
-       return connector;
-}
-
-/*
- * Free the bits allocated by intel_connector_alloc.
- * This should only be used after intel_connector_alloc has returned
- * successfully, and before drm_connector_init returns successfully.
- * Otherwise the destroy callbacks for the connector and the state should
- * take care of proper cleanup/free
- */
-void intel_connector_free(struct intel_connector *connector)
-{
-       kfree(to_intel_digital_connector_state(connector->base.state));
-       kfree(connector);
-}
-
-/* Simple connector->get_hw_state implementation for encoders that support only
- * one connector and no cloning and hence the encoder state determines the state
- * of the connector. */
-bool intel_connector_get_hw_state(struct intel_connector *connector)
-{
-       enum pipe pipe = 0;
-       struct intel_encoder *encoder = connector->encoder;
-
-       return encoder->get_hw_state(encoder, &pipe);
-}
-
 static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
 {
        if (crtc_state->base.enable && crtc_state->has_pch_encoder)
@@ -6620,7 +6591,9 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
                return -EINVAL;
        }
 
-       if (pipe_config->ycbcr420 && pipe_config->base.ctm) {
+       if ((pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
+            pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR444) &&
+            pipe_config->base.ctm) {
                /*
                 * There is only one pipe CSC unit per pipe, and we need that
                 * for output conversion from RGB->YCBCR. So if CTM is already
@@ -6676,22 +6649,20 @@ intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den)
 
 static void compute_m_n(unsigned int m, unsigned int n,
                        uint32_t *ret_m, uint32_t *ret_n,
-                       bool reduce_m_n)
+                       bool constant_n)
 {
        /*
-        * Reduce M/N as much as possible without loss in precision. Several DP
-        * dongles in particular seem to be fussy about too large *link* M/N
-        * values. The passed in values are more likely to have the least
-        * significant bits zero than M after rounding below, so do this first.
+        * Several DP dongles in particular seem to be fussy about
+        * too large link M/N values. Give N value as 0x8000 that
+        * should be acceptable by specific devices. 0x8000 is the
+        * specified fixed N value for asynchronous clock mode,
+        * which the devices expect also in synchronous clock mode.
         */
-       if (reduce_m_n) {
-               while ((m & 1) == 0 && (n & 1) == 0) {
-                       m >>= 1;
-                       n >>= 1;
-               }
-       }
+       if (constant_n)
+               *ret_n = 0x8000;
+       else
+               *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX);
 
-       *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX);
        *ret_m = div_u64((uint64_t) m * *ret_n, n);
        intel_reduce_m_n_ratio(ret_m, ret_n);
 }
@@ -6700,18 +6671,18 @@ void
 intel_link_compute_m_n(int bits_per_pixel, int nlanes,
                       int pixel_clock, int link_clock,
                       struct intel_link_m_n *m_n,
-                      bool reduce_m_n)
+                      bool constant_n)
 {
        m_n->tu = 64;
 
        compute_m_n(bits_per_pixel * pixel_clock,
                    link_clock * nlanes * 8,
                    &m_n->gmch_m, &m_n->gmch_n,
-                   reduce_m_n);
+                   constant_n);
 
        compute_m_n(pixel_clock, link_clock,
                    &m_n->link_m, &m_n->link_n,
-                   reduce_m_n);
+                   constant_n);
 }
 
 static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
@@ -6788,12 +6759,12 @@ static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, enum pipe
        vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val);
 }
 
-static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
-                                        struct intel_link_m_n *m_n)
+static void intel_pch_transcoder_set_m_n(const struct intel_crtc_state *crtc_state,
+                                        const struct intel_link_m_n *m_n)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int pipe = crtc->pipe;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
 
        I915_WRITE(PCH_TRANS_DATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
        I915_WRITE(PCH_TRANS_DATA_N1(pipe), m_n->gmch_n);
@@ -6801,25 +6772,39 @@ static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
        I915_WRITE(PCH_TRANS_LINK_N1(pipe), m_n->link_n);
 }
 
-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 bool transcoder_has_m2_n2(struct drm_i915_private *dev_priv,
+                                enum transcoder transcoder)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       int pipe = crtc->pipe;
-       enum transcoder transcoder = crtc->config->cpu_transcoder;
+       if (IS_HASWELL(dev_priv))
+               return transcoder == TRANSCODER_EDP;
+
+       /*
+        * Strictly speaking some registers are available before
+        * gen7, but we only support DRRS on gen7+
+        */
+       return IS_GEN7(dev_priv) || IS_CHERRYVIEW(dev_priv);
+}
+
+static void intel_cpu_transcoder_set_m_n(const struct intel_crtc_state *crtc_state,
+                                        const struct intel_link_m_n *m_n,
+                                        const struct intel_link_m_n *m2_n2)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+       enum transcoder transcoder = crtc_state->cpu_transcoder;
 
        if (INTEL_GEN(dev_priv) >= 5) {
                I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m);
                I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n);
                I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m);
                I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n);
-               /* M2_N2 registers to be set only for gen < 8 (M2_N2 available
-                * for gen < 8) and if DRRS is supported (to make sure the
-                * registers are not unnecessarily accessed).
+               /*
+                *  M2_N2 registers are set only if DRRS is supported
+                * (to make sure the registers are not unnecessarily accessed).
                 */
-               if (m2_n2 && (IS_CHERRYVIEW(dev_priv) ||
-                   INTEL_GEN(dev_priv) < 8) && crtc->config->has_drrs) {
+               if (m2_n2 && crtc_state->has_drrs &&
+                   transcoder_has_m2_n2(dev_priv, transcoder)) {
                        I915_WRITE(PIPE_DATA_M2(transcoder),
                                        TU_SIZE(m2_n2->tu) | m2_n2->gmch_m);
                        I915_WRITE(PIPE_DATA_N2(transcoder), m2_n2->gmch_n);
@@ -6834,29 +6819,29 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
        }
 }
 
-void intel_dp_set_m_n(struct intel_crtc *crtc, enum link_m_n_set m_n)
+void intel_dp_set_m_n(const struct intel_crtc_state *crtc_state, enum link_m_n_set m_n)
 {
-       struct intel_link_m_n *dp_m_n, *dp_m2_n2 = NULL;
+       const struct intel_link_m_n *dp_m_n, *dp_m2_n2 = NULL;
 
        if (m_n == M1_N1) {
-               dp_m_n = &crtc->config->dp_m_n;
-               dp_m2_n2 = &crtc->config->dp_m2_n2;
+               dp_m_n = &crtc_state->dp_m_n;
+               dp_m2_n2 = &crtc_state->dp_m2_n2;
        } else if (m_n == M2_N2) {
 
                /*
                 * M2_N2 registers are not supported. Hence m2_n2 divider value
                 * needs to be programmed into M1_N1.
                 */
-               dp_m_n = &crtc->config->dp_m2_n2;
+               dp_m_n = &crtc_state->dp_m2_n2;
        } else {
                DRM_ERROR("Unsupported divider value\n");
                return;
        }
 
-       if (crtc->config->has_pch_encoder)
-               intel_pch_transcoder_set_m_n(crtc, &crtc->config->dp_m_n);
+       if (crtc_state->has_pch_encoder)
+               intel_pch_transcoder_set_m_n(crtc_state, &crtc_state->dp_m_n);
        else
-               intel_cpu_transcoder_set_m_n(crtc, dp_m_n, dp_m2_n2);
+               intel_cpu_transcoder_set_m_n(crtc_state, dp_m_n, dp_m2_n2);
 }
 
 static void vlv_compute_dpll(struct intel_crtc *crtc,
@@ -6955,8 +6940,8 @@ static void vlv_prepare_pll(struct intel_crtc *crtc,
 
        /* Set HBR and RBR LPF coefficients */
        if (pipe_config->port_clock == 162000 ||
-           intel_crtc_has_type(crtc->config, INTEL_OUTPUT_ANALOG) ||
-           intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI))
+           intel_crtc_has_type(pipe_config, INTEL_OUTPUT_ANALOG) ||
+           intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI))
                vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe),
                                 0x009f0003);
        else
@@ -6983,7 +6968,7 @@ static void vlv_prepare_pll(struct intel_crtc *crtc,
 
        coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe));
        coreclk = (coreclk & 0x0000ff00) | 0x01c00000;
-       if (intel_crtc_has_dp_encoder(crtc->config))
+       if (intel_crtc_has_dp_encoder(pipe_config))
                coreclk |= 0x01000000;
        vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk);
 
@@ -7262,12 +7247,13 @@ static void i8xx_compute_dpll(struct intel_crtc *crtc,
        crtc_state->dpll_hw_state.dpll = dpll;
 }
 
-static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
+static void intel_set_pipe_timings(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
-       enum pipe pipe = intel_crtc->pipe;
-       enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
-       const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
        uint32_t crtc_vtotal, crtc_vblank_end;
        int vsyncshift = 0;
 
@@ -7281,7 +7267,7 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
                crtc_vtotal -= 1;
                crtc_vblank_end -= 1;
 
-               if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_SDVO))
+               if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO))
                        vsyncshift = (adjusted_mode->crtc_htotal - 1) / 2;
                else
                        vsyncshift = adjusted_mode->crtc_hsync_start -
@@ -7323,18 +7309,18 @@ 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_set_pipe_src_size(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = intel_crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       enum pipe pipe = intel_crtc->pipe;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
 
        /* pipesrc controls the size that is scaled from, which should
         * always be the user's requested size.
         */
        I915_WRITE(PIPESRC(pipe),
-                  ((intel_crtc->config->pipe_src_w - 1) << 16) |
-                  (intel_crtc->config->pipe_src_h - 1));
+                  ((crtc_state->pipe_src_w - 1) << 16) |
+                  (crtc_state->pipe_src_h - 1));
 }
 
 static void intel_get_pipe_timings(struct intel_crtc *crtc,
@@ -7410,29 +7396,30 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
        drm_mode_set_name(mode);
 }
 
-static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
+static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        uint32_t pipeconf;
 
        pipeconf = 0;
 
        /* we keep both pipes enabled on 830 */
        if (IS_I830(dev_priv))
-               pipeconf |= I915_READ(PIPECONF(intel_crtc->pipe)) & PIPECONF_ENABLE;
+               pipeconf |= I915_READ(PIPECONF(crtc->pipe)) & PIPECONF_ENABLE;
 
-       if (intel_crtc->config->double_wide)
+       if (crtc_state->double_wide)
                pipeconf |= PIPECONF_DOUBLE_WIDE;
 
        /* only g4x and later have fancy bpc/dither controls */
        if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) ||
            IS_CHERRYVIEW(dev_priv)) {
                /* Bspec claims that we can't use dithering for 30bpp pipes. */
-               if (intel_crtc->config->dither && intel_crtc->config->pipe_bpp != 30)
+               if (crtc_state->dither && crtc_state->pipe_bpp != 30)
                        pipeconf |= PIPECONF_DITHER_EN |
                                    PIPECONF_DITHER_TYPE_SP;
 
-               switch (intel_crtc->config->pipe_bpp) {
+               switch (crtc_state->pipe_bpp) {
                case 18:
                        pipeconf |= PIPECONF_6BPC;
                        break;
@@ -7448,9 +7435,9 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
                }
        }
 
-       if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
+       if (crtc_state->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
                if (INTEL_GEN(dev_priv) < 4 ||
-                   intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_SDVO))
+                   intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO))
                        pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
                else
                        pipeconf |= PIPECONF_INTERLACE_W_SYNC_SHIFT;
@@ -7458,11 +7445,11 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
                pipeconf |= PIPECONF_PROGRESSIVE;
 
        if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
-            intel_crtc->config->limited_color_range)
+            crtc_state->limited_color_range)
                pipeconf |= PIPECONF_COLOR_RANGE_SELECT;
 
-       I915_WRITE(PIPECONF(intel_crtc->pipe), pipeconf);
-       POSTING_READ(PIPECONF(intel_crtc->pipe));
+       I915_WRITE(PIPECONF(crtc->pipe), pipeconf);
+       POSTING_READ(PIPECONF(crtc->pipe));
 }
 
 static int i8xx_crtc_compute_clock(struct intel_crtc *crtc,
@@ -7818,6 +7805,49 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc,
        pipe_config->port_clock = chv_calc_dpll_params(refclk, &clock);
 }
 
+static void intel_get_crtc_ycbcr_config(struct intel_crtc *crtc,
+                                       struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum intel_output_format output = INTEL_OUTPUT_FORMAT_RGB;
+
+       pipe_config->lspcon_downsampling = false;
+
+       if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9) {
+               u32 tmp = I915_READ(PIPEMISC(crtc->pipe));
+
+               if (tmp & PIPEMISC_OUTPUT_COLORSPACE_YUV) {
+                       bool ycbcr420_enabled = tmp & PIPEMISC_YUV420_ENABLE;
+                       bool blend = tmp & PIPEMISC_YUV420_MODE_FULL_BLEND;
+
+                       if (ycbcr420_enabled) {
+                               /* We support 4:2:0 in full blend mode only */
+                               if (!blend)
+                                       output = INTEL_OUTPUT_FORMAT_INVALID;
+                               else if (!(IS_GEMINILAKE(dev_priv) ||
+                                          INTEL_GEN(dev_priv) >= 10))
+                                       output = INTEL_OUTPUT_FORMAT_INVALID;
+                               else
+                                       output = INTEL_OUTPUT_FORMAT_YCBCR420;
+                       } else {
+                               /*
+                                * Currently there is no interface defined to
+                                * check user preference between RGB/YCBCR444
+                                * or YCBCR420. So the only possible case for
+                                * YCBCR444 usage is driving YCBCR420 output
+                                * with LSPCON, when pipe is configured for
+                                * YCBCR444 output and LSPCON takes care of
+                                * downsampling it.
+                                */
+                               pipe_config->lspcon_downsampling = true;
+                               output = INTEL_OUTPUT_FORMAT_YCBCR444;
+                       }
+               }
+       }
+
+       pipe_config->output_format = output;
+}
+
 static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
                                 struct intel_crtc_state *pipe_config)
 {
@@ -7830,6 +7860,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
        if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
 
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
        pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = NULL;
 
@@ -8361,16 +8392,16 @@ void intel_init_pch_refclk(struct drm_i915_private *dev_priv)
                lpt_init_pch_refclk(dev_priv);
 }
 
-static void ironlake_set_pipeconf(struct drm_crtc *crtc)
+static void ironlake_set_pipeconf(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
        uint32_t val;
 
        val = 0;
 
-       switch (intel_crtc->config->pipe_bpp) {
+       switch (crtc_state->pipe_bpp) {
        case 18:
                val |= PIPECONF_6BPC;
                break;
@@ -8388,32 +8419,32 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc)
                BUG();
        }
 
-       if (intel_crtc->config->dither)
+       if (crtc_state->dither)
                val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
 
-       if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+       if (crtc_state->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
                val |= PIPECONF_INTERLACED_ILK;
        else
                val |= PIPECONF_PROGRESSIVE;
 
-       if (intel_crtc->config->limited_color_range)
+       if (crtc_state->limited_color_range)
                val |= PIPECONF_COLOR_RANGE_SELECT;
 
        I915_WRITE(PIPECONF(pipe), val);
        POSTING_READ(PIPECONF(pipe));
 }
 
-static void haswell_set_pipeconf(struct drm_crtc *crtc)
+static void haswell_set_pipeconf(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
        u32 val = 0;
 
-       if (IS_HASWELL(dev_priv) && intel_crtc->config->dither)
+       if (IS_HASWELL(dev_priv) && crtc_state->dither)
                val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
 
-       if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+       if (crtc_state->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
                val |= PIPECONF_INTERLACED_ILK;
        else
                val |= PIPECONF_PROGRESSIVE;
@@ -8422,16 +8453,15 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc)
        POSTING_READ(PIPECONF(cpu_transcoder));
 }
 
-static void haswell_set_pipemisc(struct drm_crtc *crtc)
+static void haswell_set_pipemisc(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_crtc_state *config = intel_crtc->config;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
 
        if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9) {
                u32 val = 0;
 
-               switch (intel_crtc->config->pipe_bpp) {
+               switch (crtc_state->pipe_bpp) {
                case 18:
                        val |= PIPEMISC_DITHER_6_BPC;
                        break;
@@ -8449,14 +8479,16 @@ static void haswell_set_pipemisc(struct drm_crtc *crtc)
                        BUG();
                }
 
-               if (intel_crtc->config->dither)
+               if (crtc_state->dither)
                        val |= PIPEMISC_DITHER_ENABLE | PIPEMISC_DITHER_TYPE_SP;
 
-               if (config->ycbcr420) {
-                       val |= PIPEMISC_OUTPUT_COLORSPACE_YUV |
-                               PIPEMISC_YUV420_ENABLE |
+               if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
+                   crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
+                       val |= PIPEMISC_OUTPUT_COLORSPACE_YUV;
+
+               if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
+                       val |= PIPEMISC_YUV420_ENABLE |
                                PIPEMISC_YUV420_MODE_FULL_BLEND;
-               }
 
                I915_WRITE(PIPEMISC(intel_crtc->pipe), val);
        }
@@ -8627,8 +8659,8 @@ static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
        ironlake_compute_dpll(crtc, crtc_state, NULL);
 
        if (!intel_get_shared_dpll(crtc, crtc_state, NULL)) {
-               DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
-                                pipe_name(crtc->pipe));
+               DRM_DEBUG_KMS("failed to find PLL for pipe %c\n",
+                             pipe_name(crtc->pipe));
                return -EINVAL;
        }
 
@@ -8667,12 +8699,8 @@ static void intel_cpu_transcoder_get_m_n(struct intel_crtc *crtc,
                m_n->gmch_n = I915_READ(PIPE_DATA_N1(transcoder));
                m_n->tu = ((I915_READ(PIPE_DATA_M1(transcoder))
                            & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
-               /* Read M2_N2 registers only for gen < 8 (M2_N2 available for
-                * gen < 8) and if DRRS is supported (to make sure the
-                * registers are not unnecessarily read).
-                */
-               if (m2_n2 && INTEL_GEN(dev_priv) < 8 &&
-                       crtc->config->has_drrs) {
+
+               if (m2_n2 && transcoder_has_m2_n2(dev_priv, transcoder)) {
                        m2_n2->link_m = I915_READ(PIPE_LINK_M2(transcoder));
                        m2_n2->link_n = I915_READ(PIPE_LINK_N2(transcoder));
                        m2_n2->gmch_m = I915_READ(PIPE_DATA_M2(transcoder))
@@ -8798,13 +8826,13 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
                fb->modifier = I915_FORMAT_MOD_X_TILED;
                break;
        case PLANE_CTL_TILED_Y:
-               if (val & PLANE_CTL_DECOMPRESSION_ENABLE)
+               if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
                        fb->modifier = I915_FORMAT_MOD_Y_TILED_CCS;
                else
                        fb->modifier = I915_FORMAT_MOD_Y_TILED;
                break;
        case PLANE_CTL_TILED_YF:
-               if (val & PLANE_CTL_DECOMPRESSION_ENABLE)
+               if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
                        fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS;
                else
                        fb->modifier = I915_FORMAT_MOD_Yf_TILED;
@@ -8880,6 +8908,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
        if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
 
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
        pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = NULL;
 
@@ -8973,7 +9002,7 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
                I915_STATE_WARN(crtc->active, "CRTC for pipe %c enabled\n",
                     pipe_name(crtc->pipe));
 
-       I915_STATE_WARN(I915_READ(HSW_PWR_WELL_CTL_DRIVER(HSW_DISP_PW_GLOBAL)),
+       I915_STATE_WARN(I915_READ(HSW_PWR_WELL_CTL2),
                        "Display power well on\n");
        I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
        I915_STATE_WARN(I915_READ(WRPLL_CTL(0)) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
@@ -9195,8 +9224,8 @@ static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
                        intel_get_crtc_new_encoder(state, crtc_state);
 
                if (!intel_get_shared_dpll(crtc, crtc_state, encoder)) {
-                       DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
-                                        pipe_name(crtc->pipe));
+                       DRM_DEBUG_KMS("failed to find PLL for pipe %c\n",
+                                     pipe_name(crtc->pipe));
                        return -EINVAL;
                }
        }
@@ -9514,27 +9543,11 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
        }
 
        intel_get_pipe_src_size(crtc, pipe_config);
+       intel_get_crtc_ycbcr_config(crtc, pipe_config);
 
        pipe_config->gamma_mode =
                I915_READ(GAMMA_MODE(crtc->pipe)) & GAMMA_MODE_MODE_MASK;
 
-       if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9) {
-               u32 tmp = I915_READ(PIPEMISC(crtc->pipe));
-               bool clrspace_yuv = tmp & PIPEMISC_OUTPUT_COLORSPACE_YUV;
-
-               if (IS_GEMINILAKE(dev_priv) || INTEL_GEN(dev_priv) >= 10) {
-                       bool blend_mode_420 = tmp &
-                                             PIPEMISC_YUV420_MODE_FULL_BLEND;
-
-                       pipe_config->ycbcr420 = tmp & PIPEMISC_YUV420_ENABLE;
-                       if (pipe_config->ycbcr420 != clrspace_yuv ||
-                           pipe_config->ycbcr420 != blend_mode_420)
-                               DRM_DEBUG_KMS("Bad 4:2:0 mode (%08x)\n", tmp);
-               } else if (clrspace_yuv) {
-                       DRM_DEBUG_KMS("YCbCr 4:2:0 Unsupported\n");
-               }
-       }
-
        power_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
        if (intel_display_power_get_if_enabled(dev_priv, power_domain)) {
                power_domain_mask |= BIT_ULL(power_domain);
@@ -9585,7 +9598,7 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
        else
                base = intel_plane_ggtt_offset(plane_state);
 
-       base += plane_state->main.offset;
+       base += plane_state->color_plane[0].offset;
 
        /* ILK+ do this automagically */
        if (HAS_GMCH_DISPLAY(dev_priv) &&
@@ -9628,55 +9641,86 @@ static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state)
                height > 0 && height <= config->cursor_height;
 }
 
-static int intel_check_cursor(struct intel_crtc_state *crtc_state,
-                             struct intel_plane_state *plane_state)
+static int intel_cursor_check_surface(struct intel_plane_state *plane_state)
 {
        const struct drm_framebuffer *fb = plane_state->base.fb;
+       unsigned int rotation = plane_state->base.rotation;
        int src_x, src_y;
        u32 offset;
        int ret;
 
-       ret = drm_atomic_helper_check_plane_state(&plane_state->base,
-                                                 &crtc_state->base,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 true, true);
+       intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation);
+       plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation);
+
+       ret = intel_plane_check_stride(plane_state);
        if (ret)
                return ret;
 
-       if (!fb)
-               return 0;
-
-       if (fb->modifier != DRM_FORMAT_MOD_LINEAR) {
-               DRM_DEBUG_KMS("cursor cannot be tiled\n");
-               return -EINVAL;
-       }
-
        src_x = plane_state->base.src_x >> 16;
        src_y = plane_state->base.src_y >> 16;
 
        intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
-       offset = intel_compute_tile_offset(&src_x, &src_y, plane_state, 0);
+       offset = intel_plane_compute_aligned_offset(&src_x, &src_y,
+                                                   plane_state, 0);
 
        if (src_x != 0 || src_y != 0) {
                DRM_DEBUG_KMS("Arbitrary cursor panning not supported\n");
                return -EINVAL;
        }
 
-       plane_state->main.offset = offset;
+       plane_state->color_plane[0].offset = offset;
 
        return 0;
 }
 
-static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
-                          const struct intel_plane_state *plane_state)
+static int intel_check_cursor(struct intel_crtc_state *crtc_state,
+                             struct intel_plane_state *plane_state)
 {
        const struct drm_framebuffer *fb = plane_state->base.fb;
+       int ret;
+
+       if (fb && fb->modifier != DRM_FORMAT_MOD_LINEAR) {
+               DRM_DEBUG_KMS("cursor cannot be tiled\n");
+               return -EINVAL;
+       }
+
+       ret = drm_atomic_helper_check_plane_state(&plane_state->base,
+                                                 &crtc_state->base,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 true, true);
+       if (ret)
+               return ret;
+
+       if (!plane_state->base.visible)
+               return 0;
+
+       ret = intel_plane_check_src_coordinates(plane_state);
+       if (ret)
+               return ret;
+
+       ret = intel_cursor_check_surface(plane_state);
+       if (ret)
+               return ret;
 
+       return 0;
+}
+
+static unsigned int
+i845_cursor_max_stride(struct intel_plane *plane,
+                      u32 pixel_format, u64 modifier,
+                      unsigned int rotation)
+{
+       return 2048;
+}
+
+static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
+                          const struct intel_plane_state *plane_state)
+{
        return CURSOR_ENABLE |
                CURSOR_GAMMA_ENABLE |
                CURSOR_FORMAT_ARGB |
-               CURSOR_STRIDE(fb->pitches[0]);
+               CURSOR_STRIDE(plane_state->color_plane[0].stride);
 }
 
 static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
@@ -9690,8 +9734,7 @@ static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
        return intel_cursor_size_ok(plane_state) && IS_ALIGNED(width, 64);
 }
 
-static int i845_check_cursor(struct intel_plane *plane,
-                            struct intel_crtc_state *crtc_state,
+static int i845_check_cursor(struct intel_crtc_state *crtc_state,
                             struct intel_plane_state *plane_state)
 {
        const struct drm_framebuffer *fb = plane_state->base.fb;
@@ -9713,6 +9756,9 @@ static int i845_check_cursor(struct intel_plane *plane,
                return -EINVAL;
        }
 
+       WARN_ON(plane_state->base.visible &&
+               plane_state->color_plane[0].stride != fb->pitches[0]);
+
        switch (fb->pitches[0]) {
        case 256:
        case 512:
@@ -9801,6 +9847,14 @@ static bool i845_cursor_get_hw_state(struct intel_plane *plane,
        return ret;
 }
 
+static unsigned int
+i9xx_cursor_max_stride(struct intel_plane *plane,
+                      u32 pixel_format, u64 modifier,
+                      unsigned int rotation)
+{
+       return plane->base.dev->mode_config.cursor_width * 4;
+}
+
 static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
                           const struct intel_plane_state *plane_state)
 {
@@ -9881,10 +9935,10 @@ static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state)
        return true;
 }
 
-static int i9xx_check_cursor(struct intel_plane *plane,
-                            struct intel_crtc_state *crtc_state,
+static int i9xx_check_cursor(struct intel_crtc_state *crtc_state,
                             struct intel_plane_state *plane_state)
 {
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
        const struct drm_framebuffer *fb = plane_state->base.fb;
        enum pipe pipe = plane->pipe;
@@ -9906,6 +9960,9 @@ static int i9xx_check_cursor(struct intel_plane *plane,
                return -EINVAL;
        }
 
+       WARN_ON(plane_state->base.visible &&
+               plane_state->color_plane[0].stride != fb->pitches[0]);
+
        if (fb->pitches[0] != plane_state->base.crtc_w * fb->format->cpp[0]) {
                DRM_DEBUG_KMS("Invalid cursor stride (%u) (cursor width %d)\n",
                              fb->pitches[0], plane_state->base.crtc_w);
@@ -10595,14 +10652,40 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat
                pipe_config->fb_bits |= plane->frontbuffer_bit;
 
        /*
+        * ILK/SNB DVSACNTR/Sprite Enable
+        * IVB SPR_CTL/Sprite Enable
+        * "When in Self Refresh Big FIFO mode, a write to enable the
+        *  plane will be internally buffered and delayed while Big FIFO
+        *  mode is exiting."
+        *
+        * Which means that enabling the sprite can take an extra frame
+        * when we start in big FIFO mode (LP1+). Thus we need to drop
+        * down to LP0 and wait for vblank in order to make sure the
+        * sprite gets enabled on the next vblank after the register write.
+        * Doing otherwise would risk enabling the sprite one frame after
+        * we've already signalled flip completion. We can resume LP1+
+        * once the sprite has been enabled.
+        *
+        *
         * WaCxSRDisabledForSpriteScaling:ivb
+        * IVB SPR_SCALE/Scaling Enable
+        * "Low Power watermarks must be disabled for at least one
+        *  frame before enabling sprite scaling, and kept disabled
+        *  until sprite scaling is disabled."
         *
-        * cstate->update_wm was already set above, so this flag will
-        * take effect when we commit and program watermarks.
+        * ILK/SNB DVSASCALE/Scaling Enable
+        * "When in Self Refresh Big FIFO mode, scaling enable will be
+        *  masked off while Big FIFO mode is exiting."
+        *
+        * Despite the w/a only being listed for IVB we assume that
+        * the ILK/SNB note has similar ramifications, hence we apply
+        * the w/a on all three platforms.
         */
-       if (plane->id == PLANE_SPRITE0 && IS_IVYBRIDGE(dev_priv) &&
-           needs_scaling(to_intel_plane_state(plane_state)) &&
-           !needs_scaling(old_plane_state))
+       if (plane->id == PLANE_SPRITE0 &&
+           (IS_GEN5(dev_priv) || IS_GEN6(dev_priv) ||
+            IS_IVYBRIDGE(dev_priv)) &&
+           (turn_on || (!needs_scaling(old_plane_state) &&
+                        needs_scaling(to_intel_plane_state(plane_state)))))
                pipe_config->disable_lp_wm = true;
 
        return 0;
@@ -10724,8 +10807,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
 }
 
 static const struct drm_crtc_helper_funcs intel_helper_funcs = {
-       .atomic_begin = intel_begin_crtc_commit,
-       .atomic_flush = intel_finish_crtc_commit,
        .atomic_check = intel_crtc_atomic_check,
 };
 
@@ -10882,6 +10963,20 @@ static void snprintf_output_types(char *buf, size_t len,
        WARN_ON_ONCE(output_types != 0);
 }
 
+static const char * const output_format_str[] = {
+       [INTEL_OUTPUT_FORMAT_INVALID] = "Invalid",
+       [INTEL_OUTPUT_FORMAT_RGB] = "RGB",
+       [INTEL_OUTPUT_FORMAT_YCBCR420] = "YCBCR4:2:0",
+       [INTEL_OUTPUT_FORMAT_YCBCR444] = "YCBCR4:4:4",
+};
+
+static const char *output_formats(enum intel_output_format format)
+{
+       if (format >= ARRAY_SIZE(output_format_str))
+               format = INTEL_OUTPUT_FORMAT_INVALID;
+       return output_format_str[format];
+}
+
 static void intel_dump_pipe_config(struct intel_crtc *crtc,
                                   struct intel_crtc_state *pipe_config,
                                   const char *context)
@@ -10901,6 +10996,9 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
        DRM_DEBUG_KMS("output_types: %s (0x%x)\n",
                      buf, pipe_config->output_types);
 
+       DRM_DEBUG_KMS("output format: %s\n",
+                     output_formats(pipe_config->output_format));
+
        DRM_DEBUG_KMS("cpu_transcoder: %s, pipe bpp: %i, dithering: %i\n",
                      transcoder_name(pipe_config->cpu_transcoder),
                      pipe_config->pipe_bpp, pipe_config->dither);
@@ -10910,9 +11008,6 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
                                      pipe_config->fdi_lanes,
                                      &pipe_config->fdi_m_n);
 
-       if (pipe_config->ycbcr420)
-               DRM_DEBUG_KMS("YCbCr 4:2:0 output enabled\n");
-
        if (intel_crtc_has_dp_encoder(pipe_config)) {
                intel_dump_m_n_config(pipe_config, "dp m_n",
                                pipe_config->lane_count, &pipe_config->dp_m_n);
@@ -11490,6 +11585,7 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
        PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vsync_end);
 
        PIPE_CONF_CHECK_I(pixel_multiplier);
+       PIPE_CONF_CHECK_I(output_format);
        PIPE_CONF_CHECK_BOOL(has_hdmi_sink);
        if ((INTEL_GEN(dev_priv) < 8 && !IS_HASWELL(dev_priv)) ||
            IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
@@ -11498,7 +11594,6 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
        PIPE_CONF_CHECK_BOOL(hdmi_scrambling);
        PIPE_CONF_CHECK_BOOL(hdmi_high_tmds_clock_ratio);
        PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_infoframe);
-       PIPE_CONF_CHECK_BOOL(ycbcr420);
 
        PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio);
 
@@ -12007,8 +12102,9 @@ intel_modeset_verify_disabled(struct drm_device *dev,
        verify_disabled_dpll_state(dev);
 }
 
-static void update_scanline_offset(struct intel_crtc *crtc)
+static void update_scanline_offset(const struct intel_crtc_state *crtc_state)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
        /*
@@ -12039,7 +12135,7 @@ static void update_scanline_offset(struct intel_crtc *crtc)
         * answer that's slightly in the future.
         */
        if (IS_GEN2(dev_priv)) {
-               const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+               const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
                int vtotal;
 
                vtotal = adjusted_mode->crtc_vtotal;
@@ -12048,7 +12144,7 @@ static void update_scanline_offset(struct intel_crtc *crtc)
 
                crtc->scanline_offset = vtotal - 1;
        } else if (HAS_DDI(dev_priv) &&
-                  intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI)) {
+                  intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
                crtc->scanline_offset = 2;
        } else
                crtc->scanline_offset = 1;
@@ -12394,6 +12490,7 @@ static void intel_update_crtc(struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_crtc_state *old_intel_cstate = to_intel_crtc_state(old_crtc_state);
        struct intel_crtc_state *pipe_config = to_intel_crtc_state(new_crtc_state);
        bool modeset = needs_modeset(new_crtc_state);
        struct intel_plane_state *new_plane_state =
@@ -12401,7 +12498,7 @@ static void intel_update_crtc(struct drm_crtc *crtc,
                                                 to_intel_plane(crtc->primary));
 
        if (modeset) {
-               update_scanline_offset(intel_crtc);
+               update_scanline_offset(pipe_config);
                dev_priv->display.crtc_enable(pipe_config, state);
 
                /* vblanks work again, re-enable pipe CRC. */
@@ -12414,7 +12511,12 @@ static void intel_update_crtc(struct drm_crtc *crtc,
        if (new_plane_state)
                intel_fbc_enable(intel_crtc, pipe_config, new_plane_state);
 
-       drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
+       intel_begin_crtc_commit(crtc, old_crtc_state);
+
+       intel_update_planes_on_crtc(to_intel_atomic_state(state), intel_crtc,
+                                   old_intel_cstate, pipe_config);
+
+       intel_finish_crtc_commit(crtc, old_crtc_state);
 }
 
 static void intel_update_crtcs(struct drm_atomic_state *state)
@@ -12575,8 +12677,9 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
        struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+       struct intel_crtc_state *new_intel_crtc_state, *old_intel_crtc_state;
        struct drm_crtc *crtc;
-       struct intel_crtc_state *intel_cstate;
+       struct intel_crtc *intel_crtc;
        u64 put_domains[I915_MAX_PIPES] = {};
        int i;
 
@@ -12588,24 +12691,25 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
 
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               old_intel_crtc_state = to_intel_crtc_state(old_crtc_state);
+               new_intel_crtc_state = to_intel_crtc_state(new_crtc_state);
+               intel_crtc = to_intel_crtc(crtc);
 
                if (needs_modeset(new_crtc_state) ||
                    to_intel_crtc_state(new_crtc_state)->update_pipe) {
 
-                       put_domains[to_intel_crtc(crtc)->pipe] =
+                       put_domains[intel_crtc->pipe] =
                                modeset_get_crtc_power_domains(crtc,
-                                       to_intel_crtc_state(new_crtc_state));
+                                       new_intel_crtc_state);
                }
 
                if (!needs_modeset(new_crtc_state))
                        continue;
 
-               intel_pre_plane_update(to_intel_crtc_state(old_crtc_state),
-                                      to_intel_crtc_state(new_crtc_state));
+               intel_pre_plane_update(old_intel_crtc_state, new_intel_crtc_state);
 
                if (old_crtc_state->active) {
-                       intel_crtc_disable_planes(crtc, old_crtc_state->plane_mask);
+                       intel_crtc_disable_planes(intel_crtc, old_intel_crtc_state->active_planes);
 
                        /*
                         * We need to disable pipe CRC before disabling the pipe,
@@ -12613,10 +12717,10 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                         */
                        intel_crtc_disable_pipe_crc(intel_crtc);
 
-                       dev_priv->display.crtc_disable(to_intel_crtc_state(old_crtc_state), state);
+                       dev_priv->display.crtc_disable(old_intel_crtc_state, state);
                        intel_crtc->active = false;
                        intel_fbc_disable(intel_crtc);
-                       intel_disable_shared_dpll(intel_crtc);
+                       intel_disable_shared_dpll(old_intel_crtc_state);
 
                        /*
                         * Underruns don't always raise
@@ -12634,7 +12738,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                                 */
                                if (INTEL_GEN(dev_priv) >= 9)
                                        dev_priv->display.initial_watermarks(intel_state,
-                                                                            to_intel_crtc_state(new_crtc_state));
+                                                                            new_intel_crtc_state);
                        }
                }
        }
@@ -12694,11 +12798,11 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
         * TODO: Move this (and other cleanup) to an async worker eventually.
         */
        for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
-               intel_cstate = to_intel_crtc_state(new_crtc_state);
+               new_intel_crtc_state = to_intel_crtc_state(new_crtc_state);
 
                if (dev_priv->display.optimize_watermarks)
                        dev_priv->display.optimize_watermarks(intel_state,
-                                                             intel_cstate);
+                                                             new_intel_crtc_state);
        }
 
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
@@ -12738,7 +12842,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
         * down.
         */
        INIT_WORK(&state->commit_work, intel_atomic_cleanup_work);
-       schedule_work(&state->commit_work);
+       queue_work(system_highpri_wq, &state->commit_work);
 }
 
 static void intel_atomic_commit_work(struct work_struct *work)
@@ -12895,6 +12999,8 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
        .atomic_duplicate_state = intel_crtc_duplicate_state,
        .atomic_destroy_state = intel_crtc_destroy_state,
        .set_crc_source = intel_crtc_set_crc_source,
+       .verify_crc_source = intel_crtc_verify_crc_source,
+       .get_crc_sources = intel_crtc_get_crc_sources,
 };
 
 struct wait_rps_boost {
@@ -12966,12 +13072,15 @@ static int intel_plane_pin_fb(struct intel_plane_state *plane_state)
            INTEL_INFO(dev_priv)->cursor_needs_physical) {
                struct drm_i915_gem_object *obj = intel_fb_obj(fb);
                const int align = intel_cursor_alignment(dev_priv);
+               int err;
 
-               return i915_gem_object_attach_phys(obj, align);
+               err = i915_gem_object_attach_phys(obj, align);
+               if (err)
+                       return err;
        }
 
        vma = intel_pin_and_fence_fb_obj(fb,
-                                        plane_state->base.rotation,
+                                        &plane_state->view,
                                         intel_plane_uses_fence(plane_state),
                                         &plane_state->flags);
        if (IS_ERR(vma))
@@ -13076,13 +13185,12 @@ intel_prepare_plane_fb(struct drm_plane *plane,
 
        ret = intel_plane_pin_fb(to_intel_plane_state(new_state));
 
-       fb_obj_bump_render_priority(obj);
-
        mutex_unlock(&dev_priv->drm.struct_mutex);
        i915_gem_object_unpin_pages(obj);
        if (ret)
                return ret;
 
+       fb_obj_bump_render_priority(obj);
        intel_fb_obj_flush(obj, ORIGIN_DIRTYFB);
 
        if (!new_state->fence) { /* implicit fencing */
@@ -13149,19 +13257,17 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
 }
 
 int
-skl_max_scale(struct intel_crtc *intel_crtc,
-             struct intel_crtc_state *crtc_state,
-             uint32_t pixel_format)
+skl_max_scale(const struct intel_crtc_state *crtc_state,
+             u32 pixel_format)
 {
-       struct drm_i915_private *dev_priv;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        int max_scale, mult;
        int crtc_clock, max_dotclk, tmpclk1, tmpclk2;
 
-       if (!intel_crtc || !crtc_state->base.enable)
+       if (!crtc_state->base.enable)
                return DRM_PLANE_HELPER_NO_SCALING;
 
-       dev_priv = to_i915(intel_crtc->base.dev);
-
        crtc_clock = crtc_state->base.adjusted_mode.crtc_clock;
        max_dotclk = to_intel_atomic_state(crtc_state->base.state)->cdclk.logical.cdclk;
 
@@ -13185,61 +13291,6 @@ skl_max_scale(struct intel_crtc *intel_crtc,
        return max_scale;
 }
 
-static int
-intel_check_primary_plane(struct intel_plane *plane,
-                         struct intel_crtc_state *crtc_state,
-                         struct intel_plane_state *state)
-{
-       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-       struct drm_crtc *crtc = state->base.crtc;
-       int min_scale = DRM_PLANE_HELPER_NO_SCALING;
-       int max_scale = DRM_PLANE_HELPER_NO_SCALING;
-       bool can_position = false;
-       int ret;
-       uint32_t pixel_format = 0;
-
-       if (INTEL_GEN(dev_priv) >= 9) {
-               /* use scaler when colorkey is not required */
-               if (!state->ckey.flags) {
-                       min_scale = 1;
-                       if (state->base.fb)
-                               pixel_format = state->base.fb->format->format;
-                       max_scale = skl_max_scale(to_intel_crtc(crtc),
-                                                 crtc_state, pixel_format);
-               }
-               can_position = true;
-       }
-
-       ret = drm_atomic_helper_check_plane_state(&state->base,
-                                                 &crtc_state->base,
-                                                 min_scale, max_scale,
-                                                 can_position, true);
-       if (ret)
-               return ret;
-
-       if (!state->base.fb)
-               return 0;
-
-       if (INTEL_GEN(dev_priv) >= 9) {
-               ret = skl_check_plane_surface(crtc_state, state);
-               if (ret)
-                       return ret;
-
-               state->ctl = skl_plane_ctl(crtc_state, state);
-       } else {
-               ret = i9xx_check_plane_surface(state);
-               if (ret)
-                       return ret;
-
-               state->ctl = i9xx_plane_ctl(crtc_state, state);
-       }
-
-       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
-               state->color_ctl = glk_plane_color_ctl(crtc_state, state);
-
-       return 0;
-}
-
 static void intel_begin_crtc_commit(struct drm_crtc *crtc,
                                    struct drm_crtc_state *old_crtc_state)
 {
@@ -13270,7 +13321,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
        if (intel_cstate->update_pipe)
                intel_update_pipe_config(old_intel_cstate, intel_cstate);
        else if (INTEL_GEN(dev_priv) >= 9)
-               skl_detach_scalers(intel_crtc);
+               skl_detach_scalers(intel_cstate);
 
 out:
        if (dev_priv->display.atomic_update_watermarks)
@@ -13372,57 +13423,6 @@ static bool i965_plane_format_mod_supported(struct drm_plane *_plane,
        }
 }
 
-static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
-                                          u32 format, u64 modifier)
-{
-       struct intel_plane *plane = to_intel_plane(_plane);
-
-       switch (modifier) {
-       case DRM_FORMAT_MOD_LINEAR:
-       case I915_FORMAT_MOD_X_TILED:
-       case I915_FORMAT_MOD_Y_TILED:
-       case I915_FORMAT_MOD_Yf_TILED:
-               break;
-       case I915_FORMAT_MOD_Y_TILED_CCS:
-       case I915_FORMAT_MOD_Yf_TILED_CCS:
-               if (!plane->has_ccs)
-                       return false;
-               break;
-       default:
-               return false;
-       }
-
-       switch (format) {
-       case DRM_FORMAT_XRGB8888:
-       case DRM_FORMAT_XBGR8888:
-       case DRM_FORMAT_ARGB8888:
-       case DRM_FORMAT_ABGR8888:
-               if (modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
-                   modifier == I915_FORMAT_MOD_Y_TILED_CCS)
-                       return true;
-               /* fall through */
-       case DRM_FORMAT_RGB565:
-       case DRM_FORMAT_XRGB2101010:
-       case DRM_FORMAT_XBGR2101010:
-       case DRM_FORMAT_YUYV:
-       case DRM_FORMAT_YVYU:
-       case DRM_FORMAT_UYVY:
-       case DRM_FORMAT_VYUY:
-       case DRM_FORMAT_NV12:
-               if (modifier == I915_FORMAT_MOD_Yf_TILED)
-                       return true;
-               /* fall through */
-       case DRM_FORMAT_C8:
-               if (modifier == DRM_FORMAT_MOD_LINEAR ||
-                   modifier == I915_FORMAT_MOD_X_TILED ||
-                   modifier == I915_FORMAT_MOD_Y_TILED)
-                       return true;
-               /* fall through */
-       default:
-               return false;
-       }
-}
-
 static bool intel_cursor_format_mod_supported(struct drm_plane *_plane,
                                              u32 format, u64 modifier)
 {
@@ -13430,18 +13430,7 @@ static bool intel_cursor_format_mod_supported(struct drm_plane *_plane,
                format == DRM_FORMAT_ARGB8888;
 }
 
-static struct drm_plane_funcs skl_plane_funcs = {
-       .update_plane = drm_atomic_helper_update_plane,
-       .disable_plane = drm_atomic_helper_disable_plane,
-       .destroy = intel_plane_destroy,
-       .atomic_get_property = intel_plane_atomic_get_property,
-       .atomic_set_property = intel_plane_atomic_set_property,
-       .atomic_duplicate_state = intel_plane_duplicate_state,
-       .atomic_destroy_state = intel_plane_destroy_state,
-       .format_mod_supported = skl_plane_format_mod_supported,
-};
-
-static struct drm_plane_funcs i965_plane_funcs = {
+static const struct drm_plane_funcs i965_plane_funcs = {
        .update_plane = drm_atomic_helper_update_plane,
        .disable_plane = drm_atomic_helper_disable_plane,
        .destroy = intel_plane_destroy,
@@ -13452,7 +13441,7 @@ static struct drm_plane_funcs i965_plane_funcs = {
        .format_mod_supported = i965_plane_format_mod_supported,
 };
 
-static struct drm_plane_funcs i8xx_plane_funcs = {
+static const struct drm_plane_funcs i8xx_plane_funcs = {
        .update_plane = drm_atomic_helper_update_plane,
        .disable_plane = drm_atomic_helper_disable_plane,
        .destroy = intel_plane_destroy,
@@ -13478,14 +13467,16 @@ intel_legacy_cursor_update(struct drm_plane *plane,
        struct drm_plane_state *old_plane_state, *new_plane_state;
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_framebuffer *old_fb;
-       struct drm_crtc_state *crtc_state = crtc->state;
+       struct intel_crtc_state *crtc_state =
+               to_intel_crtc_state(crtc->state);
+       struct intel_crtc_state *new_crtc_state;
 
        /*
         * When crtc is inactive or there is a modeset pending,
         * wait for it to complete in the slowpath
         */
-       if (!crtc_state->active || needs_modeset(crtc_state) ||
-           to_intel_crtc_state(crtc_state)->update_pipe)
+       if (!crtc_state->base.active || needs_modeset(&crtc_state->base) ||
+           crtc_state->update_pipe)
                goto slow;
 
        old_plane_state = plane->state;
@@ -13515,6 +13506,12 @@ intel_legacy_cursor_update(struct drm_plane *plane,
        if (!new_plane_state)
                return -ENOMEM;
 
+       new_crtc_state = to_intel_crtc_state(intel_crtc_duplicate_state(crtc));
+       if (!new_crtc_state) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
        drm_atomic_set_fb_for_plane(new_plane_state, fb);
 
        new_plane_state->src_x = src_x;
@@ -13526,9 +13523,8 @@ intel_legacy_cursor_update(struct drm_plane *plane,
        new_plane_state->crtc_w = crtc_w;
        new_plane_state->crtc_h = crtc_h;
 
-       ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state),
-                                                 to_intel_crtc_state(crtc->state), /* FIXME need a new crtc state? */
-                                                 to_intel_plane_state(plane->state),
+       ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state,
+                                                 to_intel_plane_state(old_plane_state),
                                                  to_intel_plane_state(new_plane_state));
        if (ret)
                goto out_free;
@@ -13550,10 +13546,21 @@ intel_legacy_cursor_update(struct drm_plane *plane,
        /* Swap plane state */
        plane->state = new_plane_state;
 
+       /*
+        * We cannot swap crtc_state as it may be in use by an atomic commit or
+        * page flip that's running simultaneously. If we swap crtc_state and
+        * destroy the old state, we will cause a use-after-free there.
+        *
+        * Only update active_planes, which is needed for our internal
+        * bookkeeping. Either value will do the right thing when updating
+        * planes atomically. If the cursor was part of the atomic update then
+        * we would have taken the slowpath.
+        */
+       crtc_state->active_planes = new_crtc_state->active_planes;
+
        if (plane->state->visible) {
                trace_intel_update_plane(plane, to_intel_crtc(crtc));
-               intel_plane->update_plane(intel_plane,
-                                         to_intel_crtc_state(crtc->state),
+               intel_plane->update_plane(intel_plane, crtc_state,
                                          to_intel_plane_state(plane->state));
        } else {
                trace_intel_disable_plane(plane, to_intel_crtc(crtc));
@@ -13565,6 +13572,8 @@ intel_legacy_cursor_update(struct drm_plane *plane,
 out_unlock:
        mutex_unlock(&dev_priv->drm.struct_mutex);
 out_free:
+       if (new_crtc_state)
+               intel_crtc_destroy_state(crtc, &new_crtc_state->base);
        if (ret)
                intel_plane_destroy_state(plane, new_plane_state);
        else
@@ -13605,178 +13614,90 @@ static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv,
                return i9xx_plane == PLANE_A;
 }
 
-static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv,
-                             enum pipe pipe, enum plane_id plane_id)
-{
-       if (!HAS_FBC(dev_priv))
-               return false;
-
-       return pipe == PIPE_A && plane_id == PLANE_PRIMARY;
-}
-
-bool skl_plane_has_planar(struct drm_i915_private *dev_priv,
-                         enum pipe pipe, enum plane_id plane_id)
-{
-       if (plane_id == PLANE_PRIMARY) {
-               if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv))
-                       return false;
-               else if ((INTEL_GEN(dev_priv) == 9 && pipe == PIPE_C) &&
-                        !IS_GEMINILAKE(dev_priv))
-                       return false;
-       } else if (plane_id >= PLANE_SPRITE0) {
-               if (plane_id == PLANE_CURSOR)
-                       return false;
-               if (IS_GEMINILAKE(dev_priv) || INTEL_GEN(dev_priv) == 10) {
-                       if (plane_id != PLANE_SPRITE0)
-                               return false;
-               } else {
-                       if (plane_id != PLANE_SPRITE0 || pipe == PIPE_C ||
-                           IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv))
-                               return false;
-               }
-       }
-       return true;
-}
-
 static struct intel_plane *
 intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
 {
-       struct intel_plane *primary = NULL;
-       struct intel_plane_state *state = NULL;
+       struct intel_plane *plane;
        const struct drm_plane_funcs *plane_funcs;
-       const uint32_t *intel_primary_formats;
        unsigned int supported_rotations;
-       unsigned int num_formats;
-       const uint64_t *modifiers;
+       unsigned int possible_crtcs;
+       const u64 *modifiers;
+       const u32 *formats;
+       int num_formats;
        int ret;
 
-       primary = kzalloc(sizeof(*primary), GFP_KERNEL);
-       if (!primary) {
-               ret = -ENOMEM;
-               goto fail;
-       }
-
-       state = intel_create_plane_state(&primary->base);
-       if (!state) {
-               ret = -ENOMEM;
-               goto fail;
-       }
+       if (INTEL_GEN(dev_priv) >= 9)
+               return skl_universal_plane_create(dev_priv, pipe,
+                                                 PLANE_PRIMARY);
 
-       primary->base.state = &state->base;
+       plane = intel_plane_alloc();
+       if (IS_ERR(plane))
+               return plane;
 
-       primary->can_scale = false;
-       primary->max_downscale = 1;
-       if (INTEL_GEN(dev_priv) >= 9) {
-               primary->can_scale = true;
-               state->scaler_id = -1;
-       }
-       primary->pipe = pipe;
+       plane->pipe = pipe;
        /*
         * 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.
         */
        if (HAS_FBC(dev_priv) && INTEL_GEN(dev_priv) < 4)
-               primary->i9xx_plane = (enum i9xx_plane_id) !pipe;
-       else
-               primary->i9xx_plane = (enum i9xx_plane_id) pipe;
-       primary->id = PLANE_PRIMARY;
-       primary->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, primary->id);
-
-       if (INTEL_GEN(dev_priv) >= 9)
-               primary->has_fbc = skl_plane_has_fbc(dev_priv,
-                                                    primary->pipe,
-                                                    primary->id);
+               plane->i9xx_plane = (enum i9xx_plane_id) !pipe;
        else
-               primary->has_fbc = i9xx_plane_has_fbc(dev_priv,
-                                                     primary->i9xx_plane);
+               plane->i9xx_plane = (enum i9xx_plane_id) pipe;
+       plane->id = PLANE_PRIMARY;
+       plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
 
-       if (primary->has_fbc) {
+       plane->has_fbc = i9xx_plane_has_fbc(dev_priv, plane->i9xx_plane);
+       if (plane->has_fbc) {
                struct intel_fbc *fbc = &dev_priv->fbc;
 
-               fbc->possible_framebuffer_bits |= primary->frontbuffer_bit;
+               fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
        }
 
-       primary->check_plane = intel_check_primary_plane;
-
-       if (INTEL_GEN(dev_priv) >= 9) {
-               primary->has_ccs = skl_plane_has_ccs(dev_priv, pipe,
-                                                    PLANE_PRIMARY);
-
-               if (skl_plane_has_planar(dev_priv, pipe, PLANE_PRIMARY)) {
-                       intel_primary_formats = skl_pri_planar_formats;
-                       num_formats = ARRAY_SIZE(skl_pri_planar_formats);
-               } else {
-                       intel_primary_formats = skl_primary_formats;
-                       num_formats = ARRAY_SIZE(skl_primary_formats);
-               }
-
-               if (primary->has_ccs)
-                       modifiers = skl_format_modifiers_ccs;
-               else
-                       modifiers = skl_format_modifiers_noccs;
-
-               primary->update_plane = skl_update_plane;
-               primary->disable_plane = skl_disable_plane;
-               primary->get_hw_state = skl_plane_get_hw_state;
-
-               plane_funcs = &skl_plane_funcs;
-       } else if (INTEL_GEN(dev_priv) >= 4) {
-               intel_primary_formats = i965_primary_formats;
+       if (INTEL_GEN(dev_priv) >= 4) {
+               formats = i965_primary_formats;
                num_formats = ARRAY_SIZE(i965_primary_formats);
                modifiers = i9xx_format_modifiers;
 
-               primary->update_plane = i9xx_update_plane;
-               primary->disable_plane = i9xx_disable_plane;
-               primary->get_hw_state = i9xx_plane_get_hw_state;
+               plane->max_stride = i9xx_plane_max_stride;
+               plane->update_plane = i9xx_update_plane;
+               plane->disable_plane = i9xx_disable_plane;
+               plane->get_hw_state = i9xx_plane_get_hw_state;
+               plane->check_plane = i9xx_plane_check;
 
                plane_funcs = &i965_plane_funcs;
        } else {
-               intel_primary_formats = i8xx_primary_formats;
+               formats = i8xx_primary_formats;
                num_formats = ARRAY_SIZE(i8xx_primary_formats);
                modifiers = i9xx_format_modifiers;
 
-               primary->update_plane = i9xx_update_plane;
-               primary->disable_plane = i9xx_disable_plane;
-               primary->get_hw_state = i9xx_plane_get_hw_state;
+               plane->max_stride = i9xx_plane_max_stride;
+               plane->update_plane = i9xx_update_plane;
+               plane->disable_plane = i9xx_disable_plane;
+               plane->get_hw_state = i9xx_plane_get_hw_state;
+               plane->check_plane = i9xx_plane_check;
 
                plane_funcs = &i8xx_plane_funcs;
        }
 
-       if (INTEL_GEN(dev_priv) >= 9)
-               ret = drm_universal_plane_init(&dev_priv->drm, &primary->base,
-                                              0, plane_funcs,
-                                              intel_primary_formats, num_formats,
-                                              modifiers,
-                                              DRM_PLANE_TYPE_PRIMARY,
-                                              "plane 1%c", pipe_name(pipe));
-       else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
-               ret = drm_universal_plane_init(&dev_priv->drm, &primary->base,
-                                              0, plane_funcs,
-                                              intel_primary_formats, num_formats,
-                                              modifiers,
+       possible_crtcs = BIT(pipe);
+
+       if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
+               ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
+                                              possible_crtcs, plane_funcs,
+                                              formats, num_formats, modifiers,
                                               DRM_PLANE_TYPE_PRIMARY,
                                               "primary %c", pipe_name(pipe));
        else
-               ret = drm_universal_plane_init(&dev_priv->drm, &primary->base,
-                                              0, plane_funcs,
-                                              intel_primary_formats, num_formats,
-                                              modifiers,
+               ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
+                                              possible_crtcs, plane_funcs,
+                                              formats, num_formats, modifiers,
                                               DRM_PLANE_TYPE_PRIMARY,
                                               "plane %c",
-                                              plane_name(primary->i9xx_plane));
+                                              plane_name(plane->i9xx_plane));
        if (ret)
                goto fail;
 
-       if (INTEL_GEN(dev_priv) >= 10) {
-               supported_rotations =
-                       DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
-                       DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 |
-                       DRM_MODE_REFLECT_X;
-       } else if (INTEL_GEN(dev_priv) >= 9) {
-               supported_rotations =
-                       DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
-                       DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
-       } else if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
+       if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
                supported_rotations =
                        DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
                        DRM_MODE_REFLECT_X;
@@ -13788,26 +13709,16 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
        }
 
        if (INTEL_GEN(dev_priv) >= 4)
-               drm_plane_create_rotation_property(&primary->base,
+               drm_plane_create_rotation_property(&plane->base,
                                                   DRM_MODE_ROTATE_0,
                                                   supported_rotations);
 
-       if (INTEL_GEN(dev_priv) >= 9)
-               drm_plane_create_color_properties(&primary->base,
-                                                 BIT(DRM_COLOR_YCBCR_BT601) |
-                                                 BIT(DRM_COLOR_YCBCR_BT709),
-                                                 BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
-                                                 BIT(DRM_COLOR_YCBCR_FULL_RANGE),
-                                                 DRM_COLOR_YCBCR_BT709,
-                                                 DRM_COLOR_YCBCR_LIMITED_RANGE);
-
-       drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);
+       drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
 
-       return primary;
+       return plane;
 
 fail:
-       kfree(state);
-       kfree(primary);
+       intel_plane_free(plane);
 
        return ERR_PTR(ret);
 }
@@ -13816,37 +13727,27 @@ static struct intel_plane *
 intel_cursor_plane_create(struct drm_i915_private *dev_priv,
                          enum pipe pipe)
 {
-       struct intel_plane *cursor = NULL;
-       struct intel_plane_state *state = NULL;
+       unsigned int possible_crtcs;
+       struct intel_plane *cursor;
        int ret;
 
-       cursor = kzalloc(sizeof(*cursor), GFP_KERNEL);
-       if (!cursor) {
-               ret = -ENOMEM;
-               goto fail;
-       }
-
-       state = intel_create_plane_state(&cursor->base);
-       if (!state) {
-               ret = -ENOMEM;
-               goto fail;
-       }
+       cursor = intel_plane_alloc();
+       if (IS_ERR(cursor))
+               return cursor;
 
-       cursor->base.state = &state->base;
-
-       cursor->can_scale = false;
-       cursor->max_downscale = 1;
        cursor->pipe = pipe;
        cursor->i9xx_plane = (enum i9xx_plane_id) pipe;
        cursor->id = PLANE_CURSOR;
        cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id);
 
        if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
+               cursor->max_stride = i845_cursor_max_stride;
                cursor->update_plane = i845_update_cursor;
                cursor->disable_plane = i845_disable_cursor;
                cursor->get_hw_state = i845_cursor_get_hw_state;
                cursor->check_plane = i845_check_cursor;
        } else {
+               cursor->max_stride = i9xx_cursor_max_stride;
                cursor->update_plane = i9xx_update_cursor;
                cursor->disable_plane = i9xx_disable_cursor;
                cursor->get_hw_state = i9xx_cursor_get_hw_state;
@@ -13859,8 +13760,10 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv,
        if (IS_I845G(dev_priv) || IS_I865G(dev_priv) || HAS_CUR_FBC(dev_priv))
                cursor->cursor.size = ~0;
 
+       possible_crtcs = BIT(pipe);
+
        ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base,
-                                      0, &intel_cursor_plane_funcs,
+                                      possible_crtcs, &intel_cursor_plane_funcs,
                                       intel_cursor_formats,
                                       ARRAY_SIZE(intel_cursor_formats),
                                       cursor_format_modifiers,
@@ -13875,16 +13778,12 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv,
                                                   DRM_MODE_ROTATE_0 |
                                                   DRM_MODE_ROTATE_180);
 
-       if (INTEL_GEN(dev_priv) >= 9)
-               state->scaler_id = -1;
-
        drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
 
        return cursor;
 
 fail:
-       kfree(state);
-       kfree(cursor);
+       intel_plane_free(cursor);
 
        return ERR_PTR(ret);
 }
@@ -13905,7 +13804,7 @@ static void intel_crtc_init_scalers(struct intel_crtc *crtc,
                struct intel_scaler *scaler = &scaler_state->scalers[i];
 
                scaler->in_use = 0;
-               scaler->mode = PS_SCALER_MODE_DYN;
+               scaler->mode = 0;
        }
 
        scaler_state->scaler_id = -1;
@@ -14128,6 +14027,9 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
 
        intel_pps_init(dev_priv);
 
+       if (INTEL_INFO(dev_priv)->num_pipes == 0)
+               return;
+
        /*
         * intel_edp_init_connector() depends on this completing first, to
         * prevent the registeration of both eDP and LVDS and the incorrect
@@ -14369,31 +14271,18 @@ static
 u32 intel_fb_pitch_limit(struct drm_i915_private *dev_priv,
                         uint64_t fb_modifier, uint32_t pixel_format)
 {
-       u32 gen = INTEL_GEN(dev_priv);
+       struct intel_crtc *crtc;
+       struct intel_plane *plane;
 
-       if (gen >= 9) {
-               int cpp = drm_format_plane_cpp(pixel_format, 0);
+       /*
+        * We assume the primary plane for pipe A has
+        * the highest stride limits of them all.
+        */
+       crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_A);
+       plane = to_intel_plane(crtc->base.primary);
 
-               /* "The stride in bytes must not exceed the of the size of 8K
-                *  pixels and 32K bytes."
-                */
-               return min(8192 * cpp, 32768);
-       } else if (gen >= 5 && !HAS_GMCH_DISPLAY(dev_priv)) {
-               return 32*1024;
-       } else if (gen >= 4) {
-               if (fb_modifier == I915_FORMAT_MOD_X_TILED)
-                       return 16*1024;
-               else
-                       return 32*1024;
-       } else if (gen >= 3) {
-               if (fb_modifier == I915_FORMAT_MOD_X_TILED)
-                       return 8*1024;
-               else
-                       return 16*1024;
-       } else {
-               /* XXX DSPC is limited to 4k tiled */
-               return 8*1024;
-       }
+       return plane->max_stride(plane, pixel_format, fb_modifier,
+                                DRM_MODE_ROTATE_0);
 }
 
 static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
@@ -14448,13 +14337,19 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
                        goto err;
                }
                /* fall through */
-       case I915_FORMAT_MOD_Y_TILED:
        case I915_FORMAT_MOD_Yf_TILED:
+               if (mode_cmd->pixel_format == DRM_FORMAT_C8) {
+                       DRM_DEBUG_KMS("Indexed format does not support Yf tiling\n");
+                       goto err;
+               }
+               /* fall through */
+       case I915_FORMAT_MOD_Y_TILED:
                if (INTEL_GEN(dev_priv) < 9) {
                        DRM_DEBUG_KMS("Unsupported tiling 0x%llx!\n",
                                      mode_cmd->modifier[0]);
                        goto err;
                }
+               break;
        case DRM_FORMAT_MOD_LINEAR:
        case I915_FORMAT_MOD_X_TILED:
                break;
@@ -14544,7 +14439,7 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
                break;
        case DRM_FORMAT_NV12:
                if (INTEL_GEN(dev_priv) < 9 || IS_SKYLAKE(dev_priv) ||
-                   IS_BROXTON(dev_priv)) {
+                   IS_BROXTON(dev_priv) || INTEL_GEN(dev_priv) >= 11) {
                        DRM_DEBUG_KMS("unsupported pixel format: %s\n",
                                      drm_get_format_name(mode_cmd->pixel_format,
                                                          &format_name));
@@ -14591,8 +14486,7 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
                 * potential runtime errors at plane configuration time.
                 */
                if (IS_GEN9(dev_priv) && i == 0 && fb->width > 3840 &&
-                   (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
-                    fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS))
+                   is_ccs_modifier(fb->modifier))
                        stride_alignment *= 4;
 
                if (fb->pitches[i] & (stride_alignment - 1)) {
@@ -15128,12 +15022,61 @@ static void intel_update_fdi_pll_freq(struct drm_i915_private *dev_priv)
        DRM_DEBUG_DRIVER("FDI PLL freq=%d\n", dev_priv->fdi_pll_freq);
 }
 
+static int intel_initial_commit(struct drm_device *dev)
+{
+       struct drm_atomic_state *state = NULL;
+       struct drm_modeset_acquire_ctx ctx;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *crtc_state;
+       int ret = 0;
+
+       state = drm_atomic_state_alloc(dev);
+       if (!state)
+               return -ENOMEM;
+
+       drm_modeset_acquire_init(&ctx, 0);
+
+retry:
+       state->acquire_ctx = &ctx;
+
+       drm_for_each_crtc(crtc, dev) {
+               crtc_state = drm_atomic_get_crtc_state(state, crtc);
+               if (IS_ERR(crtc_state)) {
+                       ret = PTR_ERR(crtc_state);
+                       goto out;
+               }
+
+               if (crtc_state->active) {
+                       ret = drm_atomic_add_affected_planes(state, crtc);
+                       if (ret)
+                               goto out;
+               }
+       }
+
+       ret = drm_atomic_commit(state);
+
+out:
+       if (ret == -EDEADLK) {
+               drm_atomic_state_clear(state);
+               drm_modeset_backoff(&ctx);
+               goto retry;
+       }
+
+       drm_atomic_state_put(state);
+
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+
+       return ret;
+}
+
 int intel_modeset_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
        enum pipe pipe;
        struct intel_crtc *crtc;
+       int ret;
 
        dev_priv->modeset_wq = alloc_ordered_workqueue("i915_modeset", 0);
 
@@ -15157,9 +15100,6 @@ int intel_modeset_init(struct drm_device *dev)
 
        intel_init_pm(dev_priv);
 
-       if (INTEL_INFO(dev_priv)->num_pipes == 0)
-               return 0;
-
        /*
         * There may be no VBT; and if the BIOS enabled SSC we can
         * just keep using it to avoid unnecessary flicker.  Whereas if the
@@ -15208,8 +15148,6 @@ int intel_modeset_init(struct drm_device *dev)
                      INTEL_INFO(dev_priv)->num_pipes > 1 ? "s" : "");
 
        for_each_pipe(dev_priv, pipe) {
-               int ret;
-
                ret = intel_crtc_init(dev_priv, pipe);
                if (ret) {
                        drm_mode_config_cleanup(dev);
@@ -15265,6 +15203,16 @@ int intel_modeset_init(struct drm_device *dev)
        if (!HAS_GMCH_DISPLAY(dev_priv))
                sanitize_watermarks(dev);
 
+       /*
+        * Force all active planes to recompute their states. So that on
+        * mode_setcrtc after probe, all the intel_plane_state variables
+        * are already calculated and there is no assert_plane warnings
+        * during bootup.
+        */
+       ret = intel_initial_commit(dev);
+       if (ret)
+               DRM_DEBUG_KMS("Initial commit in probe failed.\n");
+
        return 0;
 }
 
@@ -15360,17 +15308,6 @@ void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
        POSTING_READ(DPLL(pipe));
 }
 
-static bool intel_plane_mapping_ok(struct intel_crtc *crtc,
-                                  struct intel_plane *plane)
-{
-       enum pipe pipe;
-
-       if (!plane->get_hw_state(plane, &pipe))
-               return true;
-
-       return pipe == crtc->pipe;
-}
-
 static void
 intel_sanitize_plane_mapping(struct drm_i915_private *dev_priv)
 {
@@ -15382,13 +15319,20 @@ intel_sanitize_plane_mapping(struct drm_i915_private *dev_priv)
        for_each_intel_crtc(&dev_priv->drm, crtc) {
                struct intel_plane *plane =
                        to_intel_plane(crtc->base.primary);
+               struct intel_crtc *plane_crtc;
+               enum pipe pipe;
+
+               if (!plane->get_hw_state(plane, &pipe))
+                       continue;
 
-               if (intel_plane_mapping_ok(crtc, plane))
+               if (pipe == crtc->pipe)
                        continue;
 
-               DRM_DEBUG_KMS("%s attached to the wrong pipe, disabling plane\n",
-                             plane->base.name);
-               intel_plane_disable_noatomic(crtc, plane);
+               DRM_DEBUG_KMS("[PLANE:%d:%s] attached to the wrong pipe, disabling plane\n",
+                             plane->base.base.id, plane->base.name);
+
+               plane_crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
+               intel_plane_disable_noatomic(plane_crtc, plane);
        }
 }
 
@@ -15426,7 +15370,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
+       struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
 
        /* Clear any frame start delays used for debugging left by the BIOS */
        if (crtc->active && !transcoder_is_dsi(cpu_transcoder)) {
@@ -15436,13 +15381,9 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc,
                           I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
        }
 
-       /* restore vblank interrupts to correct state */
-       drm_crtc_vblank_reset(&crtc->base);
-       if (crtc->active) {
+       if (crtc_state->base.active) {
                struct intel_plane *plane;
 
-               drm_crtc_vblank_on(&crtc->base);
-
                /* Disable everything but the primary plane */
                for_each_intel_plane_on_crtc(dev, crtc, plane) {
                        const struct intel_plane_state *plane_state =
@@ -15456,10 +15397,10 @@ 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 (crtc->active && !intel_crtc_has_encoders(crtc))
+       if (crtc_state->base.active && !intel_crtc_has_encoders(crtc))
                intel_crtc_disable_noatomic(&crtc->base, ctx);
 
-       if (crtc->active || HAS_GMCH_DISPLAY(dev_priv)) {
+       if (crtc_state->base.active || HAS_GMCH_DISPLAY(dev_priv)) {
                /*
                 * We start out with underrun reporting disabled to avoid races.
                 * For correct bookkeeping mark this on active crtcs.
@@ -15560,22 +15501,35 @@ void i915_redisable_vga(struct drm_i915_private *dev_priv)
 }
 
 /* FIXME read out full plane state for all planes */
-static void readout_plane_state(struct intel_crtc *crtc)
+static void readout_plane_state(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       struct intel_crtc_state *crtc_state =
-               to_intel_crtc_state(crtc->base.state);
        struct intel_plane *plane;
+       struct intel_crtc *crtc;
 
-       for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
+       for_each_intel_plane(&dev_priv->drm, plane) {
                struct intel_plane_state *plane_state =
                        to_intel_plane_state(plane->base.state);
-               enum pipe pipe;
+               struct intel_crtc_state *crtc_state;
+               enum pipe pipe = PIPE_A;
                bool visible;
 
                visible = plane->get_hw_state(plane, &pipe);
 
+               crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
+               crtc_state = to_intel_crtc_state(crtc->base.state);
+
                intel_set_plane_visible(crtc_state, plane_state, visible);
+
+               DRM_DEBUG_KMS("[PLANE:%d:%s] hw state readout: %s, pipe %c\n",
+                             plane->base.base.id, plane->base.name,
+                             enableddisabled(visible), pipe_name(pipe));
+       }
+
+       for_each_intel_crtc(&dev_priv->drm, crtc) {
+               struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+
+               fixup_active_planes(crtc_state);
        }
 }
 
@@ -15608,13 +15562,13 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                if (crtc_state->base.active)
                        dev_priv->active_crtcs |= 1 << crtc->pipe;
 
-               readout_plane_state(crtc);
-
                DRM_DEBUG_KMS("[CRTC:%d:%s] hw state readout: %s\n",
                              crtc->base.base.id, crtc->base.name,
                              enableddisabled(crtc_state->base.active));
        }
 
+       readout_plane_state(dev_priv);
+
        for (i = 0; i < dev_priv->num_shared_dpll; i++) {
                struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
 
@@ -15721,7 +15675,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
 
                        drm_calc_timestamping_constants(&crtc->base,
                                                        &crtc_state->base.adjusted_mode);
-                       update_scanline_offset(crtc);
+                       update_scanline_offset(crtc_state);
                }
 
                dev_priv->min_cdclk[crtc->pipe] = min_cdclk;
@@ -15784,26 +15738,35 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
                             struct drm_modeset_acquire_ctx *ctx)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
-       enum pipe pipe;
        struct intel_crtc *crtc;
        struct intel_encoder *encoder;
        int i;
 
+       intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+
        intel_early_display_was(dev_priv);
        intel_modeset_readout_hw_state(dev);
 
        /* HW state is read out, now we need to sanitize this mess. */
        get_encoder_power_domains(dev_priv);
 
-       intel_sanitize_plane_mapping(dev_priv);
+       /*
+        * intel_sanitize_plane_mapping() may need to do vblank
+        * waits, so we need vblank interrupts restored beforehand.
+        */
+       for_each_intel_crtc(&dev_priv->drm, crtc) {
+               drm_crtc_vblank_reset(&crtc->base);
 
-       for_each_intel_encoder(dev, encoder) {
-               intel_sanitize_encoder(encoder);
+               if (crtc->active)
+                       drm_crtc_vblank_on(&crtc->base);
        }
 
-       for_each_pipe(dev_priv, pipe) {
-               crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
+       intel_sanitize_plane_mapping(dev_priv);
 
+       for_each_intel_encoder(dev, encoder)
+               intel_sanitize_encoder(encoder);
+
+       for_each_intel_crtc(&dev_priv->drm, crtc) {
                intel_sanitize_crtc(crtc, ctx);
                intel_dump_pipe_config(crtc, crtc->config,
                                       "[setup_hw_state]");
@@ -15843,9 +15806,8 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
                if (WARN_ON(put_domains))
                        modeset_put_power_domains(dev_priv, put_domains);
        }
-       intel_display_set_init_power(dev_priv, false);
 
-       intel_power_domains_verify_state(dev_priv);
+       intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
 
        intel_fbc_init_pipe_state(dev_priv);
 }
@@ -15884,29 +15846,6 @@ void intel_display_resume(struct drm_device *dev)
                drm_atomic_state_put(state);
 }
 
-int intel_connector_register(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       int ret;
-
-       ret = intel_backlight_device_register(intel_connector);
-       if (ret)
-               goto err;
-
-       return 0;
-
-err:
-       return ret;
-}
-
-void intel_connector_unregister(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-
-       intel_backlight_device_unregister(intel_connector);
-       intel_panel_destroy_backlight(connector);
-}
-
 static void intel_hpd_poll_fini(struct drm_device *dev)
 {
        struct intel_connector *connector;
@@ -15934,8 +15873,6 @@ void intel_modeset_cleanup(struct drm_device *dev)
        flush_work(&dev_priv->atomic_helper.free_work);
        WARN_ON(!llist_empty(&dev_priv->atomic_helper.free_list));
 
-       intel_disable_gt_powersave(dev_priv);
-
        /*
         * Interrupts and polling as the first thing to avoid creating havoc.
         * Too much stuff here (turning of connectors, ...) would
@@ -15963,20 +15900,11 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        intel_cleanup_overlay(dev_priv);
 
-       intel_cleanup_gt_powersave(dev_priv);
-
        intel_teardown_gmbus(dev_priv);
 
        destroy_workqueue(dev_priv->modeset_wq);
 }
 
-void intel_connector_attach_encoder(struct intel_connector *connector,
-                                   struct intel_encoder *encoder)
-{
-       connector->encoder = encoder;
-       drm_connector_attach_encoder(&connector->base, &encoder->base);
-}
-
 /*
  * set vga decode state - true == enable VGA decode
  */
@@ -16072,8 +16000,7 @@ intel_display_capture_error_state(struct drm_i915_private *dev_priv)
                return NULL;
 
        if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
-               error->power_well_driver =
-                       I915_READ(HSW_PWR_WELL_CTL_DRIVER(HSW_DISP_PW_GLOBAL));
+               error->power_well_driver = I915_READ(HSW_PWR_WELL_CTL2);
 
        for_each_pipe(dev_priv, i) {
                error->pipe[i].power_domain_on =