From: Wenjing Liu <wenjing....@amd.com> Redesign pipe resource interfaces in resource.h file. The new interface design addresses the issue with lack of pipe topology encapsulation and lack of pipe accessors.
Reviewed-by: Jun Lei <jun....@amd.com> Acked-by: Hamza Mahfooz <hamza.mahf...@amd.com> Signed-off-by: Wenjing Liu <wenjing....@amd.com> --- .../gpu/drm/amd/display/dc/core/dc_resource.c | 951 ++++++++++-------- .../drm/amd/display/dc/dcn20/dcn20_hwseq.c | 2 + .../drm/amd/display/dc/dcn20/dcn20_resource.c | 22 +- .../drm/amd/display/dc/dcn20/dcn20_resource.h | 4 +- .../amd/display/dc/dcn201/dcn201_resource.c | 1 + .../drm/amd/display/dc/dcn21/dcn21_resource.c | 1 + .../drm/amd/display/dc/dcn30/dcn30_resource.c | 1 + .../amd/display/dc/dcn301/dcn301_resource.c | 1 + .../amd/display/dc/dcn302/dcn302_resource.c | 1 + .../amd/display/dc/dcn303/dcn303_resource.c | 1 + .../drm/amd/display/dc/dcn31/dcn31_resource.c | 1 + .../amd/display/dc/dcn314/dcn314_resource.c | 1 + .../amd/display/dc/dcn315/dcn315_resource.c | 1 + .../amd/display/dc/dcn316/dcn316_resource.c | 1 + .../drm/amd/display/dc/dcn32/dcn32_resource.c | 11 +- .../amd/display/dc/dcn321/dcn321_resource.c | 1 + .../drm/amd/display/dc/dml/dcn20/dcn20_fpu.c | 6 +- drivers/gpu/drm/amd/display/dc/inc/resource.h | 278 ++--- 18 files changed, 740 insertions(+), 545 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 b7ab357d1b9d..84db7c5fb852 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -732,66 +732,6 @@ static inline void get_vp_scan_direction( *flip_horz_scan_dir = !*flip_horz_scan_dir; } -int resource_get_num_mpc_splits(const struct pipe_ctx *pipe) -{ - int mpc_split_count = 0; - const struct pipe_ctx *other_pipe = pipe->bottom_pipe; - - while (other_pipe && other_pipe->plane_state == pipe->plane_state) { - mpc_split_count++; - other_pipe = other_pipe->bottom_pipe; - } - other_pipe = pipe->top_pipe; - while (other_pipe && other_pipe->plane_state == pipe->plane_state) { - mpc_split_count++; - other_pipe = other_pipe->top_pipe; - } - - return mpc_split_count; -} - -int resource_get_num_odm_splits(const struct pipe_ctx *pipe) -{ - int odm_split_count = 0; - - pipe = resource_get_otg_master(pipe); - - while (pipe->next_odm_pipe) { - odm_split_count++; - pipe = pipe->next_odm_pipe; - } - return odm_split_count; -} - -int resource_get_odm_split_index(struct pipe_ctx *pipe_ctx) -{ - int index = 0; - - pipe_ctx = resource_get_opp_head(pipe_ctx); - if (!pipe_ctx) - return 0; - - while (pipe_ctx->prev_odm_pipe) { - index++; - pipe_ctx = pipe_ctx->prev_odm_pipe; - } - - return index; -} - -int resource_get_mpc_split_index(struct pipe_ctx *pipe_ctx) -{ - struct pipe_ctx *split_pipe = pipe_ctx->top_pipe; - int index = 0; - - while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) { - index++; - split_pipe = split_pipe->top_pipe; - } - - return index; -} - /* * This is a preliminary vp size calculation to allow us to check taps support. * The result is completely overridden afterwards. @@ -844,8 +784,8 @@ static struct rect shift_rec(const struct rect *rec_in, int x, int y) static struct rect calculate_odm_slice_in_timing_active(struct pipe_ctx *pipe_ctx) { const struct dc_stream_state *stream = pipe_ctx->stream; - int odm_slice_count = resource_get_num_odm_splits(pipe_ctx) + 1; - int odm_slice_idx = resource_get_odm_split_index(pipe_ctx); + int odm_slice_count = resource_get_odm_slice_count(pipe_ctx); + int odm_slice_idx = resource_get_odm_slice_index(pipe_ctx); bool is_last_odm_slice = (odm_slice_idx + 1) == odm_slice_count; int h_active = stream->timing.h_addressable + stream->timing.h_border_left + @@ -962,8 +902,8 @@ static struct rect calculate_mpc_slice_in_timing_active( struct rect *plane_clip_rec) { const struct dc_stream_state *stream = pipe_ctx->stream; - int mpc_slice_count = resource_get_num_mpc_splits(pipe_ctx) + 1; - int mpc_slice_idx = resource_get_mpc_split_index(pipe_ctx); + int mpc_slice_count = resource_get_mpc_slice_count(pipe_ctx); + int mpc_slice_idx = resource_get_mpc_slice_index(pipe_ctx); int epimo = mpc_slice_count - plane_clip_rec->width % mpc_slice_count - 1; struct rect mpc_rec; @@ -1699,7 +1639,7 @@ int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine( if (resource_is_pipe_type(cur_pipe, DPP_PIPE) && !resource_is_pipe_type(cur_pipe, OPP_HEAD) && - resource_is_for_mpcc_combine(cur_pipe) && + resource_get_mpc_slice_index(cur_pipe) > 0 && resource_is_pipe_type(new_pipe, FREE_PIPE)) { free_pipe_idx = i; break; @@ -1763,14 +1703,9 @@ bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type) } } -bool resource_is_for_mpcc_combine(const struct pipe_ctx *pipe_ctx) -{ - return resource_get_num_mpc_splits(pipe_ctx) > 0; -} - struct pipe_ctx *resource_get_otg_master_for_stream( struct resource_context *res_ctx, - struct dc_stream_state *stream) + const struct dc_stream_state *stream) { int i; @@ -1782,6 +1717,75 @@ struct pipe_ctx *resource_get_otg_master_for_stream( return NULL; } +int resource_get_opp_heads_for_otg_master(const struct pipe_ctx *otg_master, + struct resource_context *res_ctx, + struct pipe_ctx *opp_heads[MAX_PIPES]) +{ + struct pipe_ctx *opp_head = &res_ctx->pipe_ctx[otg_master->pipe_idx]; + int i = 0; + + if (!resource_is_pipe_type(otg_master, OTG_MASTER)) { + ASSERT(0); + return 0; + } + while (opp_head) { + ASSERT(i < MAX_PIPES); + opp_heads[i++] = opp_head; + opp_head = opp_head->next_odm_pipe; + } + return i; +} + +int resource_get_dpp_pipes_for_opp_head(const struct pipe_ctx *opp_head, + struct resource_context *res_ctx, + struct pipe_ctx *dpp_pipes[MAX_PIPES]) +{ + struct pipe_ctx *pipe = &res_ctx->pipe_ctx[opp_head->pipe_idx]; + int i = 0; + + if (!resource_is_pipe_type(opp_head, OPP_HEAD)) { + ASSERT(0); + return 0; + } + while (pipe && resource_is_pipe_type(pipe, DPP_PIPE)) { + ASSERT(i < MAX_PIPES); + dpp_pipes[i++] = pipe; + pipe = pipe->bottom_pipe; + } + return i; +} + +int resource_get_dpp_pipes_for_plane(const struct dc_plane_state *plane, + struct resource_context *res_ctx, + struct pipe_ctx *dpp_pipes[MAX_PIPES]) +{ + int i = 0, j; + struct pipe_ctx *pipe; + + for (j = 0; j < MAX_PIPES; j++) { + pipe = &res_ctx->pipe_ctx[j]; + if (pipe->plane_state == plane && pipe->prev_odm_pipe == NULL) { + if (resource_is_pipe_type(pipe, OPP_HEAD) || + pipe->top_pipe->plane_state != plane) + break; + } + } + + if (j < MAX_PIPES) { + if (pipe->next_odm_pipe) + while (pipe) { + dpp_pipes[i++] = pipe; + pipe = pipe->next_odm_pipe; + } + else + while (pipe && pipe->plane_state == plane) { + dpp_pipes[i++] = pipe; + pipe = pipe->bottom_pipe; + } + } + return i; +} + struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx) { struct pipe_ctx *otg_master = resource_get_opp_head(pipe_ctx); @@ -1801,6 +1805,66 @@ struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx) return opp_head; } +int resource_get_mpc_slice_index(const struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *split_pipe = pipe_ctx->top_pipe; + int index = 0; + + while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) { + index++; + split_pipe = split_pipe->top_pipe; + } + + return index; +} + +int resource_get_mpc_slice_count(const struct pipe_ctx *pipe) +{ + int mpc_split_count = 1; + const struct pipe_ctx *other_pipe = pipe->bottom_pipe; + + while (other_pipe && other_pipe->plane_state == pipe->plane_state) { + mpc_split_count++; + other_pipe = other_pipe->bottom_pipe; + } + other_pipe = pipe->top_pipe; + while (other_pipe && other_pipe->plane_state == pipe->plane_state) { + mpc_split_count++; + other_pipe = other_pipe->top_pipe; + } + + return mpc_split_count; +} + +int resource_get_odm_slice_count(const struct pipe_ctx *pipe) +{ + int odm_split_count = 1; + + pipe = resource_get_otg_master(pipe); + + while (pipe->next_odm_pipe) { + odm_split_count++; + pipe = pipe->next_odm_pipe; + } + return odm_split_count; +} + +int resource_get_odm_slice_index(const struct pipe_ctx *pipe_ctx) +{ + int index = 0; + + pipe_ctx = resource_get_opp_head(pipe_ctx); + if (!pipe_ctx) + return 0; + + while (pipe_ctx->prev_odm_pipe) { + index++; + pipe_ctx = pipe_ctx->prev_odm_pipe; + } + + return index; +} + static struct pipe_ctx *get_tail_pipe( struct pipe_ctx *head_pipe) { @@ -1902,97 +1966,265 @@ static int acquire_first_split_pipe( return FREE_PIPE_INDEX_NOT_FOUND; } -/* For each OPP head of an OTG master, add top plane at plane index 0. - * - * In the following example, the stream has 2 ODM slices without a top plane. - * By adding a plane 0 to OPP heads, we are configuring our hardware to render - * plane 0 by using each OPP head's DPP. - * - * Inter-pipe Relation (Before Adding Plane) - * __________________________________________________ - * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | - * | | | slice 0 | | - * | 0 | |blank ----ODM----------- | - * | | | slice 1 | | | - * | 1 | |blank ---- | | - * |________|_______________|___________|_____________| - * - * Inter-pipe Relation (After Adding Plane) - * __________________________________________________ - * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | - * | | plane 0 | slice 0 | | - * | 0 | -------------------------ODM----------- | - * | | plane 0 | slice 1 | | | - * | 1 | ------------------------- | | - * |________|_______________|___________|_____________| - */ -static bool add_plane_to_opp_head_pipes(struct pipe_ctx *otg_master_pipe, - struct dc_plane_state *plane_state, - struct dc_state *context) +static void update_stream_engine_usage( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct stream_encoder *stream_enc, + bool acquired) { - struct pipe_ctx *opp_head_pipe = otg_master_pipe; + int i; - while (opp_head_pipe) { - if (opp_head_pipe->plane_state) { - ASSERT(0); - return false; - } - opp_head_pipe->plane_state = plane_state; - opp_head_pipe = opp_head_pipe->next_odm_pipe; + for (i = 0; i < pool->stream_enc_count; i++) { + if (pool->stream_enc[i] == stream_enc) + res_ctx->is_stream_enc_acquired[i] = acquired; } +} - return true; +static void update_hpo_dp_stream_engine_usage( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct hpo_dp_stream_encoder *hpo_dp_stream_enc, + bool acquired) +{ + int i; + + for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { + if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc) + res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired; + } } -/* For each OPP head of an OTG master, acquire a secondary DPP pipe and add - * the plane. So the plane is added to all ODM slices associated with the OTG - * master pipe in the bottom layer. - * - * In the following example, the stream has 2 ODM slices and a top plane 0. - * By acquiring secondary DPP pipes and adding a plane 1, we are configuring our - * hardware to render the plane 1 by acquiring a new pipe for each ODM slice and - * render plane 1 using new pipes' DPP in the Z axis below plane 0. - * - * Inter-pipe Relation (Before Adding Plane) - * __________________________________________________ - * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | - * | | plane 0 | slice 0 | | - * | 0 | -------------------------ODM----------- | - * | | plane 0 | slice 1 | | | - * | 1 | ------------------------- | | - * |________|_______________|___________|_____________| - * - * Inter-pipe Relation (After Acquiring and Adding Plane) - * __________________________________________________ - * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | - * | | plane 0 | slice 0 | | - * | 0 | -------------MPC---------ODM----------- | - * | | plane 1 | | | | | - * | 2 | ------------- | | | | - * | | plane 0 | slice 1 | | | - * | 1 | -------------MPC--------- | | - * | | plane 1 | | | | - * | 3 | ------------- | | | - * |________|_______________|___________|_____________| - */ -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) +static inline int find_acquired_hpo_dp_link_enc_for_link( + const struct resource_context *res_ctx, + const struct dc_link *link) { - struct pipe_ctx *opp_head_pipe, *sec_pipe, *tail_pipe; + int i; - if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe) - return false; + for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++) + if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 && + res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index) + return i; - opp_head_pipe = otg_master_pipe; - while (opp_head_pipe) { - sec_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe( - cur_ctx, - new_ctx, - pool, + return -1; +} + +static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx, + const struct resource_pool *pool) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++) + if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0) + break; + + return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) && + i < pool->hpo_dp_link_enc_count) ? i : -1; +} + +static inline void acquire_hpo_dp_link_enc( + struct resource_context *res_ctx, + unsigned int link_index, + int enc_index) +{ + res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index; + res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1; +} + +static inline void retain_hpo_dp_link_enc( + struct resource_context *res_ctx, + int enc_index) +{ + res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++; +} + +static inline void release_hpo_dp_link_enc( + struct resource_context *res_ctx, + int enc_index) +{ + ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0); + res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--; +} + +static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx, + const struct resource_pool *pool, + struct pipe_ctx *pipe_ctx, + struct dc_stream_state *stream) +{ + int enc_index; + + enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); + + if (enc_index >= 0) { + retain_hpo_dp_link_enc(res_ctx, enc_index); + } else { + enc_index = find_free_hpo_dp_link_enc(res_ctx, pool); + if (enc_index >= 0) + acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index); + } + + if (enc_index >= 0) + pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index]; + + return pipe_ctx->link_res.hpo_dp_link_enc != NULL; +} + +static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx, + struct pipe_ctx *pipe_ctx, + struct dc_stream_state *stream) +{ + int enc_index; + + enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); + + if (enc_index >= 0) { + release_hpo_dp_link_enc(res_ctx, enc_index); + pipe_ctx->link_res.hpo_dp_link_enc = NULL; + } +} + +enum dc_status resource_add_otg_master_for_stream_output(struct dc_state *new_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream) +{ + struct dc *dc = stream->ctx->dc; + + return dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream); +} + +void resource_remove_otg_master_for_stream_output(struct dc_state *context, + const struct resource_pool *pool, + struct dc_stream_state *stream) +{ + struct pipe_ctx *otg_master = resource_get_otg_master_for_stream( + &context->res_ctx, stream); + + ASSERT(resource_get_odm_slice_count(otg_master) == 1); + ASSERT(otg_master->plane_state == NULL); + ASSERT(otg_master->stream_res.stream_enc); + update_stream_engine_usage( + &context->res_ctx, + pool, + otg_master->stream_res.stream_enc, + false); + + if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(otg_master)) { + update_hpo_dp_stream_engine_usage( + &context->res_ctx, pool, + otg_master->stream_res.hpo_dp_stream_enc, + false); + remove_hpo_dp_link_enc_from_ctx( + &context->res_ctx, otg_master, stream); + } + if (otg_master->stream_res.audio) + update_audio_usage( + &context->res_ctx, + pool, + otg_master->stream_res.audio, + false); + + resource_unreference_clock_source(&context->res_ctx, + pool, + otg_master->clock_source); + + if (pool->funcs->remove_stream_from_ctx) + pool->funcs->remove_stream_from_ctx( + stream->ctx->dc, context, stream); + memset(otg_master, 0, sizeof(*otg_master)); +} + +/* For each OPP head of an OTG master, add top plane at plane index 0. + * + * In the following example, the stream has 2 ODM slices without a top plane. + * By adding a plane 0 to OPP heads, we are configuring our hardware to render + * plane 0 by using each OPP head's DPP. + * + * Inter-pipe Relation (Before Adding Plane) + * __________________________________________________ + * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | + * | | | slice 0 | | + * | 0 | |blank ----ODM----------- | + * | | | slice 1 | | | + * | 1 | |blank ---- | | + * |________|_______________|___________|_____________| + * + * Inter-pipe Relation (After Adding Plane) + * __________________________________________________ + * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | + * | | plane 0 | slice 0 | | + * | 0 | -------------------------ODM----------- | + * | | plane 0 | slice 1 | | | + * | 1 | ------------------------- | | + * |________|_______________|___________|_____________| + */ +static bool add_plane_to_opp_head_pipes(struct pipe_ctx *otg_master_pipe, + struct dc_plane_state *plane_state, + struct dc_state *context) +{ + struct pipe_ctx *opp_head_pipe = otg_master_pipe; + + while (opp_head_pipe) { + if (opp_head_pipe->plane_state) { + ASSERT(0); + return false; + } + opp_head_pipe->plane_state = plane_state; + opp_head_pipe = opp_head_pipe->next_odm_pipe; + } + + return true; +} + +/* For each OPP head of an OTG master, acquire a secondary DPP pipe and add + * the plane. So the plane is added to all ODM slices associated with the OTG + * master pipe in the bottom layer. + * + * In the following example, the stream has 2 ODM slices and a top plane 0. + * By acquiring secondary DPP pipes and adding a plane 1, we are configuring our + * hardware to render the plane 1 by acquiring a new pipe for each ODM slice and + * render plane 1 using new pipes' DPP in the Z axis below plane 0. + * + * Inter-pipe Relation (Before Adding Plane) + * __________________________________________________ + * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | + * | | plane 0 | slice 0 | | + * | 0 | -------------------------ODM----------- | + * | | plane 0 | slice 1 | | | + * | 1 | ------------------------- | | + * |________|_______________|___________|_____________| + * + * Inter-pipe Relation (After Acquiring and Adding Plane) + * __________________________________________________ + * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | + * | | plane 0 | slice 0 | | + * | 0 | -------------MPC---------ODM----------- | + * | | plane 1 | | | | | + * | 2 | ------------- | | | | + * | | plane 0 | slice 1 | | | + * | 1 | -------------MPC--------- | | + * | | plane 1 | | | | + * | 3 | ------------- | | | + * |________|_______________|___________|_____________| + */ +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, *tail_pipe; + + if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe) { + ASSERT(0); + return false; + } + + opp_head_pipe = otg_master_pipe; + while (opp_head_pipe) { + sec_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe( + cur_ctx, + new_ctx, + pool, opp_head_pipe); if (!sec_pipe) { /* try tearing down MPCC combine */ @@ -2027,64 +2259,52 @@ static bool acquire_secondary_dpp_pipes_and_add_plane( return true; } -/* - * Acquire a pipe as OTG master and assign to the stream in new dc context. - * return - true if OTG master pipe is acquired and new dc context is updated. - * false if it fails to acquire an OTG master pipe for this stream. - * - * In the example below, we acquired pipe 0 as OTG master pipe for the stream. - * After the function its Inter-pipe Relation is represented by the diagram - * below. - * - * Inter-pipe Relation - * __________________________________________________ - * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | - * | | | | | - * | 0 | |blank ------------------ | - * |________|_______________|___________|_____________| - */ -static bool acquire_otg_master_pipe_for_stream( +bool resource_append_dpp_pipes_for_plane_composition( struct dc_state *new_ctx, + struct dc_state *cur_ctx, + struct resource_pool *pool, + struct pipe_ctx *otg_master_pipe, + struct dc_plane_state *plane_state) +{ + if (otg_master_pipe->plane_state == NULL) + return add_plane_to_opp_head_pipes(otg_master_pipe, + plane_state, new_ctx); + else + return acquire_secondary_dpp_pipes_and_add_plane( + otg_master_pipe, plane_state, new_ctx, + cur_ctx, pool); +} + +void resource_remove_dpp_pipes_for_plane_composition( + struct dc_state *context, const struct resource_pool *pool, - struct dc_stream_state *stream) + const struct dc_plane_state *plane_state) { - /* TODO: Move this function to DCN specific resource file and acquire - * DSC resource here. The reason is that the function should have the - * same level of responsibility as when we acquire secondary OPP head. - * We acquire DSC when we acquire secondary OPP head, so we should - * acquire DSC when we acquire OTG master. - */ - int pipe_idx; - struct pipe_ctx *pipe_ctx = NULL; + int i; + for (i = pool->pipe_count - 1; i >= 0; i--) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - pipe_idx = resource_find_any_free_pipe(&new_ctx->res_ctx, pool); - if (pipe_idx != FREE_PIPE_INDEX_NOT_FOUND) { - pipe_ctx = &new_ctx->res_ctx.pipe_ctx[pipe_idx]; - memset(pipe_ctx, 0, sizeof(*pipe_ctx)); - pipe_ctx->pipe_idx = pipe_idx; - pipe_ctx->stream_res.tg = pool->timing_generators[pipe_idx]; - pipe_ctx->plane_res.mi = pool->mis[pipe_idx]; - pipe_ctx->plane_res.hubp = pool->hubps[pipe_idx]; - pipe_ctx->plane_res.ipp = pool->ipps[pipe_idx]; - pipe_ctx->plane_res.xfm = pool->transforms[pipe_idx]; - pipe_ctx->plane_res.dpp = pool->dpps[pipe_idx]; - pipe_ctx->stream_res.opp = pool->opps[pipe_idx]; - if (pool->dpps[pipe_idx]) - pipe_ctx->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst; + if (pipe_ctx->plane_state == plane_state) { + if (pipe_ctx->top_pipe) + pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe; - if (pipe_idx >= pool->timing_generator_count) { - int tg_inst = pool->timing_generator_count - 1; + /* Second condition is to avoid setting NULL to top pipe + * of tail pipe making it look like head pipe in subsequent + * deletes + */ + if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe) + pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe; - pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; - pipe_ctx->stream_res.opp = pool->opps[tg_inst]; + /* + * For head pipe detach surfaces from pipe for tail + * pipe just zero it out + */ + if (!pipe_ctx->top_pipe) + pipe_ctx->plane_state = NULL; + else + memset(pipe_ctx, 0, sizeof(*pipe_ctx)); } - - pipe_ctx->stream = stream; - } else { - pipe_idx = acquire_first_split_pipe(&new_ctx->res_ctx, pool, stream); } - - return pipe_idx != FREE_PIPE_INDEX_NOT_FOUND; } /* @@ -2127,12 +2347,17 @@ static bool acquire_pipes_and_add_odm_slice( const struct resource_pool *pool) { struct pipe_ctx *last_opp_head = get_last_opp_head(otg_master_pipe); - struct pipe_ctx *new_opp_head = pool->funcs->acquire_free_pipe_as_secondary_opp_head( - cur_ctx, new_ctx, pool, - otg_master_pipe); + struct pipe_ctx *new_opp_head; struct pipe_ctx *last_top_dpp_pipe, *last_bottom_dpp_pipe, *new_top_dpp_pipe, *new_bottom_dpp_pipe; + if (!pool->funcs->acquire_free_pipe_as_secondary_opp_head) { + ASSERT(0); + return false; + } + new_opp_head = pool->funcs->acquire_free_pipe_as_secondary_opp_head( + cur_ctx, new_ctx, pool, + otg_master_pipe); if (!new_opp_head) return false; @@ -2203,6 +2428,11 @@ static bool release_pipes_and_remove_odm_slice( struct pipe_ctx *last_opp_head = get_last_opp_head(otg_master_pipe); struct pipe_ctx *tail_pipe = get_tail_pipe(last_opp_head); + if (!pool->funcs->release_pipe) { + ASSERT(0); + return false; + } + if (resource_is_pipe_type(last_opp_head, OTG_MASTER)) return false; @@ -2258,10 +2488,15 @@ static bool acquire_dpp_pipe_and_add_mpc_slice( struct pipe_ctx *last_dpp_pipe = get_last_dpp_pipe_in_mpcc_combine(dpp_pipe); struct pipe_ctx *opp_head = resource_get_opp_head(dpp_pipe); - struct pipe_ctx *new_dpp_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe( - cur_ctx, new_ctx, pool, opp_head); + struct pipe_ctx *new_dpp_pipe; - if (!new_dpp_pipe || resource_get_num_odm_splits(dpp_pipe) > 0) + if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe) { + ASSERT(0); + return false; + } + new_dpp_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe( + cur_ctx, new_ctx, pool, opp_head); + if (!new_dpp_pipe || resource_get_odm_slice_count(dpp_pipe) > 1) return false; new_dpp_pipe->bottom_pipe = last_dpp_pipe->bottom_pipe; @@ -2315,8 +2550,13 @@ static bool release_dpp_pipe_and_remove_mpc_slice( struct pipe_ctx *last_dpp_pipe = get_last_dpp_pipe_in_mpcc_combine(dpp_pipe); + if (!pool->funcs->release_pipe) { + ASSERT(0); + return false; + } + if (resource_is_pipe_type(last_dpp_pipe, OPP_HEAD) || - resource_get_num_odm_splits(dpp_pipe) > 0) + resource_get_odm_slice_count(dpp_pipe) > 1) return false; last_dpp_pipe->top_pipe->bottom_pipe = last_dpp_pipe->bottom_pipe; @@ -2327,15 +2567,17 @@ static bool release_dpp_pipe_and_remove_mpc_slice( return true; } -bool resource_update_pipes_with_odm_slice_count( - struct pipe_ctx *otg_master, +bool resource_update_pipes_for_stream_with_slice_count( struct dc_state *new_ctx, const struct dc_state *cur_ctx, const struct resource_pool *pool, + const struct dc_stream_state *stream, int new_slice_count) { int i; - int cur_slice_count = resource_get_num_odm_splits(otg_master) + 1; + struct pipe_ctx *otg_master = resource_get_otg_master_for_stream( + &new_ctx->res_ctx, stream); + int cur_slice_count = resource_get_odm_slice_count(otg_master); bool result = true; if (new_slice_count == cur_slice_count) @@ -2355,31 +2597,38 @@ bool resource_update_pipes_with_odm_slice_count( return result; } -bool resource_update_pipes_with_mpc_slice_count( - struct pipe_ctx *dpp_pipe, +bool resource_update_pipes_for_plane_with_slice_count( struct dc_state *new_ctx, const struct dc_state *cur_ctx, const struct resource_pool *pool, + const struct dc_plane_state *plane, int new_slice_count) { int i; - int cur_slice_count = resource_get_num_mpc_splits(dpp_pipe) + 1; + int dpp_pipe_count; + int cur_slice_count; + struct pipe_ctx *dpp_pipes[MAX_PIPES]; bool result = true; + dpp_pipe_count = resource_get_dpp_pipes_for_plane(plane, + &new_ctx->res_ctx, dpp_pipes); + ASSERT(dpp_pipe_count > 0); + cur_slice_count = resource_get_mpc_slice_count(dpp_pipes[0]); + if (new_slice_count == cur_slice_count) return result; if (new_slice_count > cur_slice_count) for (i = 0; i < new_slice_count - cur_slice_count && result; i++) result = acquire_dpp_pipe_and_add_mpc_slice( - dpp_pipe, new_ctx, cur_ctx, pool); + dpp_pipes[0], new_ctx, cur_ctx, pool); else for (i = 0; i < cur_slice_count - new_slice_count && result; i++) result = release_dpp_pipe_and_remove_mpc_slice( - dpp_pipe, new_ctx, pool); + dpp_pipes[0], new_ctx, pool); if (result) result = update_pipe_params_after_mpc_slice_count_change( - dpp_pipe->plane_state, new_ctx, pool); + dpp_pipes[0]->plane_state, new_ctx, pool); return result; } @@ -2406,13 +2655,9 @@ bool dc_add_plane_to_context( otg_master_pipe = resource_get_otg_master_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); + added = resource_append_dpp_pipes_for_plane_composition(context, + dc->current_state, pool, otg_master_pipe, plane_state); + if (added) { stream_status->plane_states[stream_status->plane_count] = plane_state; @@ -2448,32 +2693,8 @@ bool dc_remove_plane_from_context( return false; } - /* release pipe for plane*/ - for (i = pool->pipe_count - 1; i >= 0; i--) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->plane_state == plane_state) { - if (pipe_ctx->top_pipe) - pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe; - - /* Second condition is to avoid setting NULL to top pipe - * of tail pipe making it look like head pipe in subsequent - * deletes - */ - if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe) - pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe; - - /* - * For head pipe detach surfaces from pipe for tail - * pipe just zero it out - */ - if (!pipe_ctx->top_pipe) - pipe_ctx->plane_state = NULL; - else - memset(pipe_ctx, 0, sizeof(*pipe_ctx)); - } - } - + resource_remove_dpp_pipes_for_plane_composition( + context, pool, plane_state); for (i = 0; i < stream_status->plane_count; i++) { if (stream_status->plane_states[i] == plane_state) { @@ -2672,122 +2893,6 @@ bool dc_is_stream_scaling_unchanged(struct dc_stream_state *old_stream, return true; } -static void update_stream_engine_usage( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct stream_encoder *stream_enc, - bool acquired) -{ - int i; - - for (i = 0; i < pool->stream_enc_count; i++) { - if (pool->stream_enc[i] == stream_enc) - res_ctx->is_stream_enc_acquired[i] = acquired; - } -} - -static void update_hpo_dp_stream_engine_usage( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct hpo_dp_stream_encoder *hpo_dp_stream_enc, - bool acquired) -{ - int i; - - for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { - if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc) - res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired; - } -} - -static inline int find_acquired_hpo_dp_link_enc_for_link( - const struct resource_context *res_ctx, - const struct dc_link *link) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++) - if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 && - res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index) - return i; - - return -1; -} - -static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx, - const struct resource_pool *pool) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++) - if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0) - break; - - return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) && - i < pool->hpo_dp_link_enc_count) ? i : -1; -} - -static inline void acquire_hpo_dp_link_enc( - struct resource_context *res_ctx, - unsigned int link_index, - int enc_index) -{ - res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index; - res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1; -} - -static inline void retain_hpo_dp_link_enc( - struct resource_context *res_ctx, - int enc_index) -{ - res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++; -} - -static inline void release_hpo_dp_link_enc( - struct resource_context *res_ctx, - int enc_index) -{ - ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0); - res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--; -} - -static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx, - const struct resource_pool *pool, - struct pipe_ctx *pipe_ctx, - struct dc_stream_state *stream) -{ - int enc_index; - - enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); - - if (enc_index >= 0) { - retain_hpo_dp_link_enc(res_ctx, enc_index); - } else { - enc_index = find_free_hpo_dp_link_enc(res_ctx, pool); - if (enc_index >= 0) - acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index); - } - - if (enc_index >= 0) - pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index]; - - return pipe_ctx->link_res.hpo_dp_link_enc != NULL; -} - -static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx, - struct pipe_ctx *pipe_ctx, - struct dc_stream_state *stream) -{ - int enc_index; - - enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); - - if (enc_index >= 0) { - release_hpo_dp_link_enc(res_ctx, enc_index); - pipe_ctx->link_res.hpo_dp_link_enc = NULL; - } -} - /* TODO: release audio object */ void update_audio_usage( struct resource_context *res_ctx, @@ -2872,7 +2977,8 @@ enum dc_status dc_add_stream_to_ctx( dc_stream_retain(stream); new_ctx->stream_count++; - res = dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream); + res = resource_add_otg_master_for_stream_output( + new_ctx, dc->res_pool, stream); if (res != DC_OK) DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res); @@ -2889,53 +2995,18 @@ enum dc_status dc_remove_stream_from_ctx( { int i; struct dc_context *dc_ctx = dc->ctx; - struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream(&new_ctx->res_ctx, stream); - struct pipe_ctx *odm_pipe; + struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream( + &new_ctx->res_ctx, stream); if (!del_pipe) { DC_ERROR("Pipe not found for stream %p !\n", stream); return DC_ERROR_UNEXPECTED; } - odm_pipe = del_pipe->next_odm_pipe; - - /* Release primary pipe */ - ASSERT(del_pipe->stream_res.stream_enc); - update_stream_engine_usage( - &new_ctx->res_ctx, - dc->res_pool, - del_pipe->stream_res.stream_enc, - false); - - if (dc->link_srv->dp_is_128b_132b_signal(del_pipe)) { - update_hpo_dp_stream_engine_usage( - &new_ctx->res_ctx, dc->res_pool, - del_pipe->stream_res.hpo_dp_stream_enc, - false); - remove_hpo_dp_link_enc_from_ctx(&new_ctx->res_ctx, del_pipe, del_pipe->stream); - } - - if (del_pipe->stream_res.audio) - update_audio_usage( - &new_ctx->res_ctx, - dc->res_pool, - del_pipe->stream_res.audio, - false); - - resource_unreference_clock_source(&new_ctx->res_ctx, - dc->res_pool, - del_pipe->clock_source); - - if (dc->res_pool->funcs->remove_stream_from_ctx) - dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream); - - while (odm_pipe) { - struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe; - - memset(odm_pipe, 0, sizeof(*odm_pipe)); - odm_pipe = next_odm_pipe; - } - memset(del_pipe, 0, sizeof(*del_pipe)); + resource_update_pipes_for_stream_with_slice_count(new_ctx, + dc->current_state, dc->res_pool, stream, 1); + resource_remove_otg_master_for_stream_output( + new_ctx, dc->res_pool, stream); for (i = 0; i < new_ctx->stream_count; i++) if (new_ctx->streams[i] == stream) @@ -3154,6 +3225,66 @@ static void mark_seamless_boot_stream( } } +/* + * Acquire a pipe as OTG master and assign to the stream in new dc context. + * return - true if OTG master pipe is acquired and new dc context is updated. + * false if it fails to acquire an OTG master pipe for this stream. + * + * In the example below, we acquired pipe 0 as OTG master pipe for the stream. + * After the function its Inter-pipe Relation is represented by the diagram + * below. + * + * Inter-pipe Relation + * __________________________________________________ + * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | + * | | | | | + * | 0 | |blank ------------------ | + * |________|_______________|___________|_____________| + */ +static bool acquire_otg_master_pipe_for_stream( + struct dc_state *new_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream) +{ + /* TODO: Move this function to DCN specific resource file and acquire + * DSC resource here. The reason is that the function should have the + * same level of responsibility as when we acquire secondary OPP head. + * We acquire DSC when we acquire secondary OPP head, so we should + * acquire DSC when we acquire OTG master. + */ + int pipe_idx; + struct pipe_ctx *pipe_ctx = NULL; + + pipe_idx = resource_find_any_free_pipe(&new_ctx->res_ctx, pool); + if (pipe_idx != FREE_PIPE_INDEX_NOT_FOUND) { + pipe_ctx = &new_ctx->res_ctx.pipe_ctx[pipe_idx]; + memset(pipe_ctx, 0, sizeof(*pipe_ctx)); + pipe_ctx->pipe_idx = pipe_idx; + pipe_ctx->stream_res.tg = pool->timing_generators[pipe_idx]; + pipe_ctx->plane_res.mi = pool->mis[pipe_idx]; + pipe_ctx->plane_res.hubp = pool->hubps[pipe_idx]; + pipe_ctx->plane_res.ipp = pool->ipps[pipe_idx]; + pipe_ctx->plane_res.xfm = pool->transforms[pipe_idx]; + pipe_ctx->plane_res.dpp = pool->dpps[pipe_idx]; + pipe_ctx->stream_res.opp = pool->opps[pipe_idx]; + if (pool->dpps[pipe_idx]) + pipe_ctx->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst; + + if (pipe_idx >= pool->timing_generator_count) { + int tg_inst = pool->timing_generator_count - 1; + + pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; + pipe_ctx->stream_res.opp = pool->opps[tg_inst]; + } + + pipe_ctx->stream = stream; + } else { + pipe_idx = acquire_first_split_pipe(&new_ctx->res_ctx, pool, stream); + } + + return pipe_idx != FREE_PIPE_INDEX_NOT_FOUND; +} + enum dc_status resource_map_pool_resources( const struct dc *dc, struct dc_state *context, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index f3db16cd10db..347156d02f21 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -614,6 +614,8 @@ void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); pipe_ctx->top_pipe = NULL; pipe_ctx->bottom_pipe = NULL; + pipe_ctx->prev_odm_pipe = NULL; + pipe_ctx->next_odm_pipe = NULL; pipe_ctx->plane_state = NULL; } 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 d587f807dfd7..2820393d5c6f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -1948,7 +1948,7 @@ int dcn20_validate_apply_pipe_split_flags( v->ODMCombineEnablePerState[vlevel][pipe_plane]; if (v->ODMCombineEnabled[pipe_plane] == dm_odm_combine_mode_disabled) { - if (resource_get_num_mpc_splits(pipe) == 1) { + if (resource_get_mpc_slice_count(pipe) == 2) { /*If need split for mpc but 2 way split already*/ if (split[i] == 4) split[i] = 2; /* 2 -> 4 MPC */ @@ -1956,7 +1956,7 @@ int dcn20_validate_apply_pipe_split_flags( split[i] = 0; /* 2 -> 2 MPC */ else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) merge[i] = true; /* 2 -> 1 MPC */ - } else if (resource_get_num_mpc_splits(pipe) == 3) { + } else if (resource_get_mpc_slice_count(pipe) == 4) { /*If need split for mpc but 4 way split already*/ if (split[i] == 2 && ((pipe->top_pipe && !pipe->top_pipe->top_pipe) || !pipe->bottom_pipe)) { @@ -1965,7 +1965,7 @@ int dcn20_validate_apply_pipe_split_flags( pipe->top_pipe->plane_state == pipe->plane_state) merge[i] = true; /* 4 -> 1 MPC */ split[i] = 0; - } else if (resource_get_num_odm_splits(pipe)) { + } else if (resource_get_odm_slice_count(pipe) > 1) { /* ODM -> MPC transition */ if (pipe->prev_odm_pipe) { split[i] = 0; @@ -1973,7 +1973,7 @@ int dcn20_validate_apply_pipe_split_flags( } } } else { - if (resource_get_num_odm_splits(pipe) == 1) { + if (resource_get_odm_slice_count(pipe) == 2) { /*If need split for odm but 2 way split already*/ if (split[i] == 4) split[i] = 2; /* 2 -> 4 ODM */ @@ -1983,7 +1983,7 @@ int dcn20_validate_apply_pipe_split_flags( ASSERT(0); /* NOT expected yet */ merge[i] = true; /* exit ODM */ } - } else if (resource_get_num_odm_splits(pipe) == 3) { + } else if (resource_get_odm_slice_count(pipe) == 4) { /*If need split for odm but 4 way split already*/ if (split[i] == 2 && ((pipe->prev_odm_pipe && !pipe->prev_odm_pipe->prev_odm_pipe) || !pipe->next_odm_pipe)) { @@ -1993,7 +1993,7 @@ int dcn20_validate_apply_pipe_split_flags( merge[i] = true; /* exit ODM */ } split[i] = 0; - } else if (resource_get_num_mpc_splits(pipe)) { + } else if (resource_get_mpc_slice_count(pipe) > 1) { /* MPC -> ODM transition */ ASSERT(0); /* NOT expected yet */ if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) { @@ -2211,12 +2211,22 @@ enum dc_status dcn20_patch_unknown_plane_state(struct dc_plane_state *plane_stat return DC_OK; } +void dcn20_release_pipe(struct dc_state *context, + struct pipe_ctx *pipe, + const struct resource_pool *pool) +{ + if (resource_is_pipe_type(pipe, OPP_HEAD) && pipe->stream_res.dsc) + dcn20_release_dsc(&context->res_ctx, pool, &pipe->stream_res.dsc); + memset(pipe, 0, sizeof(*pipe)); +} + static const struct resource_funcs dcn20_res_pool_funcs = { .destroy = dcn20_destroy_resource_pool, .link_enc_create = dcn20_link_encoder_create, .panel_cntl_create = dcn20_panel_cntl_create, .validate_bandwidth = dcn20_validate_bandwidth, .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, .add_stream_to_ctx = dcn20_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/dcn20/dcn20_resource.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h index 6d1a8924e57b..37ecaccc5d12 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h @@ -63,7 +63,9 @@ struct pipe_ctx *dcn20_acquire_free_pipe_for_layer( struct dc_state *new_ctx, const struct resource_pool *pool, const struct pipe_ctx *opp_head_pipe); - +void dcn20_release_pipe(struct dc_state *context, + struct pipe_ctx *pipe, + const struct resource_pool *pool); struct stream_encoder *dcn20_stream_encoder_create( enum engine_id eng_id, struct dc_context *ctx); 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 2dc4d2c1410b..9389bd8df42b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c @@ -1069,6 +1069,7 @@ static struct resource_funcs dcn201_res_pool_funcs = { .add_dsc_to_stream_resource = NULL, .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, .acquire_free_pipe_as_secondary_dpp_pipe = dcn201_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, .populate_dml_writeback_from_context = dcn201_populate_dml_writeback_from_context, .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .set_mcif_arb_params = dcn20_set_mcif_arb_params, diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c index d1a25fe6c44f..71e82692dd7c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c @@ -1389,6 +1389,7 @@ static const struct resource_funcs dcn21_res_pool_funcs = { .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, .populate_dml_writeback_from_context = dcn20_populate_dml_writeback_from_context, .patch_unknown_plane_state = dcn21_patch_unknown_plane_state, .set_mcif_arb_params = dcn20_set_mcif_arb_params, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index 88c0b24a3249..da56962227fd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -2217,6 +2217,7 @@ static const struct resource_funcs dcn30_res_pool_funcs = { .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, .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/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c index 79d6697d13b6..c489ad043b87 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c @@ -1380,6 +1380,7 @@ static struct resource_funcs dcn301_res_pool_funcs = { .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, .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/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c index 447abcd593be..f5b8b92a84f2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c @@ -1137,6 +1137,7 @@ static struct resource_funcs dcn302_res_pool_funcs = { .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, .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/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c index adf4989177f7..d59561605c17 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c @@ -1063,6 +1063,7 @@ static struct resource_funcs dcn303_res_pool_funcs = { .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, .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/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index 82de4fe2637f..994289b3d5a3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -1824,6 +1824,7 @@ static struct resource_funcs dcn31_res_pool_funcs = { .update_soc_for_wm_a = dcn31_update_soc_for_wm_a, .populate_dml_pipes = dcn31_populate_dml_pipes_from_context, .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, .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/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index 004beed9bd44..4d0052ca742f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -1796,6 +1796,7 @@ static struct resource_funcs dcn314_res_pool_funcs = { .update_soc_for_wm_a = dcn31_update_soc_for_wm_a, .populate_dml_pipes = dcn314_populate_dml_pipes_from_context, .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, .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/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c index 127487ea3d7d..8e3acb92385b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c @@ -1819,6 +1819,7 @@ static struct resource_funcs dcn315_res_pool_funcs = { .update_soc_for_wm_a = dcn315_update_soc_for_wm_a, .populate_dml_pipes = dcn315_populate_dml_pipes_from_context, .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, .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/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c index 5fe2c61527df..9133a1ea4ca0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c @@ -1706,6 +1706,7 @@ static struct resource_funcs dcn316_res_pool_funcs = { .update_soc_for_wm_a = dcn31_update_soc_for_wm_a, .populate_dml_pipes = dcn316_populate_dml_pipes_from_context, .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, .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/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c index 072c5ba4c99c..88c9dbbacbd3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c @@ -2040,7 +2040,7 @@ static struct resource_funcs dcn32_res_pool_funcs = { .populate_dml_pipes = dcn32_populate_dml_pipes_from_context, .acquire_free_pipe_as_secondary_dpp_pipe = dcn32_acquire_free_pipe_as_secondary_dpp_pipe, .acquire_free_pipe_as_secondary_opp_head = dcn32_acquire_free_pipe_as_secondary_opp_head, - .release_pipe = dcn32_release_pipe, + .release_pipe = dcn20_release_pipe, .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, @@ -2778,15 +2778,6 @@ struct pipe_ctx *dcn32_acquire_free_pipe_as_secondary_opp_head( return free_pipe; } -void dcn32_release_pipe(struct dc_state *context, - struct pipe_ctx *pipe, - const struct resource_pool *pool) -{ - if (resource_is_pipe_type(pipe, OPP_HEAD) && pipe->stream_res.dsc) - dcn20_release_dsc(&context->res_ctx, pool, &pipe->stream_res.dsc); - memset(pipe, 0, sizeof(*pipe)); -} - unsigned int dcn32_calc_num_avail_chans_for_mall(struct dc *dc, int num_chans) { /* 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 8d73cceb485b..7d40fb6156f3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c @@ -1589,6 +1589,7 @@ static struct resource_funcs dcn321_res_pool_funcs = { .calculate_wm_and_dlg = dcn32_calculate_wm_and_dlg, .populate_dml_pipes = dcn32_populate_dml_pipes_from_context, .acquire_free_pipe_as_secondary_dpp_pipe = dcn32_acquire_free_pipe_as_secondary_dpp_pipe, + .release_pipe = dcn20_release_pipe, .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/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c index 8afda5ecc0cd..0989a0152ae8 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c @@ -1305,11 +1305,11 @@ int dcn20_populate_dml_pipes_from_context(struct dc *dc, pipes[pipe_cnt].dout.is_virtual = 0; pipes[pipe_cnt].pipe.dest.vtotal_min = res_ctx->pipe_ctx[i].stream->adjust.v_total_min; pipes[pipe_cnt].pipe.dest.vtotal_max = res_ctx->pipe_ctx[i].stream->adjust.v_total_max; - switch (resource_get_num_odm_splits(&res_ctx->pipe_ctx[i])) { - case 1: + switch (resource_get_odm_slice_count(&res_ctx->pipe_ctx[i])) { + case 2: pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_2to1; break; - case 3: + case 4: pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_4to1; break; default: diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index 4344c5a239e1..55efd5600521 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -238,8 +238,8 @@ enum pipe_type { /* OTG master pipe - the master pipe of its OPP head pipes with a * functional OTG. It merges all its OPP head pipes pixel data in ODM - * block and output to backend DIG. OTG master pipe is responsible for - * generating entire crtc timing to backend DIG. An OTG master pipe may + * block and output to back end DIG. OTG master pipe is responsible for + * generating entire CRTC timing to back end DIG. An OTG master pipe may * or may not have a plane. If it has a plane it blends it as the left * most MPC slice of the top most layer. If it doesn't have a plane it * can output pixel data from its OPP head pipes' test pattern @@ -267,33 +267,175 @@ enum pipe_type { }; /* - * Determine if the input pipe ctx is of a pipe type. - * return - true if pipe ctx is of the input type. + * Determine if the input pipe_ctx is of a pipe type. + * return - true if pipe_ctx is of the input type. */ bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type); /* - * Determine if the input pipe ctx is used for rendering a plane with MPCC - * combine. MPCC combine is a hardware feature to combine multiple DPP pipes - * into a single plane. It is typically used for bypassing pipe bandwidth - * limitation for rendering a very large plane or saving power by reducing UCLK - * and DPPCLK speeds. + * Acquire a pipe as OTG master pipe and allocate pipe resources required to + * enable stream output. + */ +enum dc_status resource_add_otg_master_for_stream_output(struct dc_state *new_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream); + +/* + * Release pipe resources and the OTG master pipe associated with the stream + * The stream must have all planes removed and ODM/MPC slice counts are reset + * to 1 before invoking this interface. + */ +void resource_remove_otg_master_for_stream_output(struct dc_state *new_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream); + +/* + * Add plane to the bottom most layer in plane composition and allocate DPP pipe + * resources as needed. + * return - true if plane is added in plane composition, false otherwise. + */ +bool resource_append_dpp_pipes_for_plane_composition( + struct dc_state *new_ctx, + struct dc_state *cur_ctx, + struct resource_pool *pool, + struct pipe_ctx *otg_master_pipe, + struct dc_plane_state *plane_state); + +/* + * Add plane to the bottom most layer in plane composition and allocate DPP pipe + * resources as needed. + * return - true if plane is added in plane composition, false otherwise. + */ +void resource_remove_dpp_pipes_for_plane_composition( + struct dc_state *context, + const struct resource_pool *pool, + const struct dc_plane_state *plane_state); + +/* + * Update ODM slice count by acquiring or releasing pipes. If new slices need + * to be added, it is going to add them to the last ODM index. If existing + * slices need to be removed, it is going to remove them from the last ODM + * index. * - * For instance in the Inter-pipe Relation diagram shown below, both PIPE 0 and - * 1 are for MPCC combine for plane 0 + * return - true if ODM slices are updated and required pipes are acquired. All + * affected pipe parameters are updated. * - * Inter-pipe Relation - * __________________________________________________ - * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | - * | | plane 0 | | | - * | 0 | -------------MPC----------------------- | - * | | plane 0 | | | | - * | 1 | ------------- | | | - * |________|_______________|___________|_____________| + * false if resource fails to complete this update. The function is not designed + * to recover the creation of invalid topologies. Returning false is typically + * an indication of insufficient validation in caller's stack. new_ctx will be + * invalid. Caller may attempt to restore new_ctx by calling this function + * again with original slice count. + */ +bool resource_update_pipes_for_stream_with_slice_count( + struct dc_state *new_ctx, + const struct dc_state *cur_ctx, + const struct resource_pool *pool, + const struct dc_stream_state *stream, + int new_slice_count); + +/* + * Update MPC slice count by acquiring or releasing DPP pipes. If new slices + * need to be added it is going to add to the last MPC index. If existing + * slices need to be removed, it is going to remove them from the last MPC + * index. + * + * @dpp_pipe - top most dpp pipe for MPCC combine. + * + * return - true if MPC slices are updated and required pipes are acquired. All + * affected pipe parameters are updated. * - * return - true if pipe ctx is used for mpcc combine. + * false if resource fails to complete this update. The function is not designed + * to recover the creation of invalid topologies. Returning false is typically + * an indication of insufficient validation in caller's stack. new_ctx will be + * invalid. Caller may attempt to restore new_ctx by calling this function + * again with original slice count. + */ +bool resource_update_pipes_for_plane_with_slice_count( + struct dc_state *new_ctx, + const struct dc_state *cur_ctx, + const struct resource_pool *pool, + const struct dc_plane_state *plane, + int slice_count); + +/* + * Get the OTG master pipe in resource context associated with the stream. + * return - NULL if not found. Otherwise the OTG master pipe associated with the + * stream. + */ +struct pipe_ctx *resource_get_otg_master_for_stream( + struct resource_context *res_ctx, + const struct dc_stream_state *stream); + +/* + * Get an array of OPP heads in opp_heads ordered with index low to high for OTG + * master pipe in res_ctx. + * return - number of OPP heads in the array. If otg_master passed in is not + * an OTG master, the function returns 0. + */ +int resource_get_opp_heads_for_otg_master(const struct pipe_ctx *otg_master, + struct resource_context *res_ctx, + struct pipe_ctx *opp_heads[MAX_PIPES]); + +/* + * Get an array of DPP pipes in dpp_pipes ordered with index low to high for OPP + * head pipe in res_ctx. + * return - number of DPP pipes in the array. If opp_head passed in is not + * an OPP pipe, the function returns 0. + */ +int resource_get_dpp_pipes_for_opp_head(const struct pipe_ctx *opp_head, + struct resource_context *res_ctx, + struct pipe_ctx *dpp_pipes[MAX_PIPES]); + +/* + * Get an array of DPP pipes in dpp_pipes ordered with index low to high for + * plane in res_ctx. + * return - number of DPP pipes in the array. + */ +int resource_get_dpp_pipes_for_plane(const struct dc_plane_state *plane, + struct resource_context *res_ctx, + struct pipe_ctx *dpp_pipes[MAX_PIPES]); + +/* + * Get the OTG master pipe for the input pipe context. + * return - the OTG master pipe for the input pipe + * context. + */ +struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx); + +/* + * Get the OPP head pipe for the input pipe context. + * return - the OPP head pipe for the input pipe + * context. + */ +struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx); + +/* + * Get the MPC slice index counting from 0 from left most slice + * For example, if a DPP pipe is used as a secondary pipe in MPCC combine, MPC + * split index is greater than 0. + */ +int resource_get_mpc_slice_index(const struct pipe_ctx *dpp_pipe); + +/* + * Get number of MPC "cuts" of the plane associated with the pipe. MPC slice + * count is equal to MPC splits + 1. For example if a plane is cut 3 times, it + * will have 4 pieces of slice. + * return - 0 if pipe is not used for a plane with MPCC combine. otherwise + * the number of MPC "cuts" for the plane. + */ +int resource_get_mpc_slice_count(const struct pipe_ctx *opp_head); + +/* + * Get number of ODM "cuts" of the timing associated with the pipe. ODM slice + * count is equal to ODM splits + 1. For example if a timing is cut 3 times, it + * will have 4 pieces of slice. + * return - 0 if pipe is not used for ODM combine. otherwise + * the number of ODM "cuts" for the timing. */ -bool resource_is_for_mpcc_combine(const struct pipe_ctx *pipe_ctx); +int resource_get_odm_slice_count(const struct pipe_ctx *otg_master); + +/* Get the ODM slice index counting from 0 from left most slice */ +int resource_get_odm_slice_index(const struct pipe_ctx *opp_head); /* * Look for a free pipe in new resource context that is used as a secondary OPP @@ -360,100 +502,6 @@ struct pipe_ctx *resource_find_free_secondary_pipe_legacy( const struct resource_pool *pool, const struct pipe_ctx *primary_pipe); -/* - * Get number of MPC "cuts" of the plane associated with the pipe. MPC slice - * count is equal to MPC splits + 1. For example if a plane is cut 3 times, it - * will have 4 pieces of slice. - * return - 0 if pipe is not used for a plane with MPCC combine. otherwise - * the number of MPC "cuts" for the plane. - */ -int resource_get_num_mpc_splits(const struct pipe_ctx *pipe); - -int resource_get_mpc_split_index(struct pipe_ctx *pipe_ctx); - - -/* - * Get number of ODM "cuts" of the timing associated with the pipe. ODM slice - * count is equal to ODM splits + 1. For example if a timing is cut 3 times, it - * will have 4 pieces of slice. - * return - 0 if pipe is not used for ODM combine. otherwise - * the number of ODM "cuts" for the timing. - */ -int resource_get_num_odm_splits(const struct pipe_ctx *pipe); - -int resource_get_odm_split_index(struct pipe_ctx *pipe_ctx); - -/* - * Get the OTG master pipe in resource context associated with the stream. - * return - NULL if not found. Otherwise the OTG master pipe associated with the - * stream. - */ -struct pipe_ctx *resource_get_otg_master_for_stream( - struct resource_context *res_ctx, - struct dc_stream_state *stream); - -/* - * Get the OTG master pipe for the input pipe context. - * return - the OTG master pipe for the input pipe - * context. - */ -struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx); - -/* - * Get the OPP head pipe for the input pipe context. - * return - the OPP head pipe for the input pipe - * context. - */ -struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx); - -/* - * Update ODM slice count by acquiring or releasing pipes. If new slices need - * to be added, it is going to add them to the last ODM index. If existing - * slices need to be removed, it is going to remove them from the last ODM - * index. - * - * return - true if ODM slices are updated and required pipes are acquired. All - * affected pipe parameters are updated. - * - * false if resource fails to complete this update. The function is not designed - * to recover the creation of invalid topologies. Returning false is typically - * an indication of insufficient validation in caller's stack. The function will - * return the new_ctx up until the last valid step performed in the function. - * Caller may use the returned new_ctx for debugging the error or it may attempt - * to restore new_ctx by calling this function again with original slice count. - */ -bool resource_update_pipes_with_odm_slice_count( - struct pipe_ctx *otg_master_pipe, - struct dc_state *new_ctx, - const struct dc_state *cur_ctx, - const struct resource_pool *pool, - int slice_count); - -/* - * Update MPC slice count by acquiring or releasing DPP pipes. If new slices - * need to be added it is going to add to the last MPC index. If existing - * slices need to be removed, it is going to remove them from the last MPC - * index. - * - * @dpp_pipe - top most dpp pipe for MPCC combine. - * - * return - true if MPC slices are updated and required pipes are acquired. All - * affected pipe parameters are updated. - * - * false if resource fails to complete this update. The function is not designed - * to recover the creation of invalid topologies. Returning false is typically - * an indication of insufficient validation in caller's stack. The function will - * return the new_ctx up until the last valid step performed in the function. - * Caller may use the returned new_ctx for debugging the error or it may attempt - * to restore new_ctx by calling this function again with original slice count. - */ -bool resource_update_pipes_with_mpc_slice_count( - struct pipe_ctx *dpp_pipe, - struct dc_state *new_ctx, - const struct dc_state *cur_ctx, - const struct resource_pool *pool, - int slice_count); - bool resource_validate_attach_surfaces( const struct dc_validation_set set[], int set_count, -- 2.41.0