Commit 4b5dda82 authored by Russell King's avatar Russell King

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: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 5740d27f
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "armada_hw.h" #include "armada_hw.h"
struct armada_frame_work { struct armada_frame_work {
struct armada_plane_work work;
struct drm_pending_vblank_event *event; struct drm_pending_vblank_event *event;
struct armada_regs regs[4]; struct armada_regs regs[4];
struct drm_framebuffer *old_fb; struct drm_framebuffer *old_fb;
...@@ -190,6 +191,41 @@ static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb, ...@@ -190,6 +191,41 @@ static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb,
return i; return i;
} }
static void armada_drm_plane_work_run(struct armada_crtc *dcrtc,
struct armada_plane *plane)
{
struct armada_plane_work *work = xchg(&plane->work, NULL);
/* Handle any pending frame work. */
if (work) {
work->fn(dcrtc, plane, work);
drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);
}
}
int armada_drm_plane_work_queue(struct armada_crtc *dcrtc,
struct armada_plane *plane, struct armada_plane_work *work)
{
int ret;
ret = drm_vblank_get(dcrtc->crtc.dev, dcrtc->num);
if (ret) {
DRM_ERROR("failed to acquire vblank counter\n");
return ret;
}
ret = cmpxchg(&plane->work, NULL, work) ? -EBUSY : 0;
if (ret)
drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);
return ret;
}
int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout)
{
return wait_event_timeout(plane->frame_wait, !plane->work, timeout);
}
void armada_drm_vbl_event_add(struct armada_crtc *dcrtc, void armada_drm_vbl_event_add(struct armada_crtc *dcrtc,
struct armada_vbl_event *evt) struct armada_vbl_event *evt)
{ {
...@@ -233,44 +269,31 @@ static void armada_drm_vbl_event_run(struct armada_crtc *dcrtc) ...@@ -233,44 +269,31 @@ static void armada_drm_vbl_event_run(struct armada_crtc *dcrtc)
static int armada_drm_crtc_queue_frame_work(struct armada_crtc *dcrtc, static int armada_drm_crtc_queue_frame_work(struct armada_crtc *dcrtc,
struct armada_frame_work *work) struct armada_frame_work *work)
{ {
struct drm_device *dev = dcrtc->crtc.dev; struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary);
int ret;
ret = drm_vblank_get(dev, dcrtc->num); return armada_drm_plane_work_queue(dcrtc, plane, &work->work);
if (ret) {
DRM_ERROR("failed to acquire vblank counter\n");
return ret;
}
if (cmpxchg(&dcrtc->frame_work, NULL, work)) {
drm_vblank_put(dev, dcrtc->num);
ret = -EBUSY;
}
return ret;
} }
static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc, static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc,
struct armada_frame_work *work) struct armada_plane *plane, struct armada_plane_work *work)
{ {
struct armada_frame_work *fwork = container_of(work, struct armada_frame_work, work);
struct drm_device *dev = dcrtc->crtc.dev; struct drm_device *dev = dcrtc->crtc.dev;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&dcrtc->irq_lock, flags); spin_lock_irqsave(&dcrtc->irq_lock, flags);
armada_drm_crtc_update_regs(dcrtc, work->regs); armada_drm_crtc_update_regs(dcrtc, fwork->regs);
spin_unlock_irqrestore(&dcrtc->irq_lock, flags); spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
if (work->event) { if (fwork->event) {
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
drm_send_vblank_event(dev, dcrtc->num, work->event); drm_send_vblank_event(dev, dcrtc->num, fwork->event);
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
} }
drm_vblank_put(dev, dcrtc->num);
/* Finally, queue the process-half of the cleanup. */ /* Finally, queue the process-half of the cleanup. */
__armada_drm_queue_unref_work(dcrtc->crtc.dev, work->old_fb); __armada_drm_queue_unref_work(dcrtc->crtc.dev, fwork->old_fb);
kfree(work); kfree(fwork);
} }
static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc, 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,6 +313,7 @@ static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc,
work = kmalloc(sizeof(*work), GFP_KERNEL); work = kmalloc(sizeof(*work), GFP_KERNEL);
if (work) { if (work) {
int i = 0; int i = 0;
work->work.fn = armada_drm_crtc_complete_frame_work;
work->event = NULL; work->event = NULL;
work->old_fb = fb; work->old_fb = fb;
armada_reg_queue_end(work->regs, i); armada_reg_queue_end(work->regs, i);
...@@ -310,18 +334,14 @@ static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc, ...@@ -310,18 +334,14 @@ static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc,
static void armada_drm_vblank_off(struct armada_crtc *dcrtc) static void armada_drm_vblank_off(struct armada_crtc *dcrtc)
{ {
struct armada_frame_work *work; struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary);
/* /*
* Tell the DRM core that vblank IRQs aren't going to happen for * Tell the DRM core that vblank IRQs aren't going to happen for
* a while. This cleans up any pending vblank events for us. * a while. This cleans up any pending vblank events for us.
*/ */
drm_crtc_vblank_off(&dcrtc->crtc); drm_crtc_vblank_off(&dcrtc->crtc);
armada_drm_plane_work_run(dcrtc, plane);
/* Handle any pending flip event. */
work = xchg(&dcrtc->frame_work, NULL);
if (work)
armada_drm_crtc_complete_frame_work(dcrtc, work);
} }
void armada_drm_crtc_gamma_set(struct drm_crtc *crtc, u16 r, u16 g, u16 b, 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,12 +470,9 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
spin_unlock(&dcrtc->irq_lock); spin_unlock(&dcrtc->irq_lock);
if (stat & GRA_FRAME_IRQ) { if (stat & GRA_FRAME_IRQ) {
struct armada_frame_work *work = xchg(&dcrtc->frame_work, NULL); struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary);
armada_drm_plane_work_run(dcrtc, plane);
if (work) wake_up(&plane->frame_wait);
armada_drm_crtc_complete_frame_work(dcrtc, work);
wake_up(&drm_to_armada_plane(dcrtc->crtc.primary)->frame_wait);
} }
} }
...@@ -571,8 +588,8 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, ...@@ -571,8 +588,8 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
adj->crtc_vtotal, tm, bm); adj->crtc_vtotal, tm, bm);
/* Wait for pending flips to complete */ /* Wait for pending flips to complete */
wait_event(drm_to_armada_plane(dcrtc->crtc.primary)->frame_wait, armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary),
!dcrtc->frame_work); MAX_SCHEDULE_TIMEOUT);
drm_crtc_vblank_off(crtc); drm_crtc_vblank_off(crtc);
...@@ -689,8 +706,8 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, ...@@ -689,8 +706,8 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
armada_reg_queue_end(regs, i); armada_reg_queue_end(regs, i);
/* Wait for pending flips to complete */ /* Wait for pending flips to complete */
wait_event(drm_to_armada_plane(dcrtc->crtc.primary)->frame_wait, armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary),
!dcrtc->frame_work); MAX_SCHEDULE_TIMEOUT);
/* Take a reference to the new fb as we're using it */ /* Take a reference to the new fb as we're using it */
drm_framebuffer_reference(crtc->primary->fb); drm_framebuffer_reference(crtc->primary->fb);
...@@ -1013,6 +1030,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, ...@@ -1013,6 +1030,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
if (!work) if (!work)
return -ENOMEM; return -ENOMEM;
work->work.fn = armada_drm_crtc_complete_frame_work;
work->event = event; work->event = event;
work->old_fb = dcrtc->crtc.primary->fb; work->old_fb = dcrtc->crtc.primary->fb;
...@@ -1046,12 +1064,8 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, ...@@ -1046,12 +1064,8 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
* Finally, if the display is blanked, we won't receive an * Finally, if the display is blanked, we won't receive an
* interrupt, so complete it now. * interrupt, so complete it now.
*/ */
if (dpms_blanked(dcrtc->dpms)) { if (dpms_blanked(dcrtc->dpms))
struct armada_frame_work *work = xchg(&dcrtc->frame_work, NULL); armada_drm_plane_work_run(dcrtc, drm_to_armada_plane(dcrtc->crtc.primary));
if (work)
armada_drm_crtc_complete_frame_work(dcrtc, work);
}
return 0; return 0;
} }
......
...@@ -31,16 +31,27 @@ struct armada_regs { ...@@ -31,16 +31,27 @@ struct armada_regs {
#define armada_reg_queue_end(_r, _i) \ #define armada_reg_queue_end(_r, _i) \
armada_reg_queue_mod(_r, _i, 0, 0, ~0) armada_reg_queue_mod(_r, _i, 0, 0, ~0)
struct armada_frame_work; struct armada_crtc;
struct armada_plane;
struct armada_variant; struct armada_variant;
struct armada_plane_work {
void (*fn)(struct armada_crtc *,
struct armada_plane *,
struct armada_plane_work *);
};
struct armada_plane { struct armada_plane {
struct drm_plane base; struct drm_plane base;
wait_queue_head_t frame_wait; wait_queue_head_t frame_wait;
struct armada_plane_work *work;
}; };
#define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) #define drm_to_armada_plane(p) container_of(p, struct armada_plane, base)
int armada_drm_plane_init(struct armada_plane *plane); int armada_drm_plane_init(struct armada_plane *plane);
int armada_drm_plane_work_queue(struct armada_crtc *dcrtc,
struct armada_plane *plane, struct armada_plane_work *work);
int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout);
struct armada_crtc { struct armada_crtc {
struct drm_crtc crtc; struct drm_crtc crtc;
...@@ -74,8 +85,6 @@ struct armada_crtc { ...@@ -74,8 +85,6 @@ struct armada_crtc {
uint32_t dumb_ctrl; uint32_t dumb_ctrl;
uint32_t spu_iopad_ctrl; uint32_t spu_iopad_ctrl;
struct armada_frame_work *frame_work;
spinlock_t irq_lock; spinlock_t irq_lock;
uint32_t irq_ena; uint32_t irq_ena;
struct list_head vbl_list; struct list_head vbl_list;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment