Commit 009114f6 authored by Anthony Koo's avatar Anthony Koo Committed by Alex Deucher
Browse files

drm/amd/display: Added locking for atomic update stream and update planes



[Why]
Screen flickering when HDR switches between FP16 and ARGB2101010

[How]
Moved pipe_control_lock so stream update and plane update occur atomically

Signed-off-by: default avatarAnthony Koo <Anthony.Koo@amd.com>
Signed-off-by: default avatarLucy Li <lucy.li@amd.com>
Reviewed-by: default avatarAric Cyr <Aric.Cyr@amd.com>
Acked-by: default avatarBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent b1e9da7f
Loading
Loading
Loading
Loading
+67 −20
Original line number Diff line number Diff line
@@ -761,6 +761,29 @@ static bool disable_all_writeback_pipes_for_stream(
	return true;
}

void apply_ctx_interdependent_lock(struct dc *dc, struct dc_state *context, struct dc_stream_state *stream, bool lock)
{
	int i = 0;

	/* Checks if interdependent update function pointer is NULL or not, takes care of DCE110 case */
	if (dc->hwss.interdependent_update_lock)
		dc->hwss.interdependent_update_lock(dc, context, lock);
	else {
		for (i = 0; i < dc->res_pool->pipe_count; i++) {
			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
			struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];

			// Copied conditions that were previously in dce110_apply_ctx_for_surface
			if (stream == pipe_ctx->stream) {
				if (!pipe_ctx->top_pipe &&
					(pipe_ctx->plane_state || old_pipe_ctx->plane_state))
					dc->hwss.pipe_control_lock(dc, pipe_ctx, lock);
				break;
			}
		}
	}
}

