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

Commit d403cd67 authored by Karthik Andhavarapu's avatar Karthik Andhavarapu
Browse files

disp: msm: sde: avoid tx wait during cwb disable and reset



TX wait during CWB encoder disable can cause a jank, as we
are not able to flush before next vsync due to delay in wait.
Changes are made to avoid TX wait during disable, separate and
delay reset encoder call till CWB frame done trigger, so that
there will be enough time to flush before next vsync.

Change-Id: Ib0e8561f4727523ec6520528beb855ae972e6909
Signed-off-by: default avatarKarthik Andhavarapu <kartkart@codeaurora.org>
parent 20c1e5e6
Loading
Loading
Loading
Loading
+61 −22
Original line number Diff line number Diff line
@@ -931,6 +931,29 @@ bool sde_encoder_in_clone_mode(struct drm_encoder *drm_enc)
	return false;
}

bool sde_encoder_is_cwb_disabling(struct drm_encoder *drm_enc,
	struct drm_crtc *crtc)
{
	struct sde_encoder_virt *sde_enc;
	int i;

	if (!drm_enc)
		return false;

	sde_enc = to_sde_encoder_virt(drm_enc);
	if (sde_enc->disp_info.intf_type != DRM_MODE_CONNECTOR_VIRTUAL)
		return false;

	for (i = 0; i < sde_enc->num_phys_encs; i++) {
		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];

		if (sde_encoder_phys_is_cwb_disabling(phys, crtc))
			return true;
	}

	return false;
}

static int _sde_encoder_atomic_check_phys_enc(struct sde_encoder_virt *sde_enc,
	struct drm_crtc_state *crtc_state,
	struct drm_connector_state *conn_state)
@@ -2003,8 +2026,13 @@ static int _sde_encoder_update_rsc_client(
		qsync_mode = sde_connector_get_qsync_mode(
				sde_enc->cur_master->connector);

	if (sde_encoder_in_clone_mode(drm_enc) ||
			(disp_info->display_type != SDE_CONNECTOR_PRIMARY) ||
	/* left primary encoder keep vote */
	if (sde_encoder_in_clone_mode(drm_enc)) {
		SDE_EVT32(rsc_state, SDE_EVTLOG_FUNC_CASE1);
		return 0;
	}

	if ((disp_info->display_type != SDE_CONNECTOR_PRIMARY) ||
			(disp_info->display_type && qsync_mode))
		rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE;
	else if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
@@ -3410,6 +3438,33 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
	_sde_encoder_virt_enable_helper(drm_enc);
}

void sde_encoder_virt_reset(struct drm_encoder *drm_enc)
{
	struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
	struct sde_kms *sde_kms = sde_encoder_get_kms(drm_enc);
	int i = 0;

	for (i = 0; i < sde_enc->num_phys_encs; i++) {
		if (sde_enc->phys_encs[i]) {
			sde_enc->phys_encs[i]->cont_splash_enabled = false;
			sde_enc->phys_encs[i]->connector = NULL;
		}
		atomic_set(&sde_enc->frame_done_cnt[i], 0);
	}

	sde_enc->cur_master = NULL;
	/*
	 * clear the cached crtc in sde_enc on use case finish, after all the
	 * outstanding events and timers have been completed
	 */
	sde_enc->crtc = NULL;
	memset(&sde_enc->mode_info, 0, sizeof(sde_enc->mode_info));

	SDE_DEBUG_ENC(sde_enc, "encoder disabled\n");

	sde_rm_release(&sde_kms->rm, drm_enc, false);
}

static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
{
	struct sde_encoder_virt *sde_enc = NULL;
@@ -3444,6 +3499,7 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
	SDE_EVT32(DRMID(drm_enc));

	/* wait for idle */
	if (!sde_encoder_in_clone_mode(drm_enc))
		sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE);

	_sde_encoder_input_handler_unregister(drm_enc);
@@ -3487,25 +3543,8 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)

	sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_STOP);

	for (i = 0; i < sde_enc->num_phys_encs; i++) {
		if (sde_enc->phys_encs[i]) {
			sde_enc->phys_encs[i]->cont_splash_enabled = false;
			sde_enc->phys_encs[i]->connector = NULL;
		}
		atomic_set(&sde_enc->frame_done_cnt[i], 0);
	}

	sde_enc->cur_master = NULL;
	/*
	 * clear the cached crtc in sde_enc on use case finish, after all the
	 * outstanding events and timers have been completed
	 */
	sde_enc->crtc = NULL;
	memset(&sde_enc->mode_info, 0, sizeof(sde_enc->mode_info));

	SDE_DEBUG_ENC(sde_enc, "encoder disabled\n");

	sde_rm_release(&sde_kms->rm, drm_enc, false);
	if (!sde_encoder_in_clone_mode(drm_enc))
		sde_encoder_virt_reset(drm_enc);
}

