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 3a6e3a0..1733f55 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 079c226..b5e82e1 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 ad253c5..1797a91 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 5cbae0c..9834d30 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 33cc48c..a570333 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 e56b9a4..b14e6e6 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 9900c87..d782080 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 849dae1..c68b201 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 5d0dfb3..0908a79 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 0d5a835..7f371cb 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 a880e4a..62f45c1 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 ed66a2b..a3431ec 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);
 }
-