diff options
Diffstat (limited to 'meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0978-drm-amd-display-Per-stream-validate_context-build-v2.patch')
-rw-r--r-- | meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0978-drm-amd-display-Per-stream-validate_context-build-v2.patch | 1841 |
1 files changed, 1841 insertions, 0 deletions
diff --git a/meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0978-drm-amd-display-Per-stream-validate_context-build-v2.patch b/meta-v1000/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/meta-v1000/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 + |