diff options
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_crtc.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 15 |
4 files changed, 35 insertions, 13 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 8cd9d8eec46..9337e5e2dbb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -259,13 +259,21 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, mutex_lock(&dev->struct_mutex); - if (event && !dev_priv->pageflip_event) { + if (event) { + /* + * the pipe from user always is 0 so we can set pipe number + * of current owner to event. + */ + event->pipe = exynos_crtc->pipe; + list_add_tail(&event->base.link, &dev_priv->pageflip_event_list); ret = drm_vblank_get(dev, exynos_crtc->pipe); if (ret) { DRM_DEBUG("failed to acquire vblank counter\n"); + list_del(&event->base.link); + goto out; } @@ -274,7 +282,7 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, if (ret) { crtc->fb = old_fb; drm_vblank_put(dev, exynos_crtc->pipe); - dev_priv->pageflip_event = false; + list_del(&event->base.link); goto out; } @@ -282,12 +290,10 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, /* * the values related to a buffer of the drm framebuffer * to be applied should be set at here. because these values - * first, is set to shadow registers and then to + * first, are set to shadow registers and then to * real registers at vsync front porch period. */ exynos_drm_crtc_apply(crtc); - - dev_priv->pageflip_event = true; } out: mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index a190348ed9b..83810cbe3c1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -124,6 +124,19 @@ static int exynos_drm_unload(struct drm_device *dev) return 0; } +static void exynos_drm_preclose(struct drm_device *dev, + struct drm_file *file_priv) +{ + struct exynos_drm_private *dev_priv = dev->dev_private; + + /* + * drm framework frees all events at release time, + * so private event list should be cleared. + */ + if (!list_empty(&dev_priv->pageflip_event_list)) + INIT_LIST_HEAD(&dev_priv->pageflip_event_list); +} + static void exynos_drm_lastclose(struct drm_device *dev) { DRM_DEBUG_DRIVER("%s\n", __FILE__); @@ -152,6 +165,7 @@ static struct drm_driver exynos_drm_driver = { DRIVER_MODESET | DRIVER_GEM, .load = exynos_drm_load, .unload = exynos_drm_unload, + .preclose = exynos_drm_preclose, .lastclose = exynos_drm_lastclose, .get_vblank_counter = drm_vblank_count, .enable_vblank = exynos_drm_crtc_enable_vblank, diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 63c1422403d..915f5cd4d10 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -187,9 +187,8 @@ struct exynos_drm_manager { struct exynos_drm_private { struct drm_fb_helper *fb_helper; - /* for pageflip */ + /* list head for new event to be added. */ struct list_head pageflip_event_list; - bool pageflip_event; /* * created crtc object would be contained at this array and diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index b0afa849323..68446b3bd8f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -487,21 +487,24 @@ static struct exynos_drm_overlay_ops fimd_overlay_ops = { .disable = fimd_win_disable, }; -/* for pageflip event */ static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc) { struct exynos_drm_private *dev_priv = drm_dev->dev_private; struct drm_pending_vblank_event *e, *t; struct timeval now; unsigned long flags; - - if (!dev_priv->pageflip_event) - return; + bool is_checked = false; spin_lock_irqsave(&drm_dev->event_lock, flags); list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, base.link) { + /* if event's pipe isn't same as crtc then ignor it. */ + if (crtc != e->pipe) + continue; + + is_checked = true; + do_gettimeofday(&now); e->event.sequence = 0; e->event.tv_sec = now.tv_sec; @@ -511,8 +514,8 @@ static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc) wake_up_interruptible(&e->base.file_priv->event_wait); } - drm_vblank_put(drm_dev, crtc); - dev_priv->pageflip_event = false; + if (is_checked) + drm_vblank_put(drm_dev, crtc); spin_unlock_irqrestore(&drm_dev->event_lock, flags); } |