1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
4 * Author: Yong Deng <[email protected]>
5 * Copyright 2021-2022 Bootlin
6 * Author: Paul Kocialkowski <[email protected]>
7 */
8
9 #include <linux/of.h>
10 #include <linux/regmap.h>
11 #include <media/v4l2-device.h>
12 #include <media/v4l2-event.h>
13 #include <media/v4l2-ioctl.h>
14 #include <media/v4l2-mc.h>
15 #include <media/videobuf2-dma-contig.h>
16 #include <media/videobuf2-v4l2.h>
17
18 #include "sun6i_csi.h"
19 #include "sun6i_csi_bridge.h"
20 #include "sun6i_csi_capture.h"
21 #include "sun6i_csi_reg.h"
22
23 /* Helpers */
24
sun6i_csi_capture_dimensions(struct sun6i_csi_device * csi_dev,unsigned int * width,unsigned int * height)25 void sun6i_csi_capture_dimensions(struct sun6i_csi_device *csi_dev,
26 unsigned int *width, unsigned int *height)
27 {
28 if (width)
29 *width = csi_dev->capture.format.fmt.pix.width;
30 if (height)
31 *height = csi_dev->capture.format.fmt.pix.height;
32 }
33
sun6i_csi_capture_format(struct sun6i_csi_device * csi_dev,u32 * pixelformat,u32 * field)34 void sun6i_csi_capture_format(struct sun6i_csi_device *csi_dev,
35 u32 *pixelformat, u32 *field)
36 {
37 if (pixelformat)
38 *pixelformat = csi_dev->capture.format.fmt.pix.pixelformat;
39
40 if (field)
41 *field = csi_dev->capture.format.fmt.pix.field;
42 }
43
44 /* Format */
45
46 static const struct sun6i_csi_capture_format sun6i_csi_capture_formats[] = {
47 /* Bayer */
48 {
49 .pixelformat = V4L2_PIX_FMT_SBGGR8,
50 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
51 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
52 },
53 {
54 .pixelformat = V4L2_PIX_FMT_SGBRG8,
55 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
56 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
57 },
58 {
59 .pixelformat = V4L2_PIX_FMT_SGRBG8,
60 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
61 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
62 },
63 {
64 .pixelformat = V4L2_PIX_FMT_SRGGB8,
65 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
66 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
67 },
68 {
69 .pixelformat = V4L2_PIX_FMT_SBGGR10,
70 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10,
71 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10,
72 },
73 {
74 .pixelformat = V4L2_PIX_FMT_SGBRG10,
75 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10,
76 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10,
77 },
78 {
79 .pixelformat = V4L2_PIX_FMT_SGRBG10,
80 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10,
81 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10,
82 },
83 {
84 .pixelformat = V4L2_PIX_FMT_SRGGB10,
85 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10,
86 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10,
87 },
88 {
89 .pixelformat = V4L2_PIX_FMT_SBGGR12,
90 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12,
91 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12,
92 },
93 {
94 .pixelformat = V4L2_PIX_FMT_SGBRG12,
95 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12,
96 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12,
97 },
98 {
99 .pixelformat = V4L2_PIX_FMT_SGRBG12,
100 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12,
101 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12,
102 },
103 {
104 .pixelformat = V4L2_PIX_FMT_SRGGB12,
105 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12,
106 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12,
107 },
108 /* RGB */
109 {
110 .pixelformat = V4L2_PIX_FMT_RGB565,
111 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RGB565,
112 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RGB565,
113 },
114 {
115 .pixelformat = V4L2_PIX_FMT_RGB565X,
116 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RGB565,
117 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RGB565,
118 },
119 /* YUV422 */
120 {
121 .pixelformat = V4L2_PIX_FMT_YUYV,
122 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
123 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
124 .input_format_raw = true,
125 .hsize_len_factor = 2,
126 },
127 {
128 .pixelformat = V4L2_PIX_FMT_YVYU,
129 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
130 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
131 .input_format_raw = true,
132 .hsize_len_factor = 2,
133 },
134 {
135 .pixelformat = V4L2_PIX_FMT_UYVY,
136 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
137 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
138 .input_format_raw = true,
139 .hsize_len_factor = 2,
140 },
141 {
142 .pixelformat = V4L2_PIX_FMT_VYUY,
143 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
144 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
145 .input_format_raw = true,
146 .hsize_len_factor = 2,
147 },
148 {
149 .pixelformat = V4L2_PIX_FMT_NV16,
150 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP,
151 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422SP,
152 },
153 {
154 .pixelformat = V4L2_PIX_FMT_NV61,
155 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP,
156 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422SP,
157 .input_yuv_seq_invert = true,
158 },
159 {
160 .pixelformat = V4L2_PIX_FMT_YUV422P,
161 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422P,
162 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422P,
163 },
164 /* YUV420 */
165 {
166 .pixelformat = V4L2_PIX_FMT_NV12_16L16,
167 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420MB,
168 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420MB,
169 },
170 {
171 .pixelformat = V4L2_PIX_FMT_NV12,
172 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP,
173 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420SP,
174 },
175 {
176 .pixelformat = V4L2_PIX_FMT_NV21,
177 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP,
178 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420SP,
179 .input_yuv_seq_invert = true,
180 },
181
182 {
183 .pixelformat = V4L2_PIX_FMT_YUV420,
184 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420P,
185 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420P,
186 },
187 {
188 .pixelformat = V4L2_PIX_FMT_YVU420,
189 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420P,
190 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420P,
191 .input_yuv_seq_invert = true,
192 },
193 /* Compressed */
194 {
195 .pixelformat = V4L2_PIX_FMT_JPEG,
196 .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
197 .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
198 },
199 };
200
201 const
sun6i_csi_capture_format_find(u32 pixelformat)202 struct sun6i_csi_capture_format *sun6i_csi_capture_format_find(u32 pixelformat)
203 {
204 unsigned int i;
205
206 for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_formats); i++)
207 if (sun6i_csi_capture_formats[i].pixelformat == pixelformat)
208 return &sun6i_csi_capture_formats[i];
209
210 return NULL;
211 }
212
213 /* RAW formats need an exact match between pixel and mbus formats. */
214 static const
215 struct sun6i_csi_capture_format_match sun6i_csi_capture_format_matches[] = {
216 /* YUV420 */
217 {
218 .pixelformat = V4L2_PIX_FMT_YUYV,
219 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
220 },
221 {
222 .pixelformat = V4L2_PIX_FMT_YUYV,
223 .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16,
224 },
225 {
226 .pixelformat = V4L2_PIX_FMT_YVYU,
227 .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8,
228 },
229 {
230 .pixelformat = V4L2_PIX_FMT_YVYU,
231 .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16,
232 },
233 {
234 .pixelformat = V4L2_PIX_FMT_UYVY,
235 .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
236 },
237 {
238 .pixelformat = V4L2_PIX_FMT_UYVY,
239 .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16,
240 },
241 {
242 .pixelformat = V4L2_PIX_FMT_VYUY,
243 .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
244 },
245 {
246 .pixelformat = V4L2_PIX_FMT_VYUY,
247 .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16,
248 },
249 /* RGB */
250 {
251 .pixelformat = V4L2_PIX_FMT_RGB565,
252 .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
253 },
254 {
255 .pixelformat = V4L2_PIX_FMT_RGB565X,
256 .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_BE,
257 },
258 /* Bayer */
259 {
260 .pixelformat = V4L2_PIX_FMT_SBGGR8,
261 .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
262 },
263 {
264 .pixelformat = V4L2_PIX_FMT_SGBRG8,
265 .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
266 },
267 {
268 .pixelformat = V4L2_PIX_FMT_SGRBG8,
269 .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
270 },
271 {
272 .pixelformat = V4L2_PIX_FMT_SRGGB8,
273 .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
274 },
275 {
276 .pixelformat = V4L2_PIX_FMT_SBGGR10,
277 .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
278 },
279 {
280 .pixelformat = V4L2_PIX_FMT_SGBRG10,
281 .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
282 },
283 {
284 .pixelformat = V4L2_PIX_FMT_SGRBG10,
285 .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
286 },
287 {
288 .pixelformat = V4L2_PIX_FMT_SRGGB10,
289 .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
290 },
291 {
292 .pixelformat = V4L2_PIX_FMT_SBGGR12,
293 .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
294 },
295 {
296 .pixelformat = V4L2_PIX_FMT_SGBRG12,
297 .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
298 },
299 {
300 .pixelformat = V4L2_PIX_FMT_SGRBG12,
301 .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
302 },
303 {
304 .pixelformat = V4L2_PIX_FMT_SRGGB12,
305 .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
306 },
307 /* Compressed */
308 {
309 .pixelformat = V4L2_PIX_FMT_JPEG,
310 .mbus_code = MEDIA_BUS_FMT_JPEG_1X8,
311 },
312 };
313
sun6i_csi_capture_format_match(u32 pixelformat,u32 mbus_code)314 static bool sun6i_csi_capture_format_match(u32 pixelformat, u32 mbus_code)
315 {
316 unsigned int i;
317
318 for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_format_matches); i++) {
319 const struct sun6i_csi_capture_format_match *match =
320 &sun6i_csi_capture_format_matches[i];
321
322 if (match->pixelformat == pixelformat &&
323 match->mbus_code == mbus_code)
324 return true;
325 }
326
327 return false;
328 }
329
330 /* Capture */
331
332 static void
sun6i_csi_capture_buffer_configure(struct sun6i_csi_device * csi_dev,struct sun6i_csi_buffer * csi_buffer)333 sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev,
334 struct sun6i_csi_buffer *csi_buffer)
335 {
336 struct regmap *regmap = csi_dev->regmap;
337 const struct v4l2_format_info *info;
338 struct vb2_buffer *vb2_buffer;
339 unsigned int width, height;
340 dma_addr_t address;
341 u32 pixelformat;
342
343 vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf;
344 address = vb2_dma_contig_plane_dma_addr(vb2_buffer, 0);
345
346 regmap_write(regmap, SUN6I_CSI_CH_FIFO0_ADDR_REG,
347 SUN6I_CSI_ADDR_VALUE(address));
348
349 sun6i_csi_capture_dimensions(csi_dev, &width, &height);
350 sun6i_csi_capture_format(csi_dev, &pixelformat, NULL);
351
352 info = v4l2_format_info(pixelformat);
353 /* Unsupported formats are single-plane, so we can stop here. */
354 if (!info)
355 return;
356
357 if (info->comp_planes > 1) {
358 address += info->bpp[0] * width * height;
359
360 regmap_write(regmap, SUN6I_CSI_CH_FIFO1_ADDR_REG,
361 SUN6I_CSI_ADDR_VALUE(address));
362 }
363
364 if (info->comp_planes > 2) {
365 address += info->bpp[1] * DIV_ROUND_UP(width, info->hdiv) *
366 DIV_ROUND_UP(height, info->vdiv);
367
368 regmap_write(regmap, SUN6I_CSI_CH_FIFO2_ADDR_REG,
369 SUN6I_CSI_ADDR_VALUE(address));
370 }
371 }
372
sun6i_csi_capture_configure(struct sun6i_csi_device * csi_dev)373 void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev)
374 {
375 struct regmap *regmap = csi_dev->regmap;
376 const struct sun6i_csi_capture_format *format;
377 const struct v4l2_format_info *info;
378 u32 hsize_len, vsize_len;
379 u32 luma_line, chroma_line = 0;
380 u32 pixelformat, field;
381 u32 width, height;
382
383 sun6i_csi_capture_dimensions(csi_dev, &width, &height);
384 sun6i_csi_capture_format(csi_dev, &pixelformat, &field);
385
386 format = sun6i_csi_capture_format_find(pixelformat);
387 if (WARN_ON(!format))
388 return;
389
390 hsize_len = width;
391 vsize_len = height;
392
393 /*
394 * When using 8-bit raw input/output (for packed YUV), we need to adapt
395 * the width to account for the difference in bpp when it's not 8-bit.
396 */
397 if (format->hsize_len_factor)
398 hsize_len *= format->hsize_len_factor;
399
400 regmap_write(regmap, SUN6I_CSI_CH_HSIZE_REG,
401 SUN6I_CSI_CH_HSIZE_LEN(hsize_len) |
402 SUN6I_CSI_CH_HSIZE_START(0));
403
404 regmap_write(regmap, SUN6I_CSI_CH_VSIZE_REG,
405 SUN6I_CSI_CH_VSIZE_LEN(vsize_len) |
406 SUN6I_CSI_CH_VSIZE_START(0));
407
408 switch (pixelformat) {
409 case V4L2_PIX_FMT_RGB565X:
410 luma_line = width * 2;
411 break;
412 case V4L2_PIX_FMT_NV12_16L16:
413 luma_line = width;
414 chroma_line = width;
415 break;
416 case V4L2_PIX_FMT_JPEG:
417 luma_line = width;
418 break;
419 default:
420 info = v4l2_format_info(pixelformat);
421 if (WARN_ON(!info))
422 return;
423
424 luma_line = width * info->bpp[0];
425
426 if (info->comp_planes > 1)
427 chroma_line = width * info->bpp[1] / info->hdiv;
428 break;
429 }
430
431 regmap_write(regmap, SUN6I_CSI_CH_BUF_LEN_REG,
432 SUN6I_CSI_CH_BUF_LEN_CHROMA_LINE(chroma_line) |
433 SUN6I_CSI_CH_BUF_LEN_LUMA_LINE(luma_line));
434 }
435
436 /* State */
437
sun6i_csi_capture_state_cleanup(struct sun6i_csi_device * csi_dev,bool error)438 static void sun6i_csi_capture_state_cleanup(struct sun6i_csi_device *csi_dev,
439 bool error)
440 {
441 struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
442 struct sun6i_csi_buffer **csi_buffer_states[] = {
443 &state->pending, &state->current, &state->complete,
444 };
445 struct sun6i_csi_buffer *csi_buffer;
446 struct vb2_buffer *vb2_buffer;
447 unsigned long flags;
448 unsigned int i;
449
450 spin_lock_irqsave(&state->lock, flags);
451
452 for (i = 0; i < ARRAY_SIZE(csi_buffer_states); i++) {
453 csi_buffer = *csi_buffer_states[i];
454 if (!csi_buffer)
455 continue;
456
457 vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf;
458 vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR :
459 VB2_BUF_STATE_QUEUED);
460
461 *csi_buffer_states[i] = NULL;
462 }
463
464 list_for_each_entry(csi_buffer, &state->queue, list) {
465 vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf;
466 vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR :
467 VB2_BUF_STATE_QUEUED);
468 }
469
470 INIT_LIST_HEAD(&state->queue);
471
472 spin_unlock_irqrestore(&state->lock, flags);
473 }
474
sun6i_csi_capture_state_update(struct sun6i_csi_device * csi_dev)475 void sun6i_csi_capture_state_update(struct sun6i_csi_device *csi_dev)
476 {
477 struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
478 struct sun6i_csi_buffer *csi_buffer;
479 unsigned long flags;
480
481 spin_lock_irqsave(&state->lock, flags);
482
483 if (list_empty(&state->queue))
484 goto complete;
485
486 if (state->pending)
487 goto complete;
488
489 csi_buffer = list_first_entry(&state->queue, struct sun6i_csi_buffer,
490 list);
491
492 sun6i_csi_capture_buffer_configure(csi_dev, csi_buffer);
493
494 list_del(&csi_buffer->list);
495
496 state->pending = csi_buffer;
497
498 complete:
499 spin_unlock_irqrestore(&state->lock, flags);
500 }
501
sun6i_csi_capture_state_complete(struct sun6i_csi_device * csi_dev)502 static void sun6i_csi_capture_state_complete(struct sun6i_csi_device *csi_dev)
503 {
504 struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
505 unsigned long flags;
506
507 spin_lock_irqsave(&state->lock, flags);
508
509 if (!state->pending)
510 goto complete;
511
512 state->complete = state->current;
513 state->current = state->pending;
514 state->pending = NULL;
515
516 if (state->complete) {
517 struct sun6i_csi_buffer *csi_buffer = state->complete;
518 struct vb2_buffer *vb2_buffer =
519 &csi_buffer->v4l2_buffer.vb2_buf;
520
521 vb2_buffer->timestamp = ktime_get_ns();
522 csi_buffer->v4l2_buffer.sequence = state->sequence;
523
524 vb2_buffer_done(vb2_buffer, VB2_BUF_STATE_DONE);
525
526 state->complete = NULL;
527 }
528
529 complete:
530 spin_unlock_irqrestore(&state->lock, flags);
531 }
532
sun6i_csi_capture_frame_done(struct sun6i_csi_device * csi_dev)533 void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev)
534 {
535 struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
536 unsigned long flags;
537
538 spin_lock_irqsave(&state->lock, flags);
539 state->sequence++;
540 spin_unlock_irqrestore(&state->lock, flags);
541 }
542
sun6i_csi_capture_sync(struct sun6i_csi_device * csi_dev)543 void sun6i_csi_capture_sync(struct sun6i_csi_device *csi_dev)
544 {
545 sun6i_csi_capture_state_complete(csi_dev);
546 sun6i_csi_capture_state_update(csi_dev);
547 }
548
549 /* Queue */
550
sun6i_csi_capture_queue_setup(struct vb2_queue * queue,unsigned int * buffers_count,unsigned int * planes_count,unsigned int sizes[],struct device * alloc_devs[])551 static int sun6i_csi_capture_queue_setup(struct vb2_queue *queue,
552 unsigned int *buffers_count,
553 unsigned int *planes_count,
554 unsigned int sizes[],
555 struct device *alloc_devs[])
556 {
557 struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
558 unsigned int size = csi_dev->capture.format.fmt.pix.sizeimage;
559
560 if (*planes_count)
561 return sizes[0] < size ? -EINVAL : 0;
562
563 *planes_count = 1;
564 sizes[0] = size;
565
566 return 0;
567 }
568
sun6i_csi_capture_buffer_prepare(struct vb2_buffer * buffer)569 static int sun6i_csi_capture_buffer_prepare(struct vb2_buffer *buffer)
570 {
571 struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue);
572 struct sun6i_csi_capture *capture = &csi_dev->capture;
573 struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev;
574 struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer);
575 unsigned long size = capture->format.fmt.pix.sizeimage;
576
577 if (vb2_plane_size(buffer, 0) < size) {
578 v4l2_err(v4l2_dev, "buffer too small (%lu < %lu)\n",
579 vb2_plane_size(buffer, 0), size);
580 return -EINVAL;
581 }
582
583 vb2_set_plane_payload(buffer, 0, size);
584
585 v4l2_buffer->field = capture->format.fmt.pix.field;
586
587 return 0;
588 }
589
sun6i_csi_capture_buffer_queue(struct vb2_buffer * buffer)590 static void sun6i_csi_capture_buffer_queue(struct vb2_buffer *buffer)
591 {
592 struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue);
593 struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
594 struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer);
595 struct sun6i_csi_buffer *csi_buffer =
596 container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer);
597 unsigned long flags;
598
599 spin_lock_irqsave(&state->lock, flags);
600 list_add_tail(&csi_buffer->list, &state->queue);
601 spin_unlock_irqrestore(&state->lock, flags);
602 }
603
sun6i_csi_capture_start_streaming(struct vb2_queue * queue,unsigned int count)604 static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue,
605 unsigned int count)
606 {
607 struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
608 struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
609 struct video_device *video_dev = &csi_dev->capture.video_dev;
610 struct v4l2_subdev *subdev = &csi_dev->bridge.subdev;
611 int ret;
612
613 state->sequence = 0;
614
615 ret = video_device_pipeline_alloc_start(video_dev);
616 if (ret < 0)
617 goto error_state;
618
619 state->streaming = true;
620
621 ret = v4l2_subdev_call(subdev, video, s_stream, 1);
622 if (ret && ret != -ENOIOCTLCMD)
623 goto error_streaming;
624
625 return 0;
626
627 error_streaming:
628 state->streaming = false;
629
630 video_device_pipeline_stop(video_dev);
631
632 error_state:
633 sun6i_csi_capture_state_cleanup(csi_dev, false);
634
635 return ret;
636 }
637
sun6i_csi_capture_stop_streaming(struct vb2_queue * queue)638 static void sun6i_csi_capture_stop_streaming(struct vb2_queue *queue)
639 {
640 struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
641 struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
642 struct video_device *video_dev = &csi_dev->capture.video_dev;
643 struct v4l2_subdev *subdev = &csi_dev->bridge.subdev;
644
645 v4l2_subdev_call(subdev, video, s_stream, 0);
646
647 state->streaming = false;
648
649 video_device_pipeline_stop(video_dev);
650
651 sun6i_csi_capture_state_cleanup(csi_dev, true);
652 }
653
654 static const struct vb2_ops sun6i_csi_capture_queue_ops = {
655 .queue_setup = sun6i_csi_capture_queue_setup,
656 .buf_prepare = sun6i_csi_capture_buffer_prepare,
657 .buf_queue = sun6i_csi_capture_buffer_queue,
658 .start_streaming = sun6i_csi_capture_start_streaming,
659 .stop_streaming = sun6i_csi_capture_stop_streaming,
660 };
661
662 /* V4L2 Device */
663
sun6i_csi_capture_format_prepare(struct v4l2_format * format)664 static void sun6i_csi_capture_format_prepare(struct v4l2_format *format)
665 {
666 struct v4l2_pix_format *pix_format = &format->fmt.pix;
667 const struct v4l2_format_info *info;
668 unsigned int width, height;
669
670 v4l_bound_align_image(&pix_format->width, SUN6I_CSI_CAPTURE_WIDTH_MIN,
671 SUN6I_CSI_CAPTURE_WIDTH_MAX, 1,
672 &pix_format->height, SUN6I_CSI_CAPTURE_HEIGHT_MIN,
673 SUN6I_CSI_CAPTURE_HEIGHT_MAX, 1, 0);
674
675 if (!sun6i_csi_capture_format_find(pix_format->pixelformat))
676 pix_format->pixelformat =
677 sun6i_csi_capture_formats[0].pixelformat;
678
679 width = pix_format->width;
680 height = pix_format->height;
681
682 info = v4l2_format_info(pix_format->pixelformat);
683
684 switch (pix_format->pixelformat) {
685 case V4L2_PIX_FMT_NV12_16L16:
686 pix_format->bytesperline = width * 12 / 8;
687 pix_format->sizeimage = pix_format->bytesperline * height;
688 break;
689 case V4L2_PIX_FMT_JPEG:
690 pix_format->bytesperline = width;
691 pix_format->sizeimage = pix_format->bytesperline * height;
692 break;
693 default:
694 v4l2_fill_pixfmt(pix_format, pix_format->pixelformat,
695 width, height);
696 break;
697 }
698
699 if (pix_format->field == V4L2_FIELD_ANY)
700 pix_format->field = V4L2_FIELD_NONE;
701
702 if (pix_format->pixelformat == V4L2_PIX_FMT_JPEG)
703 pix_format->colorspace = V4L2_COLORSPACE_JPEG;
704 else if (info && info->pixel_enc == V4L2_PIXEL_ENC_BAYER)
705 pix_format->colorspace = V4L2_COLORSPACE_RAW;
706 else
707 pix_format->colorspace = V4L2_COLORSPACE_SRGB;
708
709 pix_format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
710 pix_format->quantization = V4L2_QUANTIZATION_DEFAULT;
711 pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
712 }
713
sun6i_csi_capture_querycap(struct file * file,void * private,struct v4l2_capability * capability)714 static int sun6i_csi_capture_querycap(struct file *file, void *private,
715 struct v4l2_capability *capability)
716 {
717 struct sun6i_csi_device *csi_dev = video_drvdata(file);
718 struct video_device *video_dev = &csi_dev->capture.video_dev;
719
720 strscpy(capability->driver, SUN6I_CSI_NAME, sizeof(capability->driver));
721 strscpy(capability->card, video_dev->name, sizeof(capability->card));
722 snprintf(capability->bus_info, sizeof(capability->bus_info),
723 "platform:%s", dev_name(csi_dev->dev));
724
725 return 0;
726 }
727
sun6i_csi_capture_enum_fmt(struct file * file,void * private,struct v4l2_fmtdesc * fmtdesc)728 static int sun6i_csi_capture_enum_fmt(struct file *file, void *private,
729 struct v4l2_fmtdesc *fmtdesc)
730 {
731 u32 index = fmtdesc->index;
732
733 if (index >= ARRAY_SIZE(sun6i_csi_capture_formats))
734 return -EINVAL;
735
736 fmtdesc->pixelformat = sun6i_csi_capture_formats[index].pixelformat;
737
738 return 0;
739 }
740
sun6i_csi_capture_g_fmt(struct file * file,void * private,struct v4l2_format * format)741 static int sun6i_csi_capture_g_fmt(struct file *file, void *private,
742 struct v4l2_format *format)
743 {
744 struct sun6i_csi_device *csi_dev = video_drvdata(file);
745
746 *format = csi_dev->capture.format;
747
748 return 0;
749 }
750
sun6i_csi_capture_s_fmt(struct file * file,void * private,struct v4l2_format * format)751 static int sun6i_csi_capture_s_fmt(struct file *file, void *private,
752 struct v4l2_format *format)
753 {
754 struct sun6i_csi_device *csi_dev = video_drvdata(file);
755 struct sun6i_csi_capture *capture = &csi_dev->capture;
756
757 if (vb2_is_busy(&capture->queue))
758 return -EBUSY;
759
760 sun6i_csi_capture_format_prepare(format);
761
762 csi_dev->capture.format = *format;
763
764 return 0;
765 }
766
sun6i_csi_capture_try_fmt(struct file * file,void * private,struct v4l2_format * format)767 static int sun6i_csi_capture_try_fmt(struct file *file, void *private,
768 struct v4l2_format *format)
769 {
770 sun6i_csi_capture_format_prepare(format);
771
772 return 0;
773 }
774
sun6i_csi_capture_enum_input(struct file * file,void * private,struct v4l2_input * input)775 static int sun6i_csi_capture_enum_input(struct file *file, void *private,
776 struct v4l2_input *input)
777 {
778 if (input->index != 0)
779 return -EINVAL;
780
781 input->type = V4L2_INPUT_TYPE_CAMERA;
782 strscpy(input->name, "Camera", sizeof(input->name));
783
784 return 0;
785 }
786
sun6i_csi_capture_g_input(struct file * file,void * private,unsigned int * index)787 static int sun6i_csi_capture_g_input(struct file *file, void *private,
788 unsigned int *index)
789 {
790 *index = 0;
791
792 return 0;
793 }
794
sun6i_csi_capture_s_input(struct file * file,void * private,unsigned int index)795 static int sun6i_csi_capture_s_input(struct file *file, void *private,
796 unsigned int index)
797 {
798 if (index != 0)
799 return -EINVAL;
800
801 return 0;
802 }
803
804 static const struct v4l2_ioctl_ops sun6i_csi_capture_ioctl_ops = {
805 .vidioc_querycap = sun6i_csi_capture_querycap,
806
807 .vidioc_enum_fmt_vid_cap = sun6i_csi_capture_enum_fmt,
808 .vidioc_g_fmt_vid_cap = sun6i_csi_capture_g_fmt,
809 .vidioc_s_fmt_vid_cap = sun6i_csi_capture_s_fmt,
810 .vidioc_try_fmt_vid_cap = sun6i_csi_capture_try_fmt,
811
812 .vidioc_enum_input = sun6i_csi_capture_enum_input,
813 .vidioc_g_input = sun6i_csi_capture_g_input,
814 .vidioc_s_input = sun6i_csi_capture_s_input,
815
816 .vidioc_create_bufs = vb2_ioctl_create_bufs,
817 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
818 .vidioc_reqbufs = vb2_ioctl_reqbufs,
819 .vidioc_querybuf = vb2_ioctl_querybuf,
820 .vidioc_expbuf = vb2_ioctl_expbuf,
821 .vidioc_qbuf = vb2_ioctl_qbuf,
822 .vidioc_dqbuf = vb2_ioctl_dqbuf,
823 .vidioc_streamon = vb2_ioctl_streamon,
824 .vidioc_streamoff = vb2_ioctl_streamoff,
825 };
826
827 /* V4L2 File */
828
sun6i_csi_capture_open(struct file * file)829 static int sun6i_csi_capture_open(struct file *file)
830 {
831 struct sun6i_csi_device *csi_dev = video_drvdata(file);
832 struct sun6i_csi_capture *capture = &csi_dev->capture;
833 int ret;
834
835 if (mutex_lock_interruptible(&capture->lock))
836 return -ERESTARTSYS;
837
838 ret = v4l2_pipeline_pm_get(&capture->video_dev.entity);
839 if (ret < 0)
840 goto error_lock;
841
842 ret = v4l2_fh_open(file);
843 if (ret < 0)
844 goto error_pipeline;
845
846 mutex_unlock(&capture->lock);
847
848 return 0;
849
850 error_pipeline:
851 v4l2_pipeline_pm_put(&capture->video_dev.entity);
852
853 error_lock:
854 mutex_unlock(&capture->lock);
855
856 return ret;
857 }
858
sun6i_csi_capture_close(struct file * file)859 static int sun6i_csi_capture_close(struct file *file)
860 {
861 struct sun6i_csi_device *csi_dev = video_drvdata(file);
862 struct sun6i_csi_capture *capture = &csi_dev->capture;
863
864 mutex_lock(&capture->lock);
865
866 _vb2_fop_release(file, NULL);
867 v4l2_pipeline_pm_put(&capture->video_dev.entity);
868
869 mutex_unlock(&capture->lock);
870
871 return 0;
872 }
873
874 static const struct v4l2_file_operations sun6i_csi_capture_fops = {
875 .owner = THIS_MODULE,
876 .open = sun6i_csi_capture_open,
877 .release = sun6i_csi_capture_close,
878 .unlocked_ioctl = video_ioctl2,
879 .mmap = vb2_fop_mmap,
880 .poll = vb2_fop_poll
881 };
882
883 /* Media Entity */
884
sun6i_csi_capture_link_validate(struct media_link * link)885 static int sun6i_csi_capture_link_validate(struct media_link *link)
886 {
887 struct video_device *video_dev =
888 media_entity_to_video_device(link->sink->entity);
889 struct sun6i_csi_device *csi_dev = video_get_drvdata(video_dev);
890 struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev;
891 const struct sun6i_csi_capture_format *capture_format;
892 const struct sun6i_csi_bridge_format *bridge_format;
893 unsigned int capture_width, capture_height;
894 unsigned int bridge_width, bridge_height;
895 const struct v4l2_format_info *format_info;
896 u32 pixelformat, capture_field;
897 u32 mbus_code, bridge_field;
898 bool match;
899
900 sun6i_csi_capture_dimensions(csi_dev, &capture_width, &capture_height);
901
902 sun6i_csi_capture_format(csi_dev, &pixelformat, &capture_field);
903 capture_format = sun6i_csi_capture_format_find(pixelformat);
904 if (WARN_ON(!capture_format))
905 return -EINVAL;
906
907 sun6i_csi_bridge_dimensions(csi_dev, &bridge_width, &bridge_height);
908
909 sun6i_csi_bridge_format(csi_dev, &mbus_code, &bridge_field);
910 bridge_format = sun6i_csi_bridge_format_find(mbus_code);
911 if (WARN_ON(!bridge_format))
912 return -EINVAL;
913
914 /* No cropping/scaling is supported. */
915 if (capture_width != bridge_width || capture_height != bridge_height) {
916 v4l2_err(v4l2_dev,
917 "invalid input/output dimensions: %ux%u/%ux%u\n",
918 bridge_width, bridge_height, capture_width,
919 capture_height);
920 return -EINVAL;
921 }
922
923 format_info = v4l2_format_info(pixelformat);
924 /* Some formats are not listed. */
925 if (!format_info)
926 return 0;
927
928 if (format_info->pixel_enc == V4L2_PIXEL_ENC_BAYER &&
929 bridge_format->input_format != SUN6I_CSI_INPUT_FMT_RAW)
930 goto invalid;
931
932 if (format_info->pixel_enc == V4L2_PIXEL_ENC_RGB &&
933 bridge_format->input_format != SUN6I_CSI_INPUT_FMT_RAW)
934 goto invalid;
935
936 if (format_info->pixel_enc == V4L2_PIXEL_ENC_YUV) {
937 if (bridge_format->input_format != SUN6I_CSI_INPUT_FMT_YUV420 &&
938 bridge_format->input_format != SUN6I_CSI_INPUT_FMT_YUV422)
939 goto invalid;
940
941 /* YUV420 input can't produce YUV422 output. */
942 if (bridge_format->input_format == SUN6I_CSI_INPUT_FMT_YUV420 &&
943 format_info->vdiv == 1)
944 goto invalid;
945 }
946
947 /* With raw input mode, we need a 1:1 match between input and output. */
948 if (bridge_format->input_format == SUN6I_CSI_INPUT_FMT_RAW ||
949 capture_format->input_format_raw) {
950 match = sun6i_csi_capture_format_match(pixelformat, mbus_code);
951 if (!match)
952 goto invalid;
953 }
954
955 return 0;
956
957 invalid:
958 v4l2_err(v4l2_dev, "invalid input/output format combination\n");
959 return -EINVAL;
960 }
961
962 static const struct media_entity_operations sun6i_csi_capture_media_ops = {
963 .link_validate = sun6i_csi_capture_link_validate
964 };
965
966 /* Capture */
967
sun6i_csi_capture_setup(struct sun6i_csi_device * csi_dev)968 int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev)
969 {
970 struct sun6i_csi_capture *capture = &csi_dev->capture;
971 struct sun6i_csi_capture_state *state = &capture->state;
972 struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev;
973 struct v4l2_subdev *bridge_subdev = &csi_dev->bridge.subdev;
974 struct video_device *video_dev = &capture->video_dev;
975 struct vb2_queue *queue = &capture->queue;
976 struct media_pad *pad = &capture->pad;
977 struct v4l2_format *format = &csi_dev->capture.format;
978 struct v4l2_pix_format *pix_format = &format->fmt.pix;
979 int ret;
980
981 /* This may happen with multiple bridge notifier bound calls. */
982 if (state->setup)
983 return 0;
984
985 /* State */
986
987 INIT_LIST_HEAD(&state->queue);
988 spin_lock_init(&state->lock);
989
990 /* Media Entity */
991
992 video_dev->entity.ops = &sun6i_csi_capture_media_ops;
993
994 /* Media Pad */
995
996 pad->flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
997
998 ret = media_entity_pads_init(&video_dev->entity, 1, pad);
999 if (ret < 0)
1000 return ret;
1001
1002 /* Queue */
1003
1004 mutex_init(&capture->lock);
1005
1006 queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1007 queue->io_modes = VB2_MMAP | VB2_DMABUF;
1008 queue->buf_struct_size = sizeof(struct sun6i_csi_buffer);
1009 queue->ops = &sun6i_csi_capture_queue_ops;
1010 queue->mem_ops = &vb2_dma_contig_memops;
1011 queue->min_queued_buffers = 2;
1012 queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1013 queue->lock = &capture->lock;
1014 queue->dev = csi_dev->dev;
1015 queue->drv_priv = csi_dev;
1016
1017 ret = vb2_queue_init(queue);
1018 if (ret) {
1019 v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret);
1020 goto error_media_entity;
1021 }
1022
1023 /* V4L2 Format */
1024
1025 format->type = queue->type;
1026 pix_format->pixelformat = sun6i_csi_capture_formats[0].pixelformat;
1027 pix_format->width = 1280;
1028 pix_format->height = 720;
1029 pix_format->field = V4L2_FIELD_NONE;
1030
1031 sun6i_csi_capture_format_prepare(format);
1032
1033 /* Video Device */
1034
1035 strscpy(video_dev->name, SUN6I_CSI_CAPTURE_NAME,
1036 sizeof(video_dev->name));
1037 video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
1038 video_dev->vfl_dir = VFL_DIR_RX;
1039 video_dev->release = video_device_release_empty;
1040 video_dev->fops = &sun6i_csi_capture_fops;
1041 video_dev->ioctl_ops = &sun6i_csi_capture_ioctl_ops;
1042 video_dev->v4l2_dev = v4l2_dev;
1043 video_dev->queue = queue;
1044 video_dev->lock = &capture->lock;
1045
1046 video_set_drvdata(video_dev, csi_dev);
1047
1048 ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1);
1049 if (ret < 0) {
1050 v4l2_err(v4l2_dev, "failed to register video device: %d\n",
1051 ret);
1052 goto error_media_entity;
1053 }
1054
1055 /* Media Pad Link */
1056
1057 ret = media_create_pad_link(&bridge_subdev->entity,
1058 SUN6I_CSI_BRIDGE_PAD_SOURCE,
1059 &video_dev->entity, 0,
1060 csi_dev->isp_available ? 0 :
1061 MEDIA_LNK_FL_ENABLED |
1062 MEDIA_LNK_FL_IMMUTABLE);
1063 if (ret < 0) {
1064 v4l2_err(v4l2_dev, "failed to create %s:%u -> %s:%u link\n",
1065 bridge_subdev->entity.name,
1066 SUN6I_CSI_BRIDGE_PAD_SOURCE,
1067 video_dev->entity.name, 0);
1068 goto error_video_device;
1069 }
1070
1071 state->setup = true;
1072
1073 return 0;
1074
1075 error_video_device:
1076 vb2_video_unregister_device(video_dev);
1077
1078 error_media_entity:
1079 media_entity_cleanup(&video_dev->entity);
1080
1081 mutex_destroy(&capture->lock);
1082
1083 return ret;
1084 }
1085
sun6i_csi_capture_cleanup(struct sun6i_csi_device * csi_dev)1086 void sun6i_csi_capture_cleanup(struct sun6i_csi_device *csi_dev)
1087 {
1088 struct sun6i_csi_capture *capture = &csi_dev->capture;
1089 struct video_device *video_dev = &capture->video_dev;
1090
1091 /* This may happen if async registration failed to complete. */
1092 if (!capture->state.setup)
1093 return;
1094
1095 vb2_video_unregister_device(video_dev);
1096 media_entity_cleanup(&video_dev->entity);
1097 mutex_destroy(&capture->lock);
1098
1099 capture->state.setup = false;
1100 }
1101