1
2
3
4
5
6
7#include <linux/module.h>
8#include "imx-media.h"
9
10
11
12
13
14
15
16
17static const struct imx_media_pixfmt yuv_formats[] = {
18 {
19 .fourcc = V4L2_PIX_FMT_UYVY,
20 .codes = {
21 MEDIA_BUS_FMT_UYVY8_2X8,
22 MEDIA_BUS_FMT_UYVY8_1X16
23 },
24 .cs = IPUV3_COLORSPACE_YUV,
25 .bpp = 16,
26 }, {
27 .fourcc = V4L2_PIX_FMT_YUYV,
28 .codes = {
29 MEDIA_BUS_FMT_YUYV8_2X8,
30 MEDIA_BUS_FMT_YUYV8_1X16
31 },
32 .cs = IPUV3_COLORSPACE_YUV,
33 .bpp = 16,
34 },
35
36
37
38
39 {
40 .fourcc = V4L2_PIX_FMT_YUV420,
41 .cs = IPUV3_COLORSPACE_YUV,
42 .bpp = 12,
43 .planar = true,
44 }, {
45 .fourcc = V4L2_PIX_FMT_YVU420,
46 .cs = IPUV3_COLORSPACE_YUV,
47 .bpp = 12,
48 .planar = true,
49 }, {
50 .fourcc = V4L2_PIX_FMT_YUV422P,
51 .cs = IPUV3_COLORSPACE_YUV,
52 .bpp = 16,
53 .planar = true,
54 }, {
55 .fourcc = V4L2_PIX_FMT_NV12,
56 .cs = IPUV3_COLORSPACE_YUV,
57 .bpp = 12,
58 .planar = true,
59 }, {
60 .fourcc = V4L2_PIX_FMT_NV16,
61 .cs = IPUV3_COLORSPACE_YUV,
62 .bpp = 16,
63 .planar = true,
64 },
65};
66
67#define NUM_NON_MBUS_YUV_FORMATS 5
68#define NUM_YUV_FORMATS ARRAY_SIZE(yuv_formats)
69#define NUM_MBUS_YUV_FORMATS (NUM_YUV_FORMATS - NUM_NON_MBUS_YUV_FORMATS)
70
71static const struct imx_media_pixfmt rgb_formats[] = {
72 {
73 .fourcc = V4L2_PIX_FMT_RGB565,
74 .codes = {MEDIA_BUS_FMT_RGB565_2X8_LE},
75 .cs = IPUV3_COLORSPACE_RGB,
76 .bpp = 16,
77 .cycles = 2,
78 }, {
79 .fourcc = V4L2_PIX_FMT_RGB24,
80 .codes = {
81 MEDIA_BUS_FMT_RGB888_1X24,
82 MEDIA_BUS_FMT_RGB888_2X12_LE
83 },
84 .cs = IPUV3_COLORSPACE_RGB,
85 .bpp = 24,
86 }, {
87 .fourcc = V4L2_PIX_FMT_XRGB32,
88 .codes = {MEDIA_BUS_FMT_ARGB8888_1X32},
89 .cs = IPUV3_COLORSPACE_RGB,
90 .bpp = 32,
91 .ipufmt = true,
92 },
93
94 {
95 .fourcc = V4L2_PIX_FMT_SBGGR8,
96 .codes = {MEDIA_BUS_FMT_SBGGR8_1X8},
97 .cs = IPUV3_COLORSPACE_RGB,
98 .bpp = 8,
99 .bayer = true,
100 }, {
101 .fourcc = V4L2_PIX_FMT_SGBRG8,
102 .codes = {MEDIA_BUS_FMT_SGBRG8_1X8},
103 .cs = IPUV3_COLORSPACE_RGB,
104 .bpp = 8,
105 .bayer = true,
106 }, {
107 .fourcc = V4L2_PIX_FMT_SGRBG8,
108 .codes = {MEDIA_BUS_FMT_SGRBG8_1X8},
109 .cs = IPUV3_COLORSPACE_RGB,
110 .bpp = 8,
111 .bayer = true,
112 }, {
113 .fourcc = V4L2_PIX_FMT_SRGGB8,
114 .codes = {MEDIA_BUS_FMT_SRGGB8_1X8},
115 .cs = IPUV3_COLORSPACE_RGB,
116 .bpp = 8,
117 .bayer = true,
118 }, {
119 .fourcc = V4L2_PIX_FMT_SBGGR16,
120 .codes = {
121 MEDIA_BUS_FMT_SBGGR10_1X10,
122 MEDIA_BUS_FMT_SBGGR12_1X12,
123 MEDIA_BUS_FMT_SBGGR14_1X14,
124 MEDIA_BUS_FMT_SBGGR16_1X16
125 },
126 .cs = IPUV3_COLORSPACE_RGB,
127 .bpp = 16,
128 .bayer = true,
129 }, {
130 .fourcc = V4L2_PIX_FMT_SGBRG16,
131 .codes = {
132 MEDIA_BUS_FMT_SGBRG10_1X10,
133 MEDIA_BUS_FMT_SGBRG12_1X12,
134 MEDIA_BUS_FMT_SGBRG14_1X14,
135 MEDIA_BUS_FMT_SGBRG16_1X16,
136 },
137 .cs = IPUV3_COLORSPACE_RGB,
138 .bpp = 16,
139 .bayer = true,
140 }, {
141 .fourcc = V4L2_PIX_FMT_SGRBG16,
142 .codes = {
143 MEDIA_BUS_FMT_SGRBG10_1X10,
144 MEDIA_BUS_FMT_SGRBG12_1X12,
145 MEDIA_BUS_FMT_SGRBG14_1X14,
146 MEDIA_BUS_FMT_SGRBG16_1X16,
147 },
148 .cs = IPUV3_COLORSPACE_RGB,
149 .bpp = 16,
150 .bayer = true,
151 }, {
152 .fourcc = V4L2_PIX_FMT_SRGGB16,
153 .codes = {
154 MEDIA_BUS_FMT_SRGGB10_1X10,
155 MEDIA_BUS_FMT_SRGGB12_1X12,
156 MEDIA_BUS_FMT_SRGGB14_1X14,
157 MEDIA_BUS_FMT_SRGGB16_1X16,
158 },
159 .cs = IPUV3_COLORSPACE_RGB,
160 .bpp = 16,
161 .bayer = true,
162 }, {
163 .fourcc = V4L2_PIX_FMT_GREY,
164 .codes = {MEDIA_BUS_FMT_Y8_1X8},
165 .cs = IPUV3_COLORSPACE_RGB,
166 .bpp = 8,
167 .bayer = true,
168 }, {
169 .fourcc = V4L2_PIX_FMT_Y16,
170 .codes = {
171 MEDIA_BUS_FMT_Y10_1X10,
172 MEDIA_BUS_FMT_Y12_1X12,
173 },
174 .cs = IPUV3_COLORSPACE_RGB,
175 .bpp = 16,
176 .bayer = true,
177 },
178
179
180
181
182 {
183 .fourcc = V4L2_PIX_FMT_BGR24,
184 .cs = IPUV3_COLORSPACE_RGB,
185 .bpp = 24,
186 }, {
187 .fourcc = V4L2_PIX_FMT_BGR32,
188 .cs = IPUV3_COLORSPACE_RGB,
189 .bpp = 32,
190 },
191};
192
193#define NUM_NON_MBUS_RGB_FORMATS 2
194#define NUM_RGB_FORMATS ARRAY_SIZE(rgb_formats)
195#define NUM_MBUS_RGB_FORMATS (NUM_RGB_FORMATS - NUM_NON_MBUS_RGB_FORMATS)
196
197static const struct imx_media_pixfmt ipu_yuv_formats[] = {
198 {
199 .fourcc = V4L2_PIX_FMT_YUV32,
200 .codes = {MEDIA_BUS_FMT_AYUV8_1X32},
201 .cs = IPUV3_COLORSPACE_YUV,
202 .bpp = 32,
203 .ipufmt = true,
204 },
205};
206
207#define NUM_IPU_YUV_FORMATS ARRAY_SIZE(ipu_yuv_formats)
208
209static const struct imx_media_pixfmt ipu_rgb_formats[] = {
210 {
211 .fourcc = V4L2_PIX_FMT_XRGB32,
212 .codes = {MEDIA_BUS_FMT_ARGB8888_1X32},
213 .cs = IPUV3_COLORSPACE_RGB,
214 .bpp = 32,
215 .ipufmt = true,
216 },
217};
218
219#define NUM_IPU_RGB_FORMATS ARRAY_SIZE(ipu_rgb_formats)
220
221static void init_mbus_colorimetry(struct v4l2_mbus_framefmt *mbus,
222 const struct imx_media_pixfmt *fmt)
223{
224 mbus->colorspace = (fmt->cs == IPUV3_COLORSPACE_RGB) ?
225 V4L2_COLORSPACE_SRGB : V4L2_COLORSPACE_SMPTE170M;
226 mbus->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mbus->colorspace);
227 mbus->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mbus->colorspace);
228 mbus->quantization =
229 V4L2_MAP_QUANTIZATION_DEFAULT(fmt->cs == IPUV3_COLORSPACE_RGB,
230 mbus->colorspace,
231 mbus->ycbcr_enc);
232}
233
234static const
235struct imx_media_pixfmt *__find_format(u32 fourcc,
236 u32 code,
237 bool allow_non_mbus,
238 bool allow_bayer,
239 const struct imx_media_pixfmt *array,
240 u32 array_size)
241{
242 const struct imx_media_pixfmt *fmt;
243 int i, j;
244
245 for (i = 0; i < array_size; i++) {
246 fmt = &array[i];
247
248 if ((!allow_non_mbus && !fmt->codes[0]) ||
249 (!allow_bayer && fmt->bayer))
250 continue;
251
252 if (fourcc && fmt->fourcc == fourcc)
253 return fmt;
254
255 if (!code)
256 continue;
257
258 for (j = 0; fmt->codes[j]; j++) {
259 if (code == fmt->codes[j])
260 return fmt;
261 }
262 }
263 return NULL;
264}
265
266static const struct imx_media_pixfmt *find_format(u32 fourcc,
267 u32 code,
268 enum codespace_sel cs_sel,
269 bool allow_non_mbus,
270 bool allow_bayer)
271{
272 const struct imx_media_pixfmt *ret;
273
274 switch (cs_sel) {
275 case CS_SEL_YUV:
276 return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
277 yuv_formats, NUM_YUV_FORMATS);
278 case CS_SEL_RGB:
279 return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
280 rgb_formats, NUM_RGB_FORMATS);
281 case CS_SEL_ANY:
282 ret = __find_format(fourcc, code, allow_non_mbus, allow_bayer,
283 yuv_formats, NUM_YUV_FORMATS);
284 if (ret)
285 return ret;
286 return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
287 rgb_formats, NUM_RGB_FORMATS);
288 default:
289 return NULL;
290 }
291}
292
293static int enum_format(u32 *fourcc, u32 *code, u32 index,
294 enum codespace_sel cs_sel,
295 bool allow_non_mbus,
296 bool allow_bayer)
297{
298 const struct imx_media_pixfmt *fmt;
299 u32 mbus_yuv_sz = NUM_MBUS_YUV_FORMATS;
300 u32 mbus_rgb_sz = NUM_MBUS_RGB_FORMATS;
301 u32 yuv_sz = NUM_YUV_FORMATS;
302 u32 rgb_sz = NUM_RGB_FORMATS;
303
304 switch (cs_sel) {
305 case CS_SEL_YUV:
306 if (index >= yuv_sz ||
307 (!allow_non_mbus && index >= mbus_yuv_sz))
308 return -EINVAL;
309 fmt = &yuv_formats[index];
310 break;
311 case CS_SEL_RGB:
312 if (index >= rgb_sz ||
313 (!allow_non_mbus && index >= mbus_rgb_sz))
314 return -EINVAL;
315 fmt = &rgb_formats[index];
316 if (!allow_bayer && fmt->bayer)
317 return -EINVAL;
318 break;
319 case CS_SEL_ANY:
320 if (!allow_non_mbus) {
321 if (index >= mbus_yuv_sz) {
322 index -= mbus_yuv_sz;
323 if (index >= mbus_rgb_sz)
324 return -EINVAL;
325 fmt = &rgb_formats[index];
326 if (!allow_bayer && fmt->bayer)
327 return -EINVAL;
328 } else {
329 fmt = &yuv_formats[index];
330 }
331 } else {
332 if (index >= yuv_sz + rgb_sz)
333 return -EINVAL;
334 if (index >= yuv_sz) {
335 fmt = &rgb_formats[index - yuv_sz];
336 if (!allow_bayer && fmt->bayer)
337 return -EINVAL;
338 } else {
339 fmt = &yuv_formats[index];
340 }
341 }
342 break;
343 default:
344 return -EINVAL;
345 }
346
347 if (fourcc)
348 *fourcc = fmt->fourcc;
349 if (code)
350 *code = fmt->codes[0];
351
352 return 0;
353}
354
355const struct imx_media_pixfmt *
356imx_media_find_format(u32 fourcc, enum codespace_sel cs_sel, bool allow_bayer)
357{
358 return find_format(fourcc, 0, cs_sel, true, allow_bayer);
359}
360EXPORT_SYMBOL_GPL(imx_media_find_format);
361
362int imx_media_enum_format(u32 *fourcc, u32 index, enum codespace_sel cs_sel)
363{
364 return enum_format(fourcc, NULL, index, cs_sel, true, false);
365}
366EXPORT_SYMBOL_GPL(imx_media_enum_format);
367
368const struct imx_media_pixfmt *
369imx_media_find_mbus_format(u32 code, enum codespace_sel cs_sel,
370 bool allow_bayer)
371{
372 return find_format(0, code, cs_sel, false, allow_bayer);
373}
374EXPORT_SYMBOL_GPL(imx_media_find_mbus_format);
375
376int imx_media_enum_mbus_format(u32 *code, u32 index, enum codespace_sel cs_sel,
377 bool allow_bayer)
378{
379 return enum_format(NULL, code, index, cs_sel, false, allow_bayer);
380}
381EXPORT_SYMBOL_GPL(imx_media_enum_mbus_format);
382
383const struct imx_media_pixfmt *
384imx_media_find_ipu_format(u32 code, enum codespace_sel cs_sel)
385{
386 const struct imx_media_pixfmt *array, *fmt, *ret = NULL;
387 u32 array_size;
388 int i, j;
389
390 switch (cs_sel) {
391 case CS_SEL_YUV:
392 array_size = NUM_IPU_YUV_FORMATS;
393 array = ipu_yuv_formats;
394 break;
395 case CS_SEL_RGB:
396 array_size = NUM_IPU_RGB_FORMATS;
397 array = ipu_rgb_formats;
398 break;
399 case CS_SEL_ANY:
400 array_size = NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS;
401 array = ipu_yuv_formats;
402 break;
403 default:
404 return NULL;
405 }
406
407 for (i = 0; i < array_size; i++) {
408 if (cs_sel == CS_SEL_ANY && i >= NUM_IPU_YUV_FORMATS)
409 fmt = &ipu_rgb_formats[i - NUM_IPU_YUV_FORMATS];
410 else
411 fmt = &array[i];
412
413 for (j = 0; code && fmt->codes[j]; j++) {
414 if (code == fmt->codes[j]) {
415 ret = fmt;
416 goto out;
417 }
418 }
419 }
420
421out:
422 return ret;
423}
424EXPORT_SYMBOL_GPL(imx_media_find_ipu_format);
425
426int imx_media_enum_ipu_format(u32 *code, u32 index, enum codespace_sel cs_sel)
427{
428 switch (cs_sel) {
429 case CS_SEL_YUV:
430 if (index >= NUM_IPU_YUV_FORMATS)
431 return -EINVAL;
432 *code = ipu_yuv_formats[index].codes[0];
433 break;
434 case CS_SEL_RGB:
435 if (index >= NUM_IPU_RGB_FORMATS)
436 return -EINVAL;
437 *code = ipu_rgb_formats[index].codes[0];
438 break;
439 case CS_SEL_ANY:
440 if (index >= NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS)
441 return -EINVAL;
442 if (index >= NUM_IPU_YUV_FORMATS) {
443 index -= NUM_IPU_YUV_FORMATS;
444 *code = ipu_rgb_formats[index].codes[0];
445 } else {
446 *code = ipu_yuv_formats[index].codes[0];
447 }
448 break;
449 default:
450 return -EINVAL;
451 }
452
453 return 0;
454}
455EXPORT_SYMBOL_GPL(imx_media_enum_ipu_format);
456
457int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
458 u32 width, u32 height, u32 code, u32 field,
459 const struct imx_media_pixfmt **cc)
460{
461 const struct imx_media_pixfmt *lcc;
462
463 mbus->width = width;
464 mbus->height = height;
465 mbus->field = field;
466 if (code == 0)
467 imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false);
468 lcc = imx_media_find_mbus_format(code, CS_SEL_ANY, false);
469 if (!lcc) {
470 lcc = imx_media_find_ipu_format(code, CS_SEL_ANY);
471 if (!lcc)
472 return -EINVAL;
473 }
474
475 mbus->code = code;
476 init_mbus_colorimetry(mbus, lcc);
477 if (cc)
478 *cc = lcc;
479
480 return 0;
481}
482EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
483
484
485
486
487
488int imx_media_init_cfg(struct v4l2_subdev *sd,
489 struct v4l2_subdev_pad_config *cfg)
490{
491 struct v4l2_mbus_framefmt *mf_try;
492 struct v4l2_subdev_format format;
493 unsigned int pad;
494 int ret;
495
496 for (pad = 0; pad < sd->entity.num_pads; pad++) {
497 memset(&format, 0, sizeof(format));
498
499 format.pad = pad;
500 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
501 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format);
502 if (ret)
503 continue;
504
505 mf_try = v4l2_subdev_get_try_format(sd, cfg, pad);
506 *mf_try = format.format;
507 }
508
509 return 0;
510}
511EXPORT_SYMBOL_GPL(imx_media_init_cfg);
512
513
514
515
516
517
518
519
520
521
522
523
524void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt,
525 bool ic_route)
526{
527 const struct imx_media_pixfmt *cc;
528 bool is_rgb = false;
529
530 cc = imx_media_find_mbus_format(tryfmt->code, CS_SEL_ANY, true);
531 if (!cc)
532 cc = imx_media_find_ipu_format(tryfmt->code, CS_SEL_ANY);
533 if (cc && cc->cs == IPUV3_COLORSPACE_RGB)
534 is_rgb = true;
535
536 switch (tryfmt->colorspace) {
537 case V4L2_COLORSPACE_SMPTE170M:
538 case V4L2_COLORSPACE_REC709:
539 case V4L2_COLORSPACE_JPEG:
540 case V4L2_COLORSPACE_SRGB:
541 case V4L2_COLORSPACE_BT2020:
542 case V4L2_COLORSPACE_OPRGB:
543 case V4L2_COLORSPACE_DCI_P3:
544 case V4L2_COLORSPACE_RAW:
545 break;
546 default:
547 tryfmt->colorspace = V4L2_COLORSPACE_SRGB;
548 break;
549 }
550
551 if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT)
552 tryfmt->xfer_func =
553 V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace);
554
555 if (ic_route) {
556 if (tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_601 &&
557 tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_709)
558 tryfmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
559 } else {
560 if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
561 tryfmt->ycbcr_enc =
562 V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace);
563 }
564 }
565
566 if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT)
567 tryfmt->quantization =
568 V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb,
569 tryfmt->colorspace,
570 tryfmt->ycbcr_enc);
571}
572EXPORT_SYMBOL_GPL(imx_media_try_colorimetry);
573
574int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
575 struct v4l2_mbus_framefmt *mbus,
576 const struct imx_media_pixfmt *cc)
577{
578 u32 width;
579 u32 stride;
580
581 if (!cc) {
582 cc = imx_media_find_ipu_format(mbus->code, CS_SEL_ANY);
583 if (!cc)
584 cc = imx_media_find_mbus_format(mbus->code, CS_SEL_ANY,
585 true);
586 if (!cc)
587 return -EINVAL;
588 }
589
590
591
592
593
594 if (cc->ipufmt && cc->cs == IPUV3_COLORSPACE_YUV) {
595 u32 code;
596
597 imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false);
598 cc = imx_media_find_mbus_format(code, CS_SEL_YUV, false);
599 }
600
601
602 width = round_up(mbus->width, 8);
603
604
605 if (cc->planar)
606 stride = round_up(width, 16);
607 else
608 stride = round_up((width * cc->bpp) >> 3, 8);
609
610 pix->width = width;
611 pix->height = mbus->height;
612 pix->pixelformat = cc->fourcc;
613 pix->colorspace = mbus->colorspace;
614 pix->xfer_func = mbus->xfer_func;
615 pix->ycbcr_enc = mbus->ycbcr_enc;
616 pix->quantization = mbus->quantization;
617 pix->field = mbus->field;
618 pix->bytesperline = stride;
619 pix->sizeimage = cc->planar ? ((stride * pix->height * cc->bpp) >> 3) :
620 stride * pix->height;
621
622 return 0;
623}
624EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt);
625
626int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image,
627 struct v4l2_mbus_framefmt *mbus)
628{
629 int ret;
630
631 memset(image, 0, sizeof(*image));
632
633 ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, mbus, NULL);
634 if (ret)
635 return ret;
636
637 image->rect.width = mbus->width;
638 image->rect.height = mbus->height;
639
640 return 0;
641}
642EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image);
643
644int imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
645 struct ipu_image *image)
646{
647 const struct imx_media_pixfmt *fmt;
648
649 fmt = imx_media_find_format(image->pix.pixelformat, CS_SEL_ANY, true);
650 if (!fmt)
651 return -EINVAL;
652
653 memset(mbus, 0, sizeof(*mbus));
654 mbus->width = image->pix.width;
655 mbus->height = image->pix.height;
656 mbus->code = fmt->codes[0];
657 mbus->field = image->pix.field;
658 mbus->colorspace = image->pix.colorspace;
659 mbus->xfer_func = image->pix.xfer_func;
660 mbus->ycbcr_enc = image->pix.ycbcr_enc;
661 mbus->quantization = image->pix.quantization;
662
663 return 0;
664}
665EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt);
666
667void imx_media_free_dma_buf(struct device *dev,
668 struct imx_media_dma_buf *buf)
669{
670 if (buf->virt)
671 dma_free_coherent(dev, buf->len, buf->virt, buf->phys);
672
673 buf->virt = NULL;
674 buf->phys = 0;
675}
676EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
677
678int imx_media_alloc_dma_buf(struct device *dev,
679 struct imx_media_dma_buf *buf,
680 int size)
681{
682 imx_media_free_dma_buf(dev, buf);
683
684 buf->len = PAGE_ALIGN(size);
685 buf->virt = dma_alloc_coherent(dev, buf->len, &buf->phys,
686 GFP_DMA | GFP_KERNEL);
687 if (!buf->virt) {
688 dev_err(dev, "%s: failed\n", __func__);
689 return -ENOMEM;
690 }
691
692 return 0;
693}
694EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf);
695
696
697void imx_media_grp_id_to_sd_name(char *sd_name, int sz, u32 grp_id, int ipu_id)
698{
699 int id;
700
701 switch (grp_id) {
702 case IMX_MEDIA_GRP_ID_IPU_CSI0...IMX_MEDIA_GRP_ID_IPU_CSI1:
703 id = (grp_id >> IMX_MEDIA_GRP_ID_IPU_CSI_BIT) - 1;
704 snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id);
705 break;
706 case IMX_MEDIA_GRP_ID_IPU_VDIC:
707 snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1);
708 break;
709 case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
710 snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1);
711 break;
712 case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
713 snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1);
714 break;
715 case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
716 snprintf(sd_name, sz, "ipu%d_ic_prpvf", ipu_id + 1);
717 break;
718 default:
719 break;
720 }
721}
722EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name);
723
724struct v4l2_subdev *
725imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd,
726 struct fwnode_handle *fwnode)
727{
728 struct v4l2_subdev *sd;
729
730 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
731 if (sd->fwnode == fwnode)
732 return sd;
733 }
734
735 return NULL;
736}
737EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode);
738
739struct v4l2_subdev *
740imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd,
741 const char *devname)
742{
743 struct v4l2_subdev *sd;
744
745 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
746 if (!strcmp(devname, dev_name(sd->dev)))
747 return sd;
748 }
749
750 return NULL;
751}
752EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname);
753
754
755
756
757
758void imx_media_add_video_device(struct imx_media_dev *imxmd,
759 struct imx_media_video_dev *vdev)
760{
761 mutex_lock(&imxmd->mutex);
762
763 list_add_tail(&vdev->list, &imxmd->vdev_list);
764
765 mutex_unlock(&imxmd->mutex);
766}
767EXPORT_SYMBOL_GPL(imx_media_add_video_device);
768
769
770
771
772
773
774
775
776
777
778
779struct media_pad *
780imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id,
781 enum v4l2_buf_type buftype, bool upstream)
782{
783 struct media_entity *me = start_entity;
784 struct media_pad *pad = NULL;
785 struct video_device *vfd;
786 struct v4l2_subdev *sd;
787 int i;
788
789 for (i = 0; i < me->num_pads; i++) {
790 struct media_pad *spad = &me->pads[i];
791
792 if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) ||
793 (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE)))
794 continue;
795
796 pad = media_entity_remote_pad(spad);
797 if (!pad)
798 continue;
799
800 if (grp_id) {
801 if (is_media_entity_v4l2_subdev(pad->entity)) {
802 sd = media_entity_to_v4l2_subdev(pad->entity);
803 if (sd->grp_id & grp_id)
804 return pad;
805 }
806
807 return imx_media_pipeline_pad(pad->entity, grp_id,
808 buftype, upstream);
809 } else if (buftype) {
810 if (is_media_entity_v4l2_video_device(pad->entity)) {
811 vfd = media_entity_to_video_device(pad->entity);
812 if (buftype == vfd->queue->type)
813 return pad;
814 }
815
816 return imx_media_pipeline_pad(pad->entity, grp_id,
817 buftype, upstream);
818 } else {
819 return pad;
820 }
821 }
822
823 return NULL;
824}
825EXPORT_SYMBOL_GPL(imx_media_pipeline_pad);
826
827
828
829
830
831static struct media_entity *
832find_pipeline_entity(struct media_entity *start, u32 grp_id,
833 enum v4l2_buf_type buftype, bool upstream)
834{
835 struct media_pad *pad = NULL;
836 struct video_device *vfd;
837 struct v4l2_subdev *sd;
838
839 if (grp_id && is_media_entity_v4l2_subdev(start)) {
840 sd = media_entity_to_v4l2_subdev(start);
841 if (sd->grp_id & grp_id)
842 return &sd->entity;
843 } else if (buftype && is_media_entity_v4l2_video_device(start)) {
844 vfd = media_entity_to_video_device(start);
845 if (buftype == vfd->queue->type)
846 return &vfd->entity;
847 }
848
849 pad = imx_media_pipeline_pad(start, grp_id, buftype, upstream);
850
851 return pad ? pad->entity : NULL;
852}
853
854
855
856
857
858
859int imx_media_pipeline_csi2_channel(struct media_entity *start_entity)
860{
861 struct media_pad *pad;
862 int ret = -EPIPE;
863
864 pad = imx_media_pipeline_pad(start_entity, IMX_MEDIA_GRP_ID_CSI2,
865 0, true);
866 if (pad)
867 ret = pad->index - 1;
868
869 return ret;
870}
871EXPORT_SYMBOL_GPL(imx_media_pipeline_csi2_channel);
872
873
874
875
876
877
878struct v4l2_subdev *
879imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id,
880 bool upstream)
881{
882 struct media_entity *me;
883
884 me = find_pipeline_entity(start_entity, grp_id, 0, upstream);
885 if (!me)
886 return ERR_PTR(-ENODEV);
887
888 return media_entity_to_v4l2_subdev(me);
889}
890EXPORT_SYMBOL_GPL(imx_media_pipeline_subdev);
891
892
893
894
895
896
897struct video_device *
898imx_media_pipeline_video_device(struct media_entity *start_entity,
899 enum v4l2_buf_type buftype, bool upstream)
900{
901 struct media_entity *me;
902
903 me = find_pipeline_entity(start_entity, 0, buftype, upstream);
904 if (!me)
905 return ERR_PTR(-ENODEV);
906
907 return media_entity_to_video_device(me);
908}
909EXPORT_SYMBOL_GPL(imx_media_pipeline_video_device);
910
911
912
913
914int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
915 struct media_entity *entity,
916 bool on)
917{
918 struct v4l2_subdev *sd;
919 int ret = 0;
920
921 if (!is_media_entity_v4l2_subdev(entity))
922 return -EINVAL;
923 sd = media_entity_to_v4l2_subdev(entity);
924
925 mutex_lock(&imxmd->md.graph_mutex);
926
927 if (on) {
928 ret = __media_pipeline_start(entity, &imxmd->pipe);
929 if (ret)
930 goto out;
931 ret = v4l2_subdev_call(sd, video, s_stream, 1);
932 if (ret)
933 __media_pipeline_stop(entity);
934 } else {
935 v4l2_subdev_call(sd, video, s_stream, 0);
936 if (entity->pipe)
937 __media_pipeline_stop(entity);
938 }
939
940out:
941 mutex_unlock(&imxmd->md.graph_mutex);
942 return ret;
943}
944EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
945
946MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
947MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
948MODULE_LICENSE("GPL");
949