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

Commit c4533665 authored by Gustavo Padovan's avatar Gustavo Padovan Committed by Inki Dae
Browse files

drm/exynos: wait all planes updates to finish



Add infrastructure to wait for all planes updates to finish by using
an atomic_t variable to track how many pending updates we are waiting
plus a wait_queue for the wait part.

It also changes vblank behaviour and keeps it enabled for all types
of updates

Signed-off-by: default avatarGustavo Padovan <gustavo.padovan@collabora.co.uk>
Signed-off-by: default avatarInki Dae <inki.dae@samsung.com>
parent a379df19
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -75,10 +75,7 @@ static void exynos_crtc_atomic_begin(struct drm_crtc *crtc,
	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
	struct drm_plane *plane;

	if (crtc->state->event) {
		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
	exynos_crtc->event = crtc->state->event;
	}

	drm_atomic_crtc_for_each_plane(plane, crtc) {
		struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
@@ -156,6 +153,8 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
	exynos_crtc->ops = ops;
	exynos_crtc->ctx = ctx;

	init_waitqueue_head(&exynos_crtc->wait_update);

	crtc = &exynos_crtc->base;

	private->crtc[pipe] = crtc;
@@ -197,6 +196,13 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
		exynos_crtc->ops->disable_vblank(exynos_crtc);
}

void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc)
{
	wait_event_timeout(exynos_crtc->wait_update,
			   (atomic_read(&exynos_crtc->pending_update) == 0),
			   msecs_to_jiffies(50));
}

void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc,
				struct exynos_drm_plane *exynos_plane)
{
@@ -205,10 +211,12 @@ void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc,

	exynos_plane->pending_fb = NULL;

	if (atomic_dec_and_test(&exynos_crtc->pending_update))
		wake_up(&exynos_crtc->wait_update);

	spin_lock_irqsave(&crtc->dev->event_lock, flags);
	if (exynos_crtc->event) {
		drm_crtc_send_vblank_event(crtc, exynos_crtc->event);
		drm_crtc_vblank_put(crtc);
		wake_up(&exynos_crtc->pending_flip_queue);
	}

+1 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
					void *context);
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc);
void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc,
				   struct exynos_drm_plane *exynos_plane);
void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
+43 −1
Original line number Diff line number Diff line
@@ -45,11 +45,37 @@ struct exynos_atomic_commit {
	u32			crtcs;
};

static void exynos_atomic_wait_for_commit(struct drm_atomic_state *state)
{
	struct drm_crtc_state *crtc_state;
	struct drm_crtc *crtc;
	int i, ret;

	for_each_crtc_in_state(state, crtc, crtc_state, i) {
		struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);

		if (!crtc->state->enable)
			continue;

		ret = drm_crtc_vblank_get(crtc);
		if (ret)
			continue;

		exynos_drm_crtc_wait_pending_update(exynos_crtc);
		drm_crtc_vblank_put(crtc);
	}
}

static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit)
{
	struct drm_device *dev = commit->dev;
	struct exynos_drm_private *priv = dev->dev_private;
	struct drm_atomic_state *state = commit->state;
	struct drm_plane *plane;
	struct drm_crtc *crtc;
	struct drm_plane_state *plane_state;
	struct drm_crtc_state *crtc_state;
	int i;

	drm_atomic_helper_commit_modeset_disables(dev, state);

@@ -63,9 +89,25 @@ static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit)
	 * have the relevant clocks enabled to perform the update.
	 */

	for_each_crtc_in_state(state, crtc, crtc_state, i) {
		struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);

		atomic_set(&exynos_crtc->pending_update, 0);
	}

	for_each_plane_in_state(state, plane, plane_state, i) {
		struct exynos_drm_crtc *exynos_crtc =
						to_exynos_crtc(plane->crtc);

		if (!plane->crtc)
			continue;

		atomic_inc(&exynos_crtc->pending_update);
	}

	drm_atomic_helper_commit_planes(dev, state);

	drm_atomic_helper_wait_for_vblanks(dev, state);
	exynos_atomic_wait_for_commit(state);

	drm_atomic_helper_cleanup_planes(dev, state);

+4 −0
Original line number Diff line number Diff line
@@ -136,6 +136,8 @@ struct exynos_drm_crtc_ops {
 *	this pipe value.
 * @enabled: if the crtc is enabled or not
 * @event: vblank event that is currently queued for flip
 * @wait_update: wait all pending planes updates to finish
 * @pending_update: number of pending plane updates in this crtc
 * @ops: pointer to callbacks for exynos drm specific functionality
 * @ctx: A pointer to the crtc's implementation specific context
 */
@@ -145,6 +147,8 @@ struct exynos_drm_crtc {
	unsigned int			pipe;
	wait_queue_head_t		pending_flip_queue;
	struct drm_pending_vblank_event	*event;
	wait_queue_head_t		wait_update;
	atomic_t			pending_update;
	const struct exynos_drm_crtc_ops	*ops;
	void				*ctx;
};