]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/amd/display: Enable additional wait for pipe pending checks
authorAric Cyr <Aric.Cyr@amd.com>
Tue, 5 May 2026 20:49:47 +0000 (16:49 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 19 May 2026 15:45:40 +0000 (11:45 -0400)
[why]
In cases where there are two FULL updates within the same display frame,
it's possible for some blocks to be programmed a second time without having
been latched completely from the first programming.

DCN 3.5 and up already work around this with additional validation checks
for frame count and defer as needed via fsleep.

[how]
Enabled existing pipe checks generically for all DCN versions to avoid HW
programming hazards.

Also removed redundant max_frame_count which can be determined by the
register mask and shift.

Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Aric Cyr <Aric.Cyr@amd.com>
Signed-off-by: Ivan Lipski <ivan.lipski@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
12 files changed:
drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
drivers/gpu/drm/amd/display/dc/inc/hw/optc.h
drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c

index 3a6e3a0d18b015101b6e8c6fabe5e905a959e8ad..1733f551248e441842905c8dca7c5499ee2d2010 100644 (file)
@@ -181,6 +181,7 @@ void dcn10_set_wait_for_update_needed_for_pipe(struct dc *dc, struct pipe_ctx *p
        uint32_t vupdate_start, vupdate_end;
        struct crtc_position position;
        unsigned int vpos, cur_frame;
+       uint32_t max_frame_count;
 
        if (!pipe_ctx->stream ||
                !pipe_ctx->stream_res.tg ||
@@ -197,7 +198,8 @@ void dcn10_set_wait_for_update_needed_for_pipe(struct dc *dc, struct pipe_ctx *p
 
        struct optc *optc1 = DCN10TG_FROM_TG(tg);
 
-       ASSERT(optc1->max_frame_count != 0);
+       max_frame_count = optc1->tg_mask->OTG_FRAME_COUNT >> optc1->tg_shift->OTG_FRAME_COUNT;
+       ASSERT(max_frame_count != 0);
 
        if (tg->funcs->is_tg_enabled && !tg->funcs->is_tg_enabled(tg))
                return;
@@ -209,8 +211,8 @@ void dcn10_set_wait_for_update_needed_for_pipe(struct dc *dc, struct pipe_ctx *p
        if (vpos < vupdate_start) {
                pipe_ctx->wait_frame_count = cur_frame;
        } else {
-               if (cur_frame + 1 > optc1->max_frame_count)
-                       pipe_ctx->wait_frame_count = cur_frame + 1 - optc1->max_frame_count;
+               if (cur_frame + 1 > max_frame_count)
+                       pipe_ctx->wait_frame_count = cur_frame + 1 - max_frame_count;
                else
                        pipe_ctx->wait_frame_count = cur_frame + 1;
        }
index 079c226c1097ff0f0c21ccf69d89261431cc519b..b5e82e19012474d22a48038bd02cceed5e9405b1 100644 (file)
@@ -118,6 +118,8 @@ static const struct hwseq_private_funcs dcn10_private_funcs = {
        .dsc_pg_control = NULL,
        .set_hdr_multiplier = dcn10_set_hdr_multiplier,
        .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high,
+       .wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
+       .set_wait_for_update_needed_for_pipe = dcn10_set_wait_for_update_needed_for_pipe,
 };
 
 void dcn10_hw_sequencer_construct(struct dc *dc)
index ad253c586ea1ac78649b14e5aa69ca40e6c3f05c..1797a91b0186eb65dbd7deadde43612d70149b93 100644 (file)
@@ -136,6 +136,8 @@ static const struct hwseq_private_funcs dcn20_private_funcs = {
        .dccg_init = dcn20_dccg_init,
        .set_blend_lut = dcn20_set_blend_lut,
        .set_shaper_3dlut = dcn20_set_shaper_3dlut,
+       .wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
+       .set_wait_for_update_needed_for_pipe = dcn10_set_wait_for_update_needed_for_pipe,
 };
 
 void dcn20_hw_sequencer_construct(struct dc *dc)
index 5cbae0cdda9627d1fd8ff3d43f6514482ba34874..9834d30754878157f10e196c3086c9984ddb9f79 100644 (file)
@@ -145,6 +145,8 @@ static const struct hwseq_private_funcs dcn30_private_funcs = {
        .wait_for_blank_complete = dcn20_wait_for_blank_complete,
        .set_blend_lut = dcn30_set_blend_lut,
        .set_shaper_3dlut = dcn20_set_shaper_3dlut,
+       .wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
+       .set_wait_for_update_needed_for_pipe = dcn10_set_wait_for_update_needed_for_pipe,
 };
 
 void dcn30_hw_sequencer_construct(struct dc *dc)
index 33cc48cd01962d1182e0f806661675d649974525..a570333aeac1863be90067784e6057aef2ef06d4 100644 (file)
@@ -142,6 +142,8 @@ static const struct hwseq_private_funcs dcn301_private_funcs = {
        .wait_for_blank_complete = dcn20_wait_for_blank_complete,
        .set_blend_lut = dcn30_set_blend_lut,
        .set_shaper_3dlut = dcn20_set_shaper_3dlut,
+       .wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
+       .set_wait_for_update_needed_for_pipe = dcn10_set_wait_for_update_needed_for_pipe,
 };
 
 void dcn301_hw_sequencer_construct(struct dc *dc)
index e56b9a46aecfe125d28e030f0f7ba7e0f9711bed..b14e6e60b8786ab9dcead5aa38a8b9465a3b4394 100644 (file)
@@ -147,6 +147,8 @@ static const struct hwseq_private_funcs dcn31_private_funcs = {
        .set_blend_lut = dcn30_set_blend_lut,
        .set_shaper_3dlut = dcn20_set_shaper_3dlut,
        .setup_hpo_hw_control = dcn31_setup_hpo_hw_control,
+       .wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
+       .set_wait_for_update_needed_for_pipe = dcn10_set_wait_for_update_needed_for_pipe,
 };
 
 void dcn31_hw_sequencer_construct(struct dc *dc)
index 9900c87b4567f5250b7936785b882fd96e5934f8..d782080883ab783f68f2e0c69bb08c9b521b7ebf 100644 (file)
@@ -154,6 +154,8 @@ static const struct hwseq_private_funcs dcn314_private_funcs = {
        .setup_hpo_hw_control = dcn31_setup_hpo_hw_control,
        .calculate_dccg_k1_k2_values = dcn314_calculate_dccg_k1_k2_values,
        .resync_fifo_dccg_dio = dcn314_resync_fifo_dccg_dio,
+       .wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
+       .set_wait_for_update_needed_for_pipe = dcn10_set_wait_for_update_needed_for_pipe,
 };
 
 void dcn314_hw_sequencer_construct(struct dc *dc)
index 849dae18b7384a4b09cc1e43fce0c6d658bf10f8..c68b2010477324576c62d630420d0b1962185d66 100644 (file)
@@ -163,6 +163,8 @@ static const struct hwseq_private_funcs dcn32_private_funcs = {
        .is_dp_dig_pixel_rate_div_policy = dcn32_is_dp_dig_pixel_rate_div_policy,
        .apply_single_controller_ctx_to_hw = dce110_apply_single_controller_ctx_to_hw,
        .reset_back_end_for_pipe = dcn20_reset_back_end_for_pipe,
+       .wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
+       .set_wait_for_update_needed_for_pipe = dcn10_set_wait_for_update_needed_for_pipe,
 };
 
 void dcn32_hw_sequencer_init_functions(struct dc *dc)
index 5d0dfb36f3e1bcddb4e137e96bf53d814c6d929b..0908a791832baf077ea2e2ad64bf70028a319972 100644 (file)
@@ -167,6 +167,8 @@ static const struct hwseq_private_funcs dcn401_private_funcs = {
        .perform_3dlut_wa_unlock = dcn401_perform_3dlut_wa_unlock,
        .program_pipe_sequence = dcn401_program_pipe_sequence,
        .dc_ip_request_cntl = dcn401_dc_ip_request_cntl,
+       .wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
+       .set_wait_for_update_needed_for_pipe = dcn10_set_wait_for_update_needed_for_pipe,
 };
 
 void dcn401_hw_sequencer_init_functions(struct dc *dc)
index 0d5a8358a778070d909eee8b1326e1666ae133ad..7f371cbb35cdef1c5ef5443af03d1e162904191e 100644 (file)
@@ -68,7 +68,6 @@ struct optc {
        int pstate_keepout;
        struct dc_crtc_timing orginal_patched_timing;
        enum signal_type signal;
-       uint32_t max_frame_count;
 };
 
 void optc1_read_otg_state(struct timing_generator *optc, struct dcn_otg_state *s);
index a880e4a6d1659830a3c33382fafc6af36e86d74c..62f45c156c32590df1dfdb42858c54b6fa7e6ed9 100644 (file)
@@ -621,7 +621,6 @@ void dcn35_timing_generator_init(struct optc *optc1)
        optc1->min_v_blank_interlace = 5;
        optc1->min_h_sync_width = 4;
        optc1->min_v_sync_width = 1;
-       optc1->max_frame_count = 0xFFFFFF;
 
        dcn35_timing_generator_set_fgcg(
                optc1, CTX->dc->debug.enable_fine_grain_clock_gating.bits.optc);
index ed66a2bbb8aebd8f6f3424bd9136a3a496b05c9c..a3431ec2f058362e47546c42c870901d2d1ad665 100644 (file)
@@ -283,9 +283,7 @@ void dcn42_timing_generator_init(struct optc *optc1)
        optc1->min_v_blank_interlace = 5;
        optc1->min_h_sync_width = 4;
        optc1->min_v_sync_width = 1;
-       optc1->max_frame_count = 0xFFFFFF;
 
        dcn35_timing_generator_set_fgcg(
                optc1, CTX->dc->debug.enable_fine_grain_clock_gating.bits.optc);
 }
-