Merge tag 'v3.12-rc2' into drm-intel-next
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 24 Sep 2013 07:29:24 +0000 (09:29 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 24 Sep 2013 07:32:53 +0000 (09:32 +0200)
Backmerge Linux 3.12-rc2 to prep for a bunch of -next patches:
- Header cleanup in intel_drv.h, both changed in -fixes and my current
  -next pile.
- Cursor handling cleanup for -next which depends upon the cursor
  handling fix merged into -rc2.

All just trivial conflicts of the "changed adjacent lines" type:
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
12 files changed:
1  2 
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_sdvo.c

@@@ -52,7 -52,7 +52,7 @@@
        intel_ring_emit(LP_RING(dev_priv), x)
  
  #define ADVANCE_LP_RING() \
 -      intel_ring_advance(LP_RING(dev_priv))
 +      __intel_ring_advance(LP_RING(dev_priv))
  
  /**
   * Lock test for when it's just for synchronization of ring access.
@@@ -1324,8 -1324,6 +1324,8 @@@ static int i915_load_modeset_init(struc
  
        INIT_WORK(&dev_priv->console_resume_work, intel_console_resume);
  
 +      intel_init_power_well(dev);
 +
        intel_modeset_gem_init(dev);
  
        /* Always safe in the mode setting case. */
         */
        intel_fbdev_initial_config(dev);
  
+       /*
+        * Must do this after fbcon init so that
+        * vgacon_save_screen() works during the handover.
+        */
+       i915_disable_vga_mem(dev);
        /* Only enable hotplug handling once the fbdev is fully set up. */
        dev_priv->enable_hotplug_processing = true;
  
@@@ -1672,7 -1676,7 +1678,7 @@@ int i915_driver_load(struct drm_device 
        return 0;
  
  out_gem_unload:
-       if (dev_priv->mm.inactive_shrinker.shrink)
+       if (dev_priv->mm.inactive_shrinker.scan_objects)
                unregister_shrinker(&dev_priv->mm.inactive_shrinker);
  
        if (dev->pdev->msi_enabled)
@@@ -1711,7 -1715,7 +1717,7 @@@ int i915_driver_unload(struct drm_devic
  
        i915_teardown_sysfs(dev);
  
-       if (dev_priv->mm.inactive_shrinker.shrink)
+       if (dev_priv->mm.inactive_shrinker.scan_objects)
                unregister_shrinker(&dev_priv->mm.inactive_shrinker);
  
        mutex_lock(&dev->struct_mutex);
@@@ -41,9 -41,6 +41,9 @@@ static void i915_gem_object_flush_gtt_w
  static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj,
                                                   bool force);
  static __must_check int
 +i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
 +                             bool readonly);
 +static __must_check int
  i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
                           struct i915_address_space *vm,
                           unsigned alignment,
@@@ -60,10 -57,12 +60,12 @@@ static void i915_gem_object_update_fenc
                                         struct drm_i915_fence_reg *fence,
                                         bool enable);
  
- static int i915_gem_inactive_shrink(struct shrinker *shrinker,
-                                   struct shrink_control *sc);
+ static unsigned long i915_gem_inactive_count(struct shrinker *shrinker,
+                                            struct shrink_control *sc);
+ static unsigned long i915_gem_inactive_scan(struct shrinker *shrinker,
+                                           struct shrink_control *sc);
  static long i915_gem_purge(struct drm_i915_private *dev_priv, long target);
- static void i915_gem_shrink_all(struct drm_i915_private *dev_priv);
+ static long i915_gem_shrink_all(struct drm_i915_private *dev_priv);
  static void i915_gem_object_truncate(struct drm_i915_gem_object *obj);
  
  static bool cpu_cache_is_coherent(struct drm_device *dev,
@@@ -433,9 -432,11 +435,9 @@@ i915_gem_shmem_pread(struct drm_device 
                 * optimizes for the case when the gpu will dirty the data
                 * anyway again before the next pread happens. */
                needs_clflush = !cpu_cache_is_coherent(dev, obj->cache_level);
 -              if (i915_gem_obj_bound_any(obj)) {
 -                      ret = i915_gem_object_set_to_gtt_domain(obj, false);
 -                      if (ret)
 -                              return ret;
 -              }
 +              ret = i915_gem_object_wait_rendering(obj, true);
 +              if (ret)
 +                      return ret;
        }
  
        ret = i915_gem_object_get_pages(obj);
@@@ -747,9 -748,11 +749,9 @@@ i915_gem_shmem_pwrite(struct drm_devic
                 * optimizes for the case when the gpu will use the data
                 * right away and we therefore have to clflush anyway. */
                needs_clflush_after = cpu_write_needs_clflush(obj);
 -              if (i915_gem_obj_bound_any(obj)) {
 -                      ret = i915_gem_object_set_to_gtt_domain(obj, true);
 -                      if (ret)
 -                              return ret;
 -              }
 +              ret = i915_gem_object_wait_rendering(obj, false);
 +              if (ret)
 +                      return ret;
        }
        /* Same trick applies to invalidate partially written cachelines read
         * before writing. */
@@@ -963,7 -966,7 +965,7 @@@ i915_gem_check_olr(struct intel_ring_bu
        BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex));
  
        ret = 0;
 -      if (seqno == ring->outstanding_lazy_request)
 +      if (seqno == ring->outstanding_lazy_seqno)
                ret = i915_add_request(ring, NULL);
  
        return ret;
                if (i915_terminally_wedged(&dev_priv->gpu_error))
                        return VM_FAULT_SIGBUS;
        case -EAGAIN:
-               /* Give the error handler a chance to run and move the
-                * objects off the GPU active list. Next time we service the
-                * fault, we should be able to transition the page into the
-                * GTT without touching the GPU (and so avoid further
-                * EIO/EGAIN). If the GPU is wedged, then there is no issue
-                * with coherency, just lost writes.
+               /*
+                * EAGAIN means the gpu is hung and we'll wait for the error
+                * handler to reset everything when re-faulting in
+                * i915_mutex_lock_interruptible.
                 */
-               set_need_resched();
        case 0:
        case -ERESTARTSYS:
        case -EINTR:
@@@ -1694,6 -1694,7 +1693,7 @@@ static lon
  __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
                  bool purgeable_only)
  {
+       struct list_head still_bound_list;
        struct drm_i915_gem_object *obj, *next;
        long count = 0;
  
                }
        }
  
-       list_for_each_entry_safe(obj, next, &dev_priv->mm.bound_list,
-                                global_list) {
+       /*
+        * As we may completely rewrite the bound list whilst unbinding
+        * (due to retiring requests) we have to strictly process only
+        * one element of the list at the time, and recheck the list
+        * on every iteration.
+        */
+       INIT_LIST_HEAD(&still_bound_list);
+       while (count < target && !list_empty(&dev_priv->mm.bound_list)) {
                struct i915_vma *vma, *v;
  
+               obj = list_first_entry(&dev_priv->mm.bound_list,
+                                      typeof(*obj), global_list);
+               list_move_tail(&obj->global_list, &still_bound_list);
                if (!i915_gem_object_is_purgeable(obj) && purgeable_only)
                        continue;
  
+               /*
+                * Hold a reference whilst we unbind this object, as we may
+                * end up waiting for and retiring requests. This might
+                * release the final reference (held by the active list)
+                * and result in the object being freed from under us.
+                * in this object being freed.
+                *
+                * Note 1: Shrinking the bound list is special since only active
+                * (and hence bound objects) can contain such limbo objects, so
+                * we don't need special tricks for shrinking the unbound list.
+                * The only other place where we have to be careful with active
+                * objects suddenly disappearing due to retiring requests is the
+                * eviction code.
+                *
+                * Note 2: Even though the bound list doesn't hold a reference
+                * to the object we can safely grab one here: The final object
+                * unreferencing and the bound_list are both protected by the
+                * dev->struct_mutex and so we won't ever be able to observe an
+                * object on the bound_list with a reference count equals 0.
+                */
+               drm_gem_object_reference(&obj->base);
                list_for_each_entry_safe(vma, v, &obj->vma_list, vma_link)
                        if (i915_vma_unbind(vma))
                                break;
  
-               if (!i915_gem_object_put_pages(obj)) {
+               if (i915_gem_object_put_pages(obj) == 0)
                        count += obj->base.size >> PAGE_SHIFT;
-                       if (count >= target)
-                               return count;
-               }
+               drm_gem_object_unreference(&obj->base);
        }
+       list_splice(&still_bound_list, &dev_priv->mm.bound_list);
  
        return count;
  }
@@@ -1735,16 -1768,21 +1767,21 @@@ i915_gem_purge(struct drm_i915_private 
        return __i915_gem_shrink(dev_priv, target, true);
  }
  
- static void
+ static long
  i915_gem_shrink_all(struct drm_i915_private *dev_priv)
  {
        struct drm_i915_gem_object *obj, *next;
+       long freed = 0;
  
        i915_gem_evict_everything(dev_priv->dev);
  
        list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list,
-                                global_list)
+                                global_list) {
+               if (obj->pages_pin_count == 0)
+                       freed += obj->base.size >> PAGE_SHIFT;
                i915_gem_object_put_pages(obj);
+       }
+       return freed;
  }
  
  static int
@@@ -2040,10 -2078,11 +2077,10 @@@ int __i915_add_request(struct intel_rin
        if (ret)
                return ret;
  
 -      request = kmalloc(sizeof(*request), GFP_KERNEL);
 -      if (request == NULL)
 +      request = ring->preallocated_lazy_request;
 +      if (WARN_ON(request == NULL))
                return -ENOMEM;
  
 -
        /* Record the position of the start of the request so that
         * should we detect the updated seqno part-way through the
         * GPU processing the request, we never over-estimate the
        request_ring_position = intel_ring_get_tail(ring);
  
        ret = ring->add_request(ring);
 -      if (ret) {
 -              kfree(request);
 +      if (ret)
                return ret;
 -      }
  
        request->seqno = intel_ring_get_seqno(ring);
        request->ring = ring;
        request->head = request_start;
        request->tail = request_ring_position;
 -      request->ctx = ring->last_context;
 -      request->batch_obj = obj;
  
        /* Whilst this request exists, batch_obj will be on the
         * active_list, and so will hold the active reference. Only when this
         * inactive_list and lose its active reference. Hence we do not need
         * to explicitly hold another reference here.
         */
 +      request->batch_obj = obj;
  
 +      /* Hold a reference to the current context so that we can inspect
 +       * it later in case a hangcheck error event fires.
 +       */
 +      request->ctx = ring->last_context;
        if (request->ctx)
                i915_gem_context_reference(request->ctx);
  
        }
  
        trace_i915_gem_request_add(ring, request->seqno);
 -      ring->outstanding_lazy_request = 0;
 +      ring->outstanding_lazy_seqno = 0;
 +      ring->preallocated_lazy_request = NULL;
  
        if (!dev_priv->ums.mm_suspended) {
                i915_queue_hangcheck(ring->dev);
@@@ -2187,21 -2224,6 +2224,21 @@@ static bool i915_request_guilty(struct 
        return false;
  }
  
 +static bool i915_context_is_banned(const struct i915_ctx_hang_stats *hs)
 +{
 +      const unsigned long elapsed = get_seconds() - hs->guilty_ts;
 +
 +      if (hs->banned)
 +              return true;
 +
 +      if (elapsed <= DRM_I915_CTX_BAN_PERIOD) {
 +              DRM_ERROR("context hanging too fast, declaring banned!\n");
 +              return true;
 +      }
 +
 +      return false;
 +}
 +
  static void i915_set_reset_status(struct intel_ring_buffer *ring,
                                  struct drm_i915_gem_request *request,
                                  u32 acthd)
                hs = &request->file_priv->hang_stats;
  
        if (hs) {
 -              if (guilty)
 +              if (guilty) {
 +                      hs->banned = i915_context_is_banned(hs);
                        hs->batch_active++;
 -              else
 +                      hs->guilty_ts = get_seconds();
 +              } else {
                        hs->batch_pending++;
 +              }
        }
  }
  
@@@ -2622,17 -2641,11 +2659,17 @@@ int i915_vma_unbind(struct i915_vma *vm
        drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
        int ret;
  
 +      /* For now we only ever use 1 vma per object */
 +      WARN_ON(!list_is_singular(&obj->vma_list));
 +
        if (list_empty(&vma->vma_link))
                return 0;
  
 -      if (!drm_mm_node_allocated(&vma->node))
 -              goto destroy;
 +      if (!drm_mm_node_allocated(&vma->node)) {
 +              i915_gem_vma_destroy(vma);
 +
 +              return 0;
 +      }
  
        if (obj->pin_count)
                return -EBUSY;
  
        drm_mm_remove_node(&vma->node);
  
 -destroy:
        i915_gem_vma_destroy(vma);
  
        /* Since the unbound list is global, only move to that list if
 -       * no more VMAs exist.
 -       * NB: Until we have real VMAs there will only ever be one */
 -      WARN_ON(!list_empty(&obj->vma_list));
 +       * no more VMAs exist. */
        if (list_empty(&obj->vma_list))
                list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list);
  
@@@ -3999,6 -4015,7 +4036,6 @@@ void i915_gem_object_init(struct drm_i9
  {
        INIT_LIST_HEAD(&obj->global_list);
        INIT_LIST_HEAD(&obj->ring_list);
 -      INIT_LIST_HEAD(&obj->exec_list);
        INIT_LIST_HEAD(&obj->obj_exec_link);
        INIT_LIST_HEAD(&obj->vma_list);
  
@@@ -4130,19 -4147,8 +4167,19 @@@ void i915_gem_free_object(struct drm_ge
        i915_gem_object_free(obj);
  }
  
 -struct i915_vma *i915_gem_vma_create(struct drm_i915_gem_object *obj,
 +struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
                                     struct i915_address_space *vm)
 +{
 +      struct i915_vma *vma;
 +      list_for_each_entry(vma, &obj->vma_list, vma_link)
 +              if (vma->vm == vm)
 +                      return vma;
 +
 +      return NULL;
 +}
 +
 +static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
 +                                            struct i915_address_space *vm)
  {
        struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
        if (vma == NULL)
        return vma;
  }
  
 +struct i915_vma *
 +i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
 +                                struct i915_address_space *vm)
 +{
 +      struct i915_vma *vma;
 +
 +      vma = i915_gem_obj_to_vma(obj, vm);
 +      if (!vma)
 +              vma = __i915_gem_vma_create(obj, vm);
 +
 +      return vma;
 +}
 +
  void i915_gem_vma_destroy(struct i915_vma *vma)
  {
        WARN_ON(vma->node.allocated);
 +
 +      /* Keep the vma as a placeholder in the execbuffer reservation lists */
 +      if (!list_empty(&vma->exec_list))
 +              return;
 +
        list_del(&vma->vma_link);
 +
        kfree(vma);
  }
  
@@@ -4222,35 -4209,36 +4259,35 @@@ i915_gem_idle(struct drm_device *dev
        return 0;
  }
  
 -void i915_gem_l3_remap(struct drm_device *dev)
 +int i915_gem_l3_remap(struct intel_ring_buffer *ring, int slice)
  {
 +      struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
 -      u32 misccpctl;
 -      int i;
 -
 -      if (!HAS_L3_GPU_CACHE(dev))
 -              return;
 +      u32 reg_base = GEN7_L3LOG_BASE + (slice * 0x200);
 +      u32 *remap_info = dev_priv->l3_parity.remap_info[slice];
 +      int i, ret;
  
 -      if (!dev_priv->l3_parity.remap_info)
 -              return;
 +      if (!HAS_L3_DPF(dev) || !remap_info)
 +              return 0;
  
 -      misccpctl = I915_READ(GEN7_MISCCPCTL);
 -      I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
 -      POSTING_READ(GEN7_MISCCPCTL);
 +      ret = intel_ring_begin(ring, GEN7_L3LOG_SIZE / 4 * 3);
 +      if (ret)
 +              return ret;
  
 +      /*
 +       * Note: We do not worry about the concurrent register cacheline hang
 +       * here because no other code should access these registers other than
 +       * at initialization time.
 +       */
        for (i = 0; i < GEN7_L3LOG_SIZE; i += 4) {
 -              u32 remap = I915_READ(GEN7_L3LOG_BASE + i);
 -              if (remap && remap != dev_priv->l3_parity.remap_info[i/4])
 -                      DRM_DEBUG("0x%x was already programmed to %x\n",
 -                                GEN7_L3LOG_BASE + i, remap);
 -              if (remap && !dev_priv->l3_parity.remap_info[i/4])
 -                      DRM_DEBUG_DRIVER("Clearing remapped register\n");
 -              I915_WRITE(GEN7_L3LOG_BASE + i, dev_priv->l3_parity.remap_info[i/4]);
 +              intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
 +              intel_ring_emit(ring, reg_base + i);
 +              intel_ring_emit(ring, remap_info[i/4]);
        }
  
 -      /* Make sure all the writes land before disabling dop clock gating */
 -      POSTING_READ(GEN7_L3LOG_BASE);
 +      intel_ring_advance(ring);
  
 -      I915_WRITE(GEN7_MISCCPCTL, misccpctl);
 +      return ret;
  }
  
  void i915_gem_init_swizzling(struct drm_device *dev)
@@@ -4342,7 -4330,7 +4379,7 @@@ in
  i915_gem_init_hw(struct drm_device *dev)
  {
        drm_i915_private_t *dev_priv = dev->dev_private;
 -      int ret;
 +      int ret, i;
  
        if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt())
                return -EIO;
        if (dev_priv->ellc_size)
                I915_WRITE(HSW_IDICR, I915_READ(HSW_IDICR) | IDIHASHMSK(0xf));
  
 +      if (IS_HSW_GT3(dev))
 +              I915_WRITE(MI_PREDICATE_RESULT_2, LOWER_SLICE_ENABLED);
 +      else
 +              I915_WRITE(MI_PREDICATE_RESULT_2, LOWER_SLICE_DISABLED);
 +
        if (HAS_PCH_NOP(dev)) {
                u32 temp = I915_READ(GEN7_MSG_CTL);
                temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK);
                I915_WRITE(GEN7_MSG_CTL, temp);
        }
  
 -      i915_gem_l3_remap(dev);
 -
        i915_gem_init_swizzling(dev);
  
        ret = i915_gem_init_rings(dev);
        if (ret)
                return ret;
  
 +      for (i = 0; i < NUM_L3_SLICES(dev); i++)
 +              i915_gem_l3_remap(&dev_priv->ring[RCS], i);
 +
        /*
         * XXX: There was some w/a described somewhere suggesting loading
         * contexts before PPGTT.
@@@ -4541,7 -4523,6 +4578,7 @@@ i915_gem_load(struct drm_device *dev
        INIT_LIST_HEAD(&dev_priv->vm_list);
        i915_init_vm(dev_priv, &dev_priv->gtt.base);
  
 +      INIT_LIST_HEAD(&dev_priv->context_list);
        INIT_LIST_HEAD(&dev_priv->mm.unbound_list);
        INIT_LIST_HEAD(&dev_priv->mm.bound_list);
        INIT_LIST_HEAD(&dev_priv->mm.fence_list);
  
        dev_priv->mm.interruptible = true;
  
-       dev_priv->mm.inactive_shrinker.shrink = i915_gem_inactive_shrink;
+       dev_priv->mm.inactive_shrinker.scan_objects = i915_gem_inactive_scan;
+       dev_priv->mm.inactive_shrinker.count_objects = i915_gem_inactive_count;
        dev_priv->mm.inactive_shrinker.seeks = DEFAULT_SEEKS;
        register_shrinker(&dev_priv->mm.inactive_shrinker);
  }
@@@ -4804,8 -4786,8 +4842,8 @@@ static bool mutex_is_locked_by(struct m
  #endif
  }
  
- static int
- i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
+ static unsigned long
+ i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc)
  {
        struct drm_i915_private *dev_priv =
                container_of(shrinker,
                             mm.inactive_shrinker);
        struct drm_device *dev = dev_priv->dev;
        struct drm_i915_gem_object *obj;
-       int nr_to_scan = sc->nr_to_scan;
        bool unlock = true;
-       int cnt;
+       unsigned long count;
  
        if (!mutex_trylock(&dev->struct_mutex)) {
                if (!mutex_is_locked_by(&dev->struct_mutex, current))
-                       return 0;
+                       return SHRINK_STOP;
  
                if (dev_priv->mm.shrinker_no_lock_stealing)
-                       return 0;
+                       return SHRINK_STOP;
  
                unlock = false;
        }
  
-       if (nr_to_scan) {
-               nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan);
-               if (nr_to_scan > 0)
-                       nr_to_scan -= __i915_gem_shrink(dev_priv, nr_to_scan,
-                                                       false);
-               if (nr_to_scan > 0)
-                       i915_gem_shrink_all(dev_priv);
-       }
-       cnt = 0;
+       count = 0;
        list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
                if (obj->pages_pin_count == 0)
-                       cnt += obj->base.size >> PAGE_SHIFT;
+                       count += obj->base.size >> PAGE_SHIFT;
  
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
                if (obj->active)
                        continue;
  
                if (obj->pin_count == 0 && obj->pages_pin_count == 0)
-                       cnt += obj->base.size >> PAGE_SHIFT;
+                       count += obj->base.size >> PAGE_SHIFT;
        }
  
        if (unlock)
                mutex_unlock(&dev->struct_mutex);
-       return cnt;
+       return count;
  }
  
  /* All the new VM stuff */
@@@ -4887,10 -4859,11 +4915,10 @@@ bool i915_gem_obj_bound(struct drm_i915
  
  bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o)
  {
 -      struct drm_i915_private *dev_priv = o->base.dev->dev_private;
 -      struct i915_address_space *vm;
 +      struct i915_vma *vma;
  
 -      list_for_each_entry(vm, &dev_priv->vm_list, global_link)
 -              if (i915_gem_obj_bound(o, vm))
 +      list_for_each_entry(vma, &o->vma_list, vma_link)
 +              if (drm_mm_node_allocated(&vma->node))
                        return true;
  
        return false;
@@@ -4913,3 -4886,61 +4941,37 @@@ unsigned long i915_gem_obj_size(struct 
  
        return 0;
  }
 -
 -struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
 -                                   struct i915_address_space *vm)
 -{
 -      struct i915_vma *vma;
 -      list_for_each_entry(vma, &obj->vma_list, vma_link)
 -              if (vma->vm == vm)
 -                      return vma;
 -
 -      return NULL;
 -}
 -
 -struct i915_vma *
 -i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
 -                                struct i915_address_space *vm)
 -{
 -      struct i915_vma *vma;
 -
 -      vma = i915_gem_obj_to_vma(obj, vm);
 -      if (!vma)
 -              vma = i915_gem_vma_create(obj, vm);
 -
 -      return vma;
 -}
