diff options
Diffstat (limited to 'drivers/gpu/drm/tilcdc/tilcdc_crtc.c')
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 57 |
1 files changed, 45 insertions, 12 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 406fe4544b83..6ef4d1a1e3a9 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -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, |