From: Ville Syrj?l? <ville.syrjala at linux.intel.com> The register values are computed when the flip ioctl is issued, and they're used only after we've waited for the GPU to finish rendering. The computed values are store in the intel_crtc and intel_plane structs, so issuing another flip before the previous one has been fully completed would clobber those stored registers. Fix the problem by making a copy of the calculated register values inside the intel_flip structure. The copy is then used when it's time to commit the registers to the hardware. Signed-off-by: Ville Syrj?l? <ville.syrjala at linux.intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 4 +++- drivers/gpu/drm/i915/intel_atomic.c | 8 ++++++-- drivers/gpu/drm/i915/intel_display.c | 14 ++++++++------ drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_sprite.c | 24 ++++++++++++------------ 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 80b4b30..d8e8a4f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -269,6 +269,8 @@ struct drm_i915_error_state { struct intel_display_error_state *display; }; +struct intel_plane_regs; + struct drm_i915_display_funcs { bool (*fbc_enabled)(struct drm_device *dev); void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval); @@ -300,7 +302,7 @@ struct drm_i915_display_funcs { int x, int y); int (*calc_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y); - void (*commit_plane)(struct drm_crtc *crtc); + void (*commit_plane)(struct drm_crtc *crtc, const struct intel_plane_regs *regs); /* clock updates for mode set */ /* cursor updates */ /* render clock increase/decrease */ diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index f59be7f..e52d92a 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -47,6 +47,8 @@ struct intel_flip { struct intel_ring_buffer *ring; u32 seqno; unsigned int flip_seq; + /* FIXME need cursor regs too */ + struct intel_plane_regs regs; }; struct intel_plane_state { @@ -1986,11 +1988,11 @@ static bool intel_flip_flip(struct drm_flip *flip, struct drm_plane *plane = intel_flip->plane; struct intel_plane *intel_plane = to_intel_plane(plane); - intel_plane->commit(plane); + intel_plane->commit(plane, &intel_flip->regs); } else { struct drm_i915_private *dev_priv = dev->dev_private; - dev_priv->display.commit_plane(crtc); + dev_priv->display.commit_plane(crtc, &intel_flip->regs); } if (intel_flip->has_cursor) @@ -2321,6 +2323,7 @@ static void atomic_pipe_commit(struct drm_device *dev, /* should already be checked so can't fail */ /* FIXME refactor the failing parts? */ dev_priv->display.calc_plane(crtc, crtc->fb, crtc->x, crtc->y); + intel_flip->regs = intel_crtc->primary_regs; if (st->cursor_dirty) { intel_flip->has_cursor = true; @@ -2387,6 +2390,7 @@ static void atomic_pipe_commit(struct drm_device *dev, } intel_plane->calc(plane, plane->fb, &st->coords); + intel_flip->regs = intel_plane->regs; if (st->old.fb) intel_flip->old_fb_id = st->old.fb->base.id; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c84a839..390251d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1979,13 +1979,13 @@ unsigned long intel_gen4_compute_offset_xtiled(int *x, int *y, return tile_rows * pitch * 8 + tiles * 4096; } -static void intel_commit_plane(struct drm_crtc *crtc) +static void intel_commit_plane(struct drm_crtc *crtc, + const struct intel_plane_regs *regs) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int plane = intel_crtc->plane; - const struct intel_plane_regs *regs = &intel_crtc->primary_regs; I915_WRITE(DSPCNTR(plane), regs->cntr); I915_WRITE(DSPSTRIDE(plane), regs->stride); @@ -2102,15 +2102,16 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y) { struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int ret; ret = i9xx_calc_plane(crtc, fb, x, y); if (ret) return ret; - intel_commit_plane(crtc); + intel_commit_plane(crtc, &intel_crtc->primary_regs); - POSTING_READ(DSPCNTR(to_intel_crtc(crtc)->plane)); + POSTING_READ(DSPCNTR(intel_crtc->plane)); return 0; } @@ -2206,15 +2207,16 @@ static int ironlake_update_plane(struct drm_crtc *crtc, struct drm_framebuffer * int x, int y) { struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int ret; ret = ironlake_calc_plane(crtc, fb, x, y); if (ret) return ret; - intel_commit_plane(crtc); + intel_commit_plane(crtc, &intel_crtc->primary_regs); - POSTING_READ(DSPCNTR(to_intel_crtc(crtc)->plane)); + POSTING_READ(DSPCNTR(intel_crtc->plane)); return 0; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 33fac47..e39a10b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -277,7 +277,7 @@ struct intel_plane { void (*calc)(struct drm_plane *plane, struct drm_framebuffer *fb, const struct intel_plane_coords *clip); void (*prepare)(struct drm_plane *plane); - void (*commit)(struct drm_plane *plane); + void (*commit)(struct drm_plane *plane, const struct intel_plane_regs *regs); struct intel_plane_regs regs; struct drm_flip_helper flip_helper; }; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index ce3b950..d960e19 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -300,13 +300,13 @@ ivb_calc_plane(struct drm_plane *plane, } static void -ivb_commit_plane(struct drm_plane *plane) +ivb_commit_plane(struct drm_plane *plane, + const struct intel_plane_regs *regs) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe; - const struct intel_plane_regs *regs = &intel_plane->regs; I915_WRITE(SPRKEYVAL(pipe), regs->keyval); I915_WRITE(SPRKEYMAX(pipe), regs->keymaxval); @@ -371,7 +371,7 @@ ivb_update_plane(struct drm_plane *plane, ivb_calc_plane(plane, fb, coords); ivb_prepare_plane(plane); - ivb_commit_plane(plane); + ivb_commit_plane(plane, &intel_plane->regs); POSTING_READ(SPRSURF(pipe)); } @@ -387,7 +387,7 @@ ivb_disable_plane(struct drm_plane *plane) regs->cntr &= ~SPRITE_ENABLE; /* Can't leave the scaler enabled... */ regs->scale = 0; - ivb_commit_plane(plane); + ivb_commit_plane(plane, regs); POSTING_READ(SPRSURF(pipe)); dev_priv->sprite_scaling_enabled &= ~(1 << pipe); @@ -413,7 +413,7 @@ ivb_update_colorkey(struct drm_plane *plane, else if (key->flags & I915_SET_COLORKEY_SOURCE) regs->cntr |= SPRITE_SOURCE_KEY; - ivb_commit_plane(plane); + ivb_commit_plane(plane, regs); POSTING_READ(SPRKEYMSK(intel_plane->pipe)); return 0; @@ -546,13 +546,13 @@ ilk_prepare_plane(struct drm_plane *plane) } static void -ilk_commit_plane(struct drm_plane *plane) +ilk_commit_plane(struct drm_plane *plane, + const struct intel_plane_regs *regs) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe; - const struct intel_plane_regs *regs = &intel_plane->regs; I915_WRITE(DVSKEYVAL(pipe), regs->keyval); I915_WRITE(DVSKEYMAX(pipe), regs->keymaxval); @@ -579,7 +579,7 @@ ilk_update_plane(struct drm_plane *plane, ilk_calc_plane(plane, fb, coords); ilk_prepare_plane(plane); - ilk_commit_plane(plane); + ilk_commit_plane(plane, &intel_plane->regs); POSTING_READ(DVSSURF(pipe)); } @@ -595,7 +595,7 @@ ilk_disable_plane(struct drm_plane *plane) regs->cntr &= ~DVS_ENABLE; /* Disable the scaler */ regs->scale = 0; - ilk_commit_plane(plane); + ilk_commit_plane(plane, regs); POSTING_READ(DVSSURF(pipe)); } @@ -627,7 +627,7 @@ intel_enable_primary(struct drm_crtc *crtc) intel_update_fbc(dev); regs->cntr = I915_READ(reg) | DISPLAY_PLANE_ENABLE; - dev_priv->display.commit_plane(crtc); + dev_priv->display.commit_plane(crtc, regs); } void @@ -643,7 +643,7 @@ intel_disable_primary(struct drm_crtc *crtc) return; regs->cntr = I915_READ(reg) & ~DISPLAY_PLANE_ENABLE; - dev_priv->display.commit_plane(crtc); + dev_priv->display.commit_plane(crtc, regs); intel_crtc->primary_disabled = true; intel_update_fbc(dev); @@ -668,7 +668,7 @@ ilk_update_colorkey(struct drm_plane *plane, else if (key->flags & I915_SET_COLORKEY_SOURCE) regs->cntr |= DVS_SOURCE_KEY; - ilk_commit_plane(plane); + ilk_commit_plane(plane, regs); POSTING_READ(DVSKEYMSK(intel_plane->pipe)); return 0; -- 1.7.8.6