drm/amd/display: Add trigger connector unplug
authorEryk Brol <eryk.brol@amd.com>
Thu, 27 Aug 2020 19:45:06 +0000 (15:45 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 15 Sep 2020 21:52:41 +0000 (17:52 -0400)
[why]
We need a virtual tool that would emulate a physical
connector unplug to usermode, while connector is
still physically plugged in.

[how]
Added a new option to debugfs entry "trigger_hotplug".
It emulates hotplug irq handling scenario by clearing
DC and DM connector states.
It can be triggered with the following command:

echo 0 > /sys/kernel/debug/dri/0/DP-X/trigger_hotplug

Signed-off-by: Eryk Brol <eryk.brol@amd.com>
Signed-off-by: Mikita Lipski <mikita.lipski@amd.com>
Acked-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c

index 5cf3ba3ec5dab9e82125c03c120702dd6adcb6d3..7c7f937166dc50e063b7e94c159260b7abfa267d 100644 (file)
@@ -1058,12 +1058,17 @@ static int dp_dsc_fec_support_show(struct seq_file *m, void *data)
  *
  *     echo 1 > /sys/kernel/debug/dri/0/DP-X/trigger_hotplug
  *
+ * This function can perform HPD unplug:
+ *
+ *     echo 0 > /sys/kernel/debug/dri/0/DP-X/trigger_hotplug
+ *
  */
 static ssize_t dp_trigger_hotplug(struct file *f, const char __user *buf,
                                                        size_t size, loff_t *pos)
 {
        struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private;
        struct drm_connector *connector = &aconnector->base;
+       struct dc_link *link = NULL;
        struct drm_device *dev = connector->dev;
        enum dc_connection_type new_connection_type = dc_connection_none;
        char *wr_buf = NULL;
@@ -1114,11 +1119,33 @@ static ssize_t dp_trigger_hotplug(struct file *f, const char __user *buf,
                drm_modeset_unlock_all(dev);
 
                drm_kms_helper_hotplug_event(dev);
+       } else if (param[0] == 0) {
+               if (!aconnector->dc_link)
+                       goto unlock;
 
-unlock:
-               mutex_unlock(&aconnector->hpd_lock);
+               link = aconnector->dc_link;
+
+               if (link->local_sink) {
+                       dc_sink_release(link->local_sink);
+                       link->local_sink = NULL;
+               }
+
+               link->dpcd_sink_count = 0;
+               link->type = dc_connection_none;
+               link->dongle_max_pix_clk = 0;
+
+               amdgpu_dm_update_connector_after_detect(aconnector);
+
+               drm_modeset_lock_all(dev);
+               dm_restore_drm_connector_state(dev, connector);
+               drm_modeset_unlock_all(dev);
+
+               drm_kms_helper_hotplug_event(dev);
        }
 
+unlock:
+       mutex_unlock(&aconnector->hpd_lock);
+
        kfree(wr_buf);
        return size;
 }