diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index dcea4cd00a..5d5bdee228 100644 --- a/msm/sde/sde_encoder.c +++ b/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; + ktime_t jitter_ns, frametime_ns; - if (!drm_enc) { - SDE_ERROR("invalid encoder\n"); - return; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - info = &sde_enc->mode_info; - - 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; diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index 457b384363..a48650cc34 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/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 + * @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(struct drm_encoder *encoder, - u64 *l_bound, u64 *u_bound); +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 diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index 18ee62dc06..0afbb7dbf4 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/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); - threshold_lines = extra_time_ns / default_line_time_ns; + 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; + + 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( @@ -1485,17 +1510,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;