void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc,
+37 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 * Copyright (C) 2013 Red Hat
 * Author: Rob Clark <robdclark@gmail.com>
 *
@@ -313,6 +313,15 @@ void sde_encoder_recovery_events_handler(struct drm_encoder *encoder,
 */
bool sde_encoder_in_clone_mode(struct drm_encoder *enc);

/*
 * sde_encoder_is_cwb_disabling - check if cwb encoder disable is pending
 * @drm_enc:    Pointer to drm encoder structure
 * @drm_crtc:    Pointer to drm crtc structure
 * @Return: true if cwb encoder disable is pending
 */
bool sde_encoder_is_cwb_disabling(struct drm_encoder *drm_enc,
	struct drm_crtc *drm_crtc);

/**
 * sde_encoder_is_primary_display - checks if underlying display is primary
 *     display or not.
@@ -356,4 +365,31 @@ void sde_encoder_needs_hw_reset(struct drm_encoder *enc);
 */
void sde_encoder_uidle_enable(struct drm_encoder *drm_enc, bool enable);

/**
 * sde_encoder_virt_reset - delay encoder virt reset
 * @drm_enc:	Pointer to drm encoder structure
 */
void sde_encoder_virt_reset(struct drm_encoder *drm_enc);

/**
 * sde_encoder_get_kms - retrieve the kms from encoder
 * @drm_enc:    Pointer to drm encoder structure
 */
static inline struct sde_kms *sde_encoder_get_kms(struct drm_encoder *drm_enc)
{
	struct msm_drm_private *priv;

	if (!drm_enc || !drm_enc->dev) {
		SDE_ERROR("invalid encoder\n");
		return NULL;
	}
	priv = drm_enc->dev->dev_private;
	if (!priv || !priv->kms) {
		SDE_ERROR("invalid kms\n");
		return NULL;
	}

	return to_sde_kms(priv->kms);
}

#endif /* __SDE_ENCODER_H__ */
+21 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 */

#ifndef __SDE_ENCODER_PHYS_H__
@@ -610,6 +610,26 @@ static inline enum sde_3d_blend_mode sde_encoder_helper_get_3d_blend_mode(
	return BLEND_3D_NONE;
}

/**
 * sde_encoder_phys_is_cwb_disabling - Check if CWB encoder attached to this
 *	 CRTC and it is in SDE_ENC_DISABLING state.
 * @phys_enc: Pointer to physical encoder structure
 * @crtc: drm crtc
 * @Return: true if cwb encoder is in disabling state
 */
static inline bool sde_encoder_phys_is_cwb_disabling(
	struct sde_encoder_phys *phys, struct drm_crtc *crtc)
{
	struct sde_encoder_phys_wb *wb_enc;

	if (!phys || !phys->in_clone_mode ||
				phys->enable_state != SDE_ENC_DISABLING)
		return false;

	wb_enc = container_of(phys, struct sde_encoder_phys_wb, base);
	return (wb_enc->crtc == crtc) ? true : false;
}

/**
 * sde_encoder_helper_split_config - split display configuration helper function
 *	This helper function may be used by physical encoders to configure
+51 −23
Original line number Diff line number Diff line
@@ -1035,7 +1035,8 @@ static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error)
	SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0, wb_enc->frame_count);

	/* don't notify upper layer for internal commit */
	if (phys_enc->enable_state == SDE_ENC_DISABLING)
	if (phys_enc->enable_state == SDE_ENC_DISABLING &&
			!phys_enc->in_clone_mode)
		goto complete;

	if (phys_enc->parent_ops.handle_frame_done &&
@@ -1215,6 +1216,32 @@ static int sde_encoder_phys_wb_frame_timeout(struct sde_encoder_phys *phys_enc)
	return event;
}

static void _sde_encoder_phys_wb_reset_state(
		struct sde_encoder_phys *phys_enc)
{
	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);

	/*
	 * frame count and kickoff count are only used for debug purpose. Frame
	 * count can be more than kickoff count at the end of disable call due
	 * to extra frame_done wait. It does not cause any issue because
	 * frame_done wait is based on retire_fence count. Leaving these
	 * counters for debugging purpose.
	 */
	if (wb_enc->frame_count != wb_enc->kickoff_count) {
		SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc),
			wb_enc->kickoff_count, wb_enc->frame_count,
			phys_enc->in_clone_mode);
		wb_enc->frame_count = wb_enc->kickoff_count;
	}

	phys_enc->enable_state = SDE_ENC_DISABLED;
	wb_enc->crtc = NULL;
	phys_enc->hw_cdm = NULL;
	phys_enc->hw_ctl = NULL;
	phys_enc->in_clone_mode = false;
}

