drm/i915: Fix scanoutpos calculations
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 <mario.kleiner@tuebingen.mpg.de> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: mario.kleiner.de@gmail.com Tested-by: mario.kleiner.de@gmail.com Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
c2baf4b709
commit
3aa18df8f2
|
@ -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 drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
|
||||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||||
const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
|
const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
|
||||||
u32 position;
|
int position;
|
||||||
int vbl_start, vbl_end, htotal, vtotal;
|
int vbl_start, vbl_end, htotal, vtotal;
|
||||||
bool in_vbl = true;
|
bool in_vbl = true;
|
||||||
int ret = 0;
|
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
|
/* No obvious pixelcount register. Only query vertical
|
||||||
* scanout position from Display scan line register.
|
* scanout position from Display scan line register.
|
||||||
*/
|
*/
|
||||||
position = I915_READ(PIPEDSL(pipe));
|
position = I915_READ(PIPEDSL(pipe)) & 0x1fff;
|
||||||
|
|
||||||
/* Decode into vertical scanout position. Don't have
|
|
||||||
* horizontal scanout position.
|
|
||||||
*/
|
|
||||||
*vpos = position & 0x1fff;
|
|
||||||
*hpos = 0;
|
|
||||||
} else {
|
} else {
|
||||||
/* Have access to pixelcount since start of frame.
|
/* Have access to pixelcount since start of frame.
|
||||||
* We can split this into vertical and horizontal
|
* We can split this into vertical and horizontal
|
||||||
|
@ -635,16 +629,33 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
|
||||||
*/
|
*/
|
||||||
position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
|
position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
|
||||||
|
|
||||||
|
/* convert to pixel counts */
|
||||||
|
vbl_start *= htotal;
|
||||||
|
vbl_end *= htotal;
|
||||||
|
vtotal *= htotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
|
||||||
|
*vpos = position;
|
||||||
|
*hpos = 0;
|
||||||
|
} else {
|
||||||
*vpos = position / htotal;
|
*vpos = position / htotal;
|
||||||
*hpos = position - (*vpos * htotal);
|
*hpos = position - (*vpos * htotal);
|
||||||
}
|
}
|
||||||
|
|
||||||
in_vbl = *vpos >= vbl_start && *vpos < vbl_end;
|
|
||||||
|
|
||||||
/* Inside "upper part" of vblank area? Apply corrective offset: */
|
|
||||||
if (in_vbl && (*vpos >= vbl_start))
|
|
||||||
*vpos = *vpos - vtotal;
|
|
||||||
|
|
||||||
/* In vblank? */
|
/* In vblank? */
|
||||||
if (in_vbl)
|
if (in_vbl)
|
||||||
ret |= DRM_SCANOUTPOS_INVBL;
|
ret |= DRM_SCANOUTPOS_INVBL;
|
||||||
|
|
Loading…
Reference in New Issue