From: Aric Cyr <[email protected]>

[Why]
dc_stream_adjust_vmin_vmax() short circuits when the requested v_totals
match stream->adjust and nothing is pending. A display that is not
driving DRR requests a constant v_total, so that short circuit is
permanent once hardware stops matching - and init_hw() resets the OTG
DRR registers and the static screen trigger mask. The commit that
follows need not restore them either: apply_ctx_to_hw() skips
enable_stream_timing() when pipe_need_reprogram() considers the pipe
unchanged, and dc_commit_streams() can skip the commit entirely on
!streams_changed(). Panel replay never sees a static screen trigger
again.

timing_adjust_pending should cover this, but it lives inside struct
dc_crtc_timing_adjust, which is copied and compared by value.
hwss.set_drr() takes it by value, and copy_stream_update_to_stream()
wrote the flag back into the caller's struct.

[How]
Move timing_adjust_pending into struct dc_stream_state so a
dc_crtc_timing_adjust is pure request data, safe to copy and compare.

Add program_pending_drr_adjust() to settle any stream still carrying a
pending adjustment at the end of a commit, so a commit always leaves
stream->adjust describing the OTG. It is a no-op when nothing is
pending.

Reviewed-by: Josip Pavic <[email protected]>
Signed-off-by: Aric Cyr <[email protected]>
Signed-off-by: Ray Wu <[email protected]>
---
 .../display/amdgpu_dm/amdgpu_dm_freesync.c    |  2 +-
 .../amdgpu_dm/tests/amdgpu_dm_freesync_test.c |  4 +-
 drivers/gpu/drm/amd/display/dc/core/dc.c      | 51 +++++++++++++++----
 .../drm/amd/display/dc/core/dc_hw_sequencer.c |  2 +-
 drivers/gpu/drm/amd/display/dc/dc_hw_types.h  |  1 -
 drivers/gpu/drm/amd/display/dc/dc_stream.h    |  3 ++
 6 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
index b65af2cc1fb7..49c6048d0cc9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
@@ -42,7 +42,7 @@
 bool amdgpu_dm_is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
                                          struct dm_crtc_state *new_state)
 {
-       if (new_state->stream->adjust.timing_adjust_pending)
+       if (new_state->stream->timing_adjust_pending)
                return true;
        if (new_state->freesync_config.state ==  VRR_STATE_ACTIVE_FIXED)
                return true;
diff --git 
a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c
index 547a543b9f5d..85670e1cbb05 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c
@@ -173,7 +173,7 @@ static void dm_test_dc_timing_adjust_pending(struct kunit 
*test)
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
 
        new_state->stream = stream;
-       stream->adjust.timing_adjust_pending = 1;
+       stream->timing_adjust_pending = 1;
 
        KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_dc_timing_adjust_needed(old_state, 
new_state));
 }
@@ -592,7 +592,7 @@ static void 
dm_test_update_freesync_state_pre_ai_active(struct kunit *test)
 
        amdgpu_dm_update_freesync_state_on_stream(&adev->dm, &crtc_state, 
stream, surface, 0);
 
-       KUNIT_EXPECT_FALSE(test, stream->adjust.timing_adjust_pending);
+       KUNIT_EXPECT_FALSE(test, stream->timing_adjust_pending);
 }
 
 static void dm_test_update_freesync_state_pcon_version(struct kunit *test, u8 
version)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c 
b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 8cf6edbd39c9..f84f659c101b 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -458,7 +458,34 @@ static void invalidate_drr_adjust(struct dc *dc)
 
        for (i = 0; i < dc->current_state->stream_count; i++)
                if (dc->current_state->streams[i])
-                       
dc->current_state->streams[i]->adjust.timing_adjust_pending = true;
+                       dc->current_state->streams[i]->timing_adjust_pending = 
true;
+}
+
+/* apply_ctx_to_hw() skips controller programming for a pipe it considers 
unchanged, so a
+ * commit on its own does not guarantee the OTG matches stream->adjust. Settle 
anything
+ * still outstanding here - dc_stream_adjust_vmin_vmax() cannot, because it 
short circuits
+ * when the requested v_totals are unchanged, which is permanent for a stream 
that is not
+ * driving DRR.
+ */
+static void program_pending_drr_adjust(struct dc *dc, struct dc_state *context)
+{
+       int i;
+
+       if (!dc->hwss.set_drr)
+               return;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+
+               if (!resource_is_pipe_type(pipe, OTG_MASTER) || 
!pipe->stream_res.tg)
+                       continue;
+
+               if (!pipe->stream->timing_adjust_pending)
+                       continue;
+
+               dc_exit_ips_for_hw_access(dc);
+               dc->hwss.set_drr(&pipe, 1, pipe->stream->adjust);
+       }
 }
 
 /**
@@ -1370,7 +1397,7 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
                if (dc->optimized_required &&
                        (stream->adjust.v_total_max != adjust->v_total_max ||
                        stream->adjust.v_total_min != adjust->v_total_min)) {
-                       stream->adjust.timing_adjust_pending = true;
+                       stream->timing_adjust_pending = true;
                        return false;
                }
        }
@@ -1378,7 +1405,7 @@ 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 &&
+       drr_unchanged = !stream->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 &&
@@ -1402,13 +1429,13 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
        stream->adjust.v_total_min = adjust->v_total_min;
        stream->adjust.allow_otg_v_count_halt = adjust->allow_otg_v_count_halt;
        /* Only cleared once the new values have actually reached an OTG. */
