]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/i915/intel_display.c
Merge tag 'drm-intel-next-2017-05-29' of git://anongit.freedesktop.org/git/drm-intel...
[karo-tx-linux.git] / drivers / gpu / drm / i915 / intel_display.c
index 6a037b856d9672310a12f8652d4ed608fd93d59b..7fa21df5bcd78334ff507a305b5325d81469d91d 100644 (file)
@@ -1277,7 +1277,7 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
                I915_STATE_WARN(val & SPRITE_ENABLE,
                     "sprite %c assertion failure, should be off on pipe %c but is still active\n",
                     plane_name(pipe), pipe_name(pipe));
-       } else if (INTEL_GEN(dev_priv) >= 5) {
+       } else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) {
                u32 val = I915_READ(DVSCNTR(pipe));
                I915_STATE_WARN(val & DVS_ENABLE,
                     "sprite %c assertion failure, should be off on pipe %c but is still active\n",
@@ -2084,6 +2084,18 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view,
        }
 }
 
+static unsigned int intel_cursor_alignment(const struct drm_i915_private *dev_priv)
+{
+       if (IS_I830(dev_priv))
+               return 16 * 1024;
+       else if (IS_I85X(dev_priv))
+               return 256;
+       else if (IS_I845G(dev_priv) || IS_I865G(dev_priv))
+               return 32;
+       else
+               return 4 * 1024;
+}
+
 static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv)
 {
        if (INTEL_INFO(dev_priv)->gen >= 9)
@@ -2386,11 +2398,17 @@ u32 intel_compute_tile_offset(int *x, int *y,
                              const struct intel_plane_state *state,
                              int plane)
 {
-       const struct drm_i915_private *dev_priv = to_i915(state->base.plane->dev);
+       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);
-       u32 alignment = intel_surf_alignment(fb, plane);
+       u32 alignment;
+
+       if (intel_plane->id == PLANE_CURSOR)
+               alignment = intel_cursor_alignment(dev_priv);
+       else
+               alignment = intel_surf_alignment(fb, plane);
 
        return _intel_compute_tile_offset(dev_priv, x, y, fb, plane, pitch,
                                          rotation, alignment);
@@ -2750,7 +2768,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
                                false);
        intel_pre_disable_primary_noatomic(&intel_crtc->base);
        trace_intel_disable_plane(primary, intel_crtc);
-       intel_plane->disable_plane(primary, &intel_crtc->base);
+       intel_plane->disable_plane(intel_plane, intel_crtc);
 
        return;
 
@@ -2981,10 +2999,8 @@ static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
        if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
                dspcntr |= DISPPLANE_PIPE_CSC_ENABLE;
 
-       if (INTEL_GEN(dev_priv) < 4) {
-               if (crtc->pipe == PIPE_B)
-                       dspcntr |= DISPPLANE_SEL_PIPE_B;
-       }
+       if (INTEL_GEN(dev_priv) < 4)
+               dspcntr |= DISPPLANE_SEL_PIPE(crtc->pipe);
 
        switch (fb->format->format) {
        case DRM_FORMAT_C8:
@@ -3063,14 +3079,14 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
        return 0;
 }
 