+ static unsigned long
+ i915_gem_inactive_scan(struct shrinker *shrinker, struct shrink_control *sc)
+ {
+       struct drm_i915_private *dev_priv =
+               container_of(shrinker,
+                            struct drm_i915_private,
+                            mm.inactive_shrinker);
+       struct drm_device *dev = dev_priv->dev;
+       int nr_to_scan = sc->nr_to_scan;
+       unsigned long freed;
+       bool unlock = true;
+       if (!mutex_trylock(&dev->struct_mutex)) {
+               if (!mutex_is_locked_by(&dev->struct_mutex, current))
+                       return 0;
+               if (dev_priv->mm.shrinker_no_lock_stealing)
+                       return 0;
+               unlock = false;
+       }
+       freed = i915_gem_purge(dev_priv, nr_to_scan);
+       if (freed < nr_to_scan)
+               freed += __i915_gem_shrink(dev_priv, nr_to_scan,
+                                                       false);
+       if (freed < nr_to_scan)
+               freed += i915_gem_shrink_all(dev_priv);
+       if (unlock)
+               mutex_unlock(&dev->struct_mutex);
+       return freed;
+ }
@@@ -201,6 -201,9 +201,9 @@@ int i915_gem_init_stolen(struct drm_dev
        struct drm_i915_private *dev_priv = dev->dev_private;
        int bios_reserved = 0;
  
+       if (dev_priv->gtt.stolen_size == 0)
+               return 0;
        dev_priv->mm.stolen_base = i915_stolen_to_physical(dev);
        if (dev_priv->mm.stolen_base == 0)
                return 0;
@@@ -392,7 -395,7 +395,7 @@@ i915_gem_object_create_stolen_for_preal
        if (gtt_offset == I915_GTT_OFFSET_NONE)
                return obj;
  
 -      vma = i915_gem_vma_create(obj, ggtt);
 +      vma = i915_gem_obj_lookup_or_create_vma(obj, ggtt);
        if (IS_ERR(vma)) {
                ret = PTR_ERR(vma);
                goto err_out;
@@@ -665,8 -665,7 +665,8 @@@ static int i915_get_vblank_timestamp(st
                                                     crtc);
  }
  
 -static int intel_hpd_irq_event(struct drm_device *dev, struct drm_connector *connector)
 +static bool intel_hpd_irq_event(struct drm_device *dev,
 +                              struct drm_connector *connector)
  {
        enum drm_connector_status old_status;
  
        old_status = connector->status;
  
        connector->status = connector->funcs->detect(connector, false);
 -      DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
 +      if (old_status == connector->status)
 +              return false;
 +
 +      DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
                      connector->base.id,
                      drm_get_connector_name(connector),
 -                    old_status, connector->status);
 -      return (old_status != connector->status);
 +                    drm_get_connector_status_name(old_status),
 +                    drm_get_connector_status_name(connector->status));
 +
 +      return true;
  }
  
  /*
@@@ -888,10 -882,9 +888,10 @@@ static void ivybridge_parity_work(struc
        drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
                                                    l3_parity.error_work);
        u32 error_status, row, bank, subbank;
 -      char *parity_event[5];
 +      char *parity_event[6];
        uint32_t misccpctl;
        unsigned long flags;
 +      uint8_t slice = 0;
  
        /* We must turn off DOP level clock gating to access the L3 registers.
         * In order to prevent a get/put style interface, acquire struct mutex
         */
        mutex_lock(&dev_priv->dev->struct_mutex);
  
 +      /* If we've screwed up tracking, just let the interrupt fire again */
 +      if (WARN_ON(!dev_priv->l3_parity.which_slice))
 +              goto out;
 +
        misccpctl = I915_READ(GEN7_MISCCPCTL);
        I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
        POSTING_READ(GEN7_MISCCPCTL);
  
 -      error_status = I915_READ(GEN7_L3CDERRST1);
 -      row = GEN7_PARITY_ERROR_ROW(error_status);
 -      bank = GEN7_PARITY_ERROR_BANK(error_status);
 -      subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
 +      while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) {
 +              u32 reg;
  
 -      I915_WRITE(GEN7_L3CDERRST1, GEN7_PARITY_ERROR_VALID |
 -                                  GEN7_L3CDERRST1_ENABLE);
 -      POSTING_READ(GEN7_L3CDERRST1);
 +              slice--;
 +              if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv->dev)))
 +                      break;
  
 -      I915_WRITE(GEN7_MISCCPCTL, misccpctl);
 +              dev_priv->l3_parity.which_slice &= ~(1<<slice);
  
 -      spin_lock_irqsave(&dev_priv->irq_lock, flags);
 -      ilk_enable_gt_irq(dev_priv, GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
 -      spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
 +              reg = GEN7_L3CDERRST1 + (slice * 0x200);
  
 -      mutex_unlock(&dev_priv->dev->struct_mutex);
 +              error_status = I915_READ(reg);
 +              row = GEN7_PARITY_ERROR_ROW(error_status);
 +              bank = GEN7_PARITY_ERROR_BANK(error_status);
 +              subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
 +
 +              I915_WRITE(reg, GEN7_PARITY_ERROR_VALID | GEN7_L3CDERRST1_ENABLE);
 +              POSTING_READ(reg);
 +
 +              parity_event[0] = I915_L3_PARITY_UEVENT "=1";
 +              parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
 +              parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
 +              parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
 +              parity_event[4] = kasprintf(GFP_KERNEL, "SLICE=%d", slice);
 +              parity_event[5] = NULL;
 +
 +              kobject_uevent_env(&dev_priv->dev->primary->kdev.kobj,
 +                                 KOBJ_CHANGE, parity_event);
  
 -      parity_event[0] = I915_L3_PARITY_UEVENT "=1";
 -      parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
 -      parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
 -      parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
 -      parity_event[4] = NULL;
 +              DRM_DEBUG("Parity error: Slice = %d, Row = %d, Bank = %d, Sub bank = %d.\n",
 +                        slice, row, bank, subbank);
  
 -      kobject_uevent_env(&dev_priv->dev->primary->kdev.kobj,
 -                         KOBJ_CHANGE, parity_event);
 +              kfree(parity_event[4]);
 +              kfree(parity_event[3]);
 +              kfree(parity_event[2]);
 +              kfree(parity_event[1]);
 +      }
  
 -      DRM_DEBUG("Parity error: Row = %d, Bank = %d, Sub bank = %d.\n",
 -                row, bank, subbank);
 +      I915_WRITE(GEN7_MISCCPCTL, misccpctl);
  
 -      kfree(parity_event[3]);
 -      kfree(parity_event[2]);
 -      kfree(parity_event[1]);
 +out:
 +      WARN_ON(dev_priv->l3_parity.which_slice);
 +      spin_lock_irqsave(&dev_priv->irq_lock, flags);
 +      ilk_enable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv->dev));
 +      spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
 +
 +      mutex_unlock(&dev_priv->dev->struct_mutex);
  }
  
 -static void ivybridge_parity_error_irq_handler(struct drm_device *dev)
 +static void ivybridge_parity_error_irq_handler(struct drm_device *dev, u32 iir)
  {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
  
 -      if (!HAS_L3_GPU_CACHE(dev))
 +      if (!HAS_L3_DPF(dev))
                return;
  
        spin_lock(&dev_priv->irq_lock);
 -      ilk_disable_gt_irq(dev_priv, GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
 +      ilk_disable_gt_irq(dev_priv, GT_PARITY_ERROR(dev));
        spin_unlock(&dev_priv->irq_lock);
  
 +      iir &= GT_PARITY_ERROR(dev);
 +      if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1)
 +              dev_priv->l3_parity.which_slice |= 1 << 1;
 +
 +      if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
 +              dev_priv->l3_parity.which_slice |= 1 << 0;
 +
        queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work);
  }
  
@@@ -1008,8 -975,8 +1008,8 @@@ static void snb_gt_irq_handler(struct d
                i915_handle_error(dev, false);
        }
  
 -      if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
 -              ivybridge_parity_error_irq_handler(dev);
 +      if (gt_iir & GT_PARITY_ERROR(dev))
 +              ivybridge_parity_error_irq_handler(dev, gt_iir);
  }
  
  #define HPD_STORM_DETECT_PERIOD 1000
@@@ -1421,6 -1388,7 +1421,6 @@@ static irqreturn_t ironlake_irq_handler
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 de_iir, gt_iir, de_ier, sde_ier = 0;
        irqreturn_t ret = IRQ_NONE;
 -      bool err_int_reenable = false;
  
        atomic_inc(&dev_priv->irq_received);
  
                POSTING_READ(SDEIER);
        }
  
 -      /* On Haswell, also mask ERR_INT because we don't want to risk
 -       * generating "unclaimed register" interrupts from inside the interrupt
 -       * handler. */
 -      if (IS_HASWELL(dev)) {
 -              spin_lock(&dev_priv->irq_lock);
 -              err_int_reenable = ~dev_priv->irq_mask & DE_ERR_INT_IVB;
 -              if (err_int_reenable)
 -                      ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
 -              spin_unlock(&dev_priv->irq_lock);
 -      }
 -
        gt_iir = I915_READ(GTIIR);
        if (gt_iir) {
                if (INTEL_INFO(dev)->gen >= 6)
                }
        }
  
 -      if (err_int_reenable) {
 -              spin_lock(&dev_priv->irq_lock);
 -              if (ivb_can_enable_err_int(dev))
 -                      ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
 -              spin_unlock(&dev_priv->irq_lock);
 -      }
 -
        I915_WRITE(DEIER, de_ier);
        POSTING_READ(DEIER);
        if (!HAS_PCH_NOP(dev)) {
        return ret;
  }
  
+ static void i915_error_wake_up(struct drm_i915_private *dev_priv,
+                              bool reset_completed)
+ {
+       struct intel_ring_buffer *ring;
+       int i;
+       /*
+        * Notify all waiters for GPU completion events that reset state has
+        * been changed, and that they need to restart their wait after
+        * checking for potential errors (and bail out to drop locks if there is
+        * a gpu reset pending so that i915_error_work_func can acquire them).
+        */
+       /* Wake up __wait_seqno, potentially holding dev->struct_mutex. */
+       for_each_ring(ring, dev_priv, i)
+               wake_up_all(&ring->irq_queue);
+       /* Wake up intel_crtc_wait_for_pending_flips, holding crtc->mutex. */
+       wake_up_all(&dev_priv->pending_flip_queue);
+       /*
+        * Signal tasks blocked in i915_gem_wait_for_error that the pending
+        * reset state is cleared.
+        */
+       if (reset_completed)
+               wake_up_all(&dev_priv->gpu_error.reset_queue);
+ }
  /**
   * i915_error_work_func - do process context error handling work
   * @work: work struct
@@@ -1497,11 -1511,10 +1525,10 @@@ static void i915_error_work_func(struc
        drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t,
                                                    gpu_error);
        struct drm_device *dev = dev_priv->dev;
-       struct intel_ring_buffer *ring;
        char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
        char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
        char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
-       int i, ret;
+       int ret;
  
        kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
  
                kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE,
                                   reset_event);
  
+               /*
+                * All state reset _must_ be completed before we update the
+                * reset counter, for otherwise waiters might miss the reset
+                * pending state and not properly drop locks, resulting in
+                * deadlocks with the reset work.
+                */
                ret = i915_reset(dev);
  
+               intel_display_handle_reset(dev);
                if (ret == 0) {
                        /*
                         * After all the gem state is reset, increment the reset
                        atomic_set(&error->reset_counter, I915_WEDGED);
                }
  
-               for_each_ring(ring, dev_priv, i)
-                       wake_up_all(&ring->irq_queue);
-               intel_display_handle_reset(dev);
-               wake_up_all(&dev_priv->gpu_error.reset_queue);
+               /*
+                * Note: The wake_up also serves as a memory barrier so that
+                * waiters see the update value of the reset counter atomic_t.
+                */
+               i915_error_wake_up(dev_priv, true);
        }
  }
  
@@@ -1656,8 -1676,6 +1690,6 @@@ static void i915_report_and_clear_eir(s
  void i915_handle_error(struct drm_device *dev, bool wedged)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_ring_buffer *ring;
-       int i;
  
        i915_capture_error_state(dev);
        i915_report_and_clear_eir(dev);
                                &dev_priv->gpu_error.reset_counter);
  
                /*
-                * Wakeup waiting processes so that the reset work item
-                * doesn't deadlock trying to grab various locks.
+                * Wakeup waiting processes so that the reset work function
+                * i915_error_work_func doesn't deadlock trying to grab various
+                * locks. By bumping the reset counter first, the woken
+                * processes will see a reset in progress and back off,
+                * releasing their locks and then wait for the reset completion.
+                * We must do this for _all_ gpu waiters that might hold locks
+                * that the reset work needs to acquire.
+                *
+                * Note: The wake_up serves as the required memory barrier to
+                * ensure that the waiters see the updated value of the reset
+                * counter atomic_t.
                 */
-               for_each_ring(ring, dev_priv, i)
-                       wake_up_all(&ring->irq_queue);
+               i915_error_wake_up(dev_priv, false);
        }
  
-       queue_work(dev_priv->wq, &dev_priv->gpu_error.work);
+       /*
+        * Our reset work can grab modeset locks (since it needs to reset the
+        * state of outstanding pagelips). Hence it must not be run on our own
+        * dev-priv->wq work queue for otherwise the flush_work in the pageflip
+        * code will deadlock.
+        */
+       schedule_work(&dev_priv->gpu_error.work);
  }
  
  static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe)
