From cb053a15c5c23e775647d6b65fef4c378bf34b5b Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <wens@csie.org>
Date: Thu, 18 Jul 2019 17:07:05 +0800
Subject: [PATCH] staging: bcm2835-codec: switch to multi-planar API

There are two APIs for mem2mem devices, the older single-planar API and
the newer multi-planar one. Without making things overly complex, the
driver can only support one or the other. However the userspace libv4l2
library has a plugin that allows multi-planar API devices to service
single-planar consumers.

Chromium supports the multi-planar API exclusively, though this is
currently limited to ChromiumOS. It would be possible to add support
for generic Linux.

Switching to the multi-planar API would allow usage of both APIs from
userspace.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 .../bcm2835-codec/bcm2835-v4l2-codec.c        | 145 +++++++++---------
 1 file changed, 76 insertions(+), 69 deletions(-)

--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
@@ -504,7 +504,7 @@ static struct bcm2835_codec_fmt *find_fo
 
 	for (k = 0; k < fmts->num_entries; k++) {
 		fmt = &fmts->list[k];
-		if (fmt->fourcc == f->fmt.pix.pixelformat)
+		if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
 			break;
 	}
 	if (k == fmts->num_entries)
@@ -522,9 +522,9 @@ static struct bcm2835_codec_q_data *get_
 					       enum v4l2_buf_type type)
 {
 	switch (type) {
-	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		return &ctx->q_data[V4L2_M2M_SRC];
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		return &ctx->q_data[V4L2_M2M_DST];
 	default:
 		v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
@@ -541,9 +541,9 @@ static struct vchiq_mmal_port *get_port_
 		return NULL;
 
 	switch (type) {
-	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		return &ctx->component->input[0];
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		return &ctx->component->output[0];
 	default:
 		v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
@@ -752,7 +752,7 @@ static void handle_fmt_changed(struct bc
 		 format->es.video.crop.width, format->es.video.crop.height,
 		 format->es.video.color_space);
 
-	q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 	q_data->crop_width = format->es.video.crop.width;
 	q_data->crop_height = format->es.video.crop.height;
 	q_data->bytesperline = format->es.video.crop.width;
@@ -945,7 +945,7 @@ static int vidioc_querycap(struct file *
 	strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
 	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
 		 MEM2MEM_NAME);
-	cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+	cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
@@ -996,16 +996,20 @@ static int vidioc_g_fmt(struct bcm2835_c
 
 	q_data = get_q_data(ctx, f->type);
 
-	f->fmt.pix.width	= q_data->crop_width;
-	f->fmt.pix.height	= q_data->height;
-	f->fmt.pix.field	= V4L2_FIELD_NONE;
-	f->fmt.pix.pixelformat	= q_data->fmt->fourcc;
-	f->fmt.pix.bytesperline	= q_data->bytesperline;
-	f->fmt.pix.sizeimage	= q_data->sizeimage;
-	f->fmt.pix.colorspace	= ctx->colorspace;
-	f->fmt.pix.xfer_func	= ctx->xfer_func;
-	f->fmt.pix.ycbcr_enc	= ctx->ycbcr_enc;
-	f->fmt.pix.quantization	= ctx->quant;
+	f->fmt.pix_mp.width			= q_data->crop_width;
+	f->fmt.pix_mp.height			= q_data->height;
+	f->fmt.pix_mp.pixelformat		= q_data->fmt->fourcc;
+	f->fmt.pix_mp.field			= V4L2_FIELD_NONE;
+	f->fmt.pix_mp.colorspace		= ctx->colorspace;
+	f->fmt.pix_mp.plane_fmt[0].sizeimage	= q_data->sizeimage;
+	f->fmt.pix_mp.plane_fmt[0].bytesperline	= q_data->bytesperline;
+	f->fmt.pix_mp.num_planes		= 1;
+	f->fmt.pix_mp.ycbcr_enc			= ctx->ycbcr_enc;
+	f->fmt.pix_mp.quantization		= ctx->quant;
+	f->fmt.pix_mp.xfer_func			= ctx->xfer_func;
+
+	memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
+	       sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
 
 	return 0;
 }
@@ -1029,17 +1033,17 @@ static int vidioc_try_fmt(struct bcm2835
 	 * The V4L2 specification requires the driver to correct the format
 	 * struct if any of the dimensions is unsupported
 	 */
-	if (f->fmt.pix.width > MAX_W)
-		f->fmt.pix.width = MAX_W;
-	if (f->fmt.pix.height > MAX_H)
-		f->fmt.pix.height = MAX_H;
+	if (f->fmt.pix_mp.width > MAX_W)
+		f->fmt.pix_mp.width = MAX_W;
+	if (f->fmt.pix_mp.height > MAX_H)
+		f->fmt.pix_mp.height = MAX_H;
 
 	if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
 		/* Only clip min w/h on capture. Treat 0x0 as unknown. */
-		if (f->fmt.pix.width < MIN_W)
-			f->fmt.pix.width = MIN_W;
-		if (f->fmt.pix.height < MIN_H)
-			f->fmt.pix.height = MIN_H;
+		if (f->fmt.pix_mp.width < MIN_W)
+			f->fmt.pix_mp.width = MIN_W;
+		if (f->fmt.pix_mp.height < MIN_H)
+			f->fmt.pix_mp.height = MIN_H;
 
 		/*
 		 * For codecs the buffer must have a vertical alignment of 16
@@ -1048,16 +1052,18 @@ static int vidioc_try_fmt(struct bcm2835
 		 * some of the pixels are active.
 		 */
 		if (ctx->dev->role != ISP)
-			f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
+			f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16);
 	}
-	f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
-						   fmt);
-	f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline,
-					     f->fmt.pix.width,
-					     f->fmt.pix.height,
-					     fmt);
+	f->fmt.pix_mp.num_planes = 1;
+	f->fmt.pix_mp.plane_fmt[0].bytesperline =
+		get_bytesperline(f->fmt.pix_mp.width, fmt);
+	f->fmt.pix_mp.plane_fmt[0].sizeimage =
+		get_sizeimage(f->fmt.pix_mp.plane_fmt[0].bytesperline,
+			      f->fmt.pix_mp.width, f->fmt.pix_mp.height, fmt);
+	memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
+	       sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
 
