treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / media / platform / qcom / camss / camss-video.c
blob1d50dfbbb762e585d0cf5d9f164f6f782fa61624
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * camss-video.c
5 * Qualcomm MSM Camera Subsystem - V4L2 device node
7 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
8 * Copyright (C) 2015-2018 Linaro Ltd.
9 */
10 #include <linux/slab.h>
11 #include <media/media-entity.h>
12 #include <media/v4l2-dev.h>
13 #include <media/v4l2-device.h>
14 #include <media/v4l2-ioctl.h>
15 #include <media/v4l2-mc.h>
16 #include <media/videobuf2-dma-sg.h>
18 #include "camss-video.h"
19 #include "camss.h"
21 struct fract {
22 u8 numerator;
23 u8 denominator;
27 * struct camss_format_info - ISP media bus format information
28 * @code: V4L2 media bus format code
29 * @pixelformat: V4L2 pixel format FCC identifier
30 * @planes: Number of planes
31 * @hsub: Horizontal subsampling (for each plane)
32 * @vsub: Vertical subsampling (for each plane)
33 * @bpp: Bits per pixel when stored in memory (for each plane)
35 struct camss_format_info {
36 u32 code;
37 u32 pixelformat;
38 u8 planes;
39 struct fract hsub[3];
40 struct fract vsub[3];
41 unsigned int bpp[3];
44 static const struct camss_format_info formats_rdi_8x16[] = {
45 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
46 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
47 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
48 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
49 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
50 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
51 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
52 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
53 { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
54 { { 1, 1 } }, { { 1, 1 } }, { 8 } },
55 { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
56 { { 1, 1 } }, { { 1, 1 } }, { 8 } },
57 { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
58 { { 1, 1 } }, { { 1, 1 } }, { 8 } },
59 { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
60 { { 1, 1 } }, { { 1, 1 } }, { 8 } },
61 { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
62 { { 1, 1 } }, { { 1, 1 } }, { 10 } },
63 { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
64 { { 1, 1 } }, { { 1, 1 } }, { 10 } },
65 { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
66 { { 1, 1 } }, { { 1, 1 } }, { 10 } },
67 { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
68 { { 1, 1 } }, { { 1, 1 } }, { 10 } },
69 { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
70 { { 1, 1 } }, { { 1, 1 } }, { 12 } },
71 { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
72 { { 1, 1 } }, { { 1, 1 } }, { 12 } },
73 { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
74 { { 1, 1 } }, { { 1, 1 } }, { 12 } },
75 { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
76 { { 1, 1 } }, { { 1, 1 } }, { 12 } },
77 { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
78 { { 1, 1 } }, { { 1, 1 } }, { 10 } },
81 static const struct camss_format_info formats_rdi_8x96[] = {
82 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
83 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
84 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
85 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
86 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
87 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
88 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
89 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
90 { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
91 { { 1, 1 } }, { { 1, 1 } }, { 8 } },
92 { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
93 { { 1, 1 } }, { { 1, 1 } }, { 8 } },
94 { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
95 { { 1, 1 } }, { { 1, 1 } }, { 8 } },
96 { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
97 { { 1, 1 } }, { { 1, 1 } }, { 8 } },
98 { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
99 { { 1, 1 } }, { { 1, 1 } }, { 10 } },
100 { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
101 { { 1, 1 } }, { { 1, 1 } }, { 10 } },
102 { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
103 { { 1, 1 } }, { { 1, 1 } }, { 10 } },
104 { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
105 { { 1, 1 } }, { { 1, 1 } }, { 10 } },
106 { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1,
107 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
108 { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
109 { { 1, 1 } }, { { 1, 1 } }, { 12 } },
110 { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
111 { { 1, 1 } }, { { 1, 1 } }, { 12 } },
112 { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
113 { { 1, 1 } }, { { 1, 1 } }, { 12 } },
114 { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
115 { { 1, 1 } }, { { 1, 1 } }, { 12 } },
116 { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1,
117 { { 1, 1 } }, { { 1, 1 } }, { 14 } },
118 { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1,
119 { { 1, 1 } }, { { 1, 1 } }, { 14 } },
120 { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1,
121 { { 1, 1 } }, { { 1, 1 } }, { 14 } },
122 { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1,
123 { { 1, 1 } }, { { 1, 1 } }, { 14 } },
124 { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
125 { { 1, 1 } }, { { 1, 1 } }, { 10 } },
126 { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1,
127 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
130 static const struct camss_format_info formats_pix_8x16[] = {
131 { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
132 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
133 { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1,
134 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
135 { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
136 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
137 { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
138 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
139 { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1,
140 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
141 { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1,
142 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
143 { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
144 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
145 { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
146 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
147 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1,
148 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
149 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1,
150 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
151 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1,
152 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
153 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1,
154 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
155 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1,
156 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
157 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1,
158 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
159 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1,
160 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
161 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1,
162 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
165 static const struct camss_format_info formats_pix_8x96[] = {
166 { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
167 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
168 { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1,
169 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
170 { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
171 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
172 { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
173 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
174 { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1,
175 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
176 { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1,
177 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
178 { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
179 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
180 { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
181 { { 1, 1 } }, { { 2, 3 } }, { 8 } },
182 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1,
183 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
184 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1,
185 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
186 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1,
187 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
188 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1,
189 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
190 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1,
191 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
192 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1,
193 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
194 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1,
195 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
196 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1,
197 { { 1, 1 } }, { { 1, 2 } }, { 8 } },
198 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
199 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
200 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
201 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
202 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
203 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
204 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
205 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
208 /* -----------------------------------------------------------------------------
209 * Helper functions
212 static int video_find_format(u32 code, u32 pixelformat,
213 const struct camss_format_info *formats,
214 unsigned int nformats)
216 int i;
218 for (i = 0; i < nformats; i++) {
219 if (formats[i].code == code &&
220 formats[i].pixelformat == pixelformat)
221 return i;
224 for (i = 0; i < nformats; i++)
225 if (formats[i].code == code)
226 return i;
228 WARN_ON(1);
230 return -EINVAL;
234 * video_mbus_to_pix_mp - Convert v4l2_mbus_framefmt to v4l2_pix_format_mplane
235 * @mbus: v4l2_mbus_framefmt format (input)
236 * @pix: v4l2_pix_format_mplane format (output)
237 * @f: a pointer to formats array element to be used for the conversion
238 * @alignment: bytesperline alignment value
240 * Fill the output pix structure with information from the input mbus format.
242 * Return 0 on success or a negative error code otherwise
244 static int video_mbus_to_pix_mp(const struct v4l2_mbus_framefmt *mbus,
245 struct v4l2_pix_format_mplane *pix,
246 const struct camss_format_info *f,
247 unsigned int alignment)
249 unsigned int i;
250 u32 bytesperline;
252 memset(pix, 0, sizeof(*pix));
253 v4l2_fill_pix_format_mplane(pix, mbus);
254 pix->pixelformat = f->pixelformat;
255 pix->num_planes = f->planes;
256 for (i = 0; i < pix->num_planes; i++) {
257 bytesperline = pix->width / f->hsub[i].numerator *
258 f->hsub[i].denominator * f->bpp[i] / 8;
259 bytesperline = ALIGN(bytesperline, alignment);
260 pix->plane_fmt[i].bytesperline = bytesperline;
261 pix->plane_fmt[i].sizeimage = pix->height /
262 f->vsub[i].numerator * f->vsub[i].denominator *
263 bytesperline;
266 return 0;
269 static struct v4l2_subdev *video_remote_subdev(struct camss_video *video,
270 u32 *pad)
272 struct media_pad *remote;
274 remote = media_entity_remote_pad(&video->pad);
276 if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
277 return NULL;
279 if (pad)
280 *pad = remote->index;
282 return media_entity_to_v4l2_subdev(remote->entity);
285 static int video_get_subdev_format(struct camss_video *video,
286 struct v4l2_format *format)
288 struct v4l2_subdev_format fmt;
289 struct v4l2_subdev *subdev;
290 u32 pad;
291 int ret;
293 subdev = video_remote_subdev(video, &pad);
294 if (subdev == NULL)
295 return -EPIPE;
297 fmt.pad = pad;
298 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
300 ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
301 if (ret)
302 return ret;
304 ret = video_find_format(fmt.format.code,
305 format->fmt.pix_mp.pixelformat,
306 video->formats, video->nformats);
307 if (ret < 0)
308 return ret;
310 format->type = video->type;
312 return video_mbus_to_pix_mp(&fmt.format, &format->fmt.pix_mp,
313 &video->formats[ret], video->bpl_alignment);
316 /* -----------------------------------------------------------------------------
317 * Video queue operations
320 static int video_queue_setup(struct vb2_queue *q,
321 unsigned int *num_buffers, unsigned int *num_planes,
322 unsigned int sizes[], struct device *alloc_devs[])
324 struct camss_video *video = vb2_get_drv_priv(q);
325 const struct v4l2_pix_format_mplane *format =
326 &video->active_fmt.fmt.pix_mp;
327 unsigned int i;
329 if (*num_planes) {
330 if (*num_planes != format->num_planes)
331 return -EINVAL;
333 for (i = 0; i < *num_planes; i++)
334 if (sizes[i] < format->plane_fmt[i].sizeimage)
335 return -EINVAL;
337 return 0;
340 *num_planes = format->num_planes;
342 for (i = 0; i < *num_planes; i++)
343 sizes[i] = format->plane_fmt[i].sizeimage;
345 return 0;
348 static int video_buf_init(struct vb2_buffer *vb)
350 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
351 struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue);
352 struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer,
353 vb);
354 const struct v4l2_pix_format_mplane *format =
355 &video->active_fmt.fmt.pix_mp;
356 struct sg_table *sgt;
357 unsigned int i;
359 for (i = 0; i < format->num_planes; i++) {
360 sgt = vb2_dma_sg_plane_desc(vb, i);
361 if (!sgt)
362 return -EFAULT;
364 buffer->addr[i] = sg_dma_address(sgt->sgl);
367 if (format->pixelformat == V4L2_PIX_FMT_NV12 ||
368 format->pixelformat == V4L2_PIX_FMT_NV21 ||
369 format->pixelformat == V4L2_PIX_FMT_NV16 ||
370 format->pixelformat == V4L2_PIX_FMT_NV61)
371 buffer->addr[1] = buffer->addr[0] +
372 format->plane_fmt[0].bytesperline *
373 format->height;
375 return 0;
378 static int video_buf_prepare(struct vb2_buffer *vb)
380 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
381 struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue);
382 const struct v4l2_pix_format_mplane *format =
383 &video->active_fmt.fmt.pix_mp;
384 unsigned int i;
386 for (i = 0; i < format->num_planes; i++) {
387 if (format->plane_fmt[i].sizeimage > vb2_plane_size(vb, i))
388 return -EINVAL;
390 vb2_set_plane_payload(vb, i, format->plane_fmt[i].sizeimage);
393 vbuf->field = V4L2_FIELD_NONE;
395 return 0;
398 static void video_buf_queue(struct vb2_buffer *vb)
400 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
401 struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue);
402 struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer,
403 vb);
405 video->ops->queue_buffer(video, buffer);
408 static int video_check_format(struct camss_video *video)
410 struct v4l2_pix_format_mplane *pix = &video->active_fmt.fmt.pix_mp;
411 struct v4l2_format format;
412 struct v4l2_pix_format_mplane *sd_pix = &format.fmt.pix_mp;
413 int ret;
415 sd_pix->pixelformat = pix->pixelformat;
416 ret = video_get_subdev_format(video, &format);
417 if (ret < 0)
418 return ret;
420 if (pix->pixelformat != sd_pix->pixelformat ||
421 pix->height != sd_pix->height ||
422 pix->width != sd_pix->width ||
423 pix->num_planes != sd_pix->num_planes ||
424 pix->field != format.fmt.pix_mp.field)
425 return -EPIPE;
427 return 0;
430 static int video_start_streaming(struct vb2_queue *q, unsigned int count)
432 struct camss_video *video = vb2_get_drv_priv(q);
433 struct video_device *vdev = &video->vdev;
434 struct media_entity *entity;
435 struct media_pad *pad;
436 struct v4l2_subdev *subdev;
437 int ret;
439 ret = media_pipeline_start(&vdev->entity, &video->pipe);
440 if (ret < 0)
441 return ret;
443 ret = video_check_format(video);
444 if (ret < 0)
445 goto error;
447 entity = &vdev->entity;
448 while (1) {
449 pad = &entity->pads[0];
450 if (!(pad->flags & MEDIA_PAD_FL_SINK))
451 break;
453 pad = media_entity_remote_pad(pad);
454 if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
455 break;
457 entity = pad->entity;
458 subdev = media_entity_to_v4l2_subdev(entity);
460 ret = v4l2_subdev_call(subdev, video, s_stream, 1);
461 if (ret < 0 && ret != -ENOIOCTLCMD)
462 goto error;
465 return 0;
467 error:
468 media_pipeline_stop(&vdev->entity);
470 video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED);
472 return ret;
475 static void video_stop_streaming(struct vb2_queue *q)
477 struct camss_video *video = vb2_get_drv_priv(q);
478 struct video_device *vdev = &video->vdev;
479 struct media_entity *entity;
480 struct media_pad *pad;
481 struct v4l2_subdev *subdev;
483 entity = &vdev->entity;
484 while (1) {
485 pad = &entity->pads[0];
486 if (!(pad->flags & MEDIA_PAD_FL_SINK))
487 break;
489 pad = media_entity_remote_pad(pad);
490 if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
491 break;
493 entity = pad->entity;
494 subdev = media_entity_to_v4l2_subdev(entity);
496 v4l2_subdev_call(subdev, video, s_stream, 0);
499 media_pipeline_stop(&vdev->entity);
501 video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR);
504 static const struct vb2_ops msm_video_vb2_q_ops = {
505 .queue_setup = video_queue_setup,
506 .wait_prepare = vb2_ops_wait_prepare,
507 .wait_finish = vb2_ops_wait_finish,
508 .buf_init = video_buf_init,
509 .buf_prepare = video_buf_prepare,
510 .buf_queue = video_buf_queue,
511 .start_streaming = video_start_streaming,
512 .stop_streaming = video_stop_streaming,
515 /* -----------------------------------------------------------------------------
516 * V4L2 ioctls
519 static int video_querycap(struct file *file, void *fh,
520 struct v4l2_capability *cap)
522 struct camss_video *video = video_drvdata(file);
524 strscpy(cap->driver, "qcom-camss", sizeof(cap->driver));
525 strscpy(cap->card, "Qualcomm Camera Subsystem", sizeof(cap->card));
526 snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
527 dev_name(video->camss->dev));
529 return 0;
532 static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
534 struct camss_video *video = video_drvdata(file);
535 int i, j, k;
537 if (f->type != video->type)
538 return -EINVAL;
540 if (f->index >= video->nformats)
541 return -EINVAL;
543 /* find index "i" of "k"th unique pixelformat in formats array */
544 k = -1;
545 for (i = 0; i < video->nformats; i++) {
546 for (j = 0; j < i; j++) {
547 if (video->formats[i].pixelformat ==
548 video->formats[j].pixelformat)
549 break;
552 if (j == i)
553 k++;
555 if (k == f->index)
556 break;
559 if (k < f->index)
560 return -EINVAL;
562 f->pixelformat = video->formats[i].pixelformat;
564 return 0;
567 static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
569 struct camss_video *video = video_drvdata(file);
571 *f = video->active_fmt;
573 return 0;
576 static int __video_try_fmt(struct camss_video *video, struct v4l2_format *f)
578 struct v4l2_pix_format_mplane *pix_mp;
579 const struct camss_format_info *fi;
580 struct v4l2_plane_pix_format *p;
581 u32 bytesperline[3] = { 0 };
582 u32 sizeimage[3] = { 0 };
583 u32 width, height;
584 u32 bpl, lines;
585 int i, j;
587 pix_mp = &f->fmt.pix_mp;
589 if (video->line_based)
590 for (i = 0; i < pix_mp->num_planes && i < 3; i++) {
591 p = &pix_mp->plane_fmt[i];
592 bytesperline[i] = clamp_t(u32, p->bytesperline,
593 1, 65528);
594 sizeimage[i] = clamp_t(u32, p->sizeimage,
595 bytesperline[i],
596 bytesperline[i] * 4096);
599 for (j = 0; j < video->nformats; j++)
600 if (pix_mp->pixelformat == video->formats[j].pixelformat)
601 break;
603 if (j == video->nformats)
604 j = 0; /* default format */
606 fi = &video->formats[j];
607 width = pix_mp->width;
608 height = pix_mp->height;
610 memset(pix_mp, 0, sizeof(*pix_mp));
612 pix_mp->pixelformat = fi->pixelformat;
613 pix_mp->width = clamp_t(u32, width, 1, 8191);
614 pix_mp->height = clamp_t(u32, height, 1, 8191);
615 pix_mp->num_planes = fi->planes;
616 for (i = 0; i < pix_mp->num_planes; i++) {
617 bpl = pix_mp->width / fi->hsub[i].numerator *
618 fi->hsub[i].denominator * fi->bpp[i] / 8;
619 bpl = ALIGN(bpl, video->bpl_alignment);
620 pix_mp->plane_fmt[i].bytesperline = bpl;
621 pix_mp->plane_fmt[i].sizeimage = pix_mp->height /
622 fi->vsub[i].numerator * fi->vsub[i].denominator * bpl;
625 pix_mp->field = V4L2_FIELD_NONE;
626 pix_mp->colorspace = V4L2_COLORSPACE_SRGB;
627 pix_mp->flags = 0;
628 pix_mp->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix_mp->colorspace);
629 pix_mp->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
630 pix_mp->colorspace, pix_mp->ycbcr_enc);
631 pix_mp->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix_mp->colorspace);
633 if (video->line_based)
634 for (i = 0; i < pix_mp->num_planes; i++) {
635 p = &pix_mp->plane_fmt[i];
636 p->bytesperline = clamp_t(u32, p->bytesperline,
637 1, 65528);
638 p->sizeimage = clamp_t(u32, p->sizeimage,
639 p->bytesperline,
640 p->bytesperline * 4096);
641 lines = p->sizeimage / p->bytesperline;
643 if (p->bytesperline < bytesperline[i])
644 p->bytesperline = ALIGN(bytesperline[i], 8);
646 if (p->sizeimage < p->bytesperline * lines)
647 p->sizeimage = p->bytesperline * lines;
649 if (p->sizeimage < sizeimage[i])
650 p->sizeimage = sizeimage[i];
653 return 0;
656 static int video_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
658 struct camss_video *video = video_drvdata(file);
660 return __video_try_fmt(video, f);
663 static int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
665 struct camss_video *video = video_drvdata(file);
666 int ret;
668 if (vb2_is_busy(&video->vb2_q))
669 return -EBUSY;
671 ret = __video_try_fmt(video, f);
672 if (ret < 0)
673 return ret;
675 video->active_fmt = *f;
677 return 0;
680 static int video_enum_input(struct file *file, void *fh,
681 struct v4l2_input *input)
683 if (input->index > 0)
684 return -EINVAL;
686 strscpy(input->name, "camera", sizeof(input->name));
687 input->type = V4L2_INPUT_TYPE_CAMERA;
689 return 0;
692 static int video_g_input(struct file *file, void *fh, unsigned int *input)
694 *input = 0;
696 return 0;
699 static int video_s_input(struct file *file, void *fh, unsigned int input)
701 return input == 0 ? 0 : -EINVAL;
704 static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = {
705 .vidioc_querycap = video_querycap,
706 .vidioc_enum_fmt_vid_cap = video_enum_fmt,
707 .vidioc_g_fmt_vid_cap_mplane = video_g_fmt,
708 .vidioc_s_fmt_vid_cap_mplane = video_s_fmt,
709 .vidioc_try_fmt_vid_cap_mplane = video_try_fmt,
710 .vidioc_reqbufs = vb2_ioctl_reqbufs,
711 .vidioc_querybuf = vb2_ioctl_querybuf,
712 .vidioc_qbuf = vb2_ioctl_qbuf,
713 .vidioc_expbuf = vb2_ioctl_expbuf,
714 .vidioc_dqbuf = vb2_ioctl_dqbuf,
715 .vidioc_create_bufs = vb2_ioctl_create_bufs,
716 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
717 .vidioc_streamon = vb2_ioctl_streamon,
718 .vidioc_streamoff = vb2_ioctl_streamoff,
719 .vidioc_enum_input = video_enum_input,
720 .vidioc_g_input = video_g_input,
721 .vidioc_s_input = video_s_input,
724 /* -----------------------------------------------------------------------------
725 * V4L2 file operations
728 static int video_open(struct file *file)
730 struct video_device *vdev = video_devdata(file);
731 struct camss_video *video = video_drvdata(file);
732 struct v4l2_fh *vfh;
733 int ret;
735 mutex_lock(&video->lock);
737 vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
738 if (vfh == NULL) {
739 ret = -ENOMEM;
740 goto error_alloc;
743 v4l2_fh_init(vfh, vdev);
744 v4l2_fh_add(vfh);
746 file->private_data = vfh;
748 ret = v4l2_pipeline_pm_use(&vdev->entity, 1);
749 if (ret < 0) {
750 dev_err(video->camss->dev, "Failed to power up pipeline: %d\n",
751 ret);
752 goto error_pm_use;
755 mutex_unlock(&video->lock);
757 return 0;
759 error_pm_use:
760 v4l2_fh_release(file);
762 error_alloc:
763 mutex_unlock(&video->lock);
765 return ret;
768 static int video_release(struct file *file)
770 struct video_device *vdev = video_devdata(file);
772 vb2_fop_release(file);
774 v4l2_pipeline_pm_use(&vdev->entity, 0);
776 file->private_data = NULL;
778 return 0;
781 static const struct v4l2_file_operations msm_vid_fops = {
782 .owner = THIS_MODULE,
783 .unlocked_ioctl = video_ioctl2,
784 .open = video_open,
785 .release = video_release,
786 .poll = vb2_fop_poll,
787 .mmap = vb2_fop_mmap,
788 .read = vb2_fop_read,
791 /* -----------------------------------------------------------------------------
792 * CAMSS video core
795 static void msm_video_release(struct video_device *vdev)
797 struct camss_video *video = video_get_drvdata(vdev);
799 media_entity_cleanup(&vdev->entity);
801 mutex_destroy(&video->q_lock);
802 mutex_destroy(&video->lock);
804 if (atomic_dec_and_test(&video->camss->ref_count))
805 camss_delete(video->camss);
809 * msm_video_init_format - Helper function to initialize format
810 * @video: struct camss_video
812 * Initialize pad format with default value.
814 * Return 0 on success or a negative error code otherwise
816 static int msm_video_init_format(struct camss_video *video)
818 int ret;
819 struct v4l2_format format = {
820 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
821 .fmt.pix_mp = {
822 .width = 1920,
823 .height = 1080,
824 .pixelformat = video->formats[0].pixelformat,
828 ret = __video_try_fmt(video, &format);
829 if (ret < 0)
830 return ret;
832 video->active_fmt = format;
834 return 0;
838 * msm_video_register - Register a video device node
839 * @video: struct camss_video
840 * @v4l2_dev: V4L2 device
841 * @name: name to be used for the video device node
843 * Initialize and register a video device node to a V4L2 device. Also
844 * initialize the vb2 queue.
846 * Return 0 on success or a negative error code otherwise
849 int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
850 const char *name, int is_pix)
852 struct media_pad *pad = &video->pad;
853 struct video_device *vdev;
854 struct vb2_queue *q;
855 int ret;
857 vdev = &video->vdev;
859 mutex_init(&video->q_lock);
861 q = &video->vb2_q;
862 q->drv_priv = video;
863 q->mem_ops = &vb2_dma_sg_memops;
864 q->ops = &msm_video_vb2_q_ops;
865 q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
866 q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ;
867 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
868 q->buf_struct_size = sizeof(struct camss_buffer);
869 q->dev = video->camss->dev;
870 q->lock = &video->q_lock;
871 ret = vb2_queue_init(q);
872 if (ret < 0) {
873 dev_err(v4l2_dev->dev, "Failed to init vb2 queue: %d\n", ret);
874 goto error_vb2_init;
877 pad->flags = MEDIA_PAD_FL_SINK;
878 ret = media_entity_pads_init(&vdev->entity, 1, pad);
879 if (ret < 0) {
880 dev_err(v4l2_dev->dev, "Failed to init video entity: %d\n",
881 ret);
882 goto error_media_init;
885 mutex_init(&video->lock);
887 if (video->camss->version == CAMSS_8x16) {
888 if (is_pix) {
889 video->formats = formats_pix_8x16;
890 video->nformats = ARRAY_SIZE(formats_pix_8x16);
891 } else {
892 video->formats = formats_rdi_8x16;
893 video->nformats = ARRAY_SIZE(formats_rdi_8x16);
895 } else if (video->camss->version == CAMSS_8x96) {
896 if (is_pix) {
897 video->formats = formats_pix_8x96;
898 video->nformats = ARRAY_SIZE(formats_pix_8x96);
899 } else {
900 video->formats = formats_rdi_8x96;
901 video->nformats = ARRAY_SIZE(formats_rdi_8x96);
903 } else {
904 goto error_video_register;
907 ret = msm_video_init_format(video);
908 if (ret < 0) {
909 dev_err(v4l2_dev->dev, "Failed to init format: %d\n", ret);
910 goto error_video_register;
913 vdev->fops = &msm_vid_fops;
914 vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING |
915 V4L2_CAP_READWRITE;
916 vdev->ioctl_ops = &msm_vid_ioctl_ops;
917 vdev->release = msm_video_release;
918 vdev->v4l2_dev = v4l2_dev;
919 vdev->vfl_dir = VFL_DIR_RX;
920 vdev->queue = &video->vb2_q;
921 vdev->lock = &video->lock;
922 strscpy(vdev->name, name, sizeof(vdev->name));
924 ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
925 if (ret < 0) {
926 dev_err(v4l2_dev->dev, "Failed to register video device: %d\n",
927 ret);
928 goto error_video_register;
931 video_set_drvdata(vdev, video);
932 atomic_inc(&video->camss->ref_count);
934 return 0;
936 error_video_register:
937 media_entity_cleanup(&vdev->entity);
938 mutex_destroy(&video->lock);
939 error_media_init:
940 vb2_queue_release(&video->vb2_q);
941 error_vb2_init:
942 mutex_destroy(&video->q_lock);
944 return ret;
947 void msm_video_stop_streaming(struct camss_video *video)
949 if (vb2_is_streaming(&video->vb2_q))
950 vb2_queue_release(&video->vb2_q);
953 void msm_video_unregister(struct camss_video *video)
955 atomic_inc(&video->camss->ref_count);
956 video_unregister_device(&video->vdev);
957 atomic_dec(&video->camss->ref_count);