Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 628d1655 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'imx-drm-next-2016-11-10' of git://git.pengutronix.de/git/pza/linux into drm-next

imx-drm plane update cleanup, YUV formats

- request modeset if plane offsets changed, only the plane base
  address can be changed without disabling the plane IDMAC channel.
- cleanup of plane atomic_update
- remove unused ipu_cpmem_set_yuv_planar function
- support YUV 4:4:4, 4:2:2, NV12 and NV16 plane formats
- not only mask interrupts during irq init, also clear them
- remove a legacy check from imx-ldb
- add support to set the CSI downsizing bits
- silence an obnoxious warning during modeset

* tag 'imx-drm-next-2016-11-10' of git://git.pengutronix.de/git/pza/linux:
  gpu: ipu-di: silence videomode logspam
  gpu: ipu-v3: add ipu_csi_set_downsize
  drm/imx: imx-ldb: remove unnecessary double disable check
  gpu: ipu-v3: initially clear all interrupts
  drm/imx: ipuv3-plane: add support for YUV 4:2:2 and 4:4:4, NV12, and NV16 formats
  gpu: ipu-v3: add YUV 4:4:4 support
  gpu: ipu-cpmem: remove unused ipu_cpmem_set_yuv_planar function
  drm/imx: ipuv3-plane: let drm_plane_state_to_ubo/vbo handle chroma subsampling other than 4:2:0
  drm/imx: ipuv3-plane: merge ipu_plane_atomic_set_base into atomic_update
  drm/imx: ipuv3-plane: request modeset if plane offsets changed
parents 3e91168a b5b457b3
Loading
Loading
Loading
Loading
+0 −12
Original line number Diff line number Diff line
@@ -319,18 +319,6 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
	struct imx_ldb *ldb = imx_ldb_ch->ldb;
	int mux, ret;

	/*
	 * imx_ldb_encoder_disable is called by
	 * drm_helper_disable_unused_functions without
	 * the encoder being enabled before.
	 */
	if (imx_ldb_ch == &ldb->channel[0] &&
	    (ldb->ldb_ctrl & LDB_CH0_MODE_EN_MASK) == 0)
		return;
	else if (imx_ldb_ch == &ldb->channel[1] &&
		 (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0)
		return;

	drm_panel_disable(imx_ldb_ch->panel);

	if (imx_ldb_ch == &ldb->channel[0])
+94 −82
Original line number Diff line number Diff line
@@ -50,6 +50,12 @@ static const uint32_t ipu_plane_formats[] = {
	DRM_FORMAT_YVYU,
	DRM_FORMAT_YUV420,
	DRM_FORMAT_YVU420,
	DRM_FORMAT_YUV422,
	DRM_FORMAT_YVU422,
	DRM_FORMAT_YUV444,
	DRM_FORMAT_YVU444,
	DRM_FORMAT_NV12,
	DRM_FORMAT_NV16,
	DRM_FORMAT_RGB565,
};

@@ -64,13 +70,14 @@ drm_plane_state_to_eba(struct drm_plane_state *state)
{
	struct drm_framebuffer *fb = state->fb;
	struct drm_gem_cma_object *cma_obj;
	int x = state->src_x >> 16;
	int y = state->src_y >> 16;

	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
	BUG_ON(!cma_obj);

	return cma_obj->paddr + fb->offsets[0] +
	       fb->pitches[0] * (state->src_y >> 16) +
	       (fb->bits_per_pixel >> 3) * (state->src_x >> 16);
	return cma_obj->paddr + fb->offsets[0] + fb->pitches[0] * y +
	       drm_format_plane_cpp(fb->pixel_format, 0) * x;
}

static inline unsigned long
@@ -79,13 +86,17 @@ drm_plane_state_to_ubo(struct drm_plane_state *state)
	struct drm_framebuffer *fb = state->fb;
	struct drm_gem_cma_object *cma_obj;
	unsigned long eba = drm_plane_state_to_eba(state);
	int x = state->src_x >> 16;
	int y = state->src_y >> 16;

	cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
	BUG_ON(!cma_obj);

	return cma_obj->paddr + fb->offsets[1] +
	       fb->pitches[1] * (state->src_y >> 16) / 2 +
	       (state->src_x >> 16) / 2 - eba;
	x /= drm_format_horz_chroma_subsampling(fb->pixel_format);
	y /= drm_format_vert_chroma_subsampling(fb->pixel_format);

	return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y +
	       drm_format_plane_cpp(fb->pixel_format, 1) * x - eba;
}

static inline unsigned long
@@ -94,69 +105,17 @@ drm_plane_state_to_vbo(struct drm_plane_state *state)
	struct drm_framebuffer *fb = state->fb;
	struct drm_gem_cma_object *cma_obj;
	unsigned long eba = drm_plane_state_to_eba(state);
	int x = state->src_x >> 16;
	int y = state->src_y >> 16;

	cma_obj = drm_fb_cma_get_gem_obj(fb, 2);
	BUG_ON(!cma_obj);

	return cma_obj->paddr + fb->offsets[2] +
	       fb->pitches[2] * (state->src_y >> 16) / 2 +
	       (state->src_x >> 16) / 2 - eba;
}