static int _sde_encoder_phys_wb_wait_for_commit_done(
		struct sde_encoder_phys *phys_enc, bool is_disable)
{
@@ -1298,7 +1325,18 @@ static int _sde_encoder_phys_wb_wait_for_commit_done(
static int sde_encoder_phys_wb_wait_for_commit_done(
		struct sde_encoder_phys *phys_enc)
{
	return _sde_encoder_phys_wb_wait_for_commit_done(phys_enc, false);
	int rc;

	if (phys_enc->enable_state == SDE_ENC_DISABLING &&
			phys_enc->in_clone_mode) {
		rc = _sde_encoder_phys_wb_wait_for_commit_done(phys_enc, true);
		_sde_encoder_phys_wb_reset_state(phys_enc);
		sde_encoder_phys_wb_irq_ctrl(phys_enc, false);
	} else {
		rc = _sde_encoder_phys_wb_wait_for_commit_done(phys_enc, false);
	}

	return rc;
}

static int sde_encoder_phys_wb_wait_for_cwb_done(
@@ -1582,6 +1620,8 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc)
	SDE_DEBUG("[wait_for_done: wb:%d, frame:%u, kickoff:%u]\n",
			hw_wb->idx - WB_0, wb_enc->frame_count,
			wb_enc->kickoff_count);

	if (!phys_enc->in_clone_mode || !wb_enc->crtc->state->active)
		_sde_encoder_phys_wb_wait_for_commit_done(phys_enc, true);

	if (!phys_enc->hw_ctl || !phys_enc->parent ||
@@ -1590,11 +1630,16 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc)
		goto exit;
	}

	/* avoid reset frame for CWB */
	if (phys_enc->in_clone_mode) {
		_sde_encoder_phys_wb_setup_cwb(phys_enc, false);
		_sde_encoder_phys_wb_update_cwb_flush(phys_enc, false);
		phys_enc->in_clone_mode = false;
		phys_enc->enable_state = SDE_ENC_DISABLING;

		if (wb_enc->crtc->state->active) {
			sde_encoder_phys_wb_irq_ctrl(phys_enc, true);
			return;
		}

		goto exit;
	}

@@ -1627,24 +1672,7 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc)
	sde_encoder_phys_wb_irq_ctrl(phys_enc, false);

exit:
	/*
	 * frame count and kickoff count are only used for debug purpose. Frame
	 * count can be more than kickoff count at the end of disable call due
	 * to extra frame_done wait. It does not cause any issue because
	 * frame_done wait is based on retire_fence count. Leaving these
	 * counters for debugging purpose.
	 */
	if (wb_enc->frame_count != wb_enc->kickoff_count) {
		SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc),
			wb_enc->kickoff_count, wb_enc->frame_count,
			phys_enc->in_clone_mode);
		wb_enc->frame_count = wb_enc->kickoff_count;
	}

	phys_enc->enable_state = SDE_ENC_DISABLED;
	wb_enc->crtc = NULL;
	phys_enc->hw_cdm = NULL;
	phys_enc->hw_ctl = NULL;
	_sde_encoder_phys_wb_reset_state(phys_enc);
}

/**
+12 −2
Original line number Diff line number Diff line
@@ -1216,6 +1216,7 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
	struct drm_encoder *encoder;
	struct drm_device *dev;
	int ret;
	bool cwb_disabling;

	if (!kms || !crtc || !crtc->state) {
		SDE_ERROR("invalid params\n");
@@ -1241,8 +1242,14 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms,

	SDE_ATRACE_BEGIN("sde_kms_wait_for_commit_done");
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
		if (encoder->crtc != crtc)
		cwb_disabling = false;
		if (encoder->crtc != crtc) {
			cwb_disabling = sde_encoder_is_cwb_disabling(encoder,
					crtc);
			if (!cwb_disabling)
				continue;
		}

		/*
		 * Wait for post-flush if necessary to delay before
		 * plane_cleanup. For example, wait for vsync in case of video
@@ -1257,6 +1264,9 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
		}

		sde_crtc_complete_flip(crtc, NULL);

		if (cwb_disabling)
			sde_encoder_virt_reset(encoder);
	}

	SDE_ATRACE_END("sde_ksm_wait_for_commit_done");