static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
{
	int i, j;
@@ -786,12 +809,17 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
		if (should_disable && old_stream) {
			dc_rem_all_planes_for_stream(dc, old_stream, dangling_context);
			disable_all_writeback_pipes_for_stream(dc, old_stream, dangling_context);

			if (dc->hwss.apply_ctx_for_surface) {
				apply_ctx_interdependent_lock(dc, dc->current_state, old_stream, true);
				dc->hwss.apply_ctx_for_surface(dc, old_stream, 0, dangling_context);
				apply_ctx_interdependent_lock(dc, dc->current_state, old_stream, false);
				dc->hwss.post_unlock_program_front_end(dc, dangling_context);
			}
			if (dc->hwss.program_front_end_for_ctx) {
				dc->hwss.interdependent_update_lock(dc, dc->current_state, true);
				dc->hwss.program_front_end_for_ctx(dc, dangling_context);
				dc->hwss.interdependent_update_lock(dc, dc->current_state, false);
				dc->hwss.post_unlock_program_front_end(dc, dangling_context);
			}
		}
@@ -1214,17 +1242,19 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
	/* re-program planes for existing stream, in case we need to
	 * free up plane resource for later use
	 */
	if (dc->hwss.apply_ctx_for_surface)
	if (dc->hwss.apply_ctx_for_surface) {
		for (i = 0; i < context->stream_count; i++) {
			if (context->streams[i]->mode_changed)
				continue;

			apply_ctx_interdependent_lock(dc, context, context->streams[i], true);
			dc->hwss.apply_ctx_for_surface(
				dc, context->streams[i],
				context->stream_status[i].plane_count,
				context); /* use new pipe config in new context */
			apply_ctx_interdependent_lock(dc, context, context->streams[i], false);
			dc->hwss.post_unlock_program_front_end(dc, context);
		}
	}

	/* Program hardware */
	for (i = 0; i < dc->res_pool->pipe_count; i++) {
@@ -1244,10 +1274,11 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c

	/* Program all planes within new context*/
	if (dc->hwss.program_front_end_for_ctx) {
		dc->hwss.interdependent_update_lock(dc, context, true);
		dc->hwss.program_front_end_for_ctx(dc, context);
		dc->hwss.interdependent_update_lock(dc, context, false);
		dc->hwss.post_unlock_program_front_end(dc, context);
	}

	for (i = 0; i < context->stream_count; i++) {
		const struct dc_link *link = context->streams[i]->link;

@@ -1255,10 +1286,12 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
			continue;

		if (dc->hwss.apply_ctx_for_surface) {
			apply_ctx_interdependent_lock(dc, context, context->streams[i], true);
			dc->hwss.apply_ctx_for_surface(
					dc, context->streams[i],
					context->stream_status[i].plane_count,
					context);
			apply_ctx_interdependent_lock(dc, context, context->streams[i], false);
			dc->hwss.post_unlock_program_front_end(dc, context);
		}

@@ -2105,15 +2138,10 @@ static void commit_planes_do_stream_update(struct dc *dc,
			if (update_type == UPDATE_TYPE_FAST)
				continue;

			if (stream_update->dsc_config && dc->hwss.pipe_control_lock_global) {
				dc->hwss.pipe_control_lock_global(dc, pipe_ctx, true);
			if (stream_update->dsc_config)
				dp_update_dsc_config(pipe_ctx);
				dc->hwss.pipe_control_lock_global(dc, pipe_ctx, false);
			}

			if (stream_update->dpms_off) {
				dc->hwss.pipe_control_lock(dc, pipe_ctx, true);

				if (*stream_update->dpms_off) {
					core_link_disable_stream(pipe_ctx);
					/* for dpms, keep acquired resources*/
@@ -2127,8 +2155,6 @@ static void commit_planes_do_stream_update(struct dc *dc,

					core_link_enable_stream(dc->current_state, pipe_ctx);
				}

				dc->hwss.pipe_control_lock(dc, pipe_ctx, false);
			}

			if (stream_update->abm_level && pipe_ctx->stream_res.abm) {
@@ -2184,6 +2210,27 @@ static void commit_planes_for_stream(struct dc *dc,
		context_clock_trace(dc, 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->top_pipe &&
			!pipe_ctx->prev_odm_pipe &&
			pipe_ctx->stream &&
			pipe_ctx->stream == stream) {
			top_pipe_to_program = pipe_ctx;
		}
	}

	if ((update_type != UPDATE_TYPE_FAST) && dc->hwss.interdependent_update_lock)
		dc->hwss.interdependent_update_lock(dc, context, true);
	else
		/* Lock the top pipe while updating plane addrs, since freesync requires
		 *  plane addr update event triggers to be synchronized.
		 *  top_pipe_to_program is expected to never be NULL
		 */
		dc->hwss.pipe_control_lock(dc, top_pipe_to_program, true);


	// Stream updates
	if (stream_update)
		commit_planes_do_stream_update(dc, stream, stream_update, update_type, context);
@@ -2198,6 +2245,11 @@ static void commit_planes_for_stream(struct dc *dc,
		if (dc->hwss.program_front_end_for_ctx)
			dc->hwss.program_front_end_for_ctx(dc, context);

		if ((update_type != UPDATE_TYPE_FAST) && dc->hwss.interdependent_update_lock)
			dc->hwss.interdependent_update_lock(dc, context, false);
		else
			dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false);

		dc->hwss.post_unlock_program_front_end(dc, context);
		return;
	}
@@ -2234,8 +2286,6 @@ static void commit_planes_for_stream(struct dc *dc,
			pipe_ctx->stream == stream) {
			struct dc_stream_status *stream_status = NULL;

			top_pipe_to_program = pipe_ctx;

			if (!pipe_ctx->plane_state)
				continue;

@@ -2280,12 +2330,6 @@ static void commit_planes_for_stream(struct dc *dc,

	// Update Type FAST, Surface updates
	if (update_type == UPDATE_TYPE_FAST) {
		/* Lock the top pipe while updating plane addrs, since freesync requires
		 *  plane addr update event triggers to be synchronized.
		 *  top_pipe_to_program is expected to never be NULL
		 */
		dc->hwss.pipe_control_lock(dc, top_pipe_to_program, true);

		if (dc->hwss.set_flip_control_gsl)
			for (i = 0; i < surface_count; i++) {
				struct dc_plane_state *plane_state = srf_updates[i].surface;
@@ -2327,9 +2371,12 @@ static void commit_planes_for_stream(struct dc *dc,
					dc->hwss.update_plane_addr(dc, pipe_ctx);
			}
		}
	}

	if ((update_type != UPDATE_TYPE_FAST) && dc->hwss.interdependent_update_lock)
		dc->hwss.interdependent_update_lock(dc, context, false);
	else
		dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false);
	}

	if (update_type != UPDATE_TYPE_FAST)
		dc->hwss.post_unlock_program_front_end(dc, context);
+2 −21
Original line number Diff line number Diff line
@@ -2574,17 +2574,6 @@ static void dce110_apply_ctx_for_surface(
	if (dc->fbc_compressor)
		dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor);

	for (i = 0; i < dc->res_pool->pipe_count; i++) {
		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
		struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];

		if (stream == pipe_ctx->stream) {
			if (!pipe_ctx->top_pipe &&
				(pipe_ctx->plane_state || old_pipe_ctx->plane_state))
				dc->hwss.pipe_control_lock(dc, pipe_ctx, true);
		}
	}

	for (i = 0; i < dc->res_pool->pipe_count; i++) {
		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];

@@ -2607,16 +2596,6 @@ static void dce110_apply_ctx_for_surface(

	}

	for (i = 0; i < dc->res_pool->pipe_count; i++) {
		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
		struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];

		if ((stream == pipe_ctx->stream) &&
			(!pipe_ctx->top_pipe) &&
			(pipe_ctx->plane_state || old_pipe_ctx->plane_state))
			dc->hwss.pipe_control_lock(dc, pipe_ctx, false);
	}

	if (dc->fbc_compressor)
		enable_fbc(dc, context);
}
@@ -2626,6 +2605,7 @@ static void dce110_post_unlock_program_front_end(
		struct dc_state *context)
{
}

static void dce110_power_down_fe(struct dc *dc, struct pipe_ctx *pipe_ctx)
{
	struct dce_hwseq *hws = dc->hwseq;
@@ -2742,6 +2722,7 @@ static const struct hw_sequencer_funcs dce110_funcs = {
	.disable_audio_stream = dce110_disable_audio_stream,
	.disable_plane = dce110_power_down_fe,
	.pipe_control_lock = dce_pipe_control_lock,
	.interdependent_update_lock = NULL,
	.prepare_bandwidth = dce110_prepare_bandwidth,
	.optimize_bandwidth = dce110_optimize_bandwidth,
	.set_drr = set_drr,
+5 −27
Original line number Diff line number Diff line
@@ -82,7 +82,7 @@ void print_microsec(struct dc_context *dc_ctx,
			us_x10 % frac);
}

static void dcn10_lock_all_pipes(struct dc *dc,
void dcn10_lock_all_pipes(struct dc *dc,
	struct dc_state *context,
	bool lock)
{
@@ -93,6 +93,7 @@ static void dcn10_lock_all_pipes(struct dc *dc,
	for (i = 0; i < dc->res_pool->pipe_count; i++) {
		pipe_ctx = &context->res_ctx.pipe_ctx[i];
		tg = pipe_ctx->stream_res.tg;

		/*
		 * Only lock the top pipe's tg to prevent redundant
		 * (un)locking. Also skip if pipe is disabled.
@@ -103,9 +104,9 @@ static void dcn10_lock_all_pipes(struct dc *dc,
			continue;

		if (lock)
			tg->funcs->lock(tg);
			dc->hwss.pipe_control_lock(dc, pipe_ctx, true);
		else
			tg->funcs->unlock(tg);
			dc->hwss.pipe_control_lock(dc, pipe_ctx, false);
	}
}

@@ -1576,7 +1577,7 @@ void dcn10_pipe_control_lock(
	/* use TG master update lock to lock everything on the TG
	 * therefore only top pipe need to lock
	 */
	if (pipe->top_pipe)
	if (!pipe || pipe->top_pipe)
		return;

	if (dc->debug.sanity_checks)
@@ -2530,11 +2531,6 @@ void dcn10_apply_ctx_for_surface(
	if (underflow_check_delay_us != 0xFFFFFFFF && hws->funcs.did_underflow_occur)
		ASSERT(hws->funcs.did_underflow_occur(dc, top_pipe_to_program));

	if (interdependent_update)
		dcn10_lock_all_pipes(dc, context, true);
	else
		dcn10_pipe_control_lock(dc, top_pipe_to_program, true);

	if (underflow_check_delay_us != 0xFFFFFFFF)
		udelay(underflow_check_delay_us);

@@ -2554,19 +2550,6 @@ void dcn10_apply_ctx_for_surface(

		pipe_ctx->update_flags.raw = 0;

		/*
		 * Powergate reused pipes that are not powergated
		 * fairly hacky right now, using opp_id as indicator
		 * TODO: After move dc_post to dc_update, this will
		 * be removed.
		 */
		if (pipe_ctx->plane_state && !old_pipe_ctx->plane_state) {
			if (old_pipe_ctx->stream_res.tg == tg &&
			    old_pipe_ctx->plane_res.hubp &&
			    old_pipe_ctx->plane_res.hubp->opp_id != OPP_ID_INVALID)
				dc->hwss.disable_plane(dc, old_pipe_ctx);
		}

		if ((!pipe_ctx->plane_state ||
		     pipe_ctx->stream_res.tg != old_pipe_ctx->stream_res.tg) &&
		    old_pipe_ctx->plane_state &&
@@ -2599,11 +2582,6 @@ void dcn10_apply_ctx_for_surface(
				&pipe_ctx->dlg_regs,
				&pipe_ctx->ttu_regs);
		}

	if (interdependent_update)
		dcn10_lock_all_pipes(dc, context, false);
	else
		dcn10_pipe_control_lock(dc, top_pipe_to_program, false);
}

void dcn10_post_unlock_program_front_end(
+4 −0
Original line number Diff line number Diff line
@@ -70,6 +70,10 @@ void dcn10_reset_hw_ctx_wrap(
		struct dc *dc,
		struct dc_state *context);
void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx);
void dcn10_lock_all_pipes(
		struct dc *dc,
		struct dc_state *context,
		bool lock);
void dcn10_apply_ctx_for_surface(
		struct dc *dc,
		const struct dc_stream_state *stream,
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
	.disable_audio_stream = dce110_disable_audio_stream,
	.disable_plane = dcn10_disable_plane,
	.pipe_control_lock = dcn10_pipe_control_lock,
	.interdependent_update_lock = dcn10_lock_all_pipes,
	.prepare_bandwidth = dcn10_prepare_bandwidth,
	.optimize_bandwidth = dcn10_optimize_bandwidth,
	.set_drr = dcn10_set_drr,
Loading