@@ -339,6 +339,10 @@ struct i915_hotplug {
#define for_each_intel_crtc(dev, intel_crtc) \
list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head)
+#define for_each_intel_crtc_mask(dev, intel_crtc, crtc_mask) \
+ list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) \
+ for_each_if ((crtc_mask) & (1 << drm_crtc_index(&intel_crtc->base)))
+
#define for_each_intel_encoder(dev, intel_encoder) \
list_for_each_entry(intel_encoder, \
&(dev)->mode_config.encoder_list, \
@@ -594,6 +598,7 @@ struct drm_i915_display_funcs {
struct intel_crtc_state *newstate);
void (*initial_watermarks)(struct intel_crtc_state *cstate);
void (*optimize_watermarks)(struct intel_crtc_state *cstate);
+ int (*compute_global_watermarks)(struct drm_atomic_state *state);
void (*update_wm)(struct drm_crtc *crtc);
int (*modeset_calc_cdclk)(struct drm_atomic_state *state);
void (*modeset_commit_cdclk)(struct drm_atomic_state *state);
@@ -13315,6 +13315,7 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
static void calc_watermark_data(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
struct drm_crtc *crtc;
struct drm_crtc_state *cstate;
@@ -13344,6 +13345,10 @@ static void calc_watermark_data(struct drm_atomic_state *state)
pstate->crtc_h != pstate->src_h >> 16)
intel_state->wm_config.sprites_scaled = true;
}
+
+ /* Is there platform-specific watermark information to calculate? */
+ if (dev_priv->display.compute_global_watermarks)
+ dev_priv->display.compute_global_watermarks(state);
}
/**
@@ -13711,6 +13716,19 @@ static int intel_atomic_commit(struct drm_device *dev,
intel_modeset_verify_crtc(crtc, old_crtc_state, crtc->state);
}
+ /*
+ * Temporary sanity check: make sure our pre-computed DDB matches the
+ * one we actually wind up programming.
+ *
+ * Not a great place to put this, but the easiest place we have access
+ * to both the pre-computed and final DDB's; we'll be removing this
+ * check in the next patch anyway.
+ */
+ WARN(IS_GEN9(dev) &&
+ memcmp(&intel_state->ddb, &dev_priv->wm.skl_results.ddb,
+ sizeof(intel_state->ddb)),
+ "Pre-computed DDB does not match final DDB!\n");
+
if (intel_state->modeset)
intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
@@ -311,6 +311,9 @@ struct intel_atomic_state {
* don't bother calculating intermediate watermarks.
*/
bool skip_intermediate_wm;
+
+ /* Gen9+ only */
+ struct skl_ddb_allocation ddb;
};
struct intel_plane_state {
@@ -3812,6 +3812,75 @@ static void skl_clear_wm(struct skl_wm_values *watermarks, enum pipe pipe)
}
+static int
+skl_compute_ddb(struct drm_atomic_state *state)
+{
+ struct drm_device *dev = state->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+ struct intel_crtc *intel_crtc;
+ unsigned realloc_pipes = dev_priv->active_crtcs;
+ int ret;
+
+ /*
+ * If the modeset changes which CRTC's are active, we need to
+ * recompute the DDB allocation for *all* active pipes, even
+ * those that weren't otherwise being modified in any way by this
+ * atomic commit. Due to the shrinking of the per-pipe allocations
+ * when new active CRTC's are added, it's possible for a pipe that
+ * we were already using and aren't changing at all here to suddenly
+ * become invalid if its DDB needs exceeds its new allocation.
+ *
+ * Note that if we wind up doing a full DDB recompute, we can't let
+ * any other display updates race with this transaction, so we need
+ * to grab the lock on *all* CRTC's.
+ */
+ if (intel_state->active_pipe_changes)
+ realloc_pipes = ~0;
+
+ for_each_intel_crtc_mask(dev, intel_crtc, realloc_pipes) {
+ struct intel_crtc_state *cstate;
+
+ cstate = intel_atomic_get_crtc_state(state, intel_crtc);
+ if (IS_ERR(cstate))
+ return PTR_ERR(cstate);
+
+ ret = skl_allocate_pipe_ddb(cstate, &intel_state->ddb);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+skl_compute_wm(struct drm_atomic_state *state)
+{
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *cstate;
+ int ret, i;
+ bool changed = false;
+
+ /*
+ * If this transaction isn't actually touching any CRTC's, don't
+ * bother with watermark calculation. Note that if we pass this
+ * test, we're guaranteed to hold at least one CRTC state mutex,
+ * which means we can safely use values like dev_priv->active_crtcs
+ * since any racing commits that want to update them would need to
+ * hold _all_ CRTC state mutexes.
+ */
+ for_each_crtc_in_state(state, crtc, cstate, i)
+ changed = true;
+ if (!changed)
+ return 0;
+
+ ret = skl_compute_ddb(state);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static void skl_update_wm(struct drm_crtc *crtc)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -7349,6 +7418,7 @@ void intel_init_pm(struct drm_device *dev)
if (INTEL_INFO(dev)->gen >= 9) {
skl_setup_wm_latency(dev);
dev_priv->display.update_wm = skl_update_wm;
+ dev_priv->display.compute_global_watermarks = skl_compute_wm;
} else if (HAS_PCH_SPLIT(dev)) {
ilk_setup_wm_latency(dev);