1730b0ac3SDaniel Graefe // SPDX-License-Identifier: GPL-2.0+
271414826SSergio Aguirre /*
371414826SSergio Aguirre  * TI OMAP4 ISS V4L2 Driver - ISP IPIPE module
471414826SSergio Aguirre  *
571414826SSergio Aguirre  * Copyright (C) 2012 Texas Instruments, Inc.
671414826SSergio Aguirre  *
771414826SSergio Aguirre  * Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
871414826SSergio Aguirre  */
971414826SSergio Aguirre 
1071414826SSergio Aguirre #include <linux/module.h>
1171414826SSergio Aguirre #include <linux/uaccess.h>
1271414826SSergio Aguirre #include <linux/delay.h>
1371414826SSergio Aguirre #include <linux/device.h>
1471414826SSergio Aguirre #include <linux/dma-mapping.h>
1571414826SSergio Aguirre #include <linux/mm.h>
1671414826SSergio Aguirre #include <linux/sched.h>
1771414826SSergio Aguirre 
1871414826SSergio Aguirre #include "iss.h"
1971414826SSergio Aguirre #include "iss_regs.h"
2071414826SSergio Aguirre #include "iss_ipipe.h"
2171414826SSergio Aguirre 
2271414826SSergio Aguirre static struct v4l2_mbus_framefmt *
23ee8defecSPiotr S. Staszewski __ipipe_get_format(struct iss_ipipe_device *ipipe,
24*0d346d2aSTomi Valkeinen 		   struct v4l2_subdev_state *sd_state,
25ee8defecSPiotr S. Staszewski 		   unsigned int pad,
26ee8defecSPiotr S. Staszewski 		   enum v4l2_subdev_format_whence which);
2771414826SSergio Aguirre 
2871414826SSergio Aguirre static const unsigned int ipipe_fmts[] = {
293336f07aSBoris BREZILLON 	MEDIA_BUS_FMT_SGRBG10_1X10,
303336f07aSBoris BREZILLON 	MEDIA_BUS_FMT_SRGGB10_1X10,
313336f07aSBoris BREZILLON 	MEDIA_BUS_FMT_SBGGR10_1X10,
323336f07aSBoris BREZILLON 	MEDIA_BUS_FMT_SGBRG10_1X10,
3371414826SSergio Aguirre };
3471414826SSergio Aguirre 
3571414826SSergio Aguirre /*
3671414826SSergio Aguirre  * ipipe_print_status - Print current IPIPE Module register values.
3771414826SSergio Aguirre  * @ipipe: Pointer to ISS ISP IPIPE device.
3871414826SSergio Aguirre  *
3971414826SSergio Aguirre  * Also prints other debug information stored in the IPIPE module.
4071414826SSergio Aguirre  */
4171414826SSergio Aguirre #define IPIPE_PRINT_REGISTER(iss, name)\
4271414826SSergio Aguirre 	dev_dbg(iss->dev, "###IPIPE " #name "=0x%08x\n", \
4311abbfd3SLaurent Pinchart 		iss_reg_read(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_##name))
4471414826SSergio Aguirre 
ipipe_print_status(struct iss_ipipe_device * ipipe)4571414826SSergio Aguirre static void ipipe_print_status(struct iss_ipipe_device *ipipe)
4671414826SSergio Aguirre {
4771414826SSergio Aguirre 	struct iss_device *iss = to_iss_device(ipipe);
4871414826SSergio Aguirre 
4971414826SSergio Aguirre 	dev_dbg(iss->dev, "-------------IPIPE Register dump-------------\n");
5071414826SSergio Aguirre 
5171414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_EN);
5271414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_MODE);
5371414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_FMT);
5471414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_COL);
5571414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_VPS);
5671414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_VSZ);
5771414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_HPS);
5871414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, SRC_HSZ);
5971414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, GCK_MMR);
6071414826SSergio Aguirre 	IPIPE_PRINT_REGISTER(iss, YUV_PHS);
6171414826SSergio Aguirre 
6271414826SSergio Aguirre 	dev_dbg(iss->dev, "-----------------------------------------------\n");
6371414826SSergio Aguirre }
6471414826SSergio Aguirre 
6571414826SSergio Aguirre /*
6671414826SSergio Aguirre  * ipipe_enable - Enable/Disable IPIPE.
6771414826SSergio Aguirre  * @enable: enable flag
6871414826SSergio Aguirre  *
6971414826SSergio Aguirre  */
ipipe_enable(struct iss_ipipe_device * ipipe,u8 enable)7071414826SSergio Aguirre static void ipipe_enable(struct iss_ipipe_device *ipipe, u8 enable)
7171414826SSergio Aguirre {
7271414826SSergio Aguirre 	struct iss_device *iss = to_iss_device(ipipe);
7371414826SSergio Aguirre 
7411abbfd3SLaurent Pinchart 	iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_EN,
7511abbfd3SLaurent Pinchart 		       IPIPE_SRC_EN_EN, enable ? IPIPE_SRC_EN_EN : 0);
7671414826SSergio Aguirre }
7771414826SSergio Aguirre 
7871414826SSergio Aguirre /* -----------------------------------------------------------------------------
7971414826SSergio Aguirre  * Format- and pipeline-related configuration helpers
8071414826SSergio Aguirre  */
8171414826SSergio Aguirre 
ipipe_configure(struct iss_ipipe_device * ipipe)8271414826SSergio Aguirre static void ipipe_configure(struct iss_ipipe_device *ipipe)
8371414826SSergio Aguirre {
8471414826SSergio Aguirre 	struct iss_device *iss = to_iss_device(ipipe);
8571414826SSergio Aguirre 	struct v4l2_mbus_framefmt *format;
8671414826SSergio Aguirre 
8771414826SSergio Aguirre 	/* IPIPE_PAD_SINK */
8871414826SSergio Aguirre 	format = &ipipe->formats[IPIPE_PAD_SINK];
8971414826SSergio Aguirre 
9071414826SSergio Aguirre 	/* NOTE: Currently just supporting pipeline IN: RGB, OUT: YUV422 */
9111abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_FMT,
9211abbfd3SLaurent Pinchart 		      IPIPE_SRC_FMT_RAW2YUV);
9371414826SSergio Aguirre 
9471414826SSergio Aguirre 	/* Enable YUV444 -> YUV422 conversion */
9511abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_YUV_PHS,
9611abbfd3SLaurent Pinchart 		      IPIPE_YUV_PHS_LPF);
9771414826SSergio Aguirre 
9811abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VPS, 0);
9911abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HPS, 0);
10011abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VSZ,
10111abbfd3SLaurent Pinchart 		      (format->height - 2) & IPIPE_SRC_VSZ_MASK);
10211abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HSZ,
10311abbfd3SLaurent Pinchart 		      (format->width - 1) & IPIPE_SRC_HSZ_MASK);
10471414826SSergio Aguirre 
10571414826SSergio Aguirre 	/* Ignore ipipeif_wrt signal, and operate on-the-fly.  */
10611abbfd3SLaurent Pinchart 	iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_MODE,
10711abbfd3SLaurent Pinchart 		    IPIPE_SRC_MODE_WRT | IPIPE_SRC_MODE_OST);
10871414826SSergio Aguirre 
10971414826SSergio Aguirre 	/* HACK: Values tuned for Ducati SW (OV) */
11011abbfd3SLaurent Pinchart 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_COL,
11111abbfd3SLaurent Pinchart 		      IPIPE_SRC_COL_EE_B | IPIPE_SRC_COL_EO_GB |
11211abbfd3SLaurent Pinchart 		      IPIPE_SRC_COL_OE_GR | IPIPE_SRC_COL_OO_R);
11371414826SSergio Aguirre 
11471414826SSergio Aguirre 	/* IPIPE_PAD_SOURCE_VP */
11571414826SSergio Aguirre 	format = &ipipe->formats[IPIPE_PAD_SOURCE_VP];
11671414826SSergio Aguirre 	/* Do nothing? */
11771414826SSergio Aguirre }
11871414826SSergio Aguirre 
11971414826SSergio Aguirre /* -----------------------------------------------------------------------------
12071414826SSergio Aguirre  * V4L2 subdev operations
12171414826SSergio Aguirre  */
12271414826SSergio Aguirre 
12371414826SSergio Aguirre /*
12471414826SSergio Aguirre  * ipipe_set_stream - Enable/Disable streaming on the IPIPE module
12571414826SSergio Aguirre  * @sd: ISP IPIPE V4L2 subdevice
12671414826SSergio Aguirre  * @enable: Enable/disable stream
12771414826SSergio Aguirre  */
ipipe_set_stream(struct v4l2_subdev * sd,int enable)12871414826SSergio Aguirre static int ipipe_set_stream(struct v4l2_subdev *sd, int enable)
12971414826SSergio Aguirre {
13071414826SSergio Aguirre 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
13171414826SSergio Aguirre 	struct iss_device *iss = to_iss_device(ipipe);
13271414826SSergio Aguirre 	int ret = 0;
13371414826SSergio Aguirre 
13471414826SSergio Aguirre 	if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) {
13571414826SSergio Aguirre 		if (enable == ISS_PIPELINE_STREAM_STOPPED)
13671414826SSergio Aguirre 			return 0;
13771414826SSergio Aguirre 
13871414826SSergio Aguirre 		omap4iss_isp_subclk_enable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE);
13971414826SSergio Aguirre 
14071414826SSergio Aguirre 		/* Enable clk_arm_g0 */
14111abbfd3SLaurent Pinchart 		iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_MMR,
14211abbfd3SLaurent Pinchart 			      IPIPE_GCK_MMR_REG);
14371414826SSergio Aguirre 
14471414826SSergio Aguirre 		/* Enable clk_pix_g[3:0] */
14511abbfd3SLaurent Pinchart 		iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_PIX,
14611abbfd3SLaurent Pinchart 			      IPIPE_GCK_PIX_G3 | IPIPE_GCK_PIX_G2 |
14711abbfd3SLaurent Pinchart 			      IPIPE_GCK_PIX_G1 | IPIPE_GCK_PIX_G0);
14871414826SSergio Aguirre 	}
14971414826SSergio Aguirre 
15071414826SSergio Aguirre 	switch (enable) {
15171414826SSergio Aguirre 	case ISS_PIPELINE_STREAM_CONTINUOUS:
15271414826SSergio Aguirre 
15371414826SSergio Aguirre 		ipipe_configure(ipipe);
15471414826SSergio Aguirre 		ipipe_print_status(ipipe);
15571414826SSergio Aguirre 
15671414826SSergio Aguirre 		atomic_set(&ipipe->stopping, 0);
15771414826SSergio Aguirre 		ipipe_enable(ipipe, 1);
15871414826SSergio Aguirre 		break;
15971414826SSergio Aguirre 
16071414826SSergio Aguirre 	case ISS_PIPELINE_STREAM_STOPPED:
16171414826SSergio Aguirre 		if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED)
16271414826SSergio Aguirre 			return 0;
16371414826SSergio Aguirre 		if (omap4iss_module_sync_idle(&sd->entity, &ipipe->wait,
16471414826SSergio Aguirre 					      &ipipe->stopping))
1656016498fSLaurent Pinchart 			ret = -ETIMEDOUT;
16671414826SSergio Aguirre 
16771414826SSergio Aguirre 		ipipe_enable(ipipe, 0);
16871414826SSergio Aguirre 		omap4iss_isp_subclk_disable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE);
16971414826SSergio Aguirre 		break;
17071414826SSergio Aguirre 	}
17171414826SSergio Aguirre 
17271414826SSergio Aguirre 	ipipe->state = enable;
17371414826SSergio Aguirre 	return ret;
17471414826SSergio Aguirre }
17571414826SSergio Aguirre 
17671414826SSergio Aguirre static struct v4l2_mbus_framefmt *
__ipipe_get_format(struct iss_ipipe_device * ipipe,struct v4l2_subdev_state * sd_state,unsigned int pad,enum v4l2_subdev_format_whence which)177ee8defecSPiotr S. Staszewski __ipipe_get_format(struct iss_ipipe_device *ipipe,
178*0d346d2aSTomi Valkeinen 		   struct v4l2_subdev_state *sd_state,
179ee8defecSPiotr S. Staszewski 		   unsigned int pad,
180ee8defecSPiotr S. Staszewski 		   enum v4l2_subdev_format_whence which)
18171414826SSergio Aguirre {
18271414826SSergio Aguirre 	if (which == V4L2_SUBDEV_FORMAT_TRY)
183*0d346d2aSTomi Valkeinen 		return v4l2_subdev_get_try_format(&ipipe->subdev, sd_state,
184*0d346d2aSTomi Valkeinen 						  pad);
185ae357388SYeliz Taneroglu 
18671414826SSergio Aguirre 	return &ipipe->formats[pad];
18771414826SSergio Aguirre }
18871414826SSergio Aguirre 
18971414826SSergio Aguirre /*
19071414826SSergio Aguirre  * ipipe_try_format - Try video format on a pad
19171414826SSergio Aguirre  * @ipipe: ISS IPIPE device
192f7234138SHans Verkuil  * @cfg: V4L2 subdev pad config
19371414826SSergio Aguirre  * @pad: Pad number
19471414826SSergio Aguirre  * @fmt: Format
19571414826SSergio Aguirre  */
19671414826SSergio Aguirre static void
ipipe_try_format(struct iss_ipipe_device * ipipe,struct v4l2_subdev_state * sd_state,unsigned int pad,struct v4l2_mbus_framefmt * fmt,enum v4l2_subdev_format_whence which)197ee8defecSPiotr S. Staszewski ipipe_try_format(struct iss_ipipe_device *ipipe,
198*0d346d2aSTomi Valkeinen 		 struct v4l2_subdev_state *sd_state,
199ee8defecSPiotr S. Staszewski 		 unsigned int pad,
200ee8defecSPiotr S. Staszewski 		 struct v4l2_mbus_framefmt *fmt,
20171414826SSergio Aguirre 		 enum v4l2_subdev_format_whence which)
20271414826SSergio Aguirre {
20371414826SSergio Aguirre 	struct v4l2_mbus_framefmt *format;
20471414826SSergio Aguirre 	unsigned int width = fmt->width;
20571414826SSergio Aguirre 	unsigned int height = fmt->height;
20671414826SSergio Aguirre 	unsigned int i;
20771414826SSergio Aguirre 
20871414826SSergio Aguirre 	switch (pad) {
20971414826SSergio Aguirre 	case IPIPE_PAD_SINK:
21071414826SSergio Aguirre 		for (i = 0; i < ARRAY_SIZE(ipipe_fmts); i++) {
21171414826SSergio Aguirre 			if (fmt->code == ipipe_fmts[i])
21271414826SSergio Aguirre 				break;
21371414826SSergio Aguirre 		}
21471414826SSergio Aguirre 
21571414826SSergio Aguirre 		/* If not found, use SGRBG10 as default */
21671414826SSergio Aguirre 		if (i >= ARRAY_SIZE(ipipe_fmts))
2173336f07aSBoris BREZILLON 			fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
21871414826SSergio Aguirre 
21971414826SSergio Aguirre 		/* Clamp the input size. */
22071414826SSergio Aguirre 		fmt->width = clamp_t(u32, width, 1, 8192);
22171414826SSergio Aguirre 		fmt->height = clamp_t(u32, height, 1, 8192);
22271414826SSergio Aguirre 		fmt->colorspace = V4L2_COLORSPACE_SRGB;
22371414826SSergio Aguirre 		break;
22471414826SSergio Aguirre 
22571414826SSergio Aguirre 	case IPIPE_PAD_SOURCE_VP:
226*0d346d2aSTomi Valkeinen 		format = __ipipe_get_format(ipipe, sd_state, IPIPE_PAD_SINK,
227*0d346d2aSTomi Valkeinen 					    which);
22871414826SSergio Aguirre 		memcpy(fmt, format, sizeof(*fmt));
22971414826SSergio Aguirre 
2303336f07aSBoris BREZILLON 		fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
23171414826SSergio Aguirre 		fmt->width = clamp_t(u32, width, 32, fmt->width);
23271414826SSergio Aguirre 		fmt->height = clamp_t(u32, height, 32, fmt->height);
23371414826SSergio Aguirre 		fmt->colorspace = V4L2_COLORSPACE_JPEG;
23471414826SSergio Aguirre 		break;
23571414826SSergio Aguirre 	}
23671414826SSergio Aguirre 
23771414826SSergio Aguirre 	fmt->field = V4L2_FIELD_NONE;
23871414826SSergio Aguirre }
23971414826SSergio Aguirre 
24071414826SSergio Aguirre /*
24171414826SSergio Aguirre  * ipipe_enum_mbus_code - Handle pixel format enumeration
24271414826SSergio Aguirre  * @sd     : pointer to v4l2 subdev structure
243f7234138SHans Verkuil  * @cfg    : V4L2 subdev pad config
24471414826SSergio Aguirre  * @code   : pointer to v4l2_subdev_mbus_code_enum structure
24571414826SSergio Aguirre  * return -EINVAL or zero on success
24671414826SSergio Aguirre  */
ipipe_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)24771414826SSergio Aguirre static int ipipe_enum_mbus_code(struct v4l2_subdev *sd,
248*0d346d2aSTomi Valkeinen 				struct v4l2_subdev_state *sd_state,
24971414826SSergio Aguirre 				struct v4l2_subdev_mbus_code_enum *code)
25071414826SSergio Aguirre {
25171414826SSergio Aguirre 	switch (code->pad) {
25271414826SSergio Aguirre 	case IPIPE_PAD_SINK:
25371414826SSergio Aguirre 		if (code->index >= ARRAY_SIZE(ipipe_fmts))
25471414826SSergio Aguirre 			return -EINVAL;
25571414826SSergio Aguirre 
25671414826SSergio Aguirre 		code->code = ipipe_fmts[code->index];
25771414826SSergio Aguirre 		break;
25871414826SSergio Aguirre 
25971414826SSergio Aguirre 	case IPIPE_PAD_SOURCE_VP:
26071414826SSergio Aguirre 		/* FIXME: Forced format conversion inside IPIPE ? */
26171414826SSergio Aguirre 		if (code->index != 0)
26271414826SSergio Aguirre 			return -EINVAL;
26371414826SSergio Aguirre 
2643336f07aSBoris BREZILLON 		code->code = MEDIA_BUS_FMT_UYVY8_1X16;
26571414826SSergio Aguirre 		break;
26671414826SSergio Aguirre 
26771414826SSergio Aguirre 	default:
26871414826SSergio Aguirre 		return -EINVAL;
26971414826SSergio Aguirre 	}
27071414826SSergio Aguirre 
27171414826SSergio Aguirre 	return 0;
27271414826SSergio Aguirre }
27371414826SSergio Aguirre 
ipipe_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)27471414826SSergio Aguirre static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
275*0d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
27671414826SSergio Aguirre 				 struct v4l2_subdev_frame_size_enum *fse)
27771414826SSergio Aguirre {
27871414826SSergio Aguirre 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
27971414826SSergio Aguirre 	struct v4l2_mbus_framefmt format;
28071414826SSergio Aguirre 
28171414826SSergio Aguirre 	if (fse->index != 0)
28271414826SSergio Aguirre 		return -EINVAL;
28371414826SSergio Aguirre 
28471414826SSergio Aguirre 	format.code = fse->code;
28571414826SSergio Aguirre 	format.width = 1;
28671414826SSergio Aguirre 	format.height = 1;
287*0d346d2aSTomi Valkeinen 	ipipe_try_format(ipipe, sd_state, fse->pad, &format, fse->which);
28871414826SSergio Aguirre 	fse->min_width = format.width;
28971414826SSergio Aguirre 	fse->min_height = format.height;
29071414826SSergio Aguirre 
29171414826SSergio Aguirre 	if (format.code != fse->code)
29271414826SSergio Aguirre 		return -EINVAL;
29371414826SSergio Aguirre 
29471414826SSergio Aguirre 	format.code = fse->code;
29571414826SSergio Aguirre 	format.width = -1;
29671414826SSergio Aguirre 	format.height = -1;
297*0d346d2aSTomi Valkeinen 	ipipe_try_format(ipipe, sd_state, fse->pad, &format, fse->which);
29871414826SSergio Aguirre 	fse->max_width = format.width;
29971414826SSergio Aguirre 	fse->max_height = format.height;
30071414826SSergio Aguirre 
30171414826SSergio Aguirre 	return 0;
30271414826SSergio Aguirre }
30371414826SSergio Aguirre 
30471414826SSergio Aguirre /*
30571414826SSergio Aguirre  * ipipe_get_format - Retrieve the video format on a pad
30671414826SSergio Aguirre  * @sd : ISP IPIPE V4L2 subdevice
307f7234138SHans Verkuil  * @cfg: V4L2 subdev pad config
30871414826SSergio Aguirre  * @fmt: Format
30971414826SSergio Aguirre  *
31071414826SSergio Aguirre  * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
31171414826SSergio Aguirre  * to the format type.
31271414826SSergio Aguirre  */
ipipe_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)313ee8defecSPiotr S. Staszewski static int ipipe_get_format(struct v4l2_subdev *sd,
314*0d346d2aSTomi Valkeinen 			    struct v4l2_subdev_state *sd_state,
31571414826SSergio Aguirre 			    struct v4l2_subdev_format *fmt)
31671414826SSergio Aguirre {
31771414826SSergio Aguirre 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
31871414826SSergio Aguirre 	struct v4l2_mbus_framefmt *format;
31971414826SSergio Aguirre 
320*0d346d2aSTomi Valkeinen 	format = __ipipe_get_format(ipipe, sd_state, fmt->pad, fmt->which);
3219058fc92SAmarjargal Gundjalam 	if (!format)
32271414826SSergio Aguirre 		return -EINVAL;
32371414826SSergio Aguirre 
32471414826SSergio Aguirre 	fmt->format = *format;
32571414826SSergio Aguirre 	return 0;
32671414826SSergio Aguirre }
32771414826SSergio Aguirre 
32871414826SSergio Aguirre /*
32971414826SSergio Aguirre  * ipipe_set_format - Set the video format on a pad
33071414826SSergio Aguirre  * @sd : ISP IPIPE V4L2 subdevice
331f7234138SHans Verkuil  * @cfg: V4L2 subdev pad config
33271414826SSergio Aguirre  * @fmt: Format
33371414826SSergio Aguirre  *
33471414826SSergio Aguirre  * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
33571414826SSergio Aguirre  * to the format type.
33671414826SSergio Aguirre  */
ipipe_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)337ee8defecSPiotr S. Staszewski static int ipipe_set_format(struct v4l2_subdev *sd,
338*0d346d2aSTomi Valkeinen 			    struct v4l2_subdev_state *sd_state,
33971414826SSergio Aguirre 			    struct v4l2_subdev_format *fmt)
34071414826SSergio Aguirre {
34171414826SSergio Aguirre 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
34271414826SSergio Aguirre 	struct v4l2_mbus_framefmt *format;
34371414826SSergio Aguirre 
344*0d346d2aSTomi Valkeinen 	format = __ipipe_get_format(ipipe, sd_state, fmt->pad, fmt->which);
3459058fc92SAmarjargal Gundjalam 	if (!format)
34671414826SSergio Aguirre 		return -EINVAL;
34771414826SSergio Aguirre 
348*0d346d2aSTomi Valkeinen 	ipipe_try_format(ipipe, sd_state, fmt->pad, &fmt->format, fmt->which);
34971414826SSergio Aguirre 	*format = fmt->format;
35071414826SSergio Aguirre 
35171414826SSergio Aguirre 	/* Propagate the format from sink to source */
35271414826SSergio Aguirre 	if (fmt->pad == IPIPE_PAD_SINK) {
353*0d346d2aSTomi Valkeinen 		format = __ipipe_get_format(ipipe, sd_state,
354*0d346d2aSTomi Valkeinen 					    IPIPE_PAD_SOURCE_VP,
35571414826SSergio Aguirre 					    fmt->which);
35671414826SSergio Aguirre 		*format = fmt->format;
357*0d346d2aSTomi Valkeinen 		ipipe_try_format(ipipe, sd_state, IPIPE_PAD_SOURCE_VP, format,
35871414826SSergio Aguirre 				 fmt->which);
35971414826SSergio Aguirre 	}
36071414826SSergio Aguirre 
36171414826SSergio Aguirre 	return 0;
36271414826SSergio Aguirre }
36371414826SSergio Aguirre 
ipipe_link_validate(struct v4l2_subdev * sd,struct media_link * link,struct v4l2_subdev_format * source_fmt,struct v4l2_subdev_format * sink_fmt)36471414826SSergio Aguirre static int ipipe_link_validate(struct v4l2_subdev *sd, struct media_link *link,
36571414826SSergio Aguirre 			       struct v4l2_subdev_format *source_fmt,
36671414826SSergio Aguirre 			       struct v4l2_subdev_format *sink_fmt)
36771414826SSergio Aguirre {
36871414826SSergio Aguirre 	/* Check if the two ends match */
36971414826SSergio Aguirre 	if (source_fmt->format.width != sink_fmt->format.width ||
37071414826SSergio Aguirre 	    source_fmt->format.height != sink_fmt->format.height)
37171414826SSergio Aguirre 		return -EPIPE;
37271414826SSergio Aguirre 
37371414826SSergio Aguirre 	if (source_fmt->format.code != sink_fmt->format.code)
37471414826SSergio Aguirre 		return -EPIPE;
37571414826SSergio Aguirre 
37671414826SSergio Aguirre 	return 0;
37771414826SSergio Aguirre }
37871414826SSergio Aguirre 
37971414826SSergio Aguirre /*
38071414826SSergio Aguirre  * ipipe_init_formats - Initialize formats on all pads
38171414826SSergio Aguirre  * @sd: ISP IPIPE V4L2 subdevice
38271414826SSergio Aguirre  * @fh: V4L2 subdev file handle
38371414826SSergio Aguirre  *
38471414826SSergio Aguirre  * Initialize all pad formats with default values. If fh is not NULL, try
38571414826SSergio Aguirre  * formats are initialized on the file handle. Otherwise active formats are
38671414826SSergio Aguirre  * initialized on the device.
38771414826SSergio Aguirre  */
ipipe_init_formats(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)38871414826SSergio Aguirre static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
38971414826SSergio Aguirre {
39071414826SSergio Aguirre 	struct v4l2_subdev_format format;
39171414826SSergio Aguirre 
39271414826SSergio Aguirre 	memset(&format, 0, sizeof(format));
39371414826SSergio Aguirre 	format.pad = IPIPE_PAD_SINK;
39471414826SSergio Aguirre 	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
3953336f07aSBoris BREZILLON 	format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
39671414826SSergio Aguirre 	format.format.width = 4096;
39771414826SSergio Aguirre 	format.format.height = 4096;
398*0d346d2aSTomi Valkeinen 	ipipe_set_format(sd, fh ? fh->state : NULL, &format);
39971414826SSergio Aguirre 
40071414826SSergio Aguirre 	return 0;
40171414826SSergio Aguirre }
40271414826SSergio Aguirre 
40371414826SSergio Aguirre /* V4L2 subdev video operations */
40471414826SSergio Aguirre static const struct v4l2_subdev_video_ops ipipe_v4l2_video_ops = {
40571414826SSergio Aguirre 	.s_stream = ipipe_set_stream,
40671414826SSergio Aguirre };
40771414826SSergio Aguirre 
40871414826SSergio Aguirre /* V4L2 subdev pad operations */
40971414826SSergio Aguirre static const struct v4l2_subdev_pad_ops ipipe_v4l2_pad_ops = {
41071414826SSergio Aguirre 	.enum_mbus_code = ipipe_enum_mbus_code,
41171414826SSergio Aguirre 	.enum_frame_size = ipipe_enum_frame_size,
41271414826SSergio Aguirre 	.get_fmt = ipipe_get_format,
41371414826SSergio Aguirre 	.set_fmt = ipipe_set_format,
41471414826SSergio Aguirre 	.link_validate = ipipe_link_validate,
41571414826SSergio Aguirre };
41671414826SSergio Aguirre 
41771414826SSergio Aguirre /* V4L2 subdev operations */
41871414826SSergio Aguirre static const struct v4l2_subdev_ops ipipe_v4l2_ops = {
41971414826SSergio Aguirre 	.video = &ipipe_v4l2_video_ops,
42071414826SSergio Aguirre 	.pad = &ipipe_v4l2_pad_ops,
42171414826SSergio Aguirre };
42271414826SSergio Aguirre 
42371414826SSergio Aguirre /* V4L2 subdev internal operations */
42471414826SSergio Aguirre static const struct v4l2_subdev_internal_ops ipipe_v4l2_internal_ops = {
42571414826SSergio Aguirre 	.open = ipipe_init_formats,
42671414826SSergio Aguirre };
42771414826SSergio Aguirre 
42871414826SSergio Aguirre /* -----------------------------------------------------------------------------
42971414826SSergio Aguirre  * Media entity operations
43071414826SSergio Aguirre  */
43171414826SSergio Aguirre 
43271414826SSergio Aguirre /*
43371414826SSergio Aguirre  * ipipe_link_setup - Setup IPIPE connections
43471414826SSergio Aguirre  * @entity: IPIPE media entity
43571414826SSergio Aguirre  * @local: Pad at the local end of the link
43671414826SSergio Aguirre  * @remote: Pad at the remote end of the link
43771414826SSergio Aguirre  * @flags: Link flags
43871414826SSergio Aguirre  *
43971414826SSergio Aguirre  * return -EINVAL or zero on success
44071414826SSergio Aguirre  */
ipipe_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)44171414826SSergio Aguirre static int ipipe_link_setup(struct media_entity *entity,
44271414826SSergio Aguirre 			    const struct media_pad *local,
44371414826SSergio Aguirre 			    const struct media_pad *remote, u32 flags)
44471414826SSergio Aguirre {
44571414826SSergio Aguirre 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
44671414826SSergio Aguirre 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
44771414826SSergio Aguirre 	struct iss_device *iss = to_iss_device(ipipe);
44871414826SSergio Aguirre 
449bf4178a4SMauro Carvalho Chehab 	if (!is_media_entity_v4l2_subdev(remote->entity))
450bf4178a4SMauro Carvalho Chehab 		return -EINVAL;
451bf4178a4SMauro Carvalho Chehab 
452bf4178a4SMauro Carvalho Chehab 	switch (local->index) {
453bf4178a4SMauro Carvalho Chehab 	case IPIPE_PAD_SINK:
45471414826SSergio Aguirre 		/* Read from IPIPEIF. */
45571414826SSergio Aguirre 		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
45671414826SSergio Aguirre 			ipipe->input = IPIPE_INPUT_NONE;
45771414826SSergio Aguirre 			break;
45871414826SSergio Aguirre 		}
45971414826SSergio Aguirre 
46071414826SSergio Aguirre 		if (ipipe->input != IPIPE_INPUT_NONE)
46171414826SSergio Aguirre 			return -EBUSY;
46271414826SSergio Aguirre 
46371414826SSergio Aguirre 		if (remote->entity == &iss->ipipeif.subdev.entity)
46471414826SSergio Aguirre 			ipipe->input = IPIPE_INPUT_IPIPEIF;
46571414826SSergio Aguirre 
46671414826SSergio Aguirre 		break;
46771414826SSergio Aguirre 
468bf4178a4SMauro Carvalho Chehab 	case IPIPE_PAD_SOURCE_VP:
46971414826SSergio Aguirre 		/* Send to RESIZER */
47071414826SSergio Aguirre 		if (flags & MEDIA_LNK_FL_ENABLED) {
47171414826SSergio Aguirre 			if (ipipe->output & ~IPIPE_OUTPUT_VP)
47271414826SSergio Aguirre 				return -EBUSY;
47371414826SSergio Aguirre 			ipipe->output |= IPIPE_OUTPUT_VP;
47471414826SSergio Aguirre 		} else {
47571414826SSergio Aguirre 			ipipe->output &= ~IPIPE_OUTPUT_VP;
47671414826SSergio Aguirre 		}
47771414826SSergio Aguirre 		break;
47871414826SSergio Aguirre 
47971414826SSergio Aguirre 	default:
48071414826SSergio Aguirre 		return -EINVAL;
48171414826SSergio Aguirre 	}
48271414826SSergio Aguirre 
48371414826SSergio Aguirre 	return 0;
48471414826SSergio Aguirre }
48571414826SSergio Aguirre 
48671414826SSergio Aguirre /* media operations */
48771414826SSergio Aguirre static const struct media_entity_operations ipipe_media_ops = {
48871414826SSergio Aguirre 	.link_setup = ipipe_link_setup,
48971414826SSergio Aguirre 	.link_validate = v4l2_subdev_link_validate,
49071414826SSergio Aguirre };
49171414826SSergio Aguirre 
49271414826SSergio Aguirre /*
49371414826SSergio Aguirre  * ipipe_init_entities - Initialize V4L2 subdev and media entity
49471414826SSergio Aguirre  * @ipipe: ISS ISP IPIPE module
49571414826SSergio Aguirre  *
49671414826SSergio Aguirre  * Return 0 on success and a negative error code on failure.
49771414826SSergio Aguirre  */
ipipe_init_entities(struct iss_ipipe_device * ipipe)49871414826SSergio Aguirre static int ipipe_init_entities(struct iss_ipipe_device *ipipe)
49971414826SSergio Aguirre {
50071414826SSergio Aguirre 	struct v4l2_subdev *sd = &ipipe->subdev;
50171414826SSergio Aguirre 	struct media_pad *pads = ipipe->pads;
50271414826SSergio Aguirre 	struct media_entity *me = &sd->entity;
50371414826SSergio Aguirre 	int ret;
50471414826SSergio Aguirre 
50571414826SSergio Aguirre 	ipipe->input = IPIPE_INPUT_NONE;
50671414826SSergio Aguirre 
50771414826SSergio Aguirre 	v4l2_subdev_init(sd, &ipipe_v4l2_ops);
50871414826SSergio Aguirre 	sd->internal_ops = &ipipe_v4l2_internal_ops;
509c0decac1SMauro Carvalho Chehab 	strscpy(sd->name, "OMAP4 ISS ISP IPIPE", sizeof(sd->name));
510c762efd3SArushi Singhal 	sd->grp_id = BIT(16);	/* group ID for iss subdevs */
51171414826SSergio Aguirre 	v4l2_set_subdevdata(sd, ipipe);
51271414826SSergio Aguirre 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
51371414826SSergio Aguirre 
51471414826SSergio Aguirre 	pads[IPIPE_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
51571414826SSergio Aguirre 	pads[IPIPE_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
51671414826SSergio Aguirre 
51771414826SSergio Aguirre 	me->ops = &ipipe_media_ops;
518ab22e77cSMauro Carvalho Chehab 	ret = media_entity_pads_init(me, IPIPE_PADS_NUM, pads);
51971414826SSergio Aguirre 	if (ret < 0)
52071414826SSergio Aguirre 		return ret;
52171414826SSergio Aguirre 
52271414826SSergio Aguirre 	ipipe_init_formats(sd, NULL);
52371414826SSergio Aguirre 
52471414826SSergio Aguirre 	return 0;
52571414826SSergio Aguirre }
52671414826SSergio Aguirre 
omap4iss_ipipe_unregister_entities(struct iss_ipipe_device * ipipe)52771414826SSergio Aguirre void omap4iss_ipipe_unregister_entities(struct iss_ipipe_device *ipipe)
52871414826SSergio Aguirre {
52971414826SSergio Aguirre 	v4l2_device_unregister_subdev(&ipipe->subdev);
53071414826SSergio Aguirre }
53171414826SSergio Aguirre 
omap4iss_ipipe_register_entities(struct iss_ipipe_device * ipipe,struct v4l2_device * vdev)53271414826SSergio Aguirre int omap4iss_ipipe_register_entities(struct iss_ipipe_device *ipipe,
53371414826SSergio Aguirre 				     struct v4l2_device *vdev)
53471414826SSergio Aguirre {
53571414826SSergio Aguirre 	int ret;
53671414826SSergio Aguirre 
53771414826SSergio Aguirre 	/* Register the subdev and video node. */
53871414826SSergio Aguirre 	ret = v4l2_device_register_subdev(vdev, &ipipe->subdev);
53971414826SSergio Aguirre 	if (ret < 0)
54071414826SSergio Aguirre 		goto error;
54171414826SSergio Aguirre 
54271414826SSergio Aguirre 	return 0;
54371414826SSergio Aguirre 
54471414826SSergio Aguirre error:
54571414826SSergio Aguirre 	omap4iss_ipipe_unregister_entities(ipipe);
54671414826SSergio Aguirre 	return ret;
54771414826SSergio Aguirre }
54871414826SSergio Aguirre 
54971414826SSergio Aguirre /* -----------------------------------------------------------------------------
55071414826SSergio Aguirre  * ISP IPIPE initialisation and cleanup
55171414826SSergio Aguirre  */
55271414826SSergio Aguirre 
55371414826SSergio Aguirre /*
55471414826SSergio Aguirre  * omap4iss_ipipe_init - IPIPE module initialization.
55571414826SSergio Aguirre  * @iss: Device pointer specific to the OMAP4 ISS.
55671414826SSergio Aguirre  *
55771414826SSergio Aguirre  * TODO: Get the initialisation values from platform data.
55871414826SSergio Aguirre  *
55971414826SSergio Aguirre  * Return 0 on success or a negative error code otherwise.
56071414826SSergio Aguirre  */
omap4iss_ipipe_init(struct iss_device * iss)56171414826SSergio Aguirre int omap4iss_ipipe_init(struct iss_device *iss)
56271414826SSergio Aguirre {
56371414826SSergio Aguirre 	struct iss_ipipe_device *ipipe = &iss->ipipe;
56471414826SSergio Aguirre 
56571414826SSergio Aguirre 	ipipe->state = ISS_PIPELINE_STREAM_STOPPED;
56671414826SSergio Aguirre 	init_waitqueue_head(&ipipe->wait);
56771414826SSergio Aguirre 
56871414826SSergio Aguirre 	return ipipe_init_entities(ipipe);
56971414826SSergio Aguirre }
57071414826SSergio Aguirre 
57171414826SSergio Aguirre /*
57271414826SSergio Aguirre  * omap4iss_ipipe_cleanup - IPIPE module cleanup.
57371414826SSergio Aguirre  * @iss: Device pointer specific to the OMAP4 ISS.
57471414826SSergio Aguirre  */
omap4iss_ipipe_cleanup(struct iss_device * iss)57571414826SSergio Aguirre void omap4iss_ipipe_cleanup(struct iss_device *iss)
57671414826SSergio Aguirre {
5779d9104fbSLaurent Pinchart 	struct iss_ipipe_device *ipipe = &iss->ipipe;
5789d9104fbSLaurent Pinchart 
5799d9104fbSLaurent Pinchart 	media_entity_cleanup(&ipipe->subdev.entity);
58071414826SSergio Aguirre }
581