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