Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3f82428a authored by Yashwanth's avatar Yashwanth
Browse files

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: default avatarYashwanth <yvulapu@codeaurora.org>
parent 9122159c
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
/* 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;
};

/**
+34 −0
Original line number Diff line number Diff line
@@ -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) {