Commit dc042da0 authored by Dave Airlie's avatar Dave Airlie
Browse files

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
Loading
Loading
Loading
Loading
+27 −20
Original line number Diff line number Diff line
@@ -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,
	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;
	int num_planes = fb->format->num_planes;
	int i;

	if (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] +
			     x * fb->format->cpp[i];
			     x * format->cpp[i];
	for (; i < 3; i++)
		addrs[i] = 0;
}
@@ -744,15 +751,14 @@ void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc,
	if (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 */
	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;
		dma_ctrl0_mask = CFG_GRA_ENA;
	} else {
		/* Power down the Y/U/V FIFOs */
		sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66;
		dma_ctrl0_mask = CFG_DMA_ENA;
	}

@@ -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",
			       dcrtc);
	if (ret < 0) {
		kfree(dcrtc);
		return ret;
	}
	if (ret < 0)
		goto err_crtc;

	if (dcrtc->variant->init) {
		ret = dcrtc->variant->init(dcrtc, dev);
		if (ret) {
			kfree(dcrtc);
			return ret;
		}
		if (ret)
			goto err_crtc;
	}

	/* Ensure AXI pipeline is enabled */
@@ -1246,13 +1248,15 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
	dcrtc->crtc.port = port;

	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
	if (!primary)
		return -ENOMEM;
	if (!primary) {
		ret = -ENOMEM;
		goto err_crtc;
	}

	ret = armada_drm_plane_init(primary);
	if (ret) {
		kfree(primary);
		return ret;
		goto err_crtc;
	}

	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,
				       DRM_PLANE_TYPE_PRIMARY, NULL);
	if (ret) {
		kfree(primary);
		return ret;
		goto err_crtc;
	}

	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,

err_crtc_init:
	primary->base.funcs->destroy(&primary->base);
err_crtc:
	kfree(dcrtc);

	return ret;
}

+2 −0
Original line number Diff line number Diff line
@@ -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;
+19 −19
Original line number Diff line number Diff line
@@ -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,
@@ -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,
@@ -138,6 +139,18 @@ 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);
@@ -145,7 +158,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,

	/* 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;
@@ -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
@@ -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],