[PATCH 11/21] drm/amd/display: add more pipe resource interfaces

Hamza Mahfooz hamza.mahfooz at amd.com
Wed Aug 23 15:58:13 UTC 2023


From: Wenjing Liu <wenjing.liu at amd.com>

Redesign pipe resource interfaces in resource.h file. The new interface
design addresses the issue with lack of pipe topology encapsulation and
lack of pipe accessors.

Reviewed-by: Jun Lei <jun.lei at amd.com>
Acked-by: Hamza Mahfooz <hamza.mahfooz at amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu at amd.com>
---
 .../gpu/drm/amd/display/dc/core/dc_resource.c | 951 ++++++++++--------
 .../drm/amd/display/dc/dcn20/dcn20_hwseq.c    |   2 +
 .../drm/amd/display/dc/dcn20/dcn20_resource.c |  22 +-
 .../drm/amd/display/dc/dcn20/dcn20_resource.h |   4 +-
 .../amd/display/dc/dcn201/dcn201_resource.c   |   1 +
 .../drm/amd/display/dc/dcn21/dcn21_resource.c |   1 +
 .../drm/amd/display/dc/dcn30/dcn30_resource.c |   1 +
 .../amd/display/dc/dcn301/dcn301_resource.c   |   1 +
 .../amd/display/dc/dcn302/dcn302_resource.c   |   1 +
 .../amd/display/dc/dcn303/dcn303_resource.c   |   1 +
 .../drm/amd/display/dc/dcn31/dcn31_resource.c |   1 +
 .../amd/display/dc/dcn314/dcn314_resource.c   |   1 +
 .../amd/display/dc/dcn315/dcn315_resource.c   |   1 +
 .../amd/display/dc/dcn316/dcn316_resource.c   |   1 +
 .../drm/amd/display/dc/dcn32/dcn32_resource.c |  11 +-
 .../amd/display/dc/dcn321/dcn321_resource.c   |   1 +
 .../drm/amd/display/dc/dml/dcn20/dcn20_fpu.c  |   6 +-
 drivers/gpu/drm/amd/display/dc/inc/resource.h | 278 ++---
 18 files changed, 740 insertions(+), 545 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index b7ab357d1b9d..84db7c5fb852 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -732,66 +732,6 @@ static inline void get_vp_scan_direction(
 		*flip_horz_scan_dir = !*flip_horz_scan_dir;
 }
 
-int resource_get_num_mpc_splits(const struct pipe_ctx *pipe)
-{
-	int mpc_split_count = 0;
-	const struct pipe_ctx *other_pipe = pipe->bottom_pipe;
-
-	while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
-		mpc_split_count++;
-		other_pipe = other_pipe->bottom_pipe;
-	}
-	other_pipe = pipe->top_pipe;
-	while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
-		mpc_split_count++;
-		other_pipe = other_pipe->top_pipe;
-	}
-
-	return mpc_split_count;
-}
-
-int resource_get_num_odm_splits(const struct pipe_ctx *pipe)
-{
-	int odm_split_count = 0;
-
-	pipe = resource_get_otg_master(pipe);
-
-	while (pipe->next_odm_pipe) {
-		odm_split_count++;
-		pipe = pipe->next_odm_pipe;
-	}
-	return odm_split_count;
-}
-
-int resource_get_odm_split_index(struct pipe_ctx *pipe_ctx)
-{
-	int index = 0;
-
-	pipe_ctx = resource_get_opp_head(pipe_ctx);
-	if (!pipe_ctx)
-		return 0;
-
-	while (pipe_ctx->prev_odm_pipe) {
-		index++;
-		pipe_ctx = pipe_ctx->prev_odm_pipe;
-	}
-
-	return index;
-}
-
-int resource_get_mpc_split_index(struct pipe_ctx *pipe_ctx)
-{
-	struct pipe_ctx *split_pipe = pipe_ctx->top_pipe;
-	int index = 0;
-
-	while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) {
-		index++;
-		split_pipe = split_pipe->top_pipe;
-	}
-
-	return index;
-}
-
 /*
  * This is a preliminary vp size calculation to allow us to check taps support.
  * The result is completely overridden afterwards.
@@ -844,8 +784,8 @@ static struct rect shift_rec(const struct rect *rec_in, int x, int y)
 static struct rect calculate_odm_slice_in_timing_active(struct pipe_ctx *pipe_ctx)
 {
 	const struct dc_stream_state *stream = pipe_ctx->stream;
-	int odm_slice_count = resource_get_num_odm_splits(pipe_ctx) + 1;
-	int odm_slice_idx = resource_get_odm_split_index(pipe_ctx);
+	int odm_slice_count = resource_get_odm_slice_count(pipe_ctx);
+	int odm_slice_idx = resource_get_odm_slice_index(pipe_ctx);
 	bool is_last_odm_slice = (odm_slice_idx + 1) == odm_slice_count;
 	int h_active = stream->timing.h_addressable +
 			stream->timing.h_border_left +
@@ -962,8 +902,8 @@ static struct rect calculate_mpc_slice_in_timing_active(
 		struct rect *plane_clip_rec)
 {
 	const struct dc_stream_state *stream = pipe_ctx->stream;
-	int mpc_slice_count = resource_get_num_mpc_splits(pipe_ctx) + 1;
-	int mpc_slice_idx = resource_get_mpc_split_index(pipe_ctx);
+	int mpc_slice_count = resource_get_mpc_slice_count(pipe_ctx);
+	int mpc_slice_idx = resource_get_mpc_slice_index(pipe_ctx);
 	int epimo = mpc_slice_count - plane_clip_rec->width % mpc_slice_count - 1;
 	struct rect mpc_rec;
 
@@ -1699,7 +1639,7 @@ int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine(
 
 		if (resource_is_pipe_type(cur_pipe, DPP_PIPE) &&
 				!resource_is_pipe_type(cur_pipe, OPP_HEAD) &&
-				resource_is_for_mpcc_combine(cur_pipe) &&
+				resource_get_mpc_slice_index(cur_pipe) > 0 &&
 				resource_is_pipe_type(new_pipe, FREE_PIPE)) {
 			free_pipe_idx = i;
 			break;
@@ -1763,14 +1703,9 @@ bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type)
 	}
 }
 
-bool resource_is_for_mpcc_combine(const struct pipe_ctx *pipe_ctx)
-{
-	return resource_get_num_mpc_splits(pipe_ctx) > 0;
-}
-
 struct pipe_ctx *resource_get_otg_master_for_stream(
 		struct resource_context *res_ctx,
-		struct dc_stream_state *stream)
+		const struct dc_stream_state *stream)
 {
 	int i;
 
@@ -1782,6 +1717,75 @@ struct pipe_ctx *resource_get_otg_master_for_stream(
 	return NULL;
 }
 
+int resource_get_opp_heads_for_otg_master(const struct pipe_ctx *otg_master,
+		struct resource_context *res_ctx,
+		struct pipe_ctx *opp_heads[MAX_PIPES])
+{
+	struct pipe_ctx *opp_head = &res_ctx->pipe_ctx[otg_master->pipe_idx];
+	int i = 0;
+
+	if (!resource_is_pipe_type(otg_master, OTG_MASTER)) {
+		ASSERT(0);
+		return 0;
+	}
+	while (opp_head) {
+		ASSERT(i < MAX_PIPES);
+		opp_heads[i++] = opp_head;
+		opp_head = opp_head->next_odm_pipe;
+	}
+	return i;
+}
+
+int resource_get_dpp_pipes_for_opp_head(const struct pipe_ctx *opp_head,
+		struct resource_context *res_ctx,
+		struct pipe_ctx *dpp_pipes[MAX_PIPES])
+{
+	struct pipe_ctx *pipe = &res_ctx->pipe_ctx[opp_head->pipe_idx];
+	int i = 0;
+
+	if (!resource_is_pipe_type(opp_head, OPP_HEAD)) {
+		ASSERT(0);
+		return 0;
+	}
+	while (pipe && resource_is_pipe_type(pipe, DPP_PIPE)) {
+		ASSERT(i < MAX_PIPES);
+		dpp_pipes[i++] = pipe;
+		pipe = pipe->bottom_pipe;
+	}
+	return i;
+}
+
+int resource_get_dpp_pipes_for_plane(const struct dc_plane_state *plane,
+		struct resource_context *res_ctx,
+		struct pipe_ctx *dpp_pipes[MAX_PIPES])
+{
+	int i = 0, j;
+	struct pipe_ctx *pipe;
+
+	for (j = 0; j < MAX_PIPES; j++) {
+		pipe = &res_ctx->pipe_ctx[j];
+		if (pipe->plane_state == plane && pipe->prev_odm_pipe == NULL) {
+			if (resource_is_pipe_type(pipe, OPP_HEAD) ||
+					pipe->top_pipe->plane_state != plane)
+				break;
+		}
+	}
+
+	if (j < MAX_PIPES) {
+		if (pipe->next_odm_pipe)
+			while (pipe) {
+				dpp_pipes[i++] = pipe;
+				pipe = pipe->next_odm_pipe;
+			}
+		else
+			while (pipe && pipe->plane_state == plane) {
+				dpp_pipes[i++] = pipe;
+				pipe = pipe->bottom_pipe;
+			}
+	}
+	return i;
+}
+
 struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx)
 {
 	struct pipe_ctx *otg_master = resource_get_opp_head(pipe_ctx);
@@ -1801,6 +1805,66 @@ struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx)
 	return opp_head;
 }
 
+int resource_get_mpc_slice_index(const struct pipe_ctx *pipe_ctx)
+{
+	struct pipe_ctx *split_pipe = pipe_ctx->top_pipe;
+	int index = 0;
+
+	while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) {
+		index++;
+		split_pipe = split_pipe->top_pipe;
+	}
+
+	return index;
+}
+
+int resource_get_mpc_slice_count(const struct pipe_ctx *pipe)
+{
+	int mpc_split_count = 1;
+	const struct pipe_ctx *other_pipe = pipe->bottom_pipe;
+
+	while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
+		mpc_split_count++;
+		other_pipe = other_pipe->bottom_pipe;
+	}
+	other_pipe = pipe->top_pipe;
+	while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
+		mpc_split_count++;
+		other_pipe = other_pipe->top_pipe;
+	}
+
+	return mpc_split_count;
+}
+
+int resource_get_odm_slice_count(const struct pipe_ctx *pipe)
+{
+	int odm_split_count = 1;
+
+	pipe = resource_get_otg_master(pipe);
+
+	while (pipe->next_odm_pipe) {
+		odm_split_count++;
+		pipe = pipe->next_odm_pipe;
+	}
+	return odm_split_count;
+}
+
+int resource_get_odm_slice_index(const struct pipe_ctx *pipe_ctx)
+{
+	int index = 0;
+
+	pipe_ctx = resource_get_opp_head(pipe_ctx);
+	if (!pipe_ctx)
+		return 0;
+
+	while (pipe_ctx->prev_odm_pipe) {
+		index++;
+		pipe_ctx = pipe_ctx->prev_odm_pipe;
+	}
+
+	return index;
+}
+
 static struct pipe_ctx *get_tail_pipe(
 		struct pipe_ctx *head_pipe)
 {
@@ -1902,97 +1966,265 @@ static int acquire_first_split_pipe(
 	return FREE_PIPE_INDEX_NOT_FOUND;
 }
 
-/* For each OPP head of an OTG master, add top plane at plane index 0.
- *
- * In the following example, the stream has 2 ODM slices without a top plane.
- * By adding a plane 0 to OPP heads, we are configuring our hardware to render
- * plane 0 by using each OPP head's DPP.
- *
- *       Inter-pipe Relation (Before Adding Plane)
- *        __________________________________________________
- *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
- *       |        |               | slice 0   |             |
- *       |   0    |               |blank ----ODM----------- |
- *       |        |               | slice 1 | |             |
- *       |   1    |               |blank ---- |             |
- *       |________|_______________|___________|_____________|
- *
- *       Inter-pipe Relation (After Adding Plane)
- *        __________________________________________________
- *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
- *       |        |  plane 0      | slice 0   |             |
- *       |   0    | -------------------------ODM----------- |
- *       |        |  plane 0      | slice 1 | |             |
- *       |   1    | ------------------------- |             |
- *       |________|_______________|___________|_____________|
- */
-static bool add_plane_to_opp_head_pipes(struct pipe_ctx *otg_master_pipe,
-		struct dc_plane_state *plane_state,
-		struct dc_state *context)
+static void update_stream_engine_usage(
+		struct resource_context *res_ctx,
+		const struct resource_pool *pool,
+		struct stream_encoder *stream_enc,
+		bool acquired)
 {
-	struct pipe_ctx *opp_head_pipe = otg_master_pipe;
+	int i;
 
-	while (opp_head_pipe) {
-		if (opp_head_pipe->plane_state) {
-			ASSERT(0);
-			return false;
-		}
-		opp_head_pipe->plane_state = plane_state;
-		opp_head_pipe = opp_head_pipe->next_odm_pipe;
+	for (i = 0; i < pool->stream_enc_count; i++) {
+		if (pool->stream_enc[i] == stream_enc)
+			res_ctx->is_stream_enc_acquired[i] = acquired;
 	}
+}
 
-	return true;
+static void update_hpo_dp_stream_engine_usage(
+		struct resource_context *res_ctx,
+		const struct resource_pool *pool,
+		struct hpo_dp_stream_encoder *hpo_dp_stream_enc,
+		bool acquired)
+{
+	int i;
+
+	for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
+		if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc)
+			res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired;
+	}
 }
 
