@@ -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);
};
/*
@@ -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);
}
}
@@ -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
@@ -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);
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@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(-)