drm/i915: Update to Linux 3.10 master
authorFrançois Tigeot <ftigeot@wolfpond.org>
Sun, 25 Jan 2015 18:33:18 +0000 (19:33 +0100)
committerFrançois Tigeot <ftigeot@wolfpond.org>
Sun, 1 Feb 2015 10:30:01 +0000 (11:30 +0100)
* Page flip improvements, increased robustness after GPU hangs.
  Races have been fixed in the vblank and pageflip completion
  interrupt handlers of GEN2-GEN4 GPUs.

* Hotplug IRQ storm detection and mitigation.

* Various bug fixes and performance improvements from GEN4 to
  Haswell GPUs.
  Less "Unclaimed register" messages should be visible on Haswell.

* Improved support for Valleyview / Baytrail GPUs.

* Better overclocking support from Sandy Bridge to Haswell.
  Improved frequency scaling (turbo) on Haswell.

* Improved display detection and modesetting. It is now possible to
  precompute possible desired display pipe configurations without
  changing the hardware state.

* Daniel Vetter's blog contains more detailed information:
  http://blog.ffwll.ch/2013/04/neat-drmi915-stuff-for-310.html

27 files changed:
sys/dev/drm/i915/i915_debugfs.c
sys/dev/drm/i915/i915_dma.c
sys/dev/drm/i915/i915_drv.c
sys/dev/drm/i915/i915_drv.h
sys/dev/drm/i915/i915_gem.c
sys/dev/drm/i915/i915_gem_execbuffer.c
sys/dev/drm/i915/i915_gem_gtt.c
sys/dev/drm/i915/i915_gem_tiling.c
sys/dev/drm/i915/i915_irq.c
sys/dev/drm/i915/i915_reg.h
sys/dev/drm/i915/i915_suspend.c
sys/dev/drm/i915/intel_bios.c
sys/dev/drm/i915/intel_crt.c
sys/dev/drm/i915/intel_ddi.c
sys/dev/drm/i915/intel_display.c
sys/dev/drm/i915/intel_dp.c
sys/dev/drm/i915/intel_drv.h
sys/dev/drm/i915/intel_fb.c
sys/dev/drm/i915/intel_hdmi.c
sys/dev/drm/i915/intel_i2c.c
sys/dev/drm/i915/intel_lvds.c
sys/dev/drm/i915/intel_panel.c
sys/dev/drm/i915/intel_pm.c
sys/dev/drm/i915/intel_sdvo.c
sys/dev/drm/i915/intel_sprite.c
sys/dev/drm/i915/intel_tv.c
sys/dev/drm/include/linux/compiler.h

index 4e5d70a..059000a 100644 (file)
@@ -768,6 +768,23 @@ static int i915_error_state(struct seq_file *m, void *unused)
                                }
                        }
                }
+
+               obj = error->ring[i].ctx;
+               if (obj) {
+                       seq_printf(m, "%s --- HW Context = 0x%08x\n",
+                                  dev_priv->ring[i].name,
+                                  obj->gtt_offset);
+                       offset = 0;
+                       for (elt = 0; elt < PAGE_SIZE/16; elt += 4) {
+                               seq_printf(m, "[%04x] %08x %08x %08x %08x\n",
+                                          offset,
+                                          obj->pages[0][elt],
+                                          obj->pages[0][elt+1],
+                                          obj->pages[0][elt+2],
+                                          obj->pages[0][elt+3]);
+                                       offset += 16;
+                       }
+               }
        }
 
        if (error->overlay)
@@ -845,76 +862,42 @@ static const struct file_operations i915_error_state_fops = {
        .release = i915_error_state_release,
 };
 
-static ssize_t
-i915_next_seqno_read(struct file *filp,
-                char __user *ubuf,
-                size_t max,
-                loff_t *ppos)
+static int
+i915_next_seqno_get(void *data, u64 *val)
 {
-       struct drm_device *dev = filp->private_data;
+       struct drm_device *dev = data;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       char buf[80];
-       int len;
        int ret;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
 
-       len = snprintf(buf, sizeof(buf),
-                      "next_seqno :  0x%x\n",
-                      dev_priv->next_seqno);
-
+       *val = dev_priv->next_seqno;
        mutex_unlock(&dev->struct_mutex);
 
-       if (len > sizeof(buf))
-               len = sizeof(buf);
-
-       return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+       return 0;
 }
 
-static ssize_t
-i915_next_seqno_write(struct file *filp,
-                     const char __user *ubuf,
-                     size_t cnt,
-                     loff_t *ppos)
-{
-       struct drm_device *dev = filp->private_data;
-       char buf[20];
-       u32 val = 1;
+static int
+i915_next_seqno_set(void *data, u64 val)
+{
+       struct drm_device *dev = data;
        int ret;
 
-       if (cnt > 0) {
-               if (cnt > sizeof(buf) - 1)
-                       return -EINVAL;
-
-               if (copy_from_user(buf, ubuf, cnt))
-                       return -EFAULT;
-               buf[cnt] = 0;
-
-               ret = kstrtouint(buf, 0, &val);
-               if (ret < 0)
-                       return ret;
-       }
-
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
 
        ret = i915_gem_set_seqno(dev, val);
-
        mutex_unlock(&dev->struct_mutex);
 
-       return ret ?: cnt;
+       return ret;
 }
 
-static const struct file_operations i915_next_seqno_fops = {
-       .owner = THIS_MODULE,
-       .open = simple_open,
-       .read = i915_next_seqno_read,
-       .write = i915_next_seqno_write,
-       .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_next_seqno_fops,
+                       i915_next_seqno_get, i915_next_seqno_set,
+                       "0x%llx\n");
 
 static int i915_rstdby_delays(struct seq_file *m, void *unused)
 {
@@ -1019,6 +1002,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                max_freq = rp_state_cap & 0xff;
                seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
                           max_freq * GT_FREQUENCY_MULTIPLIER);
+
+               seq_printf(m, "Max overclocked frequency: %dMHz\n",
+                          dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER);
        } else {
                seq_printf(m, "no P-state info available\n");
        }
@@ -1367,7 +1353,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
        if (ret)
                return ret;
 
-       seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\n");
+       seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n");
 
        for (gpu_freq = dev_priv->rps.min_delay;
             gpu_freq <= dev_priv->rps.max_delay;
@@ -1376,7 +1362,10 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
                sandybridge_pcode_read(dev_priv,
                                       GEN6_PCODE_READ_MIN_FREQ_TABLE,
                                       &ia_freq);
-               seq_printf(m, "%d\t\t%d\n", gpu_freq * GT_FREQUENCY_MULTIPLIER, ia_freq * 100);
+               seq_printf(m, "%d\t\t%d\t\t\t\t%d\n",
+                          gpu_freq * GT_FREQUENCY_MULTIPLIER,
+                          ((ia_freq >> 0) & 0xff) * 100,
+                          ((ia_freq >> 8) & 0xff) * 100);
        }
 
        mutex_unlock(&dev_priv->rps.hw_lock);
@@ -1676,105 +1665,51 @@ static int i915_dpio_info(struct seq_file *m, void *data)
        return 0;
 }
 
-static ssize_t
-i915_wedged_read(struct file *filp,
-                char __user *ubuf,
-                size_t max,
-                loff_t *ppos)
+static int
+i915_wedged_get(void *data, u64 *val)
 {
-       struct drm_device *dev = filp->private_data;
+       struct drm_device *dev = data;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       char buf[80];
-       int len;
 
-       len = snprintf(buf, sizeof(buf),
-                      "wedged :  %d\n",
-                      atomic_read(&dev_priv->gpu_error.reset_counter));
+       *val = atomic_read(&dev_priv->gpu_error.reset_counter);
 
-       if (len > sizeof(buf))
-               len = sizeof(buf);
-
-       return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+       return 0;
 }
 
-static ssize_t
-i915_wedged_write(struct file *filp,
-                 const char __user *ubuf,
-                 size_t cnt,
-                 loff_t *ppos)
+static int
+i915_wedged_set(void *data, u64 val)
 {
-       struct drm_device *dev = filp->private_data;
-       char buf[20];
-       int val = 1;
-
-       if (cnt > 0) {
-               if (cnt > sizeof(buf) - 1)
-                       return -EINVAL;
+       struct drm_device *dev = data;
 
-               if (copy_from_user(buf, ubuf, cnt))
-                       return -EFAULT;
-               buf[cnt] = 0;
-
-               val = simple_strtoul(buf, NULL, 0);
-       }
-
-       DRM_INFO("Manually setting wedged to %d\n", val);
+       DRM_INFO("Manually setting wedged to %llu\n", val);
        i915_handle_error(dev, val);
 
-       return cnt;
+       return 0;
 }
 
-static const struct file_operations i915_wedged_fops = {
-       .owner = THIS_MODULE,
-       .open = simple_open,
-       .read = i915_wedged_read,
-       .write = i915_wedged_write,
-       .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_wedged_fops,
+                       i915_wedged_get, i915_wedged_set,
+                       "%llu\n");
 
-static ssize_t
-i915_ring_stop_read(struct file *filp,
-                   char __user *ubuf,
-                   size_t max,
-                   loff_t *ppos)
+static int
+i915_ring_stop_get(void *data, u64 *val)
 {
-       struct drm_device *dev = filp->private_data;
+       struct drm_device *dev = data;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       char buf[20];
-       int len;
 
-       len = snprintf(buf, sizeof(buf),
-                      "0x%08x\n", dev_priv->gpu_error.stop_rings);
+       *val = dev_priv->gpu_error.stop_rings;
 
-       if (len > sizeof(buf))
-               len = sizeof(buf);
-
-       return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+       return 0;
 }
 
-static ssize_t
-i915_ring_stop_write(struct file *filp,
-                    const char __user *ubuf,
-                    size_t cnt,
-                    loff_t *ppos)
+static int
+i915_ring_stop_set(void *data, u64 val)
 {
-       struct drm_device *dev = filp->private_data;
+       struct drm_device *dev = data;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       char buf[20];
-       int val = 0, ret;
-
-       if (cnt > 0) {
-               if (cnt > sizeof(buf) - 1)
-                       return -EINVAL;
-
-               if (copy_from_user(buf, ubuf, cnt))
-                       return -EFAULT;
-               buf[cnt] = 0;
-
-               val = simple_strtoul(buf, NULL, 0);
-       }
+       int ret;
 
-       DRM_DEBUG_DRIVER("Stopping rings 0x%08x\n", val);
+       DRM_DEBUG_DRIVER("Stopping rings 0x%08llx\n", val);
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
@@ -1783,16 +1718,12 @@ i915_ring_stop_write(struct file *filp,
        dev_priv->gpu_error.stop_rings = val;
        mutex_unlock(&dev->struct_mutex);
 
-       return cnt;
+       return 0;
 }
 
-static const struct file_operations i915_ring_stop_fops = {
-       .owner = THIS_MODULE,
-       .open = simple_open,
-       .read = i915_ring_stop_read,
-       .write = i915_ring_stop_write,
-       .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_ring_stop_fops,
+                       i915_ring_stop_get, i915_ring_stop_set,
+                       "0x%08llx\n");
 
 #define DROP_UNBOUND 0x1
 #define DROP_BOUND 0x2
@@ -1802,46 +1733,23 @@ static const struct file_operations i915_ring_stop_fops = {
                  DROP_BOUND | \
                  DROP_RETIRE | \
                  DROP_ACTIVE)
-static ssize_t
-i915_drop_caches_read(struct file *filp,
-                     char __user *ubuf,
-                     size_t max,
-                     loff_t *ppos)
+static int
+i915_drop_caches_get(void *data, u64 *val)
 {
-       char buf[20];
-       int len;
+       *val = DROP_ALL;
 
-       len = snprintf(buf, sizeof(buf), "0x%08x\n", DROP_ALL);
-       if (len > sizeof(buf))
-               len = sizeof(buf);
-
-       return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+       return 0;
 }
 
-static ssize_t
-i915_drop_caches_write(struct file *filp,
-                      const char __user *ubuf,
-                      size_t cnt,
-                      loff_t *ppos)
+static int
+i915_drop_caches_set(void *data, u64 val)
 {
-       struct drm_device *dev = filp->private_data;
+       struct drm_device *dev = data;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj, *next;
-       char buf[20];
-       int val = 0, ret;
-
-       if (cnt > 0) {
-               if (cnt > sizeof(buf) - 1)
-                       return -EINVAL;
-
-               if (copy_from_user(buf, ubuf, cnt))
-                       return -EFAULT;
-               buf[cnt] = 0;
-
-               val = simple_strtoul(buf, NULL, 0);
-       }
+       int ret;
 
-       DRM_DEBUG_DRIVER("Dropping caches: 0x%08x\n", val);
+       DRM_DEBUG_DRIVER("Dropping caches: 0x%08llx\n", val);
 
        /* No need to check and wait for gpu resets, only libdrm auto-restarts
         * on ioctls on -EAGAIN. */
@@ -1879,27 +1787,19 @@ i915_drop_caches_write(struct file *filp,
 unlock:
        mutex_unlock(&dev->struct_mutex);
 
-       return ret ?: cnt;
+       return ret;
 }
 
-static const struct file_operations i915_drop_caches_fops = {
-       .owner = THIS_MODULE,
-       .open = simple_open,
-       .read = i915_drop_caches_read,
-       .write = i915_drop_caches_write,
-       .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_drop_caches_fops,
+                       i915_drop_caches_get, i915_drop_caches_set,
+                       "0x%08llx\n");
 
-static ssize_t
-i915_max_freq_read(struct file *filp,
-                  char __user *ubuf,
-                  size_t max,
-                  loff_t *ppos)
+static int
+i915_max_freq_get(void *data, u64 *val)
 {
-       struct drm_device *dev = filp->private_data;
+       struct drm_device *dev = data;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       char buf[80];
-       int len, ret;
+       int ret;
 
        if (!(IS_GEN6(dev) || IS_GEN7(dev)))
                return -ENODEV;
@@ -1908,42 +1808,23 @@ i915_max_freq_read(struct file *filp,
        if (ret)
                return ret;
 
-       len = snprintf(buf, sizeof(buf),
-                      "max freq: %d\n", dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER);
+       *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
        mutex_unlock(&dev_priv->rps.hw_lock);
 
-       if (len > sizeof(buf))
-               len = sizeof(buf);
-
-       return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+       return 0;
 }
 
-static ssize_t
-i915_max_freq_write(struct file *filp,
-                 const char __user *ubuf,
-                 size_t cnt,
-                 loff_t *ppos)
+static int
+i915_max_freq_set(void *data, u64 val)
 {
-       struct drm_device *dev = filp->private_data;
+       struct drm_device *dev = data;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       char buf[20];
-       int val = 1, ret;
+       int ret;
 
        if (!(IS_GEN6(dev) || IS_GEN7(dev)))
                return -ENODEV;
 
-       if (cnt > 0) {
-               if (cnt > sizeof(buf) - 1)
-                       return -EINVAL;
-
-               if (copy_from_user(buf, ubuf, cnt))
-                       return -EFAULT;
-               buf[cnt] = 0;
-
-               val = simple_strtoul(buf, NULL, 0);
-       }
-
-       DRM_DEBUG_DRIVER("Manually setting max freq to %d\n", val);
+       DRM_DEBUG_DRIVER("Manually setting max freq to %llu\n", val);
 
        ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
        if (ret)
@@ -1952,30 +1833,24 @@ i915_max_freq_write(struct file *filp,
        /*
         * Turbo will still be enabled, but won't go above the set value.
         */
-       dev_priv->rps.max_delay = val / GT_FREQUENCY_MULTIPLIER;
-
-       gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER);
+       do_div(val, GT_FREQUENCY_MULTIPLIER);
+       dev_priv->rps.max_delay = val;
+       gen6_set_rps(dev, val);
        mutex_unlock(&dev_priv->rps.hw_lock);
 
-       return cnt;
+       return 0;
 }
 
-static const struct file_operations i915_max_freq_fops = {
-       .owner = THIS_MODULE,
-       .open = simple_open,
-       .read = i915_max_freq_read,
-       .write = i915_max_freq_write,
-       .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_max_freq_fops,
+                       i915_max_freq_get, i915_max_freq_set,
+                       "%llu\n");
 
-static ssize_t
-i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max,
-                  loff_t *ppos)
+static int
+i915_min_freq_get(void *data, u64 *val)
 {
-       struct drm_device *dev = filp->private_data;
+       struct drm_device *dev = data;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       char buf[80];
-       int len, ret;
+       int ret;
 
        if (!(IS_GEN6(dev) || IS_GEN7(dev)))
                return -ENODEV;
@@ -1984,40 +1859,23 @@ i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max,
        if (ret)
                return ret;
 
-       len = snprintf(buf, sizeof(buf),
-                      "min freq: %d\n", dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER);
+       *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
        mutex_unlock(&dev_priv->rps.hw_lock);
 
-       if (len > sizeof(buf))
-               len = sizeof(buf);
-
-       return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+       return 0;
 }
 
-static ssize_t
-i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt,
-                   loff_t *ppos)
+static int
+i915_min_freq_set(void *data, u64 val)
 {
-       struct drm_device *dev = filp->private_data;
+       struct drm_device *dev = data;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       char buf[20];
-       int val = 1, ret;
+       int ret;
 
        if (!(IS_GEN6(dev) || IS_GEN7(dev)))
                return -ENODEV;
 
-       if (cnt > 0) {
-               if (cnt > sizeof(buf) - 1)
-                       return -EINVAL;
-
-               if (copy_from_user(buf, ubuf, cnt))
-                       return -EFAULT;
-               buf[cnt] = 0;
-
-               val = simple_strtoul(buf, NULL, 0);
-       }
-
-       DRM_DEBUG_DRIVER("Manually setting min freq to %d\n", val);
+       DRM_DEBUG_DRIVER("Manually setting min freq to %llu\n", val);
 
        ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
        if (ret)
@@ -2026,33 +1884,25 @@ i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt,
        /*
         * Turbo will still be enabled, but won't go below the set value.
         */
-       dev_priv->rps.min_delay = val / GT_FREQUENCY_MULTIPLIER;
-
-       gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER);
+       do_div(val, GT_FREQUENCY_MULTIPLIER);
+       dev_priv->rps.min_delay = val;
+       gen6_set_rps(dev, val);
        mutex_unlock(&dev_priv->rps.hw_lock);
 
-       return cnt;
+       return 0;
 }
 
-static const struct file_operations i915_min_freq_fops = {
-       .owner = THIS_MODULE,
-       .open = simple_open,
-       .read = i915_min_freq_read,
-       .write = i915_min_freq_write,
-       .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_min_freq_fops,
+                       i915_min_freq_get, i915_min_freq_set,
+                       "%llu\n");
 
-static ssize_t
-i915_cache_sharing_read(struct file *filp,
-                  char __user *ubuf,
-                  size_t max,
-                  loff_t *ppos)
+static int
+i915_cache_sharing_get(void *data, u64 *val)
 {
-       struct drm_device *dev = filp->private_data;
+       struct drm_device *dev = data;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       char buf[80];
        u32 snpcr;
-       int len, ret;
+       int ret;
 
        if (!(IS_GEN6(dev) || IS_GEN7(dev)))
                return -ENODEV;
@@ -2064,46 +1914,25 @@ i915_cache_sharing_read(struct file *filp,
        snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
        mutex_unlock(&dev_priv->dev->struct_mutex);
 
-       len = snprintf(buf, sizeof(buf),
-                      "%d\n", (snpcr & GEN6_MBC_SNPCR_MASK) >>
-                      GEN6_MBC_SNPCR_SHIFT);
+       *val = (snpcr & GEN6_MBC_SNPCR_MASK) >> GEN6_MBC_SNPCR_SHIFT;
 
-       if (len > sizeof(buf))
-               len = sizeof(buf);
-
-       return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+       return 0;
 }
 
-static ssize_t
-i915_cache_sharing_write(struct file *filp,
-                 const char __user *ubuf,
-                 size_t cnt,
-                 loff_t *ppos)
+static int
+i915_cache_sharing_set(void *data, u64 val)
 {
-       struct drm_device *dev = filp->private_data;
+       struct drm_device *dev = data;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       char buf[20];
        u32 snpcr;
-       int val = 1;
 
        if (!(IS_GEN6(dev) || IS_GEN7(dev)))
                return -ENODEV;
 
-       if (cnt > 0) {
-               if (cnt > sizeof(buf) - 1)
-                       return -EINVAL;
-
-               if (copy_from_user(buf, ubuf, cnt))
-                       return -EFAULT;
-               buf[cnt] = 0;
-
-               val = simple_strtoul(buf, NULL, 0);
-       }
-
-       if (val < 0 || val > 3)
+       if (val > 3)
                return -EINVAL;
 
-       DRM_DEBUG_DRIVER("Manually setting uncore sharing to %d\n", val);
+       DRM_DEBUG_DRIVER("Manually setting uncore sharing to %llu\n", val);
 
        /* Update the cache sharing policy here as well */
        snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
@@ -2111,16 +1940,12 @@ i915_cache_sharing_write(struct file *filp,
        snpcr |= (val << GEN6_MBC_SNPCR_SHIFT);
        I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr);
 
-       return cnt;
+       return 0;
 }
 
-static const struct file_operations i915_cache_sharing_fops = {
-       .owner = THIS_MODULE,
-       .open = simple_open,
-       .read = i915_cache_sharing_read,
-       .write = i915_cache_sharing_write,
-       .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_cache_sharing_fops,
+                       i915_cache_sharing_get, i915_cache_sharing_set,
+                       "%llu\n");
 
 /* As the drm_debugfs_init() routines are called before dev->dev_private is
  * allocated we need to hook into the minor for release. */
index 54c771c..608707b 100644 (file)
@@ -72,15 +72,7 @@ intel_read_legacy_status_page(struct drm_i915_private *dev_priv, int reg)
 
 void i915_update_dri1_breadcrumb(struct drm_device *dev)
 {
-       /*
-        * The dri breadcrumb update races against the drm master disappearing.
-        * Instead of trying to fix this (this is by far not the only ums issue)
-        * just don't do the update in kms mode.
-        */
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return;
-
-       /* XXX: don't do it at all actually */
+       /* XXX: We don't care about dri1 */
        return;
 }
 
@@ -138,9 +130,7 @@ void i915_kernel_lost_context(struct drm_device * dev)
        if (ring->space < 0)
                ring->space += ring->size;
 
-#if 1
-       KIB_NOTYET();
-#else
+#if 0
        if (!dev->primary->master)
                return;
 #endif
@@ -154,7 +144,6 @@ static int i915_dma_cleanup(struct drm_device * dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        int i;
 
-
        /* Make sure interrupts are disabled here because the uninstall ioctl
         * may not have been called from userspace and after dev_private
         * is freed, it's too late.
@@ -658,6 +647,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
 
 fail_free:
        kfree(cliprects);
+
        return ret;
 }
 
@@ -686,7 +676,7 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
        if (batch_data == NULL)
                return -ENOMEM;
 
-       ret = -copyin(cmdbuf->buf, batch_data, cmdbuf->sz);
+       ret = copy_from_user(batch_data, cmdbuf->buf, cmdbuf->sz);
        if (ret != 0) {
                ret = -EFAULT;
                goto fail_batch_free;
@@ -722,9 +712,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
                sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
 
 fail_clip_free:
-       drm_free(cliprects, M_DRM);
+       kfree(cliprects);
 fail_batch_free:
-       drm_free(batch_data, M_DRM);
+       kfree(batch_data);
        return ret;
 }
 
@@ -1287,6 +1277,10 @@ static int i915_load_modeset_init(struct drm_device *dev)
        /* Always safe in the mode setting case. */
        /* FIXME: do pre/post-mode set stuff in core KMS code */
        dev->vblank_disable_allowed = 1;
+       if (INTEL_INFO(dev)->num_pipes == 0) {
+               dev_priv->mm.suspended = 0;
+               return 0;
+       }
 
        ret = intel_fbdev_init(dev);
        if (ret)
@@ -1357,6 +1351,22 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
 
        kfree(ap);
 }
+
+/**
+ * intel_early_sanitize_regs - clean up BIOS state
+ * @dev: DRM device
+ *
+ * This function must be called before we do any I915_READ or I915_WRITE. Its
+ * purpose is to clean up any state left by the BIOS that may affect us when
+ * reading and/or writing registers.
+ */
+static void intel_early_sanitize_regs(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (IS_HASWELL(dev))
+               I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+}
 #endif
 
 /**
@@ -1373,14 +1383,22 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
 int i915_driver_load(struct drm_device *dev, unsigned long flags)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       const struct intel_device_info *info;
        unsigned long base, size;
-       int ret = 0, mmio_bar;
+       int ret = 0, mmio_bar, mmio_size;
+       uint32_t aperture_size;
        static struct pci_dev i915_pdev;
 
        /* XXX: struct pci_dev */
        i915_pdev.dev = dev->dev;
        dev->pdev = &i915_pdev;
 
+       info = i915_get_device_id(dev->pci_device);
+
+       /* Refuse to load on gen6+ without kms enabled. */
+       if (info->gen >= 6 && !drm_core_check_feature(dev, DRIVER_MODESET))
+               return -ENODEV;
+
        /* i915 has 4 more counters */
        dev->counters += 4;
        dev->types[6] = _DRM_STAT_IRQ;
@@ -1395,13 +1413,37 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        dev->dev_private = (void *)dev_priv;
        dev_priv->dev = dev;
-       dev_priv->info = i915_get_device_id(dev->pci_device);
+       dev_priv->info = info;
 
        if (i915_get_bridge_dev(dev)) {
                ret = -EIO;
                goto free_priv;
        }
 
+       mmio_bar = IS_GEN2(dev) ? 1 : 0;
+       /* Before gen4, the registers and the GTT are behind different BARs.
+        * However, from gen4 onwards, the registers and the GTT are shared
+        * in the same BAR, so we want to restrict this ioremap from
+        * clobbering the GTT which we want ioremap_wc instead. Fortunately,
+        * the register BAR remains the same size for all the earlier
+        * generations up to Ironlake.
+        */
+       if (info->gen < 5)
+               mmio_size = 512*1024;
+       else
+               mmio_size = 2*1024*1024;
+
+#if 0
+       dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size);
+       if (!dev_priv->regs) {
+               DRM_ERROR("failed to map registers\n");
+               ret = -EIO;
+               goto put_bridge;
+       }
+
+       intel_early_sanitize_regs(dev);
+#endif
+
        ret = i915_gem_gtt_init(dev);
        if (ret)
                goto put_bridge;
@@ -1428,29 +1470,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32));
 #endif
 
-       mmio_bar = IS_GEN2(dev) ? 1 : 0;
-       /* Before gen4, the registers and the GTT are behind different BARs.
-        * However, from gen4 onwards, the registers and the GTT are shared
-        * in the same BAR, so we want to restrict this ioremap from
-        * clobbering the GTT which we want ioremap_wc instead. Fortunately,
-        * the register BAR remains the same size for all the earlier
-        * generations up to Ironlake.
-        */
-#if 0
-       if (info->gen < 5)
-               mmio_size = 512*1024;
-       else
-               mmio_size = 2*1024*1024;
-
-       dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size);
-       if (!dev_priv->regs) {
-               DRM_ERROR("failed to map registers\n");
-               ret = -EIO;
-               goto put_gmch;
-       }
-
        aperture_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
 
+#if 0
        dev_priv->gtt.mappable =
                io_mapping_create_wc(dev_priv->gtt.mappable_base,
                                     aperture_size);
@@ -1528,16 +1550,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        lockinit(&dev_priv->rps.hw_lock, "i915 rps.hw_lock", 0, LK_CANRECURSE);
        lockinit(&dev_priv->modeset_restore_lock, "i915mrl", 0, LK_CANRECURSE);
 
-       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
-               dev_priv->num_pipe = 3;
-       else if (IS_MOBILE(dev) || !IS_GEN2(dev))
-               dev_priv->num_pipe = 2;
-       else
-               dev_priv->num_pipe = 1;
+       dev_priv->num_plane = 1;
+       if (IS_VALLEYVIEW(dev))
+               dev_priv->num_plane = 2;
 
-       ret = drm_vblank_init(dev, dev_priv->num_pipe);
-       if (ret)
-               goto out_gem_unload;
+       if (INTEL_INFO(dev)->num_pipes) {
+               ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes);
+               if (ret)
+                       goto out_gem_unload;
+       }
 
        /* Start out suspended */
        dev_priv->mm.suspended = 1;
@@ -1554,11 +1575,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        i915_setup_sysfs(dev);
 #endif
 
-       /* Must be done after probing outputs */
-       intel_opregion_init(dev);
+       if (INTEL_INFO(dev)->num_pipes) {
+               /* Must be done after probing outputs */
+               intel_opregion_init(dev);
 #if 0
-       acpi_video_register();
+               acpi_video_register();
 #endif
+       }
 
        if (IS_GEN5(dev))
                intel_gpu_ips_init(dev_priv);
@@ -1713,16 +1736,22 @@ void i915_driver_lastclose(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
 
-       if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) {
-#if 1
-               KIB_NOTYET();
-#else
-               drm_fb_helper_restore();
+       /* On gen6+ we refuse to init without kms enabled, but then the drm core
+        * goes right around and calls lastclose. Check for this and don't clean
+        * up anything. */
+       if (!dev_priv)
+               return;
+
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+#if 0
+               intel_fb_restore_mode(dev);
                vga_switcheroo_process_delayed_switch();
 #endif
                return;
        }
+
        i915_gem_lastclose(dev);
+
        i915_dma_cleanup(dev);
 }
 
