Commit 9d1e1722 authored by Wenjing Liu's avatar Wenjing Liu Committed by Alex Deucher

drm/amd/display: use new pipe allocation interface in dcn32 fpu

This commit implements a new pipe resource allocation logic for DCN32
when windowed ODM MPO flag is set to enable testing. By default the
flag is not set. It will be toggled on after we complete testing.
Reviewed-by: default avatarJun Lei <jun.lei@amd.com>
Acked-by: default avatarHamza Mahfooz <hamza.mahfooz@amd.com>
Signed-off-by: default avatarWenjing Liu <wenjing.liu@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 21741810
......@@ -1654,6 +1654,188 @@ static bool dcn32_split_stream_for_mpc_or_odm(
return true;
}
struct pipe_slice_table {
struct {
struct dc_stream_state *stream;
int slice_count;
} odm_combines[MAX_STREAMS];
int odm_combine_count;
struct {
struct dc_plane_state *plane;
int slice_count;
} mpc_combines[MAX_SURFACES];
int mpc_combine_count;
};
static void update_slice_table_for_stream(struct pipe_slice_table *table,
struct dc_stream_state *stream, int diff)
{
int i;
for (i = 0; i < table->odm_combine_count; i++) {
if (table->odm_combines[i].stream == stream) {
table->odm_combines[i].slice_count += diff;
break;
}
}
if (i == table->odm_combine_count) {
table->odm_combine_count++;
table->odm_combines[i].stream = stream;
table->odm_combines[i].slice_count = diff;
}
}
static void update_slice_table_for_plane(struct pipe_slice_table *table,
struct dc_plane_state *plane, int diff)
{
int i;
for (i = 0; i < table->mpc_combine_count; i++) {
if (table->mpc_combines[i].plane == plane) {
table->mpc_combines[i].slice_count += diff;
break;
}
}
if (i == table->mpc_combine_count) {
table->mpc_combine_count++;
table->mpc_combines[i].plane = plane;
table->mpc_combines[i].slice_count = diff;
}
}
static void init_pipe_slice_table_from_context(
struct pipe_slice_table *table,
struct dc_state *context)
{
int i, j;
struct pipe_ctx *otg_master;
struct pipe_ctx *dpp_pipes[MAX_PIPES];
struct dc_stream_state *stream;
int count;
memset(table, 0, sizeof(*table));
for (i = 0; i < context->stream_count; i++) {
stream = context->streams[i];
otg_master = resource_get_otg_master_for_stream(
&context->res_ctx, stream);
count = resource_get_odm_slice_count(otg_master);
update_slice_table_for_stream(table, stream, count);
count = resource_get_dpp_pipes_for_opp_head(otg_master,
&context->res_ctx, dpp_pipes);
for (j = 0; j < count; j++)
if (dpp_pipes[j]->plane_state)
update_slice_table_for_plane(table,
dpp_pipes[j]->plane_state, 1);
}
}
static bool update_pipe_slice_table_with_split_flags(
struct pipe_slice_table *table,
struct dc *dc,
struct dc_state *context,
struct vba_vars_st *vba,
int split[MAX_PIPES],
bool merge[MAX_PIPES])
{
/* NOTE: we are deprecating the support for the concept of pipe splitting
* or pipe merging. Instead we append slices to the end and remove
* slices from the end. The following code converts a pipe split or
* merge to an append or remove operation.
*
* For example:
* When split flags describe the following pipe connection transition
*
* from:
* pipe 0 (split=2) -> pipe 1 (split=2)
* to: (old behavior)
* pipe 0 -> pipe 2 -> pipe 1 -> pipe 3
*
* the code below actually does:
* pipe 0 -> pipe 1 -> pipe 2 -> pipe 3
*
* This is the new intended behavior and for future DCNs we will retire
* the old concept completely.
*/
struct pipe_ctx *pipe;
bool odm;
int i;
bool updated = false;
for (i = 0; i < dc->res_pool->pipe_count; i++) {
pipe = &context->res_ctx.pipe_ctx[i];
if (merge[i]) {
if (resource_is_pipe_type(pipe, OPP_HEAD))
/* merging OPP head means reducing ODM slice
* count by 1
*/
update_slice_table_for_stream(table, pipe->stream, -1);
else if (resource_is_pipe_type(pipe, DPP_PIPE) &&
resource_get_odm_slice_index(resource_get_opp_head(pipe)) == 0)
/* merging DPP pipe of the first ODM slice means
* reducing MPC slice count by 1
*/
update_slice_table_for_plane(table, pipe->plane_state, -1);
updated = true;
}
if (split[i]) {
odm = vba->ODMCombineEnabled[vba->pipe_plane[i]] !=
dm_odm_combine_mode_disabled;
if (odm && resource_is_pipe_type(pipe, OPP_HEAD))
update_slice_table_for_stream(
table, pipe->stream, split[i] - 1);
else if (!odm && resource_is_pipe_type(pipe, DPP_PIPE))
update_slice_table_for_plane(
table, pipe->plane_state, split[i] - 1);
updated = true;
}
}
return updated;
}
static void update_pipes_with_slice_table(struct dc *dc, struct dc_state *context,
struct pipe_slice_table *table)
{
int i;
for (i = 0; i < table->odm_combine_count; i++) {
resource_update_pipes_for_stream_with_slice_count(context,
dc->current_state, dc->res_pool,
table->odm_combines[i].stream,
table->odm_combines[i].slice_count);
/* TODO: move this into the function above */
dcn20_build_mapped_resource(dc, context,
table->odm_combines[i].stream);
}
for (i = 0; i < table->mpc_combine_count; i++)
resource_update_pipes_for_plane_with_slice_count(context,
dc->current_state, dc->res_pool,
table->mpc_combines[i].plane,
table->mpc_combines[i].slice_count);
}
static bool update_pipes_with_split_flags(struct dc *dc, struct dc_state *context,
struct vba_vars_st *vba, int split[MAX_PIPES],
bool merge[MAX_PIPES])
{
struct pipe_slice_table slice_table;
bool updated;
init_pipe_slice_table_from_context(&slice_table, context);
updated = update_pipe_slice_table_with_split_flags(
&slice_table, dc, context, vba,
split, merge);
update_pipes_with_slice_table(dc, context, &slice_table);
return updated;
}
bool dcn32_internal_validate_bw(struct dc *dc,
struct dc_state *context,
display_e2e_pipe_params_st *pipes,
......@@ -1749,173 +1931,181 @@ bool dcn32_internal_validate_bw(struct dc *dc,
pipe_idx++;
}
/* merge pipes if necessary */
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
if (dc->config.enable_windowed_mpo_odm) {
repopulate_pipes = update_pipes_with_split_flags(
dc, context, vba, split, merge);
} else {
/* the code below will be removed once windowed mpo odm is fully
* enabled.
*/
/* merge pipes if necessary */
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
/*skip pipes that don't need merging*/
if (!merge[i])
continue;
/*skip pipes that don't need merging*/
if (!merge[i])
continue;
/* if ODM merge we ignore mpc tree, mpo pipes will have their own flags */
if (pipe->prev_odm_pipe) {
/*split off odm pipe*/
pipe->prev_odm_pipe->next_odm_pipe = pipe->next_odm_pipe;
if (pipe->next_odm_pipe)
pipe->next_odm_pipe->prev_odm_pipe = pipe->prev_odm_pipe;
/*2:1ODM+MPC Split MPO to Single Pipe + MPC Split MPO*/
if (pipe->bottom_pipe) {
if (pipe->bottom_pipe->prev_odm_pipe || pipe->bottom_pipe->next_odm_pipe) {
/*MPC split rules will handle this case*/
pipe->bottom_pipe->top_pipe = NULL;
} else {
/* when merging an ODM pipes, the bottom MPC pipe must now point to
* the previous ODM pipe and its associated stream assets
*/
if (pipe->prev_odm_pipe->bottom_pipe) {
/* 3 plane MPO*/
pipe->bottom_pipe->top_pipe = pipe->prev_odm_pipe->bottom_pipe;
pipe->prev_odm_pipe->bottom_pipe->bottom_pipe = pipe->bottom_pipe;
/* if ODM merge we ignore mpc tree, mpo pipes will have their own flags */
if (pipe->prev_odm_pipe) {
/*split off odm pipe*/
pipe->prev_odm_pipe->next_odm_pipe = pipe->next_odm_pipe;
if (pipe->next_odm_pipe)
pipe->next_odm_pipe->prev_odm_pipe = pipe->prev_odm_pipe;
/*2:1ODM+MPC Split MPO to Single Pipe + MPC Split MPO*/
if (pipe->bottom_pipe) {
if (pipe->bottom_pipe->prev_odm_pipe || pipe->bottom_pipe->next_odm_pipe) {
/*MPC split rules will handle this case*/
pipe->bottom_pipe->top_pipe = NULL;
} else {
/* 2 plane MPO*/
pipe->bottom_pipe->top_pipe = pipe->prev_odm_pipe;
pipe->prev_odm_pipe->bottom_pipe = pipe->bottom_pipe;
/* when merging an ODM pipes, the bottom MPC pipe must now point to
* the previous ODM pipe and its associated stream assets
*/
if (pipe->prev_odm_pipe->bottom_pipe) {
/* 3 plane MPO*/
pipe->bottom_pipe->top_pipe = pipe->prev_odm_pipe->bottom_pipe;
pipe->prev_odm_pipe->bottom_pipe->bottom_pipe = pipe->bottom_pipe;
} else {
/* 2 plane MPO*/
pipe->bottom_pipe->top_pipe = pipe->prev_odm_pipe;
pipe->prev_odm_pipe->bottom_pipe = pipe->bottom_pipe;
}
memcpy(&pipe->bottom_pipe->stream_res, &pipe->bottom_pipe->top_pipe->stream_res, sizeof(struct stream_resource));
}
}
memcpy(&pipe->bottom_pipe->stream_res, &pipe->bottom_pipe->top_pipe->stream_res, sizeof(struct stream_resource));
if (pipe->top_pipe) {
pipe->top_pipe->bottom_pipe = NULL;
}
}
if (pipe->top_pipe) {
pipe->top_pipe->bottom_pipe = NULL;
}
pipe->bottom_pipe = NULL;
pipe->next_odm_pipe = NULL;
pipe->plane_state = NULL;
pipe->stream = NULL;
pipe->top_pipe = NULL;
pipe->prev_odm_pipe = NULL;
if (pipe->stream_res.dsc)
dcn20_release_dsc(&context->res_ctx, dc->res_pool, &pipe->stream_res.dsc);
memset(&pipe->plane_res, 0, sizeof(pipe->plane_res));
memset(&pipe->stream_res, 0, sizeof(pipe->stream_res));
memset(&pipe->link_res, 0, sizeof(pipe->link_res));
repopulate_pipes = true;
} else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) {
struct pipe_ctx *top_pipe = pipe->top_pipe;
struct pipe_ctx *bottom_pipe = pipe->bottom_pipe;
top_pipe->bottom_pipe = bottom_pipe;
if (bottom_pipe)
bottom_pipe->top_pipe = top_pipe;
pipe->top_pipe = NULL;
pipe->bottom_pipe = NULL;
pipe->plane_state = NULL;
pipe->stream = NULL;
memset(&pipe->plane_res, 0, sizeof(pipe->plane_res));
memset(&pipe->stream_res, 0, sizeof(pipe->stream_res));
memset(&pipe->link_res, 0, sizeof(pipe->link_res));
repopulate_pipes = true;
} else
ASSERT(0); /* Should never try to merge master pipe */
pipe->bottom_pipe = NULL;
pipe->next_odm_pipe = NULL;
pipe->plane_state = NULL;
pipe->stream = NULL;
pipe->top_pipe = NULL;
pipe->prev_odm_pipe = NULL;
if (pipe->stream_res.dsc)
dcn20_release_dsc(&context->res_ctx, dc->res_pool, &pipe->stream_res.dsc);
memset(&pipe->plane_res, 0, sizeof(pipe->plane_res));
memset(&pipe->stream_res, 0, sizeof(pipe->stream_res));
memset(&pipe->link_res, 0, sizeof(pipe->link_res));
repopulate_pipes = true;
} else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) {
struct pipe_ctx *top_pipe = pipe->top_pipe;
struct pipe_ctx *bottom_pipe = pipe->bottom_pipe;
top_pipe->bottom_pipe = bottom_pipe;
if (bottom_pipe)
bottom_pipe->top_pipe = top_pipe;
pipe->top_pipe = NULL;
pipe->bottom_pipe = NULL;
pipe->plane_state = NULL;
pipe->stream = NULL;
memset(&pipe->plane_res, 0, sizeof(pipe->plane_res));
memset(&pipe->stream_res, 0, sizeof(pipe->stream_res));
memset(&pipe->link_res, 0, sizeof(pipe->link_res));
repopulate_pipes = true;
} else
ASSERT(0); /* Should never try to merge master pipe */
}
for (i = 0, pipe_idx = -1; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
struct pipe_ctx *hsplit_pipe = NULL;
bool odm;
int old_index = -1;
}
if (!pipe->stream || newly_split[i])
continue;
for (i = 0, pipe_idx = -1; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
struct pipe_ctx *hsplit_pipe = NULL;
bool odm;
int old_index = -1;
pipe_idx++;
odm = vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled;
if (!pipe->stream || newly_split[i])
continue;
if (!pipe->plane_state && !odm)
continue;
pipe_idx++;
odm = vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled;
if (split[i]) {
if (odm) {
if (split[i] == 4 && old_pipe->next_odm_pipe && old_pipe->next_odm_pipe->next_odm_pipe)
old_index = old_pipe->next_odm_pipe->next_odm_pipe->pipe_idx;
else if (old_pipe->next_odm_pipe)
if (!pipe->plane_state && !odm)
continue;
if (split[i]) {
if (odm) {
if (split[i] == 4 && old_pipe->next_odm_pipe && old_pipe->next_odm_pipe->next_odm_pipe)
old_index = old_pipe->next_odm_pipe->next_odm_pipe->pipe_idx;
else if (old_pipe->next_odm_pipe)
old_index = old_pipe->next_odm_pipe->pipe_idx;
} else {
if (split[i] == 4 && old_pipe->bottom_pipe && old_pipe->bottom_pipe->bottom_pipe &&
old_pipe->bottom_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
old_index = old_pipe->bottom_pipe->bottom_pipe->pipe_idx;
else if (old_pipe->bottom_pipe &&
old_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
old_index = old_pipe->bottom_pipe->pipe_idx;
}
hsplit_pipe = dcn32_find_split_pipe(dc, context, old_index);
ASSERT(hsplit_pipe);
if (!hsplit_pipe)
goto validate_fail;
if (!dcn32_split_stream_for_mpc_or_odm(
dc, &context->res_ctx,
pipe, hsplit_pipe, odm))
goto validate_fail;
newly_split[hsplit_pipe->pipe_idx] = true;
repopulate_pipes = true;
}
if (split[i] == 4) {
struct pipe_ctx *pipe_4to1;
if (odm && old_pipe->next_odm_pipe)
old_index = old_pipe->next_odm_pipe->pipe_idx;
} else {
if (split[i] == 4 && old_pipe->bottom_pipe && old_pipe->bottom_pipe->bottom_pipe &&
old_pipe->bottom_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
old_index = old_pipe->bottom_pipe->bottom_pipe->pipe_idx;
else if (old_pipe->bottom_pipe &&
old_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
else if (!odm && old_pipe->bottom_pipe &&
old_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
old_index = old_pipe->bottom_pipe->pipe_idx;
else
old_index = -1;
pipe_4to1 = dcn32_find_split_pipe(dc, context, old_index);
ASSERT(pipe_4to1);
if (!pipe_4to1)
goto validate_fail;
if (!dcn32_split_stream_for_mpc_or_odm(
dc, &context->res_ctx,
pipe, pipe_4to1, odm))
goto validate_fail;
newly_split[pipe_4to1->pipe_idx] = true;
if (odm && old_pipe->next_odm_pipe && old_pipe->next_odm_pipe->next_odm_pipe
&& old_pipe->next_odm_pipe->next_odm_pipe->next_odm_pipe)
old_index = old_pipe->next_odm_pipe->next_odm_pipe->next_odm_pipe->pipe_idx;
else if (!odm && old_pipe->bottom_pipe && old_pipe->bottom_pipe->bottom_pipe &&
old_pipe->bottom_pipe->bottom_pipe->bottom_pipe &&
old_pipe->bottom_pipe->bottom_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
old_index = old_pipe->bottom_pipe->bottom_pipe->bottom_pipe->pipe_idx;
else
old_index = -1;
pipe_4to1 = dcn32_find_split_pipe(dc, context, old_index);
ASSERT(pipe_4to1);
if (!pipe_4to1)
goto validate_fail;
if (!dcn32_split_stream_for_mpc_or_odm(
dc, &context->res_ctx,
hsplit_pipe, pipe_4to1, odm))
goto validate_fail;
newly_split[pipe_4to1->pipe_idx] = true;
}
hsplit_pipe = dcn32_find_split_pipe(dc, context, old_index);
ASSERT(hsplit_pipe);
if (!hsplit_pipe)
goto validate_fail;
if (!dcn32_split_stream_for_mpc_or_odm(
dc, &context->res_ctx,
pipe, hsplit_pipe, odm))
goto validate_fail;
newly_split[hsplit_pipe->pipe_idx] = true;
repopulate_pipes = true;
}
if (split[i] == 4) {
struct pipe_ctx *pipe_4to1;
if (odm && old_pipe->next_odm_pipe)
old_index = old_pipe->next_odm_pipe->pipe_idx;
else if (!odm && old_pipe->bottom_pipe &&
old_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
old_index = old_pipe->bottom_pipe->pipe_idx;
else
old_index = -1;
pipe_4to1 = dcn32_find_split_pipe(dc, context, old_index);
ASSERT(pipe_4to1);
if (!pipe_4to1)
goto validate_fail;
if (!dcn32_split_stream_for_mpc_or_odm(
dc, &context->res_ctx,
pipe, pipe_4to1, odm))
goto validate_fail;
newly_split[pipe_4to1->pipe_idx] = true;
if (odm && old_pipe->next_odm_pipe && old_pipe->next_odm_pipe->next_odm_pipe
&& old_pipe->next_odm_pipe->next_odm_pipe->next_odm_pipe)
old_index = old_pipe->next_odm_pipe->next_odm_pipe->next_odm_pipe->pipe_idx;
else if (!odm && old_pipe->bottom_pipe && old_pipe->bottom_pipe->bottom_pipe &&
old_pipe->bottom_pipe->bottom_pipe->bottom_pipe &&
old_pipe->bottom_pipe->bottom_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
old_index = old_pipe->bottom_pipe->bottom_pipe->bottom_pipe->pipe_idx;
else
old_index = -1;
pipe_4to1 = dcn32_find_split_pipe(dc, context, old_index);
ASSERT(pipe_4to1);
if (!pipe_4to1)
goto validate_fail;
if (!dcn32_split_stream_for_mpc_or_odm(
dc, &context->res_ctx,
hsplit_pipe, pipe_4to1, odm))
goto validate_fail;
newly_split[pipe_4to1->pipe_idx] = true;
if (odm)
dcn20_build_mapped_resource(dc, context, pipe->stream);
}
if (odm)
dcn20_build_mapped_resource(dc, context, pipe->stream);
}
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
if (pipe->plane_state) {
if (!resource_build_scaling_params(pipe))
goto validate_fail;
if (pipe->plane_state) {
if (!resource_build_scaling_params(pipe))
goto validate_fail;
}
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment