From a243e38e699f03b7d73b156564cfd67b78448368 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Thu, 22 Jun 2023 16:14:22 -0400 Subject: drm/amd/display: Skip querying caps when DMCUB emulation is in use [Why] Workaround to avoid accessing DMCUB state too early if the emulator is in use - we don't support any of the features the caps are querying with emulation anyway. [How] Guard the query if emulation is in use. Reviewed-by: Charlene Liu Acked-by: Alan Liu Signed-off-by: Nicholas Kazlauskas Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c') diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index c753c6f30dd7..24433409d7de 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -381,6 +381,9 @@ void dc_dmub_srv_query_caps_cmd(struct dc_dmub_srv *dc_dmub_srv) { union dmub_rb_cmd cmd = { 0 }; + if (dc_dmub_srv->ctx->dc->debug.dmcub_emulation) + return; + memset(&cmd, 0, sizeof(cmd)); /* Prepare fw command */ -- cgit v1.2.3 From 71ba6b577a353fa880b2e5c85cdd780765c51fed Mon Sep 17 00:00:00 2001 From: Stylon Wang Date: Fri, 30 Jun 2023 16:31:58 +0800 Subject: drm/amd/display: Add interface to enable DPIA trace [Why] DPIA traces from DMUB is not enabled by default, which is less convenient to debug DPIA related issues because we have to resort to other debug tools to enable DPIA trace. [How] Exposes interfaces to update trace mask from the DMUB GPINT commands. Also provides DC implementations to enable DPIA trace. Reviewed-by: Aurabindo Pillai Acked-by: Tom Chung Signed-off-by: Stylon Wang Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 29 +++++++++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h | 3 +++ drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 18 +++++++++++++++ 3 files changed, 50 insertions(+) (limited to 'drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c') diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 24433409d7de..8c75f7510880 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -1021,3 +1021,32 @@ bool dc_dmub_check_min_version(struct dmub_srv *srv) return true; return srv->hw_funcs.is_psrsu_supported(srv); } + +void dc_dmub_srv_enable_dpia_trace(const struct dc *dc) +{ + struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv; + struct dmub_srv *dmub; + enum dmub_status status; + static const uint32_t timeout_us = 30; + + if (!dc_dmub_srv || !dc_dmub_srv->dmub) { + DC_LOG_ERROR("%s: invalid parameters.", __func__); + return; + } + + dmub = dc_dmub_srv->dmub; + + status = dmub_srv_send_gpint_command(dmub, DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD1, 0x0010, timeout_us); + if (status != DMUB_STATUS_OK) { + DC_LOG_ERROR("timeout updating trace buffer mask word\n"); + return; + } + + status = dmub_srv_send_gpint_command(dmub, DMUB_GPINT__UPDATE_TRACE_BUFFER_MASK, 0x0000, timeout_us); + if (status != DMUB_STATUS_OK) { + DC_LOG_ERROR("timeout updating trace buffer mask word\n"); + return; + } + + DC_LOG_DEBUG("Enabled DPIA trace\n"); +} \ No newline at end of file diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h index 099f94b6107c..bb3fe162dd93 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h @@ -87,4 +87,7 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv); void dc_send_update_cursor_info_to_dmu(struct pipe_ctx *pCtx, uint8_t pipe_idx); bool dc_dmub_check_min_version(struct dmub_srv *srv); + +void dc_dmub_srv_enable_dpia_trace(const struct dc *dc); + #endif /* _DMUB_DC_SRV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 08c017cff43c..6a1571ffeaf9 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -779,6 +779,24 @@ enum dmub_gpint_command { * DESC: Notifies DMCUB detection is done so detection required can be cleared. */ DMUB_GPINT__NOTIFY_DETECTION_DONE = 12, + /** + * DESC: Updates the trace buffer lower 32-bit mask. + * ARGS: The new mask + * RETURN: Lower 32-bit mask. + */ + DMUB_GPINT__UPDATE_TRACE_BUFFER_MASK = 101, + /** + * DESC: Updates the trace buffer lower 32-bit mask. + * ARGS: The new mask + * RETURN: Lower 32-bit mask. + */ + DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD0 = 102, + /** + * DESC: Updates the trace buffer mask bi0~bit15. + * ARGS: The new mask + * RETURN: Lower 32-bit mask. + */ + DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD1 = 103, }; /** -- cgit v1.2.3 From c84f512387fcda784b907c4754b8c4088432fa5d Mon Sep 17 00:00:00 2001 From: Bhawanpreet Lakha Date: Wed, 28 Jun 2023 11:55:50 -0400 Subject: drm/amd/display: Add Replay supported/enabled checks - Add checks for Cursor update and dirty rects (sending updates to dmub) - Add checks for dc_notify_vsync, and fbc and subvp Signed-off-by: Bhawanpreet Lakha Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 6 ++++++ drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 3 +++ drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 5 +++++ 3 files changed, 14 insertions(+) (limited to 'drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 8504e6ee9582..508d5ea89b8b 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -3289,6 +3289,9 @@ static bool dc_dmub_should_send_dirty_rect_cmd(struct dc *dc, struct dc_stream_s && stream->ctx->dce_version >= DCN_VERSION_3_1) return true; + if (stream->link->replay_settings.config.replay_supported) + return true; + return false; } @@ -5173,6 +5176,9 @@ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bo if (link->psr_settings.psr_feature_enabled) return; + if (link->replay_settings.replay_feature_enabled) + return; + /*find primary pipe associated with stream*/ for (i = 0; i < MAX_PIPES; i++) { pipe = &dc->current_state->res_ctx.pipe_ctx[i]; diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 8c75f7510880..530b85a50b03 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -897,6 +897,9 @@ static bool dc_dmub_should_update_cursor_data(struct pipe_ctx *pipe_ctx) pipe_ctx->stream->ctx->dce_version >= DCN_VERSION_3_1) return true; + if (pipe_ctx->stream->link->replay_settings.config.replay_supported) + return true; + return false; } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 50088608a68a..ad967b58d7be 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1590,6 +1590,7 @@ static enum dc_status apply_single_controller_ctx_to_hw( */ if (pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) { pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false; + pipe_ctx->stream->link->replay_settings.replay_feature_enabled = false; } return DC_OK; } @@ -2021,6 +2022,10 @@ static bool should_enable_fbc(struct dc *dc, if (pipe_ctx->stream->link->psr_settings.psr_feature_enabled) return false; + /* Replay should not be enabled */ + if (pipe_ctx->stream->link->replay_settings.replay_feature_enabled) + return false; + /* Nothing to compress */ if (!pipe_ctx->plane_state) return false; -- cgit v1.2.3 From 53f3288079460ec7c86a39871af5c8b2a5d48685 Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Fri, 28 Jul 2023 13:42:37 -0400 Subject: drm/amd/display: implement pipe type definition and adding accessors [why] There is a lack of encapsulation of pipe connection representation in pipe context. This has caused many challenging bugs and coding errors with repeated logic to identify the same pipe type. [how] Formally define pipe types and provide getters to identify a pipe type and find a pipe based on specific requirements. Update existing logic in non dcn specific files and dcn32 and future versions to use the new accessors. Reviewed-by: Jun Lei Acked-by: Stylon Wang Signed-off-by: Wenjing Liu Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 41 ++-- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 186 +++++++++-------- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 22 ++- .../drm/amd/display/dc/dce100/dce100_resource.c | 2 +- .../drm/amd/display/dc/dce110/dce110_resource.c | 2 +- .../drm/amd/display/dc/dce112/dce112_resource.c | 4 +- .../gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 6 +- .../gpu/drm/amd/display/dc/dcn20/dcn20_resource.c | 18 +- .../drm/amd/display/dc/dcn201/dcn201_resource.c | 4 +- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c | 12 +- .../gpu/drm/amd/display/dc/dcn32/dcn32_resource.c | 4 +- .../amd/display/dc/dcn32/dcn32_resource_helpers.c | 12 +- .../gpu/drm/amd/display/dc/dml/calcs/dce_calcs.c | 2 +- .../gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c | 2 +- .../gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c | 2 +- .../gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 11 +- drivers/gpu/drm/amd/display/dc/inc/resource.h | 220 +++++++++++++++++++-- .../amd/display/dc/link/accessories/link_dp_cts.c | 3 +- drivers/gpu/drm/amd/display/dc/link/link_dpms.c | 7 +- 19 files changed, 375 insertions(+), 185 deletions(-) (limited to 'drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 508d5ea89b8b..566d7045b2de 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -586,18 +586,15 @@ dc_stream_forward_crc_window(struct dc_stream_state *stream, bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream, struct crc_params *crc_window, bool enable, bool continuous) { - int i; struct pipe_ctx *pipe; struct crc_params param; struct timing_generator *tg; - for (i = 0; i < MAX_PIPES; i++) { - pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe->stream == stream && !pipe->top_pipe && !pipe->prev_odm_pipe) - break; - } + pipe = resource_get_otg_master_for_stream( + &dc->current_state->res_ctx, stream); + /* Stream not found */ - if (i == MAX_PIPES) + if (pipe == NULL) return false; /* By default, capture the full frame */ @@ -1064,7 +1061,7 @@ static void apply_ctx_interdependent_lock(struct dc *dc, // Copied conditions that were previously in dce110_apply_ctx_for_surface if (stream == pipe_ctx->stream) { - if (!pipe_ctx->top_pipe && + if (resource_is_pipe_type(pipe_ctx, OPP_HEAD) && (pipe_ctx->plane_state || old_pipe_ctx->plane_state)) dc->hwss.pipe_control_lock(dc, pipe_ctx, lock); } @@ -3164,7 +3161,7 @@ static void commit_planes_do_stream_update(struct dc *dc, for (j = 0; j < dc->res_pool->pipe_count; j++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; - if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe && pipe_ctx->stream == stream) { + if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && pipe_ctx->stream == stream) { if (stream_update->periodic_interrupt && dc->hwss.setup_periodic_interrupt) dc->hwss.setup_periodic_interrupt(dc, pipe_ctx); @@ -3446,16 +3443,9 @@ static void commit_planes_for_stream_fast(struct dc *dc, struct pipe_ctx *top_pipe_to_program = NULL; dc_z10_restore(dc); - for (j = 0; j < dc->res_pool->pipe_count; j++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; - - if (!pipe_ctx->top_pipe && - !pipe_ctx->prev_odm_pipe && - pipe_ctx->stream && - pipe_ctx->stream == stream) { - top_pipe_to_program = pipe_ctx; - } - } + top_pipe_to_program = resource_get_otg_master_for_stream( + &context->res_ctx, + stream); if (dc->debug.visual_confirm) { for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -3560,16 +3550,9 @@ static void commit_planes_for_stream(struct dc *dc, context_clock_trace(dc, context); } - for (j = 0; j < dc->res_pool->pipe_count; j++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; - - if (!pipe_ctx->top_pipe && - !pipe_ctx->prev_odm_pipe && - pipe_ctx->stream && - pipe_ctx->stream == stream) { - top_pipe_to_program = pipe_ctx; - } - } + top_pipe_to_program = resource_get_otg_master_for_stream( + &context->res_ctx, + stream); for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; 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 853e5b99dd62..f7b51aca6020 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -732,10 +732,10 @@ static inline void get_vp_scan_direction( *flip_horz_scan_dir = !*flip_horz_scan_dir; } -int get_num_mpc_splits(struct pipe_ctx *pipe) +int resource_get_num_mpc_splits(const struct pipe_ctx *pipe) { int mpc_split_count = 0; - struct pipe_ctx *other_pipe = pipe->bottom_pipe; + const struct pipe_ctx *other_pipe = pipe->bottom_pipe; while (other_pipe && other_pipe->plane_state == pipe->plane_state) { mpc_split_count++; @@ -750,40 +750,30 @@ int get_num_mpc_splits(struct pipe_ctx *pipe) return mpc_split_count; } -int get_num_odm_splits(struct pipe_ctx *pipe) +int resource_get_num_odm_splits(const struct pipe_ctx *pipe) { int odm_split_count = 0; - struct pipe_ctx *next_pipe = NULL; - while (pipe->top_pipe) - pipe = pipe->top_pipe; + pipe = resource_get_otg_master(pipe); - next_pipe = pipe->next_odm_pipe; - while (next_pipe) { + while (pipe->next_odm_pipe) { odm_split_count++; - next_pipe = next_pipe->next_odm_pipe; - } - pipe = pipe->prev_odm_pipe; - while (pipe) { - odm_split_count++; - pipe = pipe->prev_odm_pipe; + pipe = pipe->next_odm_pipe; } return odm_split_count; } static int get_odm_split_index(struct pipe_ctx *pipe_ctx) { - struct pipe_ctx *split_pipe = NULL; int index = 0; - while (pipe_ctx->top_pipe) - pipe_ctx = pipe_ctx->top_pipe; - - split_pipe = pipe_ctx->prev_odm_pipe; + pipe_ctx = resource_get_opp_head(pipe_ctx); + if (!pipe_ctx) + return 0; - while (split_pipe) { + while (pipe_ctx->prev_odm_pipe) { index++; - split_pipe = split_pipe->prev_odm_pipe; + pipe_ctx = pipe_ctx->prev_odm_pipe; } return index; @@ -854,7 +844,7 @@ 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 = get_num_odm_splits(pipe_ctx) + 1; + int odm_slice_count = resource_get_num_odm_splits(pipe_ctx) + 1; int odm_slice_idx = get_odm_split_index(pipe_ctx); bool is_last_odm_slice = (odm_slice_idx + 1) == odm_slice_count; int h_active = stream->timing.h_addressable + @@ -972,7 +962,7 @@ 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 = get_num_mpc_splits(pipe_ctx) + 1; + int mpc_slice_count = resource_get_num_mpc_splits(pipe_ctx) + 1; int mpc_slice_idx = get_mpc_split_index(pipe_ctx); int epimo = mpc_slice_count - plane_clip_rec->width % mpc_slice_count - 1; struct rect mpc_rec; @@ -1565,7 +1555,7 @@ enum dc_status resource_build_scaling_params_for_context( return DC_OK; } -struct pipe_ctx *find_free_secondary_pipe_legacy( +struct pipe_ctx *resource_find_free_secondary_pipe_legacy( struct resource_context *res_ctx, const struct resource_pool *pool, const struct pipe_ctx *primary_pipe) @@ -1631,7 +1621,7 @@ int resource_find_free_pipe_used_in_cur_mpc_blending_tree( const struct pipe_ctx *cur_opp_head) { const struct pipe_ctx *cur_sec_dpp = cur_opp_head->bottom_pipe; - struct pipe_ctx *new_sec_dpp; + struct pipe_ctx *new_pipe; int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND; while (cur_sec_dpp) { @@ -1639,9 +1629,8 @@ int resource_find_free_pipe_used_in_cur_mpc_blending_tree( * this is to avoid MPO pipe switching to different opp blending * tree */ - new_sec_dpp = &new_res_ctx->pipe_ctx[cur_sec_dpp->pipe_idx]; - if (new_sec_dpp->plane_state == NULL && - new_sec_dpp->stream == NULL) { + new_pipe = &new_res_ctx->pipe_ctx[cur_sec_dpp->pipe_idx]; + if (resource_is_pipe_type(new_pipe, FREE_PIPE)) { free_pipe_idx = cur_sec_dpp->pipe_idx; break; } @@ -1657,17 +1646,15 @@ int recource_find_free_pipe_not_used_in_cur_res_ctx( const struct resource_pool *pool) { int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND; - const struct pipe_ctx *new_sec_dpp, *cur_sec_dpp; + const struct pipe_ctx *new_pipe, *cur_pipe; int i; for (i = 0; i < pool->pipe_count; i++) { - cur_sec_dpp = &cur_res_ctx->pipe_ctx[i]; - new_sec_dpp = &new_res_ctx->pipe_ctx[i]; + cur_pipe = &cur_res_ctx->pipe_ctx[i]; + new_pipe = &new_res_ctx->pipe_ctx[i]; - if (cur_sec_dpp->plane_state == NULL && - cur_sec_dpp->stream == NULL && - new_sec_dpp->plane_state == NULL && - new_sec_dpp->stream == NULL) { + if (resource_is_pipe_type(cur_pipe, FREE_PIPE) && + resource_is_pipe_type(new_pipe, FREE_PIPE)) { free_pipe_idx = i; break; } @@ -1682,18 +1669,17 @@ int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine( const struct resource_pool *pool) { int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND; - const struct pipe_ctx *new_sec_dpp, *cur_sec_dpp; + const struct pipe_ctx *new_pipe, *cur_pipe; int i; for (i = 0; i < pool->pipe_count; i++) { - cur_sec_dpp = &cur_res_ctx->pipe_ctx[i]; - new_sec_dpp = &new_res_ctx->pipe_ctx[i]; - - if (cur_sec_dpp->plane_state && - cur_sec_dpp->top_pipe && - cur_sec_dpp->top_pipe->plane_state == cur_sec_dpp->plane_state && - new_sec_dpp->plane_state == NULL && - new_sec_dpp->stream == NULL) { + cur_pipe = &cur_res_ctx->pipe_ctx[i]; + new_pipe = &new_res_ctx->pipe_ctx[i]; + + 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_is_pipe_type(new_pipe, FREE_PIPE)) { free_pipe_idx = i; break; } @@ -1706,14 +1692,13 @@ int resource_find_any_free_pipe(struct resource_context *new_res_ctx, const struct resource_pool *pool) { int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND; - const struct pipe_ctx *new_sec_dpp; + const struct pipe_ctx *new_pipe; int i; for (i = 0; i < pool->pipe_count; i++) { - new_sec_dpp = &new_res_ctx->pipe_ctx[i]; + new_pipe = &new_res_ctx->pipe_ctx[i]; - if (new_sec_dpp->plane_state == NULL && - new_sec_dpp->stream == NULL) { + if (resource_is_pipe_type(new_pipe, FREE_PIPE)) { free_pipe_idx = i; break; } @@ -1722,51 +1707,83 @@ int resource_find_any_free_pipe(struct resource_context *new_res_ctx, return free_pipe_idx; } -/* TODO: Unify the pipe naming convention: - * - * OPP head pipe - the head pipe of an MPC blending tree with a functional OPP - * feeding to an OTG. OPP head pipe is by convention the top most pipe. i.e. - * pipe's top_pipe is NULL. - * - * OTG master pipe - the master pipe of its OPP head pipes with a functional - * OTG. It merges all its OPP head pipes pixel data from their MPCs in ODM block - * and output to backend DIG. OTG master pipe is by convention the top most pipe - * of the first odm slice. i.e. pipe's top_pipe is NULL and pipe's prev_odm_pipe - * is NULL. - * - * Secondary OPP head pipe - an OPP head pipe which is not an OTG master pipe. - * Its output feeds to another OTG master pipe. i.e pipe's top_pipe is NULL and - * pipe's prev_odm_pipe is not NULL. - * - * Secondary DPP pipe - the pipe with a functional DPP outputting to another OPP - * head pipe's MPC. Its output is a secondary layer in the OPP head's MPC - * blending tree. Secondary DPP pipe is by convention a non top most pipe. i.e - * pipe's top_pipe should be not NULL. - * - * The function below is actually getting the OTG master pipe associated with - * the stream. Name it as getting head pipe is confusing. - */ -struct pipe_ctx *resource_get_head_pipe_for_stream( +bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type) +{ +#ifdef DBG + if (pipe_ctx->stream == NULL) { + /* a free pipe with dangling states */ + ASSERT(!pipe_ctx->plane_state); + ASSERT(!pipe_ctx->prev_odm_pipe); + ASSERT(!pipe_ctx->next_odm_pipe); + ASSERT(!pipe_ctx->top_pipe); + ASSERT(!pipe_ctx->bottom_pipe); + } else if (pipe_ctx->top_pipe) { + /* a secondary DPP pipe must be signed to a plane */ + ASSERT(pipe_ctx->plane_state) + } + /* Add more checks here to prevent corrupted pipe ctx. It is very hard + * to debug this issue afterwards because we can't pinpoint the code + * location causing inconsistent pipe context states. + */ +#endif + switch (type) { + case OTG_MASTER: + return !pipe_ctx->prev_odm_pipe && + !pipe_ctx->top_pipe && + pipe_ctx->stream; + case OPP_HEAD: + return !pipe_ctx->top_pipe && pipe_ctx->stream; + case DPP_PIPE: + return pipe_ctx->plane_state && pipe_ctx->stream; + case FREE_PIPE: + return !pipe_ctx->plane_state && !pipe_ctx->stream; + default: + return false; + } +} + +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) { int i; for (i = 0; i < MAX_PIPES; i++) { - if (res_ctx->pipe_ctx[i].stream == stream - && !res_ctx->pipe_ctx[i].top_pipe - && !res_ctx->pipe_ctx[i].prev_odm_pipe) + if (res_ctx->pipe_ctx[i].stream == stream && + resource_is_pipe_type(&res_ctx->pipe_ctx[i], OTG_MASTER)) return &res_ctx->pipe_ctx[i]; } return NULL; } +struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *otg_master = resource_get_opp_head(pipe_ctx); + + while (otg_master->prev_odm_pipe) + otg_master = otg_master->prev_odm_pipe; + return otg_master; +} + +struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *opp_head = (struct pipe_ctx *) pipe_ctx; + + ASSERT(!resource_is_pipe_type(opp_head, FREE_PIPE)); + while (opp_head->top_pipe) + opp_head = opp_head->top_pipe; + return opp_head; +} + static struct pipe_ctx *get_tail_pipe( struct pipe_ctx *head_pipe) { - struct pipe_ctx *tail_pipe; - - tail_pipe = head_pipe->bottom_pipe; + struct pipe_ctx *tail_pipe = head_pipe->bottom_pipe; while (tail_pipe) { head_pipe = tail_pipe; @@ -1908,7 +1925,7 @@ bool dc_add_plane_to_context( goto out; } - otg_master_pipe = resource_get_head_pipe_for_stream( + 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, @@ -2429,7 +2446,7 @@ enum dc_status dc_remove_stream_from_ctx( { int i; struct dc_context *dc_ctx = dc->ctx; - struct pipe_ctx *del_pipe = resource_get_head_pipe_for_stream(&new_ctx->res_ctx, stream); + struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream(&new_ctx->res_ctx, stream); struct pipe_ctx *odm_pipe; if (!del_pipe) { @@ -3683,7 +3700,7 @@ enum dc_status resource_map_clock_resources( { /* acquire new resources */ const struct resource_pool *pool = dc->res_pool; - struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream( + struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream( &context->res_ctx, stream); if (!pipe_ctx) @@ -4073,10 +4090,7 @@ void reset_syncd_pipes_from_disabled_pipes(struct dc *dc, pipe_ctx_old = &dc->current_state->res_ctx.pipe_ctx[i]; pipe_ctx = &context->res_ctx.pipe_ctx[i]; - if (!pipe_ctx_old->stream) - continue; - - if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) + if (!resource_is_pipe_type(pipe_ctx_old, OTG_MASTER)) continue; if (!pipe_ctx->stream || diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 530b85a50b03..4c5ef3ef8dbd 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -31,6 +31,7 @@ #include "core_types.h" #include "../basics/conversion.h" #include "cursor_reg_cache.h" +#include "resource.h" #define CTX dc_dmub_srv->ctx #define DC_LOGGER CTX->logger @@ -356,7 +357,7 @@ bool dc_dmub_srv_p_state_delegate(struct dc *dc, bool should_manage_pstate, stru for (i = 0, k = 0; context && i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - if (!pipe->top_pipe && !pipe->prev_odm_pipe && pipe->stream && pipe->stream->fpo_in_use) { + if (resource_is_pipe_type(pipe, OTG_MASTER) && pipe->stream->fpo_in_use) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; uint8_t min_refresh_in_hz = (pipe->stream->timing.min_refresh_in_uhz + 999999) / 1000000; @@ -531,7 +532,8 @@ static void populate_subvp_cmd_vblank_pipe_info(struct dc *dc, // We check for master pipe, but it shouldn't matter since we only need // the pipe for timing info (stream should be same for any pipe splits) - if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe) + if (!resource_is_pipe_type(pipe, OTG_MASTER) || + !resource_is_pipe_type(pipe, DPP_PIPE)) continue; // Find the SubVP pipe @@ -728,12 +730,10 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc, for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - if (!pipe->stream) - continue; - /* For SubVP pipe count, only count the top most (ODM / MPC) pipe */ - if (pipe->plane_state && !pipe->top_pipe && !pipe->prev_odm_pipe && + if (resource_is_pipe_type(pipe, OTG_MASTER) && + resource_is_pipe_type(pipe, DPP_PIPE) && pipe->stream->mall_stream_config.type == SUBVP_MAIN) subvp_pipes[subvp_count++] = pipe; } @@ -750,12 +750,14 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc, * Any ODM or MPC splits being used in SubVP will be handled internally in * populate_subvp_cmd_pipe_info */ - if (pipe->plane_state && pipe->stream->mall_stream_config.paired_stream && - !pipe->top_pipe && !pipe->prev_odm_pipe && + if (resource_is_pipe_type(pipe, OTG_MASTER) && + resource_is_pipe_type(pipe, DPP_PIPE) && + pipe->stream->mall_stream_config.paired_stream && pipe->stream->mall_stream_config.type == SUBVP_MAIN) { populate_subvp_cmd_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++); - } else if (pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_NONE && - !pipe->top_pipe && !pipe->prev_odm_pipe) { + } else if (resource_is_pipe_type(pipe, OTG_MASTER) && + resource_is_pipe_type(pipe, DPP_PIPE) && + pipe->stream->mall_stream_config.type == SUBVP_NONE) { // Don't need to check for ActiveDRAMClockChangeMargin < 0, not valid in cases where // we run through DML without calculating "natural" P-state support populate_subvp_cmd_vblank_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++); diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 42e9b6a529f6..899b25b0bad8 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -824,7 +824,7 @@ static enum dc_status build_mapped_resource( struct dc_state *context, struct dc_stream_state *stream) { - struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream); + struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); if (!pipe_ctx) return DC_ERROR_UNEXPECTED; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index c0214da714d4..1289b9418877 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -942,7 +942,7 @@ static enum dc_status build_mapped_resource( struct dc_state *context, struct dc_stream_state *stream) { - struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream); + struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); if (!pipe_ctx) return DC_ERROR_UNEXPECTED; diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index e115ff91aaaa..2b20180f1a32 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -873,7 +873,7 @@ static enum dc_status build_mapped_resource( struct dc_state *context, struct dc_stream_state *stream) { - struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream); + struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); if (!pipe_ctx) return DC_ERROR_UNEXPECTED; @@ -964,7 +964,7 @@ enum dc_status resource_map_phy_clock_resources( { /* acquire new resources */ - struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream( + struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream( &context->res_ctx, stream); if (!pipe_ctx) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 82e5af4d5d15..9f9145742f14 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -1055,7 +1055,7 @@ static enum dc_status build_mapped_resource( struct dc_state *context, struct dc_stream_state *stream) { - struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream); + struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); if (!pipe_ctx) return DC_ERROR_UNEXPECTED; @@ -1090,8 +1090,8 @@ static struct pipe_ctx *dcn10_acquire_free_pipe_for_layer( const struct pipe_ctx *opp_head_pipe) { struct resource_context *res_ctx = &new_ctx->res_ctx; - struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, opp_head_pipe->stream); - struct pipe_ctx *idle_pipe = find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe); + struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream); + struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe); if (!head_pipe) { ASSERT(0); diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index efa600e46194..66b74bb5d936 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -1294,7 +1294,7 @@ static enum dc_status build_pipe_hw_param(struct pipe_ctx *pipe_ctx) enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream) { enum dc_status status = DC_OK; - struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream); + struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); if (!pipe_ctx) return DC_ERROR_UNEXPECTED; @@ -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 (get_num_mpc_splits(pipe) == 1) { + if (resource_get_num_mpc_splits(pipe) == 1) { /*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 (get_num_mpc_splits(pipe) == 3) { + } else if (resource_get_num_mpc_splits(pipe) == 3) { /*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 (get_num_odm_splits(pipe)) { + } else if (resource_get_num_odm_splits(pipe)) { /* ODM -> MPC transition */ if (pipe->prev_odm_pipe) { split[i] = 0; @@ -1973,7 +1973,7 @@ int dcn20_validate_apply_pipe_split_flags( } } } else { - if (get_num_odm_splits(pipe) == 1) { + if (resource_get_num_odm_splits(pipe) == 1) { /*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 (get_num_odm_splits(pipe) == 3) { + } else if (resource_get_num_odm_splits(pipe) == 3) { /*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 (get_num_mpc_splits(pipe)) { + } else if (resource_get_num_mpc_splits(pipe)) { /* MPC -> ODM transition */ ASSERT(0); /* NOT expected yet */ if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) { @@ -2154,8 +2154,8 @@ struct pipe_ctx *dcn20_acquire_free_pipe_for_layer( const struct pipe_ctx *opp_head) { struct resource_context *res_ctx = &new_ctx->res_ctx; - struct pipe_ctx *otg_master = resource_get_head_pipe_for_stream(res_ctx, opp_head->stream); - struct pipe_ctx *sec_dpp_pipe = find_free_secondary_pipe_legacy(res_ctx, pool, otg_master); + struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(res_ctx, opp_head->stream); + struct pipe_ctx *sec_dpp_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, otg_master); ASSERT(otg_master); 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 4fce3485d0f5..2dc4d2c1410b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c @@ -999,8 +999,8 @@ static struct pipe_ctx *dcn201_acquire_free_pipe_for_layer( const struct pipe_ctx *opp_head_pipe) { struct resource_context *res_ctx = &new_ctx->res_ctx; - struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, opp_head_pipe->stream); - struct pipe_ctx *idle_pipe = find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe); + struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream); + struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe); if (!head_pipe) ASSERT(0); diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c index a87afb796f47..680e7fa8d18a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c @@ -567,7 +567,7 @@ bool dcn32_set_output_transfer_func(struct dc *dc, bool ret = false; /* program OGAM or 3DLUT only for the top pipe*/ - if (pipe_ctx->top_pipe == NULL) { + if (resource_is_pipe_type(pipe_ctx, OPP_HEAD)) { /*program shaper and 3dlut in MPC*/ ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream); if (ret == false && mpc->funcs->set_output_gamma && stream->out_transfer_func) { @@ -1202,10 +1202,10 @@ void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_ for (i = 0; i < dc->res_pool->pipe_count; i++) { pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe->top_pipe || pipe->prev_odm_pipe) + if (!resource_is_pipe_type(pipe, OTG_MASTER)) continue; - if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal)) + if ((pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal)) && pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) { pipe->stream_res.tg->funcs->disable_crtc(pipe->stream_res.tg); reset_sync_context_for_pipe(dc, context, i); @@ -1299,7 +1299,7 @@ static void apply_symclk_on_tx_off_wa(struct dc_link *link) if (link->phy_state.symclk_ref_cnts.otg > 0) { for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) { + if (resource_is_pipe_type(pipe_ctx, OPP_HEAD) && pipe_ctx->stream->link == link) { pipe_ctx->clock_source->funcs->program_pix_clk( pipe_ctx->clock_source, &pipe_ctx->stream_res.pix_clk_params, @@ -1382,7 +1382,7 @@ void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe) { phantom_pipe->update_flags.raw = 0; if (phantom_pipe->stream && phantom_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { - if (phantom_pipe->stream && phantom_pipe->plane_state) { + if (resource_is_pipe_type(phantom_pipe, DPP_PIPE)) { phantom_pipe->update_flags.bits.enable = 1; phantom_pipe->update_flags.bits.mpcc = 1; phantom_pipe->update_flags.bits.dppclk = 1; @@ -1392,7 +1392,7 @@ void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe) phantom_pipe->update_flags.bits.scaler = 1; phantom_pipe->update_flags.bits.viewport = 1; phantom_pipe->update_flags.bits.det_size = 1; - if (!phantom_pipe->top_pipe && !phantom_pipe->prev_odm_pipe) { + if (resource_is_pipe_type(phantom_pipe, OTG_MASTER)) { phantom_pipe->update_flags.bits.odm = 1; phantom_pipe->update_flags.bits.global_sync = 1; } 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 cadbe1dcfbfe..935cd23e6a01 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c @@ -1709,8 +1709,8 @@ void dcn32_retain_phantom_pipes(struct dc *dc, struct dc_state *context) for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - if (!pipe->top_pipe && !pipe->prev_odm_pipe && - pipe->plane_state && pipe->stream && + if (resource_is_pipe_type(pipe, OTG_MASTER) && + resource_is_pipe_type(pipe, DPP_PIPE) && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { phantom_plane = pipe->plane_state; phantom_stream = pipe->stream; diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c index db9c55a09d9f..3ad2b48954e0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c @@ -646,10 +646,8 @@ bool dcn32_subvp_drr_admissable(struct dc *dc, struct dc_state *context) for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - if (!pipe->stream) - continue; - - if (pipe->plane_state && !pipe->top_pipe) { + if (resource_is_pipe_type(pipe, OPP_HEAD) && + resource_is_pipe_type(pipe, DPP_PIPE)) { if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { subvp_count++; @@ -706,10 +704,8 @@ bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - if (!pipe->stream) - continue; - - if (pipe->plane_state && !pipe->top_pipe) { + if (resource_is_pipe_type(pipe, OPP_HEAD) && + resource_is_pipe_type(pipe, DPP_PIPE)) { if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { subvp_count++; diff --git a/drivers/gpu/drm/amd/display/dc/dml/calcs/dce_calcs.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/dce_calcs.c index 0100a6053ab6..f2dfa96f9ef5 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/calcs/dce_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dce_calcs.c @@ -3015,7 +3015,7 @@ static bool all_displays_in_sync(const struct pipe_ctx pipe[], int i, num_active_pipes = 0; for (i = 0; i < pipe_count; i++) { - if (!pipe[i].stream || pipe[i].top_pipe) + if (!resource_is_pipe_type(&pipe[i], OPP_HEAD)) continue; active_pipes[num_active_pipes++] = &pipe[i]; diff --git a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c index 794d6517e511..50b0434354f8 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c @@ -1258,7 +1258,7 @@ bool dcn_validate_bandwidth( hsplit_pipe->pipe_dlg_param.vblank_end = pipe->pipe_dlg_param.vblank_end; } else { /* pipe not split previously needs split */ - hsplit_pipe = find_free_secondary_pipe_legacy(&context->res_ctx, pool, pipe); + hsplit_pipe = resource_find_free_secondary_pipe_legacy(&context->res_ctx, pool, pipe); ASSERT(hsplit_pipe); split_stream_across_pipes(&context->res_ctx, pool, pipe, hsplit_pipe); } diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c index 8ae5ddbd1b27..8afda5ecc0cd 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,7 +1305,7 @@ 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 (get_num_odm_splits(&res_ctx->pipe_ctx[i])) { + switch (resource_get_num_odm_splits(&res_ctx->pipe_ctx[i])) { case 1: pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_2to1; break; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index 6d60ae0133ee..711d4085b33b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -756,7 +756,7 @@ static bool dcn32_enough_pipes_for_subvp(struct dc *dc, struct dc_state *context struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; // Find the minimum pipe split count for non SubVP pipes - if (pipe->stream && !pipe->top_pipe && + if (resource_is_pipe_type(pipe, OPP_HEAD) && pipe->stream->mall_stream_config.type == SUBVP_NONE) { split_cnt = 0; while (pipe) { @@ -886,7 +886,8 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context) // We check for master pipe, but it shouldn't matter since we only need // the pipe for timing info (stream should be same for any pipe splits) - if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe) + if (!resource_is_pipe_type(pipe, OTG_MASTER) || + !resource_is_pipe_type(pipe, DPP_PIPE)) continue; // Find the SubVP pipe @@ -899,7 +900,8 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context) drr_pipe = &context->res_ctx.pipe_ctx[i]; // We check for master pipe only - if (!drr_pipe->stream || !drr_pipe->plane_state || drr_pipe->top_pipe || drr_pipe->prev_odm_pipe) + if (!resource_is_pipe_type(pipe, OTG_MASTER) || + !resource_is_pipe_type(pipe, DPP_PIPE)) continue; if (drr_pipe->stream->mall_stream_config.type == SUBVP_NONE && drr_pipe->stream->ignore_msa_timing_param && @@ -980,7 +982,8 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context) // We check for master pipe, but it shouldn't matter since we only need // the pipe for timing info (stream should be same for any pipe splits) - if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe) + if (!resource_is_pipe_type(pipe, OTG_MASTER) || + !resource_is_pipe_type(pipe, DPP_PIPE)) continue; if (!found && pipe->stream->mall_stream_config.type == SUBVP_NONE) { diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index 8dabbbc2a7b9..e546b9c506c1 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -37,7 +37,6 @@ #define IS_PIPE_SYNCD_VALID(pipe) ((((pipe)->pipe_idx_syncd) & 0x80)?1:0) #define GET_PIPE_SYNCD_FROM_PIPE(pipe) ((pipe)->pipe_idx_syncd & 0x7F) #define SET_PIPE_SYNCD_TO_PIPE(pipe, pipe_syncd) ((pipe)->pipe_idx_syncd = (0x80 | pipe_syncd)) -#define FREE_PIPE_INDEX_NOT_FOUND -1 enum dce_version resource_parse_asic_id( struct hw_asic_id asic_id); @@ -143,10 +142,6 @@ struct clock_source *dc_resource_find_first_free_pll( struct resource_context *res_ctx, const struct resource_pool *pool); -struct pipe_ctx *resource_get_head_pipe_for_stream( - struct resource_context *res_ctx, - struct dc_stream_state *stream); - bool resource_attach_surfaces_to_context( struct dc_plane_state *const *plane_state, int surface_count, @@ -154,29 +149,232 @@ bool resource_attach_surfaces_to_context( struct dc_state *context, const struct resource_pool *pool); -struct pipe_ctx *find_free_secondary_pipe_legacy( - struct resource_context *res_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *primary_pipe); +#define FREE_PIPE_INDEX_NOT_FOUND -1 +/* + * pipe types are identified based on MUXes in DCN front end that are capable + * of taking input from one DCN pipeline to another DCN pipeline. The name is + * in a form of XXXX_YYYY, where XXXX is the DCN front end hardware block the + * pipeline ends with and YYYY is the rendering role that the pipe is in. + * + * For instance OTG_MASTER is a pipe ending with OTG hardware block in its + * pipeline and it is in a role of a master pipe for timing generation. + * + * For quick reference a diagram of each pipe type's areas of responsibility + * for outputting timings on the screen is shown below: + * + * Timing Active for Stream 0 + * __________________________________________________ + * |OTG master 0 (OPP head 0)|OPP head 2 (DPP pipe 2) | + * | (DPP pipe 0)| | + * | Top Plane 0 | | + * | ______________|____ | + * | |DPP pipe 1 |DPP | | + * | | |pipe| | + * | | Bottom |3 | | + * | | Plane 1 | | | + * | | | | | + * | |______________|____| | + * | | | + * | | | + * | ODM slice 0 | ODM slice 1 | + * |_________________________|________________________| + * + * Timing Active for Stream 1 + * __________________________________________________ + * |OTG master 4 (OPP head 4) | + * | | + * | | + * | | + * | | + * | | + * | Blank Pixel Data | + * | (generated by DPG4) | + * | | + * | | + * | | + * | | + * | | + * |__________________________________________________| + * + * Inter-pipe Relation + * __________________________________________________ + * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | + * | | plane 0 | slice 0 | | + * | 0 | -------------MPC---------ODM----------- | + * | | plane 1 | | | | | + * | 1 | ------------- | | | | + * | | plane 0 | slice 1 | | | + * | 2 | -------------MPC--------- | | + * | | plane 1 | | | | + * | 3 | ------------- | | | + * | | | blank | | + * | 4 | | ----------------------- | + * | | | | | + * | 5 | (FREE) | | | + * |________|_______________|___________|_____________| + */ +enum pipe_type { + /* free pipe - free pipe is an uninitialized pipe without a stream + * associated with it. It is a free DCN pipe resource. It can be + * acquired as any type of pipe. + */ + FREE_PIPE, + + /* 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 + * 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 + * generators (DPG) such as solid black pixel data to blank the screen. + */ + OTG_MASTER, + + /* OPP head pipe - the head pipe of an MPC blending tree with a + * functional OPP outputting to an OTG. OPP head pipe is responsible for + * processing output pixels in its own ODM slice. It may or may not have + * a plane. If it has a plane it blends it as the top most layer within + * its own ODM slice. If it doesn't have a plane it can output pixel + * data from its DPG such as solid black pixel data to blank the pixel + * data in its own ODM slice. OTG master pipe is also an OPP head pipe + * but with more responsibility. + */ + OPP_HEAD, + + /* DPP pipe - the pipe with a functional DPP outputting to an OPP head + * pipe's MPC. DPP pipe is responsible for processing pixel data from + * its own MPC slice of a plane. It must be connected to an OPP head + * pipe and it must have a plane associated with it. + */ + DPP_PIPE, +}; + +/* + * 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. + * + * For instance in the Inter-pipe Relation diagram shown below, both PIPE 0 and + * 1 are for MPCC combine for plane 0 + * + * Inter-pipe Relation + * __________________________________________________ + * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER | + * | | plane 0 | | | + * | 0 | -------------MPC----------------------- | + * | | plane 0 | | | | + * | 1 | ------------- | | | + * |________|_______________|___________|_____________| + * + * return - true if pipe ctx is used for mpcc combine. + */ +bool resource_is_for_mpcc_combine(const struct pipe_ctx *pipe_ctx); + +/* + * Look for a free pipe in new resource context that is used as a secondary DPP + * pipe in MPC blending tree associated with input OPP head pipe. + * + * return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise + * pipe idx of the free pipe + */ int resource_find_free_pipe_used_in_cur_mpc_blending_tree( const struct resource_context *cur_res_ctx, struct resource_context *new_res_ctx, const struct pipe_ctx *cur_opp_head); +/* + * Look for a free pipe in new resource context that is not used in current + * resource context. + * + * return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise + * pipe idx of the free pipe + */ int recource_find_free_pipe_not_used_in_cur_res_ctx( const struct resource_context *cur_res_ctx, struct resource_context *new_res_ctx, const struct resource_pool *pool); +/* + * Look for a free pipe in new resource context that is used as a secondary DPP + * pipe in any MPCC combine in current resource context. + * return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise + * pipe idx of the free pipe + */ int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine( const struct resource_context *cur_res_ctx, struct resource_context *new_res_ctx, const struct resource_pool *pool); +/* + * Look for any free pipe in new resource context. + * return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise + * pipe idx of the free pipe + */ int resource_find_any_free_pipe(struct resource_context *new_res_ctx, const struct resource_pool *pool); +/* + * Legacy find free secondary pipe logic deprecated for newer DCNs as it doesn't + * find the most optimal free pipe to prevent from time consuming hardware state + * transitions. + */ +struct pipe_ctx *resource_find_free_secondary_pipe_legacy( + struct resource_context *res_ctx, + 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); + +/* + * 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); + +/* + * 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); + + bool resource_validate_attach_surfaces( const struct dc_validation_set set[], int set_count, @@ -212,10 +410,6 @@ unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format); void get_audio_check(struct audio_info *aud_modes, struct audio_check *aud_chk); -int get_num_mpc_splits(struct pipe_ctx *pipe); - -int get_num_odm_splits(struct pipe_ctx *pipe); - bool get_temp_dp_link_res(struct dc_link *link, struct link_resource *link_res, struct dc_link_settings *link_settings); diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c index c7e1f2229afd..fe4282771cd0 100644 --- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c +++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c @@ -675,7 +675,8 @@ bool dp_set_test_pattern( if (pipes[i].stream == NULL) continue; - if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) { + if (resource_is_pipe_type(&pipes[i], OTG_MASTER) && + pipes[i].stream->link == link) { pipe_ctx = &pipes[i]; break; } diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index 7997936613fc..79aef205598b 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -182,11 +182,8 @@ void link_resume(struct dc_link *link) static bool is_master_pipe_for_link(const struct dc_link *link, const struct pipe_ctx *pipe) { - return (pipe->stream && - pipe->stream->link && - pipe->stream->link == link && - pipe->top_pipe == NULL && - pipe->prev_odm_pipe == NULL); + return resource_is_pipe_type(pipe, OTG_MASTER) && + pipe->stream->link == link; } /* -- cgit v1.2.3