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