xref: /dflybsd-src/sys/dev/drm/i915/intel_dp_mst.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
124edb884SFrançois Tigeot /*
224edb884SFrançois Tigeot  * Copyright © 2008 Intel Corporation
324edb884SFrançois Tigeot  *             2014 Red Hat Inc.
424edb884SFrançois Tigeot  *
524edb884SFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
624edb884SFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
724edb884SFrançois Tigeot  * to deal in the Software without restriction, including without limitation
824edb884SFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
924edb884SFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
1024edb884SFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
1124edb884SFrançois Tigeot  *
1224edb884SFrançois Tigeot  * The above copyright notice and this permission notice (including the next
1324edb884SFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
1424edb884SFrançois Tigeot  * Software.
1524edb884SFrançois Tigeot  *
1624edb884SFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1724edb884SFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1824edb884SFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1924edb884SFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2024edb884SFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2124edb884SFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2224edb884SFrançois Tigeot  * IN THE SOFTWARE.
2324edb884SFrançois Tigeot  *
2424edb884SFrançois Tigeot  */
2524edb884SFrançois Tigeot 
2624edb884SFrançois Tigeot #include <drm/drmP.h>
2724edb884SFrançois Tigeot #include "i915_drv.h"
2824edb884SFrançois Tigeot #include "intel_drv.h"
292c9916cdSFrançois Tigeot #include <drm/drm_atomic_helper.h>
3024edb884SFrançois Tigeot #include <drm/drm_crtc_helper.h>
3124edb884SFrançois Tigeot #include <drm/drm_edid.h>
3224edb884SFrançois Tigeot 
intel_dp_mst_compute_config(struct intel_encoder * encoder,struct intel_crtc_state * pipe_config,struct drm_connector_state * conn_state)3324edb884SFrançois Tigeot static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
341e12ee3bSFrançois Tigeot 					struct intel_crtc_state *pipe_config,
351e12ee3bSFrançois Tigeot 					struct drm_connector_state *conn_state)
3624edb884SFrançois Tigeot {
3724edb884SFrançois Tigeot 	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
3824edb884SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = intel_mst->primary;
3924edb884SFrançois Tigeot 	struct intel_dp *intel_dp = &intel_dig_port->dp;
40a85cb24fSFrançois Tigeot 	struct intel_connector *connector =
41a85cb24fSFrançois Tigeot 		to_intel_connector(conn_state->connector);
42*3f2dd94aSFrançois Tigeot 	struct drm_atomic_state *state = pipe_config->base.state;
431e12ee3bSFrançois Tigeot 	int bpp;
44352ff8bdSFrançois Tigeot 	int lane_count, slots;
45352ff8bdSFrançois Tigeot 	const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
4624edb884SFrançois Tigeot 	int mst_pbn;
47a85cb24fSFrançois Tigeot 	bool reduce_m_n = drm_dp_has_quirk(&intel_dp->desc,
48a85cb24fSFrançois Tigeot 					   DP_DPCD_QUIRK_LIMITED_M_N);
4924edb884SFrançois Tigeot 
5024edb884SFrançois Tigeot 	pipe_config->has_pch_encoder = false;
5124edb884SFrançois Tigeot 	bpp = 24;
52a85cb24fSFrançois Tigeot 	if (intel_dp->compliance.test_data.bpc) {
53a85cb24fSFrançois Tigeot 		bpp = intel_dp->compliance.test_data.bpc * 3;
54a85cb24fSFrançois Tigeot 		DRM_DEBUG_KMS("Setting pipe bpp to %d\n",
55a85cb24fSFrançois Tigeot 			      bpp);
56a85cb24fSFrançois Tigeot 	}
5724edb884SFrançois Tigeot 	/*
5824edb884SFrançois Tigeot 	 * for MST we always configure max link bw - the spec doesn't
5924edb884SFrançois Tigeot 	 * seem to suggest we should do otherwise.
6024edb884SFrançois Tigeot 	 */
61*3f2dd94aSFrançois Tigeot 	lane_count = intel_dp_max_lane_count(intel_dp);
62477eb7f9SFrançois Tigeot 
63352ff8bdSFrançois Tigeot 	pipe_config->lane_count = lane_count;
6424edb884SFrançois Tigeot 
65a85cb24fSFrançois Tigeot 	pipe_config->pipe_bpp = bpp;
6624edb884SFrançois Tigeot 
67*3f2dd94aSFrançois Tigeot 	pipe_config->port_clock = intel_dp_max_link_rate(intel_dp);
68477eb7f9SFrançois Tigeot 
69a85cb24fSFrançois Tigeot 	if (drm_dp_mst_port_has_audio(&intel_dp->mst_mgr, connector->port))
70a85cb24fSFrançois Tigeot 		pipe_config->has_audio = true;
7124edb884SFrançois Tigeot 
72*3f2dd94aSFrançois Tigeot 	mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp);
7324edb884SFrançois Tigeot 	pipe_config->pbn = mst_pbn;
74*3f2dd94aSFrançois Tigeot 
75*3f2dd94aSFrançois Tigeot 	slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr,
76*3f2dd94aSFrançois Tigeot 					      connector->port, mst_pbn);
77*3f2dd94aSFrançois Tigeot 	if (slots < 0) {
78*3f2dd94aSFrançois Tigeot 		DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", slots);
79*3f2dd94aSFrançois Tigeot 		return false;
80*3f2dd94aSFrançois Tigeot 	}
8124edb884SFrançois Tigeot 
8224edb884SFrançois Tigeot 	intel_link_compute_m_n(bpp, lane_count,
8324edb884SFrançois Tigeot 			       adjusted_mode->crtc_clock,
8424edb884SFrançois Tigeot 			       pipe_config->port_clock,
85a85cb24fSFrançois Tigeot 			       &pipe_config->dp_m_n,
86a85cb24fSFrançois Tigeot 			       reduce_m_n);
8724edb884SFrançois Tigeot 
8824edb884SFrançois Tigeot 	pipe_config->dp_m_n.tu = slots;
89a05eeebfSFrançois Tigeot 
9024edb884SFrançois Tigeot 	return true;
91*3f2dd94aSFrançois Tigeot }
9224edb884SFrançois Tigeot 
intel_dp_mst_atomic_check(struct drm_connector * connector,struct drm_connector_state * new_conn_state)93*3f2dd94aSFrançois Tigeot static int intel_dp_mst_atomic_check(struct drm_connector *connector,
94*3f2dd94aSFrançois Tigeot 		struct drm_connector_state *new_conn_state)
95*3f2dd94aSFrançois Tigeot {
96*3f2dd94aSFrançois Tigeot 	struct drm_atomic_state *state = new_conn_state->state;
97*3f2dd94aSFrançois Tigeot 	struct drm_connector_state *old_conn_state;
98*3f2dd94aSFrançois Tigeot 	struct drm_crtc *old_crtc;
99*3f2dd94aSFrançois Tigeot 	struct drm_crtc_state *crtc_state;
100*3f2dd94aSFrançois Tigeot 	int slots, ret = 0;
101*3f2dd94aSFrançois Tigeot 
102*3f2dd94aSFrançois Tigeot 	old_conn_state = drm_atomic_get_old_connector_state(state, connector);
103*3f2dd94aSFrançois Tigeot 	old_crtc = old_conn_state->crtc;
104*3f2dd94aSFrançois Tigeot 	if (!old_crtc)
105*3f2dd94aSFrançois Tigeot 		return ret;
106*3f2dd94aSFrançois Tigeot 
107*3f2dd94aSFrançois Tigeot 	crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc);
108*3f2dd94aSFrançois Tigeot 	slots = to_intel_crtc_state(crtc_state)->dp_m_n.tu;
109*3f2dd94aSFrançois Tigeot 	if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) {
110*3f2dd94aSFrançois Tigeot 		struct drm_dp_mst_topology_mgr *mgr;
111*3f2dd94aSFrançois Tigeot 		struct drm_encoder *old_encoder;
112*3f2dd94aSFrançois Tigeot 
113*3f2dd94aSFrançois Tigeot 		old_encoder = old_conn_state->best_encoder;
114*3f2dd94aSFrançois Tigeot 		mgr = &enc_to_mst(old_encoder)->primary->dp.mst_mgr;
115*3f2dd94aSFrançois Tigeot 
116*3f2dd94aSFrançois Tigeot 		ret = drm_dp_atomic_release_vcpi_slots(state, mgr, slots);
117*3f2dd94aSFrançois Tigeot 		if (ret)
118*3f2dd94aSFrançois Tigeot 			DRM_DEBUG_KMS("failed releasing %d vcpi slots:%d\n", slots, ret);
119*3f2dd94aSFrançois Tigeot 		else
120*3f2dd94aSFrançois Tigeot 			to_intel_crtc_state(crtc_state)->dp_m_n.tu = 0;
121*3f2dd94aSFrançois Tigeot 	}
122*3f2dd94aSFrançois Tigeot 	return ret;
12324edb884SFrançois Tigeot }
12424edb884SFrançois Tigeot 
intel_mst_disable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)1251e12ee3bSFrançois Tigeot static void intel_mst_disable_dp(struct intel_encoder *encoder,
126*3f2dd94aSFrançois Tigeot 				 const struct intel_crtc_state *old_crtc_state,
127*3f2dd94aSFrançois Tigeot 				 const struct drm_connector_state *old_conn_state)
12824edb884SFrançois Tigeot {
12924edb884SFrançois Tigeot 	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
13024edb884SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = intel_mst->primary;
13124edb884SFrançois Tigeot 	struct intel_dp *intel_dp = &intel_dig_port->dp;
1321e12ee3bSFrançois Tigeot 	struct intel_connector *connector =
1331e12ee3bSFrançois Tigeot 		to_intel_connector(old_conn_state->connector);
13424edb884SFrançois Tigeot 	int ret;
13524edb884SFrançois Tigeot 
136*3f2dd94aSFrançois Tigeot 	DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links);
13724edb884SFrançois Tigeot 
1381e12ee3bSFrançois Tigeot 	drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port);
13924edb884SFrançois Tigeot 
14024edb884SFrançois Tigeot 	ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
14124edb884SFrançois Tigeot 	if (ret) {
14224edb884SFrançois Tigeot 		DRM_ERROR("failed to update payload %d\n", ret);
14324edb884SFrançois Tigeot 	}
144a85cb24fSFrançois Tigeot 	if (old_crtc_state->has_audio)
145a85cb24fSFrançois Tigeot 		intel_audio_codec_disable(encoder);
14624edb884SFrançois Tigeot }
14724edb884SFrançois Tigeot 
intel_mst_post_disable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)1481e12ee3bSFrançois Tigeot static void intel_mst_post_disable_dp(struct intel_encoder *encoder,
149*3f2dd94aSFrançois Tigeot 				      const struct intel_crtc_state *old_crtc_state,
150*3f2dd94aSFrançois Tigeot 				      const struct drm_connector_state *old_conn_state)
15124edb884SFrançois Tigeot {
15224edb884SFrançois Tigeot 	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
15324edb884SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = intel_mst->primary;
15424edb884SFrançois Tigeot 	struct intel_dp *intel_dp = &intel_dig_port->dp;
1551e12ee3bSFrançois Tigeot 	struct intel_connector *connector =
1561e12ee3bSFrançois Tigeot 		to_intel_connector(old_conn_state->connector);
15724edb884SFrançois Tigeot 
15824edb884SFrançois Tigeot 	/* this can fail */
15924edb884SFrançois Tigeot 	drm_dp_check_act_status(&intel_dp->mst_mgr);
16024edb884SFrançois Tigeot 	/* and this can also fail */
16124edb884SFrançois Tigeot 	drm_dp_update_payload_part2(&intel_dp->mst_mgr);
16224edb884SFrançois Tigeot 
1631e12ee3bSFrançois Tigeot 	drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, connector->port);
16424edb884SFrançois Tigeot 
165*3f2dd94aSFrançois Tigeot 	/*
166*3f2dd94aSFrançois Tigeot 	 * Power down mst path before disabling the port, otherwise we end
167*3f2dd94aSFrançois Tigeot 	 * up getting interrupts from the sink upon detecting link loss.
168*3f2dd94aSFrançois Tigeot 	 */
169*3f2dd94aSFrançois Tigeot 	drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port,
170*3f2dd94aSFrançois Tigeot 				     false);
171*3f2dd94aSFrançois Tigeot 
17224edb884SFrançois Tigeot 	intel_dp->active_mst_links--;
1738621f407SFrançois Tigeot 
1748621f407SFrançois Tigeot 	intel_mst->connector = NULL;
17524edb884SFrançois Tigeot 	if (intel_dp->active_mst_links == 0) {
1761e12ee3bSFrançois Tigeot 		intel_dig_port->base.post_disable(&intel_dig_port->base,
1771e12ee3bSFrançois Tigeot 						  NULL, NULL);
17824edb884SFrançois Tigeot 	}
179*3f2dd94aSFrançois Tigeot 	DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links);
18024edb884SFrançois Tigeot }
18124edb884SFrançois Tigeot 
intel_mst_pre_enable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)1821e12ee3bSFrançois Tigeot static void intel_mst_pre_enable_dp(struct intel_encoder *encoder,
183*3f2dd94aSFrançois Tigeot 				    const struct intel_crtc_state *pipe_config,
184*3f2dd94aSFrançois Tigeot 				    const struct drm_connector_state *conn_state)
18524edb884SFrançois Tigeot {
18624edb884SFrançois Tigeot 	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
18724edb884SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = intel_mst->primary;
18824edb884SFrançois Tigeot 	struct intel_dp *intel_dp = &intel_dig_port->dp;
1891e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
19024edb884SFrançois Tigeot 	enum port port = intel_dig_port->port;
1911e12ee3bSFrançois Tigeot 	struct intel_connector *connector =
1921e12ee3bSFrançois Tigeot 		to_intel_connector(conn_state->connector);
19324edb884SFrançois Tigeot 	int ret;
19424edb884SFrançois Tigeot 	uint32_t temp;
19524edb884SFrançois Tigeot 
196a05eeebfSFrançois Tigeot 	/* MST encoders are bound to a crtc, not to a connector,
197a05eeebfSFrançois Tigeot 	 * force the mapping here for get_hw_state.
198a05eeebfSFrançois Tigeot 	 */
1991e12ee3bSFrançois Tigeot 	connector->encoder = encoder;
2001e12ee3bSFrançois Tigeot 	intel_mst->connector = connector;
201a05eeebfSFrançois Tigeot 
202*3f2dd94aSFrançois Tigeot 	DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links);
2038621f407SFrançois Tigeot 
204*3f2dd94aSFrançois Tigeot 	drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, true);
205a85cb24fSFrançois Tigeot 	if (intel_dp->active_mst_links == 0)
206a85cb24fSFrançois Tigeot 		intel_dig_port->base.pre_enable(&intel_dig_port->base,
207a85cb24fSFrançois Tigeot 						pipe_config, NULL);
20824edb884SFrançois Tigeot 
20924edb884SFrançois Tigeot 	ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
2101e12ee3bSFrançois Tigeot 				       connector->port,
211a85cb24fSFrançois Tigeot 				       pipe_config->pbn,
212a85cb24fSFrançois Tigeot 				       pipe_config->dp_m_n.tu);
21324edb884SFrançois Tigeot 	if (ret == false) {
21424edb884SFrançois Tigeot 		DRM_ERROR("failed to allocate vcpi\n");
21524edb884SFrançois Tigeot 		return;
21624edb884SFrançois Tigeot 	}
21724edb884SFrançois Tigeot 
21824edb884SFrançois Tigeot 
21924edb884SFrançois Tigeot 	intel_dp->active_mst_links++;
22024edb884SFrançois Tigeot 	temp = I915_READ(DP_TP_STATUS(port));
22124edb884SFrançois Tigeot 	I915_WRITE(DP_TP_STATUS(port), temp);
22224edb884SFrançois Tigeot 
22324edb884SFrançois Tigeot 	ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
22424edb884SFrançois Tigeot }
22524edb884SFrançois Tigeot 
intel_mst_enable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)2261e12ee3bSFrançois Tigeot static void intel_mst_enable_dp(struct intel_encoder *encoder,
227*3f2dd94aSFrançois Tigeot 				const struct intel_crtc_state *pipe_config,
228*3f2dd94aSFrançois Tigeot 				const struct drm_connector_state *conn_state)
22924edb884SFrançois Tigeot {
23024edb884SFrançois Tigeot 	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
23124edb884SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = intel_mst->primary;
23224edb884SFrançois Tigeot 	struct intel_dp *intel_dp = &intel_dig_port->dp;
2331e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
23424edb884SFrançois Tigeot 	enum port port = intel_dig_port->port;
23524edb884SFrançois Tigeot 	int ret;
23624edb884SFrançois Tigeot 
237*3f2dd94aSFrançois Tigeot 	DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links);
23824edb884SFrançois Tigeot 
2391487f786SFrançois Tigeot 	if (intel_wait_for_register(dev_priv,
2401487f786SFrançois Tigeot 				    DP_TP_STATUS(port),
2411487f786SFrançois Tigeot 				    DP_TP_STATUS_ACT_SENT,
2421487f786SFrançois Tigeot 				    DP_TP_STATUS_ACT_SENT,
24324edb884SFrançois Tigeot 				    1))
24424edb884SFrançois Tigeot 		DRM_ERROR("Timed out waiting for ACT sent\n");
24524edb884SFrançois Tigeot 
24624edb884SFrançois Tigeot 	ret = drm_dp_check_act_status(&intel_dp->mst_mgr);
24724edb884SFrançois Tigeot 
24824edb884SFrançois Tigeot 	ret = drm_dp_update_payload_part2(&intel_dp->mst_mgr);
249a85cb24fSFrançois Tigeot 	if (pipe_config->has_audio)
250a85cb24fSFrançois Tigeot 		intel_audio_codec_enable(encoder, pipe_config, conn_state);
25124edb884SFrançois Tigeot }
25224edb884SFrançois Tigeot 
intel_dp_mst_enc_get_hw_state(struct intel_encoder * encoder,enum i915_pipe * pipe)25324edb884SFrançois Tigeot static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
2541e12ee3bSFrançois Tigeot 				      enum i915_pipe *pipe)
25524edb884SFrançois Tigeot {
25624edb884SFrançois Tigeot 	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
25724edb884SFrançois Tigeot 	*pipe = intel_mst->pipe;
2588621f407SFrançois Tigeot 	if (intel_mst->connector)
25924edb884SFrançois Tigeot 		return true;
26024edb884SFrançois Tigeot 	return false;
26124edb884SFrançois Tigeot }
26224edb884SFrançois Tigeot 
intel_dp_mst_enc_get_config(struct intel_encoder * encoder,struct intel_crtc_state * pipe_config)26324edb884SFrançois Tigeot static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
2642c9916cdSFrançois Tigeot 					struct intel_crtc_state *pipe_config)
26524edb884SFrançois Tigeot {
26624edb884SFrançois Tigeot 	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
26724edb884SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = intel_mst->primary;
2681e12ee3bSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
2691e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
2702c9916cdSFrançois Tigeot 	enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
27124edb884SFrançois Tigeot 	u32 temp, flags = 0;
27224edb884SFrançois Tigeot 
273a85cb24fSFrançois Tigeot 	pipe_config->has_audio =
274a85cb24fSFrançois Tigeot 		intel_ddi_is_audio_enabled(dev_priv, crtc);
275a85cb24fSFrançois Tigeot 
27624edb884SFrançois Tigeot 	temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
27724edb884SFrançois Tigeot 	if (temp & TRANS_DDI_PHSYNC)
27824edb884SFrançois Tigeot 		flags |= DRM_MODE_FLAG_PHSYNC;
27924edb884SFrançois Tigeot 	else
28024edb884SFrançois Tigeot 		flags |= DRM_MODE_FLAG_NHSYNC;
28124edb884SFrançois Tigeot 	if (temp & TRANS_DDI_PVSYNC)
28224edb884SFrançois Tigeot 		flags |= DRM_MODE_FLAG_PVSYNC;
28324edb884SFrançois Tigeot 	else
28424edb884SFrançois Tigeot 		flags |= DRM_MODE_FLAG_NVSYNC;
28524edb884SFrançois Tigeot 
28624edb884SFrançois Tigeot 	switch (temp & TRANS_DDI_BPC_MASK) {
28724edb884SFrançois Tigeot 	case TRANS_DDI_BPC_6:
28824edb884SFrançois Tigeot 		pipe_config->pipe_bpp = 18;
28924edb884SFrançois Tigeot 		break;
29024edb884SFrançois Tigeot 	case TRANS_DDI_BPC_8:
29124edb884SFrançois Tigeot 		pipe_config->pipe_bpp = 24;
29224edb884SFrançois Tigeot 		break;
29324edb884SFrançois Tigeot 	case TRANS_DDI_BPC_10:
29424edb884SFrançois Tigeot 		pipe_config->pipe_bpp = 30;
29524edb884SFrançois Tigeot 		break;
29624edb884SFrançois Tigeot 	case TRANS_DDI_BPC_12:
29724edb884SFrançois Tigeot 		pipe_config->pipe_bpp = 36;
29824edb884SFrançois Tigeot 		break;
29924edb884SFrançois Tigeot 	default:
30024edb884SFrançois Tigeot 		break;
30124edb884SFrançois Tigeot 	}
3022c9916cdSFrançois Tigeot 	pipe_config->base.adjusted_mode.flags |= flags;
303352ff8bdSFrançois Tigeot 
304352ff8bdSFrançois Tigeot 	pipe_config->lane_count =
305352ff8bdSFrançois Tigeot 		((temp & DDI_PORT_WIDTH_MASK) >> DDI_PORT_WIDTH_SHIFT) + 1;
306352ff8bdSFrançois Tigeot 
30724edb884SFrançois Tigeot 	intel_dp_get_m_n(crtc, pipe_config);
30824edb884SFrançois Tigeot 
30924edb884SFrançois Tigeot 	intel_ddi_clock_get(&intel_dig_port->base, pipe_config);
31024edb884SFrançois Tigeot }
31124edb884SFrançois Tigeot 
intel_dp_mst_get_ddc_modes(struct drm_connector * connector)31224edb884SFrançois Tigeot static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
31324edb884SFrançois Tigeot {
31424edb884SFrançois Tigeot 	struct intel_connector *intel_connector = to_intel_connector(connector);
31524edb884SFrançois Tigeot 	struct intel_dp *intel_dp = intel_connector->mst_port;
31624edb884SFrançois Tigeot 	struct edid *edid;
31724edb884SFrançois Tigeot 	int ret;
31824edb884SFrançois Tigeot 
3198621f407SFrançois Tigeot 	if (!intel_dp) {
3208621f407SFrançois Tigeot 		return intel_connector_update_modes(connector, NULL);
3218621f407SFrançois Tigeot 	}
32224edb884SFrançois Tigeot 
3238621f407SFrançois Tigeot 	edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port);
32424edb884SFrançois Tigeot 	ret = intel_connector_update_modes(connector, edid);
32524edb884SFrançois Tigeot 	kfree(edid);
32624edb884SFrançois Tigeot 
32724edb884SFrançois Tigeot 	return ret;
32824edb884SFrançois Tigeot }
32924edb884SFrançois Tigeot 
33024edb884SFrançois Tigeot static enum drm_connector_status
intel_dp_mst_detect(struct drm_connector * connector,bool force)3312c9916cdSFrançois Tigeot intel_dp_mst_detect(struct drm_connector *connector, bool force)
33224edb884SFrançois Tigeot {
33324edb884SFrançois Tigeot 	struct intel_connector *intel_connector = to_intel_connector(connector);
33424edb884SFrançois Tigeot 	struct intel_dp *intel_dp = intel_connector->mst_port;
33524edb884SFrançois Tigeot 
3368621f407SFrançois Tigeot 	if (!intel_dp)
3378621f407SFrançois Tigeot 		return connector_status_disconnected;
3382c9916cdSFrançois Tigeot 	return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, intel_connector->port);
33924edb884SFrançois Tigeot }
34024edb884SFrançois Tigeot 
34124edb884SFrançois Tigeot static void
intel_dp_mst_connector_destroy(struct drm_connector * connector)34224edb884SFrançois Tigeot intel_dp_mst_connector_destroy(struct drm_connector *connector)
34324edb884SFrançois Tigeot {
34424edb884SFrançois Tigeot 	struct intel_connector *intel_connector = to_intel_connector(connector);
34524edb884SFrançois Tigeot 
34624edb884SFrançois Tigeot 	if (!IS_ERR_OR_NULL(intel_connector->edid))
34724edb884SFrançois Tigeot 		kfree(intel_connector->edid);
34824edb884SFrançois Tigeot 
34924edb884SFrançois Tigeot 	drm_connector_cleanup(connector);
35024edb884SFrançois Tigeot 	kfree(connector);
35124edb884SFrançois Tigeot }
35224edb884SFrançois Tigeot 
35324edb884SFrançois Tigeot static const struct drm_connector_funcs intel_dp_mst_connector_funcs = {
35424edb884SFrançois Tigeot 	.detect = intel_dp_mst_detect,
35524edb884SFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
3561487f786SFrançois Tigeot 	.late_register = intel_connector_register,
3571487f786SFrançois Tigeot 	.early_unregister = intel_connector_unregister,
35824edb884SFrançois Tigeot 	.destroy = intel_dp_mst_connector_destroy,
3592c9916cdSFrançois Tigeot 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
360477eb7f9SFrançois Tigeot 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
36124edb884SFrançois Tigeot };
36224edb884SFrançois Tigeot 
intel_dp_mst_get_modes(struct drm_connector * connector)36324edb884SFrançois Tigeot static int intel_dp_mst_get_modes(struct drm_connector *connector)
36424edb884SFrançois Tigeot {
36524edb884SFrançois Tigeot 	return intel_dp_mst_get_ddc_modes(connector);
36624edb884SFrançois Tigeot }
36724edb884SFrançois Tigeot 
36824edb884SFrançois Tigeot static enum drm_mode_status
intel_dp_mst_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)36924edb884SFrançois Tigeot intel_dp_mst_mode_valid(struct drm_connector *connector,
37024edb884SFrançois Tigeot 			struct drm_display_mode *mode)
37124edb884SFrançois Tigeot {
372a85cb24fSFrançois Tigeot 	struct intel_connector *intel_connector = to_intel_connector(connector);
373a85cb24fSFrançois Tigeot 	struct intel_dp *intel_dp = intel_connector->mst_port;
374c0e85e96SFrançois Tigeot 	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
375a85cb24fSFrançois Tigeot 	int bpp = 24; /* MST uses fixed bpp */
376a85cb24fSFrançois Tigeot 	int max_rate, mode_rate, max_lanes, max_link_clock;
377a85cb24fSFrançois Tigeot 
378*3f2dd94aSFrançois Tigeot 	if (!intel_dp)
379*3f2dd94aSFrançois Tigeot 		return MODE_ERROR;
380*3f2dd94aSFrançois Tigeot 
381a85cb24fSFrançois Tigeot 	max_link_clock = intel_dp_max_link_rate(intel_dp);
382*3f2dd94aSFrançois Tigeot 	max_lanes = intel_dp_max_lane_count(intel_dp);
383a85cb24fSFrançois Tigeot 
384a85cb24fSFrançois Tigeot 	max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
385a85cb24fSFrançois Tigeot 	mode_rate = intel_dp_link_required(mode->clock, bpp);
386c0e85e96SFrançois Tigeot 
38724edb884SFrançois Tigeot 	/* TODO - validate mode against available PBN for link */
38824edb884SFrançois Tigeot 	if (mode->clock < 10000)
38924edb884SFrançois Tigeot 		return MODE_CLOCK_LOW;
39024edb884SFrançois Tigeot 
39124edb884SFrançois Tigeot 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
39224edb884SFrançois Tigeot 		return MODE_H_ILLEGAL;
39324edb884SFrançois Tigeot 
394a85cb24fSFrançois Tigeot 	if (mode_rate > max_rate || mode->clock > max_dotclk)
395c0e85e96SFrançois Tigeot 		return MODE_CLOCK_HIGH;
396c0e85e96SFrançois Tigeot 
39724edb884SFrançois Tigeot 	return MODE_OK;
39824edb884SFrançois Tigeot }
39924edb884SFrançois Tigeot 
intel_mst_atomic_best_encoder(struct drm_connector * connector,struct drm_connector_state * state)40019c468b4SFrançois Tigeot static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *connector,
40119c468b4SFrançois Tigeot 							 struct drm_connector_state *state)
40219c468b4SFrançois Tigeot {
40319c468b4SFrançois Tigeot 	struct intel_connector *intel_connector = to_intel_connector(connector);
40419c468b4SFrançois Tigeot 	struct intel_dp *intel_dp = intel_connector->mst_port;
40519c468b4SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(state->crtc);
40619c468b4SFrançois Tigeot 
4078621f407SFrançois Tigeot 	if (!intel_dp)
4088621f407SFrançois Tigeot 		return NULL;
40919c468b4SFrançois Tigeot 	return &intel_dp->mst_encoders[crtc->pipe]->base.base;
41019c468b4SFrançois Tigeot }
41119c468b4SFrançois Tigeot 
intel_mst_best_encoder(struct drm_connector * connector)41224edb884SFrançois Tigeot static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connector)
41324edb884SFrançois Tigeot {
41424edb884SFrançois Tigeot 	struct intel_connector *intel_connector = to_intel_connector(connector);
41524edb884SFrançois Tigeot 	struct intel_dp *intel_dp = intel_connector->mst_port;
4168621f407SFrançois Tigeot 	if (!intel_dp)
4178621f407SFrançois Tigeot 		return NULL;
41824edb884SFrançois Tigeot 	return &intel_dp->mst_encoders[0]->base.base;
41924edb884SFrançois Tigeot }
42024edb884SFrançois Tigeot 
42124edb884SFrançois Tigeot static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = {
42224edb884SFrançois Tigeot 	.get_modes = intel_dp_mst_get_modes,
42324edb884SFrançois Tigeot 	.mode_valid = intel_dp_mst_mode_valid,
42419c468b4SFrançois Tigeot 	.atomic_best_encoder = intel_mst_atomic_best_encoder,
42524edb884SFrançois Tigeot 	.best_encoder = intel_mst_best_encoder,
426*3f2dd94aSFrançois Tigeot 	.atomic_check = intel_dp_mst_atomic_check,
42724edb884SFrançois Tigeot };
42824edb884SFrançois Tigeot 
intel_dp_mst_encoder_destroy(struct drm_encoder * encoder)42924edb884SFrançois Tigeot static void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder)
43024edb884SFrançois Tigeot {
43124edb884SFrançois Tigeot 	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
43224edb884SFrançois Tigeot 
43324edb884SFrançois Tigeot 	drm_encoder_cleanup(encoder);
43424edb884SFrançois Tigeot 	kfree(intel_mst);
43524edb884SFrançois Tigeot }
43624edb884SFrançois Tigeot 
43724edb884SFrançois Tigeot static const struct drm_encoder_funcs intel_dp_mst_enc_funcs = {
43824edb884SFrançois Tigeot 	.destroy = intel_dp_mst_encoder_destroy,
43924edb884SFrançois Tigeot };
44024edb884SFrançois Tigeot 
intel_dp_mst_get_hw_state(struct intel_connector * connector)44124edb884SFrançois Tigeot static bool intel_dp_mst_get_hw_state(struct intel_connector *connector)
44224edb884SFrançois Tigeot {
443a05eeebfSFrançois Tigeot 	if (connector->encoder && connector->base.state->crtc) {
4441e12ee3bSFrançois Tigeot 		enum i915_pipe pipe;
44524edb884SFrançois Tigeot 		if (!connector->encoder->get_hw_state(connector->encoder, &pipe))
44624edb884SFrançois Tigeot 			return false;
44724edb884SFrançois Tigeot 		return true;
44824edb884SFrançois Tigeot 	}
44924edb884SFrançois Tigeot 	return false;
45024edb884SFrançois Tigeot }
45124edb884SFrançois Tigeot 
intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr * mgr,struct drm_dp_mst_port * port,const char * pathprop)4522c9916cdSFrançois Tigeot static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *pathprop)
45324edb884SFrançois Tigeot {
45424edb884SFrançois Tigeot 	struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr);
45524edb884SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
45624edb884SFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
457*3f2dd94aSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
45824edb884SFrançois Tigeot 	struct intel_connector *intel_connector;
45924edb884SFrançois Tigeot 	struct drm_connector *connector;
460*3f2dd94aSFrançois Tigeot 	enum i915_pipe pipe;
461*3f2dd94aSFrançois Tigeot 	int ret;
46224edb884SFrançois Tigeot 
463477eb7f9SFrançois Tigeot 	intel_connector = intel_connector_alloc();
46424edb884SFrançois Tigeot 	if (!intel_connector)
46524edb884SFrançois Tigeot 		return NULL;
46624edb884SFrançois Tigeot 
46724edb884SFrançois Tigeot 	connector = &intel_connector->base;
468*3f2dd94aSFrançois Tigeot 	ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs,
469*3f2dd94aSFrançois Tigeot 				 DRM_MODE_CONNECTOR_DisplayPort);
470*3f2dd94aSFrançois Tigeot 	if (ret) {
471*3f2dd94aSFrançois Tigeot 		intel_connector_free(intel_connector);
472*3f2dd94aSFrançois Tigeot 		return NULL;
473*3f2dd94aSFrançois Tigeot 	}
474*3f2dd94aSFrançois Tigeot 
47524edb884SFrançois Tigeot 	drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs);
47624edb884SFrançois Tigeot 
47724edb884SFrançois Tigeot 	intel_connector->get_hw_state = intel_dp_mst_get_hw_state;
47824edb884SFrançois Tigeot 	intel_connector->mst_port = intel_dp;
47924edb884SFrançois Tigeot 	intel_connector->port = port;
48024edb884SFrançois Tigeot 
481*3f2dd94aSFrançois Tigeot 	for_each_pipe(dev_priv, pipe) {
482*3f2dd94aSFrançois Tigeot 		struct drm_encoder *enc =
483*3f2dd94aSFrançois Tigeot 			&intel_dp->mst_encoders[pipe]->base.base;
484*3f2dd94aSFrançois Tigeot 
485*3f2dd94aSFrançois Tigeot 		ret = drm_mode_connector_attach_encoder(&intel_connector->base,
486*3f2dd94aSFrançois Tigeot 							enc);
487*3f2dd94aSFrançois Tigeot 		if (ret)
488*3f2dd94aSFrançois Tigeot 			goto err;
48924edb884SFrançois Tigeot 	}
49024edb884SFrançois Tigeot 
49124edb884SFrançois Tigeot 	drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
4922c9916cdSFrançois Tigeot 	drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0);
4932c9916cdSFrançois Tigeot 
494*3f2dd94aSFrançois Tigeot 	ret = drm_mode_connector_set_path_property(connector, pathprop);
495*3f2dd94aSFrançois Tigeot 	if (ret)
496*3f2dd94aSFrançois Tigeot 		goto err;
497*3f2dd94aSFrançois Tigeot 
49824edb884SFrançois Tigeot 	return connector;
499*3f2dd94aSFrançois Tigeot 
500*3f2dd94aSFrançois Tigeot err:
501*3f2dd94aSFrançois Tigeot 	drm_connector_cleanup(connector);
502*3f2dd94aSFrançois Tigeot 	return NULL;
50324edb884SFrançois Tigeot }
50424edb884SFrançois Tigeot 
intel_dp_register_mst_connector(struct drm_connector * connector)505a05eeebfSFrançois Tigeot static void intel_dp_register_mst_connector(struct drm_connector *connector)
506a05eeebfSFrançois Tigeot {
507*3f2dd94aSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
5081487f786SFrançois Tigeot 
509*3f2dd94aSFrançois Tigeot 	if (dev_priv->fbdev)
510*3f2dd94aSFrançois Tigeot 		drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper,
511*3f2dd94aSFrançois Tigeot 						connector);
5121487f786SFrançois Tigeot 
513*3f2dd94aSFrançois Tigeot 	drm_connector_register(connector);
514a05eeebfSFrançois Tigeot }
515a05eeebfSFrançois Tigeot 
intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr * mgr,struct drm_connector * connector)51624edb884SFrançois Tigeot static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
51724edb884SFrançois Tigeot 					   struct drm_connector *connector)
51824edb884SFrançois Tigeot {
51924edb884SFrançois Tigeot 	struct intel_connector *intel_connector = to_intel_connector(connector);
520*3f2dd94aSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
521a05eeebfSFrançois Tigeot 
522*3f2dd94aSFrançois Tigeot 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name);
5231487f786SFrançois Tigeot 	drm_connector_unregister(connector);
524c0e85e96SFrançois Tigeot 
525*3f2dd94aSFrançois Tigeot 	if (dev_priv->fbdev)
526*3f2dd94aSFrançois Tigeot 		drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper,
527*3f2dd94aSFrançois Tigeot 						   connector);
528*3f2dd94aSFrançois Tigeot 	/* prevent race with the check in ->detect */
529*3f2dd94aSFrançois Tigeot 	drm_modeset_lock(&connector->dev->mode_config.connection_mutex, NULL);
5308621f407SFrançois Tigeot 	intel_connector->mst_port = NULL;
531*3f2dd94aSFrançois Tigeot 	drm_modeset_unlock(&connector->dev->mode_config.connection_mutex);
53224edb884SFrançois Tigeot 
533*3f2dd94aSFrançois Tigeot 	drm_connector_unreference(connector);
53424edb884SFrançois Tigeot }
53524edb884SFrançois Tigeot 
intel_dp_mst_hotplug(struct drm_dp_mst_topology_mgr * mgr)53624edb884SFrançois Tigeot static void intel_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
53724edb884SFrançois Tigeot {
53824edb884SFrançois Tigeot 	struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr);
53924edb884SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
54024edb884SFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
54124edb884SFrançois Tigeot 
54224edb884SFrançois Tigeot 	drm_kms_helper_hotplug_event(dev);
54324edb884SFrançois Tigeot }
54424edb884SFrançois Tigeot 
545aee94f86SFrançois Tigeot static const struct drm_dp_mst_topology_cbs mst_cbs = {
54624edb884SFrançois Tigeot 	.add_connector = intel_dp_add_mst_connector,
547a05eeebfSFrançois Tigeot 	.register_connector = intel_dp_register_mst_connector,
54824edb884SFrançois Tigeot 	.destroy_connector = intel_dp_destroy_mst_connector,
54924edb884SFrançois Tigeot 	.hotplug = intel_dp_mst_hotplug,
55024edb884SFrançois Tigeot };
55124edb884SFrançois Tigeot 
55224edb884SFrançois Tigeot static struct intel_dp_mst_encoder *
intel_dp_create_fake_mst_encoder(struct intel_digital_port * intel_dig_port,enum i915_pipe pipe)5531e12ee3bSFrançois Tigeot intel_dp_create_fake_mst_encoder(struct intel_digital_port *intel_dig_port, enum i915_pipe pipe)
55424edb884SFrançois Tigeot {
55524edb884SFrançois Tigeot 	struct intel_dp_mst_encoder *intel_mst;
55624edb884SFrançois Tigeot 	struct intel_encoder *intel_encoder;
55724edb884SFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
55824edb884SFrançois Tigeot 
55924edb884SFrançois Tigeot 	intel_mst = kzalloc(sizeof(*intel_mst), GFP_KERNEL);
56024edb884SFrançois Tigeot 
56124edb884SFrançois Tigeot 	if (!intel_mst)
56224edb884SFrançois Tigeot 		return NULL;
56324edb884SFrançois Tigeot 
56424edb884SFrançois Tigeot 	intel_mst->pipe = pipe;
56524edb884SFrançois Tigeot 	intel_encoder = &intel_mst->base;
56624edb884SFrançois Tigeot 	intel_mst->primary = intel_dig_port;
56724edb884SFrançois Tigeot 
56824edb884SFrançois Tigeot 	drm_encoder_init(dev, &intel_encoder->base, &intel_dp_mst_enc_funcs,
5691487f786SFrançois Tigeot 			 DRM_MODE_ENCODER_DPMST, "DP-MST %c", pipe_name(pipe));
57024edb884SFrançois Tigeot 
57124edb884SFrançois Tigeot 	intel_encoder->type = INTEL_OUTPUT_DP_MST;
572a85cb24fSFrançois Tigeot 	intel_encoder->power_domain = intel_dig_port->base.power_domain;
5731e12ee3bSFrançois Tigeot 	intel_encoder->port = intel_dig_port->port;
57424edb884SFrançois Tigeot 	intel_encoder->crtc_mask = 0x7;
57524edb884SFrançois Tigeot 	intel_encoder->cloneable = 0;
57624edb884SFrançois Tigeot 
57724edb884SFrançois Tigeot 	intel_encoder->compute_config = intel_dp_mst_compute_config;
57824edb884SFrançois Tigeot 	intel_encoder->disable = intel_mst_disable_dp;
57924edb884SFrançois Tigeot 	intel_encoder->post_disable = intel_mst_post_disable_dp;
58024edb884SFrançois Tigeot 	intel_encoder->pre_enable = intel_mst_pre_enable_dp;
58124edb884SFrançois Tigeot 	intel_encoder->enable = intel_mst_enable_dp;
58224edb884SFrançois Tigeot 	intel_encoder->get_hw_state = intel_dp_mst_enc_get_hw_state;
58324edb884SFrançois Tigeot 	intel_encoder->get_config = intel_dp_mst_enc_get_config;
58424edb884SFrançois Tigeot 
58524edb884SFrançois Tigeot 	return intel_mst;
58624edb884SFrançois Tigeot 
58724edb884SFrançois Tigeot }
58824edb884SFrançois Tigeot 
58924edb884SFrançois Tigeot static bool
intel_dp_create_fake_mst_encoders(struct intel_digital_port * intel_dig_port)59024edb884SFrançois Tigeot intel_dp_create_fake_mst_encoders(struct intel_digital_port *intel_dig_port)
59124edb884SFrançois Tigeot {
59224edb884SFrançois Tigeot 	struct intel_dp *intel_dp = &intel_dig_port->dp;
593*3f2dd94aSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
594*3f2dd94aSFrançois Tigeot 	enum i915_pipe pipe;
59524edb884SFrançois Tigeot 
596*3f2dd94aSFrançois Tigeot 	for_each_pipe(dev_priv, pipe)
597*3f2dd94aSFrançois Tigeot 		intel_dp->mst_encoders[pipe] = intel_dp_create_fake_mst_encoder(intel_dig_port, pipe);
59824edb884SFrançois Tigeot 	return true;
59924edb884SFrançois Tigeot }
60024edb884SFrançois Tigeot 
60124edb884SFrançois Tigeot int
intel_dp_mst_encoder_init(struct intel_digital_port * intel_dig_port,int conn_base_id)60224edb884SFrançois Tigeot intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_base_id)
60324edb884SFrançois Tigeot {
60424edb884SFrançois Tigeot 	struct intel_dp *intel_dp = &intel_dig_port->dp;
60524edb884SFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
60624edb884SFrançois Tigeot 	int ret;
60724edb884SFrançois Tigeot 
60824edb884SFrançois Tigeot 	intel_dp->can_mst = true;
60924edb884SFrançois Tigeot 	intel_dp->mst_mgr.cbs = &mst_cbs;
61024edb884SFrançois Tigeot 
61124edb884SFrançois Tigeot 	/* create encoders */
61224edb884SFrançois Tigeot 	intel_dp_create_fake_mst_encoders(intel_dig_port);
613a85cb24fSFrançois Tigeot 	ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev,
614a85cb24fSFrançois Tigeot 					   &intel_dp->aux, 16, 3, conn_base_id);
61524edb884SFrançois Tigeot 	if (ret) {
61624edb884SFrançois Tigeot 		intel_dp->can_mst = false;
61724edb884SFrançois Tigeot 		return ret;
61824edb884SFrançois Tigeot 	}
61924edb884SFrançois Tigeot 	return 0;
62024edb884SFrançois Tigeot }
62124edb884SFrançois Tigeot 
62224edb884SFrançois Tigeot void
intel_dp_mst_encoder_cleanup(struct intel_digital_port * intel_dig_port)62324edb884SFrançois Tigeot intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port)
62424edb884SFrançois Tigeot {
62524edb884SFrançois Tigeot 	struct intel_dp *intel_dp = &intel_dig_port->dp;
62624edb884SFrançois Tigeot 
62724edb884SFrançois Tigeot 	if (!intel_dp->can_mst)
62824edb884SFrançois Tigeot 		return;
62924edb884SFrançois Tigeot 
63024edb884SFrançois Tigeot 	drm_dp_mst_topology_mgr_destroy(&intel_dp->mst_mgr);
63124edb884SFrançois Tigeot 	/* encoders will get killed by normal cleanup */
63224edb884SFrançois Tigeot }
633