-       stream->adjust.timing_adjust_pending = true;
+       stream->timing_adjust_pending = true;
 
        if (exceeds_max_v_total) {
                if (!set_long_vtotal(dc, stream, adjust))
                        return false;
 
-               stream->adjust.timing_adjust_pending = false;
+               stream->timing_adjust_pending = false;
                return true;
        }
 
@@ -1419,7 +1446,7 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
                        dc->hwss.set_drr(&pipe,
                                        1,
                                        *adjust);
-                       stream->adjust.timing_adjust_pending = false;
+                       stream->timing_adjust_pending = false;
 
                        if (dc->debug.visual_confirm == 
VISUAL_CONFIRM_BOOSTED_REFRESH_RATE) {
                                if (pipe->stream && pipe->plane_state) {
@@ -2422,6 +2449,8 @@ static enum dc_status dc_commit_state_no_check(struct dc 
*dc, struct dc_state *c
                return result;
        }
 
+       program_pending_drr_adjust(dc, context);
+
        dc_trigger_sync(dc, context);
 
        /* Full update should unconditionally be triggered when 
dc_commit_state_no_check is called */
@@ -2578,8 +2607,10 @@ enum dc_status dc_commit_streams(struct dc *dc, struct 
dc_commit_streams_params
                return res;
 
        if (!streams_changed(dc, params->streams, params->stream_count) &&
-                       dc->current_state->power_source == params->power_source)
+                       dc->current_state->power_source == 
params->power_source) {
+               program_pending_drr_adjust(dc, dc->current_state);
                return res;
+       }
 
        dc_exit_ips_for_hw_access(dc);
 
@@ -3604,11 +3635,9 @@ static void copy_stream_update_to_stream(struct dc *dc,
 
        if (update->crtc_timing_adjust) {
                if (stream->adjust.v_total_min != 
update->crtc_timing_adjust->v_total_min ||
-                       stream->adjust.v_total_max != 
update->crtc_timing_adjust->v_total_max ||
-                       stream->adjust.timing_adjust_pending)
-                       update->crtc_timing_adjust->timing_adjust_pending = 
true;
+                       stream->adjust.v_total_max != 
update->crtc_timing_adjust->v_total_max)
+                       stream->timing_adjust_pending = true;
                stream->adjust = *update->crtc_timing_adjust;
-               update->crtc_timing_adjust->timing_adjust_pending = false;
        }
 
        if (update->dpms_off)
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 86957b4d182a..415ad6ddb740 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
@@ -756,7 +756,7 @@ void set_drr_and_clear_adjust_pending(
 
        if (stream)
                /* A null params resets DRR in hw, leaving stream->adjust 
stale. */
-               stream->adjust.timing_adjust_pending = (params == NULL);
+               stream->timing_adjust_pending = (params == NULL);
 }
 
 void get_fams2_visual_confirm_color(
diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h 
b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
index baf6091bb52d..eb9effb22658 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
@@ -1083,7 +1083,6 @@ struct dc_crtc_timing_adjust {
        uint32_t v_total_mid;
        uint32_t v_total_mid_frame_num;
        uint32_t allow_otg_v_count_halt;
-       uint8_t timing_adjust_pending;
 };
 
 struct dtbclk_dto_params {
diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h 
b/drivers/gpu/drm/amd/display/dc/dc_stream.h
index fec5e7a84bb9..7999a7d84a77 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
@@ -336,6 +336,9 @@ struct dc_stream_state {
        enum dc_blending_linearity blending_linearity;
        struct dc_update_scratch_space *update_scratch;
        bool firmware_controlled_hdr_info_packet;
+
+       /* timing adjust has not been propagated to hardware yet. */
+       bool timing_adjust_pending;
 };
 
 #define ABM_LEVEL_IMMEDIATE_DISABLE 255
-- 
2.43.0

Reply via email to