drm/i915: Try to make sure cxsr is disabled around plane enable/disable
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 24 Jun 2015 19:00:07 +0000 (22:00 +0300)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Mon, 29 Jun 2015 08:58:07 +0000 (10:58 +0200)
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>
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_pm.c

index 649c5dba5463eff98b775ed290d1cbf72a705290..b7d42e6aac1090102454c93b44ced28e87695a0c 100644 (file)
@@ -4725,6 +4725,9 @@ static void intel_post_plane_update(struct intel_crtc *crtc)
 
        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 @@ static void intel_pre_plane_update(struct intel_crtc *crtc)
 
        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 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
                         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 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
        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 @@ static int __intel_set_mode(struct drm_atomic_state *state)
                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 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        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;
index 8397d1c9005bfe504155bbc37ccb504865a5bccb..7f2e204b9fb5ae5c4da2c76e663771c5ffeb2324 100644 (file)
@@ -508,6 +508,7 @@ struct intel_crtc_atomic_commit {
        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_crtc {
                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;
index 0cccc44e1828e94a08dd24187b685983776da6bf..a023b40c046b77be2c13d3cf31cf79ca033ca1eb 100644 (file)
@@ -335,6 +335,7 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
        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 @@ static void vlv_compute_wm(struct intel_crtc *crtc)
 
        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 @@ static void vlv_update_wm(struct drm_crtc *crtc)
            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 @@ static void vlv_update_wm(struct drm_crtc *crtc)
                      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)