Skip to content

Commit

Permalink
drm/armada: fix UV swap code
Browse files Browse the repository at this point in the history
The UV swap code was not always programming things correctly when
the source origin box has been offset.  Fix this.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
  • Loading branch information
Russell King committed Dec 8, 2017
1 parent 2bf5743 commit 9c898c4
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 19 deletions.
2 changes: 2 additions & 0 deletions drivers/gpu/drm/armada/armada_crtc.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ struct armada_plane_work {
};

struct armada_plane_state {
u16 src_x;
u16 src_y;
u32 src_hw;
u32 dst_hw;
u32 dst_yx;
Expand Down
38 changes: 19 additions & 19 deletions drivers/gpu/drm/armada/armada_overlay.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
{
struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane);
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
const struct drm_format_info *format;
struct drm_rect src = {
.x1 = src_x,
.y1 = src_y,
Expand All @@ -117,7 +118,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
};
uint32_t val, ctrl0;
unsigned idx = 0;
bool visible;
bool visible, fb_changed;
int ret;

trace_armada_ovl_plane_update(plane, crtc, fb,
Expand All @@ -138,14 +139,26 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
if (!visible)
ctrl0 &= ~CFG_DMA_ENA;

/*
* Shifting a YUV packed format image by one pixel causes the U/V
* planes to swap. Compensate for it by also toggling the UV swap.
*/
format = fb->format;
if (format->num_planes == 1 && src.x1 >> 16 & (format->hsub - 1))
ctrl0 ^= CFG_DMA_MOD(CFG_SWAPUV);

fb_changed = plane->fb != fb ||
dplane->base.state.src_x != src.x1 >> 16 ||
dplane->base.state.src_y != 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 (plane->fb == fb && dplane->base.state.ctrl0 == ctrl0) {
if (!fb_changed && dplane->base.state.ctrl0 == ctrl0) {
val = (drm_rect_height(&src) & 0xffff0000) |
drm_rect_width(&src) >> 16;
dplane->base.state.src_hw = val;
Expand All @@ -169,9 +182,8 @@ 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 (plane->fb != fb) {
u32 addrs[3], pixel_format;
int num_planes, hsub;
if (fb_changed) {
u32 addrs[3];

/*
* Take a reference on the new framebuffer - we want to
Expand All @@ -182,23 +194,11 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
if (plane->fb)
armada_ovl_retire_fb(dplane, plane->fb);

src_y = src.y1 >> 16;
src_x = src.x1 >> 16;
dplane->base.state.src_y = src_y = src.y1 >> 16;
dplane->base.state.src_x = src_x = src.x1 >> 16;

armada_drm_plane_calc_addrs(addrs, fb, src_x, src_y);

pixel_format = fb->format->format;
hsub = drm_format_horz_chroma_subsampling(pixel_format);
num_planes = fb->format->num_planes;

/*
* Annoyingly, shifting a YUYV-format image by one pixel
* causes the U/V planes to toggle. Toggle the UV swap.
* (Unfortunately, this causes momentary colour flickering.)
*/
if (src_x & (hsub - 1) && num_planes == 1)
ctrl0 ^= CFG_DMA_MOD(CFG_SWAPUV);

armada_reg_queue_set(dplane->vbl.regs, idx, addrs[0],
LCD_SPU_DMA_START_ADDR_Y0);
armada_reg_queue_set(dplane->vbl.regs, idx, addrs[1],
Expand Down

0 comments on commit 9c898c4

Please sign in to comment.