From 3f82428a39077c07c32369c1ba2ae8984f8ccf0d Mon Sep 17 00:00:00 2001 From: Yashwanth Date: Thu, 8 Jul 2021 13:50:26 +0530 Subject: [PATCH] disp: msm: sde: add frame trigger count to detect frame count in TE period When qsync is enabled, if there is a large start threshold window, there might be a case where two frame transfers could happen in single TE period if second frame trigger start is issued within the window and could cause tearing on the screen. This change adds a atomic variable to detect multiple frame count and adds vsync wait in such cases to fix this issue. This variable will be set whenever wr_ptr_irq arrives and will be reset during rd_ptr_irq. Change-Id: Ice77b8a717a18d39d70dc08647e15b761ad1c126 Signed-off-by: Yashwanth --- msm/sde/sde_encoder_phys.h | 4 +++- msm/sde/sde_encoder_phys_cmd.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) 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) {