drm/i915: Try to make sure cxsr is disabled around plane enable/disable
CxSR (or maxfifo on VLV/CHV) blocks somne changes to the plane control
register (enable bit at least, not quite sure about the rest). So in
order to have the plane enable/disable when we want we need to first
kick the hardware out of cxsr.
Unfortunateloy this requires some extra vblank waits. For the CxSR
enable after the plane update we should eventually use an async
vblank worker, but since we don't have that just do sync vblank
waits. For the disable case we have no choice but to do it
synchronously.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Clint Taylor <Clinton.A.Taylor@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 649c5db..b7d42e6 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4725,6 +4725,9 @@
intel_frontbuffer_flip(dev, atomic->fb_bits);
+ if (atomic->disable_cxsr)
+ crtc->wm.cxsr_allowed = true;
+
if (crtc->atomic.update_wm_post)
intel_update_watermarks(&crtc->base);
@@ -4777,6 +4780,11 @@
if (atomic->pre_disable_primary)
intel_pre_disable_primary(&crtc->base);
+
+ if (atomic->disable_cxsr) {
+ crtc->wm.cxsr_allowed = false;
+ intel_set_memory_cxsr(dev_priv, false);
+ }
}
static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask)
@@ -11611,12 +11619,26 @@
plane->base.id, was_visible, visible,
turn_off, turn_on, mode_changed);
- if (turn_on)
+ if (turn_on) {
intel_crtc->atomic.update_wm_pre = true;
- else if (turn_off)
+ /* must disable cxsr around plane enable/disable */
+ if (plane->type != DRM_PLANE_TYPE_CURSOR) {
+ intel_crtc->atomic.disable_cxsr = true;
+ /* to potentially re-enable cxsr */
+ intel_crtc->atomic.wait_vblank = true;
+ intel_crtc->atomic.update_wm_post = true;
+ }
+ } else if (turn_off) {
intel_crtc->atomic.update_wm_post = true;
- else if (intel_wm_need_update(plane, plane_state))
+ /* must disable cxsr around plane enable/disable */
+ if (plane->type != DRM_PLANE_TYPE_CURSOR) {
+ if (is_crtc_enabled)
+ intel_crtc->atomic.wait_vblank = true;
+ intel_crtc->atomic.disable_cxsr = true;
+ }
+ } else if (intel_wm_need_update(plane, plane_state)) {
intel_crtc->atomic.update_wm_pre = true;
+ }
if (visible)
intel_crtc->atomic.fb_bits |=
@@ -11784,8 +11806,8 @@
if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES)
intel_crtc_check_initial_planes(crtc, crtc_state);
- if (mode_changed)
- intel_crtc->atomic.update_wm_post = !crtc_state->active;
+ if (mode_changed && !crtc_state->active)
+ intel_crtc->atomic.update_wm_post = true;
if (mode_changed && crtc_state->enable &&
dev_priv->display.crtc_compute_clock &&
@@ -13105,6 +13127,8 @@
if (!needs_modeset(crtc->state))
continue;
+ intel_pre_plane_update(intel_crtc);
+
any_ms = true;
intel_pre_plane_update(intel_crtc);
@@ -14065,6 +14089,8 @@
intel_crtc->cursor_cntl = ~0;
intel_crtc->cursor_size = ~0;
+ intel_crtc->wm.cxsr_allowed = true;
+
BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
dev_priv->plane_to_crtc_mapping[intel_crtc->plane] != NULL);
dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8397d1c..7f2e204 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -508,6 +508,7 @@
bool wait_for_flips;
bool disable_fbc;
bool disable_ips;
+ bool disable_cxsr;
bool pre_disable_primary;
bool update_wm_pre, update_wm_post;
unsigned disabled_planes;
@@ -566,6 +567,8 @@
struct intel_pipe_wm active;
/* SKL wm values currently in use */
struct skl_pipe_wm skl_active;
+ /* allow CxSR on this pipe */
+ bool cxsr_allowed;
} wm;
int scanline_offset;
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 0cccc44..a023b40 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -335,6 +335,7 @@
if (IS_VALLEYVIEW(dev)) {
I915_WRITE(FW_BLC_SELF_VLV, enable ? FW_CSPWRDWNEN : 0);
POSTING_READ(FW_BLC_SELF_VLV);
+ dev_priv->wm.vlv.cxsr = enable;
} else if (IS_G4X(dev) || IS_CRESTLINE(dev)) {
I915_WRITE(FW_BLC_SELF, enable ? FW_BLC_SELF_EN : 0);
POSTING_READ(FW_BLC_SELF);
@@ -1116,7 +1117,7 @@
memset(wm_state, 0, sizeof(*wm_state));
- wm_state->cxsr = crtc->pipe != PIPE_C;
+ wm_state->cxsr = crtc->pipe != PIPE_C && crtc->wm.cxsr_allowed;
if (IS_CHERRYVIEW(dev))
wm_state->num_levels = CHV_WM_NUM_LEVELS;
else
@@ -1369,10 +1370,8 @@
dev_priv->wm.vlv.level >= VLV_WM_LEVEL_PM5)
chv_set_memory_pm5(dev_priv, false);
- if (!wm.cxsr && dev_priv->wm.vlv.cxsr) {
+ if (!wm.cxsr && dev_priv->wm.vlv.cxsr)
intel_set_memory_cxsr(dev_priv, false);
- intel_wait_for_vblank(dev, pipe);
- }
/* FIXME should be part of crtc atomic commit */
vlv_pipe_set_fifo_size(intel_crtc);
@@ -1385,10 +1384,8 @@
wm.pipe[pipe].sprite[0], wm.pipe[pipe].sprite[1],
wm.sr.plane, wm.sr.cursor, wm.level, wm.cxsr);
- if (wm.cxsr && !dev_priv->wm.vlv.cxsr) {
- intel_wait_for_vblank(dev, pipe);
+ if (wm.cxsr && !dev_priv->wm.vlv.cxsr)
intel_set_memory_cxsr(dev_priv, true);
- }
if (wm.level >= VLV_WM_LEVEL_PM5 &&
dev_priv->wm.vlv.level < VLV_WM_LEVEL_PM5)