summaryrefslogtreecommitdiff
path: root/shared-core/i915_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared-core/i915_irq.c')
-rw-r--r--shared-core/i915_irq.c464
1 files changed, 341 insertions, 123 deletions
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 0125f8b3..bd11d37a 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -30,6 +30,8 @@
#include "drm.h"
#include "i915_drm.h"
#include "i915_drv.h"
+#include "intel_drv.h"
+#include "drm_crtc_helper.h"
#define MAX_NOPID ((u32)~0)
@@ -45,7 +47,7 @@
static int
i915_get_pipe(struct drm_device *dev, int plane)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
u32 dspcntr;
dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR);
@@ -82,7 +84,7 @@ i915_get_plane(struct drm_device *dev, int pipe)
static int
i915_pipe_enabled(struct drm_device *dev, int pipe)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
@@ -100,8 +102,8 @@ 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;
+ struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+ struct drm_i915_sarea *sarea_priv = master_priv->sarea_priv;
u16 x1, y1, x2, y2;
int pf_planes = 1 << plane;
@@ -145,12 +147,13 @@ i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw,
*/
static void i915_vblank_tasklet(struct drm_device *dev)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+ struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
struct list_head *list, *tmp, hits, *hit;
int nhits, nrects, 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;
+ struct drm_i915_sarea *sarea_priv = master_priv->sarea_priv;
u32 cpp = dev_priv->cpp, offsets[3];
u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
XY_SRC_COPY_BLT_WRITE_ALPHA |
@@ -189,13 +192,16 @@ static void i915_vblank_tasklet(struct drm_device *dev)
/* 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);
+ struct drm_i915_vbl_swap *vbl_swap =
+ list_entry(list, struct drm_i915_vbl_swap, head);
int pipe = i915_get_pipe(dev, vbl_swap->plane);
if ((counter[pipe] - vbl_swap->sequence) > (1<<23))
continue;
+ master_priv = vbl_swap->minor->master->driver_priv;
+ sarea_priv = master_priv->sarea_priv;
+
list_del(list);
dev_priv->swaps_pending--;
drm_vblank_put(dev, pipe);
@@ -213,8 +219,8 @@ static void i915_vblank_tasklet(struct drm_device *dev)
}
list_for_each(hit, &hits) {
- drm_i915_vbl_swap_t *swap_cmp =
- list_entry(hit, drm_i915_vbl_swap_t, head);
+ struct drm_i915_vbl_swap *swap_cmp =
+ list_entry(hit, struct drm_i915_vbl_swap, head);
struct drm_drawable_info *drw_cmp =
drm_get_drawable_info(dev, swap_cmp->drw_id);
@@ -271,8 +277,8 @@ static void i915_vblank_tasklet(struct drm_device *dev)
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);
+ struct drm_i915_vbl_swap *swap_hit =
+ list_entry(hit, struct drm_i915_vbl_swap, head);
struct drm_clip_rect *rect;
int num_rects, plane, front, back;
unsigned short top, bottom;
@@ -323,7 +329,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
top = upper[plane];
bottom = lower[plane];
- front = (dev_priv->sarea_priv->pf_current_page >>
+ front = (master_priv->sarea_priv->pf_current_page >>
(2 * plane)) & 0x3;
back = (front + 1) % num_pages;
@@ -353,8 +359,8 @@ static void i915_vblank_tasklet(struct drm_device *dev)
DRM_SPINUNLOCK(&dev->drw_lock);
list_for_each_safe(hit, tmp, &hits) {
- drm_i915_vbl_swap_t *swap_hit =
- list_entry(hit, drm_i915_vbl_swap_t, head);
+ struct drm_i915_vbl_swap *swap_hit =
+ list_entry(hit, struct drm_i915_vbl_swap, head);
list_del(hit);
@@ -364,7 +370,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
#if 0
static int i915_in_vblank(struct drm_device *dev, int pipe)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
unsigned long pipedsl, vblank, vtotal;
unsigned long vbl_start, vbl_end, cur_line;
@@ -385,7 +391,7 @@ static int i915_in_vblank(struct drm_device *dev, int pipe)
#endif
u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
unsigned long high_frame;
unsigned long low_frame;
u32 high1, high2, low, count;
@@ -435,6 +441,8 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
return count;
}
+static struct drm_device *hotplug_dev;
+
/**
* Handler for user interrupts in process context (able to sleep, do VFS
* operations, etc.
@@ -442,13 +450,56 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
* If another IRQ comes in while we're in this handler, it will still get put
* on the queue again to be rerun when we finish.
*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void i915_hotplug_work_func(void *work)
+#else
+static void i915_hotplug_work_func(struct work_struct *work)
+#endif
+{
+ struct drm_device *dev = hotplug_dev;
+
+ drm_helper_hotplug_stage_two(dev);
+ drm_handle_hotplug(dev);
+}
+
+static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ static DECLARE_WORK(hotplug, i915_hotplug_work_func, NULL);
+#else
+ static DECLARE_WORK(hotplug, i915_hotplug_work_func);
+#endif
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ hotplug_dev = dev;
+
+ if (stat & TV_HOTPLUG_INT_STATUS) {
+ DRM_DEBUG("TV event\n");
+ }
+
+ if (stat & CRT_HOTPLUG_INT_STATUS) {
+ DRM_DEBUG("CRT event\n");
+ }
+
+ if (stat & SDVOB_HOTPLUG_INT_STATUS) {
+ DRM_DEBUG("sDVOB event\n");
+ }
+
+ if (stat & SDVOC_HOTPLUG_INT_STATUS) {
+ DRM_DEBUG("sDVOC event\n");
+ }
+ queue_work(dev_priv->wq, &hotplug);
+
+ return 0;
+}
+
void
i915_user_interrupt_handler(struct work_struct *work)
{
- drm_i915_private_t *dev_priv;
+ struct drm_i915_private *dev_priv;
struct drm_device *dev;
- dev_priv = container_of(work, drm_i915_private_t,
+ dev_priv = container_of(work, struct drm_i915_private,
user_interrupt_task);
dev = dev_priv->dev;
@@ -460,22 +511,33 @@ i915_user_interrupt_handler(struct work_struct *work)
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_master_private *master_priv;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
u32 iir;
- u32 pipea_stats, pipeb_stats;
+ u32 pipea_stats = 0, pipeb_stats, tvdac;
+ int hotplug = 0;
int vblank = 0;
- iir = I915_READ(I915REG_INT_IDENTITY_R);
+ /* On i8xx/i915 hw the IIR and IER are 16bit on i9xx its 32bit */
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev))
+ iir = I915_READ(IIR);
+ else
+ iir = I915_READ16(IIR);
+
+ iir &= (dev_priv->irq_mask_reg | I915_USER_INTERRUPT);
+
#if 0
DRM_DEBUG("flag=%08x\n", iir);
#endif
if (iir == 0) {
+#if 0
DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n",
iir,
- I915_READ(I915REG_INT_MASK_R),
- I915_READ(I915REG_INT_ENABLE_R),
- I915_READ(I915REG_PIPEASTAT),
- I915_READ(I915REG_PIPEBSTAT));
+ I915_READ(IMR),
+ I915_READ(IER),
+ I915_READ(PIPEASTAT),
+ I915_READ(PIPEBSTAT));
+#endif
return IRQ_NONE;
}
@@ -484,31 +546,53 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
* we may get extra interrupts.
*/
if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
- pipea_stats = I915_READ(I915REG_PIPEASTAT);
- if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS|
- I915_VBLANK_INTERRUPT_STATUS))
+ pipea_stats = I915_READ(PIPEASTAT);
+ if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
+ PIPE_VBLANK_INTERRUPT_STATUS))
{
vblank++;
drm_handle_vblank(dev, i915_get_plane(dev, 0));
}
- I915_WRITE(I915REG_PIPEASTAT, pipea_stats);
+
+ /* This is a global event, and not a pipe A event */
+ if (pipea_stats & PIPE_HOTPLUG_INTERRUPT_STATUS)
+ hotplug = 1;
+
+ if (pipea_stats & PIPE_HOTPLUG_TV_INTERRUPT_STATUS) {
+ hotplug = 1;
+ /* Toggle hotplug detection to clear hotplug status */
+ tvdac = I915_READ(TV_DAC);
+ I915_WRITE(TV_DAC, tvdac & ~TVDAC_STATE_CHG_EN);
+ I915_WRITE(TV_DAC, tvdac | TVDAC_STATE_CHG_EN);
+ }
+
+ I915_WRITE(PIPEASTAT, pipea_stats);
}
+
if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
- pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
- if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS|
- I915_VBLANK_INTERRUPT_STATUS))
+ pipeb_stats = I915_READ(PIPEBSTAT);
+ if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
+ PIPE_VBLANK_INTERRUPT_STATUS))
{
vblank++;
drm_handle_vblank(dev, i915_get_plane(dev, 1));
}
- I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats);
+ I915_WRITE(PIPEBSTAT, pipeb_stats);
}
- if (dev_priv->sarea_priv)
- dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+ /* Clear the generated interrupt */
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
+ I915_WRITE(IIR, iir);
+ (void) I915_READ(IIR);
+ } else {
+ I915_WRITE16(IIR, iir);
+ (void) I915_READ16(IIR);
+ }
- I915_WRITE(I915REG_INT_IDENTITY_R, iir | I915_USER_INTERRUPT);
- (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted write */
+ if (dev->primary->master) {
+ master_priv = dev->primary->master->driver_priv;
+ master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+ }
if (iir & I915_USER_INTERRUPT) {
DRM_WAKEUP(&dev_priv->irq_queue);
@@ -523,12 +607,31 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
drm_locked_tasklet(dev, i915_vblank_tasklet);
}
+ if ((iir & I915_DISPLAY_PORT_INTERRUPT) || hotplug) {
+ u32 temp2 = 0;
+
+ DRM_INFO("Hotplug event received\n");
+
+ if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev)) {
+ if (pipea_stats & PIPE_HOTPLUG_INTERRUPT_STATUS)
+ temp2 |= SDVOB_HOTPLUG_INT_STATUS |
+ SDVOC_HOTPLUG_INT_STATUS;
+ if (pipea_stats & PIPE_HOTPLUG_TV_INTERRUPT_STATUS)
+ temp2 |= TV_HOTPLUG_INT_STATUS;
+ } else {
+ temp2 = I915_READ(PORT_HOTPLUG_STAT);
+
+ I915_WRITE(PORT_HOTPLUG_STAT, temp2);
+ }
+ i915_run_hotplug_tasklet(dev, temp2);
+ }
+
return IRQ_HANDLED;
}
int i915_emit_irq(struct drm_device *dev)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
RING_LOCALS;
i915_kernel_lost_context(dev);
@@ -539,32 +642,42 @@ int i915_emit_irq(struct drm_device *dev)
BEGIN_LP_RING(2);
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)
+void i915_user_irq_on(struct drm_device *dev)
{
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+
DRM_SPINLOCK(&dev_priv->user_irq_lock);
if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){
dev_priv->irq_mask_reg &= ~I915_USER_INTERRUPT;
- I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg);
- (void) I915_READ (I915REG_INT_ENABLE_R);
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev))
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ else
+ I915_WRITE16(IMR, dev_priv->irq_mask_reg);
+ I915_READ16(IMR);
}
DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
}
-
-void i915_user_irq_off(drm_i915_private_t *dev_priv)
+
+void i915_user_irq_off(struct drm_device *dev)
{
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+
DRM_SPINLOCK(&dev_priv->user_irq_lock);
BUG_ON(dev_priv->irq_enabled && dev_priv->user_irq_refcount <= 0);
if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
dev_priv->irq_mask_reg |= I915_USER_INTERRUPT;
- I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg);
- (void) I915_READ(I915REG_INT_MASK_R);
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev))
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ else
+ I915_WRITE16(IMR, dev_priv->irq_mask_reg);
+ I915_READ16(IMR);
}
DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
}
@@ -572,7 +685,8 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv)
int i915_wait_irq(struct drm_device * dev, int irq_nr)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+ struct drm_i915_master_private *master_priv;
int ret = 0;
if (!dev_priv) {
@@ -586,19 +700,21 @@ int i915_wait_irq(struct drm_device * dev, int irq_nr)
if (READ_BREADCRUMB(dev_priv) >= irq_nr)
return 0;
- i915_user_irq_on(dev_priv);
+ i915_user_irq_on(dev);
DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
READ_BREADCRUMB(dev_priv) >= irq_nr);
- i915_user_irq_off(dev_priv);
+ i915_user_irq_off(dev);
if (ret == -EBUSY) {
DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
}
+
+ if (dev->primary->master) {
+ master_priv = dev->primary->master->driver_priv;
+ master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+ }
- if (dev_priv->sarea_priv)
- dev_priv->sarea_priv->last_dispatch =
- READ_BREADCRUMB(dev_priv);
return ret;
}
@@ -607,8 +723,8 @@ int i915_wait_irq(struct drm_device * dev, int irq_nr)
int i915_irq_emit(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_irq_emit_t *emit = data;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_irq_emit *emit = data;
int result;
LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -633,8 +749,8 @@ int i915_irq_emit(struct drm_device *dev, void *data,
int i915_irq_wait(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_irq_wait_t *irqwait = data;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_irq_wait *irqwait = data;
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
@@ -646,7 +762,7 @@ int i915_irq_wait(struct drm_device *dev, void *data,
int i915_enable_vblank(struct drm_device *dev, int plane)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
int pipe = i915_get_pipe(dev, plane);
u32 pipestat_reg = 0;
u32 mask_reg = 0;
@@ -654,11 +770,11 @@ int i915_enable_vblank(struct drm_device *dev, int plane)
switch (pipe) {
case 0:
- pipestat_reg = I915REG_PIPEASTAT;
+ pipestat_reg = PIPEASTAT;
mask_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
break;
case 1:
- pipestat_reg = I915REG_PIPEBSTAT;
+ pipestat_reg = PIPEBSTAT;
mask_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
break;
default:
@@ -675,20 +791,23 @@ int i915_enable_vblank(struct drm_device *dev, int plane)
* but
*/
if (IS_I965G (dev))
- pipestat |= I915_START_VBLANK_INTERRUPT_ENABLE;
+ pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE;
else
- pipestat |= I915_VBLANK_INTERRUPT_ENABLE;
+ pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE;
/*
* Clear any pending status
*/
- pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS |
- I915_VBLANK_INTERRUPT_STATUS);
+ pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
+ PIPE_VBLANK_INTERRUPT_STATUS);
I915_WRITE(pipestat_reg, pipestat);
}
+
DRM_SPINLOCK(&dev_priv->user_irq_lock);
dev_priv->irq_mask_reg &= ~mask_reg;
- I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg);
- I915_READ(I915REG_INT_MASK_R);
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev))
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ else
+ I915_WRITE16(IMR, dev_priv->irq_mask_reg);
DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
return 0;
@@ -696,7 +815,7 @@ int i915_enable_vblank(struct drm_device *dev, int plane)
void i915_disable_vblank(struct drm_device *dev, int plane)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
int pipe = i915_get_pipe(dev, plane);
u32 pipestat_reg = 0;
u32 mask_reg = 0;
@@ -704,11 +823,11 @@ void i915_disable_vblank(struct drm_device *dev, int plane)
switch (pipe) {
case 0:
- pipestat_reg = I915REG_PIPEASTAT;
+ pipestat_reg = PIPEASTAT;
mask_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
break;
case 1:
- pipestat_reg = I915REG_PIPEBSTAT;
+ pipestat_reg = PIPEBSTAT;
mask_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
break;
default:
@@ -719,47 +838,102 @@ void i915_disable_vblank(struct drm_device *dev, int plane)
DRM_SPINLOCK(&dev_priv->user_irq_lock);
dev_priv->irq_mask_reg |= mask_reg;
- I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg);
- (void) I915_READ (I915REG_INT_MASK_R);
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev))
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ else
+ I915_WRITE16(IMR, dev_priv->irq_mask_reg);
DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
- if (pipestat_reg)
- {
+
+ if (pipestat_reg) {
pipestat = I915_READ (pipestat_reg);
- pipestat &= ~(I915_START_VBLANK_INTERRUPT_ENABLE |
- I915_VBLANK_INTERRUPT_ENABLE);
+ pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
+ PIPE_VBLANK_INTERRUPT_ENABLE);
/*
* Clear any pending status
*/
- pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS |
- I915_VBLANK_INTERRUPT_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 (struct drm_device *dev)
+void i915_enable_interrupt (struct drm_device *dev)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-
- dev_priv->irq_mask_reg = (I915_USER_INTERRUPT |
- I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
- I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
- I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg);
- I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_mask_reg);
- (void) I915_READ (I915REG_INT_ENABLE_R);
- dev_priv->irq_enabled = 1;
-}
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+ struct drm_connector *o;
-static void i915_disable_interrupt (struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-
- I915_WRITE(I915REG_HWSTAM, 0xffffffff);
- I915_WRITE(I915REG_INT_MASK_R, 0xffffffff);
- I915_WRITE(I915REG_INT_ENABLE_R, 0);
- I915_WRITE(I915REG_INT_IDENTITY_R, 0xffffffff);
- (void) I915_READ (I915REG_INT_IDENTITY_R);
- dev_priv->irq_enabled = 0;
+ dev_priv->irq_mask_reg &= ~I915_USER_INTERRUPT;
+
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
+ if (dev->mode_config.num_connector)
+ dev_priv->irq_mask_reg &= ~I915_DISPLAY_PORT_INTERRUPT;
+ } else {
+ if (dev->mode_config.num_connector)
+ dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+
+ /* Enable global interrupts for hotplug - not a pipeA event */
+ I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) |
+ PIPE_HOTPLUG_INTERRUPT_ENABLE |
+ PIPE_HOTPLUG_TV_INTERRUPT_ENABLE |
+ PIPE_HOTPLUG_TV_INTERRUPT_STATUS |
+ PIPE_HOTPLUG_INTERRUPT_STATUS);
+ }
+
+ if (!(dev_priv->irq_mask_reg & I915_DISPLAY_PORT_INTERRUPT) ||
+ !(dev_priv->irq_mask_reg & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)) {
+ u32 temp = 0;
+
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
+ temp = I915_READ(PORT_HOTPLUG_EN);
+
+ /* Activate the CRT */
+ temp |= CRT_HOTPLUG_INT_EN;
+ }
+
+ if (IS_I9XX(dev)) {
+ /* SDVOB */
+ o = intel_sdvo_find(dev, 1);
+ if (o && intel_sdvo_supports_hotplug(o)) {
+ intel_sdvo_set_hotplug(o, 1);
+ temp |= SDVOB_HOTPLUG_INT_EN;
+ }
+
+ /* SDVOC */
+ o = intel_sdvo_find(dev, 0);
+ if (o && intel_sdvo_supports_hotplug(o)) {
+ intel_sdvo_set_hotplug(o, 1);
+ temp |= SDVOC_HOTPLUG_INT_EN;
+ }
+
+ I915_WRITE(SDVOB, I915_READ(SDVOB) | SDVO_INTERRUPT_ENABLE);
+ I915_WRITE(SDVOC, I915_READ(SDVOC) | SDVO_INTERRUPT_ENABLE);
+
+ /* TV */
+ I915_WRITE(TV_DAC, I915_READ(TV_DAC) | TVDAC_STATE_CHG_EN);
+ } else {
+ /* DVO ???? */
+ }
+
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
+ I915_WRITE(PORT_HOTPLUG_EN, temp);
+
+ DRM_DEBUG("HEN %08x\n",I915_READ(PORT_HOTPLUG_EN));
+ DRM_DEBUG("HST %08x\n",I915_READ(PORT_HOTPLUG_STAT));
+
+ I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
+ }
+ }
+
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ I915_WRITE(IER, ~dev_priv->irq_mask_reg);
+ } else {
+ I915_WRITE16(IMR, dev_priv->irq_mask_reg);
+ I915_WRITE16(IER, ~(u16)dev_priv->irq_mask_reg);
+ }
+
+ dev_priv->irq_enabled = 1;
}
/* Set the vblank monitor pipe
@@ -767,8 +941,8 @@ static void i915_disable_interrupt (struct drm_device *dev)
int i915_vblank_pipe_set(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_vblank_pipe_t *pipe = data;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_vblank_pipe *pipe = data;
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
@@ -788,8 +962,8 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data,
int i915_vblank_pipe_get(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_vblank_pipe_t *pipe = data;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_vblank_pipe *pipe = data;
u16 flag;
if (!dev_priv) {
@@ -797,7 +971,11 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data,
return -EINVAL;
}
- flag = I915_READ(I915REG_INT_ENABLE_R);
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev))
+ flag = I915_READ(IER);
+ else
+ flag = I915_READ16(IER);
+
pipe->pipe = 0;
if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)
pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
@@ -813,9 +991,10 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data,
int i915_vblank_swap(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_vblank_swap_t *swap = data;
- drm_i915_vbl_swap_t *vbl_swap;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_master_private *master_priv;
+ struct drm_i915_vblank_swap *swap = data;
+ struct drm_i915_vbl_swap *vbl_swap;
unsigned int pipe, seqtype, curseq, plane;
unsigned long irqflags;
struct list_head *list;
@@ -826,7 +1005,12 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
return -EINVAL;
}
- if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) {
+ if (!dev->primary->master)
+ return -EINVAL;
+
+ master_priv = dev->primary->master->driver_priv;
+
+ if (master_priv->sarea_priv->rotation) {
DRM_DEBUG("Rotation not supported\n");
return -EINVAL;
}
@@ -909,7 +1093,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
DRM_SPINLOCK_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);
+ vbl_swap = list_entry(list, struct drm_i915_vbl_swap, head);
if (vbl_swap->drw_id == swap->drawable &&
vbl_swap->plane == plane &&
@@ -947,6 +1131,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
vbl_swap->plane = plane;
vbl_swap->sequence = swap->sequence;
vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP);
+ vbl_swap->minor = file_priv->minor;
if (vbl_swap->flip)
swap->sequence++;
@@ -965,18 +1150,32 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
*/
void i915_driver_irq_preinstall(struct drm_device * dev)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+ u32 tmp;
+
+ tmp = I915_READ(PIPEASTAT);
+ I915_WRITE(PIPEASTAT, tmp);
+ tmp = I915_READ(PIPEBSTAT);
+ I915_WRITE(PIPEBSTAT, tmp);
+
- I915_WRITE(I915REG_HWSTAM, 0xffff);
- I915_WRITE(I915REG_INT_ENABLE_R, 0x0);
- I915_WRITE(I915REG_INT_MASK_R, 0xffffffff);
- I915_WRITE(I915REG_INT_IDENTITY_R, 0xffffffff);
- (void) I915_READ(I915REG_INT_IDENTITY_R);
+ I915_WRITE16(HWSTAM, 0xeffe);
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
+ I915_WRITE(IMR, 0x0);
+ I915_WRITE(IER, 0x0);
+ tmp = I915_READ(IIR);
+ I915_WRITE(IIR, tmp);
+ } else {
+ I915_WRITE16(IMR, 0x0);
+ I915_WRITE16(IER, 0x0);
+ tmp = I915_READ16(IIR);
+ I915_WRITE16(IIR, tmp);
+ }
}
int i915_driver_irq_postinstall(struct drm_device * dev)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
int ret, num_pipes = 2;
DRM_SPININIT(&dev_priv->swaps_lock, "swap");
@@ -985,12 +1184,16 @@ int i915_driver_irq_postinstall(struct drm_device * dev)
DRM_SPININIT(&dev_priv->user_irq_lock, "userirq");
dev_priv->user_irq_refcount = 0;
- dev_priv->irq_mask_reg = 0;
+ dev_priv->irq_mask_reg = ~0;
ret = drm_vblank_init(dev, num_pipes);
if (ret)
return ret;
+ ret = drm_hotplug_init(dev);
+ if (ret)
+ return ret;
+
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
i915_enable_interrupt(dev);
@@ -1000,22 +1203,37 @@ int i915_driver_irq_postinstall(struct drm_device * dev)
* Initialize the hardware status page IRQ location.
*/
- I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21));
+ I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
return 0;
}
void i915_driver_irq_uninstall(struct drm_device * dev)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
u32 temp;
if (!dev_priv)
return;
- i915_disable_interrupt (dev);
+ dev_priv->irq_enabled = 1;
+
+ temp = I915_READ(PIPEASTAT);
+ I915_WRITE(PIPEASTAT, temp);
+ temp = I915_READ(PIPEBSTAT);
+ I915_WRITE(PIPEBSTAT, temp);
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
+ I915_WRITE(HWSTAM, 0xffffffff);
+ I915_WRITE(IMR, 0xffffffff);
+ I915_WRITE(IER, 0x0);
+
+ temp = I915_READ(IIR);
+ I915_WRITE(IIR, temp);
+ } else {
+ I915_WRITE16(HWSTAM, 0xffff);
+ I915_WRITE16(IMR, 0xffff);
+ I915_WRITE16(IER, 0x0);
- temp = I915_READ(I915REG_PIPEASTAT);
- I915_WRITE(I915REG_PIPEASTAT, temp);
- temp = I915_READ(I915REG_PIPEBSTAT);
- I915_WRITE(I915REG_PIPEBSTAT, temp);
+ temp = I915_READ16(IIR);
+ I915_WRITE16(IIR, temp);
+ }
}