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,
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;
+ }
}
}