Blob Blame History Raw
From: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com>
Date: Fri, 11 Aug 2017 10:43:45 -0400
Subject: drm/amd/display: Per plane validation context build.
Git-commit: 19f89e2392e692208a0a00465d30b2b2bf43e9a9
Patch-mainline: v4.15-rc1
References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166

Introduce add/remove plane to/from context.
Make DC wrapper to use them in WIndows/Diags.
Use them in dc_update_surface_to_stream.
Call add/remove plane from Linux DM.

Remove dc_validation_set from dc_validate_global_state interface
and by this remove clean Linux DM from using it.

Signed-off-by: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
Acked-by: Harry Wentland <Harry.Wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c       |  165 ++-----
 drivers/gpu/drm/amd/display/dc/core/dc.c                |   12 
 drivers/gpu/drm/amd/display/dc/core/dc_resource.c       |  360 ++++++++++------
 drivers/gpu/drm/amd/display/dc/dc.h                     |   37 +
 drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c |   16 
 drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c |   26 -
 drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c |   16 
 drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c   |   16 
 drivers/gpu/drm/amd/display/dc/inc/core_types.h         |    3 
 9 files changed, 352 insertions(+), 299 deletions(-)

--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4304,77 +4304,6 @@ void dm_restore_drm_connector_state(stru
 		dm_force_atomic_commit(&aconnector->base);
 }
 
