diff mbox

[12/12] drm/i915: Stop frobbing with DDI encoder->type

Message ID 1465382507-23085-13-git-send-email-ville.syrjala@linux.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ville Syrjälä June 8, 2016, 10:41 a.m. UTC
From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Now that we have the output_types bitmask in the crtc state, we
can use it to indicate in which mode we want to drive the DDI
encoders. For pre-DDI output_types will instead indicate what
kind of cloning is being done, but as DDI platforms don't
support cloning so we don't have to worry about mixing the two
approaches.

From here on out an encoder on DDI platforms can now have a
type of DDI, EDP, ANALOG, or DP_MST. A DDI type encoder can be
driven either in HDMI or DP SST mode. We maintain EDP as a
seaparete type from DDI to keep is_edp() etc. working. ANALOG
(ie. FDI) was already treated quite diffrently, so we'll stick
to that. And MST encoders remain separate beasts as well.

To achieve this neatly we'll add a new optional
.compute_output_type() hook for encoders. Only encoders with
multiple personalities will need to provide one. The hook can
do whatever it needs to figure out what kind of signal should
be output. Additionaly .get_config() will also need to read out
the current type from the hardware somehow and fill that in.
Note that in the name of consistency we'll populate the hook
also for EDP encoders on DDI platforms even though the default
fallback of using encoder->type would work just as well there.

The reason for adding a new hook instead of letting
.compute_config() do the work is to follow the rule that
output_types will already be fully populated by the time
.compute_config() is called for the first encoder (which
simplifies things such as hdmi_12bpc_possible()).

With output_types correctly populated, the biggest churn comes
from changing various encoder->type checks to consult output_types
instead.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_audio.c    |   3 +-
 drivers/gpu/drm/i915/intel_ddi.c      | 204 +++++++++++++++++++++-------------
 drivers/gpu/drm/i915/intel_display.c  |  37 +++---
 drivers/gpu/drm/i915/intel_dp.c       |  16 +--
 drivers/gpu/drm/i915/intel_dpll_mgr.c |  21 ++--
 drivers/gpu/drm/i915/intel_drv.h      |   4 +-
 drivers/gpu/drm/i915/intel_hdmi.c     |  10 +-
 drivers/gpu/drm/i915/intel_opregion.c |   2 +-
 8 files changed, 169 insertions(+), 128 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index 0653fb1d9d26..2815c8c34a66 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -653,7 +653,8 @@  static int i915_audio_component_sync_audio_rate(struct device *dev,
 	intel_encoder = dev_priv->dig_port_map[port];
 	/* intel_encoder might be NULL for DP MST */
 	if (!intel_encoder || !intel_encoder->base.crtc ||
-	    intel_encoder->type != INTEL_OUTPUT_HDMI) {
+	    !intel_crtc_has_type(to_intel_crtc(intel_encoder->base.crtc)->config,
+				 INTEL_OUTPUT_HDMI)) {
 		DRM_DEBUG_KMS("no valid port %c\n", port_name(port));
 		err = -ENODEV;
 		goto unlock;
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 4f7fc0ed8796..a1c5feb0e14c 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -301,8 +301,8 @@  static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = {
 	{ 154, 0x9A, 1, 128, true },	/* 9:	1200		0   */
 };
 
-static void bxt_ddi_vswing_sequence(struct drm_i915_private *dev_priv,
-				    u32 level, enum port port, int type);
+static void bxt_ddi_vswing_sequence(struct intel_encoder *encoder,
+				    u32 level);
 
 static void ddi_get_encoder_port(struct intel_encoder *intel_encoder,
 				 struct intel_digital_port **dig_port,
@@ -318,10 +318,8 @@  static void ddi_get_encoder_port(struct intel_encoder *intel_encoder,
 	default:
 		WARN(1, "Invalid DDI encoder type %d\n", intel_encoder->type);
 		/* fallthrough and treat as unknown */
-	case INTEL_OUTPUT_DP:
+	case INTEL_OUTPUT_DDI:
 	case INTEL_OUTPUT_EDP:
-	case INTEL_OUTPUT_HDMI:
-	case INTEL_OUTPUT_UNKNOWN:
 		*dig_port = enc_to_dig_port(encoder);
 		*port = (*dig_port)->port;
 		break;
@@ -398,6 +396,7 @@  skl_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, int *n_entries)
 void intel_prepare_ddi_buffer(struct intel_encoder *encoder)
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
 	u32 iboost_bit = 0;
 	int i, n_hdmi_entries, n_dp_entries, n_edp_entries, hdmi_default_entry,
 	    size;
@@ -413,12 +412,9 @@  void intel_prepare_ddi_buffer(struct intel_encoder *encoder)
 	hdmi_level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift;
 
 	if (IS_BROXTON(dev_priv)) {
-		if (encoder->type != INTEL_OUTPUT_HDMI)
-			return;
-
 		/* Vswing programming for HDMI */
-		bxt_ddi_vswing_sequence(dev_priv, hdmi_level, port,
-					INTEL_OUTPUT_HDMI);
+		if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI))
+			bxt_ddi_vswing_sequence(encoder, hdmi_level);
 		return;
 	}
 
@@ -436,7 +432,7 @@  void intel_prepare_ddi_buffer(struct intel_encoder *encoder)
 		    dev_priv->vbt.ddi_port_info[port].dp_boost_level)
 			iboost_bit = 1<<31;
 
