xref: /linux/drivers/media/platform/ti/omap3isp/ispvideo.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1ceafdaacSMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0-only
2ceafdaacSMauro Carvalho Chehab /*
3ceafdaacSMauro Carvalho Chehab  * ispvideo.c
4ceafdaacSMauro Carvalho Chehab  *
5ceafdaacSMauro Carvalho Chehab  * TI OMAP3 ISP - Generic video node
6ceafdaacSMauro Carvalho Chehab  *
7ceafdaacSMauro Carvalho Chehab  * Copyright (C) 2009-2010 Nokia Corporation
8ceafdaacSMauro Carvalho Chehab  *
9ceafdaacSMauro Carvalho Chehab  * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10ceafdaacSMauro Carvalho Chehab  *	     Sakari Ailus <sakari.ailus@iki.fi>
11ceafdaacSMauro Carvalho Chehab  */
12ceafdaacSMauro Carvalho Chehab 
13ceafdaacSMauro Carvalho Chehab #include <linux/clk.h>
14ceafdaacSMauro Carvalho Chehab #include <linux/mm.h>
15ceafdaacSMauro Carvalho Chehab #include <linux/module.h>
16ceafdaacSMauro Carvalho Chehab #include <linux/pagemap.h>
17ceafdaacSMauro Carvalho Chehab #include <linux/scatterlist.h>
18ceafdaacSMauro Carvalho Chehab #include <linux/sched.h>
19ceafdaacSMauro Carvalho Chehab #include <linux/slab.h>
20ceafdaacSMauro Carvalho Chehab #include <linux/vmalloc.h>
21ceafdaacSMauro Carvalho Chehab 
22ceafdaacSMauro Carvalho Chehab #include <media/v4l2-dev.h>
23ceafdaacSMauro Carvalho Chehab #include <media/v4l2-ioctl.h>
24ceafdaacSMauro Carvalho Chehab #include <media/v4l2-mc.h>
25ceafdaacSMauro Carvalho Chehab #include <media/videobuf2-dma-contig.h>
26ceafdaacSMauro Carvalho Chehab 
27ceafdaacSMauro Carvalho Chehab #include "ispvideo.h"
28ceafdaacSMauro Carvalho Chehab #include "isp.h"
29ceafdaacSMauro Carvalho Chehab 
30ceafdaacSMauro Carvalho Chehab 
31ceafdaacSMauro Carvalho Chehab /* -----------------------------------------------------------------------------
32ceafdaacSMauro Carvalho Chehab  * Helper functions
33ceafdaacSMauro Carvalho Chehab  */
34ceafdaacSMauro Carvalho Chehab 
35ceafdaacSMauro Carvalho Chehab /*
36ceafdaacSMauro Carvalho Chehab  * NOTE: When adding new media bus codes, always remember to add
37ceafdaacSMauro Carvalho Chehab  * corresponding in-memory formats to the table below!!!
38ceafdaacSMauro Carvalho Chehab  */
39ceafdaacSMauro Carvalho Chehab static struct isp_format_info formats[] = {
40ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8,
41ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8,
42ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_GREY, 8, 1, },
43ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y10_1X10,
44ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y8_1X8,
45ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_Y10, 10, 2, },
46ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y10_1X10,
47ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y8_1X8,
48ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_Y12, 12, 2, },
49ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8,
50ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8,
51ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SBGGR8, 8, 1, },
52ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8,
53ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8,
54ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SGBRG8, 8, 1, },
55ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8,
56ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8,
57ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SGRBG8, 8, 1, },
58ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8,
59ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8,
60ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SRGGB8, 8, 1, },
61ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8,
62ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SBGGR10_1X10, 0,
63ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SBGGR10DPCM8, 8, 1, },
64ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8,
65ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SGBRG10_1X10, 0,
66ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SGBRG10DPCM8, 8, 1, },
67ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
68ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SGRBG10_1X10, 0,
69ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SGRBG10DPCM8, 8, 1, },
70ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8,
71ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SRGGB10_1X10, 0,
72ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SRGGB10DPCM8, 8, 1, },
73ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10,
74ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR8_1X8,
75ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SBGGR10, 10, 2, },
76ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10,
77ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG8_1X8,
78ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SGBRG10, 10, 2, },
79ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10,
80ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG8_1X8,
81ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SGRBG10, 10, 2, },
82ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10,
83ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB8_1X8,
84ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SRGGB10, 10, 2, },
85ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR10_1X10,
86ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR8_1X8,
87ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SBGGR12, 12, 2, },
88ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG10_1X10,
89ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG8_1X8,
90ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SGBRG12, 12, 2, },
91ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG10_1X10,
92ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG8_1X8,
93ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SGRBG12, 12, 2, },
94ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB10_1X10,
95ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB8_1X8,
96ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_SRGGB12, 12, 2, },
97ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16,
98ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_UYVY8_1X16, 0,
99ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_UYVY, 16, 2, },
100ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1X16,
101ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_YUYV8_1X16, 0,
102ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_YUYV, 16, 2, },
103ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_UYVY8_2X8,
104ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_UYVY8_2X8, 0,
105ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_UYVY, 8, 2, },
106ceafdaacSMauro Carvalho Chehab 	{ MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YUYV8_2X8,
107ceafdaacSMauro Carvalho Chehab 	  MEDIA_BUS_FMT_YUYV8_2X8, 0,
108ceafdaacSMauro Carvalho Chehab 	  V4L2_PIX_FMT_YUYV, 8, 2, },
109ceafdaacSMauro Carvalho Chehab 	/* Empty entry to catch the unsupported pixel code (0) used by the CCDC
110ceafdaacSMauro Carvalho Chehab 	 * module and avoid NULL pointer dereferences.
111ceafdaacSMauro Carvalho Chehab 	 */
112ceafdaacSMauro Carvalho Chehab 	{ 0, }
113ceafdaacSMauro Carvalho Chehab };
114ceafdaacSMauro Carvalho Chehab 
omap3isp_video_format_info(u32 code)115ceafdaacSMauro Carvalho Chehab const struct isp_format_info *omap3isp_video_format_info(u32 code)
116ceafdaacSMauro Carvalho Chehab {
117ceafdaacSMauro Carvalho Chehab 	unsigned int i;
118ceafdaacSMauro Carvalho Chehab 
119ceafdaacSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
120ceafdaacSMauro Carvalho Chehab 		if (formats[i].code == code)
121ceafdaacSMauro Carvalho Chehab 			return &formats[i];
122ceafdaacSMauro Carvalho Chehab 	}
123ceafdaacSMauro Carvalho Chehab 
124ceafdaacSMauro Carvalho Chehab 	return NULL;
125ceafdaacSMauro Carvalho Chehab }
126ceafdaacSMauro Carvalho Chehab 
127ceafdaacSMauro Carvalho Chehab /*
128ceafdaacSMauro Carvalho Chehab  * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format
129ceafdaacSMauro Carvalho Chehab  * @video: ISP video instance
130ceafdaacSMauro Carvalho Chehab  * @mbus: v4l2_mbus_framefmt format (input)
131ceafdaacSMauro Carvalho Chehab  * @pix: v4l2_pix_format format (output)
132ceafdaacSMauro Carvalho Chehab  *
133ceafdaacSMauro Carvalho Chehab  * Fill the output pix structure with information from the input mbus format.
134ceafdaacSMauro Carvalho Chehab  * The bytesperline and sizeimage fields are computed from the requested bytes
135ceafdaacSMauro Carvalho Chehab  * per line value in the pix format and information from the video instance.
136ceafdaacSMauro Carvalho Chehab  *
137ceafdaacSMauro Carvalho Chehab  * Return the number of padding bytes at end of line.
138ceafdaacSMauro Carvalho Chehab  */
isp_video_mbus_to_pix(const struct isp_video * video,const struct v4l2_mbus_framefmt * mbus,struct v4l2_pix_format * pix)139ceafdaacSMauro Carvalho Chehab static unsigned int isp_video_mbus_to_pix(const struct isp_video *video,
140ceafdaacSMauro Carvalho Chehab 					  const struct v4l2_mbus_framefmt *mbus,
141ceafdaacSMauro Carvalho Chehab 					  struct v4l2_pix_format *pix)
142ceafdaacSMauro Carvalho Chehab {
143ceafdaacSMauro Carvalho Chehab 	unsigned int bpl = pix->bytesperline;
144ceafdaacSMauro Carvalho Chehab 	unsigned int min_bpl;
145ceafdaacSMauro Carvalho Chehab 	unsigned int i;
146ceafdaacSMauro Carvalho Chehab 
147ceafdaacSMauro Carvalho Chehab 	memset(pix, 0, sizeof(*pix));
148ceafdaacSMauro Carvalho Chehab 	pix->width = mbus->width;
149ceafdaacSMauro Carvalho Chehab 	pix->height = mbus->height;
150ceafdaacSMauro Carvalho Chehab 
151ceafdaacSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
152ceafdaacSMauro Carvalho Chehab 		if (formats[i].code == mbus->code)
153ceafdaacSMauro Carvalho Chehab 			break;
154ceafdaacSMauro Carvalho Chehab 	}
155ceafdaacSMauro Carvalho Chehab 
156ceafdaacSMauro Carvalho Chehab 	if (WARN_ON(i == ARRAY_SIZE(formats)))
157ceafdaacSMauro Carvalho Chehab 		return 0;
158ceafdaacSMauro Carvalho Chehab 
159ceafdaacSMauro Carvalho Chehab 	min_bpl = pix->width * formats[i].bpp;
160ceafdaacSMauro Carvalho Chehab 
161ceafdaacSMauro Carvalho Chehab 	/* Clamp the requested bytes per line value. If the maximum bytes per
162ceafdaacSMauro Carvalho Chehab 	 * line value is zero, the module doesn't support user configurable line
163ceafdaacSMauro Carvalho Chehab 	 * sizes. Override the requested value with the minimum in that case.
164ceafdaacSMauro Carvalho Chehab 	 */
165ceafdaacSMauro Carvalho Chehab 	if (video->bpl_max)
166ceafdaacSMauro Carvalho Chehab 		bpl = clamp(bpl, min_bpl, video->bpl_max);
167ceafdaacSMauro Carvalho Chehab 	else
168ceafdaacSMauro Carvalho Chehab 		bpl = min_bpl;
169ceafdaacSMauro Carvalho Chehab 
170ceafdaacSMauro Carvalho Chehab 	if (!video->bpl_zero_padding || bpl != min_bpl)
171ceafdaacSMauro Carvalho Chehab 		bpl = ALIGN(bpl, video->bpl_alignment);
172ceafdaacSMauro Carvalho Chehab 
173ceafdaacSMauro Carvalho Chehab 	pix->pixelformat = formats[i].pixelformat;
174ceafdaacSMauro Carvalho Chehab 	pix->bytesperline = bpl;
175ceafdaacSMauro Carvalho Chehab 	pix->sizeimage = pix->bytesperline * pix->height;
176ceafdaacSMauro Carvalho Chehab 	pix->colorspace = mbus->colorspace;
177ceafdaacSMauro Carvalho Chehab 	pix->field = mbus->field;
178ceafdaacSMauro Carvalho Chehab 
179ceafdaacSMauro Carvalho Chehab 	return bpl - min_bpl;
180ceafdaacSMauro Carvalho Chehab }
181ceafdaacSMauro Carvalho Chehab 
isp_video_pix_to_mbus(const struct v4l2_pix_format * pix,struct v4l2_mbus_framefmt * mbus)182ceafdaacSMauro Carvalho Chehab static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix,
183ceafdaacSMauro Carvalho Chehab 				  struct v4l2_mbus_framefmt *mbus)
184ceafdaacSMauro Carvalho Chehab {
185ceafdaacSMauro Carvalho Chehab 	unsigned int i;
186ceafdaacSMauro Carvalho Chehab 
187ceafdaacSMauro Carvalho Chehab 	memset(mbus, 0, sizeof(*mbus));
188ceafdaacSMauro Carvalho Chehab 	mbus->width = pix->width;
189ceafdaacSMauro Carvalho Chehab 	mbus->height = pix->height;
190ceafdaacSMauro Carvalho Chehab 
191ceafdaacSMauro Carvalho Chehab 	/* Skip the last format in the loop so that it will be selected if no
192ceafdaacSMauro Carvalho Chehab 	 * match is found.
193ceafdaacSMauro Carvalho Chehab 	 */
194ceafdaacSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) {
195ceafdaacSMauro Carvalho Chehab 		if (formats[i].pixelformat == pix->pixelformat)
196ceafdaacSMauro Carvalho Chehab 			break;
197ceafdaacSMauro Carvalho Chehab 	}
198ceafdaacSMauro Carvalho Chehab 
199ceafdaacSMauro Carvalho Chehab 	mbus->code = formats[i].code;
200ceafdaacSMauro Carvalho Chehab 	mbus->colorspace = pix->colorspace;
201ceafdaacSMauro Carvalho Chehab 	mbus->field = pix->field;
202ceafdaacSMauro Carvalho Chehab }
203ceafdaacSMauro Carvalho Chehab 
204ceafdaacSMauro Carvalho Chehab static struct v4l2_subdev *
isp_video_remote_subdev(struct isp_video * video,u32 * pad)205ceafdaacSMauro Carvalho Chehab isp_video_remote_subdev(struct isp_video *video, u32 *pad)
206ceafdaacSMauro Carvalho Chehab {
207ceafdaacSMauro Carvalho Chehab 	struct media_pad *remote;
208ceafdaacSMauro Carvalho Chehab 
209b2e44430SLaurent Pinchart 	remote = media_pad_remote_pad_first(&video->pad);
210ceafdaacSMauro Carvalho Chehab 
211ceafdaacSMauro Carvalho Chehab 	if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
212ceafdaacSMauro Carvalho Chehab 		return NULL;
213ceafdaacSMauro Carvalho Chehab 
214ceafdaacSMauro Carvalho Chehab 	if (pad)
215ceafdaacSMauro Carvalho Chehab 		*pad = remote->index;
216ceafdaacSMauro Carvalho Chehab 
217ceafdaacSMauro Carvalho Chehab 	return media_entity_to_v4l2_subdev(remote->entity);
218ceafdaacSMauro Carvalho Chehab }
219ceafdaacSMauro Carvalho Chehab 
220ceafdaacSMauro Carvalho Chehab /* Return a pointer to the ISP video instance at the far end of the pipeline. */
isp_video_get_graph_data(struct isp_video * video,struct isp_pipeline * pipe)221ceafdaacSMauro Carvalho Chehab static int isp_video_get_graph_data(struct isp_video *video,
222ceafdaacSMauro Carvalho Chehab 				    struct isp_pipeline *pipe)
223ceafdaacSMauro Carvalho Chehab {
2243e8537b4SLaurent Pinchart 	struct media_pipeline_entity_iter iter;
2253e8537b4SLaurent Pinchart 	struct media_entity *entity;
226ceafdaacSMauro Carvalho Chehab 	struct isp_video *far_end = NULL;
227ceafdaacSMauro Carvalho Chehab 	int ret;
228ceafdaacSMauro Carvalho Chehab 
2293e8537b4SLaurent Pinchart 	ret = media_pipeline_entity_iter_init(&pipe->pipe, &iter);
2303e8537b4SLaurent Pinchart 	if (ret)
231ceafdaacSMauro Carvalho Chehab 		return ret;
232ceafdaacSMauro Carvalho Chehab 
2333e8537b4SLaurent Pinchart 	media_pipeline_for_each_entity(&pipe->pipe, &iter, entity) {
234ceafdaacSMauro Carvalho Chehab 		struct isp_video *__video;
235ceafdaacSMauro Carvalho Chehab 
236ceafdaacSMauro Carvalho Chehab 		media_entity_enum_set(&pipe->ent_enum, entity);
237ceafdaacSMauro Carvalho Chehab 
238ceafdaacSMauro Carvalho Chehab 		if (far_end != NULL)
239ceafdaacSMauro Carvalho Chehab 			continue;
240ceafdaacSMauro Carvalho Chehab 
241ceafdaacSMauro Carvalho Chehab 		if (entity == &video->video.entity)
242ceafdaacSMauro Carvalho Chehab 			continue;
243ceafdaacSMauro Carvalho Chehab 
244ceafdaacSMauro Carvalho Chehab 		if (!is_media_entity_v4l2_video_device(entity))
245ceafdaacSMauro Carvalho Chehab 			continue;
246ceafdaacSMauro Carvalho Chehab 
247ceafdaacSMauro Carvalho Chehab 		__video = to_isp_video(media_entity_to_video_device(entity));
248ceafdaacSMauro Carvalho Chehab 		if (__video->type != video->type)
249ceafdaacSMauro Carvalho Chehab 			far_end = __video;
250ceafdaacSMauro Carvalho Chehab 	}
251ceafdaacSMauro Carvalho Chehab 
2523e8537b4SLaurent Pinchart 	media_pipeline_entity_iter_cleanup(&iter);
253ceafdaacSMauro Carvalho Chehab 
254ceafdaacSMauro Carvalho Chehab 	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
255ceafdaacSMauro Carvalho Chehab 		pipe->input = far_end;
256ceafdaacSMauro Carvalho Chehab 		pipe->output = video;
257ceafdaacSMauro Carvalho Chehab 	} else {
258ceafdaacSMauro Carvalho Chehab 		if (far_end == NULL)
259ceafdaacSMauro Carvalho Chehab 			return -EPIPE;
260ceafdaacSMauro Carvalho Chehab 
261ceafdaacSMauro Carvalho Chehab 		pipe->input = video;
262ceafdaacSMauro Carvalho Chehab 		pipe->output = far_end;
263ceafdaacSMauro Carvalho Chehab 	}
264ceafdaacSMauro Carvalho Chehab 
265ceafdaacSMauro Carvalho Chehab 	return 0;
266ceafdaacSMauro Carvalho Chehab }
267ceafdaacSMauro Carvalho Chehab 
268ceafdaacSMauro Carvalho Chehab static int
__isp_video_get_format(struct isp_video * video,struct v4l2_format * format)269ceafdaacSMauro Carvalho Chehab __isp_video_get_format(struct isp_video *video, struct v4l2_format *format)
270ceafdaacSMauro Carvalho Chehab {
271*ecefa105SLaurent Pinchart 	struct v4l2_subdev_format fmt = {
272*ecefa105SLaurent Pinchart 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
273*ecefa105SLaurent Pinchart 	};
274ceafdaacSMauro Carvalho Chehab 	struct v4l2_subdev *subdev;
275ceafdaacSMauro Carvalho Chehab 	u32 pad;
276ceafdaacSMauro Carvalho Chehab 	int ret;
277ceafdaacSMauro Carvalho Chehab 
278ceafdaacSMauro Carvalho Chehab 	subdev = isp_video_remote_subdev(video, &pad);
279ceafdaacSMauro Carvalho Chehab 	if (subdev == NULL)
280ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
281ceafdaacSMauro Carvalho Chehab 
282ceafdaacSMauro Carvalho Chehab 	fmt.pad = pad;
283ceafdaacSMauro Carvalho Chehab 
284ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->mutex);
285ceafdaacSMauro Carvalho Chehab 	ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
286ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->mutex);
287ceafdaacSMauro Carvalho Chehab 
288ceafdaacSMauro Carvalho Chehab 	if (ret)
289ceafdaacSMauro Carvalho Chehab 		return ret;
290ceafdaacSMauro Carvalho Chehab 
291ceafdaacSMauro Carvalho Chehab 	format->type = video->type;
292ceafdaacSMauro Carvalho Chehab 	return isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
293ceafdaacSMauro Carvalho Chehab }
294ceafdaacSMauro Carvalho Chehab 
295ceafdaacSMauro Carvalho Chehab static int
isp_video_check_format(struct isp_video * video,struct isp_video_fh * vfh)296ceafdaacSMauro Carvalho Chehab isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh)
297ceafdaacSMauro Carvalho Chehab {
298ceafdaacSMauro Carvalho Chehab 	struct v4l2_format format;
299ceafdaacSMauro Carvalho Chehab 	int ret;
300ceafdaacSMauro Carvalho Chehab 
301ceafdaacSMauro Carvalho Chehab 	memcpy(&format, &vfh->format, sizeof(format));
302ceafdaacSMauro Carvalho Chehab 	ret = __isp_video_get_format(video, &format);
303ceafdaacSMauro Carvalho Chehab 	if (ret < 0)
304ceafdaacSMauro Carvalho Chehab 		return ret;
305ceafdaacSMauro Carvalho Chehab 
306ceafdaacSMauro Carvalho Chehab 	if (vfh->format.fmt.pix.pixelformat != format.fmt.pix.pixelformat ||
307ceafdaacSMauro Carvalho Chehab 	    vfh->format.fmt.pix.height != format.fmt.pix.height ||
308ceafdaacSMauro Carvalho Chehab 	    vfh->format.fmt.pix.width != format.fmt.pix.width ||
309ceafdaacSMauro Carvalho Chehab 	    vfh->format.fmt.pix.bytesperline != format.fmt.pix.bytesperline ||
310ceafdaacSMauro Carvalho Chehab 	    vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage ||
311ceafdaacSMauro Carvalho Chehab 	    vfh->format.fmt.pix.field != format.fmt.pix.field)
312ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
313ceafdaacSMauro Carvalho Chehab 
314ceafdaacSMauro Carvalho Chehab 	return 0;
315ceafdaacSMauro Carvalho Chehab }
316ceafdaacSMauro Carvalho Chehab 
317ceafdaacSMauro Carvalho Chehab /* -----------------------------------------------------------------------------
318ceafdaacSMauro Carvalho Chehab  * Video queue operations
319ceafdaacSMauro Carvalho Chehab  */
320ceafdaacSMauro Carvalho Chehab 
isp_video_queue_setup(struct vb2_queue * queue,unsigned int * count,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])321ceafdaacSMauro Carvalho Chehab static int isp_video_queue_setup(struct vb2_queue *queue,
322ceafdaacSMauro Carvalho Chehab 				 unsigned int *count, unsigned int *num_planes,
323ceafdaacSMauro Carvalho Chehab 				 unsigned int sizes[], struct device *alloc_devs[])
324ceafdaacSMauro Carvalho Chehab {
325ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = vb2_get_drv_priv(queue);
326ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = vfh->video;
327ceafdaacSMauro Carvalho Chehab 
328ceafdaacSMauro Carvalho Chehab 	*num_planes = 1;
329ceafdaacSMauro Carvalho Chehab 
330ceafdaacSMauro Carvalho Chehab 	sizes[0] = vfh->format.fmt.pix.sizeimage;
331ceafdaacSMauro Carvalho Chehab 	if (sizes[0] == 0)
332ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
333ceafdaacSMauro Carvalho Chehab 
334ceafdaacSMauro Carvalho Chehab 	*count = min(*count, video->capture_mem / PAGE_ALIGN(sizes[0]));
335ceafdaacSMauro Carvalho Chehab 
336ceafdaacSMauro Carvalho Chehab 	return 0;
337ceafdaacSMauro Carvalho Chehab }
338ceafdaacSMauro Carvalho Chehab 
isp_video_buffer_prepare(struct vb2_buffer * buf)339ceafdaacSMauro Carvalho Chehab static int isp_video_buffer_prepare(struct vb2_buffer *buf)
340ceafdaacSMauro Carvalho Chehab {
341ceafdaacSMauro Carvalho Chehab 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(buf);
342ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = vb2_get_drv_priv(buf->vb2_queue);
343ceafdaacSMauro Carvalho Chehab 	struct isp_buffer *buffer = to_isp_buffer(vbuf);
344ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = vfh->video;
345ceafdaacSMauro Carvalho Chehab 	dma_addr_t addr;
346ceafdaacSMauro Carvalho Chehab 
347ceafdaacSMauro Carvalho Chehab 	/* Refuse to prepare the buffer is the video node has registered an
348ceafdaacSMauro Carvalho Chehab 	 * error. We don't need to take any lock here as the operation is
349ceafdaacSMauro Carvalho Chehab 	 * inherently racy. The authoritative check will be performed in the
350ceafdaacSMauro Carvalho Chehab 	 * queue handler, which can't return an error, this check is just a best
351ceafdaacSMauro Carvalho Chehab 	 * effort to notify userspace as early as possible.
352ceafdaacSMauro Carvalho Chehab 	 */
353ceafdaacSMauro Carvalho Chehab 	if (unlikely(video->error))
354ceafdaacSMauro Carvalho Chehab 		return -EIO;
355ceafdaacSMauro Carvalho Chehab 
356ceafdaacSMauro Carvalho Chehab 	addr = vb2_dma_contig_plane_dma_addr(buf, 0);
357ceafdaacSMauro Carvalho Chehab 	if (!IS_ALIGNED(addr, 32)) {
358ceafdaacSMauro Carvalho Chehab 		dev_dbg(video->isp->dev,
359ceafdaacSMauro Carvalho Chehab 			"Buffer address must be aligned to 32 bytes boundary.\n");
360ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
361ceafdaacSMauro Carvalho Chehab 	}
362ceafdaacSMauro Carvalho Chehab 
363ceafdaacSMauro Carvalho Chehab 	vb2_set_plane_payload(&buffer->vb.vb2_buf, 0,
364ceafdaacSMauro Carvalho Chehab 			      vfh->format.fmt.pix.sizeimage);
365ceafdaacSMauro Carvalho Chehab 	buffer->dma = addr;
366ceafdaacSMauro Carvalho Chehab 
367ceafdaacSMauro Carvalho Chehab 	return 0;
368ceafdaacSMauro Carvalho Chehab }
369ceafdaacSMauro Carvalho Chehab 
370ceafdaacSMauro Carvalho Chehab /*
371ceafdaacSMauro Carvalho Chehab  * isp_video_buffer_queue - Add buffer to streaming queue
372ceafdaacSMauro Carvalho Chehab  * @buf: Video buffer
373ceafdaacSMauro Carvalho Chehab  *
374ceafdaacSMauro Carvalho Chehab  * In memory-to-memory mode, start streaming on the pipeline if buffers are
375ceafdaacSMauro Carvalho Chehab  * queued on both the input and the output, if the pipeline isn't already busy.
376ceafdaacSMauro Carvalho Chehab  * If the pipeline is busy, it will be restarted in the output module interrupt
377ceafdaacSMauro Carvalho Chehab  * handler.
378ceafdaacSMauro Carvalho Chehab  */
isp_video_buffer_queue(struct vb2_buffer * buf)379ceafdaacSMauro Carvalho Chehab static void isp_video_buffer_queue(struct vb2_buffer *buf)
380ceafdaacSMauro Carvalho Chehab {
381ceafdaacSMauro Carvalho Chehab 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(buf);
382ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = vb2_get_drv_priv(buf->vb2_queue);
383ceafdaacSMauro Carvalho Chehab 	struct isp_buffer *buffer = to_isp_buffer(vbuf);
384ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = vfh->video;
385ceafdaacSMauro Carvalho Chehab 	struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
386ceafdaacSMauro Carvalho Chehab 	enum isp_pipeline_state state;
387ceafdaacSMauro Carvalho Chehab 	unsigned long flags;
388ceafdaacSMauro Carvalho Chehab 	unsigned int empty;
389ceafdaacSMauro Carvalho Chehab 	unsigned int start;
390ceafdaacSMauro Carvalho Chehab 
391ceafdaacSMauro Carvalho Chehab 	spin_lock_irqsave(&video->irqlock, flags);
392ceafdaacSMauro Carvalho Chehab 
393ceafdaacSMauro Carvalho Chehab 	if (unlikely(video->error)) {
394ceafdaacSMauro Carvalho Chehab 		vb2_buffer_done(&buffer->vb.vb2_buf, VB2_BUF_STATE_ERROR);
395ceafdaacSMauro Carvalho Chehab 		spin_unlock_irqrestore(&video->irqlock, flags);
396ceafdaacSMauro Carvalho Chehab 		return;
397ceafdaacSMauro Carvalho Chehab 	}
398ceafdaacSMauro Carvalho Chehab 
399ceafdaacSMauro Carvalho Chehab 	empty = list_empty(&video->dmaqueue);
400ceafdaacSMauro Carvalho Chehab 	list_add_tail(&buffer->irqlist, &video->dmaqueue);
401ceafdaacSMauro Carvalho Chehab 
402ceafdaacSMauro Carvalho Chehab 	spin_unlock_irqrestore(&video->irqlock, flags);
403ceafdaacSMauro Carvalho Chehab 
404ceafdaacSMauro Carvalho Chehab 	if (empty) {
405ceafdaacSMauro Carvalho Chehab 		if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
406ceafdaacSMauro Carvalho Chehab 			state = ISP_PIPELINE_QUEUE_OUTPUT;
407ceafdaacSMauro Carvalho Chehab 		else
408ceafdaacSMauro Carvalho Chehab 			state = ISP_PIPELINE_QUEUE_INPUT;
409ceafdaacSMauro Carvalho Chehab 
410ceafdaacSMauro Carvalho Chehab 		spin_lock_irqsave(&pipe->lock, flags);
411ceafdaacSMauro Carvalho Chehab 		pipe->state |= state;
412ceafdaacSMauro Carvalho Chehab 		video->ops->queue(video, buffer);
413ceafdaacSMauro Carvalho Chehab 		video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;
414ceafdaacSMauro Carvalho Chehab 
415ceafdaacSMauro Carvalho Chehab 		start = isp_pipeline_ready(pipe);
416ceafdaacSMauro Carvalho Chehab 		if (start)
417ceafdaacSMauro Carvalho Chehab 			pipe->state |= ISP_PIPELINE_STREAM;
418ceafdaacSMauro Carvalho Chehab 		spin_unlock_irqrestore(&pipe->lock, flags);
419ceafdaacSMauro Carvalho Chehab 
420ceafdaacSMauro Carvalho Chehab 		if (start)
421ceafdaacSMauro Carvalho Chehab 			omap3isp_pipeline_set_stream(pipe,
422ceafdaacSMauro Carvalho Chehab 						ISP_PIPELINE_STREAM_SINGLESHOT);
423ceafdaacSMauro Carvalho Chehab 	}
424ceafdaacSMauro Carvalho Chehab }
425ceafdaacSMauro Carvalho Chehab 
426ceafdaacSMauro Carvalho Chehab /*
427ceafdaacSMauro Carvalho Chehab  * omap3isp_video_return_buffers - Return all queued buffers to videobuf2
428ceafdaacSMauro Carvalho Chehab  * @video: ISP video object
429ceafdaacSMauro Carvalho Chehab  * @state: new state for the returned buffers
430ceafdaacSMauro Carvalho Chehab  *
431ceafdaacSMauro Carvalho Chehab  * Return all buffers queued on the video node to videobuf2 in the given state.
432ceafdaacSMauro Carvalho Chehab  * The buffer state should be VB2_BUF_STATE_QUEUED if called due to an error
433ceafdaacSMauro Carvalho Chehab  * when starting the stream, or VB2_BUF_STATE_ERROR otherwise.
434ceafdaacSMauro Carvalho Chehab  *
435ceafdaacSMauro Carvalho Chehab  * The function must be called with the video irqlock held.
436ceafdaacSMauro Carvalho Chehab  */
omap3isp_video_return_buffers(struct isp_video * video,enum vb2_buffer_state state)437ceafdaacSMauro Carvalho Chehab static void omap3isp_video_return_buffers(struct isp_video *video,
438ceafdaacSMauro Carvalho Chehab 					  enum vb2_buffer_state state)
439ceafdaacSMauro Carvalho Chehab {
440ceafdaacSMauro Carvalho Chehab 	while (!list_empty(&video->dmaqueue)) {
441ceafdaacSMauro Carvalho Chehab 		struct isp_buffer *buf;
442ceafdaacSMauro Carvalho Chehab 
443ceafdaacSMauro Carvalho Chehab 		buf = list_first_entry(&video->dmaqueue,
444ceafdaacSMauro Carvalho Chehab 				       struct isp_buffer, irqlist);
445ceafdaacSMauro Carvalho Chehab 		list_del(&buf->irqlist);
446ceafdaacSMauro Carvalho Chehab 		vb2_buffer_done(&buf->vb.vb2_buf, state);
447ceafdaacSMauro Carvalho Chehab 	}
448ceafdaacSMauro Carvalho Chehab }
449ceafdaacSMauro Carvalho Chehab 
isp_video_start_streaming(struct vb2_queue * queue,unsigned int count)450ceafdaacSMauro Carvalho Chehab static int isp_video_start_streaming(struct vb2_queue *queue,
451ceafdaacSMauro Carvalho Chehab 				     unsigned int count)
452ceafdaacSMauro Carvalho Chehab {
453ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = vb2_get_drv_priv(queue);
454ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = vfh->video;
455ceafdaacSMauro Carvalho Chehab 	struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
456ceafdaacSMauro Carvalho Chehab 	unsigned long flags;
457ceafdaacSMauro Carvalho Chehab 	int ret;
458ceafdaacSMauro Carvalho Chehab 
459ceafdaacSMauro Carvalho Chehab 	/* In sensor-to-memory mode, the stream can be started synchronously
460ceafdaacSMauro Carvalho Chehab 	 * to the stream on command. In memory-to-memory mode, it will be
461ceafdaacSMauro Carvalho Chehab 	 * started when buffers are queued on both the input and output.
462ceafdaacSMauro Carvalho Chehab 	 */
463ceafdaacSMauro Carvalho Chehab 	if (pipe->input)
464ceafdaacSMauro Carvalho Chehab 		return 0;
465ceafdaacSMauro Carvalho Chehab 
466ceafdaacSMauro Carvalho Chehab 	ret = omap3isp_pipeline_set_stream(pipe,
467ceafdaacSMauro Carvalho Chehab 					   ISP_PIPELINE_STREAM_CONTINUOUS);
468ceafdaacSMauro Carvalho Chehab 	if (ret < 0) {
469ceafdaacSMauro Carvalho Chehab 		spin_lock_irqsave(&video->irqlock, flags);
470ceafdaacSMauro Carvalho Chehab 		omap3isp_video_return_buffers(video, VB2_BUF_STATE_QUEUED);
471ceafdaacSMauro Carvalho Chehab 		spin_unlock_irqrestore(&video->irqlock, flags);
472ceafdaacSMauro Carvalho Chehab 		return ret;
473ceafdaacSMauro Carvalho Chehab 	}
474ceafdaacSMauro Carvalho Chehab 
475ceafdaacSMauro Carvalho Chehab 	spin_lock_irqsave(&video->irqlock, flags);
476ceafdaacSMauro Carvalho Chehab 	if (list_empty(&video->dmaqueue))
477ceafdaacSMauro Carvalho Chehab 		video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
478ceafdaacSMauro Carvalho Chehab 	spin_unlock_irqrestore(&video->irqlock, flags);
479ceafdaacSMauro Carvalho Chehab 
480ceafdaacSMauro Carvalho Chehab 	return 0;
481ceafdaacSMauro Carvalho Chehab }
482ceafdaacSMauro Carvalho Chehab 
483ceafdaacSMauro Carvalho Chehab static const struct vb2_ops isp_video_queue_ops = {
484ceafdaacSMauro Carvalho Chehab 	.queue_setup = isp_video_queue_setup,
485ceafdaacSMauro Carvalho Chehab 	.buf_prepare = isp_video_buffer_prepare,
486ceafdaacSMauro Carvalho Chehab 	.buf_queue = isp_video_buffer_queue,
487ceafdaacSMauro Carvalho Chehab 	.start_streaming = isp_video_start_streaming,
488ceafdaacSMauro Carvalho Chehab };
489ceafdaacSMauro Carvalho Chehab 
490ceafdaacSMauro Carvalho Chehab /*
491ceafdaacSMauro Carvalho Chehab  * omap3isp_video_buffer_next - Complete the current buffer and return the next
492ceafdaacSMauro Carvalho Chehab  * @video: ISP video object
493ceafdaacSMauro Carvalho Chehab  *
494ceafdaacSMauro Carvalho Chehab  * Remove the current video buffer from the DMA queue and fill its timestamp and
495ceafdaacSMauro Carvalho Chehab  * field count before handing it back to videobuf2.
496ceafdaacSMauro Carvalho Chehab  *
497ceafdaacSMauro Carvalho Chehab  * For capture video nodes the buffer state is set to VB2_BUF_STATE_DONE if no
498ceafdaacSMauro Carvalho Chehab  * error has been flagged in the pipeline, or to VB2_BUF_STATE_ERROR otherwise.
499ceafdaacSMauro Carvalho Chehab  * For video output nodes the buffer state is always set to VB2_BUF_STATE_DONE.
500ceafdaacSMauro Carvalho Chehab  *
501ceafdaacSMauro Carvalho Chehab  * The DMA queue is expected to contain at least one buffer.
502ceafdaacSMauro Carvalho Chehab  *
503ceafdaacSMauro Carvalho Chehab  * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is
504ceafdaacSMauro Carvalho Chehab  * empty.
505ceafdaacSMauro Carvalho Chehab  */
omap3isp_video_buffer_next(struct isp_video * video)506ceafdaacSMauro Carvalho Chehab struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
507ceafdaacSMauro Carvalho Chehab {
508ceafdaacSMauro Carvalho Chehab 	struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
509ceafdaacSMauro Carvalho Chehab 	enum vb2_buffer_state vb_state;
510ceafdaacSMauro Carvalho Chehab 	struct isp_buffer *buf;
511ceafdaacSMauro Carvalho Chehab 	unsigned long flags;
512ceafdaacSMauro Carvalho Chehab 
513ceafdaacSMauro Carvalho Chehab 	spin_lock_irqsave(&video->irqlock, flags);
514ceafdaacSMauro Carvalho Chehab 	if (WARN_ON(list_empty(&video->dmaqueue))) {
515ceafdaacSMauro Carvalho Chehab 		spin_unlock_irqrestore(&video->irqlock, flags);
516ceafdaacSMauro Carvalho Chehab 		return NULL;
517ceafdaacSMauro Carvalho Chehab 	}
518ceafdaacSMauro Carvalho Chehab 
519ceafdaacSMauro Carvalho Chehab 	buf = list_first_entry(&video->dmaqueue, struct isp_buffer,
520ceafdaacSMauro Carvalho Chehab 			       irqlist);
521ceafdaacSMauro Carvalho Chehab 	list_del(&buf->irqlist);
522ceafdaacSMauro Carvalho Chehab 	spin_unlock_irqrestore(&video->irqlock, flags);
523ceafdaacSMauro Carvalho Chehab 
524ceafdaacSMauro Carvalho Chehab 	buf->vb.vb2_buf.timestamp = ktime_get_ns();
525ceafdaacSMauro Carvalho Chehab 
526ceafdaacSMauro Carvalho Chehab 	/* Do frame number propagation only if this is the output video node.
527ceafdaacSMauro Carvalho Chehab 	 * Frame number either comes from the CSI receivers or it gets
528ceafdaacSMauro Carvalho Chehab 	 * incremented here if H3A is not active.
529ceafdaacSMauro Carvalho Chehab 	 * Note: There is no guarantee that the output buffer will finish
530ceafdaacSMauro Carvalho Chehab 	 * first, so the input number might lag behind by 1 in some cases.
531ceafdaacSMauro Carvalho Chehab 	 */
532ceafdaacSMauro Carvalho Chehab 	if (video == pipe->output && !pipe->do_propagation)
533ceafdaacSMauro Carvalho Chehab 		buf->vb.sequence =
534ceafdaacSMauro Carvalho Chehab 			atomic_inc_return(&pipe->frame_number);
535ceafdaacSMauro Carvalho Chehab 	else
536ceafdaacSMauro Carvalho Chehab 		buf->vb.sequence = atomic_read(&pipe->frame_number);
537ceafdaacSMauro Carvalho Chehab 
538ceafdaacSMauro Carvalho Chehab 	if (pipe->field != V4L2_FIELD_NONE)
539ceafdaacSMauro Carvalho Chehab 		buf->vb.sequence /= 2;
540ceafdaacSMauro Carvalho Chehab 
541ceafdaacSMauro Carvalho Chehab 	buf->vb.field = pipe->field;
542ceafdaacSMauro Carvalho Chehab 
543ceafdaacSMauro Carvalho Chehab 	/* Report pipeline errors to userspace on the capture device side. */
544ceafdaacSMauro Carvalho Chehab 	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) {
545ceafdaacSMauro Carvalho Chehab 		vb_state = VB2_BUF_STATE_ERROR;
546ceafdaacSMauro Carvalho Chehab 		pipe->error = false;
547ceafdaacSMauro Carvalho Chehab 	} else {
548ceafdaacSMauro Carvalho Chehab 		vb_state = VB2_BUF_STATE_DONE;
549ceafdaacSMauro Carvalho Chehab 	}
550ceafdaacSMauro Carvalho Chehab 
551ceafdaacSMauro Carvalho Chehab 	vb2_buffer_done(&buf->vb.vb2_buf, vb_state);
552ceafdaacSMauro Carvalho Chehab 
553ceafdaacSMauro Carvalho Chehab 	spin_lock_irqsave(&video->irqlock, flags);
554ceafdaacSMauro Carvalho Chehab 
555ceafdaacSMauro Carvalho Chehab 	if (list_empty(&video->dmaqueue)) {
556ceafdaacSMauro Carvalho Chehab 		enum isp_pipeline_state state;
557ceafdaacSMauro Carvalho Chehab 
558ceafdaacSMauro Carvalho Chehab 		spin_unlock_irqrestore(&video->irqlock, flags);
559ceafdaacSMauro Carvalho Chehab 
560ceafdaacSMauro Carvalho Chehab 		if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
561ceafdaacSMauro Carvalho Chehab 			state = ISP_PIPELINE_QUEUE_OUTPUT
562ceafdaacSMauro Carvalho Chehab 			      | ISP_PIPELINE_STREAM;
563ceafdaacSMauro Carvalho Chehab 		else
564ceafdaacSMauro Carvalho Chehab 			state = ISP_PIPELINE_QUEUE_INPUT
565ceafdaacSMauro Carvalho Chehab 			      | ISP_PIPELINE_STREAM;
566ceafdaacSMauro Carvalho Chehab 
567ceafdaacSMauro Carvalho Chehab 		spin_lock_irqsave(&pipe->lock, flags);
568ceafdaacSMauro Carvalho Chehab 		pipe->state &= ~state;
569ceafdaacSMauro Carvalho Chehab 		if (video->pipe.stream_state == ISP_PIPELINE_STREAM_CONTINUOUS)
570ceafdaacSMauro Carvalho Chehab 			video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
571ceafdaacSMauro Carvalho Chehab 		spin_unlock_irqrestore(&pipe->lock, flags);
572ceafdaacSMauro Carvalho Chehab 		return NULL;
573ceafdaacSMauro Carvalho Chehab 	}
574ceafdaacSMauro Carvalho Chehab 
575ceafdaacSMauro Carvalho Chehab 	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) {
576ceafdaacSMauro Carvalho Chehab 		spin_lock(&pipe->lock);
577ceafdaacSMauro Carvalho Chehab 		pipe->state &= ~ISP_PIPELINE_STREAM;
578ceafdaacSMauro Carvalho Chehab 		spin_unlock(&pipe->lock);
579ceafdaacSMauro Carvalho Chehab 	}
580ceafdaacSMauro Carvalho Chehab 
581ceafdaacSMauro Carvalho Chehab 	buf = list_first_entry(&video->dmaqueue, struct isp_buffer,
582ceafdaacSMauro Carvalho Chehab 			       irqlist);
583ceafdaacSMauro Carvalho Chehab 
584ceafdaacSMauro Carvalho Chehab 	spin_unlock_irqrestore(&video->irqlock, flags);
585ceafdaacSMauro Carvalho Chehab 
586ceafdaacSMauro Carvalho Chehab 	return buf;
587ceafdaacSMauro Carvalho Chehab }
588ceafdaacSMauro Carvalho Chehab 
589ceafdaacSMauro Carvalho Chehab /*
590ceafdaacSMauro Carvalho Chehab  * omap3isp_video_cancel_stream - Cancel stream on a video node
591ceafdaacSMauro Carvalho Chehab  * @video: ISP video object
592ceafdaacSMauro Carvalho Chehab  *
593ceafdaacSMauro Carvalho Chehab  * Cancelling a stream returns all buffers queued on the video node to videobuf2
594ceafdaacSMauro Carvalho Chehab  * in the erroneous state and makes sure no new buffer can be queued.
595ceafdaacSMauro Carvalho Chehab  */
omap3isp_video_cancel_stream(struct isp_video * video)596ceafdaacSMauro Carvalho Chehab void omap3isp_video_cancel_stream(struct isp_video *video)
597ceafdaacSMauro Carvalho Chehab {
598ceafdaacSMauro Carvalho Chehab 	unsigned long flags;
599ceafdaacSMauro Carvalho Chehab 
600ceafdaacSMauro Carvalho Chehab 	spin_lock_irqsave(&video->irqlock, flags);
601ceafdaacSMauro Carvalho Chehab 	omap3isp_video_return_buffers(video, VB2_BUF_STATE_ERROR);
602ceafdaacSMauro Carvalho Chehab 	video->error = true;
603ceafdaacSMauro Carvalho Chehab 	spin_unlock_irqrestore(&video->irqlock, flags);
604ceafdaacSMauro Carvalho Chehab }
605ceafdaacSMauro Carvalho Chehab 
606ceafdaacSMauro Carvalho Chehab /*
607ceafdaacSMauro Carvalho Chehab  * omap3isp_video_resume - Perform resume operation on the buffers
608ceafdaacSMauro Carvalho Chehab  * @video: ISP video object
609ceafdaacSMauro Carvalho Chehab  * @continuous: Pipeline is in single shot mode if 0 or continuous mode otherwise
610ceafdaacSMauro Carvalho Chehab  *
611ceafdaacSMauro Carvalho Chehab  * This function is intended to be used on suspend/resume scenario. It
612ceafdaacSMauro Carvalho Chehab  * requests video queue layer to discard buffers marked as DONE if it's in
613ceafdaacSMauro Carvalho Chehab  * continuous mode and requests ISP modules to queue again the ACTIVE buffer
614ceafdaacSMauro Carvalho Chehab  * if there's any.
615ceafdaacSMauro Carvalho Chehab  */
omap3isp_video_resume(struct isp_video * video,int continuous)616ceafdaacSMauro Carvalho Chehab void omap3isp_video_resume(struct isp_video *video, int continuous)
617ceafdaacSMauro Carvalho Chehab {
618ceafdaacSMauro Carvalho Chehab 	struct isp_buffer *buf = NULL;
619ceafdaacSMauro Carvalho Chehab 
620ceafdaacSMauro Carvalho Chehab 	if (continuous && video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
621ceafdaacSMauro Carvalho Chehab 		mutex_lock(&video->queue_lock);
622ceafdaacSMauro Carvalho Chehab 		vb2_discard_done(video->queue);
623ceafdaacSMauro Carvalho Chehab 		mutex_unlock(&video->queue_lock);
624ceafdaacSMauro Carvalho Chehab 	}
625ceafdaacSMauro Carvalho Chehab 
626ceafdaacSMauro Carvalho Chehab 	if (!list_empty(&video->dmaqueue)) {
627ceafdaacSMauro Carvalho Chehab 		buf = list_first_entry(&video->dmaqueue,
628ceafdaacSMauro Carvalho Chehab 				       struct isp_buffer, irqlist);
629ceafdaacSMauro Carvalho Chehab 		video->ops->queue(video, buf);
630ceafdaacSMauro Carvalho Chehab 		video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;
631ceafdaacSMauro Carvalho Chehab 	} else {
632ceafdaacSMauro Carvalho Chehab 		if (continuous)
633ceafdaacSMauro Carvalho Chehab 			video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
634ceafdaacSMauro Carvalho Chehab 	}
635ceafdaacSMauro Carvalho Chehab }
636ceafdaacSMauro Carvalho Chehab 
637ceafdaacSMauro Carvalho Chehab /* -----------------------------------------------------------------------------
638ceafdaacSMauro Carvalho Chehab  * V4L2 ioctls
639ceafdaacSMauro Carvalho Chehab  */
640ceafdaacSMauro Carvalho Chehab 
641ceafdaacSMauro Carvalho Chehab static int
isp_video_querycap(struct file * file,void * fh,struct v4l2_capability * cap)642ceafdaacSMauro Carvalho Chehab isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
643ceafdaacSMauro Carvalho Chehab {
644ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
645ceafdaacSMauro Carvalho Chehab 
646ceafdaacSMauro Carvalho Chehab 	strscpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver));
647ceafdaacSMauro Carvalho Chehab 	strscpy(cap->card, video->video.name, sizeof(cap->card));
648ceafdaacSMauro Carvalho Chehab 	strscpy(cap->bus_info, "media", sizeof(cap->bus_info));
649ceafdaacSMauro Carvalho Chehab 
650ceafdaacSMauro Carvalho Chehab 	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
651ceafdaacSMauro Carvalho Chehab 		| V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
652ceafdaacSMauro Carvalho Chehab 
653ceafdaacSMauro Carvalho Chehab 
654ceafdaacSMauro Carvalho Chehab 	return 0;
655ceafdaacSMauro Carvalho Chehab }
656ceafdaacSMauro Carvalho Chehab 
657ceafdaacSMauro Carvalho Chehab static int
isp_video_get_format(struct file * file,void * fh,struct v4l2_format * format)658ceafdaacSMauro Carvalho Chehab isp_video_get_format(struct file *file, void *fh, struct v4l2_format *format)
659ceafdaacSMauro Carvalho Chehab {
660ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = to_isp_video_fh(fh);
661ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
662ceafdaacSMauro Carvalho Chehab 
663ceafdaacSMauro Carvalho Chehab 	if (format->type != video->type)
664ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
665ceafdaacSMauro Carvalho Chehab 
666ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->mutex);
667ceafdaacSMauro Carvalho Chehab 	*format = vfh->format;
668ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->mutex);
669ceafdaacSMauro Carvalho Chehab 
670ceafdaacSMauro Carvalho Chehab 	return 0;
671ceafdaacSMauro Carvalho Chehab }
672ceafdaacSMauro Carvalho Chehab 
673ceafdaacSMauro Carvalho Chehab static int
isp_video_set_format(struct file * file,void * fh,struct v4l2_format * format)674ceafdaacSMauro Carvalho Chehab isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
675ceafdaacSMauro Carvalho Chehab {
676ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = to_isp_video_fh(fh);
677ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
678ceafdaacSMauro Carvalho Chehab 	struct v4l2_mbus_framefmt fmt;
679ceafdaacSMauro Carvalho Chehab 
680ceafdaacSMauro Carvalho Chehab 	if (format->type != video->type)
681ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
682ceafdaacSMauro Carvalho Chehab 
683ceafdaacSMauro Carvalho Chehab 	/* Replace unsupported field orders with sane defaults. */
684ceafdaacSMauro Carvalho Chehab 	switch (format->fmt.pix.field) {
685ceafdaacSMauro Carvalho Chehab 	case V4L2_FIELD_NONE:
686ceafdaacSMauro Carvalho Chehab 		/* Progressive is supported everywhere. */
687ceafdaacSMauro Carvalho Chehab 		break;
688ceafdaacSMauro Carvalho Chehab 	case V4L2_FIELD_ALTERNATE:
689ceafdaacSMauro Carvalho Chehab 		/* ALTERNATE is not supported on output nodes. */
690ceafdaacSMauro Carvalho Chehab 		if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
691ceafdaacSMauro Carvalho Chehab 			format->fmt.pix.field = V4L2_FIELD_NONE;
692ceafdaacSMauro Carvalho Chehab 		break;
693ceafdaacSMauro Carvalho Chehab 	case V4L2_FIELD_INTERLACED:
694ceafdaacSMauro Carvalho Chehab 		/* The ISP has no concept of video standard, select the
695ceafdaacSMauro Carvalho Chehab 		 * top-bottom order when the unqualified interlaced order is
696ceafdaacSMauro Carvalho Chehab 		 * requested.
697ceafdaacSMauro Carvalho Chehab 		 */
698ceafdaacSMauro Carvalho Chehab 		format->fmt.pix.field = V4L2_FIELD_INTERLACED_TB;
699ceafdaacSMauro Carvalho Chehab 		fallthrough;
700ceafdaacSMauro Carvalho Chehab 	case V4L2_FIELD_INTERLACED_TB:
701ceafdaacSMauro Carvalho Chehab 	case V4L2_FIELD_INTERLACED_BT:
702ceafdaacSMauro Carvalho Chehab 		/* Interlaced orders are only supported at the CCDC output. */
703ceafdaacSMauro Carvalho Chehab 		if (video != &video->isp->isp_ccdc.video_out)
704ceafdaacSMauro Carvalho Chehab 			format->fmt.pix.field = V4L2_FIELD_NONE;
705ceafdaacSMauro Carvalho Chehab 		break;
706ceafdaacSMauro Carvalho Chehab 	case V4L2_FIELD_TOP:
707ceafdaacSMauro Carvalho Chehab 	case V4L2_FIELD_BOTTOM:
708ceafdaacSMauro Carvalho Chehab 	case V4L2_FIELD_SEQ_TB:
709ceafdaacSMauro Carvalho Chehab 	case V4L2_FIELD_SEQ_BT:
710ceafdaacSMauro Carvalho Chehab 	default:
711ceafdaacSMauro Carvalho Chehab 		/* All other field orders are currently unsupported, default to
712ceafdaacSMauro Carvalho Chehab 		 * progressive.
713ceafdaacSMauro Carvalho Chehab 		 */
714ceafdaacSMauro Carvalho Chehab 		format->fmt.pix.field = V4L2_FIELD_NONE;
715ceafdaacSMauro Carvalho Chehab 		break;
716ceafdaacSMauro Carvalho Chehab 	}
717ceafdaacSMauro Carvalho Chehab 
718ceafdaacSMauro Carvalho Chehab 	/* Fill the bytesperline and sizeimage fields by converting to media bus
719ceafdaacSMauro Carvalho Chehab 	 * format and back to pixel format.
720ceafdaacSMauro Carvalho Chehab 	 */
721ceafdaacSMauro Carvalho Chehab 	isp_video_pix_to_mbus(&format->fmt.pix, &fmt);
722ceafdaacSMauro Carvalho Chehab 	isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix);
723ceafdaacSMauro Carvalho Chehab 
724ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->mutex);
725ceafdaacSMauro Carvalho Chehab 	vfh->format = *format;
726ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->mutex);
727ceafdaacSMauro Carvalho Chehab 
728ceafdaacSMauro Carvalho Chehab 	return 0;
729ceafdaacSMauro Carvalho Chehab }
730ceafdaacSMauro Carvalho Chehab 
731ceafdaacSMauro Carvalho Chehab static int
isp_video_try_format(struct file * file,void * fh,struct v4l2_format * format)732ceafdaacSMauro Carvalho Chehab isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
733ceafdaacSMauro Carvalho Chehab {
734ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
735*ecefa105SLaurent Pinchart 	struct v4l2_subdev_format fmt = {
736*ecefa105SLaurent Pinchart 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
737*ecefa105SLaurent Pinchart 	};
738ceafdaacSMauro Carvalho Chehab 	struct v4l2_subdev *subdev;
739ceafdaacSMauro Carvalho Chehab 	u32 pad;
740ceafdaacSMauro Carvalho Chehab 	int ret;
741ceafdaacSMauro Carvalho Chehab 
742ceafdaacSMauro Carvalho Chehab 	if (format->type != video->type)
743ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
744ceafdaacSMauro Carvalho Chehab 
745ceafdaacSMauro Carvalho Chehab 	subdev = isp_video_remote_subdev(video, &pad);
746ceafdaacSMauro Carvalho Chehab 	if (subdev == NULL)
747ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
748ceafdaacSMauro Carvalho Chehab 
749ceafdaacSMauro Carvalho Chehab 	isp_video_pix_to_mbus(&format->fmt.pix, &fmt.format);
750ceafdaacSMauro Carvalho Chehab 
751ceafdaacSMauro Carvalho Chehab 	fmt.pad = pad;
752ceafdaacSMauro Carvalho Chehab 	ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
753ceafdaacSMauro Carvalho Chehab 	if (ret)
754ceafdaacSMauro Carvalho Chehab 		return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
755ceafdaacSMauro Carvalho Chehab 
756ceafdaacSMauro Carvalho Chehab 	isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
757ceafdaacSMauro Carvalho Chehab 	return 0;
758ceafdaacSMauro Carvalho Chehab }
759ceafdaacSMauro Carvalho Chehab 
760ceafdaacSMauro Carvalho Chehab static int
isp_video_get_selection(struct file * file,void * fh,struct v4l2_selection * sel)761ceafdaacSMauro Carvalho Chehab isp_video_get_selection(struct file *file, void *fh, struct v4l2_selection *sel)
762ceafdaacSMauro Carvalho Chehab {
763ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
764*ecefa105SLaurent Pinchart 	struct v4l2_subdev_format format = {
765*ecefa105SLaurent Pinchart 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
766*ecefa105SLaurent Pinchart 	};
767ceafdaacSMauro Carvalho Chehab 	struct v4l2_subdev *subdev;
768ceafdaacSMauro Carvalho Chehab 	struct v4l2_subdev_selection sdsel = {
769ceafdaacSMauro Carvalho Chehab 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
770ceafdaacSMauro Carvalho Chehab 		.target = sel->target,
771ceafdaacSMauro Carvalho Chehab 	};
772ceafdaacSMauro Carvalho Chehab 	u32 pad;
773ceafdaacSMauro Carvalho Chehab 	int ret;
774ceafdaacSMauro Carvalho Chehab 
775ceafdaacSMauro Carvalho Chehab 	switch (sel->target) {
776ceafdaacSMauro Carvalho Chehab 	case V4L2_SEL_TGT_CROP:
777ceafdaacSMauro Carvalho Chehab 	case V4L2_SEL_TGT_CROP_BOUNDS:
778ceafdaacSMauro Carvalho Chehab 	case V4L2_SEL_TGT_CROP_DEFAULT:
779ceafdaacSMauro Carvalho Chehab 		if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
780ceafdaacSMauro Carvalho Chehab 			return -EINVAL;
781ceafdaacSMauro Carvalho Chehab 		break;
782ceafdaacSMauro Carvalho Chehab 	case V4L2_SEL_TGT_COMPOSE:
783ceafdaacSMauro Carvalho Chehab 	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
784ceafdaacSMauro Carvalho Chehab 	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
785ceafdaacSMauro Carvalho Chehab 		if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
786ceafdaacSMauro Carvalho Chehab 			return -EINVAL;
787ceafdaacSMauro Carvalho Chehab 		break;
788ceafdaacSMauro Carvalho Chehab 	default:
789ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
790ceafdaacSMauro Carvalho Chehab 	}
791ceafdaacSMauro Carvalho Chehab 	subdev = isp_video_remote_subdev(video, &pad);
792ceafdaacSMauro Carvalho Chehab 	if (subdev == NULL)
793ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
794ceafdaacSMauro Carvalho Chehab 
795ceafdaacSMauro Carvalho Chehab 	/* Try the get selection operation first and fallback to get format if not
796ceafdaacSMauro Carvalho Chehab 	 * implemented.
797ceafdaacSMauro Carvalho Chehab 	 */
798ceafdaacSMauro Carvalho Chehab 	sdsel.pad = pad;
799ceafdaacSMauro Carvalho Chehab 	ret = v4l2_subdev_call(subdev, pad, get_selection, NULL, &sdsel);
800ceafdaacSMauro Carvalho Chehab 	if (!ret)
801ceafdaacSMauro Carvalho Chehab 		sel->r = sdsel.r;
802ceafdaacSMauro Carvalho Chehab 	if (ret != -ENOIOCTLCMD)
803ceafdaacSMauro Carvalho Chehab 		return ret;
804ceafdaacSMauro Carvalho Chehab 
805ceafdaacSMauro Carvalho Chehab 	format.pad = pad;
806ceafdaacSMauro Carvalho Chehab 	ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format);
807ceafdaacSMauro Carvalho Chehab 	if (ret < 0)
808ceafdaacSMauro Carvalho Chehab 		return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
809ceafdaacSMauro Carvalho Chehab 
810ceafdaacSMauro Carvalho Chehab 	sel->r.left = 0;
811ceafdaacSMauro Carvalho Chehab 	sel->r.top = 0;
812ceafdaacSMauro Carvalho Chehab 	sel->r.width = format.format.width;
813ceafdaacSMauro Carvalho Chehab 	sel->r.height = format.format.height;
814ceafdaacSMauro Carvalho Chehab 
815ceafdaacSMauro Carvalho Chehab 	return 0;
816ceafdaacSMauro Carvalho Chehab }
817ceafdaacSMauro Carvalho Chehab 
818ceafdaacSMauro Carvalho Chehab static int
isp_video_set_selection(struct file * file,void * fh,struct v4l2_selection * sel)819ceafdaacSMauro Carvalho Chehab isp_video_set_selection(struct file *file, void *fh, struct v4l2_selection *sel)
820ceafdaacSMauro Carvalho Chehab {
821ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
822ceafdaacSMauro Carvalho Chehab 	struct v4l2_subdev *subdev;
823ceafdaacSMauro Carvalho Chehab 	struct v4l2_subdev_selection sdsel = {
824ceafdaacSMauro Carvalho Chehab 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
825ceafdaacSMauro Carvalho Chehab 		.target = sel->target,
826ceafdaacSMauro Carvalho Chehab 		.flags = sel->flags,
827ceafdaacSMauro Carvalho Chehab 		.r = sel->r,
828ceafdaacSMauro Carvalho Chehab 	};
829ceafdaacSMauro Carvalho Chehab 	u32 pad;
830ceafdaacSMauro Carvalho Chehab 	int ret;
831ceafdaacSMauro Carvalho Chehab 
832ceafdaacSMauro Carvalho Chehab 	switch (sel->target) {
833ceafdaacSMauro Carvalho Chehab 	case V4L2_SEL_TGT_CROP:
834ceafdaacSMauro Carvalho Chehab 		if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
835ceafdaacSMauro Carvalho Chehab 			return -EINVAL;
836ceafdaacSMauro Carvalho Chehab 		break;
837ceafdaacSMauro Carvalho Chehab 	case V4L2_SEL_TGT_COMPOSE:
838ceafdaacSMauro Carvalho Chehab 		if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
839ceafdaacSMauro Carvalho Chehab 			return -EINVAL;
840ceafdaacSMauro Carvalho Chehab 		break;
841ceafdaacSMauro Carvalho Chehab 	default:
842ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
843ceafdaacSMauro Carvalho Chehab 	}
844ceafdaacSMauro Carvalho Chehab 	subdev = isp_video_remote_subdev(video, &pad);
845ceafdaacSMauro Carvalho Chehab 	if (subdev == NULL)
846ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
847ceafdaacSMauro Carvalho Chehab 
848ceafdaacSMauro Carvalho Chehab 	sdsel.pad = pad;
849ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->mutex);
850ceafdaacSMauro Carvalho Chehab 	ret = v4l2_subdev_call(subdev, pad, set_selection, NULL, &sdsel);
851ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->mutex);
852ceafdaacSMauro Carvalho Chehab 	if (!ret)
853ceafdaacSMauro Carvalho Chehab 		sel->r = sdsel.r;
854ceafdaacSMauro Carvalho Chehab 
855ceafdaacSMauro Carvalho Chehab 	return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
856ceafdaacSMauro Carvalho Chehab }
857ceafdaacSMauro Carvalho Chehab 
858ceafdaacSMauro Carvalho Chehab static int
isp_video_get_param(struct file * file,void * fh,struct v4l2_streamparm * a)859ceafdaacSMauro Carvalho Chehab isp_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a)
860ceafdaacSMauro Carvalho Chehab {
861ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = to_isp_video_fh(fh);
862ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
863ceafdaacSMauro Carvalho Chehab 
864ceafdaacSMauro Carvalho Chehab 	if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
865ceafdaacSMauro Carvalho Chehab 	    video->type != a->type)
866ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
867ceafdaacSMauro Carvalho Chehab 
868ceafdaacSMauro Carvalho Chehab 	memset(a, 0, sizeof(*a));
869ceafdaacSMauro Carvalho Chehab 	a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
870ceafdaacSMauro Carvalho Chehab 	a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
871ceafdaacSMauro Carvalho Chehab 	a->parm.output.timeperframe = vfh->timeperframe;
872ceafdaacSMauro Carvalho Chehab 
873ceafdaacSMauro Carvalho Chehab 	return 0;
874ceafdaacSMauro Carvalho Chehab }
875ceafdaacSMauro Carvalho Chehab 
876ceafdaacSMauro Carvalho Chehab static int
isp_video_set_param(struct file * file,void * fh,struct v4l2_streamparm * a)877ceafdaacSMauro Carvalho Chehab isp_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a)
878ceafdaacSMauro Carvalho Chehab {
879ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = to_isp_video_fh(fh);
880ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
881ceafdaacSMauro Carvalho Chehab 
882ceafdaacSMauro Carvalho Chehab 	if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
883ceafdaacSMauro Carvalho Chehab 	    video->type != a->type)
884ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
885ceafdaacSMauro Carvalho Chehab 
886ceafdaacSMauro Carvalho Chehab 	if (a->parm.output.timeperframe.denominator == 0)
887ceafdaacSMauro Carvalho Chehab 		a->parm.output.timeperframe.denominator = 1;
888ceafdaacSMauro Carvalho Chehab 
889ceafdaacSMauro Carvalho Chehab 	vfh->timeperframe = a->parm.output.timeperframe;
890ceafdaacSMauro Carvalho Chehab 
891ceafdaacSMauro Carvalho Chehab 	return 0;
892ceafdaacSMauro Carvalho Chehab }
893ceafdaacSMauro Carvalho Chehab 
894ceafdaacSMauro Carvalho Chehab static int
isp_video_reqbufs(struct file * file,void * fh,struct v4l2_requestbuffers * rb)895ceafdaacSMauro Carvalho Chehab isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
896ceafdaacSMauro Carvalho Chehab {
897ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = to_isp_video_fh(fh);
898ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
899ceafdaacSMauro Carvalho Chehab 	int ret;
900ceafdaacSMauro Carvalho Chehab 
901ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->queue_lock);
902ceafdaacSMauro Carvalho Chehab 	ret = vb2_reqbufs(&vfh->queue, rb);
903ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->queue_lock);
904ceafdaacSMauro Carvalho Chehab 
905ceafdaacSMauro Carvalho Chehab 	return ret;
906ceafdaacSMauro Carvalho Chehab }
907ceafdaacSMauro Carvalho Chehab 
908ceafdaacSMauro Carvalho Chehab static int
isp_video_querybuf(struct file * file,void * fh,struct v4l2_buffer * b)909ceafdaacSMauro Carvalho Chehab isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
910ceafdaacSMauro Carvalho Chehab {
911ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = to_isp_video_fh(fh);
912ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
913ceafdaacSMauro Carvalho Chehab 	int ret;
914ceafdaacSMauro Carvalho Chehab 
915ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->queue_lock);
916ceafdaacSMauro Carvalho Chehab 	ret = vb2_querybuf(&vfh->queue, b);
917ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->queue_lock);
918ceafdaacSMauro Carvalho Chehab 
919ceafdaacSMauro Carvalho Chehab 	return ret;
920ceafdaacSMauro Carvalho Chehab }
921ceafdaacSMauro Carvalho Chehab 
922ceafdaacSMauro Carvalho Chehab static int
isp_video_qbuf(struct file * file,void * fh,struct v4l2_buffer * b)923ceafdaacSMauro Carvalho Chehab isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
924ceafdaacSMauro Carvalho Chehab {
925ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = to_isp_video_fh(fh);
926ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
927ceafdaacSMauro Carvalho Chehab 	int ret;
928ceafdaacSMauro Carvalho Chehab 
929ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->queue_lock);
930ceafdaacSMauro Carvalho Chehab 	ret = vb2_qbuf(&vfh->queue, video->video.v4l2_dev->mdev, b);
931ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->queue_lock);
932ceafdaacSMauro Carvalho Chehab 
933ceafdaacSMauro Carvalho Chehab 	return ret;
934ceafdaacSMauro Carvalho Chehab }
935ceafdaacSMauro Carvalho Chehab 
936ceafdaacSMauro Carvalho Chehab static int
isp_video_dqbuf(struct file * file,void * fh,struct v4l2_buffer * b)937ceafdaacSMauro Carvalho Chehab isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
938ceafdaacSMauro Carvalho Chehab {
939ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = to_isp_video_fh(fh);
940ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
941ceafdaacSMauro Carvalho Chehab 	int ret;
942ceafdaacSMauro Carvalho Chehab 
943ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->queue_lock);
944ceafdaacSMauro Carvalho Chehab 	ret = vb2_dqbuf(&vfh->queue, b, file->f_flags & O_NONBLOCK);
945ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->queue_lock);
946ceafdaacSMauro Carvalho Chehab 
947ceafdaacSMauro Carvalho Chehab 	return ret;
948ceafdaacSMauro Carvalho Chehab }
949ceafdaacSMauro Carvalho Chehab 
isp_video_check_external_subdevs(struct isp_video * video,struct isp_pipeline * pipe)950ceafdaacSMauro Carvalho Chehab static int isp_video_check_external_subdevs(struct isp_video *video,
951ceafdaacSMauro Carvalho Chehab 					    struct isp_pipeline *pipe)
952ceafdaacSMauro Carvalho Chehab {
953ceafdaacSMauro Carvalho Chehab 	struct isp_device *isp = video->isp;
954ceafdaacSMauro Carvalho Chehab 	struct media_entity *ents[] = {
955ceafdaacSMauro Carvalho Chehab 		&isp->isp_csi2a.subdev.entity,
956ceafdaacSMauro Carvalho Chehab 		&isp->isp_csi2c.subdev.entity,
957ceafdaacSMauro Carvalho Chehab 		&isp->isp_ccp2.subdev.entity,
958ceafdaacSMauro Carvalho Chehab 		&isp->isp_ccdc.subdev.entity
959ceafdaacSMauro Carvalho Chehab 	};
960ceafdaacSMauro Carvalho Chehab 	struct media_pad *source_pad;
961ceafdaacSMauro Carvalho Chehab 	struct media_entity *source = NULL;
962ceafdaacSMauro Carvalho Chehab 	struct media_entity *sink;
963*ecefa105SLaurent Pinchart 	struct v4l2_subdev_format fmt = {
964*ecefa105SLaurent Pinchart 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
965*ecefa105SLaurent Pinchart 	};
966ceafdaacSMauro Carvalho Chehab 	struct v4l2_ext_controls ctrls;
967ceafdaacSMauro Carvalho Chehab 	struct v4l2_ext_control ctrl;
968ceafdaacSMauro Carvalho Chehab 	unsigned int i;
969ceafdaacSMauro Carvalho Chehab 	int ret;
970ceafdaacSMauro Carvalho Chehab 
971ceafdaacSMauro Carvalho Chehab 	/* Memory-to-memory pipelines have no external subdev. */
972ceafdaacSMauro Carvalho Chehab 	if (pipe->input != NULL)
973ceafdaacSMauro Carvalho Chehab 		return 0;
974ceafdaacSMauro Carvalho Chehab 
975ceafdaacSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(ents); i++) {
976ceafdaacSMauro Carvalho Chehab 		/* Is the entity part of the pipeline? */
977ceafdaacSMauro Carvalho Chehab 		if (!media_entity_enum_test(&pipe->ent_enum, ents[i]))
978ceafdaacSMauro Carvalho Chehab 			continue;
979ceafdaacSMauro Carvalho Chehab 
980ceafdaacSMauro Carvalho Chehab 		/* ISP entities have always sink pad == 0. Find source. */
981b2e44430SLaurent Pinchart 		source_pad = media_pad_remote_pad_first(&ents[i]->pads[0]);
982ceafdaacSMauro Carvalho Chehab 		if (source_pad == NULL)
983ceafdaacSMauro Carvalho Chehab 			continue;
984ceafdaacSMauro Carvalho Chehab 
985ceafdaacSMauro Carvalho Chehab 		source = source_pad->entity;
986ceafdaacSMauro Carvalho Chehab 		sink = ents[i];
987ceafdaacSMauro Carvalho Chehab 		break;
988ceafdaacSMauro Carvalho Chehab 	}
989ceafdaacSMauro Carvalho Chehab 
990ceafdaacSMauro Carvalho Chehab 	if (!source) {
991ceafdaacSMauro Carvalho Chehab 		dev_warn(isp->dev, "can't find source, failing now\n");
992ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
993ceafdaacSMauro Carvalho Chehab 	}
994ceafdaacSMauro Carvalho Chehab 
995ceafdaacSMauro Carvalho Chehab 	if (!is_media_entity_v4l2_subdev(source))
996ceafdaacSMauro Carvalho Chehab 		return 0;
997ceafdaacSMauro Carvalho Chehab 
998ceafdaacSMauro Carvalho Chehab 	pipe->external = media_entity_to_v4l2_subdev(source);
999ceafdaacSMauro Carvalho Chehab 
1000ceafdaacSMauro Carvalho Chehab 	fmt.pad = source_pad->index;
1001ceafdaacSMauro Carvalho Chehab 	ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(sink),
1002ceafdaacSMauro Carvalho Chehab 			       pad, get_fmt, NULL, &fmt);
1003ceafdaacSMauro Carvalho Chehab 	if (unlikely(ret < 0)) {
1004ceafdaacSMauro Carvalho Chehab 		dev_warn(isp->dev, "get_fmt returned null!\n");
1005ceafdaacSMauro Carvalho Chehab 		return ret;
1006ceafdaacSMauro Carvalho Chehab 	}
1007ceafdaacSMauro Carvalho Chehab 
1008ceafdaacSMauro Carvalho Chehab 	pipe->external_width =
1009ceafdaacSMauro Carvalho Chehab 		omap3isp_video_format_info(fmt.format.code)->width;
1010ceafdaacSMauro Carvalho Chehab 
1011ceafdaacSMauro Carvalho Chehab 	memset(&ctrls, 0, sizeof(ctrls));
1012ceafdaacSMauro Carvalho Chehab 	memset(&ctrl, 0, sizeof(ctrl));
1013ceafdaacSMauro Carvalho Chehab 
1014ceafdaacSMauro Carvalho Chehab 	ctrl.id = V4L2_CID_PIXEL_RATE;
1015ceafdaacSMauro Carvalho Chehab 
1016ceafdaacSMauro Carvalho Chehab 	ctrls.count = 1;
1017ceafdaacSMauro Carvalho Chehab 	ctrls.controls = &ctrl;
1018ceafdaacSMauro Carvalho Chehab 	ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, &video->video,
1019ceafdaacSMauro Carvalho Chehab 			       NULL, &ctrls);
1020ceafdaacSMauro Carvalho Chehab 	if (ret < 0) {
1021ceafdaacSMauro Carvalho Chehab 		dev_warn(isp->dev, "no pixel rate control in subdev %s\n",
1022ceafdaacSMauro Carvalho Chehab 			 pipe->external->name);
1023ceafdaacSMauro Carvalho Chehab 		return ret;
1024ceafdaacSMauro Carvalho Chehab 	}
1025ceafdaacSMauro Carvalho Chehab 
1026ceafdaacSMauro Carvalho Chehab 	pipe->external_rate = ctrl.value64;
1027ceafdaacSMauro Carvalho Chehab 
1028ceafdaacSMauro Carvalho Chehab 	if (media_entity_enum_test(&pipe->ent_enum,
1029ceafdaacSMauro Carvalho Chehab 				   &isp->isp_ccdc.subdev.entity)) {
1030ceafdaacSMauro Carvalho Chehab 		unsigned int rate = UINT_MAX;
1031ceafdaacSMauro Carvalho Chehab 		/*
1032ceafdaacSMauro Carvalho Chehab 		 * Check that maximum allowed CCDC pixel rate isn't
1033ceafdaacSMauro Carvalho Chehab 		 * exceeded by the pixel rate.
1034ceafdaacSMauro Carvalho Chehab 		 */
1035ceafdaacSMauro Carvalho Chehab 		omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
1036ceafdaacSMauro Carvalho Chehab 		if (pipe->external_rate > rate)
1037ceafdaacSMauro Carvalho Chehab 			return -ENOSPC;
1038ceafdaacSMauro Carvalho Chehab 	}
1039ceafdaacSMauro Carvalho Chehab 
1040ceafdaacSMauro Carvalho Chehab 	return 0;
1041ceafdaacSMauro Carvalho Chehab }
1042ceafdaacSMauro Carvalho Chehab 
1043ceafdaacSMauro Carvalho Chehab /*
1044ceafdaacSMauro Carvalho Chehab  * Stream management
1045ceafdaacSMauro Carvalho Chehab  *
1046ceafdaacSMauro Carvalho Chehab  * Every ISP pipeline has a single input and a single output. The input can be
1047ceafdaacSMauro Carvalho Chehab  * either a sensor or a video node. The output is always a video node.
1048ceafdaacSMauro Carvalho Chehab  *
1049ceafdaacSMauro Carvalho Chehab  * As every pipeline has an output video node, the ISP video objects at the
1050ceafdaacSMauro Carvalho Chehab  * pipeline output stores the pipeline state. It tracks the streaming state of
1051ceafdaacSMauro Carvalho Chehab  * both the input and output, as well as the availability of buffers.
1052ceafdaacSMauro Carvalho Chehab  *
1053ceafdaacSMauro Carvalho Chehab  * In sensor-to-memory mode, frames are always available at the pipeline input.
1054ceafdaacSMauro Carvalho Chehab  * Starting the sensor usually requires I2C transfers and must be done in
1055ceafdaacSMauro Carvalho Chehab  * interruptible context. The pipeline is started and stopped synchronously
1056ceafdaacSMauro Carvalho Chehab  * to the stream on/off commands. All modules in the pipeline will get their
1057ceafdaacSMauro Carvalho Chehab  * subdev set stream handler called. The module at the end of the pipeline must
1058ceafdaacSMauro Carvalho Chehab  * delay starting the hardware until buffers are available at its output.
1059ceafdaacSMauro Carvalho Chehab  *
1060ceafdaacSMauro Carvalho Chehab  * In memory-to-memory mode, starting/stopping the stream requires
1061ceafdaacSMauro Carvalho Chehab  * synchronization between the input and output. ISP modules can't be stopped
1062ceafdaacSMauro Carvalho Chehab  * in the middle of a frame, and at least some of the modules seem to become
1063ceafdaacSMauro Carvalho Chehab  * busy as soon as they're started, even if they don't receive a frame start
1064ceafdaacSMauro Carvalho Chehab  * event. For that reason frames need to be processed in single-shot mode. The
1065ceafdaacSMauro Carvalho Chehab  * driver needs to wait until a frame is completely processed and written to
1066ceafdaacSMauro Carvalho Chehab  * memory before restarting the pipeline for the next frame. Pipelined
1067ceafdaacSMauro Carvalho Chehab  * processing might be possible but requires more testing.
1068ceafdaacSMauro Carvalho Chehab  *
1069ceafdaacSMauro Carvalho Chehab  * Stream start must be delayed until buffers are available at both the input
10706be95480SHans Verkuil  * and output. The pipeline must be started in the vb2 queue callback with
1071ceafdaacSMauro Carvalho Chehab  * the buffers queue spinlock held. The modules subdev set stream operation must
1072ceafdaacSMauro Carvalho Chehab  * not sleep.
1073ceafdaacSMauro Carvalho Chehab  */
1074ceafdaacSMauro Carvalho Chehab static int
isp_video_streamon(struct file * file,void * fh,enum v4l2_buf_type type)1075ceafdaacSMauro Carvalho Chehab isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
1076ceafdaacSMauro Carvalho Chehab {
1077ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = to_isp_video_fh(fh);
1078ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
1079ceafdaacSMauro Carvalho Chehab 	enum isp_pipeline_state state;
1080ceafdaacSMauro Carvalho Chehab 	struct isp_pipeline *pipe;
1081ceafdaacSMauro Carvalho Chehab 	unsigned long flags;
1082ceafdaacSMauro Carvalho Chehab 	int ret;
1083ceafdaacSMauro Carvalho Chehab 
1084ceafdaacSMauro Carvalho Chehab 	if (type != video->type)
1085ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
1086ceafdaacSMauro Carvalho Chehab 
1087ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->stream_lock);
1088ceafdaacSMauro Carvalho Chehab 
1089ceafdaacSMauro Carvalho Chehab 	/* Start streaming on the pipeline. No link touching an entity in the
1090ceafdaacSMauro Carvalho Chehab 	 * pipeline can be activated or deactivated once streaming is started.
1091ceafdaacSMauro Carvalho Chehab 	 */
109272b60335SLaurent Pinchart 	pipe = to_isp_pipeline(&video->video.entity) ? : &video->pipe;
1093ceafdaacSMauro Carvalho Chehab 
1094ceafdaacSMauro Carvalho Chehab 	ret = media_entity_enum_init(&pipe->ent_enum, &video->isp->media_dev);
1095ceafdaacSMauro Carvalho Chehab 	if (ret)
1096ceafdaacSMauro Carvalho Chehab 		goto err_enum_init;
1097ceafdaacSMauro Carvalho Chehab 
1098ceafdaacSMauro Carvalho Chehab 	/* TODO: Implement PM QoS */
1099ceafdaacSMauro Carvalho Chehab 	pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
1100ceafdaacSMauro Carvalho Chehab 	pipe->max_rate = pipe->l3_ick;
1101ceafdaacSMauro Carvalho Chehab 
110212cecbf9STomi Valkeinen 	ret = video_device_pipeline_start(&video->video, &pipe->pipe);
1103ceafdaacSMauro Carvalho Chehab 	if (ret < 0)
1104ceafdaacSMauro Carvalho Chehab 		goto err_pipeline_start;
1105ceafdaacSMauro Carvalho Chehab 
1106ceafdaacSMauro Carvalho Chehab 	/* Verify that the currently configured format matches the output of
1107ceafdaacSMauro Carvalho Chehab 	 * the connected subdev.
1108ceafdaacSMauro Carvalho Chehab 	 */
1109ceafdaacSMauro Carvalho Chehab 	ret = isp_video_check_format(video, vfh);
1110ceafdaacSMauro Carvalho Chehab 	if (ret < 0)
1111ceafdaacSMauro Carvalho Chehab 		goto err_check_format;
1112ceafdaacSMauro Carvalho Chehab 
1113ceafdaacSMauro Carvalho Chehab 	video->bpl_padding = ret;
1114ceafdaacSMauro Carvalho Chehab 	video->bpl_value = vfh->format.fmt.pix.bytesperline;
1115ceafdaacSMauro Carvalho Chehab 
1116ceafdaacSMauro Carvalho Chehab 	ret = isp_video_get_graph_data(video, pipe);
1117ceafdaacSMauro Carvalho Chehab 	if (ret < 0)
1118ceafdaacSMauro Carvalho Chehab 		goto err_check_format;
1119ceafdaacSMauro Carvalho Chehab 
1120ceafdaacSMauro Carvalho Chehab 	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1121ceafdaacSMauro Carvalho Chehab 		state = ISP_PIPELINE_STREAM_OUTPUT | ISP_PIPELINE_IDLE_OUTPUT;
1122ceafdaacSMauro Carvalho Chehab 	else
1123ceafdaacSMauro Carvalho Chehab 		state = ISP_PIPELINE_STREAM_INPUT | ISP_PIPELINE_IDLE_INPUT;
1124ceafdaacSMauro Carvalho Chehab 
1125ceafdaacSMauro Carvalho Chehab 	ret = isp_video_check_external_subdevs(video, pipe);
1126ceafdaacSMauro Carvalho Chehab 	if (ret < 0)
1127ceafdaacSMauro Carvalho Chehab 		goto err_check_format;
1128ceafdaacSMauro Carvalho Chehab 
1129ceafdaacSMauro Carvalho Chehab 	pipe->error = false;
1130ceafdaacSMauro Carvalho Chehab 
1131ceafdaacSMauro Carvalho Chehab 	spin_lock_irqsave(&pipe->lock, flags);
1132ceafdaacSMauro Carvalho Chehab 	pipe->state &= ~ISP_PIPELINE_STREAM;
1133ceafdaacSMauro Carvalho Chehab 	pipe->state |= state;
1134ceafdaacSMauro Carvalho Chehab 	spin_unlock_irqrestore(&pipe->lock, flags);
1135ceafdaacSMauro Carvalho Chehab 
1136ceafdaacSMauro Carvalho Chehab 	/* Set the maximum time per frame as the value requested by userspace.
1137ceafdaacSMauro Carvalho Chehab 	 * This is a soft limit that can be overridden if the hardware doesn't
1138ceafdaacSMauro Carvalho Chehab 	 * support the request limit.
1139ceafdaacSMauro Carvalho Chehab 	 */
1140ceafdaacSMauro Carvalho Chehab 	if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1141ceafdaacSMauro Carvalho Chehab 		pipe->max_timeperframe = vfh->timeperframe;
1142ceafdaacSMauro Carvalho Chehab 
1143ceafdaacSMauro Carvalho Chehab 	video->queue = &vfh->queue;
1144ceafdaacSMauro Carvalho Chehab 	INIT_LIST_HEAD(&video->dmaqueue);
1145ceafdaacSMauro Carvalho Chehab 	atomic_set(&pipe->frame_number, -1);
1146ceafdaacSMauro Carvalho Chehab 	pipe->field = vfh->format.fmt.pix.field;
1147ceafdaacSMauro Carvalho Chehab 
1148ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->queue_lock);
1149ceafdaacSMauro Carvalho Chehab 	ret = vb2_streamon(&vfh->queue, type);
1150ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->queue_lock);
1151ceafdaacSMauro Carvalho Chehab 	if (ret < 0)
1152ceafdaacSMauro Carvalho Chehab 		goto err_check_format;
1153ceafdaacSMauro Carvalho Chehab 
1154ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->stream_lock);
1155ceafdaacSMauro Carvalho Chehab 
1156ceafdaacSMauro Carvalho Chehab 	return 0;
1157ceafdaacSMauro Carvalho Chehab 
1158ceafdaacSMauro Carvalho Chehab err_check_format:
115912cecbf9STomi Valkeinen 	video_device_pipeline_stop(&video->video);
1160ceafdaacSMauro Carvalho Chehab err_pipeline_start:
1161ceafdaacSMauro Carvalho Chehab 	/* TODO: Implement PM QoS */
1162ceafdaacSMauro Carvalho Chehab 	/* The DMA queue must be emptied here, otherwise CCDC interrupts that
1163ceafdaacSMauro Carvalho Chehab 	 * will get triggered the next time the CCDC is powered up will try to
1164ceafdaacSMauro Carvalho Chehab 	 * access buffers that might have been freed but still present in the
1165ceafdaacSMauro Carvalho Chehab 	 * DMA queue. This can easily get triggered if the above
1166ceafdaacSMauro Carvalho Chehab 	 * omap3isp_pipeline_set_stream() call fails on a system with a
1167ceafdaacSMauro Carvalho Chehab 	 * free-running sensor.
1168ceafdaacSMauro Carvalho Chehab 	 */
1169ceafdaacSMauro Carvalho Chehab 	INIT_LIST_HEAD(&video->dmaqueue);
1170ceafdaacSMauro Carvalho Chehab 	video->queue = NULL;
1171ceafdaacSMauro Carvalho Chehab 
1172ceafdaacSMauro Carvalho Chehab 	media_entity_enum_cleanup(&pipe->ent_enum);
1173ceafdaacSMauro Carvalho Chehab 
1174ceafdaacSMauro Carvalho Chehab err_enum_init:
1175ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->stream_lock);
1176ceafdaacSMauro Carvalho Chehab 
1177ceafdaacSMauro Carvalho Chehab 	return ret;
1178ceafdaacSMauro Carvalho Chehab }
1179ceafdaacSMauro Carvalho Chehab 
1180ceafdaacSMauro Carvalho Chehab static int
isp_video_streamoff(struct file * file,void * fh,enum v4l2_buf_type type)1181ceafdaacSMauro Carvalho Chehab isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
1182ceafdaacSMauro Carvalho Chehab {
1183ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = to_isp_video_fh(fh);
1184ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
1185ceafdaacSMauro Carvalho Chehab 	struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
1186ceafdaacSMauro Carvalho Chehab 	enum isp_pipeline_state state;
1187ceafdaacSMauro Carvalho Chehab 	unsigned int streaming;
1188ceafdaacSMauro Carvalho Chehab 	unsigned long flags;
1189ceafdaacSMauro Carvalho Chehab 
1190ceafdaacSMauro Carvalho Chehab 	if (type != video->type)
1191ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
1192ceafdaacSMauro Carvalho Chehab 
1193ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->stream_lock);
1194ceafdaacSMauro Carvalho Chehab 
1195ceafdaacSMauro Carvalho Chehab 	/* Make sure we're not streaming yet. */
1196ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->queue_lock);
1197ceafdaacSMauro Carvalho Chehab 	streaming = vb2_is_streaming(&vfh->queue);
1198ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->queue_lock);
1199ceafdaacSMauro Carvalho Chehab 
1200ceafdaacSMauro Carvalho Chehab 	if (!streaming)
1201ceafdaacSMauro Carvalho Chehab 		goto done;
1202ceafdaacSMauro Carvalho Chehab 
1203ceafdaacSMauro Carvalho Chehab 	/* Update the pipeline state. */
1204ceafdaacSMauro Carvalho Chehab 	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1205ceafdaacSMauro Carvalho Chehab 		state = ISP_PIPELINE_STREAM_OUTPUT
1206ceafdaacSMauro Carvalho Chehab 		      | ISP_PIPELINE_QUEUE_OUTPUT;
1207ceafdaacSMauro Carvalho Chehab 	else
1208ceafdaacSMauro Carvalho Chehab 		state = ISP_PIPELINE_STREAM_INPUT
1209ceafdaacSMauro Carvalho Chehab 		      | ISP_PIPELINE_QUEUE_INPUT;
1210ceafdaacSMauro Carvalho Chehab 
1211ceafdaacSMauro Carvalho Chehab 	spin_lock_irqsave(&pipe->lock, flags);
1212ceafdaacSMauro Carvalho Chehab 	pipe->state &= ~state;
1213ceafdaacSMauro Carvalho Chehab 	spin_unlock_irqrestore(&pipe->lock, flags);
1214ceafdaacSMauro Carvalho Chehab 
1215ceafdaacSMauro Carvalho Chehab 	/* Stop the stream. */
1216ceafdaacSMauro Carvalho Chehab 	omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_STOPPED);
1217ceafdaacSMauro Carvalho Chehab 	omap3isp_video_cancel_stream(video);
1218ceafdaacSMauro Carvalho Chehab 
1219ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->queue_lock);
1220ceafdaacSMauro Carvalho Chehab 	vb2_streamoff(&vfh->queue, type);
1221ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->queue_lock);
1222ceafdaacSMauro Carvalho Chehab 	video->queue = NULL;
1223ceafdaacSMauro Carvalho Chehab 	video->error = false;
1224ceafdaacSMauro Carvalho Chehab 
1225ceafdaacSMauro Carvalho Chehab 	/* TODO: Implement PM QoS */
122612cecbf9STomi Valkeinen 	video_device_pipeline_stop(&video->video);
1227ceafdaacSMauro Carvalho Chehab 
1228ceafdaacSMauro Carvalho Chehab 	media_entity_enum_cleanup(&pipe->ent_enum);
1229ceafdaacSMauro Carvalho Chehab 
1230ceafdaacSMauro Carvalho Chehab done:
1231ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->stream_lock);
1232ceafdaacSMauro Carvalho Chehab 	return 0;
1233ceafdaacSMauro Carvalho Chehab }
1234ceafdaacSMauro Carvalho Chehab 
1235ceafdaacSMauro Carvalho Chehab static int
isp_video_enum_input(struct file * file,void * fh,struct v4l2_input * input)1236ceafdaacSMauro Carvalho Chehab isp_video_enum_input(struct file *file, void *fh, struct v4l2_input *input)
1237ceafdaacSMauro Carvalho Chehab {
1238ceafdaacSMauro Carvalho Chehab 	if (input->index > 0)
1239ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
1240ceafdaacSMauro Carvalho Chehab 
1241ceafdaacSMauro Carvalho Chehab 	strscpy(input->name, "camera", sizeof(input->name));
1242ceafdaacSMauro Carvalho Chehab 	input->type = V4L2_INPUT_TYPE_CAMERA;
1243ceafdaacSMauro Carvalho Chehab 
1244ceafdaacSMauro Carvalho Chehab 	return 0;
1245ceafdaacSMauro Carvalho Chehab }
1246ceafdaacSMauro Carvalho Chehab 
1247ceafdaacSMauro Carvalho Chehab static int
isp_video_g_input(struct file * file,void * fh,unsigned int * input)1248ceafdaacSMauro Carvalho Chehab isp_video_g_input(struct file *file, void *fh, unsigned int *input)
1249ceafdaacSMauro Carvalho Chehab {
1250ceafdaacSMauro Carvalho Chehab 	*input = 0;
1251ceafdaacSMauro Carvalho Chehab 
1252ceafdaacSMauro Carvalho Chehab 	return 0;
1253ceafdaacSMauro Carvalho Chehab }
1254ceafdaacSMauro Carvalho Chehab 
1255ceafdaacSMauro Carvalho Chehab static int
isp_video_s_input(struct file * file,void * fh,unsigned int input)1256ceafdaacSMauro Carvalho Chehab isp_video_s_input(struct file *file, void *fh, unsigned int input)
1257ceafdaacSMauro Carvalho Chehab {
1258ceafdaacSMauro Carvalho Chehab 	return input == 0 ? 0 : -EINVAL;
1259ceafdaacSMauro Carvalho Chehab }
1260ceafdaacSMauro Carvalho Chehab 
1261ceafdaacSMauro Carvalho Chehab static const struct v4l2_ioctl_ops isp_video_ioctl_ops = {
1262ceafdaacSMauro Carvalho Chehab 	.vidioc_querycap		= isp_video_querycap,
1263ceafdaacSMauro Carvalho Chehab 	.vidioc_g_fmt_vid_cap		= isp_video_get_format,
1264ceafdaacSMauro Carvalho Chehab 	.vidioc_s_fmt_vid_cap		= isp_video_set_format,
1265ceafdaacSMauro Carvalho Chehab 	.vidioc_try_fmt_vid_cap		= isp_video_try_format,
1266ceafdaacSMauro Carvalho Chehab 	.vidioc_g_fmt_vid_out		= isp_video_get_format,
1267ceafdaacSMauro Carvalho Chehab 	.vidioc_s_fmt_vid_out		= isp_video_set_format,
1268ceafdaacSMauro Carvalho Chehab 	.vidioc_try_fmt_vid_out		= isp_video_try_format,
1269ceafdaacSMauro Carvalho Chehab 	.vidioc_g_selection		= isp_video_get_selection,
1270ceafdaacSMauro Carvalho Chehab 	.vidioc_s_selection		= isp_video_set_selection,
1271ceafdaacSMauro Carvalho Chehab 	.vidioc_g_parm			= isp_video_get_param,
1272ceafdaacSMauro Carvalho Chehab 	.vidioc_s_parm			= isp_video_set_param,
1273ceafdaacSMauro Carvalho Chehab 	.vidioc_reqbufs			= isp_video_reqbufs,
1274ceafdaacSMauro Carvalho Chehab 	.vidioc_querybuf		= isp_video_querybuf,
1275ceafdaacSMauro Carvalho Chehab 	.vidioc_qbuf			= isp_video_qbuf,
1276ceafdaacSMauro Carvalho Chehab 	.vidioc_dqbuf			= isp_video_dqbuf,
1277ceafdaacSMauro Carvalho Chehab 	.vidioc_streamon		= isp_video_streamon,
1278ceafdaacSMauro Carvalho Chehab 	.vidioc_streamoff		= isp_video_streamoff,
1279ceafdaacSMauro Carvalho Chehab 	.vidioc_enum_input		= isp_video_enum_input,
1280ceafdaacSMauro Carvalho Chehab 	.vidioc_g_input			= isp_video_g_input,
1281ceafdaacSMauro Carvalho Chehab 	.vidioc_s_input			= isp_video_s_input,
1282ceafdaacSMauro Carvalho Chehab };
1283ceafdaacSMauro Carvalho Chehab 
1284ceafdaacSMauro Carvalho Chehab /* -----------------------------------------------------------------------------
1285ceafdaacSMauro Carvalho Chehab  * V4L2 file operations
1286ceafdaacSMauro Carvalho Chehab  */
1287ceafdaacSMauro Carvalho Chehab 
isp_video_open(struct file * file)1288ceafdaacSMauro Carvalho Chehab static int isp_video_open(struct file *file)
1289ceafdaacSMauro Carvalho Chehab {
1290ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
1291ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *handle;
1292ceafdaacSMauro Carvalho Chehab 	struct vb2_queue *queue;
1293ceafdaacSMauro Carvalho Chehab 	int ret = 0;
1294ceafdaacSMauro Carvalho Chehab 
1295ceafdaacSMauro Carvalho Chehab 	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
1296ceafdaacSMauro Carvalho Chehab 	if (handle == NULL)
1297ceafdaacSMauro Carvalho Chehab 		return -ENOMEM;
1298ceafdaacSMauro Carvalho Chehab 
1299ceafdaacSMauro Carvalho Chehab 	v4l2_fh_init(&handle->vfh, &video->video);
1300ceafdaacSMauro Carvalho Chehab 	v4l2_fh_add(&handle->vfh);
1301ceafdaacSMauro Carvalho Chehab 
1302ceafdaacSMauro Carvalho Chehab 	/* If this is the first user, initialise the pipeline. */
1303ceafdaacSMauro Carvalho Chehab 	if (omap3isp_get(video->isp) == NULL) {
1304ceafdaacSMauro Carvalho Chehab 		ret = -EBUSY;
1305ceafdaacSMauro Carvalho Chehab 		goto done;
1306ceafdaacSMauro Carvalho Chehab 	}
1307ceafdaacSMauro Carvalho Chehab 
1308ceafdaacSMauro Carvalho Chehab 	ret = v4l2_pipeline_pm_get(&video->video.entity);
1309ceafdaacSMauro Carvalho Chehab 	if (ret < 0) {
1310ceafdaacSMauro Carvalho Chehab 		omap3isp_put(video->isp);
1311ceafdaacSMauro Carvalho Chehab 		goto done;
1312ceafdaacSMauro Carvalho Chehab 	}
1313ceafdaacSMauro Carvalho Chehab 
1314ceafdaacSMauro Carvalho Chehab 	queue = &handle->queue;
1315ceafdaacSMauro Carvalho Chehab 	queue->type = video->type;
1316ceafdaacSMauro Carvalho Chehab 	queue->io_modes = VB2_MMAP | VB2_USERPTR;
1317ceafdaacSMauro Carvalho Chehab 	queue->drv_priv = handle;
1318ceafdaacSMauro Carvalho Chehab 	queue->ops = &isp_video_queue_ops;
1319ceafdaacSMauro Carvalho Chehab 	queue->mem_ops = &vb2_dma_contig_memops;
1320ceafdaacSMauro Carvalho Chehab 	queue->buf_struct_size = sizeof(struct isp_buffer);
1321ceafdaacSMauro Carvalho Chehab 	queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1322ceafdaacSMauro Carvalho Chehab 	queue->dev = video->isp->dev;
1323ceafdaacSMauro Carvalho Chehab 
1324ceafdaacSMauro Carvalho Chehab 	ret = vb2_queue_init(&handle->queue);
1325ceafdaacSMauro Carvalho Chehab 	if (ret < 0) {
1326ceafdaacSMauro Carvalho Chehab 		omap3isp_put(video->isp);
1327ceafdaacSMauro Carvalho Chehab 		goto done;
1328ceafdaacSMauro Carvalho Chehab 	}
1329ceafdaacSMauro Carvalho Chehab 
1330ceafdaacSMauro Carvalho Chehab 	memset(&handle->format, 0, sizeof(handle->format));
1331ceafdaacSMauro Carvalho Chehab 	handle->format.type = video->type;
1332ceafdaacSMauro Carvalho Chehab 	handle->timeperframe.denominator = 1;
1333ceafdaacSMauro Carvalho Chehab 
1334ceafdaacSMauro Carvalho Chehab 	handle->video = video;
1335ceafdaacSMauro Carvalho Chehab 	file->private_data = &handle->vfh;
1336ceafdaacSMauro Carvalho Chehab 
1337ceafdaacSMauro Carvalho Chehab done:
1338ceafdaacSMauro Carvalho Chehab 	if (ret < 0) {
1339ceafdaacSMauro Carvalho Chehab 		v4l2_fh_del(&handle->vfh);
1340ceafdaacSMauro Carvalho Chehab 		v4l2_fh_exit(&handle->vfh);
1341ceafdaacSMauro Carvalho Chehab 		kfree(handle);
1342ceafdaacSMauro Carvalho Chehab 	}
1343ceafdaacSMauro Carvalho Chehab 
1344ceafdaacSMauro Carvalho Chehab 	return ret;
1345ceafdaacSMauro Carvalho Chehab }
1346ceafdaacSMauro Carvalho Chehab 
isp_video_release(struct file * file)1347ceafdaacSMauro Carvalho Chehab static int isp_video_release(struct file *file)
1348ceafdaacSMauro Carvalho Chehab {
1349ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
1350ceafdaacSMauro Carvalho Chehab 	struct v4l2_fh *vfh = file->private_data;
1351ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *handle = to_isp_video_fh(vfh);
1352ceafdaacSMauro Carvalho Chehab 
1353ceafdaacSMauro Carvalho Chehab 	/* Disable streaming and free the buffers queue resources. */
1354ceafdaacSMauro Carvalho Chehab 	isp_video_streamoff(file, vfh, video->type);
1355ceafdaacSMauro Carvalho Chehab 
1356ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->queue_lock);
1357ceafdaacSMauro Carvalho Chehab 	vb2_queue_release(&handle->queue);
1358ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->queue_lock);
1359ceafdaacSMauro Carvalho Chehab 
1360ceafdaacSMauro Carvalho Chehab 	v4l2_pipeline_pm_put(&video->video.entity);
1361ceafdaacSMauro Carvalho Chehab 
1362ceafdaacSMauro Carvalho Chehab 	/* Release the file handle. */
1363ceafdaacSMauro Carvalho Chehab 	v4l2_fh_del(vfh);
1364ceafdaacSMauro Carvalho Chehab 	v4l2_fh_exit(vfh);
1365ceafdaacSMauro Carvalho Chehab 	kfree(handle);
1366ceafdaacSMauro Carvalho Chehab 	file->private_data = NULL;
1367ceafdaacSMauro Carvalho Chehab 
1368ceafdaacSMauro Carvalho Chehab 	omap3isp_put(video->isp);
1369ceafdaacSMauro Carvalho Chehab 
1370ceafdaacSMauro Carvalho Chehab 	return 0;
1371ceafdaacSMauro Carvalho Chehab }
1372ceafdaacSMauro Carvalho Chehab 
isp_video_poll(struct file * file,poll_table * wait)1373ceafdaacSMauro Carvalho Chehab static __poll_t isp_video_poll(struct file *file, poll_table *wait)
1374ceafdaacSMauro Carvalho Chehab {
1375ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
1376ceafdaacSMauro Carvalho Chehab 	struct isp_video *video = video_drvdata(file);
1377ceafdaacSMauro Carvalho Chehab 	__poll_t ret;
1378ceafdaacSMauro Carvalho Chehab 
1379ceafdaacSMauro Carvalho Chehab 	mutex_lock(&video->queue_lock);
1380ceafdaacSMauro Carvalho Chehab 	ret = vb2_poll(&vfh->queue, file, wait);
1381ceafdaacSMauro Carvalho Chehab 	mutex_unlock(&video->queue_lock);
1382ceafdaacSMauro Carvalho Chehab 
1383ceafdaacSMauro Carvalho Chehab 	return ret;
1384ceafdaacSMauro Carvalho Chehab }
1385ceafdaacSMauro Carvalho Chehab 
isp_video_mmap(struct file * file,struct vm_area_struct * vma)1386ceafdaacSMauro Carvalho Chehab static int isp_video_mmap(struct file *file, struct vm_area_struct *vma)
1387ceafdaacSMauro Carvalho Chehab {
1388ceafdaacSMauro Carvalho Chehab 	struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
1389ceafdaacSMauro Carvalho Chehab 
1390ceafdaacSMauro Carvalho Chehab 	return vb2_mmap(&vfh->queue, vma);
1391ceafdaacSMauro Carvalho Chehab }
1392ceafdaacSMauro Carvalho Chehab 
1393ceafdaacSMauro Carvalho Chehab static const struct v4l2_file_operations isp_video_fops = {
1394ceafdaacSMauro Carvalho Chehab 	.owner = THIS_MODULE,
1395ceafdaacSMauro Carvalho Chehab 	.unlocked_ioctl = video_ioctl2,
1396ceafdaacSMauro Carvalho Chehab 	.open = isp_video_open,
1397ceafdaacSMauro Carvalho Chehab 	.release = isp_video_release,
1398ceafdaacSMauro Carvalho Chehab 	.poll = isp_video_poll,
1399ceafdaacSMauro Carvalho Chehab 	.mmap = isp_video_mmap,
1400ceafdaacSMauro Carvalho Chehab };
1401ceafdaacSMauro Carvalho Chehab 
1402ceafdaacSMauro Carvalho Chehab /* -----------------------------------------------------------------------------
1403ceafdaacSMauro Carvalho Chehab  * ISP video core
1404ceafdaacSMauro Carvalho Chehab  */
1405ceafdaacSMauro Carvalho Chehab 
1406ceafdaacSMauro Carvalho Chehab static const struct isp_video_operations isp_video_dummy_ops = {
1407ceafdaacSMauro Carvalho Chehab };
1408ceafdaacSMauro Carvalho Chehab 
omap3isp_video_init(struct isp_video * video,const char * name)1409ceafdaacSMauro Carvalho Chehab int omap3isp_video_init(struct isp_video *video, const char *name)
1410ceafdaacSMauro Carvalho Chehab {
1411ceafdaacSMauro Carvalho Chehab 	const char *direction;
1412ceafdaacSMauro Carvalho Chehab 	int ret;
1413ceafdaacSMauro Carvalho Chehab 
1414ceafdaacSMauro Carvalho Chehab 	switch (video->type) {
1415ceafdaacSMauro Carvalho Chehab 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1416ceafdaacSMauro Carvalho Chehab 		direction = "output";
1417ceafdaacSMauro Carvalho Chehab 		video->pad.flags = MEDIA_PAD_FL_SINK
1418ceafdaacSMauro Carvalho Chehab 				   | MEDIA_PAD_FL_MUST_CONNECT;
1419ceafdaacSMauro Carvalho Chehab 		break;
1420ceafdaacSMauro Carvalho Chehab 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1421ceafdaacSMauro Carvalho Chehab 		direction = "input";
1422ceafdaacSMauro Carvalho Chehab 		video->pad.flags = MEDIA_PAD_FL_SOURCE
1423ceafdaacSMauro Carvalho Chehab 				   | MEDIA_PAD_FL_MUST_CONNECT;
1424ceafdaacSMauro Carvalho Chehab 		video->video.vfl_dir = VFL_DIR_TX;
1425ceafdaacSMauro Carvalho Chehab 		break;
1426ceafdaacSMauro Carvalho Chehab 
1427ceafdaacSMauro Carvalho Chehab 	default:
1428ceafdaacSMauro Carvalho Chehab 		return -EINVAL;
1429ceafdaacSMauro Carvalho Chehab 	}
1430ceafdaacSMauro Carvalho Chehab 
1431ceafdaacSMauro Carvalho Chehab 	ret = media_entity_pads_init(&video->video.entity, 1, &video->pad);
1432ceafdaacSMauro Carvalho Chehab 	if (ret < 0)
1433ceafdaacSMauro Carvalho Chehab 		return ret;
1434ceafdaacSMauro Carvalho Chehab 
1435ceafdaacSMauro Carvalho Chehab 	mutex_init(&video->mutex);
1436ceafdaacSMauro Carvalho Chehab 	atomic_set(&video->active, 0);
1437ceafdaacSMauro Carvalho Chehab 
1438ceafdaacSMauro Carvalho Chehab 	spin_lock_init(&video->pipe.lock);
1439ceafdaacSMauro Carvalho Chehab 	mutex_init(&video->stream_lock);
1440ceafdaacSMauro Carvalho Chehab 	mutex_init(&video->queue_lock);
1441ceafdaacSMauro Carvalho Chehab 	spin_lock_init(&video->irqlock);
1442ceafdaacSMauro Carvalho Chehab 
1443ceafdaacSMauro Carvalho Chehab 	/* Initialize the video device. */
1444ceafdaacSMauro Carvalho Chehab 	if (video->ops == NULL)
1445ceafdaacSMauro Carvalho Chehab 		video->ops = &isp_video_dummy_ops;
1446ceafdaacSMauro Carvalho Chehab 
1447ceafdaacSMauro Carvalho Chehab 	video->video.fops = &isp_video_fops;
1448ceafdaacSMauro Carvalho Chehab 	snprintf(video->video.name, sizeof(video->video.name),
1449ceafdaacSMauro Carvalho Chehab 		 "OMAP3 ISP %s %s", name, direction);
1450ceafdaacSMauro Carvalho Chehab 	video->video.vfl_type = VFL_TYPE_VIDEO;
1451ceafdaacSMauro Carvalho Chehab 	video->video.release = video_device_release_empty;
1452ceafdaacSMauro Carvalho Chehab 	video->video.ioctl_ops = &isp_video_ioctl_ops;
1453ceafdaacSMauro Carvalho Chehab 	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1454ceafdaacSMauro Carvalho Chehab 		video->video.device_caps = V4L2_CAP_VIDEO_CAPTURE
1455ceafdaacSMauro Carvalho Chehab 					 | V4L2_CAP_STREAMING;
1456ceafdaacSMauro Carvalho Chehab 	else
1457ceafdaacSMauro Carvalho Chehab 		video->video.device_caps = V4L2_CAP_VIDEO_OUTPUT
1458ceafdaacSMauro Carvalho Chehab 					 | V4L2_CAP_STREAMING;
1459ceafdaacSMauro Carvalho Chehab 
1460ceafdaacSMauro Carvalho Chehab 	video->pipe.stream_state = ISP_PIPELINE_STREAM_STOPPED;
1461ceafdaacSMauro Carvalho Chehab 
1462ceafdaacSMauro Carvalho Chehab 	video_set_drvdata(&video->video, video);
1463ceafdaacSMauro Carvalho Chehab 
1464ceafdaacSMauro Carvalho Chehab 	return 0;
1465ceafdaacSMauro Carvalho Chehab }
1466ceafdaacSMauro Carvalho Chehab 
omap3isp_video_cleanup(struct isp_video * video)1467ceafdaacSMauro Carvalho Chehab void omap3isp_video_cleanup(struct isp_video *video)
1468ceafdaacSMauro Carvalho Chehab {
1469ceafdaacSMauro Carvalho Chehab 	media_entity_cleanup(&video->video.entity);
1470ceafdaacSMauro Carvalho Chehab 	mutex_destroy(&video->queue_lock);
1471ceafdaacSMauro Carvalho Chehab 	mutex_destroy(&video->stream_lock);
1472ceafdaacSMauro Carvalho Chehab 	mutex_destroy(&video->mutex);
1473ceafdaacSMauro Carvalho Chehab }
1474ceafdaacSMauro Carvalho Chehab 
omap3isp_video_register(struct isp_video * video,struct v4l2_device * vdev)1475ceafdaacSMauro Carvalho Chehab int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev)
1476ceafdaacSMauro Carvalho Chehab {
1477ceafdaacSMauro Carvalho Chehab 	int ret;
1478ceafdaacSMauro Carvalho Chehab 
1479ceafdaacSMauro Carvalho Chehab 	video->video.v4l2_dev = vdev;
1480ceafdaacSMauro Carvalho Chehab 
1481ceafdaacSMauro Carvalho Chehab 	ret = video_register_device(&video->video, VFL_TYPE_VIDEO, -1);
1482ceafdaacSMauro Carvalho Chehab 	if (ret < 0)
1483ceafdaacSMauro Carvalho Chehab 		dev_err(video->isp->dev,
1484ceafdaacSMauro Carvalho Chehab 			"%s: could not register video device (%d)\n",
1485ceafdaacSMauro Carvalho Chehab 			__func__, ret);
1486ceafdaacSMauro Carvalho Chehab 
1487ceafdaacSMauro Carvalho Chehab 	return ret;
1488ceafdaacSMauro Carvalho Chehab }
1489ceafdaacSMauro Carvalho Chehab 
omap3isp_video_unregister(struct isp_video * video)1490ceafdaacSMauro Carvalho Chehab void omap3isp_video_unregister(struct isp_video *video)
1491ceafdaacSMauro Carvalho Chehab {
1492ceafdaacSMauro Carvalho Chehab 	video_unregister_device(&video->video);
1493ceafdaacSMauro Carvalho Chehab }
1494