[PATCH v2] drm/exynos: fimd: clear channel before enabling iommu
Daniel Kurtz
djkurtz at chromium.org
Tue Apr 29 23:21:11 PDT 2014
On Wed, Apr 30, 2014 at 1:44 PM, Inki Dae <inki.dae at samsung.com> wrote:
> Hi Daniel,
>
> Please use only text format. :)
>
>
>>From: djkurtz at google.com [mailto:djkurtz at google.com] On Behalf Of Daniel Kurtz
>>Sent: Wednesday, April 30, 2014 1:57 PM
>>To: Inki Dae
>>Cc: David Airlie; dri-devel; Akshu Agrawal; Prathyush K
>>Subject: Re: [PATCH v2] drm/exynos: fimd: clear channel before enabling iommu
>>
>>
>>
>>On Tue, Apr 29, 2014 at 9:38 AM, Inki Dae <inki.dae at samsung.com> wrote:
>>From: Akshu Agrawal <akshu.a at samsung.com>
>>
>>If any fimd channel was already active, initializing iommu will result
>>in a PAGE FAULT (e.e. u-boot could have turned on the display and
>>not disabled it before the kernel starts). This patch checks if any
>>channel is active before initializing iommu and disables it.
>>
>>Changelog v2:
>>- consider SoC without SHADOWCON register
>>
>>Signed-off-by: Akshu Agrawal <akshu.a at samsung.com>
>>Signed-off-by: Prathyush K <prathyush.k at samsung.com>
>>Signed-off-by: Inki Dae <inki.dae at samsung.com>
>>---
>> drivers/gpu/drm/exynos/exynos_drm_fimd.c | 70 +++++++++++++++++++++---------
>> 1 file changed, 50 insertions(+), 20 deletions(-)
>>
>>diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>index 40fd6cc..ef21ce4 100644
>>--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>>@@ -143,6 +143,48 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
>> return (struct fimd_driver_data *)of_id->data;
>> }
>>
>>+static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
>>+{
>>+ struct fimd_context *ctx = mgr->ctx;
>>+
>>+ if (ctx->suspended)
>>+ return;
>>+
>>
>>Hi Inki,
>>
>>I think you need this to guarantee that the irq is actually enabled:
>>
>
> Right, it needs to make sure that the irq is enabled.
>
>
>> drm_vblank_get(ctx->drm_dev, ctx->pipe);
>>
>>+ atomic_set(&ctx->wait_vsync_event, 1);
>>+
>>+ /*
>>+ * wait for FIMD to signal VSYNC interrupt or return after
>>+ * timeout which is set to 50ms (refresh rate of 20).
>>+ */
>>+ if (!wait_event_timeout(ctx->wait_vsync_queue,
>>+ !atomic_read(&ctx->wait_vsync_event),
>>+ HZ/20))
>>+ DRM_DEBUG_KMS("vblank wait timed out.\n");
>>
>> drm_vblank_put(ctx->drm_dev, ctx->pipe);
>>
>>+}
>>+
>>+
>>+static void fimd_clear_channel(struct exynos_drm_manager *mgr)
>>+{
>>+ struct fimd_context *ctx = mgr->ctx;
>>+ int win, ch_enabled = 0;
>>+
>>+ DRM_DEBUG_KMS("%s\n", __FILE__);
>>+
>>+ /* Check if any channel is enabled. */
>>+ for (win = 0; win < WINDOWS_NR; win++) {
>>+ u32 val = readl(ctx->regs + SHADOWCON);
>>+ if (val & SHADOWCON_CHx_ENABLE(win)) {
>>+ val &= ~SHADOWCON_CHx_ENABLE(win);
>>+ writel(val, ctx->regs + SHADOWCON);
>>+ ch_enabled = 1;
>>+ }
>>+ }
>>+
>>+ /* Wait for vsync, as disable channel takes effect at next vsync */
>>+ if (ch_enabled)
>>+ fimd_wait_for_vblank(mgr);
>>+}
>>+
>> static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
>> struct drm_device *drm_dev, int pipe)
>> {
>>@@ -169,8 +211,15 @@ static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
>> drm_dev->vblank_disable_allowed = true;
>>
>> /* attach this sub driver to iommu mapping if supported. */
>>- if (is_drm_iommu_supported(ctx->drm_dev))
>>+ if (is_drm_iommu_supported(ctx->drm_dev)) {
>>+ /*
>>+ * If any channel is already active, iommu will throw
>>+ * a PAGE FAULT when enabled. So clear any channel if enabled.
>>+ */
>>+ if (ctx->driver_data->has_shadowcon)
>>+ fimd_clear_channel(mgr);
>>
>>We already disable all overlays at the end of fimd_probe() by calling fimd_clear_win().
>>Perhaps all that was missing was just waiting until the next vblank to ensure that these clears have all completed?
>>
>
> No, fimd_mgr_initialize() will be called at load() so the iommu unit for fimd ip will be tried to be enabled prior to fimd_clear_channel() call - before all dma channels are disabled. In this case, page fault could be incurred if fimd ip was already on by bootloader.
Right. So, I suggest moving drm_iommu_attach_device() from
mgr_initialize to fimd_probe(), after clearing the windows and waiting
for vblank.
>
> Thanks,
> Inki Dae
>
>>Best Regards,
>>-Daniel
>>
>> drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
>>+ }
>>
>> return 0;
>> }
>>@@ -324,25 +373,6 @@ static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
>> }
>> }
>>
>>-static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
>>-{
>>- struct fimd_context *ctx = mgr->ctx;
>>-
>>- if (ctx->suspended)
>>- return;
>>-
>>- atomic_set(&ctx->wait_vsync_event, 1);
>>-
>>- /*
>>- * wait for FIMD to signal VSYNC interrupt or return after
>>- * timeout which is set to 50ms (refresh rate of 20).
>>- */
>>- if (!wait_event_timeout(ctx->wait_vsync_queue,
>>- !atomic_read(&ctx->wait_vsync_event),
>>- HZ/20))
>>- DRM_DEBUG_KMS("vblank wait timed out.\n");
>>-}
>>-
>> static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
>> struct exynos_drm_overlay *overlay)
>> {
>>--
>>1.7.9.5
>>
>>_______________________________________________
>>dri-devel mailing list
>>dri-devel at lists.freedesktop.org
>>http://lists.freedesktop.org/mailman/listinfo/dri-devel
>
>
More information about the dri-devel
mailing list