-		if (WARN_ON(encoder->type == INTEL_OUTPUT_EDP &&
+		if (WARN_ON(intel_crtc_has_type(crtc->config, INTEL_OUTPUT_EDP) &&
 			    port != PORT_A && port != PORT_E &&
 			    n_edp_entries > 9))
 			n_edp_entries = 9;
@@ -477,22 +473,20 @@  void intel_prepare_ddi_buffer(struct intel_encoder *encoder)
 		hdmi_default_entry = 7;
 	}
 
-	switch (encoder->type) {
-	case INTEL_OUTPUT_EDP:
+	if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_EDP)) {
 		ddi_translations = ddi_translations_edp;
 		size = n_edp_entries;
-		break;
-	case INTEL_OUTPUT_DP:
-	case INTEL_OUTPUT_HDMI:
+	} else if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DP) ||
+		   intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI)) {
 		ddi_translations = ddi_translations_dp;
 		size = n_dp_entries;
-		break;
-	case INTEL_OUTPUT_ANALOG:
+	} else if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_ANALOG)) {
 		ddi_translations = ddi_translations_fdi;
 		size = n_dp_entries;
-		break;
-	default:
-		BUG();
+	} else {
+		WARN(1, "Invalid encoder type 0x%x for pipe %c\n",
+		     crtc->config->output_types, pipe_name(crtc->pipe));
+		return;
 	}
 
 	for (i = 0; i < size; i++) {
@@ -502,7 +496,7 @@  void intel_prepare_ddi_buffer(struct intel_encoder *encoder)
 			   ddi_translations[i].trans2);
 	}
 
-	if (encoder->type != INTEL_OUTPUT_HDMI)
+	if (!intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI))
 		return;
 
 	/* Choose a good default if VBT is badly populated */
@@ -549,7 +543,7 @@  void hsw_fdi_link_train(struct drm_crtc *crtc)
 	u32 temp, i, rx_ctl_val;
 
 	for_each_encoder_on_crtc(dev, crtc, encoder) {
-		WARN_ON(encoder->type != INTEL_OUTPUT_ANALOG);
+		WARN_ON(!intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_ANALOG));
 		intel_prepare_ddi_buffer(encoder);
 	}
 
@@ -1063,12 +1057,10 @@  void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
 {
 	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
 	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
-	int type = intel_encoder->type;
 	uint32_t temp;
 
-	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) {
+	if (intel_crtc_has_dp_encoder(intel_crtc->config)) {
 		WARN_ON(transcoder_is_dsi(cpu_transcoder));
 
 		temp = TRANS_MSA_SYNC_CLK;
@@ -1117,7 +1109,6 @@  void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
 	enum pipe pipe = intel_crtc->pipe;
 	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 	enum port port = intel_ddi_get_encoder_port(intel_encoder);
-	int type = intel_encoder->type;
 	uint32_t temp;
 
 	/* Enable TRANS_DDI_FUNC_CTL for the pipe to work in HDMI mode */
@@ -1172,18 +1163,16 @@  void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
 		}
 	}
 