index b8a309a..305cc03 100644 (file)
@@ -52,80 +52,94 @@ MODULE_PARM_DESC(enable_hangcheck,
 
 static struct drm_driver driver;
 
-#define INTEL_VGA_DEVICE(id, info_) {          \
+#define INTEL_VGA_DEVICE(id, info) {           \
+       .class = PCI_BASE_CLASS_DISPLAY << 16,  \
+       .class_mask = 0xff0000,                 \
+       .vendor = 0x8086,                       \
        .device = id,                           \
-       .info = info_,                          \
-}
+       .subvendor = PCI_ANY_ID,                \
+       .subdevice = PCI_ANY_ID,                \
+       .driver_data = (unsigned long) info }
+
+#define INTEL_QUANTA_VGA_DEVICE(info) {                \
+       .class = PCI_BASE_CLASS_DISPLAY << 16,  \
+       .class_mask = 0xff0000,                 \
+       .vendor = 0x8086,                       \
+       .device = 0x16a,                        \
+       .subvendor = 0x152d,                    \
+       .subdevice = 0x8990,                    \
+       .driver_data = (unsigned long) info }
+
 
 static const struct intel_device_info intel_i830_info = {
-       .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1,
+       .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2,
        .has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_845g_info = {
-       .gen = 2,
+       .gen = 2, .num_pipes = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i85x_info = {
-       .gen = 2, .is_i85x = 1, .is_mobile = 1,
+       .gen = 2, .is_i85x = 1, .is_mobile = 1, .num_pipes = 2,
        .cursor_needs_physical = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i865g_info = {
-       .gen = 2,
+       .gen = 2, .num_pipes = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i915g_info = {
-       .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1,
+       .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .num_pipes = 2,
        .has_overlay = 1, .overlay_needs_physical = 1,
 };
 static const struct intel_device_info intel_i915gm_info = {
-       .gen = 3, .is_mobile = 1,
+       .gen = 3, .is_mobile = 1, .num_pipes = 2,
        .cursor_needs_physical = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
        .supports_tv = 1,
 };
 static const struct intel_device_info intel_i945g_info = {
-       .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1,
+       .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .num_pipes = 2,
        .has_overlay = 1, .overlay_needs_physical = 1,
 };
 static const struct intel_device_info intel_i945gm_info = {
-       .gen = 3, .is_i945gm = 1, .is_mobile = 1,
+       .gen = 3, .is_i945gm = 1, .is_mobile = 1, .num_pipes = 2,
        .has_hotplug = 1, .cursor_needs_physical = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
        .supports_tv = 1,
 };
 
 static const struct intel_device_info intel_i965g_info = {
-       .gen = 4, .is_broadwater = 1,
+       .gen = 4, .is_broadwater = 1, .num_pipes = 2,
        .has_hotplug = 1,
        .has_overlay = 1,
 };
 
 static const struct intel_device_info intel_i965gm_info = {
-       .gen = 4, .is_crestline = 1,
+       .gen = 4, .is_crestline = 1, .num_pipes = 2,
        .is_mobile = 1, .has_fbc = 1, .has_hotplug = 1,
        .has_overlay = 1,
        .supports_tv = 1,
 };
 
 static const struct intel_device_info intel_g33_info = {
-       .gen = 3, .is_g33 = 1,
+       .gen = 3, .is_g33 = 1, .num_pipes = 2,
        .need_gfx_hws = 1, .has_hotplug = 1,
        .has_overlay = 1,
 };
 
 static const struct intel_device_info intel_g45_info = {
-       .gen = 4, .is_g4x = 1, .need_gfx_hws = 1,
+       .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .num_pipes = 2,
        .has_pipe_cxsr = 1, .has_hotplug = 1,
        .has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_gm45_info = {
-       .gen = 4, .is_g4x = 1,
+       .gen = 4, .is_g4x = 1, .num_pipes = 2,
        .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1,
        .has_pipe_cxsr = 1, .has_hotplug = 1,
        .supports_tv = 1,
@@ -133,26 +147,26 @@ static const struct intel_device_info intel_gm45_info = {
 };
 
 static const struct intel_device_info intel_pineview_info = {
-       .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1,
+       .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .num_pipes = 2,
        .need_gfx_hws = 1, .has_hotplug = 1,
        .has_overlay = 1,
 };
 
 static const struct intel_device_info intel_ironlake_d_info = {
-       .gen = 5,
+       .gen = 5, .num_pipes = 2,
        .need_gfx_hws = 1, .has_hotplug = 1,
        .has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_ironlake_m_info = {
-       .gen = 5, .is_mobile = 1,
+       .gen = 5, .is_mobile = 1, .num_pipes = 2,
        .need_gfx_hws = 1, .has_hotplug = 1,
        .has_fbc = 1,
        .has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_sandybridge_d_info = {
-       .gen = 6,
+       .gen = 6, .num_pipes = 2,
        .need_gfx_hws = 1, .has_hotplug = 1,
        .has_bsd_ring = 1,
        .has_blt_ring = 1,
@@ -161,7 +175,7 @@ static const struct intel_device_info intel_sandybridge_d_info = {
 };
 
 static const struct intel_device_info intel_sandybridge_m_info = {
-       .gen = 6, .is_mobile = 1,
+       .gen = 6, .is_mobile = 1, .num_pipes = 2,
        .need_gfx_hws = 1, .has_hotplug = 1,
        .has_fbc = 1,
        .has_bsd_ring = 1,
@@ -170,67 +184,60 @@ static const struct intel_device_info intel_sandybridge_m_info = {
        .has_force_wake = 1,
 };
 
+#define GEN7_FEATURES  \
+       .gen = 7, .num_pipes = 3, \
+       .need_gfx_hws = 1, .has_hotplug = 1, \
+       .has_bsd_ring = 1, \
+       .has_blt_ring = 1, \
+       .has_llc = 1, \
+       .has_force_wake = 1
+
 static const struct intel_device_info intel_ivybridge_d_info = {
-       .is_ivybridge = 1, .gen = 7,
-       .need_gfx_hws = 1, .has_hotplug = 1,
-       .has_bsd_ring = 1,
-       .has_blt_ring = 1,
-       .has_llc = 1,
-       .has_force_wake = 1,
+       GEN7_FEATURES,
+       .is_ivybridge = 1,
 };
 
 static const struct intel_device_info intel_ivybridge_m_info = {
-       .is_ivybridge = 1, .gen = 7, .is_mobile = 1,
-       .need_gfx_hws = 1, .has_hotplug = 1,
-       .has_fbc = 0,   /* FBC is not enabled on Ivybridge mobile yet */
-       .has_bsd_ring = 1,
-       .has_blt_ring = 1,
-       .has_llc = 1,
-       .has_force_wake = 1,
+       GEN7_FEATURES,
+       .is_ivybridge = 1,
+       .is_mobile = 1,
+};
+
+static const struct intel_device_info intel_ivybridge_q_info = {
+       GEN7_FEATURES,
+       .is_ivybridge = 1,
+       .num_pipes = 0, /* legal, last one wins */
 };
 
 static const struct intel_device_info intel_valleyview_m_info = {
-       .gen = 7, .is_mobile = 1,
-       .need_gfx_hws = 1, .has_hotplug = 1,
-       .has_fbc = 0,
-       .has_bsd_ring = 1,
-       .has_blt_ring = 1,
+       GEN7_FEATURES,
+       .is_mobile = 1,
+       .num_pipes = 2,
        .is_valleyview = 1,
        .display_mmio_offset = VLV_DISPLAY_BASE,
+       .has_llc = 0, /* legal, last one wins */
 };
 
 static const struct intel_device_info intel_valleyview_d_info = {
-       .gen = 7,
-       .need_gfx_hws = 1, .has_hotplug = 1,
-       .has_fbc = 0,
-       .has_bsd_ring = 1,
-       .has_blt_ring = 1,
+       GEN7_FEATURES,
+       .num_pipes = 2,
        .is_valleyview = 1,
        .display_mmio_offset = VLV_DISPLAY_BASE,
+       .has_llc = 0, /* legal, last one wins */
 };
 
 static const struct intel_device_info intel_haswell_d_info = {
-       .is_haswell = 1, .gen = 7,
-       .need_gfx_hws = 1, .has_hotplug = 1,
-       .has_bsd_ring = 1,
-       .has_blt_ring = 1,
-       .has_llc = 1,
-       .has_force_wake = 1,
+       GEN7_FEATURES,
+       .is_haswell = 1,
 };
 
 static const struct intel_device_info intel_haswell_m_info = {
-       .is_haswell = 1, .gen = 7, .is_mobile = 1,
-       .need_gfx_hws = 1, .has_hotplug = 1,
-       .has_bsd_ring = 1,
-       .has_blt_ring = 1,
-       .has_llc = 1,
-       .has_force_wake = 1,
+       GEN7_FEATURES,
+       .is_haswell = 1,
+       .is_mobile = 1,
 };
 
-static const struct intel_gfx_device_id {
-       int device;
-       const struct intel_device_info *info;
-} pciidlist[] = {              /* aka */
+static const struct pci_device_id pciidlist[] = {              /* aka */
        INTEL_VGA_DEVICE(0x3577, &intel_i830_info),             /* I830_M */
        INTEL_VGA_DEVICE(0x2562, &intel_845g_info),             /* 845_G */
        INTEL_VGA_DEVICE(0x3582, &intel_i85x_info),             /* I855_GM */
@@ -336,6 +343,9 @@ static const struct intel_gfx_device_id {
        INTEL_VGA_DEVICE(0x0D1E, &intel_haswell_d_info), /* CRW GT2 reserved */
        INTEL_VGA_DEVICE(0x0D2E, &intel_haswell_d_info), /* CRW GT3 reserved */
        INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info),
+       INTEL_VGA_DEVICE(0x0f31, &intel_valleyview_m_info),
+       INTEL_VGA_DEVICE(0x0f32, &intel_valleyview_m_info),
+       INTEL_VGA_DEVICE(0x0f33, &intel_valleyview_m_info),
        INTEL_VGA_DEVICE(0x0157, &intel_valleyview_m_info),
        INTEL_VGA_DEVICE(0x0155, &intel_valleyview_d_info),
        {0, 0}
@@ -348,6 +358,15 @@ void intel_detect_pch(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        device_t pch;
 
+       /* In all current cases, num_pipes is equivalent to the PCH_NOP setting
+        * (which really amounts to a PCH but no South Display).
+        */
+       if (INTEL_INFO(dev)->num_pipes == 0) {
+               dev_priv->pch_type = PCH_NOP;
+               dev_priv->num_pch_pll = 0;
+               return;
+       }
+
        /*
         * The reason to probe ISA bridge instead of Dev31:Fun0 is to
         * make graphics device passthrough work easy for VMM, that only
@@ -382,11 +401,13 @@ void intel_detect_pch(struct drm_device *dev)
                                dev_priv->num_pch_pll = 0;
                                DRM_DEBUG_KMS("Found LynxPoint PCH\n");
                                WARN_ON(!IS_HASWELL(dev));
+                               WARN_ON(IS_ULT(dev));
                        } else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
                                dev_priv->pch_type = PCH_LPT;
                                dev_priv->num_pch_pll = 0;
                                DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
                                WARN_ON(!IS_HASWELL(dev));
+                               WARN_ON(!IS_ULT(dev));
                        }
                        BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS);
                }
@@ -416,6 +437,7 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
 static int i915_drm_freeze(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc;
 
        /* ignore lid events during suspend */
        mutex_lock(&dev_priv->modeset_restore_lock);
@@ -441,12 +463,14 @@ static int i915_drm_freeze(struct drm_device *dev)
 
                cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work);
 
-#if 0
-               intel_modeset_disable(dev);
-#endif
-
                drm_irq_uninstall(dev);
                dev_priv->enable_hotplug_processing = false;
+               /*
+                * Disable CRTCs directly since we want to preserve sw state
+                * for _thaw.
+                */
+               list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+                       dev_priv->display.crtc_disable(crtc);
        }
 
        i915_save_state(dev);
@@ -478,6 +502,24 @@ i915_suspend(device_t kdev)
        return (error);
 }
 
+static void intel_resume_hotplug(struct drm_device *dev)
+{
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
+
+       mutex_lock(&mode_config->mutex);
+       DRM_DEBUG_KMS("running encoder hotplug functions\n");
+
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+               if (encoder->hot_plug)
+                       encoder->hot_plug(encoder);
+
+       mutex_unlock(&mode_config->mutex);
+
+       /* Just fire off a uevent and let userspace tell us what to do */
+       drm_helper_hpd_irq_event(dev);
+}
+
 static int __i915_drm_thaw(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -500,7 +542,10 @@ static int __i915_drm_thaw(struct drm_device *dev)
                drm_irq_install(dev);
 
                intel_modeset_init_hw(dev);
-               intel_modeset_setup_hw_state(dev, false);
+
+               drm_modeset_lock_all(dev);
+               intel_modeset_setup_hw_state(dev, true);
+               drm_modeset_unlock_all(dev);
 
                /*
                 * ... but also need to make sure that hotplug processing
@@ -510,6 +555,8 @@ static int __i915_drm_thaw(struct drm_device *dev)
                 * */
                intel_hpd_init(dev);
                dev_priv->enable_hotplug_processing = true;
+               /* Config may have changed between suspend and resume */
+               intel_resume_hotplug(dev);
        }
 
        intel_opregion_init(dev);
@@ -605,12 +652,12 @@ i915_attach(device_t kdev)
 const struct intel_device_info *
 i915_get_device_id(int device)
 {
-       const struct intel_gfx_device_id *did;
+       const struct pci_device_id *did;
 
        for (did = &pciidlist[0]; did->device != 0; did++) {
                if (did->device != device)
                        continue;
-               return (did->info);
+               return (struct intel_device_info *)did->driver_data;
        }
        return (NULL);
 }
@@ -714,6 +761,7 @@ static int ironlake_do_reset(struct drm_device *dev)
        int ret;
 
        gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+       gdrst &= ~GRDOM_MASK;
        I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
                   gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE);
        ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
@@ -722,6 +770,7 @@ static int ironlake_do_reset(struct drm_device *dev)
 
        /* We can't reset render&media without also resetting display ... */
        gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+       gdrst &= ~GRDOM_MASK;
        I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
                   gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE);
        return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
@@ -786,7 +835,7 @@ int intel_gpu_reset(struct drm_device *dev)
 
        /* Also reset the gpu hangman. */
        if (dev_priv->gpu_error.stop_rings) {
-               DRM_DEBUG("Simulated gpu hang, resetting stop_rings\n");
+               DRM_INFO("Simulated gpu hang, resetting stop_rings\n");
                dev_priv->gpu_error.stop_rings = 0;
                if (ret == -ENODEV) {
                        DRM_ERROR("Reset not implemented, but ignoring "
@@ -865,7 +914,11 @@ int i915_reset(struct drm_device *dev)
                        ring->init(ring);
 
                i915_gem_context_init(dev);
-               i915_gem_init_ppgtt(dev);
+               if (dev_priv->mm.aliasing_ppgtt) {
+                       ret = dev_priv->mm.aliasing_ppgtt->enable(dev);
+                       if (ret)
+                               i915_gem_cleanup_aliasing_ppgtt(dev);
+               }
 
                /*
                 * It would make sense to re-init all the other hw state, at
@@ -976,6 +1029,27 @@ ilk_dummy_write(struct drm_i915_private *dev_priv)
        I915_WRITE_NOTRACE(MI_MODE, 0);
 }
 
+static void
+hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg)
+{
+       if (IS_HASWELL(dev_priv->dev) &&
+           (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
+               DRM_ERROR("Unknown unclaimed register before writing to %x\n",
+                         reg);
+               I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+       }
+}
+
+static void
+hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg)
+{
+       if (IS_HASWELL(dev_priv->dev) &&
+           (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
+               DRM_ERROR("Unclaimed write to %x\n", reg);
+               I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+       }
+}
+
 #define __i915_read(x, y) \
 u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
        u##x val = 0; \
@@ -1011,18 +1085,12 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
        } \
        if (IS_GEN5(dev_priv->dev)) \
                ilk_dummy_write(dev_priv); \
-       if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \
-               DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); \
-               I915_WRITE_NOTRACE(GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED); \
-       } \
+       hsw_unclaimed_reg_clear(dev_priv, reg); \
        DRM_WRITE##y(dev_priv->mmio_map, reg, val); \
        if (unlikely(__fifo_ret)) { \
                gen6_gt_check_fifodbg(dev_priv); \
        } \
-       if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \
-               DRM_ERROR("Unclaimed write to %x\n", reg); \
-               DRM_WRITE32(dev_priv->mmio_map, GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED);  \
-       } \
+       hsw_unclaimed_reg_check(dev_priv, reg); \
 }
 
 __i915_write(8, 8)
index 8a8f427..b4fae9e 100644 (file)
@@ -84,6 +84,19 @@ enum port {
 };
 #define port_name(p) ((p) + 'A')
 
+enum hpd_pin {
+       HPD_NONE = 0,
+       HPD_PORT_A = HPD_NONE, /* PORT_A is internal */
+       HPD_TV = HPD_NONE,     /* TV is known to be unreliable */
+       HPD_CRT,
+       HPD_SDVO_B,
+       HPD_SDVO_C,
+       HPD_PORT_B,
+       HPD_PORT_C,
+       HPD_PORT_D,
+       HPD_NUM_PINS
+};
+
 #define I915_GEM_GPU_DOMAINS \
        (I915_GEM_DOMAIN_RENDER | \
         I915_GEM_DOMAIN_SAMPLER | \
@@ -91,7 +104,7 @@ enum port {
         I915_GEM_DOMAIN_INSTRUCTION | \
         I915_GEM_DOMAIN_VERTEX)
 
-#define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++)
+#define for_each_pipe(p) for ((p) = 0; (p) < INTEL_INFO(dev)->num_pipes; (p)++)
 
 #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \
        list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \
@@ -180,9 +193,9 @@ struct drm_i915_master_private {
        struct _drm_i915_sarea *sarea_priv;
 };
 #define I915_FENCE_REG_NONE -1
-#define I915_MAX_NUM_FENCES 16
-/* 16 fences + sign bit for FENCE_REG_NONE */
-#define I915_MAX_NUM_FENCE_BITS 5
+#define I915_MAX_NUM_FENCES 32
+/* 32 fences + sign bit for FENCE_REG_NONE */
+#define I915_MAX_NUM_FENCE_BITS 6
 
 struct drm_i915_fence_reg {
        struct list_head lru_list;
@@ -241,7 +254,7 @@ struct drm_i915_error_state {
                        int page_count;
                        u32 gtt_offset;
                        u32 *pages[0];
-               } *ringbuffer, *batchbuffer;
+               } *ringbuffer, *batchbuffer, *ctx;
                struct drm_i915_error_request {
                        long jiffies;
                        u32 seqno;
@@ -269,6 +282,9 @@ struct drm_i915_error_state {
        struct intel_display_error_state *display;
 };
 
+struct intel_crtc_config;
+struct intel_crtc;
+
 struct drm_i915_display_funcs {
        bool (*fbc_enabled)(struct drm_device *dev);
        void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval);
@@ -281,9 +297,11 @@ struct drm_i915_display_funcs {
        void (*update_linetime_wm)(struct drm_device *dev, int pipe,
                                 struct drm_display_mode *mode);
        void (*modeset_global_resources)(struct drm_device *dev);
+       /* Returns the active state of the crtc, and if the crtc is active,
+        * fills out the pipe-config with the hw state. */
+       bool (*get_pipe_config)(struct intel_crtc *,
+                               struct intel_crtc_config *);
        int (*crtc_mode_set)(struct drm_crtc *crtc,
-                            struct drm_display_mode *mode,
-                            struct drm_display_mode *adjusted_mode,
                             int x, int y,
                             struct drm_framebuffer *old_fb);
        void (*crtc_enable)(struct drm_crtc *crtc);
@@ -339,6 +357,7 @@ struct drm_i915_gt_funcs {
 
 struct intel_device_info {
        u32 display_mmio_offset;
+       u8 num_pipes:3;
        u8 gen;
        u8 is_mobile:1;
        u8 is_i85x:1;
@@ -428,6 +447,7 @@ struct i915_hw_ppgtt {
                               struct sg_table *st,
                               unsigned int pg_start,
                               enum i915_cache_level cache_level);
+       int (*enable)(struct drm_device *dev);
        void (*cleanup)(struct i915_hw_ppgtt *ppgtt);
 };
 
@@ -458,6 +478,7 @@ enum intel_pch {
        PCH_IBX,        /* Ibexpeak PCH */
        PCH_CPT,        /* Cougarpoint PCH */
        PCH_LPT,        /* Lynxpoint PCH */
+       PCH_NOP,
 };
 
 enum intel_sbi_destination {
@@ -652,6 +673,7 @@ struct intel_gen6_power_mgmt {
        u8 cur_delay;
        u8 min_delay;
        u8 max_delay;
+       u8 hw_max;
 
        struct delayed_work delayed_resume_work;
 
@@ -874,7 +896,7 @@ typedef struct drm_i915_private {
 
        drm_local_map_t *sarea;
        drm_local_map_t *mmio_map;
-       void __iomem *regs;
+       char __iomem *regs;
 
        struct drm_i915_gt_funcs gt;
        /** gt_fifo_count and the subsequent register write are synchronized
@@ -920,16 +942,24 @@ typedef struct drm_i915_private {
        struct lock dpio_lock;
 
        /** Cached value of IMR to avoid reads in updating the bitfield */
-       u32 pipestat[2];
        u32 irq_mask;
        u32 gt_irq_mask;
 
-       u32 hotplug_supported_mask;
        struct work_struct hotplug_work;
        bool enable_hotplug_processing;
+       struct {
+               unsigned long hpd_last_jiffies;
+               int hpd_cnt;
+               enum {
+                       HPD_ENABLED = 0,
+                       HPD_DISABLED = 1,
+                       HPD_MARK_DISABLED = 2
+               } hpd_mark;
+       } hpd_stats[HPD_NUM_PINS];
+       struct timer_list hotplug_reenable_timer;
 
-       int num_pipe;
        int num_pch_pll;
+       int num_plane;
 
        unsigned long cfb_size;
        unsigned int cfb_fb;
@@ -943,9 +973,14 @@ typedef struct drm_i915_private {
        struct intel_overlay *overlay;
        unsigned int sprite_scaling_enabled;
 
+       /* backlight */
+       struct {
+               int level;
+               bool enabled;
+               struct backlight_device *device;
+       } backlight;
+
        /* LVDS info */
-       int backlight_level;  /* restore backlight to this value */
-       bool backlight_enabled;
        struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
        struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
 
@@ -1048,8 +1083,6 @@ typedef struct drm_i915_private {
         */
        struct work_struct console_resume_work;
 
-       struct backlight_device *backlight;
-
        struct drm_property *broadcast_rgb_property;
        struct drm_property *force_audio_property;
 
@@ -1352,6 +1385,7 @@ struct drm_i915_file_private {
 #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5)
 
 #define HAS_DDI(dev)           (IS_HASWELL(dev))
+#define HAS_POWER_WELL(dev)    (IS_HASWELL(dev))
 
 #define INTEL_PCH_DEVICE_ID_MASK               0xff00
 #define INTEL_PCH_IBX_DEVICE_ID_TYPE           0x3b00
@@ -1364,6 +1398,7 @@ struct drm_i915_file_private {
 #define HAS_PCH_LPT(dev) (INTEL_PCH_TYPE(dev) == PCH_LPT)
 #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
 #define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX)
+#define HAS_PCH_NOP(dev) (INTEL_PCH_TYPE(dev) == PCH_NOP)
 #define HAS_PCH_SPLIT(dev) (INTEL_PCH_TYPE(dev) != PCH_NONE)
 
 #define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake)
@@ -1625,7 +1660,6 @@ int __must_check i915_gem_init(struct drm_device *dev);
 int __must_check i915_gem_init_hw(struct drm_device *dev);
 void i915_gem_l3_remap(struct drm_device *dev);
 void i915_gem_init_swizzling(struct drm_device *dev);
-void i915_gem_init_ppgtt(struct drm_device *dev);
 void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
 int __must_check i915_gpu_idle(struct drm_device *dev);
 int __must_check i915_gem_idle(struct drm_device *dev);
@@ -1671,6 +1705,8 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
                                struct drm_gem_object *gem_obj, int flags);
 #endif
 
+void i915_gem_restore_fences(struct drm_device *dev);
+
 /* i915_gem_context.c */
 void i915_gem_context_init(struct drm_device *dev);
 void i915_gem_context_fini(struct drm_device *dev);
@@ -1722,6 +1758,11 @@ void i915_gem_stolen_cleanup_compression(struct drm_device *dev);
 void i915_gem_cleanup_stolen(struct drm_device *dev);
 struct drm_i915_gem_object *
 i915_gem_object_create_stolen(struct drm_device *dev, u32 size);
+struct drm_i915_gem_object *
+i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
+                                              u32 stolen_offset,
+                                              u32 gtt_offset,
+                                              u32 size);
 void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj);
 
 /* i915_gem_tiling.c */
@@ -1854,6 +1895,8 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
 
 int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val);
 int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val);
+int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val);
+int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val);
 
 #define __i915_read(x, y) \
        u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg);
@@ -1907,4 +1950,24 @@ static inline uint32_t i915_vgacntrl_reg(struct drm_device *dev)
                return VGACNTRL;
 }
 
+static inline void __user *to_user_ptr(u64 address)
+{
+       return (void __user *)(uintptr_t)address;
+}
+
+static inline unsigned long msecs_to_jiffies_timeout(const unsigned int m)
+{
+       unsigned long j = msecs_to_jiffies(m);
+
+       return min_t(unsigned long, MAX_JIFFY_OFFSET, j + 1);
+}
+
+static inline unsigned long
+timespec_to_jiffies_timeout(const struct timespec *value)
+{
+       unsigned long j = timespec_to_jiffies(value);
+
+       return min_t(unsigned long, MAX_JIFFY_OFFSET, j + 1);
+}
+
 #endif
index edf5db9..f81ace7 100644 (file)
@@ -99,9 +99,7 @@ static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj)
        obj->fence_reg = I915_FENCE_REG_NONE;
 }
 
-static int i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj);
 static bool i915_gem_object_is_inactive(struct drm_i915_gem_object *obj);
-static void i915_gem_reset_fences(struct drm_device *dev);
 static void i915_gem_lowmem(void *arg);
 
 /* some bookkeeping */
@@ -452,7 +450,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
        if (ret)
                goto out_unpin;
 
-       user_data = (char __user *) (uintptr_t) args->data_ptr;
+       user_data = to_user_ptr(args->data_ptr);
        remain = args->size;
 
        offset = obj->gtt_offset + args->offset;
@@ -738,7 +736,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
                wait_forever = false;
        }
 
-       timeout_jiffies = timespec_to_jiffies(&wait_time);
+       timeout_jiffies = timespec_to_jiffies_timeout(&wait_time);
 
        if (WARN_ON(!ring->irq_get(ring)))
                return -ENODEV;
@@ -779,6 +777,8 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
        if (timeout) {
                struct timespec sleep_time = timespec_sub(now, before);
                *timeout = timespec_sub(*timeout, sleep_time);
+               if (!timespec_valid(timeout)) /* i.e. negative time remains */
+                       set_normalized_timespec(timeout, 0, 0);
        }
 
        switch (end) {
@@ -787,8 +787,6 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
        case -ERESTARTSYS: /* Signal */
                return (int)end;
        case 0: /* Timeout */
-               if (timeout)
-                       set_normalized_timespec(timeout, 0, 0);
                return -ETIMEDOUT;      /* -ETIME on Linux */
        default: /* Completed */
                WARN_ON(end < 0); /* We're not aware of other errors */
@@ -1730,25 +1728,15 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
        }
 }
 
-static void i915_gem_reset_fences(struct drm_device *dev)
+void i915_gem_restore_fences(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
 
        for (i = 0; i < dev_priv->num_fence_regs; i++) {
                struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
-
-               i915_gem_write_fence(dev, i, NULL);
-
-               if (reg->obj)
-                       i915_gem_object_fence_lost(reg->obj);
-
-               reg->pin_count = 0;
-               reg->obj = NULL;
-               INIT_LIST_HEAD(&reg->lru_list);
+               i915_gem_write_fence(dev, i, reg->obj);
        }
-
-       INIT_LIST_HEAD(&dev_priv->mm.fence_list);
 }
 
 void i915_gem_reset(struct drm_device *dev)
@@ -1771,8 +1759,7 @@ void i915_gem_reset(struct drm_device *dev)
                obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
        }
 
-       /* The fence registers are invalidated so clear them out */
-       i915_gem_reset_fences(dev);
+       i915_gem_restore_fences(dev);
 }
 
 /**
@@ -2027,10 +2014,8 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
        mutex_unlock(&dev->struct_mutex);
 
        ret = __wait_seqno(ring, seqno, reset_counter, true, timeout);
-       if (timeout) {
-               WARN_ON(!timespec_valid(timeout));
+       if (timeout)
                args->timeout_ns = timespec_to_ns(timeout);
-       }
        return ret;
 
 out:
@@ -2401,6 +2386,7 @@ int
 i915_gem_object_put_fence(struct drm_i915_gem_object *obj)
 {
        struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+       struct drm_i915_fence_reg *fence;
        int ret;
 
        ret = i915_gem_object_wait_fence(obj);
@@ -2410,10 +2396,10 @@ i915_gem_object_put_fence(struct drm_i915_gem_object *obj)
        if (obj->fence_reg == I915_FENCE_REG_NONE)
                return 0;
 
-       i915_gem_object_update_fence(obj,
-                                    &dev_priv->fence_regs[obj->fence_reg],
-                                    false);
+       fence = &dev_priv->fence_regs[obj->fence_reg];
+
        i915_gem_object_fence_lost(obj);
+       i915_gem_object_update_fence(obj, fence, false);
 
        return 0;
 }
@@ -3507,8 +3493,6 @@ i915_gem_idle(struct drm_device *dev)
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_gem_evict_everything(dev);
 
-       i915_gem_reset_fences(dev);
-
        /* Hack!  Don't let anybody do execbuf while we don't control the chip.
         * We need to replace this with a semaphore, or something.
         * And not confound mm.suspended!
@@ -3652,6 +3636,12 @@ i915_gem_init_hw(struct drm_device *dev)
        if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1))
                I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000);
 
+       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);
@@ -3665,7 +3655,13 @@ i915_gem_init_hw(struct drm_device *dev)
         * contexts before PPGTT.
         */
        i915_gem_context_init(dev);
-       i915_gem_init_ppgtt(dev);
+       if (dev_priv->mm.aliasing_ppgtt) {
+               ret = dev_priv->mm.aliasing_ppgtt->enable(dev);
+               if (ret) {
+                       i915_gem_cleanup_aliasing_ppgtt(dev);
+                       DRM_INFO("PPGTT enable failed. This is not fatal, but unexpected\n");
+               }
+       }
 
        return 0;
 }
@@ -3676,7 +3672,16 @@ int i915_gem_init(struct drm_device *dev)
        int ret;
 
        mutex_lock(&dev->struct_mutex);
+
+       if (IS_VALLEYVIEW(dev)) {
+               /* VLVA0 (potential hack), BIOS isn't actually waking us */
+               I915_WRITE(VLV_GTLC_WAKE_CTRL, 1);
+               if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) & 1) == 1, 10))
+                       DRM_DEBUG_DRIVER("allow wake ack timed out\n");
+       }
+
        i915_gem_init_global_gtt(dev);
