drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
                intel_plane = to_intel_plane(plane);
                if (intel_plane->pipe == pipe)
-                       intel_plane_disable(&intel_plane->base);
+                       plane->funcs->disable_plane(plane);
        }
 }
 
        BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
 }
 
-static int
-intel_primary_plane_disable(struct drm_plane *plane)
-{
-       struct drm_device *dev = plane->dev;
-       struct intel_crtc *intel_crtc;
-
-       if (!plane->fb)
-               return 0;
-
-       BUG_ON(!plane->crtc);
-
-       intel_crtc = to_intel_crtc(plane->crtc);
-
-       /*
-        * Even though we checked plane->fb above, it's still possible that
-        * the primary plane has been implicitly disabled because the crtc
-        * coordinates given weren't visible, or because we detected
-        * that it was 100% covered by a sprite plane.  Or, the CRTC may be
-        * off and we've set a fb, but haven't actually turned on the CRTC yet.
-        * In either case, we need to unpin the FB and let the fb pointer get
-        * updated, but otherwise we don't need to touch the hardware.
-        */
-       if (intel_crtc->primary_enabled) {
-               intel_crtc_wait_for_pending_flips(plane->crtc);
-               intel_disable_primary_hw_plane(plane, plane->crtc);
-       }
-
-       mutex_lock(&dev->struct_mutex);
-       i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
-                         INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe));
-       intel_unpin_fb_obj(intel_fb_obj(plane->fb));
-       mutex_unlock(&dev->struct_mutex);
-       plane->fb = NULL;
-
-       return 0;
-}
-
 /**
  * intel_prepare_plane_fb - Prepare fb for usage on plane
  * @plane: drm plane to prepare for
        struct drm_device *dev = plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       enum pipe pipe = intel_crtc->pipe;
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_rect *src = &state->src;
+       enum pipe pipe = intel_plane->pipe;
 
-       crtc->primary->fb = fb;
+       if (!fb) {
+               /*
+                * 'prepare' is never called when plane is being disabled, so
+                * we need to handle frontbuffer tracking here
+                */
+               mutex_lock(&dev->struct_mutex);
+               i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
+                                 INTEL_FRONTBUFFER_PRIMARY(pipe));
+               mutex_unlock(&dev->struct_mutex);
+       }
+
+       plane->fb = fb;
        crtc->x = src->x1 >> 16;
        crtc->y = src->y1 >> 16;
 
        return 0;
 }
 
+/**
+ * intel_disable_plane - disable a plane
+ * @plane: plane to disable
+ *
+ * General disable handler for all plane types.
+ */
+int
+intel_disable_plane(struct drm_plane *plane)
+{
+       if (!plane->fb)
+               return 0;
+
+       if (WARN_ON(!plane->crtc))
+               return -EINVAL;
+
+       return plane->funcs->update_plane(plane, plane->crtc, NULL,
+                                         0, 0, 0, 0, 0, 0, 0, 0);
+}
+
 /* Common destruction function for both primary and cursor planes */
 static void intel_plane_destroy(struct drm_plane *plane)
 {
 
 static const struct drm_plane_funcs intel_primary_plane_funcs = {
        .update_plane = intel_update_plane,
-       .disable_plane = intel_primary_plane_disable,
+       .disable_plane = intel_disable_plane,
        .destroy = intel_plane_destroy,
        .set_property = intel_plane_set_property
 };
        return &primary->base;
 }
 
-static int
-intel_cursor_plane_disable(struct drm_plane *plane)
-{
-       if (!plane->fb)
-               return 0;
-
-       BUG_ON(!plane->crtc);
-
-       return plane->funcs->update_plane(plane, plane->crtc, NULL,
-                                         0, 0, 0, 0, 0, 0, 0, 0);
-}
-
 static int
 intel_check_cursor_plane(struct drm_plane *plane,
                         struct intel_plane_state *state)
 
 static const struct drm_plane_funcs intel_cursor_plane_funcs = {
        .update_plane = intel_update_plane,
-       .disable_plane = intel_cursor_plane_disable,
+       .disable_plane = intel_disable_plane,
        .destroy = intel_plane_destroy,
        .set_property = intel_plane_set_property,
 };
 
        const struct drm_rect *clip = &state->clip;
        int hscale, vscale;
        int max_scale, min_scale;
-       int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+       int pixel_size;
+
+       if (!fb) {
+               state->visible = false;
+               return 0;
+       }
 
        /* Don't modify another pipe's plane */
        if (intel_plane->pipe != intel_crtc->pipe) {
                if (src_w < 3 || src_h < 3)
                        state->visible = false;
 
+               pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
                width_bytes = ((src_x * pixel_size) & 63) +
                                        src_w * pixel_size;
 
        const struct drm_rect *clip = &state->clip;
        bool primary_enabled;
 
+       /*
+        * 'prepare' is never called when plane is being disabled, so we need
+        * to handle frontbuffer tracking here
+        */
+       if (!fb) {
+               mutex_lock(&dev->struct_mutex);
+               i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
+                                 INTEL_FRONTBUFFER_SPRITE(pipe));
+               mutex_unlock(&dev->struct_mutex);
+       }
+
        /*
         * If the sprite is completely covering the primary plane,
         * we can disable the primary and save power.
        }
 }
 
-static int
-intel_disable_plane(struct drm_plane *plane)
-{
-       struct drm_device *dev = plane->dev;
-       struct intel_plane *intel_plane = to_intel_plane(plane);
-       struct intel_crtc *intel_crtc;
-       enum pipe pipe;
-
-       if (!plane->fb)
-               return 0;
-
-       if (WARN_ON(!plane->crtc))
-               return -EINVAL;
-
-       intel_crtc = to_intel_crtc(plane->crtc);
-       pipe = intel_crtc->pipe;
-
-       if (intel_crtc->active) {
-               bool primary_was_enabled = intel_crtc->primary_enabled;
-
-               intel_crtc->primary_enabled = true;
-
-               intel_plane->disable_plane(plane, plane->crtc);
-
-               if (!primary_was_enabled && intel_crtc->primary_enabled)
-                       intel_post_enable_primary(plane->crtc);
-       }
-
-       if (intel_plane->obj) {
-               if (intel_crtc->active)
-                       intel_wait_for_vblank(dev, intel_plane->pipe);
-
-               mutex_lock(&dev->struct_mutex);
-               intel_unpin_fb_obj(intel_plane->obj);
-               i915_gem_track_fb(intel_plane->obj, NULL,
-                                 INTEL_FRONTBUFFER_SPRITE(pipe));
-               mutex_unlock(&dev->struct_mutex);
-
-               intel_plane->obj = NULL;
-       }
-
-       return 0;
-}
-
 static void intel_destroy_plane(struct drm_plane *plane)
 {
        struct intel_plane *intel_plane = to_intel_plane(plane);
                                  intel_plane->src_w, intel_plane->src_h);
 }
 
-void intel_plane_disable(struct drm_plane *plane)
-{
-       if (!plane->crtc || !plane->fb)
-               return;
-
-       intel_disable_plane(plane);
-}
-
 static const struct drm_plane_funcs intel_plane_funcs = {
        .update_plane = intel_update_plane,
        .disable_plane = intel_disable_plane,