GNU Linux-libre 4.14.332-gnu1
[releases.git] / drivers / staging / media / imx / imx-media-utils.c
1 /*
2  * V4L2 Media Controller Driver for Freescale i.MX5/6 SOC
3  *
4  * Copyright (c) 2016 Mentor Graphics Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  */
11 #include <linux/module.h>
12 #include "imx-media.h"
13
14 /*
15  * List of supported pixel formats for the subdevs.
16  *
17  * In all of these tables, the non-mbus formats (with no
18  * mbus codes) must all fall at the end of the table.
19  */
20
21 static 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          * non-mbus YUV formats start here. NOTE! when adding non-mbus
41          * formats, NUM_NON_MBUS_YUV_FORMATS must be updated below.
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
75 static 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         /*** raw bayer formats start here ***/
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          * non-mbus RGB formats start here. NOTE! when adding non-mbus
168          * formats, NUM_NON_MBUS_RGB_FORMATS must be updated below.
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
185 static 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
197 static 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
209 static 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
222 static 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
272 out:
273         return ret;
274 }
275
276 static 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
338 const struct imx_media_pixfmt *
339 imx_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 }
343 EXPORT_SYMBOL_GPL(imx_media_find_format);
344
345 int 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 }
349 EXPORT_SYMBOL_GPL(imx_media_enum_format);
350
351 const struct imx_media_pixfmt *
352 imx_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 }
357 EXPORT_SYMBOL_GPL(imx_media_find_mbus_format);
358
359 int 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 }
364 EXPORT_SYMBOL_GPL(imx_media_enum_mbus_format);
365
366 const struct imx_media_pixfmt *
367 imx_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
404 out:
405         return ret;
406 }
407 EXPORT_SYMBOL_GPL(imx_media_find_ipu_format);
408
409 int 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 }
438 EXPORT_SYMBOL_GPL(imx_media_enum_ipu_format);
439
440 int 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 }
465 EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
466
467 /*
468  * Check whether the field and colorimetry parameters in tryfmt are
469  * uninitialized, and if so fill them with the values from fmt,
470  * or if tryfmt->colorspace has been initialized, all the default
471  * colorimetry params can be derived from tryfmt->colorspace.
472  *
473  * tryfmt->code must be set on entry.
474  *
475  * If this format is destined to be routed through the Image Converter,
476  * quantization and Y`CbCr encoding must be fixed. The IC expects and
477  * produces fixed quantization and Y`CbCr encoding at its input and output
478  * (full range for RGB, limited range for YUV, and V4L2_YCBCR_ENC_601).
479  */
480 void 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         /* fill field if necessary */
494         if (tryfmt->field == V4L2_FIELD_ANY)
495                 tryfmt->field = fmt->field;
496
497         /* fill colorimetry if necessary */
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 }
527 EXPORT_SYMBOL_GPL(imx_media_fill_default_mbus_fields);
528
529 int 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          * TODO: the IPU currently does not support the AYUV32 format,
546          * so until it does convert to a supported YUV format.
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 }
570 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt);
571
572 int 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 }
588 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image);
589
590 int 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 }
611 EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt);
612
613 void 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 }
623 EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
624
625 int 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 }
641 EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf);
642
643 /* form a subdev name given a group id and ipu id */
644 void 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 }
669 EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name);
670
671 struct imx_media_subdev *
672 imx_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 }
686 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_sd);
687
688 struct imx_media_subdev *
689 imx_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 }
702 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_id);
703
704 /*
705  * Adds a video device to the master video device list. This is called by
706  * an async subdev that owns a video device when it is registered.
707  */
708 int 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++;
726 out:
727         mutex_unlock(&imxmd->mutex);
728         return ret;
729 }
730 EXPORT_SYMBOL_GPL(imx_media_add_video_device);
731
732 /*
733  * Search upstream or downstream for a subdevice in the current pipeline
734  * with given grp_id, starting from start_entity. Returns the subdev's
735  * source/sink pad that it was reached from. Must be called with
736  * mdev->graph_mutex held.
737  */
738 static struct media_pad *
739 find_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  * Search upstream for a subdev in the current pipeline with
771  * given grp_id. Must be called with mdev->graph_mutex held.
772  */
773 static struct v4l2_subdev *
774 find_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  * Find the upstream mipi-csi2 virtual channel reached from the given
795  * start entity in the current pipeline.
796  * Must be called with mdev->graph_mutex held.
797  */
798 int 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 }
814 EXPORT_SYMBOL_GPL(imx_media_find_mipi_csi2_channel);
815
816 /*
817  * Find a subdev reached upstream from the given start entity in
818  * the current pipeline.
819  * Must be called with mdev->graph_mutex held.
820  */
821 struct imx_media_subdev *
822 imx_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 }
834 EXPORT_SYMBOL_GPL(imx_media_find_upstream_subdev);
835
836 struct 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 }
843 EXPORT_SYMBOL_GPL(__imx_media_find_sensor);
844
845 struct imx_media_subdev *
846 imx_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 }
857 EXPORT_SYMBOL_GPL(imx_media_find_sensor);
858
859 /*
860  * Turn current pipeline streaming on/off starting from entity.
861  */
862 int 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
888 out:
889         mutex_unlock(&imxmd->md.graph_mutex);
890         return ret;
891 }
892 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
893
894 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
895 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
896 MODULE_LICENSE("GPL");