+
        ret = i915_gem_init_hw(dev);
        mutex_unlock(&dev->struct_mutex);
        if (ret) {
@@ -3805,13 +3810,16 @@ i915_gem_load(struct drm_device *dev)
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                dev_priv->fence_reg_start = 3;
 
-       if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+       if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev))
+               dev_priv->num_fence_regs = 32;
+       else if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
                dev_priv->num_fence_regs = 16;
        else
                dev_priv->num_fence_regs = 8;
 
        /* Initialize fence registers to zero */
-       i915_gem_reset_fences(dev);
+       INIT_LIST_HEAD(&dev_priv->mm.fence_list);
+       i915_gem_restore_fences(dev);
 
        i915_gem_detect_bit_6_swizzle(dev);
        init_waitqueue_head(&dev_priv->pending_flip_queue);
index 64b3439..2b4918e 100644 (file)
@@ -304,7 +304,7 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
        struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
        int remain, ret;
 
-       user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
+       user_relocs = to_user_ptr(entry->relocs_ptr);
 
        remain = entry->relocation_count;
        while (remain) {
@@ -358,8 +358,7 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj,
 }
 
 static int
-i915_gem_execbuffer_relocate(struct drm_device *dev,
-                            struct eb_objects *eb)
+i915_gem_execbuffer_relocate(struct eb_objects *eb)
 {
        struct drm_i915_gem_object *obj;
        int ret = 0;
@@ -478,7 +477,6 @@ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj)
 
 static int
 i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
-                           struct drm_file *file,
                            struct list_head *objects,
                            bool *need_relocs)
 {
@@ -621,7 +619,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
                u64 invalid_offset = (u64)-1;
                int j;
 
-               user_relocs = (void __user *)(uintptr_t)exec[i].relocs_ptr;
+               user_relocs = to_user_ptr(exec[i].relocs_ptr);
 
                if (copy_from_user(reloc+total, user_relocs,
                                   exec[i].relocation_count * sizeof(*reloc))) {
@@ -666,7 +664,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
                goto err;
 
        need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0;
-       ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs);
+       ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs);
        if (ret)
                goto err;
 
@@ -740,7 +738,7 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
 
        for (i = 0; i < count; i++) {
 #if 0
-               char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr;
+               char __user *ptr = to_user_ptr(exec[i].relocs_ptr);
 #endif
                int length; /* limited by fault_in_pages_readable() */
 
@@ -758,7 +756,11 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
                length = exec[i].relocation_count *
                        sizeof(struct drm_i915_gem_relocation_entry);
 #if 0
-               /* we may also need to update the presumed offsets */
+               /*
+                * We must check that the entire relocation array is safe
+                * to read, but since we may need to update the presumed
+                * offsets during execution, check for full write access.
+                */
                if (!access_ok(VERIFY_WRITE, ptr, length))
                        return -EFAULT;
 
@@ -951,9 +953,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                }
 
                if (copy_from_user(cliprects,
-                                    (struct drm_clip_rect __user *)(uintptr_t)
-                                    args->cliprects_ptr,
-                                    sizeof(*cliprects)*args->num_cliprects)) {
+                                  to_user_ptr(args->cliprects_ptr),
+                                  sizeof(*cliprects)*args->num_cliprects)) {
                        ret = -EFAULT;
                        goto pre_mutex_err;
                }
@@ -988,13 +989,13 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 
        /* Move the objects en-masse into the GTT, evicting if necessary. */
        need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0;
-       ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs);
+       ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs);
        if (ret)
                goto err;
 
        /* The objects are in their final locations, apply the relocations. */
        if (need_relocs)
-               ret = i915_gem_execbuffer_relocate(dev, eb);
+               ret = i915_gem_execbuffer_relocate(eb);
        if (ret) {
                if (ret == -EFAULT) {
                        ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring,
@@ -1117,7 +1118,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
                return -ENOMEM;
        }
        ret = copy_from_user(exec_list,
-                            (void __user *)(uintptr_t)args->buffers_ptr,
+                            to_user_ptr(args->buffers_ptr),
                             sizeof(*exec_list) * args->buffer_count);
        if (ret != 0) {
                DRM_DEBUG("copy %d exec entries failed %d\n",
@@ -1156,7 +1157,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
                for (i = 0; i < args->buffer_count; i++)
                        exec_list[i].offset = exec2_list[i].offset;
                /* ... and back out to userspace */
-               ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr,
+               ret = copy_to_user(to_user_ptr(args->buffers_ptr),
                                   exec_list,
                                   sizeof(*exec_list) * args->buffer_count);
                if (ret) {
@@ -1197,8 +1198,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
                return -ENOMEM;
        }
        ret = copy_from_user(exec2_list,
-                            (struct drm_i915_relocation_entry __user *)
-                            (uintptr_t) args->buffers_ptr,
+                            to_user_ptr(args->buffers_ptr),
                             sizeof(*exec2_list) * args->buffer_count);
        if (ret != 0) {
                DRM_DEBUG("copy %d exec entries failed %d\n",
@@ -1210,7 +1210,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
        ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list);
        if (!ret) {
                /* Copy the new buffer offsets back to the user's exec list. */
-               ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr,
+               ret = copy_to_user(to_user_ptr(args->buffers_ptr),
                                   exec2_list,
                                   sizeof(*exec2_list) * args->buffer_count);
                if (ret) {
index 88df8f8..41f93e4 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <linux/highmem.h>
 
-typedef uint32_t gtt_pte_t;
+typedef uint32_t gen6_gtt_pte_t;
 
 /* PPGTT stuff */
 #define GEN6_GTT_ADDR_ENCODE(addr)     ((addr) | (((addr) >> 28) & 0xff0))
@@ -45,11 +45,11 @@ typedef uint32_t gtt_pte_t;
 #define GEN6_PTE_CACHE_LLC_MLC         (3 << 1)
 #define GEN6_PTE_ADDR_ENCODE(addr)     GEN6_GTT_ADDR_ENCODE(addr)
 
-static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev,
-                                       dma_addr_t addr,
-                                       enum i915_cache_level level)
+static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
+                                            dma_addr_t addr,
+                                            enum i915_cache_level level)
 {
-       gtt_pte_t pte = GEN6_PTE_VALID;
+       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
@@ -73,18 +73,83 @@ static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev,
                BUG();
        }
 
-
        return pte;
 }
 
+static int gen6_ppgtt_enable(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       uint32_t pd_offset;
+       struct intel_ring_buffer *ring;
+       struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+       uint32_t pd_entry, first_pd_entry_in_global_pt;
+       int i;
+
+       first_pd_entry_in_global_pt = 512 * 1024 - I915_PPGTT_PD_ENTRIES;
+       for (i = 0; i < ppgtt->num_pd_entries; i++) {
+               dma_addr_t pt_addr;
+
+               pt_addr = VM_PAGE_TO_PHYS(ppgtt->pt_pages[i]);
+               pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr);
+               pd_entry |= GEN6_PDE_VALID;
+
+               intel_gtt_write(first_pd_entry_in_global_pt + i, pd_entry);
+       }
+       intel_gtt_read_pte(first_pd_entry_in_global_pt);
+
+       pd_offset = ppgtt->pd_offset;
+       pd_offset /= 64; /* in cachelines, */
+       pd_offset <<= 16;
+
+       if (INTEL_INFO(dev)->gen == 6) {
+               uint32_t ecochk, gab_ctl, ecobits;
+
+               ecobits = I915_READ(GAC_ECO_BITS);
+               I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT |
+                                        ECOBITS_PPGTT_CACHE64B);
+
+               gab_ctl = I915_READ(GAB_CTL);
+               I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT);
+
+               ecochk = I915_READ(GAM_ECOCHK);
+               I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT |
+                                      ECOCHK_PPGTT_CACHE64B);
+               I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
+       } else if (INTEL_INFO(dev)->gen >= 7) {
+               uint32_t ecochk, ecobits;
+
+               ecobits = I915_READ(GAC_ECO_BITS);
+               I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B);
+
+               ecochk = I915_READ(GAM_ECOCHK);
+               if (IS_HASWELL(dev)) {
+                       ecochk |= ECOCHK_PPGTT_WB_HSW;
+               } else {
+                       ecochk |= ECOCHK_PPGTT_LLC_IVB;
+                       ecochk &= ~ECOCHK_PPGTT_GFDT_IVB;
+               }
+               I915_WRITE(GAM_ECOCHK, ecochk);
+               /* GFX_MODE is per-ring on gen7+ */
+       }
+
+       for_each_ring(ring, dev_priv, i) {
+               if (INTEL_INFO(dev)->gen >= 7)
+                       I915_WRITE(RING_MODE_GEN7(ring),
+                                  _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
+
+               I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
+               I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset);
+       }
+       return 0;
+}
+
 /* PPGTT support for Sandybdrige/Gen6 and later */
 static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
                                   unsigned first_entry,
                                   unsigned num_entries)
 {
-       gtt_pte_t *pt_vaddr;
-       gtt_pte_t scratch_pte;
-       unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
+       gen6_gtt_pte_t *pt_vaddr, scratch_pte;
+       unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
        unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
        unsigned last_pte, i;
 
@@ -97,7 +162,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
                if (last_pte > I915_PPGTT_PT_ENTRIES)
                        last_pte = I915_PPGTT_PT_ENTRIES;
 
-               pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
+               pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]);
 
                for (i = first_pte; i < last_pte; i++)
                        pt_vaddr[i] = scratch_pte;
@@ -106,7 +171,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
 
                num_entries -= last_pte - first_pte;
                first_pte = 0;
-               act_pd++;
+               act_pt++;
        }
 }
 
@@ -115,8 +180,8 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
                                      unsigned first_entry,
                                      enum i915_cache_level cache_level)
 {
-       gtt_pte_t *pt_vaddr;
-       unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
+       gen6_gtt_pte_t *pt_vaddr;
+       unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
        unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
        unsigned i, j, m, segment_len;
        dma_addr_t page_addr;
@@ -129,7 +194,7 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
        m = 0;
 
        while (i < pages->nents) {
-               pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
+               pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]);
 
                for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) {
                        page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
@@ -150,7 +215,7 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
                kunmap_atomic(pt_vaddr);
 
                first_pte = 0;
-               act_pd++;
+               act_pt++;
        }
 }
 
@@ -189,6 +254,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
        first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt);
 
        ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
+       ppgtt->enable = gen6_ppgtt_enable;
        ppgtt->clear_range = gen6_ppgtt_clear_range;
        ppgtt->insert_entries = gen6_ppgtt_insert_entries;
        ppgtt->cleanup = gen6_ppgtt_cleanup;
@@ -204,12 +270,10 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
                        goto err_pt_alloc;
        }
 
-       ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma;
-
        ppgtt->clear_range(ppgtt, 0,
                           ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES);
 
-       ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t);
+       ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t);
 
        return 0;
 
@@ -231,8 +295,13 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
                return -ENOMEM;
 
        ppgtt->dev = dev;
+       ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma;
+
+       if (INTEL_INFO(dev)->gen < 8)
+               ret = gen6_ppgtt_init(ppgtt);
+       else
+               BUG();
 
-       ret = gen6_ppgtt_init(ppgtt);
        if (ret)
                kfree(ppgtt);
        else
@@ -250,6 +319,7 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
                return;
 
        ppgtt->cleanup(ppgtt);
+       dev_priv->mm.aliasing_ppgtt = NULL;
 }
 
 #if 0
@@ -326,62 +396,6 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
                           obj->base.size >> PAGE_SHIFT);
 }
 
-void i915_gem_init_ppgtt(struct drm_device *dev)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       uint32_t pd_offset;
-       struct intel_ring_buffer *ring;
-       struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
-       uint32_t pd_entry, first_pd_entry_in_global_pt;
-       int i;
-
-       if (!dev_priv->mm.aliasing_ppgtt)
-               return;
-
-       first_pd_entry_in_global_pt = 512 * 1024 - I915_PPGTT_PD_ENTRIES;
-       for (i = 0; i < ppgtt->num_pd_entries; i++) {
-               vm_paddr_t pt_addr;
-
-               pt_addr = VM_PAGE_TO_PHYS(ppgtt->pt_pages[i]);
-               pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr);
-               pd_entry |= GEN6_PDE_VALID;
-
-               intel_gtt_write(first_pd_entry_in_global_pt + i, pd_entry);
-       }
-       intel_gtt_read_pte(first_pd_entry_in_global_pt);
-
-       pd_offset = ppgtt->pd_offset;
-       pd_offset /= 64; /* in cachelines, */
-       pd_offset <<= 16;
-
-       if (INTEL_INFO(dev)->gen == 6) {
-               uint32_t ecochk, gab_ctl, ecobits;
-
-               ecobits = I915_READ(GAC_ECO_BITS);
-               I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B);
-
-               gab_ctl = I915_READ(GAB_CTL);
-               I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT);
-
-               ecochk = I915_READ(GAM_ECOCHK);
-               I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT |
-                                      ECOCHK_PPGTT_CACHE64B);
-               I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-       } else if (INTEL_INFO(dev)->gen >= 7) {
-               I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B);
-               /* GFX_MODE is per-ring on gen7+ */
-       }
-
-       for_each_ring(ring, dev_priv, i) {
-               if (INTEL_INFO(dev)->gen >= 7)
-                       I915_WRITE(RING_MODE_GEN7(ring),
-                                  _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-
-               I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
-               I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset);
-       }
-}
-
 extern int intel_iommu_gfx_mapped;
 /* Certain Gen5 chipsets require require idling the GPU before
  * unmapping anything from the GTT when VT-d is enabled.
@@ -506,9 +520,9 @@ static void gen6_ggtt_clear_range(struct drm_device *dev,
                                  unsigned int num_entries)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       gtt_pte_t scratch_pte;
-       gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
-       const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry;
+       gen6_gtt_pte_t scratch_pte, __iomem *gtt_base =
+               (gen6_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
+       const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
        int i;
 
        if (WARN(num_entries > max_entries,
@@ -659,36 +673,30 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long gtt_size, mappable_size;
-       int ret;
 
        gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT;
        mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
 
        if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) {
-               /* PPGTT pdes are stolen from global gtt ptes, so shrink the
-                * aperture accordingly when using aliasing ppgtt. */
-               gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
+               int ret;
+
+               if (INTEL_INFO(dev)->gen <= 7) {
+                       /* PPGTT pdes are stolen from global gtt ptes, so shrink the
+                        * aperture accordingly when using aliasing ppgtt. */
+                       gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
+               }
 
                i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
 
                ret = i915_gem_init_aliasing_ppgtt(dev);
-               if (ret) {
-                       DRM_UNLOCK(dev);
+               if (!ret)
                        return;
-               }
-       } else {
-               /* Let GEM Manage all of the aperture.
-                *
-                * However, leave one page at the end still bound to the scratch
-                * page.  There are a number of places where the hardware
-                * apparently prefetches past the end of the object, and we've
-                * seen multiple hangs with the GPU head pointer stuck in a
-                * batchbuffer bound at the last page of the aperture.  One page
-                * should be enough to keep any prefetching inside of the
-                * aperture.
-                */
-               i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
+
+               DRM_ERROR("Aliased PPGTT setup failed %d\n", ret);
+               drm_mm_takedown(&dev_priv->mm.gtt_space);
+               gtt_size += I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
        }
+       i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
 }
 
 int i915_gem_gtt_init(struct drm_device *dev)
index ce918e2..64af0a1 100644 (file)
@@ -217,9 +217,12 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
                tile_width = 512;
 
        /* check maximum stride & object size */
-       if (INTEL_INFO(dev)->gen >= 4) {
-               /* i965 stores the end address of the gtt mapping in the fence
-                * reg, so dont bother to check the size */
+       /* i965+ stores the end address of the gtt mapping in the fence
+        * reg, so dont bother to check the size */
+       if (INTEL_INFO(dev)->gen >= 7) {
+               if (stride / 128 > GEN7_FENCE_MAX_PITCH_VAL)
+                       return false;
+       } else if (INTEL_INFO(dev)->gen >= 4) {
                if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
                        return false;
        } else {
@@ -235,6 +238,9 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
                }
        }
 
+       if (stride < tile_width)
+               return false;
+
        /* 965+ just needs multiples of tile width */
        if (INTEL_INFO(dev)->gen >= 4) {
                if (stride & (tile_width - 1))
@@ -243,9 +249,6 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
        }
 
        /* Pre-965 needs power of two tile widths */
-       if (stride < tile_width)
-               return false;
-
        if (stride & (stride - 1))
                return false;
 
index 42f7618..e7ca102 100644 (file)
 #include "i915_drv.h"
 #include "intel_drv.h"
 
+static const u32 hpd_ibx[] = {
+       [HPD_CRT] = SDE_CRT_HOTPLUG,
+       [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
+       [HPD_PORT_B] = SDE_PORTB_HOTPLUG,
+       [HPD_PORT_C] = SDE_PORTC_HOTPLUG,
+       [HPD_PORT_D] = SDE_PORTD_HOTPLUG
+};
+
+static const u32 hpd_cpt[] = {
+       [HPD_CRT] = SDE_CRT_HOTPLUG_CPT,
+       [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT,
+       [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
+       [HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT,
+       [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT
+};
+
+static const u32 hpd_mask_i915[] = {
+       [HPD_CRT] = CRT_HOTPLUG_INT_EN,
+       [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN,
+       [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN,
+       [HPD_PORT_B] = PORTB_HOTPLUG_INT_EN,
+       [HPD_PORT_C] = PORTC_HOTPLUG_INT_EN,
+       [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN
+};
+
+static const u32 hpd_status_gen4[] = {
+       [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
+       [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X,
+       [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X,
+       [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
+       [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
+       [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
+};
+
+static const u32 hpd_status_i965[] = {
+        [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
+        [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I965,
+        [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I965,
+        [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
+        [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
+        [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
+};
+
+static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
+       [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
+       [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
+       [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915,
+       [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
+       [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
+       [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
+};
+
+static void ibx_hpd_irq_setup(struct drm_device *dev);
+static void i915_hpd_irq_setup(struct drm_device *dev);
+
 /* For display hotplug interrupt */
 static void
 ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
@@ -42,7 +97,7 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
        }
 }
 
-static inline void
+static void
 ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
        if ((dev_priv->irq_mask & mask) != mask) {
@@ -55,26 +110,30 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 void
 i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 {
-       if ((dev_priv->pipestat[pipe] & mask) != mask) {
-               u32 reg = PIPESTAT(pipe);
+       u32 reg = PIPESTAT(pipe);
+       u32 pipestat = I915_READ(reg) & 0x7fff0000;
 
-               dev_priv->pipestat[pipe] |= mask;
-               /* Enable the interrupt, clear any pending status */
-               I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16));
-               POSTING_READ(reg);
-       }
+       if ((pipestat & mask) == mask)
+               return;
+
+       /* Enable the interrupt, clear any pending status */
+       pipestat |= mask | (mask >> 16);
+       I915_WRITE(reg, pipestat);
+       POSTING_READ(reg);
 }
 
 void
 i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 {
-       if ((dev_priv->pipestat[pipe] & mask) != 0) {
-               u32 reg = PIPESTAT(pipe);
+       u32 reg = PIPESTAT(pipe);
+       u32 pipestat = I915_READ(reg) & 0x7fff0000;
 
-               dev_priv->pipestat[pipe] &= ~mask;
-               I915_WRITE(reg, dev_priv->pipestat[pipe]);
-               POSTING_READ(reg);
-       }
+       if ((pipestat & mask) == 0)
+               return;
+
+       pipestat &= ~mask;
+       I915_WRITE(reg, pipestat);
+       POSTING_READ(reg);
 }
 
 /**
@@ -244,10 +303,9 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
                              struct timeval *vblank_time,
                              unsigned flags)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc;
 
-       if (pipe < 0 || pipe >= dev_priv->num_pipe) {
+       if (pipe < 0 || pipe >= INTEL_INFO(dev)->num_pipes) {
                DRM_ERROR("Invalid crtc %d\n", pipe);
                return -EINVAL;
        }
@@ -273,13 +331,18 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
 /*
  * Handle hotplug events outside the interrupt handler proper.
  */
+#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000)
+
 static void i915_hotplug_work_func(struct work_struct *work)
 {
        drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
                                                    hotplug_work);
        struct drm_device *dev = dev_priv->dev;
        struct drm_mode_config *mode_config = &dev->mode_config;
-       struct intel_encoder *encoder;
+       struct intel_connector *intel_connector;
+       struct intel_encoder *intel_encoder;
+       struct drm_connector *connector;
+       bool hpd_disabled = false;
 
        /* HPD irq before everything is fully set up. */
        if (!dev_priv->enable_hotplug_processing)
@@ -288,9 +351,36 @@ static void i915_hotplug_work_func(struct work_struct *work)
        mutex_lock(&mode_config->mutex);
        DRM_DEBUG_KMS("running encoder hotplug functions\n");
 
-       list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
-               if (encoder->hot_plug)
-                       encoder->hot_plug(encoder);
+       lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
+       list_for_each_entry(connector, &mode_config->connector_list, head) {
+               intel_connector = to_intel_connector(connector);
+               intel_encoder = intel_connector->encoder;
+               if (intel_encoder->hpd_pin > HPD_NONE &&
+                   dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_MARK_DISABLED &&
+                   connector->polled == DRM_CONNECTOR_POLL_HPD) {
+                       DRM_INFO("HPD interrupt storm detected on connector %s: "
+                                "switching from hotplug detection to polling\n",
+                               drm_get_connector_name(connector));
+                       dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark = HPD_DISABLED;
+                       connector->polled = DRM_CONNECTOR_POLL_CONNECT
+                               | DRM_CONNECTOR_POLL_DISCONNECT;
+                       hpd_disabled = true;
+               }
+       }
+        /* if there were no outputs to poll, poll was disabled,
+         * therefore make sure it's enabled when disabling HPD on
+         * some connectors */
+       if (hpd_disabled) {
+               drm_kms_helper_poll_enable(dev);
+               mod_timer(&dev_priv->hotplug_reenable_timer,
+                         jiffies + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY));
+       }
+
+       lockmgr(&dev_priv->irq_lock, LK_RELEASE);
+
+       list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
+               if (intel_encoder->hot_plug)
+                       intel_encoder->hot_plug(intel_encoder);
 
        mutex_unlock(&mode_config->mutex);
 
@@ -503,6 +593,44 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
        queue_work(dev_priv->wq, &dev_priv->rps.work);
 }
 
+#define HPD_STORM_DETECT_PERIOD 1000
+#define HPD_STORM_THRESHOLD 5
+
+static inline bool hotplug_irq_storm_detect(struct drm_device *dev,
+                                           u32 hotplug_trigger,
+                                           const u32 *hpd)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int i;
+       bool ret = false;
+
+       lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
+
+       for (i = 1; i < HPD_NUM_PINS; i++) {
+
+               if (!(hpd[i] & hotplug_trigger) ||
+                   dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED)
+                       continue;
+
+               if (!time_in_range(jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies,
+                                  dev_priv->hpd_stats[i].hpd_last_jiffies
+                                  + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) {
+                       dev_priv->hpd_stats[i].hpd_last_jiffies = jiffies;
+                       dev_priv->hpd_stats[i].hpd_cnt = 0;
+               } else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) {
+                       dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED;
+                       DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i);
+                       ret = true;
+               } else {
+                       dev_priv->hpd_stats[i].hpd_cnt++;
+               }
+       }
+
+       lockmgr(&dev_priv->irq_lock, LK_RELEASE);
+
+       return ret;
+}
+
 static void gmbus_irq_handler(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -567,13 +695,16 @@ static irqreturn_t valleyview_irq_handler(void *arg)
                /* Consume port.  Then clear IIR or we'll miss events */
                if (iir & I915_DISPLAY_PORT_INTERRUPT) {
                        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
+                       u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
 
                        DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
                                         hotplug_status);
-                       if (hotplug_status & dev_priv->hotplug_supported_mask)
+                       if (hotplug_trigger) {
+                               if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
+                                       i915_hpd_irq_setup(dev);
                                queue_work(dev_priv->wq,
                                           &dev_priv->hotplug_work);
-
+                       }
                        I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
                        I915_READ(PORT_HOTPLUG_STAT);
                }
@@ -597,10 +728,13 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe;
+       u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
 
-       if (pch_iir & SDE_HOTPLUG_MASK)
+       if (hotplug_trigger) {
+               if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx))
+                       ibx_hpd_irq_setup(dev);
                queue_work(dev_priv->wq, &dev_priv->hotplug_work);
-
+       }
        if (pch_iir & SDE_AUDIO_POWER_MASK)
                DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
                                 (pch_iir & SDE_AUDIO_POWER_MASK) >>
@@ -643,10 +777,13 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe;
+       u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
-       if (pch_iir & SDE_HOTPLUG_MASK_CPT)
+       if (hotplug_trigger) {
+               if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt))
+                       ibx_hpd_irq_setup(dev);
                queue_work(dev_priv->wq, &dev_priv->hotplug_work);
-
+       }
        if (pch_iir & SDE_AUDIO_POWER_MASK_CPT)
                DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
                                 (pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
@@ -675,7 +812,7 @@ static irqreturn_t ivybridge_irq_handler(void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier;
+       u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier = 0;
        int i;
 
        atomic_inc(&dev_priv->irq_received);
@@ -689,9 +826,11 @@ static irqreturn_t ivybridge_irq_handler(void *arg)
         * able to process them after we restore SDEIER (as soon as we restore
         * it, we'll get an interrupt if SDEIIR still has something to process
         * due to its back queue). */
-       sde_ier = I915_READ(SDEIER);
-       I915_WRITE(SDEIER, 0);
-       POSTING_READ(SDEIER);
+       if (!HAS_PCH_NOP(dev)) {
+               sde_ier = I915_READ(SDEIER);
+               I915_WRITE(SDEIER, 0);
+               POSTING_READ(SDEIER);
+       }
 
        gt_iir = I915_READ(GTIIR);
        if (gt_iir) {
@@ -717,7 +856,7 @@ static irqreturn_t ivybridge_irq_handler(void *arg)
                }
 
                /* check event from PCH */
-               if (de_iir & DE_PCH_EVENT_IVB) {
+               if (!HAS_PCH_NOP(dev) && (de_iir & DE_PCH_EVENT_IVB)) {
                        u32 pch_iir = I915_READ(SDEIIR);
 
                        cpt_irq_handler(dev, pch_iir);
@@ -738,8 +877,10 @@ static irqreturn_t ivybridge_irq_handler(void *arg)
 
        I915_WRITE(DEIER, de_ier);
        POSTING_READ(DEIER);
-       I915_WRITE(SDEIER, sde_ier);
-       POSTING_READ(SDEIER);
+       if (!HAS_PCH_NOP(dev)) {
+               I915_WRITE(SDEIER, sde_ier);
+               POSTING_READ(SDEIER);
+       }
 }
 
 static void ilk_gt_irq_handler(struct drm_device *dev,
@@ -906,6 +1047,8 @@ static void i915_error_work_func(struct work_struct *work)
                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);
        }
 }
@@ -943,24 +1086,23 @@ static void i915_get_extra_instdone(struct drm_device *dev,
 
 #if 0 /* CONFIG_DEBUG_FS */
 static struct drm_i915_error_object *
-i915_error_object_create(struct drm_i915_private *dev_priv,
-                        struct drm_i915_gem_object *src)
+i915_error_object_create_sized(struct drm_i915_private *dev_priv,
+                              struct drm_i915_gem_object *src,
+                              const int num_pages)
 {
        struct drm_i915_error_object *dst;
-       int i, count;
+       int i;
        u32 reloc_offset;
 
        if (src == NULL || src->pages == NULL)
                return NULL;
 
-       count = src->base.size / PAGE_SIZE;
-
-       dst = kmalloc(sizeof(*dst) + count * sizeof(u32 *), GFP_ATOMIC);
+       dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC);
        if (dst == NULL)
                return NULL;
 
        reloc_offset = src->gtt_offset;
-       for (i = 0; i < count; i++) {
+       for (i = 0; i < num_pages; i++) {
                unsigned long flags;
                void *d;
 
@@ -1010,7 +1152,7 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
 
                reloc_offset += PAGE_SIZE;
        }
-       dst->page_count = count;
+       dst->page_count = num_pages;
        dst->gtt_offset = src->gtt_offset;
 
        return dst;
@@ -1021,6 +1163,9 @@ unwind:
        kfree(dst);
        return NULL;
 }
+#define i915_error_object_create(dev_priv, src) \
+       i915_error_object_create_sized((dev_priv), (src), \
+                                      (src)->base.size>>PAGE_SHIFT)
 
 static void
 i915_error_object_free(struct drm_i915_error_object *obj)
@@ -1120,7 +1265,7 @@ static void i915_gem_record_fences(struct drm_device *dev,
        switch (INTEL_INFO(dev)->gen) {
        case 7:
        case 6:
-               for (i = 0; i < 16; i++)
+               for (i = 0; i < dev_priv->num_fence_regs; i++)
                        error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
                break;
        case 5:
@@ -1228,6 +1373,26 @@ static void i915_record_ring_state(struct drm_device *dev,
        error->cpu_ring_tail[ring->id] = ring->tail;
 }
 
+
+static void i915_gem_record_active_context(struct intel_ring_buffer *ring,
+                                          struct drm_i915_error_state *error,
+                                          struct drm_i915_error_ring *ering)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct drm_i915_gem_object *obj;
+
+       /* Currently render ring is the only HW context user */
+       if (ring->id != RCS || !error->ccid)
+               return;
+
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+               if ((error->ccid & PAGE_MASK) == obj->gtt_offset) {
+                       ering->ctx = i915_error_object_create_sized(dev_priv,
+                                                                   obj, 1);
+               }
+       }
+}
+
 static void i915_gem_record_rings(struct drm_device *dev,
                                  struct drm_i915_error_state *error)
 {
@@ -1245,6 +1410,9 @@ static void i915_gem_record_rings(struct drm_device *dev,
                error->ring[i].ringbuffer =
                        i915_error_object_create(dev_priv, ring->obj);
 
+
+               i915_gem_record_active_context(ring, error, &error->ring[i]);
+
                count = 0;
                list_for_each_entry(request, &ring->request_list, list)
                        count++;
@@ -1300,14 +1468,15 @@ static void i915_capture_error_state(struct drm_device *dev)
                return;
        }
 
-       DRM_INFO("capturing error event; look for more information in"
+       DRM_INFO("capturing error event; look for more information in "
                 "/sys/kernel/debug/dri/%d/i915_error_state\n",
                 dev->primary->index);
 
        kref_init(&error->ref);
        error->eir = I915_READ(EIR);
        error->pgtbl_er = I915_READ(PGTBL_ER);
-       error->ccid = I915_READ(CCID);
+       if (HAS_HW_CONTEXTS(dev))
+               error->ccid = I915_READ(CCID);
 
        if (HAS_PCH_SPLIT(dev))
                error->ier = I915_READ(DEIER) | I915_READ(GTIER);
@@ -1328,8 +1497,9 @@ static void i915_capture_error_state(struct drm_device *dev)
        else if (INTEL_INFO(dev)->gen == 6)
                error->forcewake = I915_READ(FORCEWAKE);
 
-       for_each_pipe(pipe)
-               error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
+       if (!HAS_PCH_SPLIT(dev))
+               for_each_pipe(pipe)
+                       error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
 
        if (INTEL_INFO(dev)->gen >= 6) {
                error->error = I915_READ(ERROR_GEN6);
@@ -1538,7 +1708,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
        queue_work(dev_priv->wq, &dev_priv->gpu_error.work);
 }
 
-static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
+static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
@@ -1743,6 +1913,37 @@ static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
        return false;
 }
 
+static bool semaphore_passed(struct intel_ring_buffer *ring)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       u32 acthd = intel_ring_get_active_head(ring) & HEAD_ADDR;
+       struct intel_ring_buffer *signaller;
+       u32 cmd, ipehr, acthd_min;
+
+       ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
+       if ((ipehr & ~(0x3 << 16)) !=
+           (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER))
+               return false;
+
+       /* ACTHD is likely pointing to the dword after the actual command,
+        * so scan backwards until we find the MBOX.
+        */
+       acthd_min = max((int)acthd - 3 * 4, 0);
+       do {
+               cmd = ioread32(ring->virtual_start + acthd);
+               if (cmd == ipehr)
+                       break;
+
+               acthd -= 4;
+               if (acthd < acthd_min)
+                       return false;
+       } while (1);
+
+       signaller = &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3];
+       return i915_seqno_passed(signaller->get_seqno(signaller, false),
+                                ioread32(ring->virtual_start+acthd+4)+1);
+}
+
 static bool kick_ring(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
@@ -1754,6 +1955,15 @@ static bool kick_ring(struct intel_ring_buffer *ring)
                I915_WRITE_CTL(ring, tmp);
                return true;
        }
+
+       if (INTEL_INFO(dev)->gen >= 6 &&
+           tmp & RING_WAIT_SEMAPHORE &&
+           semaphore_passed(ring)) {
+               DRM_ERROR("Kicking stuck semaphore on %s\n",
+                         ring->name);
+               I915_WRITE_CTL(ring, tmp);
+               return true;
+       }
        return false;
 }
 
@@ -1867,9 +2077,18 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
        I915_WRITE(GTIER, 0x0);
        POSTING_READ(GTIER);
 
+       if (HAS_PCH_NOP(dev))
+               return;
+
        /* south display irq */
        I915_WRITE(SDEIMR, 0xffffffff);
-       I915_WRITE(SDEIER, 0x0);
+       /*
+        * SDEIER is also touched by the interrupt handler to work around missed
+        * PCH interrupts. Hence we can't update it after the interrupt handler
+        * is enabled - instead we unconditionally enable all PCH interrupt
+        * sources here, but then only unmask them as needed with SDEIMR.
+        */
+       I915_WRITE(SDEIER, 0xffffffff);
        POSTING_READ(SDEIER);
 }
 
@@ -1905,18 +2124,34 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
        POSTING_READ(VLV_IER);
 }
 
-/*
- * Enable digital hotplug on the PCH, and configure the DP short pulse
- * duration to 2ms (which is the minimum in the Display Port spec)
- *
- * This register is the same on all known PCH chips.
- */
-
-static void ibx_enable_hotplug(struct drm_device *dev)
+static void ibx_hpd_irq_setup(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32     hotplug;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *intel_encoder;
+       u32 mask = ~I915_READ(SDEIMR);
+       u32 hotplug;
+
+       if (HAS_PCH_IBX(dev)) {
+               mask &= ~SDE_HOTPLUG_MASK;
+               list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
+                       if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
+                               mask |= hpd_ibx[intel_encoder->hpd_pin];
+       } else {
+               mask &= ~SDE_HOTPLUG_MASK_CPT;
+               list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
+                       if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
+                               mask |= hpd_cpt[intel_encoder->hpd_pin];
+       }
 
+       I915_WRITE(SDEIMR, ~mask);
+
+       /*
+        * Enable digital hotplug on the PCH, and configure the DP short pulse
+        * duration to 2ms (which is the minimum in the Display Port spec)
+        *
+        * This register is the same on all known PCH chips.
+        */
        hotplug = I915_READ(PCH_PORT_HOTPLUG);
        hotplug &= ~(PORTD_PULSE_DURATION_MASK|PORTC_PULSE_DURATION_MASK|PORTB_PULSE_DURATION_MASK);
        hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms;
@@ -1931,20 +2166,15 @@ static void ibx_irq_postinstall(struct drm_device *dev)
        u32 mask;
 
        if (HAS_PCH_IBX(dev))
-               mask = SDE_HOTPLUG_MASK |
-                      SDE_GMBUS |
-                      SDE_AUX_MASK;
+               mask = SDE_GMBUS | SDE_AUX_MASK;
        else
-               mask = SDE_HOTPLUG_MASK_CPT |
-                      SDE_GMBUS_CPT |
-                      SDE_AUX_MASK_CPT;
+               mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
+
+       if (HAS_PCH_NOP(dev))
+               return;
 
        I915_WRITE(SDEIIR, I915_READ(SDEIIR));
        I915_WRITE(SDEIMR, ~mask);
-       I915_WRITE(SDEIER, mask);
-       POSTING_READ(SDEIER);
-
-       ibx_enable_hotplug(dev);
 }
 
 static int ironlake_irq_postinstall(struct drm_device *dev)
@@ -2055,9 +2285,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
                I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
                I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
 
-       dev_priv->pipestat[0] = 0;
-       dev_priv->pipestat[1] = 0;
-
        /* Hack for broken MSIs on VLV */
        pci_write_config_dword(dev_priv->dev->pdev, 0x94, 0xfee00000);
        pci_read_config_word(dev->pdev, 0x98, &msid);
@@ -2101,30 +2328,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
-static void valleyview_hpd_irq_setup(struct drm_device *dev)
-{
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
-
-       /* Note HDMI and DP share bits */
-       if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS)
-               hotplug_en |= PORTB_HOTPLUG_INT_EN;
-       if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS)
-               hotplug_en |= PORTC_HOTPLUG_INT_EN;
-       if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS)
-               hotplug_en |= PORTD_HOTPLUG_INT_EN;
-       if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)
-               hotplug_en |= SDVOC_HOTPLUG_INT_EN;
-       if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915)
-               hotplug_en |= SDVOB_HOTPLUG_INT_EN;
-       if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
-               hotplug_en |= CRT_HOTPLUG_INT_EN;
-               hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
-       }
-
-       I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
-}
-
 static void valleyview_irq_uninstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -2133,6 +2336,8 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
        if (!dev_priv)
                return;
 
+       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+
        for_each_pipe(pipe)
                I915_WRITE(PIPESTAT(pipe), 0xffff);
 
@@ -2154,6 +2359,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
        if (!dev_priv)
                return;
 
+       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+
        I915_WRITE(HWSTAM, 0xffffffff);
 
        I915_WRITE(DEIMR, 0xffffffff);
@@ -2164,6 +2371,9 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
        I915_WRITE(GTIER, 0x0);
        I915_WRITE(GTIIR, I915_READ(GTIIR));
 
+       if (HAS_PCH_NOP(dev))
+               return;
+
        I915_WRITE(SDEIMR, 0xffffffff);
        I915_WRITE(SDEIER, 0x0);
        I915_WRITE(SDEIIR, I915_READ(SDEIIR));
@@ -2187,9 +2397,6 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
-       dev_priv->pipestat[0] = 0;
-       dev_priv->pipestat[1] = 0;
-
        I915_WRITE16(EMR,
                     ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
 
@@ -2212,6 +2419,37 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
+/*
+ * Returns true when a page flip has completed.
+ */
+static bool i8xx_handle_vblank(struct drm_device *dev,
+                              int pipe, u16 iir)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(pipe);
+
+       if (!drm_handle_vblank(dev, pipe))
+               return false;
+
+       if ((iir & flip_pending) == 0)
+               return false;
+
+       intel_prepare_page_flip(dev, pipe);
+
+       /* We detect FlipDone by looking for the change in PendingFlip from '1'
+        * to '0' on the following vblank, i.e. IIR has the Pendingflip
+        * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
+        * the flip is completed (no longer pending). Since this doesn't raise
+        * an interrupt per se, we watch for the change at vblank.
+        */
+       if (I915_READ16(ISR) & flip_pending)
+               return false;
+
+       intel_finish_page_flip(dev, pipe);
+
+       return true;
+}
+
 static irqreturn_t i8xx_irq_handler(void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
@@ -2266,22 +2504,12 @@ static irqreturn_t i8xx_irq_handler(void *arg)
                        notify_ring(dev, &dev_priv->ring[RCS]);
 
                if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS &&
-                   drm_handle_vblank(dev, 0)) {
-                       if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
-                               intel_prepare_page_flip(dev, 0);
-                               intel_finish_page_flip(dev, 0);
-                               flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT;
-                       }
-               }
+                   i8xx_handle_vblank(dev, 0, iir))
+                       flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(0);
 
                if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS &&
-                   drm_handle_vblank(dev, 1)) {
-                       if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) {
-                               intel_prepare_page_flip(dev, 1);
-                               intel_finish_page_flip(dev, 1);
-                               flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
-                       }
-               }
+                   i8xx_handle_vblank(dev, 1, iir))
+                       flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(1);
 
                iir = new_iir;
        }
