]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'drm-intel-next-2013-06-01' of git://people.freedesktop.org/~danvet/drm...
authorDave Airlie <airlied@redhat.com>
Mon, 10 Jun 2013 22:38:56 +0000 (08:38 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 10 Jun 2013 22:38:56 +0000 (08:38 +1000)
Daniel writes:
Another round of drm-intel-next for 3.11. Highlights:
- Haswell IPS support (Paulo Zanoni)
- VECS support on Haswell (Ben Widawsky, Xiang Haihao, ...)
- Haswell watermark fixes (Paulo Zanoni)
- "Make the gun bigger again" multithread fence fix from Chris.
- i915_error_state finnally no longer fails with -ENOMEM! Big thanks to
  Mika for tackling this.
- vlv sideband locking fixes from Jani
- Hangcheck prep work for arb_robustness support (Mika&Chris)
- edp vs cpu port confusion clean-up from Imre
- pile of smaller fixes and cleanups all over.

* tag 'drm-intel-next-2013-06-01' of git://people.freedesktop.org/~danvet/drm-intel: (70 commits)
  drm/i915: add i915_ips_status debugfs entry
  drm/i915: add enable_ips module option
  drm/i915: implement IPS feature
  drm/i915: fix up the edp power well check
  drm/i915: add I915_PARAM_HAS_VEBOX to i915_getparam
  drm/i915: add I915_EXEC_VEBOX to i915_gem_do_execbuffer()
  drm/i915: add VEBOX into debugfs
  drm/i915: Enable vebox interrupts
  drm/i915: vebox interrupt get/put
  drm/i915: consolidate interrupt naming scheme
  drm/i915: Convert irq_refounct to struct
  drm/i915: make PM interrupt writes non-destructive
  drm/i915: Add PM regs to pre/post install
  drm/i915: Create an ivybridge_irq_preinstall
  drm/i915: Create a more generic pm handler for hsw+
  drm/i915: add support for 5/6 data buffer partitioning on Haswell
  drm/i915: properly set HSW WM_LP watermarks
  drm/i915: properly set HSW WM_PIPE registers
  drm/i915: fix pch_nop support
  drm/i915: Vebox ringbuffer init
  ...

30 files changed:
Documentation/DocBook/drm.tmpl
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sideband.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_sprite.c
include/drm/drm_rect.h
include/uapi/drm/i915_drm.h

index 7c7af25b330ca21be141624349b6a235de7ba092..91ee107d5d0edc819ce183f7465e720b064f1bc6 100644 (file)
@@ -1653,8 +1653,6 @@ void intel_crt_init(struct drm_device *dev)
     <sect2>
       <title>KMS API Functions</title>
 !Edrivers/gpu/drm/drm_crtc.c
-!Edrivers/gpu/drm/drm_rect.c
-!Finclude/drm/drm_rect.h
     </sect2>
   </sect1>
 
@@ -2163,6 +2161,12 @@ void intel_crt_init(struct drm_device *dev)
       <title>EDID Helper Functions Reference</title>
 !Edrivers/gpu/drm/drm_edid.c
     </sect2>
+    <sect2>
+      <title>Rectangle Utilities Reference</title>
+!Pinclude/drm/drm_rect.h rect utils
+!Iinclude/drm/drm_rect.h
+!Edrivers/gpu/drm/drm_rect.c
+    </sect2>
   </sect1>
 
   <!-- Internals: vertical blanking -->
index 91f3ac6cef35742d931060bb49049f116ac0fa25..40034ecefd3b977a435f661f5f8a057392fb9fe0 100644 (file)
@@ -36,6 +36,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
          intel_overlay.o \
          intel_sprite.o \
          intel_opregion.o \
+         intel_sideband.o \
          dvo_ch7xxx.o \
          dvo_ch7017.o \
          dvo_ivch.o \
index a55630a80f830ace22762ed0bd288428733bd812..76255a69752aa5129ae167fff01c7267c00feeb1 100644 (file)
@@ -570,6 +570,7 @@ static const char *ring_str(int ring)
        case RCS: return "render";
        case VCS: return "bsd";
        case BCS: return "blt";
+       case VECS: return "vebox";
        default: return "";
        }
 }
@@ -604,15 +605,80 @@ static const char *purgeable_flag(int purgeable)
        return purgeable ? " purgeable" : "";
 }
 
-static void print_error_buffers(struct seq_file *m,
+static void i915_error_vprintf(struct drm_i915_error_state_buf *e,
+                              const char *f, va_list args)
+{
+       unsigned len;
+
+       if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) {
+               e->err = -ENOSPC;
+               return;
+       }
+
+       if (e->bytes == e->size - 1 || e->err)
+               return;
+
+       /* Seek the first printf which is hits start position */
+       if (e->pos < e->start) {
+               len = vsnprintf(NULL, 0, f, args);
+               if (e->pos + len <= e->start) {
+                       e->pos += len;
+                       return;
+               }
+
+               /* First vsnprintf needs to fit in full for memmove*/
+               if (len >= e->size) {
+                       e->err = -EIO;
+                       return;
+               }
+       }
+
+       len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args);
+       if (len >= e->size - e->bytes)
+               len = e->size - e->bytes - 1;
+
+       /* If this is first printf in this window, adjust it so that
+        * start position matches start of the buffer
+        */
+       if (e->pos < e->start) {
+               const size_t off = e->start - e->pos;
+
+               /* Should not happen but be paranoid */
+               if (off > len || e->bytes) {
+                       e->err = -EIO;
+                       return;
+               }
+
+               memmove(e->buf, e->buf + off, len - off);
+               e->bytes = len - off;
+               e->pos = e->start;
+               return;
+       }
+
+       e->bytes += len;
+       e->pos += len;
+}
+
+void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
+{
+       va_list args;
+
+       va_start(args, f);
+       i915_error_vprintf(e, f, args);
+       va_end(args);
+}
+
+#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__)
+
+static void print_error_buffers(struct drm_i915_error_state_buf *m,
                                const char *name,
                                struct drm_i915_error_buffer *err,
                                int count)
 {
-       seq_printf(m, "%s [%d]:\n", name, count);
+       err_printf(m, "%s [%d]:\n", name, count);
 
        while (count--) {
-               seq_printf(m, "  %08x %8u %02x %02x %x %x%s%s%s%s%s%s%s",
+               err_printf(m, "  %08x %8u %02x %02x %x %x%s%s%s%s%s%s%s",
                           err->gtt_offset,
                           err->size,
                           err->read_domains,
@@ -627,50 +693,50 @@ static void print_error_buffers(struct seq_file *m,
                           cache_level_str(err->cache_level));
 
                if (err->name)
-                       seq_printf(m, " (name: %d)", err->name);
+                       err_printf(m, " (name: %d)", err->name);
                if (err->fence_reg != I915_FENCE_REG_NONE)
-                       seq_printf(m, " (fence: %d)", err->fence_reg);
+                       err_printf(m, " (fence: %d)", err->fence_reg);
 
-               seq_printf(m, "\n");
+               err_printf(m, "\n");
                err++;
        }
 }
 
-static void i915_ring_error_state(struct seq_file *m,
+static void i915_ring_error_state(struct drm_i915_error_state_buf *m,
                                  struct drm_device *dev,
                                  struct drm_i915_error_state *error,
                                  unsigned ring)
 {
        BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */
-       seq_printf(m, "%s command stream:\n", ring_str(ring));
-       seq_printf(m, "  HEAD: 0x%08x\n", error->head[ring]);
-       seq_printf(m, "  TAIL: 0x%08x\n", error->tail[ring]);
-       seq_printf(m, "  CTL: 0x%08x\n", error->ctl[ring]);
-       seq_printf(m, "  ACTHD: 0x%08x\n", error->acthd[ring]);
-       seq_printf(m, "  IPEIR: 0x%08x\n", error->ipeir[ring]);
-       seq_printf(m, "  IPEHR: 0x%08x\n", error->ipehr[ring]);
-       seq_printf(m, "  INSTDONE: 0x%08x\n", error->instdone[ring]);
+       err_printf(m, "%s command stream:\n", ring_str(ring));
+       err_printf(m, "  HEAD: 0x%08x\n", error->head[ring]);
+       err_printf(m, "  TAIL: 0x%08x\n", error->tail[ring]);
+       err_printf(m, "  CTL: 0x%08x\n", error->ctl[ring]);
+       err_printf(m, "  ACTHD: 0x%08x\n", error->acthd[ring]);
+       err_printf(m, "  IPEIR: 0x%08x\n", error->ipeir[ring]);
+       err_printf(m, "  IPEHR: 0x%08x\n", error->ipehr[ring]);
+       err_printf(m, "  INSTDONE: 0x%08x\n", error->instdone[ring]);
        if (ring == RCS && INTEL_INFO(dev)->gen >= 4)
-               seq_printf(m, "  BBADDR: 0x%08llx\n", error->bbaddr);
+               err_printf(m, "  BBADDR: 0x%08llx\n", error->bbaddr);
 
        if (INTEL_INFO(dev)->gen >= 4)
-               seq_printf(m, "  INSTPS: 0x%08x\n", error->instps[ring]);
-       seq_printf(m, "  INSTPM: 0x%08x\n", error->instpm[ring]);
-       seq_printf(m, "  FADDR: 0x%08x\n", error->faddr[ring]);
+               err_printf(m, "  INSTPS: 0x%08x\n", error->instps[ring]);
+       err_printf(m, "  INSTPM: 0x%08x\n", error->instpm[ring]);
+       err_printf(m, "  FADDR: 0x%08x\n", error->faddr[ring]);
        if (INTEL_INFO(dev)->gen >= 6) {
-               seq_printf(m, "  RC PSMI: 0x%08x\n", error->rc_psmi[ring]);
-               seq_printf(m, "  FAULT_REG: 0x%08x\n", error->fault_reg[ring]);
-               seq_printf(m, "  SYNC_0: 0x%08x [last synced 0x%08x]\n",
+               err_printf(m, "  RC PSMI: 0x%08x\n", error->rc_psmi[ring]);
+               err_printf(m, "  FAULT_REG: 0x%08x\n", error->fault_reg[ring]);
+               err_printf(m, "  SYNC_0: 0x%08x [last synced 0x%08x]\n",
                           error->semaphore_mboxes[ring][0],
                           error->semaphore_seqno[ring][0]);
-               seq_printf(m, "  SYNC_1: 0x%08x [last synced 0x%08x]\n",
+               err_printf(m, "  SYNC_1: 0x%08x [last synced 0x%08x]\n",
                           error->semaphore_mboxes[ring][1],
                           error->semaphore_seqno[ring][1]);
        }
-       seq_printf(m, "  seqno: 0x%08x\n", error->seqno[ring]);
-       seq_printf(m, "  waiting: %s\n", yesno(error->waiting[ring]));
-       seq_printf(m, "  ring->head: 0x%08x\n", error->cpu_ring_head[ring]);
-       seq_printf(m, "  ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]);
+       err_printf(m, "  seqno: 0x%08x\n", error->seqno[ring]);
+       err_printf(m, "  waiting: %s\n", yesno(error->waiting[ring]));
+       err_printf(m, "  ring->head: 0x%08x\n", error->cpu_ring_head[ring]);
+       err_printf(m, "  ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]);
 }
 
 struct i915_error_state_file_priv {
@@ -678,9 +744,11 @@ struct i915_error_state_file_priv {
        struct drm_i915_error_state *error;
 };
 
-static int i915_error_state(struct seq_file *m, void *unused)
+
+static int i915_error_state(struct i915_error_state_file_priv *error_priv,
+                           struct drm_i915_error_state_buf *m)
+
 {
-       struct i915_error_state_file_priv *error_priv = m->private;
        struct drm_device *dev = error_priv->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_error_state *error = error_priv->error;
@@ -688,34 +756,35 @@ static int i915_error_state(struct seq_file *m, void *unused)
        int i, j, page, offset, elt;
 
        if (!error) {
-               seq_printf(m, "no error state collected\n");
+               err_printf(m, "no error state collected\n");
                return 0;
        }
 
-       seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
+       err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
                   error->time.tv_usec);
-       seq_printf(m, "Kernel: " UTS_RELEASE "\n");
-       seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
-       seq_printf(m, "EIR: 0x%08x\n", error->eir);
-       seq_printf(m, "IER: 0x%08x\n", error->ier);
-       seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
-       seq_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake);
-       seq_printf(m, "DERRMR: 0x%08x\n", error->derrmr);
-       seq_printf(m, "CCID: 0x%08x\n", error->ccid);
+       err_printf(m, "Kernel: " UTS_RELEASE "\n");
+       err_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
+       err_printf(m, "EIR: 0x%08x\n", error->eir);
+       err_printf(m, "IER: 0x%08x\n", error->ier);
+       err_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
+       err_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake);
+       err_printf(m, "DERRMR: 0x%08x\n", error->derrmr);
+       err_printf(m, "CCID: 0x%08x\n", error->ccid);
 
        for (i = 0; i < dev_priv->num_fence_regs; i++)
-               seq_printf(m, "  fence[%d] = %08llx\n", i, error->fence[i]);
+               err_printf(m, "  fence[%d] = %08llx\n", i, error->fence[i]);
 
        for (i = 0; i < ARRAY_SIZE(error->extra_instdone); i++)
-               seq_printf(m, "  INSTDONE_%d: 0x%08x\n", i, error->extra_instdone[i]);
+               err_printf(m, "  INSTDONE_%d: 0x%08x\n", i,
+                          error->extra_instdone[i]);
 
        if (INTEL_INFO(dev)->gen >= 6) {
-               seq_printf(m, "ERROR: 0x%08x\n", error->error);
-               seq_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
+               err_printf(m, "ERROR: 0x%08x\n", error->error);
+               err_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
        }
 
        if (INTEL_INFO(dev)->gen == 7)
-               seq_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
+               err_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
 
        for_each_ring(ring, dev_priv, i)
                i915_ring_error_state(m, dev, error, i);
@@ -734,24 +803,25 @@ static int i915_error_state(struct seq_file *m, void *unused)
                struct drm_i915_error_object *obj;
 
                if ((obj = error->ring[i].batchbuffer)) {
-                       seq_printf(m, "%s --- gtt_offset = 0x%08x\n",
+                       err_printf(m, "%s --- gtt_offset = 0x%08x\n",
                                   dev_priv->ring[i].name,
                                   obj->gtt_offset);
                        offset = 0;
                        for (page = 0; page < obj->page_count; page++) {
                                for (elt = 0; elt < PAGE_SIZE/4; elt++) {
-                                       seq_printf(m, "%08x :  %08x\n", offset, obj->pages[page][elt]);
+                                       err_printf(m, "%08x :  %08x\n", offset,
+                                                  obj->pages[page][elt]);
                                        offset += 4;
                                }
                        }
                }
 
                if (error->ring[i].num_requests) {
-                       seq_printf(m, "%s --- %d requests\n",
+                       err_printf(m, "%s --- %d requests\n",
                                   dev_priv->ring[i].name,
                                   error->ring[i].num_requests);
                        for (j = 0; j < error->ring[i].num_requests; j++) {
-                               seq_printf(m, "  seqno 0x%08x, emitted %ld, tail 0x%08x\n",
+                               err_printf(m, "  seqno 0x%08x, emitted %ld, tail 0x%08x\n",
                                           error->ring[i].requests[j].seqno,
                                           error->ring[i].requests[j].jiffies,
                                           error->ring[i].requests[j].tail);
@@ -759,13 +829,13 @@ static int i915_error_state(struct seq_file *m, void *unused)
                }
 
                if ((obj = error->ring[i].ringbuffer)) {
-                       seq_printf(m, "%s --- ringbuffer = 0x%08x\n",
+                       err_printf(m, "%s --- ringbuffer = 0x%08x\n",
                                   dev_priv->ring[i].name,
                                   obj->gtt_offset);
                        offset = 0;
                        for (page = 0; page < obj->page_count; page++) {
                                for (elt = 0; elt < PAGE_SIZE/4; elt++) {
-                                       seq_printf(m, "%08x :  %08x\n",
+                                       err_printf(m, "%08x :  %08x\n",
                                                   offset,
                                                   obj->pages[page][elt]);
                                        offset += 4;
@@ -775,12 +845,12 @@ 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",
+                       err_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",
+                               err_printf(m, "[%04x] %08x %08x %08x %08x\n",
                                           offset,
                                           obj->pages[0][elt],
                                           obj->pages[0][elt+1],
@@ -806,8 +876,7 @@ i915_error_state_write(struct file *filp,
                       size_t cnt,
                       loff_t *ppos)
 {
-       struct seq_file *m = filp->private_data;
-       struct i915_error_state_file_priv *error_priv = m->private;
+       struct i915_error_state_file_priv *error_priv = filp->private_data;
        struct drm_device *dev = error_priv->dev;
        int ret;
 
@@ -842,25 +911,81 @@ static int i915_error_state_open(struct inode *inode, struct file *file)
                kref_get(&error_priv->error->ref);
        spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
 
-       return single_open(file, i915_error_state, error_priv);
+       file->private_data = error_priv;
+
+       return 0;
 }
 
 static int i915_error_state_release(struct inode *inode, struct file *file)
 {
-       struct seq_file *m = file->private_data;
-       struct i915_error_state_file_priv *error_priv = m->private;
+       struct i915_error_state_file_priv *error_priv = file->private_data;
 
        if (error_priv->error)
                kref_put(&error_priv->error->ref, i915_error_state_free);
        kfree(error_priv);
 
-       return single_release(inode, file);
+       return 0;
+}
+
+static ssize_t i915_error_state_read(struct file *file, char __user *userbuf,
+                                    size_t count, loff_t *pos)
+{
+       struct i915_error_state_file_priv *error_priv = file->private_data;
+       struct drm_i915_error_state_buf error_str;
+       loff_t tmp_pos = 0;
+       ssize_t ret_count = 0;
+       int ret = 0;
+
+       memset(&error_str, 0, sizeof(error_str));
+
+       /* We need to have enough room to store any i915_error_state printf
+        * so that we can move it to start position.
+        */
+       error_str.size = count + 1 > PAGE_SIZE ? count + 1 : PAGE_SIZE;
+       error_str.buf = kmalloc(error_str.size,
+                               GFP_TEMPORARY | __GFP_NORETRY | __GFP_NOWARN);
+
+       if (error_str.buf == NULL) {
+               error_str.size = PAGE_SIZE;
+               error_str.buf = kmalloc(error_str.size, GFP_TEMPORARY);
+       }
+
+       if (error_str.buf == NULL) {
+               error_str.size = 128;
+               error_str.buf = kmalloc(error_str.size, GFP_TEMPORARY);
+       }
+
+       if (error_str.buf == NULL)
+               return -ENOMEM;
+
+       error_str.start = *pos;
+
+       ret = i915_error_state(error_priv, &error_str);
+       if (ret)
+               goto out;
+
+       if (error_str.bytes == 0 && error_str.err) {
+               ret = error_str.err;
+               goto out;
+       }
+
+       ret_count = simple_read_from_buffer(userbuf, count, &tmp_pos,
+                                           error_str.buf,
+                                           error_str.bytes);
+
+       if (ret_count < 0)
+               ret = ret_count;
+       else
+               *pos = error_str.start + ret_count;
+out:
+       kfree(error_str.buf);
+       return ret ?: ret_count;
 }
 
 static const struct file_operations i915_error_state_fops = {
        .owner = THIS_MODULE,
        .open = i915_error_state_open,
-       .read = seq_read,
+       .read = i915_error_state_read,
        .write = i915_error_state_write,
        .llseek = default_llseek,
        .release = i915_error_state_release,
@@ -1013,16 +1138,15 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                u32 freq_sts, val;
 
                mutex_lock(&dev_priv->rps.hw_lock);
-               valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS,
-                                     &freq_sts);
+               freq_sts = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
                seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts);
                seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq);
 
-               valleyview_punit_read(dev_priv, PUNIT_FUSE_BUS1, &val);
+               val = vlv_punit_read(dev_priv, PUNIT_FUSE_BUS1);
                seq_printf(m, "max GPU freq: %d MHz\n",
                           vlv_gpu_freq(dev_priv->mem_freq, val));
 
-               valleyview_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val);
+               val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM);
                seq_printf(m, "min GPU freq: %d MHz\n",
                           vlv_gpu_freq(dev_priv->mem_freq, val));
 
@@ -1311,6 +1435,25 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
        return 0;
 }
 
+static int i915_ips_status(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!IS_ULT(dev)) {
+               seq_puts(m, "not supported\n");
+               return 0;
+       }
+
+       if (I915_READ(IPS_CTL) & IPS_ENABLE)
+               seq_puts(m, "enabled\n");
+       else
+               seq_puts(m, "disabled\n");
+
+       return 0;
+}
+
 static int i915_sr_status(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -1663,27 +1806,27 @@ static int i915_dpio_info(struct seq_file *m, void *data)
        seq_printf(m, "DPIO_CTL: 0x%08x\n", I915_READ(DPIO_CTL));
 
        seq_printf(m, "DPIO_DIV_A: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_DIV_A));
+                  vlv_dpio_read(dev_priv, _DPIO_DIV_A));
        seq_printf(m, "DPIO_DIV_B: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_DIV_B));
+                  vlv_dpio_read(dev_priv, _DPIO_DIV_B));
 
        seq_printf(m, "DPIO_REFSFR_A: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_REFSFR_A));
+                  vlv_dpio_read(dev_priv, _DPIO_REFSFR_A));
        seq_printf(m, "DPIO_REFSFR_B: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_REFSFR_B));
+                  vlv_dpio_read(dev_priv, _DPIO_REFSFR_B));
 
        seq_printf(m, "DPIO_CORE_CLK_A: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_CORE_CLK_A));
+                  vlv_dpio_read(dev_priv, _DPIO_CORE_CLK_A));
        seq_printf(m, "DPIO_CORE_CLK_B: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_CORE_CLK_B));
+                  vlv_dpio_read(dev_priv, _DPIO_CORE_CLK_B));
 
        seq_printf(m, "DPIO_LFP_COEFF_A: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_LFP_COEFF_A));
+                  vlv_dpio_read(dev_priv, _DPIO_LFP_COEFF_A));
        seq_printf(m, "DPIO_LFP_COEFF_B: 0x%08x\n",
-                  intel_dpio_read(dev_priv, _DPIO_LFP_COEFF_B));
+                  vlv_dpio_read(dev_priv, _DPIO_LFP_COEFF_B));
 
        seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n",
-                  intel_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE));
+                  vlv_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE));
 
        mutex_unlock(&dev_priv->dpio_lock);
 
@@ -2099,6 +2242,7 @@ static struct drm_info_list i915_debugfs_list[] = {
        {"i915_gem_hws", i915_hws_info, 0, (void *)RCS},
        {"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS},
        {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
+       {"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS},
        {"i915_rstdby_delays", i915_rstdby_delays, 0},
        {"i915_cur_delayinfo", i915_cur_delayinfo, 0},
        {"i915_delayfreq_table", i915_delayfreq_table, 0},
@@ -2108,6 +2252,7 @@ static struct drm_info_list i915_debugfs_list[] = {
        {"i915_ring_freq_table", i915_ring_freq_table, 0},
        {"i915_gfxec", i915_gfxec, 0},
        {"i915_fbc_status", i915_fbc_status, 0},
+       {"i915_ips_status", i915_ips_status, 0},
        {"i915_sr_status", i915_sr_status, 0},
        {"i915_opregion", i915_opregion, 0},
        {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
index b76da1470e71b1e9a96e82c6d2511312ae187cce..c52d866dfdb0c0205ff291e701e049aacc42c3a1 100644 (file)
@@ -955,6 +955,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
        case I915_PARAM_HAS_BLT:
                value = intel_ring_initialized(&dev_priv->ring[BCS]);
                break;
+       case I915_PARAM_HAS_VEBOX:
+               value = intel_ring_initialized(&dev_priv->ring[VECS]);
+               break;
        case I915_PARAM_HAS_RELAXED_FENCING:
                value = 1;
                break;
@@ -1358,8 +1361,10 @@ static int i915_load_modeset_init(struct drm_device *dev)
 cleanup_gem:
        mutex_lock(&dev->struct_mutex);
        i915_gem_cleanup_ringbuffer(dev);
+       i915_gem_context_fini(dev);
        mutex_unlock(&dev->struct_mutex);
        i915_gem_cleanup_aliasing_ppgtt(dev);
+       drm_mm_takedown(&dev_priv->mm.gtt_space);
 cleanup_irq:
        drm_irq_uninstall(dev);
 cleanup_gem_stolen:
@@ -1407,7 +1412,7 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
                return;
 
        ap->ranges[0].base = dev_priv->gtt.mappable_base;
-       ap->ranges[0].size = dev_priv->gtt.mappable_end - dev_priv->gtt.start;
+       ap->ranges[0].size = dev_priv->gtt.mappable_end;
 
        primary =
                pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
@@ -1744,6 +1749,7 @@ int i915_driver_unload(struct drm_device *dev)
                        i915_free_hws(dev);
        }
 
+       drm_mm_takedown(&dev_priv->mm.gtt_space);
        if (dev_priv->regs != NULL)
                pci_iounmap(dev->pdev, dev_priv->regs);
 
@@ -1753,6 +1759,8 @@ int i915_driver_unload(struct drm_device *dev)
        destroy_workqueue(dev_priv->wq);
        pm_qos_remove_request(&dev_priv->pm_qos);
 
+       dev_priv->gtt.gtt_remove(dev);
+
        if (dev_priv->slab)
                kmem_cache_destroy(dev_priv->slab);
 
index b7c3b98f78586ced089a83e6906de885de1cce13..59ff7456bd70f4dec18f3eb587f0b31498750cd5 100644 (file)
@@ -128,6 +128,10 @@ module_param_named(disable_power_well, i915_disable_power_well, int, 0600);
 MODULE_PARM_DESC(disable_power_well,
                 "Disable the power well when possible (default: false)");
 
+int i915_enable_ips __read_mostly = 1;
+module_param_named(enable_ips, i915_enable_ips, int, 0600);
+MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)");
+
 static struct drm_driver driver;
 extern int intel_agp_enabled;
 
@@ -311,6 +315,7 @@ static const struct intel_device_info intel_haswell_d_info = {
        .is_haswell = 1,
        .has_ddi = 1,
        .has_fpga_dbg = 1,
+       .has_vebox_ring = 1,
 };
 
 static const struct intel_device_info intel_haswell_m_info = {
@@ -320,6 +325,7 @@ static const struct intel_device_info intel_haswell_m_info = {
        .has_ddi = 1,
        .has_fpga_dbg = 1,
        .has_fbc = 1,
+       .has_vebox_ring = 1,
 };
 
 static const struct pci_device_id pciidlist[] = {              /* aka */
@@ -863,37 +869,14 @@ static int gen6_do_reset(struct drm_device *dev)
 
 int intel_gpu_reset(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret = -ENODEV;
-
        switch (INTEL_INFO(dev)->gen) {
        case 7:
-       case 6:
-               ret = gen6_do_reset(dev);
-               break;
-       case 5:
-               ret = ironlake_do_reset(dev);
-               break;
-       case 4:
-               ret = i965_do_reset(dev);
-               break;
-       case 2:
-               ret = i8xx_do_reset(dev);
-               break;
+       case 6: return gen6_do_reset(dev);
+       case 5: return ironlake_do_reset(dev);
+       case 4: return i965_do_reset(dev);
+       case 2: return i8xx_do_reset(dev);
+       default: return -ENODEV;
        }
-
-       /* Also reset the gpu hangman. */
-       if (dev_priv->gpu_error.stop_rings) {
-               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 "
-                                 "error for simulated gpu hangs\n");
-                       ret = 0;
-               }
-       }
-
-       return ret;
 }
 
 /**
@@ -914,6 +897,7 @@ int intel_gpu_reset(struct drm_device *dev)
 int i915_reset(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       bool simulated;
        int ret;
 
        if (!i915_try_reset)
@@ -923,13 +907,26 @@ int i915_reset(struct drm_device *dev)
 
        i915_gem_reset(dev);
 
-       ret = -ENODEV;
-       if (get_seconds() - dev_priv->gpu_error.last_reset < 5)
+       simulated = dev_priv->gpu_error.stop_rings != 0;
+
+       if (!simulated && get_seconds() - dev_priv->gpu_error.last_reset < 5) {
                DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
-       else
+               ret = -ENODEV;
+       } else {
                ret = intel_gpu_reset(dev);
 
-       dev_priv->gpu_error.last_reset = get_seconds();
+               /* Also reset the gpu hangman. */
+               if (simulated) {
+                       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 "
+                                         "error for simulated gpu hangs\n");
+                               ret = 0;
+                       }
+               } else
+                       dev_priv->gpu_error.last_reset = get_seconds();
+       }
        if (ret) {
                DRM_ERROR("Failed to reset chip.\n");
                mutex_unlock(&dev->struct_mutex);
index dfb5ade15149ce176c54141d008feb1ba3830953..359a2003086b2449f294db51dd2add657e34564d 100644 (file)
@@ -315,9 +315,8 @@ struct drm_i915_display_funcs {
        int (*get_fifo_size)(struct drm_device *dev, int plane);
        void (*update_wm)(struct drm_device *dev);
        void (*update_sprite_wm)(struct drm_device *dev, int pipe,
-                                uint32_t sprite_width, int pixel_size);
-       void (*update_linetime_wm)(struct drm_device *dev, int pipe,
-                                struct drm_display_mode *mode);
+                                uint32_t sprite_width, int pixel_size,
+                                bool enable);
        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. */
@@ -375,6 +374,7 @@ struct drm_i915_gt_funcs {
        func(supports_tv) sep \
        func(has_bsd_ring) sep \
        func(has_blt_ring) sep \
+       func(has_vebox_ring) sep \
        func(has_llc) sep \
        func(has_ddi) sep \
        func(has_fpga_dbg)
@@ -828,14 +828,21 @@ struct i915_gem_mm {
        u32 object_count;
 };
 
+struct drm_i915_error_state_buf {
+       unsigned bytes;
+       unsigned size;
+       int err;
+       u8 *buf;
+       loff_t start;
+       loff_t pos;
+};
+
 struct i915_gpu_error {
        /* For hangcheck timer */
 #define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
 #define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)
        struct timer_list hangcheck_timer;
        int hangcheck_count;
-       uint32_t last_acthd[I915_NUM_RINGS];
-       uint32_t prev_instdone[I915_NUM_INSTDONE_REG];
 
        /* For reset and error_state handling. */
        spinlock_t lock;
@@ -1367,6 +1374,7 @@ struct drm_i915_file_private {
 
 #define HAS_BSD(dev)            (INTEL_INFO(dev)->has_bsd_ring)
 #define HAS_BLT(dev)            (INTEL_INFO(dev)->has_blt_ring)
+#define HAS_VEBOX(dev)          (INTEL_INFO(dev)->has_vebox_ring)
 #define HAS_LLC(dev)            (INTEL_INFO(dev)->has_llc)
 #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
 
@@ -1462,6 +1470,7 @@ extern bool i915_enable_hangcheck __read_mostly;
 extern int i915_enable_ppgtt __read_mostly;
 extern unsigned int i915_preliminary_hw_support __read_mostly;
 extern int i915_disable_power_well __read_mostly;
+extern int i915_enable_ips __read_mostly;
 
 extern int i915_suspend(struct drm_device *dev, pm_message_t state);
 extern int i915_resume(struct drm_device *dev);
@@ -1820,6 +1829,8 @@ void i915_gem_dump_object(struct drm_i915_gem_object *obj, int len,
 /* i915_debugfs.c */
 int i915_debugfs_init(struct drm_minor *minor);
 void i915_debugfs_cleanup(struct drm_minor *minor);
+__printf(2, 3)
+void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
 
 /* i915_suspend.c */
 extern int i915_save_state(struct drm_device *dev);
@@ -1901,10 +1912,11 @@ int i915_reg_read_ioctl(struct drm_device *dev, void *data,
 /* overlay */
 #ifdef CONFIG_DEBUG_FS
 extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
-extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error);
+extern void intel_overlay_print_error_state(struct drm_i915_error_state_buf *e,
+                                           struct intel_overlay_error_state *error);
 
 extern struct intel_display_error_state *intel_display_capture_error_state(struct drm_device *dev);
-extern void intel_display_print_error_state(struct seq_file *m,
+extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e,
                                            struct drm_device *dev,
                                            struct intel_display_error_state *error);
 #endif
@@ -1919,9 +1931,17 @@ 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);
-int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val);
+
+/* intel_sideband.c */
+u32 vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr);
+void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val);
+u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr);
+u32 vlv_dpio_read(struct drm_i915_private *dev_priv, int reg);
+void vlv_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val);
+u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg,
+                  enum intel_sbi_destination destination);
+void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value,
+                    enum intel_sbi_destination destination);
 
 int vlv_gpu_freq(int ddr_freq, int val);
 int vlv_freq_opcode(int ddr_freq, int val);
index 2b51fa7e347735116d9f233a79ef69b1e5b8de9b..c605097bf5982eb06a126165b6c527726597e761 100644 (file)
@@ -2693,18 +2693,33 @@ static inline int fence_number(struct drm_i915_private *dev_priv,
        return fence - dev_priv->fence_regs;
 }
 
+struct write_fence {
+       struct drm_device *dev;
+       struct drm_i915_gem_object *obj;
+       int fence;
+};
+
 static void i915_gem_write_fence__ipi(void *data)
 {
+       struct write_fence *args = data;
+
+       /* Required for SNB+ with LLC */
        wbinvd();
+
+       /* Required for VLV */
+       i915_gem_write_fence(args->dev, args->fence, args->obj);
 }
 
 static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
                                         struct drm_i915_fence_reg *fence,
                                         bool enable)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int fence_reg = fence_number(dev_priv, fence);
+       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+       struct write_fence args = {
+               .dev = obj->base.dev,
+               .fence = fence_number(dev_priv, fence),
+               .obj = enable ? obj : NULL,
+       };
 
        /* In order to fully serialize access to the fenced region and
         * the update to the fence register we need to take extreme
@@ -2715,13 +2730,19 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
         * SNB+ we need to take a step further and emit an explicit wbinvd()
         * on each processor in order to manually flush all memory
         * transactions before updating the fence register.
+        *
+        * However, Valleyview complicates matter. There the wbinvd is
+        * insufficient and unlike SNB/IVB requires the serialising
+        * register write. (Note that that register write by itself is
+        * conversely not sufficient for SNB+.) To compromise, we do both.
         */
-       if (HAS_LLC(obj->base.dev))
-               on_each_cpu(i915_gem_write_fence__ipi, NULL, 1);
-       i915_gem_write_fence(dev, fence_reg, enable ? obj : NULL);
+       if (INTEL_INFO(args.dev)->gen >= 6)
+               on_each_cpu(i915_gem_write_fence__ipi, &args, 1);
+       else
+               i915_gem_write_fence(args.dev, args.fence, args.obj);
 
        if (enable) {
-               obj->fence_reg = fence_reg;
+               obj->fence_reg = args.fence;
                fence->obj = obj;
                list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list);
        } else {
@@ -2947,6 +2968,8 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
        struct drm_mm_node *node;
        u32 size, fence_size, fence_alignment, unfenced_alignment;
        bool mappable, fenceable;
+       size_t gtt_max = map_and_fenceable ?
+               dev_priv->gtt.mappable_end : dev_priv->gtt.total;
        int ret;
 
        fence_size = i915_gem_get_gtt_size(dev,
@@ -2973,9 +2996,11 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
        /* If the object is bigger than the entire aperture, reject it early
         * before evicting everything in a vain attempt to find space.
         */
-       if (obj->base.size >
-           (map_and_fenceable ? dev_priv->gtt.mappable_end : dev_priv->gtt.total)) {
-               DRM_ERROR("Attempting to bind an object larger than the aperture\n");
+       if (obj->base.size > gtt_max) {
+               DRM_ERROR("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%ld\n",
+                         obj->base.size,
+                         map_and_fenceable ? "mappable" : "total",
+                         gtt_max);
                return -E2BIG;
        }
 
@@ -2991,14 +3016,10 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
                return -ENOMEM;
        }
 
- search_free:
-       if (map_and_fenceable)
-               ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node,
-                                                         size, alignment, obj->cache_level,
-                                                         0, dev_priv->gtt.mappable_end);
-       else
-               ret = drm_mm_insert_node_generic(&dev_priv->mm.gtt_space, node,
-                                                size, alignment, obj->cache_level);
+search_free:
+       ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node,
+                                                 size, alignment,
+                                                 obj->cache_level, 0, gtt_max);
        if (ret) {
                ret = i915_gem_evict_something(dev, size, alignment,
                                               obj->cache_level,
@@ -3992,12 +4013,21 @@ static int i915_gem_init_rings(struct drm_device *dev)
                        goto cleanup_bsd_ring;
        }
 
+       if (HAS_VEBOX(dev)) {
+               ret = intel_init_vebox_ring_buffer(dev);
+               if (ret)
+                       goto cleanup_blt_ring;
+       }
+
+
        ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000));
        if (ret)
-               goto cleanup_blt_ring;
+               goto cleanup_vebox_ring;
 
        return 0;
 
+cleanup_vebox_ring:
+       intel_cleanup_ring_buffer(&dev_priv->ring[VECS]);
 cleanup_blt_ring:
        intel_cleanup_ring_buffer(&dev_priv->ring[BCS]);
 cleanup_bsd_ring:
index 64cb1909a0ce3c423287fda6415a4166f7292a8d..39bcc087db96b51304ca550271d073d56ceb33c8 100644 (file)
@@ -156,7 +156,8 @@ create_hw_context(struct drm_device *dev,
        if (INTEL_INFO(dev)->gen >= 7) {
                ret = i915_gem_object_set_cache_level(ctx->obj,
                                                      I915_CACHE_LLC_MLC);
-               if (ret)
+               /* Failure shouldn't ever happen this early */
+               if (WARN_ON(ret))
                        goto err_out;
        }
 
@@ -214,12 +215,16 @@ static int create_default_context(struct drm_i915_private *dev_priv)
         */
        dev_priv->ring[RCS].default_context = ctx;
        ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false, false);
-       if (ret)
+       if (ret) {
+               DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret);
                goto err_destroy;
+       }
 
        ret = do_switch(ctx);