-/* For each OPP head of an OTG master, acquire a secondary DPP pipe and add
- * the plane. So the plane is added to all ODM slices associated with the OTG
- * master pipe in the bottom layer.
- *
- * In the following example, the stream has 2 ODM slices and a top plane 0.
- * By acquiring secondary DPP pipes and adding a plane 1, we are configuring our
- * hardware to render the plane 1 by acquiring a new pipe for each ODM slice and
- * render plane 1 using new pipes' DPP in the Z axis below plane 0.
- *
- *       Inter-pipe Relation (Before Adding Plane)
- *        __________________________________________________
- *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
- *       |        |  plane 0      | slice 0   |             |
- *       |   0    | -------------------------ODM----------- |
- *       |        |  plane 0      | slice 1 | |             |
- *       |   1    | ------------------------- |             |
- *       |________|_______________|___________|_____________|
- *
- *       Inter-pipe Relation (After Acquiring and Adding Plane)
- *        __________________________________________________
- *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
- *       |        |  plane 0      | slice 0   |             |
- *       |   0    | -------------MPC---------ODM----------- |
- *       |        |  plane 1    | |         | |             |
- *       |   2    | ------------- |         | |             |
- *       |        |  plane 0      | slice 1 | |             |
- *       |   1    | -------------MPC--------- |             |
- *       |        |  plane 1    | |           |             |
- *       |   3    | ------------- |           |             |
- *       |________|_______________|___________|_____________|
- */
-static bool acquire_secondary_dpp_pipes_and_add_plane(
-		struct pipe_ctx *otg_master_pipe,
-		struct dc_plane_state *plane_state,
-		struct dc_state *new_ctx,
-		struct dc_state *cur_ctx,
-		struct resource_pool *pool)
+static inline int find_acquired_hpo_dp_link_enc_for_link(
+		const struct resource_context *res_ctx,
+		const struct dc_link *link)
 {
-	struct pipe_ctx *opp_head_pipe, *sec_pipe, *tail_pipe;
+	int i;
 
-	if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe)
-		return false;
+	for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++)
+		if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 &&
+				res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index)
+			return i;
 