-static uint32_t add_val_sets_plane(
-	struct dc_validation_set *val_sets,
-	uint32_t set_count,
-	const struct dc_stream_state *stream,
-	struct dc_plane_state *plane_state)
-{
-	uint32_t i = 0, j = 0;
-
-	while (i < set_count) {
-		if (val_sets[i].stream == stream) {
-			while (val_sets[i].plane_states[j])
-				j++;
-			break;
-		}
-		++i;
-	}
-
-	val_sets[i].plane_states[j] = plane_state;
-	val_sets[i].plane_count++;
-
-	return val_sets[i].plane_count;
-}
-
-static uint32_t update_in_val_sets_stream(
-	struct dc_validation_set *val_sets,
-	uint32_t set_count,
-	struct dc_stream_state *old_stream,
-	struct dc_stream_state *new_stream,
-	struct drm_crtc *crtc)
-{
-	uint32_t i = 0;
-
-	while (i < set_count) {
-		if (val_sets[i].stream == old_stream)
-			break;
-		++i;
-	}
-
-	val_sets[i].stream = new_stream;
-
-	if (i == set_count)
-		/* nothing found. add new one to the end */
-		return set_count + 1;
-
-	return set_count;
-}
-
-static uint32_t remove_from_val_sets(
-	struct dc_validation_set *val_sets,
-	uint32_t set_count,
-	const struct dc_stream_state *stream)
-{
-	int i;
-
-	for (i = 0; i < set_count; i++)
-		if (val_sets[i].stream == stream)
-			break;
-
-	if (i == set_count) {
-		/* nothing found */
-		return set_count;
-	}
-
-	set_count--;
-
-	for (; i < set_count; i++)
-		val_sets[i] = val_sets[i + 1];
-
-	return set_count;
-}
-
 /*`
  * Grabs all modesetting locks to serialize against any blocking commits,
  * Waits for completion of all non blocking commits.
@@ -4438,10 +4367,9 @@ int amdgpu_dm_atomic_check(struct drm_de
 	struct dc *dc = adev->dm.dc;
 	struct drm_connector *connector;
 	struct drm_connector_state *conn_state;
-	int set_count;
-	struct dc_validation_set set[MAX_STREAMS] = { { 0 } };
 	struct dm_crtc_state *old_acrtc_state, *new_acrtc_state;
 	struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
+	bool pflip_needed  = !state->allow_modeset;
 
 	/*
 	 * This bool will be set for true for any modeset/reset
@@ -4460,16 +4388,44 @@ int amdgpu_dm_atomic_check(struct drm_de
 	ASSERT(dm_state->context);
 	dc_resource_validate_ctx_copy_construct_current(dc, dm_state->context);
 
-	/* copy existing configuration */
-	set_count = 0;
-	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+	/* Remove exiting planes if they are disabled or their CRTC is updated */
+	for_each_crtc_in_state(state, crtc, crtc_state, i) {
+		new_acrtc_state = to_dm_crtc_state(crtc_state);
 
-		old_acrtc_state = to_dm_crtc_state(crtc->state);
+		if (pflip_needed)
+			continue;
+
+		for_each_plane_in_state(state, plane, plane_state, j) {
+			struct drm_crtc *plane_crtc = plane_state->crtc;
+			struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
+
+			if (plane->type == DRM_PLANE_TYPE_CURSOR)
+				continue;
+
+			if (crtc != plane_crtc || !dm_plane_state->dc_state)
+				continue;
+
+			WARN_ON(!new_acrtc_state->stream);
+
+			if (drm_atomic_plane_disabling(plane->state, plane_state) ||
+					drm_atomic_crtc_needs_modeset(crtc_state)) {
+				if (!dc_remove_plane_from_context(
+						dc,
+						new_acrtc_state->stream,
+						dm_plane_state->dc_state,
+						dm_state->context)) {
+
+					ret = EINVAL;
+					goto fail;
+				}
+
+			}
 
-		if (old_acrtc_state->stream) {
-			dc_stream_retain(old_acrtc_state->stream);
-			set[set_count].stream = old_acrtc_state->stream;
-			++set_count;
+			dc_plane_state_release(dm_plane_state->dc_state);
+			dm_plane_state->dc_state = NULL;
+
+			DRM_DEBUG_KMS("Disabling DRM plane: %d on DRM crtc %d\n",
+					plane->base.id, crtc->base.id);
 		}
 	}
 
@@ -4513,11 +4469,6 @@ int amdgpu_dm_atomic_check(struct drm_de
 					goto fail;
 				}
 
-				set_count = remove_from_val_sets(
-						set,
-						set_count,
-						new_acrtc_state->stream);
-
 				dc_stream_release(new_acrtc_state->stream);
 				new_acrtc_state->stream = NULL;
 
@@ -4576,13 +4527,6 @@ int amdgpu_dm_atomic_check(struct drm_de
 
 				new_acrtc_state->stream = new_stream;
 
-				set_count = update_in_val_sets_stream(
-						set,
-						set_count,
-						old_acrtc_state->stream,
-						new_acrtc_state->stream,
-						crtc);
-
 				if (!dc_add_stream_to_ctx(
 						dc,
 						dm_state->context,
@@ -4639,32 +4583,32 @@ int amdgpu_dm_atomic_check(struct drm_de
 		lock_and_validation_needed = true;
 	}
 
+	/* Add new planes */
 	for_each_crtc_in_state(state, crtc, crtc_state, i) {
 		new_acrtc_state = to_dm_crtc_state(crtc_state);
 
+		if (pflip_needed)
+			continue;
+
 		for_each_plane_in_state(state, plane, plane_state, j) {
 			struct drm_crtc *plane_crtc = plane_state->crtc;
-			struct drm_framebuffer *fb = plane_state->fb;
-			bool pflip_needed;
 			struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
 
 			/*TODO Implement atomic check for cursor plane */
 			if (plane->type == DRM_PLANE_TYPE_CURSOR)
 				continue;
 
-			if (!fb || !plane_crtc || crtc != plane_crtc || !crtc_state->active)
+			if (crtc != plane_crtc)
 				continue;
 
-			WARN_ON(!new_acrtc_state->stream);
-
-			pflip_needed = !state->allow_modeset;
-			if (!pflip_needed) {
+			if (!drm_atomic_plane_disabling(plane->state, plane_state)) {
 				struct dc_plane_state *dc_plane_state;
 
+				WARN_ON(!new_acrtc_state->stream);
+
 				dc_plane_state = dc_create_plane_state(dc);
 
-				if (dm_plane_state->dc_state)
-					dc_plane_state_release(dm_plane_state->dc_state);
+				WARN_ON(dm_plane_state->dc_state);
 
 				dm_plane_state->dc_state = dc_plane_state;
 
@@ -4677,10 +4621,17 @@ int amdgpu_dm_atomic_check(struct drm_de
 				if (ret)
 					goto fail;
 
-				add_val_sets_plane(set,
-						     set_count,
-						     new_acrtc_state->stream,
-						     dc_plane_state);
+
+				if (!dc_add_plane_to_context(
+						dc,
+						new_acrtc_state->stream,
+						dc_plane_state,
+						dm_state->context)) {
+
+					ret = EINVAL;
+					goto fail;
+				}
+
 
 				lock_and_validation_needed = true;
 			}
@@ -4708,7 +4659,7 @@ int amdgpu_dm_atomic_check(struct drm_de
 		if (ret)
 			goto fail;
 
-		if (!dc_validate_global_state(dc, set, set_count, dm_state->context)) {
+		if (!dc_validate_global_state(dc, dm_state->context)) {
 			ret = -EINVAL;
 			goto fail;
 		}
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -1305,10 +1305,16 @@ void dc_update_planes_and_stream(struct
 		dc_resource_validate_ctx_copy_construct(
 				core_dc->current_context, context);
 
+		/*remove old surfaces from context */
+		if (!dc_rem_all_planes_for_stream(dc, stream, context)) {
+
+			BREAK_TO_DEBUGGER();
+			goto fail;
+		}
+
 		/* add surface to context */
-		if (!resource_attach_surfaces_to_context(
-				new_planes, surface_count, stream,
-				context, core_dc->res_pool)) {
+		if (!dc_add_all_planes_for_stream(dc, stream, new_planes, surface_count, context)) {
+
 			BREAK_TO_DEBUGGER();
 			goto fail;
 		}
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -946,6 +946,26 @@ struct pipe_ctx *resource_get_head_pipe_
 	return NULL;
 }
 
+static struct pipe_ctx *resource_get_tail_pipe_for_stream(
+		struct resource_context *res_ctx,
+		struct dc_stream_state *stream)
+{
+	struct pipe_ctx *head_pipe, *tail_pipe;
+	head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);
+
+	if (!head_pipe)
+		return NULL;
+
+	tail_pipe = head_pipe->bottom_pipe;
+
+	while (tail_pipe) {
+		head_pipe = tail_pipe;
+		tail_pipe = tail_pipe->bottom_pipe;
+	}
+
+	return head_pipe;
+}
+
 /*
  * A free_pipe for a stream is defined here as a pipe
  * that has no surface attached yet
@@ -990,22 +1010,6 @@ static struct pipe_ctx *acquire_free_pip
 
 }
 
-static void release_free_pipes_for_stream(
-		struct resource_context *res_ctx,
-		struct dc_stream_state *stream)
-{
-	int i;
-
-	for (i = MAX_PIPES - 1; i >= 0; i--) {
-		/* never release the topmost pipe*/
-		if (res_ctx->pipe_ctx[i].stream == stream &&
-				res_ctx->pipe_ctx[i].top_pipe &&
-				!res_ctx->pipe_ctx[i].plane_state) {
-			memset(&res_ctx->pipe_ctx[i], 0, sizeof(struct pipe_ctx));
-		}
-	}
-}
-
 #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
 static int acquire_first_split_pipe(
 		struct resource_context *res_ctx,
@@ -1040,97 +1044,236 @@ static int acquire_first_split_pipe(
 }
 #endif
 
-bool resource_attach_surfaces_to_context(
-		struct dc_plane_state * const *plane_states,
-		int surface_count,
+bool dc_add_plane_to_context(
+		const struct dc *dc,
 		struct dc_stream_state *stream,
-		struct validate_context *context,
-		const struct resource_pool *pool)
+		struct dc_plane_state *plane_state,
+		struct validate_context *context)
 {
 	int i;
-	struct pipe_ctx *tail_pipe;
+	struct resource_pool *pool = dc->res_pool;
+	struct pipe_ctx *head_pipe, *tail_pipe, *free_pipe;
 	struct dc_stream_status *stream_status = NULL;
 
+	for (i = 0; i < context->stream_count; i++)
+		if (context->streams[i] == stream) {
+			stream_status = &context->stream_status[i];
+			break;
+		}
+	if (stream_status == NULL) {
+		dm_error("Existing stream not found; failed to attach surface!\n");
+		return false;
+	}
+
 
-	if (surface_count > MAX_SURFACE_NUM) {
-		dm_error("Surface: can not attach %d surfaces! Maximum is: %d\n",
-			surface_count, MAX_SURFACE_NUM);
+	if (stream_status->plane_count == MAX_SURFACE_NUM) {
+		dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n",
+				plane_state, MAX_SURFACE_NUM);
 		return false;
 	}
 
+	head_pipe = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
+
+	if (!head_pipe) {
+		dm_error("Head pipe not found for stream_state %p !\n", stream);
+		return false;
+	}
+
+	/* retain new surfaces */
+	dc_plane_state_retain(plane_state);
+
+	free_pipe = acquire_free_pipe_for_stream(context, pool, stream);
+
+#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
+	if (!free_pipe) {
+		int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
+		if (pipe_idx >= 0)
+			free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
+	}
+#endif
+	if (!free_pipe) {
+		stream_status->plane_states[i] = NULL;
+		return false;
+	}
+
+	free_pipe->plane_state = plane_state;
+
+	if (head_pipe != free_pipe) {
+
+		tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream);
+		ASSERT(tail_pipe);
+
+		free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
+		free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
+		free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
+		free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
+		free_pipe->clock_source = tail_pipe->clock_source;
+		free_pipe->top_pipe = tail_pipe;
+		tail_pipe->bottom_pipe = free_pipe;
+	}
+
+	/* assign new surfaces*/
+	stream_status->plane_states[stream_status->plane_count] = plane_state;
+
+	stream_status->plane_count++;
+
+	return true;
+}
+
+bool dc_remove_plane_from_context(
+		const struct dc *dc,
+		struct dc_stream_state *stream,
+		struct dc_plane_state *plane_state,
+		struct validate_context *context)
+{
+	int i;
+	struct dc_stream_status *stream_status = NULL;
+	struct resource_pool *pool = dc->res_pool;
+
 	for (i = 0; i < context->stream_count; i++)
 		if (context->streams[i] == stream) {
 			stream_status = &context->stream_status[i];
 			break;
 		}
+
 	if (stream_status == NULL) {
-		dm_error("Existing stream not found; failed to attach surfaces\n");
+		dm_error("Existing stream not found; failed to remove plane.\n");
 		return false;
 	}
 
-	/* retain new surfaces */
-	for (i = 0; i < surface_count; i++)
-		dc_plane_state_retain(plane_states[i]);
+	/* release pipe for plane*/
+	for (i = pool->pipe_count - 1; i >= 0; i--) {
+		struct pipe_ctx *pipe_ctx;
+
+		if (context->res_ctx.pipe_ctx[i].plane_state == plane_state) {
+			pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+			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;
+				pipe_ctx->bottom_pipe = NULL;
+			} else  {
+				memset(pipe_ctx, 0, sizeof(*pipe_ctx));
+			}
+		}
+	}
+
+
+	for (i = 0; i < stream_status->plane_count; i++) {
+		if (stream_status->plane_states[i] == plane_state) {
 
-	/* detach surfaces from pipes */
-	for (i = 0; i < pool->pipe_count; i++)
-		if (context->res_ctx.pipe_ctx[i].stream == stream) {
-			context->res_ctx.pipe_ctx[i].plane_state = NULL;
-			context->res_ctx.pipe_ctx[i].bottom_pipe = NULL;
+			dc_plane_state_release(stream_status->plane_states[i]);
+			break;
 		}
+	}
+
+	if (i == stream_status->plane_count) {
+		dm_error("Existing plane_state not found; failed to detach it!\n");
+		return false;
+	}
+
+	stream_status->plane_count--;
 
-	/* release existing surfaces*/
+	/* Trim back arrays */
 	for (i = 0; i < stream_status->plane_count; i++)
-		dc_plane_state_release(stream_status->plane_states[i]);
+		stream_status->plane_states[i] = stream_status->plane_states[i + 1];
 
-	for (i = surface_count; i < stream_status->plane_count; i++)
-		stream_status->plane_states[i] = NULL;
+	stream_status->plane_states[stream_status->plane_count] = NULL;
 
-	tail_pipe = NULL;
-	for (i = 0; i < surface_count; i++) {
-		struct dc_plane_state *plane_state = plane_states[i];
-		struct pipe_ctx *free_pipe = acquire_free_pipe_for_stream(
-				context, pool, stream);
+	return true;
+}
 
-#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
-		if (!free_pipe) {
-			int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
-			if (pipe_idx >= 0)
-				free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
-		}
-#endif
-		if (!free_pipe) {
-			stream_status->plane_states[i] = NULL;
+bool dc_rem_all_planes_for_stream(
+		const struct dc *dc,
+		struct dc_stream_state *stream,
+		struct validate_context *context)
+{
+	int i, old_plane_count;
+	struct dc_stream_status *stream_status = NULL;
+	struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 };
+
+	for (i = 0; i < context->stream_count; i++)
+			if (context->streams[i] == stream) {
+				stream_status = &context->stream_status[i];
+				break;
+			}
+
+	if (stream_status == NULL) {
+		dm_error("Existing stream %p not found!\n", stream);
+		return false;
+	}
+
+	old_plane_count = stream_status->plane_count;
+
+	for (i = 0; i < old_plane_count; i++)
+		del_planes[i] = stream_status->plane_states[i];
+
+	for (i = 0; i < old_plane_count; i++)
+		if (!dc_remove_plane_from_context(dc, stream, del_planes[i], context))
 			return false;
-		}
 
-		free_pipe->plane_state = plane_state;
+	return true;
+}
 
-		if (tail_pipe) {
-			free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
-			free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
-			free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
-			free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
-			free_pipe->clock_source = tail_pipe->clock_source;
-			free_pipe->top_pipe = tail_pipe;
-			tail_pipe->bottom_pipe = free_pipe;
-		}
+static bool add_all_planes_for_stream(
+		const struct dc *dc,
+		struct dc_stream_state *stream,
+		const struct dc_validation_set set[],
+		int set_count,
+		struct validate_context *context)
+{
+	int i, j;
+
+	for (i = 0; i < set_count; i++)
+		if (set[i].stream == stream)
+			break;
 
-		tail_pipe = free_pipe;
+	if (i == set_count) {
+		dm_error("Stream %p not found in set!\n", stream);
+		return false;
 	}
 
-	release_free_pipes_for_stream(&context->res_ctx, stream);
+	for (j = 0; j < set[i].plane_count; j++)
+		if (!dc_add_plane_to_context(dc, stream, set[i].plane_states[j], context))
+			return false;
 
-	/* assign new surfaces*/
-	for (i = 0; i < surface_count; i++)
-		stream_status->plane_states[i] = plane_states[i];
+	return true;
+}
 
-	stream_status->plane_count = surface_count;
+bool dc_add_all_planes_for_stream(
+		const struct dc *dc,
+		struct dc_stream_state *stream,
+		struct dc_plane_state * const *plane_states,
+		int plane_count,
+		struct validate_context *context)
+{
+	struct dc_validation_set set;
+	int i;
 
-	return true;
+	set.stream = stream;
+	set.plane_count = plane_count;
+
+	for (i = 0; i < plane_count; i++)
+		set.plane_states[i] = plane_states[i];
+
+	return add_all_planes_for_stream(dc, stream, &set, 1, context);
 }
 
 
+
 static bool is_timing_changed(struct dc_stream_state *cur_stream,
 		struct dc_stream_state *new_stream)
 {
@@ -1178,41 +1321,6 @@ bool dc_is_stream_unchanged(
 	return true;
 }
 
-bool resource_validate_attach_surfaces(
-		const struct dc_validation_set set[],
-		int set_count,
-		const struct validate_context *old_context,
-		struct validate_context *context,
-		const struct resource_pool *pool)
-{
-	int i, j;
-
-	for (i = 0; i < set_count; i++) {
-		for (j = 0; old_context && j < old_context->stream_count; j++)
-			if (dc_is_stream_unchanged(
-					old_context->streams[j],
-					context->streams[i])) {
-				if (!resource_attach_surfaces_to_context(
-						old_context->stream_status[j].plane_states,
-						old_context->stream_status[j].plane_count,
-						context->streams[i],
-						context, pool))
-					return false;
-				context->stream_status[i] = old_context->stream_status[j];
-			}
-		if (set[i].plane_count != 0)
-			if (!resource_attach_surfaces_to_context(
-					set[i].plane_states,
-					set[i].plane_count,
-					context->streams[i],
-					context, pool))
-				return false;
-
-	}
-
-	return true;
-}
-
 /* Maximum TMDS single link pixel clock 165MHz */
 #define TMDS_MAX_PIXEL_CLOCK_IN_KHZ 165000
 #define TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST 297000
@@ -1392,23 +1500,22 @@ bool dc_remove_stream_from_ctx(
 			struct validate_context *new_ctx,
 			struct dc_stream_state *stream)
 {
-	int i, j;
+	int i;
 	struct dc_context *dc_ctx = dc->ctx;
 	struct pipe_ctx *del_pipe = NULL;
 
-	/*TODO MPO to remove extra pipe or in surface remove ?*/
-
-	/* Release primary and secondary pipe (if exsist) */
+	/* Release primary pipe */
 	for (i = 0; i < MAX_PIPES; i++) {
-		if (new_ctx->res_ctx.pipe_ctx[i].stream == stream) {
+		if (new_ctx->res_ctx.pipe_ctx[i].stream == stream &&
+				!new_ctx->res_ctx.pipe_ctx[i].top_pipe) {
 			del_pipe = &new_ctx->res_ctx.pipe_ctx[i];
 
-			if (del_pipe->stream_res.stream_enc)
-				update_stream_engine_usage(
-						&new_ctx->res_ctx,
+			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);
+					del_pipe->stream_res.stream_enc,
+					false);
 
 			if (del_pipe->stream_res.audio)
 				update_audio_usage(
@@ -1418,6 +1525,8 @@ bool dc_remove_stream_from_ctx(
 					false);
 
 			memset(del_pipe, 0, sizeof(*del_pipe));
+
+			break;
 		}
 	}
 
@@ -1438,10 +1547,6 @@ bool dc_remove_stream_from_ctx(
 	dc_stream_release(new_ctx->streams[i]);
 	new_ctx->stream_count--;
 
-	/*TODO move into dc_remove_surface_from_ctx	?*/
-	for (j = 0; j < new_ctx->stream_status[i].plane_count; j++)
-		dc_plane_state_release(new_ctx->stream_status[i].plane_states[j]);
-
 	/* Trim back arrays */
 	for (; i < new_ctx->stream_count; i++) {
 		new_ctx->streams[i] = new_ctx->streams[i + 1];
@@ -1636,18 +1741,14 @@ void dc_resource_validate_ctx_copy_const
 
 bool dc_validate_global_state(
 		struct dc *dc,
-		const struct dc_validation_set set[],
-		int set_count,
 		struct validate_context *new_ctx)
 {
 	enum dc_status result = DC_ERROR_UNEXPECTED;
-	struct dc_context *dc_ctx = dc->ctx;
-	struct validate_context *old_context = dc->current_context;
 	int i, j;
 
 	if (dc->res_pool->funcs->validate_global &&
-	    dc->res_pool->funcs->validate_global(dc, set, set_count,
-						 old_context, new_ctx) != DC_OK)
+			dc->res_pool->funcs->validate_global(
+			dc, new_ctx) != DC_OK)
 		return false;
 
 	/* TODO without this SWDEV-114774 brakes */
@@ -1687,15 +1788,6 @@ bool dc_validate_global_state(
 		}
 	}
 
-	/*TODO This should be ok */
-	/* Split pipe resource, do not acquire back end */
-
-	if (!resource_validate_attach_surfaces(
-			set, set_count, old_context, new_ctx, dc->res_pool)) {
-		DC_ERROR("Failed to attach surface to stream!\n");
-		return DC_FAIL_ATTACH_SURFACES;
-	}
-
 	result = resource_build_scaling_params_for_context(dc, new_ctx);
 
 	if (result == DC_OK)
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -619,15 +619,40 @@ bool dc_stream_get_scanoutpos(const stru
 				  uint32_t *h_position,
 				  uint32_t *v_position);
 
-bool dc_remove_stream_from_ctx(
+bool dc_add_stream_to_ctx(
 			struct dc *dc,
+		struct validate_context *new_ctx,
+		struct dc_stream_state *stream);
+
+bool dc_remove_stream_from_ctx(
+		struct dc *dc,
 			struct validate_context *new_ctx,
 			struct dc_stream_state *stream);
 
-bool dc_add_stream_to_ctx(
-		struct dc *dc,
-		struct validate_context *new_ctx,
-		struct dc_stream_state *stream);
+
+bool dc_add_plane_to_context(
+		const struct dc *dc,
+		struct dc_stream_state *stream,
+		struct dc_plane_state *plane_state,
+		struct validate_context *context);
+
+bool dc_remove_plane_from_context(
+		const struct dc *dc,
+		struct dc_stream_state *stream,
+		struct dc_plane_state *plane_state,
+		struct validate_context *context);
+
+bool dc_rem_all_planes_for_stream(
+		const struct dc *dc,
+		struct dc_stream_state *stream,
+		struct validate_context *context);
+
+bool dc_add_all_planes_for_stream(
+		const struct dc *dc,
+		struct dc_stream_state *stream,
+		struct dc_plane_state * const *plane_states,
+		int plane_count,
+		struct validate_context *context);
 
 /*
  * Structure to store surface/stream associations for validation
@@ -644,8 +669,6 @@ bool dc_validate_plane(struct dc *dc, co
 
 bool dc_validate_global_state(
 		struct dc *dc,
-		const struct dc_validation_set set[],
-		int set_count,
 		struct validate_context *new_ctx);
 
 /*
--- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
@@ -684,19 +684,18 @@ bool dce100_validate_bandwidth(
 }
 
 static bool dce100_validate_surface_sets(
-		const struct dc_validation_set set[],
-		int set_count)
+		struct validate_context *context)
 {
 	int i;
 
-	for (i = 0; i < set_count; i++) {
-		if (set[i].plane_count == 0)
+	for (i = 0; i < context->stream_count; i++) {
+		if (context->stream_status[i].plane_count == 0)
 			continue;
 
-		if (set[i].plane_count > 1)
+		if (context->stream_status[i].plane_count > 1)
 			return false;
 
-		if (set[i].plane_states[0]->format
+		if (context->stream_status[i].plane_states[0]->format
 				>= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
 			return false;
 	}
@@ -706,12 +705,9 @@ static bool dce100_validate_surface_sets
 
 enum dc_status dce100_validate_global(
 		struct dc  *dc,
-		const struct dc_validation_set set[],
-		int set_count,
-		struct validate_context *old_context,
 		struct validate_context *context)
 {
-	if (!dce100_validate_surface_sets(set, set_count))
+	if (!dce100_validate_surface_sets(context))
 		return DC_FAIL_SURFACE_VALIDATE;
 
 	return DC_OK;
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
@@ -880,31 +880,30 @@ static bool dce110_validate_bandwidth(
 }
 
 static bool dce110_validate_surface_sets(
-		const struct dc_validation_set set[],
-		int set_count)
+		struct validate_context *context)
 {
 	int i;
 
-	for (i = 0; i < set_count; i++) {
-		if (set[i].plane_count == 0)
+	for (i = 0; i < context->stream_count; i++) {
+		if (context->stream_status[i].plane_count == 0)
 			continue;
 
-		if (set[i].plane_count > 2)
+		if (context->stream_status[i].plane_count > 2)
 			return false;
 
-		if (set[i].plane_states[0]->format
+		if (context->stream_status[i].plane_states[0]->format
 				>= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
 			return false;
 
-		if (set[i].plane_count == 2) {
-			if (set[i].plane_states[1]->format
+		if (context->stream_status[i].plane_count == 2) {
+			if (context->stream_status[i].plane_states[1]->format
 					< SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
 				return false;
-			if (set[i].plane_states[1]->src_rect.width > 1920
-					|| set[i].plane_states[1]->src_rect.height > 1080)
+			if (context->stream_status[i].plane_states[1]->src_rect.width > 1920
+					|| context->stream_status[i].plane_states[1]->src_rect.height > 1080)
 				return false;
 
-			if (set[i].stream->timing.pixel_encoding != PIXEL_ENCODING_RGB)
+			if (context->streams[i]->timing.pixel_encoding != PIXEL_ENCODING_RGB)
 				return false;
 		}
 	}
@@ -914,12 +913,9 @@ static bool dce110_validate_surface_sets
 
 enum dc_status dce110_validate_global(
 		struct dc *dc,
-		const struct dc_validation_set set[],
-		int set_count,
-		struct validate_context *old_context,
 		struct validate_context *context)
 {
-	if (!dce110_validate_surface_sets(set, set_count))
+	if (!dce110_validate_surface_sets(context))
 		return DC_FAIL_SURFACE_VALIDATE;
 
 	return DC_OK;
--- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
@@ -855,19 +855,18 @@ enum dc_status resource_map_phy_clock_re
 }
 
 static bool dce112_validate_surface_sets(
-		const struct dc_validation_set set[],
-		int set_count)
+		struct validate_context *context)
 {
 	int i;
 
-	for (i = 0; i < set_count; i++) {
-		if (set[i].plane_count == 0)
+	for (i = 0; i < context->stream_count; i++) {
+		if (context->stream_status[i].plane_count == 0)
 			continue;
 
-		if (set[i].plane_count > 1)
+		if (context->stream_status[i].plane_count > 1)
 			return false;
 
-		if (set[i].plane_states[0]->format
+		if (context->stream_status[i].plane_states[0]->format
 				>= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
 			return false;
 	}
@@ -928,12 +927,9 @@ enum dc_status dce112_validate_guarantee
 
 enum dc_status dce112_validate_global(
 		struct dc *dc,
-		const struct dc_validation_set set[],
-		int set_count,
-		struct validate_context *old_context,
 		struct validate_context *context)
 {
-	if (!dce112_validate_surface_sets(set, set_count))
+	if (!dce112_validate_surface_sets(context))
 		return DC_FAIL_SURFACE_VALIDATE;
 
 	return DC_OK;
--- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
@@ -716,19 +716,18 @@ bool dce80_validate_bandwidth(
 }
 
 static bool dce80_validate_surface_sets(
-		const struct dc_validation_set set[],
-		int set_count)
+		struct validate_context *context)
 {
 	int i;
 
-	for (i = 0; i < set_count; i++) {
-		if (set[i].plane_count == 0)
+	for (i = 0; i < context->stream_count; i++) {
+		if (context->stream_status[i].plane_count == 0)
 			continue;
 
-		if (set[i].plane_count > 1)
+		if (context->stream_status[i].plane_count > 1)
 			return false;
 
-		if (set[i].plane_states[0]->format
+		if (context->stream_status[i].plane_states[0]->format
 				>= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
 			return false;
 	}
@@ -738,12 +737,9 @@ static bool dce80_validate_surface_sets(
 
 enum dc_status dce80_validate_global(
 		struct dc *dc,
-		const struct dc_validation_set set[],
-		int set_count,
-		struct validate_context *old_context,
 		struct validate_context *context)
 {
-	if (!dce80_validate_surface_sets(set, set_count))
+	if (!dce80_validate_surface_sets(context))
 		return DC_FAIL_SURFACE_VALIDATE;
 
 	return DC_OK;
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -99,9 +99,6 @@ struct resource_funcs {
 
 	enum dc_status (*validate_global)(
 		struct dc *dc,
-		const struct dc_validation_set set[],
-		int set_count,
-		struct validate_context *old_context,
 		struct validate_context *context);
 
 	struct pipe_ctx *(*acquire_idle_pipe_for_layer)(