-       if (ret)
+       if (ret) {
+               DRM_DEBUG_DRIVER("Switch failed %d\n", ret);
                goto err_unpin;
+       }
 
        DRM_DEBUG_DRIVER("Default HW context loaded\n");
        return 0;
@@ -237,6 +242,7 @@ void i915_gem_context_init(struct drm_device *dev)
 
        if (!HAS_HW_CONTEXTS(dev)) {
                dev_priv->hw_contexts_disabled = true;
+               DRM_DEBUG_DRIVER("Disabling HW Contexts; old hardware\n");
                return;
        }
 
@@ -249,11 +255,13 @@ void i915_gem_context_init(struct drm_device *dev)
 
        if (dev_priv->hw_context_size > (1<<20)) {
                dev_priv->hw_contexts_disabled = true;
+               DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size\n");
                return;
        }
 
        if (create_default_context(dev_priv)) {
                dev_priv->hw_contexts_disabled = true;
+               DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed\n");
                return;
        }
 
index 117ce38136812d1689ecc4b65ffe743a5e86a71c..a8bb62ca8756a42f424bd20a446e38d28a79f25b 100644 (file)
@@ -885,6 +885,15 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                        return -EPERM;
                }
                break;
+       case I915_EXEC_VEBOX:
+               ring = &dev_priv->ring[VECS];
+               if (ctx_id != 0) {
+                       DRM_DEBUG("Ring %s doesn't support contexts\n",
+                                 ring->name);
+                       return -EPERM;
+               }
+               break;
+
        default:
                DRM_DEBUG("execbuf with unknown ring: %d\n",
                          (int)(args->flags & I915_EXEC_RING_MASK));
index 879c4ccb00dbd3306d55ee9244e47a6301928390..e17bbe201195e14d5f1503cf17b45a422e4ac1ea 100644 (file)
@@ -381,14 +381,16 @@ static int
 i915_pipe_enabled(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
-                                                                     pipe);
 
-       if (!intel_display_power_enabled(dev,
-               POWER_DOMAIN_TRANSCODER(cpu_transcoder)))
-               return false;
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               /* Locking is horribly broken here, but whatever. */
+               struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       return I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE;
+               return intel_crtc->active;
+       } else {
+               return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE;
+       }
 }
 
 /* Called from drm generic code, passed a 'crtc', which
@@ -698,10 +700,11 @@ static void gen6_pm_rps_work(struct work_struct *work)
        pm_iir = dev_priv->rps.pm_iir;
        dev_priv->rps.pm_iir = 0;
        pm_imr = I915_READ(GEN6_PMIMR);
-       I915_WRITE(GEN6_PMIMR, 0);
+       /* Make sure not to corrupt PMIMR state used by ringbuffer code */
+       I915_WRITE(GEN6_PMIMR, pm_imr & ~GEN6_PM_RPS_EVENTS);
        spin_unlock_irq(&dev_priv->rps.lock);
 
-       if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0)
+       if ((pm_iir & GEN6_PM_RPS_EVENTS) == 0)
                return;
 
        mutex_lock(&dev_priv->rps.hw_lock);
@@ -777,7 +780,7 @@ static void ivybridge_parity_work(struct work_struct *work)
        I915_WRITE(GEN7_MISCCPCTL, misccpctl);
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       dev_priv->gt_irq_mask &= ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+       dev_priv->gt_irq_mask &= ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
        spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
 
@@ -809,7 +812,7 @@ static void ivybridge_handle_parity_error(struct drm_device *dev)
                return;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       dev_priv->gt_irq_mask |= GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+       dev_priv->gt_irq_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
        spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
 
@@ -821,25 +824,26 @@ static void snb_gt_irq_handler(struct drm_device *dev,
                               u32 gt_iir)
 {
 
-       if (gt_iir & (GEN6_RENDER_USER_INTERRUPT |
-                     GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT))
+       if (gt_iir &
+           (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT))
                notify_ring(dev, &dev_priv->ring[RCS]);
-       if (gt_iir & GEN6_BSD_USER_INTERRUPT)
+       if (gt_iir & GT_BSD_USER_INTERRUPT)
                notify_ring(dev, &dev_priv->ring[VCS]);
-       if (gt_iir & GEN6_BLITTER_USER_INTERRUPT)
+       if (gt_iir & GT_BLT_USER_INTERRUPT)
                notify_ring(dev, &dev_priv->ring[BCS]);
 
-       if (gt_iir & (GT_GEN6_BLT_CS_ERROR_INTERRUPT |
-                     GT_GEN6_BSD_CS_ERROR_INTERRUPT |
-                     GT_RENDER_CS_ERROR_INTERRUPT)) {
+       if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT |
+                     GT_BSD_CS_ERROR_INTERRUPT |
+                     GT_RENDER_CS_MASTER_ERROR_INTERRUPT)) {
                DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir);
                i915_handle_error(dev, false);
        }
 
-       if (gt_iir & GT_GEN7_L3_PARITY_ERROR_INTERRUPT)
+       if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
                ivybridge_handle_parity_error(dev);
 }
 
+/* Legacy way of handling PM interrupts */
 static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
                                u32 pm_iir)
 {
@@ -919,6 +923,38 @@ static void dp_aux_irq_handler(struct drm_device *dev)
        wake_up_all(&dev_priv->gmbus_wait_queue);
 }
 
+/* Unlike gen6_queue_rps_work() from which this function is originally derived,
+ * we must be able to deal with other PM interrupts. This is complicated because
+ * of the way in which we use the masks to defer the RPS work (which for
+ * posterity is necessary because of forcewake).
+ */
+static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
+                              u32 pm_iir)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->rps.lock, flags);
+       dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
+       if (dev_priv->rps.pm_iir) {
+               I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
+               /* never want to mask useful interrupts. (also posting read) */
+               WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
+               /* TODO: if queue_work is slow, move it out of the spinlock */
+               queue_work(dev_priv->wq, &dev_priv->rps.work);
+       }
+       spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+
+       if (pm_iir & ~GEN6_PM_RPS_EVENTS) {
+               if (pm_iir & PM_VEBOX_USER_INTERRUPT)
+                       notify_ring(dev_priv->dev, &dev_priv->ring[VECS]);
+
+               if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) {
+                       DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir);
+                       i915_handle_error(dev_priv->dev, false);
+               }
+       }
+}
+
 static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
@@ -990,7 +1026,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
                        gmbus_irq_handler(dev);
 
-               if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
+               if (pm_iir & GEN6_PM_RPS_EVENTS)
                        gen6_queue_rps_work(dev_priv, pm_iir);
 
                I915_WRITE(GTIIR, gt_iir);
@@ -1229,7 +1265,9 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
 
        pm_iir = I915_READ(GEN6_PMIIR);
        if (pm_iir) {
-               if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
+               if (IS_HASWELL(dev))
+                       hsw_pm_irq_handler(dev_priv, pm_iir);
+               else if (pm_iir & GEN6_PM_RPS_EVENTS)
                        gen6_queue_rps_work(dev_priv, pm_iir);
                I915_WRITE(GEN6_PMIIR, pm_iir);
                ret = IRQ_HANDLED;
@@ -1252,9 +1290,10 @@ static void ilk_gt_irq_handler(struct drm_device *dev,
                               struct drm_i915_private *dev_priv,
                               u32 gt_iir)
 {
-       if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY))
+       if (gt_iir &
+           (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT))
                notify_ring(dev, &dev_priv->ring[RCS]);
-       if (gt_iir & GT_BSD_USER_INTERRUPT)
+       if (gt_iir & ILK_BSD_USER_INTERRUPT)
                notify_ring(dev, &dev_priv->ring[VCS]);
 }
 
@@ -1344,7 +1383,7 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        if (IS_GEN5(dev) &&  de_iir & DE_PCU_EVENT)
                ironlake_handle_rps_change(dev);
 
-       if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS)
+       if (IS_GEN6(dev) && pm_iir & GEN6_PM_RPS_EVENTS)
                gen6_queue_rps_work(dev_priv, pm_iir);
 
        I915_WRITE(GTIIR, gt_iir);
@@ -1564,11 +1603,13 @@ i915_error_state_free(struct kref *error_ref)
        for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
                i915_error_object_free(error->ring[i].batchbuffer);
                i915_error_object_free(error->ring[i].ringbuffer);
+               i915_error_object_free(error->ring[i].ctx);
                kfree(error->ring[i].requests);
        }
 
        kfree(error->active_bo);
        kfree(error->overlay);
+       kfree(error->display);
        kfree(error);
 }
 static void capture_bo(struct drm_i915_error_buffer *err,
@@ -2274,11 +2315,11 @@ ring_last_seqno(struct intel_ring_buffer *ring)
                          struct drm_i915_gem_request, list)->seqno;
 }
 
