mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 08:44:21 +08:00
Merge tag 'drm-intel-next-2013-06-01' of git://people.freedesktop.org/~danvet/drm-intel into drm-next
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 ...
This commit is contained in:
commit
e6dfcc5303
@ -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 -->
|
||||
|
@ -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 \
|
||||
|
@ -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},
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -265,13 +265,19 @@
|
||||
#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
|
||||
*/
|
||||
@ -342,27 +348,54 @@
|
||||
#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 */
|
||||
@ -554,6 +587,7 @@
|
||||
#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)
|
||||
@ -561,12 +595,20 @@
|
||||
#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)
|
||||
@ -578,6 +620,7 @@
|
||||
#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)
|
||||
@ -699,24 +742,6 @@
|
||||
#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
|
||||
@ -828,28 +853,6 @@
|
||||
#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)
|
||||
@ -860,9 +863,52 @@
|
||||
#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
|
||||
|
||||
@ -977,6 +1023,8 @@
|
||||
/* 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
|
||||
@ -3057,6 +3105,10 @@
|
||||
#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
|
||||
@ -3616,6 +3668,15 @@
|
||||
#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)
|
||||
@ -3667,21 +3728,6 @@
|
||||
#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
|
||||
@ -3711,6 +3757,9 @@
|
||||
# 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)
|
||||
@ -4516,7 +4565,7 @@
|
||||
#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)
|
||||
|
||||
@ -4538,40 +4587,6 @@
|
||||
#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
|
||||
@ -4935,6 +4950,9 @@
|
||||
#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)
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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)) &
|
||||
|
@ -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,19 +3563,13 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc)
|
||||
if (!crtc->config.gmch_pfit.control)
|
||||
return;
|
||||
|
||||
/*
|
||||
* The panel fitter should only be adjusted whilst the pipe is disabled,
|
||||
* according to register description and PRM.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
|
||||
pipe_config->gmch_pfit.control,
|
||||
pipe_config->gmch_pfit.pgm_ratios);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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, "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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 = ¶ms[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);
|
||||
}
|
||||
|
||||
I915_WRITE(PIPE_WM_LINETIME(pipe), temp);
|
||||
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 = ¶ms[pipe];
|
||||
|
||||
p->active = intel_crtc_active(crtc);
|
||||
if (!p->active)
|
||||
continue;
|
||||
|
||||
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 = ¶ms[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,
|
||||
¶ms[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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
|
177
drivers/gpu/drm/i915/intel_sideband.c
Normal file
177
drivers/gpu/drm/i915/intel_sideband.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -25,7 +25,14 @@
|
||||
#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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user