aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.14.71/0978-drm-amd-display-Per-stream-validate_context-build-v2.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.14.71/0978-drm-amd-display-Per-stream-validate_context-build-v2.patch')
-rw-r--r--common/recipes-kernel/linux/linux-yocto-4.14.71/0978-drm-amd-display-Per-stream-validate_context-build-v2.patch1841
1 files changed, 1841 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.14.71/0978-drm-amd-display-Per-stream-validate_context-build-v2.patch b/common/recipes-kernel/linux/linux-yocto-4.14.71/0978-drm-amd-display-Per-stream-validate_context-build-v2.patch
new file mode 100644
index 00000000..b08beb7a
--- /dev/null
+++ b/common/recipes-kernel/linux/linux-yocto-4.14.71/0978-drm-amd-display-Per-stream-validate_context-build-v2.patch
@@ -0,0 +1,1841 @@
+From 34e2083764b0ba353b3fb6c34230f804bad65e0e Mon Sep 17 00:00:00 2001
+From: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com>
+Date: Mon, 31 Jul 2017 11:29:25 -0400
+Subject: [PATCH 0978/4131] drm/amd/display: Per stream validate_context build
+ v2.
+
+Until now new context would start as empty, then populated
+with exsisting pipes + new. Now we start with duplication
+of existing context and then add/delete from the context
+pipes as needed.
+
+This allows to do a per stream resource
+population, start discarding dc_validation_set
+and by this brings DC closer to to DRM.
+
+v2: Add some fixes and rebase.
+
+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>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 68 ++-
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 108 +----
+ drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 468 +++++++++++++++------
+ drivers/gpu/drm/amd/display/dc/dc.h | 32 +-
+ .../drm/amd/display/dc/dce100/dce100_resource.c | 78 +---
+ .../drm/amd/display/dc/dce110/dce110_resource.c | 86 +---
+ .../drm/amd/display/dc/dce112/dce112_resource.c | 143 +++----
+ .../drm/amd/display/dc/dce112/dce112_resource.h | 5 +
+ .../drm/amd/display/dc/dce120/dce120_resource.c | 4 +-
+ .../gpu/drm/amd/display/dc/dce80/dce80_resource.c | 79 +---
+ .../gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 85 ++--
+ drivers/gpu/drm/amd/display/dc/inc/core_types.h | 19 +-
+ drivers/gpu/drm/amd/display/dc/inc/resource.h | 6 +-
+ 13 files changed, 577 insertions(+), 604 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+index 1ffe709..faca60a 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -25,6 +25,7 @@
+
+ #include "dm_services_types.h"
+ #include "dc.h"
++#include "dc/inc/core_types.h"
+
+ #include "vid.h"
+ #include "amdgpu.h"
+@@ -819,13 +820,33 @@ struct drm_atomic_state *
+ dm_atomic_state_alloc(struct drm_device *dev)
+ {
+ struct dm_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
++ struct validate_context *new_ctx;
++ struct amdgpu_device *adev = dev->dev_private;
++ struct dc *dc = adev->dm.dc;
+
+- if (!state || drm_atomic_state_init(dev, &state->base) < 0) {
+- kfree(state);
++ if (!state)
+ return NULL;
+- }
++
++ if (drm_atomic_state_init(dev, &state->base) < 0)
++ goto fail;
++
++ /* copy existing configuration */
++ new_ctx = dm_alloc(sizeof(*new_ctx));
++
++ if (!new_ctx)
++ goto fail;
++
++ atomic_inc(&new_ctx->ref_count);
++
++ dc_resource_validate_ctx_copy_construct_current(dc, new_ctx);
++
++ state->context = new_ctx;
+
+ return &state->base;
++
++fail:
++ kfree(state);
++ return NULL;
+ }
+
+ static void
+@@ -4651,7 +4672,6 @@ static int do_aquire_global_lock(
+ int amdgpu_dm_atomic_check(struct drm_device *dev,
+ struct drm_atomic_state *state)
+ {
+- struct dm_atomic_state *dm_state;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ struct drm_plane *plane;
+@@ -4665,6 +4685,7 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
+ 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);
+
+ /*
+ * This bool will be set for true for any modeset/reset
+@@ -4679,8 +4700,6 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
+ return ret;
+ }
+
+- dm_state = to_dm_atomic_state(state);
+-
+ /* copy existing configuration */
+ set_count = 0;
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+@@ -4723,8 +4742,17 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
+
+ if (modereset_required(crtc_state)) {
+
+- /* i.e. reset mode */
++ /* i.e. reset mode */
+ if (new_acrtc_state->stream) {
++
++ if (!dc_remove_stream_from_ctx(
++ dc,
++ dm_state->context,
++ new_acrtc_state->stream)) {
++ ret = -EINVAL;
++ goto fail;
++ }
++
+ set_count = remove_from_val_sets(
+ set,
+ set_count,
+@@ -4772,8 +4800,19 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
+ if (modeset_required(crtc_state, new_stream,
+ old_acrtc_state->stream)) {
+
+- if (new_acrtc_state->stream)
++ if (new_acrtc_state->stream) {
++
++ if (!dc_remove_stream_from_ctx(
++ dc,
++ dm_state->context,
++ new_acrtc_state->stream)) {
++ ret = -EINVAL;
++ goto fail;
++ }
++
++
+ dc_stream_release(new_acrtc_state->stream);
++ }
+
+ new_acrtc_state->stream = new_stream;
+
+@@ -4784,6 +4823,14 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
+ new_acrtc_state->stream,
+ crtc);
+
++ if (!dc_add_stream_to_ctx(
++ dc,
++ dm_state->context,
++ new_acrtc_state->stream)) {
++ ret = -EINVAL;
++ goto fail;
++ }
++
+ lock_and_validation_needed = true;
+ } else {
+ /*
+@@ -4900,9 +4947,8 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
+ ret = do_aquire_global_lock(dev, state);
+ if (ret)
+ goto fail;
+- WARN_ON(dm_state->context);
+- dm_state->context = dc_get_validate_context(dc, set, set_count);
+- if (!dm_state->context) {
++
++ if (!dc_validate_global_state(dc, set, set_count, dm_state->context)) {
+ ret = -EINVAL;
+ goto fail;
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index 4a543dd..28d8b04 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -669,41 +669,6 @@ void dc_destroy(struct dc **dc)
+ *dc = NULL;
+ }
+
+-static bool is_validation_required(
+- const struct dc *dc,
+- const struct dc_validation_set set[],
+- int set_count)
+-{
+- const struct validate_context *context = dc->current_context;
+- int i, j;
+-
+- if (context->stream_count != set_count)
+- return true;
+-
+- for (i = 0; i < set_count; i++) {
+-
+- if (set[i].plane_count != context->stream_status[i].plane_count)
+- return true;
+- if (!dc_is_stream_unchanged(set[i].stream, context->streams[i]))
+- return true;
+-
+- for (j = 0; j < set[i].plane_count; j++) {
+- struct dc_plane_state temp_plane;
+- memset(&temp_plane, 0, sizeof(temp_plane));
+-
+- temp_plane = *context->stream_status[i].plane_states[j];
+- temp_plane.clip_rect = set[i].plane_states[j]->clip_rect;
+- temp_plane.dst_rect.x = set[i].plane_states[j]->dst_rect.x;
+- temp_plane.dst_rect.y = set[i].plane_states[j]->dst_rect.y;
+-
+- if (memcmp(&temp_plane, set[i].plane_states[j], sizeof(temp_plane)) != 0)
+- return true;
+- }
+- }
+-
+- return false;
+-}
+-
+ static bool validate_streams (
+ struct dc *dc,
+ const struct dc_validation_set set[],
+@@ -733,52 +698,12 @@ static bool validate_surfaces(
+ return true;
+ }
+
+-struct validate_context *dc_get_validate_context(
+- struct dc *dc,
+- const struct dc_validation_set set[],
+- uint8_t set_count)
+-{
+- struct dc *core_dc = dc;
+- enum dc_status result = DC_ERROR_UNEXPECTED;
+- struct validate_context *context;
+-
+-
+- context = dm_alloc(sizeof(struct validate_context));
+- if (context == NULL)
+- goto context_alloc_fail;
+-
+- atomic_inc(&context->ref_count);
+-
+- if (!is_validation_required(core_dc, set, set_count)) {
+- dc_resource_validate_ctx_copy_construct(core_dc->current_context, context);
+- return context;
+- }
+-
+- result = core_dc->res_pool->funcs->validate_with_context(
+- core_dc, set, set_count, context, core_dc->current_context);
+-
+-context_alloc_fail:
+- if (result != DC_OK) {
+- dm_logger_write(core_dc->ctx->logger, LOG_WARNING,
+- "%s:resource validation failed, dc_status:%d\n",
+- __func__,
+- result);
+-
+- dc_release_validate_context(context);
+- context = NULL;
+- }
+-
+- return context;
+-
+-}
+-
+ bool dc_validate_resources(
+ struct dc *dc,
+ const struct dc_validation_set set[],
+ uint8_t set_count)
+ {
+- struct dc *core_dc = dc;
+- enum dc_status result = DC_ERROR_UNEXPECTED;
++ bool result = false;
+ struct validate_context *context;
+
+ if (!validate_streams(dc, set, set_count))
+@@ -793,21 +718,16 @@ bool dc_validate_resources(
+
+ atomic_inc(&context->ref_count);
+
+- result = core_dc->res_pool->funcs->validate_with_context(
+- core_dc, set, set_count, context, NULL);
++ dc_resource_validate_ctx_copy_construct_current(dc, context);
+
+-context_alloc_fail:
+- if (result != DC_OK) {
+- dm_logger_write(core_dc->ctx->logger, LOG_WARNING,
+- "%s:resource validation failed, dc_status:%d\n",
+- __func__,
+- result);
+- }
++ result = dc_validate_with_context(
++ dc, set, set_count, context);
+
++context_alloc_fail:
+ dc_release_validate_context(context);
+ context = NULL;
+
+- return result == DC_OK;
++ return result;
+ }
+
+ bool dc_validate_guaranteed(
+@@ -1093,7 +1013,7 @@ bool dc_commit_streams(
+ uint8_t stream_count)
+ {
+ struct dc *core_dc = dc;
+- enum dc_status result = DC_ERROR_UNEXPECTED;
++ bool result = false;
+ struct validate_context *context;
+ struct dc_validation_set set[MAX_STREAMS] = { {0, {0} } };
+ int i;
+@@ -1135,13 +1055,11 @@ bool dc_commit_streams(
+
+ atomic_inc(&context->ref_count);
+
+- result = core_dc->res_pool->funcs->validate_with_context(
+- core_dc, set, stream_count, context, core_dc->current_context);
+- if (result != DC_OK){
+- dm_logger_write(core_dc->ctx->logger, LOG_ERROR,
+- "%s: Context validation failed! dc_status:%d\n",
+- __func__,
+- result);
++ dc_resource_validate_ctx_copy_construct_current(dc, context);
++
++ result = dc_validate_with_context(
++ dc, set, stream_count, context);
++ if (!result) {
+ BREAK_TO_DEBUGGER();
+ goto fail;
+ }
+@@ -1152,7 +1070,7 @@ bool dc_commit_streams(
+ dc_release_validate_context(context);
+
+ context_alloc_fail:
+- return (result == DC_OK);
++ return result;
+ }
+
+ bool dc_post_update_surfaces_to_stream(struct dc *dc)
+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 e3cf519..6b4eb4c 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+@@ -938,7 +938,7 @@ struct pipe_ctx *resource_get_head_pipe_for_stream(
+ int i;
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (res_ctx->pipe_ctx[i].stream == stream &&
+- res_ctx->pipe_ctx[i].stream_res.stream_enc) {
++ !res_ctx->pipe_ctx[i].top_pipe) {
+ return &res_ctx->pipe_ctx[i];
+ break;
+ }
+@@ -1217,29 +1217,31 @@ bool resource_validate_attach_surfaces(
+ #define TMDS_MAX_PIXEL_CLOCK_IN_KHZ 165000
+ #define TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST 297000
+
+-static void set_stream_engine_in_use(
++static void update_stream_engine_usage(
+ struct resource_context *res_ctx,
+ const struct resource_pool *pool,
+- struct stream_encoder *stream_enc)
++ 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] = true;
++ res_ctx->is_stream_enc_acquired[i] = acquired;
+ }
+ }
+
+ /* TODO: release audio object */
+-static void set_audio_in_use(
++static void update_audio_usage(
+ struct resource_context *res_ctx,
+ const struct resource_pool *pool,
+- struct audio *audio)
++ struct audio *audio,
++ bool acquired)
+ {
+ int i;
+ for (i = 0; i < pool->audio_count; i++) {
+ if (pool->audios[i] == audio)
+- res_ctx->is_audio_acquired[i] = true;
++ res_ctx->is_audio_acquired[i] = acquired;
+ }
+ }
+
+@@ -1361,6 +1363,100 @@ bool resource_is_stream_unchanged(
+ return false;
+ }
+
++bool dc_add_stream_to_ctx(
++ struct dc *dc,
++ struct validate_context *new_ctx,
++ struct dc_stream_state *stream)
++{
++ struct dc_context *dc_ctx = dc->ctx;
++ enum dc_status res;
++
++ if (new_ctx->stream_count >= dc->res_pool->pipe_count) {
++ DC_ERROR("Max streams reached, can add stream %p !\n", stream);
++ return DC_ERROR_UNEXPECTED;
++ }
++
++ new_ctx->streams[new_ctx->stream_count] = stream;
++ dc_stream_retain(stream);
++ new_ctx->stream_count++;
++
++ res = dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream);
++ if (res != DC_OK)
++ DC_ERROR("Adding stream %p to context failed with err %d!\n", stream, res);
++
++ return res == DC_OK;
++}
++
++bool dc_remove_stream_from_ctx(
++ struct dc *dc,
++ struct validate_context *new_ctx,
++ struct dc_stream_state *stream)
++{
++ int i, j;
++ 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) */
++ for (i = 0; i < MAX_PIPES; i++) {
++ if (new_ctx->res_ctx.pipe_ctx[i].stream == stream) {
++ del_pipe = &new_ctx->res_ctx.pipe_ctx[i];
++
++ if (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 (del_pipe->stream_res.audio)
++ update_audio_usage(
++ &new_ctx->res_ctx,
++ dc->res_pool,
++ del_pipe->stream_res.audio,
++ false);
++
++ memset(del_pipe, 0, sizeof(*del_pipe));
++ }
++ }
++
++ if (!del_pipe) {
++ DC_ERROR("Pipe not found for stream %p !\n", stream);
++ return DC_ERROR_UNEXPECTED;
++ }
++
++ for (i = 0; i < new_ctx->stream_count; i++)
++ if (new_ctx->streams[i] == stream)
++ break;
++
++ if (new_ctx->streams[i] != stream) {
++ DC_ERROR("Context doesn't have stream %p !\n", stream);
++ return DC_ERROR_UNEXPECTED;
++ }
++
++ 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];
++ new_ctx->stream_status[i] = new_ctx->stream_status[i + 1];
++ }
++
++ new_ctx->streams[new_ctx->stream_count] = NULL;
++ memset(
++ &new_ctx->stream_status[new_ctx->stream_count],
++ 0,
++ sizeof(new_ctx->stream_status[0]));
++
++ return DC_OK;
++}
++
+ static void copy_pipe_ctx(
+ const struct pipe_ctx *from_pipe_ctx, struct pipe_ctx *to_pipe_ctx)
+ {
+@@ -1440,15 +1536,16 @@ static void calculate_phy_pix_clks(struct dc_stream_state *stream)
+ enum dc_status resource_map_pool_resources(
+ const struct dc *dc,
+ struct validate_context *context,
+- struct validate_context *old_context)
++ struct dc_stream_state *stream)
+ {
+ const struct resource_pool *pool = dc->res_pool;
+- int i, j;
+-
+- for (i = 0; old_context && i < context->stream_count; i++) {
+- struct dc_stream_state *stream = context->streams[i];
++ int i;
++ struct dc_context *dc_ctx = dc->ctx;
++ struct pipe_ctx *pipe_ctx = NULL;
++ int pipe_idx = -1;
+
+- if (!resource_is_stream_unchanged(old_context, stream)) {
++ /* TODO Check if this is needed */
++ /*if (!resource_is_stream_unchanged(old_context, stream)) {
+ if (stream != NULL && old_context->streams[i] != NULL) {
+ stream->bit_depth_params =
+ old_context->streams[i]->bit_depth_params;
+@@ -1456,119 +1553,228 @@ enum dc_status resource_map_pool_resources(
+ continue;
+ }
+ }
++ */
+
+- /* mark resources used for stream that is already active */
+- for (j = 0; j < pool->pipe_count; j++) {
+- struct pipe_ctx *pipe_ctx =
+- &context->res_ctx.pipe_ctx[j];
+- const struct pipe_ctx *old_pipe_ctx =
+- &old_context->res_ctx.pipe_ctx[j];
+-
+- if (!are_stream_backends_same(old_pipe_ctx->stream, stream))
+- continue;
++ /* acquire new resources */
++ pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream);
+
+- if (old_pipe_ctx->top_pipe)
+- continue;
++#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
++ if (pipe_idx < 0)
++ acquire_first_split_pipe(&context->res_ctx, pool, stream);
++#endif
++ if (pipe_idx < 0)
++ return DC_NO_CONTROLLER_RESOURCE;
++
++ pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
++
++ pipe_ctx->stream_res.stream_enc =
++ find_first_free_match_stream_enc_for_link(
++ &context->res_ctx, pool, stream);
++
++ if (!pipe_ctx->stream_res.stream_enc)
++ return DC_NO_STREAM_ENG_RESOURCE;
++
++ update_stream_engine_usage(
++ &context->res_ctx, pool,
++ pipe_ctx->stream_res.stream_enc,
++ true);
++
++ /* TODO: Add check if ASIC support and EDID audio */
++ if (!stream->sink->converter_disable_audio &&
++ dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&
++ stream->audio_info.mode_count) {
++ pipe_ctx->stream_res.audio = find_first_free_audio(
++ &context->res_ctx, pool);
++
++ /*
++ * Audio assigned in order first come first get.
++ * There are asics which has number of audio
++ * resources less then number of pipes
++ */
++ if (pipe_ctx->stream_res.audio)
++ update_audio_usage(&context->res_ctx, pool,
++ pipe_ctx->stream_res.audio, true);
++ }
+
+- pipe_ctx->stream = stream;
+- copy_pipe_ctx(old_pipe_ctx, pipe_ctx);
++ for (i = 0; i < context->stream_count; i++)
++ if (context->streams[i] == stream) {
++ context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst;
++ return DC_OK;
++ }
+
+- /* Split pipe resource, do not acquire back end */
+- if (!pipe_ctx->stream_res.stream_enc)
+- continue;
++ DC_ERROR("Stream %p not found in new ctx!\n", stream);
++ return DC_ERROR_UNEXPECTED;
++}
+
+- set_stream_engine_in_use(
+- &context->res_ctx, pool,
+- pipe_ctx->stream_res.stream_enc);
++/* first stream in the context is used to populate the rest */
++void validate_guaranteed_copy_streams(
++ struct validate_context *context,
++ int max_streams)
++{
++ int i;
+
+- /* Switch to dp clock source only if there is
+- * no non dp stream that shares the same timing
+- * with the dp stream.
+- */
+- if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
+- !find_pll_sharable_stream(stream, context))
+- pipe_ctx->clock_source = pool->dp_clock_source;
++ for (i = 1; i < max_streams; i++) {
++ context->streams[i] = context->streams[0];
+
+- resource_reference_clock_source(
+- &context->res_ctx, pool,
+- pipe_ctx->clock_source);
++ copy_pipe_ctx(&context->res_ctx.pipe_ctx[0],
++ &context->res_ctx.pipe_ctx[i]);
++ context->res_ctx.pipe_ctx[i].stream =
++ context->res_ctx.pipe_ctx[0].stream;
+
+- set_audio_in_use(&context->res_ctx, pool,
+- pipe_ctx->stream_res.audio);
+- }
++ dc_stream_retain(context->streams[i]);
++ context->stream_count++;
+ }
++}
+
+- for (i = 0; i < context->stream_count; i++) {
+- struct dc_stream_state *stream = context->streams[i];
+- struct pipe_ctx *pipe_ctx = NULL;
+- int pipe_idx = -1;
++void dc_resource_validate_ctx_copy_construct_current(
++ const struct dc *dc,
++ struct validate_context *dst_ctx)
++{
++ dc_resource_validate_ctx_copy_construct(dc->current_context, dst_ctx);
++}
+
+- if (old_context && resource_is_stream_unchanged(old_context, stream))
+- continue;
+- /* acquire new resources */
+- pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream);
+-#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
+- if (pipe_idx < 0)
+- acquire_first_split_pipe(&context->res_ctx, pool, stream);
+-#endif
+- if (pipe_idx < 0)
+- return DC_NO_CONTROLLER_RESOURCE;
++bool dc_validate_with_context(
++ struct dc *dc,
++ const struct dc_validation_set set[],
++ int set_count,
++ struct validate_context *context)
++{
++ int i, j;
++ enum dc_status res = DC_ERROR_UNEXPECTED;
++ bool found = false;
++ int old_stream_count = context->stream_count;
++ struct dc_stream_state *del_streams[MAX_PIPES] = { 0 };
++ struct dc_stream_state *add_streams[MAX_PIPES] = { 0 };
++ int del_streams_count = 0;
++ int add_streams_count = 0;
+
+- pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
+
+- pipe_ctx->stream_res.stream_enc =
+- find_first_free_match_stream_enc_for_link(
+- &context->res_ctx, pool, stream);
++ /* First remove from context all deleted streams */
++ for (i = 0; i < old_stream_count; i++) {
++ struct dc_stream_state *stream = context->streams[i];
++
++ for (j = 0; j < set_count; j++) {
++ if (stream == set[j].stream) {
++ found = true;
++ break;
++ }
++ }
+
+- if (!pipe_ctx->stream_res.stream_enc)
+- return DC_NO_STREAM_ENG_RESOURCE;
++ if (!found)
++ del_streams[del_streams_count++] = stream;
+
+- set_stream_engine_in_use(
+- &context->res_ctx, pool,
+- pipe_ctx->stream_res.stream_enc);
++ found = false;
++ }
+
+- /* TODO: Add check if ASIC support and EDID audio */
+- if (!stream->sink->converter_disable_audio &&
+- dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&
+- stream->audio_info.mode_count) {
+- pipe_ctx->stream_res.audio = find_first_free_audio(
+- &context->res_ctx, pool);
++ /* Now add new ones */
++ for (i = 0; i < set_count; i++) {
++ struct dc_stream_state *stream = set[i].stream;
+
+- /*
+- * Audio assigned in order first come first get.
+- * There are asics which has number of audio
+- * resources less then number of pipes
+- */
+- if (pipe_ctx->stream_res.audio)
+- set_audio_in_use(
+- &context->res_ctx, pool,
+- pipe_ctx->stream_res.audio);
++ for (j = 0; j < old_stream_count; j++) {
++ if (stream == context->streams[j]) {
++ found = true;
++ break;
++ }
+ }
+
+- context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst;
++ if (!found)
++ add_streams[add_streams_count++] = stream;
++
++ found = false;
+ }
+
+- return DC_OK;
++ for (i = 0; i < del_streams_count; i++)
++ if (!dc_remove_stream_from_ctx(dc, context, del_streams[i]))
++ goto fail;
++
++ for (i = 0; i < add_streams_count; i++)
++ if (!dc_add_stream_to_ctx(dc, context, add_streams[i]))
++ goto fail;
++
++ if (!dc_validate_global_state(dc, set, set_count, context))
++ goto fail;
++
++ res = DC_OK;
++
++fail:
++ if (res != DC_OK) {
++ dm_logger_write(dc->ctx->logger, LOG_WARNING,
++ "%s:resource validation failed, dc_status:%d\n",
++ __func__,
++ res);
++}
++ return res == DC_OK;
+ }
+
+-/* first stream in the context is used to populate the rest */
+-void validate_guaranteed_copy_streams(
+- struct validate_context *context,
+- int max_streams)
++bool dc_validate_global_state(
++ struct dc *dc,
++ const struct dc_validation_set set[],
++ int set_count,
++ struct validate_context *new_ctx)
+ {
+- int i;
++ 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;
+
+- for (i = 1; i < max_streams; i++) {
+- context->streams[i] = context->streams[0];
++ if (dc->res_pool->funcs->validate_global &&
++ dc->res_pool->funcs->validate_global(dc, set, set_count,
++ old_context, new_ctx) != DC_OK)
++ return false;
+
+- copy_pipe_ctx(&context->res_ctx.pipe_ctx[0],
+- &context->res_ctx.pipe_ctx[i]);
+- context->res_ctx.pipe_ctx[i].stream =
+- context->res_ctx.pipe_ctx[0].stream;
++ /* TODO without this SWDEV-114774 brakes */
++ for (i = 0; i < dc->res_pool->pipe_count; i++) {
++ struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[i];
+
+- dc_stream_retain(context->streams[i]);
+- context->stream_count++;
++ if (pipe_ctx->top_pipe)
++ memset(pipe_ctx, 0, sizeof(*pipe_ctx));
++ }
++
++ for (i = 0; new_ctx && i < new_ctx->stream_count; i++) {
++ struct dc_stream_state *stream = new_ctx->streams[i];
++
++ for (j = 0; j < dc->res_pool->pipe_count; j++) {
++ struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[j];
++
++ if (pipe_ctx->stream != stream)
++ continue;
++
++ /* Switch to dp clock source only if there is
++ * no non dp stream that shares the same timing
++ * with the dp stream.
++ */
++ if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
++ !find_pll_sharable_stream(stream, new_ctx)) {
++
++ resource_unreference_clock_source(
++ &new_ctx->res_ctx,
++ dc->res_pool,
++ &pipe_ctx->clock_source);
++ pipe_ctx->clock_source = dc->res_pool->dp_clock_source;
++ resource_reference_clock_source(
++ &new_ctx->res_ctx,
++ dc->res_pool,
++ pipe_ctx->clock_source);
++ }
++ }
++ }
++
++ /*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)
++ if (!dc->res_pool->funcs->validate_bandwidth(dc, new_ctx))
++ result = DC_FAIL_BANDWIDTH_VALIDATE;
++
++ return result;
+ }
+
+ static void patch_gamut_packet_checksum(
+@@ -2318,54 +2524,40 @@ void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
+ enum dc_status resource_map_clock_resources(
+ const struct dc *dc,
+ struct validate_context *context,
+- struct validate_context *old_context)
++ struct dc_stream_state *stream)
+ {
+- int i, j;
+- const struct resource_pool *pool = dc->res_pool;
+-
+ /* acquire new resources */
+- for (i = 0; i < context->stream_count; i++) {
+- struct dc_stream_state *stream = context->streams[i];
+-
+- if (old_context && resource_is_stream_unchanged(old_context, stream))
+- continue;
++ const struct resource_pool *pool = dc->res_pool;
++ struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(
++ &context->res_ctx, stream);
+
+- for (j = 0; j < MAX_PIPES; j++) {
+- struct pipe_ctx *pipe_ctx =
+- &context->res_ctx.pipe_ctx[j];
++ if (!pipe_ctx)
++ return DC_ERROR_UNEXPECTED;
+
+- if (context->res_ctx.pipe_ctx[j].stream != stream)
+- continue;
++ if (dc_is_dp_signal(pipe_ctx->stream->signal)
++ || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
++ pipe_ctx->clock_source = pool->dp_clock_source;
++ else {
++ pipe_ctx->clock_source = NULL;
+
+- if (dc_is_dp_signal(pipe_ctx->stream->signal)
+- || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
+- pipe_ctx->clock_source = pool->dp_clock_source;
+- else {
+- pipe_ctx->clock_source = NULL;
+-
+- if (!dc->config.disable_disp_pll_sharing)
+- resource_find_used_clk_src_for_sharing(
+- &context->res_ctx,
+- pipe_ctx);
+-
+- if (pipe_ctx->clock_source == NULL)
+- pipe_ctx->clock_source =
+- dc_resource_find_first_free_pll(
+- &context->res_ctx,
+- pool);
+- }
++ if (!dc->config.disable_disp_pll_sharing)
++ resource_find_used_clk_src_for_sharing(
++ &context->res_ctx,
++ pipe_ctx);
+
+- if (pipe_ctx->clock_source == NULL)
+- return DC_NO_CLOCK_SOURCE_RESOURCE;
++ if (pipe_ctx->clock_source == NULL)
++ pipe_ctx->clock_source =
++ dc_resource_find_first_free_pll(
++ &context->res_ctx,
++ pool);
++ }
+
+- resource_reference_clock_source(
+- &context->res_ctx, pool,
+- pipe_ctx->clock_source);
++ if (pipe_ctx->clock_source == NULL)
++ return DC_NO_CLOCK_SOURCE_RESOURCE;
+
+- /* only one cs per stream regardless of mpo */
+- break;
+- }
+- }
++ resource_reference_clock_source(
++ &context->res_ctx, pool,
++ pipe_ctx->clock_source);
+
+ return DC_OK;
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
+index 8a27d52..384c72c 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc.h
++++ b/drivers/gpu/drm/amd/display/dc/dc.h
+@@ -634,6 +634,16 @@ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream,
+ uint32_t *h_position,
+ uint32_t *v_position);
+
++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);
++
+ /*
+ * Structure to store surface/stream associations for validation
+ */
+@@ -646,16 +656,18 @@ struct dc_validation_set {
+ bool dc_validate_stream(struct dc *dc, struct dc_stream_state *stream);
+
+ bool dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state);
+-/*
+- * This function takes a set of resources and checks that they are cofunctional.
+- *
+- * After this call:
+- * No hardware is programmed for call. Only validation is done.
+- */
+-struct validate_context *dc_get_validate_context(
++
++bool dc_validate_with_context(
+ struct dc *dc,
+ const struct dc_validation_set set[],
+- uint8_t set_count);
++ int set_count,
++ struct validate_context *context);
++
++bool dc_validate_global_state(
++ struct dc *dc,
++ const struct dc_validation_set set[],
++ int set_count,
++ struct validate_context *new_ctx);
+
+ bool dc_validate_resources(
+ struct dc *dc,
+@@ -678,6 +690,10 @@ void dc_resource_validate_ctx_copy_construct(
+ const struct validate_context *src_ctx,
+ struct validate_context *dst_ctx);
+
++void dc_resource_validate_ctx_copy_construct_current(
++ const struct dc *dc,
++ struct validate_context *dst_ctx);
++
+ void dc_resource_validate_ctx_destruct(struct validate_context *context);
+
+ /*
+diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
+index b2b0363..c9dad4e 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
+@@ -654,35 +654,20 @@ static void destruct(struct dce110_resource_pool *pool)
+ static enum dc_status build_mapped_resource(
+ const struct dc *dc,
+ struct validate_context *context,
+- struct validate_context *old_context)
++ struct dc_stream_state *stream)
+ {
+ enum dc_status status = DC_OK;
+- uint8_t i, j;
++ struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
+
+- for (i = 0; i < context->stream_count; i++) {
+- struct dc_stream_state *stream = context->streams[i];
++ if (!pipe_ctx)
++ return DC_ERROR_UNEXPECTED;
+
+- if (old_context && resource_is_stream_unchanged(old_context, stream))
+- continue;
+-
+- for (j = 0; j < MAX_PIPES; j++) {
+- struct pipe_ctx *pipe_ctx =
+- &context->res_ctx.pipe_ctx[j];
+-
+- if (context->res_ctx.pipe_ctx[j].stream != stream)
+- continue;
+-
+- status = dce110_resource_build_pipe_hw_param(pipe_ctx);
++ status = dce110_resource_build_pipe_hw_param(pipe_ctx);
+
+- if (status != DC_OK)
+- return status;
++ if (status != DC_OK)
++ return status;
+
+- resource_build_info_frame(pipe_ctx);
+-
+- /* do not need to validate non root pipes */
+- break;
+- }
+- }
++ resource_build_info_frame(pipe_ctx);
+
+ return DC_OK;
+ }
+@@ -719,48 +704,17 @@ static bool dce100_validate_surface_sets(
+ return true;
+ }
+
+-enum dc_status dce100_validate_with_context(
++enum dc_status dce100_validate_global(
+ struct dc *dc,
+ const struct dc_validation_set set[],
+ int set_count,
+- struct validate_context *context,
+- struct validate_context *old_context)
++ struct validate_context *old_context,
++ struct validate_context *context)
+ {
+- struct dc_context *dc_ctx = dc->ctx;
+- enum dc_status result = DC_ERROR_UNEXPECTED;
+- int i;
+-
+ if (!dce100_validate_surface_sets(set, set_count))
+ return DC_FAIL_SURFACE_VALIDATE;
+
+- for (i = 0; i < set_count; i++) {
+- context->streams[i] = set[i].stream;
+- dc_stream_retain(context->streams[i]);
+- context->stream_count++;
+- }
+-
+- result = resource_map_pool_resources(dc, context, old_context);
+-
+- if (result == DC_OK)
+- result = resource_map_clock_resources(dc, context, old_context);
+-
+- if (!resource_validate_attach_surfaces(set, set_count,
+- old_context, context, dc->res_pool)) {
+- DC_ERROR("Failed to attach surface to stream!\n");
+- return DC_FAIL_ATTACH_SURFACES;
+- }
+-
+- if (result == DC_OK)
+- result = build_mapped_resource(dc, context, old_context);
+-
+- if (result == DC_OK)
+- result = resource_build_scaling_params_for_context(dc, context);
+-
+- if (result == DC_OK)
+- if (!dce100_validate_bandwidth(dc, context))
+- result = DC_FAIL_BANDWIDTH_VALIDATE;
+-
+- return result;
++ return DC_OK;
+ }
+
+ enum dc_status dce100_validate_guaranteed(
+@@ -774,13 +728,13 @@ enum dc_status dce100_validate_guaranteed(
+ dc_stream_retain(context->streams[0]);
+ context->stream_count++;
+
+- result = resource_map_pool_resources(dc, context, NULL);
++ result = resource_map_pool_resources(dc, context, dc_stream);
+
+ if (result == DC_OK)
+- result = resource_map_clock_resources(dc, context, NULL);
++ result = resource_map_clock_resources(dc, context, dc_stream);
+
+ if (result == DC_OK)
+- result = build_mapped_resource(dc, context, NULL);
++ result = build_mapped_resource(dc, context, dc_stream);
+
+ if (result == DC_OK) {
+ validate_guaranteed_copy_streams(
+@@ -816,10 +770,10 @@ enum dc_status dce100_validate_plane(const struct dc_plane_state *plane_state)
+ static const struct resource_funcs dce100_res_pool_funcs = {
+ .destroy = dce100_destroy_resource_pool,
+ .link_enc_create = dce100_link_encoder_create,
+- .validate_with_context = dce100_validate_with_context,
+ .validate_guaranteed = dce100_validate_guaranteed,
+ .validate_bandwidth = dce100_validate_bandwidth,
+ .validate_plane = dce100_validate_plane,
++ .validate_global = dce100_validate_global
+ };
+
+ static bool construct(
+diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
+index 2154c2e..d682180 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
+@@ -774,41 +774,26 @@ static bool is_surface_pixel_format_supported(struct pipe_ctx *pipe_ctx, unsigne
+ static enum dc_status build_mapped_resource(
+ const struct dc *dc,
+ struct validate_context *context,
+- struct validate_context *old_context)
++ struct dc_stream_state *stream)
+ {
+ enum dc_status status = DC_OK;
+- uint8_t i, j;
+-
+- for (i = 0; i < context->stream_count; i++) {
+- struct dc_stream_state *stream = context->streams[i];
+-
+- if (old_context && resource_is_stream_unchanged(old_context, stream))
+- continue;
++ struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
+
+- for (j = 0; j < MAX_PIPES; j++) {
+- struct pipe_ctx *pipe_ctx =
+- &context->res_ctx.pipe_ctx[j];
++ if (!pipe_ctx)
++ return DC_ERROR_UNEXPECTED;
+
+- if (context->res_ctx.pipe_ctx[j].stream != stream)
+- continue;
++ if (!is_surface_pixel_format_supported(pipe_ctx,
++ dc->res_pool->underlay_pipe_index))
++ return DC_SURFACE_PIXEL_FORMAT_UNSUPPORTED;
+
+- if (!is_surface_pixel_format_supported(pipe_ctx,
+- dc->res_pool->underlay_pipe_index))
+- return DC_SURFACE_PIXEL_FORMAT_UNSUPPORTED;
++ status = dce110_resource_build_pipe_hw_param(pipe_ctx);
+
+- status = dce110_resource_build_pipe_hw_param(pipe_ctx);
++ if (status != DC_OK)
++ return status;
+
+- if (status != DC_OK)
+- return status;
++ /* TODO: validate audio ASIC caps, encoder */
+
+- /* TODO: validate audio ASIC caps, encoder */
+-
+- resource_build_info_frame(pipe_ctx);
+-
+- /* do not need to validate non root pipes */
+- break;
+- }
+- }
++ resource_build_info_frame(pipe_ctx);
+
+ return DC_OK;
+ }
+@@ -927,48 +912,17 @@ static bool dce110_validate_surface_sets(
+ return true;
+ }
+
+-static enum dc_status dce110_validate_with_context(
++enum dc_status dce110_validate_global(
+ struct dc *dc,
+ const struct dc_validation_set set[],
+ int set_count,
+- struct validate_context *context,
+- struct validate_context *old_context)
++ struct validate_context *old_context,
++ struct validate_context *context)
+ {
+- struct dc_context *dc_ctx = dc->ctx;
+- enum dc_status result = DC_ERROR_UNEXPECTED;
+- int i;
+-
+ if (!dce110_validate_surface_sets(set, set_count))
+ return DC_FAIL_SURFACE_VALIDATE;
+
+- for (i = 0; i < set_count; i++) {
+- context->streams[i] = set[i].stream;
+- dc_stream_retain(context->streams[i]);
+- context->stream_count++;
+- }
+-
+- result = resource_map_pool_resources(dc, context, old_context);
+-
+- if (result == DC_OK)
+- result = resource_map_clock_resources(dc, context, old_context);
+-
+- if (!resource_validate_attach_surfaces(set, set_count,
+- old_context, context, dc->res_pool)) {
+- DC_ERROR("Failed to attach surface to stream!\n");
+- return DC_FAIL_ATTACH_SURFACES;
+- }
+-
+- if (result == DC_OK)
+- result = build_mapped_resource(dc, context, old_context);
+-
+- if (result == DC_OK)
+- result = resource_build_scaling_params_for_context(dc, context);
+-
+- if (result == DC_OK)
+- if (!dce110_validate_bandwidth(dc, context))
+- result = DC_FAIL_BANDWIDTH_VALIDATE;
+-
+- return result;
++ return DC_OK;
+ }
+
+ static enum dc_status dce110_validate_guaranteed(
+@@ -982,13 +936,13 @@ static enum dc_status dce110_validate_guaranteed(
+ dc_stream_retain(context->streams[0]);
+ context->stream_count++;
+
+- result = resource_map_pool_resources(dc, context, NULL);
++ result = resource_map_pool_resources(dc, context, dc_stream);
+
+ if (result == DC_OK)
+- result = resource_map_clock_resources(dc, context, NULL);
++ result = resource_map_clock_resources(dc, context, dc_stream);
+
+ if (result == DC_OK)
+- result = build_mapped_resource(dc, context, NULL);
++ result = build_mapped_resource(dc, context, dc_stream);
+
+ if (result == DC_OK) {
+ validate_guaranteed_copy_streams(
+@@ -1078,10 +1032,10 @@ static void dce110_destroy_resource_pool(struct resource_pool **pool)
+ static const struct resource_funcs dce110_res_pool_funcs = {
+ .destroy = dce110_destroy_resource_pool,
+ .link_enc_create = dce110_link_encoder_create,
+- .validate_with_context = dce110_validate_with_context,
+ .validate_guaranteed = dce110_validate_guaranteed,
+ .validate_bandwidth = dce110_validate_bandwidth,
+ .acquire_idle_pipe_for_layer = dce110_acquire_underlay,
++ .validate_global = dce110_validate_global
+ };
+
+ static bool underlay_create(struct dc_context *ctx, struct resource_pool *pool)
+diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
+index 89a8dfa..85a396e 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
+@@ -725,35 +725,20 @@ static struct clock_source *find_matching_pll(
+ static enum dc_status build_mapped_resource(
+ const struct dc *dc,
+ struct validate_context *context,
+- struct validate_context *old_context)
++ struct dc_stream_state *stream)
+ {
+ enum dc_status status = DC_OK;
+- uint8_t i, j;
++ struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
+
+- for (i = 0; i < context->stream_count; i++) {
+- struct dc_stream_state *stream = context->streams[i];
++ if (!pipe_ctx)
++ return DC_ERROR_UNEXPECTED;
+
+- if (old_context && resource_is_stream_unchanged(old_context, stream))
+- continue;
+-
+- for (j = 0; j < MAX_PIPES; j++) {
+- struct pipe_ctx *pipe_ctx =
+- &context->res_ctx.pipe_ctx[j];
+-
+- if (context->res_ctx.pipe_ctx[j].stream != stream)
+- continue;
++ status = dce110_resource_build_pipe_hw_param(pipe_ctx);
+
+- status = dce110_resource_build_pipe_hw_param(pipe_ctx);
++ if (status != DC_OK)
++ return status;
+
+- if (status != DC_OK)
+- return status;
+-
+- resource_build_info_frame(pipe_ctx);
+-
+- /* do not need to validate non root pipes */
+- break;
+- }
+- }
++ resource_build_info_frame(pipe_ctx);
+
+ return DC_OK;
+ }
+@@ -839,45 +824,32 @@ bool dce112_validate_bandwidth(
+ enum dc_status resource_map_phy_clock_resources(
+ const struct dc *dc,
+ struct validate_context *context,
+- struct validate_context *old_context)
++ struct dc_stream_state *stream)
+ {
+- uint8_t i, j;
+
+ /* acquire new resources */
+- for (i = 0; i < context->stream_count; i++) {
+- struct dc_stream_state *stream = context->streams[i];
+-
+- if (old_context && resource_is_stream_unchanged(old_context, stream))
+- continue;
+-
+- for (j = 0; j < MAX_PIPES; j++) {
+- struct pipe_ctx *pipe_ctx =
+- &context->res_ctx.pipe_ctx[j];
+-
+- if (context->res_ctx.pipe_ctx[j].stream != stream)
+- continue;
++ struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(
++ &context->res_ctx, stream);
+
+- if (dc_is_dp_signal(pipe_ctx->stream->signal)
+- || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
+- pipe_ctx->clock_source =
+- dc->res_pool->dp_clock_source;
+- else
+- pipe_ctx->clock_source = find_matching_pll(
+- &context->res_ctx, dc->res_pool,
+- stream);
++ if (!pipe_ctx)
++ return DC_ERROR_UNEXPECTED;
+
+- if (pipe_ctx->clock_source == NULL)
+- return DC_NO_CLOCK_SOURCE_RESOURCE;
++ if (dc_is_dp_signal(pipe_ctx->stream->signal)
++ || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
++ pipe_ctx->clock_source =
++ dc->res_pool->dp_clock_source;
++ else
++ pipe_ctx->clock_source = find_matching_pll(
++ &context->res_ctx, dc->res_pool,
++ stream);
+
+- resource_reference_clock_source(
+- &context->res_ctx,
+- dc->res_pool,
+- pipe_ctx->clock_source);
++ if (pipe_ctx->clock_source == NULL)
++ return DC_NO_CLOCK_SOURCE_RESOURCE;
+
+- /* only one cs per stream regardless of mpo */
+- break;
+- }
+- }
++ resource_reference_clock_source(
++ &context->res_ctx,
++ dc->res_pool,
++ pipe_ctx->clock_source);
+
+ return DC_OK;
+ }
+@@ -903,46 +875,21 @@ static bool dce112_validate_surface_sets(
+ return true;
+ }
+
+-enum dc_status dce112_validate_with_context(
++enum dc_status dce112_add_stream_to_ctx(
+ struct dc *dc,
+- const struct dc_validation_set set[],
+- int set_count,
+- struct validate_context *context,
+- struct validate_context *old_context)
++ struct validate_context *new_ctx,
++ struct dc_stream_state *dc_stream)
+ {
+- struct dc_context *dc_ctx = dc->ctx;
+ enum dc_status result = DC_ERROR_UNEXPECTED;
+- int i;
+
+- if (!dce112_validate_surface_sets(set, set_count))
+- return DC_FAIL_SURFACE_VALIDATE;
+-
+- for (i = 0; i < set_count; i++) {
+- context->streams[i] = set[i].stream;
+- dc_stream_retain(context->streams[i]);
+- context->stream_count++;
+- }
+-
+- result = resource_map_pool_resources(dc, context, old_context);
++ result = resource_map_pool_resources(dc, new_ctx, dc_stream);
+
+ if (result == DC_OK)
+- result = resource_map_phy_clock_resources(dc, context, old_context);
+-
+- if (!resource_validate_attach_surfaces(set, set_count,
+- old_context, context, dc->res_pool)) {
+- DC_ERROR("Failed to attach surface to stream!\n");
+- return DC_FAIL_ATTACH_SURFACES;
+- }
++ result = resource_map_phy_clock_resources(dc, new_ctx, dc_stream);
+
+- if (result == DC_OK)
+- result = build_mapped_resource(dc, context, old_context);
+
+ if (result == DC_OK)
+- result = resource_build_scaling_params_for_context(dc, context);
+-
+- if (result == DC_OK)
+- if (!dce112_validate_bandwidth(dc, context))
+- result = DC_FAIL_BANDWIDTH_VALIDATE;
++ result = build_mapped_resource(dc, new_ctx, dc_stream);
+
+ return result;
+ }
+@@ -958,13 +905,13 @@ enum dc_status dce112_validate_guaranteed(
+ dc_stream_retain(context->streams[0]);
+ context->stream_count++;
+
+- result = resource_map_pool_resources(dc, context, NULL);
++ result = resource_map_pool_resources(dc, context, stream);
+
+ if (result == DC_OK)
+- result = resource_map_phy_clock_resources(dc, context, NULL);
++ result = resource_map_phy_clock_resources(dc, context, stream);
+
+ if (result == DC_OK)
+- result = build_mapped_resource(dc, context, NULL);
++ result = build_mapped_resource(dc, context, stream);
+
+ if (result == DC_OK) {
+ validate_guaranteed_copy_streams(
+@@ -979,6 +926,19 @@ enum dc_status dce112_validate_guaranteed(
+ return result;
+ }
+
++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))
++ return DC_FAIL_SURFACE_VALIDATE;
++
++ return DC_OK;
++}
++
+ static void dce112_destroy_resource_pool(struct resource_pool **pool)
+ {
+ struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool);
+@@ -991,10 +951,11 @@ static void dce112_destroy_resource_pool(struct resource_pool **pool)
+ static const struct resource_funcs dce112_res_pool_funcs = {
+ .destroy = dce112_destroy_resource_pool,
+ .link_enc_create = dce112_link_encoder_create,
+- .validate_with_context = dce112_validate_with_context,
+ .validate_guaranteed = dce112_validate_guaranteed,
+ .validate_bandwidth = dce112_validate_bandwidth,
+- .validate_plane = dce100_validate_plane
++ .validate_plane = dce100_validate_plane,
++ .add_stream_to_ctx = dce112_add_stream_to_ctx,
++ .validate_global = dce112_validate_global
+ };
+
+ static void bw_calcs_data_update_from_pplib(struct dc *dc)
+diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.h b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.h
+index 69f8f68..f1834bf 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.h
++++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.h
+@@ -51,6 +51,11 @@ bool dce112_validate_bandwidth(
+ struct dc *dc,
+ struct validate_context *context);
+
++enum dc_status dce112_add_stream_to_ctx(
++ struct dc *dc,
++ struct validate_context *new_ctx,
++ struct dc_stream_state *dc_stream);
++
+
+ #endif /* __DC_RESOURCE_DCE112_H__ */
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
+index b8fcdff..e5d2d98 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
+@@ -698,10 +698,10 @@ static void dce120_destroy_resource_pool(struct resource_pool **pool)
+ static const struct resource_funcs dce120_res_pool_funcs = {
+ .destroy = dce120_destroy_resource_pool,
+ .link_enc_create = dce120_link_encoder_create,
+- .validate_with_context = dce112_validate_with_context,
+ .validate_guaranteed = dce112_validate_guaranteed,
+ .validate_bandwidth = dce112_validate_bandwidth,
+- .validate_plane = dce100_validate_plane
++ .validate_plane = dce100_validate_plane,
++ .add_stream_to_ctx = dce112_add_stream_to_ctx
+ };
+
+ static void bw_calcs_data_update_from_pplib(struct dc *dc)
+diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
+index 838bfda..ac3f42a 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
+@@ -686,35 +686,20 @@ static void destruct(struct dce110_resource_pool *pool)
+ static enum dc_status build_mapped_resource(
+ const struct dc *dc,
+ struct validate_context *context,
+- struct validate_context *old_context)
++ struct dc_stream_state *stream)
+ {
+ enum dc_status status = DC_OK;
+- uint8_t i, j;
++ struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
+
+- for (i = 0; i < context->stream_count; i++) {
+- struct dc_stream_state *stream = context->streams[i];
++ if (!pipe_ctx)
++ return DC_ERROR_UNEXPECTED;
+
+- if (old_context && resource_is_stream_unchanged(old_context, stream))
+- continue;
+-
+- for (j = 0; j < MAX_PIPES; j++) {
+- struct pipe_ctx *pipe_ctx =
+- &context->res_ctx.pipe_ctx[j];
+-
+- if (context->res_ctx.pipe_ctx[j].stream != stream)
+- continue;
+-
+- status = dce110_resource_build_pipe_hw_param(pipe_ctx);
++ status = dce110_resource_build_pipe_hw_param(pipe_ctx);
+
+- if (status != DC_OK)
+- return status;
++ if (status != DC_OK)
++ return status;
+
+- resource_build_info_frame(pipe_ctx);
+-
+- /* do not need to validate non root pipes */
+- break;
+- }
+- }
++ resource_build_info_frame(pipe_ctx);
+
+ return DC_OK;
+ }
+@@ -751,47 +736,17 @@ static bool dce80_validate_surface_sets(
+ return true;
+ }
+
+-enum dc_status dce80_validate_with_context(
++enum dc_status dce80_validate_global(
+ struct dc *dc,
+ const struct dc_validation_set set[],
+ int set_count,
+- struct validate_context *context,
+- struct validate_context *old_context)
++ struct validate_context *old_context,
++ struct validate_context *context)
+ {
+- struct dc_context *dc_ctx = dc->ctx;
+- enum dc_status result = DC_ERROR_UNEXPECTED;
+- int i;
+-
+ if (!dce80_validate_surface_sets(set, set_count))
+ return DC_FAIL_SURFACE_VALIDATE;
+
+- for (i = 0; i < set_count; i++) {
+- context->streams[i] = set[i].stream;
+- dc_stream_retain(context->streams[i]);
+- context->stream_count++;
+- }
+-
+- result = resource_map_pool_resources(dc, context, old_context);
+-
+- if (result == DC_OK)
+- result = resource_map_clock_resources(dc, context, old_context);
+-
+- if (!resource_validate_attach_surfaces(set, set_count,
+- old_context, context, dc->res_pool)) {
+- DC_ERROR("Failed to attach surface to stream!\n");
+- return DC_FAIL_ATTACH_SURFACES;
+- }
+-
+- if (result == DC_OK)
+- result = build_mapped_resource(dc, context, old_context);
+-
+- if (result == DC_OK)
+- result = resource_build_scaling_params_for_context(dc, context);
+-
+- if (result == DC_OK)
+- result = dce80_validate_bandwidth(dc, context);
+-
+- return result;
++ return DC_OK;
+ }
+
+ enum dc_status dce80_validate_guaranteed(
+@@ -805,13 +760,13 @@ enum dc_status dce80_validate_guaranteed(
+ dc_stream_retain(context->streams[0]);
+ context->stream_count++;
+
+- result = resource_map_pool_resources(dc, context, NULL);
++ result = resource_map_pool_resources(dc, context, dc_stream);
+
+ if (result == DC_OK)
+- result = resource_map_clock_resources(dc, context, NULL);
++ result = resource_map_clock_resources(dc, context, dc_stream);
+
+ if (result == DC_OK)
+- result = build_mapped_resource(dc, context, NULL);
++ result = build_mapped_resource(dc, context, dc_stream);
+
+ if (result == DC_OK) {
+ validate_guaranteed_copy_streams(
+@@ -837,10 +792,10 @@ static void dce80_destroy_resource_pool(struct resource_pool **pool)
+ static const struct resource_funcs dce80_res_pool_funcs = {
+ .destroy = dce80_destroy_resource_pool,
+ .link_enc_create = dce80_link_encoder_create,
+- .validate_with_context = dce80_validate_with_context,
+ .validate_guaranteed = dce80_validate_guaranteed,
+ .validate_bandwidth = dce80_validate_bandwidth,
+- .validate_plane = dce100_validate_plane
++ .validate_plane = dce100_validate_plane,
++ .validate_global = dce80_validate_global
+ };
+
+ static bool dce80_construct(
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
+index 954c234..ee43cbc 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
+@@ -48,6 +48,7 @@
+ #include "dce/dce_hwseq.h"
+ #include "../virtual/virtual_stream_encoder.h"
+ #include "dce110/dce110_resource.h"
++#include "dce112/dce112_resource.h"
+
+ #include "vega10/soc15ip.h"
+
+@@ -840,17 +841,15 @@ static enum dc_status build_pipe_hw_param(struct pipe_ctx *pipe_ctx)
+ static enum dc_status build_mapped_resource(
+ const struct dc *dc,
+ struct validate_context *context,
+- struct validate_context *old_context)
++ struct dc_stream_state *stream)
+ {
+ enum dc_status status = DC_OK;
+- uint8_t i, j;
+-
+- for (i = 0; i < context->stream_count; i++) {
+- struct dc_stream_state *stream = context->streams[i];
++ struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
+
+- if (old_context && resource_is_stream_unchanged(old_context, stream)) {
++ /*TODO Seems unneeded anymore */
++ /* if (old_context && resource_is_stream_unchanged(old_context, stream)) {
+ if (stream != NULL && old_context->streams[i] != NULL) {
+- /* todo: shouldn't have to copy missing parameter here */
++ todo: shouldn't have to copy missing parameter here
+ resource_build_bit_depth_reduction_params(stream,
+ &stream->bit_depth_params);
+ stream->clamping.pixel_encoding =
+@@ -863,68 +862,34 @@ static enum dc_status build_mapped_resource(
+ continue;
+ }
+ }
++ */
+
+- for (j = 0; j < dc->res_pool->pipe_count ; j++) {
+- struct pipe_ctx *pipe_ctx =
+- &context->res_ctx.pipe_ctx[j];
++ if (!pipe_ctx)
++ return DC_ERROR_UNEXPECTED;
+
+- if (context->res_ctx.pipe_ctx[j].stream != stream)
+- continue;
++ status = build_pipe_hw_param(pipe_ctx);
+
+- status = build_pipe_hw_param(pipe_ctx);
+-
+- if (status != DC_OK)
+- return status;
+-
+- /* do not need to validate non root pipes */
+- break;
+- }
+- }
++ if (status != DC_OK)
++ return status;
+
+ return DC_OK;
+ }
+
+-enum dc_status dcn10_validate_with_context(
++enum dc_status dcn10_add_stream_to_ctx(
+ struct dc *dc,
+- const struct dc_validation_set set[],
+- int set_count,
+- struct validate_context *context,
+- struct validate_context *old_context)
++ struct validate_context *new_ctx,
++ struct dc_stream_state *dc_stream)
+ {
+- enum dc_status result = DC_OK;
+- int i;
+-
+- if (set_count == 0)
+- return result;
+-
+- for (i = 0; i < set_count; i++) {
+- context->streams[i] = set[i].stream;
+- dc_stream_retain(context->streams[i]);
+- context->stream_count++;
+- }
+-
+- result = resource_map_pool_resources(dc, context, old_context);
+- if (result != DC_OK)
+- return result;
+-
+- result = resource_map_phy_clock_resources(dc, context, old_context);
+- if (result != DC_OK)
+- return result;
++ enum dc_status result = DC_ERROR_UNEXPECTED;
+
+- result = build_mapped_resource(dc, context, old_context);
+- if (result != DC_OK)
+- return result;
++ result = resource_map_pool_resources(dc, new_ctx, dc_stream);
+
+- if (!resource_validate_attach_surfaces(set, set_count,
+- old_context, context, dc->res_pool))
+- return DC_FAIL_ATTACH_SURFACES;
++ if (result == DC_OK)
++ result = resource_map_phy_clock_resources(dc, new_ctx, dc_stream);
+
+- result = resource_build_scaling_params_for_context(dc, context);
+- if (result != DC_OK)
+- return result;
+
+- if (!dcn_validate_bandwidth(dc, context))
+- return DC_FAIL_BANDWIDTH_VALIDATE;
++ if (result == DC_OK)
++ result = build_mapped_resource(dc, new_ctx, dc_stream);
+
+ return result;
+ }
+@@ -940,13 +905,13 @@ enum dc_status dcn10_validate_guaranteed(
+ dc_stream_retain(context->streams[0]);
+ context->stream_count++;
+
+- result = resource_map_pool_resources(dc, context, NULL);
++ result = resource_map_pool_resources(dc, context, dc_stream);
+
+ if (result == DC_OK)
+- result = resource_map_phy_clock_resources(dc, context, NULL);
++ result = resource_map_phy_clock_resources(dc, context, dc_stream);
+
+ if (result == DC_OK)
+- result = build_mapped_resource(dc, context, NULL);
++ result = build_mapped_resource(dc, context, dc_stream);
+
+ if (result == DC_OK) {
+ validate_guaranteed_copy_streams(
+@@ -1226,10 +1191,10 @@ static struct dc_cap_funcs cap_funcs = {
+ static struct resource_funcs dcn10_res_pool_funcs = {
+ .destroy = dcn10_destroy_resource_pool,
+ .link_enc_create = dcn10_link_encoder_create,
+- .validate_with_context = dcn10_validate_with_context,
+ .validate_guaranteed = dcn10_validate_guaranteed,
+ .validate_bandwidth = dcn_validate_bandwidth,
+ .acquire_idle_pipe_for_layer = dcn10_acquire_idle_pipe_for_layer,
++ .add_stream_to_ctx = dcn10_add_stream_to_ctx
+ };
+
+ static bool construct(
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+index a3f0039..9a32390 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+@@ -87,12 +87,6 @@ struct resource_funcs {
+ void (*destroy)(struct resource_pool **pool);
+ struct link_encoder *(*link_enc_create)(
+ const struct encoder_init_data *init);
+- enum dc_status (*validate_with_context)(
+- struct dc *dc,
+- const struct dc_validation_set set[],
+- int set_count,
+- struct validate_context *context,
+- struct validate_context *old_context);
+
+ enum dc_status (*validate_guaranteed)(
+ struct dc *dc,
+@@ -103,11 +97,24 @@ struct resource_funcs {
+ struct dc *dc,
+ struct validate_context *context);
+
++ 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)(
+ struct validate_context *context,
+ const struct resource_pool *pool,
+ struct dc_stream_state *stream);
++
+ enum dc_status (*validate_plane)(const struct dc_plane_state *plane_state);
++
++ enum dc_status (*add_stream_to_ctx)(
++ struct dc *dc,
++ struct validate_context *new_ctx,
++ struct dc_stream_state *dc_stream);
+ };
+
+ struct audio_support{
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
+index 9085ec7..ebc0f5b 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
+@@ -82,7 +82,7 @@ void dc_destroy_resource_pool(struct dc *dc);
+ enum dc_status resource_map_pool_resources(
+ const struct dc *dc,
+ struct validate_context *context,
+- struct validate_context *old_context);
++ struct dc_stream_state *stream);
+
+ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx);
+
+@@ -150,12 +150,12 @@ void resource_validate_ctx_update_pointer_after_copy(
+ enum dc_status resource_map_clock_resources(
+ const struct dc *dc,
+ struct validate_context *context,
+- struct validate_context *old_context);
++ struct dc_stream_state *stream);
+
+ enum dc_status resource_map_phy_clock_resources(
+ const struct dc *dc,
+ struct validate_context *context,
+- struct validate_context *old_context);
++ struct dc_stream_state *stream);
+
+ bool pipe_need_reprogram(
+ struct pipe_ctx *pipe_ctx_old,
+--
+2.7.4
+