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

Commit 82916e00 authored by Veera Sundaram Sankaran's avatar Veera Sundaram Sankaran Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/sde: add restore functionality after idle power collapse



During the idle_PC state all the registers are wiped out as
all the resources are disabled. The CRTC registers for the
MDP core clock enable event and restores all the register
configurations in CRTC, encoder and planes.

Change-Id: I48895899f3a0491f4dc0ad5cec66fc7c7c47da7f
Signed-off-by: default avatarVeera Sundaram Sankaran <veeras@codeaurora.org>
parent 73fb809e
Loading
Loading
Loading
Loading
+54 −2
Original line number Diff line number Diff line
@@ -2190,21 +2190,62 @@ static int _sde_crtc_vblank_no_lock(struct sde_crtc *sde_crtc, bool en)
	return 0;
}

static void sde_crtc_handle_power_event(u32 event_type, void *arg)
{
	struct drm_crtc *crtc = arg;
	struct sde_crtc *sde_crtc;
	struct drm_encoder *encoder;

	if (!crtc) {
		SDE_ERROR("invalid crtc\n");
		return;
	}
	sde_crtc = to_sde_crtc(crtc);

	mutex_lock(&sde_crtc->crtc_lock);

	SDE_EVT32(DRMID(crtc), event_type);

	if (event_type == SDE_POWER_EVENT_POST_ENABLE) {
		/* restore encoder; crtc will be programmed during commit */
		drm_for_each_encoder(encoder, crtc->dev) {
			if (encoder->crtc != crtc)
				continue;

			sde_encoder_virt_restore(encoder);
		}

	} else if (event_type == SDE_POWER_EVENT_POST_DISABLE) {
		struct drm_plane *plane;

		/*
		 * set revalidate flag in planes, so it will be re-programmed
		 * in the next frame update
		 */
		drm_atomic_crtc_for_each_plane(plane, crtc)
			sde_plane_set_revalidate(plane, true);
	}

	mutex_unlock(&sde_crtc->crtc_lock);
}

static void sde_crtc_disable(struct drm_crtc *crtc)
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *cstate;
	struct drm_encoder *encoder;
	struct msm_drm_private *priv;
	unsigned long flags;
	struct sde_crtc_irq_info *node = NULL;
	int ret;

	if (!crtc || !crtc->dev || !crtc->state) {
	if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) {
		SDE_ERROR("invalid crtc\n");
		return;
	}
	sde_crtc = to_sde_crtc(crtc);
	cstate = to_sde_crtc_state(crtc->state);
	priv = crtc->dev->dev_private;

	SDE_DEBUG("crtc%d\n", crtc->base.id);

@@ -2244,6 +2285,10 @@ static void sde_crtc_disable(struct drm_crtc *crtc)
		cstate->rsc_update = false;
	}

	if (sde_crtc->power_event)
		sde_power_handle_unregister_event(&priv->phandle,
				sde_crtc->power_event);

	memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers));
	sde_crtc->num_mixers = 0;

@@ -2265,14 +2310,16 @@ static void sde_crtc_enable(struct drm_crtc *crtc)
{
	struct sde_crtc *sde_crtc;
	struct drm_encoder *encoder;
	struct msm_drm_private *priv;
	unsigned long flags;
	struct sde_crtc_irq_info *node = NULL;
	int ret;

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

	SDE_DEBUG("crtc%d\n", crtc->base.id);
	SDE_EVT32(DRMID(crtc));
@@ -2295,6 +2342,11 @@ static void sde_crtc_enable(struct drm_crtc *crtc)
				sde_crtc->name, node->event);
	}
	spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);

	sde_crtc->power_event = sde_power_handle_register_event(
		&priv->phandle,
		SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE,
		sde_crtc_handle_power_event, crtc, sde_crtc->name);
}

