Merge branch 'core-objtool-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-block.git] / drivers / media / platform / qcom / camss / camss-video.c
CommitLineData
b873663b 1// SPDX-License-Identifier: GPL-2.0
0ac2586c
TT
2/*
3 * camss-video.c
4 *
5 * Qualcomm MSM Camera Subsystem - V4L2 device node
6 *
7 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
ec6859b2 8 * Copyright (C) 2015-2018 Linaro Ltd.
0ac2586c
TT
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>
0ac2586c
TT
16#include <media/videobuf2-dma-sg.h>
17
18#include "camss-video.h"
19#include "camss.h"
20
9b5833f7
TT
21struct fract {
22 u8 numerator;
23 u8 denominator;
24};
25
0ac2586c
TT
26/*
27 * struct camss_format_info - ISP media bus format information
28 * @code: V4L2 media bus format code
29 * @pixelformat: V4L2 pixel format FCC identifier
9b5833f7
TT
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)
0ac2586c 34 */
9b5833f7 35struct camss_format_info {
0ac2586c
TT
36 u32 code;
37 u32 pixelformat;
9b5833f7
TT
38 u8 planes;
39 struct fract hsub[3];
40 struct fract vsub[3];
41 unsigned int bpp[3];
42};
43
cba3819d 44static const struct camss_format_info formats_rdi_8x16[] = {
9b5833f7
TT
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 } },
cc8fe073
TT
77 { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
78 { { 1, 1 } }, { { 1, 1 } }, { 10 } },
9b5833f7
TT
79};
80
cba3819d
TT
81static 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 } },
5019d7c8
TT
106 { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1,
107 { { 1, 1 } }, { { 1, 1 } }, { 16 } },
cba3819d
TT
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 } },
f476fb56
TT
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 } },
cc8fe073
TT
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 } },
cba3819d
TT
128};
129
130static 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 } },
163};
164
165static const struct camss_format_info formats_pix_8x96[] = {
9b5833f7
TT
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 } },
312e1c85
TT
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 } },
0ac2586c
TT
206};
207
208/* -----------------------------------------------------------------------------
209 * Helper functions
210 */
211
9b5833f7
TT
212static int video_find_format(u32 code, u32 pixelformat,
213 const struct camss_format_info *formats,
214 unsigned int nformats)
215{
216 int i;
217
218 for (i = 0; i < nformats; i++) {
219 if (formats[i].code == code &&
220 formats[i].pixelformat == pixelformat)
221 return i;
222 }
223
224 for (i = 0; i < nformats; i++)
225 if (formats[i].code == code)
226 return i;
227
228 WARN_ON(1);
229
230 return -EINVAL;
231}
232
0ac2586c
TT
233/*
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)
9b5833f7 237 * @f: a pointer to formats array element to be used for the conversion
7b4aff6f 238 * @alignment: bytesperline alignment value
0ac2586c
TT
239 *
240 * Fill the output pix structure with information from the input mbus format.
241 *
242 * Return 0 on success or a negative error code otherwise
243 */
9b5833f7
TT
244static int video_mbus_to_pix_mp(const struct v4l2_mbus_framefmt *mbus,
245 struct v4l2_pix_format_mplane *pix,
7b4aff6f
TT
246 const struct camss_format_info *f,
247 unsigned int alignment)
0ac2586c
TT
248{
249 unsigned int i;
250 u32 bytesperline;
251
252 memset(pix, 0, sizeof(*pix));
253 v4l2_fill_pix_format_mplane(pix, mbus);
9b5833f7
TT
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;
7b4aff6f 259 bytesperline = ALIGN(bytesperline, alignment);
9b5833f7
TT
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;
0ac2586c
TT
264 }
265
0ac2586c
TT
266 return 0;
267}
268
269static struct v4l2_subdev *video_remote_subdev(struct camss_video *video,
270 u32 *pad)
271{
272 struct media_pad *remote;
273
274 remote = media_entity_remote_pad(&video->pad);
275
276 if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
277 return NULL;
278
279 if (pad)
280 *pad = remote->index;
281
282 return media_entity_to_v4l2_subdev(remote->entity);
283}
284
285static int video_get_subdev_format(struct camss_video *video,
286 struct v4l2_format *format)
287{
288 struct v4l2_subdev_format fmt;
289 struct v4l2_subdev *subdev;
290 u32 pad;
291 int ret;
292
293 subdev = video_remote_subdev(video, &pad);
294 if (subdev == NULL)
295 return -EPIPE;
296
297 fmt.pad = pad;
298 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
299
300 ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
301 if (ret)
302 return ret;
303
9b5833f7
TT
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;
309
0ac2586c 310 format->type = video->type;
9b5833f7
TT
311
312 return video_mbus_to_pix_mp(&fmt.format, &format->fmt.pix_mp,
7b4aff6f 313 &video->formats[ret], video->bpl_alignment);
0ac2586c
TT
314}
315
316/* -----------------------------------------------------------------------------
317 * Video queue operations
318 */
319
320static 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[])
323{
324 struct camss_video *video = vb2_get_drv_priv(q);
9b5833f7
TT
325 const struct v4l2_pix_format_mplane *format =
326 &video->active_fmt.fmt.pix_mp;
327 unsigned int i;
0ac2586c
TT
328
329 if (*num_planes) {
9b5833f7 330 if (*num_planes != format->num_planes)
0ac2586c
TT
331 return -EINVAL;
332
9b5833f7
TT
333 for (i = 0; i < *num_planes; i++)
334 if (sizes[i] < format->plane_fmt[i].sizeimage)
335 return -EINVAL;
0ac2586c
TT
336
337 return 0;
338 }
339
9b5833f7 340 *num_planes = format->num_planes;
0ac2586c 341
9b5833f7
TT
342 for (i = 0; i < *num_planes; i++)
343 sizes[i] = format->plane_fmt[i].sizeimage;
0ac2586c
TT
344
345 return 0;
346}
347
9b5833f7 348static int video_buf_init(struct vb2_buffer *vb)
0ac2586c
TT
349{
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);
9b5833f7
TT
354 const struct v4l2_pix_format_mplane *format =
355 &video->active_fmt.fmt.pix_mp;
0ac2586c 356 struct sg_table *sgt;
9b5833f7 357 unsigned int i;
0ac2586c 358
9b5833f7
TT
359 for (i = 0; i < format->num_planes; i++) {
360 sgt = vb2_dma_sg_plane_desc(vb, i);
361 if (!sgt)
362 return -EFAULT;
0ac2586c 363
9b5833f7
TT
364 buffer->addr[i] = sg_dma_address(sgt->sgl);
365 }
366
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;
374
375 return 0;
376}
377
378static int video_buf_prepare(struct vb2_buffer *vb)
379{
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;
0ac2586c 385
9b5833f7
TT
386 for (i = 0; i < format->num_planes; i++) {
387 if (format->plane_fmt[i].sizeimage > vb2_plane_size(vb, i))
388 return -EINVAL;
0ac2586c 389
9b5833f7
TT
390 vb2_set_plane_payload(vb, i, format->plane_fmt[i].sizeimage);
391 }
0ac2586c
TT
392
393 vbuf->field = V4L2_FIELD_NONE;
394
395 return 0;
396}
397
398static void video_buf_queue(struct vb2_buffer *vb)
399{
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);
404
405 video->ops->queue_buffer(video, buffer);
406}
407
408static int video_check_format(struct camss_video *video)
409{
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;
414
9b5833f7 415 sd_pix->pixelformat = pix->pixelformat;
0ac2586c
TT
416 ret = video_get_subdev_format(video, &format);
417 if (ret < 0)
418 return ret;
419
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 ||
0ac2586c
TT
424 pix->field != format.fmt.pix_mp.field)
425 return -EPIPE;
426
427 return 0;
428}
429
430static int video_start_streaming(struct vb2_queue *q, unsigned int count)
431{
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;
438
439 ret = media_pipeline_start(&vdev->entity, &video->pipe);
440 if (ret < 0)
441 return ret;
442
443 ret = video_check_format(video);
444 if (ret < 0)
445 goto error;
446
447 entity = &vdev->entity;
448 while (1) {
449 pad = &entity->pads[0];
450 if (!(pad->flags & MEDIA_PAD_FL_SINK))
451 break;
452
453 pad = media_entity_remote_pad(pad);
454 if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
455 break;
456
457 entity = pad->entity;
458 subdev = media_entity_to_v4l2_subdev(entity);
459
460 ret = v4l2_subdev_call(subdev, video, s_stream, 1);
461 if (ret < 0 && ret != -ENOIOCTLCMD)
462 goto error;
463 }
464
465 return 0;
466
467error:
468 media_pipeline_stop(&vdev->entity);
469
470 video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED);
471
472 return ret;
473}
474
475static void video_stop_streaming(struct vb2_queue *q)
476{
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;
0ac2586c
TT
482
483 entity = &vdev->entity;
484 while (1) {
485 pad = &entity->pads[0];
486 if (!(pad->flags & MEDIA_PAD_FL_SINK))
487 break;
488
489 pad = media_entity_remote_pad(pad);
490 if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
491 break;
492
493 entity = pad->entity;
494 subdev = media_entity_to_v4l2_subdev(entity);
495
9b5833f7 496 v4l2_subdev_call(subdev, video, s_stream, 0);
0ac2586c
TT
497 }
498
499 media_pipeline_stop(&vdev->entity);
500
501 video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR);
502}
503
504static 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,
9b5833f7 508 .buf_init = video_buf_init,
0ac2586c
TT
509 .buf_prepare = video_buf_prepare,
510 .buf_queue = video_buf_queue,
511 .start_streaming = video_start_streaming,
512 .stop_streaming = video_stop_streaming,
513};
514
515/* -----------------------------------------------------------------------------
516 * V4L2 ioctls
517 */
518
519static int video_querycap(struct file *file, void *fh,
520 struct v4l2_capability *cap)
521{
522 struct camss_video *video = video_drvdata(file);
523
c0decac1
MCC
524 strscpy(cap->driver, "qcom-camss", sizeof(cap->driver));
525 strscpy(cap->card, "Qualcomm Camera Subsystem", sizeof(cap->card));
0ac2586c
TT
526 snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
527 dev_name(video->camss->dev));
528
529 return 0;
530}
531
532static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
533{
534 struct camss_video *video = video_drvdata(file);
9b5833f7 535 int i, j, k;
0ac2586c
TT
536
537 if (f->type != video->type)
538 return -EINVAL;
539
9b5833f7
TT
540 if (f->index >= video->nformats)
541 return -EINVAL;
542
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;
550 }
551
552 if (j == i)
553 k++;
554
555 if (k == f->index)
556 break;
557 }
558
559 if (k < f->index)
0ac2586c
TT
560 return -EINVAL;
561
9b5833f7 562 f->pixelformat = video->formats[i].pixelformat;
0ac2586c
TT
563
564 return 0;
565}
566
567static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
568{
569 struct camss_video *video = video_drvdata(file);
570
571 *f = video->active_fmt;
572
573 return 0;
574}
575
576static int __video_try_fmt(struct camss_video *video, struct v4l2_format *f)
577{
578 struct v4l2_pix_format_mplane *pix_mp;
9b5833f7 579 const struct camss_format_info *fi;
7b4aff6f
TT
580 struct v4l2_plane_pix_format *p;
581 u32 bytesperline[3] = { 0 };
582 u32 sizeimage[3] = { 0 };
0ac2586c 583 u32 width, height;
7b4aff6f 584 u32 bpl, lines;
9b5833f7 585 int i, j;
0ac2586c
TT
586
587 pix_mp = &f->fmt.pix_mp;
588
7b4aff6f
TT
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);
597 }
598
9b5833f7
TT
599 for (j = 0; j < video->nformats; j++)
600 if (pix_mp->pixelformat == video->formats[j].pixelformat)
0ac2586c
TT
601 break;
602
9b5833f7 603 if (j == video->nformats)
0ac2586c
TT
604 j = 0; /* default format */
605
9b5833f7 606 fi = &video->formats[j];
0ac2586c
TT
607 width = pix_mp->width;
608 height = pix_mp->height;
609
610 memset(pix_mp, 0, sizeof(*pix_mp));
611
9b5833f7 612 pix_mp->pixelformat = fi->pixelformat;
0ac2586c
TT
613 pix_mp->width = clamp_t(u32, width, 1, 8191);
614 pix_mp->height = clamp_t(u32, height, 1, 8191);
9b5833f7
TT
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;
7b4aff6f 619 bpl = ALIGN(bpl, video->bpl_alignment);
9b5833f7
TT
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;
623 }
0ac2586c
TT
624
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);
632
7b4aff6f
TT
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;
642
643 if (p->bytesperline < bytesperline[i])
644 p->bytesperline = ALIGN(bytesperline[i], 8);
645
646 if (p->sizeimage < p->bytesperline * lines)
647 p->sizeimage = p->bytesperline * lines;
648
649 if (p->sizeimage < sizeimage[i])
650 p->sizeimage = sizeimage[i];
651 }
652
0ac2586c
TT
653 return 0;
654}
655
656static int video_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
657{
658 struct camss_video *video = video_drvdata(file);
659
660 return __video_try_fmt(video, f);
661}
662
663static int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
664{
665 struct camss_video *video = video_drvdata(file);
666 int ret;
667
668 if (vb2_is_busy(&video->vb2_q))
669 return -EBUSY;
670
671 ret = __video_try_fmt(video, f);
672 if (ret < 0)
673 return ret;
674
675 video->active_fmt = *f;
676
677 return 0;
678}
679
680static int video_enum_input(struct file *file, void *fh,
681 struct v4l2_input *input)
682{
683 if (input->index > 0)
684 return -EINVAL;
685
c0decac1 686 strscpy(input->name, "camera", sizeof(input->name));
0ac2586c
TT
687 input->type = V4L2_INPUT_TYPE_CAMERA;
688
689 return 0;
690}
691
692static int video_g_input(struct file *file, void *fh, unsigned int *input)
693{
694 *input = 0;
695
696 return 0;
697}
698
699static int video_s_input(struct file *file, void *fh, unsigned int input)
700{
701 return input == 0 ? 0 : -EINVAL;
702}
703
704static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = {
705 .vidioc_querycap = video_querycap,
7e98b7b5 706 .vidioc_enum_fmt_vid_cap = video_enum_fmt,
0ac2586c
TT
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,
722};
723
724/* -----------------------------------------------------------------------------
725 * V4L2 file operations
726 */
727
728static int video_open(struct file *file)
729{
730 struct video_device *vdev = video_devdata(file);
731 struct camss_video *video = video_drvdata(file);
732 struct v4l2_fh *vfh;
733 int ret;
734
735 mutex_lock(&video->lock);
736
737 vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
738 if (vfh == NULL) {
739 ret = -ENOMEM;
740 goto error_alloc;
741 }
742
743 v4l2_fh_init(vfh, vdev);
744 v4l2_fh_add(vfh);
745
746 file->private_data = vfh;
747
8fd390b8 748 ret = v4l2_pipeline_pm_get(&vdev->entity);
0ac2586c
TT
749 if (ret < 0) {
750 dev_err(video->camss->dev, "Failed to power up pipeline: %d\n",
751 ret);
752 goto error_pm_use;
753 }
754
755 mutex_unlock(&video->lock);
756
757 return 0;
758
759error_pm_use:
760 v4l2_fh_release(file);
761
762error_alloc:
763 mutex_unlock(&video->lock);
764
765 return ret;
766}
767
768static int video_release(struct file *file)
769{
770 struct video_device *vdev = video_devdata(file);
771
772 vb2_fop_release(file);
773
8fd390b8 774 v4l2_pipeline_pm_put(&vdev->entity);
0ac2586c
TT
775
776 file->private_data = NULL;
777
778 return 0;
779}
780
781static 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,
789};
790
791/* -----------------------------------------------------------------------------
792 * CAMSS video core
793 */
794
795static void msm_video_release(struct video_device *vdev)
796{
797 struct camss_video *video = video_get_drvdata(vdev);
798
799 media_entity_cleanup(&vdev->entity);
800
801 mutex_destroy(&video->q_lock);
802 mutex_destroy(&video->lock);
803
804 if (atomic_dec_and_test(&video->camss->ref_count))
805 camss_delete(video->camss);
806}
807
808/*
809 * msm_video_init_format - Helper function to initialize format
810 * @video: struct camss_video
811 *
812 * Initialize pad format with default value.
813 *
814 * Return 0 on success or a negative error code otherwise
815 */
816static int msm_video_init_format(struct camss_video *video)
817{
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,
9b5833f7 824 .pixelformat = video->formats[0].pixelformat,
0ac2586c
TT
825 },
826 };
827
828 ret = __video_try_fmt(video, &format);
829 if (ret < 0)
830 return ret;
831
832 video->active_fmt = format;
833
834 return 0;
835}
836
837/*
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
842 *
843 * Initialize and register a video device node to a V4L2 device. Also
844 * initialize the vb2 queue.
845 *
846 * Return 0 on success or a negative error code otherwise
847 */
848
849int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
9b5833f7 850 const char *name, int is_pix)
0ac2586c
TT
851{
852 struct media_pad *pad = &video->pad;
853 struct video_device *vdev;
854 struct vb2_queue *q;
855 int ret;
856
857 vdev = &video->vdev;
858
859 mutex_init(&video->q_lock);
860
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;
875 }
876
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;
883 }
884
885 mutex_init(&video->lock);
886
cba3819d
TT
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);
894 }
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);
902 }
903 } else {
904 goto error_video_register;
9b5833f7
TT
905 }
906
0ac2586c
TT
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;
911 }
912
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;
c0decac1 922 strscpy(vdev->name, name, sizeof(vdev->name));
0ac2586c 923
70cad449 924 ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
0ac2586c
TT
925 if (ret < 0) {
926 dev_err(v4l2_dev->dev, "Failed to register video device: %d\n",
927 ret);
928 goto error_video_register;
929 }
930
931 video_set_drvdata(vdev, video);
932 atomic_inc(&video->camss->ref_count);
933
934 return 0;
935
936error_video_register:
937 media_entity_cleanup(&vdev->entity);
938 mutex_destroy(&video->lock);
939error_media_init:
940 vb2_queue_release(&video->vb2_q);
941error_vb2_init:
942 mutex_destroy(&video->q_lock);
943
944 return ret;
945}
946
947void msm_video_stop_streaming(struct camss_video *video)
948{
949 if (vb2_is_streaming(&video->vb2_q))
950 vb2_queue_release(&video->vb2_q);
951}
952
953void msm_video_unregister(struct camss_video *video)
954{
955 atomic_inc(&video->camss->ref_count);
956 video_unregister_device(&video->vdev);
957 atomic_dec(&video->camss->ref_count);
958}