@@@ -1989,8 -2021,6 +2035,8 @@@ static void i915_hangcheck_elapsed(unsi
  
                if (ring->hangcheck.seqno == seqno) {
                        if (ring_idle(ring, seqno)) {
 +                              ring->hangcheck.action = HANGCHECK_IDLE;
 +
                                if (waitqueue_active(&ring->irq_queue)) {
                                        /* Issue a wake-up to catch stuck h/w. */
                                        DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
                                                                    acthd);
  
                                switch (ring->hangcheck.action) {
 +                              case HANGCHECK_IDLE:
                                case HANGCHECK_WAIT:
                                        break;
                                case HANGCHECK_ACTIVE:
                                }
                        }
                } else {
 +                      ring->hangcheck.action = HANGCHECK_ACTIVE;
 +
                        /* Gradually reduce the count so that we catch DoS
                         * attempts across multiple batches.
                         */
@@@ -2227,10 -2254,10 +2273,10 @@@ static void gen5_gt_irq_postinstall(str
        pm_irqs = gt_irqs = 0;
  
        dev_priv->gt_irq_mask = ~0;
 -      if (HAS_L3_GPU_CACHE(dev)) {
 +      if (HAS_L3_DPF(dev)) {
                /* L3 parity interrupt is always unmasked. */
 -              dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
 -              gt_irqs |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
 +              dev_priv->gt_irq_mask = ~GT_PARITY_ERROR(dev);
 +              gt_irqs |= GT_PARITY_ERROR(dev);
        }
  
        gt_irqs |= GT_RENDER_USER_INTERRUPT;
@@@ -58,7 -58,7 +58,7 @@@ static const u32 hsw_ddi_translations_f
        0x00FFFFFF, 0x00040006          /* HDMI parameters */
  };
  
 -static enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
 +enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
  {
        struct drm_encoder *encoder = &intel_encoder->base;
        int type = intel_encoder->type;
@@@ -767,9 -767,9 +767,9 @@@ void intel_ddi_enable_transcoder_func(s
                BUG();
        }
  
 -      if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
 +      if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_PVSYNC)
                temp |= TRANS_DDI_PVSYNC;
 -      if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
 +      if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_PHSYNC)
                temp |= TRANS_DDI_PHSYNC;
  
        if (cpu_transcoder == TRANSCODER_EDP) {
                        /* Can only use the always-on power well for eDP when
                         * not using the panel fitter, and when not using motion
                          * blur mitigation (which we don't support). */
-                       if (intel_crtc->config.pch_pfit.size)
+                       if (intel_crtc->config.pch_pfit.enabled)
                                temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
                        else
                                temp |= TRANS_DDI_EDP_INPUT_A_ON;
@@@ -1268,37 -1268,6 +1268,37 @@@ static void intel_ddi_get_config(struc
                flags |= DRM_MODE_FLAG_NVSYNC;
  
        pipe_config->adjusted_mode.flags |= flags;
 +
 +      switch (temp & TRANS_DDI_BPC_MASK) {
 +      case TRANS_DDI_BPC_6:
 +              pipe_config->pipe_bpp = 18;
 +              break;
 +      case TRANS_DDI_BPC_8:
 +              pipe_config->pipe_bpp = 24;
 +              break;
 +      case TRANS_DDI_BPC_10:
 +              pipe_config->pipe_bpp = 30;
 +              break;
 +      case TRANS_DDI_BPC_12:
 +              pipe_config->pipe_bpp = 36;
 +              break;
 +      default:
 +              break;
 +      }
 +
 +      switch (temp & TRANS_DDI_MODE_SELECT_MASK) {
 +      case TRANS_DDI_MODE_SELECT_HDMI:
 +      case TRANS_DDI_MODE_SELECT_DVI:
 +      case TRANS_DDI_MODE_SELECT_FDI:
 +              break;
 +      case TRANS_DDI_MODE_SELECT_DP_SST:
 +      case TRANS_DDI_MODE_SELECT_DP_MST:
 +              pipe_config->has_dp_encoder = true;
 +              intel_dp_get_m_n(intel_crtc, pipe_config);
 +              break;
 +      default:
 +              break;
 +      }
  }
  
  static void intel_ddi_destroy(struct drm_encoder *encoder)
@@@ -47,8 -47,8 +47,8 @@@ static void intel_crtc_update_cursor(st
  
  static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
                                struct intel_crtc_config *pipe_config);
 -static void ironlake_crtc_clock_get(struct intel_crtc *crtc,
 -                                  struct intel_crtc_config *pipe_config);
 +static void ironlake_pch_clock_get(struct intel_crtc *crtc,
 +                                 struct intel_crtc_config *pipe_config);
  
  static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
                          int x, int y, struct drm_framebuffer *old_fb);
@@@ -69,6 -69,9 +69,6 @@@ struct intel_limit 
        intel_p2_t          p2;
  };
  
 -/* FDI */
 -#define IRONLAKE_FDI_FREQ             2700000 /* in kHz for mode->clock */
 -
  int
  intel_pch_rawclk(struct drm_device *dev)
  {
@@@ -336,6 -339,19 +336,6 @@@ static const intel_limit_t intel_limits
                .p2_slow = 2, .p2_fast = 20 },
  };
  
 -static const intel_limit_t intel_limits_vlv_dp = {
 -      .dot = { .min = 25000, .max = 270000 },
 -      .vco = { .min = 4000000, .max = 6000000 },
 -      .n = { .min = 1, .max = 7 },
 -      .m = { .min = 22, .max = 450 },
 -      .m1 = { .min = 2, .max = 3 },
 -      .m2 = { .min = 11, .max = 156 },
 -      .p = { .min = 10, .max = 30 },
 -      .p1 = { .min = 1, .max = 3 },
 -      .p2 = { .dot_limit = 270000,
 -              .p2_slow = 2, .p2_fast = 20 },
 -};
 -
  static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
                                                int refclk)
  {
@@@ -398,8 -414,10 +398,8 @@@ static const intel_limit_t *intel_limit
        } else if (IS_VALLEYVIEW(dev)) {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG))
                        limit = &intel_limits_vlv_dac;
 -              else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI))
 -                      limit = &intel_limits_vlv_hdmi;
                else
 -                      limit = &intel_limits_vlv_dp;
 +                      limit = &intel_limits_vlv_hdmi;
        } else if (!IS_GEN2(dev)) {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
                        limit = &intel_limits_i9xx_lvds;
@@@ -733,23 -751,6 +733,23 @@@ vlv_find_best_dpll(const intel_limit_t 
        return true;
  }
  
 +bool intel_crtc_active(struct drm_crtc *crtc)
 +{
 +      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 +
 +      /* Be paranoid as we can arrive here with only partial
 +       * state retrieved from the hardware during setup.
 +       *
 +       * We can ditch the adjusted_mode.clock check as soon
 +       * as Haswell has gained clock readout/fastboot support.
 +       *
 +       * We can ditch the crtc->fb check as soon as we can
 +       * properly reconstruct framebuffers.
 +       */
 +      return intel_crtc->active && crtc->fb &&
 +              intel_crtc->config.adjusted_mode.clock;
 +}
 +
  enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
                                             enum pipe pipe)
  {
@@@ -928,24 -929,6 +928,24 @@@ void assert_pll(struct drm_i915_privat
             state_string(state), state_string(cur_state));
  }
  
 +/* XXX: the dsi pll is shared between MIPI DSI ports */
 +static void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state)
 +{
 +      u32 val;
 +      bool cur_state;
 +
 +      mutex_lock(&dev_priv->dpio_lock);
 +      val = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL);
 +      mutex_unlock(&dev_priv->dpio_lock);
 +
 +      cur_state = val & DSI_PLL_VCO_EN;
 +      WARN(cur_state != state,
 +           "DSI PLL state assertion failure (expected %s, current %s)\n",
 +           state_string(state), state_string(cur_state));
 +}
 +#define assert_dsi_pll_enabled(d) assert_dsi_pll(d, true)
 +#define assert_dsi_pll_disabled(d) assert_dsi_pll(d, false)
 +
  struct intel_shared_dpll *
  intel_crtc_to_shared_dpll(struct intel_crtc *crtc)
  {
@@@ -1086,26 -1069,6 +1086,26 @@@ static void assert_panel_unlocked(struc
             pipe_name(pipe));
  }
  
 +static void assert_cursor(struct drm_i915_private *dev_priv,
 +                        enum pipe pipe, bool state)
 +{
 +      struct drm_device *dev = dev_priv->dev;
 +      bool cur_state;
 +
 +      if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
 +              cur_state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE;
 +      else if (IS_845G(dev) || IS_I865G(dev))
 +              cur_state = I915_READ(_CURACNTR) & CURSOR_ENABLE;
 +      else
 +              cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
 +
 +      WARN(cur_state != state,
 +           "cursor on pipe %c assertion failure (expected %s, current %s)\n",
 +           pipe_name(pipe), state_string(state), state_string(cur_state));
 +}
 +#define assert_cursor_enabled(d, p) assert_cursor(d, p, true)
 +#define assert_cursor_disabled(d, p) assert_cursor(d, p, false)
 +
  void assert_pipe(struct drm_i915_private *dev_priv,
                 enum pipe pipe, bool state)
  {
@@@ -1698,7 -1661,7 +1698,7 @@@ static void lpt_disable_pch_transcoder(
   * returning.
   */
  static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
 -                            bool pch_port)
 +                            bool pch_port, bool dsi)
  {
        enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
                                                                      pipe);
        u32 val;
  
        assert_planes_disabled(dev_priv, pipe);
 +      assert_cursor_disabled(dev_priv, pipe);
        assert_sprites_disabled(dev_priv, pipe);
  
        if (HAS_PCH_LPT(dev_priv->dev))
         * need the check.
         */
        if (!HAS_PCH_SPLIT(dev_priv->dev))
 -              assert_pll_enabled(dev_priv, pipe);
 +              if (dsi)
 +                      assert_dsi_pll_enabled(dev_priv);
 +              else
 +                      assert_pll_enabled(dev_priv, pipe);
        else {
                if (pch_port) {
                        /* if driving the PCH, we need FDI enabled */
@@@ -1769,7 -1728,6 +1769,7 @@@ static void intel_disable_pipe(struct d
         * or we might hang the display.
         */
        assert_planes_disabled(dev_priv, pipe);
 +      assert_cursor_disabled(dev_priv, pipe);
        assert_sprites_disabled(dev_priv, pipe);
  
        /* Don't disable pipe A or pipe A PLLs if needed */
@@@ -2291,7 -2249,7 +2291,7 @@@ intel_pipe_set_base(struct drm_crtc *cr
                I915_WRITE(PIPESRC(intel_crtc->pipe),
                           ((crtc->mode.hdisplay - 1) << 16) |
                           (crtc->mode.vdisplay - 1));
-               if (!intel_crtc->config.pch_pfit.size &&
+               if (!intel_crtc->config.pch_pfit.enabled &&
                    (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
                     intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
                        I915_WRITE(PF_CTL(intel_crtc->pipe), 0);
@@@ -2914,7 -2872,6 +2914,7 @@@ static void lpt_program_iclkip(struct d
  {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 +      int clock = to_intel_crtc(crtc)->config.adjusted_mode.clock;
        u32 divsel, phaseinc, auxdiv, phasedir = 0;
        u32 temp;
  
                        SBI_ICLK);
  
        /* 20MHz is a corner case which is out of range for the 7-bit divisor */
 -      if (crtc->mode.clock == 20000) {
 +      if (clock == 20000) {
                auxdiv = 1;
                divsel = 0x41;
                phaseinc = 0x20;
        } else {
                /* The iCLK virtual clock root frequency is in MHz,
 -               * but the crtc->mode.clock in in KHz. To get the divisors,
 +               * but the adjusted_mode->clock in in KHz. To get the divisors,
                 * it is necessary to divide one by another, so we
                 * convert the virtual clock precision to KHz here for higher
                 * precision.
                u32 iclk_pi_range = 64;
                u32 desired_divisor, msb_divisor_value, pi_value;
  
 -              desired_divisor = (iclk_virtual_root_freq / crtc->mode.clock);
 +              desired_divisor = (iclk_virtual_root_freq / clock);
                msb_divisor_value = desired_divisor / iclk_pi_range;
                pi_value = desired_divisor % iclk_pi_range;
  
                ~SBI_SSCDIVINTPHASE_INCVAL_MASK);
  
        DRM_DEBUG_KMS("iCLKIP clock: found settings for %dKHz refresh rate: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n",
 -                      crtc->mode.clock,
 +                      clock,
                        auxdiv,
                        divsel,
                        phasedir,
@@@ -3246,7 -3203,7 +3246,7 @@@ static void ironlake_pfit_enable(struc
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe = crtc->pipe;
  
-       if (crtc->config.pch_pfit.size) {
+       if (crtc->config.pch_pfit.enabled) {
                /* Force use of hard-coded filter coefficients
                 * as some pre-programmed values are broken,
                 * e.g. x201.
@@@ -3302,6 -3259,8 +3302,6 @@@ static void ironlake_crtc_enable(struc
        intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
        intel_set_pch_fifo_underrun_reporting(dev, pipe, true);
  
 -      intel_update_watermarks(dev);
 -
        for_each_encoder_on_crtc(dev, crtc, encoder)
                if (encoder->pre_enable)
                        encoder->pre_enable(encoder);
         */
        intel_crtc_load_lut(crtc);
  
 +      intel_update_watermarks(crtc);
        intel_enable_pipe(dev_priv, pipe,
 -                        intel_crtc->config.has_pch_encoder);
 +                        intel_crtc->config.has_pch_encoder, false);
        intel_enable_plane(dev_priv, plane, pipe);
        intel_enable_planes(crtc);
        intel_crtc_update_cursor(crtc, true);
@@@ -3386,7 -3344,6 +3386,7 @@@ static void hsw_disable_ips(struct inte
  
        assert_plane_enabled(dev_priv, crtc->plane);
        I915_WRITE(IPS_CTL, 0);
 +      POSTING_READ(IPS_CTL);
  
        /* We need to wait for a vblank before we can disable the plane. */
        intel_wait_for_vblank(dev, crtc->pipe);
@@@ -3412,6 -3369,8 +3412,6 @@@ static void haswell_crtc_enable(struct 
        if (intel_crtc->config.has_pch_encoder)
                intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true);
  
 -      intel_update_watermarks(dev);
 -
        if (intel_crtc->config.has_pch_encoder)
                dev_priv->display.fdi_link_train(crtc);
  
        intel_ddi_set_pipe_settings(crtc);
        intel_ddi_enable_transcoder_func(crtc);
  
 +      intel_update_watermarks(crtc);
        intel_enable_pipe(dev_priv, pipe,
 -                        intel_crtc->config.has_pch_encoder);
 +                        intel_crtc->config.has_pch_encoder, false);
        intel_enable_plane(dev_priv, plane, pipe);
        intel_enable_planes(crtc);
        intel_crtc_update_cursor(crtc, true);
        intel_update_fbc(dev);
        mutex_unlock(&dev->struct_mutex);
  
 -      for_each_encoder_on_crtc(dev, crtc, encoder)
 +      for_each_encoder_on_crtc(dev, crtc, encoder) {
                encoder->enable(encoder);
 +              intel_opregion_notify_encoder(encoder, true);
 +      }
  
        /*
         * There seems to be a race in PCH platform hw (at least on some
@@@ -3472,7 -3428,7 +3472,7 @@@ static void ironlake_pfit_disable(struc
  
        /* To avoid upsetting the power well on haswell only disable the pfit if
         * it's in use. The hw state code will make sure we get this right. */
-       if (crtc->config.pch_pfit.size) {
+       if (crtc->config.pch_pfit.enabled) {
                I915_WRITE(PF_CTL(pipe), 0);
                I915_WRITE(PF_WIN_POS(pipe), 0);
                I915_WRITE(PF_WIN_SZ(pipe), 0);
@@@ -3545,7 -3501,7 +3545,7 @@@ static void ironlake_crtc_disable(struc
        }
  
        intel_crtc->active = false;
 -      intel_update_watermarks(dev);
 +      intel_update_watermarks(crtc);
  
        mutex_lock(&dev->struct_mutex);
        intel_update_fbc(dev);
@@@ -3565,10 -3521,8 +3565,10 @@@ static void haswell_crtc_disable(struc
        if (!intel_crtc->active)
                return;
  
 -      for_each_encoder_on_crtc(dev, crtc, encoder)
 +      for_each_encoder_on_crtc(dev, crtc, encoder) {
 +              intel_opregion_notify_encoder(encoder, false);
                encoder->disable(encoder);
 +      }
  
        intel_crtc_wait_for_pending_flips(crtc);
        drm_vblank_off(dev, pipe);
        }
  
        intel_crtc->active = false;
 -      intel_update_watermarks(dev);
 +      intel_update_watermarks(crtc);
  
        mutex_lock(&dev->struct_mutex);
        intel_update_fbc(dev);
@@@ -3696,7 -3650,6 +3696,7 @@@ static void valleyview_crtc_enable(stru
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
 +      bool is_dsi;
  
        WARN_ON(!crtc->enabled);
  
                return;
  
        intel_crtc->active = true;
 -      intel_update_watermarks(dev);
  
        for_each_encoder_on_crtc(dev, crtc, encoder)
                if (encoder->pre_pll_enable)
                        encoder->pre_pll_enable(encoder);
  
 -      vlv_enable_pll(intel_crtc);
 +      is_dsi = intel_pipe_has_type(crtc, INTEL_OUTPUT_DSI);
 +
 +      if (!is_dsi)
 +              vlv_enable_pll(intel_crtc);
  
        for_each_encoder_on_crtc(dev, crtc, encoder)
                if (encoder->pre_enable)
  
        intel_crtc_load_lut(crtc);
  
 -      intel_enable_pipe(dev_priv, pipe, false);
 +      intel_update_watermarks(crtc);
 +      intel_enable_pipe(dev_priv, pipe, false, is_dsi);
        intel_enable_plane(dev_priv, plane, pipe);
        intel_enable_planes(crtc);
        intel_crtc_update_cursor(crtc, true);
@@@ -3749,6 -3699,7 +3749,6 @@@ static void i9xx_crtc_enable(struct drm
                return;
  
        intel_crtc->active = true;
 -      intel_update_watermarks(dev);
  
        for_each_encoder_on_crtc(dev, crtc, encoder)
                if (encoder->pre_enable)
  
        intel_crtc_load_lut(crtc);
  
 -      intel_enable_pipe(dev_priv, pipe, false);
 +      intel_update_watermarks(crtc);
 +      intel_enable_pipe(dev_priv, pipe, false, false);
        intel_enable_plane(dev_priv, plane, pipe);
        intel_enable_planes(crtc);
        /* The fixup needs to happen before cursor is enabled */
@@@ -3828,13 -3778,11 +3828,13 @@@ static void i9xx_crtc_disable(struct dr
                if (encoder->post_disable)
                        encoder->post_disable(encoder);
  
 -      i9xx_disable_pll(dev_priv, pipe);
 +      if (!intel_pipe_has_type(crtc, INTEL_OUTPUT_DSI))
 +              i9xx_disable_pll(dev_priv, pipe);
  
        intel_crtc->active = false;
 +      intel_update_watermarks(crtc);
 +
        intel_update_fbc(dev);
 -      intel_update_watermarks(dev);
  }
  
  static void i9xx_crtc_off(struct drm_crtc *crtc)
@@@ -3908,7 -3856,6 +3908,7 @@@ static void intel_crtc_disable(struct d
        dev_priv->display.off(crtc);
  
        assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane);
 +      assert_cursor_disabled(dev_priv, to_intel_crtc(crtc)->pipe);
        assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe);
  
        if (crtc->fb) {
@@@ -4103,6 -4050,7 +4103,6 @@@ retry
        link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
  
        fdi_dotclock = adjusted_mode->clock;
 -      fdi_dotclock /= pipe_config->pixel_multiplier;
  
        lane = ironlake_get_lanes_required(fdi_dotclock, link_bw,
                                           pipe_config->pipe_bpp);
@@@ -4144,39 -4092,13 +4144,39 @@@ static int intel_crtc_compute_config(st
        struct drm_device *dev = crtc->base.dev;
        struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
  
 -      if (HAS_PCH_SPLIT(dev)) {
 -              /* FDI link clock is fixed at 2.7G */
 -              if (pipe_config->requested_mode.clock * 3
 -                  > IRONLAKE_FDI_FREQ * 4)
 +      /* FIXME should check pixel clock limits on all platforms */
 +      if (INTEL_INFO(dev)->gen < 4) {
 +              struct drm_i915_private *dev_priv = dev->dev_private;
 +              int clock_limit =
 +                      dev_priv->display.get_display_clock_speed(dev);
 +
 +              /*
 +               * Enable pixel doubling when the dot clock
 +               * is > 90% of the (display) core speed.
 +               *
 +               * GDG double wide on either pipe,
 +               * otherwise pipe A only.
 +               */
 +              if ((crtc->pipe == PIPE_A || IS_I915G(dev)) &&
 +                  adjusted_mode->clock > clock_limit * 9 / 10) {
 +                      clock_limit *= 2;
 +                      pipe_config->double_wide = true;
 +              }
 +
 +              if (adjusted_mode->clock > clock_limit * 9 / 10)
                        return -EINVAL;
        }
  
 +      /*
 +       * Pipe horizontal size must be even in:
 +       * - DVO ganged mode
 +       * - LVDS dual channel mode
 +       * - Double wide pipe
 +       */
 +      if ((intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
 +           intel_is_dual_link_lvds(dev)) || pipe_config->double_wide)
 +              pipe_config->pipe_src_w &= ~1;
 +
        /* Cantiga+ cannot handle modes with a hsync front porch of 0.
         * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw.
         */
@@@ -4340,6 -4262,28 +4340,6 @@@ static inline bool intel_panel_use_ssc(
                && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
  }
  
 -static int vlv_get_refclk(struct drm_crtc *crtc)
 -{
 -      struct drm_device *dev = crtc->dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      int refclk = 27000; /* for DP & HDMI */
 -
 -      return 100000; /* only one validated so far */
 -
 -      if (intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) {
 -              refclk = 96000;
 -      } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
 -              if (intel_panel_use_ssc(dev_priv))
 -                      refclk = 100000;
 -              else
 -                      refclk = 96000;
 -      } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) {
 -              refclk = 100000;
 -      }
 -
 -      return refclk;
 -}
 -
  static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
  {
        struct drm_device *dev = crtc->dev;
        int refclk;
  
        if (IS_VALLEYVIEW(dev)) {
 -              refclk = vlv_get_refclk(crtc);
 +              refclk = 100000;
        } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
            intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
                refclk = dev_priv->vbt.lvds_ssc_freq * 1000;
@@@ -4405,8 -4349,7 +4405,8 @@@ static void i9xx_update_pll_dividers(st
        }
  }
  
 -static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv)
 +static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, enum pipe
 +              pipe)
  {
        u32 reg_val;
  
         * PLLB opamp always calibrates to max value of 0x3f, force enable it
         * and set it to a reasonable value instead.
         */
 -      reg_val = vlv_dpio_read(dev_priv, DPIO_IREF(1));
 +      reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_IREF(1));
        reg_val &= 0xffffff00;
        reg_val |= 0x00000030;
 -      vlv_dpio_write(dev_priv, DPIO_IREF(1), reg_val);
 +      vlv_dpio_write(dev_priv, pipe, DPIO_IREF(1), reg_val);
  
 -      reg_val = vlv_dpio_read(dev_priv, DPIO_CALIBRATION);
 +      reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_CALIBRATION);
        reg_val &= 0x8cffffff;
        reg_val = 0x8c000000;
 -      vlv_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val);
 +      vlv_dpio_write(dev_priv, pipe, DPIO_CALIBRATION, reg_val);
  
 -      reg_val = vlv_dpio_read(dev_priv, DPIO_IREF(1));
 +      reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_IREF(1));
        reg_val &= 0xffffff00;
 -      vlv_dpio_write(dev_priv, DPIO_IREF(1), reg_val);
 +      vlv_dpio_write(dev_priv, pipe, DPIO_IREF(1), reg_val);
  
 -      reg_val = vlv_dpio_read(dev_priv, DPIO_CALIBRATION);
 +      reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_CALIBRATION);
        reg_val &= 0x00ffffff;
        reg_val |= 0xb0000000;
 -      vlv_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val);
 +      vlv_dpio_write(dev_priv, pipe, DPIO_CALIBRATION, reg_val);
  }
  
  static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
@@@ -4497,18 -4440,18 +4497,18 @@@ static void vlv_update_pll(struct intel
  
        /* PLL B needs special handling */
        if (pipe)
 -              vlv_pllb_recal_opamp(dev_priv);
 +              vlv_pllb_recal_opamp(dev_priv, pipe);
  
        /* Set up Tx target for periodic Rcomp update */
 -      vlv_dpio_write(dev_priv, DPIO_IREF_BCAST, 0x0100000f);
 +      vlv_dpio_write(dev_priv, pipe, DPIO_IREF_BCAST, 0x0100000f);
  
        /* Disable target IRef on PLL */
 -      reg_val = vlv_dpio_read(dev_priv, DPIO_IREF_CTL(pipe));
 +      reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_IREF_CTL(pipe));
        reg_val &= 0x00ffffff;
 -      vlv_dpio_write(dev_priv, DPIO_IREF_CTL(pipe), reg_val);
 +      vlv_dpio_write(dev_priv, pipe, DPIO_IREF_CTL(pipe), reg_val);
  
        /* Disable fast lock */
 -      vlv_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x610);
 +      vlv_dpio_write(dev_priv, pipe, DPIO_FASTCLK_DISABLE, 0x610);
  
        /* Set idtafcrecal before PLL is enabled */
        mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK));
         * Note: don't use the DAC post divider as it seems unstable.
         */
        mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT);
 -      vlv_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv);
 +      vlv_dpio_write(dev_priv, pipe, DPIO_DIV(pipe), mdiv);
  
        mdiv |= DPIO_ENABLE_CALIBRATION;
 -      vlv_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv);
 +      vlv_dpio_write(dev_priv, pipe, DPIO_DIV(pipe), mdiv);
  
        /* Set HBR and RBR LPF coefficients */
        if (crtc->config.port_clock == 162000 ||
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) ||
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI))
 -              vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe),
 +              vlv_dpio_write(dev_priv, pipe, DPIO_LPF_COEFF(pipe),
                                 0x009f0003);
        else
 -              vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe),
 +              vlv_dpio_write(dev_priv, pipe, DPIO_LPF_COEFF(pipe),
                                 0x00d0000f);
  
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) ||
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) {
                /* Use SSC source */
                if (!pipe)
 -                      vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe),
 +                      vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe),
                                         0x0df40000);
                else
 -                      vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe),
 +                      vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe),
                                         0x0df70000);
        } else { /* HDMI or VGA */
                /* Use bend source */
                if (!pipe)
 -                      vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe),
 +                      vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe),
                                         0x0df70000);
                else
 -                      vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe),
 +                      vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe),
                                         0x0df40000);
        }
  
 -      coreclk = vlv_dpio_read(dev_priv, DPIO_CORE_CLK(pipe));
 +      coreclk = vlv_dpio_read(dev_priv, pipe, DPIO_CORE_CLK(pipe));
        coreclk = (coreclk & 0x0000ff00) | 0x01c00000;
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) ||
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP))
                coreclk |= 0x01000000;
 -      vlv_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), coreclk);
 +      vlv_dpio_write(dev_priv, pipe, DPIO_CORE_CLK(pipe), coreclk);
  
 -      vlv_dpio_write(dev_priv, DPIO_PLL_CML(pipe), 0x87871000);
 +      vlv_dpio_write(dev_priv, pipe, DPIO_PLL_CML(pipe), 0x87871000);
  
        /* Enable DPIO clock input */
        dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV |
@@@ -4708,6 -4651,7 +4708,6 @@@ static void intel_set_pipe_timings(stru
        enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
        struct drm_display_mode *adjusted_mode =
                &intel_crtc->config.adjusted_mode;
 -      struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
        uint32_t vsyncshift, crtc_vtotal, crtc_vblank_end;
  
        /* We need to be careful not to changed the adjusted mode, for otherwise
         * always be the user's requested size.
         */
        I915_WRITE(PIPESRC(pipe),
 -                 ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
 +                 ((intel_crtc->config.pipe_src_w - 1) << 16) |
 +                 (intel_crtc->config.pipe_src_h - 1));
  }
  
  static void intel_get_pipe_timings(struct intel_crtc *crtc,
        }
  
        tmp = I915_READ(PIPESRC(crtc->pipe));
 -      pipe_config->requested_mode.vdisplay = (tmp & 0xffff) + 1;
 -      pipe_config->requested_mode.hdisplay = ((tmp >> 16) & 0xffff) + 1;
 +      pipe_config->pipe_src_h = (tmp & 0xffff) + 1;
 +      pipe_config->pipe_src_w = ((tmp >> 16) & 0xffff) + 1;
 +
 +      pipe_config->requested_mode.vdisplay = pipe_config->pipe_src_h;
 +      pipe_config->requested_mode.hdisplay = pipe_config->pipe_src_w;
  }
  
  static void intel_crtc_mode_from_pipe_config(struct intel_crtc *intel_crtc,
@@@ -4835,8 -4775,17 +4835,8 @@@ static void i9xx_set_pipeconf(struct in
  
        pipeconf = 0;
  
 -      if (intel_crtc->pipe == 0 && INTEL_INFO(dev)->gen < 4) {
 -              /* Enable pixel doubling when the dot clock is > 90% of the (display)
 -               * core speed.
 -               *
 -               * XXX: No double-wide on 915GM pipe B. Is that the only reason for the
 -               * pipe == 0 check?
 -               */
 -              if (intel_crtc->config.requested_mode.clock >
 -                  dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
 -                      pipeconf |= PIPECONF_DOUBLE_WIDE;
 -      }
 +      if (intel_crtc->config.double_wide)
 +              pipeconf |= PIPECONF_DOUBLE_WIDE;
  
        /* only g4x and later have fancy bpc/dither controls */
        if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) {
@@@ -4890,13 -4839,14 +4890,13 @@@ static int i9xx_crtc_mode_set(struct dr
        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_display_mode *mode = &intel_crtc->config.requested_mode;
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
        int refclk, num_connectors = 0;
        intel_clock_t clock, reduced_clock;
        u32 dspcntr;
        bool ok, has_reduced_clock = false;
 -      bool is_lvds = false;
 +      bool is_lvds = false, is_dsi = false;
        struct intel_encoder *encoder;
        const intel_limit_t *limit;
        int ret;
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
                        break;
 +              case INTEL_OUTPUT_DSI:
 +                      is_dsi = true;
 +                      break;
                }
  
                num_connectors++;
  
        refclk = i9xx_get_refclk(crtc, num_connectors);
  
 -      /*
 -       * Returns a set of divisors for the desired target clock with the given
 -       * refclk, or FALSE.  The returned values represent the clock equation:
 -       * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
 -       */
 -      limit = intel_limit(crtc, refclk);
 -      ok = dev_priv->display.find_dpll(limit, crtc,
 -                                       intel_crtc->config.port_clock,
 -                                       refclk, NULL, &clock);
 -      if (!ok && !intel_crtc->config.clock_set) {
 -              DRM_ERROR("Couldn't find PLL settings for mode!\n");
 -              return -EINVAL;
 +      if (!is_dsi && !intel_crtc->config.clock_set) {
 +              /*
 +               * Returns a set of divisors for the desired target clock with
 +               * the given refclk, or FALSE.  The returned values represent
 +               * the clock equation: reflck * (5 * (m1 + 2) + (m2 + 2)) / (n +
 +               * 2) / p1 / p2.
 +               */
 +              limit = intel_limit(crtc, refclk);
 +              ok = dev_priv->display.find_dpll(limit, crtc,
 +                                               intel_crtc->config.port_clock,
 +                                               refclk, NULL, &clock);
 +              if (!ok && !intel_crtc->config.clock_set) {
 +                      DRM_ERROR("Couldn't find PLL settings for mode!\n");
 +                      return -EINVAL;
 +              }
        }
  
-       /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc, true);
-       if (!is_dsi && is_lvds && dev_priv->lvds_downclock_avail) {
+       if (is_lvds && dev_priv->lvds_downclock_avail) {
                /*
                 * Ensure we match the reduced clock's P to the target clock.
                 * If the clocks don't match, we can't switch the display clock
                 * by using the FP0/FP1. In such case we will disable the LVDS
                 * downclock feature.
                */
 +              limit = intel_limit(crtc, refclk);
                has_reduced_clock =
                        dev_priv->display.find_dpll(limit, crtc,
                                                    dev_priv->lvds_downclock,
                intel_crtc->config.dpll.p2 = clock.p2;
        }
  
 -      if (IS_GEN2(dev))
 +      if (IS_GEN2(dev)) {
                i8xx_update_pll(intel_crtc,
                                has_reduced_clock ? &reduced_clock : NULL,
                                num_connectors);
 -      else if (IS_VALLEYVIEW(dev))
 -              vlv_update_pll(intel_crtc);
 -      else
 +      } else if (IS_VALLEYVIEW(dev)) {
 +              if (!is_dsi)
 +                      vlv_update_pll(intel_crtc);
 +      } else {
                i9xx_update_pll(intel_crtc,
                                has_reduced_clock ? &reduced_clock : NULL,
                                  num_connectors);
 +      }
  
        /* Set up the display plane register */
        dspcntr = DISPPLANE_GAMMA_ENABLE;
         * which should always be the user's requested size.
         */
        I915_WRITE(DSPSIZE(plane),
 -                 ((mode->vdisplay - 1) << 16) |
 -                 (mode->hdisplay - 1));
 +                 ((intel_crtc->config.pipe_src_h - 1) << 16) |
 +                 (intel_crtc->config.pipe_src_w - 1));
        I915_WRITE(DSPPOS(plane), 0);
  
        i9xx_set_pipeconf(intel_crtc);
  
        ret = intel_pipe_set_base(crtc, x, y, fb);
  
 -      intel_update_watermarks(dev);
 -
        return ret;
  }
  
@@@ -5043,25 -4983,6 +5040,25 @@@ static bool i9xx_get_pipe_config(struc
        if (!(tmp & PIPECONF_ENABLE))
                return false;
  
 +      if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) {
 +              switch (tmp & PIPECONF_BPC_MASK) {
 +              case PIPECONF_6BPC:
 +                      pipe_config->pipe_bpp = 18;
 +                      break;
 +              case PIPECONF_8BPC:
 +                      pipe_config->pipe_bpp = 24;
 +                      break;
 +              case PIPECONF_10BPC:
 +                      pipe_config->pipe_bpp = 30;
 +                      break;
 +              default:
 +                      break;
 +              }
 +      }
 +
 +      if (INTEL_INFO(dev)->gen < 4)
 +              pipe_config->double_wide = tmp & PIPECONF_DOUBLE_WIDE;
 +
        intel_get_pipe_timings(crtc, pipe_config);
  
        i9xx_get_pfit_config(crtc, pipe_config);
                                                     DPLL_PORTB_READY_MASK);
        }
  
 +      i9xx_crtc_clock_get(crtc, pipe_config);
 +
        return true;
  }
  
