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

Commit e1d0101d authored by Dhaval Patel's avatar Dhaval Patel
Browse files

drm/msm/sde: trigger retire fence early for qsync frame



CTL_START irq is triggered after rd_ptr irq and beyond
500us threshold for QSYNC enabled usecase. This CTL_START
irq should trigger the retire fence instead of PP_DONE
irq. It releases gpu buffer early and helps to achieve
higher FPS for double buffer usecase.

Change-Id: Idb1e1458b08d9148b2d412094e2ba044209e7a78
Signed-off-by: default avatarDhaval Patel <pdhaval@codeaurora.org>
parent 6464c0fa
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -381,6 +381,8 @@ struct sde_encoder_phys_cmd_autorefresh {
 * @rd_ptr_timestamp: last rd_ptr_irq timestamp
 * @rd_ptr_timestamp: last rd_ptr_irq timestamp
 * @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK
 * @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK
 * @pending_vblank_wq: Wait queue for blocking until VBLANK received
 * @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_cmd {
	struct sde_encoder_phys base;
	struct sde_encoder_phys base;
@@ -392,6 +394,7 @@ struct sde_encoder_phys_cmd {
	ktime_t rd_ptr_timestamp;
	ktime_t rd_ptr_timestamp;
	atomic_t pending_vblank_cnt;
	atomic_t pending_vblank_cnt;
	wait_queue_head_t pending_vblank_wq;
	wait_queue_head_t pending_vblank_wq;
	u32 ctl_start_threshold;
};
};


/**
/**
+27 −9
Original line number Original line Diff line number Diff line
@@ -333,9 +333,11 @@ static void sde_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx)
		 * Handle rare cases where the ctl_start_irq is received
		 * Handle rare cases where the ctl_start_irq is received
		 * after rd_ptr_irq. If it falls within a threshold, it is
		 * after rd_ptr_irq. If it falls within a threshold, it is
		 * guaranteed the frame would be picked up in the current TE.
		 * guaranteed the frame would be picked up in the current TE.
		 * Signal retire fence immediately in such case.
		 * 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 <= SDE_ENC_CTL_START_THRESHOLD_US)
		if ((time_diff_us <= cmd_enc->ctl_start_threshold)
			    && atomic_add_unless(
			    && atomic_add_unless(
				&phys_enc->pending_retire_fence_cnt, -1, 0)) {
				&phys_enc->pending_retire_fence_cnt, -1, 0)) {


@@ -893,7 +895,8 @@ void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc,
	}
	}
}
}


static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc)
static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc,
	u32 *extra_frame_trigger_time)
{
{
	struct drm_connector *conn = phys_enc->connector;
	struct drm_connector *conn = phys_enc->connector;
	u32 qsync_mode;
	u32 qsync_mode;
@@ -902,6 +905,7 @@ static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc)
	struct sde_encoder_phys_cmd *cmd_enc =
	struct sde_encoder_phys_cmd *cmd_enc =
			to_sde_encoder_phys_cmd(phys_enc);
			to_sde_encoder_phys_cmd(phys_enc);


	*extra_frame_trigger_time = 0;
	if (!conn || !conn->state)
	if (!conn || !conn->state)
		return 0;
		return 0;


@@ -955,6 +959,8 @@ static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc)


		SDE_EVT32(qsync_mode, qsync_min_fps, extra_time_ns, default_fps,
		SDE_EVT32(qsync_mode, qsync_min_fps, extra_time_ns, default_fps,
			yres, threshold_lines);
			yres, threshold_lines);

		*extra_frame_trigger_time = extra_time_ns;
	}
	}


exit:
exit:
@@ -971,7 +977,7 @@ static void sde_encoder_phys_cmd_tearcheck_config(
	struct sde_hw_tear_check tc_cfg = { 0 };
	struct sde_hw_tear_check tc_cfg = { 0 };
	struct drm_display_mode *mode;
	struct drm_display_mode *mode;
	bool tc_enable = true;
	bool tc_enable = true;
	u32 vsync_hz;
	u32 vsync_hz, extra_frame_trigger_time;
	struct msm_drm_private *priv;
	struct msm_drm_private *priv;
	struct sde_kms *sde_kms;
	struct sde_kms *sde_kms;


@@ -1035,11 +1041,15 @@ static void sde_encoder_phys_cmd_tearcheck_config(
	 */
	 */
	tc_cfg.sync_cfg_height = 0xFFF0;
	tc_cfg.sync_cfg_height = 0xFFF0;
	tc_cfg.vsync_init_val = mode->vdisplay;
	tc_cfg.vsync_init_val = mode->vdisplay;
	tc_cfg.sync_threshold_start = _get_tearcheck_threshold(phys_enc);
	tc_cfg.sync_threshold_start = _get_tearcheck_threshold(phys_enc,
			&extra_frame_trigger_time);
	tc_cfg.sync_threshold_continue = DEFAULT_TEARCHECK_SYNC_THRESH_CONTINUE;
	tc_cfg.sync_threshold_continue = DEFAULT_TEARCHECK_SYNC_THRESH_CONTINUE;
	tc_cfg.start_pos = mode->vdisplay;
	tc_cfg.start_pos = mode->vdisplay;
	tc_cfg.rd_ptr_irq = mode->vdisplay + 1;
	tc_cfg.rd_ptr_irq = mode->vdisplay + 1;


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

	SDE_DEBUG_CMDENC(cmd_enc,
	SDE_DEBUG_CMDENC(cmd_enc,
		"tc %d intf %d vsync_clk_speed_hz %u vtotal %u vrefresh %u\n",
		"tc %d intf %d vsync_clk_speed_hz %u vtotal %u vrefresh %u\n",
		phys_enc->hw_pp->idx - PINGPONG_0,
		phys_enc->hw_pp->idx - PINGPONG_0,
@@ -1057,11 +1067,12 @@ static void sde_encoder_phys_cmd_tearcheck_config(
		tc_cfg.hw_vsync_mode, tc_cfg.vsync_count,
		tc_cfg.hw_vsync_mode, tc_cfg.vsync_count,
		tc_cfg.vsync_init_val);
		tc_cfg.vsync_init_val);
	SDE_DEBUG_CMDENC(cmd_enc,
	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_pp->idx - PINGPONG_0,
		phys_enc->hw_intf->idx - INTF_0,
		phys_enc->hw_intf->idx - INTF_0,
		tc_cfg.sync_cfg_height,
		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) {
	if (phys_enc->has_intf_te) {
		phys_enc->hw_intf->ops.setup_tearcheck(phys_enc->hw_intf,
		phys_enc->hw_intf->ops.setup_tearcheck(phys_enc->hw_intf,
@@ -1333,6 +1344,7 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
	struct sde_encoder_phys_cmd *cmd_enc =
	struct sde_encoder_phys_cmd *cmd_enc =
			to_sde_encoder_phys_cmd(phys_enc);
			to_sde_encoder_phys_cmd(phys_enc);
	int ret;
	int ret;
	u32 extra_frame_trigger_time;


	if (!phys_enc || !phys_enc->hw_pp) {
	if (!phys_enc || !phys_enc->hw_pp) {
		SDE_ERROR("invalid encoder\n");
		SDE_ERROR("invalid encoder\n");
@@ -1359,7 +1371,8 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(


	if (sde_connector_qsync_updated(phys_enc->connector)) {
	if (sde_connector_qsync_updated(phys_enc->connector)) {
		tc_cfg.sync_threshold_start =
		tc_cfg.sync_threshold_start =
			_get_tearcheck_threshold(phys_enc);
			_get_tearcheck_threshold(phys_enc,
				&extra_frame_trigger_time);
		if (phys_enc->has_intf_te &&
		if (phys_enc->has_intf_te &&
				phys_enc->hw_intf->ops.update_tearcheck)
				phys_enc->hw_intf->ops.update_tearcheck)
			phys_enc->hw_intf->ops.update_tearcheck(
			phys_enc->hw_intf->ops.update_tearcheck(
@@ -1367,8 +1380,12 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
		else if (phys_enc->hw_pp->ops.update_tearcheck)
		else if (phys_enc->hw_pp->ops.update_tearcheck)
			phys_enc->hw_pp->ops.update_tearcheck(
			phys_enc->hw_pp->ops.update_tearcheck(
					phys_enc->hw_pp, &tc_cfg);
					phys_enc->hw_pp, &tc_cfg);

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


	SDE_DEBUG_CMDENC(cmd_enc, "pp:%d pending_cnt %d\n",
	SDE_DEBUG_CMDENC(cmd_enc, "pp:%d pending_cnt %d\n",
@@ -1675,6 +1692,7 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init(
	phys_enc->enc_spinlock = p->enc_spinlock;
	phys_enc->enc_spinlock = p->enc_spinlock;
	phys_enc->vblank_ctl_lock = p->vblank_ctl_lock;
	phys_enc->vblank_ctl_lock = p->vblank_ctl_lock;
	cmd_enc->stream_sel = 0;
	cmd_enc->stream_sel = 0;
	cmd_enc->ctl_start_threshold = SDE_ENC_CTL_START_THRESHOLD_US;
	phys_enc->enable_state = SDE_ENC_DISABLED;
	phys_enc->enable_state = SDE_ENC_DISABLED;
	sde_encoder_phys_cmd_init_ops(&phys_enc->ops);
	sde_encoder_phys_cmd_init_ops(&phys_enc->ops);
	phys_enc->comp_type = p->comp_type;
	phys_enc->comp_type = p->comp_type;