]>
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; | |
c02ba4ef LP |
41 | struct drm_connector *connector = conn_state->connector; |
42 | void *port = to_intel_connector(connector)->port; | |
f424f55e | 43 | struct drm_atomic_state *state = pipe_config->base.state; |
1189e4f4 | 44 | int bpp; |
c02ba4ef | 45 | int lane_count, slots = 0; |
7c5f93b0 | 46 | const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; |
0e32b39c | 47 | int mst_pbn; |
53ca2edc LS |
48 | bool constant_n = drm_dp_has_quirk(&intel_dp->desc, |
49 | DP_DPCD_QUIRK_CONSTANT_N); | |
0e32b39c | 50 | |
e4dd27aa VS |
51 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
52 | return false; | |
53 | ||
0e32b39c | 54 | pipe_config->has_pch_encoder = false; |
0e32b39c | 55 | bpp = 24; |
611032bf MN |
56 | if (intel_dp->compliance.test_data.bpc) { |
57 | bpp = intel_dp->compliance.test_data.bpc * 3; | |
58 | DRM_DEBUG_KMS("Setting pipe bpp to %d\n", | |
59 | bpp); | |
60 | } | |
0e32b39c DA |
61 | /* |
62 | * for MST we always configure max link bw - the spec doesn't | |
63 | * seem to suggest we should do otherwise. | |
64 | */ | |
3d65a735 | 65 | lane_count = intel_dp_max_lane_count(intel_dp); |
ed4e9c1d | 66 | |
90a6b7b0 | 67 | pipe_config->lane_count = lane_count; |
0e32b39c | 68 | |
611032bf | 69 | pipe_config->pipe_bpp = bpp; |
0e32b39c | 70 | |
f424f55e | 71 | pipe_config->port_clock = intel_dp_max_link_rate(intel_dp); |
e75f4771 | 72 | |
c02ba4ef | 73 | if (drm_dp_mst_port_has_audio(&intel_dp->mst_mgr, port)) |
7f9e7754 | 74 | pipe_config->has_audio = true; |
0e32b39c | 75 | |
f424f55e | 76 | mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp); |
0e32b39c | 77 | pipe_config->pbn = mst_pbn; |
f424f55e | 78 | |
c02ba4ef | 79 | /* Zombie connectors can't have VCPI slots */ |
de9f8eea | 80 | if (!drm_connector_is_unregistered(connector)) { |
c02ba4ef LP |
81 | slots = drm_dp_atomic_find_vcpi_slots(state, |
82 | &intel_dp->mst_mgr, | |
83 | port, | |
84 | mst_pbn); | |
85 | if (slots < 0) { | |
86 | DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", | |
87 | slots); | |
88 | return false; | |
89 | } | |
f424f55e | 90 | } |
0e32b39c DA |
91 | |
92 | intel_link_compute_m_n(bpp, lane_count, | |
93 | adjusted_mode->crtc_clock, | |
94 | pipe_config->port_clock, | |
b31e85ed | 95 | &pipe_config->dp_m_n, |
53ca2edc | 96 | constant_n); |
0e32b39c DA |
97 | |
98 | pipe_config->dp_m_n.tu = slots; | |
6fa2d197 | 99 | |
5161d058 VS |
100 | if (IS_GEN9_LP(dev_priv)) |
101 | pipe_config->lane_lat_optim_mask = | |
102 | bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count); | |
103 | ||
53e9bf5e VS |
104 | intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); |
105 | ||
0e32b39c | 106 | return true; |
f424f55e | 107 | } |
0e32b39c | 108 | |
f424f55e PD |
109 | static int intel_dp_mst_atomic_check(struct drm_connector *connector, |
110 | struct drm_connector_state *new_conn_state) | |
111 | { | |
112 | struct drm_atomic_state *state = new_conn_state->state; | |
113 | struct drm_connector_state *old_conn_state; | |
114 | struct drm_crtc *old_crtc; | |
115 | struct drm_crtc_state *crtc_state; | |
116 | int slots, ret = 0; | |
117 | ||
118 | old_conn_state = drm_atomic_get_old_connector_state(state, connector); | |
119 | old_crtc = old_conn_state->crtc; | |
120 | if (!old_crtc) | |
121 | return ret; | |
122 | ||
123 | crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc); | |
124 | slots = to_intel_crtc_state(crtc_state)->dp_m_n.tu; | |
125 | if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) { | |
126 | struct drm_dp_mst_topology_mgr *mgr; | |
127 | struct drm_encoder *old_encoder; | |
128 | ||
129 | old_encoder = old_conn_state->best_encoder; | |
130 | mgr = &enc_to_mst(old_encoder)->primary->dp.mst_mgr; | |
131 | ||
132 | ret = drm_dp_atomic_release_vcpi_slots(state, mgr, slots); | |
133 | if (ret) | |
134 | DRM_DEBUG_KMS("failed releasing %d vcpi slots:%d\n", slots, ret); | |
135 | else | |
136 | to_intel_crtc_state(crtc_state)->dp_m_n.tu = 0; | |
137 | } | |
138 | return ret; | |
0e32b39c DA |
139 | } |
140 | ||
fd6bbda9 | 141 | static void intel_mst_disable_dp(struct intel_encoder *encoder, |
5f88a9c6 VS |
142 | const struct intel_crtc_state *old_crtc_state, |
143 | const struct drm_connector_state *old_conn_state) | |
0e32b39c DA |
144 | { |
145 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
146 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | |
147 | struct intel_dp *intel_dp = &intel_dig_port->dp; | |
1e7bfa0b ML |
148 | struct intel_connector *connector = |
149 | to_intel_connector(old_conn_state->connector); | |
0e32b39c DA |
150 | int ret; |
151 | ||
9b1c5818 | 152 | DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links); |
0e32b39c | 153 | |
1e7bfa0b | 154 | drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port); |
0e32b39c DA |
155 | |
156 | ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr); | |
157 | if (ret) { | |
158 | DRM_ERROR("failed to update payload %d\n", ret); | |
159 | } | |
37255d8d | 160 | if (old_crtc_state->has_audio) |
8ec47de2 VS |
161 | intel_audio_codec_disable(encoder, |
162 | old_crtc_state, old_conn_state); | |
0e32b39c DA |
163 | } |
164 | ||
fd6bbda9 | 165 | static void intel_mst_post_disable_dp(struct intel_encoder *encoder, |
5f88a9c6 VS |
166 | const struct intel_crtc_state *old_crtc_state, |
167 | const struct drm_connector_state *old_conn_state) | |
0e32b39c DA |
168 | { |
169 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
170 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | |
171 | struct intel_dp *intel_dp = &intel_dig_port->dp; | |
1e7bfa0b ML |
172 | struct intel_connector *connector = |
173 | to_intel_connector(old_conn_state->connector); | |
0e32b39c | 174 | |
2b5cf4ef ID |
175 | intel_ddi_disable_pipe_clock(old_crtc_state); |
176 | ||
0e32b39c DA |
177 | /* this can fail */ |
178 | drm_dp_check_act_status(&intel_dp->mst_mgr); | |
179 | /* and this can also fail */ | |
180 | drm_dp_update_payload_part2(&intel_dp->mst_mgr); | |
181 | ||
1e7bfa0b | 182 | drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, connector->port); |
0e32b39c | 183 | |
5ea2355a DP |
184 | /* |
185 | * Power down mst path before disabling the port, otherwise we end | |
186 | * up getting interrupts from the sink upon detecting link loss. | |
187 | */ | |
188 | drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, | |
189 | false); | |
190 | ||
19e0b4ca | 191 | intel_dp->active_mst_links--; |
0552f765 DA |
192 | |
193 | intel_mst->connector = NULL; | |
be1c63c8 LP |
194 | if (intel_dp->active_mst_links == 0) { |
195 | intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); | |
fd6bbda9 | 196 | intel_dig_port->base.post_disable(&intel_dig_port->base, |
1939ba51 | 197 | old_crtc_state, NULL); |
be1c63c8 | 198 | } |
1939ba51 | 199 | |
9b1c5818 | 200 | DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links); |
0e32b39c DA |
201 | } |
202 | ||
5161d058 VS |
203 | static void intel_mst_pre_pll_enable_dp(struct intel_encoder *encoder, |
204 | const struct intel_crtc_state *pipe_config, | |
205 | const struct drm_connector_state *conn_state) | |
206 | { | |
207 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
208 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | |
209 | struct intel_dp *intel_dp = &intel_dig_port->dp; | |
210 | ||
211 | if (intel_dp->active_mst_links == 0 && | |
212 | intel_dig_port->base.pre_pll_enable) | |
213 | intel_dig_port->base.pre_pll_enable(&intel_dig_port->base, | |
214 | pipe_config, NULL); | |
215 | } | |
216 | ||
fd6bbda9 | 217 | static void intel_mst_pre_enable_dp(struct intel_encoder *encoder, |
5f88a9c6 VS |
218 | const struct intel_crtc_state *pipe_config, |
219 | const struct drm_connector_state *conn_state) | |
0e32b39c DA |
220 | { |
221 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
222 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | |
223 | struct intel_dp *intel_dp = &intel_dig_port->dp; | |
1e7bfa0b | 224 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
8f4f2797 | 225 | enum port port = intel_dig_port->base.port; |
1e7bfa0b ML |
226 | struct intel_connector *connector = |
227 | to_intel_connector(conn_state->connector); | |
0e32b39c DA |
228 | int ret; |
229 | uint32_t temp; | |
0e32b39c | 230 | |
e85376cb ML |
231 | /* MST encoders are bound to a crtc, not to a connector, |
232 | * force the mapping here for get_hw_state. | |
233 | */ | |
1e7bfa0b ML |
234 | connector->encoder = encoder; |
235 | intel_mst->connector = connector; | |
e85376cb | 236 | |
9b1c5818 | 237 | DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links); |
0552f765 | 238 | |
be1c63c8 LP |
239 | if (intel_dp->active_mst_links == 0) |
240 | intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); | |
241 | ||
5ea2355a | 242 | drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, true); |
be1c63c8 | 243 | |
e081c846 ACO |
244 | if (intel_dp->active_mst_links == 0) |
245 | intel_dig_port->base.pre_enable(&intel_dig_port->base, | |
246 | pipe_config, NULL); | |
0e32b39c DA |
247 | |
248 | ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr, | |
1e7bfa0b | 249 | connector->port, |
1e797f55 PD |
250 | pipe_config->pbn, |
251 | pipe_config->dp_m_n.tu); | |
65172699 | 252 | if (!ret) |
0e32b39c | 253 | DRM_ERROR("failed to allocate vcpi\n"); |
0e32b39c | 254 | |
19e0b4ca | 255 | intel_dp->active_mst_links++; |
0e32b39c DA |
256 | temp = I915_READ(DP_TP_STATUS(port)); |
257 | I915_WRITE(DP_TP_STATUS(port), temp); | |
258 | ||
259 | ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr); | |
2b5cf4ef ID |
260 | |
261 | intel_ddi_enable_pipe_clock(pipe_config); | |
0e32b39c DA |
262 | } |
263 | ||
fd6bbda9 | 264 | static void intel_mst_enable_dp(struct intel_encoder *encoder, |
5f88a9c6 VS |
265 | const struct intel_crtc_state *pipe_config, |
266 | const struct drm_connector_state *conn_state) | |
0e32b39c DA |
267 | { |
268 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
269 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | |
270 | struct intel_dp *intel_dp = &intel_dig_port->dp; | |
1e7bfa0b | 271 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
8f4f2797 | 272 | enum port port = intel_dig_port->base.port; |
0e32b39c | 273 | |
9b1c5818 | 274 | DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links); |
0e32b39c | 275 | |
3016a31f CW |
276 | if (intel_wait_for_register(dev_priv, |
277 | DP_TP_STATUS(port), | |
278 | DP_TP_STATUS_ACT_SENT, | |
279 | DP_TP_STATUS_ACT_SENT, | |
280 | 1)) | |
0e32b39c DA |
281 | DRM_ERROR("Timed out waiting for ACT sent\n"); |
282 | ||
6bd31b37 | 283 | drm_dp_check_act_status(&intel_dp->mst_mgr); |
0e32b39c | 284 | |
6bd31b37 | 285 | drm_dp_update_payload_part2(&intel_dp->mst_mgr); |
37255d8d | 286 | if (pipe_config->has_audio) |
7f9e7754 | 287 | intel_audio_codec_enable(encoder, pipe_config, conn_state); |
0e32b39c DA |
288 | } |
289 | ||
290 | static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder, | |
291 | enum pipe *pipe) | |
292 | { | |
293 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
294 | *pipe = intel_mst->pipe; | |
0552f765 | 295 | if (intel_mst->connector) |
0e32b39c DA |
296 | return true; |
297 | return false; | |
298 | } | |
299 | ||
300 | static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder, | |
5cec258b | 301 | struct intel_crtc_state *pipe_config) |
0e32b39c DA |
302 | { |
303 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | |
304 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | |
53e9bf5e | 305 | |
35686a44 | 306 | intel_ddi_get_config(&intel_dig_port->base, pipe_config); |
0e32b39c DA |
307 | } |
308 | ||
309 | static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector) | |
310 | { | |
311 | struct intel_connector *intel_connector = to_intel_connector(connector); | |
312 | struct intel_dp *intel_dp = intel_connector->mst_port; | |
313 | struct edid *edid; | |
314 | int ret; | |
315 | ||
de9f8eea | 316 | if (drm_connector_is_unregistered(connector)) |
0552f765 | 317 | return intel_connector_update_modes(connector, NULL); |
0e32b39c | 318 | |
0552f765 | 319 | edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port); |
0e32b39c DA |
320 | ret = intel_connector_update_modes(connector, edid); |
321 | kfree(edid); | |
322 | ||
323 | return ret; | |
324 | } | |
325 | ||
326 | static enum drm_connector_status | |
f7f3d48a | 327 | intel_dp_mst_detect(struct drm_connector *connector, bool force) |
0e32b39c DA |
328 | { |
329 | struct intel_connector *intel_connector = to_intel_connector(connector); | |
330 | struct intel_dp *intel_dp = intel_connector->mst_port; | |
331 | ||
de9f8eea | 332 | if (drm_connector_is_unregistered(connector)) |
0552f765 | 333 | return connector_status_disconnected; |
80c18869 LP |
334 | return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, |
335 | intel_connector->port); | |
0e32b39c DA |
336 | } |
337 | ||
0e32b39c DA |
338 | static void |
339 | intel_dp_mst_connector_destroy(struct drm_connector *connector) | |
340 | { | |
341 | struct intel_connector *intel_connector = to_intel_connector(connector); | |
342 | ||
343 | if (!IS_ERR_OR_NULL(intel_connector->edid)) | |
344 | kfree(intel_connector->edid); | |
345 | ||
346 | drm_connector_cleanup(connector); | |
347 | kfree(connector); | |
348 | } | |
349 | ||
350 | static const struct drm_connector_funcs intel_dp_mst_connector_funcs = { | |
0e32b39c DA |
351 | .detect = intel_dp_mst_detect, |
352 | .fill_modes = drm_helper_probe_single_connector_modes, | |
1ebaa0b9 | 353 | .late_register = intel_connector_register, |
c191eca1 | 354 | .early_unregister = intel_connector_unregister, |
0e32b39c | 355 | .destroy = intel_dp_mst_connector_destroy, |
c6f95f27 | 356 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
98969725 | 357 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
0e32b39c DA |
358 | }; |
359 | ||
360 | static int intel_dp_mst_get_modes(struct drm_connector *connector) | |
361 | { | |
362 | return intel_dp_mst_get_ddc_modes(connector); | |
363 | } | |
364 | ||
365 | static enum drm_mode_status | |
366 | intel_dp_mst_mode_valid(struct drm_connector *connector, | |
367 | struct drm_display_mode *mode) | |
368 | { | |
22a2c8e0 DP |
369 | struct intel_connector *intel_connector = to_intel_connector(connector); |
370 | struct intel_dp *intel_dp = intel_connector->mst_port; | |
832d5bfd | 371 | int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; |
22a2c8e0 DP |
372 | int bpp = 24; /* MST uses fixed bpp */ |
373 | int max_rate, mode_rate, max_lanes, max_link_clock; | |
374 | ||
de9f8eea | 375 | if (drm_connector_is_unregistered(connector)) |
06bfe5b0 RV |
376 | return MODE_ERROR; |
377 | ||
e4dd27aa VS |
378 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) |
379 | return MODE_NO_DBLESCAN; | |
380 | ||
22a2c8e0 | 381 | max_link_clock = intel_dp_max_link_rate(intel_dp); |
3d65a735 | 382 | max_lanes = intel_dp_max_lane_count(intel_dp); |
22a2c8e0 DP |
383 | |
384 | max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); | |
385 | mode_rate = intel_dp_link_required(mode->clock, bpp); | |
832d5bfd | 386 | |
0e32b39c DA |
387 | /* TODO - validate mode against available PBN for link */ |
388 | if (mode->clock < 10000) | |
389 | return MODE_CLOCK_LOW; | |
390 | ||
391 | if (mode->flags & DRM_MODE_FLAG_DBLCLK) | |
392 | return MODE_H_ILLEGAL; | |
393 | ||
22a2c8e0 | 394 | if (mode_rate > max_rate || mode->clock > max_dotclk) |
832d5bfd MK |
395 | return MODE_CLOCK_HIGH; |
396 | ||
0e32b39c DA |
397 | return MODE_OK; |
398 | } | |
399 | ||
459485ad SV |
400 | static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *connector, |
401 | struct drm_connector_state *state) | |
402 | { | |
403 | struct intel_connector *intel_connector = to_intel_connector(connector); | |
404 | struct intel_dp *intel_dp = intel_connector->mst_port; | |
405 | struct intel_crtc *crtc = to_intel_crtc(state->crtc); | |
406 | ||
407 | return &intel_dp->mst_encoders[crtc->pipe]->base.base; | |
408 | } | |
409 | ||
0e32b39c DA |
410 | static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = { |
411 | .get_modes = intel_dp_mst_get_modes, | |
412 | .mode_valid = intel_dp_mst_mode_valid, | |
459485ad | 413 | .atomic_best_encoder = intel_mst_atomic_best_encoder, |
f424f55e | 414 | .atomic_check = intel_dp_mst_atomic_check, |
0e32b39c DA |
415 | }; |
416 | ||
417 | static void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder) | |
418 | { | |
419 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder); | |
420 | ||
421 | drm_encoder_cleanup(encoder); | |
422 | kfree(intel_mst); | |
423 | } | |
424 | ||
425 | static const struct drm_encoder_funcs intel_dp_mst_enc_funcs = { | |
426 | .destroy = intel_dp_mst_encoder_destroy, | |
427 | }; | |
428 | ||
429 | static bool intel_dp_mst_get_hw_state(struct intel_connector *connector) | |
430 | { | |
e85376cb | 431 | if (connector->encoder && connector->base.state->crtc) { |
0e32b39c DA |
432 | enum pipe pipe; |
433 | if (!connector->encoder->get_hw_state(connector->encoder, &pipe)) | |
434 | return false; | |
435 | return true; | |
436 | } | |
437 | return false; | |
438 | } | |
439 | ||
12e6cecd | 440 | 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 |
441 | { |
442 | struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr); | |
443 | struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | |
444 | struct drm_device *dev = intel_dig_port->base.base.dev; | |
4d58443d | 445 | struct drm_i915_private *dev_priv = to_i915(dev); |
0e32b39c DA |
446 | struct intel_connector *intel_connector; |
447 | struct drm_connector *connector; | |
4d58443d | 448 | enum pipe pipe; |
091a4f91 | 449 | int ret; |
0e32b39c | 450 | |
9bdbd0b9 | 451 | intel_connector = intel_connector_alloc(); |
0e32b39c DA |
452 | if (!intel_connector) |
453 | return NULL; | |
454 | ||
7c451230 LP |
455 | intel_connector->get_hw_state = intel_dp_mst_get_hw_state; |
456 | intel_connector->mst_port = intel_dp; | |
457 | intel_connector->port = port; | |
458 | ||
0e32b39c | 459 | connector = &intel_connector->base; |
091a4f91 JA |
460 | ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, |
461 | DRM_MODE_CONNECTOR_DisplayPort); | |
462 | if (ret) { | |
463 | intel_connector_free(intel_connector); | |
464 | return NULL; | |
465 | } | |
466 | ||
0e32b39c DA |
467 | drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs); |
468 | ||
4d58443d | 469 | for_each_pipe(dev_priv, pipe) { |
091a4f91 JA |
470 | struct drm_encoder *enc = |
471 | &intel_dp->mst_encoders[pipe]->base.base; | |
472 | ||
cde4c44d | 473 | ret = drm_connector_attach_encoder(&intel_connector->base, enc); |
091a4f91 JA |
474 | if (ret) |
475 | goto err; | |
0e32b39c | 476 | } |
0e32b39c DA |
477 | |
478 | drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); | |
6f134d7b DA |
479 | drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); |
480 | ||
97e14fbe | 481 | ret = drm_connector_set_path_property(connector, pathprop); |
091a4f91 JA |
482 | if (ret) |
483 | goto err; | |
484 | ||
d9515c5e | 485 | return connector; |
091a4f91 JA |
486 | |
487 | err: | |
488 | drm_connector_cleanup(connector); | |
489 | return NULL; | |
d9515c5e DA |
490 | } |
491 | ||
492 | static void intel_dp_register_mst_connector(struct drm_connector *connector) | |
493 | { | |
666b7cdc | 494 | struct drm_i915_private *dev_priv = to_i915(connector->dev); |
7a418e34 | 495 | |
666b7cdc SV |
496 | if (dev_priv->fbdev) |
497 | drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, | |
498 | connector); | |
7a418e34 | 499 | |
666b7cdc | 500 | drm_connector_register(connector); |
0e32b39c DA |
501 | } |
502 | ||
503 | static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, | |
504 | struct drm_connector *connector) | |
505 | { | |
666b7cdc | 506 | struct drm_i915_private *dev_priv = to_i915(connector->dev); |
20fae983 | 507 | |
dd59a9ba | 508 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); |
c191eca1 | 509 | drm_connector_unregister(connector); |
1f771755 | 510 | |
666b7cdc SV |
511 | if (dev_priv->fbdev) |
512 | drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, | |
513 | connector); | |
0e32b39c | 514 | |
ef196b5c | 515 | drm_connector_put(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 | } |