Skip to content

Commit afca033

Browse files
Roman Lialexdeucher
authored andcommitted
drm/amd/display: Add periodic detection for IPS
[Why] HPD interrupt cannot be handled in IPS2 state. So if there's a display topology change while system in IPS2 it can be missed. [How] Implement worker to check each 5 sec in IPS for HPD. Reviewed-by: Hamza Mahfooz <hamza.mahfooz@amd.com> Acked-by: Wayne Lin <wayne.lin@amd.com> Signed-off-by: Roman Li <roman.li@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
1 parent 5419a20 commit afca033

File tree

6 files changed

+113
-2
lines changed

6 files changed

+113
-2
lines changed

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,6 +1838,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
18381838
DRM_ERROR("amdgpu: failed to initialize vblank_workqueue.\n");
18391839
}
18401840

1841+
if (adev->dm.dc->caps.ips_support && adev->dm.dc->config.disable_ips == DMUB_IPS_ENABLE)
1842+
adev->dm.idle_workqueue = idle_create_workqueue(adev);
1843+
18411844
if (adev->dm.dc->caps.max_links > 0 && adev->family >= AMDGPU_FAMILY_RV) {
18421845
adev->dm.hdcp_workqueue = hdcp_create_workqueue(adev, &init_params.cp_psp, adev->dm.dc);
18431846

@@ -1935,6 +1938,16 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
19351938
adev->dm.vblank_control_workqueue = NULL;
19361939
}
19371940

1941+
if (adev->dm.idle_workqueue) {
1942+
if (adev->dm.idle_workqueue->running) {
1943+
adev->dm.idle_workqueue->enable = false;
1944+
flush_work(&adev->dm.idle_workqueue->work);
1945+
}
1946+
1947+
kfree(adev->dm.idle_workqueue);
1948+
adev->dm.idle_workqueue = NULL;
1949+
}
1950+
19381951
amdgpu_dm_destroy_drm_device(&adev->dm);
19391952

19401953
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,13 @@ struct vblank_control_work {
137137
bool enable;
138138
};
139139

140+
struct idle_workqueue {
141+
struct work_struct work;
142+
struct amdgpu_display_manager *dm;
143+
bool enable;
144+
bool running;
145+
};
146+
140147
/**
141148
* struct amdgpu_dm_backlight_caps - Information about backlight
142149
*
@@ -487,6 +494,7 @@ struct amdgpu_display_manager {
487494
* Deferred work for vblank control events.
488495
*/
489496
struct workqueue_struct *vblank_control_workqueue;
497+
struct idle_workqueue *idle_workqueue;
490498

491499
struct drm_atomic_state *cached_state;
492500
struct dc_state *cached_dc_state;
@@ -956,4 +964,5 @@ amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state,
956964
struct drm_crtc *crtc);
957965

958966
int convert_dc_color_depth_into_bpc(enum dc_color_depth display_color_depth);
967+
struct idle_workqueue *idle_create_workqueue(struct amdgpu_device *adev);
959968
#endif /* __AMDGPU_DM_H__ */

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
#include "amdgpu_dm_trace.h"
3636
#include "amdgpu_dm_debugfs.h"
3737

38+
#define HPD_DETECTION_PERIOD_uS 5000000
39+
#define HPD_DETECTION_TIME_uS 1000
40+
3841
void amdgpu_dm_crtc_handle_vblank(struct amdgpu_crtc *acrtc)
3942
{
4043
struct drm_crtc *crtc = &acrtc->base;
@@ -146,11 +149,65 @@ static void amdgpu_dm_crtc_set_panel_sr_feature(
146149
struct amdgpu_dm_connector *aconn =
147150
(struct amdgpu_dm_connector *) vblank_work->stream->dm_stream_context;
148151

149-
if (!aconn->disallow_edp_enter_psr)
152+
if (!aconn->disallow_edp_enter_psr) {
153+
struct amdgpu_display_manager *dm = vblank_work->dm;
154+
150155
amdgpu_dm_psr_enable(vblank_work->stream);
156+
if (dm->idle_workqueue &&
157+
dm->dc->idle_optimizations_allowed &&
158+
dm->idle_workqueue->enable &&
159+
!dm->idle_workqueue->running)
160+
schedule_work(&dm->idle_workqueue->work);
161+
}
151162
}
152163
}
153164

