1 // SPDX-License-Identifier: GPL-2.0
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.
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"
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
{
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 /* -----------------------------------------------------------------------------
212 static int video_find_format(u32 code
, u32 pixelformat
,
213 const struct camss_format_info
*formats
,
214 unsigned int nformats
)
218 for (i
= 0; i
< nformats
; i
++) {
219 if (formats
[i
].code
== code
&&
220 formats
[i
].pixelformat
== pixelformat
)
224 for (i
= 0; i
< nformats
; i
++)
225 if (formats
[i
].code
== code
)
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
)
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
*
269 static struct v4l2_subdev
*video_remote_subdev(struct camss_video
*video
,
272 struct media_pad
*remote
;
274 remote
= media_entity_remote_pad(&video
->pad
);
276 if (!remote
|| !is_media_entity_v4l2_subdev(remote
->entity
))
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
;
293 subdev
= video_remote_subdev(video
, &pad
);
298 fmt
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
300 ret
= v4l2_subdev_call(subdev
, pad
, get_fmt
, NULL
, &fmt
);
304 ret
= video_find_format(fmt
.format
.code
,
305 format
->fmt
.pix_mp
.pixelformat
,
306 video
->formats
, video
->nformats
);
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
;
330 if (*num_planes
!= format
->num_planes
)
333 for (i
= 0; i
< *num_planes
; i
++)
334 if (sizes
[i
] < format
->plane_fmt
[i
].sizeimage
)
340 *num_planes
= format
->num_planes
;
342 for (i
= 0; i
< *num_planes
; i
++)
343 sizes
[i
] = format
->plane_fmt
[i
].sizeimage
;
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
,
354 const struct v4l2_pix_format_mplane
*format
=
355 &video
->active_fmt
.fmt
.pix_mp
;
356 struct sg_table
*sgt
;
359 for (i
= 0; i
< format
->num_planes
; i
++) {
360 sgt
= vb2_dma_sg_plane_desc(vb
, i
);
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
*
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
;
386 for (i
= 0; i
< format
->num_planes
; i
++) {
387 if (format
->plane_fmt
[i
].sizeimage
> vb2_plane_size(vb
, i
))
390 vb2_set_plane_payload(vb
, i
, format
->plane_fmt
[i
].sizeimage
);
393 vbuf
->field
= V4L2_FIELD_NONE
;
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
,
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
;
415 sd_pix
->pixelformat
= pix
->pixelformat
;
416 ret
= video_get_subdev_format(video
, &format
);
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
)
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
;
439 ret
= media_pipeline_start(&vdev
->entity
, &video
->pipe
);
443 ret
= video_check_format(video
);
447 entity
= &vdev
->entity
;
449 pad
= &entity
->pads
[0];
450 if (!(pad
->flags
& MEDIA_PAD_FL_SINK
))
453 pad
= media_entity_remote_pad(pad
);
454 if (!pad
|| !is_media_entity_v4l2_subdev(pad
->entity
))
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
)
468 media_pipeline_stop(&vdev
->entity
);
470 video
->ops
->flush_buffers(video
, VB2_BUF_STATE_QUEUED
);
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
;
485 pad
= &entity
->pads
[0];
486 if (!(pad
->flags
& MEDIA_PAD_FL_SINK
))
489 pad
= media_entity_remote_pad(pad
);
490 if (!pad
|| !is_media_entity_v4l2_subdev(pad
->entity
))
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 /* -----------------------------------------------------------------------------
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
));
532 static int video_enum_fmt(struct file
*file
, void *fh
, struct v4l2_fmtdesc
*f
)
534 struct camss_video
*video
= video_drvdata(file
);
537 if (f
->type
!= video
->type
)
540 if (f
->index
>= video
->nformats
)
543 /* find index "i" of "k"th unique pixelformat in formats array */
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
)
562 f
->pixelformat
= video
->formats
[i
].pixelformat
;
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
;
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 };
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
,
594 sizeimage
[i
] = clamp_t(u32
, p
->sizeimage
,
596 bytesperline
[i
] * 4096);
599 for (j
= 0; j
< video
->nformats
; j
++)
600 if (pix_mp
->pixelformat
== video
->formats
[j
].pixelformat
)
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
;
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
,
638 p
->sizeimage
= clamp_t(u32
, p
->sizeimage
,
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
];
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
);
668 if (vb2_is_busy(&video
->vb2_q
))
671 ret
= __video_try_fmt(video
, f
);
675 video
->active_fmt
= *f
;
680 static int video_enum_input(struct file
*file
, void *fh
,
681 struct v4l2_input
*input
)
683 if (input
->index
> 0)
686 strscpy(input
->name
, "camera", sizeof(input
->name
));
687 input
->type
= V4L2_INPUT_TYPE_CAMERA
;
692 static int video_g_input(struct file
*file
, void *fh
, unsigned int *input
)
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
);
735 mutex_lock(&video
->lock
);
737 vfh
= kzalloc(sizeof(*vfh
), GFP_KERNEL
);
743 v4l2_fh_init(vfh
, vdev
);
746 file
->private_data
= vfh
;
748 ret
= v4l2_pipeline_pm_use(&vdev
->entity
, 1);
750 dev_err(video
->camss
->dev
, "Failed to power up pipeline: %d\n",
755 mutex_unlock(&video
->lock
);
760 v4l2_fh_release(file
);
763 mutex_unlock(&video
->lock
);
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
;
781 static const struct v4l2_file_operations msm_vid_fops
= {
782 .owner
= THIS_MODULE
,
783 .unlocked_ioctl
= video_ioctl2
,
785 .release
= video_release
,
786 .poll
= vb2_fop_poll
,
787 .mmap
= vb2_fop_mmap
,
788 .read
= vb2_fop_read
,
791 /* -----------------------------------------------------------------------------
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
)
819 struct v4l2_format format
= {
820 .type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
,
824 .pixelformat
= video
->formats
[0].pixelformat
,
828 ret
= __video_try_fmt(video
, &format
);
832 video
->active_fmt
= format
;
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
;
859 mutex_init(&video
->q_lock
);
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
);
873 dev_err(v4l2_dev
->dev
, "Failed to init vb2 queue: %d\n", ret
);
877 pad
->flags
= MEDIA_PAD_FL_SINK
;
878 ret
= media_entity_pads_init(&vdev
->entity
, 1, pad
);
880 dev_err(v4l2_dev
->dev
, "Failed to init video entity: %d\n",
882 goto error_media_init
;
885 mutex_init(&video
->lock
);
887 if (video
->camss
->version
== CAMSS_8x16
) {
889 video
->formats
= formats_pix_8x16
;
890 video
->nformats
= ARRAY_SIZE(formats_pix_8x16
);
892 video
->formats
= formats_rdi_8x16
;
893 video
->nformats
= ARRAY_SIZE(formats_rdi_8x16
);
895 } else if (video
->camss
->version
== CAMSS_8x96
) {
897 video
->formats
= formats_pix_8x96
;
898 video
->nformats
= ARRAY_SIZE(formats_pix_8x96
);
900 video
->formats
= formats_rdi_8x96
;
901 video
->nformats
= ARRAY_SIZE(formats_rdi_8x96
);
904 goto error_video_register
;
907 ret
= msm_video_init_format(video
);
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
|
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);
926 dev_err(v4l2_dev
->dev
, "Failed to register video device: %d\n",
928 goto error_video_register
;
931 video_set_drvdata(vdev
, video
);
932 atomic_inc(&video
->camss
->ref_count
);
936 error_video_register
:
937 media_entity_cleanup(&vdev
->entity
);
938 mutex_destroy(&video
->lock
);
940 vb2_queue_release(&video
->vb2_q
);
942 mutex_destroy(&video
->q_lock
);
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
);