static void ipu_plane_atomic_set_base(struct ipu_plane *ipu_plane)
{
	struct drm_plane *plane = &ipu_plane->base;
	struct drm_plane_state *state = plane->state;
	struct drm_crtc_state *crtc_state = state->crtc->state;
	struct drm_framebuffer *fb = state->fb;
	unsigned long eba, ubo, vbo;
	int active;

	eba = drm_plane_state_to_eba(state);

	switch (fb->pixel_format) {
	case DRM_FORMAT_YUV420:
	case DRM_FORMAT_YVU420:
		if (!drm_atomic_crtc_needs_modeset(crtc_state))
			break;

		/*
		 * Multiplanar formats have to meet the following restrictions:
		 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
		 * - EBA, UBO and VBO are a multiple of 8
		 * - UBO and VBO are unsigned and not larger than 0xfffff8
		 * - Only EBA may be changed while scanout is active
		 * - The strides of U and V planes must be identical.
		 */
		ubo = drm_plane_state_to_ubo(state);
		vbo = drm_plane_state_to_vbo(state);

		if (fb->pixel_format == DRM_FORMAT_YUV420)
			ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
						      fb->pitches[1], ubo, vbo);
		else
			ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
						      fb->pitches[1], vbo, ubo);
	x /= drm_format_horz_chroma_subsampling(fb->pixel_format);
	y /= drm_format_vert_chroma_subsampling(fb->pixel_format);

		dev_dbg(ipu_plane->base.dev->dev,
			"phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo,
			state->src_x >> 16, state->src_y >> 16);
		break;
	default:
		dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",
			eba, state->src_x >> 16, state->src_y >> 16);

		break;
	}

	if (!drm_atomic_crtc_needs_modeset(crtc_state)) {
		active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
		ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
		ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
	} else {
		ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
		ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
	}
	return cma_obj->paddr + fb->offsets[2] + fb->pitches[2] * y +
	       drm_format_plane_cpp(fb->pixel_format, 2) * x - eba;
}

void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
@@ -339,6 +298,10 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
	switch (fb->pixel_format) {
	case DRM_FORMAT_YUV420:
	case DRM_FORMAT_YVU420:
	case DRM_FORMAT_YUV422:
	case DRM_FORMAT_YVU422:
	case DRM_FORMAT_YUV444:
	case DRM_FORMAT_YVU444:
		/*
		 * Multiplanar formats have to meet the following restrictions:
		 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
@@ -347,27 +310,34 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
		 * - Only EBA may be changed while scanout is active
		 * - The strides of U and V planes must be identical.
		 */
		ubo = drm_plane_state_to_ubo(state);
		vbo = drm_plane_state_to_vbo(state);

		if ((ubo & 0x7) || (vbo & 0x7))
		if (vbo & 0x7 || vbo > 0xfffff8)
			return -EINVAL;

		if ((ubo > 0xfffff8) || (vbo > 0xfffff8))
			return -EINVAL;

		if (old_fb &&
		    (old_fb->pixel_format == DRM_FORMAT_YUV420 ||
		     old_fb->pixel_format == DRM_FORMAT_YVU420)) {
			old_ubo = drm_plane_state_to_ubo(old_state);
		if (old_fb && (fb->pixel_format == old_fb->pixel_format)) {
			old_vbo = drm_plane_state_to_vbo(old_state);
			if (ubo != old_ubo || vbo != old_vbo)
				return -EINVAL;
			if (vbo != old_vbo)
				crtc_state->mode_changed = true;
		}

		if (fb->pitches[1] != fb->pitches[2])
			return -EINVAL;

		/* fall-through */
	case DRM_FORMAT_NV12:
	case DRM_FORMAT_NV16:
		ubo = drm_plane_state_to_ubo(state);

		if (ubo & 0x7 || ubo > 0xfffff8)
			return -EINVAL;

		if (old_fb && (fb->pixel_format == old_fb->pixel_format)) {
			old_ubo = drm_plane_state_to_ubo(old_state);
			if (ubo != old_ubo)
				crtc_state->mode_changed = true;
		}

		if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
			return -EINVAL;

@@ -399,16 +369,20 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
{
	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
	struct drm_plane_state *state = plane->state;
	struct drm_crtc_state *crtc_state = state->crtc->state;
	struct drm_framebuffer *fb = state->fb;
	unsigned long eba, ubo, vbo;
	enum ipu_color_space ics;
	int active;

	if (old_state->fb) {
		struct drm_crtc_state *crtc_state = state->crtc->state;
	eba = drm_plane_state_to_eba(state);

		if (!drm_atomic_crtc_needs_modeset(crtc_state)) {
			ipu_plane_atomic_set_base(ipu_plane);
	if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) {
		active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
		ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
		ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
		return;
	}
	}

	switch (ipu_plane->dp_flow) {
	case IPU_DP_FLOW_SYNC_BG:
@@ -451,7 +425,45 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
	ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
	ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
	ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]);
	ipu_plane_atomic_set_base(ipu_plane);
	switch (fb->pixel_format) {
	case DRM_FORMAT_YUV420:
	case DRM_FORMAT_YVU420:
	case DRM_FORMAT_YUV422:
	case DRM_FORMAT_YVU422:
	case DRM_FORMAT_YUV444:
	case DRM_FORMAT_YVU444:
		ubo = drm_plane_state_to_ubo(state);
		vbo = drm_plane_state_to_vbo(state);
		if (fb->pixel_format == DRM_FORMAT_YVU420 ||
		    fb->pixel_format == DRM_FORMAT_YVU422 ||
		    fb->pixel_format == DRM_FORMAT_YVU444)
			swap(ubo, vbo);

		ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
					      fb->pitches[1], ubo, vbo);

		dev_dbg(ipu_plane->base.dev->dev,
			"phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo,
			state->src_x >> 16, state->src_y >> 16);
		break;
	case DRM_FORMAT_NV12:
	case DRM_FORMAT_NV16:
		ubo = drm_plane_state_to_ubo(state);

		ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
					      fb->pitches[1], ubo, ubo);

		dev_dbg(ipu_plane->base.dev->dev,
			"phy = %lu %lu, x = %d, y = %d", eba, ubo,
			state->src_x >> 16, state->src_y >> 16);
		break;
	default:
		dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",
			eba, state->src_x >> 16, state->src_y >> 16);
		break;
	}
	ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
	ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
	ipu_plane_enable(ipu_plane);
}

