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.h"
31 #include "amdgpu_dm_mst_types.h"
34 #include "dm_helpers.h"
36 #include "dc_link_ddc.h"
38 /* #define TRACE_DPCD */
41 #define SIDE_BAND_MSG(address) (address >= DP_SIDEBAND_MSG_DOWN_REQ_BASE && address < DP_SINK_COUNT_ESI)
43 static inline char *side_band_msg_type_to_str(uint32_t address
)
45 static char str
[10] = {0};
47 if (address
< DP_SIDEBAND_MSG_UP_REP_BASE
)
48 strcpy(str
, "DOWN_REQ");
49 else if (address
< DP_SIDEBAND_MSG_DOWN_REP_BASE
)
50 strcpy(str
, "UP_REP");
51 else if (address
< DP_SIDEBAND_MSG_UP_REQ_BASE
)
52 strcpy(str
, "DOWN_REP");
54 strcpy(str
, "UP_REQ");
59 static void log_dpcd(uint8_t type
,
65 DRM_DEBUG_KMS("Op: %s, addr: %04x, SideBand Msg: %s, Op res: %s\n",
66 (type
== DP_AUX_NATIVE_READ
) ||
67 (type
== DP_AUX_I2C_READ
) ?
70 SIDE_BAND_MSG(address
) ?
71 side_band_msg_type_to_str(address
) : "Nop",
75 print_hex_dump(KERN_INFO
, "Body: ", DUMP_PREFIX_NONE
, 16, 1, data
, size
, false);
80 static ssize_t
dm_dp_aux_transfer(struct drm_dp_aux
*aux
,
81 struct drm_dp_aux_msg
*msg
)
83 enum i2c_mot_mode mot
= (msg
->request
& DP_AUX_I2C_MOT
) ?
84 I2C_MOT_TRUE
: I2C_MOT_FALSE
;
86 uint32_t read_bytes
= msg
->size
;
88 if (WARN_ON(msg
->size
> 16))
91 switch (msg
->request
& ~DP_AUX_I2C_MOT
) {
92 case DP_AUX_NATIVE_READ
:
93 res
= dal_ddc_service_read_dpcd_data(
94 TO_DM_AUX(aux
)->ddc_service
,
102 case DP_AUX_NATIVE_WRITE
:
103 res
= dal_ddc_service_write_dpcd_data(
104 TO_DM_AUX(aux
)->ddc_service
,
111 case DP_AUX_I2C_READ
:
112 res
= dal_ddc_service_read_dpcd_data(
113 TO_DM_AUX(aux
)->ddc_service
,
121 case DP_AUX_I2C_WRITE
:
122 res
= dal_ddc_service_write_dpcd_data(
123 TO_DM_AUX(aux
)->ddc_service
,
135 log_dpcd(msg
->request
,
139 r
== DDC_RESULT_SUCESSFULL
);
142 if (res
!= DDC_RESULT_SUCESSFULL
)
147 static enum drm_connector_status
148 dm_dp_mst_detect(struct drm_connector
*connector
, bool force
)
150 struct amdgpu_dm_connector
*aconnector
= to_amdgpu_dm_connector(connector
);
151 struct amdgpu_dm_connector
*master
= aconnector
->mst_port
;
153 enum drm_connector_status status
=
154 drm_dp_mst_detect_port(
163 dm_dp_mst_connector_destroy(struct drm_connector
*connector
)
165 struct amdgpu_dm_connector
*amdgpu_dm_connector
= to_amdgpu_dm_connector(connector
);
166 struct amdgpu_encoder
*amdgpu_encoder
= amdgpu_dm_connector
->mst_encoder
;
168 if (amdgpu_dm_connector
->edid
) {
169 kfree(amdgpu_dm_connector
->edid
);
170 amdgpu_dm_connector
->edid
= NULL
;
173 drm_encoder_cleanup(&amdgpu_encoder
->base
);
174 kfree(amdgpu_encoder
);
175 drm_connector_cleanup(connector
);
176 kfree(amdgpu_dm_connector
);
179 static const struct drm_connector_funcs dm_dp_mst_connector_funcs
= {
180 .detect
= dm_dp_mst_detect
,
181 .fill_modes
= drm_helper_probe_single_connector_modes
,
182 .destroy
= dm_dp_mst_connector_destroy
,
183 .reset
= amdgpu_dm_connector_funcs_reset
,
184 .atomic_duplicate_state
= amdgpu_dm_connector_atomic_duplicate_state
,
185 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
186 .atomic_set_property
= amdgpu_dm_connector_atomic_set_property
,
187 .atomic_get_property
= amdgpu_dm_connector_atomic_get_property
190 void dm_dp_mst_dc_sink_create(struct drm_connector
*connector
)
192 struct amdgpu_dm_connector
*aconnector
= to_amdgpu_dm_connector(connector
);
193 struct dc_sink
*dc_sink
;
194 struct dc_sink_init_data init_params
= {
195 .link
= aconnector
->dc_link
,
196 .sink_signal
= SIGNAL_TYPE_DISPLAY_PORT_MST
};
198 /* FIXME none of this is safe. we shouldn't touch aconnector here in
203 * TODO: Need to further figure out why ddc.algo is NULL while MST port exists
205 if (!aconnector
->port
|| !aconnector
->port
->aux
.ddc
.algo
)
208 ASSERT(aconnector
->edid
);
210 dc_sink
= dc_link_add_remote_sink(
212 (uint8_t *)aconnector
->edid
,
213 (aconnector
->edid
->extensions
+ 1) * EDID_LENGTH
,
216 dc_sink
->priv
= aconnector
;
217 aconnector
->dc_sink
= dc_sink
;
219 amdgpu_dm_add_sink_to_freesync_module(
220 connector
, aconnector
->edid
);
223 static int dm_dp_mst_get_modes(struct drm_connector
*connector
)
225 struct amdgpu_dm_connector
*aconnector
= to_amdgpu_dm_connector(connector
);
229 return drm_add_edid_modes(connector
, NULL
);
231 if (!aconnector
->edid
) {
233 edid
= drm_dp_mst_get_edid(connector
, &aconnector
->mst_port
->mst_mgr
, aconnector
->port
);
236 drm_connector_update_edid_property(
242 aconnector
->edid
= edid
;
245 if (!aconnector
->dc_sink
) {
246 struct dc_sink
*dc_sink
;
247 struct dc_sink_init_data init_params
= {
248 .link
= aconnector
->dc_link
,
249 .sink_signal
= SIGNAL_TYPE_DISPLAY_PORT_MST
};
250 dc_sink
= dc_link_add_remote_sink(
252 (uint8_t *)aconnector
->edid
,
253 (aconnector
->edid
->extensions
+ 1) * EDID_LENGTH
,
256 dc_sink
->priv
= aconnector
;
257 aconnector
->dc_sink
= dc_sink
;
259 if (aconnector
->dc_sink
)
260 amdgpu_dm_add_sink_to_freesync_module(
261 connector
, aconnector
->edid
);
264 drm_connector_update_edid_property(
265 &aconnector
->base
, aconnector
->edid
);
267 ret
= drm_add_edid_modes(connector
, aconnector
->edid
);
272 static struct drm_encoder
*dm_mst_best_encoder(struct drm_connector
*connector
)
274 struct amdgpu_dm_connector
*amdgpu_dm_connector
= to_amdgpu_dm_connector(connector
);
276 return &amdgpu_dm_connector
->mst_encoder
->base
;
279 static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs
= {
280 .get_modes
= dm_dp_mst_get_modes
,
281 .mode_valid
= amdgpu_dm_connector_mode_valid
,
282 .best_encoder
= dm_mst_best_encoder
,
285 static void amdgpu_dm_encoder_destroy(struct drm_encoder
*encoder
)
287 drm_encoder_cleanup(encoder
);
291 static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs
= {
292 .destroy
= amdgpu_dm_encoder_destroy
,
295 static struct amdgpu_encoder
*
296 dm_dp_create_fake_mst_encoder(struct amdgpu_dm_connector
*connector
)
298 struct drm_device
*dev
= connector
->base
.dev
;
299 struct amdgpu_device
*adev
= dev
->dev_private
;
300 struct amdgpu_encoder
*amdgpu_encoder
;
301 struct drm_encoder
*encoder
;
302 const struct drm_connector_helper_funcs
*connector_funcs
=
303 connector
->base
.helper_private
;
304 struct drm_encoder
*enc_master
=
305 connector_funcs
->best_encoder(&connector
->base
);
307 DRM_DEBUG_KMS("enc master is %p\n", enc_master
);
308 amdgpu_encoder
= kzalloc(sizeof(*amdgpu_encoder
), GFP_KERNEL
);
312 encoder
= &amdgpu_encoder
->base
;
313 encoder
->possible_crtcs
= amdgpu_dm_get_encoder_crtc_mask(adev
);
317 &amdgpu_encoder
->base
,
318 &amdgpu_dm_encoder_funcs
,
319 DRM_MODE_ENCODER_DPMST
,
322 drm_encoder_helper_add(encoder
, &amdgpu_dm_encoder_helper_funcs
);
324 return amdgpu_encoder
;
327 static struct drm_connector
*
328 dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr
*mgr
,
329 struct drm_dp_mst_port
*port
,
330 const char *pathprop
)
332 struct amdgpu_dm_connector
*master
= container_of(mgr
, struct amdgpu_dm_connector
, mst_mgr
);
333 struct drm_device
*dev
= master
->base
.dev
;
334 struct amdgpu_device
*adev
= dev
->dev_private
;
335 struct amdgpu_dm_connector
*aconnector
;
336 struct drm_connector
*connector
;
337 struct drm_connector_list_iter conn_iter
;
339 drm_connector_list_iter_begin(dev
, &conn_iter
);
340 drm_for_each_connector_iter(connector
, &conn_iter
) {
341 aconnector
= to_amdgpu_dm_connector(connector
);
342 if (aconnector
->mst_port
== master
343 && !aconnector
->port
) {
344 DRM_INFO("DM_MST: reusing connector: %p [id: %d] [master: %p]\n",
345 aconnector
, connector
->base
.id
, aconnector
->mst_port
);
347 aconnector
->port
= port
;
348 drm_mode_connector_set_path_property(connector
, pathprop
);
350 drm_connector_list_iter_end(&conn_iter
);
351 aconnector
->mst_connected
= true;
352 return &aconnector
->base
;
355 drm_connector_list_iter_end(&conn_iter
);
357 aconnector
= kzalloc(sizeof(*aconnector
), GFP_KERNEL
);
361 connector
= &aconnector
->base
;
362 aconnector
->port
= port
;
363 aconnector
->mst_port
= master
;
365 if (drm_connector_init(
368 &dm_dp_mst_connector_funcs
,
369 DRM_MODE_CONNECTOR_DisplayPort
)) {
373 drm_connector_helper_add(connector
, &dm_dp_mst_connector_helper_funcs
);
375 amdgpu_dm_connector_init_helper(
378 DRM_MODE_CONNECTOR_DisplayPort
,
380 master
->connector_id
);
382 aconnector
->mst_encoder
= dm_dp_create_fake_mst_encoder(master
);
385 * TODO: understand why this one is needed
387 drm_object_attach_property(
389 dev
->mode_config
.path_property
,
391 drm_object_attach_property(
393 dev
->mode_config
.tile_property
,
396 drm_mode_connector_set_path_property(connector
, pathprop
);
399 * Initialize connector state before adding the connectror to drm and
402 amdgpu_dm_connector_funcs_reset(connector
);
404 aconnector
->mst_connected
= true;
406 DRM_INFO("DM_MST: added connector: %p [id: %d] [master: %p]\n",
407 aconnector
, connector
->base
.id
, aconnector
->mst_port
);
409 DRM_DEBUG_KMS(":%d\n", connector
->base
.id
);
414 static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr
*mgr
,
415 struct drm_connector
*connector
)
417 struct amdgpu_dm_connector
*aconnector
= to_amdgpu_dm_connector(connector
);
419 DRM_INFO("DM_MST: Disabling connector: %p [id: %d] [master: %p]\n",
420 aconnector
, connector
->base
.id
, aconnector
->mst_port
);
422 aconnector
->port
= NULL
;
423 if (aconnector
->dc_sink
) {
424 amdgpu_dm_remove_sink_from_freesync_module(connector
);
425 dc_link_remove_remote_sink(aconnector
->dc_link
, aconnector
->dc_sink
);
426 dc_sink_release(aconnector
->dc_sink
);
427 aconnector
->dc_sink
= NULL
;
430 aconnector
->mst_connected
= false;
433 static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr
*mgr
)
435 struct amdgpu_dm_connector
*master
= container_of(mgr
, struct amdgpu_dm_connector
, mst_mgr
);
436 struct drm_device
*dev
= master
->base
.dev
;
438 drm_kms_helper_hotplug_event(dev
);
441 static void dm_dp_mst_link_status_reset(struct drm_connector
*connector
)
443 mutex_lock(&connector
->dev
->mode_config
.mutex
);
444 drm_mode_connector_set_link_status_property(connector
, DRM_MODE_LINK_STATUS_BAD
);
445 mutex_unlock(&connector
->dev
->mode_config
.mutex
);
448 static void dm_dp_mst_register_connector(struct drm_connector
*connector
)
450 struct drm_device
*dev
= connector
->dev
;
451 struct amdgpu_device
*adev
= dev
->dev_private
;
452 struct amdgpu_dm_connector
*aconnector
= to_amdgpu_dm_connector(connector
);
454 if (adev
->mode_info
.rfbdev
)
455 drm_fb_helper_add_one_connector(&adev
->mode_info
.rfbdev
->helper
, connector
);
457 DRM_ERROR("adev->mode_info.rfbdev is NULL\n");
459 drm_connector_register(connector
);
461 if (aconnector
->mst_connected
)
462 dm_dp_mst_link_status_reset(connector
);
465 static const struct drm_dp_mst_topology_cbs dm_mst_cbs
= {
466 .add_connector
= dm_dp_add_mst_connector
,
467 .destroy_connector
= dm_dp_destroy_mst_connector
,
468 .hotplug
= dm_dp_mst_hotplug
,
469 .register_connector
= dm_dp_mst_register_connector
472 void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager
*dm
,
473 struct amdgpu_dm_connector
*aconnector
)
475 aconnector
->dm_dp_aux
.aux
.name
= "dmdc";
476 aconnector
->dm_dp_aux
.aux
.dev
= dm
->adev
->dev
;
477 aconnector
->dm_dp_aux
.aux
.transfer
= dm_dp_aux_transfer
;
478 aconnector
->dm_dp_aux
.ddc_service
= aconnector
->dc_link
->ddc
;
480 drm_dp_aux_register(&aconnector
->dm_dp_aux
.aux
);
481 aconnector
->mst_mgr
.cbs
= &dm_mst_cbs
;
482 drm_dp_mst_topology_mgr_init(
483 &aconnector
->mst_mgr
,
485 &aconnector
->dm_dp_aux
.aux
,
488 aconnector
->connector_id
);