Преглед изворни кода

disp: msm: sde: override tearcheck rd_ptr_val when qsync is enabled

When qsync is enabled with a large threshold start window, there
is a chance that two frames can be latched by mdp HW in single
vsync window. This change overrides the tearcheck rd_ptr_val
to a value larger than the end of the Tear check start window
to ensure new frame is not latched in current vsync window.

Change-Id: I21273f0bca83747210792b911e964dfd2d50079f
Signed-off-by: Jayaprakash Madisetty <[email protected]>
Signed-off-by: Narendra Muppalla <[email protected]>
Jayaprakash Madisetty пре 3 година
родитељ
комит
a6658ee7e9
4 измењених фајлова са 67 додато и 4 уклоњено
  1. 2 0
      msm/sde/sde_encoder_phys.h
  2. 41 4
      msm/sde/sde_encoder_phys_cmd.c
  3. 17 0
      msm/sde/sde_hw_intf.c
  4. 7 0
      msm/sde/sde_hw_intf.h

+ 2 - 0
msm/sde/sde_encoder_phys.h

@@ -415,6 +415,7 @@ struct sde_encoder_phys_cmd_te_timestamp {
  * @wr_ptr_wait_success: log wr_ptr_wait success for release fence trigger
  * @te_timestamp_list: List head for the TE timestamp list
  * @te_timestamp: Array of size MAX_TE_PROFILE_COUNT te_timestamp_list elements
+ * @qsync_threshold_lines: tearcheck threshold lines calculated based on qsync_min_fps
  */
 struct sde_encoder_phys_cmd {
 	struct sde_encoder_phys base;
@@ -427,6 +428,7 @@ struct sde_encoder_phys_cmd {
 	struct list_head te_timestamp_list;
 	struct sde_encoder_phys_cmd_te_timestamp
 			te_timestamp[MAX_TE_PROFILE_COUNT];
+	u32 qsync_threshold_lines;
 };
 
 /**

+ 41 - 4
msm/sde/sde_encoder_phys_cmd.c

@@ -171,6 +171,37 @@ static void _sde_encoder_phys_cmd_update_intf_cfg(
 	}
 }
 
+static void sde_encoder_override_tearcheck_rd_ptr(struct sde_encoder_phys *phys_enc)
+{
+	struct sde_hw_intf *hw_intf;
+	struct drm_display_mode *mode;
+	struct sde_encoder_phys_cmd *cmd_enc;
+	struct sde_hw_pp_vsync_info info[MAX_CHANNELS_PER_ENC] = {{0}};
+	u32 adjusted_tear_rd_ptr_line_cnt;
+
+	if (!phys_enc || !phys_enc->hw_intf)
+		return;
+
+	cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
+	hw_intf = phys_enc->hw_intf;
+	mode = &phys_enc->cached_mode;
+
+	/* Configure TE rd_ptr_val to the end of qsync Start Window.
+	 * This ensures next frame trigger_start does not get latched in the current
+	 * vsync window.
+	 */
+	adjusted_tear_rd_ptr_line_cnt = mode->vdisplay + cmd_enc->qsync_threshold_lines + 1;
+
+	if (hw_intf && hw_intf->ops.override_tear_rd_ptr_val)
+		hw_intf->ops.override_tear_rd_ptr_val(hw_intf, adjusted_tear_rd_ptr_line_cnt);
+
+	sde_encoder_helper_get_pp_line_count(phys_enc->parent, info);
+	SDE_EVT32_VERBOSE(phys_enc->hw_intf->idx - INTF_0, mode->vdisplay,
+		cmd_enc->qsync_threshold_lines, info[0].rd_ptr_line_count,
+		info[0].rd_ptr_frame_count, info[0].wr_ptr_line_count,
+		info[1].rd_ptr_line_count, info[1].rd_ptr_frame_count, info[1].wr_ptr_line_count);
+}
+
 static void _sde_encoder_phys_signal_frame_done(struct sde_encoder_phys *phys_enc)
 {
 	struct sde_encoder_phys_cmd *cmd_enc;
@@ -309,9 +340,9 @@ static void sde_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx)
 	sde_encoder_helper_get_pp_line_count(phys_enc->parent, info);
 	SDE_EVT32_IRQ(DRMID(phys_enc->parent),
 		info[0].pp_idx, info[0].intf_idx,
-		info[0].wr_ptr_line_count, info[0].intf_frame_count,
+		info[0].wr_ptr_line_count, info[0].intf_frame_count, info[0].rd_ptr_line_count,
 		info[1].pp_idx, info[1].intf_idx,
-		info[1].wr_ptr_line_count, info[1].intf_frame_count,
+		info[1].wr_ptr_line_count, info[1].intf_frame_count, info[1].rd_ptr_line_count,
 		scheduler_status, fence_ready);
 
 	if (phys_enc->parent_ops.handle_vblank_virt)
@@ -327,7 +358,7 @@ static void sde_encoder_phys_cmd_wr_ptr_irq(void *arg, int irq_idx)
 {
 	struct sde_encoder_phys *phys_enc = arg;
 	struct sde_hw_ctl *ctl;
-	u32 event = 0;
+	u32 event = 0, qsync_mode = 0;
 	struct sde_hw_pp_vsync_info info[MAX_CHANNELS_PER_ENC] = {{0}};
 
 	if (!phys_enc || !phys_enc->hw_ctl)
@@ -335,6 +366,7 @@ static void sde_encoder_phys_cmd_wr_ptr_irq(void *arg, int irq_idx)
 
 	SDE_ATRACE_BEGIN("wr_ptr_irq");
 	ctl = phys_enc->hw_ctl;
+	qsync_mode = sde_connector_get_qsync_mode(phys_enc->connector);
 
 	if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0)) {
 		event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
@@ -350,7 +382,10 @@ static void sde_encoder_phys_cmd_wr_ptr_irq(void *arg, int irq_idx)
 	SDE_EVT32_IRQ(DRMID(phys_enc->parent),
 		ctl->idx - CTL_0, event,
 		info[0].pp_idx, info[0].intf_idx, info[0].wr_ptr_line_count,
-		info[1].pp_idx, info[1].intf_idx, info[1].wr_ptr_line_count);
+		info[1].pp_idx, info[1].intf_idx, info[1].wr_ptr_line_count, qsync_mode);
+
+	if (qsync_mode)
+		sde_encoder_override_tearcheck_rd_ptr(phys_enc);
 
 	/* Signal any waiting wr_ptr start interrupt */
 	wake_up_all(&phys_enc->pending_kickoff_wq);
