drm/amd/display: add seamless pipe topology transition check
authorWenjing Liu <wenjing.liu@amd.com>
Thu, 24 Aug 2023 21:08:48 +0000 (17:08 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 11 Sep 2023 21:18:23 +0000 (17:18 -0400)
[why]
We have a few cases where we need to perform update topology update
in dc update interface. However some of the updates are not seamless
This could cause user noticible glitches. To enforce seamless transition
we are adding a checking condition and error logging so the corruption
as result of non seamless transition can be easily spotted.

Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Acked-by: Stylon Wang <stylon.wang@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c
drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h

index 0320bc49458c07db3d24d33ad4921c3a8021c898..fcba9ae6e0f21d3e6d390bed49183b0c7994afde 100644 (file)
@@ -4363,6 +4363,14 @@ bool dc_update_planes_and_stream(struct dc *dc,
                                update_type,
                                context);
        } else {
+               if (!stream_update &&
+                               dc->hwss.is_pipe_topology_transition_seamless &&
+                               !dc->hwss.is_pipe_topology_transition_seamless(
+                                               dc, dc->current_state, context)) {
+
+                       DC_LOG_ERROR("performing non-seamless pipe topology transition with surface only update!\n");
+                       BREAK_TO_DEBUGGER();
+               }
                commit_planes_for_stream(
                                dc,
                                srf_updates,
index cae5e1e68c860eeba5604df2448159a37c19c902..018376146d977236cdc55ae334a7c7aaa3dd0c0d 100644 (file)
@@ -1619,3 +1619,55 @@ void dcn32_blank_phantom(struct dc *dc,
        if (tg->funcs->is_tg_enabled(tg))
                hws->funcs.wait_for_blank_complete(opp);
 }
+
+bool dcn32_is_pipe_topology_transition_seamless(struct dc *dc,
+               const struct dc_state *cur_ctx,
+               const struct dc_state *new_ctx)
+{
+       int i;
+       const struct pipe_ctx *cur_pipe, *new_pipe;
+       bool is_seamless = true;
+
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               cur_pipe = &cur_ctx->res_ctx.pipe_ctx[i];
+               new_pipe = &new_ctx->res_ctx.pipe_ctx[i];
+
+               if (resource_is_pipe_type(cur_pipe, FREE_PIPE) ||
+                               resource_is_pipe_type(new_pipe, FREE_PIPE))
+                       /* adding or removing free pipes is always seamless */
+                       continue;
+               else if (resource_is_pipe_type(cur_pipe, OTG_MASTER)) {
+                       if (resource_is_pipe_type(new_pipe, OTG_MASTER))
+                               if (cur_pipe->stream->stream_id == new_pipe->stream->stream_id)
+                               /* OTG master with the same stream is seamless */
+                                       continue;
+               } else if (resource_is_pipe_type(cur_pipe, OPP_HEAD)) {
+                       if (resource_is_pipe_type(new_pipe, OPP_HEAD)) {
+                               if (cur_pipe->stream_res.tg == new_pipe->stream_res.tg)
+                                       /*
+                                        * OPP heads sharing the same timing
+                                        * generator is seamless
+                                        */
+                                       continue;
+                       }
+               } else if (resource_is_pipe_type(cur_pipe, DPP_PIPE)) {
+                       if (resource_is_pipe_type(new_pipe, DPP_PIPE)) {
+                               if (cur_pipe->stream_res.opp == new_pipe->stream_res.opp)
+                                       /*
+                                        * DPP pipes sharing the same OPP head is
+                                        * seamless
+                                        */
+                                       continue;
+                       }
+               }
+
+               /*
+                * This pipe's transition doesn't fall under any seamless
+                * conditions
+                */
+               is_seamless = false;
+               break;
+       }
+
+       return is_seamless;
+}
index 616d5219119e998fb2472f1f3433bcd140517a89..9992e40acd217b9ad224d892f7ae6ff16f81a231 100644 (file)
@@ -120,4 +120,8 @@ void dcn32_blank_phantom(struct dc *dc,
                int width,
                int height);
 
+bool dcn32_is_pipe_topology_transition_seamless(struct dc *dc,
+               const struct dc_state *cur_ctx,
+               const struct dc_state *new_ctx);
+
 #endif /* __DC_HWSS_DCN32_H__ */
index eb4227926006a41a6f8d3d80351bac4fa1a3b14f..1edadff39a5eff9115c2706c8cab4aa8cf9764df 100644 (file)
@@ -116,6 +116,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
        .update_dsc_pg = dcn32_update_dsc_pg,
        .apply_update_flags_for_phantom = dcn32_apply_update_flags_for_phantom,
        .blank_phantom = dcn32_blank_phantom,
+       .is_pipe_topology_transition_seamless = dcn32_is_pipe_topology_transition_seamless,
 };
 
 static const struct hwseq_private_funcs dcn32_private_funcs = {
index 1ccdb73598949c3b3a58833b71d9e62d69b8a2de..e0dd56182841269d09d87befc1368c3cb51d2412 100644 (file)
@@ -410,6 +410,9 @@ struct hw_sequencer_funcs {
                        struct dc_state *context,
                        struct pipe_ctx *phantom_pipe);
        void (*apply_update_flags_for_phantom)(struct pipe_ctx *phantom_pipe);
+       bool (*is_pipe_topology_transition_seamless)(struct dc *dc,
+                       const struct dc_state *cur_ctx,
+                       const struct dc_state *new_ctx);
 
        void (*calc_blocks_to_gate)(struct dc *dc, struct dc_state *context,
                struct pg_block_update *update_state);