From 7845a3c96dbd078873947d716a0a991d5d0f578f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 19 Aug 2013 19:08:55 +0100 Subject: [PATCH] drm/i915: Use RCS flips on Haswell RCS flips do work on Iybridge+ so long as we can unmask the messages through DERRMR. However, due to an issue with events being lost if multiple events are unmasked in DERRMR on Ivybridge, we can only use RCS flips from Haswell onwards. Bugzlla: https://bugs.freedesktop.org/show_bug.cgi?id=67600 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 66 +++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 727a123..0b34755 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7709,6 +7709,67 @@ err: return ret; } +/* + * On HSW, we can trick RCS to work by unmasking the events through DERRMR. + * This fails on earlier generations as events may be lost if multiple events + * are sent at once. + */ +static int intel_hsw7_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_ring_buffer *ring; + uint32_t plane_bit = 0; + int ret; + + I915_WRITE(DERRMR, 0); + + ring = obj->ring; + if (ring == NULL) + ring = &dev_priv->ring[BCS]; + + ret = intel_pin_and_fence_fb_obj(dev, obj, ring); + if (ret) + goto err; + + switch(intel_crtc->plane) { + case PLANE_A: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_A; + break; + case PLANE_B: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_B; + break; + case PLANE_C: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_C; + break; + default: + WARN_ONCE(1, "unknown plane in flip command\n"); + ret = -ENODEV; + goto err_unpin; + } + + ret = intel_ring_begin(ring, 4); + if (ret) + goto err_unpin; + + intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit); + intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode)); + intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); + intel_ring_emit(ring, (MI_NOOP)); + + intel_mark_page_flip_active(intel_crtc); + __intel_ring_advance(ring); + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: + return ret; +} + static int intel_default_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -9681,7 +9742,10 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.queue_flip = intel_gen6_queue_flip; break; case 7: - dev_priv->display.queue_flip = intel_gen7_queue_flip; + if (IS_HSW(dev)) + dev_priv->display.queue_flip = intel_hsw_queue_flip; + else + dev_priv->display.queue_flip = intel_gen7_queue_flip; break; } } -- 1.8.4.rc2