#include "i915_drm.h"
#include "i915_drv.h"
#include "intel_drv.h"
+#include "drm_crtc_helper.h"
#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(struct drm_i915_private *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(struct drm_i915_private *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
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;
-
+
+ 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);
master_priv = vbl_swap->minor->master->driver_priv;
sarea_priv = master_priv->sarea_priv;
- pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) |
- (cpp << 23) | (1 << 24);
-
list_del(list);
dev_priv->swaps_pending--;
drm_vblank_put(dev, pipe);
}
if (init_drawrect) {
- 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();
+ 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;
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(offsets[front]);
OUT_RING((y1 << 16) | rect->x1);
- OUT_RING(pitchropcpp & 0xffff);
+ OUT_RING(src_pitch);
OUT_RING(offsets[back]);
ADVANCE_LP_RING();
drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER);
}
}
-#if 0
-static int i915_in_vblank(struct drm_device *dev, int pipe)
-{
- 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;
-
- pipedsl = pipe ? PIPEBDSL : PIPEADSL;
- vblank = pipe ? VBLANK_B : VBLANK_A;
- vtotal = pipe ? VTOTAL_B : VTOTAL_A;
-
- vbl_start = I915_READ(vblank) & VBLANK_START_MASK;
- vbl_end = (I915_READ(vblank) >> VBLANK_END_SHIFT) & VBLANK_END_MASK;
-
- cur_line = I915_READ(pipedsl);
-
- if (cur_line >= vbl_start)
- return 1;
- return 0;
-}
-#endif
u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
{
struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
if (!i915_pipe_enabled(dev, pipe)) {
- printk(KERN_ERR "trying to get vblank count for disabled "
- "pipe %d\n", pipe);
+ DRM_DEBUG("trying to get vblank count for disabled pipe %d\n", pipe);
return 0;
}
count = (high1 << 8) | low;
- /*
- * If we're in the middle of the vblank period, the
- * above regs won't have been updated yet, so return
- * an incremented count to stay accurate
- */
-#if 0
- if (i915_in_vblank(dev, pipe))
- count++;
-#endif
- /* 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 == 0 && dev->last_vblank[pipe] < dev->max_vblank_count/2)
- dev->last_vblank[pipe] = 0;
-
return count;
}
-#define HOTPLUG_CMD_CRT 1
-#define HOTPLUG_CMD_CRT_DIS 2
-#define HOTPLUG_CMD_SDVOB 4
-#define HOTPLUG_CMD_SDVOC 8
-#define HOTPLUG_CMD_TV 16
-
static struct drm_device *hotplug_dev;
-static int hotplug_cmd = 0;
-static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED;
-
-static void i915_hotplug_tv(struct drm_device *dev)
-{
- struct drm_output *output;
- struct intel_output *iout;
- enum drm_output_status status;
-
- mutex_lock(&dev->mode_config.mutex);
-
- /* find the crt output */
- list_for_each_entry(output, &dev->mode_config.output_list, head) {
- iout = output->driver_private;
- if (iout->type == INTEL_OUTPUT_TVOUT)
- break;
- else
- iout = 0;
- }
-
- if (iout == 0)
- goto unlock;
-
- /* may need to I915_WRITE(TVDAC, 1<<31) to ack the interrupt */
- status = output->funcs->detect(output);
- drm_hotplug_stage_two(dev, output,
- status == output_status_connected ? 1 : 0);
-unlock:
- mutex_unlock(&dev->mode_config.mutex);
-}
-
-static void i915_hotplug_crt(struct drm_device *dev, bool isconnected)
-{
- struct drm_output *output;
- struct intel_output *iout;
-
- mutex_lock(&dev->mode_config.mutex);
-
- /* find the crt output */
- list_for_each_entry(output, &dev->mode_config.output_list, head) {
- iout = output->driver_private;
- if (iout->type == INTEL_OUTPUT_ANALOG)
- break;
- else
- iout = 0;
- }
-
- if (iout == 0)
- goto unlock;
-
- drm_hotplug_stage_two(dev, output, isconnected);
-
-unlock:
- mutex_unlock(&dev->mode_config.mutex);
-}
-
-static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB)
-{
- struct drm_output *output = 0;
- enum drm_output_status status;
-
- mutex_lock(&dev->mode_config.mutex);
-
- output = intel_sdvo_find(dev, sdvoB);
-
- if (!output)
- goto unlock;
-
- status = output->funcs->detect(output);
-
- if (status != output_status_connected)
- drm_hotplug_stage_two(dev, output, false);
- else
- drm_hotplug_stage_two(dev, output, true);
-
- intel_sdvo_set_hotplug(output, 1);
-
-unlock:
- mutex_unlock(&dev->mode_config.mutex);
-}
-/*
- * This code is called in a more safe envirmoent to handle the hotplugs.
- * Add code here for hotplug love to userspace.
+/**
+ * Handler for user interrupts in process context (able to sleep, do VFS
+ * operations, etc.
+ *
+ * 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)
#endif
{
struct drm_device *dev = hotplug_dev;
- int crt;
- int crtDis;
- int sdvoB;
- int sdvoC;
- int tv;
-
- spin_lock(&hotplug_lock);
- tv = hotplug_cmd & HOTPLUG_CMD_TV;
- crt = hotplug_cmd & HOTPLUG_CMD_CRT;
- crtDis = hotplug_cmd & HOTPLUG_CMD_CRT_DIS;
- sdvoB = hotplug_cmd & HOTPLUG_CMD_SDVOB;
- sdvoC = hotplug_cmd & HOTPLUG_CMD_SDVOC;
- hotplug_cmd = 0;
- spin_unlock(&hotplug_lock);
-
- if (tv)
- i915_hotplug_tv(dev);
- if (crt)
- i915_hotplug_crt(dev, true);
- if (crtDis)
- i915_hotplug_crt(dev, false);
-
- if (sdvoB)
- i915_hotplug_sdvo(dev, 1);
-
- if (sdvoC)
- i915_hotplug_sdvo(dev, 0);
+ drm_helper_hotplug_stage_two(dev);
drm_handle_hotplug(dev);
}
if (stat & TV_HOTPLUG_INT_STATUS) {
DRM_DEBUG("TV event\n");
-
- spin_lock(&hotplug_lock);
- hotplug_cmd |= HOTPLUG_CMD_TV;
- spin_unlock(&hotplug_lock);
}
if (stat & CRT_HOTPLUG_INT_STATUS) {
DRM_DEBUG("CRT event\n");
-
- if (stat & CRT_HOTPLUG_MONITOR_MASK) {
- spin_lock(&hotplug_lock);
- hotplug_cmd |= HOTPLUG_CMD_CRT;
- spin_unlock(&hotplug_lock);
- } else {
- spin_lock(&hotplug_lock);
- hotplug_cmd |= HOTPLUG_CMD_CRT_DIS;
- spin_unlock(&hotplug_lock);
- }
}
if (stat & SDVOB_HOTPLUG_INT_STATUS) {
DRM_DEBUG("sDVOB event\n");
-
- spin_lock(&hotplug_lock);
- hotplug_cmd |= HOTPLUG_CMD_SDVOB;
- spin_unlock(&hotplug_lock);
}
if (stat & SDVOC_HOTPLUG_INT_STATUS) {
DRM_DEBUG("sDVOC event\n");
-
- spin_lock(&hotplug_lock);
- hotplug_cmd |= HOTPLUG_CMD_SDVOC;
- spin_unlock(&hotplug_lock);
}
-
queue_work(dev_priv->wq, &hotplug);
return 0;
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 = 0, tvdac;
int hotplug = 0;
int vblank = 0;
-
- /* 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(I915REG_INT_IDENTITY_R);
- else
- iir = I915_READ16(I915REG_INT_IDENTITY_R);
-
- iir &= (dev_priv->irq_enable_reg | I915_USER_INTERRUPT);
-
-#if 0
- DRM_DEBUG("flag=%08x\n", iir);
+#ifdef __linux__
+ if (dev->pdev->msi_enabled)
+ I915_WRITE(IMR, ~0);
#endif
+ iir = I915_READ(IIR);
+ atomic_inc(&dev_priv->irq_received);
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));
+#ifdef __linux__
+ if (dev->pdev->msi_enabled) {
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ (void) I915_READ(IMR);
+ }
#endif
return IRQ_NONE;
}
* 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))
- {
- vblank++;
- drm_handle_vblank(dev, i915_get_plane(dev, 0));
- }
-
- /* This is a global event, and not a pipe A event */
- if ((pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) ||
- (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS))
- hotplug = 1;
-
- I915_WRITE(I915REG_PIPEASTAT, pipea_stats);
+ pipea_stats = I915_READ(PIPEASTAT);
+ 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))
- {
- vblank++;
- drm_handle_vblank(dev, i915_get_plane(dev, 1));
- }
- I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats);
+ pipeb_stats = I915_READ(PIPEBSTAT);
+ I915_WRITE(PIPEBSTAT, pipeb_stats);
}
- /* Clear the generated interrupt */
- if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
- I915_WRITE(I915REG_INT_IDENTITY_R, iir);
- (void) I915_READ(I915REG_INT_IDENTITY_R);
- } else {
- I915_WRITE16(I915REG_INT_IDENTITY_R, iir);
- (void) I915_READ16(I915REG_INT_IDENTITY_R);
+ I915_WRITE(IIR, iir);
+#ifdef __linux__
+ if (dev->pdev->msi_enabled)
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+#endif
+
+ (void) I915_READ(IIR); /* Flush posted writes */
+
+ /* 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);
}
if (dev->primary->master) {
master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
}
+#ifdef __linux__
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25)
+ if ((iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) &&
+ (pipeb_stats & I915_LEGACY_BLC_EVENT_ENABLE))
+ opregion_asle_intr(dev);
+ if (iir & I915_ASLE_INTERRUPT)
+ opregion_asle_intr(dev);
+#endif
+#endif
+
if (iir & I915_USER_INTERRUPT) {
- DRM_WAKEUP(&dev_priv->irq_queue);
-#ifdef I915_HAVE_FENCE
- i915_fence_handler(dev);
+#ifdef I915_HAVE_GEM
+ dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
#endif
+ DRM_WAKEUP(&dev_priv->irq_queue);
+ }
+
+ if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
+ PIPE_VBLANK_INTERRUPT_STATUS)) {
+ vblank++;
+ drm_handle_vblank(dev, i915_get_plane(dev, 0));
+ }
+
+ /* 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 &= ~(I915_VBLANK_INTERRUPT_ENABLE);
+
+ if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
+ PIPE_VBLANK_INTERRUPT_STATUS)) {
+ vblank++;
+ drm_handle_vblank(dev, i915_get_plane(dev, 1));
}
if (vblank) {
DRM_INFO("Hotplug event received\n");
if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev)) {
- if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS)
+ if (pipea_stats & PIPE_HOTPLUG_INTERRUPT_STATUS)
temp2 |= SDVOB_HOTPLUG_INT_STATUS |
SDVOC_HOTPLUG_INT_STATUS;
- if (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS)
+ if (pipea_stats & PIPE_HOTPLUG_TV_INTERRUPT_STATUS)
temp2 |= TV_HOTPLUG_INT_STATUS;
} else {
temp2 = I915_READ(PORT_HOTPLUG_STAT);
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;
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_enable_reg |= I915_USER_INTERRUPT;
- if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev))
- I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
- else
- I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
- }
+ if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1))
+ i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
-
}
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);
- if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
- // dev_priv->irq_enable_reg &= ~I915_USER_INTERRUPT;
- // if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev))
- // I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
- // else
- // I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
- }
+#ifdef __linux__
+ BUG_ON(dev_priv->irq_enabled && dev_priv->user_irq_refcount <= 0);
+#endif
+ if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0))
+ i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
}
-static int i915_wait_irq(struct drm_device * dev, int irq_nr)
+int i915_wait_irq(struct drm_device * dev, int irq_nr)
{
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) {
+ DRM_ERROR("called with no initialization\n");
+ return -EINVAL;
+ }
+
DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
READ_BREADCRUMB(dev_priv));
- if (READ_BREADCRUMB(dev_priv) >= irq_nr)
+ master_priv = dev->primary->master->driver_priv;
+
+ if (!master_priv) {
+ DRM_ERROR("no master priv?\n");
+ return -EINVAL;
+ }
+
+ if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
+ master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
return 0;
+ }
i915_user_irq_on(dev);
DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
}
- if (dev->primary->master) {
- master_priv = dev->primary->master->driver_priv;
+ if (READ_BREADCRUMB(dev_priv) >= irq_nr)
master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- }
return ret;
}
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;
u32 pipestat;
switch (pipe) {
case 0:
- pipestat_reg = I915REG_PIPEASTAT;
- dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+ pipestat_reg = PIPEASTAT;
+ mask_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
break;
case 1:
- pipestat_reg = I915REG_PIPEBSTAT;
- dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+ 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",
* 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);
}
-
- if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev))
- I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
- else
- I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
-
+ DRM_SPINLOCK(&dev_priv->user_irq_lock);
+ i915_enable_irq(dev_priv, mask_reg);
+ DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
return 0;
}
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;
u32 pipestat;
switch (pipe) {
case 0:
- pipestat_reg = I915REG_PIPEASTAT;
- dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+ pipestat_reg = PIPEASTAT;
+ mask_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
break;
case 1:
- pipestat_reg = I915REG_PIPEBSTAT;
- dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+ 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",
break;
}
- if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev))
- I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
- else
- I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+ DRM_SPINLOCK(&dev_priv->user_irq_lock);
+ i915_disable_irq(dev_priv, 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);
}
}
void i915_enable_interrupt (struct drm_device *dev)
{
struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
- struct drm_output *o;
-
- dev_priv->irq_enable_reg |= I915_USER_INTERRUPT;
+ struct drm_connector *o;
+
+ dev_priv->irq_mask_reg &= ~0;
if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
- if (dev->mode_config.num_output)
- dev_priv->irq_enable_reg |= I915_DISPLAY_PORT_INTERRUPT;
+ if (dev->mode_config.num_connector)
+ dev_priv->irq_mask_reg &= ~I915_DISPLAY_PORT_INTERRUPT;
} else {
- if (dev->mode_config.num_output)
- dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+ 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(I915REG_PIPEASTAT, I915_READ(I915REG_PIPEASTAT) |
- I915_HOTPLUG_INTERRUPT_ENABLE |
- I915_HOTPLUG_TV_INTERRUPT_ENABLE |
- I915_HOTPLUG_TV_CLEAR |
- I915_HOTPLUG_CLEAR);
+ 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_enable_reg & (I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)) {
+ 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)) {
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(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
- else
- I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
-
+#ifdef __linux__
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25)
+ opregion_enable_asle(dev);
+#endif
+#endif
dev_priv->irq_enabled = 1;
}
struct drm_file *file_priv)
{
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");
return -EINVAL;
}
- if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
- DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe);
- return -EINVAL;
- }
-
- dev_priv->vblank_pipe = pipe->pipe;
-
return 0;
}
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_vblank_pipe *pipe = data;
- u16 flag;
+ u32 flag = 0;
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
- if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev))
- flag = I915_READ(I915REG_INT_ENABLE_R);
- else
- flag = I915_READ16(I915REG_INT_ENABLE_R);
+ if (dev_priv->irq_enabled)
+ flag = ~dev_priv->irq_mask_reg;
pipe->pipe = 0;
if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)
DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags);
- drm_update_vblank_count(dev, pipe);
+ /*
+ * 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 + 1;
} else {
DRM_DEBUG("Missed target sequence\n");
+ drm_vblank_put(dev, pipe);
return -EINVAL;
}
}
irqflags);
DRM_DEBUG("Invalid drawable ID %d\n",
swap->drawable);
+ drm_vblank_put(dev, pipe);
return -EINVAL;
}
DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags);
+ drm_vblank_put(dev, pipe);
return 0;
}
}
if (dev_priv->swaps_pending >= 100) {
DRM_DEBUG("Too many swaps queued\n");
+ drm_vblank_put(dev, pipe);
return -EBUSY;
}
if (!vbl_swap) {
DRM_ERROR("Failed to allocate memory to queue swap\n");
+ drm_vblank_put(dev, pipe);
return -ENOMEM;
}
DRM_DEBUG("\n");
- ret = drm_vblank_get(dev, pipe);
- if (ret) {
- drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
- return ret;
- }
-
vbl_swap->drw_id = swap->drawable;
vbl_swap->plane = plane;
vbl_swap->sequence = swap->sequence;
*/
void i915_driver_irq_preinstall(struct drm_device * dev)
{
- struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
- u32 tmp;
-
- tmp = I915_READ(I915REG_PIPEASTAT);
- I915_WRITE(I915REG_PIPEASTAT, tmp);
- tmp = I915_READ(I915REG_PIPEBSTAT);
- I915_WRITE(I915REG_PIPEBSTAT, tmp);
-
-
- I915_WRITE16(I915REG_HWSTAM, 0xeffe);
- if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
- I915_WRITE(I915REG_INT_MASK_R, 0x0);
- I915_WRITE(I915REG_INT_ENABLE_R, 0x0);
- tmp = I915_READ(I915REG_INT_IDENTITY_R);
- I915_WRITE(I915REG_INT_IDENTITY_R, tmp);
- } else {
- I915_WRITE16(I915REG_INT_MASK_R, 0x0);
- I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
- tmp = I915_READ16(I915REG_INT_IDENTITY_R);
- I915_WRITE16(I915REG_INT_IDENTITY_R, tmp);
- }
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ I915_WRITE16(HWSTAM, 0xeffe);
+ I915_WRITE16(IMR, 0x0);
+ I915_WRITE16(IER, 0x0);
}
int i915_driver_irq_postinstall(struct drm_device * dev)
{
- struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
int ret, num_pipes = 2;
- DRM_SPININIT(&dev_priv->swaps_lock, "swap");
INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
dev_priv->swaps_pending = 0;
- DRM_SPININIT(&dev_priv->user_irq_lock, "userirq");
dev_priv->user_irq_refcount = 0;
- dev_priv->irq_enable_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_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);
* 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)
{
- struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
u32 temp;
if (!dev_priv)
return;
- dev_priv->irq_enabled = 0;
-
- temp = I915_READ(I915REG_PIPEASTAT);
- I915_WRITE(I915REG_PIPEASTAT, temp);
- temp = I915_READ(I915REG_PIPEBSTAT);
- I915_WRITE(I915REG_PIPEBSTAT, temp);
- if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
- I915_WRITE(I915REG_HWSTAM, 0xffffffff);
- I915_WRITE(I915REG_INT_MASK_R, 0xffffffff);
- I915_WRITE(I915REG_INT_ENABLE_R, 0x0);
-
- temp = I915_READ(I915REG_INT_IDENTITY_R);
- I915_WRITE(I915REG_INT_IDENTITY_R, temp);
- } else {
- I915_WRITE16(I915REG_HWSTAM, 0xffff);
- I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
- I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+ dev_priv->vblank_pipe = 0;
- temp = I915_READ16(I915REG_INT_IDENTITY_R);
- I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
- }
+ dev_priv->irq_enabled = 0;
+ I915_WRITE(HWSTAM, 0xffffffff);
+ I915_WRITE(IMR, 0xffffffff);
+ I915_WRITE(IER, 0x0);
+
+ temp = I915_READ(PIPEASTAT);
+ I915_WRITE(PIPEASTAT, temp);
+ temp = I915_READ(PIPEBSTAT);
+ I915_WRITE(PIPEBSTAT, temp);
+ temp = I915_READ(IIR);
+ I915_WRITE(IIR, temp);
}