@@ -2329,9 +2557,6 @@ static int i915_irq_postinstall(struct drm_device *dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 enable_mask;
 
-       dev_priv->pipestat[0] = 0;
-       dev_priv->pipestat[1] = 0;
-
        I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
 
        /* Unmask the interrupts that we always want on. */
@@ -2369,33 +2594,35 @@ static int i915_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
-static void i915_hpd_irq_setup(struct drm_device *dev)
+/*
+ * Returns true when a page flip has completed.
+ */
+static bool i915_handle_vblank(struct drm_device *dev,
+                              int plane, int pipe, u32 iir)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32 hotplug_en;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
 
-       if (I915_HAS_HOTPLUG(dev)) {
-               hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+       if (!drm_handle_vblank(dev, pipe))
+               return false;
 
-               if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS)
-                       hotplug_en |= PORTB_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS)
-                       hotplug_en |= PORTC_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS)
-                       hotplug_en |= PORTD_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)
-                       hotplug_en |= SDVOC_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915)
-                       hotplug_en |= SDVOB_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
-                       hotplug_en |= CRT_HOTPLUG_INT_EN;
-                       hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
-               }
+       if ((iir & flip_pending) == 0)
+               return false;
 
-               /* Ignore TV since it's buggy */
+       intel_prepare_page_flip(dev, plane);
 
-               I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
-       }
+       /* We detect FlipDone by looking for the change in PendingFlip from '1'
+        * to '0' on the following vblank, i.e. IIR has the Pendingflip
+        * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
+        * the flip is completed (no longer pending). Since this doesn't raise
+        * an interrupt per se, we watch for the change at vblank.
+        */
+       if (I915_READ(ISR) & flip_pending)
+               return false;
+
+       intel_finish_page_flip(dev, pipe);
+
+       return true;
 }
 
 static irqreturn_t i915_irq_handler(void *arg)
@@ -2406,10 +2633,6 @@ static irqreturn_t i915_irq_handler(void *arg)
        u32 flip_mask =
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
-       u32 flip[2] = {
-               I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT,
-               I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT
-       };
        int pipe;
 
        atomic_inc(&dev_priv->irq_received);
@@ -2450,13 +2673,16 @@ static irqreturn_t i915_irq_handler(void *arg)
                if ((I915_HAS_HOTPLUG(dev)) &&
                    (iir & I915_DISPLAY_PORT_INTERRUPT)) {
                        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
+                       u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
 
                        DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
                                  hotplug_status);
-                       if (hotplug_status & dev_priv->hotplug_supported_mask)
+                       if (hotplug_trigger) {
+                               if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
+                                       i915_hpd_irq_setup(dev);
                                queue_work(dev_priv->wq,
                                           &dev_priv->hotplug_work);
-
+                       }
                        I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
                        POSTING_READ(PORT_HOTPLUG_STAT);
                }
@@ -2471,14 +2697,10 @@ static irqreturn_t i915_irq_handler(void *arg)
                        int plane = pipe;
                        if (IS_MOBILE(dev))
                                plane = !plane;
+
                        if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
-                           drm_handle_vblank(dev, pipe)) {
-                               if (iir & flip[plane]) {
-                                       intel_prepare_page_flip(dev, plane);
-                                       intel_finish_page_flip(dev, pipe);
-                                       flip_mask &= ~flip[plane];
-                               }
-                       }
+                           i915_handle_vblank(dev, plane, pipe, iir))
+                               flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane);
 
                        if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
                                blc_event = true;
@@ -2513,6 +2735,8 @@ static void i915_irq_uninstall(struct drm_device * dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe;
 
+       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
                I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -2564,13 +2788,13 @@ static int i965_irq_postinstall(struct drm_device *dev)
                               I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
 
        enable_mask = ~dev_priv->irq_mask;
+       enable_mask &= ~(I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
+                        I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT);
        enable_mask |= I915_USER_INTERRUPT;
 
        if (IS_G4X(dev))
                enable_mask |= I915_BSD_USER_INTERRUPT;
 
-       dev_priv->pipestat[0] = 0;
-       dev_priv->pipestat[1] = 0;
        i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
 
        /*
@@ -2600,45 +2824,33 @@ static int i965_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
-static void i965_hpd_irq_setup(struct drm_device *dev)
+static void i915_hpd_irq_setup(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *intel_encoder;
        u32 hotplug_en;
 
-       /* Note HDMI and DP share hotplug bits */
-       hotplug_en = 0;
-       if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS)
-               hotplug_en |= PORTB_HOTPLUG_INT_EN;
-       if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS)
-               hotplug_en |= PORTC_HOTPLUG_INT_EN;
-       if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS)
-               hotplug_en |= PORTD_HOTPLUG_INT_EN;
-       if (IS_G4X(dev)) {
-               if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X)
-                       hotplug_en |= SDVOC_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_G4X)
-                       hotplug_en |= SDVOB_HOTPLUG_INT_EN;
-       } else {
-               if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I965)
-                       hotplug_en |= SDVOC_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I965)
-                       hotplug_en |= SDVOB_HOTPLUG_INT_EN;
-       }
-       if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
-               hotplug_en |= CRT_HOTPLUG_INT_EN;
-
+       if (I915_HAS_HOTPLUG(dev)) {
+               hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+               hotplug_en &= ~HOTPLUG_INT_EN_MASK;
+               /* Note HDMI and DP share hotplug bits */
+               /* enable bits are the same for all generations */
+               list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
+                       if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
+                               hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin];
                /* Programming the CRT detection parameters tends
                   to generate a spurious hotplug event about three
                   seconds later.  So just do it once.
-                  */
+               */
                if (IS_G4X(dev))
                        hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
+               hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK;
                hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
-       }
-
-       /* Ignore TV since it's buggy */
 
-       I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
+               /* Ignore TV since it's buggy */
+               I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
+       }
 }
 
 static irqreturn_t i965_irq_handler(void *arg)
@@ -2649,6 +2861,9 @@ static irqreturn_t i965_irq_handler(void *arg)
        u32 pipe_stats[I915_MAX_PIPES];
        int irq_received;
        int pipe;
+       u32 flip_mask =
+               I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
+               I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 
        atomic_inc(&dev_priv->irq_received);
 
@@ -2657,7 +2872,7 @@ static irqreturn_t i965_irq_handler(void *arg)
        for (;;) {
                bool blc_event = false;
 
-               irq_received = iir != 0;
+               irq_received = (iir & ~flip_mask) != 0;
 
                /* Can't rely on pipestat interrupt bit in iir as it might
                 * have been cleared after the pipestat interrupt was received.
@@ -2691,18 +2906,24 @@ static irqreturn_t i965_irq_handler(void *arg)
                /* Consume port.  Then clear IIR or we'll miss events */
                if (iir & I915_DISPLAY_PORT_INTERRUPT) {
                        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
+                       u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ?
+                                                                 HOTPLUG_INT_STATUS_G4X :
+                                                                 HOTPLUG_INT_STATUS_I965);
 
                        DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
                                  hotplug_status);
-                       if (hotplug_status & dev_priv->hotplug_supported_mask)
+                       if (hotplug_trigger) {
+                               if (hotplug_irq_storm_detect(dev, hotplug_trigger,
+                                                           IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965))
+                                       i915_hpd_irq_setup(dev);
                                queue_work(dev_priv->wq,
                                           &dev_priv->hotplug_work);
-
+                       }
                        I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
                        I915_READ(PORT_HOTPLUG_STAT);
                }
 
-               I915_WRITE(IIR, iir);
+               I915_WRITE(IIR, iir & ~flip_mask);
                new_iir = I915_READ(IIR); /* Flush posted writes */
 
                if (iir & I915_USER_INTERRUPT)
@@ -2710,18 +2931,10 @@ static irqreturn_t i965_irq_handler(void *arg)
                if (iir & I915_BSD_USER_INTERRUPT)
                        notify_ring(dev, &dev_priv->ring[VCS]);
 
-               if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT)
-                       intel_prepare_page_flip(dev, 0);
-
-               if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT)
-                       intel_prepare_page_flip(dev, 1);
-
                for_each_pipe(pipe) {
                        if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
-                           drm_handle_vblank(dev, pipe)) {
-                               i915_pageflip_stall_check(dev, pipe);
-                               intel_finish_page_flip(dev, pipe);
-                       }
+                           i915_handle_vblank(dev, pipe, pipe, iir))
+                               flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe);
 
                        if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
                                blc_event = true;
@@ -2762,6 +2975,8 @@ static void i965_irq_uninstall(struct drm_device * dev)
        if (!dev_priv)
                return;
 
+       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
@@ -2777,6 +2992,40 @@ static void i965_irq_uninstall(struct drm_device * dev)
        I915_WRITE(IIR, I915_READ(IIR));
 }
 
+static void i915_reenable_hotplug_timer_func(unsigned long data)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *)data;
+       struct drm_device *dev = dev_priv->dev;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       int i;
+
+       lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
+       for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) {
+               struct drm_connector *connector;
+
+               if (dev_priv->hpd_stats[i].hpd_mark != HPD_DISABLED)
+                       continue;
+
+               dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED;
+
+               list_for_each_entry(connector, &mode_config->connector_list, head) {
+                       struct intel_connector *intel_connector = to_intel_connector(connector);
+
+                       if (intel_connector->encoder->hpd_pin == i) {
+                               if (connector->polled != intel_connector->polled)
+                                       DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n",
+                                                        drm_get_connector_name(connector));
+                               connector->polled = intel_connector->polled;
+                               if (!connector->polled)
+                                       connector->polled = DRM_CONNECTOR_POLL_HPD;
+                       }
+               }
+       }
+       if (dev_priv->display.hpd_irq_setup)
+               dev_priv->display.hpd_irq_setup(dev);
+       lockmgr(&dev_priv->irq_lock, LK_RELEASE);
+}
+
 void intel_irq_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2789,6 +3038,8 @@ void intel_irq_init(struct drm_device *dev)
        setup_timer(&dev_priv->gpu_error.hangcheck_timer,
                    i915_hangcheck_elapsed,
                    (unsigned long) dev);
+       setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func,
+                   (unsigned long) dev_priv);
 
        pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
 
@@ -2812,7 +3063,7 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->irq_uninstall = valleyview_irq_uninstall;
                dev->driver->enable_vblank = valleyview_enable_vblank;
                dev->driver->disable_vblank = valleyview_disable_vblank;
-               dev_priv->display.hpd_irq_setup = valleyview_hpd_irq_setup;
+               dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
        } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
                /* Share pre & uninstall handlers with ILK/SNB */
                dev->driver->irq_handler = ivybridge_irq_handler;
@@ -2821,6 +3072,7 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->irq_uninstall = ironlake_irq_uninstall;
                dev->driver->enable_vblank = ivybridge_enable_vblank;
                dev->driver->disable_vblank = ivybridge_disable_vblank;
+               dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
        } else if (HAS_PCH_SPLIT(dev)) {
                dev->driver->irq_handler = ironlake_irq_handler;
                dev->driver->irq_preinstall = ironlake_irq_preinstall;
@@ -2828,6 +3080,7 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->irq_uninstall = ironlake_irq_uninstall;
                dev->driver->enable_vblank = ironlake_enable_vblank;
                dev->driver->disable_vblank = ironlake_disable_vblank;
+               dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
        } else {
                if (INTEL_INFO(dev)->gen == 2) {
                        dev->driver->irq_preinstall = i8xx_irq_preinstall;
@@ -2845,7 +3098,7 @@ void intel_irq_init(struct drm_device *dev)
                        dev->driver->irq_postinstall = i965_irq_postinstall;
                        dev->driver->irq_uninstall = i965_irq_uninstall;
                        dev->driver->irq_handler = i965_irq_handler;
-                       dev_priv->display.hpd_irq_setup = i965_hpd_irq_setup;
+                       dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
                }
                dev->driver->enable_vblank = i915_enable_vblank;
                dev->driver->disable_vblank = i915_disable_vblank;
@@ -2855,7 +3108,20 @@ void intel_irq_init(struct drm_device *dev)
 void intel_hpd_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_connector *connector;
+       int i;
 
+       for (i = 1; i < HPD_NUM_PINS; i++) {
+               dev_priv->hpd_stats[i].hpd_cnt = 0;
+               dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED;
+       }
+       list_for_each_entry(connector, &mode_config->connector_list, head) {
+               struct intel_connector *intel_connector = to_intel_connector(connector);
+               connector->polled = intel_connector->polled;
+               if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
+                       connector->polled = DRM_CONNECTOR_POLL_HPD;
+       }
        if (dev_priv->display.hpd_irq_setup)
                dev_priv->display.hpd_irq_setup(dev);
 }
index c91124f..2d6b62e 100644 (file)
@@ -46,8 +46,6 @@
 #define    SNB_GMCH_GGMS_MASK  0x3
 #define    SNB_GMCH_GMS_SHIFT   3 /* Graphics Mode Select */
 #define    SNB_GMCH_GMS_MASK    0x1f
-#define    IVB_GMCH_GMS_SHIFT   4
-#define    IVB_GMCH_GMS_MASK    0xf
 
 
 /* PCI config space */
@@ -91,6 +89,7 @@
 #define  GRDOM_FULL    (0<<2)
 #define  GRDOM_RENDER  (1<<2)
 #define  GRDOM_MEDIA   (3<<2)
+#define  GRDOM_MASK    (3<<2)
 #define  GRDOM_RESET_ENABLE (1<<0)
 
 #define GEN6_MBCUNIT_SNPCR     0x900c /* for LLC config */
 
 #define GAM_ECOCHK                     0x4090
 #define   ECOCHK_SNB_BIT               (1<<10)
+#define   HSW_ECOCHK_ARB_PRIO_SOL      (1<<6)
 #define   ECOCHK_PPGTT_CACHE64B                (0x3<<3)
 #define   ECOCHK_PPGTT_CACHE4B         (0x0<<3)
+#define   ECOCHK_PPGTT_GFDT_IVB                (0x1<<4)
+#define   ECOCHK_PPGTT_LLC_IVB         (0x1<<3)
+#define   ECOCHK_PPGTT_UC_HSW          (0x1<<3)
+#define   ECOCHK_PPGTT_WT_HSW          (0x2<<3)
+#define   ECOCHK_PPGTT_WB_HSW          (0x3<<3)
 
 #define GAC_ECO_BITS                   0x14090
+#define   ECOBITS_SNB_BIT              (1<<13)
 #define   ECOBITS_PPGTT_CACHE64B       (3<<8)
 #define   ECOBITS_PPGTT_CACHE4B                (0<<8)
 
 
 #define FENCE_REG_SANDYBRIDGE_0                0x100000
 #define   SANDYBRIDGE_FENCE_PITCH_SHIFT        32
+#define   GEN7_FENCE_MAX_PITCH_VAL     0x0800
 
 /* control register for cpu gtt access */
 #define TILECTL                                0x101000
 #define GEN7_ERR_INT   0x44040
 #define   ERR_INT_MMIO_UNCLAIMED (1<<13)
 
+#define FPGA_DBG               0x42300
+#define   FPGA_DBG_RM_NOCLAIM  (1<<31)
+
 #define DERRMR         0x44050
 
 /* GM45+ chicken bits -- debug workaround bits that may be required
 #define   I915_USER_INTERRUPT                          (1<<1)
 #define   I915_ASLE_INTERRUPT                          (1<<0)
 #define   I915_BSD_USER_INTERRUPT                      (1<<25)
+#define   DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */
 #define EIR            0x020b0
 #define EMR            0x020b4
 #define ESR            0x020b8
 
 #define MCHBAR_MIRROR_BASE_SNB 0x140000
 
+/* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */
+#define DCLK 0x5e04
+
 /** 915-945 and GM965 MCH register controlling DRAM channel access */
 #define DCC                    0x10200
 #define DCC_ADDRESSING_MODE_SINGLE_CHANNEL             (0 << 0)
 #define   SDVOC_HOTPLUG_INT_EN                 (1 << 25)
 #define   TV_HOTPLUG_INT_EN                    (1 << 18)
 #define   CRT_HOTPLUG_INT_EN                   (1 << 9)
+#define HOTPLUG_INT_EN_MASK                    (PORTB_HOTPLUG_INT_EN | \
+                                                PORTC_HOTPLUG_INT_EN | \
+                                                PORTD_HOTPLUG_INT_EN | \
+                                                SDVOC_HOTPLUG_INT_EN | \
+                                                SDVOB_HOTPLUG_INT_EN | \
+                                                CRT_HOTPLUG_INT_EN)
 #define   CRT_HOTPLUG_FORCE_DETECT             (1 << 3)
 #define CRT_HOTPLUG_ACTIVATION_PERIOD_32       (0 << 8)
 /* must use period 64 on GM45 according to docs */
 #define   SDVOB_HOTPLUG_INT_STATUS_I965                (3 << 2)
 #define   SDVOC_HOTPLUG_INT_STATUS_I915                (1 << 7)
 #define   SDVOB_HOTPLUG_INT_STATUS_I915                (1 << 6)
-
-/* SDVO port control */
-#define SDVOB                  0x61140
-#define SDVOC                  0x61160
-#define   SDVO_ENABLE          (1 << 31)
-#define   SDVO_PIPE_B_SELECT   (1 << 30)
-#define   SDVO_STALL_SELECT    (1 << 29)
-#define   SDVO_INTERRUPT_ENABLE        (1 << 26)
+#define   HOTPLUG_INT_STATUS_G4X               (CRT_HOTPLUG_INT_STATUS | \
+                                                SDVOB_HOTPLUG_INT_STATUS_G4X | \
+                                                SDVOC_HOTPLUG_INT_STATUS_G4X | \
+                                                PORTB_HOTPLUG_INT_STATUS | \
+                                                PORTC_HOTPLUG_INT_STATUS | \
+                                                PORTD_HOTPLUG_INT_STATUS)
+
+#define HOTPLUG_INT_STATUS_I965                        (CRT_HOTPLUG_INT_STATUS | \
+                                                SDVOB_HOTPLUG_INT_STATUS_I965 | \
+                                                SDVOC_HOTPLUG_INT_STATUS_I965 | \
+                                                PORTB_HOTPLUG_INT_STATUS | \
+                                                PORTC_HOTPLUG_INT_STATUS | \
+                                                PORTD_HOTPLUG_INT_STATUS)
+
+#define HOTPLUG_INT_STATUS_I915                        (CRT_HOTPLUG_INT_STATUS | \
+                                                SDVOB_HOTPLUG_INT_STATUS_I915 | \
+                                                SDVOC_HOTPLUG_INT_STATUS_I915 | \
+                                                PORTB_HOTPLUG_INT_STATUS | \
+                                                PORTC_HOTPLUG_INT_STATUS | \
+                                                PORTD_HOTPLUG_INT_STATUS)
+
+/* SDVO and HDMI port control.
+ * The same register may be used for SDVO or HDMI */
+#define GEN3_SDVOB     0x61140
+#define GEN3_SDVOC     0x61160
+#define GEN4_HDMIB     GEN3_SDVOB
+#define GEN4_HDMIC     GEN3_SDVOC
+#define PCH_SDVOB      0xe1140
+#define PCH_HDMIB      PCH_SDVOB
+#define PCH_HDMIC      0xe1150
+#define PCH_HDMID      0xe1160
+
+/* Gen 3 SDVO bits: */
+#define   SDVO_ENABLE                          (1 << 31)
+#define   SDVO_PIPE_SEL(pipe)                  ((pipe) << 30)
+#define   SDVO_PIPE_SEL_MASK                   (1 << 30)
+#define   SDVO_PIPE_B_SELECT                   (1 << 30)
+#define   SDVO_STALL_SELECT                    (1 << 29)
+#define   SDVO_INTERRUPT_ENABLE                        (1 << 26)
 /**
  * 915G/GM SDVO pixel multiplier.
- *
  * Programmed value is multiplier - 1, up to 5x.
- *
  * \sa DPLL_MD_UDI_MULTIPLIER_MASK
  */
-#define   SDVO_PORT_MULTIPLY_MASK      (7 << 23)
+#define   SDVO_PORT_MULTIPLY_MASK              (7 << 23)
 #define   SDVO_PORT_MULTIPLY_SHIFT             23