-	opp_head_pipe = otg_master_pipe;
-	while (opp_head_pipe) {
-		sec_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe(
-				cur_ctx,
-				new_ctx,
-				pool,
+	return -1;
+}
+
+static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx,
+		const struct resource_pool *pool)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++)
+		if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0)
+			break;
+
+	return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) &&
+			i < pool->hpo_dp_link_enc_count) ? i : -1;
+}
+
+static inline void acquire_hpo_dp_link_enc(
+		struct resource_context *res_ctx,
+		unsigned int link_index,
+		int enc_index)
+{
+	res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index;
+	res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1;
+}
+
+static inline void retain_hpo_dp_link_enc(
+		struct resource_context *res_ctx,
+		int enc_index)
+{
+	res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++;
+}
+
+static inline void release_hpo_dp_link_enc(
+		struct resource_context *res_ctx,
+		int enc_index)
+{
+	ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0);
+	res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--;
+}
+
+static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx,
+		const struct resource_pool *pool,
+		struct pipe_ctx *pipe_ctx,
+		struct dc_stream_state *stream)
+{
+	int enc_index;
+
+	enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
+
+	if (enc_index >= 0) {
+		retain_hpo_dp_link_enc(res_ctx, enc_index);
+	} else {
+		enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
+		if (enc_index >= 0)
+			acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index);
+	}
+
+	if (enc_index >= 0)
+		pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
+
+	return pipe_ctx->link_res.hpo_dp_link_enc != NULL;
+}
+
+static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx,
+		struct pipe_ctx *pipe_ctx,
+		struct dc_stream_state *stream)
+{
+	int enc_index;
+
+	enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
+
+	if (enc_index >= 0) {
+		release_hpo_dp_link_enc(res_ctx, enc_index);
+		pipe_ctx->link_res.hpo_dp_link_enc = NULL;
+	}
+}
+
+enum dc_status resource_add_otg_master_for_stream_output(struct dc_state *new_ctx,
+		const struct resource_pool *pool,
+		struct dc_stream_state *stream)
+{
+	struct dc *dc = stream->ctx->dc;
+
+	return dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream);
+}
+
+void resource_remove_otg_master_for_stream_output(struct dc_state *context,
+		const struct resource_pool *pool,
+		struct dc_stream_state *stream)
+{
+	struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(
+			&context->res_ctx, stream);
+
+	ASSERT(resource_get_odm_slice_count(otg_master) == 1);
+	ASSERT(otg_master->plane_state == NULL);
+	ASSERT(otg_master->stream_res.stream_enc);
+	update_stream_engine_usage(
+			&context->res_ctx,
+			pool,
+			otg_master->stream_res.stream_enc,
+			false);
+
+	if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(otg_master)) {
+		update_hpo_dp_stream_engine_usage(
+			&context->res_ctx, pool,
+			otg_master->stream_res.hpo_dp_stream_enc,
+			false);
+		remove_hpo_dp_link_enc_from_ctx(
+				&context->res_ctx, otg_master, stream);
+	}
+	if (otg_master->stream_res.audio)
+		update_audio_usage(
+			&context->res_ctx,
+			pool,
+			otg_master->stream_res.audio,
+			false);
+
+	resource_unreference_clock_source(&context->res_ctx,
+					  pool,
+					  otg_master->clock_source);
+
+	if (pool->funcs->remove_stream_from_ctx)
+		pool->funcs->remove_stream_from_ctx(
+				stream->ctx->dc, context, stream);
+	memset(otg_master, 0, sizeof(*otg_master));
+}
+
+/* For each OPP head of an OTG master, add top plane at plane index 0.
+ *
+ * In the following example, the stream has 2 ODM slices without a top plane.
+ * By adding a plane 0 to OPP heads, we are configuring our hardware to render
+ * plane 0 by using each OPP head's DPP.
+ *
+ *       Inter-pipe Relation (Before Adding Plane)
+ *        __________________________________________________
+ *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
+ *       |        |               | slice 0   |             |
+ *       |   0    |               |blank ----ODM----------- |
+ *       |        |               | slice 1 | |             |
+ *       |   1    |               |blank ---- |             |
+ *       |________|_______________|___________|_____________|
+ *
+ *       Inter-pipe Relation (After Adding Plane)
+ *        __________________________________________________
+ *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
+ *       |        |  plane 0      | slice 0   |             |
+ *       |   0    | -------------------------ODM----------- |
+ *       |        |  plane 0      | slice 1 | |             |
+ *       |   1    | ------------------------- |             |
+ *       |________|_______________|___________|_____________|
+ */
+static bool add_plane_to_opp_head_pipes(struct pipe_ctx *otg_master_pipe,
+		struct dc_plane_state *plane_state,
+		struct dc_state *context)
+{
+	struct pipe_ctx *opp_head_pipe = otg_master_pipe;
+
+	while (opp_head_pipe) {
+		if (opp_head_pipe->plane_state) {
+			ASSERT(0);
+			return false;
+		}
+		opp_head_pipe->plane_state = plane_state;
+		opp_head_pipe = opp_head_pipe->next_odm_pipe;
+	}
+
+	return true;
+}
+
+/* For each OPP head of an OTG master, acquire a secondary DPP pipe and add
+ * the plane. So the plane is added to all ODM slices associated with the OTG
+ * master pipe in the bottom layer.
+ *
+ * In the following example, the stream has 2 ODM slices and a top plane 0.
+ * By acquiring secondary DPP pipes and adding a plane 1, we are configuring our
+ * hardware to render the plane 1 by acquiring a new pipe for each ODM slice and
+ * render plane 1 using new pipes' DPP in the Z axis below plane 0.
+ *
+ *       Inter-pipe Relation (Before Adding Plane)
+ *        __________________________________________________
+ *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
+ *       |        |  plane 0      | slice 0   |             |
+ *       |   0    | -------------------------ODM----------- |
+ *       |        |  plane 0      | slice 1 | |             |
+ *       |   1    | ------------------------- |             |
+ *       |________|_______________|___________|_____________|
+ *
+ *       Inter-pipe Relation (After Acquiring and Adding Plane)
+ *        __________________________________________________
+ *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
+ *       |        |  plane 0      | slice 0   |             |
+ *       |   0    | -------------MPC---------ODM----------- |
+ *       |        |  plane 1    | |         | |             |
+ *       |   2    | ------------- |         | |             |
+ *       |        |  plane 0      | slice 1 | |             |
+ *       |   1    | -------------MPC--------- |             |
+ *       |        |  plane 1    | |           |             |
+ *       |   3    | ------------- |           |             |
+ *       |________|_______________|___________|_____________|
+ */
+static bool acquire_secondary_dpp_pipes_and_add_plane(
+		struct pipe_ctx *otg_master_pipe,
+		struct dc_plane_state *plane_state,
+		struct dc_state *new_ctx,
+		struct dc_state *cur_ctx,
+		struct resource_pool *pool)
+{
+	struct pipe_ctx *opp_head_pipe, *sec_pipe, *tail_pipe;
+
+	if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe) {
+		ASSERT(0);
+		return false;
+	}
+
+	opp_head_pipe = otg_master_pipe;
+	while (opp_head_pipe) {
+		sec_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe(
+				cur_ctx,
+				new_ctx,
+				pool,
 				opp_head_pipe);
 		if (!sec_pipe) {
 			/* try tearing down MPCC combine */
@@ -2027,64 +2259,52 @@ static bool acquire_secondary_dpp_pipes_and_add_plane(
 	return true;
 }
 
-/*
- * Acquire a pipe as OTG master and assign to the stream in new dc context.
- * return - true if OTG master pipe is acquired and new dc context is updated.
- * false if it fails to acquire an OTG master pipe for this stream.
- *
- * In the example below, we acquired pipe 0 as OTG master pipe for the stream.
- * After the function its Inter-pipe Relation is represented by the diagram
- * below.
- *
- *       Inter-pipe Relation
- *        __________________________________________________
- *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
- *       |        |               |           |             |
- *       |   0    |               |blank ------------------ |
- *       |________|_______________|___________|_____________|
- */
-static bool acquire_otg_master_pipe_for_stream(
+bool resource_append_dpp_pipes_for_plane_composition(
 		struct dc_state *new_ctx,
+		struct dc_state *cur_ctx,
+		struct resource_pool *pool,
+		struct pipe_ctx *otg_master_pipe,
+		struct dc_plane_state *plane_state)
+{
+	if (otg_master_pipe->plane_state == NULL)
+		return add_plane_to_opp_head_pipes(otg_master_pipe,
+				plane_state, new_ctx);
+	else
+		return acquire_secondary_dpp_pipes_and_add_plane(
+				otg_master_pipe, plane_state, new_ctx,
+				cur_ctx, pool);
+}
+
+void resource_remove_dpp_pipes_for_plane_composition(
+		struct dc_state *context,
 		const struct resource_pool *pool,
-		struct dc_stream_state *stream)
+		const struct dc_plane_state *plane_state)
 {
-	/* TODO: Move this function to DCN specific resource file and acquire
-	 * DSC resource here. The reason is that the function should have the
-	 * same level of responsibility as when we acquire secondary OPP head.
-	 * We acquire DSC when we acquire secondary OPP head, so we should
-	 * acquire DSC when we acquire OTG master.
-	 */
-	int pipe_idx;
-	struct pipe_ctx *pipe_ctx = NULL;
+	int i;
+	for (i = pool->pipe_count - 1; i >= 0; i--) {
+		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
 
-	pipe_idx = resource_find_any_free_pipe(&new_ctx->res_ctx, pool);
-	if (pipe_idx != FREE_PIPE_INDEX_NOT_FOUND) {
-		pipe_ctx = &new_ctx->res_ctx.pipe_ctx[pipe_idx];
-		memset(pipe_ctx, 0, sizeof(*pipe_ctx));
-		pipe_ctx->pipe_idx = pipe_idx;
-		pipe_ctx->stream_res.tg = pool->timing_generators[pipe_idx];
-		pipe_ctx->plane_res.mi = pool->mis[pipe_idx];
-		pipe_ctx->plane_res.hubp = pool->hubps[pipe_idx];
-		pipe_ctx->plane_res.ipp = pool->ipps[pipe_idx];
-		pipe_ctx->plane_res.xfm = pool->transforms[pipe_idx];
-		pipe_ctx->plane_res.dpp = pool->dpps[pipe_idx];
-		pipe_ctx->stream_res.opp = pool->opps[pipe_idx];
-		if (pool->dpps[pipe_idx])
-			pipe_ctx->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst;
+		if (pipe_ctx->plane_state == plane_state) {
+			if (pipe_ctx->top_pipe)
+				pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
 
-		if (pipe_idx >= pool->timing_generator_count) {
-			int tg_inst = pool->timing_generator_count - 1;
+			/* Second condition is to avoid setting NULL to top pipe
+			 * of tail pipe making it look like head pipe in subsequent
+			 * deletes
+			 */
+			if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe)
+				pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe;
 
-			pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
-			pipe_ctx->stream_res.opp = pool->opps[tg_inst];
+			/*
+			 * For head pipe detach surfaces from pipe for tail
+			 * pipe just zero it out
+			 */
+			if (!pipe_ctx->top_pipe)
+				pipe_ctx->plane_state = NULL;
+			else
+				memset(pipe_ctx, 0, sizeof(*pipe_ctx));
 		}
-
-		pipe_ctx->stream = stream;
-	} else {
-		pipe_idx = acquire_first_split_pipe(&new_ctx->res_ctx, pool, stream);
 	}
-
-	return pipe_idx != FREE_PIPE_INDEX_NOT_FOUND;
 }
 
 /*
@@ -2127,12 +2347,17 @@ static bool acquire_pipes_and_add_odm_slice(
 		const struct resource_pool *pool)
 {
 	struct pipe_ctx *last_opp_head = get_last_opp_head(otg_master_pipe);
-	struct pipe_ctx *new_opp_head = pool->funcs->acquire_free_pipe_as_secondary_opp_head(
-					cur_ctx, new_ctx, pool,
-					otg_master_pipe);
+	struct pipe_ctx *new_opp_head;
 	struct pipe_ctx *last_top_dpp_pipe, *last_bottom_dpp_pipe,
 			*new_top_dpp_pipe, *new_bottom_dpp_pipe;
 
+	if (!pool->funcs->acquire_free_pipe_as_secondary_opp_head) {
+		ASSERT(0);
+		return false;
+	}
+	new_opp_head = pool->funcs->acquire_free_pipe_as_secondary_opp_head(
+					cur_ctx, new_ctx, pool,
+					otg_master_pipe);
 	if (!new_opp_head)
 		return false;
 
@@ -2203,6 +2428,11 @@ static bool release_pipes_and_remove_odm_slice(
 	struct pipe_ctx *last_opp_head = get_last_opp_head(otg_master_pipe);
 	struct pipe_ctx *tail_pipe = get_tail_pipe(last_opp_head);
 
+	if (!pool->funcs->release_pipe) {
+		ASSERT(0);
+		return false;
+	}
+
 	if (resource_is_pipe_type(last_opp_head, OTG_MASTER))
 		return false;
 
@@ -2258,10 +2488,15 @@ static bool acquire_dpp_pipe_and_add_mpc_slice(
 	struct pipe_ctx *last_dpp_pipe =
 			get_last_dpp_pipe_in_mpcc_combine(dpp_pipe);
 	struct pipe_ctx *opp_head = resource_get_opp_head(dpp_pipe);
-	struct pipe_ctx *new_dpp_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe(
-			cur_ctx, new_ctx, pool, opp_head);
+	struct pipe_ctx *new_dpp_pipe;
 
-	if (!new_dpp_pipe || resource_get_num_odm_splits(dpp_pipe) > 0)
+	if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe) {
+		ASSERT(0);
+		return false;
+	}
+	new_dpp_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe(
+			cur_ctx, new_ctx, pool, opp_head);
+	if (!new_dpp_pipe || resource_get_odm_slice_count(dpp_pipe) > 1)
 		return false;
 
 	new_dpp_pipe->bottom_pipe = last_dpp_pipe->bottom_pipe;
@@ -2315,8 +2550,13 @@ static bool release_dpp_pipe_and_remove_mpc_slice(
 	struct pipe_ctx *last_dpp_pipe =
 			get_last_dpp_pipe_in_mpcc_combine(dpp_pipe);
 
+	if (!pool->funcs->release_pipe) {
+		ASSERT(0);
+		return false;
+	}
+
 	if (resource_is_pipe_type(last_dpp_pipe, OPP_HEAD) ||
-			resource_get_num_odm_splits(dpp_pipe) > 0)
+			resource_get_odm_slice_count(dpp_pipe) > 1)
 		return false;
 
 	last_dpp_pipe->top_pipe->bottom_pipe = last_dpp_pipe->bottom_pipe;
@@ -2327,15 +2567,17 @@ static bool release_dpp_pipe_and_remove_mpc_slice(
 	return true;
 }
 
-bool resource_update_pipes_with_odm_slice_count(
-		struct pipe_ctx *otg_master,
+bool resource_update_pipes_for_stream_with_slice_count(
 		struct dc_state *new_ctx,
 		const struct dc_state *cur_ctx,
 		const struct resource_pool *pool,
+		const struct dc_stream_state *stream,
 		int new_slice_count)
 {
 	int i;
-	int cur_slice_count = resource_get_num_odm_splits(otg_master) + 1;
+	struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(
+			&new_ctx->res_ctx, stream);
+	int cur_slice_count = resource_get_odm_slice_count(otg_master);
 	bool result = true;
 
 	if (new_slice_count == cur_slice_count)
@@ -2355,31 +2597,38 @@ bool resource_update_pipes_with_odm_slice_count(
 	return result;
 }
 
-bool resource_update_pipes_with_mpc_slice_count(
-		struct pipe_ctx *dpp_pipe,
+bool resource_update_pipes_for_plane_with_slice_count(
 		struct dc_state *new_ctx,
 		const struct dc_state *cur_ctx,
 		const struct resource_pool *pool,
+		const struct dc_plane_state *plane,
 		int new_slice_count)
 {
 	int i;
-	int cur_slice_count = resource_get_num_mpc_splits(dpp_pipe) + 1;
+	int dpp_pipe_count;
+	int cur_slice_count;
+	struct pipe_ctx *dpp_pipes[MAX_PIPES];
 	bool result = true;
 
+	dpp_pipe_count = resource_get_dpp_pipes_for_plane(plane,
+			&new_ctx->res_ctx, dpp_pipes);
+	ASSERT(dpp_pipe_count > 0);
+	cur_slice_count = resource_get_mpc_slice_count(dpp_pipes[0]);
+
 	if (new_slice_count == cur_slice_count)
 		return result;
 
 	if (new_slice_count > cur_slice_count)
 		for (i = 0; i < new_slice_count - cur_slice_count && result; i++)
 			result = acquire_dpp_pipe_and_add_mpc_slice(
-					dpp_pipe, new_ctx, cur_ctx, pool);
+					dpp_pipes[0], new_ctx, cur_ctx, pool);
 	else
 		for (i = 0; i < cur_slice_count - new_slice_count && result; i++)
 			result = release_dpp_pipe_and_remove_mpc_slice(
-					dpp_pipe, new_ctx, pool);
+					dpp_pipes[0], new_ctx, pool);
 	if (result)
 		result = update_pipe_params_after_mpc_slice_count_change(
-				dpp_pipe->plane_state, new_ctx, pool);
+				dpp_pipes[0]->plane_state, new_ctx, pool);
 	return result;
 }
 
@@ -2406,13 +2655,9 @@ bool dc_add_plane_to_context(
 
 	otg_master_pipe = resource_get_otg_master_for_stream(
 			&context->res_ctx, stream);
-	if (otg_master_pipe->plane_state == NULL)
-		added = add_plane_to_opp_head_pipes(otg_master_pipe,
-				plane_state, context);
-	else
-		added = acquire_secondary_dpp_pipes_and_add_plane(
-				otg_master_pipe, plane_state, context,
-				dc->current_state, pool);
+	added = resource_append_dpp_pipes_for_plane_composition(context,
+			dc->current_state, pool, otg_master_pipe, plane_state);
+
 	if (added) {
 		stream_status->plane_states[stream_status->plane_count] =
 				plane_state;
@@ -2448,32 +2693,8 @@ bool dc_remove_plane_from_context(
 		return false;
 	}
 
-	/* release pipe for plane*/
-	for (i = pool->pipe_count - 1; i >= 0; i--) {
-		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
-
-		if (pipe_ctx->plane_state == plane_state) {
-			if (pipe_ctx->top_pipe)
-				pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
-
-			/* Second condition is to avoid setting NULL to top pipe
-			 * of tail pipe making it look like head pipe in subsequent
-			 * deletes
-			 */
-			if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe)
-				pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe;
-
-			/*
-			 * For head pipe detach surfaces from pipe for tail
-			 * pipe just zero it out
-			 */
-			if (!pipe_ctx->top_pipe)
-				pipe_ctx->plane_state = NULL;
-			else
-				memset(pipe_ctx, 0, sizeof(*pipe_ctx));
-		}
-	}
-
+	resource_remove_dpp_pipes_for_plane_composition(
+			context, pool, plane_state);
 
 	for (i = 0; i < stream_status->plane_count; i++) {
 		if (stream_status->plane_states[i] == plane_state) {
@@ -2672,122 +2893,6 @@ bool dc_is_stream_scaling_unchanged(struct dc_stream_state *old_stream,
 	return true;
 }
 
-static void update_stream_engine_usage(
-		struct resource_context *res_ctx,
-		const struct resource_pool *pool,
-		struct stream_encoder *stream_enc,
-		bool acquired)
-{
-	int i;
-
-	for (i = 0; i < pool->stream_enc_count; i++) {
-		if (pool->stream_enc[i] == stream_enc)
-			res_ctx->is_stream_enc_acquired[i] = acquired;
-	}
-}
-
-static void update_hpo_dp_stream_engine_usage(
-		struct resource_context *res_ctx,
-		const struct resource_pool *pool,
-		struct hpo_dp_stream_encoder *hpo_dp_stream_enc,
-		bool acquired)
-{
-	int i;
-
-	for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
-		if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc)
-			res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired;
-	}
-}
-
-static inline int find_acquired_hpo_dp_link_enc_for_link(
-		const struct resource_context *res_ctx,
-		const struct dc_link *link)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++)
-		if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 &&
-				res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index)
-			return i;
-
-	return -1;
-}
-
-static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx,
-		const struct resource_pool *pool)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++)
-		if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0)
-			break;
-
-	return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) &&
-			i < pool->hpo_dp_link_enc_count) ? i : -1;
-}
-
-static inline void acquire_hpo_dp_link_enc(
-		struct resource_context *res_ctx,
-		unsigned int link_index,
-		int enc_index)
-{
-	res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index;
-	res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1;
-}
-
-static inline void retain_hpo_dp_link_enc(
-		struct resource_context *res_ctx,
-		int enc_index)
-{
-	res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++;
-}
-
-static inline void release_hpo_dp_link_enc(
-		struct resource_context *res_ctx,
-		int enc_index)
-{
-	ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0);
-	res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--;
-}
-
-static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx,
-		const struct resource_pool *pool,
-		struct pipe_ctx *pipe_ctx,
-		struct dc_stream_state *stream)
-{
-	int enc_index;
-
-	enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
-
-	if (enc_index >= 0) {
-		retain_hpo_dp_link_enc(res_ctx, enc_index);
-	} else {
-		enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
-		if (enc_index >= 0)
-			acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index);
-	}
-
-	if (enc_index >= 0)
-		pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
-
-	return pipe_ctx->link_res.hpo_dp_link_enc != NULL;
-}
-
-static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx,
-		struct pipe_ctx *pipe_ctx,
-		struct dc_stream_state *stream)
-{
-	int enc_index;
-
-	enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
-
-	if (enc_index >= 0) {
-		release_hpo_dp_link_enc(res_ctx, enc_index);
-		pipe_ctx->link_res.hpo_dp_link_enc = NULL;
-	}
-}
-
 /* TODO: release audio object */
 void update_audio_usage(
 		struct resource_context *res_ctx,
@@ -2872,7 +2977,8 @@ enum dc_status dc_add_stream_to_ctx(
 	dc_stream_retain(stream);
 	new_ctx->stream_count++;
 
-	res = dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream);
+	res = resource_add_otg_master_for_stream_output(
+			new_ctx, dc->res_pool, stream);
 	if (res != DC_OK)
 		DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res);
 
