]> Git Repo - linux.git/blobdiff - drivers/gpu/drm/tilcdc/tilcdc_crtc.c
Merge tag 'acpi-fix-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux.git] / drivers / gpu / drm / tilcdc / tilcdc_crtc.c
index 406fe4544b83d3351669a91103a0b56207feda82..6ef4d1a1e3a9944c9bff444a014a9f90a5825386 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/completion.h>
 #include <linux/dma-mapping.h>
 #include <linux/of_graph.h>
+#include <linux/math64.h>
 
 #include "tilcdc_drv.h"
 #include "tilcdc_regs.h"
@@ -48,6 +49,7 @@ struct tilcdc_crtc {
        unsigned int lcd_fck_rate;
 
        ktime_t last_vblank;
+       unsigned int hvtotal_us;
 
        struct drm_framebuffer *curr_fb;
        struct drm_framebuffer *next_fb;
@@ -75,7 +77,7 @@ static void unref_worker(struct drm_flip_work *work, void *val)
        struct drm_device *dev = tilcdc_crtc->base.dev;
 
        mutex_lock(&dev->mode_config.mutex);
-       drm_framebuffer_unreference(val);
+       drm_framebuffer_put(val);
        mutex_unlock(&dev->mode_config.mutex);
 }
 
@@ -292,6 +294,12 @@ static void tilcdc_crtc_set_clk(struct drm_crtc *crtc)
                                LCDC_V2_CORE_CLK_EN);
 }
 
+uint tilcdc_mode_hvtotal(const struct drm_display_mode *mode)
+{
+       return (uint) div_u64(1000llu * mode->htotal * mode->vtotal,
+                             mode->clock);
+}
+
 static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
 {
        struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
@@ -456,9 +464,12 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
 
        set_scanout(crtc, fb);
 
-       drm_framebuffer_reference(fb);
+       drm_framebuffer_get(fb);
 
        crtc->hwmode = crtc->state->adjusted_mode;
+
+       tilcdc_crtc->hvtotal_us =
+               tilcdc_mode_hvtotal(&crtc->hwmode);
 }
 
 static void tilcdc_crtc_enable(struct drm_crtc *crtc)
@@ -467,7 +478,6 @@ static void tilcdc_crtc_enable(struct drm_crtc *crtc)
        struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
        unsigned long flags;
 
-       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
        mutex_lock(&tilcdc_crtc->enable_lock);
        if (tilcdc_crtc->enabled || tilcdc_crtc->shutdown) {
                mutex_unlock(&tilcdc_crtc->enable_lock);
@@ -564,7 +574,6 @@ static void tilcdc_crtc_off(struct drm_crtc *crtc, bool shutdown)
 
 static void tilcdc_crtc_disable(struct drm_crtc *crtc)
 {
-       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
        tilcdc_crtc_off(crtc, false);
 }
 
@@ -608,9 +617,7 @@ static void tilcdc_crtc_destroy(struct drm_crtc *crtc)
        struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
        struct tilcdc_drm_private *priv = crtc->dev->dev_private;
 
-       drm_modeset_lock(&crtc->mutex, NULL);
-       tilcdc_crtc_disable(crtc);
-       drm_modeset_unlock(&crtc->mutex);
+       tilcdc_crtc_shutdown(crtc);
 
        flush_workqueue(priv->wq);
 
@@ -626,14 +633,12 @@ int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
        struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
        struct drm_device *dev = crtc->dev;
 
-       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
-
        if (tilcdc_crtc->event) {
                dev_err(dev->dev, "already pending page flip!\n");
                return -EBUSY;
        }
 
-       drm_framebuffer_reference(fb);
+       drm_framebuffer_get(fb);
 
        crtc->primary->fb = fb;
        tilcdc_crtc->event = event;
@@ -648,7 +653,7 @@ int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
                spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags);
 
                next_vblank = ktime_add_us(tilcdc_crtc->last_vblank,
-                                          1000000 / crtc->hwmode.vrefresh);
+                                          tilcdc_crtc->hvtotal_us);
                tdiff = ktime_to_us(ktime_sub(next_vblank, ktime_get()));
 
                if (tdiff < TILCDC_VBLANK_SAFETY_THRESHOLD_US)
@@ -728,11 +733,39 @@ static void tilcdc_crtc_disable_vblank(struct drm_crtc *crtc)
 {
 }
 
+static void tilcdc_crtc_reset(struct drm_crtc *crtc)
+{
+       struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       int ret;
+
+       drm_atomic_helper_crtc_reset(crtc);
+
+       /* Turn the raster off if it for some reason is on. */
+       pm_runtime_get_sync(dev->dev);
+       if (tilcdc_read(dev, LCDC_RASTER_CTRL_REG) & LCDC_RASTER_ENABLE) {
+               /* Enable DMA Frame Done Interrupt */
+               tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG, LCDC_FRAME_DONE);
+               tilcdc_clear_irqstatus(dev, 0xffffffff);
+
+               tilcdc_crtc->frame_done = false;
+               tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
+
+               ret = wait_event_timeout(tilcdc_crtc->frame_done_wq,
+                                        tilcdc_crtc->frame_done,
+                                        msecs_to_jiffies(500));
+               if (ret == 0)
+                       dev_err(dev->dev, "%s: timeout waiting for framedone\n",
+                               __func__);
+       }
+       pm_runtime_put_sync(dev->dev);
+}
+
 static const struct drm_crtc_funcs tilcdc_crtc_funcs = {
        .destroy        = tilcdc_crtc_destroy,
        .set_config     = drm_atomic_helper_set_config,
        .page_flip      = drm_atomic_helper_page_flip,
-       .reset          = drm_atomic_helper_crtc_reset,
+       .reset          = tilcdc_crtc_reset,
        .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
        .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
        .enable_vblank  = tilcdc_crtc_enable_vblank,
This page took 0.038403 seconds and 4 git commands to generate.