summaryrefslogtreecommitdiff
path: root/usr/src/uts/intel
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/intel')
-rw-r--r--usr/src/uts/intel/io/agpgart/agptarget.c4
-rw-r--r--usr/src/uts/intel/io/agpmaster/agpmaster.c6
-rw-r--r--usr/src/uts/intel/io/drm/drm_pciids.h3
-rw-r--r--usr/src/uts/intel/io/drm/i915_dma.c514
-rw-r--r--usr/src/uts/intel/io/drm/i915_drm.h47
-rw-r--r--usr/src/uts/intel/io/drm/i915_drv.c19
-rw-r--r--usr/src/uts/intel/io/drm/i915_drv.h194
-rw-r--r--usr/src/uts/intel/io/drm/i915_irq.c854
8 files changed, 1222 insertions, 419 deletions
diff --git a/usr/src/uts/intel/io/agpgart/agptarget.c b/usr/src/uts/intel/io/agpgart/agptarget.c
index f34124d342..d9b710b842 100644
--- a/usr/src/uts/intel/io/agpgart/agptarget.c
+++ b/usr/src/uts/intel/io/agpgart/agptarget.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -374,6 +374,8 @@ static gms_mode_t gms_modes[] = {
{INTEL_BR_Q45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
GMS_SIZE(gms_G4X), gms_G4X},
{INTEL_BR_G45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
+ GMS_SIZE(gms_G4X), gms_G4X},
+ {INTEL_BR_G41, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
GMS_SIZE(gms_G4X), gms_G4X}
};
static int
diff --git a/usr/src/uts/intel/io/agpmaster/agpmaster.c b/usr/src/uts/intel/io/agpmaster/agpmaster.c
index 7b4d290d23..20e48b0e8c 100644
--- a/usr/src/uts/intel/io/agpmaster/agpmaster.c
+++ b/usr/src/uts/intel/io/agpmaster/agpmaster.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -113,7 +113,8 @@ int agpm_debug = 0;
/* Intel G4X series */
#define IS_INTEL_G4X(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_EL) || \
(agpmaster->agpm_id == INTEL_IGD_Q45) || \
- (agpmaster->agpm_id == INTEL_IGD_G45))
+ (agpmaster->agpm_id == INTEL_IGD_G45) || \
+ (agpmaster->agpm_id == INTEL_IGD_G41))
static struct modlmisc modlmisc = {
&mod_miscops, "AGP master interfaces"
@@ -648,6 +649,7 @@ detect_i8xx_device(agp_master_softc_t *master_softc)
case INTEL_IGD_EL:
case INTEL_IGD_Q45:
case INTEL_IGD_G45:
+ case INTEL_IGD_G41:
master_softc->agpm_dev_type = DEVICE_IS_I830;
break;
default: /* unknown id */
diff --git a/usr/src/uts/intel/io/drm/drm_pciids.h b/usr/src/uts/intel/io/drm/drm_pciids.h
index c2a63d9f40..7d7f114392 100644
--- a/usr/src/uts/intel/io/drm/drm_pciids.h
+++ b/usr/src/uts/intel/io/drm/drm_pciids.h
@@ -3,7 +3,7 @@
* Please contact dri-devel@lists.sf.net to add new cards to this list
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -206,6 +206,7 @@ extern "C" {
{0x8086, 0x2E02, CHIP_I9XX|CHIP_I965, "Intel EL"}, \
{0x8086, 0x2E12, CHIP_I9XX|CHIP_I965, "Intel Q45"}, \
{0x8086, 0x2E22, CHIP_I9XX|CHIP_I965, "Intel G45"}, \
+ {0x8086, 0x2E32, CHIP_I9XX|CHIP_I965, "Intel G41"}, \
{0, 0, 0, NULL}
#ifdef __cplusplus
diff --git a/usr/src/uts/intel/io/drm/i915_dma.c b/usr/src/uts/intel/io/drm/i915_dma.c
index ccb7ae0cb7..c75d004442 100644
--- a/usr/src/uts/intel/io/drm/i915_dma.c
+++ b/usr/src/uts/intel/io/drm/i915_dma.c
@@ -29,7 +29,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -50,42 +50,112 @@ int i915_wait_ring(drm_device_t * dev, int n, const char *caller)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
- u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+ u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+ u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
+ u32 last_acthd = I915_READ(acthd_reg);
+ u32 acthd;
int i;
- for (i = 0; i < 10000; i++) {
- ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+ for (i = 0; i < 100000; i++) {
+ ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+ acthd = I915_READ(acthd_reg);
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->Size;
if (ring->space >= n)
return 0;
- dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
-
if (ring->head != last_head)
i = 0;
+ if (acthd != last_acthd)
+ i = 0;
+
last_head = ring->head;
- DRM_UDELAY(1);
+ last_acthd = acthd;
+ DRM_UDELAY(10);
}
return (EBUSY);
}
+int i915_init_hardware_status(drm_device_t *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_dma_handle_t *dmah;
+
+ /* Program Hardware Status Page */
+ dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff,1);
+
+ if (!dmah) {
+ DRM_ERROR("Can not allocate hardware status page\n");
+ return -ENOMEM;
+ }
+
+ dev_priv->status_page_dmah = dmah;
+ dev_priv->hw_status_page = (void *)dmah->vaddr;
+ dev_priv->dma_status_page = dmah->paddr;
+
+ (void) memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+
+ I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
+ DRM_DEBUG("Enabled hardware status page\n");
+ return 0;
+}
+
+void i915_free_hardware_status(drm_device_t *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ if (!I915_NEED_GFX_HWS(dev)) {
+ if (dev_priv->status_page_dmah) {
+ drm_pci_free(dev, dev_priv->status_page_dmah);
+ dev_priv->status_page_dmah = NULL;
+ /* Need to rewrite hardware status page */
+ I915_WRITE(HWS_PGA, 0x1ffff000);
+ }
+ } else {
+ if (dev_priv->status_gfx_addr) {
+ dev_priv->status_gfx_addr = 0;
+ drm_core_ioremapfree(&dev_priv->hws_map, dev);
+ I915_WRITE(HWS_PGA, 0x1ffff000);
+ }
+ }
+}
+
+#if I915_RING_VALIDATE
+/**
+ * Validate the cached ring tail value
+ *
+ * If the X server writes to the ring and DRM doesn't
+ * reload the head and tail pointers, it will end up writing
+ * data to the wrong place in the ring, causing havoc.
+ */
+void i915_ring_validate(struct drm_device *dev, const char *func, int line)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
+ u32 tail = I915_READ(PRB0_TAIL) & HEAD_ADDR;
+ u32 head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+
+ if (tail != ring->tail) {
+ DRM_ERROR("%s:%d head sw %x, hw %x. tail sw %x hw %x\n",
+ func, line,
+ ring->head, head, ring->tail, tail);
+ }
+}
+#endif
+
void i915_kernel_lost_context(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
- ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
- ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
+ ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+ ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->Size;
- if (ring->head == ring->tail)
- dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
}
static int i915_dma_cleanup(drm_device_t * dev)
@@ -97,7 +167,7 @@ static int i915_dma_cleanup(drm_device_t * dev)
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if (dev->irq)
+ if (dev->irq_enabled)
(void) drm_irq_uninstall(dev);
if (dev_priv->ring.virtual_start) {
@@ -107,19 +177,10 @@ static int i915_dma_cleanup(drm_device_t * dev)
dev_priv->ring.map.size = 0;
}
- if (dev_priv->status_page_dmah) {
- drm_pci_free(dev, dev_priv->status_page_dmah);
- dev_priv->status_page_dmah = NULL;
+ i915_free_hardware_status(dev);
- /* Need to rewrite hardware status page */
- I915_WRITE(0x02080, 0x1ffff000);
- }
-
- if (dev_priv->status_gfx_addr) {
- dev_priv->status_gfx_addr = 0;
- drm_core_ioremapfree(&dev_priv->hws_map, dev);
- I915_WRITE(0x2080, 0x1ffff000);
- }
+ dev_priv->sarea = NULL;
+ dev_priv->sarea_priv = NULL;
return 0;
}
@@ -142,79 +203,68 @@ static int i915_initialize(drm_device_t * dev,
* mmio_map will be destoried after DMA clean up. We should not
* access mmio_map in suspend or resume process.
*/
- dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
- if (!dev_priv->mmio_map) {
- dev->dev_private = (void *)dev_priv;
- (void) i915_dma_cleanup(dev);
- DRM_ERROR("can not find mmio map!\n");
- return (EINVAL);
- }
-
- dev_priv->sarea_priv = (drm_i915_sarea_t *)(void *)
- ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
-
- dev_priv->ring.Start = init->ring_start;
- dev_priv->ring.End = init->ring_end;
- dev_priv->ring.Size = init->ring_size;
- dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
- dev_priv->ring.map.offset = (u_offset_t)init->ring_start;
- dev_priv->ring.map.size = init->ring_size;
- dev_priv->ring.map.type = 0;
- dev_priv->ring.map.flags = 0;
- dev_priv->ring.map.mtrr = 0;
+ dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
- drm_core_ioremap(&dev_priv->ring.map, dev);
-
- if (dev_priv->ring.map.handle == NULL) {
- dev->dev_private = (void *)dev_priv;
- (void) i915_dma_cleanup(dev);
- DRM_ERROR("can not ioremap virtual address for"
+ if (!dev_priv->mmio_map) {
+ dev->dev_private = (void *)dev_priv;
+ (void) i915_dma_cleanup(dev);
+ DRM_ERROR("can not find mmio map!\n");
+ return (EINVAL);
+ }
+
+ if (init->sarea_priv_offset)
+ dev_priv->sarea_priv = (drm_i915_sarea_t *)
+ ((unsigned long) dev_priv->sarea->handle +
+ init->sarea_priv_offset);
+ else {
+ /* No sarea_priv for you! */
+ dev_priv->sarea_priv = NULL;
+ }
+
+ if (init->ring_size != 0) {
+ dev_priv->ring.Size = init->ring_size;
+ dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+
+ dev_priv->ring.map.offset = (u_offset_t)init->ring_start;
+ dev_priv->ring.map.size = init->ring_size;
+ dev_priv->ring.map.type = 0;
+ dev_priv->ring.map.flags = 0;
+ dev_priv->ring.map.mtrr = 0;
+
+ drm_core_ioremap(&dev_priv->ring.map, dev);
+
+ if (dev_priv->ring.map.handle == NULL) {
+ (void) i915_dma_cleanup(dev);
+ DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return (ENOMEM);
- }
+ return (ENOMEM);
+ }
- dev_priv->ring.virtual_start = (u8 *)dev_priv->ring.map.dev_addr;
+ dev_priv->ring.virtual_start = (u8 *)dev_priv->ring.map.dev_addr;
+ }
dev_priv->cpp = init->cpp;
- dev_priv->back_offset = init->back_offset;
- dev_priv->front_offset = init->front_offset;
- dev_priv->current_page = 0;
- dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->pf_current_page = 0;
/* We are using separate values as placeholders for mechanisms for
* private backbuffer/depthbuffer usage.
*/
- dev_priv->use_mi_batchbuffer_start = 0;
/* Allow hardware batchbuffers unless told otherwise.
*/
dev_priv->allow_batchbuffer = 1;
-
+ /* Init HWS */
if (!I915_NEED_GFX_HWS(dev)) {
- /* Program Hardware Status Page */
- dev_priv->status_page_dmah =
- drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE,
- 0xffffffff, 1);
-
- if (!dev_priv->status_page_dmah) {
- dev->dev_private = (void *)dev_priv;
- (void) i915_dma_cleanup(dev);
- DRM_ERROR("Can not allocate hardware status page\n");
- return (ENOMEM);
- }
-
- dev_priv->hw_status_page =
- (void *)dev_priv->status_page_dmah->vaddr;
- dev_priv->dma_status_page = dev_priv->status_page_dmah->paddr;
- (void) memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
- DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
-
- I915_WRITE(0x02080, dev_priv->dma_status_page);
+ (void) i915_init_hardware_status(dev);
}
- DRM_DEBUG("Enabled hardware status page\n");
+ /* Enable vblank on pipe A for older X servers
+ */
+ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
#ifdef I915_HAVE_BUFFER
drm_bo_driver_init(dev);
@@ -226,18 +276,13 @@ static int i915_dma_resume(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("i915_dma_resume\n");
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
return (EINVAL);
}
- if (!dev_priv->mmio_map) {
- DRM_ERROR("can not find mmio map!\n");
- return (EINVAL);
- }
-
if (dev_priv->ring.map.handle == NULL) {
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
@@ -252,9 +297,9 @@ static int i915_dma_resume(drm_device_t * dev)
DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
if (!I915_NEED_GFX_HWS(dev))
- I915_WRITE(0x02080, dev_priv->dma_status_page);
+ I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
else
- I915_WRITE(0x02080, dev_priv->status_gfx_addr);
+ I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
DRM_DEBUG("Enabled hardware status page\n");
return 0;
@@ -407,7 +452,7 @@ static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords)
return 0;
}
-static int i915_emit_box(drm_device_t * dev,
+int i915_emit_box(drm_device_t * dev,
drm_clip_rect_t __user * boxes,
int i, int DR1, int DR4)
{
@@ -450,29 +495,34 @@ static int i915_emit_box(drm_device_t * dev,
* emit. For now, do it in both places:
*/
-static void i915_emit_breadcrumb(drm_device_t *dev)
+void i915_emit_breadcrumb(drm_device_t *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
- dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
+ if (++dev_priv->counter > BREADCRUMB_MASK) {
+ dev_priv->counter = 1;
+ DRM_DEBUG("Breadcrumb counter wrapped around\n");
+ }
+
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
+
BEGIN_LP_RING(4);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(BREADCRUMB_OFFSET << 2);
+ OUT_RING(MI_STORE_DWORD_INDEX);
+ OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
OUT_RING(dev_priv->counter);
OUT_RING(0);
ADVANCE_LP_RING();
-#ifdef I915_HAVE_FENCE
- drm_fence_flush_old(dev, 0, dev_priv->counter);
-#endif
+
}
-int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush)
+void i915_emit_mi_flush(drm_device_t *dev, uint32_t flush)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t flush_cmd = CMD_MI_FLUSH;
+ uint32_t flush_cmd = MI_FLUSH;
RING_LOCALS;
flush_cmd |= flush;
@@ -485,13 +535,14 @@ int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush)
OUT_RING(0);
OUT_RING(0);
ADVANCE_LP_RING();
-
- return 0;
}
static int i915_dispatch_cmdbuffer(drm_device_t * dev,
drm_i915_cmdbuffer_t * cmd)
{
+#ifdef I915_HAVE_FENCE
+ drm_i915_private_t *dev_priv = dev->dev_private;
+#endif
int nbox = cmd->num_cliprects;
int i = 0, count, ret;
@@ -518,6 +569,10 @@ static int i915_dispatch_cmdbuffer(drm_device_t * dev,
}
i915_emit_breadcrumb( dev );
+#ifdef I915_HAVE_FENCE
+ if (unlikely((dev_priv->counter & 0xFF) == 0))
+ drm_fence_flush_old(dev, 0, dev_priv->counter);
+#endif
return 0;
}
@@ -547,18 +602,23 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev,
return ret;
}
- if (dev_priv->use_mi_batchbuffer_start) {
- BEGIN_LP_RING(2);
- OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
- OUT_RING(batch->start | MI_BATCH_NON_SECURE);
- ADVANCE_LP_RING();
- } else {
+ if (IS_I830(dev) || IS_845G(dev)) {
BEGIN_LP_RING(4);
OUT_RING(MI_BATCH_BUFFER);
OUT_RING(batch->start | MI_BATCH_NON_SECURE);
OUT_RING(batch->start + batch->used - 4);
OUT_RING(0);
ADVANCE_LP_RING();
+ } else {
+ BEGIN_LP_RING(2);
+ if (IS_I965G(dev)) {
+ OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
+ OUT_RING(batch->start);
+ } else {
+ OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
+ OUT_RING(batch->start | MI_BATCH_NON_SECURE);
+ }
+ ADVANCE_LP_RING();
}
}
@@ -567,62 +627,96 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev,
return 0;
}
-static int i915_dispatch_flip(drm_device_t * dev)
+static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 num_pages, current_page, next_page, dspbase;
+ int shift = 2 * plane, x, y;
RING_LOCALS;
- DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
- __FUNCTION__,
- dev_priv->current_page,
- dev_priv->sarea_priv->pf_current_page);
+ /* Calculate display base offset */
+ num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
+ current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3;
+ next_page = (current_page + 1) % num_pages;
- i915_kernel_lost_context(dev);
-
- BEGIN_LP_RING(2);
- OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
- OUT_RING(0);
- ADVANCE_LP_RING();
+ switch (next_page) {
+ default:
+ case 0:
+ dspbase = dev_priv->sarea_priv->front_offset;
+ break;
+ case 1:
+ dspbase = dev_priv->sarea_priv->back_offset;
+ break;
+ case 2:
+ dspbase = dev_priv->sarea_priv->third_offset;
+ break;
+ }
- BEGIN_LP_RING(6);
- OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP);
- OUT_RING(0);
- if (dev_priv->current_page == 0) {
- OUT_RING(dev_priv->back_offset);
- dev_priv->current_page = 1;
+ if (plane == 0) {
+ x = dev_priv->sarea_priv->planeA_x;
+ y = dev_priv->sarea_priv->planeA_y;
} else {
- OUT_RING(dev_priv->front_offset);
- dev_priv->current_page = 0;
+ x = dev_priv->sarea_priv->planeB_x;
+ y = dev_priv->sarea_priv->planeB_y;
}
- OUT_RING(0);
- ADVANCE_LP_RING();
- BEGIN_LP_RING(2);
- OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
- OUT_RING(0);
- ADVANCE_LP_RING();
+ dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp;
- dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
+
+ DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page, dspbase);
BEGIN_LP_RING(4);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(BREADCRUMB_OFFSET << 2);
- OUT_RING(dev_priv->counter);
- OUT_RING(0);
+ OUT_RING(sync ? 0 :
+ (MI_WAIT_FOR_EVENT | (plane ? MI_WAIT_FOR_PLANE_B_FLIP :
+ MI_WAIT_FOR_PLANE_A_FLIP)));
+ OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) |
+ (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A));
+ OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp);
+ OUT_RING(dspbase);
ADVANCE_LP_RING();
+
+ dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift);
+ dev_priv->sarea_priv->pf_current_page |= next_page << shift;
+}
+
+void i915_dispatch_flip(struct drm_device * dev, int planes, int sync)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int i;
+
+ DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n",
+ planes, dev_priv->sarea_priv->pf_current_page);
+
+ i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH);
+
+ for (i = 0; i < 2; i++)
+ if (planes & (1 << i))
+ i915_do_dispatch_flip(dev, i, sync);
+
+ i915_emit_breadcrumb(dev);
#ifdef I915_HAVE_FENCE
- drm_fence_flush_old(dev, 0, dev_priv->counter);
+ if (unlikely(!sync && ((dev_priv->counter & 0xFF) == 0)))
+ drm_fence_flush_old(dev, 0, dev_priv->counter);
#endif
- dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
- return 0;
+
}
static int i915_quiescent(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
-
+ int ret;
i915_kernel_lost_context(dev);
- return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+ ret = i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+
+ if (ret)
+ {
+ i915_kernel_lost_context (dev);
+ DRM_ERROR ("not quiescent head %08x tail %08x space %08x\n",
+ dev_priv->ring.head,
+ dev_priv->ring.tail,
+ dev_priv->ring.space);
+ }
+ return ret;
}
/*ARGSUSED*/
@@ -640,7 +734,6 @@ static int i915_batchbuffer(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
drm_i915_batchbuffer_t batch;
@@ -668,21 +761,23 @@ static int i915_batchbuffer(DRM_IOCTL_ARGS)
DRM_COPYFROM_WITH_RETURN(&batch, (void *) data,
sizeof(batch));
- DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
- batch.start, batch.used, batch.num_cliprects);
- LOCK_TEST_WITH_RETURN(dev, fpriv);
- /*
+ DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d, counter %d\n",
+ batch.start, batch.used, batch.num_cliprects, dev_priv->counter);
+ LOCK_TEST_WITH_RETURN(dev, fpriv);
+
+/*
if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects,
batch.num_cliprects *
sizeof(drm_clip_rect_t)))
return (EFAULT);
- */
+*/
+
ret = i915_dispatch_batchbuffer(dev, &batch);
+ sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- sarea_priv->last_dispatch = (int)hw_status[5];
return ret;
}
@@ -691,7 +786,6 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
drm_i915_cmdbuffer_t cmdbuf;
@@ -719,8 +813,8 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS)
cmdbuf.buf, cmdbuf.sz, cmdbuf.num_cliprects);
LOCK_TEST_WITH_RETURN(dev, fpriv);
- /*
-
+
+/*
if (cmdbuf.num_cliprects &&
DRM_VERIFYAREA_READ(cmdbuf.cliprects,
cmdbuf.num_cliprects *
@@ -728,7 +822,7 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS)
DRM_ERROR("Fault accessing cliprects\n");
return (EFAULT);
}
- */
+*/
ret = i915_dispatch_cmdbuffer(dev, &cmdbuf);
if (ret) {
@@ -736,31 +830,50 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS)
return ret;
}
- sarea_priv->last_dispatch = (int)hw_status[5];
+ sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
return 0;
}
-static int i915_do_cleanup_pageflip(drm_device_t * dev)
+static void i915_do_cleanup_pageflip(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
- DRM_DEBUG("%s\n", __FUNCTION__);
- if (dev_priv->current_page != 0)
- (void) i915_dispatch_flip(dev);
+ DRM_DEBUG("i915_do_cleanup_pageflip\n");
+
+ for (i = 0, planes = 0; i < 2; i++)
+ if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) {
+ dev_priv->sarea_priv->pf_current_page =
+ (dev_priv->sarea_priv->pf_current_page &
+ ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i));
+
+ planes |= 1 << i;
+ }
+
+ if (planes)
+ i915_dispatch_flip(dev, planes, 0);
- return 0;
}
/*ARGSUSED*/
static int i915_flip_bufs(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
+ drm_i915_flip_t param;
+ DRM_COPYFROM_WITH_RETURN(&param, (drm_i915_flip_t *) data,
+ sizeof(param));
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("i915_flip_bufs\n");
LOCK_TEST_WITH_RETURN(dev, fpriv);
-
- return i915_dispatch_flip(dev);
+ /* This is really planes */
+ if (param.pipes & ~0x3) {
+ DRM_ERROR("Invalid planes 0x%x, only <= 0x3 is valid\n",
+ param.pipes);
+ return -EINVAL;
+ }
+ i915_dispatch_flip(dev, param.pipes, 0);
+ return 0;
}
/*ARGSUSED*/
@@ -791,7 +904,7 @@ static int i915_getparam(DRM_IOCTL_ARGS)
switch (param.param) {
case I915_PARAM_IRQ_ACTIVE:
- value = dev->irq ? 1 : 0;
+ value = dev->irq_enabled ? 1 : 0;
break;
case I915_PARAM_ALLOW_BATCHBUFFER:
value = dev_priv->allow_batchbuffer ? 1 : 0;
@@ -799,6 +912,9 @@ static int i915_getparam(DRM_IOCTL_ARGS)
case I915_PARAM_LAST_DISPATCH:
value = READ_BREADCRUMB(dev_priv);
break;
+ case I915_PARAM_CHIPSET_ID:
+ value = dev->pci_device;
+ break;
default:
DRM_ERROR("Unknown parameter %d\n", param.param);
return (EINVAL);
@@ -828,7 +944,6 @@ static int i915_setparam(DRM_IOCTL_ARGS)
switch (param.param) {
case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
- dev_priv->use_mi_batchbuffer_start = param.value;
break;
case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
dev_priv->tex_lru_log_granularity = param.value;
@@ -867,8 +982,8 @@ static int i915_set_status_page(DRM_IOCTL_ARGS)
dev_priv->hws_map.offset =
(u_offset_t)dev->agp->agp_info.agpi_aperbase + hws.addr;
- dev_priv->hws_map.size = PAGE_SIZE; /* 4K pages */
- dev_priv->hws_map.type = _DRM_REGISTERS;
+ dev_priv->hws_map.size = 4 * 1024; /* 4K pages */
+ dev_priv->hws_map.type = 0;
dev_priv->hws_map.flags = 0;
dev_priv->hws_map.mtrr = 0;
@@ -886,7 +1001,7 @@ static int i915_set_status_page(DRM_IOCTL_ARGS)
dev_priv->hw_status_page = dev_priv->hws_map.dev_addr;
(void) memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
- I915_WRITE(0x02080, dev_priv->status_gfx_addr);
+ I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n",
dev_priv->status_gfx_addr);
DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
@@ -897,6 +1012,7 @@ static int i915_set_status_page(DRM_IOCTL_ARGS)
int i915_driver_load(drm_device_t *dev, unsigned long flags)
{
struct drm_i915_private *dev_priv;
+ int ret = 0;
/* i915 has 4 more counters */
dev->counters += 4;
@@ -911,14 +1027,27 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags)
(void) memset(dev_priv, 0, sizeof(drm_i915_private_t));
dev->dev_private = (void *)dev_priv;
+ dev_priv->dev = dev;
- return 0;
+ mutex_init(&dev_priv->swaps_lock, "swap", MUTEX_DRIVER, NULL);
+ mutex_init(&dev_priv->user_irq_lock, "userirq", MUTEX_DRIVER, NULL);
+
+ return ret;
}
int i915_driver_unload(struct drm_device *dev)
{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ i915_free_hardware_status(dev);
+
+ DRM_FINI_WAITQUEUE(&dev_priv->irq_queue);
+ mutex_destroy(&dev_priv->swaps_lock);
+ mutex_destroy(&dev_priv->user_irq_lock);
+
drm_free(dev->dev_private, sizeof(drm_i915_private_t),
DRM_MEM_DRIVER);
+ dev->dev_private = NULL;
return 0;
}
@@ -926,10 +1055,40 @@ int i915_driver_unload(struct drm_device *dev)
void i915_driver_lastclose(drm_device_t * dev)
{
- if (dev->dev_private) {
- drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ /* agp off can use this to get called before dev_priv */
+ if (!dev_priv)
+ return;
+
+#ifdef I915_HAVE_BUFFER
+ if (dev_priv->val_bufs) {
+ vfree(dev_priv->val_bufs);
+ dev_priv->val_bufs = NULL;
+ }
+#endif
+
+
+ DRM_GETSAREA();
+ if (dev_priv->sarea_priv)
+ i915_do_cleanup_pageflip(dev);
+ if (dev_priv->agp_heap)
i915_mem_takedown(&(dev_priv->agp_heap));
+#if defined(I915_HAVE_BUFFER)
+ if (dev_priv->sarea_kmap.virtual) {
+ drm_bo_kunmap(&dev_priv->sarea_kmap);
+ dev_priv->sarea_kmap.virtual = NULL;
+ dev->lock.hw_lock = NULL;
+ dev->sigdata.lock = NULL;
}
+
+ if (dev_priv->sarea_bo) {
+ mutex_lock(&dev->struct_mutex);
+ drm_bo_usage_deref_locked(&dev_priv->sarea_bo);
+ mutex_unlock(&dev->struct_mutex);
+ dev_priv->sarea_bo = NULL;
+ }
+#endif
(void) i915_dma_cleanup(dev);
}
@@ -937,9 +1096,6 @@ void i915_driver_preclose(drm_device_t * dev, drm_file_t *fpriv)
{
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
- if (dev_priv->page_flipping) {
- (void) i915_do_cleanup_pageflip(dev);
- }
i915_mem_release(dev, fpriv, dev_priv->agp_heap);
}
}
@@ -971,6 +1127,12 @@ drm_ioctl_desc_t i915_ioctls[] = {
{i915_cmdbuffer, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] =
{i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+ [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] =
+ {i915_vblank_pipe_set, DRM_AUTH},
+ [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] =
+ {i915_vblank_pipe_get, DRM_AUTH},
+ [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] =
+ {i915_vblank_swap, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_HWS_ADDR)] =
{i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
};
@@ -993,3 +1155,13 @@ int i915_driver_device_is_agp(drm_device_t * dev)
{
return 1;
}
+
+/*ARGSUSED*/
+int i915_driver_firstopen(struct drm_device *dev)
+{
+#ifdef I915_HAVE_BUFFER
+ drm_bo_driver_init(dev);
+#endif
+ return 0;
+}
+
diff --git a/usr/src/uts/intel/io/drm/i915_drm.h b/usr/src/uts/intel/io/drm/i915_drm.h
index e56c9606ea..448e4534e6 100644
--- a/usr/src/uts/intel/io/drm/i915_drm.h
+++ b/usr/src/uts/intel/io/drm/i915_drm.h
@@ -27,15 +27,13 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _I915_DRM_H
#define _I915_DRM_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/* Please note that modifications to all structs defined here are
* subject to backwards-compatibility constraints.
*/
@@ -84,6 +82,7 @@ typedef struct _drm_i915_sarea {
int pf_current_page; /* which buffer is being displayed? */
int perf_boxes; /* performance boxes to be displayed */
int width, height; /* screen size in pixels */
+ int pad0;
drm_handle_t front_handle;
int front_offset;
@@ -114,14 +113,21 @@ typedef struct _drm_i915_sarea {
unsigned int rotated_tiled;
unsigned int rotated2_tiled;
- int pipeA_x;
- int pipeA_y;
- int pipeA_w;
- int pipeA_h;
- int pipeB_x;
- int pipeB_y;
- int pipeB_w;
- int pipeB_h;
+ int planeA_x;
+ int planeA_y;
+ int planeA_w;
+ int planeA_h;
+ int planeB_x;
+ int planeB_y;
+ int planeB_w;
+ int planeB_h;
+
+ /* Triple buffering */
+ drm_handle_t third_handle;
+ int third_offset;
+ int third_size;
+ unsigned int third_tiled;
+
} drm_i915_sarea_t;
/* Driver specific fence types and classes.
@@ -158,6 +164,9 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_INIT_HEAP 0x0a
#define DRM_I915_CMDBUFFER 0x0b
#define DRM_I915_DESTROY_HEAP 0x0c
+#define DRM_I915_SET_VBLANK_PIPE 0x0d
+#define DRM_I915_GET_VBLANK_PIPE 0x0e
+#define DRM_I915_VBLANK_SWAP 0x0f
#define DRM_I915_HWS_ADDR 0x11
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
@@ -173,6 +182,21 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t)
#define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t)
#define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t)
+#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
+#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
+#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
+
+/* Asynchronous page flipping:
+ */
+typedef struct drm_i915_flip {
+ /*
+ * This is really talking about planes, and we could rename it
+ * except for the fact that some of the duplicated i915_drm.h files
+ * out there check for HAVE_I915_FLIP and so might pick up this
+ * version.
+ */
+ int pipes;
+} drm_i915_flip_t;
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
@@ -235,6 +259,7 @@ typedef struct drm_i915_irq_wait {
#define I915_PARAM_IRQ_ACTIVE 1
#define I915_PARAM_ALLOW_BATCHBUFFER 2
#define I915_PARAM_LAST_DISPATCH 3
+#define I915_PARAM_CHIPSET_ID 4
typedef struct drm_i915_getparam {
int param;
diff --git a/usr/src/uts/intel/io/drm/i915_drv.c b/usr/src/uts/intel/io/drm/i915_drv.c
index 2736423075..489d3c8e74 100644
--- a/usr/src/uts/intel/io/drm/i915_drv.c
+++ b/usr/src/uts/intel/io/drm/i915_drv.c
@@ -34,7 +34,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -641,7 +641,7 @@ i915_suspend(struct drm_device *dev)
s3_priv->saveDSPATILEOFF = S3_READ(DSPATILEOFF);
}
i915_save_palette(dev, PIPE_A);
- s3_priv->savePIPEASTAT = S3_READ(I915REG_PIPEASTAT);
+ s3_priv->savePIPEASTAT = S3_READ(PIPEASTAT);
/*
* Pipe & plane B info
@@ -671,7 +671,7 @@ i915_suspend(struct drm_device *dev)
s3_priv->saveDSPBTILEOFF = S3_READ(DSPBTILEOFF);
}
i915_save_palette(dev, PIPE_B);
- s3_priv->savePIPEBSTAT = S3_READ(I915REG_PIPEBSTAT);
+ s3_priv->savePIPEBSTAT = S3_READ(PIPEBSTAT);
/*
* CRT state
@@ -703,9 +703,9 @@ i915_suspend(struct drm_device *dev)
s3_priv->saveFBC_CONTROL = S3_READ(FBC_CONTROL);
/* Interrupt state */
- s3_priv->saveIIR = S3_READ(I915REG_INT_IDENTITY_R);
- s3_priv->saveIER = S3_READ(I915REG_INT_ENABLE_R);
- s3_priv->saveIMR = S3_READ(I915REG_INT_MASK_R);
+ s3_priv->saveIIR = S3_READ(IIR);
+ s3_priv->saveIER = S3_READ(IER);
+ s3_priv->saveIMR = S3_READ(IMR);
/* VGA state */
s3_priv->saveVCLK_DIVISOR_VGA0 = S3_READ(VCLK_DIVISOR_VGA0);
@@ -962,8 +962,9 @@ static void i915_configure(drm_driver_t *driver)
driver->preclose = i915_driver_preclose;
driver->lastclose = i915_driver_lastclose;
driver->device_is_agp = i915_driver_device_is_agp;
- driver->vblank_wait = i915_driver_vblank_wait;
- driver->vblank_wait2 = i915_driver_vblank_wait2;
+ driver->get_vblank_counter = i915_get_vblank_counter;
+ driver->enable_vblank = i915_enable_vblank;
+ driver->disable_vblank = i915_disable_vblank;
driver->irq_preinstall = i915_driver_irq_preinstall;
driver->irq_postinstall = i915_driver_irq_postinstall;
driver->irq_uninstall = i915_driver_irq_uninstall;
@@ -982,6 +983,4 @@ static void i915_configure(drm_driver_t *driver)
driver->use_agp = 1;
driver->require_agp = 1;
driver->use_irq = 1;
- driver->use_vbl_irq = 1;
- driver->use_vbl_irq2 = 1;
}
diff --git a/usr/src/uts/intel/io/drm/i915_drv.h b/usr/src/uts/intel/io/drm/i915_drv.h
index 10e7fc921b..88273a8cb2 100644
--- a/usr/src/uts/intel/io/drm/i915_drv.h
+++ b/usr/src/uts/intel/io/drm/i915_drv.h
@@ -30,7 +30,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -58,7 +58,7 @@
* 1.4: Fix cmdbuffer path, add heap destroy
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 4
+#define DRIVER_MINOR 5
#define DRIVER_PATCHLEVEL 0
#if defined(__linux__)
@@ -68,8 +68,6 @@
typedef struct _drm_i915_ring_buffer {
int tail_mask;
- unsigned long Start;
- unsigned long End;
unsigned long Size;
u8 *virtual_start;
int head;
@@ -89,8 +87,9 @@ struct mem_block {
typedef struct _drm_i915_vbl_swap {
struct list_head head;
drm_drawable_t drw_id;
- unsigned int pipe;
+ unsigned int plane;
unsigned int sequence;
+ int flip;
} drm_i915_vbl_swap_t;
typedef struct s3_i915_private {
@@ -187,6 +186,8 @@ typedef struct s3_i915_private {
} s3_i915_private_t;
typedef struct drm_i915_private {
+ struct drm_device *dev;
+
drm_local_map_t *sarea;
drm_local_map_t *mmio_map;
@@ -201,15 +202,9 @@ typedef struct drm_i915_private {
drm_local_map_t hws_map;
unsigned int cpp;
- int back_offset;
- int front_offset;
- int current_page;
- int page_flipping;
- int use_mi_batchbuffer_start;
wait_queue_head_t irq_queue;
atomic_t irq_received;
- atomic_t irq_emitted;
int tex_lru_log_granularity;
int allow_batchbuffer;
@@ -219,7 +214,7 @@ typedef struct drm_i915_private {
spinlock_t user_irq_lock;
int user_irq_refcount;
int fence_irq_on;
- uint32_t irq_enable_reg;
+ uint32_t irq_mask_reg;
int irq_enabled;
#ifdef I915_HAVE_FENCE
@@ -256,22 +251,31 @@ extern void i915_driver_preclose(drm_device_t * dev, drm_file_t *filp);
extern int i915_driver_device_is_agp(drm_device_t * dev);
extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
-extern int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush);
+extern int i915_emit_box(struct drm_device *dev,
+ struct drm_clip_rect __user *boxes,
+ int i, int DR1, int DR4);
+extern void i915_emit_breadcrumb(struct drm_device *dev);
+extern void i915_dispatch_flip(struct drm_device * dev, int pipes, int sync);
+extern void i915_emit_mi_flush(drm_device_t *dev, uint32_t flush);
/* i915_irq.c */
extern int i915_irq_emit(DRM_IOCTL_ARGS);
extern int i915_irq_wait(DRM_IOCTL_ARGS);
-extern int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence);
-extern int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence);
+extern int i915_enable_vblank(struct drm_device *dev, int crtc);
+extern void i915_disable_vblank(struct drm_device *dev, int crtc);
+extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(drm_device_t * dev);
extern void i915_driver_irq_postinstall(drm_device_t * dev);
extern void i915_driver_irq_uninstall(drm_device_t * dev);
extern int i915_emit_irq(drm_device_t * dev);
+extern int i915_vblank_swap(DRM_IOCTL_ARGS);
extern void i915_user_irq_on(drm_i915_private_t *dev_priv);
extern void i915_user_irq_off(drm_i915_private_t *dev_priv);
+extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS);
+extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS);
/* i915_mem.c */
extern int i915_mem_alloc(DRM_IOCTL_ARGS);
@@ -321,10 +325,23 @@ extern int i915_move(drm_buffer_object_t *bo, int evict,
#define S3_WRITE(reg, val) \
*(uint32_t volatile *)((uintptr_t)s3_priv->saveAddr + (reg)) = (val)
+#define I915_VERBOSE 0
+#define I915_RING_VALIDATE 0
+
+#if I915_RING_VALIDATE
+void i915_ring_validate(struct drm_device *dev, const char *func, int line);
+#define I915_RING_DO_VALIDATE(dev) i915_ring_validate(dev, __FUNCTION__, __LINE__)
+#else
+#define I915_RING_DO_VALIDATE(dev)
+#endif
+
#define RING_LOCALS unsigned int outring, ringmask, outcount; \
volatile unsigned char *virt;
+#if I915_VERBOSE
#define BEGIN_LP_RING(n) do { \
+ DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \
+ I915_RING_DO_VALIDATE(dev); \
if (dev_priv->ring.space < (n)*4) \
(void) i915_wait_ring(dev, (n)*4, __FUNCTION__); \
outcount = 0; \
@@ -332,19 +349,51 @@ extern int i915_move(drm_buffer_object_t *bo, int evict,
ringmask = dev_priv->ring.tail_mask; \
virt = dev_priv->ring.virtual_start; \
} while (*"\0")
+#else
+#define BEGIN_LP_RING(n) do { \
+ I915_RING_DO_VALIDATE(dev); \
+ if (dev_priv->ring.space < (n)*4) \
+ (void) i915_wait_ring(dev, (n)*4, __FUNCTION__); \
+ outcount = 0; \
+ outring = dev_priv->ring.tail; \
+ ringmask = dev_priv->ring.tail_mask; \
+ virt = dev_priv->ring.virtual_start; \
+} while (*"\0")
+#endif
+#if I915_VERBOSE
+#define OUT_RING(n) do { \
+ DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
+ *(volatile unsigned int *)(void *)(virt + outring) = (n); \
+ outcount++; \
+ outring += 4; \
+ outring &= ringmask; \
+} while (*"\0")
+#else
#define OUT_RING(n) do { \
*(volatile unsigned int *)(void *)(virt + outring) = (n); \
outcount++; \
outring += 4; \
outring &= ringmask; \
} while (*"\0")
+#endif
+#if I915_VERBOSE
#define ADVANCE_LP_RING() do { \
+ DRM_DEBUG("ADVANCE_LP_RING %x\n", outring); \
+ I915_RING_DO_VALIDATE(dev); \
dev_priv->ring.tail = outring; \
dev_priv->ring.space -= outcount * 4; \
- I915_WRITE(LP_RING + RING_TAIL, outring); \
+ I915_WRITE(PRB0_TAIL, outring); \
} while (*"\0")
+#else
+#define ADVANCE_LP_RING() do { \
+ I915_RING_DO_VALIDATE(dev); \
+ dev_priv->ring.tail = outring; \
+ dev_priv->ring.space -= outcount * 4; \
+ I915_WRITE(PRB0_TAIL, outring); \
+} while (*"\0")
+#endif
extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
@@ -403,10 +452,14 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define INST_OP_FLUSH 0x02000000
#define INST_FLUSH_MAP_CACHE 0x00000001
-#define CMD_MI_FLUSH (0x04 << 23)
+#define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags))
+#define MI_USER_INTERRUPT MI_INSTR(2, (0 << 29))
+#define MI_FLUSH (0x04 << 23)
#define MI_NO_WRITE_FLUSH (1 << 2)
#define MI_READ_FLUSH (1 << 0)
#define MI_EXE_FLUSH (1 << 1)
+#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1)
+#define MI_STORE_DWORD_INDEX_SHIFT 2
#define BB1_START_ADDR_MASK (~0x7)
#define BB1_PROTECTED (1<<0)
@@ -414,16 +467,18 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define BB2_END_ADDR_MASK (~0x7)
#define I915REG_PGTBL_CTRL 0x2020
-#define I915REG_HWSTAM 0x02098
-#define I915REG_INT_IDENTITY_R 0x020a4
-#define I915REG_INT_MASK_R 0x020a8
-#define I915REG_INT_ENABLE_R 0x020a0
-#define I915REG_INSTPM 0x020c0
-
-#define I915REG_PIPEASTAT 0x70024
-#define I915REG_PIPEBSTAT 0x71024
-
-#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
+#define HWSTAM 0x02098
+#define IIR 0x020a4
+#define IMR 0x020a8
+#define IER 0x020a0
+#define INSTPM 0x020c0
+#define ACTHD 0x020c8
+#define PIPEASTAT 0x70024
+#define PIPEBSTAT 0x71024
+#define ACTHD_I965 0x02074
+#define HWS_PGA 0x02080
+
+#define PIPE_VBLANK_INTERRUPT_ENABLE (1UL<<17)
#define I915_VBLANK_CLEAR (1UL<<1)
#define SRX_INDEX 0x3c4
@@ -454,9 +509,7 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define NOPID 0x2094
#define LP_RING 0x2030
#define HP_RING 0x2040
-#define RING_TAIL 0x00
#define TAIL_ADDR 0x001FFFF8
-#define RING_HEAD 0x04
#define HEAD_WRAP_COUNT 0xFFE00000
#define HEAD_WRAP_ONE 0x00200000
#define HEAD_ADDR 0x001FFFFC
@@ -471,7 +524,9 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define RING_VALID_MASK 0x00000001
#define RING_VALID 0x00000001
#define RING_INVALID 0x00000000
-
+#define PRB0_TAIL 0x02030
+#define PRB0_HEAD 0x02034
+#define PRB0_CTL 0x0203c
#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19))
#define SC_UPDATE_SCISSOR (0x1<<1)
#define SC_ENABLE_MASK (0x1<<0)
@@ -497,13 +552,18 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
+#define XY_SRC_COPY_BLT_SRC_TILED (1<<15)
+#define XY_SRC_COPY_BLT_DST_TILED (1<<11)
#define MI_BATCH_BUFFER ((0x30<<23)|1)
#define MI_BATCH_BUFFER_START (0x31<<23)
#define MI_BATCH_BUFFER_END (0xA<<23)
#define MI_BATCH_NON_SECURE (1)
+#define MI_BATCH_NON_SECURE_I965 (1<<8)
+
#define MI_WAIT_FOR_EVENT ((0x3<<23))
+#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6)
#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2)
#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
@@ -511,11 +571,15 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
#define ASYNC_FLIP (1<<22)
+#define DISPLAY_PLANE_A (0<<20)
+#define DISPLAY_PLANE_B (1<<20)
#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
-#define BREADCRUMB_OFFSET 32 /* dword offset 20h */
-#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[BREADCRUMB_OFFSET])
+#define BREADCRUMB_BITS 31
+#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1)
+
+#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5])
#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg])
/*
@@ -731,7 +795,7 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define DSPBTILEOFF 0x711A4
#define PIPEACONF 0x70008
-#define PIPEACONF_ENABLE (1<<31)
+#define PIPEACONF_ENABLE (1UL<<31)
#define PIPEACONF_DISABLE 0
#define PIPEACONF_DOUBLE_WIDE (1<<30)
#define I965_PIPECONF_ACTIVE (1<<30)
@@ -746,7 +810,7 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
#define PIPEBCONF 0x71008
-#define PIPEBCONF_ENABLE (1<<31)
+#define PIPEBCONF_ENABLE (1UL<<31)
#define PIPEBCONF_DISABLE 0
#define PIPEBCONF_DOUBLE_WIDE (1<<30)
#define PIPEBCONF_DISABLE 0
@@ -820,6 +884,61 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define DSPARB 0x70030
+#define PIPEAFRAMEHIGH 0x70040
+#define PIPEBFRAMEHIGH 0x71040
+#define PIPE_FRAME_HIGH_MASK 0x0000ffff
+#define PIPE_FRAME_HIGH_SHIFT 0
+#define PIPEAFRAMEPIXEL 0x70044
+#define PIPEBFRAMEPIXEL 0x71044
+
+#define PIPE_FRAME_LOW_MASK 0xff000000
+#define PIPE_FRAME_LOW_SHIFT 24
+
+/* Interrupt bits:
+ */
+#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)
+#define I915_HWB_OOM_INTERRUPT (1<<13) /* binner out of memory */
+#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_FIFO_UNDERRUN_STATUS (1UL<<31)
+#define I915_CRC_ERROR_ENABLE (1UL<<29)
+#define I915_CRC_DONE_ENABLE (1UL<<28)
+#define I915_GMBUS_EVENT_ENABLE (1UL<<27)
+#define I915_VSYNC_INTERRUPT_ENABLE (1UL<<25)
+#define I915_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24)
+#define I915_DPST_EVENT_ENABLE (1UL<<23)
+#define I915_LEGACY_BLC_EVENT_ENABLE (1UL<<22)
+#define I915_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21)
+#define I915_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20)
+#define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */
+#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
+#define I915_OVERLAY_UPDATED_ENABLE (1UL<<16)
+#define I915_CRC_ERROR_INTERRUPT_STATUS (1UL<<13)
+#define I915_CRC_DONE_INTERRUPT_STATUS (1UL<<12)
+#define I915_GMBUS_INTERRUPT_STATUS (1UL<<11)
+#define I915_VSYNC_INTERRUPT_STATUS (1UL<<9)
+#define I915_DISPLAY_LINE_COMPARE_STATUS (1UL<<8)
+#define I915_DPST_EVENT_STATUS (1UL<<7)
+#define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6)
+#define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5)
+#define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4)
+#define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */
+#define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1)
+#define I915_OVERLAY_UPDATED_STATUS (1UL<<0)
+
/*
* Some BIOS scratch area registers. The 845 (and 830?) store the amount
* of video memory available to the BIOS in SWF1.
@@ -856,6 +975,7 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define PCI_DEVICE_ID_INTEL_EL_IG 0x2e02
#define PCI_DEVICE_ID_INTEL_82Q45_IG 0x2e12
#define PCI_DEVICE_ID_INTEL_82G45_IG 0x2e22
+#define PCI_DEVICE_ID_INTEL_82G41_IG 0x2e32
#define IS_I830(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82830_CGC)
@@ -879,7 +999,8 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
(dev)->pci_device == PCI_DEVICE_ID_INTEL_CANTIGA_IG || \
(dev)->pci_device == PCI_DEVICE_ID_INTEL_EL_IG || \
(dev)->pci_device == PCI_DEVICE_ID_INTEL_82Q45_IG || \
- (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G45_IG)
+ (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G45_IG || \
+ (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G41_IG)
#define IS_I965GM(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_GM965_IG)
@@ -887,7 +1008,8 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define IS_G4X(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_EL_IG || \
(dev)->pci_device == PCI_DEVICE_ID_INTEL_82Q45_IG || \
- (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G45_IG)
+ (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G45_IG || \
+ (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G41_IG)
#define IS_G33(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82G33_IG || \
(dev)->pci_device == PCI_DEVICE_ID_INTEL_82Q35_IG || \
diff --git a/usr/src/uts/intel/io/drm/i915_irq.c b/usr/src/uts/intel/io/drm/i915_irq.c
index dd5c141c59..a8e44ca953 100644
--- a/usr/src/uts/intel/io/drm/i915_irq.c
+++ b/usr/src/uts/intel/io/drm/i915_irq.c
@@ -29,7 +29,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -38,12 +38,140 @@
#include "i915_drm.h"
#include "i915_drv.h"
-#define USER_INT_FLAG (1<<1)
-#define VSYNC_PIPEB_FLAG (1<<5)
-#define VSYNC_PIPEA_FLAG (1<<7)
#define MAX_NOPID ((u32)~0)
+/*
+ * These are the interrupts used by the driver
+ */
+#define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
+
+static inline void
+i915_enable_irq(drm_i915_private_t *dev_priv, uint32_t mask)
+{
+ if ((dev_priv->irq_mask_reg & mask) != 0) {
+ dev_priv->irq_mask_reg &= ~mask;
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ (void) I915_READ(IMR);
+ }
+}
+
+static inline void
+i915_disable_irq(drm_i915_private_t *dev_priv, uint32_t mask)
+{
+ if ((dev_priv->irq_mask_reg & mask) != mask) {
+ dev_priv->irq_mask_reg |= mask;
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ (void) I915_READ(IMR);
+ }
+}
+ /**
+ * i915_get_pipe - return the the pipe associated with a given plane
+ * @dev: DRM device
+ * @plane: plane to look for
+ *
+ * The Intel Mesa & 2D drivers call the vblank routines with a plane number
+ * rather than a pipe number, since they may not always be equal. This routine
+ * maps the given @plane back to a pipe number.
+ */
+static int
+i915_get_pipe(struct drm_device *dev, int plane)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 dspcntr;
+
+ dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR);
+
+ return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0;
+}
+
+/**
+ * i915_get_plane - return the the plane associated with a given pipe
+ * @dev: DRM device
+ * @pipe: pipe to look for
+ *
+ * The Intel Mesa & 2D drivers call the vblank routines with a plane number
+ * rather than a plane number, since they may not always be equal. This routine
+ * maps the given @pipe back to a plane number.
+ */
+static int
+i915_get_plane(struct drm_device *dev, int pipe)
+{
+ if (i915_get_pipe(dev, 0) == pipe)
+ return 0;
+ return 1;
+}
+
+/**
+ * i915_pipe_enabled - check if a pipe is enabled
+ * @dev: DRM device
+ * @pipe: pipe to check
+ *
+ * Reading certain registers when the pipe is disabled can hang the chip.
+ * Use this routine to make sure the PLL is running and the pipe is active
+ * before reading such registers if unsure.
+ */
+static int
+i915_pipe_enabled(struct drm_device *dev, int pipe)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
+
+ if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * Emit a synchronous flip.
+ *
+ * This function must be called with the drawable spinlock held.
+ */
+static void
+i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw,
+ int plane)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ u16 x1, y1, x2, y2;
+ int pf_planes = 1 << plane;
+
+ DRM_SPINLOCK_ASSERT(&dev->drw_lock);
+
+ /* If the window is visible on the other plane, we have to flip on that
+ * plane as well.
+ */
+ if (plane == 1) {
+ x1 = sarea_priv->planeA_x;
+ y1 = sarea_priv->planeA_y;
+ x2 = x1 + sarea_priv->planeA_w;
+ y2 = y1 + sarea_priv->planeA_h;
+ } else {
+ x1 = sarea_priv->planeB_x;
+ y1 = sarea_priv->planeB_y;
+ x2 = x1 + sarea_priv->planeB_w;
+ y2 = y1 + sarea_priv->planeB_h;
+ }
+
+ if (x2 > 0 && y2 > 0) {
+ int i, num_rects = drw->num_rects;
+ struct drm_clip_rect *rect = drw->rects;
+
+ for (i = 0; i < num_rects; i++)
+ if (!(rect[i].x1 >= x2 || rect[i].y1 >= y2 ||
+ rect[i].x2 <= x1 || rect[i].y2 <= y1)) {
+ pf_planes = 0x3;
+
+ break;
+ }
+ }
+
+ i915_dispatch_flip(dev, pf_planes, 1);
+}
+
/**
* Emit blits for scheduled buffer swaps.
*
@@ -52,57 +180,74 @@
static void i915_vblank_tasklet(drm_device_t *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- /* LINTED E_FUNC_VAR_UNUSED */
- unsigned long irqflags;
struct list_head *list, *tmp, hits, *hit;
- int nhits, slice[2], upper[2], lower[2], i;
- unsigned counter[2] = { atomic_read(&dev->vbl_received),
- atomic_read(&dev->vbl_received2) };
- drm_drawable_info_t *drw;
+ int nhits, slice[2], upper[2], lower[2], i, num_pages;
+ unsigned counter[2];
+ struct drm_drawable_info *drw;
drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
- u32 cpp = dev_priv->cpp;
+ u32 cpp = dev_priv->cpp, offsets[3];
u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
XY_SRC_COPY_BLT_WRITE_ALPHA |
XY_SRC_COPY_BLT_WRITE_RGB)
: XY_SRC_COPY_BLT_CMD;
- u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) |
- (cpp << 23) | (1 << 24);
+ u32 src_pitch = sarea_priv->pitch * cpp;
+ u32 dst_pitch = sarea_priv->pitch * cpp;
+ /* COPY rop (0xcc), map cpp to magic color depth constants */
+ u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24);
RING_LOCALS;
-
- DRM_DEBUG("%s\n", __FUNCTION__);
+
+ if (IS_I965G(dev) && sarea_priv->front_tiled) {
+ cmd |= XY_SRC_COPY_BLT_DST_TILED;
+ dst_pitch >>= 2;
+ }
+ if (IS_I965G(dev) && sarea_priv->back_tiled) {
+ cmd |= XY_SRC_COPY_BLT_SRC_TILED;
+ src_pitch >>= 2;
+ }
+
+ counter[0] = drm_vblank_count(dev, 0);
+ counter[1] = drm_vblank_count(dev, 1);
INIT_LIST_HEAD(&hits);
nhits = 0;
- spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+ /* No irqsave/restore necessary. This tasklet may be run in an
+ * interrupt context or normal context, but we don't have to worry
+ * about getting interrupted by something acquiring the lock, because
+ * we are the interrupt context thing that acquires the lock.
+ */
+ DRM_SPINLOCK(&dev_priv->swaps_lock);
/* Find buffer swaps scheduled for this vertical blank */
list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
drm_i915_vbl_swap_t *vbl_swap =
list_entry(list, drm_i915_vbl_swap_t, head);
+ int pipe = i915_get_pipe(dev, vbl_swap->plane);
- if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
+ if ((counter[pipe] - vbl_swap->sequence) > (1<<23))
continue;
list_del(list);
dev_priv->swaps_pending--;
+ drm_vblank_put(dev, pipe);
- spin_unlock(&dev_priv->swaps_lock);
- spin_lock(&dev->drw_lock);
+ DRM_SPINUNLOCK(&dev_priv->swaps_lock);
+ DRM_SPINLOCK(&dev->drw_lock);
drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
if (!drw) {
- spin_unlock(&dev->drw_lock);
+ DRM_SPINUNLOCK(&dev->drw_lock);
drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
- spin_lock(&dev_priv->swaps_lock);
+ DRM_SPINLOCK(&dev_priv->swaps_lock);
continue;
}
list_for_each(hit, &hits) {
drm_i915_vbl_swap_t *swap_cmp =
list_entry(hit, drm_i915_vbl_swap_t, head);
- drm_drawable_info_t *drw_cmp =
+ struct drm_drawable_info *drw_cmp =
drm_get_drawable_info(dev, swap_cmp->drw_id);
if (drw_cmp &&
@@ -112,7 +257,7 @@ static void i915_vblank_tasklet(drm_device_t *dev)
}
}
- spin_unlock(&dev->drw_lock);
+ DRM_SPINUNLOCK(&dev->drw_lock);
/* List of hits was empty, or we reached the end of it */
if (hit == &hits)
@@ -120,38 +265,29 @@ static void i915_vblank_tasklet(drm_device_t *dev)
nhits++;
- spin_lock(&dev_priv->swaps_lock);
+ DRM_SPINLOCK(&dev_priv->swaps_lock);
}
+ DRM_SPINUNLOCK(&dev_priv->swaps_lock);
+
if (nhits == 0) {
- spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
return;
}
- spin_unlock(&dev_priv->swaps_lock);
-
i915_kernel_lost_context(dev);
- BEGIN_LP_RING(6);
-
- OUT_RING(GFX_OP_DRAWRECT_INFO);
- OUT_RING(0);
- OUT_RING(0);
- OUT_RING(sarea_priv->width | sarea_priv->height << 16);
- OUT_RING(sarea_priv->width | sarea_priv->height << 16);
- OUT_RING(0);
-
- ADVANCE_LP_RING();
-
- sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
-
upper[0] = upper[1] = 0;
- slice[0] = max(sarea_priv->pipeA_h / nhits, 1);
- slice[1] = max(sarea_priv->pipeB_h / nhits, 1);
- lower[0] = sarea_priv->pipeA_y + slice[0];
- lower[1] = sarea_priv->pipeB_y + slice[0];
+ slice[0] = max(sarea_priv->planeA_h / nhits, 1);
+ slice[1] = max(sarea_priv->planeB_h / nhits, 1);
+ lower[0] = sarea_priv->planeA_y + slice[0];
+ lower[1] = sarea_priv->planeB_y + slice[0];
+
+ offsets[0] = sarea_priv->front_offset;
+ offsets[1] = sarea_priv->back_offset;
+ offsets[2] = sarea_priv->third_offset;
+ num_pages = sarea_priv->third_handle ? 3 : 2;
- spin_lock(&dev->drw_lock);
+ DRM_SPINLOCK(&dev->drw_lock);
/* Emit blits for buffer swaps, partitioning both outputs into as many
* slices as there are buffer swaps scheduled in order to avoid tearing
@@ -161,14 +297,16 @@ static void i915_vblank_tasklet(drm_device_t *dev)
for (i = 0; i++ < nhits;
upper[0] = lower[0], lower[0] += slice[0],
upper[1] = lower[1], lower[1] += slice[1]) {
+ int init_drawrect = 1;
+
if (i == nhits)
lower[0] = lower[1] = sarea_priv->height;
list_for_each(hit, &hits) {
drm_i915_vbl_swap_t *swap_hit =
list_entry(hit, drm_i915_vbl_swap_t, head);
- drm_clip_rect_t *rect;
- int num_rects, pipe;
+ struct drm_clip_rect *rect;
+ int num_rects, plane, front, back;
unsigned short top, bottom;
drw = drm_get_drawable_info(dev, swap_hit->drw_id);
@@ -176,10 +314,46 @@ static void i915_vblank_tasklet(drm_device_t *dev)
if (!drw)
continue;
+ plane = swap_hit->plane;
+
+ if (swap_hit->flip) {
+ i915_dispatch_vsync_flip(dev, drw, plane);
+ continue;
+ }
+
+ if (init_drawrect) {
+ int width = sarea_priv->width;
+ int height = sarea_priv->height;
+ if (IS_I965G(dev)) {
+ BEGIN_LP_RING(4);
+ OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
+ OUT_RING(0);
+ OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16));
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+ } else {
+ BEGIN_LP_RING(6);
+ OUT_RING(GFX_OP_DRAWRECT_INFO);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16));
+ OUT_RING(0);
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+ }
+
+ sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
+
+ init_drawrect = 0;
+ }
+
rect = drw->rects;
- pipe = swap_hit->pipe;
- top = upper[pipe];
- bottom = lower[pipe];
+ top = upper[plane];
+ bottom = lower[plane];
+
+ front = (dev_priv->sarea_priv->pf_current_page >>
+ (2 * plane)) & 0x3;
+ back = (front + 1) % num_pages;
for (num_rects = drw->num_rects; num_rects--; rect++) {
int y1 = max(rect->y1, top);
@@ -189,22 +363,20 @@ static void i915_vblank_tasklet(drm_device_t *dev)
continue;
BEGIN_LP_RING(8);
-
OUT_RING(cmd);
- OUT_RING(pitchropcpp);
+ OUT_RING(ropcpp | dst_pitch);
OUT_RING((y1 << 16) | rect->x1);
OUT_RING((y2 << 16) | rect->x2);
- OUT_RING(sarea_priv->front_offset);
+ OUT_RING(offsets[front]);
OUT_RING((y1 << 16) | rect->x1);
- OUT_RING(pitchropcpp & 0xffff);
- OUT_RING(sarea_priv->back_offset);
-
+ OUT_RING(src_pitch);
+ OUT_RING(offsets[back]);
ADVANCE_LP_RING();
}
}
}
- spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ DRM_SPINUNLOCK(&dev->drw_lock);
list_for_each_safe(hit, tmp, &hits) {
drm_i915_vbl_swap_t *swap_hit =
@@ -216,66 +388,119 @@ static void i915_vblank_tasklet(drm_device_t *dev)
}
}
-irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
+u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
{
- drm_device_t *dev = (drm_device_t *) (void *)arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u16 temp;
- u32 pipea_stats, pipeb_stats;
+ unsigned long high_frame;
+ unsigned long low_frame;
+ u32 high1, high2, low, count;
+ int pipe;
+
+ pipe = i915_get_pipe(dev, plane);
+ high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+ low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+
+ if (!i915_pipe_enabled(dev, pipe)) {
+ DRM_DEBUG("trying to get vblank count for disabled pipe %d\n", pipe);
+ return 0;
+ }
- pipea_stats = I915_READ(I915REG_PIPEASTAT);
- pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
-
- temp = I915_READ16(I915REG_INT_IDENTITY_R);
- temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG);
+ /*
+ * High & low register fields aren't synchronized, so make sure
+ * we get a low value that's stable across two reads of the high
+ * register.
+ */
+ do {
+ high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+ PIPE_FRAME_HIGH_SHIFT);
+ low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
+ PIPE_FRAME_LOW_SHIFT);
+ high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+ PIPE_FRAME_HIGH_SHIFT);
+ } while (high1 != high2);
+
+ count = (high1 << 8) | low;
+
+ /* count may be reset by other driver(e.g. 2D driver),
+ we have no way to know if it is wrapped or resetted
+ when count is zero. do a rough guess.
+ */
+ if (count < dev->last_vblank[pipe] && dev->last_vblank[pipe] < dev->max_vblank_count/2)
+ dev->last_vblank[pipe]=0;
+ return count;
+}
-#if 0
- DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
-#endif
- if (temp == 0)
- return IRQ_NONE;
+irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
+{
+ drm_device_t *dev = (drm_device_t *) (void *) arg;
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 iir;
+ u32 pipea_stats = 0, pipeb_stats = 0;
+ int vblank = 0;
+ iir = I915_READ(IIR);
+
+ atomic_inc(&dev_priv->irq_received);
- I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+ if (iir == 0) {
+ return IRQ_NONE;
+ }
- dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+ if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
+ pipea_stats = I915_READ(PIPEASTAT);
+
+ /* The vblank interrupt gets enabled even if we didn't ask for
+ it, so make sure it's shut down again */
+ if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A))
+ pipea_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
+ PIPE_VBLANK_INTERRUPT_ENABLE);
+ else if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
+ PIPE_VBLANK_INTERRUPT_STATUS))
+ {
+ vblank++;
+ drm_handle_vblank(dev, i915_get_plane(dev, 0));
+ }
- if (temp & USER_INT_FLAG) {
- DRM_WAKEUP(&dev_priv->irq_queue);
-#ifdef I915_HAVE_FENCE
- i915_fence_handler(dev);
-#endif
+ I915_WRITE(PIPEASTAT, pipea_stats);
}
+ if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
+ pipeb_stats = I915_READ(PIPEBSTAT);
+
+ /* The vblank interrupt gets enabled even if we didn't ask for
+ it, so make sure it's shut down again */
+ if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B))
+ pipeb_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
+ PIPE_VBLANK_INTERRUPT_ENABLE);
+ else if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
+ PIPE_VBLANK_INTERRUPT_STATUS))
+ {
+ vblank++;
+ drm_handle_vblank(dev, i915_get_plane(dev, 1));
+ }
+
+ I915_WRITE(PIPEBSTAT, pipeb_stats);
+ }
+
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
- int vblank_pipe = dev_priv->vblank_pipe;
+ I915_WRITE(IIR, iir);
- if ((vblank_pipe &
- (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
- == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
- if (temp & VSYNC_PIPEA_FLAG)
- atomic_inc(&dev->vbl_received);
- if (temp & VSYNC_PIPEB_FLAG)
- atomic_inc(&dev->vbl_received2);
- } else if (((temp & VSYNC_PIPEA_FLAG) &&
- (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
- ((temp & VSYNC_PIPEB_FLAG) &&
- (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
- atomic_inc(&dev->vbl_received);
+ (void) I915_READ(IIR); /* Flush posted writes */
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
+ if (iir & I915_USER_INTERRUPT) {
+ DRM_WAKEUP(&dev_priv->irq_queue);
+#ifdef I915_HAVE_FENCE
+ i915_fence_handler(dev);
+#endif
+ }
+ if (vblank) {
if (dev_priv->swaps_pending > 0)
drm_locked_tasklet(dev, i915_vblank_tasklet);
- I915_WRITE(I915REG_PIPEASTAT,
- pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
- I915_VBLANK_CLEAR);
- I915_WRITE(I915REG_PIPEBSTAT,
- pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
- I915_VBLANK_CLEAR);
}
return IRQ_HANDLED;
+
}
int i915_emit_irq(drm_device_t * dev)
@@ -286,34 +511,21 @@ int i915_emit_irq(drm_device_t * dev)
i915_kernel_lost_context(dev);
- DRM_DEBUG("%s\n", __FUNCTION__);
-
- dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
-
- if (dev_priv->counter > 0x7FFFFFFFUL)
- dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
-
- BEGIN_LP_RING(6);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(BREADCRUMB_OFFSET << 2);
- OUT_RING(dev_priv->counter);
+ i915_emit_breadcrumb(dev);
+ BEGIN_LP_RING(2);
OUT_RING(0);
- OUT_RING(0);
- OUT_RING(GFX_OP_USER_INTERRUPT);
+ OUT_RING(MI_USER_INTERRUPT);
ADVANCE_LP_RING();
return dev_priv->counter;
-
-
}
void i915_user_irq_on(drm_i915_private_t *dev_priv)
{
spin_lock(&dev_priv->user_irq_lock);
if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){
- dev_priv->irq_enable_reg |= USER_INT_FLAG;
- I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+ i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
}
spin_unlock(&dev_priv->user_irq_lock);
@@ -323,9 +535,7 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv)
{
spin_lock(&dev_priv->user_irq_lock);
if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
- /*EMPTY*/;
- // dev_priv->irq_enable_reg &= ~USER_INT_FLAG;
- // I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+ i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
}
spin_unlock(&dev_priv->user_irq_lock);
}
@@ -336,59 +546,41 @@ static int i915_wait_irq(drm_device_t * dev, int irq_nr)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = 0;
- DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr,
- READ_BREADCRUMB(dev_priv));
- if (READ_BREADCRUMB(dev_priv) >= irq_nr)
- return 0;
- dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+ if (!dev_priv) {
+ DRM_ERROR("called with no initialization\n");
+ return -EINVAL;
+ }
+
+
+
+
+ if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_dispatch =
+ READ_BREADCRUMB(dev_priv);
+ return 0;
+ }
+ DRM_DEBUG("i915_wait_irq: irq_nr=%d breadcrumb=%d\n", irq_nr, READ_BREADCRUMB(dev_priv));
i915_user_irq_on(dev_priv);
DRM_WAIT_ON(ret, &dev_priv->irq_queue, 3 * DRM_HZ,
READ_BREADCRUMB(dev_priv) >= irq_nr);
i915_user_irq_off(dev_priv);
- if (ret == EBUSY) {
- DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n",
- __FUNCTION__,
+ if (ret == EBUSY || ret == EINTR) {
+ DRM_DEBUG("%d: EBUSY -- rec: %d emitted: %d\n",
+ ret,
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
}
- dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- return ret;
-}
-
-static int i915_driver_vblank_do_wait(drm_device_t *dev, unsigned int *sequence,
- atomic_t *counter)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- unsigned int cur_vblank;
- int ret = 0;
-
- if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return (EINVAL);
- }
-
- DRM_WAIT_ON(ret, &dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(counter))
- - *sequence) <= (1<<23)));
-
- *sequence = cur_vblank;
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
return ret;
}
-int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
-{
- return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
-}
-
-int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence)
-{
- return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
-}
/* Needs the lock as it touches the ring.
*/
@@ -448,77 +640,365 @@ int i915_irq_wait(DRM_IOCTL_ARGS)
return i915_wait_irq(dev, irqwait.irq_seq);
}
+int i915_enable_vblank(struct drm_device *dev, int plane)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe = i915_get_pipe(dev, plane);
+ u32 pipestat_reg = 0;
+ u32 mask_reg = 0;
+ u32 pipestat;
+
+ switch (pipe) {
+ case 0:
+ pipestat_reg = PIPEASTAT;
+ mask_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+ break;
+ case 1:
+ pipestat_reg = PIPEBSTAT;
+ mask_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+ break;
+ default:
+ DRM_ERROR("tried to enable vblank on non-existent pipe %d\n",
+ pipe);
+ break;
+ }
+
+ if (pipestat_reg)
+ {
+ pipestat = I915_READ (pipestat_reg);
+ /*
+ * Older chips didn't have the start vblank interrupt,
+ * but
+ */
+ if (IS_I965G (dev))
+ pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE;
+ else
+ pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE;
+ /*
+ * Clear any pending status
+ */
+ pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
+ PIPE_VBLANK_INTERRUPT_STATUS);
+ I915_WRITE(pipestat_reg, pipestat);
+ }
+ DRM_SPINLOCK(&dev_priv->user_irq_lock);
+ i915_enable_irq(dev_priv, mask_reg);
+ DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
+
+ return 0;
+}
+
+void i915_disable_vblank(struct drm_device *dev, int plane)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe = i915_get_pipe(dev, plane);
+ u32 pipestat_reg = 0;
+ u32 mask_reg = 0;
+ u32 pipestat;
+
+ switch (pipe) {
+ case 0:
+ pipestat_reg = PIPEASTAT;
+ mask_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+ break;
+ case 1:
+ pipestat_reg = PIPEBSTAT;
+ mask_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+ break;
+ default:
+ DRM_ERROR("tried to disable vblank on non-existent pipe %d\n",
+ pipe);
+ break;
+ }
+
+ DRM_SPINLOCK(&dev_priv->user_irq_lock);
+ i915_disable_irq(dev_priv, mask_reg);
+ DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
+
+ if (pipestat_reg)
+ {
+ pipestat = I915_READ (pipestat_reg);
+ pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
+ PIPE_VBLANK_INTERRUPT_ENABLE);
+ /*
+ * Clear any pending status
+ */
+ pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
+ PIPE_VBLANK_INTERRUPT_STATUS);
+ I915_WRITE(pipestat_reg, pipestat);
+ (void) I915_READ(pipestat_reg);
+ }
+}
+
+
static void i915_enable_interrupt (drm_device_t *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-
- dev_priv->irq_enable_reg = USER_INT_FLAG;
- if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
- dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG;
- if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
- dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG;
- I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+ dev_priv->irq_mask_reg = 0xffffffff;
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
+ (void) I915_READ (IER);
+
dev_priv->irq_enabled = 1;
}
+/* Set the vblank monitor pipe
+ */
+/*ARGSUSED*/
+int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ if (!dev_priv) {
+ DRM_ERROR("called with no initialization\n");
+ return (-EINVAL);
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_vblank_pipe_t pipe;
+
+ if (!dev_priv) {
+ DRM_ERROR("called with no initialization\n");
+ return -EINVAL;
+ }
+
+
+ DRM_COPYFROM_WITH_RETURN(&pipe, (drm_i915_vblank_pipe_t __user *)data, sizeof (pipe));
+
+ pipe.pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
+
+ return 0;
+}
+
+/**
+ * Schedule buffer swap at given vertical blank.
+ */
+/*ARGSUSED*/
+int i915_vblank_swap(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_vblank_swap_t *swap;
+ drm_i915_vbl_swap_t *vbl_swap;
+ unsigned int pipe, seqtype, curseq, plane;
+ struct list_head *list;
+ int ret;
+
+ if (!dev_priv) {
+ DRM_ERROR("%s called with no initialization\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) {
+ DRM_DEBUG("Rotation not supported\n");
+ return -EINVAL;
+ }
+
+ DRM_COPYFROM_WITH_RETURN(&swap, (drm_i915_vblank_swap_t __user *)data, sizeof (swap));
+
+ if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
+ _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS |
+ _DRM_VBLANK_FLIP)) {
+ DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype);
+ return -EINVAL;
+ }
+
+ plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
+ pipe = i915_get_pipe(dev, plane);
+
+ seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
+
+ if (!(dev_priv->vblank_pipe & (1 << pipe))) {
+ DRM_ERROR("Invalid pipe %d\n", pipe);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ /* It makes no sense to schedule a swap for a drawable that doesn't have
+ * valid information at this point. E.g. this could mean that the X
+ * server is too old to push drawable information to the DRM, in which
+ * case all such swaps would become ineffective.
+ */
+ if (!drm_get_drawable_info(dev, swap->drawable)) {
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable);
+ return -EINVAL;
+ }
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ /*
+ * We take the ref here and put it when the swap actually completes
+ * in the tasklet.
+ */
+ ret = drm_vblank_get(dev, pipe);
+ if (ret)
+ return ret;
+ curseq = drm_vblank_count(dev, pipe);
+
+ if (seqtype == _DRM_VBLANK_RELATIVE)
+ swap->sequence += curseq;
+
+ if ((curseq - swap->sequence) <= (1<<23)) {
+ if (swap->seqtype & _DRM_VBLANK_NEXTONMISS) {
+ swap->sequence = curseq + 1;
+ } else {
+ DRM_DEBUG("Missed target sequence\n");
+ drm_vblank_put(dev, pipe);
+ return -EINVAL;
+ }
+ }
+
+ if (swap->seqtype & _DRM_VBLANK_FLIP) {
+ swap->sequence--;
+
+ if ((curseq - swap->sequence) <= (1<<23)) {
+ struct drm_drawable_info *drw;
+
+ LOCK_TEST_WITH_RETURN(dev, fpriv);
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ drw = drm_get_drawable_info(dev, swap->drawable);
+
+ if (!drw) {
+ spin_unlock_irqrestore(&dev->drw_lock,
+ irqflags);
+ DRM_DEBUG("Invalid drawable ID %d\n",
+ swap->drawable);
+ drm_vblank_put(dev, pipe);
+ return -EINVAL;
+ }
+
+ i915_dispatch_vsync_flip(dev, drw, plane);
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ drm_vblank_put(dev, pipe);
+ return 0;
+ }
+ }
+
+ spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+ list_for_each(list, &dev_priv->vbl_swaps.head) {
+ vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
+
+ if (vbl_swap->drw_id == swap->drawable &&
+ vbl_swap->plane == plane &&
+ vbl_swap->sequence == swap->sequence) {
+ vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP);
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+ DRM_DEBUG("Already scheduled\n");
+ return 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+
+ if (dev_priv->swaps_pending >= 100) {
+ DRM_DEBUG("Too many swaps queued\n");
+ drm_vblank_put(dev, pipe);
+ return -EBUSY;
+ }
+
+ vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER);
+
+ if (!vbl_swap) {
+ DRM_ERROR("Failed to allocate memory to queue swap\n");
+ drm_vblank_put(dev, pipe);
+ return -ENOMEM;
+ }
+
+ DRM_DEBUG("vbl_swap\n");
+
+ vbl_swap->drw_id = swap->drawable;
+ vbl_swap->plane = plane;
+ vbl_swap->sequence = swap->sequence;
+ vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP);
+
+ if (vbl_swap->flip)
+ swap->sequence++;
+
+ spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+ list_add_tail(&vbl_swap->head, &dev_priv->vbl_swaps.head);
+ dev_priv->swaps_pending++;
+
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+
+ return 0;
+}
+
/* drm_dma.h hooks
*/
void i915_driver_irq_preinstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- I915_WRITE16(I915REG_HWSTAM, 0xeffe);
- I915_WRITE16(I915REG_INT_MASK_R, 0x0);
- I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+ I915_WRITE(HWSTAM, 0xeffe);
+ I915_WRITE(IMR, 0xffffffff);
+ I915_WRITE(IER, 0x0);
}
void i915_driver_irq_postinstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int ret, num_pipes=2;
- mutex_init(&dev_priv->swaps_lock, NULL, MUTEX_DRIVER, NULL);
INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
dev_priv->swaps_pending = 0;
- if (!dev_priv->vblank_pipe)
- dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
-
- mutex_init(&dev_priv->user_irq_lock, NULL, MUTEX_DRIVER, NULL);
dev_priv->user_irq_refcount = 0;
+ dev_priv->irq_mask_reg = 0xffffffff;
- if (!dev_priv->vblank_pipe)
- dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
-
- DRM_INIT_WAITQUEUE(&dev_priv->irq_queue, DRM_INTR_PRI(dev));
+ ret = drm_vblank_init(dev, num_pipes);
+ if (ret)
+ return;
+ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
+ dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
i915_enable_interrupt(dev);
+ DRM_INIT_WAITQUEUE(&dev_priv->irq_queue, DRM_INTR_PRI(dev));
/*
* Initialize the hardware status page IRQ location.
*/
- I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21));
+ I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
+ return;
}
void i915_driver_irq_uninstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u16 temp;
+ u32 temp;
if (!dev_priv)
return;
+ dev_priv->vblank_pipe = 0;
dev_priv->irq_enabled = 0;
- I915_WRITE16(I915REG_HWSTAM, 0xffff);
- I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
- I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
- temp = I915_READ16(I915REG_INT_IDENTITY_R);
- I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+ I915_WRITE(HWSTAM, 0xffffffff);
+ I915_WRITE(IMR, 0xffffffff);
+ I915_WRITE(IER, 0x0);
- DRM_FINI_WAITQUEUE(&dev_priv->irq_queue);
- mutex_destroy(&dev_priv->swaps_lock);
- mutex_destroy(&dev_priv->user_irq_lock);
+ temp = I915_READ(PIPEASTAT);
+ I915_WRITE(PIPEASTAT, temp);
+ temp = I915_READ(PIPEBSTAT);
+ I915_WRITE(PIPEBSTAT, temp);
+ temp = I915_READ(IIR);
+ I915_WRITE(IIR, temp);
}