@@ -2889,53 +2995,18 @@ enum dc_status dc_remove_stream_from_ctx(
 {
 	int i;
 	struct dc_context *dc_ctx = dc->ctx;
-	struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream(&new_ctx->res_ctx, stream);
-	struct pipe_ctx *odm_pipe;
+	struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream(
+			&new_ctx->res_ctx, stream);
 
 	if (!del_pipe) {
 		DC_ERROR("Pipe not found for stream %p !\n", stream);
 		return DC_ERROR_UNEXPECTED;
 	}
 
-	odm_pipe = del_pipe->next_odm_pipe;
-
-	/* Release primary pipe */
-	ASSERT(del_pipe->stream_res.stream_enc);
-	update_stream_engine_usage(
-			&new_ctx->res_ctx,
-				dc->res_pool,
-			del_pipe->stream_res.stream_enc,
-			false);
-
-	if (dc->link_srv->dp_is_128b_132b_signal(del_pipe)) {
-		update_hpo_dp_stream_engine_usage(
-			&new_ctx->res_ctx, dc->res_pool,
-			del_pipe->stream_res.hpo_dp_stream_enc,
-			false);
-		remove_hpo_dp_link_enc_from_ctx(&new_ctx->res_ctx, del_pipe, del_pipe->stream);
-	}
-
-	if (del_pipe->stream_res.audio)
-		update_audio_usage(
-			&new_ctx->res_ctx,
-			dc->res_pool,
-			del_pipe->stream_res.audio,
-			false);
-
-	resource_unreference_clock_source(&new_ctx->res_ctx,
-					  dc->res_pool,
-					  del_pipe->clock_source);
-
-	if (dc->res_pool->funcs->remove_stream_from_ctx)
-		dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream);
-
-	while (odm_pipe) {
-		struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe;
-
-		memset(odm_pipe, 0, sizeof(*odm_pipe));
-		odm_pipe = next_odm_pipe;
-	}
-	memset(del_pipe, 0, sizeof(*del_pipe));
+	resource_update_pipes_for_stream_with_slice_count(new_ctx,
+			dc->current_state, dc->res_pool, stream, 1);
+	resource_remove_otg_master_for_stream_output(
+			new_ctx, dc->res_pool, stream);
 
 	for (i = 0; i < new_ctx->stream_count; i++)
 		if (new_ctx->streams[i] == stream)
@@ -3154,6 +3225,66 @@ static void mark_seamless_boot_stream(
 	}
 }
 
