On 2022-10-11 14:11, Rodrigo Siqueira wrote: > Since DCN32, our DC commit become more complex and requires more > adjustments to work well with some features. This is a preparation work > for replacing dc_commit_state and dc_commit_updates_for_stream with > dc_update_planes_and_stream and dc_update_planes_and_stream I think you mean "dc_commit_streams and dc_update_planes_and_stream" Harry > respectively. > > Cc: Nicholas Kazlauskas <nicholas.kazlauskas@xxxxxxx> > Cc: Harry Wentland <harry.wentland@xxxxxxx> > Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@xxxxxxx> > Co-developed-by: Aurabindo Pillai <aurabindo.pillai@xxxxxxx> > Signed-off-by: Aurabindo Pillai <aurabindo.pillai@xxxxxxx> > --- > drivers/gpu/drm/amd/display/dc/core/dc.c | 92 ++++++++ > .../gpu/drm/amd/display/dc/core/dc_resource.c | 204 +++++++++++++++++- > drivers/gpu/drm/amd/display/dc/dc.h | 6 + > drivers/gpu/drm/amd/display/dc/dc_stream.h | 11 +- > 4 files changed, 308 insertions(+), 5 deletions(-) > > diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c > index 660316a536f7..ad3aafb73cba 100644 > --- a/drivers/gpu/drm/amd/display/dc/core/dc.c > +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c > @@ -59,6 +59,7 @@ > > #include "dc_link_dp.h" > #include "dc_dmub_srv.h" > +#include "dc_stream.h" > > #include "dsc.h" > > @@ -1505,6 +1506,25 @@ static bool context_changed( > return false; > } > > +static bool streams_changed(struct dc *dc, > + struct dc_stream_state *streams[], > + uint8_t stream_count) > +{ > + uint8_t i; > + > + if (stream_count != dc->current_state->stream_count) > + return true; > + > + for (i = 0; i < dc->current_state->stream_count; i++) { > + if (dc->current_state->streams[i] != streams[i]) > + return true; > + if (!streams[i]->link->link_state_valid) > + return true; > + } > + > + return false; > +} > + > bool dc_validate_boot_timing(const struct dc *dc, > const struct dc_sink *sink, > struct dc_crtc_timing *crtc_timing) > @@ -1923,6 +1943,78 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context) > return (result == DC_OK); > } > > +enum dc_status dc_commit_streams(struct dc *dc, > + struct dc_stream_state *streams[], > + uint8_t stream_count) > +{ > + int i, j; > + struct dc_state *context; > + enum dc_status res = DC_OK; > + struct dc_validation_set set[MAX_STREAMS] = {0}; > + > + if (dc->ctx->dce_environment == DCE_ENV_VIRTUAL_HW) > + return res; > + > + if (!streams_changed(dc, streams, stream_count)) > + return res; > + > + DC_LOG_DC("%s: %d streams\n", __func__, stream_count); > + > + for (i = 0; i < stream_count; i++) { > + struct dc_stream_state *stream = streams[i]; > + struct dc_stream_status *status = dc_stream_get_status(stream); > + > + dc_stream_log(dc, stream); > + > + set[i].stream = stream; > + > + if (status) { > + set[i].plane_count = status->plane_count; > + for (j = 0; j < status->plane_count; j++) > + set[i].plane_states[j] = status->plane_states[j]; > + } > + } > + > + context = dc_create_state(dc); > + if (!context) > + goto context_alloc_fail; > + > + dc_resource_state_copy_construct_current(dc, context); > + > + res = dc_validate_with_context(dc, set, stream_count, context, false); > + if (res != DC_OK) { > + BREAK_TO_DEBUGGER(); > + goto fail; > + } > + > + res = dc_commit_state_no_check(dc, context); > + > + for (i = 0; i < stream_count; i++) { > + for (j = 0; j < context->stream_count; j++) { > + if (streams[i]->stream_id == context->streams[j]->stream_id) > + streams[i]->out.otg_offset = context->stream_status[j].primary_otg_inst; > + > + if (dc_is_embedded_signal(streams[i]->signal)) { > + struct dc_stream_status *status = dc_stream_get_status_from_state(context, streams[i]); > + > + if (dc->hwss.is_abm_supported) > + status->is_abm_supported = dc->hwss.is_abm_supported(dc, context, streams[i]); > + else > + status->is_abm_supported = true; > + } > + } > + } > + > +fail: > + dc_release_state(context); > + > +context_alloc_fail: > + > + DC_LOG_DC("%s Finished.\n", __func__); > + > + return res; > +} > + > bool dc_acquire_release_mpc_3dlut( > struct dc *dc, bool acquire, > struct dc_stream_state *stream, > 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 fd8db482e56f..0c58a19e9115 100644 > --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c > +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c > @@ -2593,6 +2593,208 @@ bool dc_resource_is_dsc_encoding_supported(const struct dc *dc) > return dc->res_pool->res_cap->num_dsc > 0; > } > > +static bool planes_changed_for_existing_stream(struct dc_state *context, > + struct dc_stream_state *stream, > + const struct dc_validation_set set[], > + int set_count) > +{ > + int i, j; > + struct dc_stream_status *stream_status = NULL; > + > + for (i = 0; i < context->stream_count; i++) > + if (context->streams[i] == stream) { > + stream_status = &context->stream_status[i]; > + break; > + } > + > + if (!stream_status) > + ASSERT(0); > + > + for (i = 0; i < set_count; i++) > + if (set[i].stream == stream) > + break; > + > + if (i == set_count) > + ASSERT(0); > + > + if (set[i].plane_count != stream_status->plane_count) > + return true; > + > + for (j = 0; j < set[i].plane_count; j++) > + if (set[i].plane_states[j] != stream_status->plane_states[j]) > + return true; > + > + return false; > +} > + > +enum dc_status dc_validate_with_context(struct dc *dc, > + const struct dc_validation_set set[], > + int set_count, > + struct dc_state *context, > + bool fast_validate) > +{ > + struct dc_stream_state *unchanged_streams[MAX_PIPES] = { 0 }; > + struct dc_stream_state *del_streams[MAX_PIPES] = { 0 }; > + struct dc_stream_state *add_streams[MAX_PIPES] = { 0 }; > + int old_stream_count = context->stream_count; > + enum dc_status res = DC_ERROR_UNEXPECTED; > + int unchanged_streams_count = 0; > + int del_streams_count = 0; > + int add_streams_count = 0; > + bool found = false; > + int i, j, k; > + > + DC_LOGGER_INIT(dc->ctx->logger); > + > + /* 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 (!found) > + del_streams[del_streams_count++] = stream; > + > + found = false; > + } > + > + /* Now add new streams */ > + for (i = 0; i < set_count; i++) { > + struct dc_stream_state *stream = set[i].stream; > + > + for (j = 0; j < old_stream_count; j++) { > + if (stream == context->streams[j]) { > + found = true; > + break; > + } > + } > + > + if (!found) > + add_streams[add_streams_count++] = stream; > + > + found = false; > + } > + > + /* > + * Build array of unchanged streams, it is needed to handle > + * planes only changes (added/removed/updated) > + */ > + for (i = 0; i < set_count; i++) { > + for (j = 0; j < del_streams_count; j++) { > + if (set[i].stream == del_streams[j]) { > + found = true; > + break; > + } > + } > + > + if (!found) { > + for (j = 0; j < add_streams_count; j++) { > + if (set[i].stream == add_streams[j]) { > + found = true; > + break; > + } > + } > + } > + > + if (!found) > + unchanged_streams[unchanged_streams_count++] = set[i].stream; > + > + found = false; > + } > + > + /* Remove all planes for unchanged streams if planes changed */ > + for (i = 0; i < unchanged_streams_count; i++) { > + if (planes_changed_for_existing_stream(context, > + unchanged_streams[i], > + set, > + set_count)) { > + if (!dc_rem_all_planes_for_stream(dc, > + unchanged_streams[i], > + context)) { > + res = DC_FAIL_DETACH_SURFACES; > + goto fail; > + } > + } > + } > + > + /* Remove all planes for removed streams and then remove the streams */ > + for (i = 0; i < del_streams_count; i++) { > + /* Need to cpy the dwb data from the old stream in order to efc to work */ > + if (del_streams[i]->num_wb_info > 0) { > + for (j = 0; j < add_streams_count; j++) { > + if (del_streams[i]->sink == add_streams[j]->sink) { > + add_streams[j]->num_wb_info = del_streams[i]->num_wb_info; > + for (k = 0; k < del_streams[i]->num_wb_info; k++) > + add_streams[j]->writeback_info[k] = del_streams[i]->writeback_info[k]; > + } > + } > + } > + > + if (!dc_rem_all_planes_for_stream(dc, del_streams[i], context)) { > + res = DC_FAIL_DETACH_SURFACES; > + goto fail; > + } > + > + res = dc_remove_stream_from_ctx(dc, context, del_streams[i]); > + if (res != DC_OK) > + goto fail; > + } > + > + /* Swap seamless boot stream to pipe 0 (if needed) to ensure pipe_ctx matches. > + * This may change in the future if seamless_boot_stream can be multiple. > + */ > + for (i = 0; i < add_streams_count; i++) { > + mark_seamless_boot_stream(dc, add_streams[i]); > + if (add_streams[i]->apply_seamless_boot_optimization && i != 0) { > + struct dc_stream_state *temp = add_streams[0]; > + > + add_streams[0] = add_streams[i]; > + add_streams[i] = temp; > + break; > + } > + } > + > + /* Add new streams and then add all planes for the new stream */ > + for (i = 0; i < add_streams_count; i++) { > + calculate_phy_pix_clks(add_streams[i]); > + res = dc_add_stream_to_ctx(dc, context, add_streams[i]); > + if (res != DC_OK) > + goto fail; > + > + if (!add_all_planes_for_stream(dc, add_streams[i], set, set_count, context)) { > + res = DC_FAIL_ATTACH_SURFACES; > + goto fail; > + } > + } > + > + /* Add all planes for unchanged streams if planes changed */ > + for (i = 0; i < unchanged_streams_count; i++) { > + if (planes_changed_for_existing_stream(context, > + unchanged_streams[i], > + set, > + set_count)) { > + if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, set_count, context)) { > + res = DC_FAIL_ATTACH_SURFACES; > + goto fail; > + } > + } > + } > + > + res = dc_validate_global_state(dc, context, fast_validate); > + > +fail: > + if (res != DC_OK) { > + DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n", > + __func__, > + res); > + } > + return res; > +} > > /** > * dc_validate_global_state() - Determine if HW can support a given state > @@ -3734,4 +3936,4 @@ bool dc_resource_acquire_secondary_pipe_for_mpc_odm( > } > > return true; > -} > \ No newline at end of file > +} > diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h > index bfc5474c0f4c..2753d9eabd16 100644 > --- a/drivers/gpu/drm/amd/display/dc/dc.h > +++ b/drivers/gpu/drm/amd/display/dc/dc.h > @@ -1286,6 +1286,12 @@ enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *pla > > void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx *info); > > +enum dc_status dc_validate_with_context(struct dc *dc, > + const struct dc_validation_set set[], > + int set_count, > + struct dc_state *context, > + bool fast_validate); > + > bool dc_set_generic_gpio_for_stereo(bool enable, > struct gpio_service *gpio_service); > > diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h > index 9e6025c98db9..d5b3c80635ea 100644 > --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h > +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h > @@ -378,10 +378,9 @@ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream, > uint32_t *h_position, > uint32_t *v_position); > > -enum dc_status dc_add_stream_to_ctx( > - struct dc *dc, > - struct dc_state *new_ctx, > - struct dc_stream_state *stream); > +enum dc_status dc_add_stream_to_ctx(struct dc *dc, > + struct dc_state *new_ctx, > + struct dc_stream_state *stream); > > enum dc_status dc_remove_stream_from_ctx( > struct dc *dc, > @@ -445,6 +444,10 @@ enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream) > * Phy, Encoder, Timing Generator are programmed and enabled. > * New streams are enabled with blank stream; no memory read. > */ > +enum dc_status dc_commit_streams(struct dc *dc, > + struct dc_stream_state *streams[], > + uint8_t stream_count); > + > /* > * Enable stereo when commit_streams is not required, > * for example, frame alternate.