171414826SSergio Aguirre /*
271414826SSergio Aguirre  * TI OMAP4 ISS V4L2 Driver - ISP IPIPE module
371414826SSergio Aguirre  *
471414826SSergio Aguirre  * Copyright (C) 2012 Texas Instruments, Inc.
571414826SSergio Aguirre  *
671414826SSergio Aguirre  * Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
771414826SSergio Aguirre  *
871414826SSergio Aguirre  * This program is free software; you can redistribute it and/or modify
971414826SSergio Aguirre  * it under the terms of the GNU General Public License as published by
1071414826SSergio Aguirre  * the Free Software Foundation; either version 2 of the License, or
1171414826SSergio Aguirre  * (at your option) any later version.
1271414826SSergio Aguirre  */
1371414826SSergio Aguirre 
1471414826SSergio Aguirre #include <linux/module.h>
1571414826SSergio Aguirre #include <linux/uaccess.h>
1671414826SSergio Aguirre #include <linux/delay.h>
1771414826SSergio Aguirre #include <linux/device.h>
1871414826SSergio Aguirre #include <linux/dma-mapping.h>
1971414826SSergio Aguirre #include <linux/mm.h>
2071414826SSergio Aguirre #include <linux/sched.h>
2171414826SSergio Aguirre 
2271414826SSergio Aguirre #include "iss.h"
2371414826SSergio Aguirre #include "iss_regs.h"
2471414826SSergio Aguirre #include "iss_ipipe.h"
2571414826SSergio Aguirre 
2671414826SSergio Aguirre static struct v4l2_mbus_framefmt *
27ee8defecSPiotr S. Staszewski __ipipe_get_format(struct iss_ipipe_device *ipipe,
28ee8defecSPiotr S. Staszewski 		   struct v4l2_subdev_pad_config *cfg,
29ee8defecSPiotr S. Staszewski 		   unsigned int pad,
30ee8defecSPiotr S. Staszewski 		   enum v4l2_subdev_format_whence which);
3171414826SSergio Aguirre 
3271414826SSergio Aguirre static const unsigned int ipipe_fmts[] = {
333336f07aSBoris BREZILLON 	MEDIA_BUS_FMT_SGRBG10_1X10,
343336f07aSBoris BREZILLON 	MEDIA_BUS_FMT_SRGGB10_1X10,
353336f07aSBoris BREZILLON 	MEDIA_BUS_FMT_SBGGR10_1X10,
363336f07aSBoris BREZILLON 	MEDIA_BUS_FMT_SGBRG10_1X10,
3771414826SSergio Aguirre };
3871414826SSergio Aguirre 
3971414826SSergio Aguirre /*
4071414826SSergio Aguirre  * ipipe_print_status - Print current IPIPE Module register values.
4171414826SSergio Aguirre  * @ipipe: Pointer to ISS ISP IPIPE device.
4271414826SSergio Aguirre  *
4371414826SSergio Aguirre  * Also prints other debug information stored in the IPIPE module.
4471414826SSergio Aguirre  */
4571414826SSergio Aguirre #define IPIPE_PRINT_REGISTER(iss, name)\
4671414826SSergio Aguirre 	dev_dbg(iss->dev, "###IPIPE " #name "=0x%08x\n", \
4711abbfd3SLaurent Pinchart 		iss_reg_read(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_##name))
4871414826SSergio Aguirre 
4971414826SSergio Aguirre static void ipipe_print_status(struct iss_ipipe_device *ipipe)
5071414826SSergio Aguirre {
5171414826SSergio Aguirre 	struct iss_device *iss = to_iss_device(ipipe);
5271414826SSergio Aguirre 
5371414826SSergio Aguirre 	dev_dbg(iss->dev, "-------------IPIPE Register dump-------------\n");
5471414826SSergio Aguirre 
5571414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_EN);
5671414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_MODE);
5771414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_FMT);
5871414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_COL);
5971414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_VPS);
6071414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_VSZ);
6171414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_HPS);
6271414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_HSZ);
6371414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, GCK_MMR);
6471414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, YUV_PHS);
6571414826SSergio Aguirre 
6671414826SSergio Aguirre 	dev_dbg(iss->dev, "-----------------------------------------------\n");
6771414826SSergio Aguirre }
6871414826SSergio Aguirre 
6971414826SSergio Aguirre /*
7071414826SSergio Aguirre  * ipipe_enable - Enable/Disable IPIPE.
7171414826SSergio Aguirre  * @enable: enable flag
7271414826SSergio Aguirre  *
7371414826SSergio Aguirre  */
7471414826SSergio Aguirre static void ipipe_enable(struct iss_ipipe_device *ipipe, u8 enable)
7571414826SSergio Aguirre {
7671414826SSergio Aguirre 	struct iss_device *iss = to_iss_device(ipipe);
7771414826SSergio Aguirre 
7811abbfd3SLaurent Pinchart 	iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_EN,
7911abbfd3SLaurent Pinchart 		       IPIPE_SRC_EN_EN, enable ? IPIPE_SRC_EN_EN : 0);
8071414826SSergio Aguirre }
8171414826SSergio Aguirre 
8271414826SSergio Aguirre /* -----------------------------------------------------------------------------
8371414826SSergio Aguirre  * Format- and pipeline-related configuration helpers
8471414826SSergio Aguirre  */
8571414826SSergio Aguirre 
8671414826SSergio Aguirre static void ipipe_configure(struct iss_ipipe_device *ipipe)
8771414826SSergio Aguirre {
8871414826SSergio Aguirre 	struct iss_device *iss = to_iss_device(ipipe);
8971414826SSergio Aguirre 	struct v4l2_mbus_framefmt *format;
9071414826SSergio Aguirre 
9171414826SSergio Aguirre 	/* IPIPE_PAD_SINK */
9271414826SSergio Aguirre 	format = &ipipe->formats[IPIPE_PAD_SINK];
9371414826SSergio Aguirre 
9471414826SSergio Aguirre 	/* NOTE: Currently just supporting pipeline IN: RGB, OUT: YUV422 */
9511abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_FMT,
9611abbfd3SLaurent Pinchart 		      IPIPE_SRC_FMT_RAW2YUV);
9771414826SSergio Aguirre 
9871414826SSergio Aguirre 	/* Enable YUV444 -> YUV422 conversion */
9911abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_YUV_PHS,
10011abbfd3SLaurent Pinchart 		      IPIPE_YUV_PHS_LPF);
10171414826SSergio Aguirre 
10211abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VPS, 0);
10311abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HPS, 0);
10411abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VSZ,
10511abbfd3SLaurent Pinchart 		      (format->height - 2) & IPIPE_SRC_VSZ_MASK);
10611abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HSZ,
10711abbfd3SLaurent Pinchart 		      (format->width - 1) & IPIPE_SRC_HSZ_MASK);
10871414826SSergio Aguirre 
10971414826SSergio Aguirre 	/* Ignore ipipeif_wrt signal, and operate on-the-fly.  */
11011abbfd3SLaurent Pinchart 	iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_MODE,
11111abbfd3SLaurent Pinchart 		    IPIPE_SRC_MODE_WRT | IPIPE_SRC_MODE_OST);
11271414826SSergio Aguirre 
11371414826SSergio Aguirre 	/* HACK: Values tuned for Ducati SW (OV) */
11411abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_COL,
11511abbfd3SLaurent Pinchart 		      IPIPE_SRC_COL_EE_B | IPIPE_SRC_COL_EO_GB |
11611abbfd3SLaurent Pinchart 		      IPIPE_SRC_COL_OE_GR | IPIPE_SRC_COL_OO_R);
11771414826SSergio Aguirre 
11871414826SSergio Aguirre 	/* IPIPE_PAD_SOURCE_VP */
11971414826SSergio Aguirre 	format = &ipipe->formats[IPIPE_PAD_SOURCE_VP];
12071414826SSergio Aguirre 	/* Do nothing? */
12171414826SSergio Aguirre }
12271414826SSergio Aguirre 
12371414826SSergio Aguirre /* -----------------------------------------------------------------------------
12471414826SSergio Aguirre  * V4L2 subdev operations
12571414826SSergio Aguirre  */
12671414826SSergio Aguirre 
12771414826SSergio Aguirre /*
12871414826SSergio Aguirre  * ipipe_set_stream - Enable/Disable streaming on the IPIPE module
12971414826SSergio Aguirre  * @sd: ISP IPIPE V4L2 subdevice
13071414826SSergio Aguirre  * @enable: Enable/disable stream
13171414826SSergio Aguirre  */
13271414826SSergio Aguirre static int ipipe_set_stream(struct v4l2_subdev *sd, int enable)
13371414826SSergio Aguirre {
13471414826SSergio Aguirre 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
13571414826SSergio Aguirre 	struct iss_device *iss = to_iss_device(ipipe);
13671414826SSergio Aguirre 	int ret = 0;
13771414826SSergio Aguirre 
13871414826SSergio Aguirre 	if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) {
13971414826SSergio Aguirre 		if (enable == ISS_PIPELINE_STREAM_STOPPED)
14071414826SSergio Aguirre 			return 0;
14171414826SSergio Aguirre 
14271414826SSergio Aguirre 		omap4iss_isp_subclk_enable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE);
14371414826SSergio Aguirre 
14471414826SSergio Aguirre 		/* Enable clk_arm_g0 */
14511abbfd3SLaurent Pinchart 		iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_MMR,
14611abbfd3SLaurent Pinchart 			      IPIPE_GCK_MMR_REG);
14771414826SSergio Aguirre 
14871414826SSergio Aguirre 		/* Enable clk_pix_g[3:0] */
14911abbfd3SLaurent Pinchart 		iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_PIX,
15011abbfd3SLaurent Pinchart 			      IPIPE_GCK_PIX_G3 | IPIPE_GCK_PIX_G2 |
15111abbfd3SLaurent Pinchart 			      IPIPE_GCK_PIX_G1 | IPIPE_GCK_PIX_G0);
15271414826SSergio Aguirre 	}
15371414826SSergio Aguirre 
15471414826SSergio Aguirre 	switch (enable) {
15571414826SSergio Aguirre 	case ISS_PIPELINE_STREAM_CONTINUOUS:
15671414826SSergio Aguirre 
15771414826SSergio Aguirre 		ipipe_configure(ipipe);
15871414826SSergio Aguirre 		ipipe_print_status(ipipe);
15971414826SSergio Aguirre 
16071414826SSergio Aguirre 		atomic_set(&ipipe->stopping, 0);
16171414826SSergio Aguirre 		ipipe_enable(ipipe, 1);
16271414826SSergio Aguirre 		break;
16371414826SSergio Aguirre 
16471414826SSergio Aguirre 	case ISS_PIPELINE_STREAM_STOPPED:
16571414826SSergio Aguirre 		if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED)
16671414826SSergio Aguirre 			return 0;
16771414826SSergio Aguirre 		if (omap4iss_module_sync_idle(&sd->entity, &ipipe->wait,
16871414826SSergio Aguirre 					      &ipipe->stopping))
1696016498fSLaurent Pinchart 			ret = -ETIMEDOUT;
17071414826SSergio Aguirre 
17171414826SSergio Aguirre 		ipipe_enable(ipipe, 0);
17271414826SSergio Aguirre 		omap4iss_isp_subclk_disable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE);
17371414826SSergio Aguirre 		break;
17471414826SSergio Aguirre 	}
17571414826SSergio Aguirre 
17671414826SSergio Aguirre 	ipipe->state = enable;
17771414826SSergio Aguirre 	return ret;
17871414826SSergio Aguirre }
17971414826SSergio Aguirre 
18071414826SSergio Aguirre static struct v4l2_mbus_framefmt *
181ee8defecSPiotr S. Staszewski __ipipe_get_format(struct iss_ipipe_device *ipipe,
182ee8defecSPiotr S. Staszewski 		   struct v4l2_subdev_pad_config *cfg,
183ee8defecSPiotr S. Staszewski 		   unsigned int pad,
184ee8defecSPiotr S. Staszewski 		   enum v4l2_subdev_format_whence which)
18571414826SSergio Aguirre {
18671414826SSergio Aguirre 	if (which == V4L2_SUBDEV_FORMAT_TRY)
187f7234138SHans Verkuil 		return v4l2_subdev_get_try_format(&ipipe->subdev, cfg, pad);
188ae357388SYeliz Taneroglu 
18971414826SSergio Aguirre 	return &ipipe->formats[pad];
19071414826SSergio Aguirre }
19171414826SSergio Aguirre 
19271414826SSergio Aguirre /*
19371414826SSergio Aguirre  * ipipe_try_format - Try video format on a pad
19471414826SSergio Aguirre  * @ipipe: ISS IPIPE device
195f7234138SHans Verkuil  * @cfg: V4L2 subdev pad config
19671414826SSergio Aguirre  * @pad: Pad number
19771414826SSergio Aguirre  * @fmt: Format
19871414826SSergio Aguirre  */
19971414826SSergio Aguirre static void
200ee8defecSPiotr S. Staszewski ipipe_try_format(struct iss_ipipe_device *ipipe,
201ee8defecSPiotr S. Staszewski 		 struct v4l2_subdev_pad_config *cfg,
202ee8defecSPiotr S. Staszewski 		 unsigned int pad,
203ee8defecSPiotr S. Staszewski 		 struct v4l2_mbus_framefmt *fmt,
20471414826SSergio Aguirre 		 enum v4l2_subdev_format_whence which)
20571414826SSergio Aguirre {
20671414826SSergio Aguirre 	struct v4l2_mbus_framefmt *format;
20771414826SSergio Aguirre 	unsigned int width = fmt->width;
20871414826SSergio Aguirre 	unsigned int height = fmt->height;
20971414826SSergio Aguirre 	unsigned int i;
21071414826SSergio Aguirre 
21171414826SSergio Aguirre 	switch (pad) {
21271414826SSergio Aguirre 	case IPIPE_PAD_SINK:
21371414826SSergio Aguirre 		for (i = 0; i < ARRAY_SIZE(ipipe_fmts); i++) {
21471414826SSergio Aguirre 			if (fmt->code == ipipe_fmts[i])
21571414826SSergio Aguirre 				break;
21671414826SSergio Aguirre 		}
21771414826SSergio Aguirre 
21871414826SSergio Aguirre 		/* If not found, use SGRBG10 as default */
21971414826SSergio Aguirre 		if (i >= ARRAY_SIZE(ipipe_fmts))
2203336f07aSBoris BREZILLON 			fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
22171414826SSergio Aguirre 
22271414826SSergio Aguirre 		/* Clamp the input size. */
22371414826SSergio Aguirre 		fmt->width = clamp_t(u32, width, 1, 8192);
22471414826SSergio Aguirre 		fmt->height = clamp_t(u32, height, 1, 8192);
22571414826SSergio Aguirre 		fmt->colorspace = V4L2_COLORSPACE_SRGB;
22671414826SSergio Aguirre 		break;
22771414826SSergio Aguirre 
22871414826SSergio Aguirre 	case IPIPE_PAD_SOURCE_VP:
229f7234138SHans Verkuil 		format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SINK, which);
23071414826SSergio Aguirre 		memcpy(fmt, format, sizeof(*fmt));
23171414826SSergio Aguirre 
2323336f07aSBoris BREZILLON 		fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
23371414826SSergio Aguirre 		fmt->width = clamp_t(u32, width, 32, fmt->width);
23471414826SSergio Aguirre 		fmt->height = clamp_t(u32, height, 32, fmt->height);
23571414826SSergio Aguirre 		fmt->colorspace = V4L2_COLORSPACE_JPEG;
23671414826SSergio Aguirre 		break;
23771414826SSergio Aguirre 	}
23871414826SSergio Aguirre 
23971414826SSergio Aguirre 	fmt->field = V4L2_FIELD_NONE;
24071414826SSergio Aguirre }
24171414826SSergio Aguirre 
24271414826SSergio Aguirre /*
24371414826SSergio Aguirre  * ipipe_enum_mbus_code - Handle pixel format enumeration
24471414826SSergio Aguirre  * @sd     : pointer to v4l2 subdev structure
245f7234138SHans Verkuil  * @cfg    : V4L2 subdev pad config
24671414826SSergio Aguirre  * @code   : pointer to v4l2_subdev_mbus_code_enum structure
24771414826SSergio Aguirre  * return -EINVAL or zero on success
24871414826SSergio Aguirre  */
24971414826SSergio Aguirre static int ipipe_enum_mbus_code(struct v4l2_subdev *sd,
250f7234138SHans Verkuil 			       struct v4l2_subdev_pad_config *cfg,
25171414826SSergio Aguirre 			       struct v4l2_subdev_mbus_code_enum *code)
25271414826SSergio Aguirre {
25371414826SSergio Aguirre 	switch (code->pad) {
25471414826SSergio Aguirre 	case IPIPE_PAD_SINK:
25571414826SSergio Aguirre 		if (code->index >= ARRAY_SIZE(ipipe_fmts))
25671414826SSergio Aguirre 			return -EINVAL;
25771414826SSergio Aguirre 
25871414826SSergio Aguirre 		code->code = ipipe_fmts[code->index];
25971414826SSergio Aguirre 		break;
26071414826SSergio Aguirre 
26171414826SSergio Aguirre 	case IPIPE_PAD_SOURCE_VP:
26271414826SSergio Aguirre 		/* FIXME: Forced format conversion inside IPIPE ? */
26371414826SSergio Aguirre 		if (code->index != 0)
26471414826SSergio Aguirre 			return -EINVAL;
26571414826SSergio Aguirre 
2663336f07aSBoris BREZILLON 		code->code = MEDIA_BUS_FMT_UYVY8_1X16;
26771414826SSergio Aguirre 		break;
26871414826SSergio Aguirre 
26971414826SSergio Aguirre 	default:
27071414826SSergio Aguirre 		return -EINVAL;
27171414826SSergio Aguirre 	}
27271414826SSergio Aguirre 
27371414826SSergio Aguirre 	return 0;
27471414826SSergio Aguirre }
27571414826SSergio Aguirre 
27671414826SSergio Aguirre static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
277f7234138SHans Verkuil 				struct v4l2_subdev_pad_config *cfg,
27871414826SSergio Aguirre 				struct v4l2_subdev_frame_size_enum *fse)
27971414826SSergio Aguirre {
28071414826SSergio Aguirre 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
28171414826SSergio Aguirre 	struct v4l2_mbus_framefmt format;
28271414826SSergio Aguirre 
28371414826SSergio Aguirre 	if (fse->index != 0)
28471414826SSergio Aguirre 		return -EINVAL;
28571414826SSergio Aguirre 
28671414826SSergio Aguirre 	format.code = fse->code;
28771414826SSergio Aguirre 	format.width = 1;
28871414826SSergio Aguirre 	format.height = 1;
2895778e749SHans Verkuil 	ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which);
29071414826SSergio Aguirre 	fse->min_width = format.width;
29171414826SSergio Aguirre 	fse->min_height = format.height;
29271414826SSergio Aguirre 
29371414826SSergio Aguirre 	if (format.code != fse->code)
29471414826SSergio Aguirre 		return -EINVAL;
29571414826SSergio Aguirre 
29671414826SSergio Aguirre 	format.code = fse->code;
29771414826SSergio Aguirre 	format.width = -1;
29871414826SSergio Aguirre 	format.height = -1;
2995778e749SHans Verkuil 	ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which);
30071414826SSergio Aguirre 	fse->max_width = format.width;
30171414826SSergio Aguirre 	fse->max_height = format.height;
30271414826SSergio Aguirre 
30371414826SSergio Aguirre 	return 0;
30471414826SSergio Aguirre }
30571414826SSergio Aguirre 
30671414826SSergio Aguirre /*
30771414826SSergio Aguirre  * ipipe_get_format - Retrieve the video format on a pad
30871414826SSergio Aguirre  * @sd : ISP IPIPE V4L2 subdevice
309f7234138SHans Verkuil  * @cfg: V4L2 subdev pad config
31071414826SSergio Aguirre  * @fmt: Format
31171414826SSergio Aguirre  *
31271414826SSergio Aguirre  * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
31371414826SSergio Aguirre  * to the format type.
31471414826SSergio Aguirre  */
315ee8defecSPiotr S. Staszewski static int ipipe_get_format(struct v4l2_subdev *sd,
316ee8defecSPiotr S. Staszewski 			    struct v4l2_subdev_pad_config *cfg,
31771414826SSergio Aguirre 			    struct v4l2_subdev_format *fmt)
31871414826SSergio Aguirre {
31971414826SSergio Aguirre 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
32071414826SSergio Aguirre 	struct v4l2_mbus_framefmt *format;
32171414826SSergio Aguirre 
322f7234138SHans Verkuil 	format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which);
3239058fc92SAmarjargal Gundjalam 	if (!format)
32471414826SSergio Aguirre 		return -EINVAL;
32571414826SSergio Aguirre 
32671414826SSergio Aguirre 	fmt->format = *format;
32771414826SSergio Aguirre 	return 0;
32871414826SSergio Aguirre }
32971414826SSergio Aguirre 
33071414826SSergio Aguirre /*
33171414826SSergio Aguirre  * ipipe_set_format - Set the video format on a pad
33271414826SSergio Aguirre  * @sd : ISP IPIPE V4L2 subdevice
333f7234138SHans Verkuil  * @cfg: V4L2 subdev pad config
33471414826SSergio Aguirre  * @fmt: Format
33571414826SSergio Aguirre  *
33671414826SSergio Aguirre  * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
33771414826SSergio Aguirre  * to the format type.
33871414826SSergio Aguirre  */
339ee8defecSPiotr S. Staszewski static int ipipe_set_format(struct v4l2_subdev *sd,
340ee8defecSPiotr S. Staszewski 			    struct v4l2_subdev_pad_config *cfg,
34171414826SSergio Aguirre 			    struct v4l2_subdev_format *fmt)
34271414826SSergio Aguirre {
34371414826SSergio Aguirre 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
34471414826SSergio Aguirre 	struct v4l2_mbus_framefmt *format;
34571414826SSergio Aguirre 
346f7234138SHans Verkuil 	format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which);
3479058fc92SAmarjargal Gundjalam 	if (!format)
34871414826SSergio Aguirre 		return -EINVAL;
34971414826SSergio Aguirre 
350f7234138SHans Verkuil 	ipipe_try_format(ipipe, cfg, fmt->pad, &fmt->format, fmt->which);
35171414826SSergio Aguirre 	*format = fmt->format;
35271414826SSergio Aguirre 
35371414826SSergio Aguirre 	/* Propagate the format from sink to source */
35471414826SSergio Aguirre 	if (fmt->pad == IPIPE_PAD_SINK) {
355f7234138SHans Verkuil 		format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP,
35671414826SSergio Aguirre 					   fmt->which);
35771414826SSergio Aguirre 		*format = fmt->format;
358f7234138SHans Verkuil 		ipipe_try_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP, format,
35971414826SSergio Aguirre 				fmt->which);
36071414826SSergio Aguirre 	}
36171414826SSergio Aguirre 
36271414826SSergio Aguirre 	return 0;
36371414826SSergio Aguirre }
36471414826SSergio Aguirre 
36571414826SSergio Aguirre static int ipipe_link_validate(struct v4l2_subdev *sd, struct media_link *link,
36671414826SSergio Aguirre 				 struct v4l2_subdev_format *source_fmt,
36771414826SSergio Aguirre 				 struct v4l2_subdev_format *sink_fmt)
36871414826SSergio Aguirre {
36971414826SSergio Aguirre 	/* Check if the two ends match */
37071414826SSergio Aguirre 	if (source_fmt->format.width != sink_fmt->format.width ||
37171414826SSergio Aguirre 	    source_fmt->format.height != sink_fmt->format.height)
37271414826SSergio Aguirre 		return -EPIPE;
37371414826SSergio Aguirre 
37471414826SSergio Aguirre 	if (source_fmt->format.code != sink_fmt->format.code)
37571414826SSergio Aguirre 		return -EPIPE;
37671414826SSergio Aguirre 
37771414826SSergio Aguirre 	return 0;
37871414826SSergio Aguirre }
37971414826SSergio Aguirre 
38071414826SSergio Aguirre /*
38171414826SSergio Aguirre  * ipipe_init_formats - Initialize formats on all pads
38271414826SSergio Aguirre  * @sd: ISP IPIPE V4L2 subdevice
38371414826SSergio Aguirre  * @fh: V4L2 subdev file handle
38471414826SSergio Aguirre  *
38571414826SSergio Aguirre  * Initialize all pad formats with default values. If fh is not NULL, try
38671414826SSergio Aguirre  * formats are initialized on the file handle. Otherwise active formats are
38771414826SSergio Aguirre  * initialized on the device.
38871414826SSergio Aguirre  */
38971414826SSergio Aguirre static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
39071414826SSergio Aguirre {
39171414826SSergio Aguirre 	struct v4l2_subdev_format format;
39271414826SSergio Aguirre 
39371414826SSergio Aguirre 	memset(&format, 0, sizeof(format));
39471414826SSergio Aguirre 	format.pad = IPIPE_PAD_SINK;
39571414826SSergio Aguirre 	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
3963336f07aSBoris BREZILLON 	format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
39771414826SSergio Aguirre 	format.format.width = 4096;
39871414826SSergio Aguirre 	format.format.height = 4096;
399f7234138SHans Verkuil 	ipipe_set_format(sd, fh ? fh->pad : NULL, &format);
40071414826SSergio Aguirre 
40171414826SSergio Aguirre 	return 0;
40271414826SSergio Aguirre }
40371414826SSergio Aguirre 
40471414826SSergio Aguirre /* V4L2 subdev video operations */
40571414826SSergio Aguirre static const struct v4l2_subdev_video_ops ipipe_v4l2_video_ops = {
40671414826SSergio Aguirre 	.s_stream = ipipe_set_stream,
40771414826SSergio Aguirre };
40871414826SSergio Aguirre 
40971414826SSergio Aguirre /* V4L2 subdev pad operations */
41071414826SSergio Aguirre static const struct v4l2_subdev_pad_ops ipipe_v4l2_pad_ops = {
41171414826SSergio Aguirre 	.enum_mbus_code = ipipe_enum_mbus_code,
41271414826SSergio Aguirre 	.enum_frame_size = ipipe_enum_frame_size,
41371414826SSergio Aguirre 	.get_fmt = ipipe_get_format,
41471414826SSergio Aguirre 	.set_fmt = ipipe_set_format,
41571414826SSergio Aguirre 	.link_validate = ipipe_link_validate,
41671414826SSergio Aguirre };
41771414826SSergio Aguirre 
41871414826SSergio Aguirre /* V4L2 subdev operations */
41971414826SSergio Aguirre static const struct v4l2_subdev_ops ipipe_v4l2_ops = {
42071414826SSergio Aguirre 	.video = &ipipe_v4l2_video_ops,
42171414826SSergio Aguirre 	.pad = &ipipe_v4l2_pad_ops,
42271414826SSergio Aguirre };
42371414826SSergio Aguirre 
42471414826SSergio Aguirre /* V4L2 subdev internal operations */
42571414826SSergio Aguirre static const struct v4l2_subdev_internal_ops ipipe_v4l2_internal_ops = {
42671414826SSergio Aguirre 	.open = ipipe_init_formats,
42771414826SSergio Aguirre };
42871414826SSergio Aguirre 
42971414826SSergio Aguirre /* -----------------------------------------------------------------------------
43071414826SSergio Aguirre  * Media entity operations
43171414826SSergio Aguirre  */
43271414826SSergio Aguirre 
43371414826SSergio Aguirre /*
43471414826SSergio Aguirre  * ipipe_link_setup - Setup IPIPE connections
43571414826SSergio Aguirre  * @entity: IPIPE media entity
43671414826SSergio Aguirre  * @local: Pad at the local end of the link
43771414826SSergio Aguirre  * @remote: Pad at the remote end of the link
43871414826SSergio Aguirre  * @flags: Link flags
43971414826SSergio Aguirre  *
44071414826SSergio Aguirre  * return -EINVAL or zero on success
44171414826SSergio Aguirre  */
44271414826SSergio Aguirre static int ipipe_link_setup(struct media_entity *entity,
44371414826SSergio Aguirre 			   const struct media_pad *local,
44471414826SSergio Aguirre 			   const struct media_pad *remote, u32 flags)
44571414826SSergio Aguirre {
44671414826SSergio Aguirre 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
44771414826SSergio Aguirre 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
44871414826SSergio Aguirre 	struct iss_device *iss = to_iss_device(ipipe);
44971414826SSergio Aguirre 
45071414826SSergio Aguirre 	switch (local->index | media_entity_type(remote->entity)) {
45171414826SSergio Aguirre 	case IPIPE_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
45271414826SSergio Aguirre 		/* Read from IPIPEIF. */
45371414826SSergio Aguirre 		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
45471414826SSergio Aguirre 			ipipe->input = IPIPE_INPUT_NONE;
45571414826SSergio Aguirre 			break;
45671414826SSergio Aguirre 		}
45771414826SSergio Aguirre 
45871414826SSergio Aguirre 		if (ipipe->input != IPIPE_INPUT_NONE)
45971414826SSergio Aguirre 			return -EBUSY;
46071414826SSergio Aguirre 
46171414826SSergio Aguirre 		if (remote->entity == &iss->ipipeif.subdev.entity)
46271414826SSergio Aguirre 			ipipe->input = IPIPE_INPUT_IPIPEIF;
46371414826SSergio Aguirre 
46471414826SSergio Aguirre 		break;
46571414826SSergio Aguirre 
46671414826SSergio Aguirre 	case IPIPE_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
46771414826SSergio Aguirre 		/* Send to RESIZER */
46871414826SSergio Aguirre 		if (flags & MEDIA_LNK_FL_ENABLED) {
46971414826SSergio Aguirre 			if (ipipe->output & ~IPIPE_OUTPUT_VP)
47071414826SSergio Aguirre 				return -EBUSY;
47171414826SSergio Aguirre 			ipipe->output |= IPIPE_OUTPUT_VP;
47271414826SSergio Aguirre 		} else {
47371414826SSergio Aguirre 			ipipe->output &= ~IPIPE_OUTPUT_VP;
47471414826SSergio Aguirre 		}
47571414826SSergio Aguirre 		break;
47671414826SSergio Aguirre 
47771414826SSergio Aguirre 	default:
47871414826SSergio Aguirre 		return -EINVAL;
47971414826SSergio Aguirre 	}
48071414826SSergio Aguirre 
48171414826SSergio Aguirre 	return 0;
48271414826SSergio Aguirre }
48371414826SSergio Aguirre 
48471414826SSergio Aguirre /* media operations */
48571414826SSergio Aguirre static const struct media_entity_operations ipipe_media_ops = {
48671414826SSergio Aguirre 	.link_setup = ipipe_link_setup,
48771414826SSergio Aguirre 	.link_validate = v4l2_subdev_link_validate,
48871414826SSergio Aguirre };
48971414826SSergio Aguirre 
49071414826SSergio Aguirre /*
49171414826SSergio Aguirre  * ipipe_init_entities - Initialize V4L2 subdev and media entity
49271414826SSergio Aguirre  * @ipipe: ISS ISP IPIPE module
49371414826SSergio Aguirre  *
49471414826SSergio Aguirre  * Return 0 on success and a negative error code on failure.
49571414826SSergio Aguirre  */
49671414826SSergio Aguirre static int ipipe_init_entities(struct iss_ipipe_device *ipipe)
49771414826SSergio Aguirre {
49871414826SSergio Aguirre 	struct v4l2_subdev *sd = &ipipe->subdev;
49971414826SSergio Aguirre 	struct media_pad *pads = ipipe->pads;
50071414826SSergio Aguirre 	struct media_entity *me = &sd->entity;
50171414826SSergio Aguirre 	int ret;
50271414826SSergio Aguirre 
50371414826SSergio Aguirre 	ipipe->input = IPIPE_INPUT_NONE;
50471414826SSergio Aguirre 
50571414826SSergio Aguirre 	v4l2_subdev_init(sd, &ipipe_v4l2_ops);
50671414826SSergio Aguirre 	sd->internal_ops = &ipipe_v4l2_internal_ops;
50771414826SSergio Aguirre 	strlcpy(sd->name, "OMAP4 ISS ISP IPIPE", sizeof(sd->name));
50871414826SSergio Aguirre 	sd->grp_id = 1 << 16;	/* group ID for iss subdevs */
50971414826SSergio Aguirre 	v4l2_set_subdevdata(sd, ipipe);
51071414826SSergio Aguirre 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
51171414826SSergio Aguirre 
51271414826SSergio Aguirre 	pads[IPIPE_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
51371414826SSergio Aguirre 	pads[IPIPE_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
51471414826SSergio Aguirre 
51571414826SSergio Aguirre 	me->ops = &ipipe_media_ops;
51671414826SSergio Aguirre 	ret = media_entity_init(me, IPIPE_PADS_NUM, pads, 0);
51771414826SSergio Aguirre 	if (ret < 0)
51871414826SSergio Aguirre 		return ret;
51971414826SSergio Aguirre 
52071414826SSergio Aguirre 	ipipe_init_formats(sd, NULL);
52171414826SSergio Aguirre 
52271414826SSergio Aguirre 	return 0;
52371414826SSergio Aguirre }
52471414826SSergio Aguirre 
52571414826SSergio Aguirre void omap4iss_ipipe_unregister_entities(struct iss_ipipe_device *ipipe)
52671414826SSergio Aguirre {
52771414826SSergio Aguirre 	v4l2_device_unregister_subdev(&ipipe->subdev);
52871414826SSergio Aguirre }
52971414826SSergio Aguirre 
53071414826SSergio Aguirre int omap4iss_ipipe_register_entities(struct iss_ipipe_device *ipipe,
53171414826SSergio Aguirre 	struct v4l2_device *vdev)
53271414826SSergio Aguirre {
53371414826SSergio Aguirre 	int ret;
53471414826SSergio Aguirre 
53571414826SSergio Aguirre 	/* Register the subdev and video node. */
53671414826SSergio Aguirre 	ret = v4l2_device_register_subdev(vdev, &ipipe->subdev);
53771414826SSergio Aguirre 	if (ret < 0)
53871414826SSergio Aguirre 		goto error;
53971414826SSergio Aguirre 
54071414826SSergio Aguirre 	return 0;
54171414826SSergio Aguirre 
54271414826SSergio Aguirre error:
54371414826SSergio Aguirre 	omap4iss_ipipe_unregister_entities(ipipe);
54471414826SSergio Aguirre 	return ret;
54571414826SSergio Aguirre }
54671414826SSergio Aguirre 
54771414826SSergio Aguirre /* -----------------------------------------------------------------------------
54871414826SSergio Aguirre  * ISP IPIPE initialisation and cleanup
54971414826SSergio Aguirre  */
55071414826SSergio Aguirre 
55171414826SSergio Aguirre /*
55271414826SSergio Aguirre  * omap4iss_ipipe_init - IPIPE module initialization.
55371414826SSergio Aguirre  * @iss: Device pointer specific to the OMAP4 ISS.
55471414826SSergio Aguirre  *
55571414826SSergio Aguirre  * TODO: Get the initialisation values from platform data.
55671414826SSergio Aguirre  *
55771414826SSergio Aguirre  * Return 0 on success or a negative error code otherwise.
55871414826SSergio Aguirre  */
55971414826SSergio Aguirre int omap4iss_ipipe_init(struct iss_device *iss)
56071414826SSergio Aguirre {
56171414826SSergio Aguirre 	struct iss_ipipe_device *ipipe = &iss->ipipe;
56271414826SSergio Aguirre 
56371414826SSergio Aguirre 	ipipe->state = ISS_PIPELINE_STREAM_STOPPED;
56471414826SSergio Aguirre 	init_waitqueue_head(&ipipe->wait);
56571414826SSergio Aguirre 
56671414826SSergio Aguirre 	return ipipe_init_entities(ipipe);
56771414826SSergio Aguirre }
56871414826SSergio Aguirre 
56971414826SSergio Aguirre /*
57071414826SSergio Aguirre  * omap4iss_ipipe_cleanup - IPIPE module cleanup.
57171414826SSergio Aguirre  * @iss: Device pointer specific to the OMAP4 ISS.
57271414826SSergio Aguirre  */
57371414826SSergio Aguirre void omap4iss_ipipe_cleanup(struct iss_device *iss)
57471414826SSergio Aguirre {
5759d9104fbSLaurent Pinchart 	struct iss_ipipe_device *ipipe = &iss->ipipe;
5769d9104fbSLaurent Pinchart 
5779d9104fbSLaurent Pinchart 	media_entity_cleanup(&ipipe->subdev.entity);
57871414826SSergio Aguirre }
579