Răsfoiți Sursa

Merge "disp: msm: sde: improve qsync trigger window accuracy"

qctecmdr 2 ani în urmă
părinte
comite
48dc1006fd
3 a modificat fișierele cu 74 adăugiri și 48 ștergeri
  1. 7 16
      msm/sde/sde_encoder.c
  2. 9 4
      msm/sde/sde_encoder_phys.h
  3. 58 28
      msm/sde/sde_encoder_phys_cmd.c

+ 7 - 16
msm/sde/sde_encoder.c

@@ -5622,24 +5622,15 @@ int sde_encoder_wait_for_event(struct drm_encoder *drm_enc,
 	return ret;
 }
 
-void sde_encoder_helper_get_jitter_bounds_ns(struct drm_encoder *drm_enc,
-		u64 *l_bound, u64 *u_bound)
+void sde_encoder_helper_get_jitter_bounds_ns(u32 frame_rate,
+		u32 jitter_num, u32 jitter_denom,
+		ktime_t *l_bound, ktime_t *u_bound)
 {
-	struct sde_encoder_virt *sde_enc;
-	u64 jitter_ns, frametime_ns;
-	struct msm_mode_info *info;
-
-	if (!drm_enc) {
-		SDE_ERROR("invalid encoder\n");
-		return;
-	}
-
-	sde_enc = to_sde_encoder_virt(drm_enc);
-	info = &sde_enc->mode_info;
+	ktime_t jitter_ns, frametime_ns;
 
-	frametime_ns = (1 * 1000000000) / info->frame_rate;
-	jitter_ns =  info->jitter_numer * frametime_ns;
-	do_div(jitter_ns, info->jitter_denom * 100);
+	frametime_ns = (1 * 1000000000) / frame_rate;
+	jitter_ns =  jitter_num * frametime_ns;
+	do_div(jitter_ns, jitter_denom * 100);
 
 	*l_bound = frametime_ns - jitter_ns;
 	*u_bound = frametime_ns + jitter_ns;

+ 9 - 4
msm/sde/sde_encoder_phys.h

@@ -607,10 +607,15 @@ int sde_encoder_helper_wait_event_timeout(
 
 /*
  * sde_encoder_get_fps - get the allowed panel jitter in nanoseconds
- * @encoder: Pointer to drm encoder object
- */
-void sde_encoder_helper_get_jitter_bounds_ns(struct drm_encoder *encoder,
-			u64 *l_bound, u64 *u_bound);
+ * @frame_rate: custom input frame rate
+ * @jitter_num: jitter numerator value
+ * @jitter_denom: jitter denomerator value,
+ * @l_bound: lower frame period boundary
+ * @u_bound: upper frame period boundary
+ */
+void sde_encoder_helper_get_jitter_bounds_ns(uint32_t frame_rate,
+			u32 jitter_num, u32 jitter_denom,
+			ktime_t *l_bound, ktime_t *u_bound);
 
 /**
  * sde_encoder_helper_switch_vsync - switch vsync source to WD or default

+ 58 - 28
msm/sde/sde_encoder_phys_cmd.c

@@ -197,8 +197,8 @@ static void sde_encoder_override_tearcheck_rd_ptr(struct sde_encoder_phys *phys_
 
 	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,
+		cmd_enc->qsync_threshold_lines, adjusted_tear_rd_ptr_line_cnt,
+		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);
 }
 
@@ -987,28 +987,34 @@ static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc)
 	struct drm_connector *conn = phys_enc->connector;
 	u32 qsync_mode;
 	struct drm_display_mode *mode;
-	u32 threshold_lines = DEFAULT_TEARCHECK_SYNC_THRESH_START;
+	u32 threshold_lines, adjusted_threshold_lines;
 	struct sde_encoder_phys_cmd *cmd_enc =
 			to_sde_encoder_phys_cmd(phys_enc);
+	struct sde_encoder_virt *sde_enc;
+	struct msm_mode_info *info;
 
 	if (!conn || !conn->state)
 		return 0;
 
+	sde_enc = to_sde_encoder_virt(phys_enc->parent);
+	info = &sde_enc->mode_info;
 	mode = &phys_enc->cached_mode;
 	qsync_mode = sde_connector_get_qsync_mode(conn);
+	threshold_lines = adjusted_threshold_lines = DEFAULT_TEARCHECK_SYNC_THRESH_START;
 
 	if (mode && (qsync_mode == SDE_RM_QSYNC_CONTINUOUS_MODE)) {
 		u32 qsync_min_fps = 0;
+		ktime_t qsync_time_ns;
+		ktime_t qsync_l_bound_ns, qsync_u_bound_ns;
 		u32 default_fps = drm_mode_vrefresh(mode);
+		ktime_t default_time_ns;
+		ktime_t default_line_time_ns;
+		ktime_t extra_time_ns;
 		u32 yres = mode->vtotal;
-		u32 slow_time_ns;
-		u32 default_time_ns;
-		u32 extra_time_ns;
-		u32 default_line_time_ns;
 
 		if (phys_enc->parent_ops.get_qsync_fps)
-			phys_enc->parent_ops.get_qsync_fps(
-				phys_enc->parent, &qsync_min_fps, conn->state);
+			phys_enc->parent_ops.get_qsync_fps(phys_enc->parent, &qsync_min_fps,
+					conn->state);
 
 		if (!qsync_min_fps || !default_fps || !yres) {
 			SDE_ERROR_CMDENC(cmd_enc,
@@ -1024,32 +1030,51 @@ static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc)
 			goto exit;
 		}
 
-		/* Calculate the number of extra lines*/
-		slow_time_ns = DIV_ROUND_UP(1000000000, qsync_min_fps);
-		default_time_ns = DIV_ROUND_UP(1000000000, default_fps);
-		extra_time_ns = slow_time_ns - default_time_ns;
-		default_line_time_ns = DIV_ROUND_UP(default_time_ns, yres);
+		/*
+		 * Calculate safe qsync trigger window by compensating
+		 * the qsync timeout period by panel jitter value.
+		 *
+		 * qsync_safe_window_period = qsync_timeout_period * (1 - jitter) - nominal_period
+		 * nominal_line_time = nominal_period / vtotal
+		 * qsync_safe_window_lines = qsync_safe_window_period / nominal_line_time
+		 */
+		qsync_time_ns = mult_frac(1000000000, 1, qsync_min_fps);
+		default_time_ns = mult_frac(1000000000, 1, default_fps);
+
+		sde_encoder_helper_get_jitter_bounds_ns(qsync_min_fps, info->jitter_numer,
+				info->jitter_denom, &qsync_l_bound_ns, &qsync_u_bound_ns);
+		if (!qsync_l_bound_ns || !qsync_u_bound_ns)
+			qsync_l_bound_ns = qsync_u_bound_ns = qsync_time_ns;
 
-		threshold_lines = extra_time_ns / default_line_time_ns;
+		extra_time_ns = qsync_l_bound_ns - default_time_ns;
+		default_line_time_ns = mult_frac(1, default_time_ns, yres);
+		threshold_lines = mult_frac(1, extra_time_ns, default_line_time_ns);
 
 		/* some DDICs express the timeout value in lines/4, round down to compensate */
-		threshold_lines = round_down(threshold_lines, 4);
+		adjusted_threshold_lines = round_down(threshold_lines, 4);
 		/* remove 2 lines to cover for latency */
-		if (threshold_lines - 2 > DEFAULT_TEARCHECK_SYNC_THRESH_START)
-			threshold_lines -= 2;
+		if (adjusted_threshold_lines - 2 > DEFAULT_TEARCHECK_SYNC_THRESH_START)
+			adjusted_threshold_lines -= 2;
 
-		SDE_DEBUG_CMDENC(cmd_enc, "slow:%d default:%d extra:%d(ns)\n",
-			slow_time_ns, default_time_ns, extra_time_ns);
-		SDE_DEBUG_CMDENC(cmd_enc, "min_fps:%d fps:%d yres:%d lines:%d\n",
-			qsync_min_fps, default_fps, yres, threshold_lines);
+		SDE_DEBUG_CMDENC(cmd_enc,
+			"qsync mode:%u min_fps:%u time:%lld low:%lld up:%lld jitter:%u/%u\n",
+			qsync_mode, qsync_min_fps, qsync_time_ns, qsync_l_bound_ns,
+			qsync_u_bound_ns, info->jitter_numer, info->jitter_denom);
+		SDE_DEBUG_CMDENC(cmd_enc,
+			"default fps:%u time:%lld yres:%u line_time:%lld\n",
+			default_fps, default_time_ns, yres, default_line_time_ns);
+		SDE_DEBUG_CMDENC(cmd_enc,
+			"extra_time:%lld  threshold_lines:%u adjusted_threshold_lines:%u\n",
+			extra_time_ns, threshold_lines, adjusted_threshold_lines);
 
-		SDE_EVT32(qsync_mode, qsync_min_fps, extra_time_ns, default_fps,
-			yres, threshold_lines);
+		SDE_EVT32(qsync_mode, qsync_min_fps, default_fps, info->jitter_numer,
+				info->jitter_denom, yres, extra_time_ns, default_line_time_ns,
+				adjusted_threshold_lines);
 	}
 
 exit:
 
-	return threshold_lines;
+	return adjusted_threshold_lines;
 }
 
 static void sde_encoder_phys_cmd_tearcheck_config(
@@ -1500,17 +1525,22 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
 static bool _sde_encoder_phys_cmd_needs_vsync_change(
 		struct sde_encoder_phys *phys_enc, ktime_t profile_timestamp)
 {
+	struct sde_encoder_virt *sde_enc;
 	struct sde_encoder_phys_cmd *cmd_enc;
 	struct sde_encoder_phys_cmd_te_timestamp *cur;
 	struct sde_encoder_phys_cmd_te_timestamp *prev = NULL;
 	ktime_t time_diff;
-	u64 l_bound = 0, u_bound = 0;
+	struct msm_mode_info *info;
+	ktime_t l_bound = 0, u_bound = 0;
 	bool ret = false;
 	unsigned long lock_flags;
 
 	cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
-	sde_encoder_helper_get_jitter_bounds_ns(phys_enc->parent,
-							&l_bound, &u_bound);
+	sde_enc = to_sde_encoder_virt(phys_enc->parent);
+	info = &sde_enc->mode_info;
+
+	sde_encoder_helper_get_jitter_bounds_ns(info->frame_rate, info->jitter_numer,
+			info->jitter_denom, &l_bound, &u_bound);
 	if (!l_bound || !u_bound) {
 		SDE_ERROR_CMDENC(cmd_enc, "invalid vsync jitter bounds\n");
 		return false;