From 3aa18df8f22f24ab6ccd4155cb34ef6bff2f2a1c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 11 Oct 2013 19:10:32 +0300 Subject: [PATCH] drm/i915: Fix scanoutpos calculations MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The reported scanout position must be relative to the end of vblank. Currently we manage to fumble that in a few ways. First we don't consider the case when vtotal != vbl_end. While that isn't very common (happens maybe only w/ old panel fitting hardware), we can fix it easily enough. The second issue is that on pre-CTG hardware we convert the pixel count to horizontal/vertical components at the very beginning, and then forget to adjust the horizontal component to be relative to vbl_end. So instead we should keep our numbers in the pixel count domain while we're adjusting the position to be relative to vbl_end. Then when we do the conversion in the end, both vertical _and_ horizontal components will come out correct. v2: Change position to int from u32 to avoid sign issues 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 | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index cc35d52..a923dea 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -599,7 +599,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode; - u32 position; + int position; int vbl_start, vbl_end, htotal, vtotal; bool in_vbl = true; int ret = 0; @@ -621,13 +621,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, /* No obvious pixelcount register. Only query vertical * scanout position from Display scan line register. */ - position = I915_READ(PIPEDSL(pipe)); - - /* Decode into vertical scanout position. Don't have - * horizontal scanout position. - */ - *vpos = position & 0x1fff; - *hpos = 0; + position = I915_READ(PIPEDSL(pipe)) & 0x1fff; } else { /* Have access to pixelcount since start of frame. * We can split this into vertical and horizontal @@ -635,15 +629,32 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, */ position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT; - *vpos = position / htotal; - *hpos = position - (*vpos * htotal); + /* convert to pixel counts */ + vbl_start *= htotal; + vbl_end *= htotal; + vtotal *= htotal; } - in_vbl = *vpos >= vbl_start && *vpos < vbl_end; + in_vbl = position >= vbl_start && position < vbl_end; + + /* + * While in vblank, position will be negative + * counting up towards 0 at vbl_end. And outside + * vblank, position will be positive counting + * up since vbl_end. + */ + if (position >= vbl_start) + position -= vbl_end; + else + position += vtotal - vbl_end; - /* Inside "upper part" of vblank area? Apply corrective offset: */ - if (in_vbl && (*vpos >= vbl_start)) - *vpos = *vpos - vtotal; + if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { + *vpos = position; + *hpos = 0; + } else { + *vpos = position / htotal; + *hpos = position - (*vpos * htotal); + } /* In vblank? */ if (in_vbl) -- 2.7.4