]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'drm-intel-next-2015-01-17' of git://anongit.freedesktop.org/drm-intel...
authorDave Airlie <airlied@redhat.com>
Mon, 26 Jan 2015 23:01:09 +0000 (09:01 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 26 Jan 2015 23:01:09 +0000 (09:01 +1000)
- refactor i915/snd-hda interaction to use the component framework (Imre)
- psr cleanups and small fixes (Rodrigo)
- a few perf w/a from Ken Graunke
- switch to atomic plane helpers (Matt Roper)
- wc mmap support (Chris Wilson & Akash Goel)
- smaller things all over

* tag 'drm-intel-next-2015-01-17' of git://anongit.freedesktop.org/drm-intel: (40 commits)
  drm/i915: Update DRIVER_DATE to 20150117
  i915: reuse %ph to dump small buffers
  drm/i915: Ensure the HiZ RAW Stall Optimization is on for Cherryview.
  drm/i915: Enable the HiZ RAW Stall Optimization on Broadwell.
  drm/i915: PSR link standby at debugfs
  drm/i915: group link_standby setup and let this info visible everywhere.
  drm/i915: Add missing vbt check.
  drm/i915: PSR HSW/BDW: Fix inverted logic at sink main_link_active bit.
  drm/i915: PSR VLV/CHV: Remove condition checks that only applies to Haswell.
  drm/i915: VLV/CHV PSR needs to exit PSR on every flush.
  drm/i915: Fix kerneldoc for i915 atomic plane code
  drm/i915: Don't pretend SDVO hotplug works on 915
  drm/i915: Don't register HDMI connectors for eDP ports on VLV/CHV
  drm/i915: Remove I915_HAS_HOTPLUG() check from i915_hpd_irq_setup()
  drm/i915: Make hpd arrays big enough to avoid out of bounds access
  Revert "drm/i915/chv: Use timeout mode for RC6 on chv"
  drm/i915: Improve HiZ throughput on Cherryview.
  drm/i915: Reset CSB read pointer in ring init
  drm/i915: Drop unused position fields (v2)
  drm/i915: Move to atomic plane helpers (v9)
  ...

1  2 
Documentation/DocBook/drm.tmpl
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_pm.c

index 3b2571e8481928175e11eed36e77368ac10e21f8,10cffd95fd7e7348d9ccbbca80f4689a495b4bbc..77d045557daf48d6fa332f80e021bd00a74f9eb5
                Driver supports dedicated render nodes.
              </para></listitem>
            </varlistentry>
 +          <varlistentry>
 +            <term>DRIVER_ATOMIC</term>
 +            <listitem><para>
 +              Driver supports atomic properties.  In this case the driver
 +              must implement appropriate obj->atomic_get_property() vfuncs
 +              for any modeset objects with driver specific properties.
 +            </para></listitem>
 +          </varlistentry>
          </variablelist>
        </sect3>
        <sect3>
@@@ -1385,7 -1377,7 +1385,7 @@@ int max_width, max_height;</synopsis
        <itemizedlist>
          <listitem>
          DRM_PLANE_TYPE_PRIMARY represents a "main" plane for a CRTC.  Primary
 -        planes are the planes operated upon by by CRTC modesetting and flipping
 +        planes are the planes operated upon by CRTC modesetting and flipping
          operations described in <xref linkend="drm-kms-crtcops"/>.
          </listitem>
          <listitem>
@@@ -2370,7 -2362,6 +2370,7 @@@ void intel_crt_init(struct drm_device *
      </sect2>
      <sect2>
        <title>Modeset Helper Functions Reference</title>
 +!Iinclude/drm/drm_crtc_helper.h
  !Edrivers/gpu/drm/drm_crtc_helper.c
  !Pdrivers/gpu/drm/drm_crtc_helper.c overview
      </sect2>
        <td valign="top" >Description/Restrictions</td>
        </tr>
        <tr>
 -      <td rowspan="25" valign="top" >DRM</td>
 -      <td rowspan="4" valign="top" >Generic</td>
 +      <td rowspan="36" valign="top" >DRM</td>
 +      <td rowspan="5" valign="top" >Connector</td>
        <td valign="top" >“EDID”</td>
        <td valign="top" >BLOB | IMMUTABLE</td>
        <td valign="top" >0</td>
        <td valign="top" >Contains tiling information for a connector.</td>
        </tr>
        <tr>
 -      <td rowspan="1" valign="top" >Plane</td>
 +      <td valign="top" >“CRTC_ID”</td>
 +      <td valign="top" >OBJECT</td>
 +      <td valign="top" >DRM_MODE_OBJECT_CRTC</td>
 +      <td valign="top" >Connector</td>
 +      <td valign="top" >CRTC that connector is attached to (atomic)</td>
 +      </tr>
 +      <tr>
 +      <td rowspan="11" valign="top" >Plane</td>
        <td valign="top" >“type”</td>
        <td valign="top" >ENUM | IMMUTABLE</td>
        <td valign="top" >{ "Overlay", "Primary", "Cursor" }</td>
        <td valign="top" >Plane type</td>
        </tr>
        <tr>
 +      <td valign="top" >“SRC_X”</td>
 +      <td valign="top" >RANGE</td>
 +      <td valign="top" >Min=0, Max=UINT_MAX</td>
 +      <td valign="top" >Plane</td>
 +      <td valign="top" >Scanout source x coordinate in 16.16 fixed point (atomic)</td>
 +      </tr>
 +      <tr>
 +      <td valign="top" >“SRC_Y”</td>
 +      <td valign="top" >RANGE</td>
 +      <td valign="top" >Min=0, Max=UINT_MAX</td>
 +      <td valign="top" >Plane</td>
 +      <td valign="top" >Scanout source y coordinate in 16.16 fixed point (atomic)</td>
 +      </tr>
 +      <tr>
 +      <td valign="top" >“SRC_W”</td>
 +      <td valign="top" >RANGE</td>
 +      <td valign="top" >Min=0, Max=UINT_MAX</td>
 +      <td valign="top" >Plane</td>
 +      <td valign="top" >Scanout source width in 16.16 fixed point (atomic)</td>
 +      </tr>
 +      <tr>
 +      <td valign="top" >“SRC_H”</td>
 +      <td valign="top" >RANGE</td>
 +      <td valign="top" >Min=0, Max=UINT_MAX</td>
 +      <td valign="top" >Plane</td>
 +      <td valign="top" >Scanout source height in 16.16 fixed point (atomic)</td>
 +      </tr>
 +      <tr>
 +      <td valign="top" >“CRTC_X”</td>
 +      <td valign="top" >SIGNED_RANGE</td>
 +      <td valign="top" >Min=INT_MIN, Max=INT_MAX</td>
 +      <td valign="top" >Plane</td>
 +      <td valign="top" >Scanout CRTC (destination) x coordinate (atomic)</td>
 +      </tr>
 +      <tr>
 +      <td valign="top" >“CRTC_Y”</td>
 +      <td valign="top" >SIGNED_RANGE</td>
 +      <td valign="top" >Min=INT_MIN, Max=INT_MAX</td>
 +      <td valign="top" >Plane</td>
 +      <td valign="top" >Scanout CRTC (destination) y coordinate (atomic)</td>
 +      </tr>
 +      <tr>
 +      <td valign="top" >“CRTC_W”</td>
 +      <td valign="top" >RANGE</td>
 +      <td valign="top" >Min=0, Max=UINT_MAX</td>
 +      <td valign="top" >Plane</td>
 +      <td valign="top" >Scanout CRTC (destination) width (atomic)</td>
 +      </tr>
 +      <tr>
 +      <td valign="top" >“CRTC_H”</td>
 +      <td valign="top" >RANGE</td>
 +      <td valign="top" >Min=0, Max=UINT_MAX</td>
 +      <td valign="top" >Plane</td>
 +      <td valign="top" >Scanout CRTC (destination) height (atomic)</td>
 +      </tr>
 +      <tr>
 +      <td valign="top" >“FB_ID”</td>
 +      <td valign="top" >OBJECT</td>
 +      <td valign="top" >DRM_MODE_OBJECT_FB</td>
 +      <td valign="top" >Plane</td>
 +      <td valign="top" >Scanout framebuffer (atomic)</td>
 +      </tr>
 +      <tr>
 +      <td valign="top" >“CRTC_ID”</td>
 +      <td valign="top" >OBJECT</td>
 +      <td valign="top" >DRM_MODE_OBJECT_CRTC</td>
 +      <td valign="top" >Plane</td>
 +      <td valign="top" >CRTC that plane is attached to (atomic)</td>
 +      </tr>
 +      <tr>
        <td rowspan="2" valign="top" >DVI-I</td>
        <td valign="top" >“subconnector”</td>
        <td valign="top" >ENUM</td>
@@@ -4017,6 -3931,11 +4017,11 @@@ int num_ioctls;</synopsis
          framebuffer compression and panel self refresh.
          </para>
        </sect2>
+       <sect2>
+         <title>Atomic Plane Helpers</title>
+ !Pdrivers/gpu/drm/i915/intel_atomic_plane.c atomic plane helpers
+ !Idrivers/gpu/drm/i915/intel_atomic_plane.c
+       </sect2>
        <sect2>
          <title>Output Probing</title>
          <para>
  !Pdrivers/gpu/drm/i915/i915_gem_gtt.c Global GTT views
  !Idrivers/gpu/drm/i915/i915_gem_gtt.c
        </sect2>
+       <sect2>
+         <title>Buffer Object Eviction</title>
+       <para>
+         This section documents the interface function for evicting buffer
+         objects to make space available in the virtual gpu address spaces.
+         Note that this is mostly orthogonal to shrinking buffer objects
+         caches, which has the goal to make main memory (shared with the gpu
+         through the unified memory architecture) available.
+       </para>
+ !Idrivers/gpu/drm/i915/i915_gem_evict.c
+       </sect2>
      </sect1>
  
      <sect1>
index 4e4d969d3b283ee67411289cb52d3fe0d1285487,9f430f77a52026345defa1d372bbb607a7e8f0a8..6c403654e33a121c0d6c3028e1e3e467fef84b04
@@@ -153,12 -153,6 +153,6 @@@ int i915_mutex_lock_interruptible(struc
        return 0;
  }
  
- static inline bool
- i915_gem_object_is_inactive(struct drm_i915_gem_object *obj)
- {
-       return i915_gem_obj_bound_any(obj) && !obj->active;
- }
  int
  i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
                            struct drm_file *file)
@@@ -1487,18 -1481,10 +1481,10 @@@ i915_gem_set_domain_ioctl(struct drm_de
        if (ret)
                goto unref;
  
-       if (read_domains & I915_GEM_DOMAIN_GTT) {
+       if (read_domains & I915_GEM_DOMAIN_GTT)
                ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
-               /* Silently promote "you're not bound, there was nothing to do"
-                * to success, since the client was just asking us to
-                * make sure everything was done.
-                */
-               if (ret == -EINVAL)
-                       ret = 0;
-       } else {
+       else
                ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0);
-       }
  
  unref:
        drm_gem_object_unreference(&obj->base);
@@@ -1563,6 -1549,12 +1549,12 @@@ i915_gem_mmap_ioctl(struct drm_device *
        struct drm_gem_object *obj;
        unsigned long addr;
  
+       if (args->flags & ~(I915_MMAP_WC))
+               return -EINVAL;
+       if (args->flags & I915_MMAP_WC && !cpu_has_pat)
+               return -ENODEV;
        obj = drm_gem_object_lookup(dev, file, args->handle);
        if (obj == NULL)
                return -ENOENT;
        addr = vm_mmap(obj->filp, 0, args->size,
                       PROT_READ | PROT_WRITE, MAP_SHARED,
                       args->offset);
+       if (args->flags & I915_MMAP_WC) {
+               struct mm_struct *mm = current->mm;
+               struct vm_area_struct *vma;
+               down_write(&mm->mmap_sem);
+               vma = find_vma(mm, addr);
+               if (vma)
+                       vma->vm_page_prot =
+                               pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+               else
+                       addr = -ENOMEM;
+               up_write(&mm->mmap_sem);
+       }
        drm_gem_object_unreference_unlocked(obj);
        if (IS_ERR((void *)addr))
                return addr;
@@@ -2529,7 -2534,8 +2534,8 @@@ static bool i915_context_is_banned(stru
        if (ctx->hang_stats.banned)
                return true;
  
-       if (elapsed <= DRM_I915_CTX_BAN_PERIOD) {
+       if (ctx->hang_stats.ban_period_seconds &&
+           elapsed <= ctx->hang_stats.ban_period_seconds) {
                if (!i915_gem_context_is_default(ctx)) {
                        DRM_DEBUG("context hanging too fast, banning!\n");
                        return true;
@@@ -3698,15 -3704,10 +3704,10 @@@ i915_gem_object_flush_cpu_write_domain(
  int
  i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
  {
-       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
-       struct i915_vma *vma = i915_gem_obj_to_ggtt(obj);
        uint32_t old_write_domain, old_read_domains;
+       struct i915_vma *vma;
        int ret;
  
-       /* Not valid to be called on unbound objects. */
-       if (vma == NULL)
-               return -EINVAL;
        if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
                return 0;
  
                return ret;
  
        i915_gem_object_retire(obj);
+       /* Flush and acquire obj->pages so that we are coherent through
+        * direct access in memory with previous cached writes through
+        * shmemfs and that our cache domain tracking remains valid.
+        * For example, if the obj->filp was moved to swap without us
+        * being notified and releasing the pages, we would mistakenly
+        * continue to assume that the obj remained out of the CPU cached
+        * domain.
+        */
+       ret = i915_gem_object_get_pages(obj);
+       if (ret)
+               return ret;
        i915_gem_object_flush_cpu_write_domain(obj, false);
  
        /* Serialise direct access to this object with the barriers for
                                            old_write_domain);
  
        /* And bump the LRU for this access */
-       if (i915_gem_object_is_inactive(obj))
+       vma = i915_gem_obj_to_ggtt(obj);
+       if (vma && drm_mm_node_allocated(&vma->node) && !obj->active)
                list_move_tail(&vma->mm_list,
-                              &dev_priv->gtt.base.inactive_list);
+                              &to_i915(obj->base.dev)->gtt.base.inactive_list);
  
        return 0;
  }
@@@ -5096,7 -5111,7 +5111,7 @@@ static bool mutex_is_locked_by(struct m
        if (!mutex_is_locked(mutex))
                return false;
  
 -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES)
 +#if defined(CONFIG_SMP) && !defined(CONFIG_DEBUG_MUTEXES)
        return mutex->owner == task;
  #else
        /* Since UP may be pre-empted, we cannot assume that we own the lock */
index 818ab4e9dabc0201a68be2471a6f541826d7a23b,49b2eab67c0d8defd748115a935a82d1e74ca8ff..8fe5a87705f7c607fd4e75df39124a42d4f3cb55
@@@ -45,7 -45,7 +45,7 @@@
   * and related files, but that will be described in separate chapters.
   */
  
- static const u32 hpd_ibx[] = {
+ static const u32 hpd_ibx[HPD_NUM_PINS] = {
        [HPD_CRT] = SDE_CRT_HOTPLUG,
        [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
        [HPD_PORT_B] = SDE_PORTB_HOTPLUG,
@@@ -53,7 -53,7 +53,7 @@@
        [HPD_PORT_D] = SDE_PORTD_HOTPLUG
  };
  
- static const u32 hpd_cpt[] = {
+ static const u32 hpd_cpt[HPD_NUM_PINS] = {
        [HPD_CRT] = SDE_CRT_HOTPLUG_CPT,
        [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT,
        [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
@@@ -61,7 -61,7 +61,7 @@@
        [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT
  };
  
- static const u32 hpd_mask_i915[] = {
+ static const u32 hpd_mask_i915[HPD_NUM_PINS] = {
        [HPD_CRT] = CRT_HOTPLUG_INT_EN,
        [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN,
        [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN,
@@@ -70,7 -70,7 +70,7 @@@
        [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN
  };
  
- static const u32 hpd_status_g4x[] = {
+ static const u32 hpd_status_g4x[HPD_NUM_PINS] = {
        [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
        [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X,
        [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X,
@@@ -79,7 -79,7 +79,7 @@@
        [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
  };
  
- static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
+ static const u32 hpd_status_i915[HPD_NUM_PINS] = { /* i915 and valleyview are the same */
        [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
        [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
        [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915,
@@@ -296,23 -296,6 +296,23 @@@ void gen6_enable_rps_interrupts(struct 
        spin_unlock_irq(&dev_priv->irq_lock);
  }
  
 +u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask)
 +{
 +      /*
 +       * SNB,IVB can while VLV,CHV may hard hang on looping batchbuffer
 +       * if GEN6_PM_UP_EI_EXPIRED is masked.
 +       *
 +       * TODO: verify if this can be reproduced on VLV,CHV.
 +       */
 +      if (INTEL_INFO(dev_priv)->gen <= 7 && !IS_HASWELL(dev_priv))
 +              mask &= ~GEN6_PM_RP_UP_EI_EXPIRED;
 +
 +      if (INTEL_INFO(dev_priv)->gen >= 8)
 +              mask &= ~GEN8_PMINTR_REDIRECT_TO_NON_DISP;
 +
 +      return mask;
 +}
 +
  void gen6_disable_rps_interrupts(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
  
        spin_lock_irq(&dev_priv->irq_lock);
  
 -      I915_WRITE(GEN6_PMINTRMSK, INTEL_INFO(dev_priv)->gen >= 8 ?
 -                 ~GEN8_PMINTR_REDIRECT_TO_NON_DISP : ~0);
 +      I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0));
  
        __gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
        I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) &
@@@ -1522,7 -1506,7 +1522,7 @@@ static inline enum port get_port_from_p
  static inline void intel_hpd_irq_handler(struct drm_device *dev,
                                         u32 hotplug_trigger,
                                         u32 dig_hotplug_reg,
-                                        const u32 *hpd)
+                                        const u32 hpd[HPD_NUM_PINS])
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
@@@ -4145,26 -4129,24 +4145,24 @@@ static void i915_hpd_irq_setup(struct d
  
        assert_spin_locked(&dev_priv->irq_lock);
  
-       if (I915_HAS_HOTPLUG(dev)) {
-               hotplug_en = I915_READ(PORT_HOTPLUG_EN);
-               hotplug_en &= ~HOTPLUG_INT_EN_MASK;
-               /* Note HDMI and DP share hotplug bits */
-               /* enable bits are the same for all generations */
-               for_each_intel_encoder(dev, intel_encoder)
-                       if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
-                               hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin];
-               /* Programming the CRT detection parameters tends
-                  to generate a spurious hotplug event about three
-                  seconds later.  So just do it once.
-               */
-               if (IS_G4X(dev))
-                       hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
-               hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK;
-               hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
-               /* Ignore TV since it's buggy */
-               I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
-       }
+       hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+       hotplug_en &= ~HOTPLUG_INT_EN_MASK;
+       /* Note HDMI and DP share hotplug bits */
+       /* enable bits are the same for all generations */
+       for_each_intel_encoder(dev, intel_encoder)
+               if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
+                       hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin];
+       /* Programming the CRT detection parameters tends
+          to generate a spurious hotplug event about three
+          seconds later.  So just do it once.
+       */
+       if (IS_G4X(dev))
+               hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
+       hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK;
+       hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
+       /* Ignore TV since it's buggy */
+       I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
  }
  
  static irqreturn_t i965_irq_handler(int irq, void *arg)
@@@ -4428,14 -4410,14 +4426,14 @@@ void intel_irq_init(struct drm_i915_pri
                        dev->driver->irq_postinstall = i915_irq_postinstall;
                        dev->driver->irq_uninstall = i915_irq_uninstall;
                        dev->driver->irq_handler = i915_irq_handler;
-                       dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
                } else {
                        dev->driver->irq_preinstall = i965_irq_preinstall;
                        dev->driver->irq_postinstall = i965_irq_postinstall;
                        dev->driver->irq_uninstall = i965_irq_uninstall;
                        dev->driver->irq_handler = i965_irq_handler;
-                       dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
                }
+               if (I915_HAS_HOTPLUG(dev_priv))
+                       dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
                dev->driver->enable_vblank = i915_enable_vblank;
                dev->driver->disable_vblank = i915_disable_vblank;
        }
index dc266e772340f4c397d7b39a1522cc5fa171869b,ece397b691a17463c82eb30d37119ec664c6e327..91d8ada8fe6d2965f5d0875ddb94e6666b19e6a3
@@@ -98,6 -98,8 +98,8 @@@ static void vlv_prepare_pll(struct inte
                            const struct intel_crtc_config *pipe_config);
  static void chv_prepare_pll(struct intel_crtc *crtc,
                            const struct intel_crtc_config *pipe_config);
+ static void intel_begin_crtc_commit(struct drm_crtc *crtc);
+ static void intel_finish_crtc_commit(struct drm_crtc *crtc);
  
  static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
  {
@@@ -2165,7 -2167,8 +2167,8 @@@ static void intel_disable_primary_hw_pl
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
  
-       assert_pipe_enabled(dev_priv, intel_crtc->pipe);
+       if (WARN_ON(!intel_crtc->active))
+               return;
  
        if (!intel_crtc->primary_enabled)
                return;
@@@ -4036,7 -4039,7 +4039,7 @@@ static void ironlake_pfit_enable(struc
        }
  }
  
- static void intel_enable_planes(struct drm_crtc *crtc)
+ static void intel_enable_sprite_planes(struct drm_crtc *crtc)
  {
        struct drm_device *dev = crtc->dev;
        enum pipe pipe = to_intel_crtc(crtc)->pipe;
        }
  }
  
- static void intel_disable_planes(struct drm_crtc *crtc)
+ static void intel_disable_sprite_planes(struct drm_crtc *crtc)
  {
        struct drm_device *dev = crtc->dev;
        enum pipe pipe = to_intel_crtc(crtc)->pipe;
@@@ -4194,7 -4197,7 +4197,7 @@@ static void intel_crtc_enable_planes(st
        int pipe = intel_crtc->pipe;
  
        intel_enable_primary_hw_plane(crtc->primary, crtc);
-       intel_enable_planes(crtc);
+       intel_enable_sprite_planes(crtc);
        intel_crtc_update_cursor(crtc, true);
        intel_crtc_dpms_overlay(intel_crtc, true);
  
@@@ -4229,7 -4232,7 +4232,7 @@@ static void intel_crtc_disable_planes(s
  
        intel_crtc_dpms_overlay(intel_crtc, false);
        intel_crtc_update_cursor(crtc, false);
-       intel_disable_planes(crtc);
+       intel_disable_sprite_planes(crtc);
        intel_disable_primary_hw_plane(crtc->primary, crtc);
  
        /*
@@@ -4301,15 -4304,15 +4304,15 @@@ static void ironlake_crtc_enable(struc
        if (intel_crtc->config.has_pch_encoder)
                ironlake_pch_enable(crtc);
  
+       assert_vblank_disabled(crtc);
+       drm_crtc_vblank_on(crtc);
        for_each_encoder_on_crtc(dev, crtc, encoder)
                encoder->enable(encoder);
  
        if (HAS_PCH_CPT(dev))
                cpt_verify_modeset(dev, intel_crtc->pipe);
  
-       assert_vblank_disabled(crtc);
-       drm_crtc_vblank_on(crtc);
        intel_crtc_enable_planes(crtc);
  }
  
@@@ -4421,14 -4424,14 +4424,14 @@@ static void haswell_crtc_enable(struct 
        if (intel_crtc->config.dp_encoder_is_mst)
                intel_ddi_set_vc_payload_alloc(crtc, true);
  
+       assert_vblank_disabled(crtc);
+       drm_crtc_vblank_on(crtc);
        for_each_encoder_on_crtc(dev, crtc, encoder) {
                encoder->enable(encoder);
                intel_opregion_notify_encoder(encoder, true);
        }
  
-       assert_vblank_disabled(crtc);
-       drm_crtc_vblank_on(crtc);
        /* If we change the relative order between pipe/planes enabling, we need
         * to change the workaround. */
        haswell_mode_set_planes_workaround(intel_crtc);
@@@ -4479,12 -4482,12 +4482,12 @@@ static void ironlake_crtc_disable(struc
  
        intel_crtc_disable_planes(crtc);
  
-       drm_crtc_vblank_off(crtc);
-       assert_vblank_disabled(crtc);
        for_each_encoder_on_crtc(dev, crtc, encoder)
                encoder->disable(encoder);
  
+       drm_crtc_vblank_off(crtc);
+       assert_vblank_disabled(crtc);
        if (intel_crtc->config.has_pch_encoder)
                intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
  
@@@ -4543,14 -4546,14 +4546,14 @@@ static void haswell_crtc_disable(struc
  
        intel_crtc_disable_planes(crtc);
  
-       drm_crtc_vblank_off(crtc);
-       assert_vblank_disabled(crtc);
        for_each_encoder_on_crtc(dev, crtc, encoder) {
                intel_opregion_notify_encoder(encoder, false);
                encoder->disable(encoder);
        }
  
+       drm_crtc_vblank_off(crtc);
+       assert_vblank_disabled(crtc);
        if (intel_crtc->config.has_pch_encoder)
                intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
                                                      false);
@@@ -5018,12 -5021,12 +5021,12 @@@ static void valleyview_crtc_enable(stru
        intel_update_watermarks(crtc);
        intel_enable_pipe(intel_crtc);
  
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               encoder->enable(encoder);
        assert_vblank_disabled(crtc);
        drm_crtc_vblank_on(crtc);
  
+       for_each_encoder_on_crtc(dev, crtc, encoder)
+               encoder->enable(encoder);
        intel_crtc_enable_planes(crtc);
  
        /* Underruns don't raise interrupts, so check manually. */
@@@ -5079,12 -5082,12 +5082,12 @@@ static void i9xx_crtc_enable(struct drm
        intel_update_watermarks(crtc);
        intel_enable_pipe(intel_crtc);
  
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               encoder->enable(encoder);
        assert_vblank_disabled(crtc);
        drm_crtc_vblank_on(crtc);
  
+       for_each_encoder_on_crtc(dev, crtc, encoder)
+               encoder->enable(encoder);
        intel_crtc_enable_planes(crtc);
  
        /*
@@@ -5156,12 -5159,12 +5159,12 @@@ static void i9xx_crtc_disable(struct dr
         */
        intel_wait_for_vblank(dev, pipe);
  
-       drm_crtc_vblank_off(crtc);
-       assert_vblank_disabled(crtc);
        for_each_encoder_on_crtc(dev, crtc, encoder)
                encoder->disable(encoder);
  
+       drm_crtc_vblank_off(crtc);
+       assert_vblank_disabled(crtc);
        intel_disable_pipe(intel_crtc);
  
        i9xx_pfit_disable(intel_crtc);
@@@ -9613,7 -9616,6 +9616,6 @@@ static int intel_crtc_page_flip(struct 
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_plane *primary = crtc->primary;
-       struct intel_plane *intel_plane = to_intel_plane(primary);
        enum pipe pipe = intel_crtc->pipe;
        struct intel_unpin_work *work;
        struct intel_engine_cs *ring;
                if (obj->tiling_mode != work->old_fb_obj->tiling_mode)
                        /* vlv: DISPLAY_FLIP fails to change tiling */
                        ring = NULL;
 -      } else if (IS_IVYBRIDGE(dev)) {
 +      } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
                ring = &dev_priv->ring[BCS];
        } else if (INTEL_INFO(dev)->gen >= 7) {
                ring = i915_gem_request_get_ring(obj->last_read_req);
@@@ -9772,15 -9774,7 +9774,7 @@@ free_work
  
        if (ret == -EIO) {
  out_hang:
-               ret = primary->funcs->update_plane(primary, crtc, fb,
-                                                  intel_plane->crtc_x,
-                                                  intel_plane->crtc_y,
-                                                  intel_plane->crtc_h,
-                                                  intel_plane->crtc_w,
-                                                  intel_plane->src_x,
-                                                  intel_plane->src_y,
-                                                  intel_plane->src_h,
-                                                  intel_plane->src_w);
+               ret = intel_plane_restore(primary);
                if (ret == 0 && event) {
                        spin_lock_irq(&dev->event_lock);
                        drm_send_vblank_event(dev, pipe, event);
  static struct drm_crtc_helper_funcs intel_helper_funcs = {
        .mode_set_base_atomic = intel_pipe_set_base_atomic,
        .load_lut = intel_crtc_load_lut,
+       .atomic_begin = intel_begin_crtc_commit,
+       .atomic_flush = intel_finish_crtc_commit,
  };
  
  /**
@@@ -11673,7 -11669,7 +11669,7 @@@ intel_prepare_plane_fb(struct drm_plan
        unsigned frontbuffer_bits = 0;
        int ret = 0;
  
-       if (WARN_ON(fb == plane->fb || !obj))
+       if (!obj)
                return 0;
  
        switch (plane->type) {
@@@ -11737,13 -11733,20 +11733,20 @@@ static in
  intel_check_primary_plane(struct drm_plane *plane,
                          struct intel_plane_state *state)
  {
+       struct drm_device *dev = plane->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc = state->base.crtc;
+       struct intel_crtc *intel_crtc;
+       struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_framebuffer *fb = state->base.fb;
        struct drm_rect *dest = &state->dst;
        struct drm_rect *src = &state->src;
        const struct drm_rect *clip = &state->clip;
        int ret;
  
+       crtc = crtc ? crtc : plane->crtc;
+       intel_crtc = to_intel_crtc(crtc);
        ret = drm_plane_helper_check_update(plane, crtc, fb,
                                            src, dest, clip,
                                            DRM_PLANE_HELPER_NO_SCALING,
        if (ret)
                return ret;
  
-       intel_crtc_wait_for_pending_flips(crtc);
-       if (intel_crtc_has_pending_flip(crtc)) {
-               DRM_ERROR("pipe is still busy with an old pageflip\n");
-               return -EBUSY;
+       if (intel_crtc->active) {
+               intel_crtc->atomic.wait_for_flips = true;
+               /*
+                * FBC does not work on some platforms for rotated
+                * planes, so disable it when rotation is not 0 and
+                * update it when rotation is set back to 0.
+                *
+                * FIXME: This is redundant with the fbc update done in
+                * the primary plane enable function except that that
+                * one is done too late. We eventually need to unify
+                * this.
+                */
+               if (intel_crtc->primary_enabled &&
+                   INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
+                   dev_priv->fbc.plane == intel_crtc->plane &&
+                   intel_plane->rotation != BIT(DRM_ROTATE_0)) {
+                       intel_crtc->atomic.disable_fbc = true;
+               }
+               if (state->visible) {
+                       /*
+                        * BDW signals flip done immediately if the plane
+                        * is disabled, even if the plane enable is already
+                        * armed to occur at the next vblank :(
+                        */
+                       if (IS_BROADWELL(dev) && !intel_crtc->primary_enabled)
+                               intel_crtc->atomic.wait_vblank = true;
+               }
+               intel_crtc->atomic.fb_bits |=
+                       INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
+               intel_crtc->atomic.update_fbc = true;
        }
  
        return 0;
@@@ -11769,58 -11802,22 +11802,22 @@@ intel_commit_primary_plane(struct drm_p
        struct drm_framebuffer *fb = state->base.fb;
        struct drm_device *dev = plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_crtc *intel_crtc;
        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;
  
-       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);
-       }
+       crtc = crtc ? crtc : plane->crtc;
+       intel_crtc = to_intel_crtc(crtc);
  
        plane->fb = fb;
        crtc->x = src->x1 >> 16;
        crtc->y = src->y1 >> 16;
  
-       intel_plane->crtc_x = state->orig_dst.x1;
-       intel_plane->crtc_y = state->orig_dst.y1;
-       intel_plane->crtc_w = drm_rect_width(&state->orig_dst);
-       intel_plane->crtc_h = drm_rect_height(&state->orig_dst);
-       intel_plane->src_x = state->orig_src.x1;
-       intel_plane->src_y = state->orig_src.y1;
-       intel_plane->src_w = drm_rect_width(&state->orig_src);
-       intel_plane->src_h = drm_rect_height(&state->orig_src);
        intel_plane->obj = obj;
  
        if (intel_crtc->active) {
-               /*
-                * FBC does not work on some platforms for rotated
-                * planes, so disable it when rotation is not 0 and
-                * update it when rotation is set back to 0.
-                *
-                * FIXME: This is redundant with the fbc update done in
-                * the primary plane enable function except that that
-                * one is done too late. We eventually need to unify
-                * this.
-                */
-               if (intel_crtc->primary_enabled &&
-                   INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
-                   dev_priv->fbc.plane == intel_crtc->plane &&
-                   intel_plane->rotation != BIT(DRM_ROTATE_0)) {
-                       intel_fbc_disable(dev);
-               }
                if (state->visible) {
-                       bool was_enabled = intel_crtc->primary_enabled;
                        /* FIXME: kill this fastboot hack */
                        intel_update_pipe_size(intel_crtc);
  
  
                        dev_priv->display.update_primary_plane(crtc, plane->fb,
                                        crtc->x, crtc->y);
-                       /*
-                        * BDW signals flip done immediately if the plane
-                        * is disabled, even if the plane enable is already
-                        * armed to occur at the next vblank :(
-                        */
-                       if (IS_BROADWELL(dev) && !was_enabled)
-                               intel_wait_for_vblank(dev, intel_crtc->pipe);
                } else {
                        /*
                         * If clipping results in a non-visible primary plane,
                         */
                        intel_disable_primary_hw_plane(plane, crtc);
                }
-               intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
-               mutex_lock(&dev->struct_mutex);
-               intel_fbc_update(dev);
-               mutex_unlock(&dev->struct_mutex);
        }
  }
  
- int
- intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
-                  struct drm_framebuffer *fb, int crtc_x, int crtc_y,
-                  unsigned int crtc_w, unsigned int crtc_h,
-                  uint32_t src_x, uint32_t src_y,
-                  uint32_t src_w, uint32_t src_h)
+ static void intel_begin_crtc_commit(struct drm_crtc *crtc)
  {
-       struct drm_device *dev = plane->dev;
+       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_framebuffer *old_fb = plane->fb;
-       struct intel_plane_state state;
-       struct intel_plane *intel_plane = to_intel_plane(plane);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int ret;
+       struct intel_plane *intel_plane;
+       struct drm_plane *p;
+       unsigned fb_bits = 0;
+       /* Track fb's for any planes being disabled */
+       list_for_each_entry(p, &dev->mode_config.plane_list, head) {
+               intel_plane = to_intel_plane(p);
+               if (intel_crtc->atomic.disabled_planes &
+                   (1 << drm_plane_index(p))) {
+                       switch (p->type) {
+                       case DRM_PLANE_TYPE_PRIMARY:
+                               fb_bits = INTEL_FRONTBUFFER_PRIMARY(intel_plane->pipe);
+                               break;
+                       case DRM_PLANE_TYPE_CURSOR:
+                               fb_bits = INTEL_FRONTBUFFER_CURSOR(intel_plane->pipe);
+                               break;
+                       case DRM_PLANE_TYPE_OVERLAY:
+                               fb_bits = INTEL_FRONTBUFFER_SPRITE(intel_plane->pipe);
+                               break;
+                       }
  
-       state.base.crtc = crtc ? crtc : plane->crtc;
-       state.base.fb = fb;
+                       mutex_lock(&dev->struct_mutex);
+                       i915_gem_track_fb(intel_fb_obj(p->fb), NULL, fb_bits);
+                       mutex_unlock(&dev->struct_mutex);
+               }
+       }
  
-       /* sample coordinates in 16.16 fixed point */
-       state.src.x1 = src_x;
-       state.src.x2 = src_x + src_w;
-       state.src.y1 = src_y;
-       state.src.y2 = src_y + src_h;
+       if (intel_crtc->atomic.wait_for_flips)
+               intel_crtc_wait_for_pending_flips(crtc);
  
-       /* integer pixels */
-       state.dst.x1 = crtc_x;
-       state.dst.x2 = crtc_x + crtc_w;
-       state.dst.y1 = crtc_y;
-       state.dst.y2 = crtc_y + crtc_h;
+       if (intel_crtc->atomic.disable_fbc)
+               intel_fbc_disable(dev);
  
-       state.clip.x1 = 0;
-       state.clip.y1 = 0;
-       state.clip.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0;
-       state.clip.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0;
+       if (intel_crtc->atomic.pre_disable_primary)
+               intel_pre_disable_primary(crtc);
  
-       state.orig_src = state.src;
-       state.orig_dst = state.dst;
+       if (intel_crtc->atomic.update_wm)
+               intel_update_watermarks(crtc);
  
-       ret = intel_plane->check_plane(plane, &state);
-       if (ret)
-               return ret;
+       intel_runtime_pm_get(dev_priv);
  
-       if (fb != old_fb && fb) {
-               ret = intel_prepare_plane_fb(plane, fb);
-               if (ret)
-                       return ret;
-       }
+       /* Perform vblank evasion around commit operation */
+       if (intel_crtc->active)
+               intel_crtc->atomic.evade =
+                       intel_pipe_update_start(intel_crtc,
+                                               &intel_crtc->atomic.start_vbl_count);
+ }
+ static void intel_finish_crtc_commit(struct drm_crtc *crtc)
+ {
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_plane *p;
+       if (intel_crtc->atomic.evade)
+               intel_pipe_update_end(intel_crtc,
+                                     intel_crtc->atomic.start_vbl_count);
  
-       intel_runtime_pm_get(dev_priv);
-       intel_plane->commit_plane(plane, &state);
        intel_runtime_pm_put(dev_priv);
  
-       if (fb != old_fb && old_fb) {
-               if (intel_crtc->active)
-                       intel_wait_for_vblank(dev, intel_crtc->pipe);
-               intel_cleanup_plane_fb(plane, old_fb);
+       if (intel_crtc->atomic.wait_vblank)
+               intel_wait_for_vblank(dev, intel_crtc->pipe);
+       intel_frontbuffer_flip(dev, intel_crtc->atomic.fb_bits);
+       if (intel_crtc->atomic.update_fbc) {
+               mutex_lock(&dev->struct_mutex);
+               intel_fbc_update(dev);
+               mutex_unlock(&dev->struct_mutex);
        }
  
-       plane->fb = fb;
+       if (intel_crtc->atomic.post_enable_primary)
+               intel_post_enable_primary(crtc);
  
-       return 0;
+       drm_for_each_legacy_plane(p, &dev->mode_config.plane_list)
+               if (intel_crtc->atomic.update_sprite_watermarks & drm_plane_index(p))
+                       intel_update_sprite_watermarks(p, crtc, 0, 0, 0,
+                                                      false, false);
+       memset(&intel_crtc->atomic, 0, sizeof(intel_crtc->atomic));
  }
  
  /**
-  * intel_disable_plane - disable a plane
-  * @plane: plane to disable
+  * intel_plane_destroy - destroy a plane
+  * @plane: plane to destroy
   *
-  * General disable handler for all plane types.
+  * Common destruction function for all types of planes (primary, cursor,
+  * sprite).
   */
- 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)
+ void intel_plane_destroy(struct drm_plane *plane)
  {
        struct intel_plane *intel_plane = to_intel_plane(plane);
+       intel_plane_destroy_state(plane, plane->state);
        drm_plane_cleanup(plane);
        kfree(intel_plane);
  }
  
  static const struct drm_plane_funcs intel_primary_plane_funcs = {
-       .update_plane = intel_update_plane,
-       .disable_plane = intel_disable_plane,
+       .update_plane = drm_plane_helper_update,
+       .disable_plane = drm_plane_helper_disable,
        .destroy = intel_plane_destroy,
-       .set_property = intel_plane_set_property
+       .set_property = intel_plane_set_property,
+       .atomic_duplicate_state = intel_plane_duplicate_state,
+       .atomic_destroy_state = intel_plane_destroy_state,
  };
  
  static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
        if (primary == NULL)
                return NULL;
  
+       primary->base.state = intel_plane_duplicate_state(&primary->base);
+       if (primary->base.state == NULL) {
+               kfree(primary);
+               return NULL;
+       }
        primary->can_scale = false;
        primary->max_downscale = 1;
        primary->pipe = pipe;
                                primary->rotation);
        }
  
+       drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);
        return &primary->base;
  }
  
@@@ -12006,16 -12014,19 +12014,19 @@@ intel_check_cursor_plane(struct drm_pla
                         struct intel_plane_state *state)
  {
        struct drm_crtc *crtc = state->base.crtc;
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = plane->dev;
        struct drm_framebuffer *fb = state->base.fb;
        struct drm_rect *dest = &state->dst;
        struct drm_rect *src = &state->src;
        const struct drm_rect *clip = &state->clip;
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-       int crtc_w, crtc_h;
+       struct intel_crtc *intel_crtc;
        unsigned stride;
        int ret;
  
+       crtc = crtc ? crtc : plane->crtc;
+       intel_crtc = to_intel_crtc(crtc);
        ret = drm_plane_helper_check_update(plane, crtc, fb,
                                            src, dest, clip,
                                            DRM_PLANE_HELPER_NO_SCALING,
  
        /* if we want to turn off the cursor ignore width and height */
        if (!obj)
-               return 0;
+               goto finish;
  
        /* Check for which cursor types we support */
-       crtc_w = drm_rect_width(&state->orig_dst);
-       crtc_h = drm_rect_height(&state->orig_dst);
-       if (!cursor_size_ok(dev, crtc_w, crtc_h)) {
-               DRM_DEBUG("Cursor dimension not supported\n");
+       if (!cursor_size_ok(dev, 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(crtc_w) * 4;
-       if (obj->base.size < stride * crtc_h) {
+       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;
        }
        }
        mutex_unlock(&dev->struct_mutex);
  
+ finish:
+       if (intel_crtc->active) {
+               if (intel_crtc->cursor_width != state->base.crtc_w)
+                       intel_crtc->atomic.update_wm = true;
+               intel_crtc->atomic.fb_bits |=
+                       INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe);
+       }
        return ret;
  }
  
@@@ -12062,43 -12081,24 +12081,24 @@@ intel_commit_cursor_plane(struct drm_pl
                          struct intel_plane_state *state)
  {
        struct drm_crtc *crtc = state->base.crtc;
-       struct drm_device *dev = crtc->dev;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_device *dev = plane->dev;
+       struct intel_crtc *intel_crtc;
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb);
-       struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
-       enum pipe pipe = intel_crtc->pipe;
-       unsigned old_width;
        uint32_t addr;
  
+       crtc = crtc ? crtc : plane->crtc;
+       intel_crtc = to_intel_crtc(crtc);
        plane->fb = state->base.fb;
-       crtc->cursor_x = state->orig_dst.x1;
-       crtc->cursor_y = state->orig_dst.y1;
-       intel_plane->crtc_x = state->orig_dst.x1;
-       intel_plane->crtc_y = state->orig_dst.y1;
-       intel_plane->crtc_w = drm_rect_width(&state->orig_dst);
-       intel_plane->crtc_h = drm_rect_height(&state->orig_dst);
-       intel_plane->src_x = state->orig_src.x1;
-       intel_plane->src_y = state->orig_src.y1;
-       intel_plane->src_w = drm_rect_width(&state->orig_src);
-       intel_plane->src_h = drm_rect_height(&state->orig_src);
+       crtc->cursor_x = state->base.crtc_x;
+       crtc->cursor_y = state->base.crtc_y;
        intel_plane->obj = obj;
  
        if (intel_crtc->cursor_bo == obj)
                goto update;
  
-       /*
-        * 'prepare' is only called when fb != NULL; we still need to update
-        * frontbuffer tracking for the 'disable' case here.
-        */
-       if (!obj) {
-               mutex_lock(&dev->struct_mutex);
-               i915_gem_track_fb(old_obj, NULL,
-                                 INTEL_FRONTBUFFER_CURSOR(pipe));
-               mutex_unlock(&dev->struct_mutex);
-       }
        if (!obj)
                addr = 0;
        else if (!INTEL_INFO(dev)->cursor_needs_physical)
        intel_crtc->cursor_addr = addr;
        intel_crtc->cursor_bo = obj;
  update:
-       old_width = intel_crtc->cursor_width;
+       intel_crtc->cursor_width = state->base.crtc_w;
+       intel_crtc->cursor_height = state->base.crtc_h;
  
-       intel_crtc->cursor_width = drm_rect_width(&state->orig_dst);
-       intel_crtc->cursor_height = drm_rect_height(&state->orig_dst);
-       if (intel_crtc->active) {
-               if (old_width != intel_crtc->cursor_width)
-                       intel_update_watermarks(crtc);
+       if (intel_crtc->active)
                intel_crtc_update_cursor(crtc, state->visible);
-               intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe));
-       }
  }
  
  static const struct drm_plane_funcs intel_cursor_plane_funcs = {
-       .update_plane = intel_update_plane,
-       .disable_plane = intel_disable_plane,
+       .update_plane = drm_plane_helper_update,
+       .disable_plane = drm_plane_helper_disable,
        .destroy = intel_plane_destroy,
        .set_property = intel_plane_set_property,
+       .atomic_duplicate_state = intel_plane_duplicate_state,
+       .atomic_destroy_state = intel_plane_destroy_state,
  };
  
  static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
        if (cursor == NULL)
                return NULL;
  
+       cursor->base.state = intel_plane_duplicate_state(&cursor->base);
+       if (cursor->base.state == NULL) {
+               kfree(cursor);
+               return NULL;
+       }
        cursor->can_scale = false;
        cursor->max_downscale = 1;
        cursor->pipe = pipe;
                                cursor->rotation);
        }
  
+       drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
        return &cursor->base;
  }
  
@@@ -12390,14 -12393,16 +12393,16 @@@ static void intel_setup_outputs(struct 
                 * eDP ports. Consult the VBT as well as DP_DETECTED to
                 * detect eDP ports.
                 */
-               if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED)
+               if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED &&
+                   !intel_dp_is_edp(dev, PORT_B))
                        intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB,
                                        PORT_B);
                if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED ||
                    intel_dp_is_edp(dev, PORT_B))
                        intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B);
  
-               if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED)
+               if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED &&
+                   !intel_dp_is_edp(dev, PORT_C))
                        intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC,
                                        PORT_C);
                if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED ||
index bb871f3cfe2e0de18107fc4d55257b1e02326521,eca2395e13c855130d36c4d757e6a36d36f2b3ca..30e968f8c55ee51d6d083dc31383ce9ba01238b4
@@@ -248,9 -248,13 +248,13 @@@ struct intel_plane_state 
        struct drm_rect src;
        struct drm_rect dst;
        struct drm_rect clip;
-       struct drm_rect orig_src;
-       struct drm_rect orig_dst;
        bool visible;
+       /*
+        * used only for sprite planes to determine when to implicitly
+        * enable/disable the primary plane
+        */
+       bool hides_primary;
  };
  
  struct intel_plane_config {
@@@ -415,6 -419,32 +419,32 @@@ struct skl_pipe_wm 
        uint32_t linetime;
  };
  
+ /*
+  * Tracking of operations that need to be performed at the beginning/end of an
+  * atomic commit, outside the atomic section where interrupts are disabled.
+  * These are generally operations that grab mutexes or might otherwise sleep
+  * and thus can't be run with interrupts disabled.
+  */
+ struct intel_crtc_atomic_commit {
+       /* vblank evasion */
+       bool evade;
+       unsigned start_vbl_count;
+       /* Sleepable operations to perform before commit */
+       bool wait_for_flips;
+       bool disable_fbc;
+       bool pre_disable_primary;
+       bool update_wm;
+       unsigned disabled_planes;
+       /* Sleepable operations to perform after commit */
+       unsigned fb_bits;
+       bool wait_vblank;
+       bool update_fbc;
+       bool post_enable_primary;
+       unsigned update_sprite_watermarks;
+ };
  struct intel_crtc {
        struct drm_crtc base;
        enum pipe pipe;
  
        int scanline_offset;
        struct intel_mmio_flip mmio_flip;
+       struct intel_crtc_atomic_commit atomic;
  };
  
  struct intel_plane_wm_parameters {
@@@ -485,10 -517,6 +517,6 @@@ struct intel_plane 
        struct drm_i915_gem_object *obj;
        bool can_scale;
        int max_downscale;
-       int crtc_x, crtc_y;
-       unsigned int crtc_w, crtc_h;
-       uint32_t src_x, src_y;
-       uint32_t src_w, src_h;
        unsigned int rotation;
  
        /* Since we need to change the watermarks before/after
@@@ -542,6 -570,7 +570,7 @@@ struct cxsr_latency 
  #define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
  #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
  #define to_intel_plane(x) container_of(x, struct intel_plane, base)
+ #define to_intel_plane_state(x) container_of(x, struct intel_plane_state, base)
  #define intel_fb_obj(x) (x ? to_intel_framebuffer(x)->obj : NULL)
  
  struct intel_hdmi {
@@@ -795,7 -824,6 +824,7 @@@ void gen6_disable_pm_irq(struct drm_i91
  void gen6_reset_rps_interrupts(struct drm_device *dev);
  void gen6_enable_rps_interrupts(struct drm_device *dev);
  void gen6_disable_rps_interrupts(struct drm_device *dev);
 +u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask);
  void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv);
  void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv);
  static inline bool intel_irqs_enabled(struct drm_i915_private *dev_priv)
@@@ -874,6 -902,8 +903,8 @@@ void intel_fb_obj_flush(struct drm_i915
  void intel_init_audio(struct drm_device *dev);
  void intel_audio_codec_enable(struct intel_encoder *encoder);
  void intel_audio_codec_disable(struct intel_encoder *encoder);
+ void i915_audio_component_init(struct drm_i915_private *dev_priv);
+ void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
  
  /* intel_display.c */
  bool intel_has_pending_fb_unpin(struct drm_device *dev);
@@@ -1021,6 -1051,7 +1052,7 @@@ int intel_update_plane(struct drm_plan
                       uint32_t src_x, uint32_t src_y,
                       uint32_t src_w, uint32_t src_h);
  int intel_disable_plane(struct drm_plane *plane);
+ void intel_plane_destroy(struct drm_plane *plane);
  
  /* intel_dp_mst.c */
  int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
@@@ -1214,8 -1245,16 +1246,16 @@@ int intel_sprite_get_colorkey(struct dr
  bool intel_pipe_update_start(struct intel_crtc *crtc,
                             uint32_t *start_vbl_count);
  void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count);
+ void intel_post_enable_primary(struct drm_crtc *crtc);
+ void intel_pre_disable_primary(struct drm_crtc *crtc);
  
  /* intel_tv.c */
  void intel_tv_init(struct drm_device *dev);
  
+ /* intel_atomic.c */
+ struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane);
+ void intel_plane_destroy_state(struct drm_plane *plane,
+                              struct drm_plane_state *state);
+ extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
  #endif /* __INTEL_DRV_H__ */
index 7d99a9c4e49b0ecd40d37808fdcbee3ec7763087,66a1c7f669730ea5ec11909cc983bcc1e6a52d74..03fc7f2ee9d130d21a4fba47d79e5ce8bb62d65a
@@@ -3745,7 -3745,16 +3745,7 @@@ static u32 gen6_rps_pm_mask(struct drm_
        mask |= dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED);
        mask &= dev_priv->pm_rps_events;
  
 -      /* IVB and SNB hard hangs on looping batchbuffer
 -       * if GEN6_PM_UP_EI_EXPIRED is masked.
 -       */
 -      if (INTEL_INFO(dev_priv->dev)->gen <= 7 && !IS_HASWELL(dev_priv->dev))
 -              mask |= GEN6_PM_RP_UP_EI_EXPIRED;
 -
 -      if (IS_GEN8(dev_priv->dev))
 -              mask |= GEN8_PMINTR_REDIRECT_TO_NON_DISP;
 -
 -      return ~mask;
 +      return gen6_sanitize_rps_pm_mask(dev_priv, ~mask);
  }
  
  /* gen6_set_rps is called to update the frequency request, but should also be
@@@ -3814,8 -3823,7 +3814,8 @@@ static void vlv_set_rps_idle(struct drm
                return;
  
        /* Mask turbo interrupt so that they will not come in between */
 -      I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
 +      I915_WRITE(GEN6_PMINTRMSK,
 +                 gen6_sanitize_rps_pm_mask(dev_priv, ~0));
  
        vlv_force_gfx_clock(dev_priv, true);
  
@@@ -4681,8 -4689,7 +4681,7 @@@ static void cherryview_enable_rps(struc
                I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);
        I915_WRITE(GEN6_RC_SLEEP, 0);
  
-       /* TO threshold set to 1750 us ( 0x557 * 1.28 us) */
-       I915_WRITE(GEN6_RC6_THRESHOLD, 0x557);
+       I915_WRITE(GEN6_RC6_THRESHOLD, 50000); /* 50/125ms per EI */
  
        /* allows RC6 residency counter to work */
        I915_WRITE(VLV_COUNTER_CONTROL,
        /* 3: Enable RC6 */
        if ((intel_enable_rc6(dev) & INTEL_RC6_ENABLE) &&
                                                (pcbr >> VLV_PCBR_ADDR_SHIFT))
-               rc6_mode = GEN7_RC_CTL_TO_MODE;
+               rc6_mode = GEN6_RC_CTL_EI_MODE(1);
  
        I915_WRITE(GEN6_RC_CONTROL, rc6_mode);
  
@@@ -5974,6 -5981,10 +5973,10 @@@ static void haswell_init_clock_gating(s
        I915_WRITE(GEN7_GT_MODE,
                   _MASKED_FIELD(GEN6_WIZ_HASHING_MASK, GEN6_WIZ_HASHING_16x4));
  
+       /* WaSampleCChickenBitEnable:hsw */
+       I915_WRITE(HALF_SLICE_CHICKEN3,
+                  _MASKED_BIT_ENABLE(HSW_SAMPLE_C_PERFORMANCE));
        /* WaSwitchSolVfFArbitrationPriority:hsw */
        I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);