2 * Copyright 2012-15 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
26 #include <linux/version.h>
27 #include <drm/drm_atomic_helper.h>
28 #include "dm_services.h"
30 #include "amdgpu_dm_types.h"
31 #include "amdgpu_dm_mst_types.h"
34 #include "dm_helpers.h"
36 /* #define TRACE_DPCD */
39 #define SIDE_BAND_MSG(address) (address >= DP_SIDEBAND_MSG_DOWN_REQ_BASE && address < DP_SINK_COUNT_ESI)
41 static inline char *side_band_msg_type_to_str(uint32_t address
)
43 static char str
[10] = {0};
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");
52 strcpy(str
, "UP_REQ");
57 void log_dpcd(uint8_t type
,
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
) ?
68 SIDE_BAND_MSG(address
) ?
69 side_band_msg_type_to_str(address
) : "Nop",
73 print_hex_dump(KERN_INFO
, "Body: ", DUMP_PREFIX_NONE
, 16, 1, data
, size
, false);
78 static ssize_t
dm_dp_aux_transfer(struct drm_dp_aux
*aux
, struct drm_dp_aux_msg
*msg
)
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
;
86 switch (msg
->request
) {
87 case DP_AUX_NATIVE_READ
:
90 TO_DM_AUX(aux
)->link_index
,
95 case DP_AUX_NATIVE_WRITE
:
98 TO_DM_AUX(aux
)->link_index
,
108 log_dpcd(msg
->request
,
118 static enum drm_connector_status
119 dm_dp_mst_detect(struct drm_connector
*connector
, bool force
)
121 struct amdgpu_connector
*aconnector
= to_amdgpu_connector(connector
);
122 struct amdgpu_connector
*master
= aconnector
->mst_port
;
124 enum drm_connector_status status
=
125 drm_dp_mst_detect_port(
131 * we do not want to make this connector connected until we have edid on
134 if (status
== connector_status_connected
&&
135 !aconnector
->port
->cached_edid
)
136 status
= connector_status_disconnected
;
142 dm_dp_mst_connector_destroy(struct drm_connector
*connector
)
144 struct amdgpu_connector
*amdgpu_connector
= to_amdgpu_connector(connector
);
145 struct amdgpu_encoder
*amdgpu_encoder
= amdgpu_connector
->mst_encoder
;
147 drm_encoder_cleanup(&amdgpu_encoder
->base
);
148 kfree(amdgpu_encoder
);
149 drm_connector_cleanup(connector
);
150 kfree(amdgpu_connector
);
153 static const struct drm_connector_funcs dm_dp_mst_connector_funcs
= {
154 .detect
= dm_dp_mst_detect
,
155 .fill_modes
= drm_helper_probe_single_connector_modes
,
156 .destroy
= dm_dp_mst_connector_destroy
,
157 .reset
= amdgpu_dm_connector_funcs_reset
,
158 .atomic_duplicate_state
= amdgpu_dm_connector_atomic_duplicate_state
,
159 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
160 .atomic_set_property
= amdgpu_dm_connector_atomic_set_property
163 static int dm_dp_mst_get_modes(struct drm_connector
*connector
)
165 struct amdgpu_connector
*aconnector
= to_amdgpu_connector(connector
);
168 ret
= drm_add_edid_modes(&aconnector
->base
, aconnector
->edid
);
170 drm_edid_to_eld(&aconnector
->base
, aconnector
->edid
);
175 static struct drm_encoder
*dm_mst_best_encoder(struct drm_connector
*connector
)
177 struct amdgpu_connector
*amdgpu_connector
= to_amdgpu_connector(connector
);
179 return &amdgpu_connector
->mst_encoder
->base
;
182 static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs
= {
183 .get_modes
= dm_dp_mst_get_modes
,
184 .mode_valid
= amdgpu_dm_connector_mode_valid
,
185 .best_encoder
= dm_mst_best_encoder
,
188 static struct amdgpu_encoder
*
189 dm_dp_create_fake_mst_encoder(struct amdgpu_connector
*connector
)
191 struct drm_device
*dev
= connector
->base
.dev
;
192 struct amdgpu_device
*adev
= dev
->dev_private
;
193 struct amdgpu_encoder
*amdgpu_encoder
;
194 struct drm_encoder
*encoder
;
195 const struct drm_connector_helper_funcs
*connector_funcs
=
196 connector
->base
.helper_private
;
197 struct drm_encoder
*enc_master
=
198 connector_funcs
->best_encoder(&connector
->base
);
200 DRM_DEBUG_KMS("enc master is %p\n", enc_master
);
201 amdgpu_encoder
= kzalloc(sizeof(*amdgpu_encoder
), GFP_KERNEL
);
205 encoder
= &amdgpu_encoder
->base
;
206 encoder
->possible_crtcs
= amdgpu_dm_get_encoder_crtc_mask(adev
);
210 &amdgpu_encoder
->base
,
212 DRM_MODE_ENCODER_DPMST
,
215 drm_encoder_helper_add(encoder
, &amdgpu_dm_encoder_helper_funcs
);
217 return amdgpu_encoder
;
220 static struct drm_connector
*dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr
*mgr
,
221 struct drm_dp_mst_port
*port
,
222 const char *pathprop
)
224 struct amdgpu_connector
*master
= container_of(mgr
, struct amdgpu_connector
, mst_mgr
);
225 struct drm_device
*dev
= master
->base
.dev
;
226 struct amdgpu_device
*adev
= dev
->dev_private
;
227 struct amdgpu_connector
*aconnector
;
228 struct drm_connector
*connector
;
230 drm_modeset_lock(&dev
->mode_config
.connection_mutex
, NULL
);
231 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
232 aconnector
= to_amdgpu_connector(connector
);
233 if (aconnector
->mst_port
== master
234 && !aconnector
->port
) {
235 DRM_INFO("DM_MST: reusing connector: %p [id: %d] [master: %p]\n",
236 aconnector
, connector
->base
.id
, aconnector
->mst_port
);
238 aconnector
->port
= port
;
239 drm_mode_connector_set_path_property(connector
, pathprop
);
241 drm_modeset_unlock(&dev
->mode_config
.connection_mutex
);
242 return &aconnector
->base
;
245 drm_modeset_unlock(&dev
->mode_config
.connection_mutex
);
247 aconnector
= kzalloc(sizeof(*aconnector
), GFP_KERNEL
);
251 connector
= &aconnector
->base
;
252 aconnector
->port
= port
;
253 aconnector
->mst_port
= master
;
255 if (drm_connector_init(
258 &dm_dp_mst_connector_funcs
,
259 DRM_MODE_CONNECTOR_DisplayPort
)) {
263 drm_connector_helper_add(connector
, &dm_dp_mst_connector_helper_funcs
);
265 amdgpu_dm_connector_init_helper(
268 DRM_MODE_CONNECTOR_DisplayPort
,
270 master
->connector_id
);
272 aconnector
->mst_encoder
= dm_dp_create_fake_mst_encoder(master
);
275 * TODO: understand why this one is needed
277 drm_object_attach_property(
279 dev
->mode_config
.path_property
,
281 drm_object_attach_property(
283 dev
->mode_config
.tile_property
,
286 drm_mode_connector_set_path_property(connector
, pathprop
);
289 * Initialize connector state before adding the connectror to drm and
292 amdgpu_dm_connector_funcs_reset(connector
);
294 DRM_INFO("DM_MST: added connector: %p [id: %d] [master: %p]\n",
295 aconnector
, connector
->base
.id
, aconnector
->mst_port
);
297 DRM_DEBUG_KMS(":%d\n", connector
->base
.id
);
302 static void dm_dp_destroy_mst_connector(
303 struct drm_dp_mst_topology_mgr
*mgr
,
304 struct drm_connector
*connector
)
306 struct amdgpu_connector
*aconnector
= to_amdgpu_connector(connector
);
308 DRM_INFO("DM_MST: Disabling connector: %p [id: %d] [master: %p]\n",
309 aconnector
, connector
->base
.id
, aconnector
->mst_port
);
311 aconnector
->port
= NULL
;
312 if (aconnector
->dc_sink
) {
313 amdgpu_dm_remove_sink_from_freesync_module(connector
);
314 dc_link_remove_remote_sink(aconnector
->dc_link
, aconnector
->dc_sink
);
315 dc_sink_release(aconnector
->dc_sink
);
316 aconnector
->dc_sink
= NULL
;
318 if (aconnector
->edid
) {
319 kfree(aconnector
->edid
);
320 aconnector
->edid
= NULL
;
323 drm_mode_connector_update_edid_property(
328 static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr
*mgr
)
330 struct amdgpu_connector
*master
= container_of(mgr
, struct amdgpu_connector
, mst_mgr
);
331 struct drm_device
*dev
= master
->base
.dev
;
332 struct amdgpu_device
*adev
= dev
->dev_private
;
333 struct drm_connector
*connector
;
334 struct amdgpu_connector
*aconnector
;
337 drm_modeset_lock_all(dev
);
338 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
339 aconnector
= to_amdgpu_connector(connector
);
340 if (aconnector
->port
&&
341 aconnector
->port
->pdt
!= DP_PEER_DEVICE_NONE
&&
342 aconnector
->port
->pdt
!= DP_PEER_DEVICE_MST_BRANCHING
&&
343 !aconnector
->dc_sink
) {
345 * This is plug in case, where port has been created but
346 * sink hasn't been created yet
348 if (!aconnector
->edid
) {
349 struct dc_sink_init_data init_params
= {
350 .link
= aconnector
->dc_link
,
351 .sink_signal
= SIGNAL_TYPE_DISPLAY_PORT_MST
};
352 edid
= drm_dp_mst_get_edid(connector
, &aconnector
->mst_port
->mst_mgr
, aconnector
->port
);
355 drm_mode_connector_update_edid_property(
361 aconnector
->edid
= edid
;
363 aconnector
->dc_sink
= dc_link_add_remote_sink(
366 (edid
->extensions
+ 1) * EDID_LENGTH
,
368 if (aconnector
->dc_sink
)
369 amdgpu_dm_add_sink_to_freesync_module(
373 dm_restore_drm_connector_state(connector
->dev
, connector
);
375 edid
= aconnector
->edid
;
377 DRM_DEBUG_KMS("edid retrieved %p\n", edid
);
379 drm_mode_connector_update_edid_property(
384 drm_modeset_unlock_all(dev
);
386 schedule_work(&adev
->dm
.mst_hotplug_work
);
389 static void dm_dp_mst_register_connector(struct drm_connector
*connector
)
391 struct drm_device
*dev
= connector
->dev
;
392 struct amdgpu_device
*adev
= dev
->dev_private
;
395 drm_modeset_lock_all(dev
);
396 if (adev
->mode_info
.rfbdev
) {
397 /*Do not add if already registered in past*/
398 for (i
= 0; i
< adev
->mode_info
.rfbdev
->helper
.connector_count
; i
++) {
399 if (adev
->mode_info
.rfbdev
->helper
.connector_info
[i
]->connector
401 drm_modeset_unlock_all(dev
);
406 drm_fb_helper_add_one_connector(&adev
->mode_info
.rfbdev
->helper
, connector
);
409 DRM_ERROR("adev->mode_info.rfbdev is NULL\n");
411 drm_modeset_unlock_all(dev
);
413 drm_connector_register(connector
);
417 static const struct drm_dp_mst_topology_cbs dm_mst_cbs
= {
418 .add_connector
= dm_dp_add_mst_connector
,
419 .destroy_connector
= dm_dp_destroy_mst_connector
,
420 .hotplug
= dm_dp_mst_hotplug
,
421 .register_connector
= dm_dp_mst_register_connector
424 void amdgpu_dm_initialize_mst_connector(
425 struct amdgpu_display_manager
*dm
,
426 struct amdgpu_connector
*aconnector
)
428 aconnector
->dm_dp_aux
.aux
.name
= "dmdc";
429 aconnector
->dm_dp_aux
.aux
.dev
= dm
->adev
->dev
;
430 aconnector
->dm_dp_aux
.aux
.transfer
= dm_dp_aux_transfer
;
431 aconnector
->dm_dp_aux
.link_index
= aconnector
->connector_id
;
433 drm_dp_aux_register(&aconnector
->dm_dp_aux
.aux
);
434 aconnector
->mst_mgr
.cbs
= &dm_mst_cbs
;
435 drm_dp_mst_topology_mgr_init(
436 &aconnector
->mst_mgr
,
438 &aconnector
->dm_dp_aux
.aux
,
441 aconnector
->connector_id
);