]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drm/amd/display: Fix MST physical ports always disconnected
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / amd / display / amdgpu_dm / amdgpu_dm_mst_types.c
1 /*
2 * Copyright 2012-15 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26 #include <linux/version.h>
27 #include <drm/drm_atomic_helper.h>
28 #include "dm_services.h"
29 #include "amdgpu.h"
30 #include "amdgpu_dm_types.h"
31 #include "amdgpu_dm_mst_types.h"
32
33 #include "dc.h"
34 #include "dm_helpers.h"
35
36 /* #define TRACE_DPCD */
37
38 #ifdef TRACE_DPCD
39 #define SIDE_BAND_MSG(address) (address >= DP_SIDEBAND_MSG_DOWN_REQ_BASE && address < DP_SINK_COUNT_ESI)
40
41 static inline char *side_band_msg_type_to_str(uint32_t address)
42 {
43 static char str[10] = {0};
44
45 if (address < DP_SIDEBAND_MSG_UP_REP_BASE)
46 strcpy(str, "DOWN_REQ");
47 else if (address < DP_SIDEBAND_MSG_DOWN_REP_BASE)
48 strcpy(str, "UP_REP");
49 else if (address < DP_SIDEBAND_MSG_UP_REQ_BASE)
50 strcpy(str, "DOWN_REP");
51 else
52 strcpy(str, "UP_REQ");
53
54 return str;
55 }
56
57 void log_dpcd(uint8_t type,
58 uint32_t address,
59 uint8_t *data,
60 uint32_t size,
61 bool res)
62 {
63 DRM_DEBUG_KMS("Op: %s, addr: %04x, SideBand Msg: %s, Op res: %s\n",
64 (type == DP_AUX_NATIVE_READ) ||
65 (type == DP_AUX_I2C_READ) ?
66 "Read" : "Write",
67 address,
68 SIDE_BAND_MSG(address) ?
69 side_band_msg_type_to_str(address) : "Nop",
70 res ? "OK" : "Fail");
71
72 if (res) {
73 print_hex_dump(KERN_INFO, "Body: ", DUMP_PREFIX_NONE, 16, 1, data, size, false);
74 }
75 }
76 #endif
77
78 static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
79 {
80 struct pci_dev *pdev = to_pci_dev(aux->dev);
81 struct drm_device *drm_dev = pci_get_drvdata(pdev);
82 struct amdgpu_device *adev = drm_dev->dev_private;
83 struct dc *dc = adev->dm.dc;
84 bool res;
85
86 switch (msg->request) {
87 case DP_AUX_NATIVE_READ:
88 res = dc_read_dpcd(
89 dc,
90 TO_DM_AUX(aux)->link_index,
91 msg->address,
92 msg->buffer,
93 msg->size);
94 break;
95 case DP_AUX_NATIVE_WRITE:
96 res = dc_write_dpcd(
97 dc,
98 TO_DM_AUX(aux)->link_index,
99 msg->address,
100 msg->buffer,
101 msg->size);
102 break;
103 default:
104 return 0;
105 }
106
107 #ifdef TRACE_DPCD
108 log_dpcd(msg->request,
109 msg->address,
110 msg->buffer,
111 msg->size,
112 res);
113 #endif
114
115 return msg->size;
116 }
117
118 static enum drm_connector_status
119 dm_dp_mst_detect(struct drm_connector *connector, bool force)
120 {
121 struct amdgpu_connector *aconnector = to_amdgpu_connector(connector);
122 struct amdgpu_connector *master = aconnector->mst_port;
123
124 enum drm_connector_status status =
125 drm_dp_mst_detect_port(
126 connector,
127 &master->mst_mgr,
128 aconnector->port);
129
130 return status;
131 }
132
133 static void
134 dm_dp_mst_connector_destroy(struct drm_connector *connector)
135 {
136 struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
137 struct amdgpu_encoder *amdgpu_encoder = amdgpu_connector->mst_encoder;
138
139 drm_encoder_cleanup(&amdgpu_encoder->base);
140 kfree(amdgpu_encoder);
141 drm_connector_cleanup(connector);
142 kfree(amdgpu_connector);
143 }
144
145 static const struct drm_connector_funcs dm_dp_mst_connector_funcs = {
146 .detect = dm_dp_mst_detect,
147 .fill_modes = drm_helper_probe_single_connector_modes,
148 .destroy = dm_dp_mst_connector_destroy,
149 .reset = amdgpu_dm_connector_funcs_reset,
150 .atomic_duplicate_state = amdgpu_dm_connector_atomic_duplicate_state,
151 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
152 .atomic_set_property = amdgpu_dm_connector_atomic_set_property
153 };
154
155 static int dm_dp_mst_get_modes(struct drm_connector *connector)
156 {
157 struct amdgpu_connector *aconnector = to_amdgpu_connector(connector);
158 int ret = 0;
159
160 ret = drm_add_edid_modes(&aconnector->base, aconnector->edid);
161
162 drm_edid_to_eld(&aconnector->base, aconnector->edid);
163
164 return ret;
165 }
166
167 static struct drm_encoder *dm_mst_best_encoder(struct drm_connector *connector)
168 {
169 struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
170
171 return &amdgpu_connector->mst_encoder->base;
172 }
173
174 static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs = {
175 .get_modes = dm_dp_mst_get_modes,
176 .mode_valid = amdgpu_dm_connector_mode_valid,
177 .best_encoder = dm_mst_best_encoder,
178 };
179
180 static struct amdgpu_encoder *
181 dm_dp_create_fake_mst_encoder(struct amdgpu_connector *connector)
182 {
183 struct drm_device *dev = connector->base.dev;
184 struct amdgpu_device *adev = dev->dev_private;
185 struct amdgpu_encoder *amdgpu_encoder;
186 struct drm_encoder *encoder;
187 const struct drm_connector_helper_funcs *connector_funcs =
188 connector->base.helper_private;
189 struct drm_encoder *enc_master =
190 connector_funcs->best_encoder(&connector->base);
191
192 DRM_DEBUG_KMS("enc master is %p\n", enc_master);
193 amdgpu_encoder = kzalloc(sizeof(*amdgpu_encoder), GFP_KERNEL);
194 if (!amdgpu_encoder)
195 return NULL;
196
197 encoder = &amdgpu_encoder->base;
198 encoder->possible_crtcs = amdgpu_dm_get_encoder_crtc_mask(adev);
199
200 drm_encoder_init(
201 dev,
202 &amdgpu_encoder->base,
203 NULL,
204 DRM_MODE_ENCODER_DPMST,
205 NULL);
206
207 drm_encoder_helper_add(encoder, &amdgpu_dm_encoder_helper_funcs);
208
209 return amdgpu_encoder;
210 }
211
212 static struct drm_connector *dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
213 struct drm_dp_mst_port *port,
214 const char *pathprop)
215 {
216 struct amdgpu_connector *master = container_of(mgr, struct amdgpu_connector, mst_mgr);
217 struct drm_device *dev = master->base.dev;
218 struct amdgpu_device *adev = dev->dev_private;
219 struct amdgpu_connector *aconnector;
220 struct drm_connector *connector;
221
222 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
223 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
224 aconnector = to_amdgpu_connector(connector);
225 if (aconnector->mst_port == master
226 && !aconnector->port) {
227 DRM_INFO("DM_MST: reusing connector: %p [id: %d] [master: %p]\n",
228 aconnector, connector->base.id, aconnector->mst_port);
229
230 aconnector->port = port;
231 drm_mode_connector_set_path_property(connector, pathprop);
232
233 drm_modeset_unlock(&dev->mode_config.connection_mutex);
234 return &aconnector->base;
235 }
236 }
237 drm_modeset_unlock(&dev->mode_config.connection_mutex);
238
239 aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL);
240 if (!aconnector)
241 return NULL;
242
243 connector = &aconnector->base;
244 aconnector->port = port;
245 aconnector->mst_port = master;
246
247 if (drm_connector_init(
248 dev,
249 connector,
250 &dm_dp_mst_connector_funcs,
251 DRM_MODE_CONNECTOR_DisplayPort)) {
252 kfree(aconnector);
253 return NULL;
254 }
255 drm_connector_helper_add(connector, &dm_dp_mst_connector_helper_funcs);
256
257 amdgpu_dm_connector_init_helper(
258 &adev->dm,
259 aconnector,
260 DRM_MODE_CONNECTOR_DisplayPort,
261 master->dc_link,
262 master->connector_id);
263
264 aconnector->mst_encoder = dm_dp_create_fake_mst_encoder(master);
265
266 /*
267 * TODO: understand why this one is needed
268 */
269 drm_object_attach_property(
270 &connector->base,
271 dev->mode_config.path_property,
272 0);
273 drm_object_attach_property(
274 &connector->base,
275 dev->mode_config.tile_property,
276 0);
277
278 drm_mode_connector_set_path_property(connector, pathprop);
279
280 /*
281 * Initialize connector state before adding the connectror to drm and
282 * framebuffer lists
283 */
284 amdgpu_dm_connector_funcs_reset(connector);
285
286 DRM_INFO("DM_MST: added connector: %p [id: %d] [master: %p]\n",
287 aconnector, connector->base.id, aconnector->mst_port);
288
289 DRM_DEBUG_KMS(":%d\n", connector->base.id);
290
291 return connector;
292 }
293
294 static void dm_dp_destroy_mst_connector(
295 struct drm_dp_mst_topology_mgr *mgr,
296 struct drm_connector *connector)
297 {
298 struct amdgpu_connector *aconnector = to_amdgpu_connector(connector);
299
300 DRM_INFO("DM_MST: Disabling connector: %p [id: %d] [master: %p]\n",
301 aconnector, connector->base.id, aconnector->mst_port);
302
303 aconnector->port = NULL;
304 if (aconnector->dc_sink) {
305 amdgpu_dm_remove_sink_from_freesync_module(connector);
306 dc_link_remove_remote_sink(aconnector->dc_link, aconnector->dc_sink);
307 dc_sink_release(aconnector->dc_sink);
308 aconnector->dc_sink = NULL;
309 }
310 if (aconnector->edid) {
311 kfree(aconnector->edid);
312 aconnector->edid = NULL;
313 }
314
315 drm_mode_connector_update_edid_property(
316 &aconnector->base,
317 NULL);
318 }
319
320 static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
321 {
322 struct amdgpu_connector *master = container_of(mgr, struct amdgpu_connector, mst_mgr);
323 struct drm_device *dev = master->base.dev;
324 struct amdgpu_device *adev = dev->dev_private;
325 struct drm_connector *connector;
326 struct amdgpu_connector *aconnector;
327 struct edid *edid;
328
329 drm_modeset_lock_all(dev);
330 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
331 aconnector = to_amdgpu_connector(connector);
332 if (aconnector->port &&
333 aconnector->port->pdt != DP_PEER_DEVICE_NONE &&
334 aconnector->port->pdt != DP_PEER_DEVICE_MST_BRANCHING &&
335 !aconnector->dc_sink) {
336 /*
337 * This is plug in case, where port has been created but
338 * sink hasn't been created yet
339 */
340 if (!aconnector->edid) {
341 struct dc_sink_init_data init_params = {
342 .link = aconnector->dc_link,
343 .sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST};
344 edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port);
345
346 if (!edid) {
347 drm_mode_connector_update_edid_property(
348 &aconnector->base,
349 NULL);
350 continue;
351 }
352
353 aconnector->edid = edid;
354
355 aconnector->dc_sink = dc_link_add_remote_sink(
356 aconnector->dc_link,
357 (uint8_t *)edid,
358 (edid->extensions + 1) * EDID_LENGTH,
359 &init_params);
360 if (aconnector->dc_sink)
361 amdgpu_dm_add_sink_to_freesync_module(
362 connector,
363 edid);
364
365 dm_restore_drm_connector_state(connector->dev, connector);
366 } else
367 edid = aconnector->edid;
368
369 DRM_DEBUG_KMS("edid retrieved %p\n", edid);
370
371 drm_mode_connector_update_edid_property(
372 &aconnector->base,
373 aconnector->edid);
374 }
375 }
376 drm_modeset_unlock_all(dev);
377
378 schedule_work(&adev->dm.mst_hotplug_work);
379 }
380
381 static void dm_dp_mst_register_connector(struct drm_connector *connector)
382 {
383 struct drm_device *dev = connector->dev;
384 struct amdgpu_device *adev = dev->dev_private;
385 int i;
386
387 drm_modeset_lock_all(dev);
388 if (adev->mode_info.rfbdev) {
389 /*Do not add if already registered in past*/
390 for (i = 0; i < adev->mode_info.rfbdev->helper.connector_count; i++) {
391 if (adev->mode_info.rfbdev->helper.connector_info[i]->connector
392 == connector) {
393 drm_modeset_unlock_all(dev);
394 return;
395 }
396 }
397
398 drm_fb_helper_add_one_connector(&adev->mode_info.rfbdev->helper, connector);
399 }
400 else
401 DRM_ERROR("adev->mode_info.rfbdev is NULL\n");
402
403 drm_modeset_unlock_all(dev);
404
405 drm_connector_register(connector);
406
407 }
408
409 static const struct drm_dp_mst_topology_cbs dm_mst_cbs = {
410 .add_connector = dm_dp_add_mst_connector,
411 .destroy_connector = dm_dp_destroy_mst_connector,
412 .hotplug = dm_dp_mst_hotplug,
413 .register_connector = dm_dp_mst_register_connector
414 };
415
416 void amdgpu_dm_initialize_mst_connector(
417 struct amdgpu_display_manager *dm,
418 struct amdgpu_connector *aconnector)
419 {
420 aconnector->dm_dp_aux.aux.name = "dmdc";
421 aconnector->dm_dp_aux.aux.dev = dm->adev->dev;
422 aconnector->dm_dp_aux.aux.transfer = dm_dp_aux_transfer;
423 aconnector->dm_dp_aux.link_index = aconnector->connector_id;
424
425 drm_dp_aux_register(&aconnector->dm_dp_aux.aux);
426 aconnector->mst_mgr.cbs = &dm_mst_cbs;
427 drm_dp_mst_topology_mgr_init(
428 &aconnector->mst_mgr,
429 dm->adev->ddev,
430 &aconnector->dm_dp_aux.aux,
431 16,
432 4,
433 aconnector->connector_id);
434 }
435