diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_pm.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_pm.c | 148 |
1 files changed, 134 insertions, 14 deletions
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 16a08be7a99a..3355486a0b20 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2875,7 +2875,7 @@ static void intel_read_wm_latency(struct drm_i915_private *dev_priv, /* read the first set of memory latencies[0:3] */ val = 0; /* data0 to be programmed to 0 for first set */ - ret = snb_pcode_read(dev_priv, GEN9_PCODE_READ_MEM_LATENCY, + ret = snb_pcode_read(&dev_priv->uncore, GEN9_PCODE_READ_MEM_LATENCY, &val, NULL); if (ret) { @@ -2894,7 +2894,7 @@ static void intel_read_wm_latency(struct drm_i915_private *dev_priv, /* read the second set of memory latencies[4:7] */ val = 1; /* data0 to be programmed to 1 for second set */ - ret = snb_pcode_read(dev_priv, GEN9_PCODE_READ_MEM_LATENCY, + ret = snb_pcode_read(&dev_priv->uncore, GEN9_PCODE_READ_MEM_LATENCY, &val, NULL); if (ret) { drm_err(&dev_priv->drm, @@ -3680,7 +3680,7 @@ intel_sagv_block_time(struct drm_i915_private *dev_priv) u32 val = 0; int ret; - ret = snb_pcode_read(dev_priv, + ret = snb_pcode_read(&dev_priv->uncore, GEN12_PCODE_READ_SAGV_BLOCK_TIME_US, &val, NULL); if (ret) { @@ -3749,7 +3749,7 @@ static void skl_sagv_enable(struct drm_i915_private *dev_priv) return; drm_dbg_kms(&dev_priv->drm, "Enabling SAGV\n"); - ret = snb_pcode_write(dev_priv, GEN9_PCODE_SAGV_CONTROL, + ret = snb_pcode_write(&dev_priv->uncore, GEN9_PCODE_SAGV_CONTROL, GEN9_SAGV_ENABLE); /* We don't need to wait for SAGV when enabling */ @@ -3782,7 +3782,7 @@ static void skl_sagv_disable(struct drm_i915_private *dev_priv) drm_dbg_kms(&dev_priv->drm, "Disabling SAGV\n"); /* bspec says to keep retrying for at least 1 ms */ - ret = skl_pcode_request(dev_priv, GEN9_PCODE_SAGV_CONTROL, + ret = skl_pcode_request(&dev_priv->uncore, GEN9_PCODE_SAGV_CONTROL, GEN9_SAGV_DISABLE, GEN9_SAGV_IS_DISABLED, GEN9_SAGV_IS_DISABLED, 1); @@ -4369,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; @@ -4951,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) @@ -4964,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) { @@ -5916,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 && @@ -6489,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; @@ -7167,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; |