-	if (type == INTEL_OUTPUT_HDMI) {
+	if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_HDMI)) {
 		if (intel_crtc->config->has_hdmi_sink)
 			temp |= TRANS_DDI_MODE_SELECT_HDMI;
 		else
 			temp |= TRANS_DDI_MODE_SELECT_DVI;
-
-	} else if (type == INTEL_OUTPUT_ANALOG) {
+	} else if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_ANALOG)) {
 		temp |= TRANS_DDI_MODE_SELECT_FDI;
 		temp |= (intel_crtc->config->fdi_lanes - 1) << 1;
-
-	} else if (type == INTEL_OUTPUT_DP ||
-		   type == INTEL_OUTPUT_EDP) {
+	} else if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DP) ||
+		   intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_EDP)) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
 		if (intel_dp->is_mst) {
@@ -1192,7 +1181,7 @@  void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
 			temp |= TRANS_DDI_MODE_SELECT_DP_SST;
 
 		temp |= DDI_PORT_WIDTH(intel_crtc->config->lane_count);
-	} else if (type == INTEL_OUTPUT_DP_MST) {
+	} else if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DP_MST)) {
 		struct intel_dp *intel_dp = &enc_to_mst(encoder)->primary->dp;
 
 		if (intel_dp->is_mst) {
@@ -1202,8 +1191,8 @@  void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
 
 		temp |= DDI_PORT_WIDTH(intel_crtc->config->lane_count);
 	} else {
-		WARN(1, "Invalid encoder type %d for pipe %c\n",
-		     intel_encoder->type, pipe_name(pipe));
+		WARN(1, "Invalid encoder type 0x%x for pipe %c\n",
+		     intel_crtc->config->output_types, pipe_name(pipe));
 	}
 
 	I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp);
@@ -1371,9 +1360,13 @@  void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc)
 			   TRANS_CLK_SEL_DISABLED);
 }
 
-static void skl_ddi_set_iboost(struct drm_i915_private *dev_priv,
-			       u32 level, enum port port, int type)
+static void skl_ddi_set_iboost(struct intel_encoder *encoder,
+			       u32 level)
+
 {
+	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	enum port port = enc_to_dig_port(&encoder->base)->port;
 	const struct ddi_buf_trans *ddi_translations;
 	uint8_t iboost;
 	uint8_t dp_iboost, hdmi_iboost;
@@ -1384,14 +1377,14 @@  static void skl_ddi_set_iboost(struct drm_i915_private *dev_priv,
 	dp_iboost = dev_priv->vbt.ddi_port_info[port].dp_boost_level;
 	hdmi_iboost = dev_priv->vbt.ddi_port_info[port].hdmi_boost_level;
 
-	if (type == INTEL_OUTPUT_DP) {
+	if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DP)) {
 		if (dp_iboost) {
 			iboost = dp_iboost;
 		} else {
 			ddi_translations = skl_get_buf_trans_dp(dev_priv, &n_entries);
 			iboost = ddi_translations[level].i_boost;
 		}
-	} else if (type == INTEL_OUTPUT_EDP) {
+	} else if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_EDP)) {
 		if (dp_iboost) {
 			iboost = dp_iboost;
 		} else {
@@ -1403,7 +1396,7 @@  static void skl_ddi_set_iboost(struct drm_i915_private *dev_priv,
 
 			iboost = ddi_translations[level].i_boost;
 		}
-	} else if (type == INTEL_OUTPUT_HDMI) {
+	} else if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI)) {
 		if (hdmi_iboost) {
 			iboost = hdmi_iboost;
 		} else {
@@ -1432,32 +1425,38 @@  static void skl_ddi_set_iboost(struct drm_i915_private *dev_priv,
 	I915_WRITE(DISPIO_CR_TX_BMU_CR0, reg);
 }
 
-static void bxt_ddi_vswing_sequence(struct drm_i915_private *dev_priv,
-				    u32 level, enum port port, int type)
+static void bxt_ddi_vswing_sequence(struct intel_encoder *encoder,
+				    u32 level)
 {
+	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	enum port port = enc_to_dig_port(&encoder->base)->port;
+
 	const struct bxt_ddi_buf_trans *ddi_translations;
 	u32 n_entries, i;
 	uint32_t val;
 
-	if (type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.low_vswing) {
+	if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_EDP) &&
+	    dev_priv->vbt.edp.low_vswing) {
 		n_entries = ARRAY_SIZE(bxt_ddi_translations_edp);
 		ddi_translations = bxt_ddi_translations_edp;
-	} else if (type == INTEL_OUTPUT_DP
-			|| type == INTEL_OUTPUT_EDP) {
+	} else if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DP) ||
+		   intel_crtc_has_type(crtc->config, INTEL_OUTPUT_EDP)) {
 		n_entries = ARRAY_SIZE(bxt_ddi_translations_dp);
 		ddi_translations = bxt_ddi_translations_dp;
-	} else if (type == INTEL_OUTPUT_HDMI) {
+	} else if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI)) {
 		n_entries = ARRAY_SIZE(bxt_ddi_translations_hdmi);
 		ddi_translations = bxt_ddi_translations_hdmi;
 	} else {
-		DRM_DEBUG_KMS("Vswing programming not done for encoder %d\n",
-				type);
+		DRM_DEBUG_KMS("Vswing programming not done for encoder 0x%x\n",
+			      crtc->config->output_types);
 		return;
 	}
 
 	/* Check if default value has to be used */
 	if (level >= n_entries ||
-	    (type == INTEL_OUTPUT_HDMI && level == HDMI_LEVEL_SHIFT_UNKNOWN)) {
+	    (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI) &&
+	     level == HDMI_LEVEL_SHIFT_UNKNOWN)) {
 		for (i = 0; i < n_entries; i++) {
 			if (ddi_translations[i].default_index) {
 				level = i;
@@ -1548,21 +1547,19 @@  static uint32_t translate_signal_level(int signal_levels)
 
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp)
 {
-	struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
-	struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
-	struct intel_encoder *encoder = &dport->base;
+	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	uint8_t train_set = intel_dp->train_set[0];
 	int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
 					 DP_TRAIN_PRE_EMPHASIS_MASK);
-	enum port port = dport->port;
 	uint32_t level;
 
 	level = translate_signal_level(signal_levels);
 
 	if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
-		skl_ddi_set_iboost(dev_priv, level, port, encoder->type);
+		skl_ddi_set_iboost(encoder, level);
 	else if (IS_BROXTON(dev_priv))
-		bxt_ddi_vswing_sequence(dev_priv, level, port, encoder->type);
+		bxt_ddi_vswing_sequence(encoder, level);
 
 	return DDI_BUF_TRANS_SELECT(level);
 }
@@ -1599,9 +1596,8 @@  static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
 	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
 	enum port port = intel_ddi_get_encoder_port(intel_encoder);
-	int type = intel_encoder->type;
 
-	if (type == INTEL_OUTPUT_HDMI) {
+	if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI)) {
 		struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 
 		intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
@@ -1609,14 +1605,15 @@  static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 
 	intel_prepare_ddi_buffer(intel_encoder);
 
-	if (type == INTEL_OUTPUT_EDP) {
+	if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_EDP)) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 		intel_edp_panel_on(intel_dp);
 	}
 
 	intel_ddi_clk_select(intel_encoder, crtc->config);
 