-static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
+static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring,
+                                    u32 ring_seqno, bool *err)
 {
        if (list_empty(&ring->request_list) ||
-           i915_seqno_passed(ring->get_seqno(ring, false),
-                             ring_last_seqno(ring))) {
+           i915_seqno_passed(ring_seqno, ring_last_seqno(ring))) {
                /* Issue a wake-up to catch stuck h/w. */
                if (waitqueue_active(&ring->irq_queue)) {
                        DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
@@ -2345,28 +2386,33 @@ static bool kick_ring(struct intel_ring_buffer *ring)
        return false;
 }
 
+static bool i915_hangcheck_ring_hung(struct intel_ring_buffer *ring)
+{
+       if (IS_GEN2(ring->dev))
+               return false;
+
+       /* Is the chip hanging on a WAIT_FOR_EVENT?
+        * If so we can simply poke the RB_WAIT bit
+        * and break the hang. This should work on
+        * all but the second generation chipsets.
+        */
+       return !kick_ring(ring);
+}
+
 static bool i915_hangcheck_hung(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        if (dev_priv->gpu_error.hangcheck_count++ > 1) {
                bool hung = true;
+               struct intel_ring_buffer *ring;
+               int i;
 
                DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
                i915_handle_error(dev, true);
 
-               if (!IS_GEN2(dev)) {
-                       struct intel_ring_buffer *ring;
-                       int i;
-
-                       /* Is the chip hanging on a WAIT_FOR_EVENT?
-                        * If so we can simply poke the RB_WAIT bit
-                        * and break the hang. This should work on
-                        * all but the second generation chipsets.
-                        */
-                       for_each_ring(ring, dev_priv, i)
-                               hung &= !kick_ring(ring);
-               }
+               for_each_ring(ring, dev_priv, i)
+                       hung &= i915_hangcheck_ring_hung(ring);
 
                return hung;
        }
@@ -2384,19 +2430,19 @@ void i915_hangcheck_elapsed(unsigned long data)
 {
        struct drm_device *dev = (struct drm_device *)data;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       uint32_t acthd[I915_NUM_RINGS], instdone[I915_NUM_INSTDONE_REG];
        struct intel_ring_buffer *ring;
        bool err = false, idle;
        int i;
+       u32 seqno[I915_NUM_RINGS];
+       bool work_done;
 
        if (!i915_enable_hangcheck)
                return;
 
-       memset(acthd, 0, sizeof(acthd));
        idle = true;
        for_each_ring(ring, dev_priv, i) {
-           idle &= i915_hangcheck_ring_idle(ring, &err);
-           acthd[i] = intel_ring_get_active_head(ring);
+               seqno[i] = ring->get_seqno(ring, false);
+               idle &= i915_hangcheck_ring_idle(ring, seqno[i], &err);
        }
 
        /* If all work is done then ACTHD clearly hasn't advanced. */
@@ -2412,20 +2458,19 @@ void i915_hangcheck_elapsed(unsigned long data)
                return;
        }
 
-       i915_get_extra_instdone(dev, instdone);
-       if (memcmp(dev_priv->gpu_error.last_acthd, acthd,
-                  sizeof(acthd)) == 0 &&
-           memcmp(dev_priv->gpu_error.prev_instdone, instdone,
-                  sizeof(instdone)) == 0) {
+       work_done = false;
+       for_each_ring(ring, dev_priv, i) {
+               if (ring->hangcheck.seqno != seqno[i]) {
+                       work_done = true;
+                       ring->hangcheck.seqno = seqno[i];
+               }
+       }
+
+       if (!work_done) {
                if (i915_hangcheck_hung(dev))
                        return;
        } else {
                dev_priv->gpu_error.hangcheck_count = 0;
-
-               memcpy(dev_priv->gpu_error.last_acthd, acthd,
-                      sizeof(acthd));
-               memcpy(dev_priv->gpu_error.prev_instdone, instdone,
-                      sizeof(instdone));
        }
 
 repeat:
@@ -2455,6 +2500,42 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
        I915_WRITE(GTIER, 0x0);
        POSTING_READ(GTIER);
 
+       /* south display irq */
+       I915_WRITE(SDEIMR, 0xffffffff);
+       /*
+        * 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);
+}
+
+static void ivybridge_irq_preinstall(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+       atomic_set(&dev_priv->irq_received, 0);
+
+       I915_WRITE(HWSTAM, 0xeffe);
+
+       /* XXX hotplug from PCH */
+
+       I915_WRITE(DEIMR, 0xffffffff);
+       I915_WRITE(DEIER, 0x0);
+       POSTING_READ(DEIER);
+
+       /* and GT */
+       I915_WRITE(GTIMR, 0xffffffff);
+       I915_WRITE(GTIER, 0x0);
+       POSTING_READ(GTIER);
+
+       /* Power management */
+       I915_WRITE(GEN6_PMIMR, 0xffffffff);
+       I915_WRITE(GEN6_PMIER, 0x0);
+       POSTING_READ(GEN6_PMIER);
+
        if (HAS_PCH_NOP(dev))
                return;
 
@@ -2543,6 +2624,9 @@ static void ibx_irq_postinstall(struct drm_device *dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 mask;
 
+       if (HAS_PCH_NOP(dev))
+               return;
+
        if (HAS_PCH_IBX(dev)) {
                mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER |
                       SDE_TRANSA_FIFO_UNDER | SDE_POISON;
@@ -2552,9 +2636,6 @@ static void ibx_irq_postinstall(struct drm_device *dev)
                I915_WRITE(SERR_INT, I915_READ(SERR_INT));
        }
 
-       if (HAS_PCH_NOP(dev))
-               return;
-
        I915_WRITE(SDEIIR, I915_READ(SDEIIR));
        I915_WRITE(SDEIMR, ~mask);
 }
@@ -2567,7 +2648,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
                           DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
                           DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN |
                           DE_PIPEA_FIFO_UNDERRUN | DE_POISON;
-       u32 render_irqs;
+       u32 gt_irqs;
 
        dev_priv->irq_mask = ~display_mask;
 
@@ -2582,17 +2663,15 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        I915_WRITE(GTIIR, I915_READ(GTIIR));
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 
+       gt_irqs = GT_RENDER_USER_INTERRUPT;
+
        if (IS_GEN6(dev))
-               render_irqs =
-                       GT_USER_INTERRUPT |
-                       GEN6_BSD_USER_INTERRUPT |
-                       GEN6_BLITTER_USER_INTERRUPT;
+               gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
        else
-               render_irqs =
-                       GT_USER_INTERRUPT |
-                       GT_PIPE_NOTIFY |
-                       GT_BSD_USER_INTERRUPT;
-       I915_WRITE(GTIER, render_irqs);
+               gt_irqs |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT |
+                          ILK_BSD_USER_INTERRUPT;
+
+       I915_WRITE(GTIER, gt_irqs);
        POSTING_READ(GTIER);
 
        ibx_irq_postinstall(dev);
@@ -2618,7 +2697,8 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
                DE_PLANEA_FLIP_DONE_IVB |
                DE_AUX_CHANNEL_A_IVB |
                DE_ERR_INT_IVB;
-       u32 render_irqs;
+       u32 pm_irqs = GEN6_PM_RPS_EVENTS;
+       u32 gt_irqs;
 
        dev_priv->irq_mask = ~display_mask;
 
@@ -2633,16 +2713,32 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
                   DE_PIPEA_VBLANK_IVB);
        POSTING_READ(DEIER);
 
-       dev_priv->gt_irq_mask = ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+       dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
 
        I915_WRITE(GTIIR, I915_READ(GTIIR));
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 
-       render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT |
-               GEN6_BLITTER_USER_INTERRUPT | GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
-       I915_WRITE(GTIER, render_irqs);
+       gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT |
+                 GT_BLT_USER_INTERRUPT | GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+       I915_WRITE(GTIER, gt_irqs);
        POSTING_READ(GTIER);
 
+       I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+       if (HAS_VEBOX(dev))
+               pm_irqs |= PM_VEBOX_USER_INTERRUPT |
+                       PM_VEBOX_CS_ERROR_INTERRUPT;
+
+       /* Our enable/disable rps functions may touch these registers so
+        * make sure to set a known state for only the non-RPS bits.
+        * The RMW is extra paranoia since this should be called after being set
+        * to a known state in preinstall.
+        * */
+       I915_WRITE(GEN6_PMIMR,
+                  (I915_READ(GEN6_PMIMR) | ~GEN6_PM_RPS_EVENTS) & ~pm_irqs);
+       I915_WRITE(GEN6_PMIER,
+                  (I915_READ(GEN6_PMIER) & GEN6_PM_RPS_EVENTS) | pm_irqs);
+       POSTING_READ(GEN6_PMIER);
+
        ibx_irq_postinstall(dev);
 
        return 0;
@@ -2651,9 +2747,9 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
 static int valleyview_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u32 gt_irqs;
        u32 enable_mask;
        u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
-       u32 render_irqs;
 
        enable_mask = I915_DISPLAY_PORT_INTERRUPT;
        enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
@@ -2689,9 +2785,9 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
        I915_WRITE(GTIIR, I915_READ(GTIIR));
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 
-       render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT |
-               GEN6_BLITTER_USER_INTERRUPT;
-       I915_WRITE(GTIER, render_irqs);
+       gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT |
+               GT_BLT_USER_INTERRUPT;
+       I915_WRITE(GTIER, gt_irqs);
        POSTING_READ(GTIER);
 
        /* ack & enable invalid PTE error interrupts */
@@ -3458,9 +3554,9 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->disable_vblank = valleyview_disable_vblank;
                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 */
+               /* Share uninstall handlers with ILK/SNB */
                dev->driver->irq_handler = ivybridge_irq_handler;
-               dev->driver->irq_preinstall = ironlake_irq_preinstall;
+               dev->driver->irq_preinstall = ivybridge_irq_preinstall;
                dev->driver->irq_postinstall = ivybridge_irq_postinstall;
                dev->driver->irq_uninstall = ironlake_irq_uninstall;
                dev->driver->enable_vblank = ivybridge_enable_vblank;
index e4cf382f0b75397408eeab87bc892c6829c7249d..5a593d20036cd204d2e71839410862c88e6fdaaf 100644 (file)
 #define  MI_SEMAPHORE_UPDATE       (1<<21)
 #define  MI_SEMAPHORE_COMPARE      (1<<20)
 #define  MI_SEMAPHORE_REGISTER     (1<<18)
-#define  MI_SEMAPHORE_SYNC_RV      (2<<16)
-#define  MI_SEMAPHORE_SYNC_RB      (0<<16)
-#define  MI_SEMAPHORE_SYNC_VR      (0<<16)
-#define  MI_SEMAPHORE_SYNC_VB      (2<<16)
-#define  MI_SEMAPHORE_SYNC_BR      (2<<16)
-#define  MI_SEMAPHORE_SYNC_BV      (0<<16)
-#define  MI_SEMAPHORE_SYNC_INVALID  (1<<0)
+#define  MI_SEMAPHORE_SYNC_VR      (0<<16) /* RCS  wait for VCS  (RVSYNC) */
+#define  MI_SEMAPHORE_SYNC_VER     (1<<16) /* RCS  wait for VECS (RVESYNC) */
+#define  MI_SEMAPHORE_SYNC_BR      (2<<16) /* RCS  wait for BCS  (RBSYNC) */
+#define  MI_SEMAPHORE_SYNC_BV      (0<<16) /* VCS  wait for BCS  (VBSYNC) */
+#define  MI_SEMAPHORE_SYNC_VEV     (1<<16) /* VCS  wait for VECS (VVESYNC) */
+#define  MI_SEMAPHORE_SYNC_RV      (2<<16) /* VCS  wait for RCS  (VRSYNC) */
+#define  MI_SEMAPHORE_SYNC_RB      (0<<16) /* BCS  wait for RCS  (BRSYNC) */
+#define  MI_SEMAPHORE_SYNC_VEB     (1<<16) /* BCS  wait for VECS (BVESYNC) */
+#define  MI_SEMAPHORE_SYNC_VB      (2<<16) /* BCS  wait for VCS  (BVSYNC) */
+#define  MI_SEMAPHORE_SYNC_BVE     (0<<16) /* VECS wait for BCS  (VEBSYNC) */
+#define  MI_SEMAPHORE_SYNC_VVE     (1<<16) /* VECS wait for VCS  (VEVSYNC) */
+#define  MI_SEMAPHORE_SYNC_RVE     (2<<16) /* VECS wait for RCS  (VERSYNC) */
+#define  MI_SEMAPHORE_SYNC_INVALID  (3<<16)
 /*
  * 3D instructions used by the kernel
  */
 #define  DEBUG_RESET_DISPLAY           (1<<9)
 
 /*
- * DPIO - a special bus for various display related registers to hide behind:
- *  0x800c: m1, m2, n, p1, p2, k dividers
- *  0x8014: REF and SFR select
- *  0x8014: N divider, VCO select
- *  0x801c/3c: core clock bits
- *  0x8048/68: low pass filter coefficients
- *  0x8100: fast clock controls
+ * IOSF sideband
+ */
+#define VLV_IOSF_DOORBELL_REQ                  (VLV_DISPLAY_BASE + 0x2100)
+#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   IOSF_PORT_NC                         0x11
+#define   IOSF_PORT_DPIO                       0x12
+#define VLV_IOSF_DATA                          (VLV_DISPLAY_BASE + 0x2104)
+#define VLV_IOSF_ADDR                          (VLV_DISPLAY_BASE + 0x2108)
+
+#define PUNIT_OPCODE_REG_READ                  6
+#define PUNIT_OPCODE_REG_WRITE                 7
+
+#define PUNIT_REG_GPU_LFM                      0xd3
+#define PUNIT_REG_GPU_FREQ_REQ                 0xd4
+#define PUNIT_REG_GPU_FREQ_STS                 0xd8
+#define PUNIT_REG_MEDIA_TURBO_FREQ_REQ         0xdc
+
+#define PUNIT_FUSE_BUS2                                0xf6 /* bits 47:40 */
+#define PUNIT_FUSE_BUS1                                0xf5 /* bits 55:48 */
+
+#define IOSF_NC_FB_GFX_FREQ_FUSE               0x1c
+#define   FB_GFX_MAX_FREQ_FUSE_SHIFT           3
+#define   FB_GFX_MAX_FREQ_FUSE_MASK            0x000007f8
+#define   FB_GFX_FGUARANTEED_FREQ_FUSE_SHIFT   11
+#define   FB_GFX_FGUARANTEED_FREQ_FUSE_MASK    0x0007f800
+#define IOSF_NC_FB_GFX_FMAX_FUSE_HI            0x34
+#define   FB_FMAX_VMIN_FREQ_HI_MASK            0x00000007
+#define IOSF_NC_FB_GFX_FMAX_FUSE_LO            0x30
+#define   FB_FMAX_VMIN_FREQ_LO_SHIFT           27
+#define   FB_FMAX_VMIN_FREQ_LO_MASK            0xf8000000
+
+/*
+ * DPIO - a special bus for various display related registers to hide behind
  *
  * DPIO is VLV only.
  *
  * Note: digital port B is DDI0, digital pot C is DDI1
  */
-#define DPIO_PKT                       (VLV_DISPLAY_BASE + 0x2100)
-#define  DPIO_RID                      (0<<24)
-#define  DPIO_OP_WRITE                 (1<<16)
-#define  DPIO_OP_READ                  (0<<16)
-#define  DPIO_PORTID                   (0x12<<8)
-#define  DPIO_BYTE                     (0xf<<4)
-#define  DPIO_BUSY                     (1<<0) /* status only */
-#define DPIO_DATA                      (VLV_DISPLAY_BASE + 0x2104)
-#define DPIO_REG                       (VLV_DISPLAY_BASE + 0x2108)
+#define DPIO_DEVFN                     0
+#define DPIO_OPCODE_REG_WRITE          1
+#define DPIO_OPCODE_REG_READ           0
+
 #define DPIO_CTL                       (VLV_DISPLAY_BASE + 0x2110)
 #define  DPIO_MODSEL1                  (1<<3) /* if ref clk b == 27 */
 #define  DPIO_MODSEL0                  (1<<2) /* if ref clk a == 27 */
 #define RENDER_RING_BASE       0x02000
 #define BSD_RING_BASE          0x04000
 #define GEN6_BSD_RING_BASE     0x12000
+#define VEBOX_RING_BASE                0x1a000
 #define BLT_RING_BASE          0x22000
 #define RING_TAIL(base)                ((base)+0x30)
 #define RING_HEAD(base)                ((base)+0x34)
 #define RING_CTL(base)         ((base)+0x3c)
 #define RING_SYNC_0(base)      ((base)+0x40)
 #define RING_SYNC_1(base)      ((base)+0x44)
-#define GEN6_RVSYNC (RING_SYNC_0(RENDER_RING_BASE))
-#define GEN6_RBSYNC (RING_SYNC_1(RENDER_RING_BASE))
-#define GEN6_VRSYNC (RING_SYNC_1(GEN6_BSD_RING_BASE))
-#define GEN6_VBSYNC (RING_SYNC_0(GEN6_BSD_RING_BASE))
-#define GEN6_BRSYNC (RING_SYNC_0(BLT_RING_BASE))
-#define GEN6_BVSYNC (RING_SYNC_1(BLT_RING_BASE))
+#define RING_SYNC_2(base)      ((base)+0x48)
+#define GEN6_RVSYNC    (RING_SYNC_0(RENDER_RING_BASE))
+#define GEN6_RBSYNC    (RING_SYNC_1(RENDER_RING_BASE))
+#define GEN6_RVESYNC   (RING_SYNC_2(RENDER_RING_BASE))
+#define GEN6_VBSYNC    (RING_SYNC_0(GEN6_BSD_RING_BASE))
+#define GEN6_VRSYNC    (RING_SYNC_1(GEN6_BSD_RING_BASE))
+#define GEN6_VVESYNC   (RING_SYNC_2(GEN6_BSD_RING_BASE))
+#define GEN6_BRSYNC    (RING_SYNC_0(BLT_RING_BASE))
+#define GEN6_BVSYNC    (RING_SYNC_1(BLT_RING_BASE))
+#define GEN6_BVESYNC   (RING_SYNC_2(BLT_RING_BASE))
+#define GEN6_VEBSYNC   (RING_SYNC_0(VEBOX_RING_BASE))
+#define GEN6_VERSYNC   (RING_SYNC_1(VEBOX_RING_BASE))
+#define GEN6_VEVSYNC   (RING_SYNC_2(VEBOX_RING_BASE))
+#define GEN6_NOSYNC 0
 #define RING_MAX_IDLE(base)    ((base)+0x54)
 #define RING_HWS_PGA(base)     ((base)+0x80)
 #define RING_HWS_PGA_GEN6(base)        ((base)+0x2080)
 #define DONE_REG               0x40b0
 #define BSD_HWS_PGA_GEN7       (0x04180)
 #define BLT_HWS_PGA_GEN7       (0x04280)
+#define VEBOX_HWS_PGA_GEN7     (0x04380)
 #define RING_ACTHD(base)       ((base)+0x74)
 #define RING_NOPID(base)       ((base)+0x94)
 #define RING_IMR(base)         ((base)+0xa8)
 #define VLV_IMR                (VLV_DISPLAY_BASE + 0x20a8)
 #define VLV_ISR                (VLV_DISPLAY_BASE + 0x20ac)
 #define VLV_PCBR       (VLV_DISPLAY_BASE + 0x2120)
-#define   I915_PIPE_CONTROL_NOTIFY_INTERRUPT           (1<<18)
-#define   I915_DISPLAY_PORT_INTERRUPT                  (1<<17)
-#define   I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT   (1<<15)
-#define   I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT     (1<<14) /* p-state */
-#define   I915_HWB_OOM_INTERRUPT                       (1<<13)
-#define   I915_SYNC_STATUS_INTERRUPT                   (1<<12)
-#define   I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT  (1<<11)
-#define   I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT  (1<<10)
-#define   I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT    (1<<9)
-#define   I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT  (1<<8)
-#define   I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT         (1<<7)
-#define   I915_DISPLAY_PIPE_A_EVENT_INTERRUPT          (1<<6)
-#define   I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT         (1<<5)
-#define   I915_DISPLAY_PIPE_B_EVENT_INTERRUPT          (1<<4)
-#define   I915_DEBUG_INTERRUPT                         (1<<2)
-#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 CACHE_MODE_1           0x7004 /* IVB+ */
 #define   PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6)
 
-/* GEN6 interrupt control
- * Note that the per-ring interrupt bits do alias with the global interrupt bits
- * in GTIMR. */
-#define GEN6_RENDER_HWSTAM     0x2098
-#define GEN6_RENDER_IMR                0x20a8
-#define   GEN6_RENDER_CONTEXT_SWITCH_INTERRUPT         (1 << 8)
-#define   GEN6_RENDER_PPGTT_PAGE_FAULT                 (1 << 7)
-#define   GEN6_RENDER_TIMEOUT_COUNTER_EXPIRED          (1 << 6)
-#define   GEN6_RENDER_L3_PARITY_ERROR                  (1 << 5)
-#define   GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT    (1 << 4)
-#define   GEN6_RENDER_COMMAND_PARSER_MASTER_ERROR      (1 << 3)
-#define   GEN6_RENDER_SYNC_STATUS                      (1 << 2)
-#define   GEN6_RENDER_DEBUG_INTERRUPT                  (1 << 1)
-#define   GEN6_RENDER_USER_INTERRUPT                   (1 << 0)
-
-#define GEN6_BLITTER_HWSTAM    0x22098
-#define GEN6_BLITTER_IMR       0x220a8
-#define   GEN6_BLITTER_MI_FLUSH_DW_NOTIFY_INTERRUPT    (1 << 26)
-#define   GEN6_BLITTER_COMMAND_PARSER_MASTER_ERROR     (1 << 25)
-#define   GEN6_BLITTER_SYNC_STATUS                     (1 << 24)
-#define   GEN6_BLITTER_USER_INTERRUPT                  (1 << 22)
-
 #define GEN6_BLITTER_ECOSKPD   0x221d0
 #define   GEN6_BLITTER_LOCK_SHIFT                      16
 #define   GEN6_BLITTER_FBC_NOTIFY                      (1<<3)
 #define   GEN6_BSD_SLEEP_INDICATOR     (1 << 3)
 #define   GEN6_BSD_GO_INDICATOR                (1 << 4)
 
-#define GEN6_BSD_HWSTAM                        0x12098
-#define GEN6_BSD_IMR                   0x120a8
-#define   GEN6_BSD_USER_INTERRUPT      (1 << 12)
+/* On modern GEN architectures interrupt control consists of two sets
+ * of registers. The first set pertains to the ring generating the
+ * interrupt. The second control is for the functional block generating the
+ * interrupt. These are PM, GT, DE, etc.
+ *
+ * Luckily *knocks on wood* all the ring interrupt bits match up with the
+ * GT interrupt bits, so we don't need to duplicate the defines.
+ *
+ * These defines should cover us well from SNB->HSW with minor exceptions
+ * it can also work on ILK.
+ */
+#define GT_BLT_FLUSHDW_NOTIFY_INTERRUPT                (1 << 26)
+#define GT_BLT_CS_ERROR_INTERRUPT              (1 << 25)
+#define GT_BLT_USER_INTERRUPT                  (1 << 22)
+#define GT_BSD_CS_ERROR_INTERRUPT              (1 << 15)
+#define GT_BSD_USER_INTERRUPT                  (1 << 12)
+#define GT_RENDER_L3_PARITY_ERROR_INTERRUPT    (1 <<  5) /* !snb */
+#define GT_RENDER_PIPECTL_NOTIFY_INTERRUPT     (1 <<  4)
+#define GT_RENDER_CS_MASTER_ERROR_INTERRUPT    (1 <<  3)
+#define GT_RENDER_SYNC_STATUS_INTERRUPT                (1 <<  2)
+#define GT_RENDER_DEBUG_INTERRUPT              (1 <<  1)
+#define GT_RENDER_USER_INTERRUPT               (1 <<  0)
+
+#define PM_VEBOX_CS_ERROR_INTERRUPT            (1 << 12) /* hsw+ */
+#define PM_VEBOX_USER_INTERRUPT                        (1 << 10) /* hsw+ */
+
+/* These are all the "old" interrupts */
+#define ILK_BSD_USER_INTERRUPT                         (1<<5)
+#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT             (1<<18)
+#define I915_DISPLAY_PORT_INTERRUPT                    (1<<17)
+#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT     (1<<15)
+#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT       (1<<14) /* p-state */
+#define I915_HWB_OOM_INTERRUPT                         (1<<13)
+#define I915_SYNC_STATUS_INTERRUPT                     (1<<12)
+#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT    (1<<11)
+#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT    (1<<10)
+#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT      (1<<9)
+#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT    (1<<8)
+#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT           (1<<7)
+#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT            (1<<6)
+#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT           (1<<5)
+#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT            (1<<4)
+#define I915_DEBUG_INTERRUPT                           (1<<2)
+#define I915_USER_INTERRUPT                            (1<<1)
+#define I915_ASLE_INTERRUPT                            (1<<0)
+#define I915_BSD_USER_INTERRUPT                                (1 << 25)
 
 #define GEN6_BSD_RNCID                 0x12198
 
 /* Framebuffer compression for Ivybridge */
 #define IVB_FBC_RT_BASE                        0x7020
 
+#define IPS_CTL                0x43408
+#define   IPS_ENABLE   (1 << 31)
 
 #define _HSW_PIPE_SLICE_CHICKEN_1_A    0x420B0
 #define _HSW_PIPE_SLICE_CHICKEN_1_B    0x420B4
 #define WM3S_LP_IVB            0x45128
 #define  WM1S_LP_EN            (1<<31)
 
+#define HSW_WM_LP_VAL(lat, fbc, pri, cur) \
+       (WM3_LP_EN | ((lat) << WM1_LP_LATENCY_SHIFT) | \
+        ((fbc) << WM1_LP_FBC_SHIFT) | ((pri) << WM1_LP_SR_SHIFT) | (cur))
+
 /* Memory latency timer register */
 #define MLTR_ILK               0x11222
 #define  MLTR_WM1_SHIFT                0
 #define _LGC_PALETTE_B           0x4a800
 #define LGC_PALETTE(pipe) _PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B)
 
+#define _GAMMA_MODE_A          0x4a480
+#define _GAMMA_MODE_B          0x4ac80
+#define GAMMA_MODE(pipe) _PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B)
+#define GAMMA_MODE_MODE_MASK   (3 << 0)
+#define GAMMA_MODE_MODE_8bit   (0 << 0)
+#define GAMMA_MODE_MODE_10bit  (1 << 0)
+#define GAMMA_MODE_MODE_12bit  (2 << 0)
+#define GAMMA_MODE_MODE_SPLIT  (3 << 0)
+
 /* interrupts */
 #define DE_MASTER_IRQ_CONTROL   (1 << 31)
 #define DE_SPRITEB_FLIP_DONE    (1 << 29)
 #define DEIIR   0x44008
 #define DEIER   0x4400c
 
-/* GT interrupt.
- * Note that for gen6+ the ring-specific interrupt bits do alias with the
- * corresponding bits in the per-ring interrupt control registers. */
-#define GT_GEN6_BLT_FLUSHDW_NOTIFY_INTERRUPT   (1 << 26)
-#define GT_GEN6_BLT_CS_ERROR_INTERRUPT         (1 << 25)
-#define GT_GEN6_BLT_USER_INTERRUPT             (1 << 22)
-#define GT_GEN6_BSD_CS_ERROR_INTERRUPT         (1 << 15)
-#define GT_GEN6_BSD_USER_INTERRUPT             (1 << 12)
-#define GT_BSD_USER_INTERRUPT                  (1 << 5) /* ilk only */
-#define GT_GEN7_L3_PARITY_ERROR_INTERRUPT      (1 << 5)
-#define GT_PIPE_NOTIFY                         (1 << 4)
-#define GT_RENDER_CS_ERROR_INTERRUPT           (1 << 3)
-#define GT_SYNC_STATUS                         (1 << 2)
-#define GT_USER_INTERRUPT                      (1 << 0)
-
 #define GTISR   0x44010
 #define GTIMR   0x44014
 #define GTIIR   0x44018
 # define CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE     (1 << 5)
 # define CHICKEN3_DGMG_DONE_FIX_DISABLE                (1 << 2)
 
+#define CHICKEN_PAR1_1         0x42080
+#define  FORCE_ARB_IDLE_PLANES (1 << 14)
+
 #define DISP_ARB_CTL   0x45000
 #define  DISP_TILE_SURFACE_SWIZZLING   (1<<13)
 #define  DISP_FBC_WM_DIS               (1<<15)
 #define  GEN6_PM_RP_DOWN_THRESHOLD             (1<<4)
 #define  GEN6_PM_RP_UP_EI_EXPIRED              (1<<2)
 #define  GEN6_PM_RP_DOWN_EI_EXPIRED            (1<<1)
-#define  GEN6_PM_DEFERRED_EVENTS               (GEN6_PM_RP_UP_THRESHOLD | \
+#define  GEN6_PM_RPS_EVENTS                    (GEN6_PM_RP_UP_THRESHOLD | \
                                                 GEN6_PM_RP_DOWN_THRESHOLD | \
                                                 GEN6_PM_RP_DOWN_TIMEOUT)
 
 #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   IOSF_PORT_NC                         0x11
-#define VLV_IOSF_DATA                          0x182104
-#define VLV_IOSF_ADDR                          0x182108
-
-#define PUNIT_OPCODE_REG_READ                  6
-#define PUNIT_OPCODE_REG_WRITE                 7
-
-#define PUNIT_REG_GPU_LFM                      0xd3
-#define PUNIT_REG_GPU_FREQ_REQ                 0xd4
-#define PUNIT_REG_GPU_FREQ_STS                 0xd8
-#define PUNIT_REG_MEDIA_TURBO_FREQ_REQ         0xdc
-
-#define PUNIT_FUSE_BUS2                                0xf6 /* bits 47:40 */
-#define PUNIT_FUSE_BUS1                                0xf5 /* bits 55:48 */
-
-#define IOSF_NC_FB_GFX_FREQ_FUSE               0x1c
-#define   FB_GFX_MAX_FREQ_FUSE_SHIFT           3
-#define   FB_GFX_MAX_FREQ_FUSE_MASK            0x000007f8
-#define   FB_GFX_FGUARANTEED_FREQ_FUSE_SHIFT   11
-#define   FB_GFX_FGUARANTEED_FREQ_FUSE_MASK    0x0007f800
-#define IOSF_NC_FB_GFX_FMAX_FUSE_HI            0x34
-#define   FB_FMAX_VMIN_FREQ_HI_MASK            0x00000007
-#define IOSF_NC_FB_GFX_FMAX_FUSE_LO            0x30
-#define   FB_FMAX_VMIN_FREQ_LO_SHIFT           27
-#define   FB_FMAX_VMIN_FREQ_LO_MASK            0xf8000000
-
 #define GEN6_GT_CORE_STATUS            0x138060
 #define   GEN6_CORE_CPD_STATE_MASK     (7<<4)
 #define   GEN6_RCn_MASK                        7
 #define  SFUSE_STRAP_DDIC_DETECTED     (1<<1)
 #define  SFUSE_STRAP_DDID_DETECTED     (1<<0)
 
+#define WM_MISC                                0x45260
+#define  WM_MISC_DATA_PARTITION_5_6    (1 << 0)
+
 #define WM_DBG                         0x45280
 #define  WM_DBG_DISALLOW_MULTIPLE_LP   (1<<0)
 #define  WM_DBG_DISALLOW_MAXFIFO       (1<<1)
index c0d7875b475c1a30b8893c9e76d1f03996de8cd1..6875b5654c63d55a65dcf639734e0de101f1f037 100644 (file)
@@ -214,7 +214,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
        mutex_lock(&dev_priv->rps.hw_lock);
        if (IS_VALLEYVIEW(dev_priv->dev)) {
                u32 freq;
-               valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &freq);
+               freq = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
                ret = vlv_gpu_freq(dev_priv->mem_freq, (freq >> 8) & 0xff);
        } else {
                ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER;
index 66a0c6f0bb818400d216a4e32136ada0b219b19c..3acec8c4816606f1f2aa82bbe0ad3f5c105f4ad5 100644 (file)
@@ -84,6 +84,28 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
        return true;
 }
 
+static void intel_crt_get_config(struct intel_encoder *encoder,
+                                struct intel_crtc_config *pipe_config)
+{
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       struct intel_crt *crt = intel_encoder_to_crt(encoder);
+       u32 tmp, flags = 0;
+
+       tmp = I915_READ(crt->adpa_reg);
+
+       if (tmp & ADPA_HSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+
+       if (tmp & ADPA_VSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       pipe_config->adjusted_mode.flags |= flags;
+}
+
 /* Note: The caller is required to filter out dpms modes not supported by the
  * platform. */
 static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
@@ -127,7 +149,7 @@ static void intel_enable_crt(struct intel_encoder *encoder)
        intel_crt_set_dpms(encoder, crt->connector->base.dpms);
 }
 
-
+/* Special dpms function to support cloning between dvo/sdvo/crt. */
 static void intel_crt_dpms(struct drm_connector *connector, int mode)
 {
        struct drm_device *dev = connector->dev;
@@ -158,6 +180,8 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode)
        else
                encoder->connectors_active = true;
 
+       /* We call connector dpms manually below in case pipe dpms doesn't
+        * change due to cloning. */
        if (mode < old_dpms) {
                /* From off to on, enable the pipe first. */
                intel_crtc_update_dpms(crtc);
@@ -778,6 +802,7 @@ void intel_crt_init(struct drm_device *dev)
        crt->base.compute_config = intel_crt_compute_config;
        crt->base.disable = intel_disable_crt;
        crt->base.enable = intel_enable_crt;
+       crt->base.get_config = intel_crt_get_config;
        if (I915_HAS_HOTPLUG(dev))
                crt->base.hpd_pin = HPD_CRT;
        if (HAS_DDI(dev))
index 062de679f38f3ebd9143c61ac3c6fca24bfbd785..9649df806079e48eddec74c00fef1bba2398efae 100644 (file)
@@ -1153,14 +1153,14 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
 int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv)
 {
        if (I915_READ(HSW_FUSE_STRAP) & HSW_CDCLK_LIMIT)
-               return 450;
+               return 450000;
        else if ((I915_READ(LCPLL_CTL) & LCPLL_CLK_FREQ_MASK) ==
                 LCPLL_CLK_FREQ_450)
-               return 450;
+               return 450000;
        else if (IS_ULT(dev_priv->dev))
-               return 338;
+               return 337500;
        else
-               return 540;
+               return 540000;
 }
 
 void intel_ddi_pll_init(struct drm_device *dev)
@@ -1173,7 +1173,7 @@ void intel_ddi_pll_init(struct drm_device *dev)
         * Don't even try to turn it on.
         */
 
-       DRM_DEBUG_KMS("CDCLK running at %dMHz\n",
+       DRM_DEBUG_KMS("CDCLK running at %dKHz\n",
                      intel_ddi_get_cdclk_freq(dev_priv));
 
        if (val & LCPLL_CD_SOURCE_FCLK)
@@ -1259,6 +1259,28 @@ static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder)
                intel_dp_check_link_status(intel_dp);
 }
 
+static void intel_ddi_get_config(struct intel_encoder *encoder,
+                                struct intel_crtc_config *pipe_config)
+{
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+       enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+       u32 temp, flags = 0;
+
+       temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
+       if (temp & TRANS_DDI_PHSYNC)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+       if (temp & TRANS_DDI_PVSYNC)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       pipe_config->adjusted_mode.flags |= flags;
+       pipe_config->pixel_multiplier = 1;
+}
+
 static void intel_ddi_destroy(struct drm_encoder *encoder)
 {
        /* HDMI has nothing special to destroy, so we can go with this. */
@@ -1269,9 +1291,13 @@ static bool intel_ddi_compute_config(struct intel_encoder *encoder,
                                     struct intel_crtc_config *pipe_config)
 {
        int type = encoder->type;
+       int port = intel_ddi_get_encoder_port(encoder);
 
        WARN(type == INTEL_OUTPUT_UNKNOWN, "compute_config() on unknown output!\n");
 
+       if (port == PORT_A)
+               pipe_config->cpu_transcoder = TRANSCODER_EDP;
+
        if (type == INTEL_OUTPUT_HDMI)
                return intel_hdmi_compute_config(encoder, pipe_config);
        else
@@ -1318,6 +1344,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
        intel_encoder->disable = intel_disable_ddi;
        intel_encoder->post_disable = intel_ddi_post_disable;
        intel_encoder->get_hw_state = intel_ddi_get_hw_state;
+       intel_encoder->get_config = intel_ddi_get_config;
 
        intel_dig_port->port = port;
        intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) &
index a4c9f56afb38c32958b0bce61eb2b260880e5af6..dff9d4e5b92b15ba985d6153e949c7b970dac0f3 100644 (file)
@@ -381,43 +381,6 @@ static const intel_limit_t intel_limits_vlv_dp = {
        .find_pll = intel_vlv_find_best_pll,
 };
 
-u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg)
-{
-       WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
-
-       if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) {
-               DRM_ERROR("DPIO idle wait timed out\n");
-               return 0;
-       }
-
-       I915_WRITE(DPIO_REG, reg);
-       I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_READ | DPIO_PORTID |
-                  DPIO_BYTE);
-       if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) {
-               DRM_ERROR("DPIO read wait timed out\n");
-               return 0;
-       }
-
-       return I915_READ(DPIO_DATA);
-}
-
-void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val)
-{
-       WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
-
-       if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) {
-               DRM_ERROR("DPIO idle wait timed out\n");
-               return;
-       }
-
-       I915_WRITE(DPIO_DATA, val);
-       I915_WRITE(DPIO_REG, reg);
-       I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_WRITE | DPIO_PORTID |
-                  DPIO_BYTE);
-       if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100))
-               DRM_ERROR("DPIO write wait timed out\n");
-}
-
 static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
                                                int refclk)
 {
@@ -1404,67 +1367,6 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
        POSTING_READ(reg);
 }
 
-/* SBI access */
-static void
-intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value,
-               enum intel_sbi_destination destination)
-{
-       u32 tmp;
-
-       WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
-
-       if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0,
-                               100)) {
-               DRM_ERROR("timeout waiting for SBI to become ready\n");
-               return;
-       }
-
-       I915_WRITE(SBI_ADDR, (reg << 16));
-       I915_WRITE(SBI_DATA, value);
-
-       if (destination == SBI_ICLK)
-               tmp = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRWR;
-       else
-               tmp = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IOWR;
-       I915_WRITE(SBI_CTL_STAT, SBI_BUSY | tmp);
-
-       if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0,
-                               100)) {
-               DRM_ERROR("timeout waiting for SBI to complete write transaction\n");
-               return;
-       }
-}
-
-static u32
-intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg,
-              enum intel_sbi_destination destination)
-{
-       u32 value = 0;
-       WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
-
-       if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0,
-                               100)) {
-               DRM_ERROR("timeout waiting for SBI to become ready\n");
-               return 0;
-       }
-
-       I915_WRITE(SBI_ADDR, (reg << 16));
-
-       if (destination == SBI_ICLK)
-               value = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRRD;
-       else
-               value = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IORD;
-       I915_WRITE(SBI_CTL_STAT, value | SBI_BUSY);
-
-       if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0,
-                               100)) {
-               DRM_ERROR("timeout waiting for SBI to complete read transaction\n");
-               return 0;
-       }
-
-       return I915_READ(SBI_DATA);
-}
-
 void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port)
 {
        u32 port_mask;
@@ -3340,6 +3242,42 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        intel_wait_for_vblank(dev, intel_crtc->pipe);
 }
 
+/* IPS only exists on ULT machines and is tied to pipe A. */
+static bool hsw_crtc_supports_ips(struct intel_crtc *crtc)
+{
+       return IS_ULT(crtc->base.dev) && crtc->pipe == PIPE_A;
+}
+
+static void hsw_enable_ips(struct intel_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+       if (!crtc->config.ips_enabled)
+               return;
+
+       /* We can only enable IPS after we enable a plane and wait for a vblank.
+        * We guarantee that the plane is enabled by calling intel_enable_ips
+        * only after intel_enable_plane. And intel_enable_plane already waits
+        * for a vblank, so all we need to do here is to enable the IPS bit. */
+       assert_plane_enabled(dev_priv, crtc->plane);
+       I915_WRITE(IPS_CTL, IPS_ENABLE);
+}
+
+static void hsw_disable_ips(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!crtc->config.ips_enabled)
+               return;
+
+       assert_plane_enabled(dev_priv, crtc->plane);
+       I915_WRITE(IPS_CTL, 0);
+
+       /* We need to wait for a vblank before we can disable the plane. */
+       intel_wait_for_vblank(dev, crtc->pipe);
+}
+
 static void haswell_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -3387,6 +3325,8 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
                          intel_crtc->config.has_pch_encoder);
        intel_enable_plane(dev_priv, plane, pipe);
 
+       hsw_enable_ips(intel_crtc);
+
        if (intel_crtc->config.has_pch_encoder)
                lpt_pch_enable(crtc);
 
@@ -3529,6 +3469,8 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
        if (dev_priv->cfb_plane == plane)
                intel_disable_fbc(dev);
 
+       hsw_disable_ips(intel_crtc);
+
        intel_disable_plane(dev_priv, plane, pipe);
 
        if (intel_crtc->config.has_pch_encoder)
@@ -3567,12 +3509,6 @@ static void ironlake_crtc_off(struct drm_crtc *crtc)
 
 static void haswell_crtc_off(struct drm_crtc *crtc)
 {
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-       /* Stop saying we're using TRANSCODER_EDP because some other CRTC might
-        * start using it. */
-       intel_crtc->config.cpu_transcoder = (enum transcoder) intel_crtc->pipe;
-
        intel_ddi_put_crtc_pll(crtc);
 }
 
@@ -3627,18 +3563,12 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc)
        if (!crtc->config.gmch_pfit.control)
                return;
 
-       WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE);
-       assert_pipe_disabled(dev_priv, crtc->pipe);
-
        /*
-        * Enable automatic panel scaling so that non-native modes
-        * fill the screen.  The panel fitter should only be
-        * adjusted whilst the pipe is disabled, according to
-        * register description and PRM.
+        * The panel fitter should only be adjusted whilst the pipe is disabled,
+        * according to register description and PRM.
         */
-       DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
-                     pipe_config->gmch_pfit.control,
-                     pipe_config->gmch_pfit.pgm_ratios);
+       WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE);
+       assert_pipe_disabled(dev_priv, crtc->pipe);
 
        I915_WRITE(PFIT_PGM_RATIOS, pipe_config->gmch_pfit.pgm_ratios);
        I915_WRITE(PFIT_CONTROL, pipe_config->gmch_pfit.control);
@@ -4101,11 +4031,20 @@ retry:
        return setup_ok ? 0 : -EINVAL;
 }
 
+static void hsw_compute_ips_config(struct intel_crtc *crtc,
+                                  struct intel_crtc_config *pipe_config)
+{
+       pipe_config->ips_enabled = i915_enable_ips &&
+                                  hsw_crtc_supports_ips(crtc) &&
+                                  pipe_config->pipe_bpp == 24;
+}
+
 static int 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;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
        if (HAS_PCH_SPLIT(dev)) {
                /* FDI link clock is fixed at 2.7G */
@@ -4135,8 +4074,11 @@ static int intel_crtc_compute_config(struct drm_crtc *crtc,
                pipe_config->pipe_bpp = 8*3;
        }
 
+       if (IS_HASWELL(dev))
+               hsw_compute_ips_config(intel_crtc, pipe_config);
+
        if (pipe_config->has_pch_encoder)
-               return ironlake_fdi_compute_config(to_intel_crtc(crtc), pipe_config);
+               return ironlake_fdi_compute_config(intel_crtc, pipe_config);
 
        return 0;
 }
@@ -4343,24 +4285,24 @@ static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv)
         * PLLB opamp always calibrates to max value of 0x3f, force enable it
         * and set it to a reasonable value instead.
         */
-       reg_val = intel_dpio_read(dev_priv, DPIO_IREF(1));
+       reg_val = vlv_dpio_read(dev_priv, DPIO_IREF(1));
        reg_val &= 0xffffff00;
        reg_val |= 0x00000030;
-       intel_dpio_write(dev_priv, DPIO_IREF(1), reg_val);
+       vlv_dpio_write(dev_priv, DPIO_IREF(1), reg_val);
 
-       reg_val = intel_dpio_read(dev_priv, DPIO_CALIBRATION);
+       reg_val = vlv_dpio_read(dev_priv, DPIO_CALIBRATION);
        reg_val &= 0x8cffffff;
        reg_val = 0x8c000000;
-       intel_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val);
+       vlv_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val);
 
-       reg_val = intel_dpio_read(dev_priv, DPIO_IREF(1));
+       reg_val = vlv_dpio_read(dev_priv, DPIO_IREF(1));
        reg_val &= 0xffffff00;
-       intel_dpio_write(dev_priv, DPIO_IREF(1), reg_val);
+       vlv_dpio_write(dev_priv, DPIO_IREF(1), reg_val);
 
-       reg_val = intel_dpio_read(dev_priv, DPIO_CALIBRATION);
+       reg_val = vlv_dpio_read(dev_priv, DPIO_CALIBRATION);
        reg_val &= 0x00ffffff;
        reg_val |= 0xb0000000;
-       intel_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val);
+       vlv_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val);
 }
 
 static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
@@ -4435,15 +4377,15 @@ static void vlv_update_pll(struct intel_crtc *crtc)
                vlv_pllb_recal_opamp(dev_priv);
 
        /* Set up Tx target for periodic Rcomp update */
-       intel_dpio_write(dev_priv, DPIO_IREF_BCAST, 0x0100000f);
+       vlv_dpio_write(dev_priv, DPIO_IREF_BCAST, 0x0100000f);
 
        /* Disable target IRef on PLL */
-       reg_val = intel_dpio_read(dev_priv, DPIO_IREF_CTL(pipe));
+       reg_val = vlv_dpio_read(dev_priv, DPIO_IREF_CTL(pipe));
        reg_val &= 0x00ffffff;
-       intel_dpio_write(dev_priv, DPIO_IREF_CTL(pipe), reg_val);
+       vlv_dpio_write(dev_priv, DPIO_IREF_CTL(pipe), reg_val);
 
        /* Disable fast lock */
-       intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x610);
+       vlv_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x610);
 
        /* Set idtafcrecal before PLL is enabled */
        mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK));
@@ -4457,47 +4399,47 @@ static void vlv_update_pll(struct intel_crtc *crtc)
         * Note: don't use the DAC post divider as it seems unstable.
         */
        mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT);
-       intel_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv);
+       vlv_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv);
 
        mdiv |= DPIO_ENABLE_CALIBRATION;
-       intel_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv);
+       vlv_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv);
 
        /* Set HBR and RBR LPF coefficients */
        if (adjusted_mode->clock == 162000 ||
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI))
-               intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe),
+               vlv_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe),
                                 0x005f0021);
        else
-               intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe),
+               vlv_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe),
                                 0x00d0000f);
 
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) ||
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) {
                /* Use SSC source */
                if (!pipe)
-                       intel_dpio_write(dev_priv, DPIO_REFSFR(pipe),
+                       vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe),
                                         0x0df40000);
                else
-                       intel_dpio_write(dev_priv, DPIO_REFSFR(pipe),
+                       vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe),
                                         0x0df70000);
        } else { /* HDMI or VGA */
                /* Use bend source */
                if (!pipe)
-                       intel_dpio_write(dev_priv, DPIO_REFSFR(pipe),
+                       vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe),
                                         0x0df70000);
                else
-                       intel_dpio_write(dev_priv, DPIO_REFSFR(pipe),
+                       vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe),
                                         0x0df40000);
        }
 
-       coreclk = intel_dpio_read(dev_priv, DPIO_CORE_CLK(pipe));
+       coreclk = vlv_dpio_read(dev_priv, DPIO_CORE_CLK(pipe));
        coreclk = (coreclk & 0x0000ff00) | 0x01c00000;
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) ||
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP))
                coreclk |= 0x01000000;
-       intel_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), coreclk);
+       vlv_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), coreclk);
 
-       intel_dpio_write(dev_priv, DPIO_PLL_CML(pipe), 0x87871000);
+       vlv_dpio_write(dev_priv, DPIO_PLL_CML(pipe), 0x87871000);
 
        for_each_encoder_on_crtc(dev, &crtc->base, encoder)
                if (encoder->pre_pll_enable)
@@ -4961,9 +4903,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
                        dspcntr |= DISPPLANE_SEL_PIPE_B;
        }
 
-       DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe));
-       drm_mode_debug_printmodeline(mode);
-
        intel_set_pipe_timings(intel_crtc, mode, adjusted_mode);
 
        /* pipesrc and dspsize control the size that is scaled from,
@@ -5023,6 +4962,8 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t tmp;
 
+       pipe_config->cpu_transcoder = crtc->pipe;
+
        tmp = I915_READ(PIPECONF(crtc->pipe));
        if (!(tmp & PIPECONF_ENABLE))
                return false;
@@ -5745,8 +5686,6 @@ 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) {
@@ -5765,9 +5704,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        /* Ensure that the cursor is valid for the new mode before changing... */
        intel_crtc_update_cursor(crtc, true);
 
-       DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe));
-       drm_mode_debug_printmodeline(mode);
-
        /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
        if (intel_crtc->config.has_pch_encoder) {
                struct intel_pch_pll *pll;
@@ -5841,8 +5777,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 
        intel_update_watermarks(dev);
 
-       intel_update_linetime_watermarks(dev, pipe, adjusted_mode);
-
        return ret;
 }
 
@@ -5884,6 +5818,8 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t tmp;
 
+       pipe_config->cpu_transcoder = crtc->pipe;
+
        tmp = I915_READ(PIPECONF(crtc->pipe));
        if (!(tmp & PIPECONF_ENABLE))
                return false;
@@ -5909,23 +5845,13 @@ static void haswell_modeset_global_resources(struct drm_device *dev)
 {
        bool enable = false;
        struct intel_crtc *crtc;
-       struct intel_encoder *encoder;
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
-               if (crtc->pipe != PIPE_A && crtc->base.enabled)
-                       enable = true;
-               /* XXX: Should check for edp transcoder here, but thanks to init
-                * sequence that's not yet available. Just in case desktop eDP
-                * on PORT D is possible on haswell, too. */
-               /* Even the eDP panel fitter is outside the always-on well. */
-               if (crtc->config.pch_pfit.size && crtc->base.enabled)
-                       enable = true;
-       }
+               if (!crtc->base.enabled)
+                       continue;
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                           base.head) {
-               if (encoder->type != INTEL_OUTPUT_EDP &&
-                   encoder->connectors_active)
+               if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.size ||
+                   crtc->config.cpu_transcoder != TRANSCODER_EDP)
                        enable = true;
        }
 
@@ -5960,32 +5886,15 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
                num_connectors++;
        }
 
-       if (is_cpu_edp)
-               intel_crtc->config.cpu_transcoder = TRANSCODER_EDP;
-       else
-               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",
-            INTEL_PCH_TYPE(dev));
-
        WARN(num_connectors != 1, "%d connectors attached to pipe %c\n",
             num_connectors, pipe_name(pipe));
 
-       WARN_ON(I915_READ(PIPECONF(intel_crtc->config.cpu_transcoder)) &
-               (PIPECONF_ENABLE | I965_PIPECONF_ACTIVE));
-
-       WARN_ON(I915_READ(DSPCNTR(plane)) & DISPLAY_PLANE_ENABLE);
-
        if (!intel_ddi_pll_mode_set(crtc, adjusted_mode->clock))
                return -EINVAL;
 
        /* Ensure that the cursor is valid for the new mode before changing... */
        intel_crtc_update_cursor(crtc, true);
 
-       DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe));
-       drm_mode_debug_printmodeline(mode);
-
        if (intel_crtc->config.has_dp_encoder)
                intel_dp_set_m_n(intel_crtc);
 
@@ -6010,8 +5919,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
 
        intel_update_watermarks(dev);
 
-       intel_update_linetime_watermarks(dev, pipe, adjusted_mode);
-
        return ret;
 }
 
@@ -6020,15 +5927,37 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
        enum intel_display_power_domain pfit_domain;
        uint32_t tmp;
 
+       pipe_config->cpu_transcoder = crtc->pipe;
+       tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
+       if (tmp & TRANS_DDI_FUNC_ENABLE) {
+               enum pipe trans_edp_pipe;
+               switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
+               default:
+                       WARN(1, "unknown pipe linked to edp transcoder\n");
+               case TRANS_DDI_EDP_INPUT_A_ONOFF:
+               case TRANS_DDI_EDP_INPUT_A_ON:
+                       trans_edp_pipe = PIPE_A;
+                       break;
+               case TRANS_DDI_EDP_INPUT_B_ONOFF:
+                       trans_edp_pipe = PIPE_B;
+                       break;
+               case TRANS_DDI_EDP_INPUT_C_ONOFF:
+                       trans_edp_pipe = PIPE_C;
+                       break;
+               }
+
+               if (trans_edp_pipe == crtc->pipe)
+                       pipe_config->cpu_transcoder = TRANSCODER_EDP;
+       }
+
        if (!intel_display_power_enabled(dev,
-                       POWER_DOMAIN_TRANSCODER(cpu_transcoder)))
+                       POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder)))
                return false;
 
-       tmp = I915_READ(PIPECONF(cpu_transcoder));
+       tmp = I915_READ(PIPECONF(pipe_config->cpu_transcoder));
        if (!(tmp & PIPECONF_ENABLE))
                return false;
 
@@ -6037,7 +5966,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
         * 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(cpu_transcoder));
+       tmp = I915_READ(TRANS_DDI_FUNC_CTL(pipe_config->cpu_transcoder));
        if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(PORT_E) &&
            I915_READ(LPT_TRANSCONF) & TRANS_ENABLE) {
                pipe_config->has_pch_encoder = true;
@@ -6055,6 +5984,9 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
        if (intel_display_power_enabled(dev, pfit_domain))
                ironlake_get_pfit_config(crtc, pipe_config);
 
+       pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) &&
+                                  (I915_READ(IPS_CTL) & IPS_ENABLE);
+
        return true;
 }
 