-#define   SDVO_PHASE_SELECT_MASK       (15 << 19)
-#define   SDVO_PHASE_SELECT_DEFAULT    (6 << 19)
-#define   SDVO_CLOCK_OUTPUT_INVERT     (1 << 18)
-#define   SDVOC_GANG_MODE              (1 << 16)
-#define   SDVO_ENCODING_SDVO           (0x0 << 10)
-#define   SDVO_ENCODING_HDMI           (0x2 << 10)
-/** Requird for HDMI operation */
-#define   SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9)
-#define   SDVO_COLOR_RANGE_16_235      (1 << 8)
-#define   SDVO_BORDER_ENABLE           (1 << 7)
-#define   SDVO_AUDIO_ENABLE            (1 << 6)
-/** New with 965, default is to be set */
-#define   SDVO_VSYNC_ACTIVE_HIGH       (1 << 4)
-/** New with 965, default is to be set */
-#define   SDVO_HSYNC_ACTIVE_HIGH       (1 << 3)
-#define   SDVOB_PCIE_CONCURRENCY       (1 << 3)
-#define   SDVO_DETECTED                        (1 << 2)
+#define   SDVO_PHASE_SELECT_MASK               (15 << 19)
+#define   SDVO_PHASE_SELECT_DEFAULT            (6 << 19)
+#define   SDVO_CLOCK_OUTPUT_INVERT             (1 << 18)
+#define   SDVOC_GANG_MODE                      (1 << 16) /* Port C only */
+#define   SDVO_BORDER_ENABLE                   (1 << 7) /* SDVO only */
+#define   SDVOB_PCIE_CONCURRENCY               (1 << 3) /* Port B only */
+#define   SDVO_DETECTED                                (1 << 2)
 /* Bits to be preserved when writing */
-#define   SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26))
-#define   SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26))
+#define   SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | \
+                              SDVO_INTERRUPT_ENABLE)
+#define   SDVOC_PRESERVE_MASK ((1 << 17) | SDVO_INTERRUPT_ENABLE)
+
+/* Gen 4 SDVO/HDMI bits: */
+#define   SDVO_COLOR_FORMAT_8bpc               (0 << 26)
+#define   SDVO_ENCODING_SDVO                   (0 << 10)
+#define   SDVO_ENCODING_HDMI                   (2 << 10)
+#define   HDMI_MODE_SELECT_HDMI                        (1 << 9) /* HDMI only */
+#define   HDMI_MODE_SELECT_DVI                 (0 << 9) /* HDMI only */
+#define   HDMI_COLOR_RANGE_16_235              (1 << 8) /* HDMI only */
+#define   SDVO_AUDIO_ENABLE                    (1 << 6)
+/* VSYNC/HSYNC bits new with 965, default is to be set */
+#define   SDVO_VSYNC_ACTIVE_HIGH               (1 << 4)
+#define   SDVO_HSYNC_ACTIVE_HIGH               (1 << 3)
+
+/* Gen 5 (IBX) SDVO/HDMI bits: */
+#define   HDMI_COLOR_FORMAT_12bpc              (3 << 26) /* HDMI only */
+#define   SDVOB_HOTPLUG_ENABLE                 (1 << 23) /* SDVO only */
+
+/* Gen 6 (CPT) SDVO/HDMI bits: */
+#define   SDVO_PIPE_SEL_CPT(pipe)              ((pipe) << 29)
+#define   SDVO_PIPE_SEL_MASK_CPT               (3 << 29)
+
 
 /* DVO port control */
 #define DVOA                   0x61120
 #define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238)
 
 /* Backlight control */
-#define BLC_PWM_CTL2           0x61250 /* 965+ only */
+#define BLC_PWM_CTL2   (dev_priv->info->display_mmio_offset + 0x61250) /* 965+ only */
 #define   BLM_PWM_ENABLE               (1 << 31)
 #define   BLM_COMBINATION_MODE         (1 << 30) /* gen4 only */
 #define   BLM_PIPE_SELECT              (1 << 29)
 #define   BLM_PHASE_IN_COUNT_MASK      (0xff << 8)
 #define   BLM_PHASE_IN_INCR_SHIFT      (0)
 #define   BLM_PHASE_IN_INCR_MASK       (0xff << 0)
-#define BLC_PWM_CTL            0x61254
+#define BLC_PWM_CTL    (dev_priv->info->display_mmio_offset + 0x61254)
 /*
  * This is the most significant 15 bits of the number of backlight cycles in a
  * complete cycle of the modulated backlight control.
 #define   BACKLIGHT_DUTY_CYCLE_MASK_PNV                (0xfffe)
 #define   BLM_POLARITY_PNV                     (1 << 0) /* pnv only */
 
-#define BLC_HIST_CTL           0x61260
+#define BLC_HIST_CTL   (dev_priv->info->display_mmio_offset + 0x61260)
 
 /* New registers for PCH-split platforms. Safe where new bits show up, the
  * register layout machtes with gen4 BLC_PWM_CTL[12]. */
 #define _PIPEB_GMCH_DATA_M                     0x71050
 
 /* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */
-#define   PIPE_GMCH_DATA_M_TU_SIZE_MASK                (0x3f << 25)
-#define   PIPE_GMCH_DATA_M_TU_SIZE_SHIFT       25
+#define  TU_SIZE(x)             (((x)-1) << 25) /* default size 64 */
+#define  TU_SIZE_MASK           (0x3f << 25)
 
-#define   PIPE_GMCH_DATA_M_MASK                        (0xffffff)
+#define  DATA_LINK_M_N_MASK    (0xffffff)
+#define  DATA_LINK_N_MAX       (0x800000)
 
 #define _PIPEA_GMCH_DATA_N                     0x70054
 #define _PIPEB_GMCH_DATA_N                     0x71054
-#define   PIPE_GMCH_DATA_N_MASK                        (0xffffff)
 
 /*
  * Computing Link M and N values for the Display Port link
 
 #define _PIPEA_DP_LINK_M                               0x70060
 #define _PIPEB_DP_LINK_M                               0x71060
-#define   PIPEA_DP_LINK_M_MASK                 (0xffffff)
 
 #define _PIPEA_DP_LINK_N                               0x70064
 #define _PIPEB_DP_LINK_N                               0x71064
-#define   PIPEA_DP_LINK_N_MASK                 (0xffffff)
 
 #define PIPE_GMCH_DATA_M(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_M, _PIPEB_GMCH_DATA_M)
 #define PIPE_GMCH_DATA_N(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_N, _PIPEB_GMCH_DATA_N)
 #define   DSPFW_HPLL_CURSOR_SHIFT      16
 #define   DSPFW_HPLL_CURSOR_MASK       (0x3f<<16)
 #define   DSPFW_HPLL_SR_MASK           (0x1ff)
+#define DSPFW4                 (dev_priv->info->display_mmio_offset + 0x70070)
+#define DSPFW7                 (dev_priv->info->display_mmio_offset + 0x7007c)
 
 /* drain latency register values*/
 #define DRAIN_LATENCY_PRECISION_32     32
 #define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC)
 #define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE)
 
+#define _SPACNTR               0x72180
+#define   SP_ENABLE                    (1<<31)
+#define   SP_GEAMMA_ENABLE             (1<<30)
+#define   SP_PIXFORMAT_MASK            (0xf<<26)
+#define   SP_FORMAT_YUV422             (0<<26)
+#define   SP_FORMAT_BGR565             (5<<26)
+#define   SP_FORMAT_BGRX8888           (6<<26)
+#define   SP_FORMAT_BGRA8888           (7<<26)
+#define   SP_FORMAT_RGBX1010102                (8<<26)
+#define   SP_FORMAT_RGBA1010102                (9<<26)
+#define   SP_FORMAT_RGBX8888           (0xe<<26)
+#define   SP_FORMAT_RGBA8888           (0xf<<26)
+#define   SP_SOURCE_KEY                        (1<<22)
+#define   SP_YUV_BYTE_ORDER_MASK       (3<<16)
+#define   SP_YUV_ORDER_YUYV            (0<<16)
+#define   SP_YUV_ORDER_UYVY            (1<<16)
+#define   SP_YUV_ORDER_YVYU            (2<<16)
+#define   SP_YUV_ORDER_VYUY            (3<<16)
+#define   SP_TILED                     (1<<10)
+#define _SPALINOFF             0x72184
+#define _SPASTRIDE             0x72188
+#define _SPAPOS                        0x7218c
+#define _SPASIZE               0x72190
+#define _SPAKEYMINVAL          0x72194
+#define _SPAKEYMSK             0x72198
+#define _SPASURF               0x7219c
+#define _SPAKEYMAXVAL          0x721a0
+#define _SPATILEOFF            0x721a4
+#define _SPACONSTALPHA         0x721a8
+#define _SPAGAMC               0x721f4
+
+#define _SPBCNTR               0x72280
+#define _SPBLINOFF             0x72284
+#define _SPBSTRIDE             0x72288
+#define _SPBPOS                        0x7228c
+#define _SPBSIZE               0x72290
+#define _SPBKEYMINVAL          0x72294
+#define _SPBKEYMSK             0x72298
+#define _SPBSURF               0x7229c
+#define _SPBKEYMAXVAL          0x722a0
+#define _SPBTILEOFF            0x722a4
+#define _SPBCONSTALPHA         0x722a8
+#define _SPBGAMC               0x722f4
+
+#define SPCNTR(pipe, plane) _PIPE(pipe * 2 + plane, _SPACNTR, _SPBCNTR)
+#define SPLINOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPALINOFF, _SPBLINOFF)
+#define SPSTRIDE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASTRIDE, _SPBSTRIDE)
+#define SPPOS(pipe, plane) _PIPE(pipe * 2 + plane, _SPAPOS, _SPBPOS)
+#define SPSIZE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASIZE, _SPBSIZE)
+#define SPKEYMINVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMINVAL, _SPBKEYMINVAL)
+#define SPKEYMSK(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMSK, _SPBKEYMSK)
+#define SPSURF(pipe, plane) _PIPE(pipe * 2 + plane, _SPASURF, _SPBSURF)
+#define SPKEYMAXVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMAXVAL, _SPBKEYMAXVAL)
+#define SPTILEOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPATILEOFF, _SPBTILEOFF)
+#define SPCONSTALPHA(pipe, plane) _PIPE(pipe * 2 + plane, _SPACONSTALPHA, _SPBCONSTALPHA)
+#define SPGAMC(pipe, plane) _PIPE(pipe * 2 + plane, _SPAGAMC, _SPBGAMC)
+
 /* VBIOS regs */
 #define VGACNTRL               0x71400
 # define VGA_DISP_DISABLE                      (1 << 31)
 
 
 #define _PIPEA_DATA_M1           (dev_priv->info->display_mmio_offset + 0x60030)
-#define  TU_SIZE(x)             (((x)-1) << 25) /* default size 64 */
-#define  TU_SIZE_MASK           0x7e000000
 #define  PIPE_DATA_M1_OFFSET    0
 #define _PIPEA_DATA_N1           (dev_priv->info->display_mmio_offset + 0x60034)
 #define  PIPE_DATA_N1_OFFSET    0
 #define DISP_ARB_CTL   0x45000
 #define  DISP_TILE_SURFACE_SWIZZLING   (1<<13)
 #define  DISP_FBC_WM_DIS               (1<<15)
+#define GEN7_MSG_CTL   0x45010
+#define  WAIT_FOR_PCH_RESET_ACK                (1<<1)
+#define  WAIT_FOR_PCH_FLR_ACK          (1<<0)
 
 /* GEN7 chicken */
 #define GEN7_COMMON_SLICE_CHICKEN1             0x7010
 #define SDE_PORTC_HOTPLUG       (1 << 9)
 #define SDE_PORTB_HOTPLUG       (1 << 8)
 #define SDE_SDVOB_HOTPLUG       (1 << 6)
-#define SDE_HOTPLUG_MASK       (0xf << 8)
+#define SDE_HOTPLUG_MASK        (SDE_CRT_HOTPLUG | \
+                                SDE_SDVOB_HOTPLUG |    \
+                                SDE_PORTB_HOTPLUG |    \
+                                SDE_PORTC_HOTPLUG |    \
+                                SDE_PORTD_HOTPLUG)
 #define SDE_TRANSB_CRC_DONE    (1 << 5)
 #define SDE_TRANSB_CRC_ERR     (1 << 4)
 #define SDE_TRANSB_FIFO_UNDER  (1 << 3)
 #define SDE_PORTC_HOTPLUG_CPT  (1 << 22)
 #define SDE_PORTB_HOTPLUG_CPT  (1 << 21)
 #define SDE_CRT_HOTPLUG_CPT    (1 << 19)
+#define SDE_SDVOB_HOTPLUG_CPT  (1 << 18)
 #define SDE_HOTPLUG_MASK_CPT   (SDE_CRT_HOTPLUG_CPT |          \
+                                SDE_SDVOB_HOTPLUG_CPT |        \
                                 SDE_PORTD_HOTPLUG_CPT |        \
                                 SDE_PORTC_HOTPLUG_CPT |        \
                                 SDE_PORTB_HOTPLUG_CPT)
 #define HSW_VIDEO_DIP_VSC_ECC_B                0x61344
 #define HSW_VIDEO_DIP_GCP_B            0x61210
 
-#define HSW_TVIDEO_DIP_CTL(pipe) \
-        _PIPE(pipe, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B)
-#define HSW_TVIDEO_DIP_AVI_DATA(pipe) \
-        _PIPE(pipe, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B)
-#define HSW_TVIDEO_DIP_SPD_DATA(pipe) \
-        _PIPE(pipe, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B)
-#define HSW_TVIDEO_DIP_GCP(pipe) \
-       _PIPE(pipe, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B)
+#define HSW_TVIDEO_DIP_CTL(trans) \
+        _TRANSCODER(trans, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B)
+#define HSW_TVIDEO_DIP_AVI_DATA(trans) \
+        _TRANSCODER(trans, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B)
+#define HSW_TVIDEO_DIP_SPD_DATA(trans) \
+        _TRANSCODER(trans, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B)
+#define HSW_TVIDEO_DIP_GCP(trans) \
+       _TRANSCODER(trans, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B)
+#define HSW_TVIDEO_DIP_VSC_DATA(trans) \
+        _TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B)
 
 #define _TRANS_HTOTAL_B          0xe1000
 #define _TRANS_HBLANK_B          0xe1004
 #define _TRANSA_CHICKEN2        0xf0064
 #define _TRANSB_CHICKEN2        0xf1064
 #define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2)
-#define  TRANS_CHICKEN2_TIMING_OVERRIDE                (1<<31)
-#define  TRANS_CHICKEN2_FDI_POLARITY_REVERSED  (1<<29)
+#define  TRANS_CHICKEN2_TIMING_OVERRIDE                        (1<<31)
+#define  TRANS_CHICKEN2_FDI_POLARITY_REVERSED          (1<<29)
+#define  TRANS_CHICKEN2_FRAME_START_DELAY_MASK         (3<<27)
+#define  TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER     (1<<26)
+#define  TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH  (1<<25)
 
 #define SOUTH_CHICKEN1         0xc2000
 #define  FDIA_PHASE_SYNC_SHIFT_OVR     19
 #define FDI_PLL_CTL_1           0xfe000
 #define FDI_PLL_CTL_2           0xfe004
 
-/* or SDVOB */
-#define HDMIB   0xe1140
-#define  PORT_ENABLE    (1 << 31)
-#define  TRANSCODER(pipe)       ((pipe) << 30)
-#define  TRANSCODER_CPT(pipe)   ((pipe) << 29)
-#define  TRANSCODER_MASK        (1 << 30)
-#define  TRANSCODER_MASK_CPT    (3 << 29)
-#define  COLOR_FORMAT_8bpc      (0)
-#define  COLOR_FORMAT_12bpc     (3 << 26)
-#define  SDVOB_HOTPLUG_ENABLE   (1 << 23)
-#define  SDVO_ENCODING          (0)
-#define  TMDS_ENCODING          (2 << 10)
-#define  NULL_PACKET_VSYNC_ENABLE       (1 << 9)
-/* CPT */
-#define  HDMI_MODE_SELECT      (1 << 9)
-#define  DVI_MODE_SELECT       (0)
-#define  SDVOB_BORDER_ENABLE    (1 << 7)
-#define  AUDIO_ENABLE           (1 << 6)
-#define  VSYNC_ACTIVE_HIGH      (1 << 4)
-#define  HSYNC_ACTIVE_HIGH      (1 << 3)
-#define  PORT_DETECTED          (1 << 2)
-
-/* PCH SDVOB multiplex with HDMIB */
-#define PCH_SDVOB      HDMIB
-
-#define HDMIC   0xe1150
-#define HDMID   0xe1160
-
 #define PCH_LVDS       0xe1180
 #define  LVDS_DETECTED (1 << 1)
 
 #define PIPEB_PP_OFF_DELAYS     (VLV_DISPLAY_BASE + 0x6130c)
 #define PIPEB_PP_DIVISOR        (VLV_DISPLAY_BASE + 0x61310)
 
+#define VLV_PIPE_PP_STATUS(pipe) _PIPE(pipe, PIPEA_PP_STATUS, PIPEB_PP_STATUS)
+#define VLV_PIPE_PP_CONTROL(pipe) _PIPE(pipe, PIPEA_PP_CONTROL, PIPEB_PP_CONTROL)
+#define VLV_PIPE_PP_ON_DELAYS(pipe) \
+               _PIPE(pipe, PIPEA_PP_ON_DELAYS, PIPEB_PP_ON_DELAYS)
+#define VLV_PIPE_PP_OFF_DELAYS(pipe) \
+               _PIPE(pipe, PIPEA_PP_OFF_DELAYS, PIPEB_PP_OFF_DELAYS)
+#define VLV_PIPE_PP_DIVISOR(pipe) \
+               _PIPE(pipe, PIPEA_PP_DIVISOR, PIPEB_PP_DIVISOR)
+
 #define PCH_PP_STATUS          0xc7200
 #define PCH_PP_CONTROL         0xc7204
 #define  PANEL_UNLOCK_REGS     (0xabcd << 16)
 #define  FORCEWAKE                             0xA18C
 #define  FORCEWAKE_VLV                         0x1300b0
 #define  FORCEWAKE_ACK_VLV                     0x1300b4
+#define  FORCEWAKE_MEDIA_VLV                   0x1300b8
+#define  FORCEWAKE_ACK_MEDIA_VLV               0x1300bc
 #define  FORCEWAKE_ACK_HSW                     0x130044
 #define  FORCEWAKE_ACK                         0x130090
+#define  VLV_GTLC_WAKE_CTRL                    0x130090
+#define  VLV_GTLC_PW_STATUS                    0x130094
 #define  FORCEWAKE_MT                          0xa188 /* multi-threaded */
 #define   FORCEWAKE_KERNEL                     0x1
 #define   FORCEWAKE_USER                       0x2
 #define GEN6_RPNSWREQ                          0xA008
 #define   GEN6_TURBO_DISABLE                   (1<<31)
 #define   GEN6_FREQUENCY(x)                    ((x)<<25)
+#define   HSW_FREQUENCY(x)                     ((x)<<24)
 #define   GEN6_OFFSET(x)                       ((x)<<19)
 #define   GEN6_AGGRESSIVE_TURBO                        (0<<15)
 #define GEN6_RC_VIDEO_FREQ                     0xA00C
 #define   GEN6_DECODE_RC6_VID(vids)            (((vids) * 5) + 245)
 #define GEN6_PCODE_DATA                                0x138128
 #define   GEN6_PCODE_FREQ_IA_RATIO_SHIFT       8
+#define   GEN6_PCODE_FREQ_RING_RATIO_SHIFT     16
+
+#define VLV_IOSF_DOORBELL_REQ                  0x182100
+#define   IOSF_DEVFN_SHIFT                     24
+#define   IOSF_OPCODE_SHIFT                    16
+#define   IOSF_PORT_SHIFT                      8
+#define   IOSF_BYTE_ENABLES_SHIFT              4
+#define   IOSF_BAR_SHIFT                       1
+#define   IOSF_SB_BUSY                         (1<<0)
+#define   IOSF_PORT_PUNIT                      0x4
+#define VLV_IOSF_DATA                          0x182104
+#define VLV_IOSF_ADDR                          0x182108
+
+#define PUNIT_OPCODE_REG_READ                  6
+#define PUNIT_OPCODE_REG_WRITE                 7
 
 #define GEN6_GT_CORE_STATUS            0x138060
 #define   GEN6_CORE_CPD_STATE_MASK     (7<<4)
index 2135f21..369b3d8 100644 (file)
@@ -209,7 +209,8 @@ static void i915_save_display(struct drm_device *dev)
                dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2);
                dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL);
                dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2);
-               dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS);
+               if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
+                       dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS);
        } else {
                dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL);
                dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
@@ -255,6 +256,7 @@ static void i915_save_display(struct drm_device *dev)
 static void i915_restore_display(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 mask = 0xffffffff;
 
        /* Display arbitration */
        if (INTEL_INFO(dev)->gen <= 4)
@@ -267,10 +269,13 @@ static void i915_restore_display(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
                I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
 
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS);
-       } else if (IS_MOBILE(dev) && !IS_I830(dev))
-               I915_WRITE(LVDS, dev_priv->regfile.saveLVDS);
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               mask = ~LVDS_PORT_EN;
+
+       if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
+               I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS & mask);
+       else if (INTEL_INFO(dev)->gen <= 4 && IS_MOBILE(dev) && !IS_I830(dev))
+               I915_WRITE(LVDS, dev_priv->regfile.saveLVDS & mask);
 
        if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev))
                I915_WRITE(PFIT_CONTROL, dev_priv->regfile.savePFIT_CONTROL);
@@ -379,6 +384,7 @@ int i915_restore_state(struct drm_device *dev)
 
        mutex_lock(&dev->struct_mutex);
 
+       i915_gem_restore_fences(dev);
        i915_restore_display(dev);
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
index 9df14ba..8c26912 100644 (file)
@@ -695,6 +695,9 @@ intel_parse_bios(struct drm_device *dev)
        struct bdb_header *bdb = NULL;
        u8 __iomem *bios = NULL;
 
+       if (HAS_PCH_NOP(dev))
+               return -ENODEV;
+
        init_vbt_defaults(dev_priv);
 
        /* XXX Should this validation be moved to intel_opregion.c? */
index 601e0b6..d5be38e 100644 (file)
@@ -196,10 +196,14 @@ static int intel_crt_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
-static bool intel_crt_mode_fixup(struct drm_encoder *encoder,
-                                const struct drm_display_mode *mode,
-                                struct drm_display_mode *adjusted_mode)
+static bool intel_crt_compute_config(struct intel_encoder *encoder,
+                                    struct intel_crtc_config *pipe_config)
 {
+       struct drm_device *dev = encoder->base.dev;
+
+       if (HAS_PCH_SPLIT(dev))
+               pipe_config->has_pch_encoder = true;
+
        return true;
 }
 
@@ -675,7 +679,6 @@ static void intel_crt_reset(struct drm_connector *connector)
  */
 
 static const struct drm_encoder_helper_funcs crt_encoder_funcs = {
-       .mode_fixup = intel_crt_mode_fixup,
        .mode_set = intel_crt_mode_set,
        .disable = intel_encoder_noop,
 };
@@ -769,8 +772,11 @@ void intel_crt_init(struct drm_device *dev)
        else
                crt->adpa_reg = ADPA;
 
+       crt->base.compute_config = intel_crt_compute_config;
        crt->base.disable = intel_disable_crt;
        crt->base.enable = intel_enable_crt;
+       if (I915_HAS_HOTPLUG(dev))
+               crt->base.hpd_pin = HPD_CRT;
        if (HAS_DDI(dev))
                crt->base.get_hw_state = intel_ddi_get_hw_state;
        else
@@ -784,18 +790,14 @@ void intel_crt_init(struct drm_device *dev)
        drm_sysfs_connector_add(connector);
 #endif
 
-       if (I915_HAS_HOTPLUG(dev))
-               connector->polled = DRM_CONNECTOR_POLL_HPD;
-       else
-               connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+       if (!I915_HAS_HOTPLUG(dev))
+               intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
 
        /*
         * Configure the automatic hotplug detection stuff
         */
        crt->force_hotplug_required = 0;
 
-       dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
-
        /*
         * TODO: find a proper way to discover whether we need to set the the
         * polarity and link reversal bits or not, instead of relying on the
index 83a3fda..09ed817 100644 (file)
@@ -899,6 +899,9 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock)
                        plls->spll_refcount++;
                        reg = SPLL_CTL;
                        intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL;
+               } else {
+                       DRM_ERROR("SPLL already in use\n");
+                       return false;
                }
 
                WARN(I915_READ(reg) & SPLL_PLL_ENABLE,
@@ -922,14 +925,14 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = crtc->dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
-       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+       enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
        int type = intel_encoder->type;
        uint32_t temp;
 
        if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
 
                temp = TRANS_MSA_SYNC_CLK;
-               switch (intel_crtc->bpp) {
+               switch (intel_crtc->config.pipe_bpp) {
                case 18:
                        temp |= TRANS_MSA_6_BPC;
                        break;
@@ -943,22 +946,20 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
                        temp |= TRANS_MSA_12_BPC;
                        break;
                default:
-                       temp |= TRANS_MSA_8_BPC;
-                       WARN(1, "%d bpp unsupported by DDI function\n",
-                            intel_crtc->bpp);
+                       BUG();
                }
                I915_WRITE(TRANS_MSA_MISC(cpu_transcoder), temp);
        }
 }
 
-void intel_ddi_enable_pipe_func(struct drm_crtc *crtc)
+void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_i915_private *dev_priv = crtc->dev->dev_private;
        enum i915_pipe pipe = intel_crtc->pipe;
-       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+       enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
        enum port port = intel_ddi_get_encoder_port(intel_encoder);
        int type = intel_encoder->type;
        uint32_t temp;
@@ -967,7 +968,7 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc)
        temp = TRANS_DDI_FUNC_ENABLE;
        temp |= TRANS_DDI_SELECT_PORT(port);
 
-       switch (intel_crtc->bpp) {
+       switch (intel_crtc->config.pipe_bpp) {
        case 18:
                temp |= TRANS_DDI_BPC_6;
                break;
@@ -981,8 +982,7 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc)
                temp |= TRANS_DDI_BPC_12;
                break;
        default:
-               WARN(1, "%d bpp unsupported by transcoder DDI function\n",
-                    intel_crtc->bpp);
+               BUG();
        }
 
        if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
@@ -1151,7 +1151,7 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
 
        DRM_DEBUG_KMS("No pipe for ddi port %i found\n", port);
 
-       return true;
+       return false;
 }
 
 static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv,
@@ -1174,10 +1174,16 @@ static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv,
                                port = i;
        }
 
-       ret = I915_READ(PORT_CLK_SEL(port));
-
-       DRM_DEBUG_KMS("Pipe %c connected to port %c using clock 0x%08x\n",
-                     pipe_name(pipe), port_name(port), ret);
+       if (port == I915_MAX_PORTS) {
+               WARN(1, "Pipe %c enabled on an unknown port\n",
+                    pipe_name(pipe));
+               ret = PORT_CLK_SEL_NONE;
+       } else {
+               ret = I915_READ(PORT_CLK_SEL(port));
+               DRM_DEBUG_KMS("Pipe %c connected to port %c using clock "
+                             "0x%08x\n", pipe_name(pipe), port_name(port),
+                             ret);
+       }
 
        return ret;
 }
@@ -1218,7 +1224,7 @@ void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc)
        struct drm_i915_private *dev_priv = crtc->dev->dev_private;
        struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
        enum port port = intel_ddi_get_encoder_port(intel_encoder);
-       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+       enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
 
        if (cpu_transcoder != TRANSCODER_EDP)
                I915_WRITE(TRANS_CLK_SEL(cpu_transcoder),
@@ -1228,7 +1234,7 @@ void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc)
 void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc)
 {
        struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
-       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+       enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
 
        if (cpu_transcoder != TRANSCODER_EDP)
                I915_WRITE(TRANS_CLK_SEL(cpu_transcoder),
@@ -1260,6 +1266,8 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
                intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
                intel_dp_start_link_train(intel_dp);
                intel_dp_complete_link_train(intel_dp);
+               if (port != PORT_A)
+                       intel_dp_stop_link_train(intel_dp);
        }
 }
 
@@ -1321,6 +1329,9 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
        } else if (type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
+               if (port == PORT_A)
+                       intel_dp_stop_link_train(intel_dp);
+
                ironlake_edp_backlight_on(intel_dp);
        }
 
@@ -1342,15 +1353,15 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t tmp;
 
+       tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
+       tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4));
+       I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp);
+
        if (type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
                ironlake_edp_backlight_off(intel_dp);
        }
-
-       tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
-       tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4));
-       I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp);
 }
 
 int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv)
@@ -1468,19 +1479,17 @@ static void intel_ddi_destroy(struct drm_encoder *encoder)
        intel_dp_encoder_destroy(encoder);
 }
 
-static bool intel_ddi_mode_fixup(struct drm_encoder *encoder,
-                                const struct drm_display_mode *mode,
-                                struct drm_display_mode *adjusted_mode)
+static bool intel_ddi_compute_config(struct intel_encoder *encoder,
+                                    struct intel_crtc_config *pipe_config)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-       int type = intel_encoder->type;
+       int type = encoder->type;
 
-       WARN(type == INTEL_OUTPUT_UNKNOWN, "mode_fixup() on unknown output!\n");
+       WARN(type == INTEL_OUTPUT_UNKNOWN, "compute_config() on unknown output!\n");
 
        if (type == INTEL_OUTPUT_HDMI)
-               return intel_hdmi_mode_fixup(encoder, mode, adjusted_mode);
+               return intel_hdmi_compute_config(encoder, pipe_config);
        else
-               return intel_dp_mode_fixup(encoder, mode, adjusted_mode);
+               return intel_dp_compute_config(encoder, pipe_config);
 }
 
 static const struct drm_encoder_funcs intel_ddi_funcs = {
@@ -1488,7 +1497,6 @@ static const struct drm_encoder_funcs intel_ddi_funcs = {
 };
 
 static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = {
-       .mode_fixup = intel_ddi_mode_fixup,
        .mode_set = intel_ddi_mode_set,
        .disable = intel_encoder_noop,
 };
@@ -1531,6 +1539,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
                         DRM_MODE_ENCODER_TMDS);
        drm_encoder_helper_add(encoder, &intel_ddi_helper_funcs);
 
+       intel_encoder->compute_config = intel_ddi_compute_config;
        intel_encoder->enable = intel_enable_ddi;
        intel_encoder->pre_enable = intel_ddi_pre_enable;
        intel_encoder->disable = intel_disable_ddi;
@@ -1541,9 +1550,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
        intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) &
                                        DDI_BUF_PORT_REVERSAL;
        if (hdmi_connector)
-               intel_dig_port->hdmi.sdvox_reg = DDI_BUF_CTL(port);
-       else
-               intel_dig_port->hdmi.sdvox_reg = 0;
+               intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port);
        intel_dig_port->dp.output_reg = DDI_BUF_CTL(port);
 
        intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
index 729290a..9a4826e 100644 (file)
@@ -67,8 +67,24 @@ typedef struct intel_limit intel_limit_t;
 struct intel_limit {
        intel_range_t   dot, vco, n, m, m1, m2, p, p1;
        intel_p2_t          p2;
-       bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
-                       int, int, intel_clock_t *, intel_clock_t *);
+       /**
+        * find_pll() - Find the best values for the PLL
+        * @limit: limits for the PLL
+        * @crtc: current CRTC
+        * @target: target frequency in kHz
+        * @refclk: reference clock frequency in kHz
+        * @match_clock: if provided, @best_clock P divider must
+        *               match the P divider from @match_clock
+        *               used for LVDS downclocking
+        * @best_clock: best PLL values found
+        *
+        * Returns true on success, false on failure.
+        */
+       bool (*find_pll)(const intel_limit_t *limit,
+                        struct drm_crtc *crtc,
+                        int target, int refclk,
+                        intel_clock_t *match_clock,
+                        intel_clock_t *best_clock);
 };
 
 /* FDI */
