From: Ville Syrjälä <ville.syrj...@linux.intel.com>

Since the watermark registers arent double buffered on VLV/CHV, we'll
need to play around with intermediate watermarks same was as we do on
ILK-BDW.

The watermark registers on VLV/CHV contain inverted values, so to find
the intermediate watermark value we just take the minimum of the
active and optimal values. This also means that, unlike ILK-BDW,
there's no chance that we'd fail to find a working intermediate
watermarks. As long as both the active and optimal watermarks are valid
the intermediate watermarks will come out valid as well.

Signed-off-by: Ville Syrjälä <ville.syrj...@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_drv.h |  3 +-
 drivers/gpu/drm/i915/intel_pm.c  | 59 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index a92857864ee8..f66b3ce89ec4 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -527,7 +527,8 @@ struct intel_crtc_wm_state {
                        /* non-inverted optimal watermarks */
                        struct vlv_pipe_wm noninverted[NUM_VLV_WM_LEVELS];
                        struct vlv_fifo_state fifo_state;
-                       /* inverted optimal watermarks */
+                       /* inverted intermediate and optimal watermarks */
+                       struct vlv_wm_state intermediate;
                        struct vlv_wm_state optimal;
                } vlv;
        };
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index c7cc62cf51f6..c4f395370e9d 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -1379,6 +1379,45 @@ static void vlv_atomic_update_fifo(struct 
intel_atomic_state *state,
 
 #undef VLV_FIFO
 
+static int vlv_compute_intermediate_wm(struct drm_device *dev,
+                                      struct intel_crtc *crtc,
+                                      struct intel_crtc_state *crtc_state)
+{
+       struct vlv_wm_state *intermediate = &crtc_state->wm.vlv.intermediate;
+       const struct vlv_wm_state *optimal = &crtc_state->wm.vlv.optimal;
+       const struct vlv_wm_state *active = &crtc->wm.active.vlv;
+       int level;
+
+       intermediate->num_levels = min(optimal->num_levels, active->num_levels);
+       intermediate->cxsr = optimal->cxsr & active->cxsr;
+
+       for (level = 0; level < intermediate->num_levels; level++) {
+               enum plane_id plane_id;
+
+               for_each_plane_id_on_crtc(crtc, plane_id) {
+                       intermediate->wm[level].plane[plane_id] =
+                               min(optimal->wm[level].plane[plane_id],
+                                   active->wm[level].plane[plane_id]);
+               }
+
+               intermediate->sr[level].plane = min(optimal->sr[level].plane,
+                                                   active->sr[level].plane);
+               intermediate->sr[level].cursor = min(optimal->sr[level].cursor,
+                                                    active->sr[level].cursor);
+       }
+
+       vlv_invalidate_wms(crtc, intermediate, level);
+
+       /*
+        * If our intermediate WM are identical to the final WM, then we can
+        * omit the post-vblank programming; only update if it's different.
+        */
+       if (memcmp(intermediate, optimal, sizeof(*intermediate)) == 0)
+               crtc_state->wm.need_postvbl_update = false;
+
+       return 0;
+}
+
 static void vlv_merge_wm(struct drm_i915_private *dev_priv,
                         struct vlv_wm_values *wm)
 {
@@ -1472,7 +1511,22 @@ static void vlv_initial_watermarks(struct 
intel_atomic_state *state,
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
 
        mutex_lock(&dev_priv->wm.wm_mutex);
-       crtc->wm.active.vlv = crtc_state->wm.vlv.optimal;
+       crtc->wm.active.vlv = crtc_state->wm.vlv.intermediate;
+       vlv_program_watermarks(dev_priv);
+       mutex_unlock(&dev_priv->wm.wm_mutex);
+}
+
+static void vlv_optimize_watermarks(struct intel_atomic_state *state,
+                                   struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+
+       if (!crtc_state->wm.need_postvbl_update)
+               return;
+
+       mutex_lock(&dev_priv->wm.wm_mutex);
+       intel_crtc->wm.active.vlv = crtc_state->wm.vlv.optimal;
        vlv_program_watermarks(dev_priv);
        mutex_unlock(&dev_priv->wm.wm_mutex);
 }
@@ -4696,6 +4750,7 @@ void vlv_wm_get_hw_state(struct drm_device *dev)
                vlv_invalidate_wms(crtc, active, level);
 
                crtc_state->wm.vlv.optimal = *active;
+               crtc_state->wm.vlv.intermediate = *active;
 
                DRM_DEBUG_KMS("Initial watermarks: pipe %c, plane=%d, 
cursor=%d, sprite0=%d, sprite1=%d\n",
                              pipe_name(pipe),
@@ -7832,7 +7887,9 @@ void intel_init_pm(struct drm_i915_private *dev_priv)
        } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
                vlv_setup_wm_latency(dev_priv);
                dev_priv->display.compute_pipe_wm = vlv_compute_pipe_wm;
+               dev_priv->display.compute_intermediate_wm = 
vlv_compute_intermediate_wm;
                dev_priv->display.initial_watermarks = vlv_initial_watermarks;
+               dev_priv->display.optimize_watermarks = vlv_optimize_watermarks;
                dev_priv->display.atomic_update_watermarks = 
vlv_atomic_update_fifo;
        } else if (IS_PINEVIEW(dev_priv)) {
                if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev_priv),
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to