-	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
+	if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DP) ||
+	    intel_crtc_has_type(crtc->config, INTEL_OUTPUT_EDP)) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
 		intel_dp_set_link_params(intel_dp, crtc->config);
@@ -1627,7 +1624,7 @@  static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 		intel_dp_start_link_train(intel_dp);
 		if (port != PORT_A || INTEL_INFO(dev_priv)->gen >= 9)
 			intel_dp_stop_link_train(intel_dp);
-	} else if (type == INTEL_OUTPUT_HDMI) {
+	} else if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI)) {
 		struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 
 		intel_hdmi->set_infoframes(encoder,
@@ -1639,10 +1636,10 @@  static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
 {
 	struct drm_encoder *encoder = &intel_encoder->base;
+	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	enum port port = intel_ddi_get_encoder_port(intel_encoder);
-	int type = intel_encoder->type;
 	uint32_t val;
 	bool wait = false;
 
@@ -1661,7 +1658,8 @@  static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
 	if (wait)
 		intel_wait_ddi_buf_idle(dev_priv, port);
 
-	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
+	if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DP) ||
+	    intel_crtc_has_type(crtc->config, INTEL_OUTPUT_EDP)) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
 		intel_edp_panel_vdd_on(intel_dp);
@@ -1674,7 +1672,7 @@  static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
 	else if (INTEL_INFO(dev)->gen < 9)
 		I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE);
 
-	if (type == INTEL_OUTPUT_HDMI) {
+	if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI)) {
 		struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 
 		intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
@@ -1689,9 +1687,8 @@  static void intel_enable_ddi(struct intel_encoder *intel_encoder)
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	enum port port = intel_ddi_get_encoder_port(intel_encoder);
-	int type = intel_encoder->type;
 
-	if (type == INTEL_OUTPUT_HDMI) {
+	if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_HDMI)) {
 		struct intel_digital_port *intel_dig_port =
 			enc_to_dig_port(encoder);
 
@@ -1702,7 +1699,7 @@  static void intel_enable_ddi(struct intel_encoder *intel_encoder)
 		I915_WRITE(DDI_BUF_CTL(port),
 			   intel_dig_port->saved_port_bits |
 			   DDI_BUF_CTL_ENABLE);
-	} else if (type == INTEL_OUTPUT_EDP) {
+	} else if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_EDP)) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
 		if (port == PORT_A && INTEL_INFO(dev)->gen < 9)
