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