drm/amd/display: add preferred pipe split logic
authorJun Lei <Jun.Lei@amd.com>
Tue, 12 Mar 2019 19:12:41 +0000 (15:12 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 28 Mar 2019 03:41:17 +0000 (22:41 -0500)
[why]
existing logic finds "first free pipe from 5 -> 0" to split
this will cause certain sequences to require DC to move
an MPCC from one tree to another, which is unsupported
this leads to blackscreen

to mitigate this problem, we will always try to acquire the
"preferred" pipe, and each pipe has a unique preferred pipe
this means we avoid most of the scenarios where
pipe splitting leads to moving MPCC from one tree
to another

Signed-off-by: Jun Lei <Jun.Lei@amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
drivers/gpu/drm/amd/display/dc/inc/resource.h

index 0090f7491446b07a064ae051f034ecf19b8b4bcc..5476b7a552363ac69197877599041126fed73783 100644 (file)
@@ -1141,7 +1141,7 @@ bool dcn_validate_bandwidth(
                                                hsplit_pipe->pipe_dlg_param.vblank_end = pipe->pipe_dlg_param.vblank_end;
                                        } else {
                                                /* pipe not split previously needs split */
-                                               hsplit_pipe = find_idle_secondary_pipe(&context->res_ctx, pool);
+                                               hsplit_pipe = find_idle_secondary_pipe(&context->res_ctx, pool, pipe);
                                                ASSERT(hsplit_pipe);
                                                split_stream_across_pipes(
                                                        &context->res_ctx, pool,
index 374ce43096ac5436ca61253e52c168d50cd1df40..4a651d7dd0522c9487543e973cbbe82aa81fca9c 100644 (file)
@@ -1038,24 +1038,60 @@ enum dc_status resource_build_scaling_params_for_context(
 
 struct pipe_ctx *find_idle_secondary_pipe(
                struct resource_context *res_ctx,
-               const struct resource_pool *pool)
+               const struct resource_pool *pool,
+               const struct pipe_ctx *primary_pipe)
 {
        int i;
        struct pipe_ctx *secondary_pipe = NULL;
 
        /*
-        * search backwards for the second pipe to keep pipe
-        * assignment more consistent
+        * We add a preferred pipe mapping to avoid the chance that
+        * MPCCs already in use will need to be reassigned to other trees.
+        * For example, if we went with the strict, assign backwards logic:
+        *
+        * (State 1)
+        * Display A on, no surface, top pipe = 0
+        * Display B on, no surface, top pipe = 1
+        *
+        * (State 2)
+        * Display A on, no surface, top pipe = 0
+        * Display B on, surface enable, top pipe = 1, bottom pipe = 5
+        *
+        * (State 3)
+        * Display A on, surface enable, top pipe = 0, bottom pipe = 5
+        * Display B on, surface enable, top pipe = 1, bottom pipe = 4
+        *
+        * The state 2->3 transition requires remapping MPCC 5 from display B
+        * to display A.
+        *
+        * However, with the preferred pipe logic, state 2 would look like:
+        *
+        * (State 2)
+        * Display A on, no surface, top pipe = 0
+        * Display B on, surface enable, top pipe = 1, bottom pipe = 4
+        *
+        * This would then cause 2->3 to not require remapping any MPCCs.
         */
-
-       for (i = pool->pipe_count - 1; i >= 0; i--) {
-               if (res_ctx->pipe_ctx[i].stream == NULL) {
-                       secondary_pipe = &res_ctx->pipe_ctx[i];
-                       secondary_pipe->pipe_idx = i;
-                       break;
+       if (primary_pipe) {
+               int preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx;
+               if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) {
+                       secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
+                       secondary_pipe->pipe_idx = preferred_pipe_idx;
                }
        }
 
+       /*
+        * search backwards for the second pipe to keep pipe
+        * assignment more consistent
+        */
+       if (!secondary_pipe)
+               for (i = pool->pipe_count - 1; i >= 0; i--) {
+                       if (res_ctx->pipe_ctx[i].stream == NULL) {
+                               secondary_pipe = &res_ctx->pipe_ctx[i];
+                               secondary_pipe->pipe_idx = i;
+                               break;
+                       }
+               }
 
        return secondary_pipe;
 }
index e879829a34b9e07f126abfada097bc362974aac4..29f8893e44b61c6a083e16c7c45c0ad92b9086f6 100644 (file)
@@ -1081,7 +1081,7 @@ static struct pipe_ctx *dcn10_acquire_idle_pipe_for_layer(
 {
        struct resource_context *res_ctx = &context->res_ctx;
        struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);
-       struct pipe_ctx *idle_pipe = find_idle_secondary_pipe(res_ctx, pool);
+       struct pipe_ctx *idle_pipe = find_idle_secondary_pipe(res_ctx, pool, head_pipe);
 
        if (!head_pipe) {
                ASSERT(0);
index 62e00a9f3184cb6261bfcc586465442a877250d2..028c63061767659d2fc6195514cb23d0a13731c1 100644 (file)
@@ -131,7 +131,8 @@ bool resource_attach_surfaces_to_context(
 
 struct pipe_ctx *find_idle_secondary_pipe(
                struct resource_context *res_ctx,
-               const struct resource_pool *pool);
+               const struct resource_pool *pool,
+               const struct pipe_ctx *primary_pipe);
 
 bool resource_is_stream_unchanged(
        struct dc_state *old_context, struct dc_stream_state *stream);