|
@@ -54,6 +54,13 @@
|
|
|
/*******************************************************************************
|
|
|
* Private functions
|
|
|
******************************************************************************/
|
|
|
+
|
|
|
+static inline void elevate_update_type(enum surface_update_type *original, enum surface_update_type new)
|
|
|
+{
|
|
|
+ if (new > *original)
|
|
|
+ *original = new;
|
|
|
+}
|
|
|
+
|
|
|
static void destroy_links(struct dc *dc)
|
|
|
{
|
|
|
uint32_t i;
|
|
@@ -157,7 +164,7 @@ failed_alloc:
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-static bool stream_adjust_vmin_vmax(struct dc *dc,
|
|
|
+bool dc_stream_adjust_vmin_vmax(struct dc *dc,
|
|
|
struct dc_stream_state **streams, int num_streams,
|
|
|
int vmin, int vmax)
|
|
|
{
|
|
@@ -182,7 +189,7 @@ static bool stream_adjust_vmin_vmax(struct dc *dc,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static bool stream_get_crtc_position(struct dc *dc,
|
|
|
+bool dc_stream_get_crtc_position(struct dc *dc,
|
|
|
struct dc_stream_state **streams, int num_streams,
|
|
|
unsigned int *v_pos, unsigned int *nom_v_pos)
|
|
|
{
|
|
@@ -207,45 +214,7 @@ static bool stream_get_crtc_position(struct dc *dc,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static bool set_gamut_remap(struct dc *dc, const struct dc_stream_state *stream)
|
|
|
-{
|
|
|
- int i = 0;
|
|
|
- bool ret = false;
|
|
|
- struct pipe_ctx *pipes;
|
|
|
-
|
|
|
- for (i = 0; i < MAX_PIPES; i++) {
|
|
|
- if (dc->current_state->res_ctx.pipe_ctx[i].stream == stream) {
|
|
|
- pipes = &dc->current_state->res_ctx.pipe_ctx[i];
|
|
|
- dc->hwss.program_gamut_remap(pipes);
|
|
|
- ret = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-static bool program_csc_matrix(struct dc *dc, struct dc_stream_state *stream)
|
|
|
-{
|
|
|
- int i = 0;
|
|
|
- bool ret = false;
|
|
|
- struct pipe_ctx *pipes;
|
|
|
-
|
|
|
- for (i = 0; i < MAX_PIPES; i++) {
|
|
|
- if (dc->current_state->res_ctx.pipe_ctx[i].stream
|
|
|
- == stream) {
|
|
|
-
|
|
|
- pipes = &dc->current_state->res_ctx.pipe_ctx[i];
|
|
|
- dc->hwss.program_csc_matrix(pipes,
|
|
|
- stream->output_color_space,
|
|
|
- stream->csc_color_matrix.matrix);
|
|
|
- ret = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-static void set_static_screen_events(struct dc *dc,
|
|
|
+void dc_stream_set_static_screen_events(struct dc *dc,
|
|
|
struct dc_stream_state **streams,
|
|
|
int num_streams,
|
|
|
const struct dc_static_screen_events *events)
|
|
@@ -270,177 +239,6 @@ static void set_static_screen_events(struct dc *dc,
|
|
|
dc->hwss.set_static_screen_control(pipes_affected, num_pipes_affected, events);
|
|
|
}
|
|
|
|
|
|
-static void set_drive_settings(struct dc *dc,
|
|
|
- struct link_training_settings *lt_settings,
|
|
|
- const struct dc_link *link)
|
|
|
-{
|
|
|
-
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = 0; i < dc->link_count; i++) {
|
|
|
- if (dc->links[i] == link)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (i >= dc->link_count)
|
|
|
- ASSERT_CRITICAL(false);
|
|
|
-
|
|
|
- dc_link_dp_set_drive_settings(dc->links[i], lt_settings);
|
|
|
-}
|
|
|
-
|
|
|
-static void perform_link_training(struct dc *dc,
|
|
|
- struct dc_link_settings *link_setting,
|
|
|
- bool skip_video_pattern)
|
|
|
-{
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = 0; i < dc->link_count; i++)
|
|
|
- dc_link_dp_perform_link_training(
|
|
|
- dc->links[i],
|
|
|
- link_setting,
|
|
|
- skip_video_pattern);
|
|
|
-}
|
|
|
-
|
|
|
-static void set_preferred_link_settings(struct dc *dc,
|
|
|
- struct dc_link_settings *link_setting,
|
|
|
- struct dc_link *link)
|
|
|
-{
|
|
|
- link->preferred_link_setting = *link_setting;
|
|
|
- dp_retrain_link_dp_test(link, link_setting, false);
|
|
|
-}
|
|
|
-
|
|
|
-static void enable_hpd(const struct dc_link *link)
|
|
|
-{
|
|
|
- dc_link_dp_enable_hpd(link);
|
|
|
-}
|
|
|
-
|
|
|
-static void disable_hpd(const struct dc_link *link)
|
|
|
-{
|
|
|
- dc_link_dp_disable_hpd(link);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static void set_test_pattern(
|
|
|
- struct dc_link *link,
|
|
|
- enum dp_test_pattern test_pattern,
|
|
|
- const struct link_training_settings *p_link_settings,
|
|
|
- const unsigned char *p_custom_pattern,
|
|
|
- unsigned int cust_pattern_size)
|
|
|
-{
|
|
|
- if (link != NULL)
|
|
|
- dc_link_dp_set_test_pattern(
|
|
|
- link,
|
|
|
- test_pattern,
|
|
|
- p_link_settings,
|
|
|
- p_custom_pattern,
|
|
|
- cust_pattern_size);
|
|
|
-}
|
|
|
-
|
|
|
-static void set_dither_option(struct dc_stream_state *stream,
|
|
|
- enum dc_dither_option option)
|
|
|
-{
|
|
|
- struct bit_depth_reduction_params params;
|
|
|
- struct dc_link *link = stream->status.link;
|
|
|
- struct pipe_ctx *pipes = NULL;
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = 0; i < MAX_PIPES; i++) {
|
|
|
- if (link->dc->current_state->res_ctx.pipe_ctx[i].stream ==
|
|
|
- stream) {
|
|
|
- pipes = &link->dc->current_state->res_ctx.pipe_ctx[i];
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- memset(¶ms, 0, sizeof(params));
|
|
|
- if (!pipes)
|
|
|
- return;
|
|
|
- if (option > DITHER_OPTION_MAX)
|
|
|
- return;
|
|
|
-
|
|
|
- stream->dither_option = option;
|
|
|
-
|
|
|
- resource_build_bit_depth_reduction_params(stream,
|
|
|
- ¶ms);
|
|
|
- stream->bit_depth_params = params;
|
|
|
- pipes->stream_res.opp->funcs->
|
|
|
- opp_program_bit_depth_reduction(pipes->stream_res.opp, ¶ms);
|
|
|
-}
|
|
|
-
|
|
|
-void set_dpms(
|
|
|
- struct dc *dc,
|
|
|
- struct dc_stream_state *stream,
|
|
|
- bool dpms_off)
|
|
|
-{
|
|
|
- struct pipe_ctx *pipe_ctx = NULL;
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = 0; i < MAX_PIPES; i++) {
|
|
|
- if (dc->current_state->res_ctx.pipe_ctx[i].stream == stream) {
|
|
|
- pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!pipe_ctx) {
|
|
|
- ASSERT(0);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (stream->dpms_off != dpms_off) {
|
|
|
- stream->dpms_off = dpms_off;
|
|
|
- if (dpms_off)
|
|
|
- core_link_disable_stream(pipe_ctx,
|
|
|
- KEEP_ACQUIRED_RESOURCE);
|
|
|
- else
|
|
|
- core_link_enable_stream(dc->current_state, pipe_ctx);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void allocate_dc_stream_funcs(struct dc *dc)
|
|
|
-{
|
|
|
- if (dc->hwss.set_drr != NULL) {
|
|
|
- dc->stream_funcs.adjust_vmin_vmax =
|
|
|
- stream_adjust_vmin_vmax;
|
|
|
- }
|
|
|
-
|
|
|
- dc->stream_funcs.set_static_screen_events =
|
|
|
- set_static_screen_events;
|
|
|
-
|
|
|
- dc->stream_funcs.get_crtc_position =
|
|
|
- stream_get_crtc_position;
|
|
|
-
|
|
|
- dc->stream_funcs.set_gamut_remap =
|
|
|
- set_gamut_remap;
|
|
|
-
|
|
|
- dc->stream_funcs.program_csc_matrix =
|
|
|
- program_csc_matrix;
|
|
|
-
|
|
|
- dc->stream_funcs.set_dither_option =
|
|
|
- set_dither_option;
|
|
|
-
|
|
|
- dc->stream_funcs.set_dpms =
|
|
|
- set_dpms;
|
|
|
-
|
|
|
- dc->link_funcs.set_drive_settings =
|
|
|
- set_drive_settings;
|
|
|
-
|
|
|
- dc->link_funcs.perform_link_training =
|
|
|
- perform_link_training;
|
|
|
-
|
|
|
- dc->link_funcs.set_preferred_link_settings =
|
|
|
- set_preferred_link_settings;
|
|
|
-
|
|
|
- dc->link_funcs.enable_hpd =
|
|
|
- enable_hpd;
|
|
|
-
|
|
|
- dc->link_funcs.disable_hpd =
|
|
|
- disable_hpd;
|
|
|
-
|
|
|
- dc->link_funcs.set_test_pattern =
|
|
|
- set_test_pattern;
|
|
|
-}
|
|
|
-
|
|
|
static void destruct(struct dc *dc)
|
|
|
{
|
|
|
dc_release_state(dc->current_state);
|
|
@@ -558,6 +356,7 @@ static bool construct(struct dc *dc,
|
|
|
|
|
|
dc_version = resource_parse_asic_id(init_params->asic_id);
|
|
|
dc->ctx->dce_version = dc_version;
|
|
|
+
|
|
|
#if defined(CONFIG_DRM_AMD_DC_FBC)
|
|
|
dc->ctx->fbc_gpu_addr = init_params->fbc_gpu_addr;
|
|
|
#endif
|
|
@@ -616,8 +415,6 @@ static bool construct(struct dc *dc,
|
|
|
if (!create_links(dc, init_params->num_virtual_links))
|
|
|
goto fail;
|
|
|
|
|
|
- allocate_dc_stream_funcs(dc);
|
|
|
-
|
|
|
return true;
|
|
|
|
|
|
fail:
|
|
@@ -686,6 +483,7 @@ struct dc *dc_create(const struct dc_init_data *init_params)
|
|
|
|
|
|
dc->caps.max_links = dc->link_count;
|
|
|
dc->caps.max_audios = dc->res_pool->audio_count;
|
|
|
+ dc->caps.linear_pitch_alignment = 64;
|
|
|
|
|
|
dc->config = init_params->flags;
|
|
|
|
|
@@ -712,6 +510,28 @@ void dc_destroy(struct dc **dc)
|
|
|
*dc = NULL;
|
|
|
}
|
|
|
|
|
|
+static void enable_timing_multisync(
|
|
|
+ struct dc *dc,
|
|
|
+ struct dc_state *ctx)
|
|
|
+{
|
|
|
+ int i = 0, multisync_count = 0;
|
|
|
+ int pipe_count = dc->res_pool->pipe_count;
|
|
|
+ struct pipe_ctx *multisync_pipes[MAX_PIPES] = { NULL };
|
|
|
+
|
|
|
+ for (i = 0; i < pipe_count; i++) {
|
|
|
+ if (!ctx->res_ctx.pipe_ctx[i].stream ||
|
|
|
+ !ctx->res_ctx.pipe_ctx[i].stream->triggered_crtc_reset.enabled)
|
|
|
+ continue;
|
|
|
+ multisync_pipes[multisync_count] = &ctx->res_ctx.pipe_ctx[i];
|
|
|
+ multisync_count++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (multisync_count > 1) {
|
|
|
+ dc->hwss.enable_per_frame_crtc_position_reset(
|
|
|
+ dc, multisync_count, multisync_pipes);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void program_timing_sync(
|
|
|
struct dc *dc,
|
|
|
struct dc_state *ctx)
|
|
@@ -838,7 +658,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
|
|
|
struct dc_bios *dcb = dc->ctx->dc_bios;
|
|
|
enum dc_status result = DC_ERROR_UNEXPECTED;
|
|
|
struct pipe_ctx *pipe;
|
|
|
- int i, j, k, l;
|
|
|
+ int i, k, l;
|
|
|
struct dc_stream_state *dc_streams[MAX_STREAMS] = {0};
|
|
|
|
|
|
disable_dangling_plane(dc, context);
|
|
@@ -849,9 +669,44 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
|
|
|
if (!dcb->funcs->is_accelerated_mode(dcb))
|
|
|
dc->hwss.enable_accelerated_mode(dc);
|
|
|
|
|
|
+ /* re-program planes for existing stream, in case we need to
|
|
|
+ * free up plane resource for later use
|
|
|
+ */
|
|
|
+ for (i = 0; i < context->stream_count; i++) {
|
|
|
+ if (context->streams[i]->mode_changed)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ dc->hwss.apply_ctx_for_surface(
|
|
|
+ dc, context->streams[i],
|
|
|
+ context->stream_status[i].plane_count,
|
|
|
+ context); /* use new pipe config in new context */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Program hardware */
|
|
|
+ dc->hwss.ready_shared_resources(dc, context);
|
|
|
+
|
|
|
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
|
|
+ pipe = &context->res_ctx.pipe_ctx[i];
|
|
|
+ dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe);
|
|
|
+ }
|
|
|
+
|
|
|
+ result = dc->hwss.apply_ctx_to_hw(dc, context);
|
|
|
+
|
|
|
+ if (result != DC_OK)
|
|
|
+ return result;
|
|
|
+
|
|
|
+ if (context->stream_count > 1) {
|
|
|
+ enable_timing_multisync(dc, context);
|
|
|
+ program_timing_sync(dc, context);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Program all planes within new context*/
|
|
|
for (i = 0; i < context->stream_count; i++) {
|
|
|
const struct dc_sink *sink = context->streams[i]->sink;
|
|
|
|
|
|
+ if (!context->streams[i]->mode_changed)
|
|
|
+ continue;
|
|
|
+
|
|
|
dc->hwss.apply_ctx_for_surface(
|
|
|
dc, context->streams[i],
|
|
|
context->stream_status[i].plane_count,
|
|
@@ -880,27 +735,8 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
|
|
|
context->streams[i]->timing.pix_clk_khz);
|
|
|
}
|
|
|
|
|
|
- dc->hwss.ready_shared_resources(dc, context);
|
|
|
-
|
|
|
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
|
|
- pipe = &context->res_ctx.pipe_ctx[i];
|
|
|
- dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe);
|
|
|
- }
|
|
|
- result = dc->hwss.apply_ctx_to_hw(dc, context);
|
|
|
-
|
|
|
- program_timing_sync(dc, context);
|
|
|
-
|
|
|
dc_enable_stereo(dc, context, dc_streams, context->stream_count);
|
|
|
|
|
|
- for (i = 0; i < context->stream_count; i++) {
|
|
|
- for (j = 0; j < MAX_PIPES; j++) {
|
|
|
- pipe = &context->res_ctx.pipe_ctx[j];
|
|
|
-
|
|
|
- if (!pipe->top_pipe && pipe->stream == context->streams[i])
|
|
|
- dc->hwss.pipe_control_lock(dc, pipe, false);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
dc_release_state(dc->current_state);
|
|
|
|
|
|
dc->current_state = context;
|
|
@@ -936,7 +772,6 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context)
|
|
|
return (result == DC_OK);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
bool dc_post_update_surfaces_to_stream(struct dc *dc)
|
|
|
{
|
|
|
int i;
|
|
@@ -945,9 +780,11 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
|
|
|
post_surface_trace(dc);
|
|
|
|
|
|
for (i = 0; i < dc->res_pool->pipe_count; i++)
|
|
|
- if (context->res_ctx.pipe_ctx[i].stream == NULL
|
|
|
- || context->res_ctx.pipe_ctx[i].plane_state == NULL)
|
|
|
- dc->hwss.power_down_front_end(dc, i);
|
|
|
+ if (context->res_ctx.pipe_ctx[i].stream == NULL ||
|
|
|
+ context->res_ctx.pipe_ctx[i].plane_state == NULL) {
|
|
|
+ context->res_ctx.pipe_ctx[i].pipe_idx = i;
|
|
|
+ dc->hwss.disable_plane(dc, &context->res_ctx.pipe_ctx[i]);
|
|
|
+ }
|
|
|
|
|
|
/* 3rd param should be true, temp w/a for RV*/
|
|
|
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
|
|
@@ -1014,6 +851,7 @@ bool dc_commit_planes_to_stream(
|
|
|
flip_addr[i].address = plane_states[i]->address;
|
|
|
flip_addr[i].flip_immediate = plane_states[i]->flip_immediate;
|
|
|
plane_info[i].color_space = plane_states[i]->color_space;
|
|
|
+ plane_info[i].input_tf = plane_states[i]->input_tf;
|
|
|
plane_info[i].format = plane_states[i]->format;
|
|
|
plane_info[i].plane_size = plane_states[i]->plane_size;
|
|
|
plane_info[i].rotation = plane_states[i]->rotation;
|
|
@@ -1118,79 +956,91 @@ static unsigned int pixel_format_to_bpp(enum surface_pixel_format format)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static enum surface_update_type get_plane_info_update_type(
|
|
|
- const struct dc_surface_update *u,
|
|
|
- int surface_index)
|
|
|
+static enum surface_update_type get_plane_info_update_type(const struct dc_surface_update *u)
|
|
|
{
|
|
|
- struct dc_plane_info temp_plane_info;
|
|
|
- memset(&temp_plane_info, 0, sizeof(temp_plane_info));
|
|
|
+ union surface_update_flags *update_flags = &u->surface->update_flags;
|
|
|
|
|
|
if (!u->plane_info)
|
|
|
return UPDATE_TYPE_FAST;
|
|
|
|
|
|
- temp_plane_info = *u->plane_info;
|
|
|
+ if (u->plane_info->color_space != u->surface->color_space)
|
|
|
+ update_flags->bits.color_space_change = 1;
|
|
|
|
|
|
- /* Copy all parameters that will cause a full update
|
|
|
- * from current surface, the rest of the parameters
|
|
|
- * from provided plane configuration.
|
|
|
- * Perform memory compare and special validation
|
|
|
- * for those that can cause fast/medium updates
|
|
|
- */
|
|
|
+ if (u->plane_info->input_tf != u->surface->input_tf)
|
|
|
+ update_flags->bits.input_tf_change = 1;
|
|
|
|
|
|
- /* Full update parameters */
|
|
|
- temp_plane_info.color_space = u->surface->color_space;
|
|
|
- temp_plane_info.dcc = u->surface->dcc;
|
|
|
- temp_plane_info.horizontal_mirror = u->surface->horizontal_mirror;
|
|
|
- temp_plane_info.plane_size = u->surface->plane_size;
|
|
|
- temp_plane_info.rotation = u->surface->rotation;
|
|
|
- temp_plane_info.stereo_format = u->surface->stereo_format;
|
|
|
-
|
|
|
- if (surface_index == 0)
|
|
|
- temp_plane_info.visible = u->plane_info->visible;
|
|
|
- else
|
|
|
- temp_plane_info.visible = u->surface->visible;
|
|
|
-
|
|
|
- if (memcmp(u->plane_info, &temp_plane_info,
|
|
|
- sizeof(struct dc_plane_info)) != 0)
|
|
|
- return UPDATE_TYPE_FULL;
|
|
|
+ if (u->plane_info->horizontal_mirror != u->surface->horizontal_mirror)
|
|
|
+ update_flags->bits.horizontal_mirror_change = 1;
|
|
|
+
|
|
|
+ if (u->plane_info->rotation != u->surface->rotation)
|
|
|
+ update_flags->bits.rotation_change = 1;
|
|
|
+
|
|
|
+ if (u->plane_info->stereo_format != u->surface->stereo_format)
|
|
|
+ update_flags->bits.stereo_format_change = 1;
|
|
|
+
|
|
|
+ if (u->plane_info->per_pixel_alpha != u->surface->per_pixel_alpha)
|
|
|
+ update_flags->bits.per_pixel_alpha_change = 1;
|
|
|
|
|
|
if (pixel_format_to_bpp(u->plane_info->format) !=
|
|
|
- pixel_format_to_bpp(u->surface->format)) {
|
|
|
+ pixel_format_to_bpp(u->surface->format))
|
|
|
/* different bytes per element will require full bandwidth
|
|
|
* and DML calculation
|
|
|
*/
|
|
|
- return UPDATE_TYPE_FULL;
|
|
|
- }
|
|
|
+ update_flags->bits.bpp_change = 1;
|
|
|
|
|
|
if (memcmp(&u->plane_info->tiling_info, &u->surface->tiling_info,
|
|
|
sizeof(union dc_tiling_info)) != 0) {
|
|
|
+ update_flags->bits.swizzle_change = 1;
|
|
|
/* todo: below are HW dependent, we should add a hook to
|
|
|
* DCE/N resource and validated there.
|
|
|
*/
|
|
|
- if (u->plane_info->tiling_info.gfx9.swizzle != DC_SW_LINEAR) {
|
|
|
+ if (u->plane_info->tiling_info.gfx9.swizzle != DC_SW_LINEAR)
|
|
|
/* swizzled mode requires RQ to be setup properly,
|
|
|
* thus need to run DML to calculate RQ settings
|
|
|
*/
|
|
|
- return UPDATE_TYPE_FULL;
|
|
|
- }
|
|
|
+ update_flags->bits.bandwidth_change = 1;
|
|
|
}
|
|
|
|
|
|
+ if (update_flags->bits.rotation_change
|
|
|
+ || update_flags->bits.stereo_format_change
|
|
|
+ || update_flags->bits.bpp_change
|
|
|
+ || update_flags->bits.bandwidth_change)
|
|
|
+ return UPDATE_TYPE_FULL;
|
|
|
+
|
|
|
return UPDATE_TYPE_MED;
|
|
|
}
|
|
|
|
|
|
-static enum surface_update_type get_scaling_info_update_type(
|
|
|
+static enum surface_update_type get_scaling_info_update_type(
|
|
|
const struct dc_surface_update *u)
|
|
|
{
|
|
|
+ union surface_update_flags *update_flags = &u->surface->update_flags;
|
|
|
+
|
|
|
if (!u->scaling_info)
|
|
|
return UPDATE_TYPE_FAST;
|
|
|
|
|
|
- if (u->scaling_info->src_rect.width != u->surface->src_rect.width
|
|
|
- || u->scaling_info->src_rect.height != u->surface->src_rect.height
|
|
|
- || u->scaling_info->clip_rect.width != u->surface->clip_rect.width
|
|
|
+ if (u->scaling_info->clip_rect.width != u->surface->clip_rect.width
|
|
|
|| u->scaling_info->clip_rect.height != u->surface->clip_rect.height
|
|
|
|| u->scaling_info->dst_rect.width != u->surface->dst_rect.width
|
|
|
- || u->scaling_info->dst_rect.height != u->surface->dst_rect.height)
|
|
|
- return UPDATE_TYPE_FULL;
|
|
|
+ || u->scaling_info->dst_rect.height != u->surface->dst_rect.height) {
|
|
|
+ update_flags->bits.scaling_change = 1;
|
|
|
+
|
|
|
+ if ((u->scaling_info->dst_rect.width < u->surface->dst_rect.width
|
|
|
+ || u->scaling_info->dst_rect.height < u->surface->dst_rect.height)
|
|
|
+ && (u->scaling_info->dst_rect.width < u->surface->src_rect.width
|
|
|
+ || u->scaling_info->dst_rect.height < u->surface->src_rect.height))
|
|
|
+ /* Making dst rect smaller requires a bandwidth change */
|
|
|
+ update_flags->bits.bandwidth_change = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (u->scaling_info->src_rect.width != u->surface->src_rect.width
|
|
|
+ || u->scaling_info->src_rect.height != u->surface->src_rect.height) {
|
|
|
+
|
|
|
+ update_flags->bits.scaling_change = 1;
|
|
|
+ if (u->scaling_info->src_rect.width > u->surface->src_rect.width
|
|
|
+ && u->scaling_info->src_rect.height > u->surface->src_rect.height)
|
|
|
+ /* Making src rect bigger requires a bandwidth change */
|
|
|
+ update_flags->bits.clock_change = 1;
|
|
|
+ }
|
|
|
|
|
|
if (u->scaling_info->src_rect.x != u->surface->src_rect.x
|
|
|
|| u->scaling_info->src_rect.y != u->surface->src_rect.y
|
|
@@ -1198,41 +1048,56 @@ static enum surface_update_type get_scaling_info_update_type(
|
|
|
|| u->scaling_info->clip_rect.y != u->surface->clip_rect.y
|
|
|
|| u->scaling_info->dst_rect.x != u->surface->dst_rect.x
|
|
|
|| u->scaling_info->dst_rect.y != u->surface->dst_rect.y)
|
|
|
+ update_flags->bits.position_change = 1;
|
|
|
+
|
|
|
+ if (update_flags->bits.clock_change
|
|
|
+ || update_flags->bits.bandwidth_change)
|
|
|
+ return UPDATE_TYPE_FULL;
|
|
|
+
|
|
|
+ if (update_flags->bits.scaling_change
|
|
|
+ || update_flags->bits.position_change)
|
|
|
return UPDATE_TYPE_MED;
|
|
|
|
|
|
return UPDATE_TYPE_FAST;
|
|
|
}
|
|
|
|
|
|
-static enum surface_update_type det_surface_update(
|
|
|
- const struct dc *dc,
|
|
|
- const struct dc_surface_update *u,
|
|
|
- int surface_index)
|
|
|
+static enum surface_update_type det_surface_update(const struct dc *dc,
|
|
|
+ const struct dc_surface_update *u)
|
|
|
{
|
|
|
const struct dc_state *context = dc->current_state;
|
|
|
- enum surface_update_type type = UPDATE_TYPE_FAST;
|
|
|
+ enum surface_update_type type;
|
|
|
enum surface_update_type overall_type = UPDATE_TYPE_FAST;
|
|
|
+ union surface_update_flags *update_flags = &u->surface->update_flags;
|
|
|
+
|
|
|
+ update_flags->raw = 0; // Reset all flags
|
|
|
|
|
|
- if (!is_surface_in_context(context, u->surface))
|
|
|
+ if (!is_surface_in_context(context, u->surface)) {
|
|
|
+ update_flags->bits.new_plane = 1;
|
|
|
return UPDATE_TYPE_FULL;
|
|
|
+ }
|
|
|
|
|
|
- type = get_plane_info_update_type(u, surface_index);
|
|
|
- if (overall_type < type)
|
|
|
- overall_type = type;
|
|
|
+ type = get_plane_info_update_type(u);
|
|
|
+ elevate_update_type(&overall_type, type);
|
|
|
|
|
|
type = get_scaling_info_update_type(u);
|
|
|
- if (overall_type < type)
|
|
|
- overall_type = type;
|
|
|
+ elevate_update_type(&overall_type, type);
|
|
|
+
|
|
|
+ if (u->in_transfer_func)
|
|
|
+ update_flags->bits.in_transfer_func = 1;
|
|
|
|
|
|
- if (u->in_transfer_func ||
|
|
|
- u->hdr_static_metadata) {
|
|
|
- if (overall_type < UPDATE_TYPE_MED)
|
|
|
- overall_type = UPDATE_TYPE_MED;
|
|
|
+ if (u->input_csc_color_matrix)
|
|
|
+ update_flags->bits.input_csc_change = 1;
|
|
|
+
|
|
|
+ if (update_flags->bits.in_transfer_func
|
|
|
+ || update_flags->bits.input_csc_change) {
|
|
|
+ type = UPDATE_TYPE_MED;
|
|
|
+ elevate_update_type(&overall_type, type);
|
|
|
}
|
|
|
|
|
|
return overall_type;
|
|
|
}
|
|
|
|
|
|
-enum surface_update_type dc_check_update_surfaces_for_stream(
|
|
|
+static enum surface_update_type check_update_surfaces_for_stream(
|
|
|
struct dc *dc,
|
|
|
struct dc_surface_update *updates,
|
|
|
int surface_count,
|
|
@@ -1250,18 +1115,38 @@ enum surface_update_type dc_check_update_surfaces_for_stream(
|
|
|
|
|
|
for (i = 0 ; i < surface_count; i++) {
|
|
|
enum surface_update_type type =
|
|
|
- det_surface_update(dc, &updates[i], i);
|
|
|
+ det_surface_update(dc, &updates[i]);
|
|
|
|
|
|
if (type == UPDATE_TYPE_FULL)
|
|
|
return type;
|
|
|
|
|
|
- if (overall_type < type)
|
|
|
- overall_type = type;
|
|
|
+ elevate_update_type(&overall_type, type);
|
|
|
}
|
|
|
|
|
|
return overall_type;
|
|
|
}
|
|
|
|
|
|
+enum surface_update_type dc_check_update_surfaces_for_stream(
|
|
|
+ struct dc *dc,
|
|
|
+ struct dc_surface_update *updates,
|
|
|
+ int surface_count,
|
|
|
+ struct dc_stream_update *stream_update,
|
|
|
+ const struct dc_stream_status *stream_status)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ enum surface_update_type type;
|
|
|
+
|
|
|
+ for (i = 0; i < surface_count; i++)
|
|
|
+ updates[i].surface->update_flags.raw = 0;
|
|
|
+
|
|
|
+ type = check_update_surfaces_for_stream(dc, updates, surface_count, stream_update, stream_status);
|
|
|
+ if (type == UPDATE_TYPE_FULL)
|
|
|
+ for (i = 0; i < surface_count; i++)
|
|
|
+ updates[i].surface->update_flags.bits.full_update = 1;
|
|
|
+
|
|
|
+ return type;
|
|
|
+}
|
|
|
+
|
|
|
static struct dc_stream_status *stream_get_status(
|
|
|
struct dc_state *ctx,
|
|
|
struct dc_stream_state *stream)
|
|
@@ -1293,9 +1178,7 @@ static void commit_planes_for_stream(struct dc *dc,
|
|
|
if (update_type == UPDATE_TYPE_FULL) {
|
|
|
dc->hwss.set_bandwidth(dc, context, false);
|
|
|
context_clock_trace(dc, context);
|
|
|
- }
|
|
|
|
|
|
- if (update_type > UPDATE_TYPE_FAST) {
|
|
|
for (j = 0; j < dc->res_pool->pipe_count; j++) {
|
|
|
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
|
|
|
|
|
@@ -1312,103 +1195,58 @@ static void commit_planes_for_stream(struct dc *dc,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- /* Lock pipes for provided surfaces, or all active if full update*/
|
|
|
- for (i = 0; i < surface_count; i++) {
|
|
|
- struct dc_plane_state *plane_state = srf_updates[i].surface;
|
|
|
-
|
|
|
- for (j = 0; j < dc->res_pool->pipe_count; j++) {
|
|
|
- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
|
|
|
-
|
|
|
- if (update_type != UPDATE_TYPE_FULL && pipe_ctx->plane_state != plane_state)
|
|
|
- continue;
|
|
|
- if (!pipe_ctx->plane_state || pipe_ctx->top_pipe)
|
|
|
- continue;
|
|
|
-
|
|
|
- dc->hwss.pipe_control_lock(
|
|
|
- dc,
|
|
|
- pipe_ctx,
|
|
|
- true);
|
|
|
- }
|
|
|
- if (update_type == UPDATE_TYPE_FULL)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
/* Full fe update*/
|
|
|
for (j = 0; j < dc->res_pool->pipe_count; j++) {
|
|
|
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
|
|
|
|
|
|
- if (update_type != UPDATE_TYPE_FULL || !pipe_ctx->plane_state)
|
|
|
+ if (update_type == UPDATE_TYPE_FAST || !pipe_ctx->plane_state)
|
|
|
continue;
|
|
|
|
|
|
- if (!pipe_ctx->top_pipe && pipe_ctx->stream) {
|
|
|
- struct dc_stream_status *stream_status = stream_get_status(context, pipe_ctx->stream);
|
|
|
+ if (!pipe_ctx->top_pipe &&
|
|
|
+ pipe_ctx->stream &&
|
|
|
+ pipe_ctx->stream == stream) {
|
|
|
+ struct dc_stream_status *stream_status =
|
|
|
+ stream_get_status(context, pipe_ctx->stream);
|
|
|
|
|
|
dc->hwss.apply_ctx_for_surface(
|
|
|
dc, pipe_ctx->stream, stream_status->plane_count, context);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (update_type > UPDATE_TYPE_FAST)
|
|
|
+ if (update_type == UPDATE_TYPE_FULL)
|
|
|
context_timing_trace(dc, &context->res_ctx);
|
|
|
|
|
|
/* Perform requested Updates */
|
|
|
for (i = 0; i < surface_count; i++) {
|
|
|
struct dc_plane_state *plane_state = srf_updates[i].surface;
|
|
|
|
|
|
- if (update_type == UPDATE_TYPE_MED)
|
|
|
- dc->hwss.apply_ctx_for_surface(
|
|
|
- dc, stream, surface_count, context);
|
|
|
-
|
|
|
for (j = 0; j < dc->res_pool->pipe_count; j++) {
|
|
|
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
|
|
|
|
|
|
- if (pipe_ctx->plane_state != plane_state)
|
|
|
+ if (pipe_ctx->stream != stream)
|
|
|
continue;
|
|
|
|
|
|
- if (srf_updates[i].flip_addr)
|
|
|
- dc->hwss.update_plane_addr(dc, pipe_ctx);
|
|
|
-
|
|
|
- if (update_type == UPDATE_TYPE_FAST)
|
|
|
+ if (pipe_ctx->plane_state != plane_state)
|
|
|
continue;
|
|
|
|
|
|
- /* work around to program degamma regs for split pipe after set mode. */
|
|
|
- if (srf_updates[i].in_transfer_func || (pipe_ctx->top_pipe &&
|
|
|
- pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state))
|
|
|
- dc->hwss.set_input_transfer_func(
|
|
|
- pipe_ctx, pipe_ctx->plane_state);
|
|
|
-
|
|
|
- if (stream_update != NULL &&
|
|
|
- stream_update->out_transfer_func != NULL) {
|
|
|
- dc->hwss.set_output_transfer_func(
|
|
|
- pipe_ctx, pipe_ctx->stream);
|
|
|
- }
|
|
|
-
|
|
|
- if (srf_updates[i].hdr_static_metadata) {
|
|
|
- resource_build_info_frame(pipe_ctx);
|
|
|
- dc->hwss.update_info_frame(pipe_ctx);
|
|
|
- }
|
|
|
+ if (update_type == UPDATE_TYPE_FAST && srf_updates[i].flip_addr)
|
|
|
+ dc->hwss.update_plane_addr(dc, pipe_ctx);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /* Unlock pipes */
|
|
|
- for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) {
|
|
|
- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
|
|
|
+ if (stream && stream_update && update_type > UPDATE_TYPE_FAST)
|
|
|
+ for (j = 0; j < dc->res_pool->pipe_count; j++) {
|
|
|
+ struct pipe_ctx *pipe_ctx =
|
|
|
+ &context->res_ctx.pipe_ctx[j];
|
|
|
|
|
|
- for (j = 0; j < surface_count; j++) {
|
|
|
- if (update_type != UPDATE_TYPE_FULL &&
|
|
|
- srf_updates[j].surface != pipe_ctx->plane_state)
|
|
|
+ if (pipe_ctx->stream != stream)
|
|
|
continue;
|
|
|
- if (!pipe_ctx->plane_state || pipe_ctx->top_pipe)
|
|
|
- continue;
|
|
|
-
|
|
|
- dc->hwss.pipe_control_lock(
|
|
|
- dc,
|
|
|
- pipe_ctx,
|
|
|
- false);
|
|
|
|
|
|
- break;
|
|
|
+ if (stream_update->hdr_static_metadata) {
|
|
|
+ resource_build_info_frame(pipe_ctx);
|
|
|
+ dc->hwss.update_info_frame(pipe_ctx);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
void dc_commit_updates_for_stream(struct dc *dc,
|
|
@@ -1480,10 +1318,7 @@ void dc_commit_updates_for_stream(struct dc *dc,
|
|
|
stream_update,
|
|
|
update_type,
|
|
|
context);
|
|
|
-
|
|
|
- if (update_type >= UPDATE_TYPE_FULL)
|
|
|
- dc_post_update_surfaces_to_stream(dc);
|
|
|
-
|
|
|
+ /*update current_State*/
|
|
|
if (dc->current_state != context) {
|
|
|
|
|
|
struct dc_state *old = dc->current_state;
|
|
@@ -1492,6 +1327,9 @@ void dc_commit_updates_for_stream(struct dc *dc,
|
|
|
dc_release_state(old);
|
|
|
|
|
|
}
|
|
|
+ /*let's use current_state to update watermark etc*/
|
|
|
+ if (update_type >= UPDATE_TYPE_FULL)
|
|
|
+ dc_post_update_surfaces_to_stream(dc);
|
|
|
|
|
|
return;
|
|
|
|