aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2011-04-06 15:13:38 -0400
committerKeith Packard <keithp@keithp.com>2011-05-13 20:09:52 -0400
commitb1f14ad01ab09f5e22fb1240a6a158a23527ff14 (patch)
tree70054e09564a91f72939f1fa2efa2edefb8677c2
parentfe100d4da1ba8e0be9f38979da1817145e68f866 (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>
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c12
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h7
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c165
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h13
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);
1043extern int ironlake_irq_postinstall(struct drm_device *dev); 1043extern int ironlake_irq_postinstall(struct drm_device *dev);
1044extern void ironlake_irq_uninstall(struct drm_device *dev); 1044extern void ironlake_irq_uninstall(struct drm_device *dev);
1045 1045
1046extern irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS);
1047extern void ivybridge_irq_preinstall(struct drm_device *dev);
1048extern int ivybridge_irq_postinstall(struct drm_device *dev);
1049extern void ivybridge_irq_uninstall(struct drm_device *dev);
1050
1046extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, 1051extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
1047 struct drm_file *file_priv); 1052 struct drm_file *file_priv);
1048extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, 1053extern 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);
1051extern void i915_disable_vblank(struct drm_device *dev, int crtc); 1056extern void i915_disable_vblank(struct drm_device *dev, int crtc);
1052extern int ironlake_enable_vblank(struct drm_device *dev, int crtc); 1057extern int ironlake_enable_vblank(struct drm_device *dev, int crtc);
1053extern void ironlake_disable_vblank(struct drm_device *dev, int crtc); 1058extern void ironlake_disable_vblank(struct drm_device *dev, int crtc);
1059extern int ivybridge_enable_vblank(struct drm_device *dev, int crtc);
1060extern void ivybridge_disable_vblank(struct drm_device *dev, int crtc);
1054extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); 1061extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
1055extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc); 1062extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc);
1056extern int i915_vblank_swap(struct drm_device *dev, void *data, 1063extern 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
465irqreturn_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
546done:
547 I915_WRITE(DEIER, de_ier);
548 POSTING_READ(DEIER);
549
550 return ret;
551}
552
465irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) 553irqreturn_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
1497int 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
1543void 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 */
1441int i915_vblank_pipe_set(struct drm_device *dev, void *data, 1556int 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
1831int 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
1716void i915_driver_irq_preinstall(struct drm_device * dev) 1881void 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