drm/amd/display: Add 4 to 1 MPC split support
[Why] Want to make use of detile buffer of all 4 pipes to maximize amount of data stored to hide certain memory latency cases. [How] In case of 1 plane and 1 stream, program 4 pipes to each retrieve 1/4 of plane later mixed together by the MPCs. Added support for transition from 4 to 1 MPC to 2 to 1 MPC or no pipe split case and vice versa. Currently, only enabled if debug flag is set. Signed-off-by: Isabel Zhang <isabel.zhang@amd.com> Reviewed-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Acked-by: Aurabindo Pillai <aurabindo.pillai@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
committed by
Alex Deucher
parent
e0a3794d22
commit
65d6836982
@@ -277,6 +277,7 @@ struct dc_config {
|
|||||||
bool disable_extended_timeout_support; // Used to disable extended timeout and lttpr feature as well
|
bool disable_extended_timeout_support; // Used to disable extended timeout and lttpr feature as well
|
||||||
bool multi_mon_pp_mclk_switch;
|
bool multi_mon_pp_mclk_switch;
|
||||||
bool disable_dmcu;
|
bool disable_dmcu;
|
||||||
|
bool enable_4to1MPC;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum visual_confirm {
|
enum visual_confirm {
|
||||||
|
|||||||
@@ -1922,7 +1922,7 @@ bool dcn20_split_stream_for_odm(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dcn20_split_stream_for_mpc(
|
void dcn20_split_stream_for_mpc(
|
||||||
struct resource_context *res_ctx,
|
struct resource_context *res_ctx,
|
||||||
const struct resource_pool *pool,
|
const struct resource_pool *pool,
|
||||||
struct pipe_ctx *primary_pipe,
|
struct pipe_ctx *primary_pipe,
|
||||||
@@ -1951,11 +1951,6 @@ bool dcn20_split_stream_for_mpc(
|
|||||||
secondary_pipe->top_pipe = primary_pipe;
|
secondary_pipe->top_pipe = primary_pipe;
|
||||||
|
|
||||||
ASSERT(primary_pipe->plane_state);
|
ASSERT(primary_pipe->plane_state);
|
||||||
if (!resource_build_scaling_params(primary_pipe) ||
|
|
||||||
!resource_build_scaling_params(secondary_pipe))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dcn20_populate_dml_writeback_from_context(
|
void dcn20_populate_dml_writeback_from_context(
|
||||||
@@ -2581,11 +2576,32 @@ static void dcn20_merge_pipes_for_validate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dcn20_find_previous_split_count(struct pipe_ctx *pipe)
|
||||||
|
{
|
||||||
|
int previous_split = 1;
|
||||||
|
struct pipe_ctx *current_pipe = pipe;
|
||||||
|
|
||||||
|
while (current_pipe->bottom_pipe) {
|
||||||
|
if (current_pipe->plane_state != current_pipe->bottom_pipe->plane_state)
|
||||||
|
break;
|
||||||
|
previous_split++;
|
||||||
|
current_pipe = current_pipe->bottom_pipe;
|
||||||
|
}
|
||||||
|
current_pipe = pipe;
|
||||||
|
while (current_pipe->top_pipe) {
|
||||||
|
if (current_pipe->plane_state != current_pipe->top_pipe->plane_state)
|
||||||
|
break;
|
||||||
|
previous_split++;
|
||||||
|
current_pipe = current_pipe->top_pipe;
|
||||||
|
}
|
||||||
|
return previous_split;
|
||||||
|
}
|
||||||
|
|
||||||
int dcn20_validate_apply_pipe_split_flags(
|
int dcn20_validate_apply_pipe_split_flags(
|
||||||
struct dc *dc,
|
struct dc *dc,
|
||||||
struct dc_state *context,
|
struct dc_state *context,
|
||||||
int vlevel,
|
int vlevel,
|
||||||
bool *split,
|
int *split,
|
||||||
bool *merge)
|
bool *merge)
|
||||||
{
|
{
|
||||||
int i, pipe_idx, vlevel_split;
|
int i, pipe_idx, vlevel_split;
|
||||||
@@ -2640,8 +2656,14 @@ int dcn20_validate_apply_pipe_split_flags(
|
|||||||
if (!context->res_ctx.pipe_ctx[i].stream)
|
if (!context->res_ctx.pipe_ctx[i].stream)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (force_split || context->bw_ctx.dml.vba.NoOfDPP[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_plane] > 1)
|
if (force_split
|
||||||
split[i] = true;
|
|| context->bw_ctx.dml.vba.NoOfDPP[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_plane] > 1) {
|
||||||
|
if (context->stream_count == 1 && plane_count == 1
|
||||||
|
&& dc->config.enable_4to1MPC && dc->res_pool->pipe_count >= 4)
|
||||||
|
split[i] = 4;
|
||||||
|
else
|
||||||
|
split[i] = 2;
|
||||||
|
}
|
||||||
if ((pipe->stream->view_format ==
|
if ((pipe->stream->view_format ==
|
||||||
VIEW_3D_FORMAT_SIDE_BY_SIDE ||
|
VIEW_3D_FORMAT_SIDE_BY_SIDE ||
|
||||||
pipe->stream->view_format ==
|
pipe->stream->view_format ==
|
||||||
@@ -2650,9 +2672,9 @@ int dcn20_validate_apply_pipe_split_flags(
|
|||||||
TIMING_3D_FORMAT_TOP_AND_BOTTOM ||
|
TIMING_3D_FORMAT_TOP_AND_BOTTOM ||
|
||||||
pipe->stream->timing.timing_3d_format ==
|
pipe->stream->timing.timing_3d_format ==
|
||||||
TIMING_3D_FORMAT_SIDE_BY_SIDE))
|
TIMING_3D_FORMAT_SIDE_BY_SIDE))
|
||||||
split[i] = true;
|
split[i] = 2;
|
||||||
if (dc->debug.force_odm_combine & (1 << pipe->stream_res.tg->inst)) {
|
if (dc->debug.force_odm_combine & (1 << pipe->stream_res.tg->inst)) {
|
||||||
split[i] = true;
|
split[i] = 2;
|
||||||
context->bw_ctx.dml.vba.ODMCombineEnablePerState[vlevel][pipe_plane] = dm_odm_combine_mode_2to1;
|
context->bw_ctx.dml.vba.ODMCombineEnablePerState[vlevel][pipe_plane] = dm_odm_combine_mode_2to1;
|
||||||
}
|
}
|
||||||
context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_plane] =
|
context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_plane] =
|
||||||
@@ -2660,39 +2682,58 @@ int dcn20_validate_apply_pipe_split_flags(
|
|||||||
|
|
||||||
if (pipe->prev_odm_pipe && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_plane] != dm_odm_combine_mode_disabled) {
|
if (pipe->prev_odm_pipe && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_plane] != dm_odm_combine_mode_disabled) {
|
||||||
/*Already split odm pipe tree, don't try to split again*/
|
/*Already split odm pipe tree, don't try to split again*/
|
||||||
split[i] = false;
|
split[i] = 0;
|
||||||
split[pipe->prev_odm_pipe->pipe_idx] = false;
|
split[pipe->prev_odm_pipe->pipe_idx] = 0;
|
||||||
} else if (pipe->top_pipe && pipe->plane_state == pipe->top_pipe->plane_state
|
} else if (pipe->top_pipe && pipe->plane_state == pipe->top_pipe->plane_state
|
||||||
&& context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_plane] == dm_odm_combine_mode_disabled) {
|
&& context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_plane] == dm_odm_combine_mode_disabled) {
|
||||||
/*Already split mpc tree, don't try to split again, assumes only 2x mpc combine*/
|
/*If 2 way split but can support 4 way split, then split each pipe again*/
|
||||||
split[i] = false;
|
if (context->stream_count == 1 && plane_count == 1
|
||||||
split[pipe->top_pipe->pipe_idx] = false;
|
&& dc->config.enable_4to1MPC && dc->res_pool->pipe_count >= 4) {
|
||||||
} else if (pipe->prev_odm_pipe || (pipe->top_pipe && pipe->plane_state == pipe->top_pipe->plane_state)) {
|
split[i] = 2;
|
||||||
if (split[i] == false) {
|
} else {
|
||||||
|
split[i] = 0;
|
||||||
|
split[pipe->top_pipe->pipe_idx] = 0;
|
||||||
|
}
|
||||||
|
} else if (pipe->prev_odm_pipe || (dcn20_find_previous_split_count(pipe) == 2 && pipe->top_pipe)) {
|
||||||
|
if (split[i] == 0) {
|
||||||
/*Exiting mpc/odm combine*/
|
/*Exiting mpc/odm combine*/
|
||||||
merge[i] = true;
|
merge[i] = true;
|
||||||
if (pipe->prev_odm_pipe) {
|
|
||||||
ASSERT(0); /*should not actually happen yet*/
|
|
||||||
merge[pipe->prev_odm_pipe->pipe_idx] = true;
|
|
||||||
} else
|
|
||||||
merge[pipe->top_pipe->pipe_idx] = true;
|
|
||||||
} else {
|
} else {
|
||||||
/*Transition from mpc combine to odm combine or vice versa*/
|
/*Transition from mpc combine to odm combine or vice versa*/
|
||||||
ASSERT(0); /*should not actually happen yet*/
|
ASSERT(0); /*should not actually happen yet*/
|
||||||
split[i] = true;
|
split[i] = 2;
|
||||||
merge[i] = true;
|
merge[i] = true;
|
||||||
if (pipe->prev_odm_pipe) {
|
if (pipe->prev_odm_pipe) {
|
||||||
split[pipe->prev_odm_pipe->pipe_idx] = true;
|
split[pipe->prev_odm_pipe->pipe_idx] = 2;
|
||||||
merge[pipe->prev_odm_pipe->pipe_idx] = true;
|
merge[pipe->prev_odm_pipe->pipe_idx] = true;
|
||||||
} else {
|
} else {
|
||||||
split[pipe->top_pipe->pipe_idx] = true;
|
split[pipe->top_pipe->pipe_idx] = 2;
|
||||||
merge[pipe->top_pipe->pipe_idx] = true;
|
merge[pipe->top_pipe->pipe_idx] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (dcn20_find_previous_split_count(pipe) == 3) {
|
||||||
|
if (split[i] == 0 && !pipe->top_pipe) {
|
||||||
|
merge[pipe->bottom_pipe->pipe_idx] = true;
|
||||||
|
merge[pipe->bottom_pipe->bottom_pipe->pipe_idx] = true;
|
||||||
|
} else if (split[i] == 2 && !pipe->top_pipe) {
|
||||||
|
merge[pipe->bottom_pipe->bottom_pipe->pipe_idx] = true;
|
||||||
|
split[i] = 0;
|
||||||
|
}
|
||||||
|
} else if (dcn20_find_previous_split_count(pipe) == 4) {
|
||||||
|
if (split[i] == 0 && !pipe->top_pipe) {
|
||||||
|
merge[pipe->bottom_pipe->pipe_idx] = true;
|
||||||
|
merge[pipe->bottom_pipe->bottom_pipe->pipe_idx] = true;
|
||||||
|
merge[pipe->bottom_pipe->bottom_pipe->bottom_pipe->pipe_idx] = true;
|
||||||
|
} else if (split[i] == 2 && !pipe->top_pipe) {
|
||||||
|
merge[pipe->bottom_pipe->bottom_pipe->pipe_idx] = true;
|
||||||
|
merge[pipe->bottom_pipe->bottom_pipe->bottom_pipe->pipe_idx] = true;
|
||||||
|
split[i] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adjust dppclk when split is forced, do not bother with dispclk */
|
/* Adjust dppclk when split is forced, do not bother with dispclk */
|
||||||
if (split[i] && context->bw_ctx.dml.vba.NoOfDPP[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] == 1)
|
if (split[i] != 0
|
||||||
|
&& context->bw_ctx.dml.vba.NoOfDPP[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] == 1)
|
||||||
context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] /= 2;
|
context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] /= 2;
|
||||||
pipe_idx++;
|
pipe_idx++;
|
||||||
}
|
}
|
||||||
@@ -2709,7 +2750,7 @@ bool dcn20_fast_validate_bw(
|
|||||||
int *vlevel_out)
|
int *vlevel_out)
|
||||||
{
|
{
|
||||||
bool out = false;
|
bool out = false;
|
||||||
bool split[MAX_PIPES] = { false };
|
int split[MAX_PIPES] = { 0 };
|
||||||
int pipe_cnt, i, pipe_idx, vlevel;
|
int pipe_cnt, i, pipe_idx, vlevel;
|
||||||
|
|
||||||
ASSERT(pipes);
|
ASSERT(pipes);
|
||||||
@@ -2769,7 +2810,7 @@ bool dcn20_fast_validate_bw(
|
|||||||
&& context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx])
|
&& context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx])
|
||||||
goto validate_fail;
|
goto validate_fail;
|
||||||
|
|
||||||
if (split[i]) {
|
if (split[i] == 2) {
|
||||||
if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state) {
|
if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state) {
|
||||||
/* pipe not split previously needs split */
|
/* pipe not split previously needs split */
|
||||||
hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe);
|
hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe);
|
||||||
@@ -2784,11 +2825,13 @@ bool dcn20_fast_validate_bw(
|
|||||||
pipe, hsplit_pipe))
|
pipe, hsplit_pipe))
|
||||||
goto validate_fail;
|
goto validate_fail;
|
||||||
dcn20_build_mapped_resource(dc, context, pipe->stream);
|
dcn20_build_mapped_resource(dc, context, pipe->stream);
|
||||||
} else
|
} else {
|
||||||
if (!dcn20_split_stream_for_mpc(
|
dcn20_split_stream_for_mpc(
|
||||||
&context->res_ctx, dc->res_pool,
|
&context->res_ctx, dc->res_pool,
|
||||||
pipe, hsplit_pipe))
|
pipe, hsplit_pipe);
|
||||||
|
if (!resource_build_scaling_params(pipe) || !resource_build_scaling_params(hsplit_pipe))
|
||||||
goto validate_fail;
|
goto validate_fail;
|
||||||
|
}
|
||||||
pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx;
|
pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx;
|
||||||
}
|
}
|
||||||
} else if (hsplit_pipe && hsplit_pipe->plane_state == pipe->plane_state) {
|
} else if (hsplit_pipe && hsplit_pipe->plane_state == pipe->plane_state) {
|
||||||
|
|||||||
@@ -119,17 +119,18 @@ void dcn20_set_mcif_arb_params(
|
|||||||
display_e2e_pipe_params_st *pipes,
|
display_e2e_pipe_params_st *pipes,
|
||||||
int pipe_cnt);
|
int pipe_cnt);
|
||||||
bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, bool fast_validate);
|
bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, bool fast_validate);
|
||||||
|
int dcn20_find_previous_split_count(struct pipe_ctx *pipe);
|
||||||
int dcn20_validate_apply_pipe_split_flags(
|
int dcn20_validate_apply_pipe_split_flags(
|
||||||
struct dc *dc,
|
struct dc *dc,
|
||||||
struct dc_state *context,
|
struct dc_state *context,
|
||||||
int vlevel,
|
int vlevel,
|
||||||
bool *split,
|
int *split,
|
||||||
bool *merge);
|
bool *merge);
|
||||||
void dcn20_release_dsc(struct resource_context *res_ctx,
|
void dcn20_release_dsc(struct resource_context *res_ctx,
|
||||||
const struct resource_pool *pool,
|
const struct resource_pool *pool,
|
||||||
struct display_stream_compressor **dsc);
|
struct display_stream_compressor **dsc);
|
||||||
bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx);
|
bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx);
|
||||||
bool dcn20_split_stream_for_mpc(
|
void dcn20_split_stream_for_mpc(
|
||||||
struct resource_context *res_ctx,
|
struct resource_context *res_ctx,
|
||||||
const struct resource_pool *pool,
|
const struct resource_pool *pool,
|
||||||
struct pipe_ctx *primary_pipe,
|
struct pipe_ctx *primary_pipe,
|
||||||
|
|||||||
Reference in New Issue
Block a user