]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/exynos/exynos_drm_fimd.c
drm/exynos: move triggering checking
[karo-tx-linux.git] / drivers / gpu / drm / exynos / exynos_drm_fimd.c
index 5d09e33fef8716084a169bee2afb63e429187b48..ec2d1702b93b18f9e53a391df3a62cedfbde5643 100644 (file)
@@ -96,6 +96,7 @@ struct fimd_driver_data {
        unsigned int has_clksel:1;
        unsigned int has_limited_fmt:1;
        unsigned int has_vidoutcon:1;
+       unsigned int has_vtsel:1;
 };
 
 static struct fimd_driver_data s3c64xx_fimd_driver_data = {
@@ -104,12 +105,31 @@ static struct fimd_driver_data s3c64xx_fimd_driver_data = {
        .has_limited_fmt = 1,
 };
 
+static struct fimd_driver_data exynos3_fimd_driver_data = {
+       .timing_base = 0x20000,
+       .lcdblk_offset = 0x210,
+       .lcdblk_bypass_shift = 1,
+       .has_shadowcon = 1,
+       .has_vidoutcon = 1,
+};
+
 static struct fimd_driver_data exynos4_fimd_driver_data = {
        .timing_base = 0x0,
        .lcdblk_offset = 0x210,
        .lcdblk_vt_shift = 10,
        .lcdblk_bypass_shift = 1,
        .has_shadowcon = 1,
+       .has_vtsel = 1,
+};
+
+static struct fimd_driver_data exynos4415_fimd_driver_data = {
+       .timing_base = 0x20000,
+       .lcdblk_offset = 0x210,
+       .lcdblk_vt_shift = 10,
+       .lcdblk_bypass_shift = 1,
+       .has_shadowcon = 1,
+       .has_vidoutcon = 1,
+       .has_vtsel = 1,
 };
 
 static struct fimd_driver_data exynos5_fimd_driver_data = {
@@ -119,6 +139,7 @@ static struct fimd_driver_data exynos5_fimd_driver_data = {
        .lcdblk_bypass_shift = 15,
        .has_shadowcon = 1,
        .has_vidoutcon = 1,
+       .has_vtsel = 1,
 };
 
 struct fimd_win_data {
@@ -168,8 +189,12 @@ struct fimd_context {
 static const struct of_device_id fimd_driver_dt_match[] = {
        { .compatible = "samsung,s3c6400-fimd",
          .data = &s3c64xx_fimd_driver_data },
+       { .compatible = "samsung,exynos3250-fimd",
+         .data = &exynos3_fimd_driver_data },
        { .compatible = "samsung,exynos4210-fimd",
          .data = &exynos4_fimd_driver_data },
+       { .compatible = "samsung,exynos4415-fimd",
+         .data = &exynos4415_fimd_driver_data },
        { .compatible = "samsung,exynos5250-fimd",
          .data = &exynos5_fimd_driver_data },
        {},
@@ -204,7 +229,6 @@ static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
                DRM_DEBUG_KMS("vblank wait timed out.\n");
 }
 
-
 static void fimd_clear_channel(struct exynos_drm_manager *mgr)
 {
        struct fimd_context *ctx = mgr->ctx;
@@ -214,17 +238,31 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr)
 
        /* 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);
+               u32 val = readl(ctx->regs + WINCON(win));
+
+               if (val & WINCONx_ENWIN) {
+                       /* wincon */
+                       val &= ~WINCONx_ENWIN;
+                       writel(val, ctx->regs + WINCON(win));
+
+                       /* unprotect windows */
+                       if (ctx->driver_data->has_shadowcon) {
+                               val = readl(ctx->regs + SHADOWCON);
+                               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)
+       if (ch_enabled) {
+               unsigned int state = ctx->suspended;
+
+               ctx->suspended = 0;
                fimd_wait_for_vblank(mgr);
+               ctx->suspended = state;
+       }
 }
 
 static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
@@ -237,23 +275,6 @@ static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
        mgr->drm_dev = ctx->drm_dev = drm_dev;
        mgr->pipe = ctx->pipe = priv->pipe++;
 
-       /*
-        * enable drm irq mode.
-        * - with irq_enabled = true, we can use the vblank feature.
-        *
-        * P.S. note that we wouldn't use drm irq handler but
-        *      just specific driver own one instead because
-        *      drm framework supports only one irq handler.
-        */
-       drm_dev->irq_enabled = true;
-
-       /*
-        * with vblank_disable_allowed = true, vblank interrupt will be disabled
-        * by drm timer once a current process gives up ownership of
-        * vblank event.(after drm_vblank_put function is called)
-        */
-       drm_dev->vblank_disable_allowed = true;
-
        /* attach this sub driver to iommu mapping if supported. */
        if (is_drm_iommu_supported(ctx->drm_dev)) {
                /*
@@ -337,7 +358,8 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
                writel(0, timing_base + I80IFCONFBx(0));
 
                /* set video type selection to I80 interface */
-               if (ctx->sysreg && regmap_update_bits(ctx->sysreg,
+               if (driver_data->has_vtsel && ctx->sysreg &&
+                               regmap_update_bits(ctx->sysreg,
                                        driver_data->lcdblk_offset,
                                        0x3 << driver_data->lcdblk_vt_shift,
                                        0x1 << driver_data->lcdblk_vt_shift)) {
@@ -797,7 +819,6 @@ static void fimd_window_suspend(struct exynos_drm_manager *mgr)
                if (win_data->enabled)
                        fimd_win_disable(mgr, i);
        }
-       fimd_wait_for_vblank(mgr);
 }
 
 static void fimd_window_resume(struct exynos_drm_manager *mgr)
@@ -928,6 +949,13 @@ static void fimd_trigger(struct device *dev)
        void *timing_base = ctx->regs + driver_data->timing_base;
        u32 reg;
 
+        /*
+        * Skips to trigger if in triggering state, because multiple triggering
+        * requests can cause panel reset.
+        */
+       if (atomic_read(&ctx->triggering))
+               return;
+
        atomic_set(&ctx->triggering, 1);
 
        reg = readl(ctx->regs + VIDINTCON0);
@@ -948,13 +976,6 @@ static void fimd_te_handler(struct exynos_drm_manager *mgr)
        if (ctx->pipe < 0 || !ctx->drm_dev)
                return;
 
-        /*
-        * Skips to trigger if in triggering state, because multiple triggering
-        * requests can cause panel reset.
-        */
-       if (atomic_read(&ctx->triggering))
-               return;
-
        /*
         * If there is a page flip request, triggers and handles the page flip
         * event so that current fb can be updated into panel GRAM.
@@ -966,10 +987,10 @@ static void fimd_te_handler(struct exynos_drm_manager *mgr)
        if (atomic_read(&ctx->wait_vsync_event)) {
                atomic_set(&ctx->wait_vsync_event, 0);
                wake_up(&ctx->wait_vsync_queue);
-
-               if (!atomic_read(&ctx->triggering))
-                       drm_handle_vblank(ctx->drm_dev, ctx->pipe);
        }
+
+       if (!atomic_read(&ctx->triggering))
+               drm_handle_vblank(ctx->drm_dev, ctx->pipe);
 }
 
 static struct exynos_drm_manager_ops fimd_manager_ops = {
@@ -1051,7 +1072,6 @@ static void fimd_unbind(struct device *dev, struct device *master,
 {
        struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
        struct fimd_context *ctx = fimd_manager.ctx;
-       struct drm_crtc *crtc = mgr->crtc;
 
        fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
 
@@ -1059,8 +1079,6 @@ static void fimd_unbind(struct device *dev, struct device *master,
                exynos_dpi_remove(dev);
 
        fimd_mgr_remove(mgr);
-
-       crtc->funcs->destroy(crtc);
 }
 
 static const struct component_ops fimd_component_ops = {