summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2019-11-28 17:03:38 +0200
committerVille Syrjälä <ville.syrjala@linux.intel.com>2019-12-09 16:10:58 +0200
commit07fd0df822cc1818fe8ef9760f9f51116789da5e (patch)
tree9bac40950511f03e86de76a605d14162318d0404
parent6252bb78fcc30f3d5166e7af98a6f403fddc46cf (diff)
downloadlinux-07fd0df822cc1818fe8ef9760f9f51116789da5e.tar.gz
linux-07fd0df822cc1818fe8ef9760f9f51116789da5e.tar.bz2
linux-07fd0df822cc1818fe8ef9760f9f51116789da5e.zip
drm/i915/fbc: Wait for vblank after FBC disable on glk+
On glk+ the hardware gets confused if we disable FBC while it's recompressing and we perform a plane update during the same frame. The result is that top of the screen gets corrupted. We can avoid that by giving the hardware enough time to finish the FBC disable before we touch the plane registers. Ie. we need an extra vblank wait after FBC disable. v2: Don't do the vblank wait if we never activated FBC in hw Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20191128150338.12490-1-ville.syrjala@linux.intel.com Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbc.c29
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbc.h2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h1
4 files changed, 32 insertions, 4 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 538418b4889d..5c50b7d2db25 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -6063,6 +6063,10 @@ static void intel_pre_plane_update(struct intel_atomic_state *state,
if (hsw_pre_update_disable_ips(old_crtc_state, new_crtc_state))
hsw_disable_ips(old_crtc_state);
+ if (new_primary_state &&
+ intel_fbc_pre_update(crtc, new_crtc_state, new_primary_state))
+ intel_wait_for_vblank(dev_priv, pipe);
+
if (new_primary_state)
intel_fbc_pre_update(crtc, new_crtc_state, new_primary_state);
diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c
index c6ab5a051883..68416e312e5c 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.c
+++ b/drivers/gpu/drm/i915/display/intel_fbc.c
@@ -362,6 +362,7 @@ static void intel_fbc_hw_activate(struct drm_i915_private *dev_priv)
struct intel_fbc *fbc = &dev_priv->fbc;
fbc->active = true;
+ fbc->activated = true;
if (INTEL_GEN(dev_priv) >= 7)
gen7_fbc_activate(dev_priv);
@@ -859,16 +860,17 @@ static bool intel_fbc_can_flip_nuke(const struct intel_crtc_state *crtc_state)
return true;
}
-void intel_fbc_pre_update(struct intel_crtc *crtc,
+bool intel_fbc_pre_update(struct intel_crtc *crtc,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
struct intel_fbc *fbc = &dev_priv->fbc;
const char *reason = "update pending";
+ bool need_vblank_wait = false;
if (!fbc_supported(dev_priv))
- return;
+ return need_vblank_wait;
mutex_lock(&fbc->lock);
@@ -878,10 +880,31 @@ void intel_fbc_pre_update(struct intel_crtc *crtc,
intel_fbc_update_state_cache(crtc, crtc_state, plane_state);
fbc->flip_pending = true;
- if (!intel_fbc_can_flip_nuke(crtc_state))
+ if (!intel_fbc_can_flip_nuke(crtc_state)) {
intel_fbc_deactivate(dev_priv, reason);
+
+ /*
+ * Display WA #1198: glk+
+ * Need an extra vblank wait between FBC disable and most plane
+ * updates. Bspec says this is only needed for plane disable, but
+ * that is not true. Touching most plane registers will cause the
+ * corruption to appear. Also SKL/derivatives do not seem to be
+ * affected.
+ *
+ * TODO: could optimize this a bit by sampling the frame
+ * counter when we disable FBC (if it was already done earlier)
+ * and skipping the extra vblank wait before the plane update
+ * if at least one frame has already passed.
+ */
+ if (fbc->activated &&
+ (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)))
+ need_vblank_wait = true;
+ fbc->activated = false;
+ }
unlock:
mutex_unlock(&fbc->lock);
+
+ return need_vblank_wait;
}
/**
diff --git a/drivers/gpu/drm/i915/display/intel_fbc.h b/drivers/gpu/drm/i915/display/intel_fbc.h
index 3e7905003e4e..c8a5e5098687 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.h
+++ b/drivers/gpu/drm/i915/display/intel_fbc.h
@@ -19,7 +19,7 @@ struct intel_plane_state;
void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv,
struct intel_atomic_state *state);
bool intel_fbc_is_active(struct drm_i915_private *dev_priv);
-void intel_fbc_pre_update(struct intel_crtc *crtc,
+bool intel_fbc_pre_update(struct intel_crtc *crtc,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
void intel_fbc_post_update(struct intel_crtc *crtc);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 729f542d5de2..ce130e1f1e47 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -374,6 +374,7 @@ struct intel_fbc {
bool false_color;
bool active;
+ bool activated;
bool flip_pending;
bool underrun_detected;