diff options
author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2011-04-06 15:13:38 -0400 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2011-05-13 20:09:52 -0400 |
commit | b1f14ad01ab09f5e22fb1240a6a158a23527ff14 (patch) | |
tree | 70054e09564a91f72939f1fa2efa2edefb8677c2 /drivers/gpu | |
parent | fe100d4da1ba8e0be9f38979da1817145e68f866 (diff) |
drm/i915: interrupt & vblank support for Ivy Bridge
Add new interrupt handling functions for Ivy Bridge.
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 165 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 13 |
4 files changed, 195 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 52ecb90ba0a1..0239e9974bf2 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
@@ -1266,7 +1266,15 @@ static int i915_load_modeset_init(struct drm_device *dev) | |||
1266 | 1266 | ||
1267 | intel_modeset_gem_init(dev); | 1267 | intel_modeset_gem_init(dev); |
1268 | 1268 | ||
1269 | if (HAS_PCH_SPLIT(dev)) { | 1269 | if (IS_IVYBRIDGE(dev)) { |
1270 | /* Share pre & uninstall handlers with ILK/SNB */ | ||
1271 | dev->driver->irq_handler = ivybridge_irq_handler; | ||
1272 | dev->driver->irq_preinstall = ironlake_irq_preinstall; | ||
1273 | dev->driver->irq_postinstall = ivybridge_irq_postinstall; | ||
1274 | dev->driver->irq_uninstall = ironlake_irq_uninstall; | ||
1275 | dev->driver->enable_vblank = ivybridge_enable_vblank; | ||
1276 | dev->driver->disable_vblank = ivybridge_disable_vblank; | ||
1277 | } else if (HAS_PCH_SPLIT(dev)) { | ||
1270 | dev->driver->irq_handler = ironlake_irq_handler; | 1278 | dev->driver->irq_handler = ironlake_irq_handler; |
1271 | dev->driver->irq_preinstall = ironlake_irq_preinstall; | 1279 | dev->driver->irq_preinstall = ironlake_irq_preinstall; |
1272 | dev->driver->irq_postinstall = ironlake_irq_postinstall; | 1280 | dev->driver->irq_postinstall = ironlake_irq_postinstall; |
@@ -2011,7 +2019,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
2011 | 2019 | ||
2012 | dev->driver->get_vblank_counter = i915_get_vblank_counter; | 2020 | dev->driver->get_vblank_counter = i915_get_vblank_counter; |
2013 | dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ | 2021 | dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ |
2014 | if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) { | 2022 | if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) { |
2015 | dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ | 2023 | dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ |
2016 | dev->driver->get_vblank_counter = gm45_get_vblank_counter; | 2024 | dev->driver->get_vblank_counter = gm45_get_vblank_counter; |
2017 | } | 2025 | } |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 356d33dbdced..0cf65a4350c0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -1043,6 +1043,11 @@ extern void ironlake_irq_preinstall(struct drm_device *dev); | |||
1043 | extern int ironlake_irq_postinstall(struct drm_device *dev); | 1043 | extern int ironlake_irq_postinstall(struct drm_device *dev); |
1044 | extern void ironlake_irq_uninstall(struct drm_device *dev); | 1044 | extern void ironlake_irq_uninstall(struct drm_device *dev); |
1045 | 1045 | ||
1046 | extern irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS); | ||
1047 | extern void ivybridge_irq_preinstall(struct drm_device *dev); | ||
1048 | extern int ivybridge_irq_postinstall(struct drm_device *dev); | ||
1049 | extern void ivybridge_irq_uninstall(struct drm_device *dev); | ||
1050 | |||
1046 | extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, | 1051 | extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, |
1047 | struct drm_file *file_priv); | 1052 | struct drm_file *file_priv); |
1048 | extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, | 1053 | extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, |
@@ -1051,6 +1056,8 @@ extern int i915_enable_vblank(struct drm_device *dev, int crtc); | |||
1051 | extern void i915_disable_vblank(struct drm_device *dev, int crtc); | 1056 | extern void i915_disable_vblank(struct drm_device *dev, int crtc); |
1052 | extern int ironlake_enable_vblank(struct drm_device *dev, int crtc); | 1057 | extern int ironlake_enable_vblank(struct drm_device *dev, int crtc); |
1053 | extern void ironlake_disable_vblank(struct drm_device *dev, int crtc); | 1058 | extern void ironlake_disable_vblank(struct drm_device *dev, int crtc); |
1059 | extern int ivybridge_enable_vblank(struct drm_device *dev, int crtc); | ||
1060 | extern void ivybridge_disable_vblank(struct drm_device *dev, int crtc); | ||
1054 | extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); | 1061 | extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); |
1055 | extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc); | 1062 | extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc); |
1056 | extern int i915_vblank_swap(struct drm_device *dev, void *data, | 1063 | extern int i915_vblank_swap(struct drm_device *dev, void *data, |
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 33f0bc53a538..349a03e48481 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -462,6 +462,94 @@ static void pch_irq_handler(struct drm_device *dev) | |||
462 | DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n"); | 462 | DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n"); |
463 | } | 463 | } |
464 | 464 | ||
465 | irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) | ||
466 | { | ||
467 | struct drm_device *dev = (struct drm_device *) arg; | ||
468 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
469 | int ret = IRQ_NONE; | ||
470 | u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; | ||
471 | struct drm_i915_master_private *master_priv; | ||
472 | |||
473 | atomic_inc(&dev_priv->irq_received); | ||
474 | |||
475 | /* disable master interrupt before clearing iir */ | ||
476 | de_ier = I915_READ(DEIER); | ||
477 | I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); | ||
478 | POSTING_READ(DEIER); | ||
479 | |||
480 | de_iir = I915_READ(DEIIR); | ||
481 | gt_iir = I915_READ(GTIIR); | ||
482 | pch_iir = I915_READ(SDEIIR); | ||
483 | pm_iir = I915_READ(GEN6_PMIIR); | ||
484 | |||
485 | if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && pm_iir == 0) | ||
486 | goto done; | ||
487 | |||
488 | ret = IRQ_HANDLED; | ||
489 | |||
490 | if (dev->primary->master) { | ||
491 | master_priv = dev->primary->master->driver_priv; | ||
492 | if (master_priv->sarea_priv) | ||
493 | master_priv->sarea_priv->last_dispatch = | ||
494 | READ_BREADCRUMB(dev_priv); | ||
495 | } | ||
496 | |||
497 | if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY)) | ||
498 | notify_ring(dev, &dev_priv->ring[RCS]); | ||
499 | if (gt_iir & GT_GEN6_BSD_USER_INTERRUPT) | ||
500 | notify_ring(dev, &dev_priv->ring[VCS]); | ||
501 | if (gt_iir & GT_BLT_USER_INTERRUPT) | ||
502 | notify_ring(dev, &dev_priv->ring[BCS]); | ||
503 | |||
504 | if (de_iir & DE_GSE_IVB) | ||
505 | intel_opregion_gse_intr(dev); | ||
506 | |||
507 | if (de_iir & DE_PLANEA_FLIP_DONE_IVB) { | ||
508 | intel_prepare_page_flip(dev, 0); | ||
509 | intel_finish_page_flip_plane(dev, 0); | ||
510 | } | ||
511 | |||
512 | if (de_iir & DE_PLANEB_FLIP_DONE_IVB) { | ||
513 | intel_prepare_page_flip(dev, 1); | ||
514 | intel_finish_page_flip_plane(dev, 1); | ||
515 | } | ||
516 | |||
517 | if (de_iir & DE_PIPEA_VBLANK_IVB) | ||
518 | drm_handle_vblank(dev, 0); | ||
519 | |||
520 | if (de_iir & DE_PIPEB_VBLANK_IVB); | ||
521 | drm_handle_vblank(dev, 1); | ||
522 | |||
523 | /* check event from PCH */ | ||
524 | if (de_iir & DE_PCH_EVENT_IVB) { | ||
525 | if (pch_iir & SDE_HOTPLUG_MASK_CPT) | ||
526 | queue_work(dev_priv->wq, &dev_priv->hotplug_work); | ||
527 | pch_irq_handler(dev); | ||
528 | } | ||
529 | |||
530 | if (pm_iir & GEN6_PM_DEFERRED_EVENTS) { | ||
531 | unsigned long flags; | ||
532 | spin_lock_irqsave(&dev_priv->rps_lock, flags); | ||
533 | WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); | ||
534 | I915_WRITE(GEN6_PMIMR, pm_iir); | ||
535 | dev_priv->pm_iir |= pm_iir; | ||
536 | spin_unlock_irqrestore(&dev_priv->rps_lock, flags); | ||
537 | queue_work(dev_priv->wq, &dev_priv->rps_work); | ||
538 | } | ||
539 | |||
540 | /* should clear PCH hotplug event before clear CPU irq */ | ||
541 | I915_WRITE(SDEIIR, pch_iir); | ||
542 | I915_WRITE(GTIIR, gt_iir); | ||
543 | I915_WRITE(DEIIR, de_iir); | ||
544 | I915_WRITE(GEN6_PMIIR, pm_iir); | ||
545 | |||
546 | done: | ||
547 | I915_WRITE(DEIER, de_ier); | ||
548 | POSTING_READ(DEIER); | ||
549 | |||
550 | return ret; | ||
551 | } | ||
552 | |||
465 | irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) | 553 | irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) |
466 | { | 554 | { |
467 | struct drm_device *dev = (struct drm_device *) arg; | 555 | struct drm_device *dev = (struct drm_device *) arg; |
@@ -1406,6 +1494,22 @@ int ironlake_enable_vblank(struct drm_device *dev, int pipe) | |||
1406 | return 0; | 1494 | return 0; |
1407 | } | 1495 | } |
1408 | 1496 | ||
1497 | int ivybridge_enable_vblank(struct drm_device *dev, int pipe) | ||
1498 | { | ||
1499 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
1500 | unsigned long irqflags; | ||
1501 | |||
1502 | if (!i915_pipe_enabled(dev, pipe)) | ||
1503 | return -EINVAL; | ||
1504 | |||
1505 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); | ||
1506 | ironlake_enable_display_irq(dev_priv, (pipe == 0) ? | ||
1507 | DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB); | ||
1508 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); | ||
1509 | |||
1510 | return 0; | ||
1511 | } | ||
1512 | |||
1409 | /* Called from drm generic code, passed 'crtc' which | 1513 | /* Called from drm generic code, passed 'crtc' which |
1410 | * we use as a pipe index | 1514 | * we use as a pipe index |
1411 | */ | 1515 | */ |
@@ -1436,6 +1540,17 @@ void ironlake_disable_vblank(struct drm_device *dev, int pipe) | |||
1436 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); | 1540 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
1437 | } | 1541 | } |
1438 | 1542 | ||
1543 | void ivybridge_disable_vblank(struct drm_device *dev, int pipe) | ||
1544 | { | ||
1545 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
1546 | unsigned long irqflags; | ||
1547 | |||
1548 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); | ||
1549 | ironlake_disable_display_irq(dev_priv, (pipe == 0) ? | ||
1550 | DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB); | ||
1551 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); | ||
1552 | } | ||
1553 | |||
1439 | /* Set the vblank monitor pipe | 1554 | /* Set the vblank monitor pipe |
1440 | */ | 1555 | */ |
1441 | int i915_vblank_pipe_set(struct drm_device *dev, void *data, | 1556 | int i915_vblank_pipe_set(struct drm_device *dev, void *data, |
@@ -1713,6 +1828,56 @@ int ironlake_irq_postinstall(struct drm_device *dev) | |||
1713 | return 0; | 1828 | return 0; |
1714 | } | 1829 | } |
1715 | 1830 | ||
1831 | int ivybridge_irq_postinstall(struct drm_device *dev) | ||
1832 | { | ||
1833 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
1834 | /* enable kind of interrupts always enabled */ | ||
1835 | u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | | ||
1836 | DE_PCH_EVENT_IVB | DE_PLANEA_FLIP_DONE_IVB | | ||
1837 | DE_PLANEB_FLIP_DONE_IVB; | ||
1838 | u32 render_irqs; | ||
1839 | u32 hotplug_mask; | ||
1840 | |||
1841 | DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue); | ||
1842 | if (HAS_BSD(dev)) | ||
1843 | DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue); | ||
1844 | if (HAS_BLT(dev)) | ||
1845 | DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue); | ||
1846 | |||
1847 | dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; | ||
1848 | dev_priv->irq_mask = ~display_mask; | ||
1849 | |||
1850 | /* should always can generate irq */ | ||
1851 | I915_WRITE(DEIIR, I915_READ(DEIIR)); | ||
1852 | I915_WRITE(DEIMR, dev_priv->irq_mask); | ||
1853 | I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK_IVB | | ||
1854 | DE_PIPEB_VBLANK_IVB); | ||
1855 | POSTING_READ(DEIER); | ||
1856 | |||
1857 | dev_priv->gt_irq_mask = ~0; | ||
1858 | |||
1859 | I915_WRITE(GTIIR, I915_READ(GTIIR)); | ||
1860 | I915_WRITE(GTIMR, dev_priv->gt_irq_mask); | ||
1861 | |||
1862 | render_irqs = GT_USER_INTERRUPT | GT_GEN6_BSD_USER_INTERRUPT | | ||
1863 | GT_BLT_USER_INTERRUPT; | ||
1864 | I915_WRITE(GTIER, render_irqs); | ||
1865 | POSTING_READ(GTIER); | ||
1866 | |||
1867 | hotplug_mask = (SDE_CRT_HOTPLUG_CPT | | ||
1868 | SDE_PORTB_HOTPLUG_CPT | | ||
1869 | SDE_PORTC_HOTPLUG_CPT | | ||
1870 | SDE_PORTD_HOTPLUG_CPT); | ||
1871 | dev_priv->pch_irq_mask = ~hotplug_mask; | ||
1872 | |||
1873 | I915_WRITE(SDEIIR, I915_READ(SDEIIR)); | ||
1874 | I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); | ||
1875 | I915_WRITE(SDEIER, hotplug_mask); | ||
1876 | POSTING_READ(SDEIER); | ||
1877 | |||
1878 | return 0; | ||
1879 | } | ||
1880 | |||
1716 | void i915_driver_irq_preinstall(struct drm_device * dev) | 1881 | void i915_driver_irq_preinstall(struct drm_device * dev) |
1717 | { | 1882 | { |
1718 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 1883 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ea12ca01ef63..8f70fb65b496 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
@@ -2778,6 +2778,19 @@ | |||
2778 | #define DE_PIPEA_VSYNC (1 << 3) | 2778 | #define DE_PIPEA_VSYNC (1 << 3) |
2779 | #define DE_PIPEA_FIFO_UNDERRUN (1 << 0) | 2779 | #define DE_PIPEA_FIFO_UNDERRUN (1 << 0) |
2780 | 2780 | ||
2781 | /* More Ivybridge lolz */ | ||
2782 | #define DE_ERR_DEBUG_IVB (1<<30) | ||
2783 | #define DE_GSE_IVB (1<<29) | ||
2784 | #define DE_PCH_EVENT_IVB (1<<28) | ||
2785 | #define DE_DP_A_HOTPLUG_IVB (1<<27) | ||
2786 | #define DE_AUX_CHANNEL_A_IVB (1<<26) | ||
2787 | #define DE_SPRITEB_FLIP_DONE_IVB (1<<9) | ||
2788 | #define DE_SPRITEA_FLIP_DONE_IVB (1<<4) | ||
2789 | #define DE_PLANEB_FLIP_DONE_IVB (1<<8) | ||
2790 | #define DE_PLANEA_FLIP_DONE_IVB (1<<3) | ||
2791 | #define DE_PIPEB_VBLANK_IVB (1<<5) | ||
2792 | #define DE_PIPEA_VBLANK_IVB (1<<0) | ||
2793 | |||
2781 | #define DEISR 0x44000 | 2794 | #define DEISR 0x44000 |
2782 | #define DEIMR 0x44004 | 2795 | #define DEIMR 0x44004 |
2783 | #define DEIIR 0x44008 | 2796 | #define DEIIR 0x44008 |