Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e63e2491 authored by Eryk Brol's avatar Eryk Brol Committed by Alex Deucher
Browse files

drm/amd/display: Ensure DRR triggers in BP



[Why]
In the previous implementation DRR event sometimes came
in during FP2 region which is a keep-out zone. This
would cause the frame not to latch until the next frame
which resulted in heavy flicker. To fix this we need
to make sure that it triggers in the BP.

[How]
1. Remove DRR programming during flip
2. Setup manual trigger for DRR event and trigger it
after surface programming is complete

Signed-off-by: default avatarEryk Brol <eryk.brol@amd.com>
Reviewed-by: default avatarAric Cyr <Aric.Cyr@amd.com>
Acked-by: default avatarLeo Li <sunpeng.li@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 313a9a21
Loading
Loading
Loading
Loading
+19 −5
Original line number Diff line number Diff line
@@ -5127,6 +5127,11 @@ static void update_freesync_state_on_stream(
		    amdgpu_dm_vrr_active(new_crtc_state)) {
			mod_freesync_handle_v_update(dm->freesync_module,
						     new_stream, &vrr_params);

			/* Need to call this before the frame ends. */
			dc_stream_adjust_vmin_vmax(dm->dc,
						   new_crtc_state->stream,
						   &vrr_params.adjust);
		}
	}

@@ -5465,11 +5470,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
		}

		if (acrtc_state->stream) {

			if (acrtc_state->freesync_timing_changed)
				bundle->stream_update.adjust =
					&acrtc_state->stream->adjust;

			if (acrtc_state->freesync_vrr_info_changed)
				bundle->stream_update.vrr_infopacket =
					&acrtc_state->stream->vrr_infopacket;
@@ -5490,6 +5490,20 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
		if (acrtc_state->abm_level != dm_old_crtc_state->abm_level)
			bundle->stream_update.abm_level = &acrtc_state->abm_level;

		/*
		 * If FreeSync state on the stream has changed then we need to
		 * re-adjust the min/max bounds now that DC doesn't handle this
		 * as part of commit.
		 */
		if (amdgpu_dm_vrr_active(dm_old_crtc_state) !=
		    amdgpu_dm_vrr_active(acrtc_state)) {
			spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
			dc_stream_adjust_vmin_vmax(
				dm->dc, acrtc_state->stream,
				&acrtc_state->vrr_params.adjust);
			spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
		}

		mutex_lock(&dm->dc_lock);
		dc_commit_updates_for_stream(dm->dc,
						     bundle->surface_updates,
+15 −8
Original line number Diff line number Diff line
@@ -263,7 +263,7 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
	for (i = 0; i < MAX_PIPES; i++) {
		struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];

		if (pipe->stream == stream && pipe->stream_res.stream_enc) {
		if (pipe->stream == stream && pipe->stream_res.tg) {
			pipe->stream->adjust = *adjust;
			dc->hwss.set_drr(&pipe,
					1,
@@ -1745,13 +1745,6 @@ static void commit_planes_do_stream_update(struct dc *dc,
			pipe_ctx->stream &&
			pipe_ctx->stream == stream) {

			/* Fast update*/
			// VRR program can be done as part of FAST UPDATE
			if (stream_update->adjust)
				dc->hwss.set_drr(&pipe_ctx, 1,
					stream_update->adjust->v_total_min,
					stream_update->adjust->v_total_max);

			if (stream_update->periodic_interrupt0 &&
					dc->hwss.setup_periodic_interrupt)
				dc->hwss.setup_periodic_interrupt(pipe_ctx, VLINE0);
@@ -1909,6 +1902,20 @@ static void commit_planes_for_stream(struct dc *dc,

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

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

		if (pipe_ctx->top_pipe ||
			!pipe_ctx->stream ||
			pipe_ctx->stream != stream ||
			!srf_updates[i].flip_addr)
			continue;

		if (pipe_ctx->stream_res.tg->funcs->program_manual_trigger)
			pipe_ctx->stream_res.tg->funcs->program_manual_trigger(pipe_ctx->stream_res.tg);
	}
}

void dc_commit_updates_for_stream(struct dc *dc,
+0 −1
Original line number Diff line number Diff line
@@ -172,7 +172,6 @@ struct dc_stream_update {
	struct periodic_interrupt_config *periodic_interrupt0;
	struct periodic_interrupt_config *periodic_interrupt1;

	struct dc_crtc_timing_adjust *adjust;
	struct dc_info_packet *vrr_infopacket;
	struct dc_info_packet *vsc_infopacket;
	struct dc_info_packet *vsp_infopacket;
+2 −2
Original line number Diff line number Diff line
@@ -2506,8 +2506,8 @@ static void set_drr(struct pipe_ctx **pipe_ctx,
{
	int i = 0;
	struct drr_params params = {0};
	// DRR should set trigger event to monitor surface update event
	unsigned int event_triggers = 0x80;
	// DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow
	unsigned int event_triggers = 0x800;

	params.vertical_total_max = vmax;
	params.vertical_total_min = vmin;
+32 −0
Original line number Diff line number Diff line
@@ -791,6 +791,32 @@ void optc1_set_static_screen_control(
			OTG_STATIC_SCREEN_FRAME_COUNT, 2);
}

void optc1_setup_manual_trigger(struct timing_generator *optc)
{
	struct optc *optc1 = DCN10TG_FROM_TG(optc);

	REG_SET(OTG_GLOBAL_CONTROL2, 0,
			MANUAL_FLOW_CONTROL_SEL, optc->inst);

	REG_SET_8(OTG_TRIGA_CNTL, 0,
			OTG_TRIGA_SOURCE_SELECT, 22,
			OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst,
			OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1,
			OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0,
			OTG_TRIGA_POLARITY_SELECT, 0,
			OTG_TRIGA_FREQUENCY_SELECT, 0,
			OTG_TRIGA_DELAY, 0,
			OTG_TRIGA_CLEAR, 1);
}

void optc1_program_manual_trigger(struct timing_generator *optc)
{
	struct optc *optc1 = DCN10TG_FROM_TG(optc);

	REG_SET(OTG_MANUAL_FLOW_CONTROL, 0,
			MANUAL_FLOW_CONTROL, 1);
}


/**
 *****************************************************************************
@@ -823,6 +849,10 @@ void optc1_set_drr(
				OTG_FORCE_LOCK_ON_EVENT, 0,
				OTG_SET_V_TOTAL_MIN_MASK_EN, 0,
				OTG_SET_V_TOTAL_MIN_MASK, 0);

		// Setup manual flow control for EOF via TRIG_A
		optc->funcs->setup_manual_trigger(optc);

	} else {
		REG_UPDATE_4(OTG_V_TOTAL_CONTROL,
				OTG_SET_V_TOTAL_MIN_MASK, 0,
@@ -1458,6 +1488,8 @@ static const struct timing_generator_funcs dcn10_tg_funcs = {
		.get_crc = optc1_get_crc,
		.configure_crc = optc1_configure_crc,
		.set_vtg_params = optc1_set_vtg_params,
		.program_manual_trigger = optc1_program_manual_trigger,
		.setup_manual_trigger = optc1_setup_manual_trigger
};

void dcn10_timing_generator_init(struct optc *optc1)
Loading