diff options
Diffstat (limited to 'shared-core/i915_irq.c')
-rw-r--r-- | shared-core/i915_irq.c | 570 |
1 files changed, 469 insertions, 101 deletions
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 2287cd0c..592e881b 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -30,6 +30,7 @@ #include "drm.h" #include "i915_drm.h" #include "i915_drv.h" +#include "intel_drv.h" #define MAX_NOPID ((u32)~0) @@ -45,7 +46,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 +83,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 +101,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 +146,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 +191,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 +218,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 +276,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 +328,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 +358,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 +369,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 +390,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,25 +440,219 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) 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; + + 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. + */ +#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; + 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_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"); + + 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; +} + 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_enable_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; } @@ -462,31 +661,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); - (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); @@ -500,12 +721,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); @@ -516,29 +756,39 @@ 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_enable_reg |= I915_USER_INTERRUPT; - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) + I915_WRITE(IER, dev_priv->irq_enable_reg); + else + I915_WRITE16(IER, dev_priv->irq_enable_reg); } 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); if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { - // dev_priv->irq_enable_reg &= ~USER_INT_FLAG; - // I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + // dev_priv->irq_enable_reg &= ~I915_USER_INTERRUPT; + // if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) + // I915_WRITE(IER, dev_priv->irq_enable_reg); + // else + // I915_WRITE16(IER, dev_priv->irq_enable_reg); } DRM_SPINUNLOCK(&dev_priv->user_irq_lock); } @@ -546,7 +796,8 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv) static 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; DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, @@ -555,19 +806,21 @@ static 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; } @@ -576,8 +829,8 @@ static 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); @@ -602,8 +855,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"); @@ -615,18 +868,18 @@ 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 pipestat; switch (pipe) { case 0: - pipestat_reg = I915REG_PIPEASTAT; + pipestat_reg = PIPEASTAT; dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; break; case 1: - pipestat_reg = I915REG_PIPEBSTAT; + pipestat_reg = PIPEBSTAT; dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; break; default: @@ -643,35 +896,40 @@ 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); } - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) + I915_WRITE(IER, dev_priv->irq_enable_reg); + else + I915_WRITE16(IER, dev_priv->irq_enable_reg); + 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; + 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 pipestat; switch (pipe) { case 0: - pipestat_reg = I915REG_PIPEASTAT; + pipestat_reg = PIPEASTAT; dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; break; case 1: - pipestat_reg = I915REG_PIPEBSTAT; + pipestat_reg = PIPEBSTAT; dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; break; default: @@ -680,28 +938,96 @@ void i915_disable_vblank(struct drm_device *dev, int plane) break; } - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) + I915_WRITE(IER, dev_priv->irq_enable_reg); + else + I915_WRITE16(IER, dev_priv->irq_enable_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); } } -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; - + 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; - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + 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; + } else { + if (dev->mode_config.num_output) + dev_priv->irq_enable_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_enable_reg & (I915_DISPLAY_PORT_INTERRUPT | 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(IER, dev_priv->irq_enable_reg); + else + I915_WRITE16(IER, dev_priv->irq_enable_reg); + dev_priv->irq_enabled = 1; } @@ -710,8 +1036,8 @@ static void i915_enable_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"); @@ -731,8 +1057,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) { @@ -740,7 +1066,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; @@ -756,9 +1086,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; @@ -769,7 +1100,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; } @@ -852,7 +1188,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 && @@ -890,6 +1226,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++; @@ -908,16 +1245,33 @@ 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_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); + } - I915_WRITE16(I915REG_HWSTAM, 0xeffe); - I915_WRITE16(I915REG_INT_MASK_R, 0x0); - I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); } 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"); @@ -932,6 +1286,10 @@ int i915_driver_irq_postinstall(struct drm_device * dev) 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); @@ -941,27 +1299,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; dev_priv->irq_enabled = 0; - I915_WRITE(I915REG_HWSTAM, 0xffffffff); - I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); - I915_WRITE(I915REG_INT_ENABLE_R, 0x0); - - temp = I915_READ(I915REG_PIPEASTAT); - I915_WRITE(I915REG_PIPEASTAT, temp); - temp = I915_READ(I915REG_PIPEBSTAT); - I915_WRITE(I915REG_PIPEBSTAT, temp); - temp = I915_READ(I915REG_INT_IDENTITY_R); - I915_WRITE(I915REG_INT_IDENTITY_R, temp); + + 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_READ16(IIR); + I915_WRITE16(IIR, temp); + } } |