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

Commit 29d1186c authored by Clarence Ip's avatar Clarence Ip Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/sde: signal release fence after flush accepted



Avoid signaling the release fence for video mode until after
the flush bits have been accepted by the hardware. This
ensures that the new buffers and configuration are in use
before old buffers are released back to the system.

Change-Id: I0a112a16e14a0f002fcb385da71084d209344c26
Signed-off-by: default avatarClarence Ip <cip@codeaurora.org>
parent d6f74560
Loading
Loading
Loading
Loading
+25 −22
Original line number Diff line number Diff line
@@ -405,7 +405,7 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
			to_sde_encoder_phys_vid(phys_enc);
	struct sde_hw_ctl *hw_ctl;
	unsigned long lock_flags;
	u32 flush_register = 0;
	u32 flush_register = ~0;
	u32 reset_status = 0;
	int new_cnt = -1, old_cnt = -1;
	u32 event = 0;
@@ -419,42 +419,45 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)

	SDE_ATRACE_BEGIN("vblank_irq");

	/* signal only for master, where there is a pending kickoff */
	if (sde_encoder_phys_vid_is_master(phys_enc)
			&& atomic_add_unless(
				&phys_enc->pending_retire_fence_cnt, -1, 0)) {
		event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE
				| SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;

		if (phys_enc->parent_ops.handle_frame_done)
			phys_enc->parent_ops.handle_frame_done(phys_enc->parent,
				phys_enc, event);
	}

	if (phys_enc->parent_ops.handle_vblank_virt)
		phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
				phys_enc);

	old_cnt  = atomic_read(&phys_enc->pending_kickoff_cnt);

	/*
	 * only decrement the pending flush count if we've actually flushed
	 * hardware. due to sw irq latency, vblank may have already happened
	 * so we need to double-check with hw that it accepted the flush bits
	 */
	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);

	old_cnt = atomic_read(&phys_enc->pending_kickoff_cnt);

	if (hw_ctl && hw_ctl->ops.get_flush_register)
		flush_register = hw_ctl->ops.get_flush_register(hw_ctl);

	if (flush_register == 0)
		new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt,
				-1, 0);
	if (flush_register)
		goto not_flushed;

	new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);

	/* signal only for master, where there is a pending kickoff */
	if (sde_encoder_phys_vid_is_master(phys_enc)) {
		if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt,
					-1, 0))
			event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE |
				SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
	}

not_flushed:
	if (hw_ctl && hw_ctl->ops.get_reset)
		reset_status = hw_ctl->ops.get_reset(hw_ctl);

	spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);

	if (event && phys_enc->parent_ops.handle_frame_done)
		phys_enc->parent_ops.handle_frame_done(phys_enc->parent,
			phys_enc, event);

	if (phys_enc->parent_ops.handle_vblank_virt)
		phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
				phys_enc);

	SDE_EVT32_IRQ(DRMID(phys_enc->parent), vid_enc->hw_intf->idx - INTF_0,
			old_cnt, new_cnt, reset_status ? SDE_EVTLOG_ERROR : 0,
			flush_register, event);