-static void i9xx_update_primary_plane(struct drm_plane *primary,
+static void i9xx_update_primary_plane(struct intel_plane *primary,
                                      const struct intel_crtc_state *crtc_state,
                                      const struct intel_plane_state *plane_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(primary->dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct drm_framebuffer *fb = plane_state->base.fb;
-       int plane = intel_crtc->plane;
+       struct drm_i915_private *dev_priv = to_i915(primary->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       enum plane plane = primary->plane;
        u32 linear_offset;
        u32 dspcntr = plane_state->ctl;
        i915_reg_t reg = DSPCNTR(plane);
@@ -3081,12 +3097,12 @@ static void i9xx_update_primary_plane(struct drm_plane *primary,
        linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
 
        if (INTEL_GEN(dev_priv) >= 4)
-               intel_crtc->dspaddr_offset = plane_state->main.offset;
+               crtc->dspaddr_offset = plane_state->main.offset;
        else
-               intel_crtc->dspaddr_offset = linear_offset;
+               crtc->dspaddr_offset = linear_offset;
 
-       intel_crtc->adjusted_x = x;
-       intel_crtc->adjusted_y = y;
+       crtc->adjusted_x = x;
+       crtc->adjusted_y = y;
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
 
@@ -3112,31 +3128,29 @@ static void i9xx_update_primary_plane(struct drm_plane *primary,
        if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
                I915_WRITE_FW(DSPSURF(plane),
                              intel_plane_ggtt_offset(plane_state) +
-                             intel_crtc->dspaddr_offset);
+                             crtc->dspaddr_offset);
                I915_WRITE_FW(DSPOFFSET(plane), (y << 16) | x);
        } else if (INTEL_GEN(dev_priv) >= 4) {
                I915_WRITE_FW(DSPSURF(plane),
                              intel_plane_ggtt_offset(plane_state) +
-                             intel_crtc->dspaddr_offset);
+                             crtc->dspaddr_offset);
                I915_WRITE_FW(DSPTILEOFF(plane), (y << 16) | x);
                I915_WRITE_FW(DSPLINOFF(plane), linear_offset);
        } else {
                I915_WRITE_FW(DSPADDR(plane),
                              intel_plane_ggtt_offset(plane_state) +
-                             intel_crtc->dspaddr_offset);
+                             crtc->dspaddr_offset);
        }
        POSTING_READ_FW(reg);
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
-static void i9xx_disable_primary_plane(struct drm_plane *primary,
-                                      struct drm_crtc *crtc)
+static void i9xx_disable_primary_plane(struct intel_plane *primary,
+                                      struct intel_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);
-       int plane = intel_crtc->plane;
+       struct drm_i915_private *dev_priv = to_i915(primary->base.dev);
+       enum plane plane = primary->plane;
        unsigned long irqflags;
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
@@ -3321,16 +3335,15 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
        return plane_ctl;
 }
 
-static void skylake_update_primary_plane(struct drm_plane *plane,
+static void skylake_update_primary_plane(struct intel_plane *plane,
                                         const struct intel_crtc_state *crtc_state,
                                         const struct intel_plane_state *plane_state)
 {
-       struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct drm_framebuffer *fb = plane_state->base.fb;
-       enum plane_id plane_id = to_intel_plane(plane)->id;
-       enum pipe pipe = to_intel_plane(plane)->pipe;
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       enum plane_id plane_id = plane->id;
+       enum pipe pipe = plane->pipe;
        u32 plane_ctl = plane_state->ctl;
        unsigned int rotation = plane_state->base.rotation;
        u32 stride = skl_plane_stride(fb, 0, rotation);
@@ -3352,10 +3365,10 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
        dst_w--;
        dst_h--;
 
-       intel_crtc->dspaddr_offset = surf_addr;
+       crtc->dspaddr_offset = surf_addr;
 
-       intel_crtc->adjusted_x = src_x;
-       intel_crtc->adjusted_y = src_y;
+       crtc->adjusted_x = src_x;
+       crtc->adjusted_y = src_y;
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
 
@@ -3394,13 +3407,12 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
-static void skylake_disable_primary_plane(struct drm_plane *primary,
-                                         struct drm_crtc *crtc)
+static void skylake_disable_primary_plane(struct intel_plane *primary,
+                                         struct intel_crtc *crtc)
 {
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       enum plane_id plane_id = to_intel_plane(primary)->id;
-       enum pipe pipe = to_intel_plane(primary)->pipe;
+       struct drm_i915_private *dev_priv = to_i915(primary->base.dev);
+       enum plane_id plane_id = primary->id;
+       enum pipe pipe = primary->pipe;
        unsigned long irqflags;
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
@@ -3433,7 +3445,7 @@ static void intel_update_primary_planes(struct drm_device *dev)
                        trace_intel_update_plane(&plane->base,
                                                 to_intel_crtc(crtc));
 
-                       plane->update_plane(&plane->base,
+                       plane->update_plane(plane,
                                            to_intel_crtc_state(crtc->state),
                                            plane_state);
                }
@@ -4861,12 +4873,9 @@ static void intel_crtc_dpms_overlay_disable(struct intel_crtc *intel_crtc)
 {
        if (intel_crtc->overlay) {
                struct drm_device *dev = intel_crtc->base.dev;
-               struct drm_i915_private *dev_priv = to_i915(dev);
 
                mutex_lock(&dev->struct_mutex);
-               dev_priv->mm.interruptible = false;
                (void) intel_overlay_switch_off(intel_crtc->overlay);
-               dev_priv->mm.interruptible = true;
                mutex_unlock(&dev->struct_mutex);
        }
 
@@ -5086,7 +5095,7 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask
        intel_crtc_dpms_overlay_disable(intel_crtc);
 
        drm_for_each_plane_mask(p, dev, plane_mask)
-               to_intel_plane(p)->disable_plane(p, crtc);
+               to_intel_plane(p)->disable_plane(to_intel_plane(p), intel_crtc);
 
        /*
         * FIXME: Once we grow proper nuclear flip support out of this we need
@@ -5722,6 +5731,8 @@ static void i9xx_set_pll_dividers(struct intel_crtc *crtc)
 static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
                             struct drm_atomic_state *old_state)
 {
+       struct intel_atomic_state *old_intel_state =
+               to_intel_atomic_state(old_state);
        struct drm_crtc *crtc = pipe_config->base.crtc;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -5754,7 +5765,11 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
 
        intel_color_load_luts(&pipe_config->base);
 
-       intel_update_watermarks(intel_crtc);
+       if (dev_priv->display.initial_watermarks != NULL)
+               dev_priv->display.initial_watermarks(old_intel_state,
+                                                    intel_crtc->config);
+       else
+               intel_update_watermarks(intel_crtc);
        intel_enable_pipe(intel_crtc);
 
        assert_vblank_disabled(crtc);
@@ -5920,9 +5935,10 @@ void intel_encoder_destroy(struct drm_encoder *encoder)
 
 /* Cross check the actual hw state with our own modeset state tracking (and it's
  * internal consistency). */
-static void intel_connector_verify_state(struct intel_connector *connector)
+static void intel_connector_verify_state(struct drm_crtc_state *crtc_state,
+                                        struct drm_connector_state *conn_state)
 {
-       struct drm_crtc *crtc = connector->base.state->crtc;
+       struct intel_connector *connector = to_intel_connector(conn_state->connector);
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.base.id,
@@ -5930,15 +5946,14 @@ static void intel_connector_verify_state(struct intel_connector *connector)
 
        if (connector->get_hw_state(connector)) {
                struct intel_encoder *encoder = connector->encoder;
-               struct drm_connector_state *conn_state = connector->base.state;
 
-               I915_STATE_WARN(!crtc,
+               I915_STATE_WARN(!crtc_state,
                         "connector enabled without attached crtc\n");
 
-               if (!crtc)
+               if (!crtc_state)
                        return;
 
-               I915_STATE_WARN(!crtc->state->active,
+               I915_STATE_WARN(!crtc_state->active,
                      "connector is active, but attached crtc isn't\n");
 
                if (!encoder || encoder->type == INTEL_OUTPUT_DP_MST)
@@ -5950,9 +5965,9 @@ static void intel_connector_verify_state(struct intel_connector *connector)
                I915_STATE_WARN(conn_state->crtc != encoder->base.crtc,
                        "attached encoder crtc differs from connector crtc\n");
        } else {
-               I915_STATE_WARN(crtc && crtc->state->active,
+               I915_STATE_WARN(crtc_state && crtc_state->active,
                        "attached crtc is active, but connector isn't\n");
-               I915_STATE_WARN(!crtc && connector->base.state->best_encoder,
+               I915_STATE_WARN(!crtc_state && conn_state->best_encoder,
                        "best encoder set without crtc!\n");
        }
 }
@@ -6372,8 +6387,8 @@ static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, enum pipe
        vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val);
 
        reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13);
-       reg_val &= 0x8cffffff;
-       reg_val = 0x8c000000;
+       reg_val &= 0x00ffffff;
+       reg_val |= 0x8c000000;
        vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val);
 
        reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1));
@@ -8177,9 +8192,6 @@ static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct dpll reduced_clock;
-       bool has_reduced_clock = false;
-       struct intel_shared_dpll *pll;
        const struct intel_limit *limit;
        int refclk = 120000;
 
@@ -8221,20 +8233,14 @@ static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
                return -EINVAL;
        }
 
-       ironlake_compute_dpll(crtc, crtc_state,
-                             has_reduced_clock ? &reduced_clock : NULL);
+       ironlake_compute_dpll(crtc, crtc_state, NULL);
 
-       pll = intel_get_shared_dpll(crtc, crtc_state, NULL);
-       if (pll == 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));
                return -EINVAL;
        }
 
-       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
-           has_reduced_clock)
-               crtc->lowfreq_avail = true;
-
        return 0;
 }
 
