@@ -15496,7 +15496,7 @@ static void intel_update_crtc(struct intel_atomic_state *state,
else
i9xx_update_planes_on_crtc(state, crtc);
- intel_pipe_update_end(new_crtc_state);
+ intel_pipe_update_end(new_crtc_state, NULL);
/*
* We usually enable FIFO underrun interrupts as part of the
@@ -15594,6 +15594,52 @@ static void intel_commit_modeset_disables(struct intel_atomic_state *state)
}
}
+static void intel_update_bigjoiner(struct intel_crtc *crtc,
+ struct intel_atomic_state *state,
+ struct intel_crtc_state *old_crtc_state,
+ struct intel_crtc_state *new_crtc_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ bool modeset = needs_modeset(new_crtc_state);
+ struct intel_crtc *slave = new_crtc_state->bigjoiner_linked_crtc;
+ struct intel_crtc_state *new_slave_crtc_state =
+ intel_atomic_get_new_crtc_state(state, slave);
+
+ if (modeset) {
+ /* Enable slave first */
+ intel_crtc_update_active_timings(new_slave_crtc_state);
+ dev_priv->display.crtc_enable(state, slave);
+
+ /* Then master */
+ intel_crtc_update_active_timings(new_crtc_state);
+ dev_priv->display.crtc_enable(state, crtc);
+
+ /* vblanks work again, re-enable pipe CRC. */
+ intel_crtc_enable_pipe_crc(crtc);
+
+ } else {
+ intel_pre_plane_update(state, crtc);
+ intel_pre_plane_update(state, slave);
+
+ if (new_crtc_state->update_pipe)
+ intel_encoders_update_pipe(state, crtc);
+ }
+
+ /*
+ * Perform vblank evasion around commit operation, and make sure to
+ * commit both planes simultaneously for best results.
+ */
+ intel_pipe_update_start(new_crtc_state);
+
+ commit_pipe_config(state, crtc);
+ commit_pipe_config(state, slave);
+
+ skl_update_planes_on_crtc(state, crtc);
+ skl_update_planes_on_crtc(state, slave);
+
+ intel_pipe_update_end(new_crtc_state, new_slave_crtc_state);
+}
+
static void intel_commit_modeset_enables(struct intel_atomic_state *state)
{
struct intel_crtc_state *new_crtc_state;
@@ -15635,15 +15681,22 @@ static void icl_dbuf_slice_post_update(struct intel_atomic_state *state)
static void skl_commit_modeset_enables(struct intel_atomic_state *state)
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
- struct intel_crtc *crtc;
+ struct intel_crtc *crtc, *slave;
struct intel_crtc_state *old_crtc_state, *new_crtc_state;
struct skl_ddb_entry entries[I915_MAX_PIPES] = {};
+ struct skl_ddb_entry new_entries[I915_MAX_PIPES] = {};
u8 update_pipes = 0, modeset_pipes = 0;
+ const struct intel_crtc_state *slave_crtc_state;
int i;
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
enum pipe pipe = crtc->pipe;
+ if (new_crtc_state->bigjoiner_slave) {
+ /* We're updated from master */
+ continue;
+ }
+
if (!new_crtc_state->hw.active)
continue;
@@ -15654,6 +15707,34 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)
} else {
modeset_pipes |= BIT(pipe);
}
+
+ if (new_crtc_state->bigjoiner) {
+ slave = new_crtc_state->bigjoiner_linked_crtc;
+ slave_crtc_state =
+ intel_atomic_get_new_crtc_state(state,
+ slave);
+
+ /* put both entries in */
+ new_entries[i].start = new_crtc_state->wm.skl.ddb.start;
+ new_entries[i].end = slave_crtc_state->wm.skl.ddb.end;
+ } else {
+ new_entries[i] = new_crtc_state->wm.skl.ddb;
+ }
+
+ /* ignore allocations for crtc's that have been turned off during modeset. */
+ if (needs_modeset(new_crtc_state))
+ continue;
+
+ if (old_crtc_state->bigjoiner) {
+ slave = old_crtc_state->bigjoiner_linked_crtc;
+ slave_crtc_state =
+ intel_atomic_get_old_crtc_state(state, slave);
+
+ entries[i].start = old_crtc_state->wm.skl.ddb.start;
+ entries[i].end = slave_crtc_state->wm.skl.ddb.end;
+ } else {
+ entries[i] = old_crtc_state->wm.skl.ddb;
+ }
}
/*
@@ -15669,28 +15750,34 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
enum pipe pipe = crtc->pipe;
+ bool ddb_changed;
if ((update_pipes & BIT(pipe)) == 0)
continue;
- if (skl_ddb_allocation_overlaps(&new_crtc_state->wm.skl.ddb,
+ if (skl_ddb_allocation_overlaps(&new_entries[pipe],
entries, I915_MAX_PIPES, pipe))
continue;
- entries[pipe] = new_crtc_state->wm.skl.ddb;
+ ddb_changed = !skl_ddb_entry_equal(&new_entries[pipe], &entries[pipe]);
+ entries[pipe] = new_entries[pipe];
update_pipes &= ~BIT(pipe);
- intel_update_crtc(state, crtc);
-
/*
* If this is an already active pipe, it's DDB changed,
* and this isn't the last pipe that needs updating
* then we need to wait for a vblank to pass for the
* new ddb allocation to take effect.
*/
- if (!skl_ddb_entry_equal(&new_crtc_state->wm.skl.ddb,
- &old_crtc_state->wm.skl.ddb) &&
- (update_pipes | modeset_pipes))
+ if (new_crtc_state->bigjoiner) {
+ intel_update_bigjoiner(crtc, state,
+ old_crtc_state,
+ new_crtc_state);
+ } else {
+ intel_update_crtc(state, crtc);
+ }
+
+ if (ddb_changed && (update_pipes | modeset_pipes))
intel_wait_for_vblank(dev_priv, pipe);
}
}
@@ -15726,9 +15813,18 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)
if ((modeset_pipes & BIT(pipe)) == 0)
continue;
+ WARN_ON(skl_ddb_allocation_overlaps(&new_entries[pipe],
+ entries, I915_MAX_PIPES, pipe));
+
+ entries[pipe] = new_entries[pipe];
modeset_pipes &= ~BIT(pipe);
- intel_enable_crtc(state, crtc);
+ if (new_crtc_state->bigjoiner)
+ intel_update_bigjoiner(crtc, state,
+ old_crtc_state,
+ new_crtc_state);
+ else
+ intel_enable_crtc(state, crtc);
}
/*
@@ -15740,10 +15836,10 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)
if ((update_pipes & BIT(pipe)) == 0)
continue;
- drm_WARN_ON(&dev_priv->drm, skl_ddb_allocation_overlaps(&new_crtc_state->wm.skl.ddb,
+ drm_WARN_ON(&dev_priv->drm, skl_ddb_allocation_overlaps(&new_entries[pipe],
entries, I915_MAX_PIPES, pipe));
- entries[pipe] = new_crtc_state->wm.skl.ddb;
+ entries[pipe] = new_entries[pipe];
update_pipes &= ~BIT(pipe);
intel_update_crtc(state, crtc);
@@ -98,6 +98,8 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
/* FIXME needs to be calibrated sensibly */
min = vblank_start - intel_usecs_to_scanlines(adjusted_mode,
+ new_crtc_state->bigjoiner ?
+ 2 * VBLANK_EVASION_TIME_US :
VBLANK_EVASION_TIME_US);
max = vblank_start - 1;
@@ -190,7 +192,8 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
* re-enables interrupts and verifies the update was actually completed
* before a vblank.
*/
-void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state)
+void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state,
+ struct intel_crtc_state *slave_crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
enum pipe pipe = crtc->pipe;
@@ -205,16 +208,26 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state)
* Would be slightly nice to just grab the vblank count and arm the
* event outside of the critical section - the spinlock might spin for a
* while ... */
- if (new_crtc_state->uapi.event) {
- drm_WARN_ON(&dev_priv->drm,
- drm_crtc_vblank_get(&crtc->base) != 0);
+ if (new_crtc_state->uapi.event || (slave_crtc_state && slave_crtc_state->uapi.event)) {
+ if (new_crtc_state->uapi.event)
+ drm_WARN_ON(&dev_priv->drm,
+ drm_crtc_vblank_get(&crtc->base) != 0);
+ if (slave_crtc_state && slave_crtc_state->uapi.event)
+ drm_WARN_ON(&dev_priv->drm,
+ drm_crtc_vblank_get(&crtc->base) != 0);
spin_lock(&crtc->base.dev->event_lock);
- drm_crtc_arm_vblank_event(&crtc->base,
- new_crtc_state->uapi.event);
+ if (new_crtc_state->uapi.event)
+ drm_crtc_arm_vblank_event(&crtc->base,
+ new_crtc_state->uapi.event);
+ if (slave_crtc_state && slave_crtc_state->uapi.event)
+ drm_crtc_arm_vblank_event(&crtc->base,
+ slave_crtc_state->uapi.event);
spin_unlock(&crtc->base.dev->event_lock);
new_crtc_state->uapi.event = NULL;
+ if (slave_crtc_state)
+ slave_crtc_state->uapi.event = NULL;
}
local_irq_enable();
@@ -24,7 +24,8 @@ struct intel_plane *intel_sprite_plane_create(struct drm_i915_private *dev_priv,
int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state);
-void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state);
+void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state,
+ struct intel_crtc_state *slave_crtc_state);
int intel_plane_check_stride(const struct intel_plane_state *plane_state);
int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state);
int chv_plane_check_rotation(const struct intel_plane_state *plane_state);