aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2013-10-28 18:04:43 -0400
committerVille Syrjälä <ville.syrjala@linux.intel.com>2014-01-20 05:21:36 -0500
commit095163bad59bfeed294a81e0d873fa8943e4fa01 (patch)
treecbab1bb3b847a6c4c39dd0f16ea5347f53309d41
parent8072bfa6045a264d3913102a35fab125b06603a2 (diff)
drm/i915: Add a kludge for DSL incrementing too late and ISR not working
On pre-PCH platforms ISR doesn't seem to be an actual ISR, at least as far as display interrupts are concerned. Instead it sort of looks like some ISR bits just directly reflect the corresponding bit from PIPESTAT. The bit appears in the ISR only if the PIPESTAT interrupt is enabled. So in that sense it sort of looks a bit like the south interrupt scheme on PCH platforms. So it goes something a bit like this: PIPESTAT.status & PIPESTAT.enable -> ISR -> IMR -> IIR -> IER -> actual interrupt In any case that means the intel_pipe_in_vblank_locked() doesn't actually work for pre-PCH platforms. As a last resort, add a similar kludge as radeon has that fixes things up if we got called from the vblank interrupt, but the scanline counter value indicates that we're not quite there yet. We know that the scanline counter increments at hsync but is otherwise accurate, so we can limit the kludge to the line just prior to vblank start, instead of the relative distance that radeon uses. Reviewed-by: mario.kleiner.de@gmail.com Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c79
1 files changed, 39 insertions, 40 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index fb4801c7d9e4..17d8fcb1b6f7 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -621,36 +621,15 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
621#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__)) 621#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
622#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__)) 622#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__))
623 623
624static bool intel_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe) 624static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
625{ 625{
626 struct drm_i915_private *dev_priv = dev->dev_private; 626 struct drm_i915_private *dev_priv = dev->dev_private;
627 uint32_t status; 627 uint32_t status;
628 int reg;
629 628
630 if (IS_VALLEYVIEW(dev)) { 629 if (INTEL_INFO(dev)->gen < 7) {
631 status = pipe == PIPE_A ?
632 I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
633 I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
634
635 reg = VLV_ISR;
636 } else if (IS_GEN2(dev)) {
637 status = pipe == PIPE_A ?
638 I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
639 I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
640
641 reg = ISR;
642 } else if (INTEL_INFO(dev)->gen < 5) {
643 status = pipe == PIPE_A ?
644 I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
645 I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
646
647 reg = ISR;
648 } else if (INTEL_INFO(dev)->gen < 7) {
649 status = pipe == PIPE_A ? 630 status = pipe == PIPE_A ?
650 DE_PIPEA_VBLANK : 631 DE_PIPEA_VBLANK :
651 DE_PIPEB_VBLANK; 632 DE_PIPEB_VBLANK;
652
653 reg = DEISR;
654 } else { 633 } else {
655 switch (pipe) { 634 switch (pipe) {
656 default: 635 default:
@@ -664,14 +643,9 @@ static bool intel_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
664 status = DE_PIPEC_VBLANK_IVB; 643 status = DE_PIPEC_VBLANK_IVB;
665 break; 644 break;
666 } 645 }
667
668 reg = DEISR;
669 } 646 }
670 647
671 if (IS_GEN2(dev)) 648 return __raw_i915_read32(dev_priv, DEISR) & status;
672 return __raw_i915_read16(dev_priv, reg) & status;
673 else
674 return __raw_i915_read32(dev_priv, reg) & status;
675} 649}
676 650
677static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, 651static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
@@ -729,17 +703,42 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
729 else 703 else
730 position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; 704 position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
731 705
732 /* 706 if (HAS_PCH_SPLIT(dev)) {
733 * The scanline counter increments at the leading edge 707 /*
734 * of hsync, ie. it completely misses the active portion 708 * The scanline counter increments at the leading edge
735 * of the line. Fix up the counter at both edges of vblank 709 * of hsync, ie. it completely misses the active portion
736 * to get a more accurate picture whether we're in vblank 710 * of the line. Fix up the counter at both edges of vblank
737 * or not. 711 * to get a more accurate picture whether we're in vblank
738 */ 712 * or not.
739 in_vbl = intel_pipe_in_vblank_locked(dev, pipe); 713 */
740 if ((in_vbl && position == vbl_start - 1) || 714 in_vbl = ilk_pipe_in_vblank_locked(dev, pipe);
741 (!in_vbl && position == vbl_end - 1)) 715 if ((in_vbl && position == vbl_start - 1) ||
742 position = (position + 1) % vtotal; 716 (!in_vbl && position == vbl_end - 1))
717 position = (position + 1) % vtotal;
718 } else {
719 /*
720 * ISR vblank status bits don't work the way we'd want
721 * them to work on non-PCH platforms (for
722 * ilk_pipe_in_vblank_locked()), and there doesn't
723 * appear any other way to determine if we're currently
724 * in vblank.
725 *
726 * Instead let's assume that we're already in vblank if
727 * we got called from the vblank interrupt and the
728 * scanline counter value indicates that we're on the
729 * line just prior to vblank start. This should result
730 * in the correct answer, unless the vblank interrupt
731 * delivery really got delayed for almost exactly one
732 * full frame/field.
733 */
734 if (flags & DRM_CALLED_FROM_VBLIRQ &&
735 position == vbl_start - 1) {
736 position = (position + 1) % vtotal;
737
738 /* Signal this correction as "applied". */
739 ret |= 0x8;
740 }
741 }
743 } else { 742 } else {
744 /* Have access to pixelcount since start of frame. 743 /* Have access to pixelcount since start of frame.
745 * We can split this into vertical and horizontal 744 * We can split this into vertical and horizontal