diff options
| author | Alan Kwong <akwong@codeaurora.org> | 2016-10-16 01:02:35 -0400 |
|---|---|---|
| committer | Alan Kwong <akwong@codeaurora.org> | 2016-10-19 17:11:13 -0400 |
| commit | 0107866c1e93a2adf68bf13e8eacc305852de3e6 (patch) | |
| tree | 440875bc2cdd3dbdf0ddc2a201c7f9af4fcb8314 /drivers/gpu | |
| parent | 9d3282bce7872a01874852ff18eb1c9786222176 (diff) | |
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: Alan Kwong <akwong@codeaurora.org>
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 24 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_kms.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_kms.c | 22 |
3 files changed, 47 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index c822fa5a42f4..803bfb35e6ce 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -447,6 +447,15 @@ static int msm_load(struct drm_device *dev, unsigned long flags) if (ret) goto fail; + /* 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; @@ -622,6 +631,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); diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 803086c36373..f97bf277f8c1 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -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); diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 50e8631ecd60..49e28c4c233e 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -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, |
