diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2015-08-06 11:37:18 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2015-10-01 09:33:28 -0400 |
commit | 4b5dda82c20c2eee500520010c0558789592d62f (patch) | |
tree | 6c7c804a0816d5b67bd2e0fb431de3953b6fc7bb | |
parent | 5740d27fa5594344ed4d2c18d7ae7bea69002004 (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.c | 102 | ||||
-rw-r--r-- | drivers/gpu/drm/armada/armada_crtc.h | 15 |
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 | ||
22 | struct armada_frame_work { | 22 | struct 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 | ||
194 | static 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 | |||
206 | int 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 | |||
224 | int 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 | |||
193 | void armada_drm_vbl_event_add(struct armada_crtc *dcrtc, | 229 | void 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) | |||
233 | static int armada_drm_crtc_queue_frame_work(struct armada_crtc *dcrtc, | 269 | static 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 | ||
253 | static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc, | 277 | static 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 | ||
276 | static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc, | 299 | static 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 | ||
311 | static void armada_drm_vblank_off(struct armada_crtc *dcrtc) | 335 | static 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 | ||
327 | void armada_drm_crtc_gamma_set(struct drm_crtc *crtc, u16 r, u16 g, u16 b, | 347 | void 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 | ||
34 | struct armada_frame_work; | 34 | struct armada_crtc; |
35 | struct armada_plane; | ||
35 | struct armada_variant; | 36 | struct armada_variant; |
36 | 37 | ||
38 | struct armada_plane_work { | ||
39 | void (*fn)(struct armada_crtc *, | ||
40 | struct armada_plane *, | ||
41 | struct armada_plane_work *); | ||
42 | }; | ||
43 | |||
37 | struct armada_plane { | 44 | struct 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 | ||
43 | int armada_drm_plane_init(struct armada_plane *plane); | 51 | int armada_drm_plane_init(struct armada_plane *plane); |
52 | int armada_drm_plane_work_queue(struct armada_crtc *dcrtc, | ||
53 | struct armada_plane *plane, struct armada_plane_work *work); | ||
54 | int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout); | ||
44 | 55 | ||
45 | struct armada_crtc { | 56 | struct 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; |