]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Nov 2023 17:14:44 +0000 (17:14 +0000)
[ Upstream commit 15c6798ae26d5c7a7776f4f7d0c1fa8c462688a2 ]

[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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
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 ab79bcd264164b9a514d3fcd94f493d3787b58d9..93e6265e585096b5bedad1565dc2b56896926ad7 100644 (file)
@@ -4414,6 +4414,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 b6608d7ab44509bb29c23267d57373871ae694d5..5b3d0e5b90a3e2b0c2232402362d70c3554a4ad6 100644 (file)
@@ -1621,3 +1621,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 279f312f74076351fb97b0d34ed4485448e3a33f..12e0f48a13e48574d678203ace3d4692940e4201 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 7a702e216e530f057ae75fee62d31a3515d3f57e..66e680902c95c797fffe81929f4540ae9f4b1deb 100644 (file)
@@ -401,6 +401,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 (*commit_subvp_config)(struct dc *dc, struct dc_state *context);
        void (*enable_phantom_streams)(struct dc *dc, struct dc_state *context);