@@@ -5846,9 -5765,6 +5843,6 @@@ static int ironlake_crtc_mode_set(struc
                intel_crtc->config.dpll.p2 = clock.p2;
        }
  
-       /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc, true);
        /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
        if (intel_crtc->config.has_pch_encoder) {
                fp = i9xx_dpll_compute_fp(&intel_crtc->config.dpll);
  
        ret = intel_pipe_set_base(crtc, x, y, fb);
  
 -      intel_update_watermarks(dev);
 -
        return ret;
  }
  
 -static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc,
 -                                      struct intel_crtc_config *pipe_config)
 +static void intel_pch_transcoder_get_m_n(struct intel_crtc *crtc,
 +                                       struct intel_link_m_n *m_n)
 +{
 +      struct drm_device *dev = crtc->base.dev;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      enum pipe pipe = crtc->pipe;
 +
 +      m_n->link_m = I915_READ(PCH_TRANS_LINK_M1(pipe));
 +      m_n->link_n = I915_READ(PCH_TRANS_LINK_N1(pipe));
 +      m_n->gmch_m = I915_READ(PCH_TRANS_DATA_M1(pipe))
 +              & ~TU_SIZE_MASK;
 +      m_n->gmch_n = I915_READ(PCH_TRANS_DATA_N1(pipe));
 +      m_n->tu = ((I915_READ(PCH_TRANS_DATA_M1(pipe))
 +                  & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
 +}
 +
 +static void intel_cpu_transcoder_get_m_n(struct intel_crtc *crtc,
 +                                       enum transcoder transcoder,
 +                                       struct intel_link_m_n *m_n)
  {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      enum transcoder transcoder = pipe_config->cpu_transcoder;
 +      enum pipe pipe = crtc->pipe;
  
 -      pipe_config->fdi_m_n.link_m = I915_READ(PIPE_LINK_M1(transcoder));
 -      pipe_config->fdi_m_n.link_n = I915_READ(PIPE_LINK_N1(transcoder));
 -      pipe_config->fdi_m_n.gmch_m = I915_READ(PIPE_DATA_M1(transcoder))
 -                                      & ~TU_SIZE_MASK;
 -      pipe_config->fdi_m_n.gmch_n = I915_READ(PIPE_DATA_N1(transcoder));
 -      pipe_config->fdi_m_n.tu = ((I915_READ(PIPE_DATA_M1(transcoder))
 -                                 & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
 +      if (INTEL_INFO(dev)->gen >= 5) {
 +              m_n->link_m = I915_READ(PIPE_LINK_M1(transcoder));
 +              m_n->link_n = I915_READ(PIPE_LINK_N1(transcoder));
 +              m_n->gmch_m = I915_READ(PIPE_DATA_M1(transcoder))
 +                      & ~TU_SIZE_MASK;
 +              m_n->gmch_n = I915_READ(PIPE_DATA_N1(transcoder));
 +              m_n->tu = ((I915_READ(PIPE_DATA_M1(transcoder))
 +                          & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
 +      } else {
 +              m_n->link_m = I915_READ(PIPE_LINK_M_G4X(pipe));
 +              m_n->link_n = I915_READ(PIPE_LINK_N_G4X(pipe));
 +              m_n->gmch_m = I915_READ(PIPE_DATA_M_G4X(pipe))
 +                      & ~TU_SIZE_MASK;
 +              m_n->gmch_n = I915_READ(PIPE_DATA_N_G4X(pipe));
 +              m_n->tu = ((I915_READ(PIPE_DATA_M_G4X(pipe))
 +                          & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
 +      }
 +}
 +
 +void intel_dp_get_m_n(struct intel_crtc *crtc,
 +                    struct intel_crtc_config *pipe_config)
 +{
 +      if (crtc->config.has_pch_encoder)
 +              intel_pch_transcoder_get_m_n(crtc, &pipe_config->dp_m_n);
 +      else
 +              intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder,
 +                                           &pipe_config->dp_m_n);
 +}
 +
 +static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc,
 +                                      struct intel_crtc_config *pipe_config)
 +{
 +      intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder,
 +                                   &pipe_config->fdi_m_n);
  }
  
  static void ironlake_get_pfit_config(struct intel_crtc *crtc,
        tmp = I915_READ(PF_CTL(crtc->pipe));
  
        if (tmp & PF_ENABLE) {
+               pipe_config->pch_pfit.enabled = true;
                pipe_config->pch_pfit.pos = I915_READ(PF_WIN_POS(crtc->pipe));
                pipe_config->pch_pfit.size = I915_READ(PF_WIN_SZ(crtc->pipe));
  
@@@ -6006,23 -5881,6 +6001,23 @@@ static bool ironlake_get_pipe_config(st
        if (!(tmp & PIPECONF_ENABLE))
                return false;
  
 +      switch (tmp & PIPECONF_BPC_MASK) {
 +      case PIPECONF_6BPC:
 +              pipe_config->pipe_bpp = 18;
 +              break;
 +      case PIPECONF_8BPC:
 +              pipe_config->pipe_bpp = 24;
 +              break;
 +      case PIPECONF_10BPC:
 +              pipe_config->pipe_bpp = 30;
 +              break;
 +      case PIPECONF_12BPC:
 +              pipe_config->pipe_bpp = 36;
 +              break;
 +      default:
 +              break;
 +      }
 +
        if (I915_READ(PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) {
                struct intel_shared_dpll *pll;
  
                pipe_config->pixel_multiplier =
                        ((tmp & PLL_REF_SDVO_HDMI_MULTIPLIER_MASK)
                         >> PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT) + 1;
 +
 +              ironlake_pch_clock_get(crtc, pipe_config);
        } else {
                pipe_config->pixel_multiplier = 1;
        }
@@@ -6141,10 -5997,7 +6136,10 @@@ void hsw_disable_lcpll(struct drm_i915_
  
        val = I915_READ(D_COMP);
        val |= D_COMP_COMP_DISABLE;
 -      I915_WRITE(D_COMP, val);
 +      mutex_lock(&dev_priv->rps.hw_lock);
 +      if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP, val))
 +              DRM_ERROR("Failed to disable D_COMP\n");
 +      mutex_unlock(&dev_priv->rps.hw_lock);
        POSTING_READ(D_COMP);
        ndelay(100);
  
@@@ -6186,10 -6039,7 +6181,10 @@@ void hsw_restore_lcpll(struct drm_i915_
        val = I915_READ(D_COMP);
        val |= D_COMP_COMP_FORCE;
        val &= ~D_COMP_COMP_DISABLE;
 -      I915_WRITE(D_COMP, val);
 +      mutex_lock(&dev_priv->rps.hw_lock);
 +      if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP, val))
 +              DRM_ERROR("Failed to enable D_COMP\n");
 +      mutex_unlock(&dev_priv->rps.hw_lock);
        POSTING_READ(D_COMP);
  
        val = I915_READ(LCPLL_CTL);
@@@ -6381,7 -6231,7 +6376,7 @@@ static void haswell_modeset_global_reso
                if (!crtc->base.enabled)
                        continue;
  
-               if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.size ||
+               if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.enabled ||
                    crtc->config.cpu_transcoder != TRANSCODER_EDP)
                        enable = true;
        }
@@@ -6404,9 -6254,6 +6399,6 @@@ static int haswell_crtc_mode_set(struc
        if (!intel_ddi_pll_mode_set(crtc))
                return -EINVAL;
  
-       /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc, true);
        if (intel_crtc->config.has_dp_encoder)
                intel_dp_set_m_n(intel_crtc);
  
  
        ret = intel_pipe_set_base(crtc, x, y, fb);
  
 -      intel_update_watermarks(dev);
 -
        return ret;
  }
  
@@@ -6637,15 -6486,15 +6629,15 @@@ static void haswell_write_eld(struct dr
  
        /* Set ELD valid state */
        tmp = I915_READ(aud_cntrl_st2);
-       DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%8x\n", tmp);
+       DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%08x\n", tmp);
        tmp |= (AUDIO_ELD_VALID_A << (pipe * 4));
        I915_WRITE(aud_cntrl_st2, tmp);
        tmp = I915_READ(aud_cntrl_st2);
-       DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%8x\n", tmp);
+       DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%08x\n", tmp);
  
        /* Enable HDMI mode */
        tmp = I915_READ(aud_config);
-       DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%8x\n", tmp);
+       DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%08x\n", tmp);
        /* clear N_programing_enable and N_value_index */
        tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE);
        I915_WRITE(aud_config, tmp);
@@@ -6806,12 -6655,8 +6798,12 @@@ void intel_crtc_load_lut(struct drm_crt
        if (!crtc->enabled || !intel_crtc->active)
                return;
  
 -      if (!HAS_PCH_SPLIT(dev_priv->dev))
 -              assert_pll_enabled(dev_priv, pipe);
 +      if (!HAS_PCH_SPLIT(dev_priv->dev)) {
 +              if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DSI))
 +                      assert_dsi_pll_enabled(dev_priv);
 +              else
 +                      assert_pll_enabled(dev_priv, pipe);
 +      }
  
        /* use legacy palette for Ironlake */
        if (HAS_PCH_SPLIT(dev))
@@@ -6933,20 -6778,23 +6925,20 @@@ static void intel_crtc_update_cursor(st
        int pipe = intel_crtc->pipe;
        int x = intel_crtc->cursor_x;
        int y = intel_crtc->cursor_y;
 -      u32 base, pos;
 +      u32 base = 0, pos = 0;
        bool visible;
  
 -      pos = 0;
 -
 -      if (on && crtc->enabled && crtc->fb) {
 +      if (on)
                base = intel_crtc->cursor_addr;
 -              if (x > (int) crtc->fb->width)
 -                      base = 0;
  
 -              if (y > (int) crtc->fb->height)
 -                      base = 0;
 -      } else
 +      if (x >= intel_crtc->config.pipe_src_w)
 +              base = 0;
 +
 +      if (y >= intel_crtc->config.pipe_src_h)
                base = 0;
  
        if (x < 0) {
 -              if (x + intel_crtc->cursor_width < 0)
 +              if (x + intel_crtc->cursor_width <= 0)
                        base = 0;
  
                pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
        pos |= x << CURSOR_X_SHIFT;
  
        if (y < 0) {
 -              if (y + intel_crtc->cursor_height < 0)
 +              if (y + intel_crtc->cursor_height <= 0)
                        base = 0;
  
                pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
@@@ -7081,7 -6929,8 +7073,8 @@@ static int intel_crtc_cursor_set(struc
        intel_crtc->cursor_width = width;
        intel_crtc->cursor_height = height;
  
-       intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
+       if (intel_crtc->active)
+               intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
  
        return 0;
  fail_unpin:
@@@ -7100,7 -6949,8 +7093,8 @@@ static int intel_crtc_cursor_move(struc
        intel_crtc->cursor_x = x;
        intel_crtc->cursor_y = y;
  
-       intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
+       if (intel_crtc->active)
+               intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
  
        return 0;
  }
@@@ -7374,22 -7224,6 +7368,22 @@@ void intel_release_load_detect_pipe(str
        mutex_unlock(&crtc->mutex);
  }
  
 +static int i9xx_pll_refclk(struct drm_device *dev,
 +                         const struct intel_crtc_config *pipe_config)
 +{
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      u32 dpll = pipe_config->dpll_hw_state.dpll;
 +
 +      if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN)
 +              return dev_priv->vbt.lvds_ssc_freq * 1000;
 +      else if (HAS_PCH_SPLIT(dev))
 +              return 120000;
 +      else if (!IS_GEN2(dev))
 +              return 96000;
 +      else
 +              return 48000;
 +}
 +
  /* Returns the clock of the currently programmed mode of the given pipe. */
  static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
                                struct intel_crtc_config *pipe_config)
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe = pipe_config->cpu_transcoder;
 -      u32 dpll = I915_READ(DPLL(pipe));
 +      u32 dpll = pipe_config->dpll_hw_state.dpll;
        u32 fp;
        intel_clock_t clock;
 +      int refclk = i9xx_pll_refclk(dev, pipe_config);
  
        if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
 -              fp = I915_READ(FP0(pipe));
 +              fp = pipe_config->dpll_hw_state.fp0;
        else
 -              fp = I915_READ(FP1(pipe));
 +              fp = pipe_config->dpll_hw_state.fp1;
  
        clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
        if (IS_PINEVIEW(dev)) {
                default:
                        DRM_DEBUG_KMS("Unknown DPLL mode %08x in programmed "
                                  "mode\n", (int)(dpll & DPLL_MODE_MASK));
 -                      pipe_config->adjusted_mode.clock = 0;
                        return;
                }
  
                if (IS_PINEVIEW(dev))
 -                      pineview_clock(96000, &clock);
 +                      pineview_clock(refclk, &clock);
                else
 -                      i9xx_clock(96000, &clock);
 +                      i9xx_clock(refclk, &clock);
        } else {
                bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN);
  
                        clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >>
                                       DPLL_FPA01_P1_POST_DIV_SHIFT);
                        clock.p2 = 14;
 -
 -                      if ((dpll & PLL_REF_INPUT_MASK) ==
 -                          PLLB_REF_INPUT_SPREADSPECTRUMIN) {
 -                              /* XXX: might not be 66MHz */
 -                              i9xx_clock(66000, &clock);
 -                      } else
 -                              i9xx_clock(48000, &clock);
                } else {
                        if (dpll & PLL_P1_DIVIDE_BY_TWO)
                                clock.p1 = 2;
                                clock.p2 = 4;
                        else
                                clock.p2 = 2;
 -
 -                      i9xx_clock(48000, &clock);
                }
 +
 +              i9xx_clock(refclk, &clock);
        }
  
 -      pipe_config->adjusted_mode.clock = clock.dot;
 +      /*
 +       * This value includes pixel_multiplier. We will use
 +       * port_clock to compute adjusted_mode.clock in the
 +       * encoder's get_config() function.
 +       */
 +      pipe_config->port_clock = clock.dot;
  }
  
 -static void ironlake_crtc_clock_get(struct intel_crtc *crtc,
 -                                  struct intel_crtc_config *pipe_config)
 +int intel_dotclock_calculate(int link_freq,
 +                           const struct intel_link_m_n *m_n)
  {
 -      struct drm_device *dev = crtc->base.dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
 -      int link_freq, repeat;
 -      u64 clock;
 -      u32 link_m, link_n;
 -
 -      repeat = pipe_config->pixel_multiplier;
 -
        /*
         * The calculation for the data clock is:
 -       * pixel_clock = ((m/n)*(link_clock * nr_lanes * repeat))/bpp
 +       * pixel_clock = ((m/n)*(link_clock * nr_lanes))/bpp
         * But we want to avoid losing precison if possible, so:
 -       * pixel_clock = ((m * link_clock * nr_lanes * repeat)/(n*bpp))
 +       * pixel_clock = ((m * link_clock * nr_lanes)/(n*bpp))
         *
         * and the link clock is simpler:
 -       * link_clock = (m * link_clock * repeat) / n
 +       * link_clock = (m * link_clock) / n
         */
  
 -      /*
 -       * We need to get the FDI or DP link clock here to derive
 -       * the M/N dividers.
 -       *
 -       * For FDI, we read it from the BIOS or use a fixed 2.7GHz.
 -       * For DP, it's either 1.62GHz or 2.7GHz.
 -       * We do our calculations in 10*MHz since we don't need much precison.
 -       */
 -      if (pipe_config->has_pch_encoder)
 -              link_freq = intel_fdi_link_freq(dev) * 10000;
 -      else
 -              link_freq = pipe_config->port_clock;
 +      if (!m_n->link_n)
 +              return 0;
  
 -      link_m = I915_READ(PIPE_LINK_M1(cpu_transcoder));
 -      link_n = I915_READ(PIPE_LINK_N1(cpu_transcoder));
 +      return div_u64((u64)m_n->link_m * link_freq, m_n->link_n);
 +}
  
 -      if (!link_m || !link_n)
 -              return;
 +static void ironlake_pch_clock_get(struct intel_crtc *crtc,
 +                                 struct intel_crtc_config *pipe_config)
 +{
 +      struct drm_device *dev = crtc->base.dev;
  
 -      clock = ((u64)link_m * (u64)link_freq * (u64)repeat);
 -      do_div(clock, link_n);
 +      /* read out port_clock from the DPLL */
 +      i9xx_crtc_clock_get(crtc, pipe_config);
  
 -      pipe_config->adjusted_mode.clock = clock;
 +      /*
 +       * This value does not include pixel_multiplier.
 +       * We will check that port_clock and adjusted_mode.clock
 +       * agree once we know their relationship in the encoder's
 +       * get_config() function.
 +       */
 +      pipe_config->adjusted_mode.clock =
 +              intel_dotclock_calculate(intel_fdi_link_freq(dev) * 10000,
 +                                       &pipe_config->fdi_m_n);
  }
  
  /** Returns the currently programmed mode of the given pipe. */
@@@ -7525,7 -7370,6 +7519,7 @@@ struct drm_display_mode *intel_crtc_mod
        int hsync = I915_READ(HSYNC(cpu_transcoder));
        int vtot = I915_READ(VTOTAL(cpu_transcoder));
        int vsync = I915_READ(VSYNC(cpu_transcoder));
 +      enum pipe pipe = intel_crtc->pipe;
  
        mode = kzalloc(sizeof(*mode), GFP_KERNEL);
        if (!mode)
         * Note, if LVDS ever uses a non-1 pixel multiplier, we'll need
         * to use a real value here instead.
         */
 -      pipe_config.cpu_transcoder = (enum transcoder) intel_crtc->pipe;
 +      pipe_config.cpu_transcoder = (enum transcoder) pipe;
        pipe_config.pixel_multiplier = 1;
 +      pipe_config.dpll_hw_state.dpll = I915_READ(DPLL(pipe));
 +      pipe_config.dpll_hw_state.fp0 = I915_READ(FP0(pipe));
 +      pipe_config.dpll_hw_state.fp1 = I915_READ(FP1(pipe));
        i9xx_crtc_clock_get(intel_crtc, &pipe_config);
  
        mode->clock = pipe_config.adjusted_mode.clock;