@@ -9138,38 +9144,171 @@ out:
        return active;
 }
 
+static u32 intel_cursor_base(const 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;
+       const struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       u32 base;
+
+       if (INTEL_INFO(dev_priv)->cursor_needs_physical)
+               base = obj->phys_handle->busaddr;
+       else
+               base = intel_plane_ggtt_offset(plane_state);
+
+       base += plane_state->main.offset;
+
+       /* ILK+ do this automagically */
+       if (HAS_GMCH_DISPLAY(dev_priv) &&
+           plane_state->base.rotation & DRM_MODE_ROTATE_180)
+               base += (plane_state->base.crtc_h *
+                        plane_state->base.crtc_w - 1) * fb->format->cpp[0];
+
+       return base;
+}
+
+static u32 intel_cursor_position(const struct intel_plane_state *plane_state)
+{
+       int x = plane_state->base.crtc_x;
+       int y = plane_state->base.crtc_y;
+       u32 pos = 0;
+
+       if (x < 0) {
+               pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
+               x = -x;
+       }
+       pos |= x << CURSOR_X_SHIFT;
+
+       if (y < 0) {
+               pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
+               y = -y;
+       }
+       pos |= y << CURSOR_Y_SHIFT;
+
+       return pos;
+}
+
+static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state)
+{
+       const struct drm_mode_config *config =
+               &plane_state->base.plane->dev->mode_config;
+       int width = plane_state->base.crtc_w;
+       int height = plane_state->base.crtc_h;
+
+       return width > 0 && width <= config->cursor_width &&
+               height > 0 && height <= config->cursor_height;
+}
+
+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 src_x, src_y;
+       u32 offset;
+       int ret;
+
+       ret = drm_plane_helper_check_state(&plane_state->base,
+                                          &plane_state->clip,
+                                          DRM_PLANE_HELPER_NO_SCALING,
+                                          DRM_PLANE_HELPER_NO_SCALING,
+                                          true, true);
+       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);
+
+       if (src_x != 0 || src_y != 0) {
+               DRM_DEBUG_KMS("Arbitrary cursor panning not supported\n");
+               return -EINVAL;
+       }
+
+       plane_state->main.offset = offset;
+
+       return 0;
+}
+
 static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
                           const struct intel_plane_state *plane_state)
 {
-       unsigned int width = plane_state->base.crtc_w;
-       unsigned int stride = roundup_pow_of_two(width) * 4;
+       const struct drm_framebuffer *fb = plane_state->base.fb;
 
-       switch (stride) {
-       default:
-               WARN_ONCE(1, "Invalid cursor width/stride, width=%u, stride=%u\n",
-                         width, stride);
-               stride = 256;
-               /* fallthrough */
+       return CURSOR_ENABLE |
+               CURSOR_GAMMA_ENABLE |
+               CURSOR_FORMAT_ARGB |
+               CURSOR_STRIDE(fb->pitches[0]);
+}
+
+static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
+{
+       int width = plane_state->base.crtc_w;
+
+       /*
+        * 845g/865g are only limited by the width of their cursors,
+        * the height is arbitrary up to the precision of the register.
+        */
+       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,
+                            struct intel_plane_state *plane_state)
+{
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       int ret;
+
+       ret = intel_check_cursor(crtc_state, plane_state);
+       if (ret)
+               return ret;
+
+       /* if we want to turn off the cursor ignore width and height */
+       if (!fb)
+               return 0;
+
+       /* Check for which cursor types we support */
+       if (!i845_cursor_size_ok(plane_state)) {
+               DRM_DEBUG("Cursor dimension %dx%d not supported\n",
+                         plane_state->base.crtc_w,
+                         plane_state->base.crtc_h);
+               return -EINVAL;
+       }
+
+       switch (fb->pitches[0]) {
        case 256:
        case 512:
        case 1024:
        case 2048:
                break;
+       default:
+               DRM_DEBUG_KMS("Invalid cursor stride (%u)\n",
+                             fb->pitches[0]);
+               return -EINVAL;
        }
 
-       return CURSOR_ENABLE |
-               CURSOR_GAMMA_ENABLE |
-               CURSOR_FORMAT_ARGB |
-               CURSOR_STRIDE(stride);
+       plane_state->ctl = i845_cursor_ctl(crtc_state, plane_state);
+
+       return 0;
 }
 
-static void i845_update_cursor(struct drm_crtc *crtc, u32 base,
+static void i845_update_cursor(struct intel_plane *plane,
+                              const struct intel_crtc_state *crtc_state,
                               const struct intel_plane_state *plane_state)
 {
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       uint32_t cntl = 0, size = 0;
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       u32 cntl = 0, base = 0, pos = 0, size = 0;
+       unsigned long irqflags;
 
        if (plane_state && plane_state->base.visible) {
                unsigned int width = plane_state->base.crtc_w;
@@ -9177,35 +9316,41 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base,
 
                cntl = plane_state->ctl;
                size = (height << 12) | width;
-       }
 
-       if (intel_crtc->cursor_cntl != 0 &&
-           (intel_crtc->cursor_base != base ||
-            intel_crtc->cursor_size != size ||
-            intel_crtc->cursor_cntl != cntl)) {
-               /* On these chipsets we can only modify the base/size/stride
-                * whilst the cursor is disabled.
-                */
-               I915_WRITE_FW(CURCNTR(PIPE_A), 0);
-               POSTING_READ_FW(CURCNTR(PIPE_A));
-               intel_crtc->cursor_cntl = 0;
+               base = intel_cursor_base(plane_state);
+               pos = intel_cursor_position(plane_state);
        }
 
-       if (intel_crtc->cursor_base != base) {
-               I915_WRITE_FW(CURBASE(PIPE_A), base);
-               intel_crtc->cursor_base = base;
-       }
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
 
-       if (intel_crtc->cursor_size != size) {
+       /* On these chipsets we can only modify the base/size/stride
+        * whilst the cursor is disabled.
+        */
+       if (plane->cursor.base != base ||
+           plane->cursor.size != size ||
+           plane->cursor.cntl != cntl) {
+               I915_WRITE_FW(CURCNTR(PIPE_A), 0);
+               I915_WRITE_FW(CURBASE(PIPE_A), base);
                I915_WRITE_FW(CURSIZE, size);
-               intel_crtc->cursor_size = size;
-       }
-
-       if (intel_crtc->cursor_cntl != cntl) {
+               I915_WRITE_FW(CURPOS(PIPE_A), pos);
                I915_WRITE_FW(CURCNTR(PIPE_A), cntl);
-               POSTING_READ_FW(CURCNTR(PIPE_A));
-               intel_crtc->cursor_cntl = cntl;
+
+               plane->cursor.base = base;
+               plane->cursor.size = size;
+               plane->cursor.cntl = cntl;
+       } else {
+               I915_WRITE_FW(CURPOS(PIPE_A), pos);
        }
+
+       POSTING_READ_FW(CURCNTR(PIPE_A));
+
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+static void i845_disable_cursor(struct intel_plane *plane,
+                               struct intel_crtc *crtc)
+{
+       i845_update_cursor(plane, NULL, NULL);
 }
 
 static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
@@ -9214,7 +9359,6 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
        struct drm_i915_private *dev_priv =
                to_i915(plane_state->base.plane->dev);
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       enum pipe pipe = crtc->pipe;
        u32 cntl;
 
        cntl = MCURSOR_GAMMA_ENABLE;
@@ -9222,7 +9366,7 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
        if (HAS_DDI(dev_priv))
                cntl |= CURSOR_PIPE_CSC_ENABLE;
 
-       cntl |= pipe << 28; /* Connect to correct pipe */
+       cntl |= MCURSOR_PIPE_SELECT(crtc->pipe);
 
        switch (plane_state->base.crtc_w) {
        case 64:
@@ -9245,116 +9389,154 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
        return cntl;
 }
 
-static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base,
-                              const struct intel_plane_state *plane_state)
+static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state)
 {
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
-       uint32_t cntl = 0;
+       struct drm_i915_private *dev_priv =
+               to_i915(plane_state->base.plane->dev);
+       int width = plane_state->base.crtc_w;
+       int height = plane_state->base.crtc_h;
 
-       if (plane_state && plane_state->base.visible)
-               cntl = plane_state->ctl;
+       if (!intel_cursor_size_ok(plane_state))
+               return false;
 
-       if (intel_crtc->cursor_cntl != cntl) {
-               I915_WRITE_FW(CURCNTR(pipe), cntl);
-               POSTING_READ_FW(CURCNTR(pipe));
-               intel_crtc->cursor_cntl = cntl;
+       /* Cursor width is limited to a few power-of-two sizes */
+       switch (width) {
+       case 256:
+       case 128:
+       case 64:
+               break;
+       default:
+               return false;
        }
 
-       /* and commit changes on next vblank */
-       I915_WRITE_FW(CURBASE(pipe), base);
-       POSTING_READ_FW(CURBASE(pipe));
+       /*
+        * IVB+ have CUR_FBC_CTL which allows an arbitrary cursor
+        * height from 8 lines up to the cursor width, when the
+        * cursor is not rotated. Everything else requires square
+        * cursors.
+        */
+       if (HAS_CUR_FBC(dev_priv) &&
+           plane_state->base.rotation & DRM_MODE_ROTATE_0) {
+               if (height < 8 || height > width)
+                       return false;
+       } else {
+               if (height != width)
+                       return false;
+       }
 
-       intel_crtc->cursor_base = base;
+       return true;
 }
 
-/* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
-static void intel_crtc_update_cursor(struct drm_crtc *crtc,
-                                    const struct intel_plane_state *plane_state)
+static int i9xx_check_cursor(struct intel_plane *plane,
+                            struct intel_crtc_state *crtc_state,
+                            struct intel_plane_state *plane_state)
 {
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
-       u32 base = intel_crtc->cursor_addr;
-       unsigned long irqflags;
-       u32 pos = 0;
-
-       if (plane_state) {
-               int x = plane_state->base.crtc_x;
-               int y = plane_state->base.crtc_y;
+       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;
+       int ret;
 
-               if (x < 0) {
-                       pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
-                       x = -x;
-               }
-               pos |= x << CURSOR_X_SHIFT;
+       ret = intel_check_cursor(crtc_state, plane_state);
+       if (ret)
+               return ret;
 
-               if (y < 0) {
-                       pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
-                       y = -y;
-               }
-               pos |= y << CURSOR_Y_SHIFT;
+       /* if we want to turn off the cursor ignore width and height */
+       if (!fb)
+               return 0;
 
-               /* ILK+ do this automagically */
-               if (HAS_GMCH_DISPLAY(dev_priv) &&
-                   plane_state->base.rotation & DRM_MODE_ROTATE_180) {
-                       base += (plane_state->base.crtc_h *
-                                plane_state->base.crtc_w - 1) * 4;
-               }
+       /* Check for which cursor types we support */
+       if (!i9xx_cursor_size_ok(plane_state)) {
+               DRM_DEBUG("Cursor dimension %dx%d not supported\n",
+                         plane_state->base.crtc_w,
+                         plane_state->base.crtc_h);
+               return -EINVAL;
        }
 
-       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+       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);
+               return -EINVAL;
+       }
 
-       I915_WRITE_FW(CURPOS(pipe), pos);
+       /*
+        * There's something wrong with the cursor on CHV pipe C.
+        * If it straddles the left edge of the screen then
+        * moving it away from the edge or disabling it often
+        * results in a pipe underrun, and often that can lead to
+        * dead pipe (constant underrun reported, and it scans
+        * out just a solid color). To recover from that, the
+        * display power well must be turned off and on again.
+        * Refuse the put the cursor into that compromised position.
+        */
+       if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_C &&
+           plane_state->base.visible && plane_state->base.crtc_x < 0) {
+               DRM_DEBUG_KMS("CHV cursor C not allowed to straddle the left screen edge\n");
+               return -EINVAL;
+       }
 
