diff options
author | Wenjing Liu <wenjing.liu@amd.com> | 2023-08-10 13:59:29 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2023-08-30 15:35:30 -0400 |
commit | 2174181019e4273e583a0f0a9795e9db38984784 (patch) | |
tree | c397e68e33e4a80f200f57313d05395654a8570d /drivers | |
parent | 7b0c688d4db2a4ecef64ab512a94cc8b154478f7 (diff) | |
download | linux-stable-2174181019e4273e583a0f0a9795e9db38984784.tar.gz linux-stable-2174181019e4273e583a0f0a9795e9db38984784.tar.bz2 linux-stable-2174181019e4273e583a0f0a9795e9db38984784.zip |
drm/amd/display: add more pipe resource interfaces
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.lei@amd.com>
Acked-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers')
18 files changed, 659 insertions, 464 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,6 +1966,172 @@ static int acquire_first_split_pipe( return FREE_PIPE_INDEX_NOT_FOUND; } +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; + } +} + +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. @@ -1984,8 +2214,10 @@ static bool acquire_secondary_dpp_pipes_and_add_plane( { struct pipe_ctx *opp_head_pipe, *sec_pipe, *tail_pipe; - if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_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) { @@ -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, |