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

Commit 33db428d authored by Veera Sundaram Sankaran's avatar Veera Sundaram Sankaran
Browse files

drm/msm/sde: handle VSYNC_IN_EN during crtc power events



Currently VSYNC_IN_EN is closely tied with frame updates,
it is enabled during the kickoff and disabled as part of
idle power collapse sequence. This will impact vblank
request without a frame update during idle power collapse,
as the RD_PTR_IRQ will be triggered only after the wraparound.
Disable VSYNC_IN_EN during PRE_DISABLE power event, to ensure
no vsync is triggered when RSC enters mode-2. Enable it during
POST_ENABLE power event as part of encoder restore and during
virtual encoder enable to support bootup/resume cases.

Change-Id: Iea6d6e9617a9db2c2518695ff5a428a97f887a2d
Signed-off-by: default avatarVeera Sundaram Sankaran <veeras@codeaurora.org>
parent 06e4dc68
Loading
Loading
Loading
Loading
+15 −0
Original line number Original line Diff line number Diff line
@@ -3968,6 +3968,21 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
		}
		}
		break;
		break;
	case SDE_POWER_EVENT_PRE_DISABLE:
	case SDE_POWER_EVENT_PRE_DISABLE:
		drm_for_each_encoder(encoder, crtc->dev) {
			if (encoder->crtc != crtc)
				continue;
			/*
			 * disable the vsync source after updating the
			 * rsc state. rsc state update might have vsync wait
			 * and vsync source must be disabled after it.
			 * It will avoid generating any vsync from this point
			 * till mode-2 entry. It is SW workaround for HW
			 * limitation and should not be removed without
			 * checking the updated design.
			 */
			sde_encoder_control_te(encoder, false);
		}

		for (i = 0; i < sde_crtc->num_mixers; ++i) {
		for (i = 0; i < sde_crtc->num_mixers; ++i) {
			m = &sde_crtc->mixers[i];
			m = &sde_crtc->mixers[i];
			if (!m->hw_lm || !m->hw_lm->ops.collect_misr ||
			if (!m->hw_lm || !m->hw_lm->ops.collect_misr ||
+25 −18
Original line number Original line Diff line number Diff line
@@ -1611,9 +1611,7 @@ struct sde_rsc_client *sde_encoder_get_rsc_client(struct drm_encoder *drm_enc)
static void _sde_encoder_resource_control_rsc_update(
static void _sde_encoder_resource_control_rsc_update(
		struct drm_encoder *drm_enc, bool enable)
		struct drm_encoder *drm_enc, bool enable)
{
{
	struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
	struct sde_encoder_rsc_config rsc_cfg = { 0 };
	struct sde_encoder_rsc_config rsc_cfg = { 0 };
	int i;


	if (enable) {
	if (enable) {
		rsc_cfg.inline_rotate_prefill =
		rsc_cfg.inline_rotate_prefill =
@@ -1622,22 +1620,6 @@ static void _sde_encoder_resource_control_rsc_update(
		_sde_encoder_update_rsc_client(drm_enc, &rsc_cfg, true);
		_sde_encoder_update_rsc_client(drm_enc, &rsc_cfg, true);
	} else {
	} else {
		_sde_encoder_update_rsc_client(drm_enc, NULL, false);
		_sde_encoder_update_rsc_client(drm_enc, NULL, false);

		/**
		 * disable the vsync source after updating the rsc state. rsc
		 * state update might have vsync wait and vsync source must be
		 * disabled after it. It will avoid generating any vsync from
		 * this point till mode-2 entry. It is SW workaround for
		 * HW limitation and should not be removed without checking the
		 * updated design.
		 */
		for (i = 0; i < sde_enc->num_phys_encs; i++) {
			struct sde_encoder_phys *phys = sde_enc->phys_encs[i];

			if (phys && phys->ops.prepare_idle_pc)
				phys->ops.prepare_idle_pc(phys);
		}

	}
	}
}
}


@@ -2148,6 +2130,30 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
						SDE_ENC_RC_EVENT_POST_MODESET);
						SDE_ENC_RC_EVENT_POST_MODESET);
}
}


void sde_encoder_control_te(struct drm_encoder *drm_enc, bool enable)
{
	struct sde_encoder_virt *sde_enc;
	struct sde_encoder_phys *phys;
	int i;

	if (!drm_enc) {
		SDE_ERROR("invalid parameters\n");
		return;
	}

	sde_enc = to_sde_encoder_virt(drm_enc);
	if (!sde_enc) {
		SDE_ERROR("invalid sde encoder\n");
		return;
	}

	for (i = 0; i < sde_enc->num_phys_encs; i++) {
		phys = sde_enc->phys_encs[i];
		if (phys && phys->ops.control_te)
			phys->ops.control_te(phys, enable);
	}
}

static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
{
{
	struct sde_encoder_virt *sde_enc = NULL;
	struct sde_encoder_virt *sde_enc = NULL;
@@ -2185,6 +2191,7 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
				sde_kms->catalog);
				sde_kms->catalog);


	_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, false);
	_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, false);
	sde_encoder_control_te(drm_enc, true);


	memset(&sde_enc->prv_conn_roi, 0, sizeof(sde_enc->prv_conn_roi));
	memset(&sde_enc->prv_conn_roi, 0, sizeof(sde_enc->prv_conn_roi));
	memset(&sde_enc->cur_conn_roi, 0, sizeof(sde_enc->cur_conn_roi));
	memset(&sde_enc->cur_conn_roi, 0, sizeof(sde_enc->cur_conn_roi));
