Commit | Line | Data |
---|---|---|
0e32b39c DA |
1 | /* |
2 | * Copyright © 2008 Intel Corporation | |
3 | * 2014 Red Hat Inc. | |
4 | * | |
5 | * Permission is hereby granted, free of charge, to any person obtaining a | |
6 | * copy of this software and associated documentation files (the "Software"), | |
7 | * to deal in the Software without restriction, including without limitation | |
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
9 | * and/or sell copies of the Software, and to permit persons to whom the | |
10 | * Software is furnished to do so, subject to the following conditions: | |
11 | * | |
12 | * The above copyright notice and this permission notice (including the next | |
13 | * paragraph) shall be included in all copies or substantial portions of the | |
14 | * Software. | |
15 | * | |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
22 | * IN THE SOFTWARE. | |
23 | * | |
24 | */ | |
25 | ||
26 | #include <drm/drmP.h> | |
27 | #include "i915_drv.h" | |
28 | #include "intel_drv.h" | |
c6f95f27 | 29 | #include <drm/drm_atomic_helper.h> |
0e32b39c DA |
30 | #include <drm/drm_crtc_helper.h> |
31 | #include <drm/drm_edid.h> | |
32 | ||
33 | static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, | |
0a478c27 ML |
34 | struct intel_crtc_state *pipe_config, |
35 | struct drm_connector_state *conn_state) | |
0e32b39c | 36 | { |
53e9bf5e | 37 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
0e32b39c DA |
38 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); |
39 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | |
40 | struct intel_dp *intel_dp = &intel_dig_port->dp; | |
7f9e7754 LY |
41 | struct intel_connector *connector = |
42 | to_intel_connector(conn_state->connector); | |
f424f55e | 43 | struct drm_atomic_state *state = pipe_config->base.state; |
1189e4f4 | 44 | int bpp; |
04a60f9f | 45 | int lane_count, slots; |
7c5f93b0 | 46 | const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; |
0e32b39c | 47 | int mst_pbn; |
b31e85ed JN |
48 | bool reduce_m_n = drm_dp_has_quirk(&intel_dp->desc, |
49 | DP_DPCD_QUIRK_LIMITED_M_N); | |
0e32b39c | 50 | |
0e32b39c | 51 | pipe_config->has_pch_encoder = false; |
0e32b39c | 52 | bpp = 24; |
611032bf MN |
53 | if (intel_dp->compliance.test_data.bpc) { |
54 | bpp = intel_dp->compliance.test_data.bpc * 3; | |
55 | DRM_DEBUG_KMS("Setting pipe bpp to %d\n", | |
56 | bpp); | |
57 | } | |
0e32b39c DA |
58 | /* |
59 | * for MST we always configure max link bw - the spec doesn't | |
60 | * seem to suggest we should do otherwise. | |
61 | */ | |
3d65a735 | 62 | lane_count = intel_dp_max_lane_count(intel_dp); |
ed4e9c1d | 63 | |
90a6b7b0 | 64 | pipe_config->lane_count = lane_count; |
0e32b39c | 65 | |
611032bf | 66 | pipe_config->pipe_bpp = bpp; |
0e32b39c | 67 | |
f424f55e | 68 | pipe_config->port_clock = intel_dp_max_link_rate(intel_dp); |
e75f4771 | 69 | |
7f9e7754 LY |
70 | if (drm_dp_mst_port_has_audio(&intel_dp->mst_mgr, connector->port)) |
71 | pipe_config->has_audio = true; | |
0e32b39c | 72 | |
f424f55e | 73 | mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp); |
0e32b39c | 74 | pipe_config->pbn = mst_pbn; |
f424f55e PD |
75 | |
76 | slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr, | |
77 | connector->port, mst_pbn); | |
78 | if (slots < 0) { | |
79 | DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", slots); | |
80 | return false; | |
81 | } | |
0e32b39c DA |
82 | |
83 | intel_link_compute_m_n(bpp, lane_count, | |
84 | adjusted_mode->crtc_clock, | |
85 | pipe_config->port_clock, | |
b31e85ed JN |
86 | &pipe_config->dp_m_n, |
87 | reduce_m_n); | |
0e32b39c DA |
88 | |
89 | pipe_config->dp_m_n.tu = slots; | |
6fa2d197 | 90 | |
5161d058 VS |
91 | if (IS_GEN9_LP(dev_priv)) |
92 | pipe_config->lane_lat_optim_mask = | |
93 | bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count); | |
94 | ||
53e9bf5e VS |
95 | intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); |
96 | ||
0e32b39c | 97 | return true; |
f424f55e | 98 | } |
0e32b39c | 99 | |
f424f55e PD |
100 | static int intel_dp_mst_atomic_check(struct drm_connector *connector, |
101 | struct drm_connector_state *new_conn_state) | |
102 | { | |
103 | struct drm_atomic_state *state = new_conn_state->state; | |
104 | struct drm_connector_state *old_conn_state; | |
105 | struct drm_crtc *old_crtc; | |
106 | struct drm_crtc_state *crtc_state; | |
107 | int slots, ret = 0; | |
108 | ||
109 | old_conn_state = drm_atomic_get_old_connector_state(state, connector); | |
110 | old_crtc = old_conn_state->crtc; | |
111 | if (!old_crtc) | |
112 | return ret; | |
113 | ||
114 | crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc); | |
115 | slots = to_intel_crtc_state(crtc_state)->dp_m_n.tu; | |
116 | if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) { | |
117 | struct drm_dp_mst_topology_mgr *mgr; | |
118 | struct drm_encoder *old_encoder; | |
119 | ||
120 | old_encoder = old_conn_state->best_encoder; | |
121 | mgr = &enc_to_mst(old_encoder)->primary->dp.mst_mgr; | |
122 | ||
123 | ret = drm_dp_atomic_release_vcpi_slots(state, mgr, slots); | |
124 | if (ret) | |
125 | DRM_DEBUG_KMS("failed releasing %d vcpi slots:%d\n", slots, ret); | |
126 | else | |
127 | to_intel_crtc_state(crtc_state)->dp_m_n.tu = 0; | |
128 | } | |
129 | return ret; | |
0e32b39c DA |
130 | } |
131 | ||
fd6bbda9 | 132 | static void intel_mst_disable_dp(struct intel_encoder *encoder, |
5f88a9c6 VS |
133 | const struct intel_crtc_state *old_crtc_state, |
134 | const struct drm_connector_state *old_conn_state) | |
0e32b39c DA |
135 | { |
136 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
137 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | |
138 | struct intel_dp *intel_dp = &intel_dig_port->dp; | |
1e7bfa0b ML |
139 | struct intel_connector *connector = |
140 | to_intel_connector(old_conn_state->connector); | |
0e32b39c DA |
141 | int ret; |
142 | ||
9b1c5818 | 143 | DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links); |
0e32b39c | 144 | |
1e7bfa0b | 145 | drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port); |
0e32b39c DA |
146 | |
147 | ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr); | |
148 | if (ret) { | |
149 | DRM_ERROR("failed to update payload %d\n", ret); | |
150 | } | |
37255d8d | 151 | if (old_crtc_state->has_audio) |
8ec47de2 VS |
152 | intel_audio_codec_disable(encoder, |
153 | old_crtc_state, old_conn_state); | |
0e32b39c DA |
154 | } |
155 | ||
fd6bbda9 | 156 | static void intel_mst_post_disable_dp(struct intel_encoder *encoder, |
5f88a9c6 VS |
157 | const struct intel_crtc_state *old_crtc_state, |
158 | const struct drm_connector_state *old_conn_state) | |
0e32b39c DA |
159 | { |
160 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
161 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | |
162 | struct intel_dp *intel_dp = &intel_dig_port->dp; | |
1e7bfa0b ML |
163 | struct intel_connector *connector = |
164 | to_intel_connector(old_conn_state->connector); | |
0e32b39c | 165 | |
0e32b39c DA |
166 | /* this can fail */ |
167 | drm_dp_check_act_status(&intel_dp->mst_mgr); | |
168 | /* and this can also fail */ | |
169 | drm_dp_update_payload_part2(&intel_dp->mst_mgr); | |
170 | ||
1e7bfa0b | 171 | drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, connector->port); |
0e32b39c | 172 | |
5ea2355a DP |
173 | /* |
174 | * Power down mst path before disabling the port, otherwise we end | |
175 | * up getting interrupts from the sink upon detecting link loss. | |
176 | */ | |
177 | drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, | |
178 | false); | |
179 | ||
19e0b4ca | 180 | intel_dp->active_mst_links--; |
0552f765 DA |
181 | |
182 | intel_mst->connector = NULL; | |
1939ba51 | 183 | if (intel_dp->active_mst_links == 0) |
fd6bbda9 | 184 | intel_dig_port->base.post_disable(&intel_dig_port->base, |
1939ba51 VS |
185 | old_crtc_state, NULL); |
186 | ||
9b1c5818 | 187 | DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links); |
0e32b39c DA |
188 | } |
189 | ||
5161d058 VS |
190 | static void intel_mst_pre_pll_enable_dp(struct intel_encoder *encoder, |
191 | const struct intel_crtc_state *pipe_config, | |
192 | const struct drm_connector_state *conn_state) | |
193 | { | |
194 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
195 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | |
196 | struct intel_dp *intel_dp = &intel_dig_port->dp; | |
197 | ||
198 | if (intel_dp->active_mst_links == 0 && | |
199 | intel_dig_port->base.pre_pll_enable) | |
200 | intel_dig_port->base.pre_pll_enable(&intel_dig_port->base, | |
201 | pipe_config, NULL); | |
202 | } | |
203 | ||
fd6bbda9 | 204 | static void intel_mst_pre_enable_dp(struct intel_encoder *encoder, |
5f88a9c6 VS |
205 | const struct intel_crtc_state *pipe_config, |
206 | const struct drm_connector_state *conn_state) | |
0e32b39c DA |
207 | { |
208 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
209 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | |
210 | struct intel_dp *intel_dp = &intel_dig_port->dp; | |
1e7bfa0b | 211 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
8f4f2797 | 212 | enum port port = intel_dig_port->base.port; |
1e7bfa0b ML |
213 | struct intel_connector *connector = |
214 | to_intel_connector(conn_state->connector); | |
0e32b39c DA |
215 | int ret; |
216 | uint32_t temp; | |
0e32b39c | 217 | |
e85376cb ML |
218 | /* MST encoders are bound to a crtc, not to a connector, |
219 | * force the mapping here for get_hw_state. | |
220 | */ | |
1e7bfa0b ML |
221 | connector->encoder = encoder; |
222 | intel_mst->connector = connector; | |
e85376cb | 223 | |
9b1c5818 | 224 | DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links); |
0552f765 | 225 | |
5ea2355a | 226 | drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, true); |
e081c846 ACO |
227 | if (intel_dp->active_mst_links == 0) |
228 | intel_dig_port->base.pre_enable(&intel_dig_port->base, | |
229 | pipe_config, NULL); | |
0e32b39c DA |
230 | |
231 | ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr, | |
1e7bfa0b | 232 | connector->port, |
1e797f55 PD |
233 | pipe_config->pbn, |
234 | pipe_config->dp_m_n.tu); | |
0e32b39c DA |
235 | if (ret == false) { |
236 | DRM_ERROR("failed to allocate vcpi\n"); | |
237 | return; | |
238 | } | |
239 | ||
240 | ||
19e0b4ca | 241 | intel_dp->active_mst_links++; |
0e32b39c DA |
242 | temp = I915_READ(DP_TP_STATUS(port)); |
243 | I915_WRITE(DP_TP_STATUS(port), temp); | |
244 | ||
245 | ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr); | |
246 | } | |
247 | ||
fd6bbda9 | 248 | static void intel_mst_enable_dp(struct intel_encoder *encoder, |
5f88a9c6 VS |
249 | const struct intel_crtc_state *pipe_config, |
250 | const struct drm_connector_state *conn_state) | |
0e32b39c DA |
251 | { |
252 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
253 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | |
254 | struct intel_dp *intel_dp = &intel_dig_port->dp; | |
1e7bfa0b | 255 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
8f4f2797 | 256 | enum port port = intel_dig_port->base.port; |
0e32b39c DA |
257 | int ret; |
258 | ||
9b1c5818 | 259 | DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links); |
0e32b39c | 260 | |
3016a31f CW |
261 | if (intel_wait_for_register(dev_priv, |
262 | DP_TP_STATUS(port), | |
263 | DP_TP_STATUS_ACT_SENT, | |
264 | DP_TP_STATUS_ACT_SENT, | |
265 | 1)) | |
0e32b39c DA |
266 | DRM_ERROR("Timed out waiting for ACT sent\n"); |
267 | ||
268 | ret = drm_dp_check_act_status(&intel_dp->mst_mgr); | |
269 | ||
270 | ret = drm_dp_update_payload_part2(&intel_dp->mst_mgr); | |
37255d8d | 271 | if (pipe_config->has_audio) |
7f9e7754 | 272 | intel_audio_codec_enable(encoder, pipe_config, conn_state); |
0e32b39c DA |
273 | } |
274 | ||
275 | static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder, | |
276 | enum pipe *pipe) | |
277 | { | |
278 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
279 | *pipe = intel_mst->pipe; | |
0552f765 | 280 | if (intel_mst->connector) |
0e32b39c DA |
281 | return true; |
282 | return false; | |
283 | } | |
284 | ||
285 | static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder, | |
5cec258b | 286 | struct intel_crtc_state *pipe_config) |
0e32b39c DA |
287 | { |
288 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
289 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | |
53e9bf5e | 290 | |
35686a44 | 291 | intel_ddi_get_config(&intel_dig_port->base, pipe_config); |
0e32b39c DA |
292 | } |
293 | ||
294 | static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector) | |
295 | { | |
296 | struct intel_connector *intel_connector = to_intel_connector(connector); | |
297 | struct intel_dp *intel_dp = intel_connector->mst_port; | |
298 | struct edid *edid; | |
299 | int ret; | |
300 | ||
0552f765 DA |
301 | if (!intel_dp) { |
302 | return intel_connector_update_modes(connector, NULL); | |
303 | } | |
0e32b39c | 304 | |
0552f765 | 305 | edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port); |
0e32b39c DA |
306 | ret = intel_connector_update_modes(connector, edid); |
307 | kfree(edid); | |
308 | ||
309 | return ret; | |
310 | } | |
311 | ||
312 | static enum drm_connector_status | |
f7f3d48a | 313 | intel_dp_mst_detect(struct drm_connector *connector, bool force) |
0e32b39c DA |
314 | { |
315 | struct intel_connector *intel_connector = to_intel_connector(connector); | |
316 | struct intel_dp *intel_dp = intel_connector->mst_port; | |
317 | ||
0552f765 DA |
318 | if (!intel_dp) |
319 | return connector_status_disconnected; | |
c6a0aed4 | 320 | return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, intel_connector->port); |
0e32b39c DA |
321 | } |
322 | ||
0e32b39c DA |
323 | static void |
324 | intel_dp_mst_connector_destroy(struct drm_connector *connector) | |
325 | { | |
326 | struct intel_connector *intel_connector = to_intel_connector(connector); | |
327 | ||
328 | if (!IS_ERR_OR_NULL(intel_connector->edid)) | |
329 | kfree(intel_connector->edid); | |
330 | ||
331 | drm_connector_cleanup(connector); | |
332 | kfree(connector); | |
333 | } | |
334 | ||
335 | static const struct drm_connector_funcs intel_dp_mst_connector_funcs = { | |
0e32b39c DA |
336 | .detect = intel_dp_mst_detect, |
337 | .fill_modes = drm_helper_probe_single_connector_modes, | |
1ebaa0b9 | 338 | .late_register = intel_connector_register, |
c191eca1 | 339 | .early_unregister = intel_connector_unregister, |
0e32b39c | 340 | .destroy = intel_dp_mst_connector_destroy, |
c6f95f27 | 341 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
98969725 | 342 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
0e32b39c DA |
343 | }; |
344 | ||
345 | static int intel_dp_mst_get_modes(struct drm_connector *connector) | |
346 | { | |
347 | return intel_dp_mst_get_ddc_modes(connector); | |
348 | } | |
349 | ||
350 | static enum drm_mode_status | |
351 | intel_dp_mst_mode_valid(struct drm_connector *connector, | |
352 | struct drm_display_mode *mode) | |
353 | { | |
22a2c8e0 DP |
354 | struct intel_connector *intel_connector = to_intel_connector(connector); |
355 | struct intel_dp *intel_dp = intel_connector->mst_port; | |
832d5bfd | 356 | int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; |
22a2c8e0 DP |
357 | int bpp = 24; /* MST uses fixed bpp */ |
358 | int max_rate, mode_rate, max_lanes, max_link_clock; | |
359 | ||
06bfe5b0 RV |
360 | if (!intel_dp) |
361 | return MODE_ERROR; | |
362 | ||
22a2c8e0 | 363 | max_link_clock = intel_dp_max_link_rate(intel_dp); |
3d65a735 | 364 | max_lanes = intel_dp_max_lane_count(intel_dp); |
22a2c8e0 DP |
365 | |
366 | max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); | |
367 | mode_rate = intel_dp_link_required(mode->clock, bpp); | |
832d5bfd | 368 | |
0e32b39c DA |
369 | /* TODO - validate mode against available PBN for link */ |
370 | if (mode->clock < 10000) | |
371 | return MODE_CLOCK_LOW; | |
372 | ||
373 | if (mode->flags & DRM_MODE_FLAG_DBLCLK) | |
374 | return MODE_H_ILLEGAL; | |
375 | ||
22a2c8e0 | 376 | if (mode_rate > max_rate || mode->clock > max_dotclk) |
832d5bfd MK |
377 | return MODE_CLOCK_HIGH; |
378 | ||
0e32b39c DA |
379 | return MODE_OK; |
380 | } | |
381 | ||
459485ad DV |
382 | static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *connector, |
383 | struct drm_connector_state *state) | |
384 | { | |
385 | struct intel_connector *intel_connector = to_intel_connector(connector); | |
386 | struct intel_dp *intel_dp = intel_connector->mst_port; | |
387 | struct intel_crtc *crtc = to_intel_crtc(state->crtc); | |
388 | ||
0552f765 DA |
389 | if (!intel_dp) |
390 | return NULL; | |
459485ad DV |
391 | return &intel_dp->mst_encoders[crtc->pipe]->base.base; |
392 | } | |
393 | ||
0e32b39c DA |
394 | static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connector) |
395 | { | |
396 | struct intel_connector *intel_connector = to_intel_connector(connector); | |
397 | struct intel_dp *intel_dp = intel_connector->mst_port; | |
0552f765 DA |
398 | if (!intel_dp) |
399 | return NULL; | |
0e32b39c DA |
400 | return &intel_dp->mst_encoders[0]->base.base; |
401 | } | |
402 | ||
403 | static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = { | |
404 | .get_modes = intel_dp_mst_get_modes, | |
405 | .mode_valid = intel_dp_mst_mode_valid, | |
459485ad | 406 | .atomic_best_encoder = intel_mst_atomic_best_encoder, |
0e32b39c | 407 | .best_encoder = intel_mst_best_encoder, |
f424f55e | 408 | .atomic_check = intel_dp_mst_atomic_check, |
0e32b39c DA |
409 | }; |
410 | ||
411 | static void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder) | |
412 | { | |
413 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder); | |
414 | ||
415 | drm_encoder_cleanup(encoder); | |
416 | kfree(intel_mst); | |
417 | } | |
418 | ||
419 | static const struct drm_encoder_funcs intel_dp_mst_enc_funcs = { | |
420 | .destroy = intel_dp_mst_encoder_destroy, | |
421 | }; | |
422 | ||
423 | static bool intel_dp_mst_get_hw_state(struct intel_connector *connector) | |
424 | { | |
e85376cb | 425 | if (connector->encoder && connector->base.state->crtc) { |
0e32b39c DA |
426 | enum pipe pipe; |
427 | if (!connector->encoder->get_hw_state(connector->encoder, &pipe)) | |
428 | return false; | |
429 | return true; | |
430 | } | |
431 | return false; | |
432 | } | |
433 | ||
12e6cecd | 434 | 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) |
0e32b39c DA |
435 | { |
436 | struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr); | |
437 | struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | |
438 | struct drm_device *dev = intel_dig_port->base.base.dev; | |
4d58443d | 439 | struct drm_i915_private *dev_priv = to_i915(dev); |
0e32b39c DA |
440 | struct intel_connector *intel_connector; |
441 | struct drm_connector *connector; | |
4d58443d | 442 | enum pipe pipe; |
091a4f91 | 443 | int ret; |
0e32b39c | 444 | |
9bdbd0b9 | 445 | intel_connector = intel_connector_alloc(); |
0e32b39c DA |
446 | if (!intel_connector) |
447 | return NULL; | |
448 | ||
449 | connector = &intel_connector->base; | |
091a4f91 JA |
450 | ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, |
451 | DRM_MODE_CONNECTOR_DisplayPort); | |
452 | if (ret) { | |
453 | intel_connector_free(intel_connector); | |
454 | return NULL; | |
455 | } | |
456 | ||
0e32b39c DA |
457 | drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs); |
458 | ||
0e32b39c DA |
459 | intel_connector->get_hw_state = intel_dp_mst_get_hw_state; |
460 | intel_connector->mst_port = intel_dp; | |
461 | intel_connector->port = port; | |
462 | ||
4d58443d | 463 | for_each_pipe(dev_priv, pipe) { |
091a4f91 JA |
464 | struct drm_encoder *enc = |
465 | &intel_dp->mst_encoders[pipe]->base.base; | |
466 | ||
467 | ret = drm_mode_connector_attach_encoder(&intel_connector->base, | |
468 | enc); | |
469 | if (ret) | |
470 | goto err; | |
0e32b39c | 471 | } |
0e32b39c DA |
472 | |
473 | drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); | |
6f134d7b DA |
474 | drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); |
475 | ||
091a4f91 JA |
476 | ret = drm_mode_connector_set_path_property(connector, pathprop); |
477 | if (ret) | |
478 | goto err; | |
479 | ||
d9515c5e | 480 | return connector; |
091a4f91 JA |
481 | |
482 | err: | |
483 | drm_connector_cleanup(connector); | |
484 | return NULL; | |
d9515c5e DA |
485 | } |
486 | ||
487 | static void intel_dp_register_mst_connector(struct drm_connector *connector) | |
488 | { | |
666b7cdc | 489 | struct drm_i915_private *dev_priv = to_i915(connector->dev); |
7a418e34 | 490 | |
666b7cdc DV |
491 | if (dev_priv->fbdev) |
492 | drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, | |
493 | connector); | |
7a418e34 | 494 | |
666b7cdc | 495 | drm_connector_register(connector); |
0e32b39c DA |
496 | } |
497 | ||
498 | static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, | |
499 | struct drm_connector *connector) | |
500 | { | |
501 | struct intel_connector *intel_connector = to_intel_connector(connector); | |
666b7cdc | 502 | struct drm_i915_private *dev_priv = to_i915(connector->dev); |
20fae983 | 503 | |
dd59a9ba | 504 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); |
c191eca1 | 505 | drm_connector_unregister(connector); |
1f771755 | 506 | |
666b7cdc DV |
507 | if (dev_priv->fbdev) |
508 | drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, | |
509 | connector); | |
af2405af TR |
510 | /* prevent race with the check in ->detect */ |
511 | drm_modeset_lock(&connector->dev->mode_config.connection_mutex, NULL); | |
0552f765 | 512 | intel_connector->mst_port = NULL; |
af2405af | 513 | drm_modeset_unlock(&connector->dev->mode_config.connection_mutex); |
0e32b39c | 514 | |
666b7cdc | 515 | drm_connector_unreference(connector); |
0e32b39c DA |
516 | } |
517 | ||
518 | static void intel_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) | |
519 | { | |
520 | struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr); | |
521 | struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | |
522 | struct drm_device *dev = intel_dig_port->base.base.dev; | |
523 | ||
524 | drm_kms_helper_hotplug_event(dev); | |
525 | } | |
526 | ||
69a0f89c | 527 | static const struct drm_dp_mst_topology_cbs mst_cbs = { |
0e32b39c | 528 | .add_connector = intel_dp_add_mst_connector, |
d9515c5e | 529 | .register_connector = intel_dp_register_mst_connector, |
0e32b39c DA |
530 | .destroy_connector = intel_dp_destroy_mst_connector, |
531 | .hotplug = intel_dp_mst_hotplug, | |
532 | }; | |
533 | ||
534 | static struct intel_dp_mst_encoder * | |
535 | intel_dp_create_fake_mst_encoder(struct intel_digital_port *intel_dig_port, enum pipe pipe) | |
536 | { | |
537 | struct intel_dp_mst_encoder *intel_mst; | |
538 | struct intel_encoder *intel_encoder; | |
539 | struct drm_device *dev = intel_dig_port->base.base.dev; | |
540 | ||
541 | intel_mst = kzalloc(sizeof(*intel_mst), GFP_KERNEL); | |
542 | ||
543 | if (!intel_mst) | |
544 | return NULL; | |
545 | ||
546 | intel_mst->pipe = pipe; | |
547 | intel_encoder = &intel_mst->base; | |
548 | intel_mst->primary = intel_dig_port; | |
549 | ||
550 | drm_encoder_init(dev, &intel_encoder->base, &intel_dp_mst_enc_funcs, | |
580d8ed5 | 551 | DRM_MODE_ENCODER_DPMST, "DP-MST %c", pipe_name(pipe)); |
0e32b39c DA |
552 | |
553 | intel_encoder->type = INTEL_OUTPUT_DP_MST; | |
79f255a0 | 554 | intel_encoder->power_domain = intel_dig_port->base.power_domain; |
8f4f2797 | 555 | intel_encoder->port = intel_dig_port->base.port; |
0e32b39c DA |
556 | intel_encoder->crtc_mask = 0x7; |
557 | intel_encoder->cloneable = 0; | |
558 | ||
559 | intel_encoder->compute_config = intel_dp_mst_compute_config; | |
560 | intel_encoder->disable = intel_mst_disable_dp; | |
561 | intel_encoder->post_disable = intel_mst_post_disable_dp; | |
5161d058 | 562 | intel_encoder->pre_pll_enable = intel_mst_pre_pll_enable_dp; |
0e32b39c DA |
563 | intel_encoder->pre_enable = intel_mst_pre_enable_dp; |
564 | intel_encoder->enable = intel_mst_enable_dp; | |
565 | intel_encoder->get_hw_state = intel_dp_mst_enc_get_hw_state; | |
566 | intel_encoder->get_config = intel_dp_mst_enc_get_config; | |
567 | ||
568 | return intel_mst; | |
569 | ||
570 | } | |
571 | ||
572 | static bool | |
573 | intel_dp_create_fake_mst_encoders(struct intel_digital_port *intel_dig_port) | |
574 | { | |
0e32b39c | 575 | struct intel_dp *intel_dp = &intel_dig_port->dp; |
4d58443d MK |
576 | struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev); |
577 | enum pipe pipe; | |
0e32b39c | 578 | |
4d58443d MK |
579 | for_each_pipe(dev_priv, pipe) |
580 | intel_dp->mst_encoders[pipe] = intel_dp_create_fake_mst_encoder(intel_dig_port, pipe); | |
0e32b39c DA |
581 | return true; |
582 | } | |
583 | ||
584 | int | |
585 | intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_base_id) | |
586 | { | |
587 | struct intel_dp *intel_dp = &intel_dig_port->dp; | |
588 | struct drm_device *dev = intel_dig_port->base.base.dev; | |
589 | int ret; | |
590 | ||
591 | intel_dp->can_mst = true; | |
592 | intel_dp->mst_mgr.cbs = &mst_cbs; | |
593 | ||
594 | /* create encoders */ | |
595 | intel_dp_create_fake_mst_encoders(intel_dig_port); | |
7b0a89a6 DP |
596 | ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev, |
597 | &intel_dp->aux, 16, 3, conn_base_id); | |
0e32b39c DA |
598 | if (ret) { |
599 | intel_dp->can_mst = false; | |
600 | return ret; | |
601 | } | |
602 | return 0; | |
603 | } | |
604 | ||
605 | void | |
606 | intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port) | |
607 | { | |
608 | struct intel_dp *intel_dp = &intel_dig_port->dp; | |
609 | ||
610 | if (!intel_dp->can_mst) | |
611 | return; | |
612 | ||
613 | drm_dp_mst_topology_mgr_destroy(&intel_dp->mst_mgr); | |
614 | /* encoders will get killed by normal cleanup */ | |
615 | } |