diff mbox

[08/13] drm/exynos: make sure that hardware overlay for fimd is disabled

Message ID 1345197059-25583-9-git-send-email-inki.dae@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Inki Dae Aug. 17, 2012, 9:50 a.m. UTC
the values set to registers will be updated into real registers
at vsync so dma operation could be malfunctioned when accessed
to memory after gem buffer was released. this patch makes sure
that hw overlay is disabled before the gem buffer is released.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_drv.h     |   17 +++++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_encoder.c |   10 ++++++++++
 drivers/gpu/drm/exynos/exynos_drm_fimd.c    |   12 ++++++++++++
 3 files changed, 39 insertions(+), 0 deletions(-)

Comments

Joonyoung Shim Aug. 20, 2012, 2:09 a.m. UTC | #1
On 08/17/2012 06:50 PM, Inki Dae wrote:
> the values set to registers will be updated into real registers
> at vsync so dma operation could be malfunctioned when accessed
> to memory after gem buffer was released. this patch makes sure
> that hw overlay is disabled before the gem buffer is released.
>
> Signed-off-by: Inki Dae <inki.dae@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>   drivers/gpu/drm/exynos/exynos_drm_drv.h     |   17 +++++++++++++++++
>   drivers/gpu/drm/exynos/exynos_drm_encoder.c |   10 ++++++++++
>   drivers/gpu/drm/exynos/exynos_drm_fimd.c    |   12 ++++++++++++

Please split patch to exynos_drm part and fimd part.

>   3 files changed, 39 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
> index 24c45d8..00e4bdc 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
> @@ -37,6 +37,20 @@
>   #define MAX_FB_BUFFER	4
>   #define DEFAULT_ZPOS	-1
>   
> +#define _wait_for(COND, MS) ({ \
> +	unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);	\
> +	int ret__ = 0;							\
> +	while (!(COND)) {						\
> +		if (time_after(jiffies, timeout__)) {			\
> +			ret__ = -ETIMEDOUT;				\
> +			break;						\
> +		}							\
> +	}								\
> +	ret__;								\
> +})
> +
> +#define wait_for(COND, MS) _wait_for(COND, MS)
> +
>   struct drm_device;
>   struct exynos_drm_overlay;
>   struct drm_connector;
> @@ -61,6 +75,8 @@ enum exynos_drm_output_type {
>    * @commit: apply hardware specific overlay data to registers.
>    * @enable: enable hardware specific overlay.
>    * @disable: disable hardware specific overlay.
> + * @wait_for_vblank: wait for vblank interrupt to make sure that
> + *	dma transfer is completed.
>    */
>   struct exynos_drm_overlay_ops {
>   	void (*mode_set)(struct device *subdrv_dev,
> @@ -68,6 +84,7 @@ struct exynos_drm_overlay_ops {
>   	void (*commit)(struct device *subdrv_dev, int zpos);
>   	void (*enable)(struct device *subdrv_dev, int zpos);
>   	void (*disable)(struct device *subdrv_dev, int zpos);
> +	void (*wait_for_vblank)(struct device *subdrv_dev);
>   };
>   
>   /*
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> index 7da5714..a562a94 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> @@ -399,4 +399,14 @@ void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
>   
>   	if (overlay_ops && overlay_ops->disable)
>   		overlay_ops->disable(manager->dev, zpos);
> +
> +	/*
> +	 * wait for vblank interrupt
> +	 * - with iommu, the dma operation could induce page fault
> +	 * when accessed to memory after gem buffer was released so
> +	 * make sure that the dma operation is completed before releasing
> +	 * the gem bufer.
> +	 */
> +	if (overlay_ops->wait_for_vblank)
> +		overlay_ops->wait_for_vblank(manager->dev);
>   }
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> index 0ec9d86..2378d80 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> @@ -570,10 +570,22 @@ static void fimd_win_disable(struct device *dev, int zpos)
>   	win_data->enabled = false;
>   }
>   
> +static void fimd_wait_for_vblank(struct device *dev)
> +{
> +	struct fimd_context *ctx = get_fimd_context(dev);
> +	int ret;
> +
> +	ret = wait_for((__raw_readl(ctx->regs + VIDCON1) &
> +					VIDCON1_VSTATUS_BACKPORCH), 50);
> +	if (ret < 0)
> +		DRM_DEBUG_KMS("vblank wait timed out.\n");
> +}
> +
>   static struct exynos_drm_overlay_ops fimd_overlay_ops = {
>   	.mode_set = fimd_win_mode_set,
>   	.commit = fimd_win_commit,
>   	.disable = fimd_win_disable,
> +	.wait_for_vblank = fimd_wait_for_vblank,
>   };
>   
>   static struct exynos_drm_manager fimd_manager = {
diff mbox

Patch

diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 24c45d8..00e4bdc 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -37,6 +37,20 @@ 
 #define MAX_FB_BUFFER	4
 #define DEFAULT_ZPOS	-1
 
+#define _wait_for(COND, MS) ({ \
+	unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);	\
+	int ret__ = 0;							\
+	while (!(COND)) {						\
+		if (time_after(jiffies, timeout__)) {			\
+			ret__ = -ETIMEDOUT;				\
+			break;						\
+		}							\
+	}								\
+	ret__;								\
+})
+
+#define wait_for(COND, MS) _wait_for(COND, MS)
+
 struct drm_device;
 struct exynos_drm_overlay;
 struct drm_connector;
