From: Alvin Lee <Alvin.Lee2@xxxxxxx> [Why & How] If we find that DML requires pipe split, run through DML again because the DET allocation per pipe must be re-assigned. Reviewed-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@xxxxxxx> Acked-by: Wayne Lin <wayne.lin@xxxxxxx> Signed-off-by: Alvin Lee <Alvin.Lee2@xxxxxxx> --- .../drm/amd/display/dc/dcn32/dcn32_resource.c | 26 +----- .../drm/amd/display/dc/dcn32/dcn32_resource.h | 9 +- .../display/dc/dcn32/dcn32_resource_helpers.c | 89 ++++++++++++------- .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 14 ++- .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.h | 5 -- 5 files changed, 76 insertions(+), 67 deletions(-) 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 dad174a52449..55198c3878b6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c @@ -1837,12 +1837,6 @@ bool dcn32_validate_bandwidth(struct dc *dc, return out; } - -static bool is_dual_plane(enum surface_pixel_format format) -{ - return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA; -} - int dcn32_populate_dml_pipes_from_context( struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes, @@ -1852,7 +1846,6 @@ int dcn32_populate_dml_pipes_from_context( struct resource_context *res_ctx = &context->res_ctx; struct pipe_ctx *pipe; bool subvp_in_use = false; - uint8_t is_pipe_split_expected[MAX_PIPES] = {0}; int plane_count = 0; struct dc_crtc_timing *timing; @@ -1940,11 +1933,6 @@ int dcn32_populate_dml_pipes_from_context( if (pipe->stream && !pipe->prev_odm_pipe && (!pipe->top_pipe || pipe->top_pipe->plane_state != pipe->plane_state)) ++plane_count; - - DC_FP_START(); - is_pipe_split_expected[i] = dcn32_predict_pipe_split(context, &pipes[pipe_cnt]); - DC_FP_END(); - pipe_cnt++; } @@ -1952,19 +1940,7 @@ int dcn32_populate_dml_pipes_from_context( * the DET available for each pipe). Use the DET override input to maintain our driver * policy. */ - if (pipe_cnt == 1 && !is_pipe_split_expected[0]) { - pipes[0].pipe.src.det_size_override = DCN3_2_MAX_DET_SIZE; - if (pipe->plane_state && !dc->debug.disable_z9_mpc) { - if (!is_dual_plane(pipe->plane_state->format)) { - pipes[0].pipe.src.det_size_override = DCN3_2_DEFAULT_DET_SIZE; - pipes[0].pipe.src.unbounded_req_mode = true; - if (pipe->plane_state->src_rect.width >= 5120 && - pipe->plane_state->src_rect.height >= 2880) - pipes[0].pipe.src.det_size_override = 320; // 5K or higher - } - } - } else - dcn32_determine_det_override(dc, context, pipes, is_pipe_split_expected); + dcn32_set_det_allocations(dc, context, pipes); // In general cases we want to keep the dram clock change requirement // (prefer configs that support MCLK switch). Only override to false diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h index 1039df3f9565..40e9211eec1e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h @@ -28,6 +28,10 @@ #include "core_types.h" +#define DCN3_2_DEFAULT_DET_SIZE 256 +#define DCN3_2_MAX_DET_SIZE 1152 +#define DCN3_2_MIN_DET_SIZE 128 +#define DCN3_2_MIN_COMPBUF_SIZE_KB 128 #define DCN3_2_DET_SEG_SIZE 64 #define DCN3_2_MALL_MBLK_SIZE_BYTES 65536 // 64 * 1024 #define DCN3_2_MBLK_WIDTH 128 @@ -111,9 +115,10 @@ struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer( void dcn32_determine_det_override(struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - uint8_t *is_pipe_split_expected); + display_e2e_pipe_params_st *pipes); +void dcn32_set_det_allocations(struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes); /* definitions for run time init of reg offsets */ /* CLK SRC */ 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 160aefaac173..46ba6eee69ea 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 @@ -28,6 +28,11 @@ #include "dcn20/dcn20_resource.h" #include "dml/dcn32/display_mode_vba_util_32.h" +static bool is_dual_plane(enum surface_pixel_format format) +{ + return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA; +} + /** * ******************************************************************************************** * dcn32_helper_calculate_num_ways_for_subvp: Calculate number of ways needed for SubVP @@ -239,22 +244,17 @@ bool dcn32_mpo_in_use(struct dc_state *context) * If there is a plane that's driven by more than 1 pipe (i.e. pipe split), then the * number of DET for that given plane will be split among the pipes driving that plane. * - * The pipe split prediction (is_pipe_split_expected) has to work 100% of the time in - * order for this function to work properly. * * High level algorithm: * 1. Split total DET among number of streams * 2. For each stream, split DET among the planes - * 3. For each plane, check if pipe split is expected. If yes, split the DET for that plane - * among the number of splits we expect (i.e. 2 [2:1] or 4 [4:1]) - * - NOTE: Make sure not to double count the pipe splits (i.e. the pipes could - * already be split in the context). + * 3. For each plane, check if there is a pipe split. If yes, split the DET allocation + * among those pipes. * 4. Assign the DET override to the DML pipes. * * @param [in]: dc: Current DC state * @param [in]: context: New DC state to be programmed * @param [in]: pipes: Array of DML pipes - * @param [in]: is_pipe_split_expected: Array indicating pipe split prediction for each pipe * * @return: void * @@ -262,16 +262,13 @@ bool dcn32_mpo_in_use(struct dc_state *context) */ void dcn32_determine_det_override(struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - uint8_t *is_pipe_split_expected) + display_e2e_pipe_params_st *pipes) { - uint32_t i, j; + uint32_t i, j, k; uint8_t pipe_plane_count, stream_segments, plane_segments, pipe_segments[MAX_PIPES] = {0}; uint8_t pipe_counted[MAX_PIPES] = {0}; uint8_t pipe_cnt = 0; struct dc_plane_state *current_plane = NULL; - struct pipe_ctx *next_odm_pipe = NULL; - struct pipe_ctx *bottom_pipe = NULL; uint8_t stream_count = 0; for (i = 0; i < context->stream_count; i++) { @@ -301,32 +298,21 @@ void dcn32_determine_det_override(struct dc *dc, pipe_plane_count++; pipe_counted[j] = 1; current_plane = context->res_ctx.pipe_ctx[j].plane_state; - if (is_pipe_split_expected[j] != 0) { - pipe_plane_count += is_pipe_split_expected[j]; - - next_odm_pipe = context->res_ctx.pipe_ctx[j].next_odm_pipe; - bottom_pipe = context->res_ctx.pipe_ctx[j].bottom_pipe; - - /* If pipe already happens to be split in context, mark as already - * counted so we don't double count the pipe split. - */ - while (next_odm_pipe) { - if (next_odm_pipe->plane_state == current_plane) { - pipe_counted[next_odm_pipe->pipe_idx] = 1; - pipe_segments[next_odm_pipe->pipe_idx] = plane_segments / pipe_plane_count; - } - next_odm_pipe = next_odm_pipe->next_odm_pipe; + for (k = 0; k < dc->res_pool->pipe_count; k++) { + if (k != j && context->res_ctx.pipe_ctx[k].stream == context->streams[i] && + context->res_ctx.pipe_ctx[k].plane_state == current_plane) { + pipe_plane_count++; + pipe_counted[k] = 1; } + } - while (bottom_pipe) { - if (bottom_pipe->plane_state == current_plane) { - pipe_counted[bottom_pipe->pipe_idx] = 1; - pipe_segments[bottom_pipe->pipe_idx] = plane_segments / pipe_plane_count; - } - bottom_pipe = bottom_pipe->bottom_pipe; + pipe_segments[j] = plane_segments / pipe_plane_count; + for (k = 0; k < dc->res_pool->pipe_count; k++) { + if (k != j && context->res_ctx.pipe_ctx[k].stream == context->streams[i] && + context->res_ctx.pipe_ctx[k].plane_state == current_plane) { + pipe_segments[k] = plane_segments / pipe_plane_count; } } - pipe_segments[j] = plane_segments / pipe_plane_count; } } } @@ -342,3 +328,38 @@ void dcn32_determine_det_override(struct dc *dc, pipes[i].pipe.src.det_size_override = 4 * DCN3_2_DET_SEG_SIZE; //DCN3_2_DEFAULT_DET_SIZE } } + +void dcn32_set_det_allocations(struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes) +{ + int i, pipe_cnt; + struct resource_context *res_ctx = &context->res_ctx; + struct pipe_ctx *pipe; + + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + + if (!res_ctx->pipe_ctx[i].stream) + continue; + + pipe = &res_ctx->pipe_ctx[i]; + pipe_cnt++; + } + + /* For DET allocation, we don't want to use DML policy (not optimal for utilizing all + * the DET available for each pipe). Use the DET override input to maintain our driver + * policy. + */ + if (pipe_cnt == 1) { + pipes[0].pipe.src.det_size_override = DCN3_2_MAX_DET_SIZE; + if (pipe->plane_state && !dc->debug.disable_z9_mpc && pipe->plane_state->tiling_info.gfx9.swizzle != DC_SW_LINEAR) { + if (!is_dual_plane(pipe->plane_state->format)) { + pipes[0].pipe.src.det_size_override = DCN3_2_DEFAULT_DET_SIZE; + pipes[0].pipe.src.unbounded_req_mode = true; + if (pipe->plane_state->src_rect.width >= 5120 && + pipe->plane_state->src_rect.height >= 2880) + pipes[0].pipe.src.det_size_override = 320; // 5K or higher + } + } + } else + dcn32_determine_det_override(dc, context, pipes); +} 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 b573ab7b81ed..fe0770038a90 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 @@ -1720,8 +1720,20 @@ bool dcn32_internal_validate_bw(struct dc *dc, goto validate_fail; } - if (repopulate_pipes) + if (repopulate_pipes) { pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate); + + /* repopulate_pipes = 1 means the pipes were either split or merged. In this case + * we have to re-calculate the DET allocation and run through DML once more to + * ensure all the params are calculated correctly. We do not need to run the + * pipe split check again after this call (pipes are already split / merged). + * */ + if (!fast_validate) { + context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final = + dm_prefetch_support_uclk_fclk_and_stutter_if_possible; + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + } + } *vlevel_out = vlevel; *pipe_cnt_out = pipe_cnt; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h index b43c45adb7d3..732ed7fadb8a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h @@ -29,11 +29,6 @@ #include "clk_mgr_internal.h" -#define DCN3_2_DEFAULT_DET_SIZE 256 -#define DCN3_2_MAX_DET_SIZE 1152 -#define DCN3_2_MIN_DET_SIZE 128 -#define DCN3_2_MIN_COMPBUF_SIZE_KB 128 - void dcn32_build_wm_range_table_fpu(struct clk_mgr_internal *clk_mgr); void dcn32_helper_populate_phantom_dlg_params(struct dc *dc, -- 2.37.3