165+
static void amdgpu_dm_idle_worker(struct work_struct *work)
166+
{
167+
struct idle_workqueue *idle_work;
168+
169+
idle_work = container_of(work, struct idle_workqueue, work);
170+
idle_work->dm->idle_workqueue->running = true;
171+
fsleep(HPD_DETECTION_PERIOD_uS);
172+
mutex_lock(&idle_work->dm->dc_lock);
173+
while (idle_work->enable) {
174+
if (!idle_work->dm->dc->idle_optimizations_allowed)
175+
break;
176+
177+
dc_allow_idle_optimizations(idle_work->dm->dc, false);
178+
179+
mutex_unlock(&idle_work->dm->dc_lock);
180+
fsleep(HPD_DETECTION_TIME_uS);
181+
mutex_lock(&idle_work->dm->dc_lock);
182+
183+
if (!amdgpu_dm_psr_is_active_allowed(idle_work->dm))
184+
break;
185+
186+
dc_allow_idle_optimizations(idle_work->dm->dc, true);
187+
mutex_unlock(&idle_work->dm->dc_lock);
188+
fsleep(HPD_DETECTION_PERIOD_uS);
189+
mutex_lock(&idle_work->dm->dc_lock);
190+
}
191+
mutex_unlock(&idle_work->dm->dc_lock);
192+
idle_work->dm->idle_workqueue->running = false;
193+
}
194+
195+
struct idle_workqueue *idle_create_workqueue(struct amdgpu_device *adev)
196+
{
197+
struct idle_workqueue *idle_work;
198+
199+
idle_work = kzalloc(sizeof(*idle_work), GFP_KERNEL);
200+
if (ZERO_OR_NULL_PTR(idle_work))
201+
return NULL;
202+
203+
idle_work->dm = &adev->dm;
204+
idle_work->enable = false;
205+
idle_work->running = false;
206+
INIT_WORK(&idle_work->work, amdgpu_dm_idle_worker);
207+
208+
return idle_work;
209+
}
210+
154211
static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work)
155212
{
156213
struct vblank_control_work *vblank_work =

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1261,7 +1261,10 @@ void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz)
12611261

12621262
void dm_helpers_enable_periodic_detection(struct dc_context *ctx, bool enable)
12631263
{
1264-
/* TODO: add periodic detection implementation */
1264+
struct amdgpu_device *adev = ctx->driver_context;
1265+
1266+
if (adev->dm.idle_workqueue)
1267+
adev->dm.idle_workqueue->enable = enable;
12651268
}
12661269

12671270
void dm_helpers_dp_mst_update_branch_bandwidth(

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,31 @@ bool amdgpu_dm_psr_disable_all(struct amdgpu_display_manager *dm)
223223
return dc_set_psr_allow_active(dm->dc, false);
224224
}
225225

226+
/*
227+
* amdgpu_dm_psr_is_active_allowed() - check if psr is allowed on any stream
228+
* @dm: pointer to amdgpu_display_manager
229+
*
230+
* Return: true if allowed
231+
*/
232+
233+
bool amdgpu_dm_psr_is_active_allowed(struct amdgpu_display_manager *dm)
234+
{
235+
unsigned int i;
236+
bool allow_active = false;
237+
238+
for (i = 0; i < dm->dc->current_state->stream_count ; i++) {
239+
struct dc_link *link;
240+
struct dc_stream_state *stream = dm->dc->current_state->streams[i];
241+
242+
link = stream->link;
243+
if (!link)
244+
continue;
245+
if (link->psr_settings.psr_feature_enabled &&
246+
link->psr_settings.psr_allow_active) {
247+
allow_active = true;
248+
break;
249+
}
250+
}
251+
252+
return allow_active;
253+
}

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@ void amdgpu_dm_psr_enable(struct dc_stream_state *stream);
3636
bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream);
3737
bool amdgpu_dm_psr_disable(struct dc_stream_state *stream);
3838
bool amdgpu_dm_psr_disable_all(struct amdgpu_display_manager *dm);
39+
bool amdgpu_dm_psr_is_active_allowed(struct amdgpu_display_manager *dm);
3940

4041
#endif /* AMDGPU_DM_AMDGPU_DM_PSR_H_ */

0 commit comments

Comments
 (0)