Message ID | 1345197059-25583-9-git-send-email-inki.dae@samsung.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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 --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 = {