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

Commit bfaa231d authored by Ray Zhang's avatar Ray Zhang
Browse files

Revert "disp: msm: sde: use wr_ptr interrupt instead of ctl_start"



This reverts commit 6e3e2450.

Change-Id: I2a239708eb72d03daf51c0efd7fcf0ca096ae6c5
Signed-off-by: default avatarRay Zhang <rayz@codeaurora.org>
parent 22bfc32c
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -944,6 +944,26 @@ static bool sde_crtc_mode_fixup(struct drm_crtc *crtc,
	return true;
}

static int _sde_crtc_get_ctlstart_timeout(struct drm_crtc *crtc)
{
	struct drm_encoder *encoder;
	int rc = 0;

	if (!crtc || !crtc->dev)
		return 0;

	list_for_each_entry(encoder,
			&crtc->dev->mode_config.encoder_list, head) {
		if (encoder->crtc != crtc)
			continue;

		if (sde_encoder_get_intf_mode(encoder) == INTF_MODE_CMD)
			rc += sde_encoder_get_ctlstart_timeout_state(encoder);
	}

	return rc;
}

static void _sde_crtc_setup_blend_cfg(struct sde_crtc_mixer *mixer,
	struct sde_plane_state *pstate, struct sde_format *format)
{
@@ -3742,7 +3762,13 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc,
	if (unlikely(!sde_crtc->num_mixers))
		goto end;

	if (_sde_crtc_get_ctlstart_timeout(crtc)) {
		_sde_crtc_blend_setup(crtc, old_state, false);
		SDE_ERROR("border fill only commit after ctlstart timeout\n");
	} else {
		_sde_crtc_blend_setup(crtc, old_state, true);
	}

	_sde_crtc_dest_scaler_setup(crtc);

	/* cancel the idle notify delayed work */
+17 −0
Original line number Diff line number Diff line
@@ -3757,6 +3757,23 @@ int sde_encoder_idle_request(struct drm_encoder *drm_enc)
	return 0;
}

int sde_encoder_get_ctlstart_timeout_state(struct drm_encoder *drm_enc)
{
	struct sde_encoder_virt *sde_enc = NULL;
	int i, count = 0;

	if (!drm_enc)
		return 0;

	sde_enc = to_sde_encoder_virt(drm_enc);

	for (i = 0; i < sde_enc->num_phys_encs; i++) {
		count += atomic_read(&sde_enc->phys_encs[i]->ctlstart_timeout);
		atomic_set(&sde_enc->phys_encs[i]->ctlstart_timeout, 0);
	}

	return count;
}
/**
 * _sde_encoder_trigger_flush - trigger flush for a physical encoder
 * drm_enc: Pointer to drm encoder structure
+9 −2
Original line number Diff line number Diff line
@@ -171,11 +171,11 @@ void sde_encoder_kickoff(struct drm_encoder *encoder, bool is_error);
 * @encoder:	encoder pointer
 * @event:      event to wait for
 * MSM_ENC_COMMIT_DONE -  Wait for hardware to have flushed the current pending
 *                        frames to hardware at a vblank or wr_ptr_start
 *                        frames to hardware at a vblank or ctl_start
 *                        Encoders will map this differently depending on the
 *                        panel type.
 *	                  vid mode -> vsync_irq
 *                        cmd mode -> wr_ptr_start_irq
 *                        cmd mode -> ctl_start
 * MSM_ENC_TX_COMPLETE -  Wait for the hardware to transfer all the pixels to
 *                        the panel. Encoders will map this differently
 *                        depending on the panel type.
@@ -345,4 +345,11 @@ void sde_encoder_control_idle_pc(struct drm_encoder *enc, bool enable);
 */
int sde_encoder_in_cont_splash(struct drm_encoder *enc);

/**
 * sde_encoder_get_ctlstart_timeout_state - checks if ctl start timeout happened
 * @drm_enc:    Pointer to drm encoder structure
 * @Return:     non zero value if ctl start timeout occurred
 */
int sde_encoder_get_ctlstart_timeout_state(struct drm_encoder *enc);