+6 −1
Original line number Diff line number Diff line
@@ -88,6 +88,8 @@ enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
	case DRM_FORMAT_YVU420:
	case DRM_FORMAT_YUV422:
	case DRM_FORMAT_YVU422:
	case DRM_FORMAT_YUV444:
	case DRM_FORMAT_YVU444:
	case DRM_FORMAT_NV12:
	case DRM_FORMAT_NV21:
	case DRM_FORMAT_NV16:
@@ -1284,8 +1286,11 @@ static int ipu_irq_init(struct ipu_soc *ipu)
		return ret;
	}

	for (i = 0; i < IPU_NUM_IRQS; i += 32)
	/* Mask and clear all interrupts */
	for (i = 0; i < IPU_NUM_IRQS; i += 32) {
		ipu_cm_write(ipu, 0, IPU_INT_CTRL(i / 32));
		ipu_cm_write(ipu, ~unused[i / 32], IPU_INT_STAT(i / 32));
	}

	for (i = 0; i < IPU_NUM_IRQS; i += 32) {
		gc = irq_get_domain_generic_chip(ipu->domain, i);
+7 −36
Original line number Diff line number Diff line
@@ -417,42 +417,6 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);

void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
			      u32 pixel_format, int stride, int height)
{
	int fourcc, u_offset, v_offset;
	int uv_stride = 0;

	fourcc = v4l2_pix_fmt_to_drm_fourcc(pixel_format);
	switch (fourcc) {
	case DRM_FORMAT_YUV420:
		uv_stride = stride / 2;
		u_offset = stride * height;
		v_offset = u_offset + (uv_stride * height / 2);
		break;
	case DRM_FORMAT_YVU420:
		uv_stride = stride / 2;
		v_offset = stride * height;
		u_offset = v_offset + (uv_stride * height / 2);
		break;
	case DRM_FORMAT_YUV422:
		uv_stride = stride / 2;
		u_offset = stride * height;
		v_offset = u_offset + (uv_stride * height);
		break;
	case DRM_FORMAT_NV12:
	case DRM_FORMAT_NV16:
		uv_stride = stride;
		u_offset = stride * height;
		v_offset = 0;
		break;
	default:
		return;
	}
	ipu_cpmem_set_yuv_planar_full(ch, uv_stride, u_offset, v_offset);
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);

static const struct ipu_rgb def_xrgb_32 = {
	.red	= { .offset = 16, .length = 8, },
	.green	= { .offset =  8, .length = 8, },
@@ -590,6 +554,13 @@ int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
		/* burst size */
		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
		break;
	case DRM_FORMAT_YUV444:
	case DRM_FORMAT_YVU444:
		/* pix format */
		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
		/* burst size */
		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
		break;
	case DRM_FORMAT_NV12:
		/* pix format */
		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
+16 −0
Original line number Diff line number Diff line
@@ -529,6 +529,22 @@ void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w)
}
EXPORT_SYMBOL_GPL(ipu_csi_set_window);

void ipu_csi_set_downsize(struct ipu_csi *csi, bool horiz, bool vert)
{
	unsigned long flags;
	u32 reg;

	spin_lock_irqsave(&csi->lock, flags);

	reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
	reg &= ~(CSI_HORI_DOWNSIZE_EN | CSI_VERT_DOWNSIZE_EN);
	reg |= (horiz ? CSI_HORI_DOWNSIZE_EN : 0) |
	       (vert ? CSI_VERT_DOWNSIZE_EN : 0);
	ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);

	spin_unlock_irqrestore(&csi->lock, flags);
}

void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
				u32 r_value, u32 g_value, u32 b_value,
				u32 pix_clk)
Loading