|
@@ -2278,6 +2278,29 @@ static void skl_setup_wm_latency(struct drm_device *dev)
|
|
intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency);
|
|
intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool ilk_validate_pipe_wm(struct drm_device *dev,
|
|
|
|
+ struct intel_pipe_wm *pipe_wm)
|
|
|
|
+{
|
|
|
|
+ /* LP0 watermark maximums depend on this pipe alone */
|
|
|
|
+ const struct intel_wm_config config = {
|
|
|
|
+ .num_pipes_active = 1,
|
|
|
|
+ .sprites_enabled = pipe_wm->sprites_enabled,
|
|
|
|
+ .sprites_scaled = pipe_wm->sprites_scaled,
|
|
|
|
+ };
|
|
|
|
+ struct ilk_wm_maximums max;
|
|
|
|
+
|
|
|
|
+ /* LP0 watermarks always use 1/2 DDB partitioning */
|
|
|
|
+ ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
|
|
|
|
+
|
|
|
|
+ /* At least LP0 must be valid */
|
|
|
|
+ if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0])) {
|
|
|
|
+ DRM_DEBUG_KMS("LP0 watermark invalid\n");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
/* Compute new watermarks for the pipe */
|
|
/* Compute new watermarks for the pipe */
|
|
static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc,
|
|
static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc,
|
|
struct drm_atomic_state *state)
|
|
struct drm_atomic_state *state)
|
|
@@ -2292,10 +2315,6 @@ static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc,
|
|
struct intel_plane_state *sprstate = NULL;
|
|
struct intel_plane_state *sprstate = NULL;
|
|
struct intel_plane_state *curstate = NULL;
|
|
struct intel_plane_state *curstate = NULL;
|
|
int level, max_level = ilk_wm_max_level(dev);
|
|
int level, max_level = ilk_wm_max_level(dev);
|
|
- /* LP0 watermark maximums depend on this pipe alone */
|
|
|
|
- struct intel_wm_config config = {
|
|
|
|
- .num_pipes_active = 1,
|
|
|
|
- };
|
|
|
|
struct ilk_wm_maximums max;
|
|
struct ilk_wm_maximums max;
|
|
|
|
|
|
cstate = intel_atomic_get_crtc_state(state, intel_crtc);
|
|
cstate = intel_atomic_get_crtc_state(state, intel_crtc);
|
|
@@ -2319,21 +2338,18 @@ static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc,
|
|
curstate = to_intel_plane_state(ps);
|
|
curstate = to_intel_plane_state(ps);
|
|
}
|
|
}
|
|
|
|
|
|
- config.sprites_enabled = sprstate->visible;
|
|
|
|
- config.sprites_scaled = sprstate->visible &&
|
|
|
|
|
|
+ pipe_wm->pipe_enabled = cstate->base.active;
|
|
|
|
+ pipe_wm->sprites_enabled = sprstate->visible;
|
|
|
|
+ pipe_wm->sprites_scaled = sprstate->visible &&
|
|
(drm_rect_width(&sprstate->dst) != drm_rect_width(&sprstate->src) >> 16 ||
|
|
(drm_rect_width(&sprstate->dst) != drm_rect_width(&sprstate->src) >> 16 ||
|
|
drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16);
|
|
drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16);
|
|
|
|
|
|
- pipe_wm->pipe_enabled = cstate->base.active;
|
|
|
|
- pipe_wm->sprites_enabled = config.sprites_enabled;
|
|
|
|
- pipe_wm->sprites_scaled = config.sprites_scaled;
|
|
|
|
-
|
|
|
|
/* ILK/SNB: LP2+ watermarks only w/o sprites */
|
|
/* ILK/SNB: LP2+ watermarks only w/o sprites */
|
|
if (INTEL_INFO(dev)->gen <= 6 && sprstate->visible)
|
|
if (INTEL_INFO(dev)->gen <= 6 && sprstate->visible)
|
|
max_level = 1;
|
|
max_level = 1;
|
|
|
|
|
|
/* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */
|
|
/* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */
|
|
- if (config.sprites_scaled)
|
|
|
|
|
|
+ if (pipe_wm->sprites_scaled)
|
|
max_level = 0;
|
|
max_level = 0;
|
|
|
|
|
|
ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate,
|
|
ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate,
|
|
@@ -2342,12 +2358,8 @@ static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc,
|
|
if (IS_HASWELL(dev) || IS_BROADWELL(dev))
|
|
if (IS_HASWELL(dev) || IS_BROADWELL(dev))
|
|
pipe_wm->linetime = hsw_compute_linetime_wm(dev, cstate);
|
|
pipe_wm->linetime = hsw_compute_linetime_wm(dev, cstate);
|
|
|
|
|
|
- /* LP0 watermarks always use 1/2 DDB partitioning */
|
|
|
|
- ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
|
|
|
|
-
|
|
|
|
- /* At least LP0 must be valid */
|
|
|
|
- if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]))
|
|
|
|
- return -EINVAL;
|
|
|
|
|
|
+ if (!ilk_validate_pipe_wm(dev, pipe_wm))
|
|
|
|
+ return false;
|
|
|
|
|
|
ilk_compute_wm_reg_maximums(dev, 1, &max);
|
|
ilk_compute_wm_reg_maximums(dev, 1, &max);
|
|
|
|
|
|
@@ -2371,6 +2383,59 @@ static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Build a set of 'intermediate' watermark values that satisfy both the old
|
|
|
|
+ * state and the new state. These can be programmed to the hardware
|
|
|
|
+ * immediately.
|
|
|
|
+ */
|
|
|
|
+static int ilk_compute_intermediate_wm(struct drm_device *dev,
|
|
|
|
+ struct intel_crtc *intel_crtc,
|
|
|
|
+ struct intel_crtc_state *newstate)
|
|
|
|
+{
|
|
|
|
+ struct intel_pipe_wm *a = &newstate->wm.intermediate;
|
|
|
|
+ struct intel_pipe_wm *b = &intel_crtc->wm.active.ilk;
|
|
|
|
+ int level, max_level = ilk_wm_max_level(dev);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Start with the final, target watermarks, then combine with the
|
|
|
|
+ * currently active watermarks to get values that are safe both before
|
|
|
|
+ * and after the vblank.
|
|
|
|
+ */
|
|
|
|
+ *a = newstate->wm.optimal.ilk;
|
|
|
|
+ a->pipe_enabled |= b->pipe_enabled;
|
|
|
|
+ a->sprites_enabled |= b->sprites_enabled;
|
|
|
|
+ a->sprites_scaled |= b->sprites_scaled;
|
|
|
|
+
|
|
|
|
+ for (level = 0; level <= max_level; level++) {
|
|
|
|
+ struct intel_wm_level *a_wm = &a->wm[level];
|
|
|
|
+ const struct intel_wm_level *b_wm = &b->wm[level];
|
|
|
|
+
|
|
|
|
+ a_wm->enable &= b_wm->enable;
|
|
|
|
+ a_wm->pri_val = max(a_wm->pri_val, b_wm->pri_val);
|
|
|
|
+ a_wm->spr_val = max(a_wm->spr_val, b_wm->spr_val);
|
|
|
|
+ a_wm->cur_val = max(a_wm->cur_val, b_wm->cur_val);
|
|
|
|
+ a_wm->fbc_val = max(a_wm->fbc_val, b_wm->fbc_val);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * We need to make sure that these merged watermark values are
|
|
|
|
+ * actually a valid configuration themselves. If they're not,
|
|
|
|
+ * there's no safe way to transition from the old state to
|
|
|
|
+ * the new state, so we need to fail the atomic transaction.
|
|
|
|
+ */
|
|
|
|
+ if (!ilk_validate_pipe_wm(dev, a))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * 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(a, &newstate->wm.optimal.ilk, sizeof(*a)) == 0)
|
|
|
|
+ newstate->wm.need_postvbl_update = false;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Merge the watermarks from all active pipes for a specific level.
|
|
* Merge the watermarks from all active pipes for a specific level.
|
|
*/
|
|
*/
|
|
@@ -2383,9 +2448,7 @@ static void ilk_merge_wm_level(struct drm_device *dev,
|
|
ret_wm->enable = true;
|
|
ret_wm->enable = true;
|
|
|
|
|
|
for_each_intel_crtc(dev, intel_crtc) {
|
|
for_each_intel_crtc(dev, intel_crtc) {
|
|
- const struct intel_crtc_state *cstate =
|
|
|
|
- to_intel_crtc_state(intel_crtc->base.state);
|
|
|
|
- const struct intel_pipe_wm *active = &cstate->wm.optimal.ilk;
|
|
|
|
|
|
+ const struct intel_pipe_wm *active = &intel_crtc->wm.active.ilk;
|
|
const struct intel_wm_level *wm = &active->wm[level];
|
|
const struct intel_wm_level *wm = &active->wm[level];
|
|
|
|
|
|
if (!active->pipe_enabled)
|
|
if (!active->pipe_enabled)
|
|
@@ -2533,15 +2596,14 @@ static void ilk_compute_wm_results(struct drm_device *dev,
|
|
|
|
|
|
/* LP0 register values */
|
|
/* LP0 register values */
|
|
for_each_intel_crtc(dev, intel_crtc) {
|
|
for_each_intel_crtc(dev, intel_crtc) {
|
|
- const struct intel_crtc_state *cstate =
|
|
|
|
- to_intel_crtc_state(intel_crtc->base.state);
|
|
|
|
enum pipe pipe = intel_crtc->pipe;
|
|
enum pipe pipe = intel_crtc->pipe;
|
|
- const struct intel_wm_level *r = &cstate->wm.optimal.ilk.wm[0];
|
|
|
|
|
|
+ const struct intel_wm_level *r =
|
|
|
|
+ &intel_crtc->wm.active.ilk.wm[0];
|
|
|
|
|
|
if (WARN_ON(!r->enable))
|
|
if (WARN_ON(!r->enable))
|
|
continue;
|
|
continue;
|
|
|
|
|
|
- results->wm_linetime[pipe] = cstate->wm.optimal.ilk.linetime;
|
|
|
|
|
|
+ results->wm_linetime[pipe] = intel_crtc->wm.active.ilk.linetime;
|
|
|
|
|
|
results->wm_pipe[pipe] =
|
|
results->wm_pipe[pipe] =
|
|
(r->pri_val << WM0_PIPE_PLANE_SHIFT) |
|
|
(r->pri_val << WM0_PIPE_PLANE_SHIFT) |
|
|
@@ -2748,7 +2810,7 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
|
|
dev_priv->wm.hw = *results;
|
|
dev_priv->wm.hw = *results;
|
|
}
|
|
}
|
|
|
|
|
|
-static bool ilk_disable_lp_wm(struct drm_device *dev)
|
|
|
|
|
|
+bool ilk_disable_lp_wm(struct drm_device *dev)
|
|
{
|
|
{
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
|
|
|
@@ -3643,11 +3705,9 @@ static void ilk_compute_wm_config(struct drm_device *dev,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static void ilk_program_watermarks(struct intel_crtc_state *cstate)
|
|
|
|
|
|
+static void ilk_program_watermarks(struct drm_i915_private *dev_priv)
|
|
{
|
|
{
|
|
- struct drm_crtc *crtc = cstate->base.crtc;
|
|
|
|
- struct drm_device *dev = crtc->dev;
|
|
|
|
- struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
|
+ struct drm_device *dev = dev_priv->dev;
|
|
struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
|
|
struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
|
|
struct ilk_wm_maximums max;
|
|
struct ilk_wm_maximums max;
|
|
struct intel_wm_config config = {};
|
|
struct intel_wm_config config = {};
|
|
@@ -3678,28 +3738,28 @@ static void ilk_program_watermarks(struct intel_crtc_state *cstate)
|
|
ilk_write_wm_values(dev_priv, &results);
|
|
ilk_write_wm_values(dev_priv, &results);
|
|
}
|
|
}
|
|
|
|
|
|
-static void ilk_update_wm(struct drm_crtc *crtc)
|
|
|
|
|
|
+static void ilk_initial_watermarks(struct intel_crtc_state *cstate)
|
|
{
|
|
{
|
|
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
- struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
|
|
|
|
-
|
|
|
|
- WARN_ON(cstate->base.active != intel_crtc->active);
|
|
|
|
|
|
+ struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
|
|
|
|
+ struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
|
|
|
|
|
|
- /*
|
|
|
|
- * IVB workaround: must disable low power watermarks for at least
|
|
|
|
- * one frame before enabling scaling. LP watermarks can be re-enabled
|
|
|
|
- * when scaling is disabled.
|
|
|
|
- *
|
|
|
|
- * WaCxSRDisabledForSpriteScaling:ivb
|
|
|
|
- */
|
|
|
|
- if (cstate->disable_lp_wm) {
|
|
|
|
- ilk_disable_lp_wm(crtc->dev);
|
|
|
|
- intel_wait_for_vblank(crtc->dev, intel_crtc->pipe);
|
|
|
|
- }
|
|
|
|
|
|
+ mutex_lock(&dev_priv->wm.wm_mutex);
|
|
|
|
+ intel_crtc->wm.active.ilk = cstate->wm.intermediate;
|
|
|
|
+ ilk_program_watermarks(dev_priv);
|
|
|
|
+ mutex_unlock(&dev_priv->wm.wm_mutex);
|
|
|
|
+}
|
|
|
|
|
|
- intel_crtc->wm.active.ilk = cstate->wm.optimal.ilk;
|
|
|
|
|
|
+static void ilk_optimize_watermarks(struct intel_crtc_state *cstate)
|
|
|
|
+{
|
|
|
|
+ struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
|
|
|
|
+ struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
|
|
|
|
|
|
- ilk_program_watermarks(cstate);
|
|
|
|
|
|
+ mutex_lock(&dev_priv->wm.wm_mutex);
|
|
|
|
+ if (cstate->wm.need_postvbl_update) {
|
|
|
|
+ intel_crtc->wm.active.ilk = cstate->wm.optimal.ilk;
|
|
|
|
+ ilk_program_watermarks(dev_priv);
|
|
|
|
+ }
|
|
|
|
+ mutex_unlock(&dev_priv->wm.wm_mutex);
|
|
}
|
|
}
|
|
|
|
|
|
static void skl_pipe_wm_active_state(uint32_t val,
|
|
static void skl_pipe_wm_active_state(uint32_t val,
|
|
@@ -7076,9 +7136,13 @@ void intel_init_pm(struct drm_device *dev)
|
|
dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) ||
|
|
dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) ||
|
|
(!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] &&
|
|
(!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] &&
|
|
dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
|
|
dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
|
|
- dev_priv->display.update_wm = ilk_update_wm;
|
|
|
|
dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm;
|
|
dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm;
|
|
- dev_priv->display.program_watermarks = ilk_program_watermarks;
|
|
|
|
|
|
+ dev_priv->display.compute_intermediate_wm =
|
|
|
|
+ ilk_compute_intermediate_wm;
|
|
|
|
+ dev_priv->display.initial_watermarks =
|
|
|
|
+ ilk_initial_watermarks;
|
|
|
|
+ dev_priv->display.optimize_watermarks =
|
|
|
|
+ ilk_optimize_watermarks;
|
|
} else {
|
|
} else {
|
|
DRM_DEBUG_KMS("Failed to read display plane latency. "
|
|
DRM_DEBUG_KMS("Failed to read display plane latency. "
|
|
"Disable CxSR\n");
|
|
"Disable CxSR\n");
|