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

Commit 52e68630 authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915: Fix offset page-flips on i965+



i965 uses the Display Registers to compute the offset from the display
base so the new base does not need adjusting when flipping. The older
chipsets use a fence to access the display and so do perceive the
surface as linear and have a single base register which is reprogrammed
using the flip.

Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Reported-by: default avatarMarty Jack <martyj19@comcast.net>
Reviewed-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent c96c3a8c
Loading
Loading
Loading
Loading
+48 −19
Original line number Diff line number Diff line
@@ -5042,9 +5042,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
	struct intel_unpin_work *work;
	unsigned long flags, offset;
	int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC;
	int ret, pipesrc;
	u32 flip_mask;
	int pipe = intel_crtc->pipe;
	u32 pf, pipesrc;
	int ret;

	work = kzalloc(sizeof *work, GFP_KERNEL);
	if (work == NULL)
@@ -5093,12 +5093,14 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
	atomic_inc(&obj_priv->pending_flip);
	work->pending_flip_obj = obj;

	if (IS_GEN3(dev) || IS_GEN2(dev)) {
		u32 flip_mask;

		if (intel_crtc->plane)
			flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
		else
			flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;

	if (IS_GEN3(dev) || IS_GEN2(dev)) {
		BEGIN_LP_RING(2);
		OUT_RING(MI_WAIT_FOR_EVENT | flip_mask);
		OUT_RING(0);
@@ -5106,29 +5108,56 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
	}

	/* Offset into the new buffer for cases of shared fbs between CRTCs */
	offset = obj_priv->gtt_offset;
	offset += (crtc->y * fb->pitch) + (crtc->x * (fb->bits_per_pixel) / 8);
	offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8;

	BEGIN_LP_RING(4);
	if (IS_I965G(dev)) {
	switch(INTEL_INFO(dev)->gen) {
	case 2:
		OUT_RING(MI_DISPLAY_FLIP |
			 MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
		OUT_RING(fb->pitch);
		OUT_RING(offset | obj_priv->tiling_mode);
		pipesrc = I915_READ(pipesrc_reg); 
		OUT_RING(pipesrc & 0x0fff0fff);
	} else if (IS_GEN3(dev)) {
		OUT_RING(obj_priv->gtt_offset + offset);
		OUT_RING(MI_NOOP);
		break;

	case 3:
		OUT_RING(MI_DISPLAY_FLIP_I915 |
			 MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
		OUT_RING(fb->pitch);
		OUT_RING(offset);
		OUT_RING(obj_priv->gtt_offset + offset);
		OUT_RING(MI_NOOP);
	} else {
		break;

	case 4:
	case 5:
		/* i965+ uses the linear or tiled offsets from the
		 * Display Registers (which do not change across a page-flip)
		 * so we need only reprogram the base address.
		 */
		OUT_RING(MI_DISPLAY_FLIP |
			 MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
		OUT_RING(fb->pitch);
		OUT_RING(offset);
		OUT_RING(MI_NOOP);
		OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode);

		/* XXX Enabling the panel-fitter across page-flip is so far
		 * untested on non-native modes, so ignore it for now.
		 * pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE;
		 */
		pf = 0;
		pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff;
		OUT_RING(pf | pipesrc);
		break;

	case 6:
		OUT_RING(MI_DISPLAY_FLIP |
			 MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
		OUT_RING(fb->pitch | obj_priv->tiling_mode);
		OUT_RING(obj_priv->gtt_offset);

		pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE;
		pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff;
		OUT_RING(pf | pipesrc);
		break;
	}
	ADVANCE_LP_RING();