@@ -61,6 +75,8 @@  enum exynos_drm_output_type {
  * @commit: apply hardware specific overlay data to registers.
  * @enable: enable hardware specific overlay.
  * @disable: disable hardware specific overlay.
+ * @wait_for_vblank: wait for vblank interrupt to make sure that
+ *	dma transfer is completed.
  */
 struct exynos_drm_overlay_ops {
 	void (*mode_set)(struct device *subdrv_dev,
@@ -68,6 +84,7 @@  struct exynos_drm_overlay_ops {
 	void (*commit)(struct device *subdrv_dev, int zpos);
 	void (*enable)(struct device *subdrv_dev, int zpos);
 	void (*disable)(struct device *subdrv_dev, int zpos);
+	void (*wait_for_vblank)(struct device *subdrv_dev);
 };
 
 /*
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 7da5714..a562a94 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -399,4 +399,14 @@  void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
 
 	if (overlay_ops && overlay_ops->disable)
 		overlay_ops->disable(manager->dev, zpos);
+
+	/*
+	 * wait for vblank interrupt
+	 * - with iommu, the dma operation could induce page fault
+	 * when accessed to memory after gem buffer was released so
+	 * make sure that the dma operation is completed before releasing
+	 * the gem bufer.
+	 */
+	if (overlay_ops->wait_for_vblank)
+		overlay_ops->wait_for_vblank(manager->dev);
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 0ec9d86..2378d80 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -570,10 +570,22 @@  static void fimd_win_disable(struct device *dev, int zpos)
 	win_data->enabled = false;
 }
 
+static void fimd_wait_for_vblank(struct device *dev)
+{
+	struct fimd_context *ctx = get_fimd_context(dev);
+	int ret;
+
+	ret = wait_for((__raw_readl(ctx->regs + VIDCON1) &
+					VIDCON1_VSTATUS_BACKPORCH), 50);
+	if (ret < 0)
+		DRM_DEBUG_KMS("vblank wait timed out.\n");
+}
+
 static struct exynos_drm_overlay_ops fimd_overlay_ops = {
 	.mode_set = fimd_win_mode_set,
 	.commit = fimd_win_commit,
 	.disable = fimd_win_disable,
+	.wait_for_vblank = fimd_wait_for_vblank,
 };
 
 static struct exynos_drm_manager fimd_manager = {