From: Saaem Rizvi Date: Mon, 25 Sep 2023 04:45:25 +0000 (-0400) Subject: drm/amd/display: Modify Pipe Selection for Policy for ODM X-Git-Tag: microblaze-v6.8~11^2~16^2~105 X-Git-Url: http://git.monstr.eu/?a=commitdiff_plain;h=ba85d293a30e358abe9740ac0c945211066e4273;p=linux-2.6-microblaze.git drm/amd/display: Modify Pipe Selection for Policy for ODM [Why] There are certain cases during a transition to ODM that might cause corruption on the display. This occurs when we choose certain pipes in a particular state. [How] We now will store the pipe indexes of the any pipes that might be problematic to switch to during an ODM transition, and only use them as a last resort. Reviewed-by: Dmytro Laktyushkin Acked-by: Qingqing Zhuo Signed-off-by: Qingqing Zhuo Signed-off-by: Saaem Rizvi Signed-off-by: Alex Deucher --- diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c index e22b5106df8f..36baf35bb170 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c @@ -213,6 +213,82 @@ static bool is_pipe_free(const struct pipe_ctx *pipe) return false; } +static unsigned int find_preferred_pipe_candidates(const struct dc_state *existing_state, + const int pipe_count, + const unsigned int stream_id, + unsigned int *preferred_pipe_candidates) +{ + unsigned int num_preferred_candidates = 0; + int i; + + /* There is only one case which we consider for adding a pipe to the preferred + * pipe candidate array: + * + * 1. If the existing stream id of the pipe is equivalent to the stream id + * of the stream we are trying to achieve MPC/ODM combine for. This allows + * us to minimize the changes in pipe topology during the transition. + * + * However this condition comes with a caveat. We need to ignore pipes that will + * require a change in OPP but still have the same stream id. For example during + * an MPC to ODM transiton. + */ + if (existing_state) { + for (i = 0; i < pipe_count; i++) { + if (existing_state->res_ctx.pipe_ctx[i].stream && existing_state->res_ctx.pipe_ctx[i].stream->stream_id == stream_id) { + if (existing_state->res_ctx.pipe_ctx[i].plane_res.hubp && + existing_state->res_ctx.pipe_ctx[i].plane_res.hubp->opp_id != i) + continue; + + preferred_pipe_candidates[num_preferred_candidates++] = i; + } + } + } + + return num_preferred_candidates; +} + +static unsigned int find_last_resort_pipe_candidates(const struct dc_state *existing_state, + const int pipe_count, + const unsigned int stream_id, + unsigned int *last_resort_pipe_candidates) +{ + unsigned int num_last_resort_candidates = 0; + int i; + + /* There are two cases where we would like to add a given pipe into the last + * candidate array: + * + * 1. If the pipe requires a change in OPP, for example during an MPC + * to ODM transiton. + * + * 2. If the pipe already has an enabled OTG. + */ + if (existing_state) { + for (i = 0; i < pipe_count; i++) { + if ((existing_state->res_ctx.pipe_ctx[i].plane_res.hubp && + existing_state->res_ctx.pipe_ctx[i].plane_res.hubp->opp_id != i) || + existing_state->res_ctx.pipe_ctx[i].stream_res.tg) + last_resort_pipe_candidates[num_last_resort_candidates++] = i; + } + } + + return num_last_resort_candidates; +} + +static bool is_pipe_in_candidate_array(const unsigned int pipe_idx, + const unsigned int *candidate_array, + const unsigned int candidate_array_size) +{ + int i; + + for (i = 0; i < candidate_array_size; i++) { + if (candidate_array[i] == pipe_idx) + return true; + } + + return false; +} + static bool find_more_pipes_for_stream(struct dml2_context *ctx, struct dc_state *state, // The state we want to find a free mapping in unsigned int stream_id, // The stream we want this pipe to drive @@ -222,16 +298,18 @@ static bool find_more_pipes_for_stream(struct dml2_context *ctx, const struct dc_state *existing_state) // The state (optional) that we want to minimize remapping relative to { struct pipe_ctx *pipe = NULL; - unsigned int preferred_pipe_candidates[MAX_PIPES]; + unsigned int preferred_pipe_candidates[MAX_PIPES] = {0}; + unsigned int last_resort_pipe_candidates[MAX_PIPES] = {0}; unsigned int num_preferred_candidates = 0; + unsigned int num_last_resort_candidates = 0; int i; if (existing_state) { - // To minimize prioritize candidates from existing stream - for (i = 0; i < ctx->config.dcn_pipe_count; i++) { - if (existing_state->res_ctx.pipe_ctx[i].stream && existing_state->res_ctx.pipe_ctx[i].stream->stream_id == stream_id) - preferred_pipe_candidates[num_preferred_candidates++] = existing_state->res_ctx.pipe_ctx[i].pipe_idx; - } + num_preferred_candidates = + find_preferred_pipe_candidates(existing_state, ctx->config.dcn_pipe_count, stream_id, preferred_pipe_candidates); + + num_last_resort_candidates = + find_last_resort_pipe_candidates(existing_state, ctx->config.dcn_pipe_count, stream_id, last_resort_pipe_candidates); } // First see if any of the preferred are unmapped, and choose those instead @@ -247,6 +325,11 @@ static bool find_more_pipes_for_stream(struct dml2_context *ctx, // We like to pair pipes starting from the higher order indicies for combining for (i = ctx->config.dcn_pipe_count - 1; pipes_needed > 0 && i >= 0; i--) { + // Ignore any pipes that are the preferred or last resort candidate + if (is_pipe_in_candidate_array(i, preferred_pipe_candidates, num_preferred_candidates) || + is_pipe_in_candidate_array(i, last_resort_pipe_candidates, num_last_resort_candidates)) + continue; + pipe = &state->res_ctx.pipe_ctx[i]; if (!is_plane_using_pipe(pipe)) { pipes_needed--; @@ -256,6 +339,17 @@ static bool find_more_pipes_for_stream(struct dml2_context *ctx, } } + // Only use the last resort pipe candidates as a last resort + for (i = 0; pipes_needed > 0 && i < num_last_resort_candidates; i++) { + pipe = &state->res_ctx.pipe_ctx[last_resort_pipe_candidates[i]]; + if (!is_plane_using_pipe(pipe)) { + pipes_needed--; + // TODO: This doens't make sense really, pipe_idx should always be valid + pipe->pipe_idx = last_resort_pipe_candidates[i]; + assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; + } + } + ASSERT(pipes_needed <= 0); // Validation should prevent us from building a pipe context that exceeds the number of HW resoruces available return pipes_needed <= 0; @@ -270,16 +364,18 @@ static bool find_more_free_pipes(struct dml2_context *ctx, const struct dc_state *existing_state) // The state (optional) that we want to minimize remapping relative to { struct pipe_ctx *pipe = NULL; - unsigned int preferred_pipe_candidates[MAX_PIPES]; + unsigned int preferred_pipe_candidates[MAX_PIPES] = {0}; + unsigned int last_resort_pipe_candidates[MAX_PIPES] = {0}; unsigned int num_preferred_candidates = 0; + unsigned int num_last_resort_candidates = 0; int i; if (existing_state) { - // To minimize prioritize candidates from existing stream - for (i = 0; i < ctx->config.dcn_pipe_count; i++) { - if (existing_state->res_ctx.pipe_ctx[i].stream && existing_state->res_ctx.pipe_ctx[i].stream->stream_id == stream_id) - preferred_pipe_candidates[num_preferred_candidates++] = existing_state->res_ctx.pipe_ctx[i].pipe_idx; - } + num_preferred_candidates = + find_preferred_pipe_candidates(existing_state, ctx->config.dcn_pipe_count, stream_id, preferred_pipe_candidates); + + num_last_resort_candidates = + find_last_resort_pipe_candidates(existing_state, ctx->config.dcn_pipe_count, stream_id, last_resort_pipe_candidates); } // First see if any of the preferred are unmapped, and choose those instead @@ -295,6 +391,11 @@ static bool find_more_free_pipes(struct dml2_context *ctx, // We like to pair pipes starting from the higher order indicies for combining for (i = ctx->config.dcn_pipe_count - 1; pipes_needed > 0 && i >= 0; i--) { + // Ignore any pipes that are the preferred or last resort candidate + if (is_pipe_in_candidate_array(i, preferred_pipe_candidates, num_preferred_candidates) || + is_pipe_in_candidate_array(i, last_resort_pipe_candidates, num_last_resort_candidates)) + continue; + pipe = &state->res_ctx.pipe_ctx[i]; if (is_pipe_free(pipe)) { pipes_needed--; @@ -304,6 +405,17 @@ static bool find_more_free_pipes(struct dml2_context *ctx, } } + // Only use the last resort pipe candidates as a last resort + for (i = 0; pipes_needed > 0 && i < num_last_resort_candidates; i++) { + pipe = &state->res_ctx.pipe_ctx[last_resort_pipe_candidates[i]]; + if (is_pipe_free(pipe)) { + pipes_needed--; + // TODO: This doens't make sense really, pipe_idx should always be valid + pipe->pipe_idx = last_resort_pipe_candidates[i]; + assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; + } + } + ASSERT(pipes_needed == 0); // Validation should prevent us from building a pipe context that exceeds the number of HW resoruces available return pipes_needed == 0; @@ -465,7 +577,7 @@ static struct pipe_ctx *assign_pipes_to_stream(struct dml2_context *ctx, struct struct pipe_ctx *master_pipe; unsigned int pipes_needed; unsigned int pipes_assigned; - unsigned int pipes[MAX_PIPES]; + unsigned int pipes[MAX_PIPES] = {0}; unsigned int next_pipe_to_assign; int odm_slice; @@ -502,7 +614,7 @@ static struct pipe_ctx *assign_pipes_to_plane(struct dml2_context *ctx, struct d unsigned int plane_id; unsigned int pipes_needed; unsigned int pipes_assigned; - unsigned int pipes[MAX_PIPES]; + unsigned int pipes[MAX_PIPES] = {0}; unsigned int next_pipe_to_assign; int odm_slice, mpc_slice;