@@@ -7839,7 -7680,7 +7833,7 @@@ static int intel_gen2_queue_flip(struc
        intel_ring_emit(ring, 0); /* aux display base address, unused */
  
        intel_mark_page_flip_active(intel_crtc);
 -      intel_ring_advance(ring);
 +      __intel_ring_advance(ring);
        return 0;
  
  err_unpin:
@@@ -7881,7 -7722,7 +7875,7 @@@ static int intel_gen3_queue_flip(struc
        intel_ring_emit(ring, MI_NOOP);
  
        intel_mark_page_flip_active(intel_crtc);
 -      intel_ring_advance(ring);
 +      __intel_ring_advance(ring);
        return 0;
  
  err_unpin:
@@@ -7930,7 -7771,7 +7924,7 @@@ static int intel_gen4_queue_flip(struc
        intel_ring_emit(ring, pf | pipesrc);
  
        intel_mark_page_flip_active(intel_crtc);
 -      intel_ring_advance(ring);
 +      __intel_ring_advance(ring);
        return 0;
  
  err_unpin:
@@@ -7975,7 -7816,7 +7969,7 @@@ static int intel_gen6_queue_flip(struc
        intel_ring_emit(ring, pf | pipesrc);
  
        intel_mark_page_flip_active(intel_crtc);
 -      intel_ring_advance(ring);
 +      __intel_ring_advance(ring);
        return 0;
  
  err_unpin:
@@@ -7997,7 -7838,7 +7991,7 @@@ static int intel_gen7_queue_flip(struc
        int len, ret;
  
        ring = obj->ring;
-       if (ring == NULL || ring->id != RCS)
+       if (IS_VALLEYVIEW(dev) || ring == NULL || ring->id != RCS)
                ring = &dev_priv->ring[BCS];
  
        ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
        intel_ring_emit(ring, (MI_NOOP));
  
        intel_mark_page_flip_active(intel_crtc);
 -      intel_ring_advance(ring);
 +      __intel_ring_advance(ring);
        return 0;
  
  err_unpin:
@@@ -8334,17 -8175,6 +8328,17 @@@ compute_baseline_pipe_bpp(struct intel_
        return bpp;
  }
  
 +static void intel_dump_crtc_timings(const struct drm_display_mode *mode)
 +{
 +      DRM_DEBUG_KMS("crtc timings: %d %d %d %d %d %d %d %d %d, "
 +                      "type: 0x%x flags: 0x%x\n",
 +              mode->clock,
 +              mode->crtc_hdisplay, mode->crtc_hsync_start,
 +              mode->crtc_hsync_end, mode->crtc_htotal,
 +              mode->crtc_vdisplay, mode->crtc_vsync_start,
 +              mode->crtc_vsync_end, mode->crtc_vtotal, mode->type, mode->flags);
 +}
 +
  static void intel_dump_pipe_config(struct intel_crtc *crtc,
                                   struct intel_crtc_config *pipe_config,
                                   const char *context)
                      pipe_config->fdi_m_n.gmch_m, pipe_config->fdi_m_n.gmch_n,
                      pipe_config->fdi_m_n.link_m, pipe_config->fdi_m_n.link_n,
                      pipe_config->fdi_m_n.tu);
 +      DRM_DEBUG_KMS("dp: %i, gmch_m: %u, gmch_n: %u, link_m: %u, link_n: %u, tu: %u\n",
 +                    pipe_config->has_dp_encoder,
 +                    pipe_config->dp_m_n.gmch_m, pipe_config->dp_m_n.gmch_n,
 +                    pipe_config->dp_m_n.link_m, pipe_config->dp_m_n.link_n,
 +                    pipe_config->dp_m_n.tu);
        DRM_DEBUG_KMS("requested mode:\n");
        drm_mode_debug_printmodeline(&pipe_config->requested_mode);
        DRM_DEBUG_KMS("adjusted mode:\n");
        drm_mode_debug_printmodeline(&pipe_config->adjusted_mode);
 +      intel_dump_crtc_timings(&pipe_config->adjusted_mode);
 +      DRM_DEBUG_KMS("port clock: %d\n", pipe_config->port_clock);
 +      DRM_DEBUG_KMS("pipe src size: %dx%d\n",
 +                    pipe_config->pipe_src_w, pipe_config->pipe_src_h);
        DRM_DEBUG_KMS("gmch pfit: control: 0x%08x, ratios: 0x%08x, lvds border: 0x%08x\n",
                      pipe_config->gmch_pfit.control,
                      pipe_config->gmch_pfit.pgm_ratios,
                      pipe_config->gmch_pfit.lvds_border_bits);
-       DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x\n",
+       DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x, %s\n",
                      pipe_config->pch_pfit.pos,
-                     pipe_config->pch_pfit.size);
+                     pipe_config->pch_pfit.size,
+                     pipe_config->pch_pfit.enabled ? "enabled" : "disabled");
        DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled);
 +      DRM_DEBUG_KMS("double wide: %i\n", pipe_config->double_wide);
  }
  
  static bool check_encoder_cloning(struct drm_crtc *crtc)
@@@ -8426,10 -8247,6 +8421,10 @@@ intel_modeset_pipe_config(struct drm_cr
  
        drm_mode_copy(&pipe_config->adjusted_mode, mode);
        drm_mode_copy(&pipe_config->requested_mode, mode);
 +
 +      pipe_config->pipe_src_w = mode->hdisplay;
 +      pipe_config->pipe_src_h = mode->vdisplay;
 +
        pipe_config->cpu_transcoder =
                (enum transcoder) to_intel_crtc(crtc)->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
@@@ -8483,8 -8300,7 +8478,8 @@@ encoder_retry
        /* Set default port clock if not overwritten by the encoder. Needs to be
         * done afterwards in case the encoder adjusts the mode. */
        if (!pipe_config->port_clock)
 -              pipe_config->port_clock = pipe_config->adjusted_mode.clock;
 +              pipe_config->port_clock = pipe_config->adjusted_mode.clock *
 +                      pipe_config->pixel_multiplier;
  
        ret = intel_crtc_compute_config(to_intel_crtc(crtc), pipe_config);
        if (ret < 0) {
@@@ -8671,9 -8487,13 +8666,9 @@@ intel_modeset_update_state(struct drm_d
  
  }
  
 -static bool intel_fuzzy_clock_check(struct intel_crtc_config *cur,
 -                                  struct intel_crtc_config *new)
 +static bool intel_fuzzy_clock_check(int clock1, int clock2)
  {
 -      int clock1, clock2, diff;
 -
 -      clock1 = cur->adjusted_mode.clock;
 -      clock2 = new->adjusted_mode.clock;
 +      int diff;
  
        if (clock1 == clock2)
                return true;
@@@ -8727,15 -8547,6 +8722,15 @@@ intel_pipe_config_compare(struct drm_de
                return false; \
        }
  
 +#define PIPE_CONF_CHECK_CLOCK_FUZZY(name) \
 +      if (!intel_fuzzy_clock_check(current_config->name, pipe_config->name)) { \
 +              DRM_ERROR("mismatch in " #name " " \
 +                        "(expected %i, found %i)\n", \
 +                        current_config->name, \
 +                        pipe_config->name); \
 +              return false; \
 +      }
 +
  #define PIPE_CONF_QUIRK(quirk)        \
        ((current_config->quirks | pipe_config->quirks) & (quirk))
  
        PIPE_CONF_CHECK_I(fdi_m_n.link_n);
        PIPE_CONF_CHECK_I(fdi_m_n.tu);
  
 +      PIPE_CONF_CHECK_I(has_dp_encoder);
 +      PIPE_CONF_CHECK_I(dp_m_n.gmch_m);
 +      PIPE_CONF_CHECK_I(dp_m_n.gmch_n);
 +      PIPE_CONF_CHECK_I(dp_m_n.link_m);
 +      PIPE_CONF_CHECK_I(dp_m_n.link_n);
 +      PIPE_CONF_CHECK_I(dp_m_n.tu);
 +
        PIPE_CONF_CHECK_I(adjusted_mode.crtc_hdisplay);
        PIPE_CONF_CHECK_I(adjusted_mode.crtc_htotal);
        PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_start);
                                      DRM_MODE_FLAG_NVSYNC);
        }
  
 -      PIPE_CONF_CHECK_I(requested_mode.hdisplay);
 -      PIPE_CONF_CHECK_I(requested_mode.vdisplay);
 +      PIPE_CONF_CHECK_I(pipe_src_w);
 +      PIPE_CONF_CHECK_I(pipe_src_h);
  
        PIPE_CONF_CHECK_I(gmch_pfit.control);
        /* pfit ratios are autocomputed by the hw on gen4+ */
        if (INTEL_INFO(dev)->gen < 4)
                PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios);
        PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits);
-       PIPE_CONF_CHECK_I(pch_pfit.pos);
-       PIPE_CONF_CHECK_I(pch_pfit.size);
+       PIPE_CONF_CHECK_I(pch_pfit.enabled);
+       if (current_config->pch_pfit.enabled) {
+               PIPE_CONF_CHECK_I(pch_pfit.pos);
+               PIPE_CONF_CHECK_I(pch_pfit.size);
+       }
  
        PIPE_CONF_CHECK_I(ips_enabled);
  
 +      PIPE_CONF_CHECK_I(double_wide);
 +
        PIPE_CONF_CHECK_I(shared_dpll);
        PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
        PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md);
        PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
        PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
  
 +      if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5)
 +              PIPE_CONF_CHECK_I(pipe_bpp);
 +
 +      if (!IS_HASWELL(dev)) {
 +              PIPE_CONF_CHECK_CLOCK_FUZZY(adjusted_mode.clock);
 +              PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock);
 +      }
 +
  #undef PIPE_CONF_CHECK_X
  #undef PIPE_CONF_CHECK_I
  #undef PIPE_CONF_CHECK_FLAGS
 +#undef PIPE_CONF_CHECK_CLOCK_FUZZY
  #undef PIPE_CONF_QUIRK
  
 -      if (!IS_HASWELL(dev)) {
 -              if (!intel_fuzzy_clock_check(current_config, pipe_config)) {
 -                      DRM_ERROR("mismatch in clock (expected %d, found %d)\n",
 -                                current_config->adjusted_mode.clock,
 -                                pipe_config->adjusted_mode.clock);
 -                      return false;
 -              }
 -      }
 -
        return true;
  }
  
@@@ -8952,6 -8757,9 +8950,6 @@@ check_crtc_state(struct drm_device *dev
                                encoder->get_config(encoder, &pipe_config);
                }
  
 -              if (dev_priv->display.get_clock)
 -                      dev_priv->display.get_clock(crtc, &pipe_config);
 -
                WARN(crtc->active != active,
                     "crtc active state doesn't match with hw state "
                     "(expected %i, found %i)\n", crtc->active, active);
@@@ -9026,18 -8834,6 +9024,18 @@@ intel_modeset_check_state(struct drm_de
        check_shared_dpll_state(dev);
  }
  
 +void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
 +                                   int dotclock)
 +{
 +      /*
 +       * FDI already provided one idea for the dotclock.
 +       * Yell if the encoder disagrees.
 +       */
 +      WARN(!intel_fuzzy_clock_check(pipe_config->adjusted_mode.clock, dotclock),
 +           "FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n",
 +           pipe_config->adjusted_mode.clock, dotclock);
 +}
 +
  static int __intel_set_mode(struct drm_crtc *crtc,
                            struct drm_display_mode *mode,
                            int x, int y, struct drm_framebuffer *fb)