+7 −0
Original line number Original line Diff line number Diff line
@@ -162,6 +162,13 @@ int sde_encoder_wait_for_event(struct drm_encoder *drm_encoder,
 */
 */
enum sde_intf_mode sde_encoder_get_intf_mode(struct drm_encoder *encoder);
enum sde_intf_mode sde_encoder_get_intf_mode(struct drm_encoder *encoder);


/**
 * sde_encoder_control_te - control enabling/disabling VSYNC_IN_EN
 * @encoder:	encoder pointer
 * @enable:	boolean to indicate enable/disable
 */
void sde_encoder_control_te(struct drm_encoder *encoder, bool enable);

/**
/**
 * sde_encoder_virt_restore - restore the encoder configs
 * sde_encoder_virt_restore - restore the encoder configs
 * @encoder:	encoder pointer
 * @encoder:	encoder pointer
+2 −3
Original line number Original line Diff line number Diff line
@@ -126,8 +126,7 @@ struct sde_encoder_virt_ops {
 *				SDE_ENC_ERR_NEEDS_HW_RESET state
 *				SDE_ENC_ERR_NEEDS_HW_RESET state
 * @irq_control:		Handler to enable/disable all the encoder IRQs
 * @irq_control:		Handler to enable/disable all the encoder IRQs
 * @update_split_role:		Update the split role of the phys enc
 * @update_split_role:		Update the split role of the phys enc
 * @prepare_idle_pc:		phys encoder can update the vsync_enable status
 * @control_te:			Interface to control the vsync_enable status
 *                              on idle power collapse prepare
 * @restore:			Restore all the encoder configs.
 * @restore:			Restore all the encoder configs.
 * @is_autorefresh_enabled:	provides the autorefresh current
 * @is_autorefresh_enabled:	provides the autorefresh current
 *                              enable/disable state.
 *                              enable/disable state.
@@ -174,7 +173,7 @@ struct sde_encoder_phys_ops {
	void (*irq_control)(struct sde_encoder_phys *phys, bool enable);
	void (*irq_control)(struct sde_encoder_phys *phys, bool enable);
	void (*update_split_role)(struct sde_encoder_phys *phys_enc,
	void (*update_split_role)(struct sde_encoder_phys *phys_enc,
			enum sde_enc_split_role role);
			enum sde_enc_split_role role);
	void (*prepare_idle_pc)(struct sde_encoder_phys *phys_enc);
	void (*control_te)(struct sde_encoder_phys *phys_enc, bool enable);
	void (*restore)(struct sde_encoder_phys *phys);
	void (*restore)(struct sde_encoder_phys *phys);
	bool (*is_autorefresh_enabled)(struct sde_encoder_phys *phys);
	bool (*is_autorefresh_enabled)(struct sde_encoder_phys *phys);
	int (*get_line_count)(struct sde_encoder_phys *phys);
	int (*get_line_count)(struct sde_encoder_phys *phys);
+2 −22
Original line number Original line Diff line number Diff line
@@ -891,7 +891,7 @@ static bool sde_encoder_phys_cmd_is_autorefresh_enabled(
	return cfg.enable;
	return cfg.enable;
}
}


static void _sde_encoder_phys_cmd_connect_te(
static void sde_encoder_phys_cmd_connect_te(
		struct sde_encoder_phys *phys_enc, bool enable)
		struct sde_encoder_phys *phys_enc, bool enable)
{
{
	if (!phys_enc || !phys_enc->hw_pp ||
	if (!phys_enc || !phys_enc->hw_pp ||
@@ -902,12 +902,6 @@ static void _sde_encoder_phys_cmd_connect_te(
	phys_enc->hw_pp->ops.connect_external_te(phys_enc->hw_pp, enable);
	phys_enc->hw_pp->ops.connect_external_te(phys_enc->hw_pp, enable);
}
}


static void sde_encoder_phys_cmd_prepare_idle_pc(
		struct sde_encoder_phys *phys_enc)
{
	_sde_encoder_phys_cmd_connect_te(phys_enc, false);
}

static int sde_encoder_phys_cmd_get_line_count(
static int sde_encoder_phys_cmd_get_line_count(
		struct sde_encoder_phys *phys_enc)
		struct sde_encoder_phys *phys_enc)
{
{
@@ -1214,19 +1208,6 @@ static void sde_encoder_phys_cmd_prepare_commit(
	SDE_DEBUG_CMDENC(cmd_enc, "disabled autorefresh\n");
	SDE_DEBUG_CMDENC(cmd_enc, "disabled autorefresh\n");
}
}


static void sde_encoder_phys_cmd_handle_post_kickoff(
		struct sde_encoder_phys *phys_enc)
{
	if (!phys_enc)
		return;

	/**
	 * re-enable external TE, either for the first time after enabling
	 * or if disabled for Autorefresh
	 */
	_sde_encoder_phys_cmd_connect_te(phys_enc, true);
}

