]> git.samba.org - sfrench/cifs-2.6.git/blob - drivers/staging/media/imx/imx-media-utils.c
Merge tag 'selinux-pr-20210629' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.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  * @code: If non-zero, only include in the enumeration entries matching this
287  *      media bus code.
288  */
289 int imx_media_enum_pixel_formats(u32 *fourcc, u32 index,
290                                  enum imx_pixfmt_sel fmt_sel, u32 code)
291 {
292         bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
293         unsigned int i;
294
295         fmt_sel &= ~PIXFMT_SEL_IPU;
296
297         for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
298                 const struct imx_media_pixfmt *fmt = &pixel_formats[i];
299                 enum imx_pixfmt_sel sel;
300
301                 if (sel_ipu != fmt->ipufmt)
302                         continue;
303
304                 sel = fmt->bayer ? PIXFMT_SEL_BAYER :
305                         ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
306                          PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
307
308                 if (!(fmt_sel & sel))
309                         continue;
310
311                 /*
312                  * If a media bus code is specified, only consider formats that
313                  * match it.
314                  */
315                 if (code) {
316                         unsigned int j;
317
318                         if (!fmt->codes)
319                                 continue;
320
321                         for (j = 0; fmt->codes[j]; j++) {
322                                 if (code == fmt->codes[j])
323                                         break;
324                         }
325
326                         if (!fmt->codes[j])
327                                 continue;
328                 }
329
330                 if (index == 0) {
331                         *fourcc = fmt->fourcc;
332                         return 0;
333                 }
334
335                 index--;
336         }
337
338         return -EINVAL;
339 }
340 EXPORT_SYMBOL_GPL(imx_media_enum_pixel_formats);
341
342 /*
343  * Enumerate entries in the pixel_formats[] array that match the
344  * requested search criteria. Return the media-bus code that matches
345  * the search criteria at the requested match index.
346  *
347  * @code: The returned media-bus code that matches the search criteria at
348  *        the requested match index.
349  * @index: The requested match index.
350  * @fmt_sel: Include in the enumeration entries with the given selection
351  *           criteria.
352  */
353 int imx_media_enum_mbus_formats(u32 *code, u32 index,
354                                 enum imx_pixfmt_sel fmt_sel)
355 {
356         bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
357         unsigned int i;
358
359         fmt_sel &= ~PIXFMT_SEL_IPU;
360
361         for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
362                 const struct imx_media_pixfmt *fmt = &pixel_formats[i];
363                 enum imx_pixfmt_sel sel;
364                 unsigned int j;
365
366                 if (sel_ipu != fmt->ipufmt)
367                         continue;
368
369                 sel = fmt->bayer ? PIXFMT_SEL_BAYER :
370                         ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
371                          PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
372
373                 if (!(fmt_sel & sel) || !fmt->codes)
374                         continue;
375
376                 for (j = 0; fmt->codes[j]; j++) {
377                         if (index == 0) {
378                                 *code = fmt->codes[j];
379                                 return 0;
380                         }
381
382                         index--;
383                 }
384         }
385
386         return -EINVAL;
387 }
388 EXPORT_SYMBOL_GPL(imx_media_enum_mbus_formats);
389
390 int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
391                             u32 width, u32 height, u32 code, u32 field,
392                             const struct imx_media_pixfmt **cc)
393 {
394         const struct imx_media_pixfmt *lcc;
395
396         mbus->width = width;
397         mbus->height = height;
398         mbus->field = field;
399
400         if (code == 0)
401                 imx_media_enum_mbus_formats(&code, 0, PIXFMT_SEL_YUV);
402
403         lcc = imx_media_find_mbus_format(code, PIXFMT_SEL_ANY);
404         if (!lcc) {
405                 lcc = imx_media_find_ipu_format(code, PIXFMT_SEL_YUV_RGB);
406                 if (!lcc)
407                         return -EINVAL;
408         }
409
410         mbus->code = code;
411
412         mbus->colorspace = V4L2_COLORSPACE_SRGB;
413         mbus->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mbus->colorspace);
414         mbus->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mbus->colorspace);
415         mbus->quantization =
416                 V4L2_MAP_QUANTIZATION_DEFAULT(lcc->cs == IPUV3_COLORSPACE_RGB,
417                                               mbus->colorspace,
418                                               mbus->ycbcr_enc);
419
420         if (cc)
421                 *cc = lcc;
422
423         return 0;
424 }
425 EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
426
427 /*
428  * Initializes the TRY format to the ACTIVE format on all pads
429  * of a subdev. Can be used as the .init_cfg pad operation.
430  */
431 int imx_media_init_cfg(struct v4l2_subdev *sd,
432                        struct v4l2_subdev_state *sd_state)
433 {
434         struct v4l2_mbus_framefmt *mf_try;
435         struct v4l2_subdev_format format;
436         unsigned int pad;
437         int ret;
438
439         for (pad = 0; pad < sd->entity.num_pads; pad++) {
440                 memset(&format, 0, sizeof(format));
441
442                 format.pad = pad;
443                 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
444                 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format);
445                 if (ret)
446                         continue;
447
448                 mf_try = v4l2_subdev_get_try_format(sd, sd_state, pad);
449                 *mf_try = format.format;
450         }
451
452         return 0;
453 }
454 EXPORT_SYMBOL_GPL(imx_media_init_cfg);
455
456 /*
457  * Default the colorspace in tryfmt to SRGB if set to an unsupported
458  * colorspace or not initialized. Then set the remaining colorimetry
459  * parameters based on the colorspace if they are uninitialized.
460  *
461  * tryfmt->code must be set on entry.
462  *
463  * If this format is destined to be routed through the Image Converter,
464  * Y`CbCr encoding must be fixed. The IC supports only BT.601 Y`CbCr
465  * or Rec.709 Y`CbCr encoding.
466  */
467 void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt,
468                                bool ic_route)
469 {
470         const struct imx_media_pixfmt *cc;
471         bool is_rgb = false;
472
473         cc = imx_media_find_mbus_format(tryfmt->code, PIXFMT_SEL_ANY);
474         if (!cc)
475                 cc = imx_media_find_ipu_format(tryfmt->code,
476                                                PIXFMT_SEL_YUV_RGB);
477
478         if (cc && cc->cs == IPUV3_COLORSPACE_RGB)
479                 is_rgb = true;
480
481         switch (tryfmt->colorspace) {
482         case V4L2_COLORSPACE_SMPTE170M:
483         case V4L2_COLORSPACE_REC709:
484         case V4L2_COLORSPACE_JPEG:
485         case V4L2_COLORSPACE_SRGB:
486         case V4L2_COLORSPACE_BT2020:
487         case V4L2_COLORSPACE_OPRGB:
488         case V4L2_COLORSPACE_DCI_P3:
489         case V4L2_COLORSPACE_RAW:
490                 break;
491         default:
492                 tryfmt->colorspace = V4L2_COLORSPACE_SRGB;
493                 break;
494         }
495
496         if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT)
497                 tryfmt->xfer_func =
498                         V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace);
499
500         if (ic_route) {
501                 if (tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_601 &&
502                     tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_709)
503                         tryfmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
504         } else {
505                 if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
506                         tryfmt->ycbcr_enc =
507                                 V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace);
508                 }
509         }
510
511         if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT)
512                 tryfmt->quantization =
513                         V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb,
514                                                       tryfmt->colorspace,
515                                                       tryfmt->ycbcr_enc);
516 }
517 EXPORT_SYMBOL_GPL(imx_media_try_colorimetry);
518
519 int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
520                                   const struct v4l2_mbus_framefmt *mbus,
521                                   const struct imx_media_pixfmt *cc)
522 {
523         u32 width;
524         u32 stride;
525
526         if (!cc) {
527                 cc = imx_media_find_ipu_format(mbus->code,
528                                                PIXFMT_SEL_YUV_RGB);
529                 if (!cc)
530                         cc = imx_media_find_mbus_format(mbus->code,
531                                                         PIXFMT_SEL_ANY);
532                 if (!cc)
533                         return -EINVAL;
534         }
535
536         /*
537          * TODO: the IPU currently does not support the AYUV32 format,
538          * so until it does convert to a supported YUV format.
539          */
540         if (cc->ipufmt && cc->cs == IPUV3_COLORSPACE_YUV) {
541                 u32 code;
542
543                 imx_media_enum_mbus_formats(&code, 0, PIXFMT_SEL_YUV);
544                 cc = imx_media_find_mbus_format(code, PIXFMT_SEL_YUV);
545         }
546
547         /* Round up width for minimum burst size */
548         width = round_up(mbus->width, 8);
549
550         /* Round up stride for IDMAC line start address alignment */
551         if (cc->planar)
552                 stride = round_up(width, 16);
553         else
554                 stride = round_up((width * cc->bpp) >> 3, 8);
555
556         pix->width = width;
557         pix->height = mbus->height;
558         pix->pixelformat = cc->fourcc;
559         pix->colorspace = mbus->colorspace;
560         pix->xfer_func = mbus->xfer_func;
561         pix->ycbcr_enc = mbus->ycbcr_enc;
562         pix->quantization = mbus->quantization;
563         pix->field = mbus->field;
564         pix->bytesperline = stride;
565         pix->sizeimage = cc->planar ? ((stride * pix->height * cc->bpp) >> 3) :
566                          stride * pix->height;
567
568         return 0;
569 }
570 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt);
571
572 int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image,
573                                     const struct v4l2_mbus_framefmt *mbus)
574 {
575         int ret;
576
577         memset(image, 0, sizeof(*image));
578
579         ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, mbus, NULL);
580         if (ret)
581                 return ret;
582
583         image->rect.width = mbus->width;
584         image->rect.height = mbus->height;
585
586         return 0;
587 }
588 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image);
589
590 int imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
591                                     const struct ipu_image *image)
592 {
593         const struct imx_media_pixfmt *fmt;
594
595         fmt = imx_media_find_pixel_format(image->pix.pixelformat,
596                                           PIXFMT_SEL_ANY);
597         if (!fmt || !fmt->codes || !fmt->codes[0])
598                 return -EINVAL;
599
600         memset(mbus, 0, sizeof(*mbus));
601         mbus->width = image->pix.width;
602         mbus->height = image->pix.height;
603         mbus->code = fmt->codes[0];
604         mbus->field = image->pix.field;
605         mbus->colorspace = image->pix.colorspace;
606         mbus->xfer_func = image->pix.xfer_func;
607         mbus->ycbcr_enc = image->pix.ycbcr_enc;
608         mbus->quantization = image->pix.quantization;
609
610         return 0;
611 }
612 EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt);
613
614 void imx_media_free_dma_buf(struct device *dev,
615                             struct imx_media_dma_buf *buf)
616 {
617         if (buf->virt)
618                 dma_free_coherent(dev, buf->len, buf->virt, buf->phys);
619
620         buf->virt = NULL;
621         buf->phys = 0;
622 }
623 EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
624
625 int imx_media_alloc_dma_buf(struct device *dev,
626                             struct imx_media_dma_buf *buf,
627                             int size)
628 {
629         imx_media_free_dma_buf(dev, buf);
630
631         buf->len = PAGE_ALIGN(size);
632         buf->virt = dma_alloc_coherent(dev, buf->len, &buf->phys,
633                                        GFP_DMA | GFP_KERNEL);
634         if (!buf->virt) {
635                 dev_err(dev, "%s: failed\n", __func__);
636                 return -ENOMEM;
637         }
638
639         return 0;
640 }
641 EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf);
642
643 /* form a subdev name given a group id and ipu id */
644 void imx_media_grp_id_to_sd_name(char *sd_name, int sz, u32 grp_id, int ipu_id)
645 {
646         int id;
647
648         switch (grp_id) {
649         case IMX_MEDIA_GRP_ID_IPU_CSI0...IMX_MEDIA_GRP_ID_IPU_CSI1:
650                 id = (grp_id >> IMX_MEDIA_GRP_ID_IPU_CSI_BIT) - 1;
651                 snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id);
652                 break;
653         case IMX_MEDIA_GRP_ID_IPU_VDIC:
654                 snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1);
655                 break;
656         case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
657                 snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1);
658                 break;
659         case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
660                 snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1);
661                 break;
662         case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
663                 snprintf(sd_name, sz, "ipu%d_ic_prpvf", ipu_id + 1);
664                 break;
665         default:
666                 break;
667         }
668 }
669 EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name);
670
671 struct v4l2_subdev *
672 imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd,
673                                 struct fwnode_handle *fwnode)
674 {
675         struct v4l2_subdev *sd;
676
677         list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
678                 if (sd->fwnode == fwnode)
679                         return sd;
680         }
681
682         return NULL;
683 }
684 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode);
685
686 struct v4l2_subdev *
687 imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd,
688                                  const char *devname)
689 {
690         struct v4l2_subdev *sd;
691
692         list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
693                 if (!strcmp(devname, dev_name(sd->dev)))
694                         return sd;
695         }
696
697         return NULL;
698 }
699 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname);
700
701 /*
702  * Adds a video device to the master video device list. This is called
703  * when a video device is registered.
704  */
705 void imx_media_add_video_device(struct imx_media_dev *imxmd,
706                                 struct imx_media_video_dev *vdev)
707 {
708         mutex_lock(&imxmd->mutex);
709
710         list_add_tail(&vdev->list, &imxmd->vdev_list);
711
712         mutex_unlock(&imxmd->mutex);
713 }
714 EXPORT_SYMBOL_GPL(imx_media_add_video_device);
715
716 /*
717  * Search upstream/downstream for a subdevice or video device pad in the
718  * current pipeline, starting from start_entity. Returns the device's
719  * source/sink pad that it was reached from. Must be called with
720  * mdev->graph_mutex held.
721  *
722  * If grp_id != 0, finds a subdevice's pad of given grp_id.
723  * Else If buftype != 0, finds a video device's pad of given buffer type.
724  * Else, returns the nearest source/sink pad to start_entity.
725  */
726 struct media_pad *
727 imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id,
728                        enum v4l2_buf_type buftype, bool upstream)
729 {
730         struct media_entity *me = start_entity;
731         struct media_pad *pad = NULL;
732         struct video_device *vfd;
733         struct v4l2_subdev *sd;
734         int i;
735
736         for (i = 0; i < me->num_pads; i++) {
737                 struct media_pad *spad = &me->pads[i];
738
739                 if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) ||
740                     (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE)))
741                         continue;
742
743                 pad = media_entity_remote_pad(spad);
744                 if (!pad)
745                         continue;
746
747                 if (grp_id) {
748                         if (is_media_entity_v4l2_subdev(pad->entity)) {
749                                 sd = media_entity_to_v4l2_subdev(pad->entity);
750                                 if (sd->grp_id & grp_id)
751                                         return pad;
752                         }
753
754                         return imx_media_pipeline_pad(pad->entity, grp_id,
755                                                       buftype, upstream);
756                 } else if (buftype) {
757                         if (is_media_entity_v4l2_video_device(pad->entity)) {
758                                 vfd = media_entity_to_video_device(pad->entity);
759                                 if (buftype == vfd->queue->type)
760                                         return pad;
761                         }
762
763                         return imx_media_pipeline_pad(pad->entity, grp_id,
764                                                       buftype, upstream);
765                 } else {
766                         return pad;
767                 }
768         }
769
770         return NULL;
771 }
772 EXPORT_SYMBOL_GPL(imx_media_pipeline_pad);
773
774 /*
775  * Search upstream/downstream for a subdev or video device in the current
776  * pipeline. Must be called with mdev->graph_mutex held.
777  */
778 static struct media_entity *
779 find_pipeline_entity(struct media_entity *start, u32 grp_id,
780                      enum v4l2_buf_type buftype, bool upstream)
781 {
782         struct media_pad *pad = NULL;
783         struct video_device *vfd;
784         struct v4l2_subdev *sd;
785
786         if (grp_id && is_media_entity_v4l2_subdev(start)) {
787                 sd = media_entity_to_v4l2_subdev(start);
788                 if (sd->grp_id & grp_id)
789                         return &sd->entity;
790         } else if (buftype && is_media_entity_v4l2_video_device(start)) {
791                 vfd = media_entity_to_video_device(start);
792                 if (buftype == vfd->queue->type)
793                         return &vfd->entity;
794         }
795
796         pad = imx_media_pipeline_pad(start, grp_id, buftype, upstream);
797
798         return pad ? pad->entity : NULL;
799 }
800
801 /*
802  * Find the upstream mipi-csi2 virtual channel reached from the given
803  * start entity in the current pipeline.
804  * Must be called with mdev->graph_mutex held.
805  */
806 int imx_media_pipeline_csi2_channel(struct media_entity *start_entity)
807 {
808         struct media_pad *pad;
809         int ret = -EPIPE;
810
811         pad = imx_media_pipeline_pad(start_entity, IMX_MEDIA_GRP_ID_CSI2,
812                                      0, true);
813         if (pad)
814                 ret = pad->index - 1;
815
816         return ret;
817 }
818 EXPORT_SYMBOL_GPL(imx_media_pipeline_csi2_channel);
819
820 /*
821  * Find a subdev reached upstream from the given start entity in
822  * the current pipeline.
823  * Must be called with mdev->graph_mutex held.
824  */
825 struct v4l2_subdev *
826 imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id,
827                           bool upstream)
828 {
829         struct media_entity *me;
830
831         me = find_pipeline_entity(start_entity, grp_id, 0, upstream);
832         if (!me)
833                 return ERR_PTR(-ENODEV);
834
835         return media_entity_to_v4l2_subdev(me);
836 }
837 EXPORT_SYMBOL_GPL(imx_media_pipeline_subdev);
838
839 /*
840  * Find a subdev reached upstream from the given start entity in
841  * the current pipeline.
842  * Must be called with mdev->graph_mutex held.
843  */
844 struct video_device *
845 imx_media_pipeline_video_device(struct media_entity *start_entity,
846                                 enum v4l2_buf_type buftype, bool upstream)
847 {
848         struct media_entity *me;
849
850         me = find_pipeline_entity(start_entity, 0, buftype, upstream);
851         if (!me)
852                 return ERR_PTR(-ENODEV);
853
854         return media_entity_to_video_device(me);
855 }
856 EXPORT_SYMBOL_GPL(imx_media_pipeline_video_device);
857
858 /*
859  * Find a fwnode endpoint that maps to the given subdevice's pad.
860  * If there are multiple endpoints that map to the pad, only the
861  * first endpoint encountered is returned.
862  *
863  * On success the refcount of the returned fwnode endpoint is
864  * incremented.
865  */
866 struct fwnode_handle *imx_media_get_pad_fwnode(struct media_pad *pad)
867 {
868         struct fwnode_handle *endpoint;
869         struct v4l2_subdev *sd;
870
871         if (!is_media_entity_v4l2_subdev(pad->entity))
872                 return ERR_PTR(-ENODEV);
873
874         sd = media_entity_to_v4l2_subdev(pad->entity);
875
876         fwnode_graph_for_each_endpoint(dev_fwnode(sd->dev), endpoint) {
877                 int pad_idx = media_entity_get_fwnode_pad(&sd->entity,
878                                                           endpoint,
879                                                           pad->flags);
880                 if (pad_idx < 0)
881                         continue;
882
883                 if (pad_idx == pad->index)
884                         return endpoint;
885         }
886
887         return ERR_PTR(-ENODEV);
888 }
889 EXPORT_SYMBOL_GPL(imx_media_get_pad_fwnode);
890
891 /*
892  * Turn current pipeline streaming on/off starting from entity.
893  */
894 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
895                                   struct media_entity *entity,
896                                   bool on)
897 {
898         struct v4l2_subdev *sd;
899         int ret = 0;
900
901         if (!is_media_entity_v4l2_subdev(entity))
902                 return -EINVAL;
903         sd = media_entity_to_v4l2_subdev(entity);
904
905         mutex_lock(&imxmd->md.graph_mutex);
906
907         if (on) {
908                 ret = __media_pipeline_start(entity, &imxmd->pipe);
909                 if (ret)
910                         goto out;
911                 ret = v4l2_subdev_call(sd, video, s_stream, 1);
912                 if (ret)
913                         __media_pipeline_stop(entity);
914         } else {
915                 v4l2_subdev_call(sd, video, s_stream, 0);
916                 if (entity->pipe)
917                         __media_pipeline_stop(entity);
918         }
919
920 out:
921         mutex_unlock(&imxmd->md.graph_mutex);
922         return ret;
923 }
924 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
925
926 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
927 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
928 MODULE_LICENSE("GPL");