@@@ -9755,8 -9551,6 +9753,8 @@@ static void intel_setup_outputs(struct 
                        if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED)
                                intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B);
                }
 +
 +              intel_dsi_init(dev);
        } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) {
                bool found = false;
  
@@@ -9989,6 -9783,7 +9987,6 @@@ static void intel_init_display(struct d
                dev_priv->display.update_plane = ironlake_update_plane;
        } else if (HAS_PCH_SPLIT(dev)) {
                dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
 -              dev_priv->display.get_clock = ironlake_crtc_clock_get;
                dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
                dev_priv->display.crtc_enable = ironlake_crtc_enable;
                dev_priv->display.crtc_disable = ironlake_crtc_disable;
                dev_priv->display.update_plane = ironlake_update_plane;
        } else if (IS_VALLEYVIEW(dev)) {
                dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
 -              dev_priv->display.get_clock = i9xx_crtc_clock_get;
                dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
                dev_priv->display.crtc_enable = valleyview_crtc_enable;
                dev_priv->display.crtc_disable = i9xx_crtc_disable;
                dev_priv->display.update_plane = i9xx_update_plane;
        } else {
                dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
 -              dev_priv->display.get_clock = i9xx_crtc_clock_get;
                dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
                dev_priv->display.crtc_enable = i9xx_crtc_enable;
                dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@@ -10188,11 -9985,20 +10186,11 @@@ static struct intel_quirk intel_quirks[
        /* Sony Vaio Y cannot use SSC on LVDS */
        { 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable },
  
 -      /* Acer Aspire 5734Z must invert backlight brightness */
 -      { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness },
 -
 -      /* Acer/eMachines G725 */
 -      { 0x2a42, 0x1025, 0x0210, quirk_invert_brightness },
 -
 -      /* Acer/eMachines e725 */
 -      { 0x2a42, 0x1025, 0x0212, quirk_invert_brightness },
 -
 -      /* Acer/Packard Bell NCL20 */
 -      { 0x2a42, 0x1025, 0x034b, quirk_invert_brightness },
 -
 -      /* Acer Aspire 4736Z */
 -      { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness },
 +      /*
 +       * All GM45 Acer (and its brands eMachines and Packard Bell) laptops
 +       * seem to use inverted backlight PWM.
 +       */
 +      { 0x2a42, 0x1025, PCI_ANY_ID, quirk_invert_brightness },
  
        /* Dell XPS13 HD Sandy Bridge */
        { 0x0116, 0x1028, 0x052e, quirk_no_pcm_pwm_enable },
@@@ -10232,15 -10038,6 +10230,6 @@@ static void i915_disable_vga(struct drm
        outb(SR01, VGA_SR_INDEX);
        sr1 = inb(VGA_SR_DATA);
        outb(sr1 | 1<<5, VGA_SR_DATA);
-       /* Disable VGA memory on Intel HD */
-       if (HAS_PCH_SPLIT(dev)) {
-               outb(inb(VGA_MSR_READ) & ~VGA_MSR_MEM_EN, VGA_MSR_WRITE);
-               vga_set_legacy_decoding(dev->pdev, VGA_RSRC_LEGACY_IO |
-                                                  VGA_RSRC_NORMAL_IO |
-                                                  VGA_RSRC_NORMAL_MEM);
-       }
        vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
        udelay(300);
  
        POSTING_READ(vga_reg);
  }
  
- static void i915_enable_vga(struct drm_device *dev)
+ static void i915_enable_vga_mem(struct drm_device *dev)
  {
        /* Enable VGA memory on Intel HD */
        if (HAS_PCH_SPLIT(dev)) {
        }
  }
  
+ void i915_disable_vga_mem(struct drm_device *dev)
+ {
+       /* Disable VGA memory on Intel HD */
+       if (HAS_PCH_SPLIT(dev)) {
+               vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
+               outb(inb(VGA_MSR_READ) & ~VGA_MSR_MEM_EN, VGA_MSR_WRITE);
+               vga_set_legacy_decoding(dev->pdev, VGA_RSRC_LEGACY_IO |
+                                                  VGA_RSRC_NORMAL_IO |
+                                                  VGA_RSRC_NORMAL_MEM);
+               vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
+       }
+ }
  void intel_modeset_init_hw(struct drm_device *dev)
  {
 -      intel_init_power_well(dev);
 -
        intel_prepare_ddi(dev);
  
        intel_init_clock_gating(dev);
@@@ -10538,6 -10350,7 +10540,7 @@@ void i915_redisable_vga(struct drm_devi
        if (I915_READ(vga_reg) != VGA_DISP_DISABLE) {
                DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n");
                i915_disable_vga(dev);
+               i915_disable_vga_mem(dev);
        }
  }
  
@@@ -10605,6 -10418,15 +10608,6 @@@ static void intel_modeset_readout_hw_st
                              pipe);
        }
  
 -      list_for_each_entry(crtc, &dev->mode_config.crtc_list,
 -                          base.head) {
 -              if (!crtc->active)
 -                      continue;
 -              if (dev_priv->display.get_clock)
 -                      dev_priv->display.get_clock(crtc,
 -                                                  &crtc->config);
 -      }
 -
        list_for_each_entry(connector, &dev->mode_config.connector_list,
                            base.head) {
                if (connector->get_hw_state(connector)) {
@@@ -10742,7 -10564,7 +10745,7 @@@ void intel_modeset_cleanup(struct drm_d
  
        intel_disable_fbc(dev);
  
-       i915_enable_vga(dev);
+       i915_enable_vga_mem(dev);
  
        intel_disable_gt_powersave(dev);
  
  #define INTEL_OUTPUT_HDMI 6
  #define INTEL_OUTPUT_DISPLAYPORT 7
  #define INTEL_OUTPUT_EDP 8
 -#define INTEL_OUTPUT_UNKNOWN 9
 +#define INTEL_OUTPUT_DSI 9
 +#define INTEL_OUTPUT_UNKNOWN 10
  
  #define INTEL_DVO_CHIP_NONE 0
  #define INTEL_DVO_CHIP_LVDS 1
  #define INTEL_DVO_CHIP_TMDS 2
  #define INTEL_DVO_CHIP_TVOUT 4
  
 +#define INTEL_DSI_COMMAND_MODE        0
 +#define INTEL_DSI_VIDEO_MODE  1
 +
  struct intel_framebuffer {
        struct drm_framebuffer base;
        struct drm_i915_gem_object *obj;
@@@ -211,21 -207,8 +211,21 @@@ struct intel_crtc_config 
  #define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */
        unsigned long quirks;
  
 +      /* User requested mode, only valid as a starting point to
 +       * compute adjusted_mode, except in the case of (S)DVO where
 +       * it's also for the output timings of the (S)DVO chip.
 +       * adjusted_mode will then correspond to the S(DVO) chip's
 +       * preferred input timings. */
        struct drm_display_mode requested_mode;
 +      /* Actual pipe timings ie. what we program into the pipe timing
 +       * registers. adjusted_mode.clock is the pipe pixel clock. */
        struct drm_display_mode adjusted_mode;
 +
 +      /* Pipe source size (ie. panel fitter input size)
 +       * All planes will be positioned inside this space,
 +       * and get clipped at the edges. */
 +      int pipe_src_w, pipe_src_h;
 +
        /* Whether to set up the PCH/FDI. Note that we never allow sharing
         * between pch encoders and cpu encoders. */
        bool has_pch_encoder;
  
        /*
         * Frequence the dpll for the port should run at. Differs from the
 -       * adjusted dotclock e.g. for DP or 12bpc hdmi mode.
 +       * adjusted dotclock e.g. for DP or 12bpc hdmi mode. This is also
 +       * already multiplied by pixel_multiplier.
         */
        int port_clock;
  
        struct {
                u32 pos;
                u32 size;
+               bool enabled;
        } pch_pfit;
  
        /* FDI configuration, only valid if has_pch_encoder is set. */
        struct intel_link_m_n fdi_m_n;
  
        bool ips_enabled;
 +
 +      bool double_wide;
  };
  
  struct intel_crtc {
@@@ -541,7 -522,6 +542,7 @@@ extern void intel_mark_fb_busy(struct d
                               struct intel_ring_buffer *ring);
  extern void intel_mark_idle(struct drm_device *dev);
  extern void intel_lvds_init(struct drm_device *dev);
 +extern bool intel_dsi_init(struct drm_device *dev);
  extern bool intel_is_dual_link_lvds(struct drm_device *dev);
  extern void intel_dp_init(struct drm_device *dev, int output_reg,
                          enum port port);
@@@ -728,10 -708,9 +729,10 @@@ extern void intel_write_eld(struct drm_
  extern void intel_prepare_ddi(struct drm_device *dev);
  extern void hsw_fdi_link_train(struct drm_crtc *crtc);
  extern void intel_ddi_init(struct drm_device *dev, enum port port);
 +extern enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder);
  
  /* For use by IVB LP watermark workaround in intel_sprite.c */
 -extern void intel_update_watermarks(struct drm_device *dev);
 +extern void intel_update_watermarks(struct drm_crtc *crtc);
  extern void intel_update_sprite_watermarks(struct drm_plane *plane,
                                           struct drm_crtc *crtc,
                                           uint32_t sprite_width, int pixel_size,
@@@ -762,13 -741,8 +763,13 @@@ extern void i915_remove_power_well(stru
  
  extern bool intel_display_power_enabled(struct drm_device *dev,
                                        enum intel_display_power_domain domain);
 +extern void intel_display_power_get(struct drm_device *dev,
 +                                  enum intel_display_power_domain domain);
 +extern void intel_display_power_put(struct drm_device *dev,
 +                                  enum intel_display_power_domain domain);
  extern void intel_init_power_well(struct drm_device *dev);
  extern void intel_set_power_well(struct drm_device *dev, bool enable);
 +extern void intel_resume_power_well(struct drm_device *dev);
  extern void intel_enable_gt_powersave(struct drm_device *dev);
  extern void intel_disable_gt_powersave(struct drm_device *dev);
  extern void ironlake_teardown_rc6(struct drm_device *dev);
@@@ -819,13 -793,6 +820,14 @@@ extern void hsw_pc8_disable_interrupts(
  extern void hsw_pc8_restore_interrupts(struct drm_device *dev);
  extern void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv);
  extern void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv);
 +extern void intel_dp_get_m_n(struct intel_crtc *crtc,
 +                           struct intel_crtc_config *pipe_config);
 +extern int intel_dotclock_calculate(int link_freq,
 +                                  const struct intel_link_m_n *m_n);
 +extern void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
 +                                          int dotclock);
 +
 +extern bool intel_crtc_active(struct drm_crtc *crtc);
+ extern void i915_disable_vga_mem(struct drm_device *dev);
  
  #endif /* __INTEL_DRV_H__ */
@@@ -153,8 -153,6 +153,8 @@@ static void intel_dvo_get_config(struc
                flags |= DRM_MODE_FLAG_NVSYNC;
  
        pipe_config->adjusted_mode.flags |= flags;
 +
 +      pipe_config->adjusted_mode.clock = pipe_config->port_clock;
  }
  
  static void intel_disable_dvo(struct intel_encoder *encoder)
@@@ -265,8 -263,15 +265,10 @@@ static bool intel_dvo_compute_config(st
                C(vtotal);
                C(clock);
  #undef C
+               drm_mode_set_crtcinfo(adjusted_mode, 0);
        }
  
 -      if (intel_dvo->dev.dev_ops->mode_fixup)
 -              return intel_dvo->dev.dev_ops->mode_fixup(&intel_dvo->dev,
 -                                                        &pipe_config->requested_mode,
 -                                                        adjusted_mode);
 -
        return true;
  }
  
  #include "i915_drv.h"
  #include "intel_drv.h"
  
 -#define PCI_ASLE 0xe4
 -#define PCI_ASLS 0xfc
 +#define PCI_ASLE              0xe4
 +#define PCI_ASLS              0xfc
 +#define PCI_SWSCI             0xe8
 +#define PCI_SWSCI_SCISEL      (1 << 15)
 +#define PCI_SWSCI_GSSCIE      (1 << 0)
  
  #define OPREGION_HEADER_OFFSET 0
  #define OPREGION_ACPI_OFFSET   0x100
@@@ -110,38 -107,25 +110,38 @@@ struct opregion_asle 
        u32 epfm;       /* enabled panel fitting modes */
        u8 plut[74];    /* panel LUT and identifier */
        u32 pfmb;       /* PWM freq and min brightness */
 -      u8 rsvd[102];
 +      u32 cddv;       /* color correction default values */
 +      u32 pcft;       /* power conservation features */
 +      u32 srot;       /* supported rotation angles */
 +      u32 iuer;       /* IUER events */
 +      u8 rsvd[86];
  } __attribute__((packed));
  
  /* Driver readiness indicator */
  #define ASLE_ARDY_READY               (1 << 0)
  #define ASLE_ARDY_NOT_READY   (0 << 0)
  
 -/* ASLE irq request bits */
 -#define ASLE_SET_ALS_ILLUM     (1 << 0)
 -#define ASLE_SET_BACKLIGHT     (1 << 1)
 -#define ASLE_SET_PFIT          (1 << 2)
 -#define ASLE_SET_PWM_FREQ      (1 << 3)
 -#define ASLE_REQ_MSK           0xf
 -
 -/* response bits of ASLE irq request */
 -#define ASLE_ALS_ILLUM_FAILED (1<<10)
 -#define ASLE_BACKLIGHT_FAILED (1<<12)
 -#define ASLE_PFIT_FAILED      (1<<14)
 -#define ASLE_PWM_FREQ_FAILED  (1<<16)
 +/* ASLE Interrupt Command (ASLC) bits */
 +#define ASLC_SET_ALS_ILLUM            (1 << 0)
 +#define ASLC_SET_BACKLIGHT            (1 << 1)
 +#define ASLC_SET_PFIT                 (1 << 2)
 +#define ASLC_SET_PWM_FREQ             (1 << 3)
 +#define ASLC_SUPPORTED_ROTATION_ANGLES        (1 << 4)
 +#define ASLC_BUTTON_ARRAY             (1 << 5)
 +#define ASLC_CONVERTIBLE_INDICATOR    (1 << 6)
 +#define ASLC_DOCKING_INDICATOR                (1 << 7)
 +#define ASLC_ISCT_STATE_CHANGE                (1 << 8)
 +#define ASLC_REQ_MSK                  0x1ff
 +/* response bits */
 +#define ASLC_ALS_ILLUM_FAILED         (1 << 10)
 +#define ASLC_BACKLIGHT_FAILED         (1 << 12)
 +#define ASLC_PFIT_FAILED              (1 << 14)
 +#define ASLC_PWM_FREQ_FAILED          (1 << 16)
 +#define ASLC_ROTATION_ANGLES_FAILED   (1 << 18)
 +#define ASLC_BUTTON_ARRAY_FAILED      (1 << 20)
 +#define ASLC_CONVERTIBLE_FAILED               (1 << 22)
 +#define ASLC_DOCKING_FAILED           (1 << 24)
 +#define ASLC_ISCT_STATE_FAILED                (1 << 26)
  
  /* Technology enabled indicator */
  #define ASLE_TCHE_ALS_EN      (1 << 0)
  
  #define ASLE_CBLV_VALID         (1<<31)
  
 +/* IUER */
 +#define ASLE_IUER_DOCKING             (1 << 7)
 +#define ASLE_IUER_CONVERTIBLE         (1 << 6)
 +#define ASLE_IUER_ROTATION_LOCK_BTN   (1 << 4)
 +#define ASLE_IUER_VOLUME_DOWN_BTN     (1 << 3)
 +#define ASLE_IUER_VOLUME_UP_BTN               (1 << 2)
 +#define ASLE_IUER_WINDOWS_BTN         (1 << 1)
 +#define ASLE_IUER_POWER_BTN           (1 << 0)
 +
 +/* Software System Control Interrupt (SWSCI) */
 +#define SWSCI_SCIC_INDICATOR          (1 << 0)
 +#define SWSCI_SCIC_MAIN_FUNCTION_SHIFT        1
 +#define SWSCI_SCIC_MAIN_FUNCTION_MASK (0xf << 1)
 +#define SWSCI_SCIC_SUB_FUNCTION_SHIFT 8
 +#define SWSCI_SCIC_SUB_FUNCTION_MASK  (0xff << 8)
 +#define SWSCI_SCIC_EXIT_PARAMETER_SHIFT       8
 +#define SWSCI_SCIC_EXIT_PARAMETER_MASK        (0xff << 8)
 +#define SWSCI_SCIC_EXIT_STATUS_SHIFT  5
 +#define SWSCI_SCIC_EXIT_STATUS_MASK   (7 << 5)
 +#define SWSCI_SCIC_EXIT_STATUS_SUCCESS        1
 +
 +#define SWSCI_FUNCTION_CODE(main, sub) \
 +      ((main) << SWSCI_SCIC_MAIN_FUNCTION_SHIFT | \
 +       (sub) << SWSCI_SCIC_SUB_FUNCTION_SHIFT)
 +
 +/* SWSCI: Get BIOS Data (GBDA) */
 +#define SWSCI_GBDA                    4
 +#define SWSCI_GBDA_SUPPORTED_CALLS    SWSCI_FUNCTION_CODE(SWSCI_GBDA, 0)
 +#define SWSCI_GBDA_REQUESTED_CALLBACKS        SWSCI_FUNCTION_CODE(SWSCI_GBDA, 1)
 +#define SWSCI_GBDA_BOOT_DISPLAY_PREF  SWSCI_FUNCTION_CODE(SWSCI_GBDA, 4)
 +#define SWSCI_GBDA_PANEL_DETAILS      SWSCI_FUNCTION_CODE(SWSCI_GBDA, 5)
 +#define SWSCI_GBDA_TV_STANDARD                SWSCI_FUNCTION_CODE(SWSCI_GBDA, 6)
 +#define SWSCI_GBDA_INTERNAL_GRAPHICS  SWSCI_FUNCTION_CODE(SWSCI_GBDA, 7)
 +#define SWSCI_GBDA_SPREAD_SPECTRUM    SWSCI_FUNCTION_CODE(SWSCI_GBDA, 10)
 +
 +/* SWSCI: System BIOS Callbacks (SBCB) */
 +#define SWSCI_SBCB                    6
 +#define SWSCI_SBCB_SUPPORTED_CALLBACKS        SWSCI_FUNCTION_CODE(SWSCI_SBCB, 0)
 +#define SWSCI_SBCB_INIT_COMPLETION    SWSCI_FUNCTION_CODE(SWSCI_SBCB, 1)
 +#define SWSCI_SBCB_PRE_HIRES_SET_MODE SWSCI_FUNCTION_CODE(SWSCI_SBCB, 3)
 +#define SWSCI_SBCB_POST_HIRES_SET_MODE        SWSCI_FUNCTION_CODE(SWSCI_SBCB, 4)
 +#define SWSCI_SBCB_DISPLAY_SWITCH     SWSCI_FUNCTION_CODE(SWSCI_SBCB, 5)
 +#define SWSCI_SBCB_SET_TV_FORMAT      SWSCI_FUNCTION_CODE(SWSCI_SBCB, 6)
 +#define SWSCI_SBCB_ADAPTER_POWER_STATE        SWSCI_FUNCTION_CODE(SWSCI_SBCB, 7)
 +#define SWSCI_SBCB_DISPLAY_POWER_STATE        SWSCI_FUNCTION_CODE(SWSCI_SBCB, 8)
 +#define SWSCI_SBCB_SET_BOOT_DISPLAY   SWSCI_FUNCTION_CODE(SWSCI_SBCB, 9)
 +#define SWSCI_SBCB_SET_PANEL_DETAILS  SWSCI_FUNCTION_CODE(SWSCI_SBCB, 10)
 +#define SWSCI_SBCB_SET_INTERNAL_GFX   SWSCI_FUNCTION_CODE(SWSCI_SBCB, 11)
 +#define SWSCI_SBCB_POST_HIRES_TO_DOS_FS       SWSCI_FUNCTION_CODE(SWSCI_SBCB, 16)
 +#define SWSCI_SBCB_SUSPEND_RESUME     SWSCI_FUNCTION_CODE(SWSCI_SBCB, 17)
 +#define SWSCI_SBCB_SET_SPREAD_SPECTRUM        SWSCI_FUNCTION_CODE(SWSCI_SBCB, 18)
 +#define SWSCI_SBCB_POST_VBE_PM                SWSCI_FUNCTION_CODE(SWSCI_SBCB, 19)
 +#define SWSCI_SBCB_ENABLE_DISABLE_AUDIO       SWSCI_FUNCTION_CODE(SWSCI_SBCB, 21)
 +
  #define ACPI_OTHER_OUTPUT (0<<8)
  #define ACPI_VGA_OUTPUT (1<<8)
  #define ACPI_TV_OUTPUT (2<<8)
  #define ACPI_LVDS_OUTPUT (4<<8)
  
  #ifdef CONFIG_ACPI
 +static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out)
 +{
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct opregion_swsci __iomem *swsci = dev_priv->opregion.swsci;
 +      u32 main_function, sub_function, scic;
 +      u16 pci_swsci;
 +      u32 dslp;
 +
 +      if (!swsci)
 +              return -ENODEV;
 +
 +      main_function = (function & SWSCI_SCIC_MAIN_FUNCTION_MASK) >>
 +              SWSCI_SCIC_MAIN_FUNCTION_SHIFT;
 +      sub_function = (function & SWSCI_SCIC_SUB_FUNCTION_MASK) >>
 +              SWSCI_SCIC_SUB_FUNCTION_SHIFT;
 +
 +      /* Check if we can call the function. See swsci_setup for details. */
 +      if (main_function == SWSCI_SBCB) {
 +              if ((dev_priv->opregion.swsci_sbcb_sub_functions &
 +                   (1 << sub_function)) == 0)
 +                      return -EINVAL;
 +      } else if (main_function == SWSCI_GBDA) {
 +              if ((dev_priv->opregion.swsci_gbda_sub_functions &
 +                   (1 << sub_function)) == 0)
 +                      return -EINVAL;
 +      }
 +
 +      /* Driver sleep timeout in ms. */
 +      dslp = ioread32(&swsci->dslp);
 +      if (!dslp) {
 +              dslp = 2;
 +      } else if (dslp > 500) {
 +              /* Hey bios, trust must be earned. */
 +              WARN_ONCE(1, "excessive driver sleep timeout (DSPL) %u\n", dslp);
 +              dslp = 500;
 +      }
 +
 +      /* The spec tells us to do this, but we are the only user... */
 +      scic = ioread32(&swsci->scic);
 +      if (scic & SWSCI_SCIC_INDICATOR) {
 +              DRM_DEBUG_DRIVER("SWSCI request already in progress\n");
 +              return -EBUSY;
 +      }
 +
 +      scic = function | SWSCI_SCIC_INDICATOR;
 +
 +      iowrite32(parm, &swsci->parm);
 +      iowrite32(scic, &swsci->scic);
 +
 +      /* Ensure SCI event is selected and event trigger is cleared. */
 +      pci_read_config_word(dev->pdev, PCI_SWSCI, &pci_swsci);
 +      if (!(pci_swsci & PCI_SWSCI_SCISEL) || (pci_swsci & PCI_SWSCI_GSSCIE)) {
 +              pci_swsci |= PCI_SWSCI_SCISEL;
 +              pci_swsci &= ~PCI_SWSCI_GSSCIE;
 +              pci_write_config_word(dev->pdev, PCI_SWSCI, pci_swsci);
 +      }
 +
 +      /* Use event trigger to tell bios to check the mail. */
 +      pci_swsci |= PCI_SWSCI_GSSCIE;
 +      pci_write_config_word(dev->pdev, PCI_SWSCI, pci_swsci);
 +
 +      /* Poll for the result. */
 +#define C (((scic = ioread32(&swsci->scic)) & SWSCI_SCIC_INDICATOR) == 0)
 +      if (wait_for(C, dslp)) {
 +              DRM_DEBUG_DRIVER("SWSCI request timed out\n");
 +              return -ETIMEDOUT;
 +      }
 +
 +      scic = (scic & SWSCI_SCIC_EXIT_STATUS_MASK) >>
 +              SWSCI_SCIC_EXIT_STATUS_SHIFT;
 +
 +      /* Note: scic == 0 is an error! */
 +      if (scic != SWSCI_SCIC_EXIT_STATUS_SUCCESS) {
 +              DRM_DEBUG_DRIVER("SWSCI request error %u\n", scic);
 +              return -EIO;
 +      }
 +
 +      if (parm_out)
 +              *parm_out = ioread32(&swsci->parm);
 +
 +      return 0;
 +
 +#undef C
 +}
 +
 +#define DISPLAY_TYPE_CRT                      0
 +#define DISPLAY_TYPE_TV                               1
 +#define DISPLAY_TYPE_EXTERNAL_FLAT_PANEL      2
 +#define DISPLAY_TYPE_INTERNAL_FLAT_PANEL      3
 +
 +int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
 +                                bool enable)
 +{
 +      struct drm_device *dev = intel_encoder->base.dev;
 +      u32 parm = 0;
 +      u32 type = 0;
 +      u32 port;
 +
 +      /* don't care about old stuff for now */
 +      if (!HAS_DDI(dev))
 +              return 0;
 +
 +      port = intel_ddi_get_encoder_port(intel_encoder);
 +      if (port == PORT_E) {
 +              port = 0;
 +      } else {
 +              parm |= 1 << port;
 +              port++;
 +      }
 +
 +      if (!enable)
 +              parm |= 4 << 8;
 +
 +      switch (intel_encoder->type) {
 +      case INTEL_OUTPUT_ANALOG:
 +              type = DISPLAY_TYPE_CRT;
 +              break;
 +      case INTEL_OUTPUT_UNKNOWN:
 +      case INTEL_OUTPUT_DISPLAYPORT:
 +      case INTEL_OUTPUT_HDMI:
 +              type = DISPLAY_TYPE_EXTERNAL_FLAT_PANEL;
 +              break;
 +      case INTEL_OUTPUT_EDP:
 +              type = DISPLAY_TYPE_INTERNAL_FLAT_PANEL;
 +              break;
 +      default:
 +              WARN_ONCE(1, "unsupported intel_encoder type %d\n",
 +                        intel_encoder->type);
 +              return -EINVAL;
 +      }
 +
 +      parm |= type << (16 + port * 3);
 +
 +      return swsci(dev, SWSCI_SBCB_DISPLAY_POWER_STATE, parm, NULL);
 +}
 +
 +static const struct {
 +      pci_power_t pci_power_state;
 +      u32 parm;
 +} power_state_map[] = {
 +      { PCI_D0,       0x00 },
 +      { PCI_D1,       0x01 },
 +      { PCI_D2,       0x02 },
 +      { PCI_D3hot,    0x04 },
 +      { PCI_D3cold,   0x04 },
 +};
 +
 +int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state)
 +{
 +      int i;
 +
 +      if (!HAS_DDI(dev))
 +              return 0;
 +
 +      for (i = 0; i < ARRAY_SIZE(power_state_map); i++) {
 +              if (state == power_state_map[i].pci_power_state)
 +                      return swsci(dev, SWSCI_SBCB_ADAPTER_POWER_STATE,
 +                                   power_state_map[i].parm, NULL);
 +      }
 +
 +      return -EINVAL;
 +}
 +
  static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp);
  
        if (!(bclp & ASLE_BCLP_VALID))
 -              return ASLE_BACKLIGHT_FAILED;
 +              return ASLC_BACKLIGHT_FAILED;
  
        bclp &= ASLE_BCLP_MSK;
        if (bclp > 255)
 -              return ASLE_BACKLIGHT_FAILED;
 +              return ASLC_BACKLIGHT_FAILED;
  
        intel_panel_set_backlight(dev, bclp, 255);
-       iowrite32((bclp*0x64)/0xff | ASLE_CBLV_VALID, &asle->cblv);
+       iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv);
  
        return 0;
  }