@@ -6359,8 +6291,10 @@ void intel_crtc_load_lut(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);
-       int palreg = PALETTE(intel_crtc->pipe);
+       enum pipe pipe = intel_crtc->pipe;
+       int palreg = PALETTE(pipe);
        int i;
+       bool reenable_ips = false;
 
        /* The clocks have to be on to load the palette. */
        if (!crtc->enabled || !intel_crtc->active)
@@ -6368,7 +6302,17 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
 
        /* use legacy palette for Ironlake */
        if (HAS_PCH_SPLIT(dev))
-               palreg = LGC_PALETTE(intel_crtc->pipe);
+               palreg = LGC_PALETTE(pipe);
+
+       /* Workaround : Do not read or write the pipe palette/gamma data while
+        * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
+        */
+       if (intel_crtc->config.ips_enabled &&
+           ((I915_READ(GAMMA_MODE(pipe)) & GAMMA_MODE_MODE_MASK) ==
+            GAMMA_MODE_MODE_SPLIT)) {
+               hsw_disable_ips(intel_crtc);
+               reenable_ips = true;
+       }
 
        for (i = 0; i < 256; i++) {
                I915_WRITE(palreg + 4 * i,
@@ -6376,6 +6320,9 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
                           (intel_crtc->lut_g[i] << 8) |
                           intel_crtc->lut_b[i]);
        }
+
+       if (reenable_ips)
+               hsw_enable_ips(intel_crtc);
 }
 
 static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
@@ -6622,7 +6569,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        intel_crtc->cursor_width = width;
        intel_crtc->cursor_height = height;
 
-       intel_crtc_update_cursor(crtc, true);
+       intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
 
        return 0;
 fail_unpin:
@@ -6641,7 +6588,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        intel_crtc->cursor_x = x;
        intel_crtc->cursor_y = y;
 
-       intel_crtc_update_cursor(crtc, true);
+       intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
 
        return 0;
 }
@@ -7155,6 +7102,8 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
                kfree(work);
        }
 
+       intel_crtc_cursor_set(crtc, NULL, 0, 0, 0);
+
        drm_crtc_cleanup(crtc);
 
        kfree(intel_crtc);
@@ -7774,6 +7723,36 @@ pipe_config_set_bpp(struct drm_crtc *crtc,
        return bpp;
 }
 
+static void intel_dump_pipe_config(struct intel_crtc *crtc,
+                                  struct intel_crtc_config *pipe_config,
+                                  const char *context)
+{
+       DRM_DEBUG_KMS("[CRTC:%d]%s config for pipe %c\n", crtc->base.base.id,
+                     context, pipe_name(crtc->pipe));
+
+       DRM_DEBUG_KMS("cpu_transcoder: %c\n", transcoder_name(pipe_config->cpu_transcoder));
+       DRM_DEBUG_KMS("pipe bpp: %i, dithering: %i\n",
+                     pipe_config->pipe_bpp, pipe_config->dither);
+       DRM_DEBUG_KMS("fdi/pch: %i, lanes: %i, gmch_m: %u, gmch_n: %u, link_m: %u, link_n: %u, tu: %u\n",
+                     pipe_config->has_pch_encoder,
+                     pipe_config->fdi_lanes,
+                     pipe_config->fdi_m_n.gmch_m, pipe_config->fdi_m_n.gmch_n,
+                     pipe_config->fdi_m_n.link_m, pipe_config->fdi_m_n.link_n,
+                     pipe_config->fdi_m_n.tu);
+       DRM_DEBUG_KMS("requested mode:\n");
+       drm_mode_debug_printmodeline(&pipe_config->requested_mode);
+       DRM_DEBUG_KMS("adjusted mode:\n");
+       drm_mode_debug_printmodeline(&pipe_config->adjusted_mode);
+       DRM_DEBUG_KMS("gmch pfit: control: 0x%08x, ratios: 0x%08x, lvds border: 0x%08x\n",
+                     pipe_config->gmch_pfit.control,
+                     pipe_config->gmch_pfit.pgm_ratios,
+                     pipe_config->gmch_pfit.lvds_border_bits);
+       DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x\n",
+                     pipe_config->pch_pfit.pos,
+                     pipe_config->pch_pfit.size);
+       DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled);
+}
+
 static struct intel_crtc_config *
 intel_modeset_pipe_config(struct drm_crtc *crtc,
                          struct drm_framebuffer *fb,
@@ -7792,6 +7771,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
 
        drm_mode_copy(&pipe_config->adjusted_mode, mode);
        drm_mode_copy(&pipe_config->requested_mode, mode);
+       pipe_config->cpu_transcoder = to_intel_crtc(crtc)->pipe;
 
        plane_bpp = pipe_config_set_bpp(crtc, fb, pipe_config);
        if (plane_bpp < 0)
@@ -7843,8 +7823,6 @@ encoder_retry:
                goto encoder_retry;
        }
 
-       DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
-
        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);
@@ -8042,6 +8020,8 @@ intel_pipe_config_compare(struct drm_device *dev,
                return false; \
        }
 
+       PIPE_CONF_CHECK_I(cpu_transcoder);
+
        PIPE_CONF_CHECK_I(has_pch_encoder);
        PIPE_CONF_CHECK_I(fdi_lanes);
        PIPE_CONF_CHECK_I(fdi_m_n.gmch_m);
@@ -8067,6 +8047,15 @@ intel_pipe_config_compare(struct drm_device *dev,
        PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
                              DRM_MODE_FLAG_INTERLACE);
 
+       PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+                             DRM_MODE_FLAG_PHSYNC);
+       PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+                             DRM_MODE_FLAG_NHSYNC);
+       PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+                             DRM_MODE_FLAG_PVSYNC);
+       PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+                             DRM_MODE_FLAG_NVSYNC);
+
        PIPE_CONF_CHECK_I(requested_mode.hdisplay);
        PIPE_CONF_CHECK_I(requested_mode.vdisplay);
 
@@ -8078,6 +8067,8 @@ intel_pipe_config_compare(struct drm_device *dev,
        PIPE_CONF_CHECK_I(pch_pfit.pos);
        PIPE_CONF_CHECK_I(pch_pfit.size);
 
+       PIPE_CONF_CHECK_I(ips_enabled);
+
 #undef PIPE_CONF_CHECK_I
 #undef PIPE_CONF_CHECK_FLAGS
 
@@ -8159,6 +8150,8 @@ intel_modeset_check_state(struct drm_device *dev)
                bool enabled = false;
                bool active = false;
 
+               memset(&pipe_config, 0, sizeof(pipe_config));
+
                DRM_DEBUG_KMS("[CRTC:%d]\n",
                              crtc->base.base.id);
 
@@ -8172,6 +8165,8 @@ intel_modeset_check_state(struct drm_device *dev)
                        enabled = true;
                        if (encoder->connectors_active)
                                active = true;
+                       if (encoder->get_config)
+                               encoder->get_config(encoder, &pipe_config);
                }
                WARN(active != crtc->active,
                     "crtc's computed active state doesn't match tracked active state "
@@ -8180,17 +8175,20 @@ 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);
 
-               memset(&pipe_config, 0, sizeof(pipe_config));
-               pipe_config.cpu_transcoder = crtc->config.cpu_transcoder;
                active = dev_priv->display.get_pipe_config(crtc,
                                                           &pipe_config);
                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(dev, &crtc->config, &pipe_config),
-                    "pipe state doesn't match!\n");
+               if (active &&
+                   !intel_pipe_config_compare(dev, &crtc->config, &pipe_config)) {
+                       WARN(1, "pipe state doesn't match!\n");
+                       intel_dump_pipe_config(crtc, &pipe_config,
+                                              "[hw state]");
+                       intel_dump_pipe_config(crtc, &crtc->config,
+                                              "[sw state]");
+               }
        }
 }
 
@@ -8230,6 +8228,8 @@ static int __intel_set_mode(struct drm_crtc *crtc,
 
                        goto out;
                }
+               intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
+                                      "[modeset]");
        }
 
        for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
@@ -8244,12 +8244,10 @@ static int __intel_set_mode(struct drm_crtc *crtc,
         * to set it here already despite that we pass it down the callchain.
         */
        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
@@ -8588,12 +8586,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
                goto fail;
 
        if (config->mode_changed) {
-               if (set->mode) {
-                       DRM_DEBUG_KMS("attempting to set mode from"
-                                       " userspace\n");
-                       drm_mode_debug_printmodeline(set->mode);
-               }
-
                ret = intel_set_mode(set->crtc, set->mode,
                                     set->x, set->y, set->fb);
        } else if (config->fb_changed) {
@@ -8675,7 +8667,6 @@ 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->config.cpu_transcoder = pipe;
        if (IS_MOBILE(dev) && IS_GEN3(dev)) {
                DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
                intel_crtc->plane = !pipe;
@@ -9545,50 +9536,14 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe;
-       u32 tmp;
        struct drm_plane *plane;
        struct intel_crtc *crtc;
        struct intel_encoder *encoder;
        struct intel_connector *connector;
 
-       if (HAS_DDI(dev)) {
-               tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
-
-               if (tmp & TRANS_DDI_FUNC_ENABLE) {
-                       switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
-                       case TRANS_DDI_EDP_INPUT_A_ON:
-                       case TRANS_DDI_EDP_INPUT_A_ONOFF:
-                               pipe = PIPE_A;
-                               break;
-                       case TRANS_DDI_EDP_INPUT_B_ONOFF:
-                               pipe = PIPE_B;
-                               break;
-                       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->config.cpu_transcoder = TRANSCODER_EDP;
-
-                       DRM_DEBUG_KMS("Pipe %c using transcoder EDP\n",
-                                     pipe_name(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;
 
                crtc->active = dev_priv->display.get_pipe_config(crtc,
                                                                 &crtc->config);
@@ -9608,8 +9563,10 @@ setup_pipes:
                pipe = 0;
 
                if (encoder->get_hw_state(encoder, &pipe)) {
-                       encoder->base.crtc =
-                               dev_priv->pipe_to_crtc_mapping[pipe];
+                       crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+                       encoder->base.crtc = &crtc->base;
+                       if (encoder->get_config)
+                               encoder->get_config(encoder, &crtc->config);
                } else {
                        encoder->base.crtc = NULL;
                }
@@ -9647,6 +9604,7 @@ setup_pipes:
        for_each_pipe(pipe) {
                crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
                intel_sanitize_crtc(crtc);
+               intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]");
        }
 
        if (force_restore) {
@@ -9867,48 +9825,50 @@ intel_display_capture_error_state(struct drm_device *dev)
        return error;
 }
 
+#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__)
+
 void
-intel_display_print_error_state(struct seq_file *m,
+intel_display_print_error_state(struct drm_i915_error_state_buf *m,
                                struct drm_device *dev,
                                struct intel_display_error_state *error)
 {
        int i;
 
-       seq_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes);
+       err_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes);
        if (HAS_POWER_WELL(dev))
-               seq_printf(m, "PWR_WELL_CTL2: %08x\n",
+               err_printf(m, "PWR_WELL_CTL2: %08x\n",
                           error->power_well_driver);
        for_each_pipe(i) {
-               seq_printf(m, "Pipe [%d]:\n", i);
-               seq_printf(m, "  CPU transcoder: %c\n",
+               err_printf(m, "Pipe [%d]:\n", i);
+               err_printf(m, "  CPU transcoder: %c\n",
                           transcoder_name(error->pipe[i].cpu_transcoder));
-               seq_printf(m, "  CONF: %08x\n", error->pipe[i].conf);
-               seq_printf(m, "  SRC: %08x\n", error->pipe[i].source);
-               seq_printf(m, "  HTOTAL: %08x\n", error->pipe[i].htotal);
-               seq_printf(m, "  HBLANK: %08x\n", error->pipe[i].hblank);
-               seq_printf(m, "  HSYNC: %08x\n", error->pipe[i].hsync);
-               seq_printf(m, "  VTOTAL: %08x\n", error->pipe[i].vtotal);
-               seq_printf(m, "  VBLANK: %08x\n", error->pipe[i].vblank);
-               seq_printf(m, "  VSYNC: %08x\n", error->pipe[i].vsync);
-
-               seq_printf(m, "Plane [%d]:\n", i);
-               seq_printf(m, "  CNTR: %08x\n", error->plane[i].control);
-               seq_printf(m, "  STRIDE: %08x\n", error->plane[i].stride);
+               err_printf(m, "  CONF: %08x\n", error->pipe[i].conf);
+               err_printf(m, "  SRC: %08x\n", error->pipe[i].source);
+               err_printf(m, "  HTOTAL: %08x\n", error->pipe[i].htotal);
+               err_printf(m, "  HBLANK: %08x\n", error->pipe[i].hblank);
+               err_printf(m, "  HSYNC: %08x\n", error->pipe[i].hsync);
+               err_printf(m, "  VTOTAL: %08x\n", error->pipe[i].vtotal);
+               err_printf(m, "  VBLANK: %08x\n", error->pipe[i].vblank);
+               err_printf(m, "  VSYNC: %08x\n", error->pipe[i].vsync);
+
+               err_printf(m, "Plane [%d]:\n", i);
+               err_printf(m, "  CNTR: %08x\n", error->plane[i].control);
+               err_printf(m, "  STRIDE: %08x\n", error->plane[i].stride);
                if (INTEL_INFO(dev)->gen <= 3) {
-                       seq_printf(m, "  SIZE: %08x\n", error->plane[i].size);
-                       seq_printf(m, "  POS: %08x\n", error->plane[i].pos);
+                       err_printf(m, "  SIZE: %08x\n", error->plane[i].size);
+                       err_printf(m, "  POS: %08x\n", error->plane[i].pos);
                }
                if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev))
-                       seq_printf(m, "  ADDR: %08x\n", error->plane[i].addr);
+                       err_printf(m, "  ADDR: %08x\n", error->plane[i].addr);
                if (INTEL_INFO(dev)->gen >= 4) {
-                       seq_printf(m, "  SURF: %08x\n", error->plane[i].surface);
-                       seq_printf(m, "  TILEOFF: %08x\n", error->plane[i].tile_offset);
+                       err_printf(m, "  SURF: %08x\n", error->plane[i].surface);
+                       err_printf(m, "  TILEOFF: %08x\n", error->plane[i].tile_offset);
                }
 
-               seq_printf(m, "Cursor [%d]:\n", i);
-               seq_printf(m, "  CNTR: %08x\n", error->cursor[i].control);
-               seq_printf(m, "  POS: %08x\n", error->cursor[i].position);
-               seq_printf(m, "  BASE: %08x\n", error->cursor[i].base);
+               err_printf(m, "Cursor [%d]:\n", i);
+               err_printf(m, "  CNTR: %08x\n", error->cursor[i].control);
+               err_printf(m, "  POS: %08x\n", error->cursor[i].position);
+               err_printf(m, "  BASE: %08x\n", error->cursor[i].base);
        }
 }
 #endif
index bfc8664be8dc0e89a775a34279fbcdfbe3e1e81d..91a31b3b98295107096b6e3c94431ec05478d0c2 100644 (file)
@@ -59,22 +59,6 @@ static struct drm_device *intel_dp_to_dev(struct intel_dp *intel_dp)
        return intel_dig_port->base.base.dev;
 }
 
-/**
- * is_cpu_edp - is the port on the CPU and attached to an eDP panel?
- * @intel_dp: DP struct
- *
- * Returns true if the given DP struct corresponds to a CPU eDP port.
- */
-static bool is_cpu_edp(struct intel_dp *intel_dp)
-{
-       struct drm_device *dev = intel_dp_to_dev(intel_dp);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       enum port port = intel_dig_port->port;
-
-       return is_edp(intel_dp) &&
-               (port == PORT_A || (port == PORT_C && IS_VALLEYVIEW(dev)));
-}
-
 static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
 {
        return enc_to_intel_dp(&intel_attached_encoder(connector)->base);
@@ -317,11 +301,12 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
         * Note that PCH attached eDP panels should use a 125MHz input
         * clock divider.
         */
-       if (is_cpu_edp(intel_dp)) {
+       if (IS_VALLEYVIEW(dev)) {
+               aux_clock_divider = 100;
+       } else if (intel_dig_port->port == PORT_A) {
                if (HAS_DDI(dev))
-                       aux_clock_divider = intel_ddi_get_cdclk_freq(dev_priv) >> 1;
-               else if (IS_VALLEYVIEW(dev))
-                       aux_clock_divider = 100;
+                       aux_clock_divider = DIV_ROUND_CLOSEST(
+                               intel_ddi_get_cdclk_freq(dev_priv), 2000);
                else if (IS_GEN6(dev) || IS_GEN7(dev))
                        aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */
                else
@@ -684,6 +669,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       enum port port = dp_to_dig_port(intel_dp)->port;
        struct intel_crtc *intel_crtc = encoder->new_crtc;
        struct intel_connector *intel_connector = intel_dp->attached_connector;
        int lane_count, clock;
@@ -693,7 +679,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
        int target_clock, link_avail, link_clock;
 
-       if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && !is_cpu_edp(intel_dp))
+       if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && port != PORT_A)
                pipe_config->has_pch_encoder = true;
 
        pipe_config->has_dp_encoder = true;
@@ -827,6 +813,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+       enum port port = dp_to_dig_port(intel_dp)->port;
        struct drm_crtc *crtc = encoder->crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
@@ -867,7 +854,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
 
        /* Split out the IBX/CPU vs CPT settings */
 
-       if (is_cpu_edp(intel_dp) && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) {
+       if (port == PORT_A && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) {
                if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
                        intel_dp->DP |= DP_SYNC_HS_HIGH;
                if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
@@ -884,7 +871,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                        intel_dp->DP |= DP_PLL_FREQ_160MHZ;
                else
                        intel_dp->DP |= DP_PLL_FREQ_270MHZ;
-       } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
+       } else if (!HAS_PCH_CPT(dev) || port == PORT_A) {
                if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev))
                        intel_dp->DP |= intel_dp->color_range;
 
@@ -900,7 +887,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                if (intel_crtc->pipe == 1)
                        intel_dp->DP |= DP_PIPEB_SELECT;
 
-               if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) {
+               if (port == PORT_A && !IS_VALLEYVIEW(dev)) {
                        /* don't miss out required setting for eDP */
                        if (adjusted_mode->clock < 200000)
                                intel_dp->DP |= DP_PLL_FREQ_160MHZ;
@@ -911,7 +898,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
        }
 
-       if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev))
+       if (port == PORT_A && !IS_VALLEYVIEW(dev))
                ironlake_set_pll_edp(crtc, adjusted_mode->clock);
 }
 
@@ -1301,6 +1288,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
                                  enum pipe *pipe)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       enum port port = dp_to_dig_port(intel_dp)->port;
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 tmp = I915_READ(intel_dp->output_reg);
@@ -1308,9 +1296,9 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
        if (!(tmp & DP_PORT_EN))
                return false;
 
-       if (is_cpu_edp(intel_dp) && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) {
+       if (port == PORT_A && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) {
                *pipe = PORT_TO_PIPE_CPT(tmp);
-       } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
+       } else if (!HAS_PCH_CPT(dev) || port == PORT_A) {
                *pipe = PORT_TO_PIPE(tmp);
        } else {
                u32 trans_sel;
@@ -1346,9 +1334,33 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
        return true;
 }
 
+static void intel_dp_get_config(struct intel_encoder *encoder,
+                               struct intel_crtc_config *pipe_config)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       u32 tmp, flags = 0;
+
+       tmp = I915_READ(intel_dp->output_reg);
+
+       if (tmp & DP_SYNC_HS_HIGH)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+
+       if (tmp & DP_SYNC_VS_HIGH)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       pipe_config->adjusted_mode.flags |= flags;
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       enum port port = dp_to_dig_port(intel_dp)->port;
+       struct drm_device *dev = encoder->base.dev;
 
        /* Make sure the panel is off before trying to change the mode. But also
         * ensure that we have vdd while we switch off the panel. */
@@ -1358,16 +1370,17 @@ static void intel_disable_dp(struct intel_encoder *encoder)
        ironlake_edp_panel_off(intel_dp);
 
        /* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */
-       if (!is_cpu_edp(intel_dp))
+       if (!(port == PORT_A || IS_VALLEYVIEW(dev)))
                intel_dp_link_down(intel_dp);
 }
 
 static void intel_post_disable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       enum port port = dp_to_dig_port(intel_dp)->port;
        struct drm_device *dev = encoder->base.dev;
 
-       if (is_cpu_edp(intel_dp)) {
+       if (port == PORT_A || IS_VALLEYVIEW(dev)) {
                intel_dp_link_down(intel_dp);
                if (!IS_VALLEYVIEW(dev))
                        ironlake_edp_pll_off(intel_dp);
@@ -1405,34 +1418,32 @@ static void intel_enable_dp(struct intel_encoder *encoder)
 static void intel_pre_enable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev))
+       if (dport->port == PORT_A && !IS_VALLEYVIEW(dev))
                ironlake_edp_pll_on(intel_dp);
 
        if (IS_VALLEYVIEW(dev)) {
-               struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
                struct intel_crtc *intel_crtc =
                        to_intel_crtc(encoder->base.crtc);
                int port = vlv_dport_to_channel(dport);
                int pipe = intel_crtc->pipe;
                u32 val;
 
-               WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
-
-               val = intel_dpio_read(dev_priv, DPIO_DATA_LANE_A(port));
+               val = vlv_dpio_read(dev_priv, DPIO_DATA_LANE_A(port));
                val = 0;
                if (pipe)
                        val |= (1<<21);
                else
                        val &= ~(1<<21);
                val |= 0x001000c4;
-               intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL(port), val);
+               vlv_dpio_write(dev_priv, DPIO_DATA_CHANNEL(port), val);
 
-               intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF0(port),
+               vlv_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF0(port),
                                 0x00760018);
-               intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF8(port),
+               vlv_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF8(port),
                                 0x00400888);
        }
 }
@@ -1447,22 +1458,20 @@ static void intel_dp_pre_pll_enable(struct intel_encoder *encoder)
        if (!IS_VALLEYVIEW(dev))
                return;
 
-       WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
-
        /* Program Tx lane resets to default */
-       intel_dpio_write(dev_priv, DPIO_PCS_TX(port),
+       vlv_dpio_write(dev_priv, DPIO_PCS_TX(port),
                         DPIO_PCS_TX_LANE2_RESET |
                         DPIO_PCS_TX_LANE1_RESET);
-       intel_dpio_write(dev_priv, DPIO_PCS_CLK(port),
+       vlv_dpio_write(dev_priv, DPIO_PCS_CLK(port),
                         DPIO_PCS_CLK_CRI_RXEB_EIOS_EN |
                         DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN |
                         (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) |
                                 DPIO_PCS_CLK_SOFT_RESET);
 
        /* Fix up inter-pair skew failure */
-       intel_dpio_write(dev_priv, DPIO_PCS_STAGGER1(port), 0x00750f00);
-       intel_dpio_write(dev_priv, DPIO_TX_CTL(port), 0x00001500);
-       intel_dpio_write(dev_priv, DPIO_TX_LANE(port), 0x40400000);
+       vlv_dpio_write(dev_priv, DPIO_PCS_STAGGER1(port), 0x00750f00);
+       vlv_dpio_write(dev_priv, DPIO_TX_CTL(port), 0x00001500);
+       vlv_dpio_write(dev_priv, DPIO_TX_LANE(port), 0x40400000);
 }
 
 /*
@@ -1524,12 +1533,13 @@ static uint8_t
 intel_dp_voltage_max(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       enum port port = dp_to_dig_port(intel_dp)->port;
 
        if (IS_VALLEYVIEW(dev))
                return DP_TRAIN_VOLTAGE_SWING_1200;
-       else if (IS_GEN7(dev) && is_cpu_edp(intel_dp))
+       else if (IS_GEN7(dev) && port == PORT_A)
                return DP_TRAIN_VOLTAGE_SWING_800;
-       else if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
+       else if (HAS_PCH_CPT(dev) && port != PORT_A)
                return DP_TRAIN_VOLTAGE_SWING_1200;
        else
                return DP_TRAIN_VOLTAGE_SWING_800;
@@ -1539,6 +1549,7 @@ static uint8_t
 intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       enum port port = dp_to_dig_port(intel_dp)->port;
 
        if (HAS_DDI(dev)) {
                switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
@@ -1564,7 +1575,7 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
                default:
                        return DP_TRAIN_PRE_EMPHASIS_0;
                }
-       } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) {
+       } else if (IS_GEN7(dev) && port == PORT_A) {
                switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
                case DP_TRAIN_VOLTAGE_SWING_400:
                        return DP_TRAIN_PRE_EMPHASIS_6;
@@ -1599,8 +1610,6 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
        uint8_t train_set = intel_dp->train_set[0];
        int port = vlv_dport_to_channel(dport);
 
-       WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
-
        switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
        case DP_TRAIN_PRE_EMPHASIS_0:
                preemph_reg_value = 0x0004000;
@@ -1674,14 +1683,14 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
                return 0;
        }
 
-       intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x00000000);
-       intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL4(port), demph_reg_value);
-       intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL2(port),
+       vlv_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x00000000);
+       vlv_dpio_write(dev_priv, DPIO_TX_SWING_CTL4(port), demph_reg_value);
+       vlv_dpio_write(dev_priv, DPIO_TX_SWING_CTL2(port),
                         uniqtranscale_reg_value);
-       intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL3(port), 0x0C782040);
-       intel_dpio_write(dev_priv, DPIO_PCS_STAGGER0(port), 0x00030000);
-       intel_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port), preemph_reg_value);
-       intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x80000000);
+       vlv_dpio_write(dev_priv, DPIO_TX_SWING_CTL3(port), 0x0C782040);
+       vlv_dpio_write(dev_priv, DPIO_PCS_STAGGER0(port), 0x00030000);
+       vlv_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port), preemph_reg_value);
+       vlv_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x80000000);
 
        return 0;
 }
@@ -1853,6 +1862,7 @@ static void
 intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       enum port port = intel_dig_port->port;
        struct drm_device *dev = intel_dig_port->base.base.dev;
        uint32_t signal_levels, mask;
        uint8_t train_set = intel_dp->train_set[0];
@@ -1863,10 +1873,10 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
        } else if (IS_VALLEYVIEW(dev)) {
                signal_levels = intel_vlv_signal_levels(intel_dp);
                mask = 0;
-       } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) {
+       } else if (IS_GEN7(dev) && port == PORT_A) {
                signal_levels = intel_gen7_edp_signal_levels(train_set);
                mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB;
-       } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
+       } else if (IS_GEN6(dev) && port == PORT_A) {
                signal_levels = intel_gen6_edp_signal_levels(train_set);
                mask = EDP_LINK_TRAIN_VOL_EMP_MASK_SNB;
        } else {
@@ -1916,8 +1926,7 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
                }
                I915_WRITE(DP_TP_CTL(port), temp);
 
-       } else if (HAS_PCH_CPT(dev) &&
-                  (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) {
+       } else if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || port != PORT_A)) {
                dp_reg_value &= ~DP_LINK_TRAIN_MASK_CPT;
 
                switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
@@ -2168,6 +2177,7 @@ static void
 intel_dp_link_down(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       enum port port = intel_dig_port->port;
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc =
@@ -2197,7 +2207,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
 
        DRM_DEBUG_KMS("\n");
 
-       if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) {
+       if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || port != PORT_A)) {
                DP &= ~DP_LINK_TRAIN_MASK_CPT;
                I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
        } else {
@@ -2488,11 +2498,10 @@ intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
                        return NULL;
 
                size = (intel_connector->edid->extensions + 1) * EDID_LENGTH;
-               edid = kmalloc(size, GFP_KERNEL);
+               edid = kmemdup(intel_connector->edid, size, GFP_KERNEL);
                if (!edid)
                        return NULL;
 
-               memcpy(edid, intel_connector->edid, size);
                return edid;
        }
 
@@ -2925,9 +2934,6 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
                pp_div_reg = PIPEA_PP_DIVISOR;
        }
 
-       if (IS_VALLEYVIEW(dev))
-               port_sel = I915_READ(pp_on_reg) & 0xc0000000;
-
        /* And finally store the new values in the power sequencer. */
        pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) |
                (seq->t8 << PANEL_LIGHT_ON_DELAY_SHIFT);
