diff options
Diffstat (limited to 'drivers/gpu/drm/tilcdc/tilcdc_crtc.c')
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 43 |
1 files changed, 20 insertions, 23 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 7418dcd986d3..d36efc13b16f 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c | |||
@@ -15,7 +15,7 @@ | |||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | 15 | * this program. If not, see <http://www.gnu.org/licenses/>. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/kfifo.h> | 18 | #include "drm_flip_work.h" |
19 | 19 | ||
20 | #include "tilcdc_drv.h" | 20 | #include "tilcdc_drv.h" |
21 | #include "tilcdc_regs.h" | 21 | #include "tilcdc_regs.h" |
@@ -35,21 +35,18 @@ struct tilcdc_crtc { | |||
35 | struct drm_framebuffer *scanout[2]; | 35 | struct drm_framebuffer *scanout[2]; |
36 | 36 | ||
37 | /* for deferred fb unref's: */ | 37 | /* for deferred fb unref's: */ |
38 | DECLARE_KFIFO_PTR(unref_fifo, struct drm_framebuffer *); | 38 | struct drm_flip_work unref_work; |
39 | struct work_struct work; | ||
40 | }; | 39 | }; |
41 | #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base) | 40 | #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base) |
42 | 41 | ||
43 | static void unref_worker(struct work_struct *work) | 42 | static void unref_worker(struct drm_flip_work *work, void *val) |
44 | { | 43 | { |
45 | struct tilcdc_crtc *tilcdc_crtc = | 44 | struct tilcdc_crtc *tilcdc_crtc = |
46 | container_of(work, struct tilcdc_crtc, work); | 45 | container_of(work, struct tilcdc_crtc, unref_work); |
47 | struct drm_device *dev = tilcdc_crtc->base.dev; | 46 | struct drm_device *dev = tilcdc_crtc->base.dev; |
48 | struct drm_framebuffer *fb; | ||
49 | 47 | ||
50 | mutex_lock(&dev->mode_config.mutex); | 48 | mutex_lock(&dev->mode_config.mutex); |
51 | while (kfifo_get(&tilcdc_crtc->unref_fifo, &fb)) | 49 | drm_framebuffer_unreference(val); |
52 | drm_framebuffer_unreference(fb); | ||
53 | mutex_unlock(&dev->mode_config.mutex); | 50 | mutex_unlock(&dev->mode_config.mutex); |
54 | } | 51 | } |
55 | 52 | ||
@@ -68,19 +65,14 @@ static void set_scanout(struct drm_crtc *crtc, int n) | |||
68 | }; | 65 | }; |
69 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 66 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |
70 | struct drm_device *dev = crtc->dev; | 67 | struct drm_device *dev = crtc->dev; |
68 | struct tilcdc_drm_private *priv = dev->dev_private; | ||
71 | 69 | ||
72 | pm_runtime_get_sync(dev->dev); | 70 | pm_runtime_get_sync(dev->dev); |
73 | tilcdc_write(dev, base_reg[n], tilcdc_crtc->start); | 71 | tilcdc_write(dev, base_reg[n], tilcdc_crtc->start); |
74 | tilcdc_write(dev, ceil_reg[n], tilcdc_crtc->end); | 72 | tilcdc_write(dev, ceil_reg[n], tilcdc_crtc->end); |
75 | if (tilcdc_crtc->scanout[n]) { | 73 | if (tilcdc_crtc->scanout[n]) { |
76 | if (kfifo_put(&tilcdc_crtc->unref_fifo, | 74 | drm_flip_work_queue(&tilcdc_crtc->unref_work, tilcdc_crtc->scanout[n]); |
77 | (const struct drm_framebuffer **)&tilcdc_crtc->scanout[n])) { | 75 | drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq); |
78 | struct tilcdc_drm_private *priv = dev->dev_private; | ||
79 | queue_work(priv->wq, &tilcdc_crtc->work); | ||
80 | } else { | ||
81 | dev_err(dev->dev, "unref fifo full!\n"); | ||
82 | drm_framebuffer_unreference(tilcdc_crtc->scanout[n]); | ||
83 | } | ||
84 | } | 76 | } |
85 | tilcdc_crtc->scanout[n] = crtc->fb; | 77 | tilcdc_crtc->scanout[n] = crtc->fb; |
86 | drm_framebuffer_reference(tilcdc_crtc->scanout[n]); | 78 | drm_framebuffer_reference(tilcdc_crtc->scanout[n]); |
@@ -149,14 +141,15 @@ static void tilcdc_crtc_destroy(struct drm_crtc *crtc) | |||
149 | WARN_ON(tilcdc_crtc->dpms == DRM_MODE_DPMS_ON); | 141 | WARN_ON(tilcdc_crtc->dpms == DRM_MODE_DPMS_ON); |
150 | 142 | ||
151 | drm_crtc_cleanup(crtc); | 143 | drm_crtc_cleanup(crtc); |
152 | WARN_ON(!kfifo_is_empty(&tilcdc_crtc->unref_fifo)); | 144 | drm_flip_work_cleanup(&tilcdc_crtc->unref_work); |
153 | kfifo_free(&tilcdc_crtc->unref_fifo); | 145 | |
154 | kfree(tilcdc_crtc); | 146 | kfree(tilcdc_crtc); |
155 | } | 147 | } |
156 | 148 | ||
157 | static int tilcdc_crtc_page_flip(struct drm_crtc *crtc, | 149 | static int tilcdc_crtc_page_flip(struct drm_crtc *crtc, |
158 | struct drm_framebuffer *fb, | 150 | struct drm_framebuffer *fb, |
159 | struct drm_pending_vblank_event *event) | 151 | struct drm_pending_vblank_event *event, |
152 | uint32_t page_flip_flags) | ||
160 | { | 153 | { |
161 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 154 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |
162 | struct drm_device *dev = crtc->dev; | 155 | struct drm_device *dev = crtc->dev; |
@@ -379,7 +372,12 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc, | |||
379 | else | 372 | else |
380 | tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_EDGE); | 373 | tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_EDGE); |
381 | 374 | ||
382 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | 375 | /* |
376 | * use value from adjusted_mode here as this might have been | ||
377 | * changed as part of the fixup for slave encoders to solve the | ||
378 | * issue where tilcdc timings are not VESA compliant | ||
379 | */ | ||
380 | if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
383 | tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_HSYNC); | 381 | tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_HSYNC); |
384 | else | 382 | else |
385 | tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_HSYNC); | 383 | tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_HSYNC); |
@@ -666,14 +664,13 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev) | |||
666 | tilcdc_crtc->dpms = DRM_MODE_DPMS_OFF; | 664 | tilcdc_crtc->dpms = DRM_MODE_DPMS_OFF; |
667 | init_waitqueue_head(&tilcdc_crtc->frame_done_wq); | 665 | init_waitqueue_head(&tilcdc_crtc->frame_done_wq); |
668 | 666 | ||
669 | ret = kfifo_alloc(&tilcdc_crtc->unref_fifo, 16, GFP_KERNEL); | 667 | ret = drm_flip_work_init(&tilcdc_crtc->unref_work, 16, |
668 | "unref", unref_worker); | ||
670 | if (ret) { | 669 | if (ret) { |
671 | dev_err(dev->dev, "could not allocate unref FIFO\n"); | 670 | dev_err(dev->dev, "could not allocate unref FIFO\n"); |
672 | goto fail; | 671 | goto fail; |
673 | } | 672 | } |
674 | 673 | ||
675 | INIT_WORK(&tilcdc_crtc->work, unref_worker); | ||
676 | |||
677 | ret = drm_crtc_init(dev, crtc, &tilcdc_crtc_funcs); | 674 | ret = drm_crtc_init(dev, crtc, &tilcdc_crtc_funcs); |
678 | if (ret < 0) | 675 | if (ret < 0) |
679 | goto fail; | 676 | goto fail; |