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 @@ | |||
24 | #include <linux/completion.h> | 24 | #include <linux/completion.h> |
25 | #include <linux/dma-mapping.h> | 25 | #include <linux/dma-mapping.h> |
26 | #include <linux/of_graph.h> | 26 | #include <linux/of_graph.h> |
27 | #include <linux/math64.h> | ||
27 | 28 | ||
28 | #include "tilcdc_drv.h" | 29 | #include "tilcdc_drv.h" |
29 | #include "tilcdc_regs.h" | 30 | #include "tilcdc_regs.h" |
@@ -48,6 +49,7 @@ struct tilcdc_crtc { | |||
48 | unsigned int lcd_fck_rate; | 49 | unsigned int lcd_fck_rate; |
49 | 50 | ||
50 | ktime_t last_vblank; | 51 | ktime_t last_vblank; |
52 | unsigned int hvtotal_us; | ||
51 | 53 | ||
52 | struct drm_framebuffer *curr_fb; | 54 | struct drm_framebuffer *curr_fb; |
53 | struct drm_framebuffer *next_fb; | 55 | struct drm_framebuffer *next_fb; |
@@ -75,7 +77,7 @@ static void unref_worker(struct drm_flip_work *work, void *val) | |||
75 | struct drm_device *dev = tilcdc_crtc->base.dev; | 77 | struct drm_device *dev = tilcdc_crtc->base.dev; |
76 | 78 | ||
77 | mutex_lock(&dev->mode_config.mutex); | 79 | mutex_lock(&dev->mode_config.mutex); |
78 | drm_framebuffer_unreference(val); | 80 | drm_framebuffer_put(val); |
79 | mutex_unlock(&dev->mode_config.mutex); | 81 | mutex_unlock(&dev->mode_config.mutex); |
80 | } | 82 | } |
81 | 83 | ||
@@ -292,6 +294,12 @@ static void tilcdc_crtc_set_clk(struct drm_crtc *crtc) | |||
292 | LCDC_V2_CORE_CLK_EN); | 294 | LCDC_V2_CORE_CLK_EN); |
293 | } | 295 | } |
294 | 296 | ||
297 | uint tilcdc_mode_hvtotal(const struct drm_display_mode *mode) | ||
298 | { | ||
299 | return (uint) div_u64(1000llu * mode->htotal * mode->vtotal, | ||
300 | mode->clock); | ||
301 | } | ||
302 | |||
295 | static void tilcdc_crtc_set_mode(struct drm_crtc *crtc) | 303 | static void tilcdc_crtc_set_mode(struct drm_crtc *crtc) |
296 | { | 304 | { |
297 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 305 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |
@@ -456,9 +464,12 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc) | |||
456 | 464 | ||
457 | set_scanout(crtc, fb); | 465 | set_scanout(crtc, fb); |
458 | 466 | ||
459 | drm_framebuffer_reference(fb); | 467 | drm_framebuffer_get(fb); |
460 | 468 | ||
461 | crtc->hwmode = crtc->state->adjusted_mode; | 469 | crtc->hwmode = crtc->state->adjusted_mode; |
470 | |||
471 | tilcdc_crtc->hvtotal_us = | ||
472 | tilcdc_mode_hvtotal(&crtc->hwmode); | ||
462 | } | 473 | } |
463 | 474 | ||
464 | static void tilcdc_crtc_enable(struct drm_crtc *crtc) | 475 | static void tilcdc_crtc_enable(struct drm_crtc *crtc) |
@@ -467,7 +478,6 @@ static void tilcdc_crtc_enable(struct drm_crtc *crtc) | |||
467 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 478 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |
468 | unsigned long flags; | 479 | unsigned long flags; |
469 | 480 | ||
470 | WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); | ||
471 | mutex_lock(&tilcdc_crtc->enable_lock); | 481 | mutex_lock(&tilcdc_crtc->enable_lock); |
472 | if (tilcdc_crtc->enabled || tilcdc_crtc->shutdown) { | 482 | if (tilcdc_crtc->enabled || tilcdc_crtc->shutdown) { |
473 | mutex_unlock(&tilcdc_crtc->enable_lock); | 483 | mutex_unlock(&tilcdc_crtc->enable_lock); |
@@ -564,7 +574,6 @@ static void tilcdc_crtc_off(struct drm_crtc *crtc, bool shutdown) | |||
564 | 574 | ||
565 | static void tilcdc_crtc_disable(struct drm_crtc *crtc) | 575 | static void tilcdc_crtc_disable(struct drm_crtc *crtc) |
566 | { | 576 | { |
567 | WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); | ||
568 | tilcdc_crtc_off(crtc, false); | 577 | tilcdc_crtc_off(crtc, false); |
569 | } | 578 | } |
570 | 579 | ||
@@ -608,9 +617,7 @@ static void tilcdc_crtc_destroy(struct drm_crtc *crtc) | |||
608 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 617 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |
609 | struct tilcdc_drm_private *priv = crtc->dev->dev_private; | 618 | struct tilcdc_drm_private *priv = crtc->dev->dev_private; |
610 | 619 | ||
611 | drm_modeset_lock(&crtc->mutex, NULL); | 620 | tilcdc_crtc_shutdown(crtc); |
612 | tilcdc_crtc_disable(crtc); | ||
613 | drm_modeset_unlock(&crtc->mutex); | ||
614 | 621 | ||
615 | flush_workqueue(priv->wq); | 622 | flush_workqueue(priv->wq); |
616 | 623 | ||
@@ -626,14 +633,12 @@ int tilcdc_crtc_update_fb(struct drm_crtc *crtc, | |||
626 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 633 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |
627 | struct drm_device *dev = crtc->dev; | 634 | struct drm_device *dev = crtc->dev; |
628 | 635 | ||
629 | WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); | ||
630 | |||
631 | if (tilcdc_crtc->event) { | 636 | if (tilcdc_crtc->event) { |
632 | dev_err(dev->dev, "already pending page flip!\n"); | 637 | dev_err(dev->dev, "already pending page flip!\n"); |
633 | return -EBUSY; | 638 | return -EBUSY; |
634 | } | 639 | } |
635 | 640 | ||
636 | drm_framebuffer_reference(fb); | 641 | drm_framebuffer_get(fb); |
637 | 642 | ||
638 | crtc->primary->fb = fb; | 643 | crtc->primary->fb = fb; |
639 | tilcdc_crtc->event = event; | 644 | tilcdc_crtc->event = event; |
@@ -648,7 +653,7 @@ int tilcdc_crtc_update_fb(struct drm_crtc *crtc, | |||
648 | spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags); | 653 | spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags); |
649 | 654 | ||
650 | next_vblank = ktime_add_us(tilcdc_crtc->last_vblank, | 655 | next_vblank = ktime_add_us(tilcdc_crtc->last_vblank, |
651 | 1000000 / crtc->hwmode.vrefresh); | 656 | tilcdc_crtc->hvtotal_us); |
652 | tdiff = ktime_to_us(ktime_sub(next_vblank, ktime_get())); | 657 | tdiff = ktime_to_us(ktime_sub(next_vblank, ktime_get())); |
653 | 658 | ||
654 | if (tdiff < TILCDC_VBLANK_SAFETY_THRESHOLD_US) | 659 | if (tdiff < TILCDC_VBLANK_SAFETY_THRESHOLD_US) |
@@ -728,11 +733,39 @@ static void tilcdc_crtc_disable_vblank(struct drm_crtc *crtc) | |||
728 | { | 733 | { |
729 | } | 734 | } |
730 | 735 | ||
736 | static void tilcdc_crtc_reset(struct drm_crtc *crtc) | ||
737 | { | ||
738 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | ||
739 | struct drm_device *dev = crtc->dev; | ||
740 | int ret; | ||
741 | |||
742 | drm_atomic_helper_crtc_reset(crtc); | ||
743 | |||
744 | /* Turn the raster off if it for some reason is on. */ | ||
745 | pm_runtime_get_sync(dev->dev); | ||
746 | if (tilcdc_read(dev, LCDC_RASTER_CTRL_REG) & LCDC_RASTER_ENABLE) { | ||
747 | /* Enable DMA Frame Done Interrupt */ | ||
748 | tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG, LCDC_FRAME_DONE); | ||
749 | tilcdc_clear_irqstatus(dev, 0xffffffff); | ||
750 | |||
751 | tilcdc_crtc->frame_done = false; | ||
752 | tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); | ||
753 | |||
754 | ret = wait_event_timeout(tilcdc_crtc->frame_done_wq, | ||
755 | tilcdc_crtc->frame_done, | ||
756 | msecs_to_jiffies(500)); | ||
757 | if (ret == 0) | ||
758 | dev_err(dev->dev, "%s: timeout waiting for framedone\n", | ||
759 | __func__); | ||
760 | } | ||
761 | pm_runtime_put_sync(dev->dev); | ||
762 | } | ||
763 | |||
731 | static const struct drm_crtc_funcs tilcdc_crtc_funcs = { | 764 | static const struct drm_crtc_funcs tilcdc_crtc_funcs = { |
732 | .destroy = tilcdc_crtc_destroy, | 765 | .destroy = tilcdc_crtc_destroy, |
733 | .set_config = drm_atomic_helper_set_config, | 766 | .set_config = drm_atomic_helper_set_config, |
734 | .page_flip = drm_atomic_helper_page_flip, | 767 | .page_flip = drm_atomic_helper_page_flip, |
735 | .reset = drm_atomic_helper_crtc_reset, | 768 | .reset = tilcdc_crtc_reset, |
736 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | 769 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, |
737 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | 770 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, |
738 | .enable_vblank = tilcdc_crtc_enable_vblank, | 771 | .enable_vblank = tilcdc_crtc_enable_vblank, |