#endif /* __SDE_ENCODER_H__ */
+17 −5
Original line number Diff line number Diff line
@@ -197,9 +197,9 @@ struct sde_encoder_phys_ops {
/**
 * enum sde_intr_idx - sde encoder interrupt index
 * @INTR_IDX_VSYNC:    Vsync interrupt for video mode panel
 * @INTR_IDX_PINGPONG: Pingpong done interrupt for cmd mode panel
 * @INTR_IDX_UNDERRUN: Underrun interrupt for video and cmd mode panel
 * @INTR_IDX_RDPTR:    Readpointer done interrupt for cmd mode panel
 * @INTR_IDX_PINGPONG: Pingpong done unterrupt for cmd mode panel
 * @INTR_IDX_UNDERRUN: Underrun unterrupt for video and cmd mode panel
 * @INTR_IDX_RDPTR:    Readpointer done unterrupt for cmd mode panel
 * @INTR_IDX_WB_DONE:  Writeback done interrupt for WB
 * @INTR_IDX_PP1_OVFL: Pingpong overflow interrupt on PP1 for Concurrent WB
 * @INTR_IDX_PP2_OVFL: Pingpong overflow interrupt on PP2 for Concurrent WB
@@ -208,7 +208,6 @@ struct sde_encoder_phys_ops {
 * @INTR_IDX_PP5_OVFL: Pingpong overflow interrupt on PP5 for Concurrent WB
 * @INTR_IDX_AUTOREFRESH_DONE:  Autorefresh done for cmd mode panel meaning
 *                              autorefresh has triggered a double buffer flip
 * @INTR_IDX_WRPTR:    Writepointer start interrupt for cmd mode panel
 */
enum sde_intr_idx {
	INTR_IDX_VSYNC,
@@ -223,7 +222,6 @@ enum sde_intr_idx {
	INTR_IDX_PP3_OVFL,
	INTR_IDX_PP4_OVFL,
	INTR_IDX_PP5_OVFL,
	INTR_IDX_WRPTR,
	INTR_IDX_MAX,
};

@@ -285,9 +283,12 @@ struct sde_encoder_irq {
 *				vs. the number of done/vblank irqs. Should hover
 *				between 0-2 Incremented when a new kickoff is
 *				scheduled. Decremented in irq handler
 * @pending_ctlstart_cnt:	Atomic counter tracking the number of ctl start
 *                              pending.
 * @pending_retire_fence_cnt:   Atomic counter tracking the pending retire
 *                              fences that have to be signalled.
 * @pending_kickoff_wq:		Wait queue for blocking until kickoff completes
 * @ctlstart_timeout:		Indicates if ctl start timeout occurred
 * @irq:			IRQ tracking structures
 * @has_intf_te:		Interface TE configuration support
 * @cont_splash_single_flush	Variable to check if single flush is enabled.
@@ -329,8 +330,10 @@ struct sde_encoder_phys {
	atomic_t wbirq_refcount;
	atomic_t vsync_cnt;
	atomic_t underrun_cnt;
	atomic_t pending_ctlstart_cnt;
	atomic_t pending_kickoff_cnt;
	atomic_t pending_retire_fence_cnt;
	atomic_t ctlstart_timeout;
	wait_queue_head_t pending_kickoff_wq;
	struct sde_encoder_irq irq[INTR_IDX_MAX];
	bool has_intf_te;
@@ -343,6 +346,7 @@ struct sde_encoder_phys {

static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys)
{
	atomic_inc_return(&phys->pending_ctlstart_cnt);
	return atomic_inc_return(&phys->pending_kickoff_cnt);
}

@@ -383,16 +387,24 @@ struct sde_encoder_phys_cmd_autorefresh {
 * @stream_sel:	Stream selection for multi-stream interfaces
 * @pp_timeout_report_cnt: number of pingpong done irq timeout errors
 * @autorefresh: autorefresh feature state
 * @pending_rd_ptr_cnt: atomic counter to indicate if retire fence can be
 *                      signaled at the next rd_ptr_irq
 * @rd_ptr_timestamp: last rd_ptr_irq timestamp
 * @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK
 * @pending_vblank_wq: Wait queue for blocking until VBLANK received
 * @ctl_start_threshold: A threshold in microseconds allows command mode
 *   engine to trigger the retire fence without waiting for rd_ptr.
 */
struct sde_encoder_phys_cmd {
	struct sde_encoder_phys base;
	int stream_sel;
	int pp_timeout_report_cnt;
	struct sde_encoder_phys_cmd_autorefresh autorefresh;
	atomic_t pending_rd_ptr_cnt;
	ktime_t rd_ptr_timestamp;
	atomic_t pending_vblank_cnt;
	wait_queue_head_t pending_vblank_wq;
	u32 ctl_start_threshold;
};

/**
+140 −56
Original line number Diff line number Diff line
@@ -44,6 +44,12 @@

#define SDE_ENC_WR_PTR_START_TIMEOUT_US 20000

/*
 * Threshold for signalling retire fences in cases where
 * CTL_START_IRQ is received just after RD_PTR_IRQ
 */
#define SDE_ENC_CTL_START_THRESHOLD_US 500

#define SDE_ENC_MAX_POLL_TIMEOUT_US	2000

static inline int _sde_encoder_phys_cmd_get_idle_timeout(
@@ -206,6 +212,23 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
	SDE_EVT32_IRQ(DRMID(phys_enc->parent),
			phys_enc->hw_pp->idx - PINGPONG_0, new_cnt, event);

	/*
	 * Reduce the refcount for the retire fence as well as for the ctl_start
	 * if the counters are greater than zero. Signal retire fence if there
	 * was a retire fence count pending and kickoff count is zero.
	 */
	if (sde_encoder_phys_cmd_is_master(phys_enc) && (new_cnt == 0)) {
		while (atomic_add_unless(&phys_enc->pending_retire_fence_cnt,
			 -1, 0)) {
			if (phys_enc->parent_ops.handle_frame_done)
				phys_enc->parent_ops.handle_frame_done(
					phys_enc->parent, phys_enc,
				SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
			atomic_add_unless(&phys_enc->pending_ctlstart_cnt,
				-1, 0);
		}
	}

	/* Signal any waiting atomic commit thread */
	wake_up_all(&phys_enc->pending_kickoff_wq);
	SDE_ATRACE_END("pp_done_irq");
@@ -240,6 +263,7 @@ static void sde_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx)
{
	struct sde_encoder_phys *phys_enc = arg;
	struct sde_encoder_phys_cmd *cmd_enc;
	u32 event = 0;

	if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf)
		return;
@@ -247,46 +271,94 @@ static void sde_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx)
	SDE_ATRACE_BEGIN("rd_ptr_irq");
	cmd_enc = to_sde_encoder_phys_cmd(phys_enc);

	/**
	 * signal only for master, when the ctl_start irq is
	 * done and incremented the pending_rd_ptr_cnt.
	 */
	if (sde_encoder_phys_cmd_is_master(phys_enc)
		    && atomic_add_unless(&cmd_enc->pending_rd_ptr_cnt, -1, 0)
		    && atomic_add_unless(
				&phys_enc->pending_retire_fence_cnt, -1, 0)) {

		event = 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);
	}

	SDE_EVT32_IRQ(DRMID(phys_enc->parent),
			phys_enc->hw_pp->idx - PINGPONG_0,
			phys_enc->hw_intf->idx - INTF_0,
			0xfff);
			event, 0xfff);

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

	cmd_enc->rd_ptr_timestamp = ktime_get();

	atomic_add_unless(&cmd_enc->pending_vblank_cnt, -1, 0);
	wake_up_all(&cmd_enc->pending_vblank_wq);
	SDE_ATRACE_END("rd_ptr_irq");
}

static void sde_encoder_phys_cmd_wr_ptr_irq(void *arg, int irq_idx)
static void sde_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx)
{
	struct sde_encoder_phys *phys_enc = arg;
	struct sde_encoder_phys_cmd *cmd_enc;
	struct sde_hw_ctl *ctl;
	u32 event = 0;
	s64 time_diff_us;

	if (!phys_enc || !phys_enc->hw_ctl)
		return;

	SDE_ATRACE_BEGIN("wr_ptr_irq");
	SDE_ATRACE_BEGIN("ctl_start_irq");
	cmd_enc = to_sde_encoder_phys_cmd(phys_enc);

	ctl = phys_enc->hw_ctl;
	atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0);
	atomic_set(&phys_enc->ctlstart_timeout, 0);

	time_diff_us = ktime_us_delta(ktime_get(), cmd_enc->rd_ptr_timestamp);

	/* handle retire fence based on only master */
	if (sde_encoder_phys_cmd_is_master(phys_enc)
			&& atomic_read(&phys_enc->pending_retire_fence_cnt)) {
		/**
		 * Handle rare cases where the ctl_start_irq is received
		 * after rd_ptr_irq. If it falls within a threshold, it is
		 * guaranteed the frame would be picked up in the current TE.
		 * Signal retire fence immediately in such case. The threshold
		 * timer adds extra line time duration based on lowest panel
		 * fps for qsync enabled case.
		 */
		if ((time_diff_us <= cmd_enc->ctl_start_threshold)
			    && atomic_add_unless(
				&phys_enc->pending_retire_fence_cnt, -1, 0)) {

	if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0)) {
			event = 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);

		/**
		 * In ideal cases, ctl_start_irq is received before the
		 * rd_ptr_irq, so set the atomic flag to indicate the event
		 * and rd_ptr_irq will handle signalling the retire fence
		 */
		} else {
			atomic_inc(&cmd_enc->pending_rd_ptr_cnt);
		}
	}

	SDE_EVT32_IRQ(DRMID(phys_enc->parent), ctl->idx - CTL_0,
				event, 0xfff);
				time_diff_us, event, 0xfff);

	/* Signal any waiting wr_ptr interrupt */
	/* Signal any waiting ctl start interrupt */
	wake_up_all(&phys_enc->pending_kickoff_wq);
	SDE_ATRACE_END("wr_ptr_irq");
	SDE_ATRACE_END("ctl_start_irq");
}

