diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index 019130364b0a..710c1aff62b0 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #ifndef __SDE_ENCODER_PHYS_H__ @@ -394,6 +394,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 + * @frame_trigger_count: atomic counter tracking number of frame triggers per TE interval */ struct sde_encoder_phys_cmd { struct sde_encoder_phys base; @@ -406,6 +407,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]; + atomic_t frame_trigger_count; }; /** diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index a6acf9f31a85..e9c456aaa6d8 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/msm/sde/sde_encoder_phys_cmd.c @@ -241,6 +241,7 @@ static void sde_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx) struct sde_hw_pp_vsync_info info[MAX_CHANNELS_PER_ENC] = {{0}}; struct sde_encoder_phys_cmd_te_timestamp *te_timestamp; unsigned long lock_flags; + struct drm_display_mode *mode; if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) return; @@ -270,6 +271,11 @@ static void sde_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx) info[1].wr_ptr_line_count, info[1].intf_frame_count, scheduler_status); + mode = &phys_enc->cached_mode; + if (!mode || info[0].wr_ptr_line_count == mode->vdisplay || + !info[0].wr_ptr_line_count) + atomic_add_unless(&cmd_enc->frame_trigger_count, -1, 0); + if (phys_enc->parent_ops.handle_vblank_virt) phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent, phys_enc); @@ -285,12 +291,16 @@ static void sde_encoder_phys_cmd_wr_ptr_irq(void *arg, int irq_idx) struct sde_hw_ctl *ctl; u32 event = 0; struct sde_hw_pp_vsync_info info[MAX_CHANNELS_PER_ENC] = {{0}}; + struct sde_encoder_phys_cmd *cmd_enc; if (!phys_enc || !phys_enc->hw_ctl) return; SDE_ATRACE_BEGIN("wr_ptr_irq"); ctl = phys_enc->hw_ctl; + cmd_enc = to_sde_encoder_phys_cmd(phys_enc); + + atomic_inc(&cmd_enc->frame_trigger_count); if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0)) { event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE; @@ -1923,10 +1933,34 @@ static void sde_encoder_phys_cmd_trigger_start( struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); u32 frame_cnt; + struct drm_connector *conn; + int threshold_lines, curr_rd_ptr_line_count; + struct sde_hw_pp_vsync_info info[MAX_CHANNELS_PER_ENC] = {{0}}; + struct drm_display_mode *mode; if (!phys_enc) return; + conn = phys_enc->connector; + mode = &phys_enc->cached_mode; + if (mode && sde_connector_get_qsync_mode(conn)) { + threshold_lines = _get_tearcheck_threshold(phys_enc); + sde_encoder_helper_get_pp_line_count(phys_enc->parent, info); + curr_rd_ptr_line_count = info[0].rd_ptr_line_count; + + /* + * Vsync wait is required only if both the below conditions satisfy + * - current rd_ptr linecount is within the start threshold window + * - frame trigger already happened in this TE interval + */ + if ((curr_rd_ptr_line_count < mode->vdisplay + threshold_lines) && + atomic_read(&cmd_enc->frame_trigger_count)) { + SDE_EVT32(curr_rd_ptr_line_count, mode->vdisplay + threshold_lines, + atomic_read(&cmd_enc->frame_trigger_count), 0xebad); + sde_encoder_phys_cmd_wait_for_vblank(phys_enc); + } + } + /* we don't issue CTL_START when using autorefresh */ frame_cnt = _sde_encoder_phys_cmd_get_autorefresh_property(phys_enc); if (frame_cnt) {