@@ -2941,8 +2947,10 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
 
        /* Haswell doesn't have any port selection bits for the panel
         * power sequencer any more. */
-       if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) {
-               if (is_cpu_edp(intel_dp))
+       if (IS_VALLEYVIEW(dev)) {
+               port_sel = I915_READ(pp_on_reg) & 0xc0000000;
+       } else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) {
+               if (dp_to_dig_port(intel_dp)->port == PORT_A)
                        port_sel = PANEL_POWER_PORT_DP_A;
                else
                        port_sel = PANEL_POWER_PORT_DP_D;
@@ -3184,6 +3192,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
        intel_encoder->disable = intel_disable_dp;
        intel_encoder->post_disable = intel_post_disable_dp;
        intel_encoder->get_hw_state = intel_dp_get_hw_state;
+       intel_encoder->get_config = intel_dp_get_config;
        if (IS_VALLEYVIEW(dev))
                intel_encoder->pre_pll_enable = intel_dp_pre_pll_enable;
 
index 9b0af7e27c82a40a41b9d26a94eab454834edfde..fdf6303be0a96951057d6fa6eb1e9f89289d58d4 100644 (file)
@@ -139,6 +139,10 @@ struct intel_encoder {
         * the encoder is active. If the encoder is enabled it also set the pipe
         * it is connected to in the pipe parameter. */
        bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe);
+       /* Reconstructs the equivalent mode flags for the current hardware
+        * state. */
+       void (*get_config)(struct intel_encoder *,
+                          struct intel_crtc_config *pipe_config);
        int crtc_mask;
        enum hpd_pin hpd_pin;
 };
@@ -264,6 +268,8 @@ struct intel_crtc_config {
        /* FDI configuration, only valid if has_pch_encoder is set. */
        int fdi_lanes;
        struct intel_link_m_n fdi_m_n;
+
+       bool ips_enabled;
 };
 
 struct intel_crtc {
@@ -322,6 +328,18 @@ struct intel_plane {
        unsigned int crtc_w, crtc_h;
        uint32_t src_x, src_y;
        uint32_t src_w, src_h;
+
+       /* Since we need to change the watermarks before/after
+        * enabling/disabling the planes, we need to store the parameters here
+        * as the other pieces of the struct may not reflect the values we want
+        * for the watermark calculations. Currently only Haswell uses this.
+        */
+       struct {
+               bool enable;
+               uint8_t bytes_per_pixel;
+               uint32_t horiz_pixels;
+       } wm;
+
        void (*update_plane)(struct drm_plane *plane,
                             struct drm_framebuffer *fb,
                             struct drm_i915_gem_object *obj,
@@ -727,9 +745,7 @@ extern void intel_ddi_init(struct drm_device *dev, enum port port);
 extern void intel_update_watermarks(struct drm_device *dev);
 extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
                                           uint32_t sprite_width,
-                                          int pixel_size);
-extern void intel_update_linetime_watermarks(struct drm_device *dev, int pipe,
-                        struct drm_display_mode *mode);
+                                          int pixel_size, bool enable);
 
 extern unsigned long intel_gen4_compute_page_offset(int *x, int *y,
                                                    unsigned int tiling_mode,
@@ -741,10 +757,6 @@ extern int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
 extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
                                     struct drm_file *file_priv);
 
-extern u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg);
-extern void intel_dpio_write(struct drm_i915_private *dev_priv, int reg,
-                            u32 val);
-
 /* Power-related functions, located in intel_pm.c */
 extern void intel_init_pm(struct drm_device *dev);
 /* FBC */
index 2c0be924e9a9553f380eb20bb85eea9e4816b653..eb2020eb2b7ea1c60dde15062c426182e30d9d05 100644 (file)
@@ -136,6 +136,26 @@ static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
        return true;
 }
 
+static void intel_dvo_get_config(struct intel_encoder *encoder,
+                                struct intel_crtc_config *pipe_config)
+{
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
+       u32 tmp, flags = 0;
+
+       tmp = I915_READ(intel_dvo->dev.dvo_reg);
+       if (tmp & DVO_HSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+       if (tmp & DVO_VSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       pipe_config->adjusted_mode.flags |= flags;
+}
+
 static void intel_disable_dvo(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
@@ -160,6 +180,7 @@ static void intel_enable_dvo(struct intel_encoder *encoder)
        intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
 }
 
+/* Special dpms function to support cloning between dvo/sdvo/crt. */
 static void intel_dvo_dpms(struct drm_connector *connector, int mode)
 {
        struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
@@ -181,6 +202,8 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode)
                return;
        }
 
+       /* We call connector dpms manually below in case pipe dpms doesn't
+        * change due to cloning. */
        if (mode == DRM_MODE_DPMS_ON) {
                intel_dvo->base.connectors_active = true;
 
@@ -447,6 +470,7 @@ void intel_dvo_init(struct drm_device *dev)
        intel_encoder->disable = intel_disable_dvo;
        intel_encoder->enable = intel_enable_dvo;
        intel_encoder->get_hw_state = intel_dvo_get_hw_state;
+       intel_encoder->get_config = intel_dvo_get_config;
        intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
 
        /* Now, try to find a controller */
index 2b727f0d201fd8e7e0f82e5efa5e77553fcff630..8062a92e6e80cc57b1b08bd12575a08b487dad3a 100644 (file)
@@ -658,6 +658,28 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
        return true;
 }
 
+static void intel_hdmi_get_config(struct intel_encoder *encoder,
+                                 struct intel_crtc_config *pipe_config)
+{
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       u32 tmp, flags = 0;
+
+       tmp = I915_READ(intel_hdmi->hdmi_reg);
+
+       if (tmp & SDVO_HSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+
+       if (tmp & SDVO_VSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       pipe_config->adjusted_mode.flags |= flags;
+}
+
 static void intel_enable_hdmi(struct intel_encoder *encoder)
 {
        struct drm_device *dev = encoder->base.dev;
@@ -996,38 +1018,36 @@ static void intel_hdmi_pre_enable(struct intel_encoder *encoder)
        if (!IS_VALLEYVIEW(dev))
                return;
 
-       WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
-
        /* Enable clock channels for this port */
-       val = intel_dpio_read(dev_priv, DPIO_DATA_LANE_A(port));
+       val = vlv_dpio_read(dev_priv, DPIO_DATA_LANE_A(port));
        val = 0;
        if (pipe)
                val |= (1<<21);
        else
                val &= ~(1<<21);
        val |= 0x001000c4;
-       intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL(port), val);
+       vlv_dpio_write(dev_priv, DPIO_DATA_CHANNEL(port), val);
 
        /* HDMI 1.0V-2dB */
-       intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0);
-       intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL4(port),
+       vlv_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0);
+       vlv_dpio_write(dev_priv, DPIO_TX_SWING_CTL4(port),
                         0x2b245f5f);
-       intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL2(port),
+       vlv_dpio_write(dev_priv, DPIO_TX_SWING_CTL2(port),
                         0x5578b83a);
-       intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL3(port),
+       vlv_dpio_write(dev_priv, DPIO_TX_SWING_CTL3(port),
                         0x0c782040);
-       intel_dpio_write(dev_priv, DPIO_TX3_SWING_CTL4(port),
+       vlv_dpio_write(dev_priv, DPIO_TX3_SWING_CTL4(port),
                         0x2b247878);
-       intel_dpio_write(dev_priv, DPIO_PCS_STAGGER0(port), 0x00030000);
-       intel_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port),
+       vlv_dpio_write(dev_priv, DPIO_PCS_STAGGER0(port), 0x00030000);
+       vlv_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port),
                         0x00002000);
-       intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port),
+       vlv_dpio_write(dev_priv, DPIO_TX_OCALINIT(port),
                         DPIO_TX_OCALINIT_EN);
 
        /* Program lane clock */
-       intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF0(port),
+       vlv_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF0(port),
                         0x00760018);
-       intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF8(port),
+       vlv_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF8(port),
                         0x00400888);
 }
 
@@ -1041,26 +1061,24 @@ static void intel_hdmi_pre_pll_enable(struct intel_encoder *encoder)
        if (!IS_VALLEYVIEW(dev))
                return;
 
-       WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
-
        /* Program Tx lane resets to default */
-       intel_dpio_write(dev_priv, DPIO_PCS_TX(port),
+       vlv_dpio_write(dev_priv, DPIO_PCS_TX(port),
                         DPIO_PCS_TX_LANE2_RESET |
                         DPIO_PCS_TX_LANE1_RESET);
-       intel_dpio_write(dev_priv, DPIO_PCS_CLK(port),
+       vlv_dpio_write(dev_priv, DPIO_PCS_CLK(port),
                         DPIO_PCS_CLK_CRI_RXEB_EIOS_EN |
                         DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN |
                         (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) |
                         DPIO_PCS_CLK_SOFT_RESET);
 
        /* Fix up inter-pair skew failure */
-       intel_dpio_write(dev_priv, DPIO_PCS_STAGGER1(port), 0x00750f00);
-       intel_dpio_write(dev_priv, DPIO_TX_CTL(port), 0x00001500);
-       intel_dpio_write(dev_priv, DPIO_TX_LANE(port), 0x40400000);
+       vlv_dpio_write(dev_priv, DPIO_PCS_STAGGER1(port), 0x00750f00);
+       vlv_dpio_write(dev_priv, DPIO_TX_CTL(port), 0x00001500);
+       vlv_dpio_write(dev_priv, DPIO_TX_LANE(port), 0x40400000);
 
-       intel_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port),
+       vlv_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port),
                         0x00002000);
-       intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port),
+       vlv_dpio_write(dev_priv, DPIO_TX_OCALINIT(port),
                         DPIO_TX_OCALINIT_EN);
 }
 
@@ -1072,8 +1090,8 @@ static void intel_hdmi_post_disable(struct intel_encoder *encoder)
 
        /* Reset lanes to avoid HDMI flicker (VLV w/a) */
        mutex_lock(&dev_priv->dpio_lock);
-       intel_dpio_write(dev_priv, DPIO_PCS_TX(port), 0x00000000);
-       intel_dpio_write(dev_priv, DPIO_PCS_CLK(port), 0x00e00060);
+       vlv_dpio_write(dev_priv, DPIO_PCS_TX(port), 0x00000000);
+       vlv_dpio_write(dev_priv, DPIO_PCS_CLK(port), 0x00e00060);
        mutex_unlock(&dev_priv->dpio_lock);
 }
 
@@ -1216,6 +1234,7 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
        intel_encoder->enable = intel_enable_hdmi;
        intel_encoder->disable = intel_disable_hdmi;
        intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
+       intel_encoder->get_config = intel_hdmi_get_config;
        if (IS_VALLEYVIEW(dev)) {
                intel_encoder->pre_enable = intel_hdmi_pre_enable;
                intel_encoder->pre_pll_enable = intel_hdmi_pre_pll_enable;
index 36fe291172ee973b121c9bec0edefdf81f7d956c..655486099b76483bd2300744af1918d410f743bb 100644 (file)
@@ -86,6 +86,31 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
        return true;
 }
 
+static void intel_lvds_get_config(struct intel_encoder *encoder,
+                                 struct intel_crtc_config *pipe_config)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 lvds_reg, tmp, flags = 0;
+
+       if (HAS_PCH_SPLIT(dev))
+               lvds_reg = PCH_LVDS;
+       else
+               lvds_reg = LVDS;
+
+       tmp = I915_READ(lvds_reg);
+       if (tmp & LVDS_HSYNC_POLARITY)
+               flags |= DRM_MODE_FLAG_NHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       if (tmp & LVDS_VSYNC_POLARITY)
+               flags |= DRM_MODE_FLAG_NVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_PVSYNC;
+
+       pipe_config->adjusted_mode.flags |= flags;
+}
+
 /* The LVDS pin pair needs to be on before the DPLLs are enabled.
  * This is an exception to the general rule that mode_set doesn't turn
  * things on.
@@ -921,6 +946,7 @@ bool intel_lvds_init(struct drm_device *dev)
        intel_encoder->compute_config = intel_lvds_compute_config;
        intel_encoder->disable = intel_disable_lvds;
        intel_encoder->get_hw_state = intel_lvds_get_hw_state;
+       intel_encoder->get_config = intel_lvds_get_config;
        intel_connector->get_hw_state = intel_connector_get_hw_state;
 
        intel_connector_attach_encoder(intel_connector, intel_encoder);
index 67a2501d519db97bc59e24f0a93c334e58fc1f74..836794b68fc6cb9df13b6ee578ff5c1999bfe401 100644 (file)
@@ -1485,14 +1485,15 @@ err:
 }
 
 void
-intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error)
+intel_overlay_print_error_state(struct drm_i915_error_state_buf *m,
+                               struct intel_overlay_error_state *error)
 {
-       seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
-                  error->dovsta, error->isr);
-       seq_printf(m, "  Register file at 0x%08lx:\n",
-                  error->base);
+       i915_error_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
+                         error->dovsta, error->isr);
+       i915_error_printf(m, "  Register file at 0x%08lx:\n",
+                         error->base);
 
-#define P(x) seq_printf(m, "    " #x ":        0x%08x\n", error->regs.x)
+#define P(x) i915_error_printf(m, "    " #x ": 0x%08x\n", error->regs.x)
        P(OBUF_0Y);
        P(OBUF_1Y);
        P(OBUF_0U);
index 56f17b2382fc6b9cdcb925275adc543f02df42b9..80bea1d3209fad623a9d189f5ac1b3e1c12b6f0f 100644 (file)
@@ -332,7 +332,7 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 val;
 
-       WARN_ON(!spin_is_locked(&dev_priv->backlight.lock));
+       WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight.lock));
 
        /* Restore the CTL value if it lost, e.g. GPU reset */
 
index e2255ed9789458dac8b63781192a1cc48ed7411e..49a188718f9da9297fed0b44c82f11708f92a153 100644 (file)
@@ -2072,31 +2072,561 @@ static void ivybridge_update_wm(struct drm_device *dev)
                   cursor_wm);
 }
 
-static void
-haswell_update_linetime_wm(struct drm_device *dev, int pipe,
-                                struct drm_display_mode *mode)
+static uint32_t hsw_wm_get_pixel_rate(struct drm_device *dev,
+                                     struct drm_crtc *crtc)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       uint32_t pixel_rate, pfit_size;
+
+       if (intel_crtc->config.pixel_target_clock)
+               pixel_rate = intel_crtc->config.pixel_target_clock;
+       else
+               pixel_rate = intel_crtc->config.adjusted_mode.clock;
+
+       /* We only use IF-ID interlacing. If we ever use PF-ID we'll need to
+        * adjust the pixel_rate here. */
+
+       pfit_size = intel_crtc->config.pch_pfit.size;
+       if (pfit_size) {
+               uint64_t pipe_w, pipe_h, pfit_w, pfit_h;
+
+               pipe_w = intel_crtc->config.requested_mode.hdisplay;
+               pipe_h = intel_crtc->config.requested_mode.vdisplay;
+               pfit_w = (pfit_size >> 16) & 0xFFFF;
+               pfit_h = pfit_size & 0xFFFF;
+               if (pipe_w < pfit_w)
+                       pipe_w = pfit_w;
+               if (pipe_h < pfit_h)
+                       pipe_h = pfit_h;
+
+               pixel_rate = div_u64((uint64_t) pixel_rate * pipe_w * pipe_h,
+                                    pfit_w * pfit_h);
+       }
+
+       return pixel_rate;
+}
+
+static uint32_t hsw_wm_method1(uint32_t pixel_rate, uint8_t bytes_per_pixel,
+                              uint32_t latency)
+{
+       uint64_t ret;
+
+       ret = (uint64_t) pixel_rate * bytes_per_pixel * latency;
+       ret = DIV_ROUND_UP_ULL(ret, 64 * 10000) + 2;
+
+       return ret;
+}
+
+static uint32_t hsw_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal,
+                              uint32_t horiz_pixels, uint8_t bytes_per_pixel,
+                              uint32_t latency)
+{
+       uint32_t ret;
+
+       ret = (latency * pixel_rate) / (pipe_htotal * 10000);
+       ret = (ret + 1) * horiz_pixels * bytes_per_pixel;
+       ret = DIV_ROUND_UP(ret, 64) + 2;
+       return ret;
+}
+
+static uint32_t hsw_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels,
+                          uint8_t bytes_per_pixel)
+{
+       return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2;
+}
+
+struct hsw_pipe_wm_parameters {
+       bool active;
+       bool sprite_enabled;
+       uint8_t pri_bytes_per_pixel;
+       uint8_t spr_bytes_per_pixel;
+       uint8_t cur_bytes_per_pixel;
+       uint32_t pri_horiz_pixels;
+       uint32_t spr_horiz_pixels;
+       uint32_t cur_horiz_pixels;
+       uint32_t pipe_htotal;
+       uint32_t pixel_rate;
+};
+
+struct hsw_wm_maximums {
+       uint16_t pri;
+       uint16_t spr;
+       uint16_t cur;
+       uint16_t fbc;
+};
+
+struct hsw_lp_wm_result {
+       bool enable;
+       bool fbc_enable;
+       uint32_t pri_val;
+       uint32_t spr_val;
+       uint32_t cur_val;
+       uint32_t fbc_val;
+};
+
+struct hsw_wm_values {
+       uint32_t wm_pipe[3];
+       uint32_t wm_lp[3];
+       uint32_t wm_lp_spr[3];
+       uint32_t wm_linetime[3];
+       bool enable_fbc_wm;
+};
+
+enum hsw_data_buf_partitioning {
+       HSW_DATA_BUF_PART_1_2,
+       HSW_DATA_BUF_PART_5_6,
+};
+
+/* For both WM_PIPE and WM_LP. */
+static uint32_t hsw_compute_pri_wm(struct hsw_pipe_wm_parameters *params,
+                                  uint32_t mem_value,
+                                  bool is_lp)
+{
+       uint32_t method1, method2;
+
+       /* TODO: for now, assume the primary plane is always enabled. */
+       if (!params->active)
+               return 0;
+
+       method1 = hsw_wm_method1(params->pixel_rate,
+                                params->pri_bytes_per_pixel,
+                                mem_value);
+
+       if (!is_lp)
+               return method1;
+
+       method2 = hsw_wm_method2(params->pixel_rate,
+                                params->pipe_htotal,
+                                params->pri_horiz_pixels,
+                                params->pri_bytes_per_pixel,
+                                mem_value);
+
+       return min(method1, method2);
+}
+
+/* For both WM_PIPE and WM_LP. */
+static uint32_t hsw_compute_spr_wm(struct hsw_pipe_wm_parameters *params,
+                                  uint32_t mem_value)
+{
+       uint32_t method1, method2;
+
+       if (!params->active || !params->sprite_enabled)
+               return 0;
+
+       method1 = hsw_wm_method1(params->pixel_rate,
+                                params->spr_bytes_per_pixel,
+                                mem_value);
+       method2 = hsw_wm_method2(params->pixel_rate,
+                                params->pipe_htotal,
+                                params->spr_horiz_pixels,
+                                params->spr_bytes_per_pixel,
+                                mem_value);
+       return min(method1, method2);
+}
+
+/* For both WM_PIPE and WM_LP. */
+static uint32_t hsw_compute_cur_wm(struct hsw_pipe_wm_parameters *params,
+                                  uint32_t mem_value)
+{
+       if (!params->active)
+               return 0;
+
+       return hsw_wm_method2(params->pixel_rate,
+                             params->pipe_htotal,
+                             params->cur_horiz_pixels,
+                             params->cur_bytes_per_pixel,
+                             mem_value);
+}
+
+/* Only for WM_LP. */
+static uint32_t hsw_compute_fbc_wm(struct hsw_pipe_wm_parameters *params,
+                                  uint32_t pri_val,
+                                  uint32_t mem_value)
+{
+       if (!params->active)
+               return 0;
+
+       return hsw_wm_fbc(pri_val,
+                         params->pri_horiz_pixels,
+                         params->pri_bytes_per_pixel);
+}
+
+static bool hsw_compute_lp_wm(uint32_t mem_value, struct hsw_wm_maximums *max,
+                             struct hsw_pipe_wm_parameters *params,
+                             struct hsw_lp_wm_result *result)
+{
+       enum pipe pipe;
+       uint32_t pri_val[3], spr_val[3], cur_val[3], fbc_val[3];
+
+       for (pipe = PIPE_A; pipe <= PIPE_C; pipe++) {
+               struct hsw_pipe_wm_parameters *p = &params[pipe];
+
+               pri_val[pipe] = hsw_compute_pri_wm(p, mem_value, true);
+               spr_val[pipe] = hsw_compute_spr_wm(p, mem_value);
+               cur_val[pipe] = hsw_compute_cur_wm(p, mem_value);
+               fbc_val[pipe] = hsw_compute_fbc_wm(p, pri_val[pipe], mem_value);
+       }
+
+       result->pri_val = max3(pri_val[0], pri_val[1], pri_val[2]);
+       result->spr_val = max3(spr_val[0], spr_val[1], spr_val[2]);
+       result->cur_val = max3(cur_val[0], cur_val[1], cur_val[2]);
+       result->fbc_val = max3(fbc_val[0], fbc_val[1], fbc_val[2]);
+
+       if (result->fbc_val > max->fbc) {
+               result->fbc_enable = false;
+               result->fbc_val = 0;
+       } else {
+               result->fbc_enable = true;
+       }
+
+       result->enable = result->pri_val <= max->pri &&
+                        result->spr_val <= max->spr &&
+                        result->cur_val <= max->cur;
+       return result->enable;
+}
+
+static uint32_t hsw_compute_wm_pipe(struct drm_i915_private *dev_priv,
+                                   uint32_t mem_value, enum pipe pipe,
+                                   struct hsw_pipe_wm_parameters *params)
+{
+       uint32_t pri_val, cur_val, spr_val;
+
+       pri_val = hsw_compute_pri_wm(params, mem_value, false);
+       spr_val = hsw_compute_spr_wm(params, mem_value);
+       cur_val = hsw_compute_cur_wm(params, mem_value);
+
+       WARN(pri_val > 127,
+            "Primary WM error, mode not supported for pipe %c\n",
+            pipe_name(pipe));
+       WARN(spr_val > 127,
+            "Sprite WM error, mode not supported for pipe %c\n",
+            pipe_name(pipe));
+       WARN(cur_val > 63,
+            "Cursor WM error, mode not supported for pipe %c\n",
+            pipe_name(pipe));
+
+       return (pri_val << WM0_PIPE_PLANE_SHIFT) |
+              (spr_val << WM0_PIPE_SPRITE_SHIFT) |
+              cur_val;
+}
+
+static uint32_t
+hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 temp;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
+       u32 linetime, ips_linetime;
 