@@@ -416,13 -183,13 +416,13 @@@ static u32 asle_set_als_illum(struct dr
        /* alsi is the current ALS reading in lux. 0 indicates below sensor
           range, 0xffff indicates above sensor range. 1-0xfffe are valid */
        DRM_DEBUG_DRIVER("Illum is not supported\n");
 -      return ASLE_ALS_ILLUM_FAILED;
 +      return ASLC_ALS_ILLUM_FAILED;
  }
  
  static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
  {
        DRM_DEBUG_DRIVER("PWM freq is not supported\n");
 -      return ASLE_PWM_FREQ_FAILED;
 +      return ASLC_PWM_FREQ_FAILED;
  }
  
  static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
        /* Panel fitting is currently controlled by the X code, so this is a
           noop until modesetting support works fully */
        DRM_DEBUG_DRIVER("Pfit is not supported\n");
 -      return ASLE_PFIT_FAILED;
 +      return ASLC_PFIT_FAILED;
 +}
 +
 +static u32 asle_set_supported_rotation_angles(struct drm_device *dev, u32 srot)
 +{
 +      DRM_DEBUG_DRIVER("SROT is not supported\n");
 +      return ASLC_ROTATION_ANGLES_FAILED;
 +}
 +
 +static u32 asle_set_button_array(struct drm_device *dev, u32 iuer)
 +{
 +      if (!iuer)
 +              DRM_DEBUG_DRIVER("Button array event is not supported (nothing)\n");
 +      if (iuer & ASLE_IUER_ROTATION_LOCK_BTN)
 +              DRM_DEBUG_DRIVER("Button array event is not supported (rotation lock)\n");
 +      if (iuer & ASLE_IUER_VOLUME_DOWN_BTN)
 +              DRM_DEBUG_DRIVER("Button array event is not supported (volume down)\n");
 +      if (iuer & ASLE_IUER_VOLUME_UP_BTN)
 +              DRM_DEBUG_DRIVER("Button array event is not supported (volume up)\n");
 +      if (iuer & ASLE_IUER_WINDOWS_BTN)
 +              DRM_DEBUG_DRIVER("Button array event is not supported (windows)\n");
 +      if (iuer & ASLE_IUER_POWER_BTN)
 +              DRM_DEBUG_DRIVER("Button array event is not supported (power)\n");
 +
 +      return ASLC_BUTTON_ARRAY_FAILED;
 +}
 +
 +static u32 asle_set_convertible(struct drm_device *dev, u32 iuer)
 +{
 +      if (iuer & ASLE_IUER_CONVERTIBLE)
 +              DRM_DEBUG_DRIVER("Convertible is not supported (clamshell)\n");
 +      else
 +              DRM_DEBUG_DRIVER("Convertible is not supported (slate)\n");
 +
 +      return ASLC_CONVERTIBLE_FAILED;
 +}
 +
 +static u32 asle_set_docking(struct drm_device *dev, u32 iuer)
 +{
 +      if (iuer & ASLE_IUER_DOCKING)
 +              DRM_DEBUG_DRIVER("Docking is not supported (docked)\n");
 +      else
 +              DRM_DEBUG_DRIVER("Docking is not supported (undocked)\n");
 +
 +      return ASLC_DOCKING_FAILED;
 +}
 +
 +static u32 asle_isct_state(struct drm_device *dev)
 +{
 +      DRM_DEBUG_DRIVER("ISCT is not supported\n");
 +      return ASLC_ISCT_STATE_FAILED;
  }
  
  void intel_opregion_asle_intr(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
 -      u32 asle_stat = 0;
 -      u32 asle_req;
 +      u32 aslc_stat = 0;
 +      u32 aslc_req;
  
        if (!asle)
                return;
  
 -      asle_req = ioread32(&asle->aslc) & ASLE_REQ_MSK;
 +      aslc_req = ioread32(&asle->aslc);
  
 -      if (!asle_req) {
 -              DRM_DEBUG_DRIVER("non asle set request??\n");
 +      if (!(aslc_req & ASLC_REQ_MSK)) {
 +              DRM_DEBUG_DRIVER("No request on ASLC interrupt 0x%08x\n",
 +                               aslc_req);
                return;
        }
  
 -      if (asle_req & ASLE_SET_ALS_ILLUM)
 -              asle_stat |= asle_set_als_illum(dev, ioread32(&asle->alsi));
 +      if (aslc_req & ASLC_SET_ALS_ILLUM)
 +              aslc_stat |= asle_set_als_illum(dev, ioread32(&asle->alsi));
 +
 +      if (aslc_req & ASLC_SET_BACKLIGHT)
 +              aslc_stat |= asle_set_backlight(dev, ioread32(&asle->bclp));
 +
 +      if (aslc_req & ASLC_SET_PFIT)
 +              aslc_stat |= asle_set_pfit(dev, ioread32(&asle->pfit));
 +
 +      if (aslc_req & ASLC_SET_PWM_FREQ)
 +              aslc_stat |= asle_set_pwm_freq(dev, ioread32(&asle->pfmb));
  
 -      if (asle_req & ASLE_SET_BACKLIGHT)
 -              asle_stat |= asle_set_backlight(dev, ioread32(&asle->bclp));
 +      if (aslc_req & ASLC_SUPPORTED_ROTATION_ANGLES)
 +              aslc_stat |= asle_set_supported_rotation_angles(dev,
 +                                                      ioread32(&asle->srot));
  
 -      if (asle_req & ASLE_SET_PFIT)
 -              asle_stat |= asle_set_pfit(dev, ioread32(&asle->pfit));
 +      if (aslc_req & ASLC_BUTTON_ARRAY)
 +              aslc_stat |= asle_set_button_array(dev, ioread32(&asle->iuer));
  
 -      if (asle_req & ASLE_SET_PWM_FREQ)
 -              asle_stat |= asle_set_pwm_freq(dev, ioread32(&asle->pfmb));
 +      if (aslc_req & ASLC_CONVERTIBLE_INDICATOR)
 +              aslc_stat |= asle_set_convertible(dev, ioread32(&asle->iuer));
  
 -      iowrite32(asle_stat, &asle->aslc);
 +      if (aslc_req & ASLC_DOCKING_INDICATOR)
 +              aslc_stat |= asle_set_docking(dev, ioread32(&asle->iuer));
 +
 +      if (aslc_req & ASLC_ISCT_STATE_CHANGE)
 +              aslc_stat |= asle_isct_state(dev);
 +
 +      iowrite32(aslc_stat, &asle->aslc);
  }
  
  #define ACPI_EV_DISPLAY_SWITCH (1<<0)
@@@ -746,68 -446,8 +746,68 @@@ void intel_opregion_fini(struct drm_dev
        opregion->swsci = NULL;
        opregion->asle = NULL;
        opregion->vbt = NULL;
 +      opregion->lid_state = NULL;
 +}
 +
 +static void swsci_setup(struct drm_device *dev)
 +{
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct intel_opregion *opregion = &dev_priv->opregion;
 +      bool requested_callbacks = false;
 +      u32 tmp;
 +
 +      /* Sub-function code 0 is okay, let's allow them. */
 +      opregion->swsci_gbda_sub_functions = 1;
 +      opregion->swsci_sbcb_sub_functions = 1;
 +
 +      /* We use GBDA to ask for supported GBDA calls. */
 +      if (swsci(dev, SWSCI_GBDA_SUPPORTED_CALLS, 0, &tmp) == 0) {
 +              /* make the bits match the sub-function codes */
 +              tmp <<= 1;
 +              opregion->swsci_gbda_sub_functions |= tmp;
 +      }
 +
 +      /*
 +       * We also use GBDA to ask for _requested_ SBCB callbacks. The driver
 +       * must not call interfaces that are not specifically requested by the
 +       * bios.
 +       */
 +      if (swsci(dev, SWSCI_GBDA_REQUESTED_CALLBACKS, 0, &tmp) == 0) {
 +              /* here, the bits already match sub-function codes */
 +              opregion->swsci_sbcb_sub_functions |= tmp;
 +              requested_callbacks = true;
 +      }
 +
 +      /*
 +       * But we use SBCB to ask for _supported_ SBCB calls. This does not mean
 +       * the callback is _requested_. But we still can't call interfaces that
 +       * are not requested.
 +       */
 +      if (swsci(dev, SWSCI_SBCB_SUPPORTED_CALLBACKS, 0, &tmp) == 0) {
 +              /* make the bits match the sub-function codes */
 +              u32 low = tmp & 0x7ff;
 +              u32 high = tmp & ~0xfff; /* bit 11 is reserved */
 +              tmp = (high << 4) | (low << 1) | 1;
 +
 +              /* best guess what to do with supported wrt requested */
 +              if (requested_callbacks) {
 +                      u32 req = opregion->swsci_sbcb_sub_functions;
 +                      if ((req & tmp) != req)
 +                              DRM_DEBUG_DRIVER("SWSCI BIOS requested (%08x) SBCB callbacks that are not supported (%08x)\n", req, tmp);
 +                      /* XXX: for now, trust the requested callbacks */
 +                      /* opregion->swsci_sbcb_sub_functions &= tmp; */
 +              } else {
 +                      opregion->swsci_sbcb_sub_functions |= tmp;
 +              }
 +      }
 +
 +      DRM_DEBUG_DRIVER("SWSCI GBDA callbacks %08x, SBCB callbacks %08x\n",
 +                       opregion->swsci_gbda_sub_functions,
 +                       opregion->swsci_sbcb_sub_functions);
  }
 -#endif
 +#else /* CONFIG_ACPI */
 +static inline void swsci_setup(struct drm_device *dev) {}
 +#endif  /* CONFIG_ACPI */
  
  int intel_opregion_setup(struct drm_device *dev)
  {
        if (mboxes & MBOX_SWSCI) {
                DRM_DEBUG_DRIVER("SWSCI supported\n");
                opregion->swsci = base + OPREGION_SWSCI_OFFSET;
 +              swsci_setup(dev);
        }
        if (mboxes & MBOX_ASLE) {
                DRM_DEBUG_DRIVER("ASLE supported\n");
@@@ -50,22 -50,23 +50,22 @@@ intel_pch_panel_fitting(struct intel_cr
                        struct intel_crtc_config *pipe_config,
                        int fitting_mode)
  {
 -      struct drm_display_mode *mode, *adjusted_mode;
 +      struct drm_display_mode *adjusted_mode;
        int x, y, width, height;
  
 -      mode = &pipe_config->requested_mode;
        adjusted_mode = &pipe_config->adjusted_mode;
  
        x = y = width = height = 0;
  
        /* Native modes don't need fitting */
 -      if (adjusted_mode->hdisplay == mode->hdisplay &&
 -          adjusted_mode->vdisplay == mode->vdisplay)
 +      if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
 +          adjusted_mode->vdisplay == pipe_config->pipe_src_h)
                goto done;
  
        switch (fitting_mode) {
        case DRM_MODE_SCALE_CENTER:
 -              width = mode->hdisplay;
 -              height = mode->vdisplay;
 +              width = pipe_config->pipe_src_w;
 +              height = pipe_config->pipe_src_h;
                x = (adjusted_mode->hdisplay - width + 1)/2;
                y = (adjusted_mode->vdisplay - height + 1)/2;
                break;
        case DRM_MODE_SCALE_ASPECT:
                /* Scale but preserve the aspect ratio */
                {
 -                      u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
 -                      u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
 +                      u32 scaled_width = adjusted_mode->hdisplay
 +                              * pipe_config->pipe_src_h;
 +                      u32 scaled_height = pipe_config->pipe_src_w
 +                              * adjusted_mode->vdisplay;
                        if (scaled_width > scaled_height) { /* pillar */
 -                              width = scaled_height / mode->vdisplay;
 +                              width = scaled_height / pipe_config->pipe_src_h;
                                if (width & 1)
                                        width++;
                                x = (adjusted_mode->hdisplay - width + 1) / 2;
                                y = 0;
                                height = adjusted_mode->vdisplay;
                        } else if (scaled_width < scaled_height) { /* letter */
 -                              height = scaled_width / mode->hdisplay;
 +                              height = scaled_width / pipe_config->pipe_src_w;
                                if (height & 1)
                                    height++;
                                y = (adjusted_mode->vdisplay - height + 1) / 2;
  done:
        pipe_config->pch_pfit.pos = (x << 16) | y;
        pipe_config->pch_pfit.size = (width << 16) | height;
+       pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
  }
  
  static void
@@@ -171,96 -171,20 +172,96 @@@ static inline u32 panel_fitter_scaling(
        return (FACTOR * ratio + FACTOR/2) / FACTOR;
  }
  
 +static void i965_scale_aspect(struct intel_crtc_config *pipe_config,
 +                            u32 *pfit_control)
 +{
 +      struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
 +      u32 scaled_width = adjusted_mode->hdisplay *
 +              pipe_config->pipe_src_h;
 +      u32 scaled_height = pipe_config->pipe_src_w *
 +              adjusted_mode->vdisplay;
 +
 +      /* 965+ is easy, it does everything in hw */
 +      if (scaled_width > scaled_height)
 +              *pfit_control |= PFIT_ENABLE |
 +                      PFIT_SCALING_PILLAR;
 +      else if (scaled_width < scaled_height)
 +              *pfit_control |= PFIT_ENABLE |
 +                      PFIT_SCALING_LETTER;
 +      else if (adjusted_mode->hdisplay != pipe_config->pipe_src_w)
 +              *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
 +}
 +
 +static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config,
 +                            u32 *pfit_control, u32 *pfit_pgm_ratios,
 +                            u32 *border)
 +{
 +      struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
 +      u32 scaled_width = adjusted_mode->hdisplay *
 +              pipe_config->pipe_src_h;
 +      u32 scaled_height = pipe_config->pipe_src_w *
 +              adjusted_mode->vdisplay;
 +      u32 bits;
 +
 +      /*
 +       * For earlier chips we have to calculate the scaling
 +       * ratio by hand and program it into the
 +       * PFIT_PGM_RATIO register
 +       */
 +      if (scaled_width > scaled_height) { /* pillar */
 +              centre_horizontally(adjusted_mode,
 +                                  scaled_height /
 +                                  pipe_config->pipe_src_h);
 +
 +              *border = LVDS_BORDER_ENABLE;
 +              if (pipe_config->pipe_src_h != adjusted_mode->vdisplay) {
 +                      bits = panel_fitter_scaling(pipe_config->pipe_src_h,
 +                                                  adjusted_mode->vdisplay);
 +
 +                      *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
 +                                           bits << PFIT_VERT_SCALE_SHIFT);
 +                      *pfit_control |= (PFIT_ENABLE |
 +                                        VERT_INTERP_BILINEAR |
 +                                        HORIZ_INTERP_BILINEAR);
 +              }
 +      } else if (scaled_width < scaled_height) { /* letter */
 +              centre_vertically(adjusted_mode,
 +                                scaled_width /
 +                                pipe_config->pipe_src_w);
 +
 +              *border = LVDS_BORDER_ENABLE;
 +              if (pipe_config->pipe_src_w != adjusted_mode->hdisplay) {
 +                      bits = panel_fitter_scaling(pipe_config->pipe_src_w,
 +                                                  adjusted_mode->hdisplay);
 +
 +                      *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
 +                                           bits << PFIT_VERT_SCALE_SHIFT);
 +                      *pfit_control |= (PFIT_ENABLE |
 +                                        VERT_INTERP_BILINEAR |
 +                                        HORIZ_INTERP_BILINEAR);
 +              }
 +      } else {
 +              /* Aspects match, Let hw scale both directions */
 +              *pfit_control |= (PFIT_ENABLE |
 +                                VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
 +                                VERT_INTERP_BILINEAR |
 +                                HORIZ_INTERP_BILINEAR);
 +      }
 +}
 +
  void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
                              struct intel_crtc_config *pipe_config,
                              int fitting_mode)
  {
        struct drm_device *dev = intel_crtc->base.dev;
        u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
 -      struct drm_display_mode *mode, *adjusted_mode;
 +      struct drm_display_mode *adjusted_mode;
  
 -      mode = &pipe_config->requested_mode;
        adjusted_mode = &pipe_config->adjusted_mode;
  
        /* Native modes don't need fitting */
 -      if (adjusted_mode->hdisplay == mode->hdisplay &&
 -          adjusted_mode->vdisplay == mode->vdisplay)
 +      if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
 +          adjusted_mode->vdisplay == pipe_config->pipe_src_h)
                goto out;
  
        switch (fitting_mode) {
                 * For centered modes, we have to calculate border widths &
                 * heights and modify the values programmed into the CRTC.
                 */
 -              centre_horizontally(adjusted_mode, mode->hdisplay);
 -              centre_vertically(adjusted_mode, mode->vdisplay);
 +              centre_horizontally(adjusted_mode, pipe_config->pipe_src_w);
 +              centre_vertically(adjusted_mode, pipe_config->pipe_src_h);
                border = LVDS_BORDER_ENABLE;
                break;
        case DRM_MODE_SCALE_ASPECT:
                /* Scale but preserve the aspect ratio */
 -              if (INTEL_INFO(dev)->gen >= 4) {
 -                      u32 scaled_width = adjusted_mode->hdisplay *
 -                              mode->vdisplay;
 -                      u32 scaled_height = mode->hdisplay *
 -                              adjusted_mode->vdisplay;
 -
 -                      /* 965+ is easy, it does everything in hw */
 -                      if (scaled_width > scaled_height)
 -                              pfit_control |= PFIT_ENABLE |
 -                                      PFIT_SCALING_PILLAR;
 -                      else if (scaled_width < scaled_height)
 -                              pfit_control |= PFIT_ENABLE |
 -                                      PFIT_SCALING_LETTER;
 -                      else if (adjusted_mode->hdisplay != mode->hdisplay)
 -                              pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
 -              } else {
 -                      u32 scaled_width = adjusted_mode->hdisplay *
 -                              mode->vdisplay;
 -                      u32 scaled_height = mode->hdisplay *
 -                              adjusted_mode->vdisplay;
 -                      /*
 -                       * For earlier chips we have to calculate the scaling
 -                       * ratio by hand and program it into the
 -                       * PFIT_PGM_RATIO register
 -                       */
 -                      if (scaled_width > scaled_height) { /* pillar */
 -                              centre_horizontally(adjusted_mode,
 -                                                  scaled_height /
 -                                                  mode->vdisplay);
 -
 -                              border = LVDS_BORDER_ENABLE;
 -                              if (mode->vdisplay != adjusted_mode->vdisplay) {
 -                                      u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay);
 -                                      pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
 -                                                          bits << PFIT_VERT_SCALE_SHIFT);
 -                                      pfit_control |= (PFIT_ENABLE |
 -                                                       VERT_INTERP_BILINEAR |
 -                                                       HORIZ_INTERP_BILINEAR);
 -                              }
 -                      } else if (scaled_width < scaled_height) { /* letter */
 -                              centre_vertically(adjusted_mode,
 -                                                scaled_width /
 -                                                mode->hdisplay);
 -
 -                              border = LVDS_BORDER_ENABLE;
 -                              if (mode->hdisplay != adjusted_mode->hdisplay) {
 -                                      u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay);
 -                                      pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
 -                                                          bits << PFIT_VERT_SCALE_SHIFT);
 -                                      pfit_control |= (PFIT_ENABLE |
 -                                                       VERT_INTERP_BILINEAR |
 -                                                       HORIZ_INTERP_BILINEAR);
 -                              }
 -                      } else {
 -                              /* Aspects match, Let hw scale both directions */
 -                              pfit_control |= (PFIT_ENABLE |
 -                                               VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
 -                                               VERT_INTERP_BILINEAR |
 -                                               HORIZ_INTERP_BILINEAR);
 -                      }
 -              }
 +              if (INTEL_INFO(dev)->gen >= 4)
 +                      i965_scale_aspect(pipe_config, &pfit_control);
 +              else
 +                      i9xx_scale_aspect(pipe_config, &pfit_control,
 +                                        &pfit_pgm_ratios, &border);
                break;
        case DRM_MODE_SCALE_FULLSCREEN:
                /*
                 * Full scaling, even if it changes the aspect ratio.
                 * Fortunately this is all done for us in hw.
                 */
 -              if (mode->vdisplay != adjusted_mode->vdisplay ||
 -                  mode->hdisplay != adjusted_mode->hdisplay) {
 +              if (pipe_config->pipe_src_h != adjusted_mode->vdisplay ||
 +                  pipe_config->pipe_src_w != adjusted_mode->hdisplay) {
                        pfit_control |= PFIT_ENABLE;
                        if (INTEL_INFO(dev)->gen >= 4)
                                pfit_control |= PFIT_SCALING_AUTO;
@@@ -461,8 -441,7 +462,8 @@@ static void intel_pch_panel_set_backlig
        I915_WRITE(BLC_PWM_CPU_CTL, val | level);
  }
  
 -static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level)
 +static void intel_panel_actually_set_backlight(struct drm_device *dev,
 +                                             u32 level)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 tmp;
