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

Commit 888677e7 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

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

parents cf096efb ab0a91c1
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;