diff mbox

[v2,05/23] drm/exynos: add atomic asynchronous commit

Message ID 1436192424-18194-6-git-send-email-gustavo@padovan.org (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Gustavo Padovan July 6, 2015, 2:20 p.m. UTC
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

The atomic modesetting interfaces supports async commits that should be
implemented by the drivers. If drm core requests an async commit
exynos_atomic_commit() will schedule a work task to run the update later.

It also waits an update to finish before schedule a new one.

Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
 drivers/gpu/drm/exynos/exynos_drm_drv.c |  6 ++++
 drivers/gpu/drm/exynos/exynos_drm_drv.h |  6 ++++
 drivers/gpu/drm/exynos/exynos_drm_fb.c  | 51 ++++++++++++++++++++++++++-------
 3 files changed, 52 insertions(+), 11 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 63a68c6..3542f2c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -47,6 +47,9 @@  static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 	if (!private)
 		return -ENOMEM;
 
+	INIT_WORK(&private->work, exynos_drm_atomic_work);
+	private->dev = dev;
+
 	dev_set_drvdata(dev->dev, dev);
 	dev->dev_private = (void *)private;
 
@@ -127,6 +130,8 @@  err_free_private:
 
 static int exynos_drm_unload(struct drm_device *dev)
 {
+	struct exynos_drm_private *private = dev->dev_private;
+
 	exynos_drm_device_subdrv_remove(dev);
 
 	exynos_drm_fbdev_fini(dev);
@@ -137,6 +142,7 @@  static int exynos_drm_unload(struct drm_device *dev)
 	drm_mode_config_cleanup(dev);
 	drm_release_iommu_mapping(dev);
 
+	flush_work(&private->work);
 	kfree(dev->dev_private);
 	dev->dev_private = NULL;
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index dd00f16..d9fd8e1 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -244,6 +244,10 @@  struct exynos_drm_private {
 	unsigned long da_space_size;
 
 	unsigned int pipe;
+
+	struct drm_device *dev;
+	struct work_struct work;
+	struct drm_atomic_state *state;
 };
 
 /*
@@ -296,6 +300,8 @@  static inline int exynos_dpi_remove(struct exynos_drm_display *display)
 }
 #endif
 
+void exynos_drm_atomic_work(struct work_struct *work);
+
 /* This function creates a encoder and a connector, and initializes them. */
 int exynos_drm_create_enc_conn(struct drm_device *dev,
 				struct exynos_drm_display *display);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 2b6320e..ad6b8ac 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -267,20 +267,18 @@  static void exynos_drm_output_poll_changed(struct drm_device *dev)
 		exynos_drm_fbdev_init(dev);
 }
 
-static int exynos_atomic_commit(struct drm_device *dev,
-				struct drm_atomic_state *state,
-				bool async)
+static void exynos_atomic_commit_schedule(struct drm_device *dev,
+				struct drm_atomic_state *state)
 {
-	int ret;
-
-	ret = drm_atomic_helper_prepare_planes(dev, state);
-	if (ret)
-		return ret;
-
-	/* This is the point of no return */
+	struct exynos_drm_private *private = dev->dev_private;
 
-	drm_atomic_helper_swap_state(dev, state);
+	private->state = state;
+	schedule_work(&private->work);
+}
 
+static void exynos_atomic_commit_complete(struct drm_device *dev,
+					  struct drm_atomic_state *state)
+{
 	drm_atomic_helper_commit_modeset_disables(dev, state);
 
 	drm_atomic_helper_commit_modeset_enables(dev, state);
@@ -298,6 +296,37 @@  static int exynos_atomic_commit(struct drm_device *dev,
 	drm_atomic_helper_cleanup_planes(dev, state);
 
 	drm_atomic_state_free(state);
+}
+
+void exynos_drm_atomic_work(struct work_struct *work)
+{
+	struct exynos_drm_private *private = container_of(work,
+				struct exynos_drm_private, work);
+
+	exynos_atomic_commit_complete(private->dev, private->state);
+}
+
+static int exynos_atomic_commit(struct drm_device *dev,
+				struct drm_atomic_state *state,
+				bool async)
+{
+	struct exynos_drm_private *private = dev->dev_private;
+	int ret;
+
+	ret = drm_atomic_helper_prepare_planes(dev, state);
+	if (ret)
+		return ret;
+
+	/* This is the point of no return */
+
+	flush_work(&private->work);
+
+	drm_atomic_helper_swap_state(dev, state);
+
+	if (async)
+		exynos_atomic_commit_schedule(dev, state);
+	else
+		exynos_atomic_commit_complete(dev, state);
 
 	return 0;
 }