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