drm/amd/display: Add MST capability to trigger_hotplug interface

[Why]
Need to be able to trigger software hotplug for MST connectors

[How]
For unplug the driver calls to disable topologies manager
that connector is attached to. For plugging in it does the
whole rediscovery of all connectors in drm device and enbles their
topologies if attached.

The interface for MST connectors works in the following way:

1. To disconnect all MST topologies currently connected:
   echo 0 > /sys/kernel/debug/dri/0/amdgpu_dm_trigger_hpd_mst

2. To reconnect/rediscover all topologies that are physically
connected to the card:
   echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_trigger_hpd_mst

A related fix which has been merged with this patch
Leo Ma(Hanghong Ma)'s work:

Set power states before disable MST topology
[Why]
	When we try to disable MST topology from the
	debugfs entry, some receiver will hang.
[How]
	Set DPCD 600h power states to
	2(power down mode)before disable MST topology.

Signed-off-by: Mikita Lipski <mikita.lipski@amd.com>
Reviewed-by: Sun peng Li <Sunpeng.Li@amd.com>
Acked-by: Qingqing Zhuo <qingqing.zhuo@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Mikita Lipski 2020-09-15 08:50:49 -04:00 committed by Alex Deucher
parent f5b6a20c7e
commit 41efcd3879
1 changed files with 70 additions and 1 deletions

View File

@ -2980,7 +2980,73 @@ static int mst_topo_show(struct seq_file *m, void *unused)
}
/*
* Sets the force_timing_sync debug optino from the given string.
* Sets trigger hpd for MST topologies.
* All connected connectors will be rediscovered and re started as needed if val of 1 is sent.
* All topologies will be disconnected if val of 0 is set .
* Usage to enable topologies: echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_trigger_hpd_mst
* Usage to disable topologies: echo 0 > /sys/kernel/debug/dri/0/amdgpu_dm_trigger_hpd_mst
*/
static int trigger_hpd_mst_set(void *data, u64 val)
{
struct amdgpu_device *adev = data;
struct drm_device *dev = adev_to_drm(adev);
struct drm_connector_list_iter iter;
struct amdgpu_dm_connector *aconnector;
struct drm_connector *connector;
struct dc_link *link = NULL;
if (val == 1) {
drm_connector_list_iter_begin(dev, &iter);
drm_for_each_connector_iter(connector, &iter) {
aconnector = to_amdgpu_dm_connector(connector);
if (aconnector->dc_link->type == dc_connection_mst_branch &&
aconnector->mst_mgr.aux) {
dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD);
drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true);
}
}
} else if (val == 0) {
drm_connector_list_iter_begin(dev, &iter);
drm_for_each_connector_iter(connector, &iter) {
aconnector = to_amdgpu_dm_connector(connector);
if (!aconnector->dc_link)
continue;
if (!(aconnector->port && &aconnector->mst_port->mst_mgr))
continue;
link = aconnector->dc_link;
dp_receiver_power_ctrl(link, false);
drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_port->mst_mgr, false);
link->mst_stream_alloc_table.stream_count = 0;
memset(link->mst_stream_alloc_table.stream_allocations, 0,
sizeof(link->mst_stream_alloc_table.stream_allocations));
}
} else {
return 0;
}
drm_kms_helper_hotplug_event(dev);
return 0;
}
/*
* The interface doesn't need get function, so it will return the
* value of zero
* Usage: cat /sys/kernel/debug/dri/0/amdgpu_dm_trigger_hpd_mst
*/
static int trigger_hpd_mst_get(void *data, u64 *val)
{
*val = 0;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(trigger_hpd_mst_ops, trigger_hpd_mst_get,
trigger_hpd_mst_set, "%llu\n");
/*
* Sets the force_timing_sync debug option from the given string.
* All connected displays will be force synchronized immediately.
* Usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_force_timing_sync
*/
@ -3142,6 +3208,9 @@ void dtn_debugfs_init(struct amdgpu_device *adev)
debugfs_create_file_unsafe("amdgpu_dm_dmcub_trace_event_en", 0644, root,
adev, &dmcub_trace_event_state_fops);
debugfs_create_file_unsafe("amdgpu_dm_trigger_hpd_mst", 0644, root,
adev, &trigger_hpd_mst_ops);
debugfs_create_file_unsafe("amdgpu_dm_dcc_en", 0644, root, adev,
&dcc_en_bits_fops);
}