static void sde_encoder_phys_cmd_underrun_irq(void *arg, int irq_idx)
@@ -360,13 +432,6 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx(
	else
		irq->hw_idx = phys_enc->hw_pp->idx;

	irq = &phys_enc->irq[INTR_IDX_WRPTR];
	irq->irq_idx = -EINVAL;
	if (phys_enc->has_intf_te)
		irq->hw_idx = phys_enc->hw_intf->idx;
	else
		irq->hw_idx = phys_enc->hw_pp->idx;

	mutex_unlock(phys_enc->vblank_ctl_lock);
}

@@ -487,6 +552,17 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
	cmd_enc->pp_timeout_report_cnt++;
	pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt);

	if (sde_encoder_phys_cmd_is_master(phys_enc)) {
		 /* trigger the retire fence if it was missed */
		if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt,
				-1, 0))
			phys_enc->parent_ops.handle_frame_done(
				phys_enc->parent,
				phys_enc,
				SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
		atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0);
	}

	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
			cmd_enc->pp_timeout_report_cnt,
			pending_kickoff_cnt,
@@ -828,11 +904,12 @@ void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc,

	if (enable) {
		sde_encoder_helper_register_irq(phys_enc, INTR_IDX_PINGPONG);
		sde_encoder_helper_register_irq(phys_enc, INTR_IDX_UNDERRUN);
		sde_encoder_phys_cmd_control_vblank_irq(phys_enc, true);

		if (sde_encoder_phys_cmd_is_master(phys_enc)) {
			sde_encoder_helper_register_irq(phys_enc,
					INTR_IDX_WRPTR);
					INTR_IDX_CTL_START);
			sde_encoder_helper_register_irq(phys_enc,
					INTR_IDX_AUTOREFRESH_DONE);
		}
