aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorAndrzej Hajda <a.hajda@samsung.com>2016-09-23 04:15:23 -0400
committerInki Dae <daeinki@gmail.com>2016-09-30 11:39:35 -0400
commit8574e927b4818320257d8b965fb7e0b832532aff (patch)
tree00eeee96c1b2055ddf56accaa4ca737e71c32daf /drivers/gpu
parent61865b5d4db1f3814385ead23f04dc2b014ba6ff (diff)
drm/exynos/vidi: use timer for vblanks instead of sleeping worker
VIDI driver uses fake vblank handler to generate vblank events. It was implemented using worker which slept for vblank time, additionally it did not work if there were no page flips. The patch replaces it with timer, uses drm_crtc_vblank_(on|off) helpers to manage it and fixes behavior for non-page-flip cases. This change allows further improvements of vblank in exynos-drm framework. Signed-off-by: Andrzej Hajda <a.hajda@samsung.com> Reviewed-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk> Signed-off-by: Inki Dae <inki.dae@samsung.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c66
1 files changed, 20 insertions, 46 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index e8f6c92b2a36..a91dad65e908 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -15,6 +15,7 @@
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#include <linux/platform_device.h> 16#include <linux/platform_device.h>
17#include <linux/component.h> 17#include <linux/component.h>
18#include <linux/timer.h>
18 19
19#include <drm/exynos_drm.h> 20#include <drm/exynos_drm.h>
20 21
@@ -28,6 +29,9 @@
28#include "exynos_drm_plane.h" 29#include "exynos_drm_plane.h"
29#include "exynos_drm_vidi.h" 30#include "exynos_drm_vidi.h"
30 31
32/* VIDI uses fixed refresh rate of 50Hz */
33#define VIDI_REFRESH_TIME (1000 / 50)
34
31/* vidi has totally three virtual windows. */ 35/* vidi has totally three virtual windows. */
32#define WINDOWS_NR 3 36#define WINDOWS_NR 3
33 37
@@ -43,12 +47,9 @@ struct vidi_context {
43 struct exynos_drm_plane planes[WINDOWS_NR]; 47 struct exynos_drm_plane planes[WINDOWS_NR];
44 struct edid *raw_edid; 48 struct edid *raw_edid;
45 unsigned int clkdiv; 49 unsigned int clkdiv;
46 unsigned long irq_flags;
47 unsigned int connected; 50 unsigned int connected;
48 bool vblank_on;
49 bool suspended; 51 bool suspended;
50 bool direct_vblank; 52 struct timer_list timer;
51 struct work_struct work;
52 struct mutex lock; 53 struct mutex lock;
53 int pipe; 54 int pipe;
54}; 55};
@@ -102,30 +103,14 @@ static int vidi_enable_vblank(struct exynos_drm_crtc *crtc)
102 if (ctx->suspended) 103 if (ctx->suspended)
103 return -EPERM; 104 return -EPERM;
104 105
105 if (!test_and_set_bit(0, &ctx->irq_flags)) 106 mod_timer(&ctx->timer,
106 ctx->vblank_on = true; 107 jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1);
107
108 ctx->direct_vblank = true;
109
110 /*
111 * in case of page flip request, vidi_finish_pageflip function
112 * will not be called because direct_vblank is true and then
113 * that function will be called by crtc_ops->update_plane callback
114 */
115 schedule_work(&ctx->work);
116 108
117 return 0; 109 return 0;
118} 110}
119 111
120static void vidi_disable_vblank(struct exynos_drm_crtc *crtc) 112static void vidi_disable_vblank(struct exynos_drm_crtc *crtc)
121{ 113{
122 struct vidi_context *ctx = crtc->ctx;
123
124 if (ctx->suspended)
125 return;
126
127 if (test_and_clear_bit(0, &ctx->irq_flags))
128 ctx->vblank_on = false;
129} 114}
130 115
131static void vidi_update_plane(struct exynos_drm_crtc *crtc, 116static void vidi_update_plane(struct exynos_drm_crtc *crtc,
@@ -140,9 +125,6 @@ static void vidi_update_plane(struct exynos_drm_crtc *crtc,
140 125
141 addr = exynos_drm_fb_dma_addr(state->fb, 0); 126 addr = exynos_drm_fb_dma_addr(state->fb, 0);
142 DRM_DEBUG_KMS("dma_addr = %pad\n", &addr); 127 DRM_DEBUG_KMS("dma_addr = %pad\n", &addr);
143
144 if (ctx->vblank_on)
145 schedule_work(&ctx->work);
146} 128}
147 129
148static void vidi_enable(struct exynos_drm_crtc *crtc) 130static void vidi_enable(struct exynos_drm_crtc *crtc)
@@ -153,17 +135,17 @@ static void vidi_enable(struct exynos_drm_crtc *crtc)
153 135
154 ctx->suspended = false; 136 ctx->suspended = false;
155 137
156 /* if vblank was enabled status, enable it again. */
157 if (test_and_clear_bit(0, &ctx->irq_flags))
158 vidi_enable_vblank(ctx->crtc);
159
160 mutex_unlock(&ctx->lock); 138 mutex_unlock(&ctx->lock);
139
140 drm_crtc_vblank_on(&crtc->base);
161} 141}
162 142
163static void vidi_disable(struct exynos_drm_crtc *crtc) 143static void vidi_disable(struct exynos_drm_crtc *crtc)
164{ 144{
165 struct vidi_context *ctx = crtc->ctx; 145 struct vidi_context *ctx = crtc->ctx;
166 146
147 drm_crtc_vblank_off(&crtc->base);
148
167 mutex_lock(&ctx->lock); 149 mutex_lock(&ctx->lock);
168 150
169 ctx->suspended = true; 151 ctx->suspended = true;
@@ -190,28 +172,17 @@ static const struct exynos_drm_crtc_ops vidi_crtc_ops = {
190 .update_plane = vidi_update_plane, 172 .update_plane = vidi_update_plane,
191}; 173};
192 174
193static void vidi_fake_vblank_handler(struct work_struct *work) 175static void vidi_fake_vblank_timer(unsigned long arg)
194{ 176{
195 struct vidi_context *ctx = container_of(work, struct vidi_context, 177 struct vidi_context *ctx = (void *)arg;
196 work);
197 int win; 178 int win;
198 179
199 if (ctx->pipe < 0) 180 if (ctx->pipe < 0)
200 return; 181 return;
201 182
202 /* refresh rate is about 50Hz. */ 183 if (drm_crtc_handle_vblank(&ctx->crtc->base))
203 usleep_range(16000, 20000); 184 mod_timer(&ctx->timer,
204 185 jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1);
205 mutex_lock(&ctx->lock);
206
207 if (ctx->direct_vblank) {
208 drm_crtc_handle_vblank(&ctx->crtc->base);
209 ctx->direct_vblank = false;
210 mutex_unlock(&ctx->lock);
211 return;
212 }
213
214 mutex_unlock(&ctx->lock);
215 186
216 for (win = 0 ; win < WINDOWS_NR ; win++) { 187 for (win = 0 ; win < WINDOWS_NR ; win++) {
217 struct exynos_drm_plane *plane = &ctx->planes[win]; 188 struct exynos_drm_plane *plane = &ctx->planes[win];
@@ -489,6 +460,9 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
489 460
490static void vidi_unbind(struct device *dev, struct device *master, void *data) 461static void vidi_unbind(struct device *dev, struct device *master, void *data)
491{ 462{
463 struct vidi_context *ctx = dev_get_drvdata(dev);
464
465 del_timer_sync(&ctx->timer);
492} 466}
493 467
494static const struct component_ops vidi_component_ops = { 468static const struct component_ops vidi_component_ops = {
@@ -507,7 +481,7 @@ static int vidi_probe(struct platform_device *pdev)
507 481
508 ctx->pdev = pdev; 482 ctx->pdev = pdev;
509 483
510 INIT_WORK(&ctx->work, vidi_fake_vblank_handler); 484 setup_timer(&ctx->timer, vidi_fake_vblank_timer, (unsigned long)ctx);
511 485
512 mutex_init(&ctx->lock); 486 mutex_init(&ctx->lock);
513 487