From: Roman Li <roman...@amd.com>

[WHY]
Hotplug is not detected in headless (no eDP) mode on dcn35x.
With no display dcn35x goes to IPS2 powersaving state where HPD interrupt
is not handled.

[HOW]
Use idle worker thread for periodic detection of HPD in headless mode.

Reviewed-by: Aurabindo Pillai <aurabindo.pil...@amd.com>
Cc: Mario Limonciello <mario.limoncie...@amd.com>
Cc: Alex Deucher <alexander.deuc...@amd.com>
Cc: sta...@vger.kernel.org
Acked-by: Alex Hung <alex.h...@amd.com>
Signed-off-by: Roman Li <roman...@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  3 ++
 .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c    | 48 +++++++++++++++----
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  5 +-
 3 files changed, 46 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index dfcbc1970fe6..5fd1b6b44577 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -989,4 +989,7 @@ void *dm_allocate_gpu_mem(struct amdgpu_device *adev,
                                                  enum dc_gpu_mem_alloc_type 
type,
                                                  size_t size,
                                                  long long *addr);
+
+bool amdgpu_dm_is_headless(struct amdgpu_device *adev);
+
 #endif /* __AMDGPU_DM_H__ */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index e16eecb146fd..99014339aaa3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -162,33 +162,63 @@ static void amdgpu_dm_crtc_set_panel_sr_feature(
        }
 }
 
+bool amdgpu_dm_is_headless(struct amdgpu_device *adev)
+{
+       struct drm_connector *connector;
+       struct drm_connector_list_iter iter;
+       struct drm_device *dev;
+       bool is_headless = true;
+
+       if (adev == NULL)
+               return true;
+
+       dev = adev->dm.ddev;
+
+       drm_connector_list_iter_begin(dev, &iter);
+       drm_for_each_connector_iter(connector, &iter) {
+
+               if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+                       continue;
+
+               if (connector->status == connector_status_connected) {
+                       is_headless = false;
+                       break;
+               }
+       }
+       drm_connector_list_iter_end(&iter);
+       return is_headless;
+}
+
 static void amdgpu_dm_idle_worker(struct work_struct *work)
 {
        struct idle_workqueue *idle_work;
 
        idle_work = container_of(work, struct idle_workqueue, work);
        idle_work->dm->idle_workqueue->running = true;
-       fsleep(HPD_DETECTION_PERIOD_uS);
-       mutex_lock(&idle_work->dm->dc_lock);
+
        while (idle_work->enable) {
-               if (!idle_work->dm->dc->idle_optimizations_allowed)
+               fsleep(HPD_DETECTION_PERIOD_uS);
+               mutex_lock(&idle_work->dm->dc_lock);
+               if (!idle_work->dm->dc->idle_optimizations_allowed) {
+                       mutex_unlock(&idle_work->dm->dc_lock);
                        break;
-
+               }
                dc_allow_idle_optimizations(idle_work->dm->dc, false);
 
                mutex_unlock(&idle_work->dm->dc_lock);
                fsleep(HPD_DETECTION_TIME_uS);
                mutex_lock(&idle_work->dm->dc_lock);
 
-               if (!amdgpu_dm_psr_is_active_allowed(idle_work->dm))
+               if (!amdgpu_dm_is_headless(idle_work->dm->adev) &&
+                   !amdgpu_dm_psr_is_active_allowed(idle_work->dm)) {
+                       mutex_unlock(&idle_work->dm->dc_lock);
                        break;
+               }
 
-               dc_allow_idle_optimizations(idle_work->dm->dc, true);
+               if (idle_work->enable)
+                       dc_allow_idle_optimizations(idle_work->dm->dc, true);
                mutex_unlock(&idle_work->dm->dc_lock);
-               fsleep(HPD_DETECTION_PERIOD_uS);
-               mutex_lock(&idle_work->dm->dc_lock);
        }
-       mutex_unlock(&idle_work->dm->dc_lock);
        idle_work->dm->idle_workqueue->running = false;
 }
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 659dd67be1ba..f5e1f2d1c5f2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -1239,8 +1239,11 @@ void dm_helpers_enable_periodic_detection(struct 
dc_context *ctx, bool enable)
 {
        struct amdgpu_device *adev = ctx->driver_context;
 
-       if (adev->dm.idle_workqueue)
+       if (adev->dm.idle_workqueue) {
                adev->dm.idle_workqueue->enable = enable;
+               if (enable && !adev->dm.idle_workqueue->running && 
amdgpu_dm_is_headless(adev))
+                       schedule_work(&adev->dm.idle_workqueue->work);
+       }
 }
 
 void dm_helpers_dp_mst_update_branch_bandwidth(
-- 
2.34.1

Reply via email to