@@ -1092,6 +1127,7 @@ static void sde_encoder_phys_cmd_tearcheck_config(
 	tc_cfg.start_pos = mode->vdisplay;
 	tc_cfg.rd_ptr_irq = mode->vdisplay + 1;
 	tc_cfg.wr_ptr_irq = 1;
+	cmd_enc->qsync_threshold_lines = tc_cfg.sync_threshold_start;
 
 	SDE_DEBUG_CMDENC(cmd_enc,
 	  "tc %d intf %d vsync_clk_speed_hz %u vtotal %u vrefresh %u\n",
@@ -1418,6 +1454,7 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
 	if (sde_connector_is_qsync_updated(phys_enc->connector)) {
 		tc_cfg.sync_threshold_start = _get_tearcheck_threshold(
 				phys_enc);
+		cmd_enc->qsync_threshold_lines = tc_cfg.sync_threshold_start;
 		if (phys_enc->has_intf_te &&
 				phys_enc->hw_intf->ops.update_tearcheck)
 			phys_enc->hw_intf->ops.update_tearcheck(

+ 17 - 0
msm/sde/sde_hw_intf.c

@@ -858,6 +858,21 @@ static int sde_hw_intf_v1_check_and_reset_tearcheck(struct sde_hw_intf *intf,
 	return 0;
 }
 
+static void sde_hw_intf_override_tear_rd_ptr_val(struct sde_hw_intf *intf,
+		u32 adjusted_rd_ptr_val)
+{
+	struct sde_hw_blk_reg_map *c;
+
+	if (!intf || !adjusted_rd_ptr_val)
+		return;
+
+	c = &intf->hw;
+
+	SDE_REG_WRITE(c, INTF_TEAR_SYNC_WRCOUNT, (adjusted_rd_ptr_val & 0xFFFF));
+	/* ensure rd_ptr_val is written */
+	wmb();
+}
+
 static void sde_hw_intf_vsync_sel(struct sde_hw_intf *intf,
 		u32 vsync_source)
 {
@@ -956,6 +971,8 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
 		ops->vsync_sel = sde_hw_intf_vsync_sel;
 		ops->check_and_reset_tearcheck =
 			sde_hw_intf_v1_check_and_reset_tearcheck;
+		ops->override_tear_rd_ptr_val =
+			sde_hw_intf_override_tear_rd_ptr_val;
 	}
 
 	if (cap & BIT(SDE_INTF_RESET_COUNTER))

+ 7 - 0
msm/sde/sde_hw_intf.h

@@ -247,6 +247,13 @@ struct sde_hw_intf_ops {
 	 * Get the INTF interrupt status
 	 */
 	u32 (*get_intr_status)(struct sde_hw_intf *intf);
+
+	/**
+	 * Override tear check rd_ptr_val with adjusted_linecnt
+	 * when qsync is enabled.
+	 */
+	void (*override_tear_rd_ptr_val)(struct sde_hw_intf *intf,
+			u32 adjusted_linecnt);
 };
 
 struct sde_hw_intf {