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