1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
4 * Author: Yong Deng <yong.deng@magewell.com>
5 * Copyright 2021-2022 Bootlin
6 * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
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 .wait_prepare = vb2_ops_wait_prepare,
661 .wait_finish = vb2_ops_wait_finish,
662 };
663
664 /* V4L2 Device */
665
sun6i_csi_capture_format_prepare(struct v4l2_format * format)666 static void sun6i_csi_capture_format_prepare(struct v4l2_format *format)
667 {
668 struct v4l2_pix_format *pix_format = &format->fmt.pix;
669 const struct v4l2_format_info *info;
670 unsigned int width, height;
671
672 v4l_bound_align_image(&pix_format->width, SUN6I_CSI_CAPTURE_WIDTH_MIN,
673 SUN6I_CSI_CAPTURE_WIDTH_MAX, 1,
674 &pix_format->height, SUN6I_CSI_CAPTURE_HEIGHT_MIN,
675 SUN6I_CSI_CAPTURE_HEIGHT_MAX, 1, 0);
676
677 if (!sun6i_csi_capture_format_find(pix_format->pixelformat))
678 pix_format->pixelformat =
679 sun6i_csi_capture_formats[0].pixelformat;
680
681 width = pix_format->width;
682 height = pix_format->height;
683
684 info = v4l2_format_info(pix_format->pixelformat);
685
686 switch (pix_format->pixelformat) {
687 case V4L2_PIX_FMT_NV12_16L16:
688 pix_format->bytesperline = width * 12 / 8;
689 pix_format->sizeimage = pix_format->bytesperline * height;
690 break;
691 case V4L2_PIX_FMT_JPEG:
692 pix_format->bytesperline = width;
693 pix_format->sizeimage = pix_format->bytesperline * height;
694 break;
695 default:
696 v4l2_fill_pixfmt(pix_format, pix_format->pixelformat,
697 width, height);
698 break;
699 }
700
701 if (pix_format->field == V4L2_FIELD_ANY)
702 pix_format->field = V4L2_FIELD_NONE;
703
704 if (pix_format->pixelformat == V4L2_PIX_FMT_JPEG)
705 pix_format->colorspace = V4L2_COLORSPACE_JPEG;
706 else if (info && info->pixel_enc == V4L2_PIXEL_ENC_BAYER)
707 pix_format->colorspace = V4L2_COLORSPACE_RAW;
708 else
709 pix_format->colorspace = V4L2_COLORSPACE_SRGB;
710
711 pix_format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
712 pix_format->quantization = V4L2_QUANTIZATION_DEFAULT;
713 pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
714 }
715
sun6i_csi_capture_querycap(struct file * file,void * private,struct v4l2_capability * capability)716 static int sun6i_csi_capture_querycap(struct file *file, void *private,
717 struct v4l2_capability *capability)
718 {
719 struct sun6i_csi_device *csi_dev = video_drvdata(file);
720 struct video_device *video_dev = &csi_dev->capture.video_dev;
721
722 strscpy(capability->driver, SUN6I_CSI_NAME, sizeof(capability->driver));
723 strscpy(capability->card, video_dev->name, sizeof(capability->card));
724 snprintf(capability->bus_info, sizeof(capability->bus_info),
725 "platform:%s", dev_name(csi_dev->dev));
726
727 return 0;
728 }
729
sun6i_csi_capture_enum_fmt(struct file * file,void * private,struct v4l2_fmtdesc * fmtdesc)730 static int sun6i_csi_capture_enum_fmt(struct file *file, void *private,
731 struct v4l2_fmtdesc *fmtdesc)
732 {
733 u32 index = fmtdesc->index;
734
735 if (index >= ARRAY_SIZE(sun6i_csi_capture_formats))
736 return -EINVAL;
737
738 fmtdesc->pixelformat = sun6i_csi_capture_formats[index].pixelformat;
739
740 return 0;
741 }
742
sun6i_csi_capture_g_fmt(struct file * file,void * private,struct v4l2_format * format)743 static int sun6i_csi_capture_g_fmt(struct file *file, void *private,
744 struct v4l2_format *format)
745 {
746 struct sun6i_csi_device *csi_dev = video_drvdata(file);
747
748 *format = csi_dev->capture.format;
749
750 return 0;
751 }
752
sun6i_csi_capture_s_fmt(struct file * file,void * private,struct v4l2_format * format)753 static int sun6i_csi_capture_s_fmt(struct file *file, void *private,
754 struct v4l2_format *format)
755 {
756 struct sun6i_csi_device *csi_dev = video_drvdata(file);
757 struct sun6i_csi_capture *capture = &csi_dev->capture;
758
759 if (vb2_is_busy(&capture->queue))
760 return -EBUSY;
761
762 sun6i_csi_capture_format_prepare(format);
763
764 csi_dev->capture.format = *format;
765
766 return 0;
767 }
768
sun6i_csi_capture_try_fmt(struct file * file,void * private,struct v4l2_format * format)769 static int sun6i_csi_capture_try_fmt(struct file *file, void *private,
770 struct v4l2_format *format)
771 {
772 sun6i_csi_capture_format_prepare(format);
773
774 return 0;
775 }
776
sun6i_csi_capture_enum_input(struct file * file,void * private,struct v4l2_input * input)777 static int sun6i_csi_capture_enum_input(struct file *file, void *private,
778 struct v4l2_input *input)
779 {
780 if (input->index != 0)
781 return -EINVAL;
782
783 input->type = V4L2_INPUT_TYPE_CAMERA;
784 strscpy(input->name, "Camera", sizeof(input->name));
785
786 return 0;
787 }
788
sun6i_csi_capture_g_input(struct file * file,void * private,unsigned int * index)789 static int sun6i_csi_capture_g_input(struct file *file, void *private,
790 unsigned int *index)
791 {
792 *index = 0;
793
794 return 0;
795 }
796
sun6i_csi_capture_s_input(struct file * file,void * private,unsigned int index)797 static int sun6i_csi_capture_s_input(struct file *file, void *private,
798 unsigned int index)
799 {
800 if (index != 0)
801 return -EINVAL;
802
803 return 0;
804 }
805
806 static const struct v4l2_ioctl_ops sun6i_csi_capture_ioctl_ops = {
807 .vidioc_querycap = sun6i_csi_capture_querycap,
808
809 .vidioc_enum_fmt_vid_cap = sun6i_csi_capture_enum_fmt,
810 .vidioc_g_fmt_vid_cap = sun6i_csi_capture_g_fmt,
811 .vidioc_s_fmt_vid_cap = sun6i_csi_capture_s_fmt,
812 .vidioc_try_fmt_vid_cap = sun6i_csi_capture_try_fmt,
813
814 .vidioc_enum_input = sun6i_csi_capture_enum_input,
815 .vidioc_g_input = sun6i_csi_capture_g_input,
816 .vidioc_s_input = sun6i_csi_capture_s_input,
817
818 .vidioc_create_bufs = vb2_ioctl_create_bufs,
819 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
820 .vidioc_reqbufs = vb2_ioctl_reqbufs,
821 .vidioc_querybuf = vb2_ioctl_querybuf,
822 .vidioc_expbuf = vb2_ioctl_expbuf,
823 .vidioc_qbuf = vb2_ioctl_qbuf,
824 .vidioc_dqbuf = vb2_ioctl_dqbuf,
825 .vidioc_streamon = vb2_ioctl_streamon,
826 .vidioc_streamoff = vb2_ioctl_streamoff,
827 };
828
829 /* V4L2 File */
830
sun6i_csi_capture_open(struct file * file)831 static int sun6i_csi_capture_open(struct file *file)
832 {
833 struct sun6i_csi_device *csi_dev = video_drvdata(file);
834 struct sun6i_csi_capture *capture = &csi_dev->capture;
835 int ret;
836
837 if (mutex_lock_interruptible(&capture->lock))
838 return -ERESTARTSYS;
839
840 ret = v4l2_pipeline_pm_get(&capture->video_dev.entity);
841 if (ret < 0)
842 goto error_lock;
843
844 ret = v4l2_fh_open(file);
845 if (ret < 0)
846 goto error_pipeline;
847
848 mutex_unlock(&capture->lock);
849
850 return 0;
851
852 error_pipeline:
853 v4l2_pipeline_pm_put(&capture->video_dev.entity);
854
855 error_lock:
856 mutex_unlock(&capture->lock);
857
858 return ret;
859 }
860
sun6i_csi_capture_close(struct file * file)861 static int sun6i_csi_capture_close(struct file *file)
862 {
863 struct sun6i_csi_device *csi_dev = video_drvdata(file);
864 struct sun6i_csi_capture *capture = &csi_dev->capture;
865
866 mutex_lock(&capture->lock);
867
868 _vb2_fop_release(file, NULL);
869 v4l2_pipeline_pm_put(&capture->video_dev.entity);
870
871 mutex_unlock(&capture->lock);
872
873 return 0;
874 }
875
876 static const struct v4l2_file_operations sun6i_csi_capture_fops = {
877 .owner = THIS_MODULE,
878 .open = sun6i_csi_capture_open,
879 .release = sun6i_csi_capture_close,
880 .unlocked_ioctl = video_ioctl2,
881 .mmap = vb2_fop_mmap,
882 .poll = vb2_fop_poll
883 };
884
885 /* Media Entity */
886
sun6i_csi_capture_link_validate(struct media_link * link)887 static int sun6i_csi_capture_link_validate(struct media_link *link)
888 {
889 struct video_device *video_dev =
890 media_entity_to_video_device(link->sink->entity);
891 struct sun6i_csi_device *csi_dev = video_get_drvdata(video_dev);
892 struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev;
893 const struct sun6i_csi_capture_format *capture_format;
894 const struct sun6i_csi_bridge_format *bridge_format;
895 unsigned int capture_width, capture_height;
896 unsigned int bridge_width, bridge_height;
897 const struct v4l2_format_info *format_info;
898 u32 pixelformat, capture_field;
899 u32 mbus_code, bridge_field;
900 bool match;
901
902 sun6i_csi_capture_dimensions(csi_dev, &capture_width, &capture_height);
903
904 sun6i_csi_capture_format(csi_dev, &pixelformat, &capture_field);
905 capture_format = sun6i_csi_capture_format_find(pixelformat);
906 if (WARN_ON(!capture_format))
907 return -EINVAL;
908
909 sun6i_csi_bridge_dimensions(csi_dev, &bridge_width, &bridge_height);
910
911 sun6i_csi_bridge_format(csi_dev, &mbus_code, &bridge_field);
912 bridge_format = sun6i_csi_bridge_format_find(mbus_code);
913 if (WARN_ON(!bridge_format))
914 return -EINVAL;
915
916 /* No cropping/scaling is supported. */
917 if (capture_width != bridge_width || capture_height != bridge_height) {
918 v4l2_err(v4l2_dev,
919 "invalid input/output dimensions: %ux%u/%ux%u\n",
920 bridge_width, bridge_height, capture_width,
921 capture_height);
922 return -EINVAL;
923 }
924
925 format_info = v4l2_format_info(pixelformat);
926 /* Some formats are not listed. */
927 if (!format_info)
928 return 0;
929
930 if (format_info->pixel_enc == V4L2_PIXEL_ENC_BAYER &&
931 bridge_format->input_format != SUN6I_CSI_INPUT_FMT_RAW)
932 goto invalid;
933
934 if (format_info->pixel_enc == V4L2_PIXEL_ENC_RGB &&
935 bridge_format->input_format != SUN6I_CSI_INPUT_FMT_RAW)
936 goto invalid;
937
938 if (format_info->pixel_enc == V4L2_PIXEL_ENC_YUV) {
939 if (bridge_format->input_format != SUN6I_CSI_INPUT_FMT_YUV420 &&
940 bridge_format->input_format != SUN6I_CSI_INPUT_FMT_YUV422)
941 goto invalid;
942
943 /* YUV420 input can't produce YUV422 output. */
944 if (bridge_format->input_format == SUN6I_CSI_INPUT_FMT_YUV420 &&
945 format_info->vdiv == 1)
946 goto invalid;
947 }
948
949 /* With raw input mode, we need a 1:1 match between input and output. */
950 if (bridge_format->input_format == SUN6I_CSI_INPUT_FMT_RAW ||
951 capture_format->input_format_raw) {
952 match = sun6i_csi_capture_format_match(pixelformat, mbus_code);
953 if (!match)
954 goto invalid;
955 }
956
957 return 0;
958
959 invalid:
960 v4l2_err(v4l2_dev, "invalid input/output format combination\n");
961 return -EINVAL;
962 }
963
964 static const struct media_entity_operations sun6i_csi_capture_media_ops = {
965 .link_validate = sun6i_csi_capture_link_validate
966 };
967
968 /* Capture */
969
sun6i_csi_capture_setup(struct sun6i_csi_device * csi_dev)970 int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev)
971 {
972 struct sun6i_csi_capture *capture = &csi_dev->capture;
973 struct sun6i_csi_capture_state *state = &capture->state;
974 struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev;
975 struct v4l2_subdev *bridge_subdev = &csi_dev->bridge.subdev;
976 struct video_device *video_dev = &capture->video_dev;
977 struct vb2_queue *queue = &capture->queue;
978 struct media_pad *pad = &capture->pad;
979 struct v4l2_format *format = &csi_dev->capture.format;
980 struct v4l2_pix_format *pix_format = &format->fmt.pix;
981 int ret;
982
983 /* This may happen with multiple bridge notifier bound calls. */
984 if (state->setup)
985 return 0;
986
987 /* State */
988
989 INIT_LIST_HEAD(&state->queue);
990 spin_lock_init(&state->lock);
991
992 /* Media Entity */
993
994 video_dev->entity.ops = &sun6i_csi_capture_media_ops;
995
996 /* Media Pad */
997
998 pad->flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
999
1000 ret = media_entity_pads_init(&video_dev->entity, 1, pad);
1001 if (ret < 0)
1002 return ret;
1003
1004 /* Queue */
1005
1006 mutex_init(&capture->lock);
1007
1008 queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1009 queue->io_modes = VB2_MMAP | VB2_DMABUF;
1010 queue->buf_struct_size = sizeof(struct sun6i_csi_buffer);
1011 queue->ops = &sun6i_csi_capture_queue_ops;
1012 queue->mem_ops = &vb2_dma_contig_memops;
1013 queue->min_queued_buffers = 2;
1014 queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1015 queue->lock = &capture->lock;
1016 queue->dev = csi_dev->dev;
1017 queue->drv_priv = csi_dev;
1018
1019 ret = vb2_queue_init(queue);
1020 if (ret) {
1021 v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret);
1022 goto error_media_entity;
1023 }
1024
1025 /* V4L2 Format */
1026
1027 format->type = queue->type;
1028 pix_format->pixelformat = sun6i_csi_capture_formats[0].pixelformat;
1029 pix_format->width = 1280;
1030 pix_format->height = 720;
1031 pix_format->field = V4L2_FIELD_NONE;
1032
1033 sun6i_csi_capture_format_prepare(format);
1034
1035 /* Video Device */
1036
1037 strscpy(video_dev->name, SUN6I_CSI_CAPTURE_NAME,
1038 sizeof(video_dev->name));
1039 video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
1040 video_dev->vfl_dir = VFL_DIR_RX;
1041 video_dev->release = video_device_release_empty;
1042 video_dev->fops = &sun6i_csi_capture_fops;
1043 video_dev->ioctl_ops = &sun6i_csi_capture_ioctl_ops;
1044 video_dev->v4l2_dev = v4l2_dev;
1045 video_dev->queue = queue;
1046 video_dev->lock = &capture->lock;
1047
1048 video_set_drvdata(video_dev, csi_dev);
1049
1050 ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1);
1051 if (ret < 0) {
1052 v4l2_err(v4l2_dev, "failed to register video device: %d\n",
1053 ret);
1054 goto error_media_entity;
1055 }
1056
1057 /* Media Pad Link */
1058
1059 ret = media_create_pad_link(&bridge_subdev->entity,
1060 SUN6I_CSI_BRIDGE_PAD_SOURCE,
1061 &video_dev->entity, 0,
1062 csi_dev->isp_available ? 0 :
1063 MEDIA_LNK_FL_ENABLED |
1064 MEDIA_LNK_FL_IMMUTABLE);
1065 if (ret < 0) {
1066 v4l2_err(v4l2_dev, "failed to create %s:%u -> %s:%u link\n",
1067 bridge_subdev->entity.name,
1068 SUN6I_CSI_BRIDGE_PAD_SOURCE,
1069 video_dev->entity.name, 0);
1070 goto error_video_device;
1071 }
1072
1073 state->setup = true;
1074
1075 return 0;
1076
1077 error_video_device:
1078 vb2_video_unregister_device(video_dev);
1079
1080 error_media_entity:
1081 media_entity_cleanup(&video_dev->entity);
1082
1083 mutex_destroy(&capture->lock);
1084
1085 return ret;
1086 }
1087
sun6i_csi_capture_cleanup(struct sun6i_csi_device * csi_dev)1088 void sun6i_csi_capture_cleanup(struct sun6i_csi_device *csi_dev)
1089 {
1090 struct sun6i_csi_capture *capture = &csi_dev->capture;
1091 struct video_device *video_dev = &capture->video_dev;
1092
1093 /* This may happen if async registration failed to complete. */
1094 if (!capture->state.setup)
1095 return;
1096
1097 vb2_video_unregister_device(video_dev);
1098 media_entity_cleanup(&video_dev->entity);
1099 mutex_destroy(&capture->lock);
1100
1101 capture->state.setup = false;
1102 }
1103