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

Commit 5a3ac754 authored by Alan Kwong's avatar Alan Kwong Committed by Narendra Muppalla
Browse files

drm/msm: execute pending vblank disable upon last close



Vblank disable is dispatched by delay timer upon file
release.  If all vblank disable are not dispatched by
last close, device may have unbalanced vblank requests
upon next device open.  As a result, before closing down
all mode objects in last close, trigger vblank delay timer
and wait until all requests are executed and cleared from
workqueue.

Change-Id: I56d39e617fc88d40b22740c0178e339c32305549
Signed-off-by: default avatarAlan Kwong <akwong@codeaurora.org>
parent 4f1c869d
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -502,7 +502,16 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
	if (ret)
		goto fail;

	drm_kms_helper_poll_init(ddev);
	/* perform subdriver post initialization */
	if (kms && kms->funcs && kms->funcs->postinit) {
		ret = kms->funcs->postinit(kms);
		if (ret) {
			dev_err(dev->dev, "kms post init failed: %d\n", ret);
			goto fail;
		}
	}

	drm_kms_helper_poll_init(dev);

	return 0;

@@ -681,6 +690,21 @@ static void msm_lastclose(struct drm_device *dev)
{
	struct msm_drm_private *priv = dev->dev_private;
	struct msm_kms *kms = priv->kms;
	int i;

	/*
	 * clean up vblank disable immediately as this is the last close.
	 */
	for (i = 0; i < dev->num_crtcs; i++) {
		struct drm_vblank_crtc *vblank = &dev->vblank[i];
		struct timer_list *disable_timer = &vblank->disable_timer;

		if (del_timer_sync(disable_timer))
			disable_timer->function(disable_timer->data);
	}

	/* wait for pending vblank requests to be executed by worker thread */
	flush_workqueue(priv->wq);

	if (priv->fbdev) {
		drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
+1 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@
struct msm_kms_funcs {
	/* hw initialization: */
	int (*hw_init)(struct msm_kms *kms);
	int (*postinit)(struct msm_kms *kms);
	/* irq handling: */
	void (*irq_preinstall)(struct msm_kms *kms);
	int (*irq_postinstall)(struct msm_kms *kms);
+22 −0
Original line number Diff line number Diff line
@@ -401,6 +401,27 @@ static int sde_hw_init(struct msm_kms *kms)
{
	return 0;
}

static int sde_kms_postinit(struct msm_kms *kms)
{
	struct sde_kms *sde_kms = to_sde_kms(kms);
	struct drm_device *dev;

	if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev) {
		SDE_ERROR("invalid sde_kms\n");
		return -EINVAL;
	}

	dev = sde_kms->dev;

	/*
	 * Allow vblank interrupt to be disabled by drm vblank timer.
	 */
	dev->vblank_disable_allowed = true;

	return 0;
}

static long sde_round_pixclk(struct msm_kms *kms, unsigned long rate,
		struct drm_encoder *encoder)
{
@@ -438,6 +459,7 @@ static void sde_kms_preclose(struct msm_kms *kms, struct drm_file *file)

static const struct msm_kms_funcs kms_funcs = {
	.hw_init         = sde_hw_init,
	.postinit        = sde_kms_postinit,
	.irq_preinstall  = sde_irq_preinstall,
	.irq_postinstall = sde_irq_postinstall,
	.irq_uninstall   = sde_irq_uninstall,