@@@ -658,7 -637,7 +659,7 @@@ intel_panel_detect(struct drm_device *d
        }
  }
  
 -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
 +#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
  static int intel_panel_update_status(struct backlight_device *bd)
  {
        struct drm_device *dev = bl_get_data(bd);
   * i915.i915_enable_fbc parameter
   */
  
 -static bool intel_crtc_active(struct drm_crtc *crtc)
 -{
 -      /* Be paranoid as we can arrive here with only partial
 -       * state retrieved from the hardware during setup.
 -       */
 -      return to_intel_crtc(crtc)->active && crtc->fb && crtc->mode.clock;
 -}
 -
  static void i8xx_disable_fbc(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@@ -450,8 -458,7 +450,8 @@@ void intel_update_fbc(struct drm_devic
        struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
        struct drm_i915_gem_object *obj;
 -      unsigned int max_hdisplay, max_vdisplay;
 +      const struct drm_display_mode *adjusted_mode;
 +      unsigned int max_width, max_height;
  
        if (!I915_HAS_FBC(dev)) {
                set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED);
        fb = crtc->fb;
        intel_fb = to_intel_framebuffer(fb);
        obj = intel_fb->obj;
 +      adjusted_mode = &intel_crtc->config.adjusted_mode;
  
        if (i915_enable_fbc < 0 &&
            INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) {
                        DRM_DEBUG_KMS("fbc disabled per module param\n");
                goto out_disable;
        }
 -      if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
 -          (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
 +      if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ||
 +          (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
                if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
                        DRM_DEBUG_KMS("mode incompatible with compression, "
                                      "disabling\n");
        }
  
        if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
 -              max_hdisplay = 4096;
 -              max_vdisplay = 2048;
 +              max_width = 4096;
 +              max_height = 2048;
        } else {
 -              max_hdisplay = 2048;
 -              max_vdisplay = 1536;
 +              max_width = 2048;
 +              max_height = 1536;
        }
 -      if ((crtc->mode.hdisplay > max_hdisplay) ||
 -          (crtc->mode.vdisplay > max_vdisplay)) {
 +      if (intel_crtc->config.pipe_src_w > max_width ||
 +          intel_crtc->config.pipe_src_h > max_height) {
                if (set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE))
                        DRM_DEBUG_KMS("mode too large for compression, disabling\n");
                goto out_disable;
@@@ -1081,9 -1087,8 +1081,9 @@@ static struct drm_crtc *single_enabled_
        return enabled;
  }
  
 -static void pineview_update_wm(struct drm_device *dev)
 +static void pineview_update_wm(struct drm_crtc *unused_crtc)
  {
 +      struct drm_device *dev = unused_crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc;
        const struct cxsr_latency *latency;
  
        crtc = single_enabled_crtc(dev);
        if (crtc) {
 -              int clock = crtc->mode.clock;
 +              int clock = to_intel_crtc(crtc)->config.adjusted_mode.clock;
                int pixel_size = crtc->fb->bits_per_pixel / 8;
  
                /* Display SR */
@@@ -1161,7 -1166,6 +1161,7 @@@ static bool g4x_compute_wm0(struct drm_
                            int *cursor_wm)
  {
        struct drm_crtc *crtc;
 +      const struct drm_display_mode *adjusted_mode;
        int htotal, hdisplay, clock, pixel_size;
        int line_time_us, line_count;
        int entries, tlb_miss;
                return false;
        }
  
 -      htotal = crtc->mode.htotal;
 -      hdisplay = crtc->mode.hdisplay;
 -      clock = crtc->mode.clock;
 +      adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
 +      clock = adjusted_mode->clock;
 +      htotal = adjusted_mode->htotal;
 +      hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
        pixel_size = crtc->fb->bits_per_pixel / 8;
  
        /* Use the small buffer method to calculate plane watermark */
@@@ -1247,7 -1250,6 +1247,7 @@@ static bool g4x_compute_srwm(struct drm
                             int *display_wm, int *cursor_wm)
  {
        struct drm_crtc *crtc;
 +      const struct drm_display_mode *adjusted_mode;
        int hdisplay, htotal, pixel_size, clock;
        unsigned long line_time_us;
        int line_count, line_size;
        }
  
        crtc = intel_get_crtc_for_plane(dev, plane);
 -      hdisplay = crtc->mode.hdisplay;
 -      htotal = crtc->mode.htotal;
 -      clock = crtc->mode.clock;
 +      adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
 +      clock = adjusted_mode->clock;
 +      htotal = adjusted_mode->htotal;
 +      hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
        pixel_size = crtc->fb->bits_per_pixel / 8;
  
        line_time_us = (htotal * 1000) / clock;
@@@ -1302,7 -1303,7 +1302,7 @@@ static bool vlv_compute_drain_latency(s
        if (!intel_crtc_active(crtc))
                return false;
  
 -      clock = crtc->mode.clock;       /* VESA DOT Clock */
 +      clock = to_intel_crtc(crtc)->config.adjusted_mode.clock;
        pixel_size = crtc->fb->bits_per_pixel / 8;      /* BPP */
  
        entries = (clock / 1000) * pixel_size;
@@@ -1364,9 -1365,8 +1364,9 @@@ static void vlv_update_drain_latency(st
  
  #define single_plane_enabled(mask) is_power_of_2(mask)
  
 -static void valleyview_update_wm(struct drm_device *dev)
 +static void valleyview_update_wm(struct drm_crtc *crtc)
  {
 +      struct drm_device *dev = crtc->dev;
        static const int sr_latency_ns = 12000;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
                   (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
  }
  
 -static void g4x_update_wm(struct drm_device *dev)
 +static void g4x_update_wm(struct drm_crtc *crtc)
  {
 +      struct drm_device *dev = crtc->dev;
        static const int sr_latency_ns = 12000;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
                   (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
  }
  
 -static void i965_update_wm(struct drm_device *dev)
 +static void i965_update_wm(struct drm_crtc *unused_crtc)
  {
 +      struct drm_device *dev = unused_crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc;
        int srwm = 1;
        if (crtc) {
                /* self-refresh has much higher latency */
                static const int sr_latency_ns = 12000;
 -              int clock = crtc->mode.clock;
 -              int htotal = crtc->mode.htotal;
 -              int hdisplay = crtc->mode.hdisplay;
 +              const struct drm_display_mode *adjusted_mode =
 +                      &to_intel_crtc(crtc)->config.adjusted_mode;
 +              int clock = adjusted_mode->clock;
 +              int htotal = adjusted_mode->htotal;
 +              int hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
                int pixel_size = crtc->fb->bits_per_pixel / 8;
                unsigned long line_time_us;
                int entries;
        I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
  }
  
 -static void i9xx_update_wm(struct drm_device *dev)
 +static void i9xx_update_wm(struct drm_crtc *unused_crtc)
  {
 +      struct drm_device *dev = unused_crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        const struct intel_watermark_params *wm_info;
        uint32_t fwater_lo;
                if (IS_GEN2(dev))
                        cpp = 4;
  
 -              planea_wm = intel_calculate_wm(crtc->mode.clock,
 +              planea_wm = intel_calculate_wm(to_intel_crtc(crtc)->config.adjusted_mode.clock,
                                               wm_info, fifo_size, cpp,
                                               latency_ns);
                enabled = crtc;
                if (IS_GEN2(dev))
                        cpp = 4;
  
 -              planeb_wm = intel_calculate_wm(crtc->mode.clock,
 +              planeb_wm = intel_calculate_wm(to_intel_crtc(crtc)->config.adjusted_mode.clock,
                                               wm_info, fifo_size, cpp,
                                               latency_ns);
                if (enabled == NULL)
        if (HAS_FW_BLC(dev) && enabled) {
                /* self-refresh has much higher latency */
                static const int sr_latency_ns = 6000;
 -              int clock = enabled->mode.clock;
 -              int htotal = enabled->mode.htotal;
 -              int hdisplay = enabled->mode.hdisplay;
 +              const struct drm_display_mode *adjusted_mode =
 +                      &to_intel_crtc(enabled)->config.adjusted_mode;
 +              int clock = adjusted_mode->clock;
 +              int htotal = adjusted_mode->htotal;
 +              int hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
                int pixel_size = enabled->fb->bits_per_pixel / 8;
                unsigned long line_time_us;
                int entries;
        }
  }
  
 -static void i830_update_wm(struct drm_device *dev)
 +static void i830_update_wm(struct drm_crtc *unused_crtc)
  {
 +      struct drm_device *dev = unused_crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc;
        uint32_t fwater_lo;
        if (crtc == NULL)
                return;
  
 -      planea_wm = intel_calculate_wm(crtc->mode.clock, &i830_wm_info,
 +      planea_wm = intel_calculate_wm(to_intel_crtc(crtc)->config.adjusted_mode.clock,
 +                                     &i830_wm_info,
                                       dev_priv->display.get_fifo_size(dev, 0),
                                       4, latency_ns);
        fwater_lo = I915_READ(FW_BLC) & ~0xfff;
@@@ -1750,7 -1741,6 +1750,7 @@@ static bool ironlake_compute_srwm(struc
                                  int *fbc_wm, int *display_wm, int *cursor_wm)
  {
        struct drm_crtc *crtc;
 +      const struct drm_display_mode *adjusted_mode;
        unsigned long line_time_us;
        int hdisplay, htotal, pixel_size, clock;
        int line_count, line_size;
        }
  
        crtc = intel_get_crtc_for_plane(dev, plane);
 -      hdisplay = crtc->mode.hdisplay;
 -      htotal = crtc->mode.htotal;
 -      clock = crtc->mode.clock;
 +      adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
 +      clock = adjusted_mode->clock;
 +      htotal = adjusted_mode->htotal;
 +      hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
        pixel_size = crtc->fb->bits_per_pixel / 8;
  
        line_time_us = (htotal * 1000) / clock;
                                   display, cursor);
  }
  
 -static void ironlake_update_wm(struct drm_device *dev)
 +static void ironlake_update_wm(struct drm_crtc *crtc)
  {
 +      struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int fbc_wm, plane_wm, cursor_wm;
        unsigned int enabled;
         */
  }
  
 -static void sandybridge_update_wm(struct drm_device *dev)
 +static void sandybridge_update_wm(struct drm_crtc *crtc)
  {
 +      struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int latency = dev_priv->wm.pri_latency[0] * 100;        /* In unit 0.1us */
        u32 val;
                   cursor_wm);
  }
  
 -static void ivybridge_update_wm(struct drm_device *dev)
 +static void ivybridge_update_wm(struct drm_crtc *crtc)
  {
 +      struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int latency = dev_priv->wm.pri_latency[0] * 100;        /* In unit 0.1us */
        u32 val;
@@@ -2110,19 -2096,19 +2110,19 @@@ static uint32_t ilk_pipe_pixel_rate(str
                                    struct drm_crtc *crtc)
  {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       uint32_t pixel_rate, pfit_size;
+       uint32_t pixel_rate;
  
        pixel_rate = intel_crtc->config.adjusted_mode.clock;
  
        /* We only use IF-ID interlacing. If we ever use PF-ID we'll need to
         * adjust the pixel_rate here. */
  
-       pfit_size = intel_crtc->config.pch_pfit.size;
-       if (pfit_size) {
+       if (intel_crtc->config.pch_pfit.enabled) {
                uint64_t pipe_w, pipe_h, pfit_w, pfit_h;
+               uint32_t pfit_size = intel_crtc->config.pch_pfit.size;
  
 -              pipe_w = intel_crtc->config.requested_mode.hdisplay;
 -              pipe_h = intel_crtc->config.requested_mode.vdisplay;
 +              pipe_w = intel_crtc->config.pipe_src_w;
 +              pipe_h = intel_crtc->config.pipe_src_h;
                pfit_w = (pfit_size >> 16) & 0xFFFF;
                pfit_h = pfit_size & 0xFFFF;
                if (pipe_w < pfit_w)
@@@ -2210,7 -2196,7 +2210,7 @@@ struct intel_wm_config 
   * For both WM_PIPE and WM_LP.
   * mem_value must be in 0.1us units.
   */
 -static uint32_t ilk_compute_pri_wm(struct hsw_pipe_wm_parameters *params,
 +static uint32_t ilk_compute_pri_wm(const struct hsw_pipe_wm_parameters *params,
                                   uint32_t mem_value,
                                   bool is_lp)
  {
   * For both WM_PIPE and WM_LP.
   * mem_value must be in 0.1us units.
   */
 -static uint32_t ilk_compute_spr_wm(struct hsw_pipe_wm_parameters *params,
 +static uint32_t ilk_compute_spr_wm(const struct hsw_pipe_wm_parameters *params,
                                   uint32_t mem_value)
  {
        uint32_t method1, method2;
   * For both WM_PIPE and WM_LP.
   * mem_value must be in 0.1us units.
   */
 -static uint32_t ilk_compute_cur_wm(struct hsw_pipe_wm_parameters *params,
 +static uint32_t ilk_compute_cur_wm(const struct hsw_pipe_wm_parameters *params,
                                   uint32_t mem_value)
  {
        if (!params->active || !params->cur.enabled)
  }
  
  /* Only for WM_LP. */
 -static uint32_t ilk_compute_fbc_wm(struct hsw_pipe_wm_parameters *params,
 +static uint32_t ilk_compute_fbc_wm(const struct hsw_pipe_wm_parameters *params,
                                   uint32_t pri_val)
  {
        if (!params->active || !params->pri.enabled)
@@@ -2427,7 -2413,7 +2427,7 @@@ static bool ilk_check_wm(int level
  
  static void ilk_compute_wm_level(struct drm_i915_private *dev_priv,
                                 int level,
 -                               struct hsw_pipe_wm_parameters *p,
 +                               const struct hsw_pipe_wm_parameters *p,
                                 struct intel_wm_level *result)
  {
        uint16_t pri_latency = dev_priv->wm.pri_latency[level];
  }
  
  static bool hsw_compute_lp_wm(struct drm_i915_private *dev_priv,
 -                            int level, struct hsw_wm_maximums *max,
 -                            struct hsw_pipe_wm_parameters *params,
 +                            int level, const struct hsw_wm_maximums *max,
 +                            const struct hsw_pipe_wm_parameters *params,
                              struct intel_wm_level *result)
  {
        enum pipe pipe;
        return ilk_check_wm(level, max, result);
  }
  
 -static uint32_t hsw_compute_wm_pipe(struct drm_i915_private *dev_priv,
 -                                  enum pipe pipe,
 -                                  struct hsw_pipe_wm_parameters *params)
 +
 +static uint32_t hsw_compute_wm_pipe(struct drm_device *dev,
 +                                  const struct hsw_pipe_wm_parameters *params)
  {
 -      uint32_t pri_val, cur_val, spr_val;
 -      /* WM0 latency values stored in 0.1us units */
 -      uint16_t pri_latency = dev_priv->wm.pri_latency[0];
 -      uint16_t spr_latency = dev_priv->wm.spr_latency[0];
 -      uint16_t cur_latency = dev_priv->wm.cur_latency[0];
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct intel_wm_config config = {
 +              .num_pipes_active = 1,
 +              .sprites_enabled = params->spr.enabled,
 +              .sprites_scaled = params->spr.scaled,
 +      };
 +      struct hsw_wm_maximums max;
 +      struct intel_wm_level res;
 +
 +      if (!params->active)
 +              return 0;
 +
 +      ilk_wm_max(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
  
 -      pri_val = ilk_compute_pri_wm(params, pri_latency, false);
 -      spr_val = ilk_compute_spr_wm(params, spr_latency);
 -      cur_val = ilk_compute_cur_wm(params, cur_latency);
 +      ilk_compute_wm_level(dev_priv, 0, params, &res);
  
 -      WARN(pri_val > 127,
 -           "Primary WM error, mode not supported for pipe %c\n",
 -           pipe_name(pipe));
 -      WARN(spr_val > 127,
 -           "Sprite WM error, mode not supported for pipe %c\n",
 -           pipe_name(pipe));
 -      WARN(cur_val > 63,
 -           "Cursor WM error, mode not supported for pipe %c\n",
 -           pipe_name(pipe));
 +      ilk_check_wm(0, &max, &res);
  
 -      return (pri_val << WM0_PIPE_PLANE_SHIFT) |
 -             (spr_val << WM0_PIPE_SPRITE_SHIFT) |
 -             cur_val;
 +      return (res.pri_val << WM0_PIPE_PLANE_SHIFT) |
 +             (res.spr_val << WM0_PIPE_SPRITE_SHIFT) |
 +             res.cur_val;
  }
  
  static uint32_t
@@@ -2566,22 -2554,19 +2566,22 @@@ static void intel_fixup_cur_wm_latency(
                wm[3] *= 2;
  }
  
 -static void intel_print_wm_latency(struct drm_device *dev,
 -                                 const char *name,
 -                                 const uint16_t wm[5])
 +static int ilk_wm_max_level(const struct drm_device *dev)
  {
 -      int level, max_level;
 -
        /* how many WM levels are we expecting */
        if (IS_HASWELL(dev))
 -              max_level = 4;
 +              return 4;
        else if (INTEL_INFO(dev)->gen >= 6)
 -              max_level = 3;
 +              return 3;
        else
 -              max_level = 2;
 +              return 2;
 +}
 +
 +static void intel_print_wm_latency(struct drm_device *dev,
 +                                 const char *name,
 +                                 const uint16_t wm[5])
 +{
 +      int level, max_level = ilk_wm_max_level(dev);
  
        for (level = 0; level <= max_level; level++) {
                unsigned int latency = wm[level];
@@@ -2648,7 -2633,8 +2648,7 @@@ static void hsw_compute_wm_parameters(s
                p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
                p->pri.bytes_per_pixel = crtc->fb->bits_per_pixel / 8;
                p->cur.bytes_per_pixel = 4;
 -              p->pri.horiz_pixels =
 -                      intel_crtc->config.requested_mode.hdisplay;
 +              p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
                p->cur.horiz_pixels = 64;
                /* TODO: for now, assume primary and cursor planes are always enabled. */
                p->pri.enabled = true;
  }
  
  static void hsw_compute_wm_results(struct drm_device *dev,
 -                                 struct hsw_pipe_wm_parameters *params,
 -                                 struct hsw_wm_maximums *lp_maximums,
 +                                 const struct hsw_pipe_wm_parameters *params,
 +                                 const struct hsw_wm_maximums *lp_maximums,
                                   struct hsw_wm_values *results)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        }
  
        for_each_pipe(pipe)
 -              results->wm_pipe[pipe] = hsw_compute_wm_pipe(dev_priv, pipe,
 +              results->wm_pipe[pipe] = hsw_compute_wm_pipe(dev,
                                                             &params[pipe]);
  
        for_each_pipe(pipe) {
@@@ -2855,9 -2841,8 +2855,9 @@@ static void hsw_write_wm_values(struct 
                I915_WRITE(WM3_LP_ILK, results->wm_lp[2]);
  }
  
 -static void haswell_update_wm(struct drm_device *dev)
 +static void haswell_update_wm(struct drm_crtc *crtc)
  {
 +      struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct hsw_wm_maximums lp_max_1_2, lp_max_5_6;
        struct hsw_pipe_wm_parameters params[3];
@@@ -2894,7 -2879,7 +2894,7 @@@ static void haswell_update_sprite_wm(st
        intel_plane->wm.horiz_pixels = sprite_width;
        intel_plane->wm.bytes_per_pixel = pixel_size;
  
 -      haswell_update_wm(plane->dev);
 +      haswell_update_wm(crtc);
  }
  
  static bool
@@@ -2913,7 -2898,7 +2913,7 @@@ sandybridge_compute_sprite_wm(struct dr
                return false;
        }
  
 -      clock = crtc->mode.clock;
 +      clock = to_intel_crtc(crtc)->config.adjusted_mode.clock;
  
        /* Use the small buffer method to calculate the sprite watermark */
        entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
@@@ -2948,7 -2933,7 +2948,7 @@@ sandybridge_compute_sprite_srwm(struct 
        }
  
        crtc = intel_get_crtc_for_plane(dev, plane);
 -      clock = crtc->mode.clock;
 +      clock = to_intel_crtc(crtc)->config.adjusted_mode.clock;
        if (!clock) {
                *sprite_wm = 0;
                return false;
@@@ -3091,12 -3076,12 +3091,12 @@@ static void sandybridge_update_sprite_w
   * We don't use the sprite, so we can ignore that.  And on Crestline we have
   * to set the non-SR watermarks to 8.
   */
 -void intel_update_watermarks(struct drm_device *dev)
 +void intel_update_watermarks(struct drm_crtc *crtc)
  {
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct drm_i915_private *dev_priv = crtc->dev->dev_private;
  
        if (dev_priv->display.update_wm)
 -              dev_priv->display.update_wm(dev);
 +              dev_priv->display.update_wm(crtc);
  }
  
  void intel_update_sprite_watermarks(struct drm_plane *plane,
@@@ -3788,7 -3773,7 +3788,7 @@@ static void valleyview_enable_rps(struc
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
 -      u32 gtfifodbg, val;
 +      u32 gtfifodbg, val, rc6_mode = 0;
        int i;
  
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
  
        /* allows RC6 residency counter to work */
        I915_WRITE(0x138104, _MASKED_BIT_ENABLE(0x3));
 -      I915_WRITE(GEN6_RC_CONTROL,
 -                 GEN7_RC_CTL_TO_MODE);
 +      if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE)
 +              rc6_mode = GEN7_RC_CTL_TO_MODE;
 +      I915_WRITE(GEN6_RC_CONTROL, rc6_mode);
  
        val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
        switch ((val >> 6) & 3) {
@@@ -5283,7 -5267,6 +5283,7 @@@ bool intel_display_power_enabled(struc
        case POWER_DOMAIN_PIPE_A:
        case POWER_DOMAIN_TRANSCODER_EDP:
                return true;
 +      case POWER_DOMAIN_VGA:
        case POWER_DOMAIN_PIPE_B:
        case POWER_DOMAIN_PIPE_C:
        case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
@@@ -5346,81 -5329,6 +5346,81 @@@ static void __intel_set_power_well(stru
        }
  }
  
 +static void __intel_power_well_get(struct i915_power_well *power_well)
 +{
 +      if (!power_well->count++)
 +              __intel_set_power_well(power_well->device, true);
 +}
 +
 +static void __intel_power_well_put(struct i915_power_well *power_well)
 +{
 +      WARN_ON(!power_well->count);
 +      if (!--power_well->count)
 +              __intel_set_power_well(power_well->device, false);
 +}
 +
 +void intel_display_power_get(struct drm_device *dev,
 +                           enum intel_display_power_domain domain)
 +{
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct i915_power_well *power_well = &dev_priv->power_well;
 +
 +      if (!HAS_POWER_WELL(dev))
 +              return;
 +
 +      switch (domain) {
 +      case POWER_DOMAIN_PIPE_A:
 +      case POWER_DOMAIN_TRANSCODER_EDP:
 +              return;
 +      case POWER_DOMAIN_VGA:
 +      case POWER_DOMAIN_PIPE_B:
 +      case POWER_DOMAIN_PIPE_C:
 +      case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
 +      case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
 +      case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
 +      case POWER_DOMAIN_TRANSCODER_A:
 +      case POWER_DOMAIN_TRANSCODER_B:
 +      case POWER_DOMAIN_TRANSCODER_C:
 +              spin_lock_irq(&power_well->lock);
 +              __intel_power_well_get(power_well);
 +              spin_unlock_irq(&power_well->lock);
 +              return;
 +      default:
 +              BUG();
 +      }
 +}
 +
 +void intel_display_power_put(struct drm_device *dev,
 +                           enum intel_display_power_domain domain)
 +{
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct i915_power_well *power_well = &dev_priv->power_well;
 +
 +      if (!HAS_POWER_WELL(dev))
 +              return;
 +
 +      switch (domain) {
 +      case POWER_DOMAIN_PIPE_A:
 +      case POWER_DOMAIN_TRANSCODER_EDP:
 +              return;
 +      case POWER_DOMAIN_VGA:
 +      case POWER_DOMAIN_PIPE_B:
 +      case POWER_DOMAIN_PIPE_C:
 +      case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
 +      case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
 +      case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
 +      case POWER_DOMAIN_TRANSCODER_A:
 +      case POWER_DOMAIN_TRANSCODER_B:
 +      case POWER_DOMAIN_TRANSCODER_C:
 +              spin_lock_irq(&power_well->lock);
 +              __intel_power_well_put(power_well);
 +              spin_unlock_irq(&power_well->lock);
 +              return;
 +      default:
 +              BUG();
 +      }
 +}
 +
  static struct i915_power_well *hsw_pwr;
  
  /* Display audio driver power well request */
@@@ -5430,7 -5338,9 +5430,7 @@@ void i915_request_power_well(void
                return;
  
        spin_lock_irq(&hsw_pwr->lock);
 -      if (!hsw_pwr->count++ &&
 -                      !hsw_pwr->i915_request)
 -              __intel_set_power_well(hsw_pwr->device, true);
 +      __intel_power_well_get(hsw_pwr);
        spin_unlock_irq(&hsw_pwr->lock);
  }
  EXPORT_SYMBOL_GPL(i915_request_power_well);
@@@ -5442,7 -5352,10 +5442,7 @@@ void i915_release_power_well(void
                return;
  
        spin_lock_irq(&hsw_pwr->lock);
 -      WARN_ON(!hsw_pwr->count);
 -      if (!--hsw_pwr->count &&
 -                     !hsw_pwr->i915_request)
 -              __intel_set_power_well(hsw_pwr->device, false);
 +      __intel_power_well_put(hsw_pwr);
        spin_unlock_irq(&hsw_pwr->lock);
  }
  EXPORT_SYMBOL_GPL(i915_release_power_well);
@@@ -5477,37 -5390,15 +5477,37 @@@ void intel_set_power_well(struct drm_de
                return;
  
        spin_lock_irq(&power_well->lock);
 +
 +      /*
 +       * This function will only ever contribute one
 +       * to the power well reference count. i915_request
 +       * is what tracks whether we have or have not
 +       * added the one to the reference count.
 +       */
 +      if (power_well->i915_request == enable)
 +              goto out;
 +
        power_well->i915_request = enable;
  
 -      /* only reject "disable" power well request */
 -      if (power_well->count && !enable) {
 -              spin_unlock_irq(&power_well->lock);
 +      if (enable)
 +              __intel_power_well_get(power_well);
 +      else
 +              __intel_power_well_put(power_well);
 +
 + out:
 +      spin_unlock_irq(&power_well->lock);
 +}
 +
 +void intel_resume_power_well(struct drm_device *dev)
 +{
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct i915_power_well *power_well = &dev_priv->power_well;
 +
 +      if (!HAS_POWER_WELL(dev))
                return;
 -      }
  
 -      __intel_set_power_well(dev, enable);
 +      spin_lock_irq(&power_well->lock);
 +      __intel_set_power_well(dev, power_well->count > 0);
        spin_unlock_irq(&power_well->lock);
  }
  
@@@ -5526,7 -5417,6 +5526,7 @@@ void intel_init_power_well(struct drm_d
  
        /* For now, we need the power well to be always enabled. */
        intel_set_power_well(dev, true);
 +      intel_resume_power_well(dev);
  
        /* We're taking over the BIOS, so clear any requests made by it since
         * the driver is in charge now. */
@@@ -788,6 -788,8 +788,8 @@@ static void intel_sdvo_get_dtd_from_mod
        uint16_t h_sync_offset, v_sync_offset;
        int mode_clock;
  
+       memset(dtd, 0, sizeof(*dtd));
        width = mode->hdisplay;
        height = mode->vdisplay;
  
        if (mode->flags & DRM_MODE_FLAG_PVSYNC)
                dtd->part2.dtd_flags |= DTD_FLAG_VSYNC_POSITIVE;
  
-       dtd->part2.sdvo_flags = 0;
        dtd->part2.v_sync_off_high = v_sync_offset & 0xc0;
-       dtd->part2.reserved = 0;
  }
  
- static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
+ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode *pmode,
                                         const struct intel_sdvo_dtd *dtd)
  {
-       mode->hdisplay = dtd->part1.h_active;
-       mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
-       mode->hsync_start = mode->hdisplay + dtd->part2.h_sync_off;
-       mode->hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
-       mode->hsync_end = mode->hsync_start + dtd->part2.h_sync_width;
-       mode->hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
-       mode->htotal = mode->hdisplay + dtd->part1.h_blank;
-       mode->htotal += (dtd->part1.h_high & 0xf) << 8;
-       mode->vdisplay = dtd->part1.v_active;
-       mode->vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
-       mode->vsync_start = mode->vdisplay;
-       mode->vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
-       mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
-       mode->vsync_start += dtd->part2.v_sync_off_high & 0xc0;
-       mode->vsync_end = mode->vsync_start +
+       struct drm_display_mode mode = {};
+       mode.hdisplay = dtd->part1.h_active;
+       mode.hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
+       mode.hsync_start = mode.hdisplay + dtd->part2.h_sync_off;
+       mode.hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
+       mode.hsync_end = mode.hsync_start + dtd->part2.h_sync_width;
+       mode.hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
+       mode.htotal = mode.hdisplay + dtd->part1.h_blank;
+       mode.htotal += (dtd->part1.h_high & 0xf) << 8;
+       mode.vdisplay = dtd->part1.v_active;
+       mode.vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
+       mode.vsync_start = mode.vdisplay;
+       mode.vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
+       mode.vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
+       mode.vsync_start += dtd->part2.v_sync_off_high & 0xc0;
+       mode.vsync_end = mode.vsync_start +
                (dtd->part2.v_sync_off_width & 0xf);
-       mode->vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4;
-       mode->vtotal = mode->vdisplay + dtd->part1.v_blank;
-       mode->vtotal += (dtd->part1.v_high & 0xf) << 8;
+       mode.vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4;
+       mode.vtotal = mode.vdisplay + dtd->part1.v_blank;
+       mode.vtotal += (dtd->part1.v_high & 0xf) << 8;
  
-       mode->clock = dtd->part1.clock * 10;
+       mode.clock = dtd->part1.clock * 10;
  
-       mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
        if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE)
-               mode->flags |= DRM_MODE_FLAG_INTERLACE;
+               mode.flags |= DRM_MODE_FLAG_INTERLACE;
        if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
-               mode->flags |= DRM_MODE_FLAG_PHSYNC;
+               mode.flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               mode.flags |= DRM_MODE_FLAG_NHSYNC;
        if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
-               mode->flags |= DRM_MODE_FLAG_PVSYNC;
+               mode.flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               mode.flags |= DRM_MODE_FLAG_NVSYNC;
+       drm_mode_set_crtcinfo(&mode, 0);
+       drm_mode_copy(pmode, &mode);
  }
  
  static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)
@@@ -1059,7 -1068,7 +1068,7 @@@ intel_sdvo_get_preferred_input_mode(str
  
  static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_config *pipe_config)
  {
 -      unsigned dotclock = pipe_config->adjusted_mode.clock;
 +      unsigned dotclock = pipe_config->port_clock;
        struct dpll *clock = &pipe_config->dpll;
  
        /* SDVO TV has fixed PLL values depend on its clock range,
@@@ -1124,6 -1133,7 +1133,6 @@@ static bool intel_sdvo_compute_config(s
         */
        pipe_config->pixel_multiplier =
                intel_sdvo_get_pixel_multiplier(adjusted_mode);
 -      adjusted_mode->clock *= pipe_config->pixel_multiplier;
  
        if (intel_sdvo->color_range_auto) {
                /* See CEA-861-E - 5.1 Default Encoding Parameters */
@@@ -1207,7 -1217,11 +1216,7 @@@ static void intel_sdvo_mode_set(struct 
            !intel_sdvo_set_tv_format(intel_sdvo))
                return;
  
 -      /* We have tried to get input timing in mode_fixup, and filled into
 -       * adjusted_mode.
 -       */
        intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
 -      input_dtd.part1.clock /= crtc->config.pixel_multiplier;
  
        if (intel_sdvo->is_tv || intel_sdvo->is_lvds)
                input_dtd.part2.sdvo_flags = intel_sdvo->dtd_sdvo_flags;
@@@ -1316,7 -1330,6 +1325,7 @@@ static void intel_sdvo_get_config(struc
        struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
        struct intel_sdvo_dtd dtd;
        int encoder_pixel_multiplier = 0;
 +      int dotclock;
        u32 flags = 0, sdvox;
        u8 val;
        bool ret;
                         >> SDVO_PORT_MULTIPLY_SHIFT) + 1;
        }
  
 +      dotclock = pipe_config->port_clock / pipe_config->pixel_multiplier;
 +
 +      if (HAS_PCH_SPLIT(dev))
 +              ironlake_check_encoder_dotclock(pipe_config, dotclock);
 +
 +      pipe_config->adjusted_mode.clock = dotclock;
 +
        /* Cross check the port pixel multiplier with the sdvo encoder state. */
        if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT,
                                 &val, 1)) {