Skip to content

Commit

Permalink
drm/armada: disable planes at next blanking period
Browse files Browse the repository at this point in the history
Disable planes at the next blanking period rather than immediately.
In order to achieve this, we need to delay the clearing of dcrtc->plane
until after the next blanking period, so move that into a separate
work function.  To avoid races, we also need to move its assignment in
the overlay code.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
  • Loading branch information
Russell King committed Dec 8, 2017
1 parent d924155 commit 890ca8d
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 32 deletions.
59 changes: 44 additions & 15 deletions drivers/gpu/drm/armada/armada_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,19 @@ static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc,
spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
}

static void armada_drm_crtc_complete_disable_work(struct armada_crtc *dcrtc,
struct armada_plane_work *work)
{
unsigned long flags;

if (dcrtc->plane == work->plane)
dcrtc->plane = NULL;

spin_lock_irqsave(&dcrtc->irq_lock, flags);
armada_drm_crtc_update_regs(dcrtc, work->regs);
spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
}

static struct armada_plane_work *
armada_drm_crtc_alloc_plane_work(struct drm_plane *plane)
{
Expand Down Expand Up @@ -392,8 +405,11 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc)
* the new mode parameters.
*/
plane = dcrtc->plane;
if (plane)
if (plane) {
drm_plane_force_disable(plane);
WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane),
HZ));
}
}

/* The mode_config.mutex will be held for this call */
Expand Down Expand Up @@ -1120,28 +1136,22 @@ int armada_drm_plane_disable(struct drm_plane *plane,
{
struct armada_plane *dplane = drm_to_armada_plane(plane);
struct armada_crtc *dcrtc;
struct armada_plane_work *work;
unsigned int idx = 0;
u32 sram_para1, enable_mask;

if (!plane->crtc)
return 0;

/*
* Drop our reference on any framebuffer attached to this plane.
* We don't need to NULL this out as drm_plane_force_disable(),
* and __setplane_internal() will do so for an overlay plane, and
* __drm_helper_disable_unused_functions() will do so for the
* primary plane.
* Arrange to power down most RAMs and FIFOs if this is the primary
* plane, otherwise just the YUV FIFOs for the overlay plane.
*/
if (plane->fb)
drm_framebuffer_put(plane->fb);

/* Power down most RAMs and FIFOs if this is the primary plane */
if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
sram_para1 = CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
CFG_PDWN32x32 | CFG_PDWN64x66;
enable_mask = CFG_GRA_ENA;
} else {
/* Power down the Y/U/V FIFOs */
sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66;
enable_mask = CFG_DMA_ENA;
}
Expand All @@ -1150,14 +1160,33 @@ int armada_drm_plane_disable(struct drm_plane *plane,

dcrtc = drm_to_armada_crtc(plane->crtc);

/*
* Try to disable the plane and drop our ref on the framebuffer
* at the next frame update. If we fail for any reason, disable
* the plane immediately.
*/
work = &dplane->works[dplane->next_work];
work->fn = armada_drm_crtc_complete_disable_work;
work->cancel = armada_drm_crtc_complete_disable_work;
work->old_fb = plane->fb;

armada_reg_queue_mod(work->regs, idx,
0, enable_mask, LCD_SPU_DMA_CTRL0);
armada_reg_queue_mod(work->regs, idx,
sram_para1, 0, LCD_SPU_SRAM_PARA1);
armada_reg_queue_end(work->regs, idx);

/* Wait for any preceding work to complete, but don't wedge */
if (WARN_ON(!armada_drm_plane_work_wait(dplane, HZ)))
armada_drm_plane_work_cancel(dcrtc, dplane);

spin_lock_irq(&dcrtc->irq_lock);
armada_updatel(0, enable_mask, dcrtc->base + LCD_SPU_DMA_CTRL0);
armada_updatel(sram_para1, 0, dcrtc->base + LCD_SPU_SRAM_PARA1);
spin_unlock_irq(&dcrtc->irq_lock);
if (armada_drm_plane_work_queue(dcrtc, work)) {
work->fn(dcrtc, work);
if (work->old_fb)
drm_framebuffer_unreference(work->old_fb);
}

dplane->next_work = !dplane->next_work;

return 0;
}
Expand Down
23 changes: 6 additions & 17 deletions drivers/gpu/drm/armada/armada_overlay.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,6 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
dplane->base.state.src_x != state.src.x1 >> 16 ||
dplane->base.state.src_y != state.src.y1 >> 16;

if (!dcrtc->plane) {
dcrtc->plane = plane;
armada_ovl_update_attr(&dplane->prop, dcrtc);
}

/* FIXME: overlay on an interlaced display */
/* Just updating the position/size? */
if (!fb_changed && dplane->base.state.ctrl0 == ctrl0) {
Expand Down Expand Up @@ -173,6 +168,11 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
if (armada_drm_plane_work_wait(&dplane->base, HZ / 25) == 0)
armada_drm_plane_work_cancel(dcrtc, &dplane->base);

if (!dcrtc->plane) {
dcrtc->plane = plane;
armada_ovl_update_attr(&dplane->prop, dcrtc);
}

if (fb_changed) {
u32 addrs[3];

Expand Down Expand Up @@ -255,17 +255,6 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
return 0;
}

static int armada_ovl_plane_disable(struct drm_plane *plane,
struct drm_modeset_acquire_ctx *ctx)
{
armada_drm_plane_disable(plane, ctx);

if (plane->crtc)
drm_to_armada_crtc(plane->crtc)->plane = NULL;

return 0;
}

static void armada_ovl_plane_destroy(struct drm_plane *plane)
{
struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane);
Expand Down Expand Up @@ -345,7 +334,7 @@ static int armada_ovl_plane_set_property(struct drm_plane *plane,

static const struct drm_plane_funcs armada_ovl_plane_funcs = {
.update_plane = armada_ovl_plane_update,
.disable_plane = armada_ovl_plane_disable,
.disable_plane = armada_drm_plane_disable,
.destroy = armada_ovl_plane_destroy,
.set_property = armada_ovl_plane_set_property,
};
Expand Down

0 comments on commit 890ca8d

Please sign in to comment.