+/*
+ * Acquire a pipe as OTG master and assign to the stream in new dc context.
+ * return - true if OTG master pipe is acquired and new dc context is updated.
+ * false if it fails to acquire an OTG master pipe for this stream.
+ *
+ * In the example below, we acquired pipe 0 as OTG master pipe for the stream.
+ * After the function its Inter-pipe Relation is represented by the diagram
+ * below.
+ *
+ *       Inter-pipe Relation
+ *        __________________________________________________
+ *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
+ *       |        |               |           |             |
+ *       |   0    |               |blank ------------------ |
+ *       |________|_______________|___________|_____________|
+ */
+static bool acquire_otg_master_pipe_for_stream(
+		struct dc_state *new_ctx,
+		const struct resource_pool *pool,
+		struct dc_stream_state *stream)
+{
+	/* TODO: Move this function to DCN specific resource file and acquire
+	 * DSC resource here. The reason is that the function should have the
+	 * same level of responsibility as when we acquire secondary OPP head.
+	 * We acquire DSC when we acquire secondary OPP head, so we should
+	 * acquire DSC when we acquire OTG master.
+	 */
+	int pipe_idx;
+	struct pipe_ctx *pipe_ctx = NULL;
+
+	pipe_idx = resource_find_any_free_pipe(&new_ctx->res_ctx, pool);
+	if (pipe_idx != FREE_PIPE_INDEX_NOT_FOUND) {
+		pipe_ctx = &new_ctx->res_ctx.pipe_ctx[pipe_idx];
+		memset(pipe_ctx, 0, sizeof(*pipe_ctx));
+		pipe_ctx->pipe_idx = pipe_idx;
+		pipe_ctx->stream_res.tg = pool->timing_generators[pipe_idx];
+		pipe_ctx->plane_res.mi = pool->mis[pipe_idx];
+		pipe_ctx->plane_res.hubp = pool->hubps[pipe_idx];
+		pipe_ctx->plane_res.ipp = pool->ipps[pipe_idx];
+		pipe_ctx->plane_res.xfm = pool->transforms[pipe_idx];
+		pipe_ctx->plane_res.dpp = pool->dpps[pipe_idx];
+		pipe_ctx->stream_res.opp = pool->opps[pipe_idx];
+		if (pool->dpps[pipe_idx])
+			pipe_ctx->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst;
+
+		if (pipe_idx >= pool->timing_generator_count) {
+			int tg_inst = pool->timing_generator_count - 1;
+
+			pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
+			pipe_ctx->stream_res.opp = pool->opps[tg_inst];
+		}
+
+		pipe_ctx->stream = stream;
+	} else {
+		pipe_idx = acquire_first_split_pipe(&new_ctx->res_ctx, pool, stream);
+	}
+
+	return pipe_idx != FREE_PIPE_INDEX_NOT_FOUND;
+}
+
 enum dc_status resource_map_pool_resources(
 		const struct dc  *dc,
 		struct dc_state *context,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
index f3db16cd10db..347156d02f21 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
@@ -614,6 +614,8 @@ void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
 	memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res));
 	pipe_ctx->top_pipe = NULL;
 	pipe_ctx->bottom_pipe = NULL;