struct plane_state {
+3 −0
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ struct sde_crtc_event {
 * @event_free_list : List of available event structures
 * @event_lock    : Spinlock around event handling code
 * @misr_enable   : boolean entry indicates misr enable/disable status.
 * @power_event   : registered power event handle
 */
struct sde_crtc {
	struct drm_crtc base;
@@ -187,6 +188,8 @@ struct sde_crtc {
	struct list_head event_free_list;
	spinlock_t event_lock;
	bool misr_enable;

	struct sde_power_event *power_event;
};

#define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
+59 −25
Original line number Diff line number Diff line
@@ -1169,34 +1169,79 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
	}
}

static void sde_encoder_virt_enable(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 msm_drm_private *priv;
	struct sde_kms *sde_kms;
	int i = 0;
	int ret = 0;

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

	sde_enc = to_sde_encoder_virt(drm_enc);
	priv = drm_enc->dev->dev_private;
	sde_kms = to_sde_kms(priv->kms);
	if (!sde_enc || !sde_enc->cur_master) {
		SDE_ERROR("invalid sde encoder/master\n");
		return;
	}

	sde_kms = to_sde_kms(priv->kms);
	if (!sde_kms) {
		SDE_ERROR("invalid sde_kms\n");
		return;
	}

	if (sde_enc->cur_master->hw_mdptop &&
			sde_enc->cur_master->hw_mdptop->ops.reset_ubwc)
		sde_enc->cur_master->hw_mdptop->ops.reset_ubwc(
				sde_enc->cur_master->hw_mdptop,
				sde_kms->catalog);

	if (_sde_is_dsc_enabled(sde_enc)) {
		ret = _sde_encoder_dsc_setup(sde_enc);
		if (ret)
			SDE_ERROR_ENC(sde_enc, "failed to setup DSC:%d\n", ret);
	}
}

void sde_encoder_virt_restore(struct drm_encoder *drm_enc)
{
	struct sde_encoder_virt *sde_enc = NULL;
	int i;

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

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

		if (phys && (phys != sde_enc->cur_master) && phys->ops.restore)
			phys->ops.restore(phys);
	}

	if (sde_enc->cur_master && sde_enc->cur_master->ops.restore)
		sde_enc->cur_master->ops.restore(sde_enc->cur_master);

	_sde_encoder_virt_enable_helper(drm_enc);
}

static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
{
	struct sde_encoder_virt *sde_enc = NULL;
	int i, ret = 0;

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

	SDE_DEBUG_ENC(sde_enc, "\n");
	SDE_EVT32(DRMID(drm_enc));

@@ -1230,21 +1275,10 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
			phys->ops.enable(phys);
	}

	if (sde_enc->cur_master && sde_enc->cur_master->ops.enable)
	if (sde_enc->cur_master->ops.enable)
		sde_enc->cur_master->ops.enable(sde_enc->cur_master);

	if (sde_enc->cur_master && sde_enc->cur_master->hw_mdptop &&
			sde_enc->cur_master->hw_mdptop->ops.reset_ubwc)
		sde_enc->cur_master->hw_mdptop->ops.reset_ubwc(
				sde_enc->cur_master->hw_mdptop,
				sde_kms->catalog);

	if (_sde_is_dsc_enabled(sde_enc)) {
		ret = _sde_encoder_dsc_setup(sde_enc);
		if (ret)
			SDE_ERROR_ENC(sde_enc, "failed to setup DSC: %d\n",
					ret);
	}
	_sde_encoder_virt_enable_helper(drm_enc);
}

static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
+6 −0
Original line number Diff line number Diff line
@@ -126,6 +126,12 @@ int sde_encoder_wait_for_commit_done(struct drm_encoder *drm_encoder);
 */
enum sde_intf_mode sde_encoder_get_intf_mode(struct drm_encoder *encoder);

/**
 * sde_encoder_virt_restore - restore the encoder configs
 * @encoder:	encoder pointer
 */
void sde_encoder_virt_restore(struct drm_encoder *encoder);

/**
 * enum sde_encoder_property - property tags for sde enoder
 * @SDE_ENCODER_PROPERTY_INLINE_ROTATE_REFILL: # of prefill line, 0 to disable
+2 −0
Original line number Diff line number Diff line
@@ -121,6 +121,7 @@ struct sde_encoder_virt_ops {
 *				SDE_ENC_ERR_NEEDS_HW_RESET state
 * @irq_control:		Handler to enable/disable all the encoder IRQs
 * @update_split_role:		Update the split role of the phys enc
 * @restore:			Restore all the encoder configs.
 */

struct sde_encoder_phys_ops {
@@ -157,6 +158,7 @@ struct sde_encoder_phys_ops {
	void (*irq_control)(struct sde_encoder_phys *phys, bool enable);
	void (*update_split_role)(struct sde_encoder_phys *phys_enc,
			enum sde_enc_split_role role);
	void (*restore)(struct sde_encoder_phys *phys);
};

/**
Loading