-       if (IS_I845G(dev_priv) || IS_I865G(dev_priv))
-               i845_update_cursor(crtc, base, plane_state);
-       else
-               i9xx_update_cursor(crtc, base, plane_state);
+       plane_state->ctl = i9xx_cursor_ctl(crtc_state, plane_state);
 
-       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+       return 0;
 }
 
-static bool cursor_size_ok(struct drm_i915_private *dev_priv,
-                          uint32_t width, uint32_t height)
+static void i9xx_update_cursor(struct intel_plane *plane,
+                              const struct intel_crtc_state *crtc_state,
+                              const struct intel_plane_state *plane_state)
 {
-       if (width == 0 || height == 0)
-               return false;
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       enum pipe pipe = plane->pipe;
+       u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0;
+       unsigned long irqflags;
 
-       /*
-        * 845g/865g are special in that they are only limited by
-        * the width of their cursors, the height is arbitrary up to
-        * the precision of the register. Everything else requires
-        * square cursors, limited to a few power-of-two sizes.
-        */
-       if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
-               if ((width & 63) != 0)
-                       return false;
+       if (plane_state && plane_state->base.visible) {
+               cntl = plane_state->ctl;
 
-               if (width > (IS_I845G(dev_priv) ? 64 : 512))
-                       return false;
+               if (plane_state->base.crtc_h != plane_state->base.crtc_w)
+                       fbc_ctl = CUR_FBC_CTL_EN | (plane_state->base.crtc_h - 1);
 
-               if (height > 1023)
-                       return false;
+               base = intel_cursor_base(plane_state);
+               pos = intel_cursor_position(plane_state);
+       }
+
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+       /*
+        * On some platforms writing CURCNTR first will also
+        * cause CURPOS to be armed by the CURBASE write.
+        * Without the CURCNTR write the CURPOS write would
+        * arm itself.
+        *
+        * CURCNTR and CUR_FBC_CTL are always
+        * armed by the CURBASE write only.
+        */
+       if (plane->cursor.base != base ||
+           plane->cursor.size != fbc_ctl ||
+           plane->cursor.cntl != cntl) {
+               I915_WRITE_FW(CURCNTR(pipe), cntl);
+               if (HAS_CUR_FBC(dev_priv))
+                       I915_WRITE_FW(CUR_FBC_CTL(pipe), fbc_ctl);
+               I915_WRITE_FW(CURPOS(pipe), pos);
+               I915_WRITE_FW(CURBASE(pipe), base);
+
+               plane->cursor.base = base;
+               plane->cursor.size = fbc_ctl;
+               plane->cursor.cntl = cntl;
        } else {
-               switch (width | height) {
-               case 256:
-               case 128:
-                       if (IS_GEN2(dev_priv))
-                               return false;
-               case 64:
-                       break;
-               default:
-                       return false;
-               }
+               I915_WRITE_FW(CURPOS(pipe), pos);
        }
 
-       return true;
+       POSTING_READ_FW(CURBASE(pipe));
+
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+static void i9xx_disable_cursor(struct intel_plane *plane,
+                               struct intel_crtc *crtc)
+{
+       i9xx_update_cursor(plane, NULL, NULL);
 }
 
+
 /* VESA 640x480x72Hz mode to set on the pipe */
 static struct drm_display_mode load_detect_mode = {
        DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664,
@@ -9566,6 +9748,7 @@ int intel_get_load_detect_pipe(struct drm_connector *connector,
         */
        if (!crtc) {
                DRM_DEBUG_KMS("no pipe available for load-detect\n");
+               ret = -ENODEV;
                goto fail;
        }
 
@@ -9622,6 +9805,7 @@ found:
                DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
        if (IS_ERR(fb)) {
                DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
+               ret = PTR_ERR(fb);
                goto fail;
        }
 
@@ -10853,21 +11037,21 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
                         turn_off, turn_on, mode_changed);
 
        if (turn_on) {
-               if (INTEL_GEN(dev_priv) < 5)
+               if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
                        pipe_config->update_wm_pre = true;
 
                /* must disable cxsr around plane enable/disable */
                if (plane->id != PLANE_CURSOR)
                        pipe_config->disable_cxsr = true;
        } else if (turn_off) {
-               if (INTEL_GEN(dev_priv) < 5)
+               if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
                        pipe_config->update_wm_post = true;
 
                /* must disable cxsr around plane enable/disable */
                if (plane->id != PLANE_CURSOR)
                        pipe_config->disable_cxsr = true;
        } else if (intel_wm_need_update(&plane->base, plane_state)) {
-               if (INTEL_GEN(dev_priv) < 5) {
+               if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv)) {
                        /* FIXME bollocks */
                        pipe_config->update_wm_pre = true;
                        pipe_config->update_wm_post = true;
@@ -11291,7 +11475,8 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
        shared_dpll = crtc_state->shared_dpll;
        dpll_hw_state = crtc_state->dpll_hw_state;
        force_thru = crtc_state->pch_pfit.force_thru;
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+       if (IS_G4X(dev_priv) ||
+           IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
                wm_state = crtc_state->wm;
 
        /* Keep base drm_crtc_state intact, only clear our extended struct */
@@ -11303,7 +11488,8 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
        crtc_state->shared_dpll = shared_dpll;
        crtc_state->dpll_hw_state = dpll_hw_state;
        crtc_state->pch_pfit.force_thru = force_thru;
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+       if (IS_G4X(dev_priv) ||
+           IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
                crtc_state->wm = wm_state;
 }
 
@@ -11865,7 +12051,7 @@ static void verify_wm_state(struct drm_crtc *crtc,
         * allocation. In that case since the ddb allocation will be updated
         * once the plane becomes visible, we can skip this check
         */
-       if (intel_crtc->cursor_addr) {
+       if (1) {
                hw_plane_wm = &hw_wm.planes[PLANE_CURSOR];
                sw_plane_wm = &sw_wm->planes[PLANE_CURSOR];
 
@@ -11921,11 +12107,15 @@ verify_connector_state(struct drm_device *dev,
 
        for_each_new_connector_in_state(state, connector, new_conn_state, i) {
                struct drm_encoder *encoder = connector->encoder;
+               struct drm_crtc_state *crtc_state = NULL;
 
                if (new_conn_state->crtc != crtc)
                        continue;
 
-               intel_connector_verify_state(to_intel_connector(connector));
+               if (crtc)
+                       crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
+
+               intel_connector_verify_state(crtc_state, new_conn_state);
 
                I915_STATE_WARN(new_conn_state->best_encoder != encoder,
                     "connector's atomic encoder doesn't match legacy encoder\n");
@@ -12043,7 +12233,7 @@ verify_crtc_state(struct drm_crtc *crtc,
 
        intel_pipe_config_sanity_check(dev_priv, pipe_config);
 
-       sw_config = to_intel_crtc_state(crtc->state);
+       sw_config = to_intel_crtc_state(new_crtc_state);
        if (!intel_pipe_config_compare(dev_priv, sw_config,
                                       pipe_config, false)) {
                I915_STATE_WARN(1, "pipe state doesn't match!\n");
@@ -13139,7 +13329,7 @@ intel_prepare_plane_fb(struct drm_plane *plane,
        if (obj) {
                if (plane->type == DRM_PLANE_TYPE_CURSOR &&
                    INTEL_INFO(dev_priv)->cursor_needs_physical) {
-                       const int align = IS_I830(dev_priv) ? 16 * 1024 : 256;
+                       const int align = intel_cursor_alignment(dev_priv);
 
                        ret = i915_gem_object_attach_phys(obj, align);
                        if (ret) {
@@ -13269,11 +13459,11 @@ skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state
 }
 
 static int
-intel_check_primary_plane(struct drm_plane *plane,
+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->dev);
+       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;
@@ -13452,7 +13642,7 @@ intel_legacy_cursor_update(struct drm_plane *plane,
                goto out_free;
 
        if (INTEL_INFO(dev_priv)->cursor_needs_physical) {
-               int align = IS_I830(dev_priv) ? 16 * 1024 : 256;
+               int align = intel_cursor_alignment(dev_priv);
 
                ret = i915_gem_object_attach_phys(intel_fb_obj(fb), align);
                if (ret) {
@@ -13488,12 +13678,12 @@ intel_legacy_cursor_update(struct drm_plane *plane,
 
        if (plane->state->visible) {
                trace_intel_update_plane(plane, to_intel_crtc(crtc));
-               intel_plane->update_plane(plane,
+               intel_plane->update_plane(intel_plane,
                                          to_intel_crtc_state(crtc->state),
                                          to_intel_plane_state(plane->state));
        } else {
                trace_intel_disable_plane(plane, to_intel_crtc(crtc));
-               intel_plane->disable_plane(plane, crtc);
+               intel_plane->disable_plane(intel_plane, to_intel_crtc(crtc));
        }
 
        intel_cleanup_plane_fb(plane, new_plane_state);
@@ -13636,107 +13826,9 @@ fail:
        return ERR_PTR(ret);
 }
 
-static int
-intel_check_cursor_plane(struct drm_plane *plane,
-                        struct intel_crtc_state *crtc_state,
-                        struct intel_plane_state *state)
-{
-       struct drm_i915_private *dev_priv = to_i915(plane->dev);
-       struct drm_framebuffer *fb = state->base.fb;
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-       enum pipe pipe = to_intel_plane(plane)->pipe;
-       unsigned stride;
-       int ret;
-
-       ret = drm_plane_helper_check_state(&state->base,
-                                          &state->clip,
-                                          DRM_PLANE_HELPER_NO_SCALING,
-                                          DRM_PLANE_HELPER_NO_SCALING,
-                                          true, true);
-       if (ret)
-               return ret;
-
-       /* if we want to turn off the cursor ignore width and height */
-       if (!obj)
-               return 0;
-
-       /* Check for which cursor types we support */
-       if (!cursor_size_ok(dev_priv, state->base.crtc_w,
-                           state->base.crtc_h)) {
-               DRM_DEBUG("Cursor dimension %dx%d not supported\n",
-                         state->base.crtc_w, state->base.crtc_h);
-               return -EINVAL;
-       }
-
-       stride = roundup_pow_of_two(state->base.crtc_w) * 4;
-       if (obj->base.size < stride * state->base.crtc_h) {
-               DRM_DEBUG_KMS("buffer is too small\n");
-               return -ENOMEM;
-       }
-
-       if (fb->modifier != DRM_FORMAT_MOD_LINEAR) {
-               DRM_DEBUG_KMS("cursor cannot be tiled\n");
-               return -EINVAL;
-       }
-
-       /*
-        * There's something wrong with the cursor on CHV pipe C.
-        * If it straddles the left edge of the screen then
-        * moving it away from the edge or disabling it often
-        * results in a pipe underrun, and often that can lead to
-        * dead pipe (constant underrun reported, and it scans
-        * out just a solid color). To recover from that, the
-        * display power well must be turned off and on again.
-        * Refuse the put the cursor into that compromised position.
-        */
-       if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_C &&
-           state->base.visible && state->base.crtc_x < 0) {
-               DRM_DEBUG_KMS("CHV cursor C not allowed to straddle the left screen edge\n");
-               return -EINVAL;
-       }
-
-       if (IS_I845G(dev_priv) || IS_I865G(dev_priv))
-               state->ctl = i845_cursor_ctl(crtc_state, state);
-       else
-               state->ctl = i9xx_cursor_ctl(crtc_state, state);
-
-       return 0;
-}
-
-static void
-intel_disable_cursor_plane(struct drm_plane *plane,
-                          struct drm_crtc *crtc)
-{
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-       intel_crtc->cursor_addr = 0;
-       intel_crtc_update_cursor(crtc, NULL);
-}
-
-static void
-intel_update_cursor_plane(struct drm_plane *plane,
-                         const struct intel_crtc_state *crtc_state,
-                         const struct intel_plane_state *state)
-{
-       struct drm_crtc *crtc = crtc_state->base.crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct drm_i915_private *dev_priv = to_i915(plane->dev);
-       struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb);
-       uint32_t addr;
-
-       if (!obj)
-               addr = 0;
-       else if (!INTEL_INFO(dev_priv)->cursor_needs_physical)
-               addr = intel_plane_ggtt_offset(state);
-       else
-               addr = obj->phys_handle->busaddr;
-
-       intel_crtc->cursor_addr = addr;
-       intel_crtc_update_cursor(crtc, state);
-}
-
 static struct intel_plane *
-intel_cursor_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
+intel_cursor_plane_create(struct drm_i915_private *dev_priv,
+                         enum pipe pipe)
 {
        struct intel_plane *cursor = NULL;
        struct intel_plane_state *state = NULL;
@@ -13762,9 +13854,22 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
        cursor->plane = pipe;
        cursor->id = PLANE_CURSOR;
        cursor->frontbuffer_bit = INTEL_FRONTBUFFER_CURSOR(pipe);
-       cursor->check_plane = intel_check_cursor_plane;
-       cursor->update_plane = intel_update_cursor_plane;
-       cursor->disable_plane = intel_disable_cursor_plane;
+
+       if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
+               cursor->update_plane = i845_update_cursor;
+               cursor->disable_plane = i845_disable_cursor;
+               cursor->check_plane = i845_check_cursor;
+       } else {
+               cursor->update_plane = i9xx_update_cursor;
+               cursor->disable_plane = i9xx_disable_cursor;
+               cursor->check_plane = i9xx_check_cursor;
+       }
+
+       cursor->cursor.base = ~0;
+       cursor->cursor.cntl = ~0;
+
+       if (IS_I845G(dev_priv) || IS_I865G(dev_priv) || HAS_CUR_FBC(dev_priv))
+               cursor->cursor.size = ~0;
 
        ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base,
                                       0, &intel_cursor_plane_funcs,
@@ -13873,10 +13978,6 @@ static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
        intel_crtc->pipe = pipe;
        intel_crtc->plane = primary->plane;
 
-       intel_crtc->cursor_base = ~0;
-       intel_crtc->cursor_cntl = ~0;
-       intel_crtc->cursor_size = ~0;
-
        /* initialize shared scalers */
        intel_crtc_init_scalers(intel_crtc, crtc_state);
 
@@ -14416,7 +14517,7 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
        case DRM_FORMAT_UYVY:
        case DRM_FORMAT_YVYU:
        case DRM_FORMAT_VYUY:
-               if (INTEL_GEN(dev_priv) < 5) {
+               if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv)) {
                        DRM_DEBUG_KMS("unsupported pixel format: %s\n",
                                      drm_get_format_name(mode_cmd->pixel_format, &format_name));
                        goto err;
@@ -14928,6 +15029,7 @@ int intel_modeset_init(struct drm_device *dev)
 
        dev->mode_config.funcs = &intel_mode_funcs;
 
+       init_llist_head(&dev_priv->atomic_helper.free_list);
        INIT_WORK(&dev_priv->atomic_helper.free_work,
                  intel_atomic_helper_free_state_worker);
 
@@ -15149,7 +15251,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
                                continue;
 
                        trace_intel_disable_plane(&plane->base, crtc);
-                       plane->disable_plane(&plane->base, &crtc->base);
+                       plane->disable_plane(plane, crtc);
                }
        }
 
@@ -15520,7 +15622,10 @@ intel_modeset_setup_hw_state(struct drm_device *dev)
                pll->on = false;
        }
 
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+       if (IS_G4X(dev_priv)) {
+               g4x_wm_get_hw_state(dev);
+               g4x_wm_sanitize(dev_priv);
+       } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
                vlv_wm_get_hw_state(dev);
                vlv_wm_sanitize(dev_priv);
        } else if (IS_GEN9(dev_priv)) {
@@ -15554,13 +15659,6 @@ void intel_display_resume(struct drm_device *dev)
        if (state)
                state->acquire_ctx = &ctx;
 
-       /*
-        * This is a cludge because with real atomic modeset mode_config.mutex
-        * won't be taken. Unfortunately some probed state like
-        * audio_codec_enable is still protected by mode_config.mutex, so lock
-        * it here for now.
-        */
-       mutex_lock(&dev->mode_config.mutex);
        drm_modeset_acquire_init(&ctx, 0);
 
        while (1) {
@@ -15576,7 +15674,6 @@ void intel_display_resume(struct drm_device *dev)
 
        drm_modeset_drop_locks(&ctx);
        drm_modeset_acquire_fini(&ctx);
-       mutex_unlock(&dev->mode_config.mutex);
 
        if (ret)
                DRM_ERROR("Restoring old state failed with %i\n", ret);