diff options
| author | Aric Cyr <Aric.Cyr@amd.com> | 2026-09-18 18:37:43 -0400 |
|---|---|---|
| committer | Alex Deucher <alexander.deucher@amd.com> | 2026-10-07 12:06:01 -0400 |
| commit | d07fc866c52dc759d823ecdbb026306c1273434c (patch) | |
| tree | 36d155ba0b2ee73b783e0fc68810c58e7db8c1de | |
| parent | e69156294e47185ba96f879d6ddf9d092a61b74d (diff) | |
drm/amd/display: only reprogram DRR when v_total values change
[Why]
dc_stream_adjust_vmin_vmax() programmed the OTG on every call. FreeSync
BTR calls it once per vblank, so identical v_total values were rewritten
every frame, each one paying dc_exit_ips_for_hw_access() and, when FAMS
is enabled, a blocking DMUB round trip from setup_manual_trigger().
[How]
Return early when timing_adjust_pending is clear and every v_total field
already matches the request, so hardware is only touched when the values
change. stream->adjust is still updated on every path that continues, so
a later commit programs the requested values.
timing_adjust_pending is the existing "stream->adjust has not reached
hardware" marker, so keep it accurate wherever hardware is left
untouched: set_drr_and_clear_adjust_pending() now sets it when called
with null params, which resets DRR in the OTG during pipe back-end
teardown, and the max_v_total overflow path only clears it when
set_long_vtotal() runs.
Reviewed-by: Josip Pavic <josip.pavic@amd.com>
Signed-off-by: Aric Cyr <Aric.Cyr@amd.com>
Signed-off-by: Roman Li <roman.li@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
| -rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc.c | 24 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c | 3 |
2 files changed, 22 insertions, 5 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 878856ee1dfe..4e3f04530013 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1341,6 +1341,7 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc, struct dc_crtc_timing_adjust *adjust) { int i; + bool drr_unchanged; /* * Don't adjust DRR while there's bandwidth optimizations pending to @@ -1355,6 +1356,19 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc, } } + /* timing_adjust_pending tracks whether stream->adjust still describes the + * OTG, so a cleared flag plus matching values means hw is already current. + */ + drr_unchanged = !stream->adjust.timing_adjust_pending && + stream->adjust.v_total_min == adjust->v_total_min && + stream->adjust.v_total_max == adjust->v_total_max && + stream->adjust.v_total_mid == adjust->v_total_mid && + stream->adjust.v_total_mid_frame_num == adjust->v_total_mid_frame_num && + stream->adjust.allow_otg_v_count_halt == adjust->allow_otg_v_count_halt; + + if (drr_unchanged) + return true; + dc_exit_ips_for_hw_access(dc); stream->adjust.v_total_max = adjust->v_total_max; @@ -1365,11 +1379,13 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc, if (dc->caps.max_v_total != 0 && (adjust->v_total_max > dc->caps.max_v_total || adjust->v_total_min > dc->caps.max_v_total)) { - stream->adjust.timing_adjust_pending = false; - if (adjust->allow_otg_v_count_halt) + if (adjust->allow_otg_v_count_halt) { + stream->adjust.timing_adjust_pending = false; return set_long_vtotal(dc, stream, adjust); - else - return false; + } + /* Nothing reached hw, so stream->adjust no longer describes the OTG. */ + stream->adjust.timing_adjust_pending = true; + return false; } for (i = 0; i < MAX_PIPES; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index 21a62ca4c8dc..3d88c5c377fc 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -716,7 +716,8 @@ void set_drr_and_clear_adjust_pending( pipe_ctx->stream_res.tg, params); if (stream) - stream->adjust.timing_adjust_pending = false; + /* A null params resets DRR in hw, leaving stream->adjust stale. */ + stream->adjust.timing_adjust_pending = (params == NULL); } void get_fams2_visual_confirm_color( |