@@ -840,11 +917,12 @@ void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc,
	} else {
		if (sde_encoder_phys_cmd_is_master(phys_enc)) {
			sde_encoder_helper_unregister_irq(phys_enc,
					INTR_IDX_WRPTR);
					INTR_IDX_CTL_START);
			sde_encoder_helper_unregister_irq(phys_enc,
					INTR_IDX_AUTOREFRESH_DONE);
		}

		sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_UNDERRUN);
		sde_encoder_phys_cmd_control_vblank_irq(phys_enc, false);
		sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_PINGPONG);
	}
@@ -1000,7 +1078,9 @@ static void sde_encoder_phys_cmd_tearcheck_config(
	tc_cfg.sync_threshold_continue = DEFAULT_TEARCHECK_SYNC_THRESH_CONTINUE;
	tc_cfg.start_pos = mode->vdisplay;
	tc_cfg.rd_ptr_irq = mode->vdisplay + 1;
	tc_cfg.wr_ptr_irq = 1;

	cmd_enc->ctl_start_threshold = (extra_frame_trigger_time / 1000) +
			SDE_ENC_CTL_START_THRESHOLD_US;

	SDE_DEBUG_CMDENC(cmd_enc,
		"tc %d intf %d vsync_clk_speed_hz %u vtotal %u vrefresh %u\n",
@@ -1008,11 +1088,10 @@ static void sde_encoder_phys_cmd_tearcheck_config(
		phys_enc->hw_intf->idx - INTF_0,
		vsync_hz, mode->vtotal, mode->vrefresh);
	SDE_DEBUG_CMDENC(cmd_enc,
		"tc %d intf %d enable %u start_pos %u rd_ptr_irq %u wr_ptr_irq %u\n",
		"tc %d intf %d enable %u start_pos %u rd_ptr_irq %u\n",
		phys_enc->hw_pp->idx - PINGPONG_0,
		phys_enc->hw_intf->idx - INTF_0,
		tc_enable, tc_cfg.start_pos, tc_cfg.rd_ptr_irq,
		tc_cfg.wr_ptr_irq);
		tc_enable, tc_cfg.start_pos, tc_cfg.rd_ptr_irq);
	SDE_DEBUG_CMDENC(cmd_enc,
		"tc %d intf %d hw_vsync_mode %u vsync_count %u vsync_init_val %u\n",
		phys_enc->hw_pp->idx - PINGPONG_0,
@@ -1020,11 +1099,12 @@ static void sde_encoder_phys_cmd_tearcheck_config(
		tc_cfg.hw_vsync_mode, tc_cfg.vsync_count,
		tc_cfg.vsync_init_val);
	SDE_DEBUG_CMDENC(cmd_enc,
		"tc %d intf %d cfgheight %u thresh_start %u thresh_cont %u\n",
		"tc %d intf %d cfgheight %u thresh_start %u thresh_cont %u ctl_start_threshold:%d\n",
		phys_enc->hw_pp->idx - PINGPONG_0,
		phys_enc->hw_intf->idx - INTF_0,
		tc_cfg.sync_cfg_height,
		tc_cfg.sync_threshold_start, tc_cfg.sync_threshold_continue);
		tc_cfg.sync_threshold_start, tc_cfg.sync_threshold_continue,
		cmd_enc->ctl_start_threshold);

	if (phys_enc->has_intf_te) {
		phys_enc->hw_intf->ops.setup_tearcheck(phys_enc->hw_intf,
@@ -1220,6 +1300,7 @@ static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc)
		SDE_ERROR("invalid encoder\n");
		return;
	}
	atomic_set(&phys_enc->ctlstart_timeout, 0);
	SDE_DEBUG_CMDENC(cmd_enc, "pp %d intf %d state %d\n",
			phys_enc->hw_pp->idx - PINGPONG_0,
			phys_enc->hw_intf->idx - INTF_0,
@@ -1297,7 +1378,6 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
			atomic_read(&phys_enc->pending_kickoff_cnt),
			atomic_read(&cmd_enc->autorefresh.kickoff_cnt));
	phys_enc->frame_trigger_mode = params->frame_trigger_mode;

	if (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_DEFAULT) {
		/*
@@ -1326,7 +1406,11 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
			phys_enc->hw_pp->ops.update_tearcheck(
					phys_enc->hw_pp, &tc_cfg);

		SDE_EVT32(DRMID(phys_enc->parent), tc_cfg.sync_threshold_start);
		cmd_enc->ctl_start_threshold =
			(extra_frame_trigger_time / 1000) +
				SDE_ENC_CTL_START_THRESHOLD_US;
		SDE_EVT32(DRMID(phys_enc->parent),
		    tc_cfg.sync_threshold_start, cmd_enc->ctl_start_threshold);
	}

	SDE_DEBUG_CMDENC(cmd_enc, "pp:%d pending_cnt %d\n",
@@ -1335,7 +1419,7 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
	return ret;
}

static int _sde_encoder_phys_cmd_wait_for_wr_ptr(
static int _sde_encoder_phys_cmd_wait_for_ctl_start(
		struct sde_encoder_phys *phys_enc)
{
	struct sde_encoder_phys_cmd *cmd_enc =
@@ -1352,14 +1436,14 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr(
	ctl = phys_enc->hw_ctl;

	wait_info.wq = &phys_enc->pending_kickoff_wq;
	wait_info.atomic_cnt = &phys_enc->pending_retire_fence_cnt;
	wait_info.atomic_cnt = &phys_enc->pending_ctlstart_cnt;
	wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;

	/* slave encoder doesn't enable for ppsplit */
	if (_sde_encoder_phys_is_ppsplit_slave(phys_enc))
		return 0;

	ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WRPTR,
	ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_CTL_START,
			&wait_info);
	if (ret == -ETIMEDOUT) {
		struct sde_hw_ctl *ctl = phys_enc->hw_ctl;
@@ -1369,23 +1453,29 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr(

		if (frame_pending)
			SDE_ERROR_CMDENC(cmd_enc,
					"wr_ptr interrupt wait failed\n");
					"ctl start interrupt wait failed\n");
		else
			ret = 0;

		if (sde_encoder_phys_cmd_is_master(phys_enc)) {
			/*
		 * Signaling the retire fence at wr_ptr timeout
			 * Signaling the retire fence at ctl start timeout
			 * to allow the next commit and avoid device freeze.
		 * As wr_ptr timeout can occurs due to no read ptr,
			 * As ctl start timeout can occurs due to no read ptr,
			 * updating pending_rd_ptr_cnt here may not cover all
			 * cases. Hence signaling the retire fence.
			 */
		if (sde_encoder_phys_cmd_is_master(phys_enc) &&
			atomic_add_unless(&phys_enc->pending_retire_fence_cnt,
				-1, 0))
			if (atomic_add_unless(
			 &phys_enc->pending_retire_fence_cnt, -1, 0))
				phys_enc->parent_ops.handle_frame_done(
				phys_enc->parent, phys_enc,
				 phys_enc->parent,
				 phys_enc,
				 SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
			atomic_add_unless(
				&phys_enc->pending_ctlstart_cnt, -1, 0);
			atomic_inc_return(&phys_enc->ctlstart_timeout);
		}

	} else if ((ret == 0) &&
	  (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) &&
	  atomic_read(&phys_enc->pending_kickoff_cnt) &&
@@ -1437,7 +1527,7 @@ static int sde_encoder_phys_cmd_wait_for_commit_done(

	/* only required for master controller */
	if (sde_encoder_phys_cmd_is_master(phys_enc))
		rc = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc);
		rc = _sde_encoder_phys_cmd_wait_for_ctl_start(phys_enc);

	if (!rc && sde_encoder_phys_cmd_is_master(phys_enc) &&
			cmd_enc->autorefresh.cfg.enable)
@@ -1670,6 +1760,7 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init(
	phys_enc->enc_spinlock = p->enc_spinlock;
	phys_enc->vblank_ctl_lock = p->vblank_ctl_lock;
	cmd_enc->stream_sel = 0;
	cmd_enc->ctl_start_threshold = SDE_ENC_CTL_START_THRESHOLD_US;
	phys_enc->enable_state = SDE_ENC_DISABLED;
	sde_encoder_phys_cmd_init_ops(&phys_enc->ops);
	phys_enc->comp_type = p->comp_type;
@@ -1691,7 +1782,7 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init(
	irq->name = "ctl_start";
	irq->intr_type = SDE_IRQ_TYPE_CTL_START;
	irq->intr_idx = INTR_IDX_CTL_START;
	irq->cb.func = NULL;
	irq->cb.func = sde_encoder_phys_cmd_ctl_start_irq;

	irq = &phys_enc->irq[INTR_IDX_PINGPONG];
	irq->name = "pp_done";
@@ -1727,20 +1818,13 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init(
	irq->intr_idx = INTR_IDX_AUTOREFRESH_DONE;
	irq->cb.func = sde_encoder_phys_cmd_autorefresh_done_irq;

	irq = &phys_enc->irq[INTR_IDX_WRPTR];
	irq->intr_idx = INTR_IDX_WRPTR;
	irq->name = "wr_ptr";

	if (phys_enc->has_intf_te)
		irq->intr_type = SDE_IRQ_TYPE_INTF_TEAR_WR_PTR;
	else
		irq->intr_type = SDE_IRQ_TYPE_PING_PONG_WR_PTR;
	irq->cb.func = sde_encoder_phys_cmd_wr_ptr_irq;

	atomic_set(&phys_enc->vblank_refcount, 0);
	atomic_set(&phys_enc->pending_kickoff_cnt, 0);
	atomic_set(&phys_enc->pending_ctlstart_cnt, 0);
	atomic_set(&phys_enc->pending_retire_fence_cnt, 0);
	atomic_set(&cmd_enc->pending_rd_ptr_cnt, 0);
	atomic_set(&cmd_enc->pending_vblank_cnt, 0);
	atomic_set(&phys_enc->ctlstart_timeout, 0);
	init_waitqueue_head(&phys_enc->pending_kickoff_wq);
	init_waitqueue_head(&cmd_enc->pending_vblank_wq);
	atomic_set(&cmd_enc->autorefresh.kickoff_cnt, 0);
Loading