-       temp = I915_READ(PIPE_WM_LINETIME(pipe));
-       temp &= ~PIPE_WM_LINETIME_MASK;
+       if (!intel_crtc_active(crtc))
+               return 0;
 
        /* The WM are computed with base on how long it takes to fill a single
         * row at the given clock rate, multiplied by 8.
         * */
-       temp |= PIPE_WM_LINETIME_TIME(
-               ((mode->crtc_hdisplay * 1000) / mode->clock) * 8);
+       linetime = DIV_ROUND_CLOSEST(mode->htotal * 1000 * 8, mode->clock);
+       ips_linetime = DIV_ROUND_CLOSEST(mode->htotal * 1000 * 8,
+                                        intel_ddi_get_cdclk_freq(dev_priv));
 
-       /* IPS watermarks are only used by pipe A, and are ignored by
-        * pipes B and C.  They are calculated similarly to the common
-        * linetime values, except that we are using CD clock frequency
-        * in MHz instead of pixel rate for the division.
-        *
-        * This is a placeholder for the IPS watermark calculation code.
-        */
+       return PIPE_WM_LINETIME_IPS_LINETIME(ips_linetime) |
+              PIPE_WM_LINETIME_TIME(linetime);
+}
+
+static void hsw_compute_wm_parameters(struct drm_device *dev,
+                                     struct hsw_pipe_wm_parameters *params,
+                                     uint32_t *wm,
+                                     struct hsw_wm_maximums *lp_max_1_2,
+                                     struct hsw_wm_maximums *lp_max_5_6)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc;
+       struct drm_plane *plane;
+       uint64_t sskpd = I915_READ64(MCH_SSKPD);
+       enum pipe pipe;
+       int pipes_active = 0, sprites_enabled = 0;
+
+       if ((sskpd >> 56) & 0xFF)
+               wm[0] = (sskpd >> 56) & 0xFF;
+       else
+               wm[0] = sskpd & 0xF;
+       wm[1] = ((sskpd >> 4) & 0xFF) * 5;
+       wm[2] = ((sskpd >> 12) & 0xFF) * 5;
+       wm[3] = ((sskpd >> 20) & 0x1FF) * 5;
+       wm[4] = ((sskpd >> 32) & 0x1FF) * 5;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               struct hsw_pipe_wm_parameters *p;
+
+               pipe = intel_crtc->pipe;
+               p = &params[pipe];
+
+               p->active = intel_crtc_active(crtc);
+               if (!p->active)
+                       continue;
 
-       I915_WRITE(PIPE_WM_LINETIME(pipe), temp);
+               pipes_active++;
+
+               p->pipe_htotal = intel_crtc->config.adjusted_mode.htotal;
+               p->pixel_rate = hsw_wm_get_pixel_rate(dev, crtc);
+               p->pri_bytes_per_pixel = crtc->fb->bits_per_pixel / 8;
+               p->cur_bytes_per_pixel = 4;
+               p->pri_horiz_pixels =
+                       intel_crtc->config.requested_mode.hdisplay;
+               p->cur_horiz_pixels = 64;
+       }
+
+       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+               struct intel_plane *intel_plane = to_intel_plane(plane);
+               struct hsw_pipe_wm_parameters *p;
+
+               pipe = intel_plane->pipe;
+               p = &params[pipe];
+
+               p->sprite_enabled = intel_plane->wm.enable;
+               p->spr_bytes_per_pixel = intel_plane->wm.bytes_per_pixel;
+               p->spr_horiz_pixels = intel_plane->wm.horiz_pixels;
+
+               if (p->sprite_enabled)
+                       sprites_enabled++;
+       }
+
+       if (pipes_active > 1) {
+               lp_max_1_2->pri = lp_max_5_6->pri = sprites_enabled ? 128 : 256;
+               lp_max_1_2->spr = lp_max_5_6->spr = 128;
+               lp_max_1_2->cur = lp_max_5_6->cur = 64;
+       } else {
+               lp_max_1_2->pri = sprites_enabled ? 384 : 768;
+               lp_max_5_6->pri = sprites_enabled ? 128 : 768;
+               lp_max_1_2->spr = 384;
+               lp_max_5_6->spr = 640;
+               lp_max_1_2->cur = lp_max_5_6->cur = 255;
+       }
+       lp_max_1_2->fbc = lp_max_5_6->fbc = 15;
+}
+
+static void hsw_compute_wm_results(struct drm_device *dev,
+                                  struct hsw_pipe_wm_parameters *params,
+                                  uint32_t *wm,
+                                  struct hsw_wm_maximums *lp_maximums,
+                                  struct hsw_wm_values *results)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc;
+       struct hsw_lp_wm_result lp_results[4] = {};
+       enum pipe pipe;
+       int level, max_level, wm_lp;
+
+       for (level = 1; level <= 4; level++)
+               if (!hsw_compute_lp_wm(wm[level], lp_maximums, params,
+                                      &lp_results[level - 1]))
+                       break;
+       max_level = level - 1;
+
+       /* The spec says it is preferred to disable FBC WMs instead of disabling
+        * a WM level. */
+       results->enable_fbc_wm = true;
+       for (level = 1; level <= max_level; level++) {
+               if (!lp_results[level - 1].fbc_enable) {
+                       results->enable_fbc_wm = false;
+                       break;
+               }
+       }
+
+       memset(results, 0, sizeof(*results));
+       for (wm_lp = 1; wm_lp <= 3; wm_lp++) {
+               const struct hsw_lp_wm_result *r;
+
+               level = (max_level == 4 && wm_lp > 1) ? wm_lp + 1 : wm_lp;
+               if (level > max_level)
+                       break;
+
+               r = &lp_results[level - 1];
+               results->wm_lp[wm_lp - 1] = HSW_WM_LP_VAL(level * 2,
+                                                         r->fbc_val,
+                                                         r->pri_val,
+                                                         r->cur_val);
+               results->wm_lp_spr[wm_lp - 1] = r->spr_val;
+       }
+
+       for_each_pipe(pipe)
+               results->wm_pipe[pipe] = hsw_compute_wm_pipe(dev_priv, wm[0],
+                                                            pipe,
+                                                            &params[pipe]);
+
+       for_each_pipe(pipe) {
+               crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+               results->wm_linetime[pipe] = hsw_compute_linetime_wm(dev, crtc);
+       }
+}
+
+/* Find the result with the highest level enabled. Check for enable_fbc_wm in
+ * case both are at the same level. Prefer r1 in case they're the same. */
+struct hsw_wm_values *hsw_find_best_result(struct hsw_wm_values *r1,
+                                          struct hsw_wm_values *r2)
+{
+       int i, val_r1 = 0, val_r2 = 0;
+
+       for (i = 0; i < 3; i++) {
+               if (r1->wm_lp[i] & WM3_LP_EN)
+                       val_r1 = r1->wm_lp[i] & WM1_LP_LATENCY_MASK;
+               if (r2->wm_lp[i] & WM3_LP_EN)
+                       val_r2 = r2->wm_lp[i] & WM1_LP_LATENCY_MASK;
+       }
+
+       if (val_r1 == val_r2) {
+               if (r2->enable_fbc_wm && !r1->enable_fbc_wm)
+                       return r2;
+               else
+                       return r1;
+       } else if (val_r1 > val_r2) {
+               return r1;
+       } else {
+               return r2;
+       }
+}
+
+/*
+ * The spec says we shouldn't write when we don't need, because every write
+ * causes WMs to be re-evaluated, expending some power.
+ */
+static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
+                               struct hsw_wm_values *results,
+                               enum hsw_data_buf_partitioning partitioning)
+{
+       struct hsw_wm_values previous;
+       uint32_t val;
+       enum hsw_data_buf_partitioning prev_partitioning;
+       bool prev_enable_fbc_wm;
+
+       previous.wm_pipe[0] = I915_READ(WM0_PIPEA_ILK);
+       previous.wm_pipe[1] = I915_READ(WM0_PIPEB_ILK);
+       previous.wm_pipe[2] = I915_READ(WM0_PIPEC_IVB);
+       previous.wm_lp[0] = I915_READ(WM1_LP_ILK);
+       previous.wm_lp[1] = I915_READ(WM2_LP_ILK);
+       previous.wm_lp[2] = I915_READ(WM3_LP_ILK);
+       previous.wm_lp_spr[0] = I915_READ(WM1S_LP_ILK);
+       previous.wm_lp_spr[1] = I915_READ(WM2S_LP_IVB);
+       previous.wm_lp_spr[2] = I915_READ(WM3S_LP_IVB);
+       previous.wm_linetime[0] = I915_READ(PIPE_WM_LINETIME(PIPE_A));
+       previous.wm_linetime[1] = I915_READ(PIPE_WM_LINETIME(PIPE_B));
+       previous.wm_linetime[2] = I915_READ(PIPE_WM_LINETIME(PIPE_C));
+
+       prev_partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ?
+                           HSW_DATA_BUF_PART_5_6 : HSW_DATA_BUF_PART_1_2;
+
+       prev_enable_fbc_wm = !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS);
+
+       if (memcmp(results->wm_pipe, previous.wm_pipe,
+                  sizeof(results->wm_pipe)) == 0 &&
+           memcmp(results->wm_lp, previous.wm_lp,
+                  sizeof(results->wm_lp)) == 0 &&
+           memcmp(results->wm_lp_spr, previous.wm_lp_spr,
+                  sizeof(results->wm_lp_spr)) == 0 &&
+           memcmp(results->wm_linetime, previous.wm_linetime,
+                  sizeof(results->wm_linetime)) == 0 &&
+           partitioning == prev_partitioning &&
+           results->enable_fbc_wm == prev_enable_fbc_wm)
+               return;
+
+       if (previous.wm_lp[2] != 0)
+               I915_WRITE(WM3_LP_ILK, 0);
+       if (previous.wm_lp[1] != 0)
+               I915_WRITE(WM2_LP_ILK, 0);
+       if (previous.wm_lp[0] != 0)
+               I915_WRITE(WM1_LP_ILK, 0);
+
+       if (previous.wm_pipe[0] != results->wm_pipe[0])
+               I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]);
+       if (previous.wm_pipe[1] != results->wm_pipe[1])
+               I915_WRITE(WM0_PIPEB_ILK, results->wm_pipe[1]);
+       if (previous.wm_pipe[2] != results->wm_pipe[2])
+               I915_WRITE(WM0_PIPEC_IVB, results->wm_pipe[2]);
+
+       if (previous.wm_linetime[0] != results->wm_linetime[0])
+               I915_WRITE(PIPE_WM_LINETIME(PIPE_A), results->wm_linetime[0]);
+       if (previous.wm_linetime[1] != results->wm_linetime[1])
+               I915_WRITE(PIPE_WM_LINETIME(PIPE_B), results->wm_linetime[1]);
+       if (previous.wm_linetime[2] != results->wm_linetime[2])
+               I915_WRITE(PIPE_WM_LINETIME(PIPE_C), results->wm_linetime[2]);
+
+       if (prev_partitioning != partitioning) {
+               val = I915_READ(WM_MISC);
+               if (partitioning == HSW_DATA_BUF_PART_1_2)
+                       val &= ~WM_MISC_DATA_PARTITION_5_6;
+               else
+                       val |= WM_MISC_DATA_PARTITION_5_6;
+               I915_WRITE(WM_MISC, val);
+       }
+
+       if (prev_enable_fbc_wm != results->enable_fbc_wm) {
+               val = I915_READ(DISP_ARB_CTL);
+               if (results->enable_fbc_wm)
+                       val &= ~DISP_FBC_WM_DIS;
+               else
+                       val |= DISP_FBC_WM_DIS;
+               I915_WRITE(DISP_ARB_CTL, val);
+       }
+
+       if (previous.wm_lp_spr[0] != results->wm_lp_spr[0])
+               I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]);
+       if (previous.wm_lp_spr[1] != results->wm_lp_spr[1])
+               I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]);
+       if (previous.wm_lp_spr[2] != results->wm_lp_spr[2])
+               I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]);
+
+       if (results->wm_lp[0] != 0)
+               I915_WRITE(WM1_LP_ILK, results->wm_lp[0]);
+       if (results->wm_lp[1] != 0)
+               I915_WRITE(WM2_LP_ILK, results->wm_lp[1]);
+       if (results->wm_lp[2] != 0)
+               I915_WRITE(WM3_LP_ILK, results->wm_lp[2]);
+}
+
+static void haswell_update_wm(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct hsw_wm_maximums lp_max_1_2, lp_max_5_6;
+       struct hsw_pipe_wm_parameters params[3];
+       struct hsw_wm_values results_1_2, results_5_6, *best_results;
+       uint32_t wm[5];
+       enum hsw_data_buf_partitioning partitioning;
+
+       hsw_compute_wm_parameters(dev, params, wm, &lp_max_1_2, &lp_max_5_6);
+
+       hsw_compute_wm_results(dev, params, wm, &lp_max_1_2, &results_1_2);
+       if (lp_max_1_2.pri != lp_max_5_6.pri) {
+               hsw_compute_wm_results(dev, params, wm, &lp_max_5_6,
+                                      &results_5_6);
+               best_results = hsw_find_best_result(&results_1_2, &results_5_6);
+       } else {
+               best_results = &results_1_2;
+       }
+
+       partitioning = (best_results == &results_1_2) ?
+                      HSW_DATA_BUF_PART_1_2 : HSW_DATA_BUF_PART_5_6;
+
+       hsw_write_wm_values(dev_priv, best_results, partitioning);
+}
+
+static void haswell_update_sprite_wm(struct drm_device *dev, int pipe,
+                                    uint32_t sprite_width, int pixel_size,
+                                    bool enable)
+{
+       struct drm_plane *plane;
+
+       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+               struct intel_plane *intel_plane = to_intel_plane(plane);
+
+               if (intel_plane->pipe == pipe) {
+                       intel_plane->wm.enable = enable;
+                       intel_plane->wm.horiz_pixels = sprite_width + 1;
+                       intel_plane->wm.bytes_per_pixel = pixel_size;
+                       break;
+               }
+       }
+
+       haswell_update_wm(dev);
 }
 
 static bool
@@ -2176,7 +2706,8 @@ sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane,
 }
 
 static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
-                                        uint32_t sprite_width, int pixel_size)
+                                        uint32_t sprite_width, int pixel_size,
+                                        bool enable)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int latency = SNB_READ_WM0_LATENCY() * 100;     /* In unit 0.1us */
@@ -2184,6 +2715,9 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
        int sprite_wm, reg;
        int ret;
 
+       if (!enable)
+               return;
+
        switch (pipe) {
        case 0:
                reg = WM0_PIPEA_ILK;
@@ -2294,23 +2828,15 @@ void intel_update_watermarks(struct drm_device *dev)
                dev_priv->display.update_wm(dev);
 }
 
-void intel_update_linetime_watermarks(struct drm_device *dev,
-               int pipe, struct drm_display_mode *mode)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->display.update_linetime_wm)
-               dev_priv->display.update_linetime_wm(dev, pipe, mode);
-}
-
 void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
-                                   uint32_t sprite_width, int pixel_size)
+                                   uint32_t sprite_width, int pixel_size,
+                                   bool enable)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (dev_priv->display.update_sprite_wm)
                dev_priv->display.update_sprite_wm(dev, pipe, sprite_width,
-                                                  pixel_size);
+                                                  pixel_size, enable);
 }
 
 static struct drm_i915_gem_object *
@@ -2556,10 +3082,10 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
        if (val == dev_priv->rps.cur_delay)
                return;
 
-       valleyview_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
+       vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
 
        do {
-               valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval);
+               pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
                if (time_after(jiffies, timeout)) {
                        DRM_DEBUG_DRIVER("timed out waiting for Punit\n");
                        break;
@@ -2567,7 +3093,7 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
                udelay(10);
        } while (pval & 1);
 
-       valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval);
+       pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
        if ((pval >> 8) != val)
                DRM_DEBUG_DRIVER("punit overrode freq: %d requested, but got %d\n",
                          val, pval >> 8);
@@ -2590,7 +3116,7 @@ static void gen6_disable_rps(struct drm_device *dev)
        I915_WRITE(GEN6_RC_CONTROL, 0);
        I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
        I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
-       I915_WRITE(GEN6_PMIER, 0);
+       I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) & ~GEN6_PM_RPS_EVENTS);
        /* Complete PM interrupt masking here doesn't race with the rps work
         * item again unmasking PM interrupts because that is using a different
         * register (PMIMR) to mask PM interrupts. The only risk is in leaving
@@ -2600,7 +3126,7 @@ static void gen6_disable_rps(struct drm_device *dev)
        dev_priv->rps.pm_iir = 0;
        spin_unlock_irq(&dev_priv->rps.lock);
 
-       I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+       I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
 }
 
 static void valleyview_disable_rps(struct drm_device *dev)
@@ -2781,12 +3307,15 @@ static void gen6_enable_rps(struct drm_device *dev)
        gen6_set_rps(dev_priv->dev, (gt_perf_status & 0xff00) >> 8);
 
        /* requires MSI enabled */
-       I915_WRITE(GEN6_PMIER, GEN6_PM_DEFERRED_EVENTS);
+       I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) | GEN6_PM_RPS_EVENTS);
        spin_lock_irq(&dev_priv->rps.lock);
-       WARN_ON(dev_priv->rps.pm_iir != 0);
-       I915_WRITE(GEN6_PMIMR, 0);
+       /* FIXME: Our interrupt enabling sequence is bonghits.
+        * dev_priv->rps.pm_iir really should be 0 here. */
+       dev_priv->rps.pm_iir = 0;
+       I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
+       I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
        spin_unlock_irq(&dev_priv->rps.lock);
-       /* enable all PM interrupts */
+       /* unmask all PM interrupts */
        I915_WRITE(GEN6_PMINTRMSK, 0);
 
        rc6vids = 0;
@@ -2872,7 +3401,7 @@ int valleyview_rps_max_freq(struct drm_i915_private *dev_priv)
 {
        u32 val, rp0;
 
-       valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FREQ_FUSE, &val);
+       val = vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FREQ_FUSE);
 
        rp0 = (val & FB_GFX_MAX_FREQ_FUSE_MASK) >> FB_GFX_MAX_FREQ_FUSE_SHIFT;
        /* Clamp to max */
@@ -2885,9 +3414,9 @@ static int valleyview_rps_rpe_freq(struct drm_i915_private *dev_priv)
 {
        u32 val, rpe;
 
-       valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_LO, &val);
+       val = vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_LO);
        rpe = (val & FB_FMAX_VMIN_FREQ_LO_MASK) >> FB_FMAX_VMIN_FREQ_LO_SHIFT;
-       valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_HI, &val);
+       val = vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_HI);
        rpe |= (val & FB_FMAX_VMIN_FREQ_HI_MASK) << 5;
 
        return rpe;
@@ -2895,11 +3424,7 @@ static int valleyview_rps_rpe_freq(struct drm_i915_private *dev_priv)
 
 int valleyview_rps_min_freq(struct drm_i915_private *dev_priv)
 {
-       u32 val;
-
-       valleyview_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val);
-
-       return val & 0xff;
+       return vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM) & 0xff;
 }
 
 static void vlv_rps_timer_work(struct work_struct *work)
@@ -3008,7 +3533,7 @@ static void valleyview_enable_rps(struct drm_device *dev)
        I915_WRITE(GEN6_RC_CONTROL,
                   GEN7_RC_CTL_TO_MODE);
 
-       valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &val);
+       val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
        switch ((val >> 6) & 3) {
        case 0:
        case 1:
@@ -3053,7 +3578,7 @@ static void valleyview_enable_rps(struct drm_device *dev)
        valleyview_set_rps(dev_priv->dev, rpe);
 
        /* requires MSI enabled */
-       I915_WRITE(GEN6_PMIER, GEN6_PM_DEFERRED_EVENTS);
+       I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS);
        spin_lock_irq(&dev_priv->rps.lock);
        WARN_ON(dev_priv->rps.pm_iir != 0);
        I915_WRITE(GEN6_PMIMR, 0);
@@ -4162,14 +4687,9 @@ static void haswell_init_clock_gating(struct drm_device *dev)
        /* WaSwitchSolVfFArbitrationPriority:hsw */
        I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
 
-       /* XXX: This is a workaround for early silicon revisions and should be
-        * removed later.
-        */
-       I915_WRITE(WM_DBG,
-                       I915_READ(WM_DBG) |
-                       WM_DBG_DISALLOW_MULTIPLE_LP |
-                       WM_DBG_DISALLOW_SPRITE |
-                       WM_DBG_DISALLOW_MAXFIFO);
+       /* WaRsPkgCStateDisplayPMReq:hsw */
+       I915_WRITE(CHICKEN_PAR1_1,
+                  I915_READ(CHICKEN_PAR1_1) | FORCE_ARB_IDLE_PLANES);
 
        lpt_init_clock_gating(dev);
 }
@@ -4623,10 +5143,10 @@ void intel_init_pm(struct drm_device *dev)
                        }
                        dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
                } else if (IS_HASWELL(dev)) {
-                       if (SNB_READ_WM0_LATENCY()) {
-                               dev_priv->display.update_wm = sandybridge_update_wm;
-                               dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
-                               dev_priv->display.update_linetime_wm = haswell_update_linetime_wm;
+                       if (I915_READ64(MCH_SSKPD)) {
+                               dev_priv->display.update_wm = haswell_update_wm;
+                               dev_priv->display.update_sprite_wm =
+                                       haswell_update_sprite_wm;
                        } else {
                                DRM_DEBUG_KMS("Failed to read display plane latency. "
                                              "Disable CxSR\n");
@@ -4952,66 +5472,6 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val)
        return 0;
 }
 
-static int vlv_punit_rw(struct drm_i915_private *dev_priv, u32 port, u8 opcode,
-                       u8 addr, u32 *val)
-{
-       u32 cmd, devfn, be, bar;
-
-       bar = 0;
-       be = 0xf;
-       devfn = PCI_DEVFN(2, 0);
-
-       cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) |
-               (port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) |
-               (bar << IOSF_BAR_SHIFT);
-
-       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-
-       if (I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) {
-               DRM_DEBUG_DRIVER("warning: pcode (%s) mailbox access failed\n",
-                                opcode == PUNIT_OPCODE_REG_READ ?
-                                "read" : "write");
-               return -EAGAIN;
-       }
-
-       I915_WRITE(VLV_IOSF_ADDR, addr);
-       if (opcode == PUNIT_OPCODE_REG_WRITE)
-               I915_WRITE(VLV_IOSF_DATA, *val);
-       I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd);
-
-       if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0,
-                    5)) {
-               DRM_ERROR("timeout waiting for pcode %s (%d) to finish\n",
-                         opcode == PUNIT_OPCODE_REG_READ ? "read" : "write",
-                         addr);
-               return -ETIMEDOUT;
-       }
-
-       if (opcode == PUNIT_OPCODE_REG_READ)
-               *val = I915_READ(VLV_IOSF_DATA);
-       I915_WRITE(VLV_IOSF_DATA, 0);
-
-       return 0;
-}
-
-int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val)
-{
-       return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_READ,
-                           addr, val);
-}
-
-int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val)
-{
-       return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_WRITE,
-                           addr, &val);
-}
-
-int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val)
-{
-       return vlv_punit_rw(dev_priv, IOSF_PORT_NC, PUNIT_OPCODE_REG_READ,
-                           addr, val);
-}
-
 int vlv_gpu_freq(int ddr_freq, int val)
 {
        int mult, base;
index 3d2c236e15abd4dcc10c1bf4414e127430257e4a..0e72da6ad0fa87c5864e102dc162f0ca9f080128 100644 (file)
@@ -464,9 +464,11 @@ init_pipe_control(struct intel_ring_buffer *ring)
                goto err_unref;
 
        pc->gtt_offset = obj->gtt_offset;
-       pc->cpu_page =  kmap(sg_page(obj->pages->sgl));
-       if (pc->cpu_page == NULL)
+       pc->cpu_page = kmap(sg_page(obj->pages->sgl));
+       if (pc->cpu_page == NULL) {
+               ret = -ENOMEM;
                goto err_unpin;
+       }
 
        DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n",
                         ring->name, pc->gtt_offset);
@@ -558,7 +560,7 @@ static int init_render_ring(struct intel_ring_buffer *ring)
                I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
 
        if (HAS_L3_GPU_CACHE(dev))
-               I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
+               I915_WRITE_IMR(ring, ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
 
        return ret;
 }
