[PATCH 6/8] drm/exynos: add complete_scanout interface

Prathyush K prathyush.k at samsung.com
Wed Dec 26 03:27:43 PST 2012


Before freeing a framebuffer, we call complete_scanout encoder
function which just calls wait for vblank of all the encoders.
This is not a very optimized method since a framebuffer might not
be in use by a crtc and we end up waiting for vblank unnecessarily.

Instead, this patch modifies the wait_for_vblank interface to
complete_scanout interface. In this function, each crtc must
check if the fb is currently being used. If it is being used,
it must wait for vsync (or even disable a window if necessary)
and ensure that the buffer is no longer used by crtc before returning.
So if a crtc is not actually reading from the buffer, the complete
scanout function will just return and not wait for vsync.

Signed-off-by: Prathyush K <prathyush.k at samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_drv.h     |  7 ++++---
 drivers/gpu/drm/exynos/exynos_drm_encoder.c | 23 +++++++++++------------
 drivers/gpu/drm/exynos/exynos_drm_encoder.h |  4 +++-
 drivers/gpu/drm/exynos/exynos_drm_fb.c      | 13 +++++++++++--
 4 files changed, 29 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index b9e51bc..d351daf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -167,8 +167,7 @@ struct exynos_drm_display_ops {
  * @commit: set current hw specific display mode to hw.
  * @enable_vblank: specific driver callback for enabling vblank interrupt.
  * @disable_vblank: specific driver callback for disabling vblank interrupt.
- * @wait_for_vblank: wait for vblank interrupt to make sure that
- *	hardware overlay is updated.
+ * @complete_scanout: complete scan of buffer so that it can be freed.
  */
 struct exynos_drm_manager_ops {
 	void (*dpms)(struct device *subdrv_dev, int mode);
@@ -183,7 +182,9 @@ struct exynos_drm_manager_ops {
 	void (*commit)(struct device *subdrv_dev);
 	int (*enable_vblank)(struct device *subdrv_dev);
 	void (*disable_vblank)(struct device *subdrv_dev);
-	void (*wait_for_vblank)(struct device *subdrv_dev);
+	void (*complete_scanout)(struct device *subdrv_dev,
+					dma_addr_t dma_addr,
+					unsigned long size);
 };
 
 /*
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index c63721f..7e772ed 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -220,28 +220,27 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
 	exynos_encoder->dpms = DRM_MODE_DPMS_ON;
 }
 
-void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
+void exynos_drm_encoder_complete_scanout(struct drm_device *drm_dev,
+					 dma_addr_t dma_addr,
+					 unsigned long size)
 {
 	struct exynos_drm_encoder *exynos_encoder;
 	struct exynos_drm_manager_ops *ops;
-	struct drm_device *dev = fb->dev;
 	struct drm_encoder *encoder;
+	struct device *dev;
 
-	/*
-	 * make sure that overlay data are updated to real hardware
-	 * for all encoders.
-	 */
-	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+	/* make sure that current framebuffer is not in use for all encoders */
+	list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list, head) {
 		exynos_encoder = to_exynos_encoder(encoder);
 		ops = exynos_encoder->manager->ops;
+		dev = exynos_encoder->manager->dev;
 
 		/*
-		 * wait for vblank interrupt
-		 * - this makes sure that overlay data are updated to
-		 *	real hardware.
+		 * complete_scanout
+		 * - this makes sure that framebuffer is not in use.
 		 */
-		if (ops->wait_for_vblank)
-			ops->wait_for_vblank(exynos_encoder->manager->dev);
+		if (ops->complete_scanout)
+			ops->complete_scanout(dev, dma_addr, size);
 	}
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
index 89e2fb0..b85211b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
@@ -32,6 +32,8 @@ void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data);
 void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data);
 void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data);
 void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb);
+void exynos_drm_encoder_complete_scanout(struct drm_device *drm_dev,
+					 dma_addr_t dma_addr,
+					 unsigned long size);
 
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 294c051..1ef684a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -69,11 +69,20 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
 {
 	struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
 	unsigned int i;
+	dma_addr_t dma_addr;
+	unsigned long size;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	/* make sure that overlay data are updated before relesing fb. */
-	exynos_drm_encoder_complete_scanout(fb);
+	for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem_obj); i++) {
+		if (exynos_fb->exynos_gem_obj[i] == NULL)
+			continue;
+
+		dma_addr = exynos_fb->exynos_gem_obj[i]->buffer->dma_addr;
+		size = exynos_fb->exynos_gem_obj[i]->buffer->size;
+
+		exynos_drm_encoder_complete_scanout(fb->dev, dma_addr, size);
+	}
 
 	drm_framebuffer_cleanup(fb);
 
-- 
1.8.0



More information about the dri-devel mailing list