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

Commit ab0a91c1 authored by Prabhanjan Kandula's avatar Prabhanjan Kandula Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/sde: move auto-refresh disable to commit phase



Boot-loader enables auto-refresh and it is disabled during
SDE driver probe in current SDE driver design. It should be
moved to commit phase to avoid cpu sleep and interrupt wait
sequence during SDE driver probe. This patch cleans up
auto-refrsh disable logic from resource manager and uses
existing autorefresh disable sequence logic from command mode
physical encoder.

Change-Id: I9d4ee8ea800ab7b4438c830cfb987957aaef7ff0
Signed-off-by: default avatarPrabhanjan Kandula <pkandula@codeaurora.org>
parent 92a2b707
Loading
Loading
Loading
Loading
+42 −25
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@
 */
#define SDE_ENC_CTL_START_THRESHOLD_US 500

#define SDE_ENC_MAX_POLL_TIMEOUT_US	2000

static inline int _sde_encoder_phys_cmd_get_idle_timeout(
		struct sde_encoder_phys_cmd *cmd_enc)
{
@@ -420,6 +422,10 @@ static void sde_encoder_phys_cmd_cont_splash_mode_set(
		struct sde_encoder_phys *phys_enc,
		struct drm_display_mode *adj_mode)
{
	struct sde_hw_intf *hw_intf;
	struct sde_hw_pingpong *hw_pp;
	struct sde_encoder_phys_cmd *cmd_enc;

