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

Commit ccf4d883 authored by Inki Dae's avatar Inki Dae Committed by Dave Airlie
Browse files

drm/exynos: fixed page flip bug.



in case of using two drivers such as fimd and hdmi controller that
they have their own hardware interrupt, drm framework doesn't provide
pipe number corresponding to it. so the pipe should be set to event's
from specific crtc.

Signed-off-by: default avatarSeung-Woo Kim <sw0312.kim@samsung.com>
Signed-off-by: default avatarInki Dae <inki.dae@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent f6b98252
Loading
Loading
Loading
Loading
+11 −5
Original line number Original line Diff line number Diff line
@@ -259,13 +259,21 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,


	mutex_lock(&dev->struct_mutex);
	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,
		list_add_tail(&event->base.link,
				&dev_priv->pageflip_event_list);
				&dev_priv->pageflip_event_list);


		ret = drm_vblank_get(dev, exynos_crtc->pipe);
		ret = drm_vblank_get(dev, exynos_crtc->pipe);
		if (ret) {
		if (ret) {
			DRM_DEBUG("failed to acquire vblank counter\n");
			DRM_DEBUG("failed to acquire vblank counter\n");
			list_del(&event->base.link);

			goto out;
			goto out;
		}
		}


@@ -274,7 +282,7 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
		if (ret) {
		if (ret) {
			crtc->fb = old_fb;
			crtc->fb = old_fb;
			drm_vblank_put(dev, exynos_crtc->pipe);
			drm_vblank_put(dev, exynos_crtc->pipe);
			dev_priv->pageflip_event = false;
			list_del(&event->base.link);


			goto out;
			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
		 * the values related to a buffer of the drm framebuffer
		 * to be applied should be set at here. because these values
		 * 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.
		 * real registers at vsync front porch period.
		 */
		 */
		exynos_drm_crtc_apply(crtc);
		exynos_drm_crtc_apply(crtc);

		dev_priv->pageflip_event = true;
	}
	}
out:
out:
	mutex_unlock(&dev->struct_mutex);
	mutex_unlock(&dev->struct_mutex);
+14 −0
Original line number Original line Diff line number Diff line
@@ -124,6 +124,19 @@ static int exynos_drm_unload(struct drm_device *dev)
	return 0;
	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)
static void exynos_drm_lastclose(struct drm_device *dev)
{
{
	DRM_DEBUG_DRIVER("%s\n", __FILE__);
	DRM_DEBUG_DRIVER("%s\n", __FILE__);
@@ -152,6 +165,7 @@ static struct drm_driver exynos_drm_driver = {
				  DRIVER_MODESET | DRIVER_GEM,
				  DRIVER_MODESET | DRIVER_GEM,
	.load			= exynos_drm_load,
	.load			= exynos_drm_load,
	.unload			= exynos_drm_unload,
	.unload			= exynos_drm_unload,
	.preclose		= exynos_drm_preclose,
	.lastclose		= exynos_drm_lastclose,
	.lastclose		= exynos_drm_lastclose,
	.get_vblank_counter	= drm_vblank_count,
	.get_vblank_counter	= drm_vblank_count,
	.enable_vblank		= exynos_drm_crtc_enable_vblank,
	.enable_vblank		= exynos_drm_crtc_enable_vblank,
+1 −2
Original line number Original line Diff line number Diff line
@@ -187,9 +187,8 @@ struct exynos_drm_manager {
struct exynos_drm_private {
struct exynos_drm_private {
	struct drm_fb_helper *fb_helper;
	struct drm_fb_helper *fb_helper;


	/* for pageflip */
	/* list head for new event to be added. */
	struct list_head pageflip_event_list;
	struct list_head pageflip_event_list;
	bool pageflip_event;


	/*
	/*
	 * created crtc object would be contained at this array and
	 * created crtc object would be contained at this array and
+9 −6
Original line number Original line Diff line number Diff line
@@ -487,21 +487,24 @@ static struct exynos_drm_overlay_ops fimd_overlay_ops = {
	.disable = fimd_win_disable,
	.disable = fimd_win_disable,
};
};


/* for pageflip event */
static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc)
static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc)
{
{
	struct exynos_drm_private *dev_priv = drm_dev->dev_private;
	struct exynos_drm_private *dev_priv = drm_dev->dev_private;
	struct drm_pending_vblank_event *e, *t;
	struct drm_pending_vblank_event *e, *t;
	struct timeval now;
	struct timeval now;
	unsigned long flags;
	unsigned long flags;

	bool is_checked = false;
	if (!dev_priv->pageflip_event)
		return;


	spin_lock_irqsave(&drm_dev->event_lock, flags);
	spin_lock_irqsave(&drm_dev->event_lock, flags);


	list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
	list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
			base.link) {
			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);
		do_gettimeofday(&now);
		e->event.sequence = 0;
		e->event.sequence = 0;
		e->event.tv_sec = now.tv_sec;
		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);
		wake_up_interruptible(&e->base.file_priv->event_wait);
	}
	}


	if (is_checked)
		drm_vblank_put(drm_dev, crtc);
		drm_vblank_put(drm_dev, crtc);
	dev_priv->pageflip_event = false;


	spin_unlock_irqrestore(&drm_dev->event_lock, flags);
	spin_unlock_irqrestore(&drm_dev->event_lock, flags);
}
}