Commit dc042da0 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-armada-fixes-4.15' of git://git.armlinux.org.uk/~rmk/linux-arm into drm-fixes

Armada fixes.

* 'drm-armada-fixes-4.15' of git://git.armlinux.org.uk/~rmk/linux-arm:
  drm/armada: fix YUV planar format framebuffer offsets
  drm/armada: improve efficiency of armada_drm_plane_calc_addrs()
  drm/armada: fix UV swap code
  drm/armada: fix SRAM powerdown
  drm/armada: fix leak of crtc structure
parents 041ea478 de0ea9ad
...@@ -168,16 +168,23 @@ static void armada_drm_crtc_update(struct armada_crtc *dcrtc) ...@@ -168,16 +168,23 @@ static void armada_drm_crtc_update(struct armada_crtc *dcrtc)
void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb,
int x, int y) int x, int y)
{ {
const struct drm_format_info *format = fb->format;
unsigned int num_planes = format->num_planes;
u32 addr = drm_fb_obj(fb)->dev_addr; u32 addr = drm_fb_obj(fb)->dev_addr;
int num_planes = fb->format->num_planes;
int i; int i;
if (num_planes > 3) if (num_planes > 3)
num_planes = 3; num_planes = 3;
for (i = 0; i < num_planes; i++) addrs[0] = addr + fb->offsets[0] + y * fb->pitches[0] +
x * format->cpp[0];
y /= format->vsub;
x /= format->hsub;
for (i = 1; i < num_planes; i++)
addrs[i] = addr + fb->offsets[i] + y * fb->pitches[i] + addrs[i] = addr + fb->offsets[i] + y * fb->pitches[i] +
x * fb->format->cpp[i]; x * format->cpp[i];
for (; i < 3; i++) for (; i < 3; i++)
addrs[i] = 0; addrs[i] = 0;
} }
...@@ -744,15 +751,14 @@ void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc, ...@@ -744,15 +751,14 @@ void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc,
if (plane->fb) if (plane->fb)
drm_framebuffer_put(plane->fb); drm_framebuffer_put(plane->fb);
/* Power down the Y/U/V FIFOs */
sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66;
/* Power down most RAMs and FIFOs if this is the primary plane */ /* Power down most RAMs and FIFOs if this is the primary plane */
if (plane->type == DRM_PLANE_TYPE_PRIMARY) { if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
sram_para1 |= CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | sram_para1 = CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
CFG_PDWN32x32 | CFG_PDWN64x66; CFG_PDWN32x32 | CFG_PDWN64x66;
dma_ctrl0_mask = CFG_GRA_ENA; dma_ctrl0_mask = CFG_GRA_ENA;
} else { } else {
/* Power down the Y/U/V FIFOs */
sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66;
dma_ctrl0_mask = CFG_DMA_ENA; dma_ctrl0_mask = CFG_DMA_ENA;
} }
...@@ -1225,17 +1231,13 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, ...@@ -1225,17 +1231,13 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
ret = devm_request_irq(dev, irq, armada_drm_irq, 0, "armada_drm_crtc", ret = devm_request_irq(dev, irq, armada_drm_irq, 0, "armada_drm_crtc",
dcrtc); dcrtc);
if (ret < 0) { if (ret < 0)
kfree(dcrtc); goto err_crtc;
return ret;
}
if (dcrtc->variant->init) { if (dcrtc->variant->init) {
ret = dcrtc->variant->init(dcrtc, dev); ret = dcrtc->variant->init(dcrtc, dev);
if (ret) { if (ret)
kfree(dcrtc); goto err_crtc;
return ret;
}
} }
/* Ensure AXI pipeline is enabled */ /* Ensure AXI pipeline is enabled */
...@@ -1246,13 +1248,15 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, ...@@ -1246,13 +1248,15 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
dcrtc->crtc.port = port; dcrtc->crtc.port = port;
primary = kzalloc(sizeof(*primary), GFP_KERNEL); primary = kzalloc(sizeof(*primary), GFP_KERNEL);
if (!primary) if (!primary) {
return -ENOMEM; ret = -ENOMEM;
goto err_crtc;
}
ret = armada_drm_plane_init(primary); ret = armada_drm_plane_init(primary);
if (ret) { if (ret) {
kfree(primary); kfree(primary);
return ret; goto err_crtc;
} }
ret = drm_universal_plane_init(drm, &primary->base, 0, ret = drm_universal_plane_init(drm, &primary->base, 0,
...@@ -1263,7 +1267,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, ...@@ -1263,7 +1267,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
DRM_PLANE_TYPE_PRIMARY, NULL); DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret) { if (ret) {
kfree(primary); kfree(primary);
return ret; goto err_crtc;
} }
ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, &primary->base, NULL, ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, &primary->base, NULL,
...@@ -1282,6 +1286,9 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, ...@@ -1282,6 +1286,9 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
err_crtc_init: err_crtc_init:
primary->base.funcs->destroy(&primary->base); primary->base.funcs->destroy(&primary->base);
err_crtc:
kfree(dcrtc);
return ret; return ret;
} }
......
...@@ -42,6 +42,8 @@ struct armada_plane_work { ...@@ -42,6 +42,8 @@ struct armada_plane_work {
}; };
struct armada_plane_state { struct armada_plane_state {
u16 src_x;
u16 src_y;
u32 src_hw; u32 src_hw;
u32 dst_hw; u32 dst_hw;
u32 dst_yx; u32 dst_yx;
......
...@@ -99,6 +99,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -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_ovl_plane *dplane = drm_to_armada_ovl_plane(plane);
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
const struct drm_format_info *format;
struct drm_rect src = { struct drm_rect src = {
.x1 = src_x, .x1 = src_x,
.y1 = src_y, .y1 = src_y,
...@@ -117,7 +118,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -117,7 +118,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
}; };
uint32_t val, ctrl0; uint32_t val, ctrl0;
unsigned idx = 0; unsigned idx = 0;
bool visible; bool visible, fb_changed;
int ret; int ret;
trace_armada_ovl_plane_update(plane, crtc, fb, trace_armada_ovl_plane_update(plane, crtc, fb,
...@@ -138,6 +139,18 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -138,6 +139,18 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
if (!visible) if (!visible)
ctrl0 &= ~CFG_DMA_ENA; 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) { if (!dcrtc->plane) {
dcrtc->plane = plane; dcrtc->plane = plane;
armada_ovl_update_attr(&dplane->prop, dcrtc); armada_ovl_update_attr(&dplane->prop, dcrtc);
...@@ -145,7 +158,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -145,7 +158,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
/* FIXME: overlay on an interlaced display */ /* FIXME: overlay on an interlaced display */
/* Just updating the position/size? */ /* 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) | val = (drm_rect_height(&src) & 0xffff0000) |
drm_rect_width(&src) >> 16; drm_rect_width(&src) >> 16;
dplane->base.state.src_hw = val; dplane->base.state.src_hw = val;
...@@ -169,9 +182,8 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -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) if (armada_drm_plane_work_wait(&dplane->base, HZ / 25) == 0)
armada_drm_plane_work_cancel(dcrtc, &dplane->base); armada_drm_plane_work_cancel(dcrtc, &dplane->base);
if (plane->fb != fb) { if (fb_changed) {
u32 addrs[3], pixel_format; u32 addrs[3];
int num_planes, hsub;
/* /*
* Take a reference on the new framebuffer - we want to * Take a reference on the new framebuffer - we want to
...@@ -182,23 +194,11 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -182,23 +194,11 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
if (plane->fb) if (plane->fb)
armada_ovl_retire_fb(dplane, plane->fb); armada_ovl_retire_fb(dplane, plane->fb);
src_y = src.y1 >> 16; dplane->base.state.src_y = src_y = src.y1 >> 16;
src_x = src.x1 >> 16; dplane->base.state.src_x = src_x = src.x1 >> 16;
armada_drm_plane_calc_addrs(addrs, fb, src_x, src_y); 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], armada_reg_queue_set(dplane->vbl.regs, idx, addrs[0],
LCD_SPU_DMA_START_ADDR_Y0); LCD_SPU_DMA_START_ADDR_Y0);
armada_reg_queue_set(dplane->vbl.regs, idx, addrs[1], armada_reg_queue_set(dplane->vbl.regs, idx, addrs[1],
......
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