@@ -467,7 +483,6 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
 
        if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
                if (intel_is_dual_link_lvds(dev)) {
-                       /* LVDS dual channel */
                        if (refclk == 100000)
                                limit = &intel_limits_ironlake_dual_lvds_100m;
                        else
@@ -494,10 +509,8 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
 
        if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
                if (intel_is_dual_link_lvds(dev))
-                       /* LVDS with dual channel */
                        limit = &intel_limits_g4x_dual_channel_lvds;
                else
-                       /* LVDS with dual channel */
                        limit = &intel_limits_g4x_single_channel_lvds;
        } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) ||
                   intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) {
@@ -876,7 +889,7 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       return intel_crtc->cpu_transcoder;
+       return intel_crtc->config.cpu_transcoder;
 }
 
 static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe)
@@ -1211,8 +1224,8 @@ void assert_pipe(struct drm_i915_private *dev_priv,
        if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
                state = true;
 
-       if (IS_HASWELL(dev_priv->dev) && cpu_transcoder != TRANSCODER_EDP &&
-           !(I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_ENABLE)) {
+       if (!intel_using_power_well(dev_priv->dev) &&
+           cpu_transcoder != TRANSCODER_EDP) {
                cur_state = false;
        } else {
                reg = PIPECONF(cpu_transcoder);
@@ -1251,7 +1264,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
        int cur_pipe;
 
        /* Planes are fixed to pipes on ILK+ */
-       if (HAS_PCH_SPLIT(dev_priv->dev)) {
+       if (HAS_PCH_SPLIT(dev_priv->dev) || IS_VALLEYVIEW(dev_priv->dev)) {
                reg = DSPCNTR(pipe);
                val = I915_READ(reg);
                WARN((val & DISPLAY_PLANE_ENABLE),
@@ -1272,6 +1285,25 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
        }
 }
 
+static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
+                                   enum i915_pipe pipe)
+{
+       int reg, i;
+       u32 val;
+
+       if (!IS_VALLEYVIEW(dev_priv->dev))
+               return;
+
+       /* Need to check both planes against the pipe */
+       for (i = 0; i < dev_priv->num_plane; i++) {
+               reg = SPCNTR(pipe, i);
+               val = I915_READ(reg);
+               WARN((val & SP_ENABLE),
+                    "sprite %d assertion failure, should be off on pipe %c but is still active\n",
+                    pipe * 2 + i, pipe_name(pipe));
+       }
+}
+
 static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
 {
        u32 val;
@@ -1324,14 +1356,14 @@ static bool dp_pipe_enabled(struct drm_i915_private *dev_priv,
 static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv,
                              enum i915_pipe pipe, u32 val)
 {
-       if ((val & PORT_ENABLE) == 0)
+       if ((val & SDVO_ENABLE) == 0)
                return false;
 
        if (HAS_PCH_CPT(dev_priv->dev)) {
-               if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
+               if ((val & SDVO_PIPE_SEL_MASK_CPT) != SDVO_PIPE_SEL_CPT(pipe))
                        return false;
        } else {
-               if ((val & TRANSCODER_MASK) != TRANSCODER(pipe))
+               if ((val & SDVO_PIPE_SEL_MASK) != SDVO_PIPE_SEL(pipe))
                        return false;
        }
        return true;
@@ -1389,7 +1421,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
             "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
             reg, pipe_name(pipe));
 
-       WARN(HAS_PCH_IBX(dev_priv->dev) && (val & PORT_ENABLE) == 0
+       WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0
             && (val & SDVO_PIPE_B_SELECT),
             "IBX PCH hdmi port still using transcoder B\n");
 }
@@ -1416,9 +1448,9 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
             "PCH LVDS enabled on transcoder %c, should be disabled\n",
             pipe_name(pipe));
 
-       assert_pch_hdmi_disabled(dev_priv, pipe, HDMIB);
-       assert_pch_hdmi_disabled(dev_priv, pipe, HDMIC);
-       assert_pch_hdmi_disabled(dev_priv, pipe, HDMID);
+       assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIB);
+       assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIC);
+       assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID);
 }
 
 /**
@@ -1855,6 +1887,7 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv,
         * or we might hang the display.
         */
        assert_planes_disabled(dev_priv, pipe);
+       assert_sprites_disabled(dev_priv, pipe);
 
        /* Don't disable pipe A or pipe A PLLs if needed */
        if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
@@ -1933,6 +1966,15 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv,
        intel_wait_for_vblank(dev_priv->dev, pipe);
 }
 
+static bool need_vtd_wa(struct drm_device *dev)
+{
+#ifdef CONFIG_INTEL_IOMMU
+       if (INTEL_INFO(dev)->gen >= 6 && intel_iommu_gfx_mapped)
+               return true;
+#endif
+       return false;
+}
+
 int
 intel_pin_and_fence_fb_obj(struct drm_device *dev,
                           struct drm_i915_gem_object *obj,
@@ -1956,13 +1998,23 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
                alignment = 0;
                break;
        case I915_TILING_Y:
-               /* FIXME: Is this true? */
-               DRM_ERROR("Y tiled not allowed for scan out buffers\n");
+               /* Despite that we check this in framebuffer_init userspace can
+                * screw us over and change the tiling after the fact. Only
+                * pinned buffers can't change their tiling. */
+               DRM_DEBUG_DRIVER("Y tiled not allowed for scan out buffers\n");
                return -EINVAL;
        default:
                BUG();
        }
 
+       /* Note that the w/a also requires 64 PTE of padding following the
+        * bo. We currently fill all unused PTE with the shadow page and so
+        * we should always have valid PTE following the scanout preventing
+        * the VT-d warning.
+        */
+       if (need_vtd_wa(dev) && alignment < 256 * 1024)
+               alignment = 256 * 1024;
+
        dev_priv->mm.interruptible = false;
        ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined);
        if (ret)
@@ -2079,8 +2131,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                dspcntr |= DISPPLANE_RGBX101010;
                break;
        default:
-               DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format);
-               return -EINVAL;
+               BUG();
        }
 
        if (INTEL_INFO(dev)->gen >= 4) {
@@ -2173,8 +2224,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
                dspcntr |= DISPPLANE_RGBX101010;
                break;
        default:
-               DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format);
-               return -EINVAL;
+               BUG();
        }
 
        if (obj->tiling_mode != I915_TILING_NONE)
@@ -2225,6 +2275,44 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        return dev_priv->display.update_plane(crtc, fb, x, y);
 }
 
+void intel_display_handle_reset(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc;
+
+       /*
+        * Flips in the rings have been nuked by the reset,
+        * so complete all pending flips so that user space
+        * will get its events and not get stuck.
+        *
+        * Also update the base address of all primary
+        * planes to the the last fb to make sure we're
+        * showing the correct fb after a reset.
+        *
+        * Need to make two loops over the crtcs so that we
+        * don't try to grab a crtc mutex before the
+        * pending_flip_queue really got woken up.
+        */
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               enum plane plane = intel_crtc->plane;
+
+               intel_prepare_page_flip(dev, plane);
+               intel_finish_page_flip_plane(dev, plane);
+       }
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+               mutex_lock(&crtc->mutex);
+               if (intel_crtc->active)
+                       dev_priv->display.update_plane(crtc, crtc->fb,
+                                                      crtc->x, crtc->y);
+               mutex_unlock(&crtc->mutex);
+       }
+}
+
 static int
 intel_finish_fb(struct drm_framebuffer *old_fb)
 {
@@ -2310,10 +2398,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                return 0;
        }
 
-       if(intel_crtc->plane > dev_priv->num_pipe) {
+       if (intel_crtc->plane > INTEL_INFO(dev)->num_pipes) {
                DRM_ERROR("no plane for crtc: plane %d, num_pipes %d\n",
                                intel_crtc->plane,
-                               dev_priv->num_pipe);
+                               INTEL_INFO(dev)->num_pipes);
                return -EINVAL;
        }
 
@@ -2327,9 +2415,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                return ret;
        }
 
-       if (crtc->fb)
-               intel_finish_fb(crtc->fb);
-
        ret = dev_priv->display.update_plane(crtc, fb, x, y);
        if (ret) {
                intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj);
@@ -2926,32 +3011,6 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
        mutex_unlock(&dev->struct_mutex);
 }
 
-static bool ironlake_crtc_driving_pch(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct intel_encoder *intel_encoder;
-
-       /*
-        * If there's a non-PCH eDP on this crtc, it must be DP_A, and that
-        * must be driven by its own crtc; no sharing is possible.
-        */
-       for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
-               switch (intel_encoder->type) {
-               case INTEL_OUTPUT_EDP:
-                       if (!intel_encoder_is_pch_edp(&intel_encoder->base))
-                               return false;
-                       continue;
-               }
-       }
-
-       return true;
-}
-
-static bool haswell_crtc_driving_pch(struct drm_crtc *crtc)
-{
-       return intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG);
-}
-
 /* Program iCLKIP clock to the desired frequency */
 static void lpt_program_iclkip(struct drm_crtc *crtc)
 {
@@ -3158,7 +3217,7 @@ static void lpt_pch_enable(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+       enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
 
        assert_transcoder_disabled(dev_priv, TRANSCODER_A);
 
@@ -3287,7 +3346,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
        u32 temp;
-       bool is_pch_port;
 
        WARN_ON(!crtc->enabled);
 
@@ -3303,9 +3361,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
                        I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
        }
 
-       is_pch_port = ironlake_crtc_driving_pch(crtc);
 
-       if (is_pch_port) {
+       if (intel_crtc->config.has_pch_encoder) {
                /* Note: FDI PLL enabling _must_ be done before we enable the
                 * cpu pipes, hence this is separate from all the other fdi/pch
                 * enabling. */
@@ -3342,10 +3399,11 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
         */
        intel_crtc_load_lut(crtc);
 
-       intel_enable_pipe(dev_priv, pipe, is_pch_port);
+       intel_enable_pipe(dev_priv, pipe,
+                         intel_crtc->config.has_pch_encoder);
        intel_enable_plane(dev_priv, plane, pipe);
 
-       if (is_pch_port)
+       if (intel_crtc->config.has_pch_encoder)
                ironlake_pch_enable(crtc);
 
        mutex_lock(&dev->struct_mutex);
@@ -3379,7 +3437,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
-       bool is_pch_port;
 
        WARN_ON(!crtc->enabled);
 
@@ -3389,9 +3446,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        intel_crtc->active = true;
        intel_update_watermarks(dev);
 
-       is_pch_port = haswell_crtc_driving_pch(crtc);
-
-       if (is_pch_port)
+       if (intel_crtc->config.has_pch_encoder)
                dev_priv->display.fdi_link_train(crtc);
 
        for_each_encoder_on_crtc(dev, crtc, encoder)
@@ -3420,12 +3475,13 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        intel_crtc_load_lut(crtc);
 
        intel_ddi_set_pipe_settings(crtc);
-       intel_ddi_enable_pipe_func(crtc);
+       intel_ddi_enable_transcoder_func(crtc);
 
-       intel_enable_pipe(dev_priv, pipe, is_pch_port);
+       intel_enable_pipe(dev_priv, pipe,
+                         intel_crtc->config.has_pch_encoder);
        intel_enable_plane(dev_priv, plane, pipe);
 
-       if (is_pch_port)
+       if (intel_crtc->config.has_pch_encoder)
                lpt_pch_enable(crtc);
 
        mutex_lock(&dev->struct_mutex);
@@ -3536,14 +3592,11 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
-       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
-       bool is_pch_port;
+       enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
 
        if (!intel_crtc->active)
                return;
 
-       is_pch_port = haswell_crtc_driving_pch(crtc);
-
        for_each_encoder_on_crtc(dev, crtc, encoder)
                encoder->disable(encoder);
 
@@ -3560,9 +3613,13 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
 
        intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
 
-       /* Disable PF */
-       I915_WRITE(PF_CTL(pipe), 0);
-       I915_WRITE(PF_WIN_SZ(pipe), 0);
+       /* XXX: Once we have proper panel fitter state tracking implemented with
+        * hardware state read/check support we should switch to only disable
+        * the panel fitter when we know it's used. */
+       if (intel_using_power_well(dev)) {
+               I915_WRITE(PF_CTL(pipe), 0);
+               I915_WRITE(PF_WIN_SZ(pipe), 0);
+       }
 
        intel_ddi_disable_pipe_clock(intel_crtc);
 
@@ -3570,7 +3627,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
                if (encoder->post_disable)
                        encoder->post_disable(encoder);
 
-       if (is_pch_port) {
+       if (intel_crtc->config.has_pch_encoder) {
                lpt_disable_pch_transcoder(dev_priv);
                intel_ddi_fdi_disable(crtc);
        }
@@ -3595,7 +3652,7 @@ static void haswell_crtc_off(struct drm_crtc *crtc)
 
        /* Stop saying we're using TRANSCODER_EDP because some other CRTC might
         * start using it. */
-       intel_crtc->cpu_transcoder = (enum transcoder) intel_crtc->pipe;
+       intel_crtc->config.cpu_transcoder = (enum transcoder) intel_crtc->pipe;
 
        intel_ddi_put_crtc_pll(crtc);
 }
@@ -3681,6 +3738,26 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
                encoder->enable(encoder);
 }
 
+static void i9xx_pfit_disable(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum i915_pipe pipe;
+       uint32_t pctl = I915_READ(PFIT_CONTROL);
+
+       assert_pipe_disabled(dev_priv, crtc->pipe);
+
+       if (INTEL_INFO(dev)->gen >= 4)
+               pipe = (pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT;
+       else
+               pipe = PIPE_B;
+
+       if (pipe == crtc->pipe) {
+               DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n", pctl);
+               I915_WRITE(PFIT_CONTROL, 0);
+       }
+}
+
 static void i9xx_crtc_disable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -3689,8 +3766,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
-       u32 pctl;
-
 
        if (!intel_crtc->active)
                return;
@@ -3710,11 +3785,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
        intel_disable_plane(dev_priv, plane, pipe);
        intel_disable_pipe(dev_priv, pipe);
 
-       /* Disable pannel fitter if it is on this pipe. */
-       pctl = I915_READ(PFIT_CONTROL);
-       if ((pctl & PFIT_ENABLE) &&
-           ((pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT) == pipe)
-               I915_WRITE(PFIT_CONTROL, 0);
+       i9xx_pfit_disable(intel_crtc);
 
        intel_disable_pll(dev_priv, pipe);
 
@@ -3946,22 +4017,23 @@ bool intel_connector_get_hw_state(struct intel_connector *connector)
        return encoder->get_hw_state(encoder, &pipe);
 }
 
-static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
-                                 const struct drm_display_mode *mode,
-                                 struct drm_display_mode *adjusted_mode)
+static bool intel_crtc_compute_config(struct drm_crtc *crtc,
+                                     struct intel_crtc_config *pipe_config)
 {
        struct drm_device *dev = crtc->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 (mode->clock * 3 > IRONLAKE_FDI_FREQ * 4)
+               if (pipe_config->requested_mode.clock * 3
+                   > IRONLAKE_FDI_FREQ * 4)
                        return false;
        }
 
        /* All interlaced capable intel hw wants timings in frames. Note though
         * that intel_lvds_mode_fixup does some funny tricks with the crtc
         * timings, so we need to be careful not to clobber these.*/
-       if (!(adjusted_mode->private_flags & INTEL_MODE_CRTC_TIMINGS_SET))
+       if (!pipe_config->timings_set)
                drm_mode_set_crtcinfo(adjusted_mode, 0);
 
        /* WaPruneModeWithIncorrectHsyncOffset: Cantiga+ cannot handle modes
@@ -3971,6 +4043,14 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
                adjusted_mode->hsync_start == adjusted_mode->hdisplay)
                return false;
 
+       if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10*3) {
+               pipe_config->pipe_bpp = 10*3; /* 12bpc is gen5+ */
+       } else if (INTEL_INFO(dev)->gen <= 4 && pipe_config->pipe_bpp > 8*3) {
+               /* only a 8bpc pipe, with 6bpc dither through the panel fitter
+                * for lvds. */
+               pipe_config->pipe_bpp = 8*3;
+       }
+
        return true;
 }
 
@@ -4044,26 +4124,36 @@ static int i830_get_display_clock_speed(struct drm_device *dev)
 }
 
 static void
-intel_reduce_ratio(uint32_t *num, uint32_t *den)
+intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den)
 {
-       while (*num > 0xffffff || *den > 0xffffff) {
+       while (*num > DATA_LINK_M_N_MASK ||
+              *den > DATA_LINK_M_N_MASK) {
                *num >>= 1;
                *den >>= 1;
        }
 }
 
+static void compute_m_n(unsigned int m, unsigned int n,
+                       uint32_t *ret_m, uint32_t *ret_n)
+{
+       *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX);
+       *ret_m = div_u64((uint64_t) m * *ret_n, n);
+       intel_reduce_m_n_ratio(ret_m, ret_n);
+}
+
 void
 intel_link_compute_m_n(int bits_per_pixel, int nlanes,
                       int pixel_clock, int link_clock,
                       struct intel_link_m_n *m_n)
 {
        m_n->tu = 64;
-       m_n->gmch_m = bits_per_pixel * pixel_clock;
-       m_n->gmch_n = link_clock * nlanes * 8;
-       intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
-       m_n->link_m = pixel_clock;
-       m_n->link_n = link_clock;
-       intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
+
+       compute_m_n(bits_per_pixel * pixel_clock,
+                   link_clock * nlanes * 8,
+                   &m_n->gmch_m, &m_n->gmch_n);
+
+       compute_m_n(pixel_clock, link_clock,
+                   &m_n->link_m, &m_n->link_n);
 }
 
 static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
@@ -4074,142 +4164,6 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
                && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
 }
 
-/**
- * intel_choose_pipe_bpp_dither - figure out what color depth the pipe should send
- * @crtc: CRTC structure
- * @mode: requested mode
- *
- * A pipe may be connected to one or more outputs.  Based on the depth of the
- * attached framebuffer, choose a good color depth to use on the pipe.
- *
- * If possible, match the pipe depth to the fb depth.  In some cases, this
- * isn't ideal, because the connected output supports a lesser or restricted
- * set of depths.  Resolve that here:
- *    LVDS typically supports only 6bpc, so clamp down in that case
- *    HDMI supports only 8bpc or 12bpc, so clamp to 8bpc with dither for 10bpc
- *    Displays may support a restricted set as well, check EDID and clamp as
- *      appropriate.
- *    DP may want to dither down to 6bpc to fit larger modes
- *
- * RETURNS:
- * Dithering requirement (i.e. false if display bpc and pipe bpc match,
- * true if they don't match).
- */
-static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
-                                        struct drm_framebuffer *fb,
-                                        unsigned int *pipe_bpp,
-                                        struct drm_display_mode *mode)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_connector *connector;
-       struct intel_encoder *intel_encoder;
-       unsigned int display_bpc = UINT_MAX, bpc;
-
-       /* Walk the encoders & connectors on this crtc, get min bpc */
-       for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
-
-               if (intel_encoder->type == INTEL_OUTPUT_LVDS) {
-                       unsigned int lvds_bpc;
-
-                       if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) ==
-                           LVDS_A3_POWER_UP)
-                               lvds_bpc = 8;
-                       else
-                               lvds_bpc = 6;
-
-                       if (lvds_bpc < display_bpc) {
-                               DRM_DEBUG_KMS("clamping display bpc (was %d) to LVDS (%d)\n", display_bpc, lvds_bpc);
-                               display_bpc = lvds_bpc;
-                       }
-                       continue;
-               }
-
-               /* Not one of the known troublemakers, check the EDID */
-               list_for_each_entry(connector, &dev->mode_config.connector_list,
-                                   head) {
-                       if (connector->encoder != &intel_encoder->base)
-                               continue;
-
-                       /* Don't use an invalid EDID bpc value */
-                       if (connector->display_info.bpc &&
-                           connector->display_info.bpc < display_bpc) {
-                               DRM_DEBUG_KMS("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc);
-                               display_bpc = connector->display_info.bpc;
-                       }
-               }
-
-               if (intel_encoder->type == INTEL_OUTPUT_EDP) {
-                       /* Use VBT settings if we have an eDP panel */
-                       unsigned int edp_bpc = dev_priv->edp.bpp / 3;
-
-                       if (edp_bpc && edp_bpc < display_bpc) {
-                               DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc);
-                               display_bpc = edp_bpc;
-                       }
-                       continue;
-               }
-
-               /*
-                * HDMI is either 12 or 8, so if the display lets 10bpc sneak
-                * through, clamp it down.  (Note: >12bpc will be caught below.)
-                */
-               if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
-                       if (display_bpc > 8 && display_bpc < 12) {
-                               DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n");
-                               display_bpc = 12;
-                       } else {
-                               DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n");
-                               display_bpc = 8;
-                       }
-               }
-       }
-
-       if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
-               DRM_DEBUG_KMS("Dithering DP to 6bpc\n");
-               display_bpc = 6;
-       }
-
-       /*
-        * We could just drive the pipe at the highest bpc all the time and
-        * enable dithering as needed, but that costs bandwidth.  So choose
-        * the minimum value that expresses the full color range of the fb but
-        * also stays within the max display bpc discovered above.
-        */
-
-       switch (fb->depth) {
-       case 8:
-               bpc = 8; /* since we go through a colormap */
-               break;
-       case 15:
-       case 16:
-               bpc = 6; /* min is 18bpp */
-               break;
-       case 24:
-               bpc = 8;
-               break;
-       case 30:
-               bpc = 10;
-               break;
-       case 48:
-               bpc = 12;
-               break;
-       default:
-               DRM_DEBUG("unsupported depth, assuming 24 bits\n");
-               bpc = min((unsigned int)8, display_bpc);
-               break;
-       }
-
-       display_bpc = min(display_bpc, bpc);
-
-       DRM_DEBUG_KMS("setting pipe bpc to %d (max display bpc %d)\n",
-                     bpc, display_bpc);
-
-       *pipe_bpp = display_bpc * 3;
-
-       return display_bpc != bpc;
-}
-
 static int vlv_get_refclk(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -4254,37 +4208,38 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
        return refclk;
 }
 
-static void i9xx_adjust_sdvo_tv_clock(struct drm_display_mode *adjusted_mode,
-                                     intel_clock_t *clock)
+static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc *crtc)
 {
+       unsigned dotclock = crtc->config.adjusted_mode.clock;
+       struct dpll *clock = &crtc->config.dpll;
+
        /* SDVO TV has fixed PLL values depend on its clock range,
           this mirrors vbios setting. */
-       if (adjusted_mode->clock >= 100000
-           && adjusted_mode->clock < 140500) {
+       if (dotclock >= 100000 && dotclock < 140500) {
                clock->p1 = 2;
                clock->p2 = 10;
                clock->n = 3;
                clock->m1 = 16;
                clock->m2 = 8;
-       } else if (adjusted_mode->clock >= 140500
-                  && adjusted_mode->clock <= 200000) {
+       } else if (dotclock >= 140500 && dotclock <= 200000) {
                clock->p1 = 1;
                clock->p2 = 10;
                clock->n = 6;
                clock->m1 = 12;
                clock->m2 = 8;
        }
+
+       crtc->config.clock_set = true;
 }
 
-static void i9xx_update_pll_dividers(struct drm_crtc *crtc,
-                                    intel_clock_t *clock,
+static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
                                     intel_clock_t *reduced_clock)
 {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
+       int pipe = crtc->pipe;
        u32 fp, fp2 = 0;
+       struct dpll *clock = &crtc->config.dpll;
 
        if (IS_PINEVIEW(dev)) {
                fp = (1 << clock->n) << 16 | clock->m1 << 8 | clock->m2;
@@ -4300,26 +4255,29 @@ static void i9xx_update_pll_dividers(struct drm_crtc *crtc,
 
        I915_WRITE(FP0(pipe), fp);
 
-       intel_crtc->lowfreq_avail = false;
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+       crtc->lowfreq_avail = false;
+       if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
            reduced_clock && i915_powersave) {
                I915_WRITE(FP1(pipe), fp2);
-               intel_crtc->lowfreq_avail = true;
+               crtc->lowfreq_avail = true;
        } else {
                I915_WRITE(FP1(pipe), fp);
        }
 }
 
-static void vlv_update_pll(struct drm_crtc *crtc,
-                          struct drm_display_mode *mode,
-                          struct drm_display_mode *adjusted_mode,
-                          intel_clock_t *clock, intel_clock_t *reduced_clock,
-                          int num_connectors)
+static void intel_dp_set_m_n(struct intel_crtc *crtc)
 {
-       struct drm_device *dev = crtc->dev;
+       if (crtc->config.has_pch_encoder)
+               intel_pch_transcoder_set_m_n(crtc, &crtc->config.dp_m_n);
+       else
+               intel_cpu_transcoder_set_m_n(crtc, &crtc->config.dp_m_n);
+}
+
+static void vlv_update_pll(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
+       int pipe = crtc->pipe;
        u32 dpll, mdiv, pdiv;
        u32 bestn, bestm1, bestm2, bestp1, bestp2;
        bool is_sdvo;
@@ -4327,8 +4285,8 @@ static void vlv_update_pll(struct drm_crtc *crtc,
 
        lockmgr(&dev_priv->dpio_lock, LK_EXCLUSIVE);
 
-       is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) ||
-               intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI);
+       is_sdvo = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_SDVO) ||
+               intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI);
 
        dpll = DPLL_VGA_MODE_DIS;
        dpll |= DPLL_EXT_BUFFER_ENABLE_VLV;
@@ -4338,11 +4296,11 @@ static void vlv_update_pll(struct drm_crtc *crtc,
        I915_WRITE(DPLL(pipe), dpll);
        POSTING_READ(DPLL(pipe));
 
-       bestn = clock->n;
-       bestm1 = clock->m1;
-       bestm2 = clock->m2;
-       bestp1 = clock->p1;
-       bestp2 = clock->p2;
+       bestn = crtc->config.dpll.n;
+       bestm1 = crtc->config.dpll.m1;
+       bestm2 = crtc->config.dpll.m2;
+       bestp1 = crtc->config.dpll.p1;
+       bestp2 = crtc->config.dpll.p2;
 
        /*
         * In Valleyview PLL and program lane counter registers are exposed
@@ -4374,8 +4332,8 @@ static void vlv_update_pll(struct drm_crtc *crtc,
 
        intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x620);
 
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
-               intel_dp_set_m_n(crtc, mode, adjusted_mode);
+       if (crtc->config.has_dp_encoder)
+               intel_dp_set_m_n(crtc);
 
        I915_WRITE(DPLL(pipe), dpll);
 
@@ -4385,26 +4343,25 @@ static void vlv_update_pll(struct drm_crtc *crtc,
 
        temp = 0;
        if (is_sdvo) {
-               temp = intel_mode_get_pixel_multiplier(adjusted_mode);
-               if (temp > 1)
-                       temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
-               else
-                       temp = 0;
+               temp = 0;
+               if (crtc->config.pixel_multiplier > 1) {
+                       temp = (crtc->config.pixel_multiplier - 1)
+                               << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+               }
        }
        I915_WRITE(DPLL_MD(pipe), temp);
        POSTING_READ(DPLL_MD(pipe));
 
        /* Now program lane control registers */
-       if(intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)
-                       || intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI))
-       {
+       if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)
+          || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) {
                temp = 0x1000C4;
                if(pipe == 1)
                        temp |= (1 << 21);
                intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL1, temp);
        }
-       if(intel_pipe_has_type(crtc,INTEL_OUTPUT_EDP))
-       {
+
+       if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) {
                temp = 0x1000C4;
                if(pipe == 1)
                        temp |= (1 << 21);
@@ -4414,40 +4371,39 @@ static void vlv_update_pll(struct drm_crtc *crtc,
        lockmgr(&dev_priv->dpio_lock, LK_RELEASE);
 }
 
-static void i9xx_update_pll(struct drm_crtc *crtc,
-                           struct drm_display_mode *mode,
-                           struct drm_display_mode *adjusted_mode,
-                           intel_clock_t *clock, intel_clock_t *reduced_clock,
+static void i9xx_update_pll(struct intel_crtc *crtc,
+                           intel_clock_t *reduced_clock,
                            int num_connectors)
 {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
-       int pipe = intel_crtc->pipe;
+       int pipe = crtc->pipe;
        u32 dpll;
        bool is_sdvo;
+       struct dpll *clock = &crtc->config.dpll;
 
-       i9xx_update_pll_dividers(crtc, clock, reduced_clock);
+       i9xx_update_pll_dividers(crtc, reduced_clock);
 
-       is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) ||
-               intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI);
+       is_sdvo = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_SDVO) ||
+               intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI);
 
        dpll = DPLL_VGA_MODE_DIS;
 
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+       if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS))
                dpll |= DPLLB_MODE_LVDS;
        else
                dpll |= DPLLB_MODE_DAC_SERIAL;
+
        if (is_sdvo) {
-               int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
-               if (pixel_multiplier > 1) {
-                       if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
-                               dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
+               if ((crtc->config.pixel_multiplier > 1) &&
+                   (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))) {
+                       dpll |= (crtc->config.pixel_multiplier - 1)
+                               << SDVO_MULTIPLIER_SHIFT_HIRES;
                }
                dpll |= DPLL_DVO_HIGH_SPEED;
        }
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
+       if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT))
                dpll |= DPLL_DVO_HIGH_SPEED;
 
        /* compute bitmask from p1 value */
@@ -4475,13 +4431,13 @@ static void i9xx_update_pll(struct drm_crtc *crtc,
        if (INTEL_INFO(dev)->gen >= 4)
                dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
 
-       if (is_sdvo && intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT))
+       if (is_sdvo && intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_TVOUT))
                dpll |= PLL_REF_INPUT_TVCLKINBC;
