spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
+static void
+g4x_primary_async_flip(struct intel_plane *plane,
+                      const struct intel_crtc_state *crtc_state,
+                      const struct intel_plane_state *plane_state,
+                      bool async_flip)
+{
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       u32 dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);
+       u32 dspaddr_offset = plane_state->color_plane[0].offset;
+       enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
+       unsigned long irqflags;
+
+       if (async_flip)
+               dspcntr |= DISPPLANE_ASYNC_FLIP;
+
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+       intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
+       intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane),
+                         intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+static void
+bdw_primary_enable_flip_done(struct intel_plane *plane)
+{
+       struct drm_i915_private *i915 = to_i915(plane->base.dev);
+       enum pipe pipe = plane->pipe;
+
+       spin_lock_irq(&i915->irq_lock);
+       bdw_enable_pipe_irq(i915, pipe, GEN8_PIPE_PRIMARY_FLIP_DONE);
+       spin_unlock_irq(&i915->irq_lock);
+}
+
+static void
+bdw_primary_disable_flip_done(struct intel_plane *plane)
+{
+       struct drm_i915_private *i915 = to_i915(plane->base.dev);
+       enum pipe pipe = plane->pipe;
+
+       spin_lock_irq(&i915->irq_lock);
+       bdw_disable_pipe_irq(i915, pipe, GEN8_PIPE_PRIMARY_FLIP_DONE);
+       spin_unlock_irq(&i915->irq_lock);
+}
+
 static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
                                    enum pipe *pipe)
 {
        plane->get_hw_state = i9xx_plane_get_hw_state;
        plane->check_plane = i9xx_plane_check;
 
+       if (IS_BROADWELL(dev_priv)) {
+               plane->need_async_flip_disable_wa = true;
+               plane->async_flip = g4x_primary_async_flip;
+               plane->enable_flip_done = bdw_primary_enable_flip_done;
+               plane->disable_flip_done = bdw_primary_disable_flip_done;
+       }
+
        if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
                ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
                                               0, plane_funcs,
 
                return 0;
 }
 
+static bool has_async_flips(struct drm_i915_private *i915)
+{
+       return INTEL_GEN(i915) >= 9 || IS_BROADWELL(i915);
+}
+
 static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
                                         int color_plane)
 {
        case DRM_FORMAT_MOD_LINEAR:
                return intel_linear_alignment(dev_priv);
        case I915_FORMAT_MOD_X_TILED:
-               if (INTEL_GEN(dev_priv) >= 9)
+               if (has_async_flips(dev_priv))
                        return 256 * 1024;
                return 0;
        case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
 
        mode_config->funcs = &intel_mode_funcs;
 
-       if (INTEL_GEN(i915) >= 9)
-               mode_config->async_page_flip = true;
+       mode_config->async_page_flip = has_async_flips(i915);
 
        /*
         * Maximum framebuffer dimensions, chosen to match
 
        intel_uncore_write(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), tmp);
 }
 
+static u32 gen8_de_pipe_flip_done_mask(struct drm_i915_private *i915)
+{
+       if (INTEL_GEN(i915) >= 9)
+               return GEN9_PIPE_PLANE1_FLIP_DONE;
+       else
+               return GEN8_PIPE_PRIMARY_FLIP_DONE;
+}
+
 static irqreturn_t
 gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 {
                if (iir & GEN8_PIPE_VBLANK)
                        intel_handle_vblank(dev_priv, pipe);
 
-               if (iir & GEN9_PIPE_PLANE1_FLIP_DONE)
+               if (iir & gen8_de_pipe_flip_done_mask(dev_priv))
                        flip_done_handler(dev_priv, pipe);
 
                if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
                                     u8 pipe_mask)
 {
        struct intel_uncore *uncore = &dev_priv->uncore;
-
-       u32 extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN;
+       u32 extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN |
+               gen8_de_pipe_flip_done_mask(dev_priv);
        enum pipe pipe;
 
-       if (INTEL_GEN(dev_priv) >= 9)
-               extra_ier |= GEN9_PIPE_PLANE1_FLIP_DONE;
-
        spin_lock_irq(&dev_priv->irq_lock);
 
        if (!intel_irqs_enabled(dev_priv)) {
                        de_port_masked |= DSI0_TE | DSI1_TE;
        }
 
-       de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
-                                          GEN8_PIPE_FIFO_UNDERRUN;
-
-       if (INTEL_GEN(dev_priv) >= 9)
-               de_pipe_enables |= GEN9_PIPE_PLANE1_FLIP_DONE;
+       de_pipe_enables = de_pipe_masked |
+               GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN |
+               gen8_de_pipe_flip_done_mask(dev_priv);
 
        de_port_enables = de_port_masked;
        if (IS_GEN9_LP(dev_priv))
 
 #define   DISPPLANE_ROTATE_180                 (1 << 15)
 #define   DISPPLANE_TRICKLE_FEED_DISABLE       (1 << 14) /* Ironlake */
 #define   DISPPLANE_TILED                      (1 << 10)
+#define   DISPPLANE_ASYNC_FLIP                 (1 << 9) /* g4x+ */
 #define   DISPPLANE_MIRROR                     (1 << 8) /* CHV pipe B */
 #define _DSPAADDR                              0x70184
 #define _DSPASTRIDE                            0x70188