Merge tag 'drm-intel-gt-next-2022-06-29' of git://anongit.freedesktop.org/drm/drm...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / i915 / intel_pm.c
index 7a3f023d39e968f8e9af7c55d364fbad45d86268..9b7e93ca1ff9edfd22843395b9bac301b877ec1f 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/pm_runtime.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_plane_helper.h>
 
@@ -2862,7 +2863,7 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv,
 }
 
 static void intel_read_wm_latency(struct drm_i915_private *dev_priv,
-                                 u16 wm[8])
+                                 u16 wm[])
 {
        struct intel_uncore *uncore = &dev_priv->uncore;
 
@@ -4368,9 +4369,9 @@ skl_ddb_get_hw_plane_state(struct drm_i915_private *dev_priv,
        skl_ddb_entry_init_from_hw(ddb_y, val);
 }
 
-void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
-                              struct skl_ddb_entry *ddb,
-                              struct skl_ddb_entry *ddb_y)
+static void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
+                                     struct skl_ddb_entry *ddb,
+                                     struct skl_ddb_entry *ddb_y)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        enum intel_display_power_domain power_domain;
@@ -4950,7 +4951,7 @@ skl_total_relative_data_rate(const struct intel_crtc_state *crtc_state)
        return data_rate;
 }
 
-const struct skl_wm_level *
+static const struct skl_wm_level *
 skl_plane_wm_level(const struct skl_pipe_wm *pipe_wm,
                   enum plane_id plane_id,
                   int level)
@@ -4963,7 +4964,7 @@ skl_plane_wm_level(const struct skl_pipe_wm *pipe_wm,
        return &wm->wm[level];
 }
 
-const struct skl_wm_level *
+static const struct skl_wm_level *
 skl_plane_trans_wm(const struct skl_pipe_wm *pipe_wm,
                   enum plane_id plane_id)
 {
@@ -5915,8 +5916,8 @@ void skl_write_cursor_wm(struct intel_plane *plane,
        skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe), ddb);
 }
 
-bool skl_wm_level_equals(const struct skl_wm_level *l1,
-                        const struct skl_wm_level *l2)
+static bool skl_wm_level_equals(const struct skl_wm_level *l1,
+                               const struct skl_wm_level *l2)
 {
        return l1->enable == l2->enable &&
                l1->ignore_lines == l2->ignore_lines &&
@@ -6488,8 +6489,8 @@ static void skl_wm_level_from_reg_val(u32 val, struct skl_wm_level *level)
        level->lines = REG_FIELD_GET(PLANE_WM_LINES_MASK, val);
 }
 
-void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc,
-                             struct skl_pipe_wm *out)
+static void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc,
+                                    struct skl_pipe_wm *out)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        enum pipe pipe = crtc->pipe;
@@ -7166,6 +7167,126 @@ void ilk_wm_get_hw_state(struct drm_i915_private *dev_priv)
                !(intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) & DISP_FBC_WM_DIS);
 }
 
