diff options
author | Zhenyu Wang <zhenyuw@linux.intel.com> | 2009-06-08 02:40:19 -0400 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2009-06-09 14:15:27 -0400 |
commit | 036a4a7d9272582fc7370359515d807393e2f728 (patch) | |
tree | 1f6be44c18dd9823155e60d9bc53260a41b40630 /drivers/gpu/drm/i915/i915_irq.c | |
parent | d765898970f35acef960581f678b9da9d5c779fa (diff) |
drm/i915: handle interrupt on new chipset
Update interrupt handling methods for IGDNG with new registers
for display and graphics interrupt functions. As we won't use
irq-based vblank sync in dri2, so display interrupt on new chip
will be used for hotplug only in future.
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 186 |
1 files changed, 180 insertions, 6 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 701d6809deb7..b86b7b7130c6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -58,6 +58,47 @@ | |||
58 | DRM_I915_VBLANK_PIPE_B) | 58 | DRM_I915_VBLANK_PIPE_B) |
59 | 59 | ||
60 | void | 60 | void |
61 | igdng_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) | ||
62 | { | ||
63 | if ((dev_priv->gt_irq_mask_reg & mask) != 0) { | ||
64 | dev_priv->gt_irq_mask_reg &= ~mask; | ||
65 | I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); | ||
66 | (void) I915_READ(GTIMR); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | static inline void | ||
71 | igdng_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) | ||
72 | { | ||
73 | if ((dev_priv->gt_irq_mask_reg & mask) != mask) { | ||
74 | dev_priv->gt_irq_mask_reg |= mask; | ||
75 | I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); | ||
76 | (void) I915_READ(GTIMR); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | /* For display hotplug interrupt */ | ||
81 | void | ||
82 | igdng_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) | ||
83 | { | ||
84 | if ((dev_priv->irq_mask_reg & mask) != 0) { | ||
85 | dev_priv->irq_mask_reg &= ~mask; | ||
86 | I915_WRITE(DEIMR, dev_priv->irq_mask_reg); | ||
87 | (void) I915_READ(DEIMR); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | static inline void | ||
92 | igdng_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) | ||
93 | { | ||
94 | if ((dev_priv->irq_mask_reg & mask) != mask) { | ||
95 | dev_priv->irq_mask_reg |= mask; | ||
96 | I915_WRITE(DEIMR, dev_priv->irq_mask_reg); | ||
97 | (void) I915_READ(DEIMR); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | void | ||
61 | i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) | 102 | i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) |
62 | { | 103 | { |
63 | if ((dev_priv->irq_mask_reg & mask) != 0) { | 104 | if ((dev_priv->irq_mask_reg & mask) != 0) { |
@@ -196,6 +237,47 @@ static void i915_hotplug_work_func(struct work_struct *work) | |||
196 | drm_sysfs_hotplug_event(dev); | 237 | drm_sysfs_hotplug_event(dev); |
197 | } | 238 | } |
198 | 239 | ||
240 | irqreturn_t igdng_irq_handler(struct drm_device *dev) | ||
241 | { | ||
242 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
243 | int ret = IRQ_NONE; | ||
244 | u32 de_iir, gt_iir; | ||
245 | u32 new_de_iir, new_gt_iir; | ||
246 | struct drm_i915_master_private *master_priv; | ||
247 | |||
248 | de_iir = I915_READ(DEIIR); | ||
249 | gt_iir = I915_READ(GTIIR); | ||
250 | |||
251 | for (;;) { | ||
252 | if (de_iir == 0 && gt_iir == 0) | ||
253 | break; | ||
254 | |||
255 | ret = IRQ_HANDLED; | ||
256 | |||
257 | I915_WRITE(DEIIR, de_iir); | ||
258 | new_de_iir = I915_READ(DEIIR); | ||
259 | I915_WRITE(GTIIR, gt_iir); | ||
260 | new_gt_iir = I915_READ(GTIIR); | ||
261 | |||
262 | if (dev->primary->master) { | ||
263 | master_priv = dev->primary->master->driver_priv; | ||
264 | if (master_priv->sarea_priv) | ||
265 | master_priv->sarea_priv->last_dispatch = | ||
266 | READ_BREADCRUMB(dev_priv); | ||
267 | } | ||
268 | |||
269 | if (gt_iir & GT_USER_INTERRUPT) { | ||
270 | dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); | ||
271 | DRM_WAKEUP(&dev_priv->irq_queue); | ||
272 | } | ||
273 | |||
274 | de_iir = new_de_iir; | ||
275 | gt_iir = new_gt_iir; | ||
276 | } | ||
277 | |||
278 | return ret; | ||
279 | } | ||
280 | |||
199 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | 281 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) |
200 | { | 282 | { |
201 | struct drm_device *dev = (struct drm_device *) arg; | 283 | struct drm_device *dev = (struct drm_device *) arg; |
@@ -212,6 +294,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
212 | 294 | ||
213 | atomic_inc(&dev_priv->irq_received); | 295 | atomic_inc(&dev_priv->irq_received); |
214 | 296 | ||
297 | if (IS_IGDNG(dev)) | ||
298 | return igdng_irq_handler(dev); | ||
299 | |||
215 | iir = I915_READ(IIR); | 300 | iir = I915_READ(IIR); |
216 | 301 | ||
217 | if (IS_I965G(dev)) { | 302 | if (IS_I965G(dev)) { |
@@ -349,8 +434,12 @@ void i915_user_irq_get(struct drm_device *dev) | |||
349 | unsigned long irqflags; | 434 | unsigned long irqflags; |
350 | 435 | ||
351 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); | 436 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); |
352 | if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) | 437 | if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) { |
353 | i915_enable_irq(dev_priv, I915_USER_INTERRUPT); | 438 | if (IS_IGDNG(dev)) |
439 | igdng_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT); | ||
440 | else | ||
441 | i915_enable_irq(dev_priv, I915_USER_INTERRUPT); | ||
442 | } | ||
354 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); | 443 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); |
355 | } | 444 | } |
356 | 445 | ||
@@ -361,8 +450,12 @@ void i915_user_irq_put(struct drm_device *dev) | |||
361 | 450 | ||
362 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); | 451 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); |
363 | BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); | 452 | BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); |
364 | if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) | 453 | if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { |
365 | i915_disable_irq(dev_priv, I915_USER_INTERRUPT); | 454 | if (IS_IGDNG(dev)) |
455 | igdng_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT); | ||
456 | else | ||
457 | i915_disable_irq(dev_priv, I915_USER_INTERRUPT); | ||
458 | } | ||
366 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); | 459 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); |
367 | } | 460 | } |
368 | 461 | ||
@@ -455,6 +548,9 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) | |||
455 | if (!(pipeconf & PIPEACONF_ENABLE)) | 548 | if (!(pipeconf & PIPEACONF_ENABLE)) |
456 | return -EINVAL; | 549 | return -EINVAL; |
457 | 550 | ||
551 | if (IS_IGDNG(dev)) | ||
552 | return 0; | ||
553 | |||
458 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); | 554 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); |
459 | if (IS_I965G(dev)) | 555 | if (IS_I965G(dev)) |
460 | i915_enable_pipestat(dev_priv, pipe, | 556 | i915_enable_pipestat(dev_priv, pipe, |
@@ -474,6 +570,9 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) | |||
474 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 570 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
475 | unsigned long irqflags; | 571 | unsigned long irqflags; |
476 | 572 | ||
573 | if (IS_IGDNG(dev)) | ||
574 | return; | ||
575 | |||
477 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); | 576 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); |
478 | i915_disable_pipestat(dev_priv, pipe, | 577 | i915_disable_pipestat(dev_priv, pipe, |
479 | PIPE_VBLANK_INTERRUPT_ENABLE | | 578 | PIPE_VBLANK_INTERRUPT_ENABLE | |
@@ -547,12 +646,65 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
547 | 646 | ||
548 | /* drm_dma.h hooks | 647 | /* drm_dma.h hooks |
549 | */ | 648 | */ |
649 | static void igdng_irq_preinstall(struct drm_device *dev) | ||
650 | { | ||
651 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
652 | |||
653 | I915_WRITE(HWSTAM, 0xeffe); | ||
654 | |||
655 | /* XXX hotplug from PCH */ | ||
656 | |||
657 | I915_WRITE(DEIMR, 0xffffffff); | ||
658 | I915_WRITE(DEIER, 0x0); | ||
659 | (void) I915_READ(DEIER); | ||
660 | |||
661 | /* and GT */ | ||
662 | I915_WRITE(GTIMR, 0xffffffff); | ||
663 | I915_WRITE(GTIER, 0x0); | ||
664 | (void) I915_READ(GTIER); | ||
665 | } | ||
666 | |||
667 | static int igdng_irq_postinstall(struct drm_device *dev) | ||
668 | { | ||
669 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
670 | /* enable kind of interrupts always enabled */ | ||
671 | u32 display_mask = DE_MASTER_IRQ_CONTROL /*| DE_PCH_EVENT */; | ||
672 | u32 render_mask = GT_USER_INTERRUPT; | ||
673 | |||
674 | dev_priv->irq_mask_reg = ~display_mask; | ||
675 | dev_priv->de_irq_enable_reg = display_mask; | ||
676 | |||
677 | /* should always can generate irq */ | ||
678 | I915_WRITE(DEIIR, I915_READ(DEIIR)); | ||
679 | I915_WRITE(DEIMR, dev_priv->irq_mask_reg); | ||
680 | I915_WRITE(DEIER, dev_priv->de_irq_enable_reg); | ||
681 | (void) I915_READ(DEIER); | ||
682 | |||
683 | /* user interrupt should be enabled, but masked initial */ | ||
684 | dev_priv->gt_irq_mask_reg = 0xffffffff; | ||
685 | dev_priv->gt_irq_enable_reg = render_mask; | ||
686 | |||
687 | I915_WRITE(GTIIR, I915_READ(GTIIR)); | ||
688 | I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); | ||
689 | I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg); | ||
690 | (void) I915_READ(GTIER); | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
550 | void i915_driver_irq_preinstall(struct drm_device * dev) | 695 | void i915_driver_irq_preinstall(struct drm_device * dev) |
551 | { | 696 | { |
552 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 697 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
553 | 698 | ||
554 | atomic_set(&dev_priv->irq_received, 0); | 699 | atomic_set(&dev_priv->irq_received, 0); |
555 | 700 | ||
701 | INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); | ||
702 | |||
703 | if (IS_IGDNG(dev)) { | ||
704 | igdng_irq_preinstall(dev); | ||
705 | return; | ||
706 | } | ||
707 | |||
556 | if (I915_HAS_HOTPLUG(dev)) { | 708 | if (I915_HAS_HOTPLUG(dev)) { |
557 | I915_WRITE(PORT_HOTPLUG_EN, 0); | 709 | I915_WRITE(PORT_HOTPLUG_EN, 0); |
558 | I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); | 710 | I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); |
@@ -564,7 +716,6 @@ void i915_driver_irq_preinstall(struct drm_device * dev) | |||
564 | I915_WRITE(IMR, 0xffffffff); | 716 | I915_WRITE(IMR, 0xffffffff); |
565 | I915_WRITE(IER, 0x0); | 717 | I915_WRITE(IER, 0x0); |
566 | (void) I915_READ(IER); | 718 | (void) I915_READ(IER); |
567 | INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); | ||
568 | } | 719 | } |
569 | 720 | ||
570 | int i915_driver_irq_postinstall(struct drm_device *dev) | 721 | int i915_driver_irq_postinstall(struct drm_device *dev) |
@@ -572,8 +723,13 @@ int i915_driver_irq_postinstall(struct drm_device *dev) | |||
572 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 723 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
573 | u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; | 724 | u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; |
574 | 725 | ||
726 | DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); | ||
727 | |||
575 | dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; | 728 | dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; |
576 | 729 | ||
730 | if (IS_IGDNG(dev)) | ||
731 | return igdng_irq_postinstall(dev); | ||
732 | |||
577 | /* Unmask the interrupts that we always want on. */ | 733 | /* Unmask the interrupts that we always want on. */ |
578 | dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX; | 734 | dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX; |
579 | 735 | ||
@@ -613,11 +769,24 @@ int i915_driver_irq_postinstall(struct drm_device *dev) | |||
613 | (void) I915_READ(IER); | 769 | (void) I915_READ(IER); |
614 | 770 | ||
615 | opregion_enable_asle(dev); | 771 | opregion_enable_asle(dev); |
616 | DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); | ||
617 | 772 | ||
618 | return 0; | 773 | return 0; |
619 | } | 774 | } |
620 | 775 | ||
776 | static void igdng_irq_uninstall(struct drm_device *dev) | ||
777 | { | ||
778 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
779 | I915_WRITE(HWSTAM, 0xffffffff); | ||
780 | |||
781 | I915_WRITE(DEIMR, 0xffffffff); | ||
782 | I915_WRITE(DEIER, 0x0); | ||
783 | I915_WRITE(DEIIR, I915_READ(DEIIR)); | ||
784 | |||
785 | I915_WRITE(GTIMR, 0xffffffff); | ||
786 | I915_WRITE(GTIER, 0x0); | ||
787 | I915_WRITE(GTIIR, I915_READ(GTIIR)); | ||
788 | } | ||
789 | |||
621 | void i915_driver_irq_uninstall(struct drm_device * dev) | 790 | void i915_driver_irq_uninstall(struct drm_device * dev) |
622 | { | 791 | { |
623 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 792 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
@@ -627,6 +796,11 @@ void i915_driver_irq_uninstall(struct drm_device * dev) | |||
627 | 796 | ||
628 | dev_priv->vblank_pipe = 0; | 797 | dev_priv->vblank_pipe = 0; |
629 | 798 | ||
799 | if (IS_IGDNG(dev)) { | ||
800 | igdng_irq_uninstall(dev); | ||
801 | return; | ||
802 | } | ||
803 | |||
630 | if (I915_HAS_HOTPLUG(dev)) { | 804 | if (I915_HAS_HOTPLUG(dev)) { |
631 | I915_WRITE(PORT_HOTPLUG_EN, 0); | 805 | I915_WRITE(PORT_HOTPLUG_EN, 0); |
632 | I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); | 806 | I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); |