diff options
Diffstat (limited to 'drivers/gpu')
12 files changed, 328 insertions, 254 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index dc6ebfa205b0..43273e54147b 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1557,7 +1557,7 @@ enum dc_status resource_build_scaling_params_for_context( return DC_OK; } -struct pipe_ctx *find_idle_secondary_pipe( +struct pipe_ctx *find_idle_secondary_pipe_legacy( struct resource_context *res_ctx, const struct resource_pool *pool, const struct pipe_ctx *primary_pipe) @@ -1617,6 +1617,165 @@ struct pipe_ctx *find_idle_secondary_pipe( return secondary_pipe; } +/* + * Find the most optimal idle pipe from res_ctx, which could be used as a + * secondary dpp pipe for input opp head pipe. + * + * an idle pipe - a pipe in input res_ctx not yet used for any streams or + * planes. + * secondary dpp pipe - a pipe gets inserted to a head OPP pipe's MPC blending + * tree. This is typical used for rendering MPO planes or additional offset + * areas in MPCC combine. + * + * Hardware Transition Minimization Algorithm for Finding a Secondary DPP Pipe + * ------------------------------------------------------------------------- + * + * PROBLEM: + * + * 1. There is a hardware limitation that a secondary DPP pipe cannot be + * transferred from one MPC blending tree to the other in a single frame. + * Otherwise it could cause glitches on the screen. + * + * For instance, we cannot transition from state 1 to state 2 in one frame. This + * is because PIPE1 is transferred from PIPE0's MPC blending tree over to + * PIPE2's MPC blending tree, which is not supported by hardware. + * To support this transition we need to first remove PIPE1 from PIPE0's MPC + * blending tree in one frame and then insert PIPE1 to PIPE2's MPC blending tree + * in the next frame. This is not optimal as it will delay the flip for two + * frames. + * + * State 1: + * PIPE0 -- secondary DPP pipe --> (PIPE1) + * PIPE2 -- secondary DPP pipe --> NONE + * + * State 2: + * PIPE0 -- secondary DPP pipe --> NONE + * PIPE2 -- secondary DPP pipe --> (PIPE1) + * + * 2. We want to in general minimize the unnecessary changes in pipe topology. + * If a pipe is already added in current blending tree and there are no changes + * to plane topology, we don't want to swap it with another idle pipe + * unnecessarily in every update. Powering up and down a pipe would require a + * full update which delays the flip for 1 frame. If we use the original pipe + * we don't have to toggle its power. So we can flip faster. + */ +struct pipe_ctx *find_optimal_idle_pipe_as_secondary_dpp_pipe( + const struct resource_context *cur_res_ctx, + struct resource_context *new_res_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *new_head) +{ + const struct pipe_ctx *cur_head, *cur_sec; + struct pipe_ctx *new_sec; + bool found = false; + int i; + + cur_head = &cur_res_ctx->pipe_ctx[new_head->pipe_idx]; + cur_sec = cur_head->bottom_pipe; + + while (cur_sec) { + /* find an idle pipe used in current opp blend tree, + * this is to avoid MPO pipe switching to different opp blending + * tree + */ + new_sec = &new_res_ctx->pipe_ctx[cur_sec->pipe_idx]; + if (new_sec->plane_state == NULL && new_sec->stream == NULL) { + new_sec->pipe_idx = cur_sec->pipe_idx; + found = true; + break; + } + cur_sec = cur_sec->bottom_pipe; + } + + /* Up until here if we have not found an idle secondary pipe, we will + * need to wait for at least one frame to complete the transition + * sequence. + */ + if (!found) { + /* find a free pipe not used in current res ctx, this is to + * avoid tearing down other pipe's topology + */ + for (i = 0; i < pool->pipe_count; i++) { + cur_sec = &cur_res_ctx->pipe_ctx[i]; + new_sec = &new_res_ctx->pipe_ctx[i]; + + if (cur_sec->plane_state == NULL && + cur_sec->stream == NULL && + new_sec->plane_state == NULL && + new_sec->stream == NULL) { + new_sec->pipe_idx = i; + found = true; + break; + } + } + } + + /* Up until here if we have not found an idle secondary pipe, we will + * need to wait for at least two frames to complete the transition + * sequence. It really doesn't matter which pipe we decide take from + * current enabled pipes. It won't save our frame time when we swap only + * one pipe or more pipes. + */ + if (!found) { + /* find a free pipe by taking away a secondary dpp pipe from an + * MPCC combine in current context + */ + for (i = 0; i < pool->pipe_count; i++) { + cur_sec = &cur_res_ctx->pipe_ctx[i]; + new_sec = &new_res_ctx->pipe_ctx[i]; + + if (cur_sec->plane_state && + cur_sec->bottom_pipe && + cur_sec->bottom_pipe->plane_state == cur_sec->plane_state && + new_sec->plane_state == NULL && + new_sec->stream == NULL) { + found = true; + new_sec->pipe_idx = i; + break; + } + } + } + + if (!found) { + /* find any pipe not used by new state */ + for (i = 0; i < pool->pipe_count; i++) { + new_sec = &new_res_ctx->pipe_ctx[i]; + + if (new_sec->plane_state == NULL) { + found = true; + new_sec->pipe_idx = i; + break; + } + } + } + + return found ? new_sec : NULL; +} + +/* TODO: Unify the pipe naming convention: + * + * OPP head pipe - the head pipe of an MPC blending tree with a functional OPP + * feeding to an OTG. OPP head pipe is by convention the top most pipe. i.e. + * pipe's top_pipe is NULL. + * + * OTG master pipe - the master pipe of its OPP head pipes with a functional + * OTG. It merges all its OPP head pipes pixel data from their MPCs in ODM block + * and output to backend DIG. OTG master pipe is by convention the top most pipe + * of the first odm slice. i.e. pipe's top_pipe is NULL and pipe's prev_odm_pipe + * is NULL. + * + * Secondary OPP head pipe - an OPP head pipe which is not an OTG master pipe. + * Its output feeds to another OTG master pipe. i.e pipe's top_pipe is NULL and + * pipe's prev_odm_pipe is not NULL. + * + * Secondary DPP pipe - the pipe with a functional DPP outputting to another OPP + * head pipe's MPC. Its output is a secondary layer in the OPP head's MPC + * blending tree. Secondary DPP pipe is by convention a non top most pipe. i.e + * pipe's top_pipe should be not NULL. + * + * The function below is actually getting the OTG master pipe associated with + * the stream. Name it as getting head pipe is confusing. + */ struct pipe_ctx *resource_get_head_pipe_for_stream( struct resource_context *res_ctx, struct dc_stream_state *stream) @@ -1632,8 +1791,7 @@ struct pipe_ctx *resource_get_head_pipe_for_stream( return NULL; } -static struct pipe_ctx *resource_get_tail_pipe( - struct resource_context *res_ctx, +static struct pipe_ctx *get_tail_pipe( struct pipe_ctx *head_pipe) { struct pipe_ctx *tail_pipe; @@ -1648,44 +1806,6 @@ static struct pipe_ctx *resource_get_tail_pipe( return head_pipe; } -/* - * A free_pipe for a stream is defined here as a pipe - * that has no surface attached yet - */ -static struct pipe_ctx *acquire_free_pipe_for_head( - struct dc_state *context, - const struct resource_pool *pool, - struct pipe_ctx *head_pipe) -{ - int i; - struct resource_context *res_ctx = &context->res_ctx; - - if (!head_pipe->plane_state) - return head_pipe; - - /* Re-use pipe already acquired for this stream if available*/ - for (i = pool->pipe_count - 1; i >= 0; i--) { - if (res_ctx->pipe_ctx[i].stream == head_pipe->stream && - !res_ctx->pipe_ctx[i].plane_state) { - return &res_ctx->pipe_ctx[i]; - } - } - - /* - * At this point we have no re-useable pipe for this stream and we need - * to acquire an idle one to satisfy the request - */ - - if (!pool->funcs->acquire_idle_pipe_for_layer) { - if (!pool->funcs->acquire_idle_pipe_for_head_pipe_in_layer) - return NULL; - else - return pool->funcs->acquire_idle_pipe_for_head_pipe_in_layer(context, pool, head_pipe->stream, head_pipe); - } - - return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream); -} - static int acquire_first_split_pipe( struct resource_context *res_ctx, const struct resource_pool *pool, @@ -1721,88 +1841,121 @@ static int acquire_first_split_pipe( return UNABLE_TO_SPLIT; } -bool dc_add_plane_to_context( - const struct dc *dc, - struct dc_stream_state *stream, +static bool add_plane_to_opp_head_pipes(struct pipe_ctx *otg_master_pipe, struct dc_plane_state *plane_state, struct dc_state *context) { - int i; - struct resource_pool *pool = dc->res_pool; - struct pipe_ctx *head_pipe, *tail_pipe, *free_pipe; - struct dc_stream_status *stream_status = NULL; + struct pipe_ctx *opp_head_pipe = otg_master_pipe; - DC_LOGGER_INIT(stream->ctx->logger); - for (i = 0; i < context->stream_count; i++) - if (context->streams[i] == stream) { - stream_status = &context->stream_status[i]; - break; + while (opp_head_pipe) { + if (opp_head_pipe->plane_state) { + ASSERT(0); + return false; } - if (stream_status == NULL) { - dm_error("Existing stream not found; failed to attach surface!\n"); - return false; + opp_head_pipe->plane_state = plane_state; + opp_head_pipe = opp_head_pipe->next_odm_pipe; } + return true; +} - if (stream_status->plane_count == MAX_SURFACE_NUM) { - dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n", - plane_state, MAX_SURFACE_NUM); - return false; +static void insert_secondary_dpp_pipe_with_plane(struct pipe_ctx *opp_head_pipe, + struct pipe_ctx *sec_pipe, struct dc_plane_state *plane_state) +{ + struct pipe_ctx *tail_pipe = get_tail_pipe(opp_head_pipe); + + tail_pipe->bottom_pipe = sec_pipe; + sec_pipe->top_pipe = tail_pipe; + if (tail_pipe->prev_odm_pipe) { + ASSERT(tail_pipe->prev_odm_pipe->bottom_pipe); + sec_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe; + tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = sec_pipe; } + sec_pipe->plane_state = plane_state; +} - head_pipe = resource_get_head_pipe_for_stream(&context->res_ctx, stream); +/* for each opp head pipe of an otg master pipe, acquire a secondary dpp pipe + * and add the plane. So the plane is added to all MPC blend trees associated + * with the otg master pipe. + */ +static bool acquire_secondary_dpp_pipes_and_add_plane( + struct pipe_ctx *otg_master_pipe, + struct dc_plane_state *plane_state, + struct dc_state *new_ctx, + struct dc_state *cur_ctx, + struct resource_pool *pool) +{ + struct pipe_ctx *opp_head_pipe, *sec_pipe; - if (!head_pipe) { - dm_error("Head pipe not found for stream_state %p !\n", stream); + if (!pool->funcs->acquire_idle_pipe_for_layer) return false; - } - /* retain new surface, but only once per stream */ - dc_plane_state_retain(plane_state); - - while (head_pipe) { - free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe); + opp_head_pipe = otg_master_pipe; + while (opp_head_pipe) { + sec_pipe = pool->funcs->acquire_idle_pipe_for_layer( + cur_ctx, + new_ctx, + pool, + opp_head_pipe); + if (!sec_pipe) { + /* try tearing down MPCC combine */ + int pipe_idx = acquire_first_split_pipe( + &new_ctx->res_ctx, pool, + otg_master_pipe->stream); - if (!free_pipe) { - int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); if (pipe_idx >= 0) - free_pipe = &context->res_ctx.pipe_ctx[pipe_idx]; + sec_pipe = &new_ctx->res_ctx.pipe_ctx[pipe_idx]; } - if (!free_pipe) { - dc_plane_state_release(plane_state); + if (!sec_pipe) return false; - } - - free_pipe->plane_state = plane_state; - - if (head_pipe != free_pipe) { - tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe); - ASSERT(tail_pipe); - - free_pipe->stream_res.tg = tail_pipe->stream_res.tg; - free_pipe->stream_res.abm = tail_pipe->stream_res.abm; - free_pipe->stream_res.opp = tail_pipe->stream_res.opp; - free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc; - free_pipe->stream_res.audio = tail_pipe->stream_res.audio; - free_pipe->clock_source = tail_pipe->clock_source; - free_pipe->top_pipe = tail_pipe; - tail_pipe->bottom_pipe = free_pipe; - if (tail_pipe->prev_odm_pipe) { - tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_pipe; - free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe; - } - } - head_pipe = head_pipe->next_odm_pipe; + insert_secondary_dpp_pipe_with_plane(opp_head_pipe, sec_pipe, + plane_state); + opp_head_pipe = opp_head_pipe->next_odm_pipe; } + return true; +} - /* assign new surfaces*/ - stream_status->plane_states[stream_status->plane_count] = plane_state; +bool dc_add_plane_to_context( + const struct dc *dc, + struct dc_stream_state *stream, + struct dc_plane_state *plane_state, + struct dc_state *context) +{ + struct resource_pool *pool = dc->res_pool; + struct pipe_ctx *otg_master_pipe; + struct dc_stream_status *stream_status = NULL; + bool added = false; - stream_status->plane_count++; + stream_status = dc_stream_get_status_from_state(context, stream); + if (stream_status == NULL) { + dm_error("Existing stream not found; failed to attach surface!\n"); + goto out; + } else if (stream_status->plane_count == MAX_SURFACE_NUM) { + dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n", + plane_state, MAX_SURFACE_NUM); + goto out; + } - return true; + otg_master_pipe = resource_get_head_pipe_for_stream( + &context->res_ctx, stream); + if (otg_master_pipe->plane_state == NULL) + added = add_plane_to_opp_head_pipes(otg_master_pipe, + plane_state, context); + else + added = acquire_secondary_dpp_pipes_and_add_plane( + otg_master_pipe, plane_state, context, + dc->current_state, pool); + if (added) { + stream_status->plane_states[stream_status->plane_count] = + plane_state; + stream_status->plane_count++; + dc_plane_state_retain(plane_state); + } + +out: + return added; } bool dc_remove_plane_from_context( diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 46eca5a21e1c..b17134504944 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -1119,13 +1119,15 @@ static enum dc_status dce110_add_stream_to_ctx( } static struct pipe_ctx *dce110_acquire_underlay( - struct dc_state *context, + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, const struct resource_pool *pool, - struct dc_stream_state *stream) + const struct pipe_ctx *opp_head_pipe) { + struct dc_stream_state *stream = opp_head_pipe->stream; struct dc *dc = stream->ctx->dc; struct dce_hwseq *hws = dc->hwseq; - struct resource_context *res_ctx = &context->res_ctx; + struct resource_context *res_ctx = &new_ctx->res_ctx; unsigned int underlay_idx = pool->underlay_pipe_index; struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[underlay_idx]; @@ -1173,7 +1175,7 @@ static struct pipe_ctx *dce110_acquire_underlay( stream->timing.h_total, stream->timing.v_total, stream->timing.pix_clk_100hz / 10, - context->stream_count); + new_ctx->stream_count); color_space_to_black_color(dc, COLOR_SPACE_YCBCR601, &black_color); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 4b02f8443534..292e71b99808 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -1084,13 +1084,14 @@ static enum dc_status dcn10_add_stream_to_ctx( } static struct pipe_ctx *dcn10_acquire_idle_pipe_for_layer( - struct dc_state *context, + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, const struct resource_pool *pool, - struct dc_stream_state *stream) + const struct pipe_ctx *opp_head_pipe) { - 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, head_pipe); + struct resource_context *res_ctx = &new_ctx->res_ctx; + struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, opp_head_pipe->stream); + struct pipe_ctx *idle_pipe = find_idle_secondary_pipe_legacy(res_ctx, pool, head_pipe); if (!head_pipe) { ASSERT(0); diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index 4cc8de2627ce..d526f06e8f1a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -2148,13 +2148,14 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, } struct pipe_ctx *dcn20_acquire_idle_pipe_for_layer( - struct dc_state *state, + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, const struct resource_pool *pool, - struct dc_stream_state *stream) + const struct pipe_ctx *opp_head_pipe) { - struct resource_context *res_ctx = &state->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, head_pipe); + struct resource_context *res_ctx = &new_ctx->res_ctx; + struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, opp_head_pipe->stream); + struct pipe_ctx *idle_pipe = find_idle_secondary_pipe_legacy(res_ctx, pool, head_pipe); if (!head_pipe) ASSERT(0); diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h index da0241e8c255..67a78ea2c0e4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h @@ -59,9 +59,10 @@ unsigned int dcn20_calc_max_scaled_time( unsigned int urgent_watermark); struct pipe_ctx *dcn20_acquire_idle_pipe_for_layer( - struct dc_state *state, + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, const struct resource_pool *pool, - struct dc_stream_state *stream); + const struct pipe_ctx *opp_head_pipe); struct stream_encoder *dcn20_stream_encoder_create( enum engine_id eng_id, diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c index fdba8a9f5c30..1a8927e9b64b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c @@ -993,13 +993,14 @@ static struct hubp *dcn201_hubp_create( } static struct pipe_ctx *dcn201_acquire_idle_pipe_for_layer( - struct dc_state *context, + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, const struct resource_pool *pool, - struct dc_stream_state *stream) + const struct pipe_ctx *opp_head_pipe) { - 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, head_pipe); + struct resource_context *res_ctx = &new_ctx->res_ctx; + struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, opp_head_pipe->stream); + struct pipe_ctx *idle_pipe = find_idle_secondary_pipe_legacy(res_ctx, pool, head_pipe); if (!head_pipe) ASSERT(0); diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c index 0d1f18f8348e..fd6511da2903 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c @@ -2038,7 +2038,7 @@ static struct resource_funcs dcn32_res_pool_funcs = { .validate_bandwidth = dcn32_validate_bandwidth, .calculate_wm_and_dlg = dcn32_calculate_wm_and_dlg, .populate_dml_pipes = dcn32_populate_dml_pipes_from_context, - .acquire_idle_pipe_for_head_pipe_in_layer = dcn32_acquire_idle_pipe_for_head_pipe_in_layer, + .acquire_idle_pipe_for_layer = dcn32_acquire_idle_pipe_for_layer, .add_stream_to_ctx = dcn30_add_stream_to_ctx, .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, @@ -2485,108 +2485,31 @@ struct resource_pool *dcn32_create_resource_pool( return NULL; } -static struct pipe_ctx *find_idle_secondary_pipe_check_mpo( - struct resource_context *res_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *primary_pipe) -{ - int i; - struct pipe_ctx *secondary_pipe = NULL; - struct pipe_ctx *next_odm_mpo_pipe = NULL; - int primary_index, preferred_pipe_idx; - struct pipe_ctx *old_primary_pipe = NULL; - - /* - * Modified from find_idle_secondary_pipe - * With windowed MPO and ODM, we want to avoid the case where we want a - * free pipe for the left side but the free pipe is being used on the - * right side. - * Add check on current_state if the primary_pipe is the left side, - * to check the right side ( primary_pipe->next_odm_pipe ) to see if - * it is using a pipe for MPO ( primary_pipe->next_odm_pipe->bottom_pipe ) - * - If so, then don't use this pipe - * EXCEPTION - 3 plane ( 2 MPO plane ) case - * - in this case, the primary pipe has already gotten a free pipe for the - * MPO window in the left - * - when it tries to get a free pipe for the MPO window on the right, - * it will see that it is already assigned to the right side - * ( primary_pipe->next_odm_pipe ). But in this case, we want this - * free pipe, since it will be for the right side. So add an - * additional condition, that skipping the free pipe on the right only - * applies if the primary pipe has no bottom pipe currently assigned - */ - if (primary_pipe) { - primary_index = primary_pipe->pipe_idx; - old_primary_pipe = &primary_pipe->stream->ctx->dc->current_state->res_ctx.pipe_ctx[primary_index]; - if ((old_primary_pipe->next_odm_pipe) && (old_primary_pipe->next_odm_pipe->bottom_pipe) - && (!primary_pipe->bottom_pipe)) - next_odm_mpo_pipe = old_primary_pipe->next_odm_pipe->bottom_pipe; - - preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx; - if ((res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) && - !(next_odm_mpo_pipe && next_odm_mpo_pipe->pipe_idx == preferred_pipe_idx)) { - 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) && - !(next_odm_mpo_pipe && next_odm_mpo_pipe->pipe_idx == i)) { - secondary_pipe = &res_ctx->pipe_ctx[i]; - secondary_pipe->pipe_idx = i; - break; - } - } - - return secondary_pipe; -} - -struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer( - struct dc_state *state, +struct pipe_ctx *dcn32_acquire_idle_pipe_for_layer( + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, const struct resource_pool *pool, - struct dc_stream_state *stream, - struct pipe_ctx *head_pipe) + const struct pipe_ctx *opp_head_pipe) { - struct resource_context *res_ctx = &state->res_ctx; - struct pipe_ctx *idle_pipe, *pipe; - struct resource_context *old_ctx = &stream->ctx->dc->current_state->res_ctx; - int head_index; - - if (!head_pipe) - ASSERT(0); - - /* - * Modified from dcn20_acquire_idle_pipe_for_layer - * Check if head_pipe in old_context already has bottom_pipe allocated. - * - If so, check if that pipe is available in the current context. - * -- If so, reuse pipe from old_context - */ - head_index = head_pipe->pipe_idx; - pipe = &old_ctx->pipe_ctx[head_index]; - if (pipe->bottom_pipe && res_ctx->pipe_ctx[pipe->bottom_pipe->pipe_idx].stream == NULL) { - idle_pipe = &res_ctx->pipe_ctx[pipe->bottom_pipe->pipe_idx]; - idle_pipe->pipe_idx = pipe->bottom_pipe->pipe_idx; + struct pipe_ctx *idle_pipe = + find_optimal_idle_pipe_as_secondary_dpp_pipe( + &cur_ctx->res_ctx, &new_ctx->res_ctx, + pool, opp_head_pipe); + + if (idle_pipe) { + idle_pipe->stream = opp_head_pipe->stream; + idle_pipe->stream_res.tg = opp_head_pipe->stream_res.tg; + idle_pipe->stream_res.opp = opp_head_pipe->stream_res.opp; + + idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.mpcc_inst = + pool->dpps[idle_pipe->pipe_idx]->inst; } else { - idle_pipe = find_idle_secondary_pipe_check_mpo(res_ctx, pool, head_pipe); - if (!idle_pipe) - return NULL; + ASSERT(opp_head_pipe); } - idle_pipe->stream = head_pipe->stream; - idle_pipe->stream_res.tg = head_pipe->stream_res.tg; - idle_pipe->stream_res.opp = head_pipe->stream_res.opp; - - idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx]; - idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx]; - idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx]; - idle_pipe->plane_res.mpcc_inst = pool->dpps[idle_pipe->pipe_idx]->inst; - return idle_pipe; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h index 81e443170829..165754ed5f49 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h @@ -136,11 +136,11 @@ bool dcn32_any_surfaces_rotated(struct dc *dc, struct dc_state *context); bool dcn32_is_center_timing(struct pipe_ctx *pipe); bool dcn32_is_psr_capable(struct pipe_ctx *pipe); -struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer( - struct dc_state *state, +struct pipe_ctx *dcn32_acquire_idle_pipe_for_layer( + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, const struct resource_pool *pool, - struct dc_stream_state *stream, - struct pipe_ctx *head_pipe); + const struct pipe_ctx *opp_head_pipe); void dcn32_determine_det_override(struct dc *dc, struct dc_state *context, diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c index a53478e15ce3..c2fd841d4c0b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c @@ -1588,7 +1588,7 @@ static struct resource_funcs dcn321_res_pool_funcs = { .validate_bandwidth = dcn32_validate_bandwidth, .calculate_wm_and_dlg = dcn32_calculate_wm_and_dlg, .populate_dml_pipes = dcn32_populate_dml_pipes_from_context, - .acquire_idle_pipe_for_head_pipe_in_layer = dcn32_acquire_idle_pipe_for_head_pipe_in_layer, + .acquire_idle_pipe_for_layer = dcn32_acquire_idle_pipe_for_layer, .add_stream_to_ctx = dcn30_add_stream_to_ctx, .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c index e73f089c84bb..8377a0b58ec3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c @@ -1258,7 +1258,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, pipe); + hsplit_pipe = find_idle_secondary_pipe_legacy(&context->res_ctx, pool, pipe); ASSERT(hsplit_pipe); split_stream_across_pipes(&context->res_ctx, pool, pipe, hsplit_pipe); } diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index bc0c26a5f228..5b9d0bb0328c 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -126,38 +126,24 @@ struct resource_funcs { struct dc_state *context); /* - * Acquires a free pipe for the head pipe. - * The head pipe is first pipe in the current context that matches the stream - * and does not have a top pipe or prev_odm_pipe. - */ - struct pipe_ctx *(*acquire_idle_pipe_for_layer)( - struct dc_state *context, - const struct resource_pool *pool, - struct dc_stream_state *stream); - - /* - * Acquires a free pipe for the head pipe with some additional checks for odm. - * The head pipe is passed in as an argument unlike acquire_idle_pipe_for_layer - * where it is read from the context. So this allows us look for different - * idle_pipe if the head_pipes are different ( ex. in odm 2:1 when we have - * a left and right pipe ). - * - * It also checks the old context to see if: + * Acquire an idle pipe from context, which could be used as a secondary + * pipe for the otg master pipe associated with the input stream. * - * 1. a pipe has already been allocated for the head pipe. If so, it will - * try to select that pipe as the idle pipe if it is available in the current - * context. - * 2. if the head_pipe is on the left, it will check if the right pipe has - * a pipe already allocated. If so, it will not use that pipe if it is - * selected as the idle pipe. + * an idle pipe - a pipe not yet used for any streams or + * planes. + * secondary pipe - a pipe gets inserted to a head OPP pipe's blending + * tree. This is typical used for rendering MPO planes or additional + * offset areas in MPCC combine. */ - struct pipe_ctx *(*acquire_idle_pipe_for_head_pipe_in_layer)( - struct dc_state *context, + struct pipe_ctx *(*acquire_idle_pipe_for_layer)( + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, const struct resource_pool *pool, - struct dc_stream_state *stream, - struct pipe_ctx *head_pipe); + const struct pipe_ctx *opp_head_pipe); - enum dc_status (*validate_plane)(const struct dc_plane_state *plane_state, struct dc_caps *caps); + enum dc_status (*validate_plane)( + const struct dc_plane_state *plane_state, + struct dc_caps *caps); enum dc_status (*add_stream_to_ctx)( struct dc *dc, diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index eaeb684c8a48..6ac6680711ff 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -153,11 +153,17 @@ bool resource_attach_surfaces_to_context( struct dc_state *context, const struct resource_pool *pool); -struct pipe_ctx *find_idle_secondary_pipe( +struct pipe_ctx *find_idle_secondary_pipe_legacy( struct resource_context *res_ctx, const struct resource_pool *pool, const struct pipe_ctx *primary_pipe); +struct pipe_ctx *find_optimal_idle_pipe_as_secondary_dpp_pipe( + const struct resource_context *cur_res_ctx, + struct resource_context *new_res_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *new_pri); + bool resource_validate_attach_surfaces( const struct dc_validation_set set[], int set_count, |