-       else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT))
+       else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_TVOUT))
                /* XXX: just matching BIOS for now */
                /*      dpll |= PLL_REF_INPUT_TVCLKINBC; */
                dpll |= 3;
-       else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+       else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
                 intel_panel_use_ssc(dev_priv) && num_connectors < 2)
                dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
        else
@@ -4492,12 +4448,12 @@ static void i9xx_update_pll(struct drm_crtc *crtc,
        POSTING_READ(DPLL(pipe));
        udelay(150);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
+       for_each_encoder_on_crtc(dev, &crtc->base, encoder)
                if (encoder->pre_pll_enable)
                        encoder->pre_pll_enable(encoder);
 
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
-               intel_dp_set_m_n(crtc, mode, adjusted_mode);
+       if (crtc->config.has_dp_encoder)
+               intel_dp_set_m_n(crtc);
 
        I915_WRITE(DPLL(pipe), dpll);
 
@@ -4508,11 +4464,11 @@ static void i9xx_update_pll(struct drm_crtc *crtc,
        if (INTEL_INFO(dev)->gen >= 4) {
                u32 temp = 0;
                if (is_sdvo) {
-                       temp = intel_mode_get_pixel_multiplier(adjusted_mode);
-                       if (temp > 1)
-                               temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
-                       else
-                               temp = 0;
+                       temp = 0;
+                       if (crtc->config.pixel_multiplier > 1) {
+                               temp = (crtc->config.pixel_multiplier - 1)
+                                       << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+                       }
                }
                I915_WRITE(DPLL_MD(pipe), temp);
        } else {
@@ -4525,23 +4481,23 @@ static void i9xx_update_pll(struct drm_crtc *crtc,
        }
 }
 
-static void i8xx_update_pll(struct drm_crtc *crtc,
+static void i8xx_update_pll(struct intel_crtc *crtc,
                            struct drm_display_mode *adjusted_mode,
-                           intel_clock_t *clock, intel_clock_t *reduced_clock,
+                           intel_clock_t *reduced_clock,
                            int num_connectors)
 {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
-       int pipe = intel_crtc->pipe;
+       int pipe = crtc->pipe;
        u32 dpll;
+       struct dpll *clock = &crtc->config.dpll;
 
-       i9xx_update_pll_dividers(crtc, clock, reduced_clock);
+       i9xx_update_pll_dividers(crtc, reduced_clock);
 
        dpll = DPLL_VGA_MODE_DIS;
 
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+       if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS)) {
                dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
        } else {
                if (clock->p1 == 2)
@@ -4552,11 +4508,7 @@ static void i8xx_update_pll(struct drm_crtc *crtc,
                        dpll |= PLL_P2_DIVIDE_BY_4;
        }
 
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT))
-               /* XXX: just matching BIOS for now */
-               /*      dpll |= PLL_REF_INPUT_TVCLKINBC; */
-               dpll |= 3;
-       else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+       if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
                 intel_panel_use_ssc(dev_priv) && num_connectors < 2)
                dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
        else
@@ -4567,7 +4519,7 @@ static void i8xx_update_pll(struct drm_crtc *crtc,
        POSTING_READ(DPLL(pipe));
        udelay(150);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
+       for_each_encoder_on_crtc(dev, &crtc->base, encoder)
                if (encoder->pre_pll_enable)
                        encoder->pre_pll_enable(encoder);
 
@@ -4592,7 +4544,7 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc,
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum i915_pipe pipe = intel_crtc->pipe;
-       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+       enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
        uint32_t vsyncshift;
 
        if (!IS_GEN2(dev) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
@@ -4643,22 +4595,92 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc,
                   ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
 }
 
+static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
+{
+       struct drm_device *dev = intel_crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t pipeconf;
+
+       pipeconf = I915_READ(PIPECONF(intel_crtc->pipe));
+
+       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;
+               else
+                       pipeconf &= ~PIPECONF_DOUBLE_WIDE;
+       }
+
+       /* default to 8bpc */
+       pipeconf &= ~(PIPECONF_BPC_MASK | PIPECONF_DITHER_EN);
+       if (intel_crtc->config.has_dp_encoder) {
+               if (intel_crtc->config.dither) {
+                       pipeconf |= PIPECONF_6BPC |
+                                   PIPECONF_DITHER_EN |
+                                   PIPECONF_DITHER_TYPE_SP;
+               }
+       }
+
+       if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(&intel_crtc->base,
+                                                     INTEL_OUTPUT_EDP)) {
+               if (intel_crtc->config.dither) {
+                       pipeconf |= PIPECONF_6BPC |
+                                       PIPECONF_ENABLE |
+                                       I965_PIPECONF_ACTIVE;
+               }
+       }
+
+       if (HAS_PIPE_CXSR(dev)) {
+               if (intel_crtc->lowfreq_avail) {
+                       DRM_DEBUG_KMS("enabling CxSR downclocking\n");
+                       pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
+               } else {
+                       DRM_DEBUG_KMS("disabling CxSR downclocking\n");
+                       pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
+               }
+       }
+
+       pipeconf &= ~PIPECONF_INTERLACE_MASK;
+       if (!IS_GEN2(dev) &&
+           intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+               pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+       else
+               pipeconf |= PIPECONF_PROGRESSIVE;
+
+       if (IS_VALLEYVIEW(dev)) {
+               if (intel_crtc->config.limited_color_range)
+                       pipeconf |= PIPECONF_COLOR_RANGE_SELECT;
+               else
+                       pipeconf &= ~PIPECONF_COLOR_RANGE_SELECT;
+       }
+
+       I915_WRITE(PIPECONF(intel_crtc->pipe), pipeconf);
+       POSTING_READ(PIPECONF(intel_crtc->pipe));
+}
+
 static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
-                             struct drm_display_mode *mode,
-                             struct drm_display_mode *adjusted_mode,
                              int x, int y,
                              struct drm_framebuffer *fb)
 {
        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 *adjusted_mode =
+               &intel_crtc->config.adjusted_mode;
+       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, pipeconf;
+       u32 dspcntr;
        bool ok, has_reduced_clock = false, is_sdvo = false;
-       bool is_lvds = false, is_tv = false, is_dp = false;
+       bool is_lvds = false, is_tv = false;
        struct intel_encoder *encoder;
        const intel_limit_t *limit;
        int ret;
@@ -4677,9 +4699,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
                case INTEL_OUTPUT_TVOUT:
                        is_tv = true;
                        break;
-               case INTEL_OUTPUT_DISPLAYPORT:
-                       is_dp = true;
-                       break;
                }
 
                num_connectors++;
@@ -4716,85 +4735,41 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
                                                    &clock,
                                                    &reduced_clock);
        }
-
-       if (is_sdvo && is_tv)
-               i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock);
-
-       if (IS_GEN2(dev))
-               i8xx_update_pll(crtc, adjusted_mode, &clock,
-                               has_reduced_clock ? &reduced_clock : NULL,
-                               num_connectors);
-       else if (IS_VALLEYVIEW(dev))
-               vlv_update_pll(crtc, mode, adjusted_mode, &clock,
-                               has_reduced_clock ? &reduced_clock : NULL,
-                               num_connectors);
-       else
-               i9xx_update_pll(crtc, mode, adjusted_mode, &clock,
-                               has_reduced_clock ? &reduced_clock : NULL,
-                               num_connectors);
-
-       /* setup pipeconf */
-       pipeconf = I915_READ(PIPECONF(pipe));
-
-       /* Set up the display plane register */
-       dspcntr = DISPPLANE_GAMMA_ENABLE;
-
-       if (pipe == 0)
-               dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
-       else
-               dspcntr |= DISPPLANE_SEL_PIPE_B;
-
-       if (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 (mode->clock >
-                   dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
-                       pipeconf |= PIPECONF_DOUBLE_WIDE;
-               else
-                       pipeconf &= ~PIPECONF_DOUBLE_WIDE;
-       }
-
-       /* default to 8bpc */
-       pipeconf &= ~(PIPECONF_BPC_MASK | PIPECONF_DITHER_EN);
-       if (is_dp) {
-               if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
-                       pipeconf |= PIPECONF_6BPC |
-                                   PIPECONF_DITHER_EN |
-                                   PIPECONF_DITHER_TYPE_SP;
-               }
+       /* Compat-code for transition, will disappear. */
+       if (!intel_crtc->config.clock_set) {
+               intel_crtc->config.dpll.n = clock.n;
+               intel_crtc->config.dpll.m1 = clock.m1;
+               intel_crtc->config.dpll.m2 = clock.m2;
+               intel_crtc->config.dpll.p1 = clock.p1;
+               intel_crtc->config.dpll.p2 = clock.p2;
        }
 
-       if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) {
-               if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
-                       pipeconf |= PIPECONF_6BPC |
-                                       PIPECONF_ENABLE |
-                                       I965_PIPECONF_ACTIVE;
-               }
-       }
+       if (is_sdvo && is_tv)
+               i9xx_adjust_sdvo_tv_clock(intel_crtc);
 
-       DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
-       drm_mode_debug_printmodeline(mode);
+       if (IS_GEN2(dev))
+               i8xx_update_pll(intel_crtc, adjusted_mode,
+                               has_reduced_clock ? &reduced_clock : NULL,
+                               num_connectors);
+       else if (IS_VALLEYVIEW(dev))
+               vlv_update_pll(intel_crtc);
+       else
+               i9xx_update_pll(intel_crtc,
+                               has_reduced_clock ? &reduced_clock : NULL,
+                               num_connectors);
 
-       if (HAS_PIPE_CXSR(dev)) {
-               if (intel_crtc->lowfreq_avail) {
-                       DRM_DEBUG_KMS("enabling CxSR downclocking\n");
-                       pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
-               } else {
-                       DRM_DEBUG_KMS("disabling CxSR downclocking\n");
-                       pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
-               }
+       /* Set up the display plane register */
+       dspcntr = DISPPLANE_GAMMA_ENABLE;
+
+       if (!IS_VALLEYVIEW(dev)) {
+               if (pipe == 0)
+                       dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
+               else
+                       dspcntr |= DISPPLANE_SEL_PIPE_B;
        }
 
-       pipeconf &= ~PIPECONF_INTERLACE_MASK;
-       if (!IS_GEN2(dev) &&
-           adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
-               pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
-       else
-               pipeconf |= PIPECONF_PROGRESSIVE;
+       DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
+       drm_mode_debug_printmodeline(mode);
 
        intel_set_pipe_timings(intel_crtc, mode, adjusted_mode);
 
@@ -4806,8 +4781,8 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
                   (mode->hdisplay - 1));
        I915_WRITE(DSPPOS(plane), 0);
 
-       I915_WRITE(PIPECONF(pipe), pipeconf);
-       POSTING_READ(PIPECONF(pipe));
+       i9xx_set_pipeconf(intel_crtc);
+
        intel_enable_pipe(dev_priv, pipe, false);
 
        intel_wait_for_vblank(dev, pipe);
@@ -4822,12 +4797,26 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
        return ret;
 }
 
+static bool i9xx_get_pipe_config(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;
+       uint32_t tmp;
+
+       tmp = I915_READ(PIPECONF(crtc->pipe));
+       if (!(tmp & PIPECONF_ENABLE))
+               return false;
+
+       return true;
+}
+
 static void ironlake_init_pch_refclk(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *encoder;
-       u32 temp;
+       u32 val, final;
        bool has_lvds = false;
        bool has_cpu_edp = false;
        bool has_pch_edp = false;
@@ -4870,70 +4859,109 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
         * PCH B stepping, previous chipset stepping should be
         * ignoring this setting.
         */
-       temp = I915_READ(PCH_DREF_CONTROL);
+       val = I915_READ(PCH_DREF_CONTROL);
+
+       /* As we must carefully and slowly disable/enable each source in turn,
+        * compute the final state we want first and check if we need to
+        * make any changes at all.
+        */
+       final = val;
+       final &= ~DREF_NONSPREAD_SOURCE_MASK;
+       if (has_ck505)
+               final |= DREF_NONSPREAD_CK505_ENABLE;
+       else
+               final |= DREF_NONSPREAD_SOURCE_ENABLE;
+
+       final &= ~DREF_SSC_SOURCE_MASK;
+       final &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+       final &= ~DREF_SSC1_ENABLE;
+
+       if (has_panel) {
+               final |= DREF_SSC_SOURCE_ENABLE;
+
+               if (intel_panel_use_ssc(dev_priv) && can_ssc)
+                       final |= DREF_SSC1_ENABLE;
+
+               if (has_cpu_edp) {
+                       if (intel_panel_use_ssc(dev_priv) && can_ssc)
+                               final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                       else
+                               final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+               } else
+                       final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+       } else {
+               final |= DREF_SSC_SOURCE_DISABLE;
+               final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+       }
+
+       if (final == val)
+               return;
+
        /* Always enable nonspread source */
-       temp &= ~DREF_NONSPREAD_SOURCE_MASK;
+       val &= ~DREF_NONSPREAD_SOURCE_MASK;
 
        if (has_ck505)
-               temp |= DREF_NONSPREAD_CK505_ENABLE;
+               val |= DREF_NONSPREAD_CK505_ENABLE;
        else
-               temp |= DREF_NONSPREAD_SOURCE_ENABLE;
+               val |= DREF_NONSPREAD_SOURCE_ENABLE;
 
        if (has_panel) {
-               temp &= ~DREF_SSC_SOURCE_MASK;
-               temp |= DREF_SSC_SOURCE_ENABLE;
+               val &= ~DREF_SSC_SOURCE_MASK;
+               val |= DREF_SSC_SOURCE_ENABLE;
 
                /* SSC must be turned on before enabling the CPU output  */
                if (intel_panel_use_ssc(dev_priv) && can_ssc) {
                        DRM_DEBUG_KMS("Using SSC on panel\n");
-                       temp |= DREF_SSC1_ENABLE;
+                       val |= DREF_SSC1_ENABLE;
                } else
-                       temp &= ~DREF_SSC1_ENABLE;
+                       val &= ~DREF_SSC1_ENABLE;
 
                /* Get SSC going before enabling the outputs */
-               I915_WRITE(PCH_DREF_CONTROL, temp);
+               I915_WRITE(PCH_DREF_CONTROL, val);
                POSTING_READ(PCH_DREF_CONTROL);
                udelay(200);
 
-               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+               val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 
                /* Enable CPU source on CPU attached eDP */
                if (has_cpu_edp) {
                        if (intel_panel_use_ssc(dev_priv) && can_ssc) {
                                DRM_DEBUG_KMS("Using SSC on eDP\n");
-                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                               val |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
                        }
                        else
-                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+                               val |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
                } else
-                       temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+                       val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
 
-               I915_WRITE(PCH_DREF_CONTROL, temp);
+               I915_WRITE(PCH_DREF_CONTROL, val);
                POSTING_READ(PCH_DREF_CONTROL);
                udelay(200);
        } else {
                DRM_DEBUG_KMS("Disabling SSC entirely\n");
 
-               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+               val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 
                /* Turn off CPU output */
-               temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+               val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
 
-               I915_WRITE(PCH_DREF_CONTROL, temp);
+               I915_WRITE(PCH_DREF_CONTROL, val);
                POSTING_READ(PCH_DREF_CONTROL);
                udelay(200);
 
                /* Turn off the SSC source */
-               temp &= ~DREF_SSC_SOURCE_MASK;
-               temp |= DREF_SSC_SOURCE_DISABLE;
+               val &= ~DREF_SSC_SOURCE_MASK;
+               val |= DREF_SSC_SOURCE_DISABLE;
 
                /* Turn off SSC1 */
-               temp &= ~ DREF_SSC1_ENABLE;
+               val &= ~DREF_SSC1_ENABLE;
 
-               I915_WRITE(PCH_DREF_CONTROL, temp);
+               I915_WRITE(PCH_DREF_CONTROL, val);
                POSTING_READ(PCH_DREF_CONTROL);
                udelay(200);
        }
+
+       BUG_ON(val != final);
 }
 
 /* Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O. */
@@ -4998,13 +5026,6 @@ static void lpt_init_pch_refclk(struct drm_device *dev)
        tmp |= (0x12 << 24);
        intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY);
 
-       if (!is_sdv) {
-               tmp = intel_sbi_read(dev_priv, 0x808C, SBI_MPHY);
-               tmp &= ~(0x3 << 6);
-               tmp |= (1 << 6) | (1 << 0);
-               intel_sbi_write(dev_priv, 0x808C, tmp, SBI_MPHY);
-       }
-
        if (is_sdv) {
                tmp = intel_sbi_read(dev_priv, 0x800C, SBI_MPHY);
                tmp |= 0x7FFF;
@@ -5158,7 +5179,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc,
        val = I915_READ(PIPECONF(pipe));
 
        val &= ~PIPECONF_BPC_MASK;
-       switch (intel_crtc->bpp) {
+       switch (intel_crtc->config.pipe_bpp) {
        case 18:
                val |= PIPECONF_6BPC;
                break;
@@ -5186,7 +5207,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc,
        else
                val |= PIPECONF_PROGRESSIVE;
 
-       if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
+       if (intel_crtc->config.limited_color_range)
                val |= PIPECONF_COLOR_RANGE_SELECT;
        else
                val &= ~PIPECONF_COLOR_RANGE_SELECT;
@@ -5202,8 +5223,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc,
  * is supported, but eventually this should handle various
  * RGB<->YCbCr scenarios as well.
  */
-static void intel_set_pipe_csc(struct drm_crtc *crtc,
-                              const struct drm_display_mode *adjusted_mode)
+static void intel_set_pipe_csc(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5218,7 +5238,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc,
         * consideration.
         */
 
-       if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
+       if (intel_crtc->config.limited_color_range)
                coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */
 
        /*
@@ -5242,7 +5262,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc,
        if (INTEL_INFO(dev)->gen > 6) {
                uint16_t postoff = 0;
 
-               if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
+               if (intel_crtc->config.limited_color_range)
                        postoff = (16 * (1 << 13) / 255) & 0x1fff;
 
                I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff);
@@ -5253,7 +5273,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc,
        } else {
                uint32_t mode = CSC_MODE_YUV_TO_RGB;
 
-               if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
+               if (intel_crtc->config.limited_color_range)
                        mode |= CSC_BLACK_SCREEN_OFFSET;
 
                I915_WRITE(PIPE_CSC_MODE(pipe), mode);
@@ -5266,7 +5286,7 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc,
 {
        struct drm_i915_private *dev_priv = crtc->dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+       enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
        uint32_t val;
 
        val = I915_READ(PIPECONF(cpu_transcoder));
@@ -5343,7 +5363,7 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
        }
 
        if (is_sdvo && is_tv)
-               i9xx_adjust_sdvo_tv_clock(adjusted_mode, clock);
+               i9xx_adjust_sdvo_tv_clock(to_intel_crtc(crtc));
 
        return true;
 }
@@ -5384,7 +5404,7 @@ static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc)
                return false;
        }
 
-       if (dev_priv->num_pipe == 2)
+       if (INTEL_INFO(dev)->num_pipes == 2)
                return true;
 
        switch (intel_crtc->pipe) {
@@ -5441,87 +5461,87 @@ int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp)
        return bps / (link_bw * 8) + 1;
 }
 
-static void ironlake_set_m_n(struct drm_crtc *crtc,
-                            struct drm_display_mode *mode,
-                            struct drm_display_mode *adjusted_mode)
+void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
+                                 struct intel_link_m_n *m_n)
 {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
-       struct intel_encoder *intel_encoder, *edp_encoder = NULL;
-       struct intel_link_m_n m_n = {0};
-       int target_clock, pixel_multiplier, lane, link_bw;
-       bool is_dp = false, is_cpu_edp = false;
+       int pipe = crtc->pipe;
 
-       for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
-               switch (intel_encoder->type) {
-               case INTEL_OUTPUT_DISPLAYPORT:
-                       is_dp = true;
-                       break;
-               case INTEL_OUTPUT_EDP:
-                       is_dp = true;
-                       if (!intel_encoder_is_pch_edp(&intel_encoder->base))
-                               is_cpu_edp = true;
-                       edp_encoder = intel_encoder;
-                       break;
-               }
-       }
+       I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
+       I915_WRITE(TRANSDATA_N1(pipe), m_n->gmch_n);
+       I915_WRITE(TRANSDPLINK_M1(pipe), m_n->link_m);
+       I915_WRITE(TRANSDPLINK_N1(pipe), m_n->link_n);
+}
+
+void intel_cpu_transcoder_set_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;
+       int pipe = crtc->pipe;
+       enum transcoder transcoder = crtc->config.cpu_transcoder;
 
-       /* FDI link */
-       pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
-       lane = 0;
-       /* CPU eDP doesn't require FDI link, so just set DP M/N
-          according to current link config */
-       if (is_cpu_edp) {
-               intel_edp_link_config(edp_encoder, &lane, &link_bw);
+       if (INTEL_INFO(dev)->gen >= 5) {
+               I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m);
+               I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n);
+               I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m);
+               I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n);
        } else {
-               /* FDI is a binary signal running at ~2.7GHz, encoding
-                * each output octet as 10 bits. The actual frequency
-                * is stored as a divider into a 100MHz clock, and the
-                * mode pixel clock is stored in units of 1KHz.
-                * Hence the bw of each lane in terms of the mode signal
-                * is:
-                */
-               link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
+               I915_WRITE(PIPE_GMCH_DATA_M(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
+               I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n->gmch_n);
+               I915_WRITE(PIPE_DP_LINK_M(pipe), m_n->link_m);
+               I915_WRITE(PIPE_DP_LINK_N(pipe), m_n->link_n);
        }
+}
 
-       /* [e]DP over FDI requires target mode clock instead of link clock. */
-       if (edp_encoder)
-               target_clock = intel_edp_target_clock(edp_encoder, mode);
-       else if (is_dp)
-               target_clock = mode->clock;
+static void ironlake_fdi_set_m_n(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_display_mode *adjusted_mode =
+               &intel_crtc->config.adjusted_mode;
+       struct intel_link_m_n m_n = {0};
+       int target_clock, lane, link_bw;
+
+       /* FDI is a binary signal running at ~2.7GHz, encoding
+        * each output octet as 10 bits. The actual frequency
+        * is stored as a divider into a 100MHz clock, and the
+        * mode pixel clock is stored in units of 1KHz.
+        * Hence the bw of each lane in terms of the mode signal
+        * is:
+        */
+       link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
+
+       if (intel_crtc->config.pixel_target_clock)
+               target_clock = intel_crtc->config.pixel_target_clock;
        else
                target_clock = adjusted_mode->clock;
 
-       if (!lane)
-               lane = ironlake_get_lanes_required(target_clock, link_bw,
-                                                  intel_crtc->bpp);
+       lane = ironlake_get_lanes_required(target_clock, link_bw,
+                                          intel_crtc->config.pipe_bpp);
 
        intel_crtc->fdi_lanes = lane;
 
-       if (pixel_multiplier > 1)
-               link_bw *= pixel_multiplier;
-       intel_link_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw, &m_n);
+       if (intel_crtc->config.pixel_multiplier > 1)
+               link_bw *= intel_crtc->config.pixel_multiplier;
+       intel_link_compute_m_n(intel_crtc->config.pipe_bpp, lane, target_clock,
+                              link_bw, &m_n);
 
-       I915_WRITE(PIPE_DATA_M1(cpu_transcoder), TU_SIZE(m_n.tu) | m_n.gmch_m);
-       I915_WRITE(PIPE_DATA_N1(cpu_transcoder), m_n.gmch_n);
-       I915_WRITE(PIPE_LINK_M1(cpu_transcoder), m_n.link_m);
-       I915_WRITE(PIPE_LINK_N1(cpu_transcoder), m_n.link_n);
+       intel_cpu_transcoder_set_m_n(intel_crtc, &m_n);
 }
 
 static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
-                                     struct drm_display_mode *adjusted_mode,
-                                     intel_clock_t *clock, u32 fp)
+                                     intel_clock_t *clock, u32 *fp,
+                                     intel_clock_t *reduced_clock, u32 *fp2)
 {
        struct drm_crtc *crtc = &intel_crtc->base;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_encoder *intel_encoder;
        uint32_t dpll;
-       int factor, pixel_multiplier, num_connectors = 0;
+       int factor, num_connectors = 0;
        bool is_lvds = false, is_sdvo = false, is_tv = false;
-       bool is_dp = false, is_cpu_edp = false;
 
        for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
                switch (intel_encoder->type) {
@@ -5537,14 +5557,6 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
                case INTEL_OUTPUT_TVOUT:
                        is_tv = true;
                        break;
-               case INTEL_OUTPUT_DISPLAYPORT:
-                       is_dp = true;
-                       break;
-               case INTEL_OUTPUT_EDP:
-                       is_dp = true;
-                       if (!intel_encoder_is_pch_edp(&intel_encoder->base))
-                               is_cpu_edp = true;
-                       break;
                }
 
                num_connectors++;
@@ -5555,13 +5567,16 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
        if (is_lvds) {
                if ((intel_panel_use_ssc(dev_priv) &&
                     dev_priv->lvds_ssc_freq == 100) ||
-                   intel_is_dual_link_lvds(dev))
+                   (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev)))
                        factor = 25;
        } else if (is_sdvo && is_tv)
                factor = 20;
 
        if (clock->m < factor * clock->n)
-               fp |= FP_CB_TUNE;
+               *fp |= FP_CB_TUNE;
+
+       if (fp2 && (reduced_clock->m < factor * reduced_clock->n))
+               *fp2 |= FP_CB_TUNE;
 
        dpll = 0;
 
@@ -5570,13 +5585,14 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
        else
                dpll |= DPLLB_MODE_DAC_SERIAL;
        if (is_sdvo) {
-               pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
-               if (pixel_multiplier > 1) {
-                       dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+               if (intel_crtc->config.pixel_multiplier > 1) {
+                       dpll |= (intel_crtc->config.pixel_multiplier - 1)
+                               << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
                }
                dpll |= DPLL_DVO_HIGH_SPEED;
        }
-       if (is_dp && !is_cpu_edp)
+       if (intel_crtc->config.has_dp_encoder &&
+           intel_crtc->config.has_pch_encoder)
                dpll |= DPLL_DVO_HIGH_SPEED;
 
        /* compute bitmask from p1 value */
@@ -5614,21 +5630,22 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
 }
 
 static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
-                                 struct drm_display_mode *mode,
-                                 struct drm_display_mode *adjusted_mode,
                                  int x, int y,
                                  struct drm_framebuffer *fb)
 {
        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 *adjusted_mode =
+               &intel_crtc->config.adjusted_mode;
+       struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
        int num_connectors = 0;
        intel_clock_t clock, reduced_clock;
        u32 dpll, fp = 0, fp2 = 0;
        bool ok, has_reduced_clock = false;
-       bool is_lvds = false, is_dp = false, is_cpu_edp = false;
+       bool is_lvds = false;
        struct intel_encoder *encoder;
        int ret;
        bool dither, fdi_config_ok;
@@ -5638,14 +5655,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
                        break;
-               case INTEL_OUTPUT_DISPLAYPORT:
-                       is_dp = true;
-                       break;
-               case INTEL_OUTPUT_EDP:
-                       is_dp = true;
-                       if (!intel_encoder_is_pch_edp(&encoder->base))
-                               is_cpu_edp = true;
-                       break;
                }
 
                num_connectors++;
@@ -5654,19 +5663,28 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)),
             "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev));
 
+       intel_crtc->config.cpu_transcoder = pipe;
+
        ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock,
                                     &has_reduced_clock, &reduced_clock);
        if (!ok) {
                DRM_ERROR("Couldn't find PLL settings for mode!\n");
                return -EINVAL;
        }
+       /* Compat-code for transition, will disappear. */
+       if (!intel_crtc->config.clock_set) {
+               intel_crtc->config.dpll.n = clock.n;
+               intel_crtc->config.dpll.m1 = clock.m1;
+               intel_crtc->config.dpll.m2 = clock.m2;
+               intel_crtc->config.dpll.p1 = clock.p1;
+               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);
 
        /* determine panel color depth */
-       dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp,
-                                             adjusted_mode);
+       dither = intel_crtc->config.dither;
        if (is_lvds && dev_priv->lvds_dither)
                dither = true;
 
@@ -5675,13 +5693,14 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
                        reduced_clock.m2;
 
-       dpll = ironlake_compute_dpll(intel_crtc, adjusted_mode, &clock, fp);
+       dpll = ironlake_compute_dpll(intel_crtc, &clock, &fp, &reduced_clock,
+                                    has_reduced_clock ? &fp2 : NULL);
 
        DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
        drm_mode_debug_printmodeline(mode);
 
        /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
-       if (!is_cpu_edp) {
+       if (intel_crtc->config.has_pch_encoder) {
                struct intel_pch_pll *pll;
 
                pll = intel_get_pch_pll(intel_crtc, dpll, fp);
@@ -5693,8 +5712,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        } else
                intel_put_pch_pll(intel_crtc);
 
-       if (is_dp && !is_cpu_edp)
-               intel_dp_set_m_n(crtc, mode, adjusted_mode);
+       if (intel_crtc->config.has_dp_encoder)
+               intel_dp_set_m_n(intel_crtc);
 
        for_each_encoder_on_crtc(dev, crtc, encoder)
                if (encoder->pre_pll_enable)
@@ -5729,8 +5748,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 
        /* Note, this also computes intel_crtc->fdi_lanes which is used below in
         * ironlake_check_fdi_lanes. */
-
-       ironlake_set_m_n(crtc, mode, adjusted_mode);
+       intel_crtc->fdi_lanes = 0;
+       if (intel_crtc->config.has_pch_encoder)
+               ironlake_fdi_set_m_n(crtc);
 
        fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc);
 
@@ -5751,6 +5771,23 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        return fdi_config_ok ? ret : -EINVAL;
 }
 