+	pipe_ctx->prev_odm_pipe = NULL;
+	pipe_ctx->next_odm_pipe = NULL;
 	pipe_ctx->plane_state = NULL;
 }
 
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
index d587f807dfd7..2820393d5c6f 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
@@ -1948,7 +1948,7 @@ int dcn20_validate_apply_pipe_split_flags(
 			v->ODMCombineEnablePerState[vlevel][pipe_plane];
 
 		if (v->ODMCombineEnabled[pipe_plane] == dm_odm_combine_mode_disabled) {
-			if (resource_get_num_mpc_splits(pipe) == 1) {
+			if (resource_get_mpc_slice_count(pipe) == 2) {
 				/*If need split for mpc but 2 way split already*/
 				if (split[i] == 4)
 					split[i] = 2; /* 2 -> 4 MPC */
@@ -1956,7 +1956,7 @@ int dcn20_validate_apply_pipe_split_flags(
 					split[i] = 0; /* 2 -> 2 MPC */
 				else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state)
 					merge[i] = true; /* 2 -> 1 MPC */
-			} else if (resource_get_num_mpc_splits(pipe) == 3) {
+			} else if (resource_get_mpc_slice_count(pipe) == 4) {
 				/*If need split for mpc but 4 way split already*/
 				if (split[i] == 2 && ((pipe->top_pipe && !pipe->top_pipe->top_pipe)
 						|| !pipe->bottom_pipe)) {
@@ -1965,7 +1965,7 @@ int dcn20_validate_apply_pipe_split_flags(
 						pipe->top_pipe->plane_state == pipe->plane_state)
 					merge[i] = true; /* 4 -> 1 MPC */
 				split[i] = 0;
-			} else if (resource_get_num_odm_splits(pipe)) {
+			} else if (resource_get_odm_slice_count(pipe) > 1) {
 				/* ODM -> MPC transition */
 				if (pipe->prev_odm_pipe) {
 					split[i] = 0;
@@ -1973,7 +1973,7 @@ int dcn20_validate_apply_pipe_split_flags(
 				}
 			}
 		} else {
-			if (resource_get_num_odm_splits(pipe) == 1) {
+			if (resource_get_odm_slice_count(pipe) == 2) {
 				/*If need split for odm but 2 way split already*/
 				if (split[i] == 4)
 					split[i] = 2; /* 2 -> 4 ODM */
@@ -1983,7 +1983,7 @@ int dcn20_validate_apply_pipe_split_flags(
 					ASSERT(0); /* NOT expected yet */
 					merge[i] = true; /* exit ODM */
 				}
-			} else if (resource_get_num_odm_splits(pipe) == 3) {
+			} else if (resource_get_odm_slice_count(pipe) == 4) {
 				/*If need split for odm but 4 way split already*/
 				if (split[i] == 2 && ((pipe->prev_odm_pipe && !pipe->prev_odm_pipe->prev_odm_pipe)
 						|| !pipe->next_odm_pipe)) {
@@ -1993,7 +1993,7 @@ int dcn20_validate_apply_pipe_split_flags(
 					merge[i] = true; /* exit ODM */
 				}
 				split[i] = 0;
-			} else if (resource_get_num_mpc_splits(pipe)) {
+			} else if (resource_get_mpc_slice_count(pipe) > 1) {
 				/* MPC -> ODM transition */
 				ASSERT(0); /* NOT expected yet */
 				if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) {
@@ -2211,12 +2211,22 @@ enum dc_status dcn20_patch_unknown_plane_state(struct dc_plane_state *plane_stat
 	return DC_OK;
 }
 
+void dcn20_release_pipe(struct dc_state *context,
+			struct pipe_ctx *pipe,
+			const struct resource_pool *pool)
+{
+	if (resource_is_pipe_type(pipe, OPP_HEAD) && pipe->stream_res.dsc)
+		dcn20_release_dsc(&context->res_ctx, pool, &pipe->stream_res.dsc);
+	memset(pipe, 0, sizeof(*pipe));
+}
+
 static const struct resource_funcs dcn20_res_pool_funcs = {
 	.destroy = dcn20_destroy_resource_pool,
 	.link_enc_create = dcn20_link_encoder_create,
 	.panel_cntl_create = dcn20_panel_cntl_create,
 	.validate_bandwidth = dcn20_validate_bandwidth,
 	.acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer,
+	.release_pipe = dcn20_release_pipe,
 	.add_stream_to_ctx = dcn20_add_stream_to_ctx,
 	.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
 	.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h
index 6d1a8924e57b..37ecaccc5d12 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h
@@ -63,7 +63,9 @@ struct pipe_ctx *dcn20_acquire_free_pipe_for_layer(
 		struct dc_state *new_ctx,
 		const struct resource_pool *pool,
 		const struct pipe_ctx *opp_head_pipe);
-
+void dcn20_release_pipe(struct dc_state *context,
+			struct pipe_ctx *pipe,
+			const struct resource_pool *pool);
 struct stream_encoder *dcn20_stream_encoder_create(
 	enum engine_id eng_id,
 	struct dc_context *ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c
index 2dc4d2c1410b..9389bd8df42b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c
@@ -1069,6 +1069,7 @@ static struct resource_funcs dcn201_res_pool_funcs = {
 	.add_dsc_to_stream_resource = NULL,
 	.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
 	.acquire_free_pipe_as_secondary_dpp_pipe = dcn201_acquire_free_pipe_for_layer,
+	.release_pipe = dcn20_release_pipe,
 	.populate_dml_writeback_from_context = dcn201_populate_dml_writeback_from_context,
 	.patch_unknown_plane_state = dcn20_patch_unknown_plane_state,
 	.set_mcif_arb_params = dcn20_set_mcif_arb_params,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
index d1a25fe6c44f..71e82692dd7c 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
@@ -1389,6 +1389,7 @@ static const struct resource_funcs dcn21_res_pool_funcs = {
 	.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
 	.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
 	.acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer,
+	.release_pipe = dcn20_release_pipe,
 	.populate_dml_writeback_from_context = dcn20_populate_dml_writeback_from_context,
 	.patch_unknown_plane_state = dcn21_patch_unknown_plane_state,
 	.set_mcif_arb_params = dcn20_set_mcif_arb_params,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
index 88c0b24a3249..da56962227fd 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
@@ -2217,6 +2217,7 @@ static const struct resource_funcs dcn30_res_pool_funcs = {
 	.update_soc_for_wm_a = dcn30_update_soc_for_wm_a,
 	.populate_dml_pipes = dcn30_populate_dml_pipes_from_context,
 	.acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer,
+	.release_pipe = dcn20_release_pipe,
 	.add_stream_to_ctx = dcn30_add_stream_to_ctx,
 	.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
 	.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
index 79d6697d13b6..c489ad043b87 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
@@ -1380,6 +1380,7 @@ static struct resource_funcs dcn301_res_pool_funcs = {
 	.update_soc_for_wm_a = dcn30_update_soc_for_wm_a,
 	.populate_dml_pipes = dcn30_populate_dml_pipes_from_context,
 	.acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer,
+	.release_pipe = dcn20_release_pipe,
 	.add_stream_to_ctx = dcn30_add_stream_to_ctx,
 	.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
 	.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c
index 447abcd593be..f5b8b92a84f2 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c
@@ -1137,6 +1137,7 @@ static struct resource_funcs dcn302_res_pool_funcs = {
 		.update_soc_for_wm_a = dcn30_update_soc_for_wm_a,
 		.populate_dml_pipes = dcn30_populate_dml_pipes_from_context,
 		.acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer,
+		.release_pipe = dcn20_release_pipe,
 		.add_stream_to_ctx = dcn30_add_stream_to_ctx,
 		.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
 		.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
index adf4989177f7..d59561605c17 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
@@ -1063,6 +1063,7 @@ static struct resource_funcs dcn303_res_pool_funcs = {
 		.update_soc_for_wm_a = dcn30_update_soc_for_wm_a,
 		.populate_dml_pipes = dcn30_populate_dml_pipes_from_context,
 		.acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer,
+		.release_pipe = dcn20_release_pipe,
 		.add_stream_to_ctx = dcn30_add_stream_to_ctx,
 		.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
 		.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
index 82de4fe2637f..994289b3d5a3 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
@@ -1824,6 +1824,7 @@ static struct resource_funcs dcn31_res_pool_funcs = {
 	.update_soc_for_wm_a = dcn31_update_soc_for_wm_a,
 	.populate_dml_pipes = dcn31_populate_dml_pipes_from_context,
 	.acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer,
+	.release_pipe = dcn20_release_pipe,
 	.add_stream_to_ctx = dcn30_add_stream_to_ctx,
 	.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
 	.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c
index 004beed9bd44..4d0052ca742f 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c
@@ -1796,6 +1796,7 @@ static struct resource_funcs dcn314_res_pool_funcs = {
 	.update_soc_for_wm_a = dcn31_update_soc_for_wm_a,
 	.populate_dml_pipes = dcn314_populate_dml_pipes_from_context,
 	.acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer,
+	.release_pipe = dcn20_release_pipe,
 	.add_stream_to_ctx = dcn30_add_stream_to_ctx,
 	.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
 	.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
index 127487ea3d7d..8e3acb92385b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
@@ -1819,6 +1819,7 @@ static struct resource_funcs dcn315_res_pool_funcs = {
 	.update_soc_for_wm_a = dcn315_update_soc_for_wm_a,
 	.populate_dml_pipes = dcn315_populate_dml_pipes_from_context,
 	.acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer,
+	.release_pipe = dcn20_release_pipe,
 	.add_stream_to_ctx = dcn30_add_stream_to_ctx,
 	.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
 	.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c
index 5fe2c61527df..9133a1ea4ca0 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c
@@ -1706,6 +1706,7 @@ static struct resource_funcs dcn316_res_pool_funcs = {
 	.update_soc_for_wm_a = dcn31_update_soc_for_wm_a,
 	.populate_dml_pipes = dcn316_populate_dml_pipes_from_context,
 	.acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer,
+	.release_pipe = dcn20_release_pipe,
 	.add_stream_to_ctx = dcn30_add_stream_to_ctx,
 	.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
 	.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
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 072c5ba4c99c..88c9dbbacbd3 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -2040,7 +2040,7 @@ static struct resource_funcs dcn32_res_pool_funcs = {
 	.populate_dml_pipes = dcn32_populate_dml_pipes_from_context,
 	.acquire_free_pipe_as_secondary_dpp_pipe = dcn32_acquire_free_pipe_as_secondary_dpp_pipe,
 	.acquire_free_pipe_as_secondary_opp_head = dcn32_acquire_free_pipe_as_secondary_opp_head,
-	.release_pipe = dcn32_release_pipe,
+	.release_pipe = dcn20_release_pipe,
 	.add_stream_to_ctx = dcn30_add_stream_to_ctx,
 	.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
 	.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
@@ -2778,15 +2778,6 @@ struct pipe_ctx *dcn32_acquire_free_pipe_as_secondary_opp_head(
 	return free_pipe;
 }
 
-void dcn32_release_pipe(struct dc_state *context,
-			struct pipe_ctx *pipe,
-			const struct resource_pool *pool)
-{
-	if (resource_is_pipe_type(pipe, OPP_HEAD) && pipe->stream_res.dsc)
-		dcn20_release_dsc(&context->res_ctx, pool, &pipe->stream_res.dsc);
-	memset(pipe, 0, sizeof(*pipe));
-}
-
 unsigned int dcn32_calc_num_avail_chans_for_mall(struct dc *dc, int num_chans)
 {
 	/*
diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
index 8d73cceb485b..7d40fb6156f3 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
@@ -1589,6 +1589,7 @@ static struct resource_funcs dcn321_res_pool_funcs = {
 	.calculate_wm_and_dlg = dcn32_calculate_wm_and_dlg,
 	.populate_dml_pipes = dcn32_populate_dml_pipes_from_context,
 	.acquire_free_pipe_as_secondary_dpp_pipe = dcn32_acquire_free_pipe_as_secondary_dpp_pipe,
+	.release_pipe = dcn20_release_pipe,
 	.add_stream_to_ctx = dcn30_add_stream_to_ctx,
 	.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
 	.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
index 8afda5ecc0cd..0989a0152ae8 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
@@ -1305,11 +1305,11 @@ int dcn20_populate_dml_pipes_from_context(struct dc *dc,
 		pipes[pipe_cnt].dout.is_virtual = 0;
 		pipes[pipe_cnt].pipe.dest.vtotal_min = res_ctx->pipe_ctx[i].stream->adjust.v_total_min;
 		pipes[pipe_cnt].pipe.dest.vtotal_max = res_ctx->pipe_ctx[i].stream->adjust.v_total_max;
-		switch (resource_get_num_odm_splits(&res_ctx->pipe_ctx[i])) {
-		case 1:
+		switch (resource_get_odm_slice_count(&res_ctx->pipe_ctx[i])) {
+		case 2:
 			pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_2to1;
 			break;
-		case 3:
+		case 4:
 			pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_4to1;
 			break;
 		default:
diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
index 4344c5a239e1..55efd5600521 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
@@ -238,8 +238,8 @@ enum pipe_type {
 
 	/* OTG master pipe - the master pipe of its OPP head pipes with a
 	 * functional OTG. It merges all its OPP head pipes pixel data in ODM
-	 * block and output to backend DIG. OTG master pipe is responsible for
-	 * generating entire crtc timing to backend DIG. An OTG master pipe may
+	 * block and output to back end DIG. OTG master pipe is responsible for
+	 * generating entire CRTC timing to back end DIG. An OTG master pipe may
 	 * or may not have a plane. If it has a plane it blends it as the left
 	 * most MPC slice of the top most layer. If it doesn't have a plane it
 	 * can output pixel data from its OPP head pipes' test pattern
@@ -267,33 +267,175 @@ enum pipe_type {
 };
 
 /*
- * Determine if the input pipe ctx is of a pipe type.
- * return - true if pipe ctx is of the input type.
+ * Determine if the input pipe_ctx is of a pipe type.
+ * return - true if pipe_ctx is of the input type.
  */
 bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type);
 
 /*
- * Determine if the input pipe ctx is used for rendering a plane with MPCC
- * combine. MPCC combine is a hardware feature to combine multiple DPP pipes
- * into a single plane. It is typically used for bypassing pipe bandwidth
- * limitation for rendering a very large plane or saving power by reducing UCLK
- * and DPPCLK speeds.
+ * Acquire a pipe as OTG master pipe and allocate pipe resources required to
+ * enable stream output.
+ */
+enum dc_status resource_add_otg_master_for_stream_output(struct dc_state *new_ctx,
+		const struct resource_pool *pool,
+		struct dc_stream_state *stream);
+
+/*
+ * Release pipe resources and the OTG master pipe associated with the stream
+ * The stream must have all planes removed and ODM/MPC slice counts are reset
+ * to 1 before invoking this interface.
+ */
+void resource_remove_otg_master_for_stream_output(struct dc_state *new_ctx,
+		const struct resource_pool *pool,
+		struct dc_stream_state *stream);
+
+/*
+ * Add plane to the bottom most layer in plane composition and allocate DPP pipe
+ * resources as needed.
+ * return - true if plane is added in plane composition, false otherwise.
+ */
+bool resource_append_dpp_pipes_for_plane_composition(
+		struct dc_state *new_ctx,
+		struct dc_state *cur_ctx,
+		struct resource_pool *pool,
+		struct pipe_ctx *otg_master_pipe,
+		struct dc_plane_state *plane_state);
+
+/*
+ * Add plane to the bottom most layer in plane composition and allocate DPP pipe
+ * resources as needed.
+ * return - true if plane is added in plane composition, false otherwise.
+ */
+void resource_remove_dpp_pipes_for_plane_composition(
+		struct dc_state *context,
+		const struct resource_pool *pool,
+		const struct dc_plane_state *plane_state);
+
+/*
+ * Update ODM slice count by acquiring or releasing pipes. If new slices need
+ * to be added, it is going to add them to the last ODM index. If existing
+ * slices need to be removed, it is going to remove them from the last ODM
+ * index.
  *
- * For instance in the Inter-pipe Relation diagram shown below, both PIPE 0 and
- * 1 are for MPCC combine for plane 0
+ * return - true if ODM slices are updated and required pipes are acquired. All
+ * affected pipe parameters are updated.
  *
- *       Inter-pipe Relation
- *        __________________________________________________
- *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
- *       |        |  plane 0      |           |             |
- *       |   0    | -------------MPC----------------------- |
- *       |        |  plane 0    | |           |             |
- *       |   1    | ------------- |           |             |
- *       |________|_______________|___________|_____________|
+ * false if resource fails to complete this update. The function is not designed
+ * to recover the creation of invalid topologies. Returning false is typically
+ * an indication of insufficient validation in caller's stack. new_ctx will be
+ * invalid. Caller may attempt to restore new_ctx by calling this function
+ * again with original slice count.
+ */
+bool resource_update_pipes_for_stream_with_slice_count(
+		struct dc_state *new_ctx,
+		const struct dc_state *cur_ctx,
+		const struct resource_pool *pool,
+		const struct dc_stream_state *stream,
+		int new_slice_count);
+
+/*
+ * Update MPC slice count by acquiring or releasing DPP pipes. If new slices
+ * need to be added it is going to add to the last MPC index. If existing
+ * slices need to be removed, it is going to remove them from the last MPC
+ * index.
+ *
+ * @dpp_pipe - top most dpp pipe for MPCC combine.
+ *
+ * return - true if MPC slices are updated and required pipes are acquired. All
+ * affected pipe parameters are updated.
  *
- * return - true if pipe ctx is used for mpcc combine.
+ * false if resource fails to complete this update. The function is not designed
+ * to recover the creation of invalid topologies. Returning false is typically
+ * an indication of insufficient validation in caller's stack. new_ctx will be
+ * invalid. Caller may attempt to restore new_ctx by calling this function
+ * again with original slice count.
+ */
+bool resource_update_pipes_for_plane_with_slice_count(
+		struct dc_state *new_ctx,
+		const struct dc_state *cur_ctx,
+		const struct resource_pool *pool,
+		const struct dc_plane_state *plane,
+		int slice_count);
+
+/*
+ * Get the OTG master pipe in resource context associated with the stream.
+ * return - NULL if not found. Otherwise the OTG master pipe associated with the
+ * stream.
+ */
+struct pipe_ctx *resource_get_otg_master_for_stream(
+		struct resource_context *res_ctx,
+		const struct dc_stream_state *stream);
+
+/*
+ * Get an array of OPP heads in opp_heads ordered with index low to high for OTG
+ * master pipe in res_ctx.
+ * return - number of OPP heads in the array. If otg_master passed in is not
+ * an OTG master, the function returns 0.
+ */
+int resource_get_opp_heads_for_otg_master(const struct pipe_ctx *otg_master,
+		struct resource_context *res_ctx,
+		struct pipe_ctx *opp_heads[MAX_PIPES]);
+
+/*
+ * Get an array of DPP pipes in dpp_pipes ordered with index low to high for OPP
+ * head pipe in res_ctx.
+ * return - number of DPP pipes in the array. If opp_head passed in is not
+ * an OPP pipe, the function returns 0.
+ */
+int resource_get_dpp_pipes_for_opp_head(const struct pipe_ctx *opp_head,
+		struct resource_context *res_ctx,
+		struct pipe_ctx *dpp_pipes[MAX_PIPES]);
+
+/*
+ * Get an array of DPP pipes in dpp_pipes ordered with index low to high for
+ * plane in res_ctx.
+ * return - number of DPP pipes in the array.
+ */
+int resource_get_dpp_pipes_for_plane(const struct dc_plane_state *plane,
+		struct resource_context *res_ctx,
+		struct pipe_ctx *dpp_pipes[MAX_PIPES]);
+
+/*
+ * Get the OTG master pipe for the input pipe context.
+ * return - the OTG master pipe for the input pipe
+ * context.
+ */
+struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx);
+
+/*
+ * Get the OPP head pipe for the input pipe context.
+ * return - the OPP head pipe for the input pipe
+ * context.
+ */
+struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx);
+
+/*
+ * Get the MPC slice index counting from 0 from left most slice
+ * For example, if a DPP pipe is used as a secondary pipe in MPCC combine, MPC
+ * split index is greater than 0.
+ */
+int resource_get_mpc_slice_index(const struct pipe_ctx *dpp_pipe);
+
+/*
+ * Get number of MPC "cuts" of the plane associated with the pipe. MPC slice
+ * count is equal to MPC splits + 1. For example if a plane is cut 3 times, it
+ * will have 4 pieces of slice.
+ * return - 0 if pipe is not used for a plane with MPCC combine. otherwise
+ * the number of MPC "cuts" for the plane.
+ */
+int resource_get_mpc_slice_count(const struct pipe_ctx *opp_head);
+
+/*
+ * Get number of ODM "cuts" of the timing associated with the pipe. ODM slice
+ * count is equal to ODM splits + 1. For example if a timing is cut 3 times, it
+ * will have 4 pieces of slice.
+ * return - 0 if pipe is not used for ODM combine. otherwise
+ * the number of ODM "cuts" for the timing.
  */
-bool resource_is_for_mpcc_combine(const struct pipe_ctx *pipe_ctx);
+int resource_get_odm_slice_count(const struct pipe_ctx *otg_master);
+
+/* Get the ODM slice index counting from 0 from left most slice */
+int resource_get_odm_slice_index(const struct pipe_ctx *opp_head);
 
 /*
  * Look for a free pipe in new resource context that is used as a secondary OPP
@@ -360,100 +502,6 @@ struct pipe_ctx *resource_find_free_secondary_pipe_legacy(
 		const struct resource_pool *pool,
 		const struct pipe_ctx *primary_pipe);
 
-/*
- * Get number of MPC "cuts" of the plane associated with the pipe. MPC slice
- * count is equal to MPC splits + 1. For example if a plane is cut 3 times, it
- * will have 4 pieces of slice.
- * return - 0 if pipe is not used for a plane with MPCC combine. otherwise
- * the number of MPC "cuts" for the plane.
- */
-int resource_get_num_mpc_splits(const struct pipe_ctx *pipe);
-
-int resource_get_mpc_split_index(struct pipe_ctx *pipe_ctx);
-
-
-/*
- * Get number of ODM "cuts" of the timing associated with the pipe. ODM slice
- * count is equal to ODM splits + 1. For example if a timing is cut 3 times, it
- * will have 4 pieces of slice.
- * return - 0 if pipe is not used for ODM combine. otherwise
- * the number of ODM "cuts" for the timing.
- */
-int resource_get_num_odm_splits(const struct pipe_ctx *pipe);
-
-int resource_get_odm_split_index(struct pipe_ctx *pipe_ctx);
-
-/*
- * Get the OTG master pipe in resource context associated with the stream.
- * return - NULL if not found. Otherwise the OTG master pipe associated with the
- * stream.
- */
-struct pipe_ctx *resource_get_otg_master_for_stream(
-		struct resource_context *res_ctx,
-		struct dc_stream_state *stream);
-
-/*
- * Get the OTG master pipe for the input pipe context.
- * return - the OTG master pipe for the input pipe
- * context.
- */
-struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx);
-
-/*
- * Get the OPP head pipe for the input pipe context.
- * return - the OPP head pipe for the input pipe
- * context.
- */
-struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx);
-
-/*
- * Update ODM slice count by acquiring or releasing pipes. If new slices need
- * to be added, it is going to add them to the last ODM index. If existing
- * slices need to be removed, it is going to remove them from the last ODM
- * index.
- *
- * return - true if ODM slices are updated and required pipes are acquired. All
- * affected pipe parameters are updated.
- *
- * false if resource fails to complete this update. The function is not designed
- * to recover the creation of invalid topologies. Returning false is typically
- * an indication of insufficient validation in caller's stack. The function will
- * return the new_ctx up until the last valid step performed in the function.
- * Caller may use the returned new_ctx for debugging the error or it may attempt
- * to restore new_ctx by calling this function again with original slice count.
- */
-bool resource_update_pipes_with_odm_slice_count(
-		struct pipe_ctx *otg_master_pipe,
-		struct dc_state *new_ctx,
-		const struct dc_state *cur_ctx,
-		const struct resource_pool *pool,
-		int slice_count);
-
-/*
- * Update MPC slice count by acquiring or releasing DPP pipes. If new slices
- * need to be added it is going to add to the last MPC index. If existing
- * slices need to be removed, it is going to remove them from the last MPC
- * index.
- *
- * @dpp_pipe - top most dpp pipe for MPCC combine.
- *
- * return - true if MPC slices are updated and required pipes are acquired. All
- * affected pipe parameters are updated.
- *
- * false if resource fails to complete this update. The function is not designed
- * to recover the creation of invalid topologies. Returning false is typically
- * an indication of insufficient validation in caller's stack. The function will
- * return the new_ctx up until the last valid step performed in the function.
- * Caller may use the returned new_ctx for debugging the error or it may attempt
- * to restore new_ctx by calling this function again with original slice count.
- */
-bool resource_update_pipes_with_mpc_slice_count(
-		struct pipe_ctx *dpp_pipe,
-		struct dc_state *new_ctx,
-		const struct dc_state *cur_ctx,
-		const struct resource_pool *pool,
-		int slice_count);
-
 bool resource_validate_attach_surfaces(
 		const struct dc_validation_set set[],
 		int set_count,
-- 
2.41.0



More information about the amd-gfx mailing list