@@ -580,9 +582,16 @@ static void
 update_mboxes(struct intel_ring_buffer *ring,
              u32 mmio_offset)
 {
+/* NB: In order to be able to do semaphore MBOX updates for varying number
+ * of rings, it's easiest if we round up each individual update to a
+ * multiple of 2 (since ring updates must always be a multiple of 2)
+ * even though the actual update only requires 3 dwords.
+ */
+#define MBOX_UPDATE_DWORDS 4
        intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
        intel_ring_emit(ring, mmio_offset);
        intel_ring_emit(ring, ring->outstanding_lazy_request);
+       intel_ring_emit(ring, MI_NOOP);
 }
 
 /**
@@ -597,19 +606,24 @@ update_mboxes(struct intel_ring_buffer *ring,
 static int
 gen6_add_request(struct intel_ring_buffer *ring)
 {
-       u32 mbox1_reg;
-       u32 mbox2_reg;
-       int ret;
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *useless;
+       int i, ret;
 
-       ret = intel_ring_begin(ring, 10);
+       ret = intel_ring_begin(ring, ((I915_NUM_RINGS-1) *
+                                     MBOX_UPDATE_DWORDS) +
+                                     4);
        if (ret)
                return ret;
+#undef MBOX_UPDATE_DWORDS
 
-       mbox1_reg = ring->signal_mbox[0];
-       mbox2_reg = ring->signal_mbox[1];
+       for_each_ring(useless, dev_priv, i) {
+               u32 mbox_reg = ring->signal_mbox[i];
+               if (mbox_reg != GEN6_NOSYNC)
+                       update_mboxes(ring, mbox_reg);
+       }
 
-       update_mboxes(ring, mbox1_reg);
-       update_mboxes(ring, mbox2_reg);
        intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
        intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
        intel_ring_emit(ring, ring->outstanding_lazy_request);
@@ -781,7 +795,7 @@ gen5_ring_get_irq(struct intel_ring_buffer *ring)
                return false;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (ring->irq_refcount++ == 0) {
+       if (ring->irq_refcount.gt++ == 0) {
                dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
                I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
                POSTING_READ(GTIMR);
@@ -799,7 +813,7 @@ gen5_ring_put_irq(struct intel_ring_buffer *ring)
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (--ring->irq_refcount == 0) {
+       if (--ring->irq_refcount.gt == 0) {
                dev_priv->gt_irq_mask |= ring->irq_enable_mask;
                I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
                POSTING_READ(GTIMR);
@@ -818,7 +832,7 @@ i9xx_ring_get_irq(struct intel_ring_buffer *ring)
                return false;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (ring->irq_refcount++ == 0) {
+       if (ring->irq_refcount.gt++ == 0) {
                dev_priv->irq_mask &= ~ring->irq_enable_mask;
                I915_WRITE(IMR, dev_priv->irq_mask);
                POSTING_READ(IMR);
@@ -836,7 +850,7 @@ i9xx_ring_put_irq(struct intel_ring_buffer *ring)
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (--ring->irq_refcount == 0) {
+       if (--ring->irq_refcount.gt == 0) {
                dev_priv->irq_mask |= ring->irq_enable_mask;
                I915_WRITE(IMR, dev_priv->irq_mask);
                POSTING_READ(IMR);
@@ -855,7 +869,7 @@ i8xx_ring_get_irq(struct intel_ring_buffer *ring)
                return false;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (ring->irq_refcount++ == 0) {
+       if (ring->irq_refcount.gt++ == 0) {
                dev_priv->irq_mask &= ~ring->irq_enable_mask;
                I915_WRITE16(IMR, dev_priv->irq_mask);
                POSTING_READ16(IMR);
@@ -873,7 +887,7 @@ i8xx_ring_put_irq(struct intel_ring_buffer *ring)
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (--ring->irq_refcount == 0) {
+       if (--ring->irq_refcount.gt == 0) {
                dev_priv->irq_mask |= ring->irq_enable_mask;
                I915_WRITE16(IMR, dev_priv->irq_mask);
                POSTING_READ16(IMR);
@@ -901,6 +915,9 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
                case VCS:
                        mmio = BSD_HWS_PGA_GEN7;
                        break;
+               case VECS:
+                       mmio = VEBOX_HWS_PGA_GEN7;
+                       break;
                }
        } else if (IS_GEN6(ring->dev)) {
                mmio = RING_HWS_PGA_GEN6(ring->mmio_base);
@@ -963,10 +980,11 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring)
        gen6_gt_force_wake_get(dev_priv);
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (ring->irq_refcount++ == 0) {
+       if (ring->irq_refcount.gt++ == 0) {
                if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
-                       I915_WRITE_IMR(ring, ~(ring->irq_enable_mask |
-                                               GEN6_RENDER_L3_PARITY_ERROR));
+                       I915_WRITE_IMR(ring,
+                                      ~(ring->irq_enable_mask |
+                                        GT_RENDER_L3_PARITY_ERROR_INTERRUPT));
                else
                        I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
                dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
@@ -986,9 +1004,10 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (--ring->irq_refcount == 0) {
+       if (--ring->irq_refcount.gt == 0) {
                if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
-                       I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
+                       I915_WRITE_IMR(ring,
+                                      ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
                else
                        I915_WRITE_IMR(ring, ~0);
                dev_priv->gt_irq_mask |= ring->irq_enable_mask;
@@ -1000,6 +1019,48 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
        gen6_gt_force_wake_put(dev_priv);
 }
 
+static bool
+hsw_vebox_get_irq(struct intel_ring_buffer *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long flags;
+
+       if (!dev->irq_enabled)
+               return false;
+
+       spin_lock_irqsave(&dev_priv->rps.lock, flags);
+       if (ring->irq_refcount.pm++ == 0) {
+               u32 pm_imr = I915_READ(GEN6_PMIMR);
+               I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
+               I915_WRITE(GEN6_PMIMR, pm_imr & ~ring->irq_enable_mask);
+               POSTING_READ(GEN6_PMIMR);
+       }
+       spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+
+       return true;
+}
+
+static void
+hsw_vebox_put_irq(struct intel_ring_buffer *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long flags;
+
+       if (!dev->irq_enabled)
+               return;
+
+       spin_lock_irqsave(&dev_priv->rps.lock, flags);
+       if (--ring->irq_refcount.pm == 0) {
+               u32 pm_imr = I915_READ(GEN6_PMIMR);
+               I915_WRITE_IMR(ring, ~0);
+               I915_WRITE(GEN6_PMIMR, pm_imr | ring->irq_enable_mask);
+               POSTING_READ(GEN6_PMIMR);
+       }
+       spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+}
+
 static int
 i965_dispatch_execbuffer(struct intel_ring_buffer *ring,
                         u32 offset, u32 length,
@@ -1502,6 +1563,7 @@ void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno)
        }
 
        ring->set_seqno(ring, seqno);
+       ring->hangcheck.seqno = seqno;
 }
 
 void intel_ring_advance(struct intel_ring_buffer *ring)
@@ -1548,8 +1610,8 @@ static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring,
                   _MASKED_BIT_DISABLE(GEN6_BSD_SLEEP_MSG_DISABLE));
 }
 
-static int gen6_ring_flush(struct intel_ring_buffer *ring,
-                          u32 invalidate, u32 flush)
+static int gen6_bsd_ring_flush(struct intel_ring_buffer *ring,
+                              u32 invalidate, u32 flush)
 {
        uint32_t cmd;
        int ret;
@@ -1620,8 +1682,8 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
 
 /* Blitter support (SandyBridge+) */
 
-static int blt_ring_flush(struct intel_ring_buffer *ring,
-                         u32 invalidate, u32 flush)
+static int gen6_ring_flush(struct intel_ring_buffer *ring,
+                          u32 invalidate, u32 flush)
 {
        uint32_t cmd;
        int ret;
@@ -1664,15 +1726,18 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
                        ring->flush = gen6_render_ring_flush;
                ring->irq_get = gen6_ring_get_irq;
                ring->irq_put = gen6_ring_put_irq;
-               ring->irq_enable_mask = GT_USER_INTERRUPT;
+               ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
                ring->get_seqno = gen6_ring_get_seqno;
                ring->set_seqno = ring_set_seqno;
                ring->sync_to = gen6_ring_sync;
-               ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_INVALID;
-               ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_RV;
-               ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_RB;
-               ring->signal_mbox[0] = GEN6_VRSYNC;
-               ring->signal_mbox[1] = GEN6_BRSYNC;
+               ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_INVALID;
+               ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_RV;
+               ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_RB;
+               ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_RVE;
+               ring->signal_mbox[RCS] = GEN6_NOSYNC;
+               ring->signal_mbox[VCS] = GEN6_VRSYNC;
+               ring->signal_mbox[BCS] = GEN6_BRSYNC;
+               ring->signal_mbox[VECS] = GEN6_VERSYNC;
        } else if (IS_GEN5(dev)) {
                ring->add_request = pc_render_add_request;
                ring->flush = gen4_render_ring_flush;
@@ -1680,7 +1745,8 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
                ring->set_seqno = pc_render_set_seqno;
                ring->irq_get = gen5_ring_get_irq;
                ring->irq_put = gen5_ring_put_irq;
-               ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY;
+               ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT |
+                                       GT_RENDER_PIPECTL_NOTIFY_INTERRUPT;
        } else {
                ring->add_request = i9xx_add_request;
                if (INTEL_INFO(dev)->gen < 4)
@@ -1818,20 +1884,23 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
                /* gen6 bsd needs a special wa for tail updates */
                if (IS_GEN6(dev))
                        ring->write_tail = gen6_bsd_ring_write_tail;
-               ring->flush = gen6_ring_flush;
+               ring->flush = gen6_bsd_ring_flush;
                ring->add_request = gen6_add_request;
                ring->get_seqno = gen6_ring_get_seqno;
                ring->set_seqno = ring_set_seqno;
-               ring->irq_enable_mask = GEN6_BSD_USER_INTERRUPT;
+               ring->irq_enable_mask = GT_BSD_USER_INTERRUPT;
                ring->irq_get = gen6_ring_get_irq;
                ring->irq_put = gen6_ring_put_irq;
                ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
                ring->sync_to = gen6_ring_sync;
-               ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_VR;
-               ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_INVALID;
-               ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_VB;
-               ring->signal_mbox[0] = GEN6_RVSYNC;
-               ring->signal_mbox[1] = GEN6_BVSYNC;
+               ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VR;
+               ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_INVALID;
+               ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VB;
+               ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_VVE;
+               ring->signal_mbox[RCS] = GEN6_RVSYNC;
+               ring->signal_mbox[VCS] = GEN6_NOSYNC;
+               ring->signal_mbox[BCS] = GEN6_BVSYNC;
+               ring->signal_mbox[VECS] = GEN6_VEVSYNC;
        } else {
                ring->mmio_base = BSD_RING_BASE;
                ring->flush = bsd_ring_flush;
@@ -1839,7 +1908,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
                ring->get_seqno = ring_get_seqno;
                ring->set_seqno = ring_set_seqno;
                if (IS_GEN5(dev)) {
-                       ring->irq_enable_mask = GT_BSD_USER_INTERRUPT;
+                       ring->irq_enable_mask = ILK_BSD_USER_INTERRUPT;
                        ring->irq_get = gen5_ring_get_irq;
                        ring->irq_put = gen5_ring_put_irq;
                } else {
@@ -1864,20 +1933,56 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
 
        ring->mmio_base = BLT_RING_BASE;
        ring->write_tail = ring_write_tail;
-       ring->flush = blt_ring_flush;
+       ring->flush = gen6_ring_flush;
        ring->add_request = gen6_add_request;
        ring->get_seqno = gen6_ring_get_seqno;
        ring->set_seqno = ring_set_seqno;
-       ring->irq_enable_mask = GEN6_BLITTER_USER_INTERRUPT;
+       ring->irq_enable_mask = GT_BLT_USER_INTERRUPT;
        ring->irq_get = gen6_ring_get_irq;
        ring->irq_put = gen6_ring_put_irq;
        ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
        ring->sync_to = gen6_ring_sync;
-       ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_BR;
-       ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_BV;
-       ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_INVALID;
-       ring->signal_mbox[0] = GEN6_RBSYNC;
-       ring->signal_mbox[1] = GEN6_VBSYNC;
+       ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_BR;
+       ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_BV;
+       ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_INVALID;
+       ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_BVE;
+       ring->signal_mbox[RCS] = GEN6_RBSYNC;
+       ring->signal_mbox[VCS] = GEN6_VBSYNC;
+       ring->signal_mbox[BCS] = GEN6_NOSYNC;
+       ring->signal_mbox[VECS] = GEN6_VEBSYNC;
+       ring->init = init_ring_common;
+
+       return intel_init_ring_buffer(dev, ring);
+}
+
+int intel_init_vebox_ring_buffer(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring = &dev_priv->ring[VECS];
+
+       ring->name = "video enhancement ring";
+       ring->id = VECS;
+
+       ring->mmio_base = VEBOX_RING_BASE;
+       ring->write_tail = ring_write_tail;
+       ring->flush = gen6_ring_flush;
+       ring->add_request = gen6_add_request;
+       ring->get_seqno = gen6_ring_get_seqno;
+       ring->set_seqno = ring_set_seqno;
+       ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT |
+               PM_VEBOX_CS_ERROR_INTERRUPT;
+       ring->irq_get = hsw_vebox_get_irq;
+       ring->irq_put = hsw_vebox_put_irq;
+       ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
+       ring->sync_to = gen6_ring_sync;
+       ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VER;
+       ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_VEV;
+       ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VEB;
+       ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_INVALID;
+       ring->signal_mbox[RCS] = GEN6_RVESYNC;
+       ring->signal_mbox[VCS] = GEN6_VVESYNC;
+       ring->signal_mbox[BCS] = GEN6_BVESYNC;
+       ring->signal_mbox[VECS] = GEN6_NOSYNC;
        ring->init = init_ring_common;
 
        return intel_init_ring_buffer(dev, ring);
index dac1614a1bcae92ec2e06a561d9f0b148cb7d25f..022d07e43d129871c13dc56d146509d9797aad8d 100644 (file)
@@ -37,14 +37,19 @@ struct  intel_hw_status_page {
 #define I915_READ_SYNC_0(ring) I915_READ(RING_SYNC_0((ring)->mmio_base))
 #define I915_READ_SYNC_1(ring) I915_READ(RING_SYNC_1((ring)->mmio_base))
 
+struct intel_ring_hangcheck {
+       u32 seqno;
+};
+
 struct  intel_ring_buffer {
        const char      *name;
        enum intel_ring_id {
                RCS = 0x0,
                VCS,
                BCS,
+               VECS,
        } id;
-#define I915_NUM_RINGS 3
+#define I915_NUM_RINGS 4
        u32             mmio_base;
        void            __iomem *virtual_start;
        struct          drm_device *dev;
@@ -67,7 +72,10 @@ struct  intel_ring_buffer {
         */
        u32             last_retired_head;
 
-       u32             irq_refcount;           /* protected by dev_priv->irq_lock */
+       struct {
+               u32     gt; /*  protected by dev_priv->irq_lock */
+               u32     pm; /*  protected by dev_priv->rps.lock (sucks) */
+       } irq_refcount;
        u32             irq_enable_mask;        /* bitmask to enable ring interrupt */
        u32             trace_irq_seqno;
        u32             sync_seqno[I915_NUM_RINGS-1];
@@ -102,8 +110,11 @@ struct  intel_ring_buffer {
                                   struct intel_ring_buffer *to,
                                   u32 seqno);
 
-       u32             semaphore_register[3]; /*our mbox written by others */
-       u32             signal_mbox[2]; /* mboxes this ring signals to */
+       /* our mbox written by others */
+       u32             semaphore_register[I915_NUM_RINGS];
+       /* mboxes this ring signals to */
+       u32             signal_mbox[I915_NUM_RINGS];
+
        /**
         * List of objects currently involved in rendering from the
         * ringbuffer.
@@ -137,6 +148,8 @@ struct  intel_ring_buffer {
        struct i915_hw_context *default_context;
        struct i915_hw_context *last_context;
 
+       struct intel_ring_hangcheck hangcheck;
+
        void *private;
 };
 
@@ -224,6 +237,7 @@ int intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring);
 int intel_init_render_ring_buffer(struct drm_device *dev);
 int intel_init_bsd_ring_buffer(struct drm_device *dev);
 int intel_init_blt_ring_buffer(struct drm_device *dev);
+int intel_init_vebox_ring_buffer(struct drm_device *dev);
 
 u32 intel_ring_get_active_head(struct intel_ring_buffer *ring);
 void intel_ring_setup_status_page(struct intel_ring_buffer *ring);
index 78f0631b1c43ae33cf5259ea1672efdc0d5af484..7068195376ef0c7ab2a912d08d45ece43d3b488d 100644 (file)
@@ -712,6 +712,13 @@ static bool intel_sdvo_set_timing(struct intel_sdvo *intel_sdvo, u8 cmd,
                intel_sdvo_set_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2));
 }
 
+static bool intel_sdvo_get_timing(struct intel_sdvo *intel_sdvo, u8 cmd,
+                                 struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_get_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) &&
+               intel_sdvo_get_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2));
+}
+
 static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo,
                                         struct intel_sdvo_dtd *dtd)
 {
@@ -726,6 +733,13 @@ static bool intel_sdvo_set_output_timing(struct intel_sdvo *intel_sdvo,
                                     SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd);
 }
 
+static bool intel_sdvo_get_input_timing(struct intel_sdvo *intel_sdvo,
+                                       struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_get_timing(intel_sdvo,
+                                    SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd);
+}
+
 static bool
 intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo,
                                         uint16_t clock,
@@ -1295,6 +1309,33 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
        return true;
 }
 
+static void intel_sdvo_get_config(struct intel_encoder *encoder,
+                                 struct intel_crtc_config *pipe_config)
+{
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+       struct intel_sdvo_dtd dtd;
+       u32 flags = 0;
+       bool ret;
+
+       ret = intel_sdvo_get_input_timing(intel_sdvo, &dtd);
+       if (!ret) {
+               DRM_DEBUG_DRIVER("failed to retrieve SDVO DTD\n");
+               return;
+       }
+
+       if (dtd.part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+
+       if (dtd.part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       pipe_config->adjusted_mode.flags |= flags;
+}
+
 static void intel_disable_sdvo(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
@@ -1375,6 +1416,7 @@ static void intel_enable_sdvo(struct intel_encoder *encoder)
        intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
 }
 
+/* Special dpms function to support cloning between dvo/sdvo/crt. */
 static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
 {
        struct drm_crtc *crtc;
@@ -1396,6 +1438,8 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
                return;
        }
 
+       /* We set active outputs manually below in case pipe dpms doesn't change
+        * due to cloning. */
        if (mode != DRM_MODE_DPMS_ON) {
                intel_sdvo_set_active_outputs(intel_sdvo, 0);
                if (0)
@@ -2827,6 +2871,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
        intel_encoder->mode_set = intel_sdvo_mode_set;
        intel_encoder->enable = intel_enable_sdvo;
        intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
+       intel_encoder->get_config = intel_sdvo_get_config;
 
        /* In default case sdvo lvds is false */
        if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c
new file mode 100644 (file)
index 0000000..9a0e6c5
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include "i915_drv.h"
+#include "intel_drv.h"
+
+/* IOSF sideband */
+static int vlv_sideband_rw(struct drm_i915_private *dev_priv, u32 devfn,
+                          u32 port, u32 opcode, u32 addr, u32 *val)
+{
+       u32 cmd, be = 0xf, bar = 0;
+       bool is_read = (opcode == PUNIT_OPCODE_REG_READ ||
+                       opcode == DPIO_OPCODE_REG_READ);
+
+       cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) |
+               (port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) |
+               (bar << IOSF_BAR_SHIFT);
+
+       WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
+
+       if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, 5)) {
+               DRM_DEBUG_DRIVER("IOSF sideband idle wait (%s) timed out\n",
+                                is_read ? "read" : "write");
+               return -EAGAIN;
+       }
+
+       I915_WRITE(VLV_IOSF_ADDR, addr);
+       if (!is_read)
+               I915_WRITE(VLV_IOSF_DATA, *val);
+       I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd);
+
+       if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, 5)) {
+               DRM_DEBUG_DRIVER("IOSF sideband finish wait (%s) timed out\n",
+                                is_read ? "read" : "write");
+               return -ETIMEDOUT;
+       }
+
+       if (is_read)
+               *val = I915_READ(VLV_IOSF_DATA);
+       I915_WRITE(VLV_IOSF_DATA, 0);
+
+       return 0;
+}
+
+u32 vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr)
+{
+       u32 val = 0;
+
+       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
+
+       mutex_lock(&dev_priv->dpio_lock);
+       vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT,
+                       PUNIT_OPCODE_REG_READ, addr, &val);
+       mutex_unlock(&dev_priv->dpio_lock);
+
+       return val;
+}
+
+void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val)
+{
+       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
+
+       mutex_lock(&dev_priv->dpio_lock);
+       vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT,
+                       PUNIT_OPCODE_REG_WRITE, addr, &val);
+       mutex_unlock(&dev_priv->dpio_lock);
+}
+
+u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr)
+{
+       u32 val = 0;
+
+       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
+
+       mutex_lock(&dev_priv->dpio_lock);
+       vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_NC,
+                       PUNIT_OPCODE_REG_READ, addr, &val);
+       mutex_unlock(&dev_priv->dpio_lock);
+
+       return val;
+}
+
+u32 vlv_dpio_read(struct drm_i915_private *dev_priv, int reg)
+{
+       u32 val = 0;
+
+       vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_DPIO,
+                       DPIO_OPCODE_REG_READ, reg, &val);
+
+       return val;
+}
+
+void vlv_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val)
+{
+       vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_DPIO,
+                       DPIO_OPCODE_REG_WRITE, reg, &val);
+}
+
+/* SBI access */
+u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg,
+                  enum intel_sbi_destination destination)
+{
+       u32 value = 0;
+       WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
+
+       if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0,
+                               100)) {
+               DRM_ERROR("timeout waiting for SBI to become ready\n");
+               return 0;
+       }
+
+       I915_WRITE(SBI_ADDR, (reg << 16));
+
+       if (destination == SBI_ICLK)
+               value = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRRD;
+       else
+               value = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IORD;
+       I915_WRITE(SBI_CTL_STAT, value | SBI_BUSY);
+
+       if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0,
+                               100)) {
+               DRM_ERROR("timeout waiting for SBI to complete read transaction\n");
+               return 0;
+       }
+
+       return I915_READ(SBI_DATA);
+}
+
+void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value,
+                    enum intel_sbi_destination destination)
+{
+       u32 tmp;
+
+       WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
+
+       if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0,
+                               100)) {
+               DRM_ERROR("timeout waiting for SBI to become ready\n");
+               return;
+       }
+
+       I915_WRITE(SBI_ADDR, (reg << 16));
+       I915_WRITE(SBI_DATA, value);
+
+       if (destination == SBI_ICLK)
+               tmp = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRWR;
+       else
+               tmp = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IOWR;
+       I915_WRITE(SBI_CTL_STAT, SBI_BUSY | tmp);
+
+       if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0,
+                               100)) {
+               DRM_ERROR("timeout waiting for SBI to complete write transaction\n");
+               return;
+       }
+}
index 19b9cb961b5a19ef401434bda5dd1b548ee53deb..04d38d4d811a9ac82c4818658beb8e311332e57f 100644 (file)
@@ -114,7 +114,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_framebuffer *fb,
        crtc_w--;
        crtc_h--;
 
-       intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
+       intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size, true);
 
        I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
        I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
@@ -268,7 +268,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        crtc_w--;
        crtc_h--;
 
-       intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
+       intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size, true);
 
        /*
         * IVB workaround: must disable low power watermarks for at least
@@ -335,6 +335,8 @@ ivb_disable_plane(struct drm_plane *plane)
 
        dev_priv->sprite_scaling_enabled &= ~(1 << pipe);
 
+       intel_update_sprite_watermarks(dev, pipe, 0, 0, false);
+
        /* potentially re-enable LP watermarks */
        if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled)
                intel_update_watermarks(dev);
@@ -453,7 +455,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        crtc_w--;
        crtc_h--;
 
-       intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
+       intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size, true);
 
        dvsscale = 0;
        if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h)
index 64fa265c6ffbf98064b5e89c5fef53474aa733fe..d1286297567bdbfd50c90a5fc3e98fc8834df059 100644 (file)
 #define DRM_RECT_H
 
 /**
- * drm_rect - two dimensional rectangle
+ * DOC: rect utils
+ *
+ * Utility functions to help manage rectangular areas for
+ * clipping, scaling, etc. calculations.
+ */
+
+/**
+ * struct drm_rect - two dimensional rectangle
  * @x1: horizontal starting coordinate (inclusive)
  * @x2: horizontal ending coordinate (exclusive)
  * @y1: vertical starting coordinate (inclusive)
index 07d59419fe6ba29a03a5cc4bdfe8ffb46acb29ab..923ed7fe5775b61743ba9df9037d27c2c3fe7b6b 100644 (file)
@@ -305,7 +305,7 @@ typedef struct drm_i915_irq_wait {
 #define I915_PARAM_HAS_WAIT_TIMEOUT     19
 #define I915_PARAM_HAS_SEMAPHORES       20
 #define I915_PARAM_HAS_PRIME_VMAP_FLUSH         21
-#define I915_PARAM_RSVD_FOR_FUTURE_USE  22
+#define I915_PARAM_HAS_VEBOX            22
 #define I915_PARAM_HAS_SECURE_BATCHES   23
 #define I915_PARAM_HAS_PINNED_BATCHES   24
 #define I915_PARAM_HAS_EXEC_NO_RELOC    25
@@ -660,6 +660,7 @@ struct drm_i915_gem_execbuffer2 {
 #define I915_EXEC_RENDER                 (1<<0)
 #define I915_EXEC_BSD                    (2<<0)
 #define I915_EXEC_BLT                    (3<<0)
+#define I915_EXEC_VEBOX                  (4<<0)
 
 /* Used for switching the constants addressing mode on gen4+ RENDER ring.
  * Gen6+ only supports relative addressing to dynamic state (default) and