diff options
| -rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 79 |
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 | ||
| 624 | static bool intel_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe) | 624 | static 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 | ||
| 677 | static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, | 651 | static 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 |