static void sde_encoder_phys_cmd_trigger_start(
static void sde_encoder_phys_cmd_trigger_start(
		struct sde_encoder_phys *phys_enc)
		struct sde_encoder_phys *phys_enc)
{
{
@@ -1270,10 +1251,9 @@ static void sde_encoder_phys_cmd_init_ops(
	ops->irq_control = sde_encoder_phys_cmd_irq_control;
	ops->irq_control = sde_encoder_phys_cmd_irq_control;
	ops->update_split_role = sde_encoder_phys_cmd_update_split_role;
	ops->update_split_role = sde_encoder_phys_cmd_update_split_role;
	ops->restore = sde_encoder_phys_cmd_enable_helper;
	ops->restore = sde_encoder_phys_cmd_enable_helper;
	ops->prepare_idle_pc = sde_encoder_phys_cmd_prepare_idle_pc;
	ops->control_te = sde_encoder_phys_cmd_connect_te;
	ops->is_autorefresh_enabled =
	ops->is_autorefresh_enabled =
			sde_encoder_phys_cmd_is_autorefresh_enabled;
			sde_encoder_phys_cmd_is_autorefresh_enabled;
	ops->handle_post_kickoff = sde_encoder_phys_cmd_handle_post_kickoff;
	ops->get_line_count = sde_encoder_phys_cmd_get_line_count;
	ops->get_line_count = sde_encoder_phys_cmd_get_line_count;
}
}