@@ -1724,7 +1721,6 @@  static void intel_disable_ddi(struct intel_encoder *intel_encoder)
 	struct drm_encoder *encoder = &intel_encoder->base;
 	struct drm_crtc *crtc = encoder->crtc;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int type = intel_encoder->type;
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -1733,7 +1729,7 @@  static void intel_disable_ddi(struct intel_encoder *intel_encoder)
 		intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
 	}
 
-	if (type == INTEL_OUTPUT_EDP) {
+	if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_EDP)) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
 		intel_edp_drrs_disable(intel_dp);
@@ -2157,6 +2153,26 @@  void intel_ddi_get_config(struct intel_encoder *encoder,
 		return;
 
 	temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
+
+	switch (temp & TRANS_DDI_MODE_SELECT_MASK) {
+	case TRANS_DDI_MODE_SELECT_HDMI:
+	case TRANS_DDI_MODE_SELECT_DVI:
+		pipe_config->output_types |= 1 << INTEL_OUTPUT_HDMI;
+		break;
+	case TRANS_DDI_MODE_SELECT_DP_SST:
+		if (encoder->type == INTEL_OUTPUT_EDP)
+			pipe_config->output_types |= 1 << INTEL_OUTPUT_EDP;
+		else
+			pipe_config->output_types |= 1 << INTEL_OUTPUT_DP;
+		break;
+	case TRANS_DDI_MODE_SELECT_FDI:
+		WARN_ON(pipe_config->output_types != 1 << INTEL_OUTPUT_ANALOG);
+		break;
+	default:
+		MISSING_CASE(pipe_config->output_types);
+		break;
+	}
+
 	if (temp & TRANS_DDI_PHSYNC)
 		flags |= DRM_MODE_FLAG_PHSYNC;
 	else
@@ -2214,7 +2230,8 @@  void intel_ddi_get_config(struct intel_encoder *encoder,
 			pipe_config->has_audio = true;
 	}
 
-	if (encoder->type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.bpp &&
+	if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_EDP) &&
+	    dev_priv->vbt.edp.bpp &&
 	    pipe_config->pipe_bpp > dev_priv->vbt.edp.bpp) {
 		/*
 		 * This is a big fat ugly hack.
@@ -2237,18 +2254,54 @@  void intel_ddi_get_config(struct intel_encoder *encoder,
 	intel_ddi_clock_get(encoder, pipe_config);
 }
 
+static enum intel_output_type
+intel_ddi_compute_output_type(struct intel_encoder *encoder,
+			      struct intel_crtc_state *crtc_state)
+{
+	struct drm_atomic_state *state = crtc_state->base.state;
+	struct drm_crtc *crtc = crtc_state->base.crtc;
+	struct drm_connector *connector;
+	struct drm_connector_state *connector_state;
+	int i;
+
+	for_each_connector_in_state(state, connector, connector_state, i) {
+		if (connector_state->crtc != crtc)
+			continue;
+
+		if (connector_state->best_encoder != &encoder->base)
+			continue;
+
+		switch (connector->connector_type) {
+		case DRM_MODE_CONNECTOR_HDMIA:
+			return INTEL_OUTPUT_HDMI;
+		case DRM_MODE_CONNECTOR_eDP:
+			return INTEL_OUTPUT_EDP;
+		case DRM_MODE_CONNECTOR_DisplayPort:
+			return INTEL_OUTPUT_DP;
+		default:
+			MISSING_CASE(connector->connector_type);
+			break;
+		}
+	}
+
+	return INTEL_OUTPUT_UNUSED;
+}
+
 static bool intel_ddi_compute_config(struct intel_encoder *encoder,
 				     struct intel_crtc_state *pipe_config)
 {
-	int type = encoder->type;
-	int port = intel_ddi_get_encoder_port(encoder);
+	enum port port = intel_ddi_get_encoder_port(encoder);
 
-	WARN(type == INTEL_OUTPUT_UNKNOWN, "compute_config() on unknown output!\n");
+	WARN(pipe_config->output_types == 0 ||
+	     pipe_config->output_types & ~(1 << INTEL_OUTPUT_EDP |
+					   1 << INTEL_OUTPUT_DP |
+					   1 << INTEL_OUTPUT_HDMI),
+	     "Bad output_types = 0x%x\n", pipe_config->output_types);
 
 	if (port == PORT_A)
 		pipe_config->cpu_transcoder = TRANSCODER_EDP;
 
-	if (type == INTEL_OUTPUT_HDMI)
+	if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI))
 		return intel_hdmi_compute_config(encoder, pipe_config);
 	else
 		return intel_dp_compute_config(encoder, pipe_config);
@@ -2348,6 +2401,7 @@  void intel_ddi_init(struct drm_device *dev, enum port port)
 	drm_encoder_init(dev, encoder, &intel_ddi_funcs,
 			 DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
 
+	intel_encoder->compute_output_type = intel_ddi_compute_output_type;
 	intel_encoder->compute_config = intel_ddi_compute_config;
 	intel_encoder->enable = intel_enable_ddi;
 	intel_encoder->pre_enable = intel_ddi_pre_enable;
@@ -2379,7 +2433,7 @@  void intel_ddi_init(struct drm_device *dev, enum port port)
 
 	intel_dig_port->max_lanes = max_lanes;
 
-	intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
+	intel_encoder->type = INTEL_OUTPUT_DDI;
 	intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
 	intel_encoder->cloneable = 0;
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 442ed6320082..a6d723a50ccb 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5113,7 +5113,7 @@  intel_display_port_power_domain(struct intel_encoder *intel_encoder)
 	struct intel_digital_port *intel_dig_port;
 
 	switch (intel_encoder->type) {
-	case INTEL_OUTPUT_UNKNOWN:
+	case INTEL_OUTPUT_DDI:
 		/* Only DDI platforms should ever use this output type */
 		WARN_ON_ONCE(!HAS_DDI(dev));
 	case INTEL_OUTPUT_DP:
@@ -5140,15 +5140,8 @@  intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder)
 	struct intel_digital_port *intel_dig_port;
 
 	switch (intel_encoder->type) {
-	case INTEL_OUTPUT_UNKNOWN:
-	case INTEL_OUTPUT_HDMI:
-		/*
-		 * Only DDI platforms should ever use these output types.
-		 * We can get here after the HDMI detect code has already set
-		 * the type of the shared encoder. Since we can't be sure
-		 * what's the status of the given connectors, play safe and
-		 * run the DP detection too.
-		 */
+	case INTEL_OUTPUT_DDI:
+		/* Only DDI platforms should ever use this output type */
 		WARN_ON_ONCE(!HAS_DDI(dev));
 	case INTEL_OUTPUT_DP:
 	case INTEL_OUTPUT_EDP:
@@ -12341,7 +12334,7 @@  static bool check_digital_port_conflicts(struct drm_atomic_state *state)
 
 		switch (encoder->type) {
 			unsigned int port_mask;
-		case INTEL_OUTPUT_UNKNOWN:
+		case INTEL_OUTPUT_DDI:
 			if (WARN_ON(!HAS_DDI(dev)))
 				break;
 		case INTEL_OUTPUT_DP:
@@ -12447,6 +12440,8 @@  intel_modeset_pipe_config(struct drm_crtc *crtc,
 
 		encoder = to_intel_encoder(connector_state->best_encoder);
 
+		DRM_DEBUG_KMS("Using encoder %s\n", encoder->base.name);
+
 		if (!check_single_encoder_cloning(state, to_intel_crtc(crtc), encoder)) {
 			DRM_DEBUG_KMS("rejecting invalid cloning configuration\n");
 			goto fail;
@@ -12456,7 +12451,11 @@  intel_modeset_pipe_config(struct drm_crtc *crtc,
 		 * Determine output_types before calling the .compute_config()
 		 * hooks so that the hooks can use this information safely.
 		 */
-		pipe_config->output_types |= 1 << encoder->type;
+		if (encoder->compute_output_type)
+			pipe_config->output_types |=
+				1 << encoder->compute_output_type(encoder, pipe_config);
+		else
+			pipe_config->output_types |= 1 << encoder->type;
 	}
 
 encoder_retry:
@@ -13023,7 +13022,12 @@  verify_crtc_state(struct drm_crtc *crtc,
 				pipe_name(pipe));
 
 		if (active) {
-			pipe_config->output_types |= 1 << encoder->type;
+			/*
+			 * .get_config() is responsible for this if the
+			 * encoder has multiple personalities
+			 */
+			if (!encoder->compute_output_type)
+				pipe_config->output_types |= 1 << encoder->type;
 			encoder->get_config(encoder, pipe_config);
 		}
 	}
@@ -15916,7 +15920,12 @@  static void intel_modeset_readout_hw_state(struct drm_device *dev)
 		if (encoder->get_hw_state(encoder, &pipe)) {
 			crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
 			encoder->base.crtc = &crtc->base;
-			crtc->config->output_types |= 1 << encoder->type;
+			/*
+			 * .get_config() is responsible for this if the
+			 * encoder has multiple personalities
+			 */
+			if (!encoder->compute_output_type)
+				crtc->config->output_types |= 1 << encoder->type;
 			encoder->get_config(encoder, crtc->config);
 		} else {
 			encoder->base.crtc = NULL;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index e34426dc5c1e..5ee7775d71da 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -4200,9 +4200,6 @@  intel_dp_long_pulse(struct intel_connector *intel_connector)
 		goto out;
 	}
 
-	if (intel_encoder->type != INTEL_OUTPUT_EDP)
-		intel_encoder->type = INTEL_OUTPUT_DP;
-
 	intel_dp_probe_oui(intel_dp);
 
 	ret = intel_dp_probe_mst(intel_dp);
@@ -4266,8 +4263,6 @@  static enum drm_connector_status
 intel_dp_detect(struct drm_connector *connector, bool force)
 {
 	struct intel_dp *intel_dp = intel_attached_dp(connector);
-	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-	struct intel_encoder *intel_encoder = &intel_dig_port->base;
 	struct intel_connector *intel_connector = to_intel_connector(connector);
 
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
@@ -4276,8 +4271,6 @@  intel_dp_detect(struct drm_connector *connector, bool force)
 	if (intel_dp->is_mst) {
 		/* MST devices are disconnected from a monitor POV */
 		intel_dp_unset_edid(intel_dp);
-		if (intel_encoder->type != INTEL_OUTPUT_EDP)
-			intel_encoder->type = INTEL_OUTPUT_DP;
 		return connector_status_disconnected;
 	}
 
@@ -4314,9 +4307,6 @@  intel_dp_force(struct drm_connector *connector)
 	intel_dp_set_edid(intel_dp);
 
 	intel_display_power_put(dev_priv, power_domain);
-
-	if (intel_encoder->type != INTEL_OUTPUT_EDP)
-		intel_encoder->type = INTEL_OUTPUT_DP;
 }
 
 static int intel_dp_get_modes(struct drm_connector *connector)
@@ -4595,10 +4585,6 @@  intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 	enum intel_display_power_domain power_domain;
 	enum irqreturn ret = IRQ_NONE;
 
-	if (intel_dig_port->base.type != INTEL_OUTPUT_EDP &&
-	    intel_dig_port->base.type != INTEL_OUTPUT_HDMI)
-		intel_dig_port->base.type = INTEL_OUTPUT_DP;
-
 	if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) {
 		/*
 		 * vdd off can generate a long pulse on eDP which
@@ -5455,7 +5441,7 @@  intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 	/*
 	 * For eDP we always set the encoder type to INTEL_OUTPUT_EDP, but
 	 * for DP the encoder type can be set by the caller to
-	 * INTEL_OUTPUT_UNKNOWN for DDI, so don't rewrite it.
+	 * INTEL_OUTPUT_DDI, so don't rewrite it.
 	 */
 	if (type == DRM_MODE_CONNECTOR_eDP)
 		intel_encoder->type = INTEL_OUTPUT_EDP;
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
index 5f96466e4e47..f2e2829ebf51 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
@@ -698,7 +698,7 @@  hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 	memset(&crtc_state->dpll_hw_state, 0,
 	       sizeof(crtc_state->dpll_hw_state));
 
-	if (encoder->type == INTEL_OUTPUT_HDMI) {
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
 		uint32_t val;
 		unsigned p, n2, r2;
 
@@ -713,9 +713,7 @@  hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 		pll = intel_find_shared_dpll(crtc, crtc_state,
 					     DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
 
-	} else if (encoder->type == INTEL_OUTPUT_DP ||
-		   encoder->type == INTEL_OUTPUT_DP_MST ||
-		   encoder->type == INTEL_OUTPUT_EDP) {
+	} else if (intel_crtc_has_dp_encoder(crtc_state)) {
 		enum intel_dpll_id pll_id;
 
 		switch (clock / 2) {
@@ -735,7 +733,7 @@  hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 
 		pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
 
-	} else if (encoder->type == INTEL_OUTPUT_ANALOG) {
+	} else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) {
 		if (WARN_ON(crtc_state->port_clock / 2 != 135000))
 			return NULL;
 
@@ -1205,7 +1203,7 @@  skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 
 	ctrl1 = DPLL_CTRL1_OVERRIDE(0);
 
-	if (encoder->type == INTEL_OUTPUT_HDMI) {
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
 		struct skl_wrpll_params wrpll_params = { 0, };
 
 		ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
@@ -1222,9 +1220,7 @@  skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 			 DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
 			 DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
 			 wrpll_params.central_freq;
-	} else if (encoder->type == INTEL_OUTPUT_DP ||
-		   encoder->type == INTEL_OUTPUT_DP_MST ||
-		   encoder->type == INTEL_OUTPUT_EDP) {
+	} else if (intel_crtc_has_dp_encoder(crtc_state)) {
 		switch (crtc_state->port_clock / 2) {
 		case 81000:
 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
@@ -1259,7 +1255,7 @@  skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 	crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
 	crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
 
-	if (encoder->type == INTEL_OUTPUT_EDP)
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
 		pll = intel_find_shared_dpll(crtc, crtc_state,
 					     DPLL_ID_SKL_DPLL0,
 					     DPLL_ID_SKL_DPLL0);
@@ -1507,7 +1503,7 @@  bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 	uint32_t lanestagger;
 	int clock = crtc_state->port_clock;
 
-	if (encoder->type == INTEL_OUTPUT_HDMI) {
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
 		struct dpll best_clock;
 
 		/* Calculate HDMI div */
@@ -1530,8 +1526,7 @@  bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 		clk_div.m2_frac_en = clk_div.m2_frac != 0;
 
 		vco = best_clock.vco;
-	} else if (encoder->type == INTEL_OUTPUT_DP ||
-		   encoder->type == INTEL_OUTPUT_EDP) {
+	} else if (intel_crtc_has_dp_encoder(crtc_state)) {
 		int i;
 
 		clk_div = bxt_dp_clk_val[0];
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 3cc0d4fcdc36..d829d57c9fad 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -138,7 +138,7 @@  enum intel_output_type {
 	INTEL_OUTPUT_DP = 7,
 	INTEL_OUTPUT_EDP = 8,
 	INTEL_OUTPUT_DSI = 9,
-	INTEL_OUTPUT_UNKNOWN = 10,
+	INTEL_OUTPUT_DDI = 10,
 	INTEL_OUTPUT_DP_MST = 11,
 };
 
@@ -168,6 +168,8 @@  struct intel_encoder {
 	enum intel_output_type type;
 	unsigned int cloneable;
 	void (*hot_plug)(struct intel_encoder *);
+	enum intel_output_type (*compute_output_type)(struct intel_encoder *,
+						      struct intel_crtc_state *);
 	bool (*compute_config)(struct intel_encoder *,
 			       struct intel_crtc_state *);
 	void (*pre_pll_enable)(struct intel_encoder *);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 1b91d65ecfb9..830968cdc1c7 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1495,12 +1495,9 @@  intel_hdmi_detect(struct drm_connector *connector, bool force)
 
 	intel_hdmi_unset_edid(connector);
 
-	if (intel_hdmi_set_edid(connector, live_status)) {
-		struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-
-		hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
+	if (intel_hdmi_set_edid(connector, live_status))
 		status = connector_status_connected;
-	} else
+	else
 		status = connector_status_disconnected;
 
 	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
@@ -1511,8 +1508,6 @@  intel_hdmi_detect(struct drm_connector *connector, bool force)
 static void
 intel_hdmi_force(struct drm_connector *connector)
 {
-	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
 		      connector->base.id, connector->name);
 
@@ -1522,7 +1517,6 @@  intel_hdmi_force(struct drm_connector *connector)
 		return;
 
 	intel_hdmi_set_edid(connector, true);
-	hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
 }
 
 static int intel_hdmi_get_modes(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index e61317f5a586..bf9df664cf10 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -365,7 +365,7 @@  int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
 	case INTEL_OUTPUT_ANALOG:
 		type = DISPLAY_TYPE_CRT;
 		break;
-	case INTEL_OUTPUT_UNKNOWN:
+	case INTEL_OUTPUT_DDI:
 	case INTEL_OUTPUT_DP:
 	case INTEL_OUTPUT_HDMI:
 	case INTEL_OUTPUT_DP_MST: