[media] vivid: add support for 8-bit Bayer formats

Add support for: PIX_FMT_SBGGR8, SGBRG8, SGRBG8 and SRGGB8.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c
index 7079460..9656e4d 100644
--- a/drivers/media/platform/vivid/vivid-tpg.c
+++ b/drivers/media/platform/vivid/vivid-tpg.c
@@ -181,6 +181,7 @@
 	tpg->planes = 1;
 	tpg->buffers = 1;
 	tpg->recalc_colors = true;
+	tpg->interleaved = false;
 	tpg->vdownsampling[0] = 1;
 	tpg->hdownsampling[0] = 1;
 	tpg->hmask[0] = ~0;
@@ -188,6 +189,15 @@
 	tpg->hmask[2] = ~0;
 
 	switch (fourcc) {
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SRGGB8:
+		tpg->interleaved = true;
+		tpg->vdownsampling[1] = 1;
+		tpg->hdownsampling[1] = 1;
+		tpg->planes = 2;
+		/* fall through */
 	case V4L2_PIX_FMT_RGB332:
 	case V4L2_PIX_FMT_RGB565:
 	case V4L2_PIX_FMT_RGB565X:
@@ -326,13 +336,14 @@
 	case V4L2_PIX_FMT_NV21:
 	case V4L2_PIX_FMT_NV12M:
 	case V4L2_PIX_FMT_NV21M:
-		tpg->twopixelsize[0] = 2;
-		tpg->twopixelsize[1] = 2;
-		break;
 	case V4L2_PIX_FMT_NV16:
 	case V4L2_PIX_FMT_NV61:
 	case V4L2_PIX_FMT_NV16M:
 	case V4L2_PIX_FMT_NV61M:
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SRGGB8:
 		tpg->twopixelsize[0] = 2;
 		tpg->twopixelsize[1] = 2;
 		break;
@@ -1011,6 +1022,35 @@
 		buf[0][offset + 2] = r_y;
 		buf[0][offset + 3] = alpha;
 		break;
+	case V4L2_PIX_FMT_SBGGR8:
+		buf[0][offset] = odd ? g_u : b_v;
+		buf[1][offset] = odd ? r_y : g_u;
+		break;
+	case V4L2_PIX_FMT_SGBRG8:
+		buf[0][offset] = odd ? b_v : g_u;
+		buf[1][offset] = odd ? g_u : r_y;
+		break;
+	case V4L2_PIX_FMT_SGRBG8:
+		buf[0][offset] = odd ? r_y : g_u;
+		buf[1][offset] = odd ? g_u : b_v;
+		break;
+	case V4L2_PIX_FMT_SRGGB8:
+		buf[0][offset] = odd ? g_u : r_y;
+		buf[1][offset] = odd ? b_v : g_u;
+		break;
+	}
+}
+
+unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
+{
+	switch (tpg->fourcc) {
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SRGGB8:
+		return buf_line & 1;
+	default:
+		return 0;
 	}
 }
 
@@ -1614,6 +1654,8 @@
 		basep[p][1] += h * stride / 2;
 	else if (tpg->field == V4L2_FIELD_SEQ_BT)
 		basep[p][0] += h * stride / 2;
+	if (p == 0 && tpg->interleaved)
+		tpg_calc_text_basep(tpg, basep, 1, vbuf);
 }
 
 static int tpg_pattern_avg(const struct tpg_data *tpg,
@@ -1990,6 +2032,13 @@
 			src_y++;
 		}
 
