drm/amd/display: Enable additional wait for pipe pending checks

[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>
This commit is contained in:
Aric Cyr 2026-05-05 16:49:47 -04:00 committed by Alex Deucher
parent 2f28f0063a
commit e91130c016
12 changed files with 21 additions and 7 deletions

View 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;
}

View 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)

View 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)

View 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)

View 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)

View 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)

View 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)

View 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)

View 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)

View 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);

View 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);

View 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);
}