	if (!phys_enc || !adj_mode) {
		SDE_ERROR("invalid args\n");
		return;
@@ -435,6 +441,21 @@ static void sde_encoder_phys_cmd_cont_splash_mode_set(
		return;
	}

	if (sde_encoder_phys_cmd_is_master(phys_enc)) {
		cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
		hw_pp = phys_enc->hw_pp;
		hw_intf = phys_enc->hw_intf;

		if (phys_enc->has_intf_te && hw_intf &&
				hw_intf->ops.get_autorefresh) {
			hw_intf->ops.get_autorefresh(hw_intf,
					&cmd_enc->autorefresh.cfg);
		} else if (hw_pp && hw_pp->ops.get_autorefresh) {
			hw_pp->ops.get_autorefresh(hw_pp,
					&cmd_enc->autorefresh.cfg);
		}
	}

	_sde_encoder_phys_cmd_setup_irq_hw_idx(phys_enc);
}

@@ -1506,7 +1527,7 @@ static void sde_encoder_phys_cmd_prepare_commit(
{
	struct sde_encoder_phys_cmd *cmd_enc =
		to_sde_encoder_phys_cmd(phys_enc);
	unsigned long lock_flags;
	int trial = 0;

	if (!phys_enc)
		return;
@@ -1520,35 +1541,31 @@ static void sde_encoder_phys_cmd_prepare_commit(
	if (!sde_encoder_phys_cmd_is_autorefresh_enabled(phys_enc))
		return;

	/**
	 * Autorefresh must be disabled carefully:
	 *  - Autorefresh must be disabled between pp_done and te
	 *    signal prior to sdm845 targets. All targets after sdm845
	 *    supports autorefresh disable without turning off the
	 *    hardware TE and pp_done wait.
	 *
	 *  - Wait for TX to Complete
	 *    Wait for PPDone confirms the last frame transfer is complete.
	 *
	 *  - Leave Autorefresh Disabled
	 *    - Assume disable of Autorefresh since it is now safe
	 *    - Can now safely Disable Encoder, do debug printing, etc.
	 *     without worrying that Autorefresh will kickoff
	/*
	 * If autorefresh is enabled, disable it and make sure it is safe to
	 * proceed with current frame commit/push. Sequence fallowed is,
	 * 1. Disable TE
	 * 2. Disable autorefresh config
	 * 4. Poll for frame transfer ongoing to be false
	 * 5. Enable TE back
	 */

	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
	sde_encoder_phys_cmd_connect_te(phys_enc, false);

	_sde_encoder_phys_cmd_config_autorefresh(phys_enc, 0);

	/* check for outstanding TX */
	if (_sde_encoder_phys_cmd_is_ongoing_pptx(phys_enc))
		atomic_add_unless(&phys_enc->pending_kickoff_cnt, 1, 1);
	spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
	do {
		udelay(SDE_ENC_MAX_POLL_TIMEOUT_US);
		if ((trial * SDE_ENC_MAX_POLL_TIMEOUT_US)
				> (KICKOFF_TIMEOUT_MS * USEC_PER_MSEC)) {
			SDE_ERROR_CMDENC(cmd_enc,
					"disable autorefresh failed\n");
			break;
		}

	/* wait for ppdone if necessary due to catching ongoing TX */
	if (_sde_encoder_phys_cmd_wait_for_idle(phys_enc))
		SDE_ERROR_CMDENC(cmd_enc, "pp:%d kickoff timed out\n",
				phys_enc->hw_pp->idx - PINGPONG_0);
		trial++;
	} while (_sde_encoder_phys_cmd_is_ongoing_pptx(phys_enc));

	sde_encoder_phys_cmd_connect_te(phys_enc, true);

	SDE_DEBUG_CMDENC(cmd_enc, "disabled autorefresh\n");
}
+2 −252
Original line number Diff line number Diff line
@@ -1158,234 +1158,6 @@ static int _sde_rm_make_next_rsvp(
	return ret;
}

static void _sde_rm_clear_irq_status(struct sde_hw_intr *hw_intr,
	int irq_idx_pp_done, int irq_idx_autorefresh)
{
	u32 intr_value = 0;

	if ((irq_idx_pp_done >= 0) && (hw_intr->ops.get_intr_status_nomask)) {
		intr_value = hw_intr->ops.get_intr_status_nomask(hw_intr,
			irq_idx_pp_done, false);
		hw_intr->ops.clear_intr_status_force_mask(hw_intr,
			irq_idx_pp_done, intr_value);
	}

	if ((irq_idx_autorefresh >= 0) &&
			(hw_intr->ops.get_intr_status_nomask)) {
		intr_value = hw_intr->ops.get_intr_status_nomask(hw_intr,
			irq_idx_autorefresh, false);
		hw_intr->ops.clear_intr_status_force_mask(hw_intr,
			irq_idx_autorefresh, intr_value);
	}
}

static u32 _sde_rm_poll_intr_status_for_cont_splash(struct sde_hw_intr *intr,
	int irq_idx_pp_done, int irq_idx_autorefresh, u32 const msec)
{
	int i;
	u32 status = 0;
	u32 const delay_us = 500;
	u32 const timeout_us = msec * 1000;
	/* Make sure the status is checked atleast once */
	int loop = max((u32)1, (u32)(timeout_us / delay_us));

	if (!intr)
		return 0;

	for (i = 0; i < loop; i++) {
		status = intr->ops.get_intr_status_nomask
				(intr, irq_idx_pp_done, false);

		if (status & BIT(irq_idx_pp_done)) {
			SDE_DEBUG("pp_done received i=%d, status=0x%x\n",
							i, status);
			SDE_EVT32(status, i, irq_idx_pp_done);

			if (status & BIT(irq_idx_autorefresh))
				_sde_rm_clear_irq_status(intr,
					irq_idx_pp_done, irq_idx_autorefresh);
			else
				return 0;
		}
		usleep_range(delay_us, delay_us + 10);
	}

	SDE_EVT32(status, irq_idx_pp_done, SDE_EVTLOG_ERROR);
	SDE_DEBUG("polling timed out. status = 0x%x\n", status);
	return -ETIMEDOUT;
}

static inline bool _sde_rm_autorefresh_validate(struct sde_hw_pingpong *pp,
		struct sde_hw_intf *intf,
		bool hw_intf_te)
{

	if ((hw_intf_te && !intf) ||
		(!hw_intf_te && !pp)) {
		SDE_ERROR("autorefresh wrong params!\n");
		return true;
	}

	if (hw_intf_te) {
		if (!intf->ops.get_autorefresh ||
				!intf->ops.setup_autorefresh ||
				!intf->ops.connect_external_te ||
				!intf->ops.get_vsync_info) {
			SDE_ERROR("intf autorefresh apis not supported\n");
			return true;
		}
	} else {
		if (!pp->ops.get_autorefresh ||
				!pp->ops.setup_autorefresh ||
				!pp->ops.connect_external_te ||
				!pp->ops.get_vsync_info) {
			SDE_ERROR("pp autorefresh apis not supported\n");
			return true;
		}
	}

	return false;
}

static inline void _sde_rm_autorefresh_get_cfg(
		struct sde_hw_pingpong *pp,
		struct sde_hw_intf *intf,
		struct sde_hw_autorefresh *cfg,
		bool hw_intf_te)
{
	if (hw_intf_te)
		intf->ops.get_autorefresh(intf, cfg);
	else
		pp->ops.get_autorefresh(pp, cfg);
}

static inline void _sde_rm_autorefresh_connect_external_te(
		struct sde_hw_pingpong *pp,
		struct sde_hw_intf *intf,
		bool hw_intf_te,
		bool enable)
{
	if (hw_intf_te)
		intf->ops.connect_external_te(intf, enable);
	else
		pp->ops.connect_external_te(pp, enable);
}

static inline void _sde_rm_autorefresh_setup(struct sde_hw_pingpong *pp,
		struct sde_hw_intf *intf,
		struct sde_hw_autorefresh *cfg,
		bool hw_intf_te)
{
	if (hw_intf_te)
		intf->ops.setup_autorefresh(intf, cfg);
	else
		pp->ops.setup_autorefresh(pp, cfg);
}

static inline void _sde_rm_autorefresh_get_vsync_info(
		struct sde_hw_pingpong *pp,
		struct sde_hw_intf *intf,
		struct sde_hw_pp_vsync_info *info,
		bool hw_intf_te)
{
	if (hw_intf_te)
		intf->ops.get_vsync_info(intf, info);
	else
		pp->ops.get_vsync_info(pp, info);
}

static int _sde_rm_autorefresh_disable(struct sde_hw_pingpong *pp,
		struct sde_hw_intf *intf,
		struct sde_hw_intr *hw_intr,
		bool hw_intf_te)
{
	u32 const timeout_ms = 35; /* Max two vsyncs delay */
	int rc = 0, i, loop = 3;
	struct sde_hw_pp_vsync_info info;
	int irq_idx_pp_done = -1, irq_idx_autorefresh = -1;
	struct sde_hw_autorefresh cfg = {0};
	int dbg_idx;
	int te_irq_idx;

	if (_sde_rm_autorefresh_validate(pp, intf, hw_intf_te))
		return 0;

	dbg_idx = hw_intf_te ? intf->idx - INTF_0 : pp->idx - PINGPONG_0;
	te_irq_idx = hw_intf_te ? intf->idx : pp->idx;

	/* read default autorefresh configuration */
	_sde_rm_autorefresh_get_cfg(pp, intf, &cfg, hw_intf_te);

	if (!cfg.enable) {
		SDE_DEBUG("autorefresh already disabled idx:%d\n",
			dbg_idx);
		SDE_EVT32(dbg_idx, SDE_EVTLOG_FUNC_CASE1);
		return 0;
	}

	/* disable external TE first */
	_sde_rm_autorefresh_connect_external_te(pp, intf, hw_intf_te, false);

	/* get all IRQ indexes */
	if (hw_intr->ops.irq_idx_lookup) {
		irq_idx_pp_done = hw_intr->ops.irq_idx_lookup(
				SDE_IRQ_TYPE_PING_PONG_COMP, te_irq_idx);
		irq_idx_autorefresh = hw_intr->ops.irq_idx_lookup(
				SDE_IRQ_TYPE_PING_PONG_AUTO_REF, te_irq_idx);
		SDE_DEBUG("pp_done irq_idx = %d autorefresh irq_idx:%d\n",
				irq_idx_pp_done, irq_idx_autorefresh);
	}

	/* disable autorefresh */
	cfg.enable = false;
	_sde_rm_autorefresh_setup(pp, intf, &cfg, hw_intf_te);

	SDE_EVT32(dbg_idx, irq_idx_pp_done, irq_idx_autorefresh);
	_sde_rm_clear_irq_status(hw_intr, irq_idx_pp_done, irq_idx_autorefresh);

	/*
	 * Check the line count again if
	 * the line count is equal to the active
	 * height to make sure their is no
	 * additional frame updates
	 */
	for (i = 0; i < loop; i++) {
		info.wr_ptr_line_count = 0;
		info.rd_ptr_init_val = 0;
		_sde_rm_autorefresh_get_vsync_info(pp, intf, &info, hw_intf_te);

		SDE_EVT32(dbg_idx, info.wr_ptr_line_count,
			info.rd_ptr_init_val, SDE_EVTLOG_FUNC_CASE1);

		/* wait for read ptr intr */
		rc = _sde_rm_poll_intr_status_for_cont_splash(hw_intr,
			irq_idx_pp_done, irq_idx_autorefresh, timeout_ms);

		info.wr_ptr_line_count = 0;
		info.rd_ptr_init_val = 0;

		_sde_rm_autorefresh_get_vsync_info(pp, intf, &info, hw_intf_te);

		SDE_DEBUG("i=%d, line count=%d\n", i, info.wr_ptr_line_count);
		SDE_EVT32(dbg_idx, info.wr_ptr_line_count,
			info.rd_ptr_init_val, SDE_EVTLOG_FUNC_CASE2);

		/* log line count and return */
		if (!rc)
			break;
		/*
		 * Wait for few milli seconds for line count
		 * to increase if any frame transfer is
		 * pending.
		 */
		usleep_range(3000, 4000);
	}

	_sde_rm_autorefresh_connect_external_te(pp, intf, hw_intf_te, true);

	return rc;
}

/**
 * sde_rm_get_pp_dsc_for_cont_splash - retrieve the current dsc enabled blocks
 *	and disable autorefresh if enabled.
@@ -1401,22 +1173,13 @@ static int _sde_rm_get_pp_dsc_for_cont_splash(struct sde_rm *rm,
{
	int index = 0;
	int value, dsc_cnt = 0;
	struct sde_rm_hw_iter iter_pp, intf_iter;
	bool hw_intf_te_supported;
	struct sde_hw_intr *hw_intr = NULL;
	struct sde_rm_hw_iter iter_pp;

	if (!rm || !sde_kms || !dsc_ids) {
		SDE_ERROR("invalid input parameters\n");
		return 0;
	}

	hw_intf_te_supported = sde_hw_intf_te_supported(sde_kms->catalog);
	hw_intr = sde_kms->hw_intr;
	if (!hw_intr) {
		SDE_ERROR("hw_intr handler not initialized\n");
		return 0;
	}

	SDE_DEBUG("max_dsc_cnt = %d\n", max_dsc_cnt);
	sde_rm_init_hw_iter(&iter_pp, 0, SDE_HW_BLK_PINGPONG);
	while (_sde_rm_get_hw_locked(rm, &iter_pp)) {
@@ -1435,21 +1198,8 @@ static int _sde_rm_get_pp_dsc_for_cont_splash(struct sde_rm *rm,
			dsc_ids[dsc_cnt] = index + DSC_0;
			dsc_cnt++;
		}
		index++;

		if (!hw_intf_te_supported)
			_sde_rm_autorefresh_disable(pp, NULL, hw_intr,
				hw_intf_te_supported);
	}

	sde_rm_init_hw_iter(&intf_iter, 0, SDE_HW_BLK_INTF);
	while (_sde_rm_get_hw_locked(rm, &intf_iter)) {
		struct sde_hw_intf *intf =
			to_sde_hw_intf(intf_iter.blk->hw);

		if (hw_intf_te_supported)
			_sde_rm_autorefresh_disable(NULL, intf, hw_intr,
				hw_intf_te_supported);
		index++;
	}

	return dsc_cnt;