dm_force_atomic_commit(&aconnector->base);
}
-static uint32_t add_val_sets_plane(
- struct dc_validation_set *val_sets,
- uint32_t set_count,
- const struct dc_stream_state *stream,
- struct dc_plane_state *plane_state)
-{
- uint32_t i = 0, j = 0;
-
- while (i < set_count) {
- if (val_sets[i].stream == stream) {
- while (val_sets[i].plane_states[j])
- j++;
- break;
- }
- ++i;
- }
-
- val_sets[i].plane_states[j] = plane_state;
- val_sets[i].plane_count++;
-
- return val_sets[i].plane_count;
-}
-
-static uint32_t update_in_val_sets_stream(
- struct dc_validation_set *val_sets,
- uint32_t set_count,
- struct dc_stream_state *old_stream,
- struct dc_stream_state *new_stream,
- struct drm_crtc *crtc)
-{
- uint32_t i = 0;
-
- while (i < set_count) {
- if (val_sets[i].stream == old_stream)
- break;
- ++i;
- }
-
- val_sets[i].stream = new_stream;
-
- if (i == set_count)
- /* nothing found. add new one to the end */
- return set_count + 1;
-
- return set_count;
-}
-
-static uint32_t remove_from_val_sets(
- struct dc_validation_set *val_sets,
- uint32_t set_count,
- const struct dc_stream_state *stream)
-{
- int i;
-
- for (i = 0; i < set_count; i++)
- if (val_sets[i].stream == stream)
- break;
-
- if (i == set_count) {
- /* nothing found */
- return set_count;
- }
-
- set_count--;
-
- for (; i < set_count; i++)
- val_sets[i] = val_sets[i + 1];
-
- return set_count;
-}
-
/*`
* Grabs all modesetting locks to serialize against any blocking commits,
* Waits for completion of all non blocking commits.
struct dc *dc = adev->dm.dc;
struct drm_connector *connector;
struct drm_connector_state *conn_state;
- int set_count;
- struct dc_validation_set set[MAX_STREAMS] = { { 0 } };
struct dm_crtc_state *old_acrtc_state, *new_acrtc_state;
struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
+ bool pflip_needed = !state->allow_modeset;
/*
* This bool will be set for true for any modeset/reset
ASSERT(dm_state->context);
dc_resource_validate_ctx_copy_construct_current(dc, dm_state->context);
- /* copy existing configuration */
- set_count = 0;
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ /* Remove exiting planes if they are disabled or their CRTC is updated */
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ new_acrtc_state = to_dm_crtc_state(crtc_state);
- old_acrtc_state = to_dm_crtc_state(crtc->state);
+ if (pflip_needed)
+ continue;
- if (old_acrtc_state->stream) {
- dc_stream_retain(old_acrtc_state->stream);
- set[set_count].stream = old_acrtc_state->stream;
- ++set_count;
+ for_each_plane_in_state(state, plane, plane_state, j) {
+ struct drm_crtc *plane_crtc = plane_state->crtc;
+ struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
+
+ if (plane->type == DRM_PLANE_TYPE_CURSOR)
+ continue;
+
+ if (crtc != plane_crtc || !dm_plane_state->dc_state)
+ continue;
+
+ WARN_ON(!new_acrtc_state->stream);
+
+ if (drm_atomic_plane_disabling(plane->state, plane_state) ||
+ drm_atomic_crtc_needs_modeset(crtc_state)) {
+ if (!dc_remove_plane_from_context(
+ dc,
+ new_acrtc_state->stream,
+ dm_plane_state->dc_state,
+ dm_state->context)) {
+
+ ret = EINVAL;
+ goto fail;
+ }
+
+ }
+
+ dc_plane_state_release(dm_plane_state->dc_state);
+ dm_plane_state->dc_state = NULL;
+
+ DRM_DEBUG_KMS("Disabling DRM plane: %d on DRM crtc %d\n",
+ plane->base.id, crtc->base.id);
}
}
goto fail;
}
- set_count = remove_from_val_sets(
- set,
- set_count,
- new_acrtc_state->stream);
-
dc_stream_release(new_acrtc_state->stream);
new_acrtc_state->stream = NULL;
new_acrtc_state->stream = new_stream;
- set_count = update_in_val_sets_stream(
- set,
- set_count,
- old_acrtc_state->stream,
- new_acrtc_state->stream,
- crtc);
-
if (!dc_add_stream_to_ctx(
dc,
dm_state->context,
lock_and_validation_needed = true;
}
+ /* Add new planes */
for_each_crtc_in_state(state, crtc, crtc_state, i) {
new_acrtc_state = to_dm_crtc_state(crtc_state);
+ if (pflip_needed)
+ continue;
+
for_each_plane_in_state(state, plane, plane_state, j) {
struct drm_crtc *plane_crtc = plane_state->crtc;
- struct drm_framebuffer *fb = plane_state->fb;
- bool pflip_needed;
struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
/*TODO Implement atomic check for cursor plane */
if (plane->type == DRM_PLANE_TYPE_CURSOR)
continue;
- if (!fb || !plane_crtc || crtc != plane_crtc || !crtc_state->active)
+ if (crtc != plane_crtc)
continue;
- WARN_ON(!new_acrtc_state->stream);
-
- pflip_needed = !state->allow_modeset;
- if (!pflip_needed) {
+ if (!drm_atomic_plane_disabling(plane->state, plane_state)) {
struct dc_plane_state *dc_plane_state;
+ WARN_ON(!new_acrtc_state->stream);
+
dc_plane_state = dc_create_plane_state(dc);
- if (dm_plane_state->dc_state)
- dc_plane_state_release(dm_plane_state->dc_state);
+ WARN_ON(dm_plane_state->dc_state);
dm_plane_state->dc_state = dc_plane_state;
if (ret)
goto fail;
- add_val_sets_plane(set,
- set_count,
- new_acrtc_state->stream,
- dc_plane_state);
+
+ if (!dc_add_plane_to_context(
+ dc,
+ new_acrtc_state->stream,
+ dc_plane_state,
+ dm_state->context)) {
+
+ ret = EINVAL;
+ goto fail;
+ }
+
lock_and_validation_needed = true;
}
if (ret)
goto fail;
- if (!dc_validate_global_state(dc, set, set_count, dm_state->context)) {
+ if (!dc_validate_global_state(dc, dm_state->context)) {
ret = -EINVAL;
goto fail;
}
return NULL;
}
+static struct pipe_ctx *resource_get_tail_pipe_for_stream(
+ struct resource_context *res_ctx,
+ struct dc_stream_state *stream)
+{
+ struct pipe_ctx *head_pipe, *tail_pipe;
+ head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);
+
+ if (!head_pipe)
+ return NULL;
+
+ tail_pipe = head_pipe->bottom_pipe;
+
+ while (tail_pipe) {
+ head_pipe = tail_pipe;
+ tail_pipe = tail_pipe->bottom_pipe;
+ }
+
+ return head_pipe;
+}
+
/*
* A free_pipe for a stream is defined here as a pipe
* that has no surface attached yet
}
-static void release_free_pipes_for_stream(
- struct resource_context *res_ctx,
- struct dc_stream_state *stream)
-{
- int i;
-
- for (i = MAX_PIPES - 1; i >= 0; i--) {
- /* never release the topmost pipe*/
- if (res_ctx->pipe_ctx[i].stream == stream &&
- res_ctx->pipe_ctx[i].top_pipe &&
- !res_ctx->pipe_ctx[i].plane_state) {
- memset(&res_ctx->pipe_ctx[i], 0, sizeof(struct pipe_ctx));
- }
- }
-}
-
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
static int acquire_first_split_pipe(
struct resource_context *res_ctx,
}
#endif
-bool resource_attach_surfaces_to_context(
- struct dc_plane_state * const *plane_states,
- int surface_count,
+bool dc_add_plane_to_context(
+ const struct dc *dc,
struct dc_stream_state *stream,
- struct validate_context *context,
- const struct resource_pool *pool)
+ struct dc_plane_state *plane_state,
+ struct validate_context *context)
{
int i;
- struct pipe_ctx *tail_pipe;
+ struct resource_pool *pool = dc->res_pool;
+ struct pipe_ctx *head_pipe, *tail_pipe, *free_pipe;
struct dc_stream_status *stream_status = NULL;
+ for (i = 0; i < context->stream_count; i++)
+ if (context->streams[i] == stream) {
+ stream_status = &context->stream_status[i];
+ break;
+ }
+ if (stream_status == NULL) {
+ dm_error("Existing stream not found; failed to attach surface!\n");
+ return false;
+ }
+
+
+ if (stream_status->plane_count == MAX_SURFACE_NUM) {
+ dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n",
+ plane_state, MAX_SURFACE_NUM);
+ return false;
+ }
+
+ head_pipe = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
+
+ if (!head_pipe) {
+ dm_error("Head pipe not found for stream_state %p !\n", stream);
+ return false;
+ }
+
+ /* retain new surfaces */
+ dc_plane_state_retain(plane_state);
+
+ free_pipe = acquire_free_pipe_for_stream(context, pool, stream);
- if (surface_count > MAX_SURFACE_NUM) {
- dm_error("Surface: can not attach %d surfaces! Maximum is: %d\n",
- surface_count, MAX_SURFACE_NUM);
+#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
+ if (!free_pipe) {
+ int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
+ if (pipe_idx >= 0)
+ free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
+ }
+#endif
+ if (!free_pipe) {
+ stream_status->plane_states[i] = NULL;
return false;
}
+ free_pipe->plane_state = plane_state;
+
+ if (head_pipe != free_pipe) {
+
+ tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream);
+ ASSERT(tail_pipe);
+
+ free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
+ free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
+ free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
+ free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
+ free_pipe->clock_source = tail_pipe->clock_source;
+ free_pipe->top_pipe = tail_pipe;
+ tail_pipe->bottom_pipe = free_pipe;
+ }
+
+ /* assign new surfaces*/
+ stream_status->plane_states[stream_status->plane_count] = plane_state;
+
+ stream_status->plane_count++;
+
+ return true;
+}
+
+bool dc_remove_plane_from_context(
+ const struct dc *dc,
+ struct dc_stream_state *stream,
+ struct dc_plane_state *plane_state,
+ struct validate_context *context)
+{
+ int i;
+ struct dc_stream_status *stream_status = NULL;
+ struct resource_pool *pool = dc->res_pool;
+
for (i = 0; i < context->stream_count; i++)
if (context->streams[i] == stream) {
stream_status = &context->stream_status[i];
break;
}
+
if (stream_status == NULL) {
- dm_error("Existing stream not found; failed to attach surfaces\n");
+ dm_error("Existing stream not found; failed to remove plane.\n");
return false;
}
- /* retain new surfaces */
- for (i = 0; i < surface_count; i++)
- dc_plane_state_retain(plane_states[i]);
-
- /* detach surfaces from pipes */
- for (i = 0; i < pool->pipe_count; i++)
- if (context->res_ctx.pipe_ctx[i].stream == stream) {
- context->res_ctx.pipe_ctx[i].plane_state = NULL;
- context->res_ctx.pipe_ctx[i].bottom_pipe = NULL;
- }
+ /* release pipe for plane*/
+ for (i = pool->pipe_count - 1; i >= 0; i--) {
+ struct pipe_ctx *pipe_ctx;
- /* release existing surfaces*/
- for (i = 0; i < stream_status->plane_count; i++)
- dc_plane_state_release(stream_status->plane_states[i]);
+ if (context->res_ctx.pipe_ctx[i].plane_state == plane_state) {
+ pipe_ctx = &context->res_ctx.pipe_ctx[i];
- for (i = surface_count; i < stream_status->plane_count; i++)
- stream_status->plane_states[i] = NULL;
+ if (pipe_ctx->top_pipe)
+ pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
- tail_pipe = NULL;
- for (i = 0; i < surface_count; i++) {
- struct dc_plane_state *plane_state = plane_states[i];
- struct pipe_ctx *free_pipe = acquire_free_pipe_for_stream(
- context, pool, stream);
+ /* Second condition is to avoid setting NULL to top pipe
+ * of tail pipe making it look like head pipe in subsequent
+ * deletes
+ */
+ if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe)
+ pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe;
-#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
- if (!free_pipe) {
- int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
- if (pipe_idx >= 0)
- free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
- }
-#endif
- if (!free_pipe) {
- stream_status->plane_states[i] = NULL;
- return false;
+ /*
+ * For head pipe detach surfaces from pipe for tail
+ * pipe just zero it out
+ */
+ if (!pipe_ctx->top_pipe) {
+ pipe_ctx->plane_state = NULL;
+ pipe_ctx->bottom_pipe = NULL;
+ } else {
+ memset(pipe_ctx, 0, sizeof(*pipe_ctx));
+ }
}
+ }
+
- free_pipe->plane_state = plane_state;
+ for (i = 0; i < stream_status->plane_count; i++) {
+ if (stream_status->plane_states[i] == plane_state) {
- if (tail_pipe) {
- free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
- free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
- free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
- free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
- free_pipe->clock_source = tail_pipe->clock_source;
- free_pipe->top_pipe = tail_pipe;
- tail_pipe->bottom_pipe = free_pipe;
+ dc_plane_state_release(stream_status->plane_states[i]);
+ break;
}
+ }
- tail_pipe = free_pipe;
+ if (i == stream_status->plane_count) {
+ dm_error("Existing plane_state not found; failed to detach it!\n");
+ return false;
}
- release_free_pipes_for_stream(&context->res_ctx, stream);
+ stream_status->plane_count--;
- /* assign new surfaces*/
- for (i = 0; i < surface_count; i++)
- stream_status->plane_states[i] = plane_states[i];
+ /* Trim back arrays */
+ for (i = 0; i < stream_status->plane_count; i++)
+ stream_status->plane_states[i] = stream_status->plane_states[i + 1];
+
+ stream_status->plane_states[stream_status->plane_count] = NULL;
+
+ return true;
+}
+
+bool dc_rem_all_planes_for_stream(
+ const struct dc *dc,
+ struct dc_stream_state *stream,
+ struct validate_context *context)
+{
+ int i, old_plane_count;
+ struct dc_stream_status *stream_status = NULL;
+ struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 };
+
+ for (i = 0; i < context->stream_count; i++)
+ if (context->streams[i] == stream) {
+ stream_status = &context->stream_status[i];
+ break;
+ }
+
+ if (stream_status == NULL) {
+ dm_error("Existing stream %p not found!\n", stream);
+ return false;
+ }
+
+ old_plane_count = stream_status->plane_count;
- stream_status->plane_count = surface_count;
+ for (i = 0; i < old_plane_count; i++)
+ del_planes[i] = stream_status->plane_states[i];
+
+ for (i = 0; i < old_plane_count; i++)
+ if (!dc_remove_plane_from_context(dc, stream, del_planes[i], context))
+ return false;
return true;
}
+static bool add_all_planes_for_stream(
+ const struct dc *dc,
+ struct dc_stream_state *stream,
+ const struct dc_validation_set set[],
+ int set_count,
+ struct validate_context *context)
+{
+ int i, j;
+
+ for (i = 0; i < set_count; i++)
+ if (set[i].stream == stream)
+ break;
+
+ if (i == set_count) {
+ dm_error("Stream %p not found in set!\n", stream);
+ return false;
+ }
+
+ for (j = 0; j < set[i].plane_count; j++)
+ if (!dc_add_plane_to_context(dc, stream, set[i].plane_states[j], context))
+ return false;
+
+ return true;
+}
+
+bool dc_add_all_planes_for_stream(
+ const struct dc *dc,
+ struct dc_stream_state *stream,
+ struct dc_plane_state * const *plane_states,
+ int plane_count,
+ struct validate_context *context)
+{
+ struct dc_validation_set set;
+ int i;
+
+ set.stream = stream;
+ set.plane_count = plane_count;
+
+ for (i = 0; i < plane_count; i++)
+ set.plane_states[i] = plane_states[i];
+
+ return add_all_planes_for_stream(dc, stream, &set, 1, context);
+}
+
+
static bool is_timing_changed(struct dc_stream_state *cur_stream,
struct dc_stream_state *new_stream)
return true;
}
-bool resource_validate_attach_surfaces(
- const struct dc_validation_set set[],
- int set_count,
- const struct validate_context *old_context,
- struct validate_context *context,
- const struct resource_pool *pool)
-{
- int i, j;
-
- for (i = 0; i < set_count; i++) {
- for (j = 0; old_context && j < old_context->stream_count; j++)
- if (dc_is_stream_unchanged(
- old_context->streams[j],
- context->streams[i])) {
- if (!resource_attach_surfaces_to_context(
- old_context->stream_status[j].plane_states,
- old_context->stream_status[j].plane_count,
- context->streams[i],
- context, pool))
- return false;
- context->stream_status[i] = old_context->stream_status[j];
- }
- if (set[i].plane_count != 0)
- if (!resource_attach_surfaces_to_context(
- set[i].plane_states,
- set[i].plane_count,
- context->streams[i],
- context, pool))
- return false;
-
- }
-
- return true;
-}
-
/* Maximum TMDS single link pixel clock 165MHz */
#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ 165000
#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST 297000
struct validate_context *new_ctx,
struct dc_stream_state *stream)
{
- int i, j;
+ int i;
struct dc_context *dc_ctx = dc->ctx;
struct pipe_ctx *del_pipe = NULL;
- /*TODO MPO to remove extra pipe or in surface remove ?*/
-
- /* Release primary and secondary pipe (if exsist) */
+ /* Release primary pipe */
for (i = 0; i < MAX_PIPES; i++) {
- if (new_ctx->res_ctx.pipe_ctx[i].stream == stream) {
+ if (new_ctx->res_ctx.pipe_ctx[i].stream == stream &&
+ !new_ctx->res_ctx.pipe_ctx[i].top_pipe) {
del_pipe = &new_ctx->res_ctx.pipe_ctx[i];
- if (del_pipe->stream_res.stream_enc)
- update_stream_engine_usage(
- &new_ctx->res_ctx,
+ ASSERT(del_pipe->stream_res.stream_enc);
+ update_stream_engine_usage(
+ &new_ctx->res_ctx,
dc->res_pool,
- del_pipe->stream_res.stream_enc,
- false);
+ del_pipe->stream_res.stream_enc,
+ false);
if (del_pipe->stream_res.audio)
update_audio_usage(
false);
memset(del_pipe, 0, sizeof(*del_pipe));
+
+ break;
}
}
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];
bool dc_validate_global_state(
struct dc *dc,
- const struct dc_validation_set set[],
- int set_count,
struct validate_context *new_ctx)
{
enum dc_status result = DC_ERROR_UNEXPECTED;
- struct dc_context *dc_ctx = dc->ctx;
- struct validate_context *old_context = dc->current_context;
int i, j;
if (dc->res_pool->funcs->validate_global &&
- dc->res_pool->funcs->validate_global(dc, set, set_count,
- old_context, new_ctx) != DC_OK)
+ dc->res_pool->funcs->validate_global(
+ dc, new_ctx) != DC_OK)
return false;
/* TODO without this SWDEV-114774 brakes */
}
}
- /*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)