@@ -3347,7 +3347,8 @@ static void hsw_ddi_pre_enable_dp(struct intel_encoder *encoder,
true);
intel_dp_sink_set_fec_ready(intel_dp, crtc_state);
intel_dp_start_link_train(intel_dp);
- if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
+ if ((port != PORT_A || INTEL_GEN(dev_priv) >= 9) &&
+ !is_trans_port_sync_mode(dev_priv, crtc_state))
intel_dp_stop_link_train(intel_dp);
intel_ddi_enable_fec(encoder, crtc_state);
@@ -521,6 +521,24 @@ needs_modeset(const struct intel_crtc_state *state)
return drm_atomic_crtc_needs_modeset(&state->base);
}
+bool
+is_trans_port_sync_mode(struct drm_i915_private *dev_priv,
+ const struct intel_crtc_state *state)
+{
+ return (INTEL_GEN(dev_priv) >= 11 &&
+ (state->master_transcoder != INVALID_TRANSCODER ||
+ state->sync_mode_slaves_mask));
+}
+
+static bool
+is_trans_port_sync_master(struct drm_i915_private *dev_priv,
+ const struct intel_crtc_state *state)
+{
+ return (INTEL_GEN(dev_priv) >= 11 &&
+ (state->master_transcoder == INVALID_TRANSCODER &&
+ state->sync_mode_slaves_mask));
+}
+
/*
* Platform specific helpers to calculate the port PLL loopback- (clock.m),
* and post-divider (clock.p) values, pre- (clock.vco) and post-divided fast
@@ -13890,6 +13908,30 @@ static void intel_update_crtc(struct intel_crtc *crtc,
intel_finish_crtc_commit(state, crtc);
}
+static struct intel_crtc *intel_get_slave_crtc(struct drm_i915_private *dev_priv,
+ struct intel_crtc_state *new_crtc_state)
+{
+ if (new_crtc_state->sync_mode_slaves_mask &
+ BIT(TRANSCODER_A))
+ return intel_get_crtc_for_pipe(dev_priv,
+ PIPE_A);
+ else if (new_crtc_state->sync_mode_slaves_mask &
+ BIT(TRANSCODER_B))
+ return intel_get_crtc_for_pipe(dev_priv,
+ PIPE_B);
+ else if (new_crtc_state->sync_mode_slaves_mask &
+ BIT(TRANSCODER_C))
+ return intel_get_crtc_for_pipe(dev_priv,
+ PIPE_C);
+ else if (new_crtc_state->sync_mode_slaves_mask &
+ BIT(TRANSCODER_D))
+ return intel_get_crtc_for_pipe(dev_priv,
+ PIPE_D);
+ /* should never happen */
+ WARN_ON(1);
+ return NULL;
+}
+
static void intel_old_crtc_state_disables(struct intel_atomic_state *state,
struct intel_crtc_state *old_crtc_state,
struct intel_crtc_state *new_crtc_state,
@@ -13968,6 +14010,104 @@ static void intel_commit_modeset_enables(struct intel_atomic_state *state)
}
}
+static void intel_crtc_enable_trans_port_sync(struct intel_crtc *crtc,
+ struct intel_atomic_state *state,
+ struct intel_crtc_state *new_crtc_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+
+ update_scanline_offset(new_crtc_state);
+ dev_priv->display.crtc_enable(new_crtc_state, state);
+ intel_crtc_enable_pipe_crc(crtc);
+}
+
+static void intel_set_dp_tp_ctl_normal(struct intel_crtc *crtc,
+ struct intel_atomic_state *state)
+{
+ struct drm_connector_state *conn_state;
+ struct drm_connector *conn;
+ struct intel_dp *intel_dp;
+ int i;
+
+ for_each_new_connector_in_state(&state->base, conn, conn_state, i) {
+ if (conn_state->crtc == &crtc->base)
+ break;
+ }
+ intel_dp = enc_to_intel_dp(&intel_attached_encoder(conn)->base);
+ intel_dp_stop_link_train(intel_dp);
+}
+
+static void intel_post_crtc_enable_updates(struct intel_crtc *crtc,
+ struct intel_atomic_state *state,
+ struct intel_crtc_state *old_crtc_state,
+ struct intel_crtc_state *new_crtc_state)
+{
+ struct intel_plane_state *new_plane_state =
+ intel_atomic_get_new_plane_state(state,
+ to_intel_plane(crtc->base.primary));
+
+ if (new_crtc_state->update_pipe && !new_crtc_state->enable_fbc)
+ intel_fbc_disable(crtc);
+ else if (new_plane_state)
+ intel_fbc_enable(crtc, new_crtc_state, new_plane_state);
+
+ intel_begin_crtc_commit(state, crtc);
+ skl_update_planes_on_crtc(state, crtc);
+ intel_finish_crtc_commit(state, crtc);
+}
+
+static void intel_update_trans_port_sync_crtcs(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);
+ struct intel_crtc *slave_crtc = intel_get_slave_crtc(dev_priv,
+ new_crtc_state);
+ struct intel_crtc_state *new_slave_crtc_state =
+ intel_atomic_get_new_crtc_state(state, slave_crtc);
+ struct intel_crtc_state *old_slave_crtc_state =
+ intel_atomic_get_old_crtc_state(state, slave_crtc);
+
+ WARN_ON(!slave_crtc || !new_slave_crtc_state ||
+ !old_slave_crtc_state);
+
+ DRM_DEBUG_KMS("Updating Transcoder Port Sync Master CRTC = %d %s and Slave CRTC %d %s\n",
+ crtc->base.base.id, crtc->base.name, slave_crtc->base.base.id,
+ slave_crtc->base.name);
+
+ /* Enable seq for slave with with DP_TP_CTL left Idle until the
+ * master is ready
+ */
+ intel_crtc_enable_trans_port_sync(slave_crtc,
+ state,
+ new_slave_crtc_state);
+
+ /* Enable seq for master with with DP_TP_CTL left Idle */
+ intel_crtc_enable_trans_port_sync(crtc,
+ state,
+ new_crtc_state);
+
+ /* Set Slave's DP_TP_CTL to Normal */
+ intel_set_dp_tp_ctl_normal(slave_crtc,
+ state);
+
+ /* Set Master's DP_TP_CTL To Normal */
+ usleep_range(200, 400);
+ intel_set_dp_tp_ctl_normal(crtc,
+ state);
+
+ /* Now do the post crtc enable for all master and slaves */
+ intel_post_crtc_enable_updates(slave_crtc,
+ state,
+ new_slave_crtc_state,
+ old_slave_crtc_state);
+ intel_post_crtc_enable_updates(crtc,
+ state,
+ new_crtc_state,
+ old_crtc_state);
+}
+
static void skl_commit_modeset_enables(struct intel_atomic_state *state)
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
@@ -14002,6 +14142,7 @@ 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) {
bool vbl_wait = false;
unsigned int cmask = drm_crtc_mask(&crtc->base);
+ bool modeset = needs_modeset(new_crtc_state);
pipe = crtc->pipe;
@@ -14024,12 +14165,24 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)
*/
if (!skl_ddb_entry_equal(&new_crtc_state->wm.skl.ddb,
&old_crtc_state->wm.skl.ddb) &&
- !new_crtc_state->base.active_changed &&
+ !modeset &&
state->wm_results.dirty_pipes != updated)
vbl_wait = true;
- intel_update_crtc(crtc, state, old_crtc_state,
- new_crtc_state);
+ if (modeset && is_trans_port_sync_mode(dev_priv,
+ new_crtc_state)) {
+ if (is_trans_port_sync_master(dev_priv,
+ new_crtc_state))
+ intel_update_trans_port_sync_crtcs(crtc,
+ state,
+ old_crtc_state,
+ new_crtc_state);
+ else
+ continue;
+ } else {
+ intel_update_crtc(crtc, state, old_crtc_state,
+ new_crtc_state);
+ }
if (vbl_wait)
intel_wait_for_vblank(dev_priv, pipe);
@@ -27,6 +27,7 @@
#include <drm/drm_util.h>
#include <drm/i915_drm.h>
+#include "intel_dp_link_training.h"
enum link_m_n_set;
struct dpll;
@@ -54,6 +55,7 @@ struct intel_plane;
struct intel_plane_state;
struct intel_remapped_info;
struct intel_rotation_info;
+struct intel_crtc_state;
enum i915_gpio {
GPIOA,
@@ -454,6 +456,8 @@ enum drm_mode_status
intel_mode_valid_max_plane_size(struct drm_i915_private *dev_priv,
const struct drm_display_mode *mode);
enum phy intel_port_to_phy(struct drm_i915_private *i915, enum port port);
+bool is_trans_port_sync_mode(struct drm_i915_private *i915,
+ const struct intel_crtc_state *state);
void intel_plane_destroy(struct drm_plane *plane);
void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe);