if (ret)
return ret;
- if (old_dbuf_state->joined_mbus != new_dbuf_state->joined_mbus) {
- /* TODO: Implement vblank synchronized MBUS joining changes */
- ret = intel_modeset_all_pipes_late(state, "MBUS joining change");
- if (ret)
- return ret;
- }
-
drm_dbg_kms(&i915->drm,
"Enabled dbuf slices 0x%x -> 0x%x (total dbuf slices 0x%x), mbus joined? %s->%s\n",
old_dbuf_state->enabled_slices,
return false;
}
-void intel_mbus_dbox_update(struct intel_atomic_state *state)
+static void intel_mbus_dbox_update(struct intel_atomic_state *state)
{
struct drm_i915_private *i915 = to_i915(state->base.dev);
const struct intel_dbuf_state *new_dbuf_state, *old_dbuf_state;
{
enum dbuf_slice slice;
+ if (!HAS_MBUS_JOINING(i915))
+ return;
+
if (DISPLAY_VER(i915) >= 20)
intel_de_rmw(i915, MBUS_CTL, MBUS_TRANSLATION_THROTTLE_MIN_MASK,
MBUS_TRANSLATION_THROTTLE_MIN(ratio - 1));
new_dbuf_state->joined_mbus);
}
-static void intel_dbuf_mbus_join_update(struct intel_atomic_state *state)
+static enum pipe intel_mbus_joined_pipe(struct intel_atomic_state *state,
+ const struct intel_dbuf_state *dbuf_state)
+{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ enum pipe pipe = ffs(dbuf_state->active_pipes) - 1;
+ const struct intel_crtc_state *new_crtc_state;
+ struct intel_crtc *crtc;
+
+ drm_WARN_ON(&i915->drm, !dbuf_state->joined_mbus);
+ drm_WARN_ON(&i915->drm, !is_power_of_2(dbuf_state->active_pipes));
+
+ crtc = intel_crtc_for_pipe(i915, pipe);
+ new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
+
+ if (new_crtc_state && !intel_crtc_needs_modeset(new_crtc_state))
+ return pipe;
+ else
+ return INVALID_PIPE;
+}
+
+static void intel_dbuf_mbus_join_update(struct intel_atomic_state *state,
+ enum pipe pipe)
{
struct drm_i915_private *i915 = to_i915(state->base.dev);
const struct intel_dbuf_state *old_dbuf_state =
intel_atomic_get_new_dbuf_state(state);
u32 mbus_ctl;
- drm_dbg_kms(&i915->drm, "Changing mbus joined: %s -> %s\n",
+ drm_dbg_kms(&i915->drm, "Changing mbus joined: %s -> %s (pipe: %c)\n",
str_yes_no(old_dbuf_state->joined_mbus),
- str_yes_no(new_dbuf_state->joined_mbus));
+ str_yes_no(new_dbuf_state->joined_mbus),
+ pipe != INVALID_PIPE ? pipe_name(pipe) : '*');
- /*
- * TODO: Implement vblank synchronized MBUS joining changes.
- * Must be properly coordinated with dbuf reprogramming.
- */
if (new_dbuf_state->joined_mbus)
- mbus_ctl = MBUS_HASHING_MODE_1x4 | MBUS_JOIN |
- MBUS_JOIN_PIPE_SELECT_NONE;
+ mbus_ctl = MBUS_HASHING_MODE_1x4 | MBUS_JOIN;
else
- mbus_ctl = MBUS_HASHING_MODE_2x2 |
- MBUS_JOIN_PIPE_SELECT_NONE;
+ mbus_ctl = MBUS_HASHING_MODE_2x2;
+
+ if (pipe != INVALID_PIPE)
+ mbus_ctl |= MBUS_JOIN_PIPE_SELECT(pipe);
+ else
+ mbus_ctl |= MBUS_JOIN_PIPE_SELECT_NONE;
intel_de_rmw(i915, MBUS_CTL,
MBUS_HASHING_MODE_MASK | MBUS_JOIN |
MBUS_JOIN_PIPE_SELECT_MASK, mbus_ctl);
}
-/*
- * Configure MBUS_CTL and all DBUF_CTL_S of each slice to join_mbus state before
- * update the request state of all DBUS slices.
- */
-static void update_mbus_pre_enable(struct intel_atomic_state *state)
+void intel_dbuf_mbus_pre_ddb_update(struct intel_atomic_state *state)
+{
+ const struct intel_dbuf_state *new_dbuf_state =
+ intel_atomic_get_new_dbuf_state(state);
+ const struct intel_dbuf_state *old_dbuf_state =
+ intel_atomic_get_old_dbuf_state(state);
+
+ if (!new_dbuf_state)
+ return;
+
+ if (!old_dbuf_state->joined_mbus && new_dbuf_state->joined_mbus) {
+ enum pipe pipe = intel_mbus_joined_pipe(state, new_dbuf_state);
+
+ WARN_ON(!new_dbuf_state->base.changed);
+
+ intel_dbuf_mbus_join_update(state, pipe);
+ intel_mbus_dbox_update(state);
+ intel_dbuf_mdclk_min_tracker_update(state);
+ }
+}
+
+void intel_dbuf_mbus_post_ddb_update(struct intel_atomic_state *state)
{
struct drm_i915_private *i915 = to_i915(state->base.dev);
+ const struct intel_dbuf_state *new_dbuf_state =
+ intel_atomic_get_new_dbuf_state(state);
+ const struct intel_dbuf_state *old_dbuf_state =
+ intel_atomic_get_old_dbuf_state(state);
- if (!HAS_MBUS_JOINING(i915))
+ if (!new_dbuf_state)
return;
- /*
- * TODO: Implement vblank synchronized MBUS joining changes.
- * Must be properly coordinated with dbuf reprogramming.
- */
- intel_dbuf_mbus_join_update(state);
+ if (old_dbuf_state->joined_mbus && !new_dbuf_state->joined_mbus) {
+ enum pipe pipe = intel_mbus_joined_pipe(state, old_dbuf_state);
+
+ WARN_ON(!new_dbuf_state->base.changed);
+
+ intel_dbuf_mdclk_min_tracker_update(state);
+ intel_mbus_dbox_update(state);
+ intel_dbuf_mbus_join_update(state, pipe);
+
+ if (pipe != INVALID_PIPE) {
+ struct intel_crtc *crtc = intel_crtc_for_pipe(i915, pipe);
+
+ intel_crtc_wait_for_next_vblank(crtc);
+ }
+ } else if (old_dbuf_state->joined_mbus == new_dbuf_state->joined_mbus &&
+ old_dbuf_state->active_pipes != new_dbuf_state->active_pipes) {
+ WARN_ON(!new_dbuf_state->base.changed);
+
+ intel_dbuf_mdclk_min_tracker_update(state);
+ intel_mbus_dbox_update(state);
+ }
- intel_dbuf_mdclk_min_tracker_update(state);
}
void intel_dbuf_pre_plane_update(struct intel_atomic_state *state)
intel_atomic_get_old_dbuf_state(state);
if (!new_dbuf_state ||
- (new_dbuf_state->enabled_slices == old_dbuf_state->enabled_slices &&
- new_dbuf_state->joined_mbus == old_dbuf_state->joined_mbus))
+ new_dbuf_state->enabled_slices == old_dbuf_state->enabled_slices)
return;
WARN_ON(!new_dbuf_state->base.changed);
- update_mbus_pre_enable(state);
gen9_dbuf_slices_update(i915,
old_dbuf_state->enabled_slices |
new_dbuf_state->enabled_slices);
intel_atomic_get_old_dbuf_state(state);
if (!new_dbuf_state ||
- (new_dbuf_state->enabled_slices == old_dbuf_state->enabled_slices &&
- new_dbuf_state->joined_mbus == old_dbuf_state->joined_mbus))
+ new_dbuf_state->enabled_slices == old_dbuf_state->enabled_slices)
return;
WARN_ON(!new_dbuf_state->base.changed);