+void intel_wm_state_verify(struct intel_crtc *crtc,
+                          struct intel_crtc_state *new_crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       struct skl_hw_state {
+               struct skl_ddb_entry ddb[I915_MAX_PLANES];
+               struct skl_ddb_entry ddb_y[I915_MAX_PLANES];
+               struct skl_pipe_wm wm;
+       } *hw;
+       const struct skl_pipe_wm *sw_wm = &new_crtc_state->wm.skl.optimal;
+       int level, max_level = ilk_wm_max_level(dev_priv);
+       struct intel_plane *plane;
+       u8 hw_enabled_slices;
+
+       if (DISPLAY_VER(dev_priv) < 9 || !new_crtc_state->hw.active)
+               return;
+
+       hw = kzalloc(sizeof(*hw), GFP_KERNEL);
+       if (!hw)
+               return;
+
+       skl_pipe_wm_get_hw_state(crtc, &hw->wm);
+
+       skl_pipe_ddb_get_hw_state(crtc, hw->ddb, hw->ddb_y);
+
+       hw_enabled_slices = intel_enabled_dbuf_slices_mask(dev_priv);
+
+       if (DISPLAY_VER(dev_priv) >= 11 &&
+           hw_enabled_slices != dev_priv->dbuf.enabled_slices)
+               drm_err(&dev_priv->drm,
+                       "mismatch in DBUF Slices (expected 0x%x, got 0x%x)\n",
+                       dev_priv->dbuf.enabled_slices,
+                       hw_enabled_slices);
+
+       for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
+               const struct skl_ddb_entry *hw_ddb_entry, *sw_ddb_entry;
+               const struct skl_wm_level *hw_wm_level, *sw_wm_level;
+
+               /* Watermarks */
+               for (level = 0; level <= max_level; level++) {
+                       hw_wm_level = &hw->wm.planes[plane->id].wm[level];
+                       sw_wm_level = skl_plane_wm_level(sw_wm, plane->id, level);
+
+                       if (skl_wm_level_equals(hw_wm_level, sw_wm_level))
+                               continue;
+
+                       drm_err(&dev_priv->drm,
+                               "[PLANE:%d:%s] mismatch in WM%d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n",
+                               plane->base.base.id, plane->base.name, level,
+                               sw_wm_level->enable,
+                               sw_wm_level->blocks,
+                               sw_wm_level->lines,
+                               hw_wm_level->enable,
+                               hw_wm_level->blocks,
+                               hw_wm_level->lines);
+               }
+
+               hw_wm_level = &hw->wm.planes[plane->id].trans_wm;
+               sw_wm_level = skl_plane_trans_wm(sw_wm, plane->id);
+
+               if (!skl_wm_level_equals(hw_wm_level, sw_wm_level)) {
+                       drm_err(&dev_priv->drm,
+                               "[PLANE:%d:%s] mismatch in trans WM (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n",
+                               plane->base.base.id, plane->base.name,
+                               sw_wm_level->enable,
+                               sw_wm_level->blocks,
+                               sw_wm_level->lines,
+                               hw_wm_level->enable,
+                               hw_wm_level->blocks,
+                               hw_wm_level->lines);
+               }
+
+               hw_wm_level = &hw->wm.planes[plane->id].sagv.wm0;
+               sw_wm_level = &sw_wm->planes[plane->id].sagv.wm0;
+
+               if (HAS_HW_SAGV_WM(dev_priv) &&
+                   !skl_wm_level_equals(hw_wm_level, sw_wm_level)) {
+                       drm_err(&dev_priv->drm,
+                               "[PLANE:%d:%s] mismatch in SAGV WM (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n",
+                               plane->base.base.id, plane->base.name,
+                               sw_wm_level->enable,
+                               sw_wm_level->blocks,
+                               sw_wm_level->lines,
+                               hw_wm_level->enable,
+                               hw_wm_level->blocks,
+                               hw_wm_level->lines);
+               }
+
+               hw_wm_level = &hw->wm.planes[plane->id].sagv.trans_wm;
+               sw_wm_level = &sw_wm->planes[plane->id].sagv.trans_wm;
+
+               if (HAS_HW_SAGV_WM(dev_priv) &&
+                   !skl_wm_level_equals(hw_wm_level, sw_wm_level)) {
+                       drm_err(&dev_priv->drm,
+                               "[PLANE:%d:%s] mismatch in SAGV trans WM (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n",
+                               plane->base.base.id, plane->base.name,
+                               sw_wm_level->enable,
+                               sw_wm_level->blocks,
+                               sw_wm_level->lines,
+                               hw_wm_level->enable,
+                               hw_wm_level->blocks,
+                               hw_wm_level->lines);
+               }
+
+               /* DDB */
+               hw_ddb_entry = &hw->ddb[PLANE_CURSOR];
+               sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[PLANE_CURSOR];
+
+               if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
+                       drm_err(&dev_priv->drm,
+                               "[PLANE:%d:%s] mismatch in DDB (expected (%u,%u), found (%u,%u))\n",
+                               plane->base.base.id, plane->base.name,
+                               sw_ddb_entry->start, sw_ddb_entry->end,
+                               hw_ddb_entry->start, hw_ddb_entry->end);
+               }
+       }
+
+       kfree(hw);
+}
+
 void intel_enable_ipc(struct drm_i915_private *dev_priv)
 {
        u32 val;