drm/amd/display: add ODM case when looking for first split pipe
authorjsg <jsg@openbsd.org>
Fri, 4 Aug 2023 08:36:52 +0000 (08:36 +0000)
committerjsg <jsg@openbsd.org>
Fri, 4 Aug 2023 08:36:52 +0000 (08:36 +0000)
From Samson Tam
8d515d39d8005981479a93fd6bee2649c59f0b1b in linux-6.1.y/6.1.43
59de751e3845d699e02dc4da47322b92d83a41e2 in mainline linux

sys/dev/pci/drm/amd/display/dc/core/amdgpu_dc.c
sys/dev/pci/drm/amd/display/dc/core/dc_resource.c

index c429748..629bc53 100644 (file)
@@ -1913,6 +1913,9 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
        return result;
 }
 
+static bool commit_minimal_transition_state(struct dc *dc,
+               struct dc_state *transition_base_context);
+
 /**
  * dc_commit_streams - Commit current stream state
  *
@@ -1934,6 +1937,8 @@ enum dc_status dc_commit_streams(struct dc *dc,
        struct dc_state *context;
        enum dc_status res = DC_OK;
        struct dc_validation_set set[MAX_STREAMS] = {0};
+       struct pipe_ctx *pipe;
+       bool handle_exit_odm2to1 = false;
 
        if (!streams_changed(dc, streams, stream_count))
                return res;
@@ -1955,6 +1960,22 @@ enum dc_status dc_commit_streams(struct dc *dc,
                }
        }
 
+       /* Check for case where we are going from odm 2:1 to max
+        *  pipe scenario.  For these cases, we will call
+        *  commit_minimal_transition_state() to exit out of odm 2:1
+        *  first before processing new streams
+        */
+       if (stream_count == dc->res_pool->pipe_count) {
+               for (i = 0; i < dc->res_pool->pipe_count; i++) {
+                       pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+                       if (pipe->next_odm_pipe)
+                               handle_exit_odm2to1 = true;
+               }
+       }
+
+       if (handle_exit_odm2to1)
+               res = commit_minimal_transition_state(dc, dc->current_state);
+
        context = dc_create_state(dc);
        if (!context)
                goto context_alloc_fail;
@@ -3759,6 +3780,7 @@ static bool commit_minimal_transition_state(struct dc *dc,
        unsigned int i, j;
        unsigned int pipe_in_use = 0;
        bool subvp_in_use = false;
+       bool odm_in_use = false;
 
        if (!transition_context)
                return false;
@@ -3783,6 +3805,18 @@ static bool commit_minimal_transition_state(struct dc *dc,
                }
        }
 
+       /* If ODM is enabled and we are adding or removing planes from any ODM
+        * pipe, we must use the minimal transition.
+        */
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+
+               if (pipe->stream && pipe->next_odm_pipe) {
+                       odm_in_use = true;
+                       break;
+               }
+       }
+
        /* When the OS add a new surface if we have been used all of pipes with odm combine
         * and mpc split feature, it need use commit_minimal_transition_state to transition safely.
         * After OS exit MPO, it will back to use odm and mpc split with all of pipes, we need
@@ -3791,7 +3825,7 @@ static bool commit_minimal_transition_state(struct dc *dc,
         * Reduce the scenarios to use dc_commit_state_no_check in the stage of flip. Especially
         * enter/exit MPO when DCN still have enough resources.
         */
-       if (pipe_in_use != dc->res_pool->pipe_count && !subvp_in_use) {
+       if (pipe_in_use != dc->res_pool->pipe_count && !subvp_in_use && !odm_in_use) {
                dc_release_state(transition_context);
                return true;
        }
index 658913c..79fc718 100644 (file)
@@ -1444,6 +1444,26 @@ static int acquire_first_split_pipe(
                        split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst;
                        split_pipe->pipe_idx = i;
 
+                       split_pipe->stream = stream;
+                       return i;
+               } else if (split_pipe->prev_odm_pipe &&
+                               split_pipe->prev_odm_pipe->plane_state == split_pipe->plane_state) {
+                       split_pipe->prev_odm_pipe->next_odm_pipe = split_pipe->next_odm_pipe;
+                       if (split_pipe->next_odm_pipe)
+                               split_pipe->next_odm_pipe->prev_odm_pipe = split_pipe->prev_odm_pipe;
+
+                       if (split_pipe->prev_odm_pipe->plane_state)
+                               resource_build_scaling_params(split_pipe->prev_odm_pipe);
+
+                       memset(split_pipe, 0, sizeof(*split_pipe));
+                       split_pipe->stream_res.tg = pool->timing_generators[i];
+                       split_pipe->plane_res.hubp = pool->hubps[i];
+                       split_pipe->plane_res.ipp = pool->ipps[i];
+                       split_pipe->plane_res.dpp = pool->dpps[i];
+                       split_pipe->stream_res.opp = pool->opps[i];
+                       split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst;
+                       split_pipe->pipe_idx = i;
+
                        split_pipe->stream = stream;
                        return i;
                }