Commit 54ddcbd2 authored by Ville Syrjälä's avatar Ville Syrjälä Committed by Daniel Vetter

drm/i915: Improve the accuracy of get_scanout_pos on CTG+

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 <mario.kleiner@tuebingen.mpg.de>
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: mario.kleiner.de@gmail.com
Tested-by: mario.kleiner.de@gmail.com
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 3aa18df8
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment