GNU Linux-libre 4.19.304-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                 .cycles = 2,
82         }, {
83                 .fourcc = V4L2_PIX_FMT_RGB24,
84                 .codes  = {
85                         MEDIA_BUS_FMT_RGB888_1X24,
86                         MEDIA_BUS_FMT_RGB888_2X12_LE
87                 },
88                 .cs     = IPUV3_COLORSPACE_RGB,
89                 .bpp    = 24,
90         }, {
91                 .fourcc = V4L2_PIX_FMT_RGB32,
92                 .codes  = {MEDIA_BUS_FMT_ARGB8888_1X32},
93                 .cs     = IPUV3_COLORSPACE_RGB,
94                 .bpp    = 32,
95                 .ipufmt = true,
96         },
97         /*** raw bayer and grayscale formats start here ***/
98         {
99                 .fourcc = V4L2_PIX_FMT_SBGGR8,
100                 .codes  = {MEDIA_BUS_FMT_SBGGR8_1X8},
101                 .cs     = IPUV3_COLORSPACE_RGB,
102                 .bpp    = 8,
103                 .bayer  = true,
104         }, {
105                 .fourcc = V4L2_PIX_FMT_SGBRG8,
106                 .codes  = {MEDIA_BUS_FMT_SGBRG8_1X8},
107                 .cs     = IPUV3_COLORSPACE_RGB,
108                 .bpp    = 8,
109                 .bayer  = true,
110         }, {
111                 .fourcc = V4L2_PIX_FMT_SGRBG8,
112                 .codes  = {MEDIA_BUS_FMT_SGRBG8_1X8},
113                 .cs     = IPUV3_COLORSPACE_RGB,
114                 .bpp    = 8,
115                 .bayer  = true,
116         }, {
117                 .fourcc = V4L2_PIX_FMT_SRGGB8,
118                 .codes  = {MEDIA_BUS_FMT_SRGGB8_1X8},
119                 .cs     = IPUV3_COLORSPACE_RGB,
120                 .bpp    = 8,
121                 .bayer  = true,
122         }, {
123                 .fourcc = V4L2_PIX_FMT_SBGGR16,
124                 .codes  = {
125                         MEDIA_BUS_FMT_SBGGR10_1X10,
126                         MEDIA_BUS_FMT_SBGGR12_1X12,
127                         MEDIA_BUS_FMT_SBGGR14_1X14,
128                         MEDIA_BUS_FMT_SBGGR16_1X16
129                 },
130                 .cs     = IPUV3_COLORSPACE_RGB,
131                 .bpp    = 16,
132                 .bayer  = true,
133         }, {
134                 .fourcc = V4L2_PIX_FMT_SGBRG16,
135                 .codes  = {
136                         MEDIA_BUS_FMT_SGBRG10_1X10,
137                         MEDIA_BUS_FMT_SGBRG12_1X12,
138                         MEDIA_BUS_FMT_SGBRG14_1X14,
139                         MEDIA_BUS_FMT_SGBRG16_1X16,
140                 },
141                 .cs     = IPUV3_COLORSPACE_RGB,
142                 .bpp    = 16,
143                 .bayer  = true,
144         }, {
145                 .fourcc = V4L2_PIX_FMT_SGRBG16,
146                 .codes  = {
147                         MEDIA_BUS_FMT_SGRBG10_1X10,
148                         MEDIA_BUS_FMT_SGRBG12_1X12,
149                         MEDIA_BUS_FMT_SGRBG14_1X14,
150                         MEDIA_BUS_FMT_SGRBG16_1X16,
151                 },
152                 .cs     = IPUV3_COLORSPACE_RGB,
153                 .bpp    = 16,
154                 .bayer  = true,
155         }, {
156                 .fourcc = V4L2_PIX_FMT_SRGGB16,
157                 .codes  = {
158                         MEDIA_BUS_FMT_SRGGB10_1X10,
159                         MEDIA_BUS_FMT_SRGGB12_1X12,
160                         MEDIA_BUS_FMT_SRGGB14_1X14,
161                         MEDIA_BUS_FMT_SRGGB16_1X16,
162                 },
163                 .cs     = IPUV3_COLORSPACE_RGB,
164                 .bpp    = 16,
165                 .bayer  = true,
166         }, {
167                 .fourcc = V4L2_PIX_FMT_GREY,
168                 .codes = {MEDIA_BUS_FMT_Y8_1X8},
169                 .cs     = IPUV3_COLORSPACE_RGB,
170                 .bpp    = 8,
171                 .bayer  = true,
172         }, {
173                 .fourcc = V4L2_PIX_FMT_Y16,
174                 .codes = {
175                         MEDIA_BUS_FMT_Y10_1X10,
176                         MEDIA_BUS_FMT_Y12_1X12,
177                 },
178                 .cs     = IPUV3_COLORSPACE_RGB,
179                 .bpp    = 16,
180                 .bayer  = true,
181         },
182         /***
183          * non-mbus RGB formats start here. NOTE! when adding non-mbus
184          * formats, NUM_NON_MBUS_RGB_FORMATS must be updated below.
185          ***/
186         {
187                 .fourcc = V4L2_PIX_FMT_BGR24,
188                 .cs     = IPUV3_COLORSPACE_RGB,
189                 .bpp    = 24,
190         }, {
191                 .fourcc = V4L2_PIX_FMT_BGR32,
192                 .cs     = IPUV3_COLORSPACE_RGB,
193                 .bpp    = 32,
194         },
195 };
196
197 #define NUM_NON_MBUS_RGB_FORMATS 2
198 #define NUM_RGB_FORMATS ARRAY_SIZE(rgb_formats)
199 #define NUM_MBUS_RGB_FORMATS (NUM_RGB_FORMATS - NUM_NON_MBUS_RGB_FORMATS)
200
201 static const struct imx_media_pixfmt ipu_yuv_formats[] = {
202         {
203                 .fourcc = V4L2_PIX_FMT_YUV32,
204                 .codes  = {MEDIA_BUS_FMT_AYUV8_1X32},
205                 .cs     = IPUV3_COLORSPACE_YUV,
206                 .bpp    = 32,
207                 .ipufmt = true,
208         },
209 };
210
211 #define NUM_IPU_YUV_FORMATS ARRAY_SIZE(ipu_yuv_formats)
212
213 static const struct imx_media_pixfmt ipu_rgb_formats[] = {
214         {
215                 .fourcc = V4L2_PIX_FMT_RGB32,
216                 .codes  = {MEDIA_BUS_FMT_ARGB8888_1X32},
217                 .cs     = IPUV3_COLORSPACE_RGB,
218                 .bpp    = 32,
219                 .ipufmt = true,
220         },
221 };
222
223 #define NUM_IPU_RGB_FORMATS ARRAY_SIZE(ipu_rgb_formats)
224
225 static void init_mbus_colorimetry(struct v4l2_mbus_framefmt *mbus,
226                                   const struct imx_media_pixfmt *fmt)
227 {
228         mbus->colorspace = (fmt->cs == IPUV3_COLORSPACE_RGB) ?
229                 V4L2_COLORSPACE_SRGB : V4L2_COLORSPACE_SMPTE170M;
230         mbus->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mbus->colorspace);
231         mbus->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mbus->colorspace);
232         mbus->quantization =
233                 V4L2_MAP_QUANTIZATION_DEFAULT(fmt->cs == IPUV3_COLORSPACE_RGB,
234                                               mbus->colorspace,
235                                               mbus->ycbcr_enc);
236 }
237
238 static const
239 struct imx_media_pixfmt *__find_format(u32 fourcc,
240                                        u32 code,
241                                        bool allow_non_mbus,
242                                        bool allow_bayer,
243                                        const struct imx_media_pixfmt *array,
244                                        u32 array_size)
245 {
246         const struct imx_media_pixfmt *fmt;
247         int i, j;
248
249         for (i = 0; i < array_size; i++) {
250                 fmt = &array[i];
251
252                 if ((!allow_non_mbus && !fmt->codes[0]) ||
253                     (!allow_bayer && fmt->bayer))
254                         continue;
255
256                 if (fourcc && fmt->fourcc == fourcc)
257                         return fmt;
258
259                 if (!code)
260                         continue;
261
262                 for (j = 0; fmt->codes[j]; j++) {
263                         if (code == fmt->codes[j])
264                                 return fmt;
265                 }
266         }
267         return NULL;
268 }
269
270 static const struct imx_media_pixfmt *find_format(u32 fourcc,
271                                                   u32 code,
272                                                   enum codespace_sel cs_sel,
273                                                   bool allow_non_mbus,
274                                                   bool allow_bayer)
275 {
276         const struct imx_media_pixfmt *ret;
277
278         switch (cs_sel) {
279         case CS_SEL_YUV:
280                 return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
281                                      yuv_formats, NUM_YUV_FORMATS);
282         case CS_SEL_RGB:
283                 return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
284                                      rgb_formats, NUM_RGB_FORMATS);
285         case CS_SEL_ANY:
286                 ret = __find_format(fourcc, code, allow_non_mbus, allow_bayer,
287                                     yuv_formats, NUM_YUV_FORMATS);
288                 if (ret)
289                         return ret;
290                 return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
291                                      rgb_formats, NUM_RGB_FORMATS);
292         default:
293                 return NULL;
294         }
295 }
296
297 static int enum_format(u32 *fourcc, u32 *code, u32 index,
298                        enum codespace_sel cs_sel,
299                        bool allow_non_mbus,
300                        bool allow_bayer)
301 {
302         const struct imx_media_pixfmt *fmt;
303         u32 mbus_yuv_sz = NUM_MBUS_YUV_FORMATS;
304         u32 mbus_rgb_sz = NUM_MBUS_RGB_FORMATS;
305         u32 yuv_sz = NUM_YUV_FORMATS;
306         u32 rgb_sz = NUM_RGB_FORMATS;
307
308         switch (cs_sel) {
309         case CS_SEL_YUV:
310                 if (index >= yuv_sz ||
311                     (!allow_non_mbus && index >= mbus_yuv_sz))
312                         return -EINVAL;
313                 fmt = &yuv_formats[index];
314                 break;
315         case CS_SEL_RGB:
316                 if (index >= rgb_sz ||
317                     (!allow_non_mbus && index >= mbus_rgb_sz))
318                         return -EINVAL;
319                 fmt = &rgb_formats[index];
320                 if (!allow_bayer && fmt->bayer)
321                         return -EINVAL;
322                 break;
323         case CS_SEL_ANY:
324                 if (!allow_non_mbus) {
325                         if (index >= mbus_yuv_sz) {
326                                 index -= mbus_yuv_sz;
327                                 if (index >= mbus_rgb_sz)
328                                         return -EINVAL;
329                                 fmt = &rgb_formats[index];
330                                 if (!allow_bayer && fmt->bayer)
331                                         return -EINVAL;
332                         } else {
333                                 fmt = &yuv_formats[index];
334                         }
335                 } else {
336                         if (index >= yuv_sz + rgb_sz)
337                                 return -EINVAL;
338                         if (index >= yuv_sz) {
339                                 fmt = &rgb_formats[index - yuv_sz];
340                                 if (!allow_bayer && fmt->bayer)
341                                         return -EINVAL;
342                         } else {
343                                 fmt = &yuv_formats[index];
344                         }
345                 }
346                 break;
347         default:
348                 return -EINVAL;
349         }
350
351         if (fourcc)
352                 *fourcc = fmt->fourcc;
353         if (code)
354                 *code = fmt->codes[0];
355
356         return 0;
357 }
358
359 const struct imx_media_pixfmt *
360 imx_media_find_format(u32 fourcc, enum codespace_sel cs_sel, bool allow_bayer)
361 {
362         return find_format(fourcc, 0, cs_sel, true, allow_bayer);
363 }
364 EXPORT_SYMBOL_GPL(imx_media_find_format);
365
366 int imx_media_enum_format(u32 *fourcc, u32 index, enum codespace_sel cs_sel)
367 {
368         return enum_format(fourcc, NULL, index, cs_sel, true, false);
369 }
370 EXPORT_SYMBOL_GPL(imx_media_enum_format);
371
372 const struct imx_media_pixfmt *
373 imx_media_find_mbus_format(u32 code, enum codespace_sel cs_sel,
374                            bool allow_bayer)
375 {
376         return find_format(0, code, cs_sel, false, allow_bayer);
377 }
378 EXPORT_SYMBOL_GPL(imx_media_find_mbus_format);
379
380 int imx_media_enum_mbus_format(u32 *code, u32 index, enum codespace_sel cs_sel,
381                                bool allow_bayer)
382 {
383         return enum_format(NULL, code, index, cs_sel, false, allow_bayer);
384 }
385 EXPORT_SYMBOL_GPL(imx_media_enum_mbus_format);
386
387 const struct imx_media_pixfmt *
388 imx_media_find_ipu_format(u32 code, enum codespace_sel cs_sel)
389 {
390         const struct imx_media_pixfmt *array, *fmt, *ret = NULL;
391         u32 array_size;
392         int i, j;
393
394         switch (cs_sel) {
395         case CS_SEL_YUV:
396                 array_size = NUM_IPU_YUV_FORMATS;
397                 array = ipu_yuv_formats;
398                 break;
399         case CS_SEL_RGB:
400                 array_size = NUM_IPU_RGB_FORMATS;
401                 array = ipu_rgb_formats;
402                 break;
403         case CS_SEL_ANY:
404                 array_size = NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS;
405                 array = ipu_yuv_formats;
406                 break;
407         default:
408                 return NULL;
409         }
410
411         for (i = 0; i < array_size; i++) {
412                 if (cs_sel == CS_SEL_ANY && i >= NUM_IPU_YUV_FORMATS)
413                         fmt = &ipu_rgb_formats[i - NUM_IPU_YUV_FORMATS];
414                 else
415                         fmt = &array[i];
416
417                 for (j = 0; code && fmt->codes[j]; j++) {
418                         if (code == fmt->codes[j]) {
419                                 ret = fmt;
420                                 goto out;
421                         }
422                 }
423         }
424
425 out:
426         return ret;
427 }
428 EXPORT_SYMBOL_GPL(imx_media_find_ipu_format);
429
430 int imx_media_enum_ipu_format(u32 *code, u32 index, enum codespace_sel cs_sel)
431 {
432         switch (cs_sel) {
433         case CS_SEL_YUV:
434                 if (index >= NUM_IPU_YUV_FORMATS)
435                         return -EINVAL;
436                 *code = ipu_yuv_formats[index].codes[0];
437                 break;
438         case CS_SEL_RGB:
439                 if (index >= NUM_IPU_RGB_FORMATS)
440                         return -EINVAL;
441                 *code = ipu_rgb_formats[index].codes[0];
442                 break;
443         case CS_SEL_ANY:
444                 if (index >= NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS)
445                         return -EINVAL;
446                 if (index >= NUM_IPU_YUV_FORMATS) {
447                         index -= NUM_IPU_YUV_FORMATS;
448                         *code = ipu_rgb_formats[index].codes[0];
449                 } else {
450                         *code = ipu_yuv_formats[index].codes[0];
451                 }
452                 break;
453         default:
454                 return -EINVAL;
455         }
456
457         return 0;
458 }
459 EXPORT_SYMBOL_GPL(imx_media_enum_ipu_format);
460
461 int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
462                             u32 width, u32 height, u32 code, u32 field,
463                             const struct imx_media_pixfmt **cc)
464 {
465         const struct imx_media_pixfmt *lcc;
466
467         mbus->width = width;
468         mbus->height = height;
469         mbus->field = field;
470         if (code == 0)
471                 imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false);
472         lcc = imx_media_find_mbus_format(code, CS_SEL_ANY, false);
473         if (!lcc) {
474                 lcc = imx_media_find_ipu_format(code, CS_SEL_ANY);
475                 if (!lcc)
476                         return -EINVAL;
477         }
478
479         mbus->code = code;
480         init_mbus_colorimetry(mbus, lcc);
481         if (cc)
482                 *cc = lcc;
483
484         return 0;
485 }
486 EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
487
488 /*
489  * Initializes the TRY format to the ACTIVE format on all pads
490  * of a subdev. Can be used as the .init_cfg pad operation.
491  */
492 int imx_media_init_cfg(struct v4l2_subdev *sd,
493                        struct v4l2_subdev_pad_config *cfg)
494 {
495         struct v4l2_mbus_framefmt *mf_try;
496         struct v4l2_subdev_format format;
497         unsigned int pad;
498         int ret;
499
500         for (pad = 0; pad < sd->entity.num_pads; pad++) {
501                 memset(&format, 0, sizeof(format));
502
503                 format.pad = pad;
504                 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
505                 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format);
506                 if (ret)
507                         continue;
508
509                 mf_try = v4l2_subdev_get_try_format(sd, cfg, pad);
510                 *mf_try = format.format;
511         }
512
513         return 0;
514 }
515 EXPORT_SYMBOL_GPL(imx_media_init_cfg);
516
517 /*
518  * Check whether the field and colorimetry parameters in tryfmt are
519  * uninitialized, and if so fill them with the values from fmt,
520  * or if tryfmt->colorspace has been initialized, all the default
521  * colorimetry params can be derived from tryfmt->colorspace.
522  *
523  * tryfmt->code must be set on entry.
524  *
525  * If this format is destined to be routed through the Image Converter,
526  * quantization and Y`CbCr encoding must be fixed. The IC expects and
527  * produces fixed quantization and Y`CbCr encoding at its input and output
528  * (full range for RGB, limited range for YUV, and V4L2_YCBCR_ENC_601).
529  */
530 void imx_media_fill_default_mbus_fields(struct v4l2_mbus_framefmt *tryfmt,
531                                         struct v4l2_mbus_framefmt *fmt,
532                                         bool ic_route)
533 {
534         const struct imx_media_pixfmt *cc;
535         bool is_rgb = false;
536
537         cc = imx_media_find_mbus_format(tryfmt->code, CS_SEL_ANY, true);
538         if (!cc)
539                 cc = imx_media_find_ipu_format(tryfmt->code, CS_SEL_ANY);
540         if (cc && cc->cs != IPUV3_COLORSPACE_YUV)
541                 is_rgb = true;
542
543         /* fill field if necessary */
544         if (tryfmt->field == V4L2_FIELD_ANY)
545                 tryfmt->field = fmt->field;
546
547         /* fill colorimetry if necessary */
548         if (tryfmt->colorspace == V4L2_COLORSPACE_DEFAULT) {
549                 tryfmt->colorspace = fmt->colorspace;
550                 tryfmt->xfer_func = fmt->xfer_func;
551                 tryfmt->ycbcr_enc = fmt->ycbcr_enc;
552                 tryfmt->quantization = fmt->quantization;
553         } else {
554                 if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT) {
555                         tryfmt->xfer_func =
556                                 V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace);
557                 }
558                 if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
559                         tryfmt->ycbcr_enc =
560                                 V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace);
561                 }
562                 if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT) {
563                         tryfmt->quantization =
564                                 V4L2_MAP_QUANTIZATION_DEFAULT(
565                                         is_rgb, tryfmt->colorspace,
566                                         tryfmt->ycbcr_enc);
567                 }
568         }
569
570         if (ic_route) {
571                 tryfmt->quantization = is_rgb ?
572                         V4L2_QUANTIZATION_FULL_RANGE :
573                         V4L2_QUANTIZATION_LIM_RANGE;
574                 tryfmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
575         }
576 }
577 EXPORT_SYMBOL_GPL(imx_media_fill_default_mbus_fields);
578
579 int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
580                                   struct v4l2_mbus_framefmt *mbus,
581                                   const struct imx_media_pixfmt *cc)
582 {
583         u32 stride;
584
585         if (!cc) {
586                 cc = imx_media_find_ipu_format(mbus->code, CS_SEL_ANY);
587                 if (!cc)
588                         cc = imx_media_find_mbus_format(mbus->code, CS_SEL_ANY,
589                                                         true);
590                 if (!cc)
591                         return -EINVAL;
592         }
593
594         /*
595          * TODO: the IPU currently does not support the AYUV32 format,
596          * so until it does convert to a supported YUV format.
597          */
598         if (cc->ipufmt && cc->cs == IPUV3_COLORSPACE_YUV) {
599                 u32 code;
600
601                 imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false);
602                 cc = imx_media_find_mbus_format(code, CS_SEL_YUV, false);
603         }
604
605         stride = cc->planar ? mbus->width : (mbus->width * cc->bpp) >> 3;
606
607         pix->width = mbus->width;
608         pix->height = mbus->height;
609         pix->pixelformat = cc->fourcc;
610         pix->colorspace = mbus->colorspace;
611         pix->xfer_func = mbus->xfer_func;
612         pix->ycbcr_enc = mbus->ycbcr_enc;
613         pix->quantization = mbus->quantization;
614         pix->field = mbus->field;
615         pix->bytesperline = stride;
616         pix->sizeimage = (pix->width * pix->height * cc->bpp) >> 3;
617
618         return 0;
619 }
620 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt);
621
622 int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image,
623                                     struct v4l2_mbus_framefmt *mbus)
624 {
625         int ret;
626
627         memset(image, 0, sizeof(*image));
628
629         ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, mbus, NULL);
630         if (ret)
631                 return ret;
632
633         image->rect.width = mbus->width;
634         image->rect.height = mbus->height;
635
636         return 0;
637 }
638 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image);
639
640 int imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
641                                     struct ipu_image *image)
642 {
643         const struct imx_media_pixfmt *fmt;
644
645         fmt = imx_media_find_format(image->pix.pixelformat, CS_SEL_ANY, true);
646         if (!fmt)
647                 return -EINVAL;
648
649         memset(mbus, 0, sizeof(*mbus));
650         mbus->width = image->pix.width;
651         mbus->height = image->pix.height;
652         mbus->code = fmt->codes[0];
653         mbus->field = image->pix.field;
654         mbus->colorspace = image->pix.colorspace;
655         mbus->xfer_func = image->pix.xfer_func;
656         mbus->ycbcr_enc = image->pix.ycbcr_enc;
657         mbus->quantization = image->pix.quantization;
658
659         return 0;
660 }
661 EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt);
662
663 void imx_media_free_dma_buf(struct imx_media_dev *imxmd,
664                             struct imx_media_dma_buf *buf)
665 {
666         if (buf->virt)
667                 dma_free_coherent(imxmd->md.dev, buf->len,
668                                   buf->virt, buf->phys);
669
670         buf->virt = NULL;
671         buf->phys = 0;
672 }
673 EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
674
675 int imx_media_alloc_dma_buf(struct imx_media_dev *imxmd,
676                             struct imx_media_dma_buf *buf,
677                             int size)
678 {
679         imx_media_free_dma_buf(imxmd, buf);
680
681         buf->len = PAGE_ALIGN(size);
682         buf->virt = dma_alloc_coherent(imxmd->md.dev, buf->len, &buf->phys,
683                                        GFP_DMA | GFP_KERNEL);
684         if (!buf->virt) {
685                 dev_err(imxmd->md.dev, "failed to alloc dma buffer\n");
686                 return -ENOMEM;
687         }
688
689         return 0;
690 }
691 EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf);
692
693 /* form a subdev name given a group id and ipu id */
694 void imx_media_grp_id_to_sd_name(char *sd_name, int sz, u32 grp_id, int ipu_id)
695 {
696         int id;
697
698         switch (grp_id) {
699         case IMX_MEDIA_GRP_ID_CSI0...IMX_MEDIA_GRP_ID_CSI1:
700                 id = (grp_id >> IMX_MEDIA_GRP_ID_CSI_BIT) - 1;
701                 snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id);
702                 break;
703         case IMX_MEDIA_GRP_ID_VDIC:
704                 snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1);
705                 break;
706         case IMX_MEDIA_GRP_ID_IC_PRP:
707                 snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1);
708                 break;
709         case IMX_MEDIA_GRP_ID_IC_PRPENC:
710                 snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1);
711                 break;
712         case IMX_MEDIA_GRP_ID_IC_PRPVF:
713                 snprintf(sd_name, sz, "ipu%d_ic_prpvf", ipu_id + 1);
714                 break;
715         default:
716                 break;
717         }
718 }
719 EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name);
720
721 struct v4l2_subdev *
722 imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd,
723                                 struct fwnode_handle *fwnode)
724 {
725         struct v4l2_subdev *sd;
726
727         list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
728                 if (sd->fwnode == fwnode)
729                         return sd;
730         }
731
732         return NULL;
733 }
734 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode);
735
736 struct v4l2_subdev *
737 imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd,
738                                  const char *devname)
739 {
740         struct v4l2_subdev *sd;
741
742         list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
743                 if (!strcmp(devname, dev_name(sd->dev)))
744                         return sd;
745         }
746
747         return NULL;
748 }
749 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname);
750
751 /*
752  * Adds a video device to the master video device list. This is called by
753  * an async subdev that owns a video device when it is registered.
754  */
755 int imx_media_add_video_device(struct imx_media_dev *imxmd,
756                                struct imx_media_video_dev *vdev)
757 {
758         mutex_lock(&imxmd->mutex);
759
760         list_add_tail(&vdev->list, &imxmd->vdev_list);
761
762         mutex_unlock(&imxmd->mutex);
763         return 0;
764 }
765 EXPORT_SYMBOL_GPL(imx_media_add_video_device);
766
767 /*
768  * Search upstream/downstream for a subdevice in the current pipeline
769  * with given grp_id, starting from start_entity. Returns the subdev's
770  * source/sink pad that it was reached from. If grp_id is zero, just
771  * returns the nearest source/sink pad to start_entity. Must be called
772  * with mdev->graph_mutex held.
773  */
774 static struct media_pad *
775 find_pipeline_pad(struct imx_media_dev *imxmd,
776                   struct media_entity *start_entity,
777                   u32 grp_id, bool upstream)
778 {
779         struct media_entity *me = start_entity;
780         struct media_pad *pad = NULL;
781         struct v4l2_subdev *sd;
782         int i;
783
784         for (i = 0; i < me->num_pads; i++) {
785                 struct media_pad *spad = &me->pads[i];
786
787                 if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) ||
788                     (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE)))
789                         continue;
790
791                 pad = media_entity_remote_pad(spad);
792                 if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
793                         continue;
794
795                 if (grp_id != 0) {
796                         sd = media_entity_to_v4l2_subdev(pad->entity);
797                         if (sd->grp_id & grp_id)
798                                 return pad;
799
800                         return find_pipeline_pad(imxmd, pad->entity,
801                                                  grp_id, upstream);
802                 } else {
803                         return pad;
804                 }
805         }
806
807         return NULL;
808 }
809
810 /*
811  * Search upstream for a subdev in the current pipeline with
812  * given grp_id. Must be called with mdev->graph_mutex held.
813  */
814 static struct v4l2_subdev *
815 find_upstream_subdev(struct imx_media_dev *imxmd,
816                      struct media_entity *start_entity,
817                      u32 grp_id)
818 {
819         struct v4l2_subdev *sd;
820         struct media_pad *pad;
821
822         if (is_media_entity_v4l2_subdev(start_entity)) {
823                 sd = media_entity_to_v4l2_subdev(start_entity);
824                 if (sd->grp_id & grp_id)
825                         return sd;
826         }
827
828         pad = find_pipeline_pad(imxmd, start_entity, grp_id, true);
829
830         return pad ? media_entity_to_v4l2_subdev(pad->entity) : NULL;
831 }
832
833 /*
834  * Find the upstream mipi-csi2 virtual channel reached from the given
835  * start entity in the current pipeline.
836  * Must be called with mdev->graph_mutex held.
837  */
838 int imx_media_find_mipi_csi2_channel(struct imx_media_dev *imxmd,
839                                      struct media_entity *start_entity)
840 {
841         struct media_pad *pad;
842         int ret = -EPIPE;
843
844         pad = find_pipeline_pad(imxmd, start_entity, IMX_MEDIA_GRP_ID_CSI2,
845                                 true);
846         if (pad) {
847                 ret = pad->index - 1;
848                 dev_dbg(imxmd->md.dev, "found vc%d from %s\n",
849                         ret, start_entity->name);
850         }
851
852         return ret;
853 }
854 EXPORT_SYMBOL_GPL(imx_media_find_mipi_csi2_channel);
855
856 /*
857  * Find a source pad reached upstream from the given start entity in
858  * the current pipeline. Must be called with mdev->graph_mutex held.
859  */
860 struct media_pad *
861 imx_media_find_upstream_pad(struct imx_media_dev *imxmd,
862                             struct media_entity *start_entity,
863                             u32 grp_id)
864 {
865         struct media_pad *pad;
866
867         pad = find_pipeline_pad(imxmd, start_entity, grp_id, true);
868         if (!pad)
869                 return ERR_PTR(-ENODEV);
870
871         return pad;
872 }
873 EXPORT_SYMBOL_GPL(imx_media_find_upstream_pad);
874
875 /*
876  * Find a subdev reached upstream from the given start entity in
877  * the current pipeline.
878  * Must be called with mdev->graph_mutex held.
879  */
880 struct v4l2_subdev *
881 imx_media_find_upstream_subdev(struct imx_media_dev *imxmd,
882                                struct media_entity *start_entity,
883                                u32 grp_id)
884 {
885         struct v4l2_subdev *sd;
886
887         sd = find_upstream_subdev(imxmd, start_entity, grp_id);
888         if (!sd)
889                 return ERR_PTR(-ENODEV);
890
891         return sd;
892 }
893 EXPORT_SYMBOL_GPL(imx_media_find_upstream_subdev);
894
895 /*
896  * Turn current pipeline streaming on/off starting from entity.
897  */
898 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
899                                   struct media_entity *entity,
900                                   bool on)
901 {
902         struct v4l2_subdev *sd;
903         int ret = 0;
904
905         if (!is_media_entity_v4l2_subdev(entity))
906                 return -EINVAL;
907         sd = media_entity_to_v4l2_subdev(entity);
908
909         mutex_lock(&imxmd->md.graph_mutex);
910
911         if (on) {
912                 ret = __media_pipeline_start(entity, &imxmd->pipe);
913                 if (ret)
914                         goto out;
915                 ret = v4l2_subdev_call(sd, video, s_stream, 1);
916                 if (ret)
917                         __media_pipeline_stop(entity);
918         } else {
919                 v4l2_subdev_call(sd, video, s_stream, 0);
920                 if (entity->pipe)
921                         __media_pipeline_stop(entity);
922         }
923
924 out:
925         mutex_unlock(&imxmd->md.graph_mutex);
926         return ret;
927 }
928 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
929
930 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
931 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
932 MODULE_LICENSE("GPL");