-	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix_mp.field = V4L2_FIELD_NONE;
 
 	return 0;
 }
@@ -1070,8 +1076,8 @@ static int vidioc_try_fmt_vid_cap(struct
 
 	fmt = find_format(f, ctx->dev, true);
 	if (!fmt) {
-		f->fmt.pix.pixelformat = get_default_format(ctx->dev,
-							    true)->fourcc;
+		f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
+							       true)->fourcc;
 		fmt = find_format(f, ctx->dev, true);
 	}
 
@@ -1086,13 +1092,13 @@ static int vidioc_try_fmt_vid_out(struct
 
 	fmt = find_format(f, ctx->dev, false);
 	if (!fmt) {
-		f->fmt.pix.pixelformat = get_default_format(ctx->dev,
-							    false)->fourcc;
+		f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
+							       false)->fourcc;
 		fmt = find_format(f, ctx->dev, false);
 	}
 
-	if (!f->fmt.pix.colorspace)
-		f->fmt.pix.colorspace = ctx->colorspace;
+	if (!f->fmt.pix_mp.colorspace)
+		f->fmt.pix_mp.colorspace = ctx->colorspace;
 
 	return vidioc_try_fmt(ctx, f, fmt);
 }
@@ -1106,9 +1112,10 @@ static int vidioc_s_fmt(struct bcm2835_c
 	bool update_capture_port = false;
 	int ret;
 
-	v4l2_dbg(1, debug, &ctx->dev->v4l2_dev,	"Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
-		 f->type, f->fmt.pix.width, f->fmt.pix.height,
-		 f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
+	v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
+		 f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+		 f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage);
+
 
 	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
 	if (!vq)
@@ -1124,9 +1131,9 @@ static int vidioc_s_fmt(struct bcm2835_c
 	}
 
 	q_data->fmt = find_format(f, ctx->dev,
-				  f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
-	q_data->crop_width = f->fmt.pix.width;
-	q_data->height = f->fmt.pix.height;
+				  f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	q_data->crop_width = f->fmt.pix_mp.width;
+	q_data->height = f->fmt.pix_mp.height;
 	if (!q_data->selection_set)
 		q_data->crop_height = requested_height;
 
@@ -1134,21 +1141,21 @@ static int vidioc_s_fmt(struct bcm2835_c
 	 * Copying the behaviour of vicodec which retains a single set of
 	 * colorspace parameters for both input and output.
 	 */
-	ctx->colorspace = f->fmt.pix.colorspace;
-	ctx->xfer_func = f->fmt.pix.xfer_func;
-	ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
-	ctx->quant = f->fmt.pix.quantization;
+	ctx->colorspace = f->fmt.pix_mp.colorspace;
+	ctx->xfer_func = f->fmt.pix_mp.xfer_func;
+	ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+	ctx->quant = f->fmt.pix_mp.quantization;
 
 	/* All parameters should have been set correctly by try_fmt */
-	q_data->bytesperline = f->fmt.pix.bytesperline;
-	q_data->sizeimage = f->fmt.pix.sizeimage;
+	q_data->bytesperline = f->fmt.pix_mp.plane_fmt[0].bytesperline;
+	q_data->sizeimage = f->fmt.pix_mp.plane_fmt[0].sizeimage;
 
 	v4l2_dbg(1, debug, &ctx->dev->v4l2_dev,	"Calulated bpl as %u, size %u\n",
 		 q_data->bytesperline, q_data->sizeimage);
 
 	if (ctx->dev->role == DECODE &&
 	    q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
-	    f->fmt.pix.width && f->fmt.pix.height) {
+	    q_data->crop_width && q_data->height) {
 		/*
 		 * On the decoder, if provided with a resolution on the input
 		 * side, then replicate that to the output side.
@@ -1165,7 +1172,7 @@ static int vidioc_s_fmt(struct bcm2835_c
 		q_data_dst->height = ALIGN(q_data->crop_height, 16);
 
 		q_data_dst->bytesperline =
-			get_bytesperline(f->fmt.pix.width, q_data_dst->fmt);
+			get_bytesperline(f->fmt.pix_mp.width, q_data_dst->fmt);
 		q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline,
 						      q_data_dst->crop_width,
 						      q_data_dst->height,
@@ -1215,7 +1222,7 @@ static int vidioc_s_fmt(struct bcm2835_c
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
-	unsigned int height = f->fmt.pix.height;
+	unsigned int height = f->fmt.pix_mp.height;
 	int ret;
 
 	ret = vidioc_try_fmt_vid_cap(file, priv, f);
@@ -1228,7 +1235,7 @@ static int vidioc_s_fmt_vid_cap(struct f
 static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
-	unsigned int height = f->fmt.pix.height;
+	unsigned int height = f->fmt.pix_mp.height;
 	int ret;
 
 	ret = vidioc_try_fmt_vid_out(file, priv, f);
@@ -1244,7 +1251,7 @@ static int vidioc_g_selection(struct fil
 {
 	struct bcm2835_codec_ctx *ctx = file2ctx(file);
 	struct bcm2835_codec_q_data *q_data;
-	bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+	bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
 								true : false;
 
 	if ((ctx->dev->role == DECODE && !capture_queue) ||
@@ -1307,7 +1314,7 @@ static int vidioc_s_selection(struct fil
 {
 	struct bcm2835_codec_ctx *ctx = file2ctx(file);
 	struct bcm2835_codec_q_data *q_data = NULL;
-	bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+	bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
 								true : false;
 
 	v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
@@ -1368,7 +1375,7 @@ static int vidioc_s_parm(struct file *fi
 {
 	struct bcm2835_codec_ctx *ctx = file2ctx(file);
 
-	if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+	if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 		return -EINVAL;
 
 	ctx->framerate_num =
@@ -1738,15 +1745,15 @@ static int vidioc_encoder_cmd(struct fil
 static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = {
 	.vidioc_querycap	= vidioc_querycap,
 
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
-
-	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
-	.vidioc_g_fmt_vid_out	= vidioc_g_fmt_vid_out,
-	.vidioc_try_fmt_vid_out	= vidioc_try_fmt_vid_out,
-	.vidioc_s_fmt_vid_out	= vidioc_s_fmt_vid_out,
+	.vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap_mplane	= vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap_mplane	= vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap_mplane	= vidioc_s_fmt_vid_cap,
+
+	.vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out_mplane	= vidioc_g_fmt_vid_out,
+	.vidioc_try_fmt_vid_out_mplane	= vidioc_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out_mplane	= vidioc_s_fmt_vid_out,
 
 	.vidioc_reqbufs		= v4l2_m2m_ioctl_reqbufs,
 	.vidioc_querybuf	= v4l2_m2m_ioctl_querybuf,
@@ -2089,7 +2096,7 @@ static int bcm2835_codec_start_streaming
 		ctx->component_enabled = true;
 	}
 
-	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		/*
 		 * Create the EOS buffer.
 		 * We only need the MMAL part, and want to NOT attach a memory
@@ -2216,7 +2223,7 @@ static int queue_init(void *priv, struct
 	struct bcm2835_codec_ctx *ctx = priv;
 	int ret;
 
-	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
 	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	src_vq->drv_priv = ctx;
 	src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
@@ -2230,7 +2237,7 @@ static int queue_init(void *priv, struct
 	if (ret)
 		return ret;
 
-	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	dst_vq->drv_priv = ctx;
 	dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
