Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3aa18df8 authored by Ville Syrjälä's avatar Ville Syrjälä Committed by Daniel Vetter
Browse files

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: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatar <mario.kleiner.de@gmail.com>
Tested-by: default avatar <mario.kleiner.de@gmail.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent c2baf4b7
Loading
Loading
Loading
Loading
+25 −14
Original line number Diff line number Diff line
@@ -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)