From: Wenjing Liu <wenjing.liu@xxxxxxx> Given an issue with pipe topology transition. It is very hard to tell the before and after pipe topology without a pipe topology logging. The change adds such logging to help with visualizing the issue. Reviewed-by: Jun Lei <jun.lei@xxxxxxx> Acked-by: Hamza Mahfooz <hamza.mahfooz@xxxxxxx> Signed-off-by: Wenjing Liu <wenjing.liu@xxxxxxx> --- .../gpu/drm/amd/display/dc/core/dc_resource.c | 159 ++++++++++++++++++ .../drm/amd/display/dc/dcn20/dcn20_hwseq.c | 10 +- drivers/gpu/drm/amd/display/dc/inc/resource.h | 7 + 3 files changed, 168 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 84db7c5fb852..f32337122f5b 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1865,6 +1865,165 @@ int resource_get_odm_slice_index(const struct pipe_ctx *pipe_ctx) return index; } +bool resource_is_pipe_topology_changed(const struct dc_state *state_a, + const struct dc_state *state_b) +{ + int i; + const struct pipe_ctx *pipe_a, *pipe_b; + + if (state_a->stream_count != state_b->stream_count) + return true; + + for (i = 0; i < MAX_PIPES; i++) { + pipe_a = &state_a->res_ctx.pipe_ctx[i]; + pipe_b = &state_b->res_ctx.pipe_ctx[i]; + + if (pipe_a->stream && !pipe_b->stream) + return true; + else if (!pipe_a->stream && pipe_b->stream) + return true; + + if (pipe_a->plane_state && !pipe_b->plane_state) + return true; + else if (!pipe_a->plane_state && pipe_b->plane_state) + return true; + + if (pipe_a->bottom_pipe && pipe_b->bottom_pipe) { + if (pipe_a->bottom_pipe->pipe_idx != pipe_b->bottom_pipe->pipe_idx) + return true; + if ((pipe_a->bottom_pipe->plane_state == pipe_a->plane_state) && + (pipe_b->bottom_pipe->plane_state != pipe_b->plane_state)) + return true; + else if ((pipe_a->bottom_pipe->plane_state != pipe_a->plane_state) && + (pipe_b->bottom_pipe->plane_state == pipe_b->plane_state)) + return true; + } else if (pipe_a->bottom_pipe || pipe_b->bottom_pipe) { + return true; + } + + if (pipe_a->next_odm_pipe && pipe_b->next_odm_pipe) { + if (pipe_a->next_odm_pipe->pipe_idx != pipe_b->next_odm_pipe->pipe_idx) + return true; + } else if (pipe_a->next_odm_pipe || pipe_b->next_odm_pipe) { + return true; + } + } + return false; +} + +/* + * Sample log: + * pipe topology update + * ________________________ + * | plane0 slice0 stream0| + * |DPP0----OPP0----OTG0----| <--- case 0 (OTG master pipe with plane) + * | plane1 | | | + * |DPP1----| | | <--- case 5 (DPP pipe not in last slice) + * | plane0 slice1 | | + * |DPP2----OPP2----| | <--- case 2 (OPP head pipe with plane) + * | plane1 | | + * |DPP3----| | <--- case 4 (DPP pipe in last slice) + * | slice0 stream1| + * |DPG4----OPP4----OTG4----| <--- case 1 (OTG master pipe without plane) + * | slice1 | | + * |DPG5----OPP5----| | <--- case 3 (OPP head pipe without plane) + * |________________________| + */ + +static void resource_log_pipe(struct dc *dc, struct pipe_ctx *pipe, + int stream_idx, int slice_idx, int plane_idx, int slice_count, + bool is_primary) +{ + DC_LOGGER_INIT(dc->ctx->logger); + + if (slice_idx == 0 && plane_idx == 0 && is_primary) { + /* case 0 (OTG master pipe with plane) */ + DC_LOG_DC(" | plane%d slice%d stream%d|", + plane_idx, slice_idx, stream_idx); + DC_LOG_DC(" |DPP%d----OPP%d----OTG%d----|", + pipe->plane_res.dpp->inst, + pipe->stream_res.opp->inst, + pipe->stream_res.tg->inst); + } else if (slice_idx == 0 && plane_idx == -1) { + /* case 1 (OTG master pipe without plane) */ + DC_LOG_DC(" | slice%d stream%d|", + slice_idx, stream_idx); + DC_LOG_DC(" |DPG%d----OPP%d----OTG%d----|", + pipe->stream_res.opp->inst, + pipe->stream_res.opp->inst, + pipe->stream_res.tg->inst); + } else if (slice_idx != 0 && plane_idx == 0 && is_primary) { + /* case 2 (OPP head pipe with plane) */ + DC_LOG_DC(" | plane%d slice%d | |", + plane_idx, slice_idx); + DC_LOG_DC(" |DPP%d----OPP%d----| |", + pipe->plane_res.dpp->inst, + pipe->stream_res.opp->inst); + } else if (slice_idx != 0 && plane_idx == -1) { + /* case 3 (OPP head pipe without plane) */ + DC_LOG_DC(" | slice%d | |", slice_idx); + DC_LOG_DC(" |DPG%d----OPP%d----| |", + pipe->plane_res.dpp->inst, + pipe->stream_res.opp->inst); + } else if (slice_idx == slice_count - 1) { + /* case 4 (DPP pipe in last slice) */ + DC_LOG_DC(" | plane%d | |", plane_idx); + DC_LOG_DC(" |DPP%d----| |", + pipe->plane_res.dpp->inst); + } else { + /* case 5 (DPP pipe not in last slice) */ + DC_LOG_DC(" | plane%d | | |", plane_idx); + DC_LOG_DC(" |DPP%d----| | |", + pipe->plane_res.dpp->inst); + } +} + +void resource_log_pipe_topology_update(struct dc *dc, struct dc_state *state) +{ + struct pipe_ctx *otg_master; + struct pipe_ctx *opp_heads[MAX_PIPES]; + struct pipe_ctx *dpp_pipes[MAX_PIPES]; + + int stream_idx, slice_idx, dpp_idx, plane_idx, slice_count, dpp_count; + bool is_primary; + DC_LOGGER_INIT(dc->ctx->logger); + + DC_LOG_DC(" pipe topology update"); + DC_LOG_DC(" ________________________"); + for (stream_idx = 0; stream_idx < state->stream_count; stream_idx++) { + otg_master = resource_get_otg_master_for_stream( + &state->res_ctx, state->streams[stream_idx]); + slice_count = resource_get_opp_heads_for_otg_master(otg_master, + &state->res_ctx, opp_heads); + for (slice_idx = 0; slice_idx < slice_count; slice_idx++) { + if (opp_heads[slice_idx]->plane_state) { + plane_idx = 0; + dpp_count = resource_get_dpp_pipes_for_opp_head( + opp_heads[slice_idx], + &state->res_ctx, + dpp_pipes); + for (dpp_idx = 0; dpp_idx < dpp_count; dpp_idx++) { + is_primary = !dpp_pipes[dpp_idx]->top_pipe || + dpp_pipes[dpp_idx]->top_pipe->plane_state != dpp_pipes[dpp_idx]->plane_state; + resource_log_pipe(dc, dpp_pipes[dpp_idx], + stream_idx, slice_idx, + plane_idx, slice_count, + is_primary); + if (is_primary) + plane_idx++; + } + } else { + plane_idx = -1; + resource_log_pipe(dc, opp_heads[slice_idx], + stream_idx, slice_idx, plane_idx, + slice_count, true); + } + + } + } + DC_LOG_DC(" |________________________|\n"); +} + static struct pipe_ctx *get_tail_pipe( struct pipe_ctx *head_pipe) { diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 347156d02f21..dd4c7a7faf28 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -1816,14 +1816,8 @@ void dcn20_program_front_end_for_ctx( struct dce_hwseq *hws = dc->hwseq; DC_LOGGER_INIT(dc->ctx->logger); - /* Carry over GSL groups in case the context is changing. */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream == old_pipe_ctx->stream) - pipe_ctx->stream_res.gsl_group = old_pipe_ctx->stream_res.gsl_group; - } + if (resource_is_pipe_topology_changed(dc->current_state, context)) + resource_log_pipe_topology_update(dc, context); if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) { for (i = 0; i < dc->res_pool->pipe_count; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index 55efd5600521..6777b07d0727 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -437,6 +437,13 @@ int resource_get_odm_slice_count(const struct pipe_ctx *otg_master); /* Get the ODM slice index counting from 0 from left most slice */ int resource_get_odm_slice_index(const struct pipe_ctx *opp_head); +/* determine if pipe topology is changed between state a and state b */ +bool resource_is_pipe_topology_changed(const struct dc_state *state_a, + const struct dc_state *state_b); + +/* log the pipe topology update in state */ +void resource_log_pipe_topology_update(struct dc *dc, struct dc_state *state); + /* * Look for a free pipe in new resource context that is used as a secondary OPP * head by cur_otg_master. -- 2.41.0