From 54ddcbd26a677524d4bcd9f2a9539e6d743592d8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 23 Sep 2013 13:02:07 +0300 Subject: [PATCH] drm/i915: Improve the accuracy of get_scanout_pos on CTG+ MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The DSL register increments at the start of horizontal sync, so it manages to miss the entire active portion of the current line. Improve the get_scanoutpos accuracy a bit when the scanout position is close to the start or end of vblank. We can do that by double checking the DSL value against the vblank status bit from ISR. Cc: Mario Kleiner Signed-off-by: Ville Syrjälä Reviewed-by: mario.kleiner.de@gmail.com Tested-by: mario.kleiner.de@gmail.com Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a923dea245ac..dfa5c68c2763 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -592,6 +592,47 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) return I915_READ(reg); } +static bool g4x_pipe_in_vblank(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t status; + + if (IS_VALLEYVIEW(dev)) { + status = pipe == PIPE_A ? + I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT : + I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; + + return I915_READ(VLV_ISR) & status; + } else if (IS_G4X(dev)) { + status = pipe == PIPE_A ? + I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT : + I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; + + return I915_READ(ISR) & status; + } else if (INTEL_INFO(dev)->gen < 7) { + status = pipe == PIPE_A ? + DE_PIPEA_VBLANK : + DE_PIPEB_VBLANK; + + return I915_READ(DEISR) & status; + } else { + switch (pipe) { + default: + case PIPE_A: + status = DE_PIPEA_VBLANK_IVB; + break; + case PIPE_B: + status = DE_PIPEB_VBLANK_IVB; + break; + case PIPE_C: + status = DE_PIPEC_VBLANK_IVB; + break; + } + + return I915_READ(DEISR) & status; + } +} + static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, int *vpos, int *hpos) { @@ -622,6 +663,18 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, * scanout position from Display scan line register. */ position = I915_READ(PIPEDSL(pipe)) & 0x1fff; + + /* + * The scanline counter increments at the leading edge + * of hsync, ie. it completely misses the active portion + * of the line. Fix up the counter at both edges of vblank + * to get a more accurate picture whether we're in vblank + * or not. + */ + in_vbl = g4x_pipe_in_vblank(dev, pipe); + if ((in_vbl && position == vbl_start - 1) || + (!in_vbl && position == vbl_end - 1)) + position = (position + 1) % vtotal; } else { /* Have access to pixelcount since start of frame. * We can split this into vertical and horizontal -- 2.20.1