Merge branch 'core-objtool-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-block.git] / drivers / staging / media / imx / imx-media-utils.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * V4L2 Media Controller Driver for Freescale i.MX5/6 SOC
4  *
5  * Copyright (c) 2016 Mentor Graphics Inc.
6  */
7 #include <linux/module.h>
8 #include "imx-media.h"
9
10 /*
11  * List of supported pixel formats for the subdevs.
12  *
13  * In all of these tables, the non-mbus formats (with no
14  * mbus codes) must all fall at the end of the table.
15  */
16
17 static 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          * non-mbus YUV formats start here. NOTE! when adding non-mbus
37          * formats, NUM_NON_MBUS_YUV_FORMATS must be updated below.
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
71 static 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         /*** raw bayer and grayscale formats start here ***/
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 = {
165                         MEDIA_BUS_FMT_Y8_1X8,
166                         MEDIA_BUS_FMT_Y10_1X10,
167                         MEDIA_BUS_FMT_Y12_1X12,
168                 },
169                 .cs     = IPUV3_COLORSPACE_RGB,
170                 .bpp    = 8,
171                 .bayer  = true,
172         }, {
173                 .fourcc = V4L2_PIX_FMT_Y10,
174                 .codes = {MEDIA_BUS_FMT_Y10_1X10},
175                 .cs     = IPUV3_COLORSPACE_RGB,
176                 .bpp    = 16,
177                 .bayer  = true,
178         }, {
179                 .fourcc = V4L2_PIX_FMT_Y12,
180                 .codes = {MEDIA_BUS_FMT_Y12_1X12},
181                 .cs     = IPUV3_COLORSPACE_RGB,
182                 .bpp    = 16,
183                 .bayer  = true,
184         },
185         /***
186          * non-mbus RGB formats start here. NOTE! when adding non-mbus
187          * formats, NUM_NON_MBUS_RGB_FORMATS must be updated below.
188          ***/
189         {
190                 .fourcc = V4L2_PIX_FMT_BGR24,
191                 .cs     = IPUV3_COLORSPACE_RGB,
192                 .bpp    = 24,
193         }, {
194                 .fourcc = V4L2_PIX_FMT_XBGR32,
195                 .cs     = IPUV3_COLORSPACE_RGB,
196                 .bpp    = 32,
197         }, {
198                 .fourcc = V4L2_PIX_FMT_BGRX32,
199                 .cs     = IPUV3_COLORSPACE_RGB,
200                 .bpp    = 32,
201         }, {
202                 .fourcc = V4L2_PIX_FMT_RGBX32,
203                 .cs     = IPUV3_COLORSPACE_RGB,
204                 .bpp    = 32,
205         },
206 };
207
208 #define NUM_NON_MBUS_RGB_FORMATS 2
209 #define NUM_RGB_FORMATS ARRAY_SIZE(rgb_formats)
210 #define NUM_MBUS_RGB_FORMATS (NUM_RGB_FORMATS - NUM_NON_MBUS_RGB_FORMATS)
211
212 static const struct imx_media_pixfmt ipu_yuv_formats[] = {
213         {
214                 .fourcc = V4L2_PIX_FMT_YUV32,
215                 .codes  = {MEDIA_BUS_FMT_AYUV8_1X32},
216                 .cs     = IPUV3_COLORSPACE_YUV,
217                 .bpp    = 32,
218                 .ipufmt = true,
219         },
220 };
221
222 #define NUM_IPU_YUV_FORMATS ARRAY_SIZE(ipu_yuv_formats)
223
224 static const struct imx_media_pixfmt ipu_rgb_formats[] = {
225         {
226                 .fourcc = V4L2_PIX_FMT_XRGB32,
227                 .codes  = {MEDIA_BUS_FMT_ARGB8888_1X32},
228                 .cs     = IPUV3_COLORSPACE_RGB,
229                 .bpp    = 32,
230                 .ipufmt = true,
231         },
232 };
233
234 #define NUM_IPU_RGB_FORMATS ARRAY_SIZE(ipu_rgb_formats)
235
236 static void init_mbus_colorimetry(struct v4l2_mbus_framefmt *mbus,
237                                   const struct imx_media_pixfmt *fmt)
238 {
239         mbus->colorspace = (fmt->cs == IPUV3_COLORSPACE_RGB) ?
240                 V4L2_COLORSPACE_SRGB : V4L2_COLORSPACE_SMPTE170M;
241         mbus->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mbus->colorspace);
242         mbus->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mbus->colorspace);
243         mbus->quantization =
244                 V4L2_MAP_QUANTIZATION_DEFAULT(fmt->cs == IPUV3_COLORSPACE_RGB,
245                                               mbus->colorspace,
246                                               mbus->ycbcr_enc);
247 }
248
249 static const
250 struct imx_media_pixfmt *__find_format(u32 fourcc,
251                                        u32 code,
252                                        bool allow_non_mbus,
253                                        bool allow_bayer,
254                                        const struct imx_media_pixfmt *array,
255                                        u32 array_size)
256 {
257         const struct imx_media_pixfmt *fmt;
258         int i, j;
259
260         for (i = 0; i < array_size; i++) {
261                 fmt = &array[i];
262
263                 if ((!allow_non_mbus && !fmt->codes[0]) ||
264                     (!allow_bayer && fmt->bayer))
265                         continue;
266
267                 if (fourcc && fmt->fourcc == fourcc)
268                         return fmt;
269
270                 if (!code)
271                         continue;
272
273                 for (j = 0; fmt->codes[j]; j++) {
274                         if (code == fmt->codes[j])
275                                 return fmt;
276                 }
277         }
278         return NULL;
279 }
280
281 static const struct imx_media_pixfmt *find_format(u32 fourcc,
282                                                   u32 code,
283                                                   enum codespace_sel cs_sel,
284                                                   bool allow_non_mbus,
285                                                   bool allow_bayer)
286 {
287         const struct imx_media_pixfmt *ret;
288
289         switch (cs_sel) {
290         case CS_SEL_YUV:
291                 return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
292                                      yuv_formats, NUM_YUV_FORMATS);
293         case CS_SEL_RGB:
294                 return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
295                                      rgb_formats, NUM_RGB_FORMATS);
296         case CS_SEL_ANY:
297                 ret = __find_format(fourcc, code, allow_non_mbus, allow_bayer,
298                                     yuv_formats, NUM_YUV_FORMATS);
299                 if (ret)
300                         return ret;
301                 return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
302                                      rgb_formats, NUM_RGB_FORMATS);
303         default:
304                 return NULL;
305         }
306 }
307
308 static int enum_format(u32 *fourcc, u32 *code, u32 index,
309                        enum codespace_sel cs_sel,
310                        bool allow_non_mbus,
311                        bool allow_bayer)
312 {
313         const struct imx_media_pixfmt *fmt;
314         u32 mbus_yuv_sz = NUM_MBUS_YUV_FORMATS;
315         u32 mbus_rgb_sz = NUM_MBUS_RGB_FORMATS;
316         u32 yuv_sz = NUM_YUV_FORMATS;
317         u32 rgb_sz = NUM_RGB_FORMATS;
318
319         switch (cs_sel) {
320         case CS_SEL_YUV:
321                 if (index >= yuv_sz ||
322                     (!allow_non_mbus && index >= mbus_yuv_sz))
323                         return -EINVAL;
324                 fmt = &yuv_formats[index];
325                 break;
326         case CS_SEL_RGB:
327                 if (index >= rgb_sz ||
328                     (!allow_non_mbus && index >= mbus_rgb_sz))
329                         return -EINVAL;
330                 fmt = &rgb_formats[index];
331                 if (!allow_bayer && fmt->bayer)
332                         return -EINVAL;
333                 break;
334         case CS_SEL_ANY:
335                 if (!allow_non_mbus) {
336                         if (index >= mbus_yuv_sz) {
337                                 index -= mbus_yuv_sz;
338                                 if (index >= mbus_rgb_sz)
339                                         return -EINVAL;
340                                 fmt = &rgb_formats[index];
341                                 if (!allow_bayer && fmt->bayer)
342                                         return -EINVAL;
343                         } else {
344                                 fmt = &yuv_formats[index];
345                         }
346                 } else {
347                         if (index >= yuv_sz + rgb_sz)
348                                 return -EINVAL;
349                         if (index >= yuv_sz) {
350                                 fmt = &rgb_formats[index - yuv_sz];
351                                 if (!allow_bayer && fmt->bayer)
352                                         return -EINVAL;
353                         } else {
354                                 fmt = &yuv_formats[index];
355                         }
356                 }
357                 break;
358         default:
359                 return -EINVAL;
360         }
361
362         if (fourcc)
363                 *fourcc = fmt->fourcc;
364         if (code)
365                 *code = fmt->codes[0];
366
367         return 0;
368 }
369
370 const struct imx_media_pixfmt *
371 imx_media_find_format(u32 fourcc, enum codespace_sel cs_sel, bool allow_bayer)
372 {
373         return find_format(fourcc, 0, cs_sel, true, allow_bayer);
374 }
375 EXPORT_SYMBOL_GPL(imx_media_find_format);
376
377 int imx_media_enum_format(u32 *fourcc, u32 index, enum codespace_sel cs_sel)
378 {
379         return enum_format(fourcc, NULL, index, cs_sel, true, false);
380 }
381 EXPORT_SYMBOL_GPL(imx_media_enum_format);
382
383 const struct imx_media_pixfmt *
384 imx_media_find_mbus_format(u32 code, enum codespace_sel cs_sel,
385                            bool allow_bayer)
386 {
387         return find_format(0, code, cs_sel, false, allow_bayer);
388 }
389 EXPORT_SYMBOL_GPL(imx_media_find_mbus_format);
390
391 int imx_media_enum_mbus_format(u32 *code, u32 index, enum codespace_sel cs_sel,
392                                bool allow_bayer)
393 {
394         return enum_format(NULL, code, index, cs_sel, false, allow_bayer);
395 }
396 EXPORT_SYMBOL_GPL(imx_media_enum_mbus_format);
397
398 const struct imx_media_pixfmt *
399 imx_media_find_ipu_format(u32 code, enum codespace_sel cs_sel)
400 {
401         const struct imx_media_pixfmt *array, *fmt, *ret = NULL;
402         u32 array_size;
403         int i, j;
404
405         switch (cs_sel) {
406         case CS_SEL_YUV:
407                 array_size = NUM_IPU_YUV_FORMATS;
408                 array = ipu_yuv_formats;
409                 break;
410         case CS_SEL_RGB:
411                 array_size = NUM_IPU_RGB_FORMATS;
412                 array = ipu_rgb_formats;
413                 break;
414         case CS_SEL_ANY:
415                 array_size = NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS;
416                 array = ipu_yuv_formats;
417                 break;
418         default:
419                 return NULL;
420         }
421
422         for (i = 0; i < array_size; i++) {
423                 if (cs_sel == CS_SEL_ANY && i >= NUM_IPU_YUV_FORMATS)
424                         fmt = &ipu_rgb_formats[i - NUM_IPU_YUV_FORMATS];
425                 else
426                         fmt = &array[i];
427
428                 for (j = 0; code && fmt->codes[j]; j++) {
429                         if (code == fmt->codes[j]) {
430                                 ret = fmt;
431                                 goto out;
432                         }
433                 }
434         }
435
436 out:
437         return ret;
438 }
439 EXPORT_SYMBOL_GPL(imx_media_find_ipu_format);
440
441 int imx_media_enum_ipu_format(u32 *code, u32 index, enum codespace_sel cs_sel)
442 {
443         switch (cs_sel) {
444         case CS_SEL_YUV:
445                 if (index >= NUM_IPU_YUV_FORMATS)
446                         return -EINVAL;
447                 *code = ipu_yuv_formats[index].codes[0];
448                 break;
449         case CS_SEL_RGB:
450                 if (index >= NUM_IPU_RGB_FORMATS)
451                         return -EINVAL;
452                 *code = ipu_rgb_formats[index].codes[0];
453                 break;
454         case CS_SEL_ANY:
455                 if (index >= NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS)
456                         return -EINVAL;
457                 if (index >= NUM_IPU_YUV_FORMATS) {
458                         index -= NUM_IPU_YUV_FORMATS;
459                         *code = ipu_rgb_formats[index].codes[0];
460                 } else {
461                         *code = ipu_yuv_formats[index].codes[0];
462                 }
463                 break;
464         default:
465                 return -EINVAL;
466         }
467
468         return 0;
469 }
470 EXPORT_SYMBOL_GPL(imx_media_enum_ipu_format);
471
472 int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
473                             u32 width, u32 height, u32 code, u32 field,
474                             const struct imx_media_pixfmt **cc)
475 {
476         const struct imx_media_pixfmt *lcc;
477
478         mbus->width = width;
479         mbus->height = height;
480         mbus->field = field;
481         if (code == 0)
482                 imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false);
483         lcc = imx_media_find_mbus_format(code, CS_SEL_ANY, false);
484         if (!lcc) {
485                 lcc = imx_media_find_ipu_format(code, CS_SEL_ANY);
486                 if (!lcc)
487                         return -EINVAL;
488         }
489
490         mbus->code = code;
491         init_mbus_colorimetry(mbus, lcc);
492         if (cc)
493                 *cc = lcc;
494
495         return 0;
496 }
497 EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
498
499 /*
500  * Initializes the TRY format to the ACTIVE format on all pads
501  * of a subdev. Can be used as the .init_cfg pad operation.
502  */
503 int imx_media_init_cfg(struct v4l2_subdev *sd,
504                        struct v4l2_subdev_pad_config *cfg)
505 {
506         struct v4l2_mbus_framefmt *mf_try;
507         struct v4l2_subdev_format format;
508         unsigned int pad;
509         int ret;
510
511         for (pad = 0; pad < sd->entity.num_pads; pad++) {
512                 memset(&format, 0, sizeof(format));
513
514                 format.pad = pad;
515                 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
516                 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format);
517                 if (ret)
518                         continue;
519
520                 mf_try = v4l2_subdev_get_try_format(sd, cfg, pad);
521                 *mf_try = format.format;
522         }
523
524         return 0;
525 }
526 EXPORT_SYMBOL_GPL(imx_media_init_cfg);
527
528 /*
529  * Default the colorspace in tryfmt to SRGB if set to an unsupported
530  * colorspace or not initialized. Then set the remaining colorimetry
531  * parameters based on the colorspace if they are uninitialized.
532  *
533  * tryfmt->code must be set on entry.
534  *
535  * If this format is destined to be routed through the Image Converter,
536  * Y`CbCr encoding must be fixed. The IC supports only BT.601 Y`CbCr
537  * or Rec.709 Y`CbCr encoding.
538  */
539 void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt,
540                                bool ic_route)
541 {
542         const struct imx_media_pixfmt *cc;
543         bool is_rgb = false;
544
545         cc = imx_media_find_mbus_format(tryfmt->code, CS_SEL_ANY, true);
546         if (!cc)
547                 cc = imx_media_find_ipu_format(tryfmt->code, CS_SEL_ANY);
548         if (cc && cc->cs == IPUV3_COLORSPACE_RGB)
549                 is_rgb = true;
550
551         switch (tryfmt->colorspace) {
552         case V4L2_COLORSPACE_SMPTE170M:
553         case V4L2_COLORSPACE_REC709:
554         case V4L2_COLORSPACE_JPEG:
555         case V4L2_COLORSPACE_SRGB:
556         case V4L2_COLORSPACE_BT2020:
557         case V4L2_COLORSPACE_OPRGB:
558         case V4L2_COLORSPACE_DCI_P3:
559         case V4L2_COLORSPACE_RAW:
560                 break;
561         default:
562                 tryfmt->colorspace = V4L2_COLORSPACE_SRGB;
563                 break;
564         }
565
566         if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT)
567                 tryfmt->xfer_func =
568                         V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace);
569
570         if (ic_route) {
571                 if (tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_601 &&
572                     tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_709)
573                         tryfmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
574         } else {
575                 if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
576                         tryfmt->ycbcr_enc =
577                                 V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace);
578                 }
579         }
580
581         if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT)
582                 tryfmt->quantization =
583                         V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb,
584                                                       tryfmt->colorspace,
585                                                       tryfmt->ycbcr_enc);
586 }
587 EXPORT_SYMBOL_GPL(imx_media_try_colorimetry);
588
589 int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
590                                   struct v4l2_mbus_framefmt *mbus,
591                                   const struct imx_media_pixfmt *cc)
592 {
593         u32 width;
594         u32 stride;
595
596         if (!cc) {
597                 cc = imx_media_find_ipu_format(mbus->code, CS_SEL_ANY);
598                 if (!cc)
599                         cc = imx_media_find_mbus_format(mbus->code, CS_SEL_ANY,
600                                                         true);
601                 if (!cc)
602                         return -EINVAL;
603         }
604
605         /*
606          * TODO: the IPU currently does not support the AYUV32 format,
607          * so until it does convert to a supported YUV format.
608          */
609         if (cc->ipufmt && cc->cs == IPUV3_COLORSPACE_YUV) {
610                 u32 code;
611
612                 imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false);
613                 cc = imx_media_find_mbus_format(code, CS_SEL_YUV, false);
614         }
615
616         /* Round up width for minimum burst size */
617         width = round_up(mbus->width, 8);
618
619         /* Round up stride for IDMAC line start address alignment */
620         if (cc->planar)
621                 stride = round_up(width, 16);
622         else
623                 stride = round_up((width * cc->bpp) >> 3, 8);
624
625         pix->width = width;
626         pix->height = mbus->height;
627         pix->pixelformat = cc->fourcc;
628         pix->colorspace = mbus->colorspace;
629         pix->xfer_func = mbus->xfer_func;
630         pix->ycbcr_enc = mbus->ycbcr_enc;
631         pix->quantization = mbus->quantization;
632         pix->field = mbus->field;
633         pix->bytesperline = stride;
634         pix->sizeimage = cc->planar ? ((stride * pix->height * cc->bpp) >> 3) :
635                          stride * pix->height;
636
637         return 0;
638 }
639 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt);
640
641 int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image,
642                                     struct v4l2_mbus_framefmt *mbus)
643 {
644         int ret;
645
646         memset(image, 0, sizeof(*image));
647
648         ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, mbus, NULL);
649         if (ret)
650                 return ret;
651
652         image->rect.width = mbus->width;
653         image->rect.height = mbus->height;
654
655         return 0;
656 }
657 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image);
658
659 int imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
660                                     struct ipu_image *image)
661 {
662         const struct imx_media_pixfmt *fmt;
663
664         fmt = imx_media_find_format(image->pix.pixelformat, CS_SEL_ANY, true);
665         if (!fmt)
666                 return -EINVAL;
667
668         memset(mbus, 0, sizeof(*mbus));
669         mbus->width = image->pix.width;
670         mbus->height = image->pix.height;
671         mbus->code = fmt->codes[0];
672         mbus->field = image->pix.field;
673         mbus->colorspace = image->pix.colorspace;
674         mbus->xfer_func = image->pix.xfer_func;
675         mbus->ycbcr_enc = image->pix.ycbcr_enc;
676         mbus->quantization = image->pix.quantization;
677
678         return 0;
679 }
680 EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt);
681
682 void imx_media_free_dma_buf(struct device *dev,
683                             struct imx_media_dma_buf *buf)
684 {
685         if (buf->virt)
686                 dma_free_coherent(dev, buf->len, buf->virt, buf->phys);
687
688         buf->virt = NULL;
689         buf->phys = 0;
690 }
691 EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
692
693 int imx_media_alloc_dma_buf(struct device *dev,
694                             struct imx_media_dma_buf *buf,
695                             int size)
696 {
697         imx_media_free_dma_buf(dev, buf);
698
699         buf->len = PAGE_ALIGN(size);
700         buf->virt = dma_alloc_coherent(dev, buf->len, &buf->phys,
701                                        GFP_DMA | GFP_KERNEL);
702         if (!buf->virt) {
703                 dev_err(dev, "%s: failed\n", __func__);
704                 return -ENOMEM;
705         }
706
707         return 0;
708 }
709 EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf);
710
711 /* form a subdev name given a group id and ipu id */
712 void imx_media_grp_id_to_sd_name(char *sd_name, int sz, u32 grp_id, int ipu_id)
713 {
714         int id;
715
716         switch (grp_id) {
717         case IMX_MEDIA_GRP_ID_IPU_CSI0...IMX_MEDIA_GRP_ID_IPU_CSI1:
718                 id = (grp_id >> IMX_MEDIA_GRP_ID_IPU_CSI_BIT) - 1;
719                 snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id);
720                 break;
721         case IMX_MEDIA_GRP_ID_IPU_VDIC:
722                 snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1);
723                 break;
724         case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
725                 snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1);
726                 break;
727         case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
728                 snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1);
729                 break;
730         case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
731                 snprintf(sd_name, sz, "ipu%d_ic_prpvf", ipu_id + 1);
732                 break;
733         default:
734                 break;
735         }
736 }
737 EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name);
738
739 struct v4l2_subdev *
740 imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd,
741                                 struct fwnode_handle *fwnode)
742 {
743         struct v4l2_subdev *sd;
744
745         list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
746                 if (sd->fwnode == fwnode)
747                         return sd;
748         }
749
750         return NULL;
751 }
752 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode);
753
754 struct v4l2_subdev *
755 imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd,
756                                  const char *devname)
757 {
758         struct v4l2_subdev *sd;
759
760         list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
761                 if (!strcmp(devname, dev_name(sd->dev)))
762                         return sd;
763         }
764
765         return NULL;
766 }
767 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname);
768
769 /*
770  * Adds a video device to the master video device list. This is called
771  * when a video device is registered.
772  */
773 void imx_media_add_video_device(struct imx_media_dev *imxmd,
774                                 struct imx_media_video_dev *vdev)
775 {
776         mutex_lock(&imxmd->mutex);
777
778         list_add_tail(&vdev->list, &imxmd->vdev_list);
779
780         mutex_unlock(&imxmd->mutex);
781 }
782 EXPORT_SYMBOL_GPL(imx_media_add_video_device);
783
784 /*
785  * Search upstream/downstream for a subdevice or video device pad in the
786  * current pipeline, starting from start_entity. Returns the device's
787  * source/sink pad that it was reached from. Must be called with
788  * mdev->graph_mutex held.
789  *
790  * If grp_id != 0, finds a subdevice's pad of given grp_id.
791  * Else If buftype != 0, finds a video device's pad of given buffer type.
792  * Else, returns the nearest source/sink pad to start_entity.
793  */
794 struct media_pad *
795 imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id,
796                        enum v4l2_buf_type buftype, bool upstream)
797 {
798         struct media_entity *me = start_entity;
799         struct media_pad *pad = NULL;
800         struct video_device *vfd;
801         struct v4l2_subdev *sd;
802         int i;
803
804         for (i = 0; i < me->num_pads; i++) {
805                 struct media_pad *spad = &me->pads[i];
806
807                 if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) ||
808                     (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE)))
809                         continue;
810
811                 pad = media_entity_remote_pad(spad);
812                 if (!pad)
813                         continue;
814
815                 if (grp_id) {
816                         if (is_media_entity_v4l2_subdev(pad->entity)) {
817                                 sd = media_entity_to_v4l2_subdev(pad->entity);
818                                 if (sd->grp_id & grp_id)
819                                         return pad;
820                         }
821
822                         return imx_media_pipeline_pad(pad->entity, grp_id,
823                                                       buftype, upstream);
824                 } else if (buftype) {
825                         if (is_media_entity_v4l2_video_device(pad->entity)) {
826                                 vfd = media_entity_to_video_device(pad->entity);
827                                 if (buftype == vfd->queue->type)
828                                         return pad;
829                         }
830
831                         return imx_media_pipeline_pad(pad->entity, grp_id,
832                                                       buftype, upstream);
833                 } else {
834                         return pad;
835                 }
836         }
837
838         return NULL;
839 }
840 EXPORT_SYMBOL_GPL(imx_media_pipeline_pad);
841
842 /*
843  * Search upstream/downstream for a subdev or video device in the current
844  * pipeline. Must be called with mdev->graph_mutex held.
845  */
846 static struct media_entity *
847 find_pipeline_entity(struct media_entity *start, u32 grp_id,
848                      enum v4l2_buf_type buftype, bool upstream)
849 {
850         struct media_pad *pad = NULL;
851         struct video_device *vfd;
852         struct v4l2_subdev *sd;
853
854         if (grp_id && is_media_entity_v4l2_subdev(start)) {
855                 sd = media_entity_to_v4l2_subdev(start);
856                 if (sd->grp_id & grp_id)
857                         return &sd->entity;
858         } else if (buftype && is_media_entity_v4l2_video_device(start)) {
859                 vfd = media_entity_to_video_device(start);
860                 if (buftype == vfd->queue->type)
861                         return &vfd->entity;
862         }
863
864         pad = imx_media_pipeline_pad(start, grp_id, buftype, upstream);
865
866         return pad ? pad->entity : NULL;
867 }
868
869 /*
870  * Find the upstream mipi-csi2 virtual channel reached from the given
871  * start entity in the current pipeline.
872  * Must be called with mdev->graph_mutex held.
873  */
874 int imx_media_pipeline_csi2_channel(struct media_entity *start_entity)
875 {
876         struct media_pad *pad;
877         int ret = -EPIPE;
878
879         pad = imx_media_pipeline_pad(start_entity, IMX_MEDIA_GRP_ID_CSI2,
880                                      0, true);
881         if (pad)
882                 ret = pad->index - 1;
883
884         return ret;
885 }
886 EXPORT_SYMBOL_GPL(imx_media_pipeline_csi2_channel);
887
888 /*
889  * Find a subdev reached upstream from the given start entity in
890  * the current pipeline.
891  * Must be called with mdev->graph_mutex held.
892  */
893 struct v4l2_subdev *
894 imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id,
895                           bool upstream)
896 {
897         struct media_entity *me;
898
899         me = find_pipeline_entity(start_entity, grp_id, 0, upstream);
900         if (!me)
901                 return ERR_PTR(-ENODEV);
902
903         return media_entity_to_v4l2_subdev(me);
904 }
905 EXPORT_SYMBOL_GPL(imx_media_pipeline_subdev);
906
907 /*
908  * Find a subdev reached upstream from the given start entity in
909  * the current pipeline.
910  * Must be called with mdev->graph_mutex held.
911  */
912 struct video_device *
913 imx_media_pipeline_video_device(struct media_entity *start_entity,
914                                 enum v4l2_buf_type buftype, bool upstream)
915 {
916         struct media_entity *me;
917
918         me = find_pipeline_entity(start_entity, 0, buftype, upstream);
919         if (!me)
920                 return ERR_PTR(-ENODEV);
921
922         return media_entity_to_video_device(me);
923 }
924 EXPORT_SYMBOL_GPL(imx_media_pipeline_video_device);
925
926 /*
927  * Turn current pipeline streaming on/off starting from entity.
928  */
929 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
930                                   struct media_entity *entity,
931                                   bool on)
932 {
933         struct v4l2_subdev *sd;
934         int ret = 0;
935
936         if (!is_media_entity_v4l2_subdev(entity))
937                 return -EINVAL;
938         sd = media_entity_to_v4l2_subdev(entity);
939
940         mutex_lock(&imxmd->md.graph_mutex);
941
942         if (on) {
943                 ret = __media_pipeline_start(entity, &imxmd->pipe);
944                 if (ret)
945                         goto out;
946                 ret = v4l2_subdev_call(sd, video, s_stream, 1);
947                 if (ret)
948                         __media_pipeline_stop(entity);
949         } else {
950                 v4l2_subdev_call(sd, video, s_stream, 0);
951                 if (entity->pipe)
952                         __media_pipeline_stop(entity);
953         }
954
955 out:
956         mutex_unlock(&imxmd->md.graph_mutex);
957         return ret;
958 }
959 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
960
961 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
962 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
963 MODULE_LICENSE("GPL");