+static bool ironlake_get_pipe_config(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;
+       uint32_t tmp;
+
+       tmp = I915_READ(PIPECONF(crtc->pipe));
+       if (!(tmp & PIPECONF_ENABLE))
+               return false;
+
+       if (I915_READ(TRANSCONF(crtc->pipe)) & TRANS_ENABLE)
+               pipe_config->has_pch_encoder = true;
+
+       return true;
+}
+
 static void haswell_modeset_global_resources(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5781,29 +5818,26 @@ static void haswell_modeset_global_resources(struct drm_device *dev)
 }
 
 static int haswell_crtc_mode_set(struct drm_crtc *crtc,
-                                struct drm_display_mode *mode,
-                                struct drm_display_mode *adjusted_mode,
                                 int x, int y,
                                 struct drm_framebuffer *fb)
 {
        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 *adjusted_mode =
+               &intel_crtc->config.adjusted_mode;
+       struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
        int num_connectors = 0;
-       bool is_dp = false, is_cpu_edp = false;
+       bool is_cpu_edp = false;
        struct intel_encoder *encoder;
        int ret;
        bool dither;
 
        for_each_encoder_on_crtc(dev, crtc, encoder) {
                switch (encoder->type) {
-               case INTEL_OUTPUT_DISPLAYPORT:
-                       is_dp = true;
-                       break;
                case INTEL_OUTPUT_EDP:
-                       is_dp = true;
                        if (!intel_encoder_is_pch_edp(&encoder->base))
                                is_cpu_edp = true;
                        break;
@@ -5813,9 +5847,9 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
        }
 
        if (is_cpu_edp)
-               intel_crtc->cpu_transcoder = TRANSCODER_EDP;
+               intel_crtc->config.cpu_transcoder = TRANSCODER_EDP;
        else
-               intel_crtc->cpu_transcoder = pipe;
+               intel_crtc->config.cpu_transcoder = pipe;
 
        /* We are not sure yet this won't happen. */
        WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n",
@@ -5824,7 +5858,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
        WARN(num_connectors != 1, "%d connectors attached to pipe %c\n",
             num_connectors, pipe_name(pipe));
 
-       WARN_ON(I915_READ(PIPECONF(intel_crtc->cpu_transcoder)) &
+       WARN_ON(I915_READ(PIPECONF(intel_crtc->config.cpu_transcoder)) &
                (PIPECONF_ENABLE | I965_PIPECONF_ACTIVE));
 
        WARN_ON(I915_READ(DSPCNTR(plane)) & DISPLAY_PLANE_ENABLE);
@@ -5836,25 +5870,24 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
        intel_crtc_update_cursor(crtc, true);
 
        /* determine panel color depth */
-       dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp,
-                                             adjusted_mode);
+       dither = intel_crtc->config.dither;
 
        DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
        drm_mode_debug_printmodeline(mode);
 
-       if (is_dp && !is_cpu_edp)
-               intel_dp_set_m_n(crtc, mode, adjusted_mode);
+       if (intel_crtc->config.has_dp_encoder)
+               intel_dp_set_m_n(intel_crtc);
 
        intel_crtc->lowfreq_avail = false;
 
        intel_set_pipe_timings(intel_crtc, mode, adjusted_mode);
 
-       if (!is_dp || is_cpu_edp)
-               ironlake_set_m_n(crtc, mode, adjusted_mode);
+       if (intel_crtc->config.has_pch_encoder)
+               ironlake_fdi_set_m_n(crtc);
 
        haswell_set_pipeconf(crtc, adjusted_mode, dither);
 
-       intel_set_pipe_csc(crtc, adjusted_mode);
+       intel_set_pipe_csc(crtc);
 
        /* Set up the display plane register */
        I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE | DISPPLANE_PIPE_CSC_ENABLE);
@@ -5869,9 +5902,32 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
        return ret;
 }
 
+static bool haswell_get_pipe_config(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;
+       uint32_t tmp;
+
+       tmp = I915_READ(PIPECONF(crtc->config.cpu_transcoder));
+       if (!(tmp & PIPECONF_ENABLE))
+               return false;
+
+       /*
+        * aswell has only FDI/PCH transcoder A. It is which is connected to
+        * DDI E. So just check whether this pipe is wired to DDI E and whether
+        * the PCH transcoder is on.
+        */
+       tmp = I915_READ(TRANS_DDI_FUNC_CTL(crtc->pipe));
+       if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(PORT_E) &&
+           I915_READ(TRANSCONF(PIPE_A)) & TRANS_ENABLE)
+               pipe_config->has_pch_encoder = true;
+
+
+       return true;
+}
+
 static int intel_crtc_mode_set(struct drm_crtc *crtc,
-                              struct drm_display_mode *mode,
-                              struct drm_display_mode *adjusted_mode,
                               int x, int y,
                               struct drm_framebuffer *fb)
 {
@@ -5880,13 +5936,16 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        struct drm_encoder_helper_funcs *encoder_funcs;
        struct intel_encoder *encoder;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_display_mode *adjusted_mode =
+               &intel_crtc->config.adjusted_mode;
+       struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
        int pipe = intel_crtc->pipe;
        int ret;
 
        drm_vblank_pre_modeset(dev, pipe);
 
-       ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode,
-                                             x, y, fb);
+       ret = dev_priv->display.crtc_mode_set(crtc, x, y, fb);
+
        drm_vblank_post_modeset(dev, pipe);
 
        if (ret != 0)
@@ -5897,8 +5956,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        encoder->base.base.id,
                        drm_get_encoder_name(&encoder->base),
                        mode->base.id, mode->name);
-               encoder_funcs = encoder->base.helper_private;
-               encoder_funcs->mode_set(&encoder->base, mode, adjusted_mode);
+               if (encoder->mode_set) {
+                       encoder->mode_set(encoder);
+               } else {
+                       encoder_funcs = encoder->base.helper_private;
+                       encoder_funcs->mode_set(&encoder->base, mode, adjusted_mode);
+               }
        }
 
        return 0;
@@ -6366,13 +6429,24 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        /* we only need to pin inside GTT if cursor is non-phy */
        mutex_lock(&dev->struct_mutex);
        if (!dev_priv->info->cursor_needs_physical) {
+               unsigned alignment;
+
                if (obj->tiling_mode) {
                        DRM_ERROR("cursor cannot be tiled\n");
                        ret = -EINVAL;
                        goto fail_locked;
                }
 
-               ret = i915_gem_object_pin_to_display_plane(obj, 0, NULL);
+               /* Note that the w/a also requires 2 PTE of padding following
+                * the bo. We currently fill all unused PTE with the shadow
+                * page and so we should always have valid PTE following the
+                * cursor preventing the VT-d warning.
+                */
+               alignment = 0;
+               if (need_vtd_wa(dev))
+                       alignment = 64*1024;
+
+               ret = i915_gem_object_pin_to_display_plane(obj, alignment, NULL);
                if (ret) {
                        DRM_ERROR("failed to move cursor bo into the GTT\n");
                        goto fail_locked;
@@ -6477,20 +6551,6 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
        intel_crtc_load_lut(crtc);
 }
 
-/**
- * Get a pipe with a simple mode set on it for doing load-based monitor
- * detection.
- *
- * It will be up to the load-detect code to adjust the pipe as appropriate for
- * its requirements.  The pipe will be connected to no other encoders.
- *
- * Currently this code will only succeed if there is a pipe with no encoders
- * configured for it.  In the future, it could choose to temporarily disable
- * some outputs to free up a pipe for its use.
- *
- * \return crtc, or NULL if no pipes are available.
- */
-
 /* VESA 640x480x72Hz mode to set on the pipe */
 static struct drm_display_mode load_detect_mode = {
        DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664,
@@ -6817,7 +6877,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+       enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
        struct drm_display_mode *mode;
        int htot = I915_READ(HTOTAL(cpu_transcoder));
        int hsync = I915_READ(HSYNC(cpu_transcoder));
@@ -6993,7 +7053,6 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_unpin_work *work;
-       struct drm_i915_gem_object *obj;
 
        /* Ignore early vblank irqs */
        if (intel_crtc == NULL)
@@ -7022,8 +7081,6 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
 
        lockmgr(&dev->event_lock, LK_RELEASE);
 
-       obj = work->old_fb_obj;
-
        wake_up_all(&dev_priv->pending_flip_queue);
 
        queue_work(dev_priv->wq, &work->work);
@@ -7510,19 +7567,93 @@ static void intel_modeset_commit_output_state(struct drm_device *dev)
        }
 }
 
-static struct drm_display_mode *
-intel_modeset_adjusted_mode(struct drm_crtc *crtc,
-                           struct drm_display_mode *mode)
+static int
+pipe_config_set_bpp(struct drm_crtc *crtc,
+                   struct drm_framebuffer *fb,
+                   struct intel_crtc_config *pipe_config)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_connector *connector;
+       int bpp;
+
+       switch (fb->pixel_format) {
+       case DRM_FORMAT_C8:
+               bpp = 8*3; /* since we go through a colormap */
+               break;
+       case DRM_FORMAT_XRGB1555:
+       case DRM_FORMAT_ARGB1555:
+               /* checked in intel_framebuffer_init already */
+               if (WARN_ON(INTEL_INFO(dev)->gen > 3))
+                       return -EINVAL;
+       case DRM_FORMAT_RGB565:
+               bpp = 6*3; /* min is 18bpp */
+               break;
+       case DRM_FORMAT_XBGR8888:
+       case DRM_FORMAT_ABGR8888:
+               /* checked in intel_framebuffer_init already */
+               if (WARN_ON(INTEL_INFO(dev)->gen < 4))
+                       return -EINVAL;
+       case DRM_FORMAT_XRGB8888:
+       case DRM_FORMAT_ARGB8888:
+               bpp = 8*3;
+               break;
+       case DRM_FORMAT_XRGB2101010:
+       case DRM_FORMAT_ARGB2101010:
+       case DRM_FORMAT_XBGR2101010:
+       case DRM_FORMAT_ABGR2101010:
+               /* checked in intel_framebuffer_init already */
+               if (WARN_ON(INTEL_INFO(dev)->gen < 4))
+                       return -EINVAL;
+               bpp = 10*3;
+               break;
+       /* TODO: gen4+ supports 16 bpc floating point, too. */
+       default:
+               DRM_DEBUG_KMS("unsupported depth\n");
+               return -EINVAL;
+       }
+
+       pipe_config->pipe_bpp = bpp;
+
+       /* Clamp display bpp to EDID value */
+       list_for_each_entry(connector, &dev->mode_config.connector_list,
+                           head) {
+               if (connector->encoder && connector->encoder->crtc != crtc)
+                       continue;
+
+               /* Don't use an invalid EDID bpc value */
+               if (connector->display_info.bpc &&
+                   connector->display_info.bpc * 3 < bpp) {
+                       DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n",
+                                     bpp, connector->display_info.bpc*3);
+                       pipe_config->pipe_bpp = connector->display_info.bpc*3;
+               }
+       }
+
+       return bpp;
+}
+
+static struct intel_crtc_config *
+intel_modeset_pipe_config(struct drm_crtc *crtc,
+                         struct drm_framebuffer *fb,
+                         struct drm_display_mode *mode)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_display_mode *adjusted_mode;
        struct drm_encoder_helper_funcs *encoder_funcs;
        struct intel_encoder *encoder;
+       struct intel_crtc_config *pipe_config;
+       int plane_bpp;
 
-       adjusted_mode = drm_mode_duplicate(dev, mode);
-       if (!adjusted_mode)
+       pipe_config = kmalloc(sizeof(*pipe_config), M_DRM, M_WAITOK | M_ZERO);
+       if (!pipe_config)
                return ERR_PTR(-ENOMEM);
 
+       drm_mode_copy(&pipe_config->adjusted_mode, mode);
+       drm_mode_copy(&pipe_config->requested_mode, mode);
+
+       plane_bpp = pipe_config_set_bpp(crtc, fb, pipe_config);
+       if (plane_bpp < 0)
+               goto fail;
+
        /* Pass our mode to the connectors and the CRTC to give them a chance to
         * adjust it according to limitations or connector properties, and also
         * a chance to reject the mode entirely.
@@ -7532,23 +7663,38 @@ intel_modeset_adjusted_mode(struct drm_crtc *crtc,
 
                if (&encoder->new_crtc->base != crtc)
                        continue;
+
+               if (encoder->compute_config) {
+                       if (!(encoder->compute_config(encoder, pipe_config))) {
+                               DRM_DEBUG_KMS("Encoder config failure\n");
+                               goto fail;
+                       }
+
+                       continue;
+               }
+
                encoder_funcs = encoder->base.helper_private;
-               if (!(encoder_funcs->mode_fixup(&encoder->base, mode,
-                                               adjusted_mode))) {
+               if (!(encoder_funcs->mode_fixup(&encoder->base,
+                                               &pipe_config->requested_mode,
+                                               &pipe_config->adjusted_mode))) {
                        DRM_DEBUG_KMS("Encoder fixup failed\n");
                        goto fail;
                }
        }
 
-       if (!(intel_crtc_mode_fixup(crtc, mode, adjusted_mode))) {
+       if (!(intel_crtc_compute_config(crtc, pipe_config))) {
                DRM_DEBUG_KMS("CRTC fixup failed\n");
                goto fail;
        }
        DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
 
-       return adjusted_mode;
+       pipe_config->dither = pipe_config->pipe_bpp != plane_bpp;
+       DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n",
+                     plane_bpp, pipe_config->pipe_bpp, pipe_config->dither);
+
+       return pipe_config;
 fail:
-       drm_mode_destroy(dev, adjusted_mode);
+       kfree(pipe_config);
        return ERR_PTR(-EINVAL);
 }
 
@@ -7713,12 +7859,29 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
                            base.head) \
                if (mask & (1 <<(intel_crtc)->pipe)) \
 
+static bool
+intel_pipe_config_compare(struct intel_crtc_config *current_config,
+                         struct intel_crtc_config *pipe_config)
+{
+       if (current_config->has_pch_encoder != pipe_config->has_pch_encoder) {
+               DRM_ERROR("mismatch in has_pch_encoder "
+                         "(expected %i, found %i)\n",
+                         current_config->has_pch_encoder,
+                         pipe_config->has_pch_encoder);
+               return false;
+       }
+
+       return true;
+}
+
 void
 intel_modeset_check_state(struct drm_device *dev)
 {
+       drm_i915_private_t *dev_priv = dev->dev_private;
        struct intel_crtc *crtc;
        struct intel_encoder *encoder;
        struct intel_connector *connector;
+       struct intel_crtc_config pipe_config;
 
        list_for_each_entry(connector, &dev->mode_config.connector_list,
                            base.head) {
@@ -7807,7 +7970,21 @@ intel_modeset_check_state(struct drm_device *dev)
                     "crtc's computed enabled state doesn't match tracked enabled state "
                     "(expected %i, found %i)\n", enabled, crtc->base.enabled);
 
-               assert_pipe(dev->dev_private, crtc->pipe, crtc->active);
+               memset(&pipe_config, 0, sizeof(pipe_config));
+               active = dev_priv->display.get_pipe_config(crtc,
+                                                          &pipe_config);
+
+               /* hw state is inconsistent with the pipe A quirk */
+               if (crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
+                       active = crtc->active;
+
+               WARN(crtc->active != active,
+                    "crtc active state doesn't match with hw state "
+                    "(expected %i, found %i)\n", crtc->active, active);
+
+               WARN(active &&
+                    !intel_pipe_config_compare(&crtc->config, &pipe_config),
+                    "pipe state doesn't match!\n");
        }
 }
 
@@ -7817,7 +7994,8 @@ static int __intel_set_mode(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_display_mode *adjusted_mode, *saved_mode, *saved_hwmode;
+       struct drm_display_mode *saved_mode, *saved_hwmode;
+       struct intel_crtc_config *pipe_config = NULL;
        struct intel_crtc *intel_crtc;
        unsigned disable_pipes, prepare_pipes, modeset_pipes;
        int ret = 0;
@@ -7830,12 +8008,6 @@ static int __intel_set_mode(struct drm_crtc *crtc,
        intel_modeset_affected_pipes(crtc, &modeset_pipes,
                                     &prepare_pipes, &disable_pipes);
 
-       DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n",
-                     modeset_pipes, prepare_pipes, disable_pipes);
-
-       for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
-               intel_crtc_disable(&intel_crtc->base);
-
        *saved_hwmode = crtc->hwmode;
        *saved_mode = crtc->mode;
 
@@ -7844,15 +8016,22 @@ static int __intel_set_mode(struct drm_crtc *crtc,
         * Hence simply check whether any bit is set in modeset_pipes in all the
         * pieces of code that are not yet converted to deal with mutliple crtcs
         * changing their mode at the same time. */
-       adjusted_mode = NULL;
        if (modeset_pipes) {
-               adjusted_mode = intel_modeset_adjusted_mode(crtc, mode);
-               if (IS_ERR(adjusted_mode)) {
-                       ret = PTR_ERR(adjusted_mode);
+               pipe_config = intel_modeset_pipe_config(crtc, fb, mode);
+               if (IS_ERR(pipe_config)) {
+                       ret = PTR_ERR(pipe_config);
+                       pipe_config = NULL;
+
                        goto out;
                }
        }
 
+       DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n",
+                     modeset_pipes, prepare_pipes, disable_pipes);
+
+       for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
+               intel_crtc_disable(&intel_crtc->base);
+
        for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) {
                if (intel_crtc->base.enabled)
                        dev_priv->display.crtc_disable(&intel_crtc->base);
@@ -7861,8 +8040,14 @@ static int __intel_set_mode(struct drm_crtc *crtc,
        /* crtc->mode is already used by the ->mode_set callbacks, hence we need
         * to set it here already despite that we pass it down the callchain.
         */
-       if (modeset_pipes)
+       if (modeset_pipes) {
+               enum transcoder tmp = to_intel_crtc(crtc)->config.cpu_transcoder;
                crtc->mode = *mode;
+               /* mode_set/enable/disable functions rely on a correct pipe
+                * config. */
+               to_intel_crtc(crtc)->config = *pipe_config;
+               to_intel_crtc(crtc)->config.cpu_transcoder = tmp;
+       }
 
        /* Only after disabling all output pipelines that will be changed can we
         * update the the output configuration. */
@@ -7876,7 +8061,6 @@ static int __intel_set_mode(struct drm_crtc *crtc,
         */
        for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
                ret = intel_crtc_mode_set(&intel_crtc->base,
-                                         mode, adjusted_mode,
                                          x, y, fb);
                if (ret)
                        goto done;
@@ -7888,7 +8072,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
 
        if (modeset_pipes) {
                /* Store real post-adjustment hardware mode. */
-               crtc->hwmode = *adjusted_mode;
+               crtc->hwmode = pipe_config->adjusted_mode;
 
                /* Calculate and store various constants which
                 * are later needed by vblank and swap-completion
@@ -7899,13 +8083,13 @@ static int __intel_set_mode(struct drm_crtc *crtc,
 
        /* FIXME: add subpixel order */
 done:
-       drm_mode_destroy(dev, adjusted_mode);
        if (ret && crtc->enabled) {
                crtc->hwmode = *saved_hwmode;
                crtc->mode = *saved_mode;
        }
 
 out:
+       kfree(pipe_config);
        kfree(saved_mode);
        return ret;
 }
@@ -8030,10 +8214,8 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
                        config->mode_changed = true;
                } else if (set->fb == NULL) {
                        config->mode_changed = true;
-               } else if (set->fb->depth != set->crtc->fb->depth) {
-                       config->mode_changed = true;
-               } else if (set->fb->bits_per_pixel !=
-                          set->crtc->fb->bits_per_pixel) {
+               } else if (set->fb->pixel_format !=
+                          set->crtc->fb->pixel_format) {
                        config->mode_changed = true;
                } else {
                        config->fb_changed = true;
@@ -8211,28 +8393,25 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
 
                ret = intel_set_mode(set->crtc, set->mode,
                                     set->x, set->y, set->fb);
-               if (ret) {
-                       DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n",
-                                 set->crtc->base.id, ret);
-                       goto fail;
-               }
        } else if (config->fb_changed) {
+               intel_crtc_wait_for_pending_flips(set->crtc);
+
                ret = intel_pipe_set_base(set->crtc,
                                          set->x, set->y, set->fb);
        }
 
-       intel_set_config_free(config);
-
-       return 0;
-
+       if (ret) {
+               DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n",
+                         set->crtc->base.id, ret);
 fail:
-       intel_set_config_restore_state(dev, config);
+               intel_set_config_restore_state(dev, config);
 
-       /* Try to restore the config */
-       if (config->mode_changed &&
-           intel_set_mode(save_set.crtc, save_set.mode,
-                          save_set.x, save_set.y, save_set.fb))
-               DRM_ERROR("failed to restore config after modeset failure\n");
+               /* Try to restore the config */
+               if (config->mode_changed &&
+                   intel_set_mode(save_set.crtc, save_set.mode,
+                                  save_set.x, save_set.y, save_set.fb))
+                       DRM_ERROR("failed to restore config after modeset failure\n");
+       }
 
 out_config:
        intel_set_config_free(config);
@@ -8295,7 +8474,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        /* Swap pipes & planes for FBC on pre-965 */
        intel_crtc->pipe = pipe;
        intel_crtc->plane = pipe;
-       intel_crtc->cpu_transcoder = pipe;
+       intel_crtc->config.cpu_transcoder = pipe;
        if (IS_MOBILE(dev) && IS_GEN3(dev)) {
                DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
                intel_crtc->plane = !pipe;
@@ -8306,8 +8485,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
        dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
 
-       intel_crtc->bpp = 24; /* default for pre-Ironlake */
-
        drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
 }
 
@@ -8417,20 +8594,20 @@ static void intel_setup_outputs(struct drm_device *dev)
                if (has_edp_a(dev))
                        intel_dp_init(dev, DP_A, PORT_A);
 
-               if (I915_READ(HDMIB) & PORT_DETECTED) {
+               if (I915_READ(PCH_HDMIB) & SDVO_DETECTED) {
                        /* PCH SDVOB multiplex with HDMIB */
                        found = intel_sdvo_init(dev, PCH_SDVOB, true);
                        if (!found)
-                               intel_hdmi_init(dev, HDMIB, PORT_B);
+                               intel_hdmi_init(dev, PCH_HDMIB, PORT_B);
                        if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
                                intel_dp_init(dev, PCH_DP_B, PORT_B);
                }
 
-               if (I915_READ(HDMIC) & PORT_DETECTED)
-                       intel_hdmi_init(dev, HDMIC, PORT_C);
+               if (I915_READ(PCH_HDMIC) & SDVO_DETECTED)
+                       intel_hdmi_init(dev, PCH_HDMIC, PORT_C);
 
-               if (!dpd_is_edp && I915_READ(HDMID) & PORT_DETECTED)
-                       intel_hdmi_init(dev, HDMID, PORT_D);
+               if (!dpd_is_edp && I915_READ(PCH_HDMID) & SDVO_DETECTED)
+                       intel_hdmi_init(dev, PCH_HDMID, PORT_D);
 
                if (I915_READ(PCH_DP_C) & DP_DETECTED)
                        intel_dp_init(dev, PCH_DP_C, PORT_C);
@@ -8442,24 +8619,21 @@ static void intel_setup_outputs(struct drm_device *dev)
                if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED)
                        intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C);
 
-               if (I915_READ(VLV_DISPLAY_BASE + SDVOB) & PORT_DETECTED) {
-                       intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOB, PORT_B);
+               if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED) {
+                       intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB,
+                                       PORT_B);
                        if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED)
                                intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B);
                }
-
-               if (I915_READ(VLV_DISPLAY_BASE + SDVOC) & PORT_DETECTED)
-                       intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOC, PORT_C);
-
        } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) {
                bool found = false;
 
-               if (I915_READ(SDVOB) & SDVO_DETECTED) {
+               if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) {
                        DRM_DEBUG_KMS("probing SDVOB\n");
-                       found = intel_sdvo_init(dev, SDVOB, true);
+                       found = intel_sdvo_init(dev, GEN3_SDVOB, true);
                        if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) {
                                DRM_DEBUG_KMS("probing HDMI on SDVOB\n");
-                               intel_hdmi_init(dev, SDVOB, PORT_B);
+                               intel_hdmi_init(dev, GEN4_HDMIB, PORT_B);
                        }
 
                        if (!found && SUPPORTS_INTEGRATED_DP(dev)) {
@@ -8470,16 +8644,16 @@ static void intel_setup_outputs(struct drm_device *dev)
 
                /* Before G4X SDVOC doesn't have its own detect register */
 
-               if (I915_READ(SDVOB) & SDVO_DETECTED) {
+               if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) {
                        DRM_DEBUG_KMS("probing SDVOC\n");
-                       found = intel_sdvo_init(dev, SDVOC, false);
+                       found = intel_sdvo_init(dev, GEN3_SDVOC, false);
                }
 
-               if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) {
+               if (!found && (I915_READ(GEN3_SDVOC) & SDVO_DETECTED)) {
 
                        if (SUPPORTS_INTEGRATED_HDMI(dev)) {
                                DRM_DEBUG_KMS("probing HDMI on SDVOC\n");
-                               intel_hdmi_init(dev, SDVOC, PORT_C);
+                               intel_hdmi_init(dev, GEN4_HDMIC, PORT_C);
                        }
                        if (SUPPORTS_INTEGRATED_DP(dev)) {
                                DRM_DEBUG_KMS("probing DP_C\n");
@@ -8649,20 +8823,22 @@ static void intel_init_display(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       /* We always want a DPMS function */
        if (HAS_DDI(dev)) {
+               dev_priv->display.get_pipe_config = haswell_get_pipe_config;
                dev_priv->display.crtc_mode_set = haswell_crtc_mode_set;
                dev_priv->display.crtc_enable = haswell_crtc_enable;
                dev_priv->display.crtc_disable = haswell_crtc_disable;
                dev_priv->display.off = haswell_crtc_off;
                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.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.off = ironlake_crtc_off;
                dev_priv->display.update_plane = ironlake_update_plane;
        } else {
+               dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
                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;
@@ -8909,7 +9085,7 @@ void intel_modeset_init_hw(struct drm_device *dev)
 void intel_modeset_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int i, ret;
+       int i, j, ret;
 
        drm_mode_config_init(dev);
 
@@ -8925,6 +9101,9 @@ void intel_modeset_init(struct drm_device *dev)
 
        intel_init_pm(dev);
 
+       if (INTEL_INFO(dev)->num_pipes == 0)
+               return;
+
        intel_init_display(dev);
 
        if (IS_GEN2(dev)) {
@@ -8940,13 +9119,17 @@ void intel_modeset_init(struct drm_device *dev)
        dev->mode_config.fb_base = dev->agp->base;
 
        DRM_DEBUG_KMS("%d display pipe%s available.\n",
-                     dev_priv->num_pipe, dev_priv->num_pipe > 1 ? "s" : "");
+                     INTEL_INFO(dev)->num_pipes,
+                     INTEL_INFO(dev)->num_pipes > 1 ? "s" : "");
 
-       for (i = 0; i < dev_priv->num_pipe; i++) {
+       for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) {
                intel_crtc_init(dev, i);
-               ret = intel_plane_init(dev, i);
-               if (ret)
-                       DRM_DEBUG_KMS("plane %d init failed: %d\n", i, ret);
+               for (j = 0; j < dev_priv->num_plane; j++) {
+                       ret = intel_plane_init(dev, i, j);
+                       if (ret)
+                               DRM_DEBUG_KMS("pipe %d plane %d init failed: %d\n",
+                                             i, j, ret);
+               }
        }
 
        intel_cpu_pll_init(dev);
@@ -8999,10 +9182,11 @@ static void intel_enable_pipe_a(struct drm_device *dev)
 static bool
 intel_check_plane_mapping(struct intel_crtc *crtc)
 {
-       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 reg, val;
 
-       if (dev_priv->num_pipe == 1)
+       if (INTEL_INFO(dev)->num_pipes == 1)
                return true;
 
        reg = DSPCNTR(!crtc->plane);
@@ -9022,7 +9206,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
        u32 reg;
 
        /* Clear any frame start delays used for debugging left by the BIOS */
-       reg = PIPECONF(crtc->cpu_transcoder);
+       reg = PIPECONF(crtc->config.cpu_transcoder);
        I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
 
        /* We need to sanitize the plane -> pipe mapping first because this will
@@ -9158,6 +9342,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum i915_pipe pipe;
        u32 tmp;
+       struct drm_plane *plane;
        struct intel_crtc *crtc;
        struct intel_encoder *encoder;
        struct intel_connector *connector;
@@ -9177,24 +9362,32 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
                        case TRANS_DDI_EDP_INPUT_C_ONOFF:
                                pipe = PIPE_C;
                                break;
+                       default:
+                               /* A bogus value has been programmed, disable
+                                * the transcoder */
+                               WARN(1, "Bogus eDP source %08x\n", tmp);
+                               intel_ddi_disable_transcoder_func(dev_priv,
+                                               TRANSCODER_EDP);
+                               goto setup_pipes;
                        }
 
                        crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
-                       crtc->cpu_transcoder = TRANSCODER_EDP;
+                       crtc->config.cpu_transcoder = TRANSCODER_EDP;
 
                        DRM_DEBUG_KMS("Pipe %c using transcoder EDP\n",
                                      pipe_name(pipe));
                }
        }
 
-       for_each_pipe(pipe) {
-               crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+setup_pipes:
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+                           base.head) {
+               enum transcoder tmp = crtc->config.cpu_transcoder;
+               memset(&crtc->config, 0, sizeof(crtc->config));
+               crtc->config.cpu_transcoder = tmp;
 
-               tmp = I915_READ(PIPECONF(crtc->cpu_transcoder));
-               if (tmp & PIPECONF_ENABLE)
-                       crtc->active = true;
-               else
-                       crtc->active = false;
+               crtc->active = dev_priv->display.get_pipe_config(crtc,
+                                                                &crtc->config);
 
                crtc->base.enabled = crtc->active;
 
@@ -9258,12 +9451,14 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
                 * checking (bogus) intermediate states.
                 */
                for_each_pipe(pipe) {
-                       struct drm_crtc *crtc =
-                               dev_priv->pipe_to_crtc_mapping[pipe];
+                       struct drm_crtc *crtc =
+                               dev_priv->pipe_to_crtc_mapping[pipe];
 
                        __intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
                                         crtc->fb);
                }
+               list_for_each_entry(plane, &dev->mode_config.plane_list, head)
+                       intel_plane_restore(plane);
 
                i915_redisable_vga(dev);
        } else {
@@ -9416,15 +9611,24 @@ intel_display_capture_error_state(struct drm_device *dev)
        for_each_pipe(i) {
                cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, i);
 
-               error->cursor[i].control = I915_READ(CURCNTR(i));
-               error->cursor[i].position = I915_READ(CURPOS(i));
-               error->cursor[i].base = I915_READ(CURBASE(i));
+               if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) {
+                       error->cursor[i].control = I915_READ(CURCNTR(i));
+                       error->cursor[i].position = I915_READ(CURPOS(i));
+                       error->cursor[i].base = I915_READ(CURBASE(i));
+               } else {
+                       error->cursor[i].control = I915_READ(CURCNTR_IVB(i));
+                       error->cursor[i].position = I915_READ(CURPOS_IVB(i));
+                       error->cursor[i].base = I915_READ(CURBASE_IVB(i));
+               }