aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2015-08-06 11:37:18 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2015-10-01 09:33:28 -0400
commit4b5dda82c20c2eee500520010c0558789592d62f (patch)
tree6c7c804a0816d5b67bd2e0fb431de3953b6fc7bb
parent5740d27fa5594344ed4d2c18d7ae7bea69002004 (diff)
drm/armada: move CRTC flip work to primary plane work
Add a plane work implementation, and move the CRTC framebuffer flip work to it for the primary plane. The idea is to have a common plane work implementation for both the primary and overlay planes. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c102
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.h15
2 files changed, 70 insertions, 47 deletions
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 46d932bc7678..0c1a1524f5d5 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -20,6 +20,7 @@
20#include "armada_hw.h" 20#include "armada_hw.h"
21 21
22struct armada_frame_work { 22struct armada_frame_work {
23 struct armada_plane_work work;
23 struct drm_pending_vblank_event *event; 24 struct drm_pending_vblank_event *event;
24 struct armada_regs regs[4]; 25 struct armada_regs regs[4];
25 struct drm_framebuffer *old_fb; 26 struct drm_framebuffer *old_fb;
@@ -190,6 +191,41 @@ static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb,
190 return i; 191 return i;
191} 192}
192 193
194static void armada_drm_plane_work_run(struct armada_crtc *dcrtc,
195 struct armada_plane *plane)
196{
197 struct armada_plane_work *work = xchg(&plane->work, NULL);
198
199 /* Handle any pending frame work. */
200 if (work) {
201 work->fn(dcrtc, plane, work);
202 drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);
203 }
204}
205
206int armada_drm_plane_work_queue(struct armada_crtc *dcrtc,
207 struct armada_plane *plane, struct armada_plane_work *work)
208{
209 int ret;
210
211 ret = drm_vblank_get(dcrtc->crtc.dev, dcrtc->num);
212 if (ret) {
213 DRM_ERROR("failed to acquire vblank counter\n");
214 return ret;
215 }
216
217 ret = cmpxchg(&plane->work, NULL, work) ? -EBUSY : 0;
218 if (ret)
219 drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);
220
221 return ret;
222}
223
224int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout)
225{
226 return wait_event_timeout(plane->frame_wait, !plane->work, timeout);
227}
228
193void armada_drm_vbl_event_add(struct armada_crtc *dcrtc, 229void armada_drm_vbl_event_add(struct armada_crtc *dcrtc,
194 struct armada_vbl_event *evt) 230 struct armada_vbl_event *evt)
195{ 231{
@@ -233,44 +269,31 @@ static void armada_drm_vbl_event_run(struct armada_crtc *dcrtc)
233static int armada_drm_crtc_queue_frame_work(struct armada_crtc *dcrtc, 269static int armada_drm_crtc_queue_frame_work(struct armada_crtc *dcrtc,
234 struct armada_frame_work *work) 270 struct armada_frame_work *work)
235{ 271{
236 struct drm_device *dev = dcrtc->crtc.dev; 272 struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary);
237 int ret;
238 273
239 ret = drm_vblank_get(dev, dcrtc->num); 274 return armada_drm_plane_work_queue(dcrtc, plane, &work->work);
240 if (ret) {
241 DRM_ERROR("failed to acquire vblank counter\n");
242 return ret;
243 }
244
245 if (cmpxchg(&dcrtc->frame_work, NULL, work)) {
246 drm_vblank_put(dev, dcrtc->num);
247 ret = -EBUSY;
248 }
249
250 return ret;
251} 275}
252 276
253static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc, 277static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc,
254 struct armada_frame_work *work) 278 struct armada_plane *plane, struct armada_plane_work *work)
255{ 279{
280 struct armada_frame_work *fwork = container_of(work, struct armada_frame_work, work);
256 struct drm_device *dev = dcrtc->crtc.dev; 281 struct drm_device *dev = dcrtc->crtc.dev;
257 unsigned long flags; 282 unsigned long flags;
258 283
259 spin_lock_irqsave(&dcrtc->irq_lock, flags); 284 spin_lock_irqsave(&dcrtc->irq_lock, flags);
260 armada_drm_crtc_update_regs(dcrtc, work->regs); 285 armada_drm_crtc_update_regs(dcrtc, fwork->regs);
261 spin_unlock_irqrestore(&dcrtc->irq_lock, flags); 286 spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
262 287
263 if (work->event) { 288 if (fwork->event) {
264 spin_lock_irqsave(&dev->event_lock, flags); 289 spin_lock_irqsave(&dev->event_lock, flags);
265 drm_send_vblank_event(dev, dcrtc->num, work->event); 290 drm_send_vblank_event(dev, dcrtc->num, fwork->event);
266 spin_unlock_irqrestore(&dev->event_lock, flags); 291 spin_unlock_irqrestore(&dev->event_lock, flags);
267 } 292 }
268 293
269 drm_vblank_put(dev, dcrtc->num);
270
271 /* Finally, queue the process-half of the cleanup. */ 294 /* Finally, queue the process-half of the cleanup. */
272 __armada_drm_queue_unref_work(dcrtc->crtc.dev, work->old_fb); 295 __armada_drm_queue_unref_work(dcrtc->crtc.dev, fwork->old_fb);
273 kfree(work); 296 kfree(fwork);
274} 297}
275 298
276static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc, 299static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc,
@@ -290,6 +313,7 @@ static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc,
290 work = kmalloc(sizeof(*work), GFP_KERNEL); 313 work = kmalloc(sizeof(*work), GFP_KERNEL);
291 if (work) { 314 if (work) {
292 int i = 0; 315 int i = 0;
316 work->work.fn = armada_drm_crtc_complete_frame_work;
293 work->event = NULL; 317 work->event = NULL;
294 work->old_fb = fb; 318 work->old_fb = fb;
295 armada_reg_queue_end(work->regs, i); 319 armada_reg_queue_end(work->regs, i);
@@ -310,18 +334,14 @@ static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc,
310 334
311static void armada_drm_vblank_off(struct armada_crtc *dcrtc) 335static void armada_drm_vblank_off(struct armada_crtc *dcrtc)
312{ 336{
313 struct armada_frame_work *work; 337 struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary);
314 338
315 /* 339 /*
316 * Tell the DRM core that vblank IRQs aren't going to happen for 340 * Tell the DRM core that vblank IRQs aren't going to happen for
317 * a while. This cleans up any pending vblank events for us. 341 * a while. This cleans up any pending vblank events for us.
318 */ 342 */
319 drm_crtc_vblank_off(&dcrtc->crtc); 343 drm_crtc_vblank_off(&dcrtc->crtc);
320 344 armada_drm_plane_work_run(dcrtc, plane);
321 /* Handle any pending flip event. */
322 work = xchg(&dcrtc->frame_work, NULL);
323 if (work)
324 armada_drm_crtc_complete_frame_work(dcrtc, work);
325} 345}
326 346
327void armada_drm_crtc_gamma_set(struct drm_crtc *crtc, u16 r, u16 g, u16 b, 347void armada_drm_crtc_gamma_set(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
@@ -450,12 +470,9 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
450 spin_unlock(&dcrtc->irq_lock); 470 spin_unlock(&dcrtc->irq_lock);
451 471
452 if (stat & GRA_FRAME_IRQ) { 472 if (stat & GRA_FRAME_IRQ) {
453 struct armada_frame_work *work = xchg(&dcrtc->frame_work, NULL); 473 struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary);
454 474 armada_drm_plane_work_run(dcrtc, plane);
455 if (work) 475 wake_up(&plane->frame_wait);
456 armada_drm_crtc_complete_frame_work(dcrtc, work);
457
458 wake_up(&drm_to_armada_plane(dcrtc->crtc.primary)->frame_wait);
459 } 476 }
460} 477}
461 478
@@ -571,8 +588,8 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
571 adj->crtc_vtotal, tm, bm); 588 adj->crtc_vtotal, tm, bm);
572 589
573 /* Wait for pending flips to complete */ 590 /* Wait for pending flips to complete */
574 wait_event(drm_to_armada_plane(dcrtc->crtc.primary)->frame_wait, 591 armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary),
575 !dcrtc->frame_work); 592 MAX_SCHEDULE_TIMEOUT);
576 593
577 drm_crtc_vblank_off(crtc); 594 drm_crtc_vblank_off(crtc);
578 595
@@ -689,8 +706,8 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
689 armada_reg_queue_end(regs, i); 706 armada_reg_queue_end(regs, i);
690 707
691 /* Wait for pending flips to complete */ 708 /* Wait for pending flips to complete */
692 wait_event(drm_to_armada_plane(dcrtc->crtc.primary)->frame_wait, 709 armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary),
693 !dcrtc->frame_work); 710 MAX_SCHEDULE_TIMEOUT);
694 711
695 /* Take a reference to the new fb as we're using it */ 712 /* Take a reference to the new fb as we're using it */
696 drm_framebuffer_reference(crtc->primary->fb); 713 drm_framebuffer_reference(crtc->primary->fb);
@@ -1013,6 +1030,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
1013 if (!work) 1030 if (!work)
1014 return -ENOMEM; 1031 return -ENOMEM;
1015 1032
1033 work->work.fn = armada_drm_crtc_complete_frame_work;
1016 work->event = event; 1034 work->event = event;
1017 work->old_fb = dcrtc->crtc.primary->fb; 1035 work->old_fb = dcrtc->crtc.primary->fb;
1018 1036
@@ -1046,12 +1064,8 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
1046 * Finally, if the display is blanked, we won't receive an 1064 * Finally, if the display is blanked, we won't receive an
1047 * interrupt, so complete it now. 1065 * interrupt, so complete it now.
1048 */ 1066 */
1049 if (dpms_blanked(dcrtc->dpms)) { 1067 if (dpms_blanked(dcrtc->dpms))
1050 struct armada_frame_work *work = xchg(&dcrtc->frame_work, NULL); 1068 armada_drm_plane_work_run(dcrtc, drm_to_armada_plane(dcrtc->crtc.primary));
1051
1052 if (work)
1053 armada_drm_crtc_complete_frame_work(dcrtc, work);
1054 }
1055 1069
1056 return 0; 1070 return 0;
1057} 1071}
diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h
index 3ec5101e13f7..aaad5ab78673 100644
--- a/drivers/gpu/drm/armada/armada_crtc.h
+++ b/drivers/gpu/drm/armada/armada_crtc.h
@@ -31,16 +31,27 @@ struct armada_regs {
31#define armada_reg_queue_end(_r, _i) \ 31#define armada_reg_queue_end(_r, _i) \
32 armada_reg_queue_mod(_r, _i, 0, 0, ~0) 32 armada_reg_queue_mod(_r, _i, 0, 0, ~0)
33 33
34struct armada_frame_work; 34struct armada_crtc;
35struct armada_plane;
35struct armada_variant; 36struct armada_variant;
36 37
38struct armada_plane_work {
39 void (*fn)(struct armada_crtc *,
40 struct armada_plane *,
41 struct armada_plane_work *);
42};
43
37struct armada_plane { 44struct armada_plane {
38 struct drm_plane base; 45 struct drm_plane base;
39 wait_queue_head_t frame_wait; 46 wait_queue_head_t frame_wait;
47 struct armada_plane_work *work;
40}; 48};
41#define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) 49#define drm_to_armada_plane(p) container_of(p, struct armada_plane, base)
42 50
43int armada_drm_plane_init(struct armada_plane *plane); 51int armada_drm_plane_init(struct armada_plane *plane);
52int armada_drm_plane_work_queue(struct armada_crtc *dcrtc,
53 struct armada_plane *plane, struct armada_plane_work *work);
54int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout);
44 55
45struct armada_crtc { 56struct armada_crtc {
46 struct drm_crtc crtc; 57 struct drm_crtc crtc;
@@ -74,8 +85,6 @@ struct armada_crtc {
74 uint32_t dumb_ctrl; 85 uint32_t dumb_ctrl;
75 uint32_t spu_iopad_ctrl; 86 uint32_t spu_iopad_ctrl;
76 87
77 struct armada_frame_work *frame_work;
78
79 spinlock_t irq_lock; 88 spinlock_t irq_lock;
80 uint32_t irq_ena; 89 uint32_t irq_ena;
81 struct list_head vbl_list; 90 struct list_head vbl_list;