+		/*
+		 * For line-interleaved formats determine the 'plane'
+		 * based on the buffer line.
+		 */
+		if (tpg_g_interleaved(tpg))
+			p = tpg_g_interleaved_plane(tpg, buf_line);
+
 		if (tpg->vdownsampling[p] > 1) {
 			/*
 			 * When doing vertical downsampling the field setting
@@ -2036,7 +2085,7 @@
 		return;
 	}
 
-	for (i = 0; i < tpg->planes; i++) {
+	for (i = 0; i < tpg_g_planes(tpg); i++) {
 		tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
 		offset += tpg_calc_plane_size(tpg, i);
 	}
diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h
index 82ce9bf..a50cd2e 100644
--- a/drivers/media/platform/vivid/vivid-tpg.h
+++ b/drivers/media/platform/vivid/vivid-tpg.h
@@ -140,6 +140,7 @@
 	unsigned			real_rgb_range;
 	unsigned			buffers;
 	unsigned			planes;
+	bool				interleaved;
 	u8				vdownsampling[TPG_MAX_PLANES];
 	u8				hdownsampling[TPG_MAX_PLANES];
 	/*
@@ -197,6 +198,7 @@
 		u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text);
 void tpg_calc_text_basep(struct tpg_data *tpg,
 		u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf);
+unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line);
 void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
 			   unsigned p, u8 *vbuf);
 void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std,
@@ -346,7 +348,12 @@
 
 static inline unsigned tpg_g_planes(const struct tpg_data *tpg)
 {
-	return tpg->planes;
+	return tpg->interleaved ? 1 : tpg->planes;
+}
+
+static inline bool tpg_g_interleaved(const struct tpg_data *tpg)
+{
+	return tpg->interleaved;
 }
 
 static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane)
@@ -386,7 +393,7 @@
 		return;
 	}
 
-	for (p = 0; p < tpg->planes; p++) {
+	for (p = 0; p < tpg_g_planes(tpg); p++) {
 		unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0];
 
 		tpg->bytesperline[p] = plane_w / tpg->hdownsampling[p];
@@ -401,7 +408,7 @@
 
 	if (tpg->buffers > 1)
 		return tpg_g_bytesperline(tpg, plane);
-	for (p = 0; p < tpg->planes; p++) {
+	for (p = 0; p < tpg_g_planes(tpg); p++) {
 		unsigned plane_w = tpg_g_bytesperline(tpg, p);
 
 		w += plane_w / tpg->vdownsampling[p];
@@ -417,7 +424,7 @@
 
 	if (tpg->buffers > 1)
 		return bpl;
-	for (p = 0; p < tpg->planes; p++) {
+	for (p = 0; p < tpg_g_planes(tpg); p++) {
 		unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0];
 
 		plane_w /= tpg->hdownsampling[p];
@@ -428,7 +435,7 @@
 
 static inline unsigned tpg_calc_plane_size(const struct tpg_data *tpg, unsigned plane)
 {
-	if (plane >= tpg->planes)
+	if (plane >= tpg_g_planes(tpg))
 		return 0;
 
 	return tpg_g_bytesperline(tpg, plane) * tpg->buf_height /
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c
index 8f0910d..283b2e8 100644
--- a/drivers/media/platform/vivid/vivid-vid-common.c
+++ b/drivers/media/platform/vivid/vivid-vid-common.c
@@ -384,6 +384,38 @@
 		.alpha_mask = 0xff000000,
 	},
 	{
+		.name     = "Bayer BG/GR",
+		.fourcc   = V4L2_PIX_FMT_SBGGR8, /* Bayer BG/GR */
+		.vdownsampling = { 1 },
+		.bit_depth = { 8 },
+		.planes   = 1,
+		.buffers = 1,
+	},
+	{
+		.name     = "Bayer GB/RG",
+		.fourcc   = V4L2_PIX_FMT_SGBRG8, /* Bayer GB/RG */
+		.vdownsampling = { 1 },
+		.bit_depth = { 8 },
+		.planes   = 1,
+		.buffers = 1,
+	},
+	{
+		.name     = "Bayer GR/BG",
+		.fourcc   = V4L2_PIX_FMT_SGRBG8, /* Bayer GR/BG */
+		.vdownsampling = { 1 },
+		.bit_depth = { 8 },
+		.planes   = 1,
+		.buffers = 1,
+	},
+	{
+		.name     = "Bayer RG/GB",
+		.fourcc   = V4L2_PIX_FMT_SRGGB8, /* Bayer RG/GB */
+		.vdownsampling = { 1 },
+		.bit_depth = { 8 },
+		.planes   = 1,
+		.buffers = 1,
+	},
+	{
 		.name     = "4:2:2, biplanar, YUV",
 		.fourcc   = V4L2_PIX_FMT_NV16M,
 		.vdownsampling = { 1, 1 },