|
@@ -3851,6 +3851,11 @@ void skl_write_plane_wm(struct intel_crtc *intel_crtc,
|
|
|
wm->plane[pipe][plane][level]);
|
|
|
}
|
|
|
I915_WRITE(PLANE_WM_TRANS(pipe, plane), wm->plane_trans[pipe][plane]);
|
|
|
+
|
|
|
+ skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane),
|
|
|
+ &wm->ddb.plane[pipe][plane]);
|
|
|
+ skl_ddb_entry_write(dev_priv, PLANE_NV12_BUF_CFG(pipe, plane),
|
|
|
+ &wm->ddb.y_plane[pipe][plane]);
|
|
|
}
|
|
|
|
|
|
void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
|
|
@@ -3867,170 +3872,46 @@ void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
|
|
|
wm->plane[pipe][PLANE_CURSOR][level]);
|
|
|
}
|
|
|
I915_WRITE(CUR_WM_TRANS(pipe), wm->plane_trans[pipe][PLANE_CURSOR]);
|
|
|
-}
|
|
|
-
|
|
|
-static void skl_write_wm_values(struct drm_i915_private *dev_priv,
|
|
|
- const struct skl_wm_values *new)
|
|
|
-{
|
|
|
- struct drm_device *dev = &dev_priv->drm;
|
|
|
- struct intel_crtc *crtc;
|
|
|
-
|
|
|
- for_each_intel_crtc(dev, crtc) {
|
|
|
- int i;
|
|
|
- enum pipe pipe = crtc->pipe;
|
|
|
-
|
|
|
- if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
|
|
|
- continue;
|
|
|
- if (!crtc->active)
|
|
|
- continue;
|
|
|
-
|
|
|
- for (i = 0; i < intel_num_planes(crtc); i++) {
|
|
|
- skl_ddb_entry_write(dev_priv,
|
|
|
- PLANE_BUF_CFG(pipe, i),
|
|
|
- &new->ddb.plane[pipe][i]);
|
|
|
- skl_ddb_entry_write(dev_priv,
|
|
|
- PLANE_NV12_BUF_CFG(pipe, i),
|
|
|
- &new->ddb.y_plane[pipe][i]);
|
|
|
- }
|
|
|
|
|
|
- skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
|
|
|
- &new->ddb.plane[pipe][PLANE_CURSOR]);
|
|
|
- }
|
|
|
+ skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
|
|
|
+ &wm->ddb.plane[pipe][PLANE_CURSOR]);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * When setting up a new DDB allocation arrangement, we need to correctly
|
|
|
- * sequence the times at which the new allocations for the pipes are taken into
|
|
|
- * account or we'll have pipes fetching from space previously allocated to
|
|
|
- * another pipe.
|
|
|
- *
|
|
|
- * Roughly the sequence looks like:
|
|
|
- * 1. re-allocate the pipe(s) with the allocation being reduced and not
|
|
|
- * overlapping with a previous light-up pipe (another way to put it is:
|
|
|
- * pipes with their new allocation strickly included into their old ones).
|
|
|
- * 2. re-allocate the other pipes that get their allocation reduced
|
|
|
- * 3. allocate the pipes having their allocation increased
|
|
|
- *
|
|
|
- * Steps 1. and 2. are here to take care of the following case:
|
|
|
- * - Initially DDB looks like this:
|
|
|
- * | B | C |
|
|
|
- * - enable pipe A.
|
|
|
- * - pipe B has a reduced DDB allocation that overlaps with the old pipe C
|
|
|
- * allocation
|
|
|
- * | A | B | C |
|
|
|
- *
|
|
|
- * We need to sequence the re-allocation: C, B, A (and not B, C, A).
|
|
|
- */
|
|
|
-
|
|
|
-static void
|
|
|
-skl_wm_flush_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, int pass)
|
|
|
+bool skl_ddb_allocation_equals(const struct skl_ddb_allocation *old,
|
|
|
+ const struct skl_ddb_allocation *new,
|
|
|
+ enum pipe pipe)
|
|
|
{
|
|
|
- int plane;
|
|
|
-
|
|
|
- DRM_DEBUG_KMS("flush pipe %c (pass %d)\n", pipe_name(pipe), pass);
|
|
|
-
|
|
|
- for_each_plane(dev_priv, pipe, plane) {
|
|
|
- I915_WRITE(PLANE_SURF(pipe, plane),
|
|
|
- I915_READ(PLANE_SURF(pipe, plane)));
|
|
|
- }
|
|
|
- I915_WRITE(CURBASE(pipe), I915_READ(CURBASE(pipe)));
|
|
|
+ return new->pipe[pipe].start == old->pipe[pipe].start &&
|
|
|
+ new->pipe[pipe].end == old->pipe[pipe].end;
|
|
|
}
|
|
|
|
|
|
-static bool
|
|
|
-skl_ddb_allocation_included(const struct skl_ddb_allocation *old,
|
|
|
- const struct skl_ddb_allocation *new,
|
|
|
- enum pipe pipe)
|
|
|
+static inline bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a,
|
|
|
+ const struct skl_ddb_entry *b)
|
|
|
{
|
|
|
- uint16_t old_size, new_size;
|
|
|
-
|
|
|
- old_size = skl_ddb_entry_size(&old->pipe[pipe]);
|
|
|
- new_size = skl_ddb_entry_size(&new->pipe[pipe]);
|
|
|
-
|
|
|
- return old_size != new_size &&
|
|
|
- new->pipe[pipe].start >= old->pipe[pipe].start &&
|
|
|
- new->pipe[pipe].end <= old->pipe[pipe].end;
|
|
|
+ return a->start < b->end && b->start < a->end;
|
|
|
}
|
|
|
|
|
|
-static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
|
|
|
- struct skl_wm_values *new_values)
|
|
|
+bool skl_ddb_allocation_overlaps(struct drm_atomic_state *state,
|
|
|
+ const struct skl_ddb_allocation *old,
|
|
|
+ const struct skl_ddb_allocation *new,
|
|
|
+ enum pipe pipe)
|
|
|
{
|
|
|
- struct drm_device *dev = &dev_priv->drm;
|
|
|
- struct skl_ddb_allocation *cur_ddb, *new_ddb;
|
|
|
- bool reallocated[I915_MAX_PIPES] = {};
|
|
|
- struct intel_crtc *crtc;
|
|
|
- enum pipe pipe;
|
|
|
-
|
|
|
- new_ddb = &new_values->ddb;
|
|
|
- cur_ddb = &dev_priv->wm.skl_hw.ddb;
|
|
|
-
|
|
|
- /*
|
|
|
- * First pass: flush the pipes with the new allocation contained into
|
|
|
- * the old space.
|
|
|
- *
|
|
|
- * We'll wait for the vblank on those pipes to ensure we can safely
|
|
|
- * re-allocate the freed space without this pipe fetching from it.
|
|
|
- */
|
|
|
- for_each_intel_crtc(dev, crtc) {
|
|
|
- if (!crtc->active)
|
|
|
- continue;
|
|
|
-
|
|
|
- pipe = crtc->pipe;
|
|
|
-
|
|
|
- if (!skl_ddb_allocation_included(cur_ddb, new_ddb, pipe))
|
|
|
- continue;
|
|
|
-
|
|
|
- skl_wm_flush_pipe(dev_priv, pipe, 1);
|
|
|
- intel_wait_for_vblank(dev, pipe);
|
|
|
-
|
|
|
- reallocated[pipe] = true;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /*
|
|
|
- * Second pass: flush the pipes that are having their allocation
|
|
|
- * reduced, but overlapping with a previous allocation.
|
|
|
- *
|
|
|
- * Here as well we need to wait for the vblank to make sure the freed
|
|
|
- * space is not used anymore.
|
|
|
- */
|
|
|
- for_each_intel_crtc(dev, crtc) {
|
|
|
- if (!crtc->active)
|
|
|
- continue;
|
|
|
+ struct drm_device *dev = state->dev;
|
|
|
+ struct intel_crtc *intel_crtc;
|
|
|
+ enum pipe otherp;
|
|
|
|
|
|
- pipe = crtc->pipe;
|
|
|
+ for_each_intel_crtc(dev, intel_crtc) {
|
|
|
+ otherp = intel_crtc->pipe;
|
|
|
|
|
|
- if (reallocated[pipe])
|
|
|
+ if (otherp == pipe)
|
|
|
continue;
|
|
|
|
|
|
- if (skl_ddb_entry_size(&new_ddb->pipe[pipe]) <
|
|
|
- skl_ddb_entry_size(&cur_ddb->pipe[pipe])) {
|
|
|
- skl_wm_flush_pipe(dev_priv, pipe, 2);
|
|
|
- intel_wait_for_vblank(dev, pipe);
|
|
|
- reallocated[pipe] = true;
|
|
|
- }
|
|
|
+ if (skl_ddb_entries_overlap(&new->pipe[pipe],
|
|
|
+ &old->pipe[otherp]))
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * Third pass: flush the pipes that got more space allocated.
|
|
|
- *
|
|
|
- * We don't need to actively wait for the update here, next vblank
|
|
|
- * will just get more DDB space with the correct WM values.
|
|
|
- */
|
|
|
- for_each_intel_crtc(dev, crtc) {
|
|
|
- if (!crtc->active)
|
|
|
- continue;
|
|
|
-
|
|
|
- pipe = crtc->pipe;
|
|
|
-
|
|
|
- /*
|
|
|
- * At this point, only the pipes more space than before are
|
|
|
- * left to re-allocate.
|
|
|
- */
|
|
|
- if (reallocated[pipe])
|
|
|
- continue;
|
|
|
-
|
|
|
- skl_wm_flush_pipe(dev_priv, pipe, 3);
|
|
|
- }
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
static int skl_update_pipe_wm(struct drm_crtc_state *cstate,
|
|
@@ -4232,7 +4113,7 @@ static void skl_update_wm(struct drm_crtc *crtc)
|
|
|
struct skl_wm_values *hw_vals = &dev_priv->wm.skl_hw;
|
|
|
struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
|
|
|
struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
|
|
|
- int pipe;
|
|
|
+ enum pipe pipe = intel_crtc->pipe;
|
|
|
|
|
|
if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0)
|
|
|
return;
|
|
@@ -4241,15 +4122,22 @@ static void skl_update_wm(struct drm_crtc *crtc)
|
|
|
|
|
|
mutex_lock(&dev_priv->wm.wm_mutex);
|
|
|
|
|
|
- skl_write_wm_values(dev_priv, results);
|
|
|
- skl_flush_wm_values(dev_priv, results);
|
|
|
-
|
|
|
/*
|
|
|
- * Store the new configuration (but only for the pipes that have
|
|
|
- * changed; the other values weren't recomputed).
|
|
|
+ * If this pipe isn't active already, we're going to be enabling it
|
|
|
+ * very soon. Since it's safe to update a pipe's ddb allocation while
|
|
|
+ * the pipe's shut off, just do so here. Already active pipes will have
|
|
|
+ * their watermarks updated once we update their planes.
|
|
|
*/
|
|
|
- for_each_pipe_masked(dev_priv, pipe, results->dirty_pipes)
|
|
|
- skl_copy_wm_for_pipe(hw_vals, results, pipe);
|
|
|
+ if (crtc->state->active_changed) {
|
|
|
+ int plane;
|
|
|
+
|
|
|
+ for (plane = 0; plane < intel_num_planes(intel_crtc); plane++)
|
|
|
+ skl_write_plane_wm(intel_crtc, results, plane);
|
|
|
+
|
|
|
+ skl_write_cursor_wm(intel_crtc, results);
|
|
|
+ }
|
|
|
+
|
|
|
+ skl_copy_wm_for_pipe(hw_vals, results, pipe);
|
|
|
|
|
|
mutex_unlock(&dev_priv->wm.wm_mutex);
|
|
|
}
|