summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c367
1 files changed, 212 insertions, 155 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index de6ef87..170936b 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -1007,7 +1007,7 @@ bool dc_commit_streams(
struct dc_bios *dcb = core_dc->ctx->dc_bios;
enum dc_status result = DC_ERROR_UNEXPECTED;
struct validate_context *context;
- struct dc_validation_set set[MAX_STREAMS] = { 0 };
+ struct dc_validation_set set[MAX_STREAMS] = { {0, {0} } };
int i, j, k;
if (false == streams_changed(core_dc, streams, stream_count))
@@ -1321,80 +1321,167 @@ bool dc_commit_surfaces_to_stream(
return dc_post_update_surfaces_to_stream(dc);
}
-void dc_update_surfaces_for_stream(struct dc *dc, struct dc_surface_update *updates,
- int surface_count, const struct dc_stream *dc_stream)
+static bool is_surface_in_context(
+ const struct validate_context *context,
+ const struct dc_surface *surface)
{
- struct core_dc *core_dc = DC_TO_CORE(dc);
- struct validate_context *context = core_dc->temp_flip_context;
- int i, j;
- bool is_new_pipe_surface[MAX_PIPES];
- const struct dc_surface *new_surfaces[MAX_SURFACES] = { 0 };
- bool need_apply_clk_constraints = false;
- bool can_skip_context_building = true;
+ int j;
- update_surface_trace(dc, updates, surface_count);
+ for (j = 0; j < context->res_ctx.pool->pipe_count; j++) {
+ const struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
- *context = *core_dc->current_context;
+ if (surface == &pipe_ctx->surface->public) {
+ return true;
+ }
+ }
- for (i = 0; i < context->res_ctx.pool->pipe_count; i++) {
- struct pipe_ctx *cur_pipe = &context->res_ctx.pipe_ctx[i];
+ return false;
+}
- if (cur_pipe->top_pipe)
- cur_pipe->top_pipe =
- &context->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx];
+enum surface_update_type {
+ UPDATE_TYPE_FAST, /* super fast, safe to execute in isr */
+ UPDATE_TYPE_MED, /* a lot of programming needed. may need to alloc */
+ UPDATE_TYPE_FULL, /* may need to shuffle resources */
+};
- if (cur_pipe->bottom_pipe)
- cur_pipe->bottom_pipe =
- &context->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];
- }
+static enum surface_update_type det_surface_update(
+ const struct core_dc *dc,
+ const struct dc_surface_update *u)
+{
+ const struct validate_context *context = dc->current_context;
- for (j = 0; j < MAX_PIPES; j++)
- is_new_pipe_surface[j] = true;
+ if (u->scaling_info || u->plane_info)
+ /* todo: not all scale and plane_info update need full update
+ * ie. check if following is the same
+ * scale ratio, view port, surface bpp etc
+ */
+ return UPDATE_TYPE_FULL; /* may need bandwidth update */
- for (i = 0 ; i < surface_count; i++) {
- struct core_surface *surface = DC_SURFACE_TO_CORE(updates[i].surface);
- bool existing_surface = false;
+ if (!is_surface_in_context(context, u->surface))
+ return UPDATE_TYPE_FULL;
- new_surfaces[i] = updates[i].surface;
+ if (u->in_transfer_func ||
+ u->out_transfer_func ||
+ u->hdr_static_metadata)
+ return UPDATE_TYPE_MED;
- for (j = 0; j < context->res_ctx.pool->pipe_count; j++) {
- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
+ return UPDATE_TYPE_FAST;
+}
- if (surface == pipe_ctx->surface) {
- existing_surface = true;
- is_new_pipe_surface[j] = false;
- }
- }
+static enum surface_update_type check_update_surfaces_for_stream(
+ struct core_dc *dc,
+ struct dc_surface_update *updates,
+ int surface_count,
+ const struct dc_stream_status *stream_status)
+{
+ int i;
+ enum surface_update_type overall_type = UPDATE_TYPE_FAST;
- if (updates[i].plane_info ||
- updates[i].scaling_info ||
- !existing_surface)
- can_skip_context_building = false;
+ if (stream_status->surface_count != surface_count)
+ return UPDATE_TYPE_FULL;
+
+ for (i = 0 ; i < surface_count; i++) {
+ enum surface_update_type type =
+ det_surface_update(dc, &updates[i]);
+
+ if (type == UPDATE_TYPE_FULL)
+ return type;
+
+ if (overall_type < type)
+ overall_type = type;
}
- if (!can_skip_context_building && dc_stream) {
- const struct core_stream *stream = DC_STREAM_TO_CORE(dc_stream);
+ return overall_type;
+}
- if (core_dc->current_context->stream_count == 0)
- return;
+enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL;
- /* Cannot commit surface to a stream that is not commited */
- for (i = 0; i < core_dc->current_context->stream_count; i++)
- if (stream == core_dc->current_context->streams[i])
- break;
- if (i == core_dc->current_context->stream_count)
- return;
+void dc_update_surfaces_for_stream(struct dc *dc,
+ struct dc_surface_update *updates, int surface_count,
+ const struct dc_stream *dc_stream)
+{
+ struct core_dc *core_dc = DC_TO_CORE(dc);
+ struct validate_context *context;
+ int i, j;
+
+ enum surface_update_type update_type;
+ const struct dc_stream_status *stream_status;
+
+ stream_status = dc_stream_get_status(dc_stream);
+ ASSERT(stream_status);
+ if (!stream_status)
+ return; /* Cannot commit surface to stream that is not committed */
+
+ update_type = check_update_surfaces_for_stream(
+ core_dc, updates, surface_count, stream_status);
+
+ if (update_type >= update_surface_trace_level)
+ update_surface_trace(dc, updates, surface_count);
+ if (update_type >= UPDATE_TYPE_FULL) {
+ const struct dc_surface *new_surfaces[MAX_SURFACES] = { 0 };
+
+ for (i = 0; i < surface_count; i++)
+ new_surfaces[i] = updates[i].surface;
+
+ /* initialize scratch memory for building context */
+ context = core_dc->temp_flip_context;
+ resource_validate_ctx_copy_construct(
+ core_dc->current_context, context);
+
+ /* add surface to context */
if (!resource_attach_surfaces_to_context(
new_surfaces, surface_count, dc_stream, context)) {
BREAK_TO_DEBUGGER();
return;
}
+ } else {
+ context = core_dc->current_context;
}
-
for (i = 0; i < surface_count; i++) {
+ /* save update param into surface */
struct core_surface *surface = DC_SURFACE_TO_CORE(updates[i].surface);
+ struct core_stream *stream = DC_STREAM_TO_CORE(dc_stream);
+ if (updates[i].flip_addr) {
+ surface->public.address = updates[i].flip_addr->address;
+ surface->public.flip_immediate =
+ updates[i].flip_addr->flip_immediate;
+ }
+
+ if (updates[i].scaling_info) {
+ surface->public.scaling_quality =
+ updates[i].scaling_info->scaling_quality;
+ surface->public.dst_rect =
+ updates[i].scaling_info->dst_rect;
+ surface->public.src_rect =
+ updates[i].scaling_info->src_rect;
+ surface->public.clip_rect =
+ updates[i].scaling_info->clip_rect;
+ }
+
+ if (updates[i].plane_info) {
+ surface->public.color_space =
+ updates[i].plane_info->color_space;
+ surface->public.format =
+ updates[i].plane_info->format;
+ surface->public.plane_size =
+ updates[i].plane_info->plane_size;
+ surface->public.rotation =
+ updates[i].plane_info->rotation;
+ surface->public.horizontal_mirror =
+ updates[i].plane_info->horizontal_mirror;
+ surface->public.stereo_format =
+ updates[i].plane_info->stereo_format;
+ surface->public.tiling_info =
+ updates[i].plane_info->tiling_info;
+ surface->public.visible =
+ updates[i].plane_info->visible;
+ surface->public.dcc =
+ updates[i].plane_info->dcc;
+ }
+
+ /* not sure if we still need this */
for (j = 0; j < context->res_ctx.pool->pipe_count; j++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
struct core_stream *stream = pipe_ctx->stream;
@@ -1402,133 +1489,101 @@ void dc_update_surfaces_for_stream(struct dc *dc, struct dc_surface_update *upda
if (pipe_ctx->surface != surface)
continue;
- if (updates[i].flip_addr) {
- surface->public.address = updates[i].flip_addr->address;
- surface->public.flip_immediate =
- updates[i].flip_addr->flip_immediate;
- }
-
- if (updates[i].plane_info || updates[i].scaling_info
- || is_new_pipe_surface[j]) {
- need_apply_clk_constraints = true;
-
- if (updates[i].plane_info) {
- surface->public.color_space =
- updates[i].plane_info->color_space;
- surface->public.format =
- updates[i].plane_info->format;
- surface->public.plane_size =
- updates[i].plane_info->plane_size;
- surface->public.rotation =
- updates[i].plane_info->rotation;
- surface->public.horizontal_mirror =
- updates[i].plane_info->horizontal_mirror;
- surface->public.stereo_format =
- updates[i].plane_info->stereo_format;
- surface->public.tiling_info =
- updates[i].plane_info->tiling_info;
- surface->public.visible =
- updates[i].plane_info->visible;
- surface->public.dcc =
- updates[i].plane_info->dcc;
- }
-
- if (updates[i].scaling_info) {
- surface->public.scaling_quality =
- updates[i].scaling_info->scaling_quality;
- surface->public.dst_rect =
- updates[i].scaling_info->dst_rect;
- surface->public.src_rect =
- updates[i].scaling_info->src_rect;
- surface->public.clip_rect =
- updates[i].scaling_info->clip_rect;
- }
-
- resource_build_scaling_params(updates[i].surface, pipe_ctx);
- if (dc->debug.surface_visual_confirm) {
- pipe_ctx->scl_data.recout.height -= 2;
- pipe_ctx->scl_data.recout.width -= 2;
- }
+ resource_build_scaling_params(updates[i].surface, pipe_ctx);
+ if (dc->debug.surface_visual_confirm) {
+ pipe_ctx->scl_data.recout.height -= 2;
+ pipe_ctx->scl_data.recout.width -= 2;
}
+ }
- if (dc->debug.disable_color_module)
- continue; /* skip below color updates */
+ if (dc->debug.disable_color_module)
+ continue; /* skip below color updates */
- if (updates[i].gamma &&
- updates[i].gamma != surface->public.gamma_correction) {
- if (surface->public.gamma_correction != NULL)
- dc_gamma_release(&surface->public.
- gamma_correction);
+ if (updates[i].gamma &&
+ updates[i].gamma != surface->public.gamma_correction) {
+ if (surface->public.gamma_correction != NULL)
+ dc_gamma_release(&surface->public.
+ gamma_correction);
- dc_gamma_retain(updates[i].gamma);
- surface->public.gamma_correction =
- updates[i].gamma;
- }
+ dc_gamma_retain(updates[i].gamma);
+ surface->public.gamma_correction =
+ updates[i].gamma;
+ }
- if (updates[i].in_transfer_func &&
- updates[i].in_transfer_func != surface->public.in_transfer_func) {
- if (surface->public.in_transfer_func != NULL)
- dc_transfer_func_release(
- surface->public.
- in_transfer_func);
-
- dc_transfer_func_retain(
- updates[i].in_transfer_func);
- surface->public.in_transfer_func =
- updates[i].in_transfer_func;
- }
+ if (updates[i].in_transfer_func &&
+ updates[i].in_transfer_func != surface->public.in_transfer_func) {
+ if (surface->public.in_transfer_func != NULL)
+ dc_transfer_func_release(
+ surface->public.
+ in_transfer_func);
+
+ dc_transfer_func_retain(
+ updates[i].in_transfer_func);
+ surface->public.in_transfer_func =
+ updates[i].in_transfer_func;
+ }
- if (updates[i].out_transfer_func &&
- updates[i].out_transfer_func != stream->public.out_transfer_func) {
- if (stream->public.out_transfer_func != NULL)
- dc_transfer_func_release(
- stream->public.
- out_transfer_func);
- dc_transfer_func_retain(
- updates[i].out_transfer_func);
- stream->public.out_transfer_func =
- updates[i].out_transfer_func;
- }
- if (updates[i].hdr_static_metadata)
- surface->public.hdr_static_ctx =
- *(updates[i].hdr_static_metadata);
+ if (updates[i].out_transfer_func &&
+ updates[i].out_transfer_func != dc_stream->out_transfer_func) {
+ if (dc_stream->out_transfer_func != NULL)
+ dc_transfer_func_release(dc_stream->out_transfer_func);
+ dc_transfer_func_retain(updates[i].out_transfer_func);
+ stream->public.out_transfer_func = updates[i].out_transfer_func;
}
+ if (updates[i].hdr_static_metadata)
+ surface->public.hdr_static_ctx =
+ *(updates[i].hdr_static_metadata);
}
+
+ if (!surface_count) /* reset */
+ core_dc->hwss.apply_ctx_for_surface(core_dc, NULL, context);
+
for (i = 0; i < surface_count; i++) {
struct core_surface *surface = DC_SURFACE_TO_CORE(updates[i].surface);
for (j = 0; j < context->res_ctx.pool->pipe_count; j++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
+ struct pipe_ctx *cur_pipe_ctx;
+ bool is_new_pipe_surface = true;
if (pipe_ctx->surface != surface)
continue;
- if (updates[i].flip_addr && can_skip_context_building) {
- core_dc->hwss.update_plane_addr(core_dc, pipe_ctx);
- } else {
+ if (update_type != UPDATE_TYPE_FAST &&
+ !pipe_ctx->tg->funcs->is_blanked(pipe_ctx->tg)) {
+ core_dc->hwss.pipe_control_lock(
+ core_dc->hwseq,
+ pipe_ctx->pipe_idx,
+ PIPE_LOCK_CONTROL_GRAPHICS |
+ PIPE_LOCK_CONTROL_SCL |
+ PIPE_LOCK_CONTROL_BLENDER |
+ PIPE_LOCK_CONTROL_MODE,
+ true);
+ }
- if (!pipe_ctx->tg->funcs->is_blanked(pipe_ctx->tg)) {
- core_dc->hwss.pipe_control_lock(
- core_dc->hwseq,
- pipe_ctx->pipe_idx,
- PIPE_LOCK_CONTROL_GRAPHICS |
- PIPE_LOCK_CONTROL_SCL |
- PIPE_LOCK_CONTROL_BLENDER |
- PIPE_LOCK_CONTROL_MODE,
- true);
- }
+ if (update_type == UPDATE_TYPE_FULL) {
+ core_dc->hwss.apply_ctx_for_surface(core_dc, surface, context);
+ } else if (updates[i].flip_addr) {
+ core_dc->hwss.update_plane_addr(core_dc, pipe_ctx);
}
+ if (update_type == UPDATE_TYPE_FAST)
+ continue;
+
+ cur_pipe_ctx = &core_dc->current_context->res_ctx.pipe_ctx[j];
+ if (cur_pipe_ctx->surface == pipe_ctx->surface)
+ is_new_pipe_surface = false;
+
if (dc->debug.disable_color_module)
continue; /* skip below color updates */
- if (is_new_pipe_surface[j] ||
+ if (is_new_pipe_surface ||
updates[i].in_transfer_func)
core_dc->hwss.set_input_transfer_func(
pipe_ctx, pipe_ctx->surface);
- if (is_new_pipe_surface[j] ||
+ if (is_new_pipe_surface ||
updates[i].out_transfer_func)
core_dc->hwss.set_output_transfer_func(
pipe_ctx,
@@ -1539,14 +1594,12 @@ void dc_update_surfaces_for_stream(struct dc *dc, struct dc_surface_update *upda
resource_build_info_frame(pipe_ctx);
core_dc->hwss.update_info_frame(pipe_ctx);
}
-
- }
- if (!can_skip_context_building) {
- core_dc->hwss.apply_ctx_for_surface(core_dc, surface, context);
- context_timing_trace(dc, &context->res_ctx);
}
}
+ if (update_type == UPDATE_TYPE_FAST)
+ return;
+
for (i = context->res_ctx.pool->pipe_count - 1; i >= 0; i--) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
@@ -1566,8 +1619,12 @@ void dc_update_surfaces_for_stream(struct dc *dc, struct dc_surface_update *upda
}
}
- core_dc->temp_flip_context = core_dc->current_context;
- core_dc->current_context = context;
+ if (core_dc->current_context != context) {
+ resource_validate_ctx_destruct(core_dc->current_context);
+ core_dc->temp_flip_context = core_dc->current_context;
+
+ core_dc->current_context = context;
+ }
}
uint8_t dc_get_current_stream_count(const struct dc *dc)
OpenPOWER on IntegriCloud