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 *
imx_media_find_pixel_format(u32 fourcc,enum imx_pixfmt_sel fmt_sel)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 *
imx_media_find_mbus_format(u32 code,enum imx_pixfmt_sel fmt_sel)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 */
imx_media_enum_pixel_formats(u32 * fourcc,u32 index,enum imx_pixfmt_sel fmt_sel,u32 code)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 */
imx_media_enum_mbus_formats(u32 * code,u32 index,enum imx_pixfmt_sel fmt_sel)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
imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt * mbus,u32 width,u32 height,u32 code,u32 field,const struct imx_media_pixfmt ** cc)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 */
imx_media_init_cfg(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)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 */
imx_media_try_colorimetry(struct v4l2_mbus_framefmt * tryfmt,bool ic_route)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
imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format * pix,const struct v4l2_mbus_framefmt * mbus,const struct imx_media_pixfmt * cc)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
imx_media_free_dma_buf(struct device * dev,struct imx_media_dma_buf * buf)572 void imx_media_free_dma_buf(struct device *dev,
573 struct imx_media_dma_buf *buf)
574 {
575 if (buf->virt)
576 dma_free_coherent(dev, buf->len, buf->virt, buf->phys);
577
578 buf->virt = NULL;
579 buf->phys = 0;
580 }
581 EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
582
imx_media_alloc_dma_buf(struct device * dev,struct imx_media_dma_buf * buf,int size)583 int imx_media_alloc_dma_buf(struct device *dev,
584 struct imx_media_dma_buf *buf,
585 int size)
586 {
587 imx_media_free_dma_buf(dev, buf);
588
589 buf->len = PAGE_ALIGN(size);
590 buf->virt = dma_alloc_coherent(dev, buf->len, &buf->phys,
591 GFP_DMA | GFP_KERNEL);
592 if (!buf->virt) {
593 dev_err(dev, "%s: failed\n", __func__);
594 return -ENOMEM;
595 }
596
597 return 0;
598 }
599 EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf);
600
601 /* form a subdev name given a group id and ipu id */
imx_media_grp_id_to_sd_name(char * sd_name,int sz,u32 grp_id,int ipu_id)602 void imx_media_grp_id_to_sd_name(char *sd_name, int sz, u32 grp_id, int ipu_id)
603 {
604 int id;
605
606 switch (grp_id) {
607 case IMX_MEDIA_GRP_ID_IPU_CSI0...IMX_MEDIA_GRP_ID_IPU_CSI1:
608 id = (grp_id >> IMX_MEDIA_GRP_ID_IPU_CSI_BIT) - 1;
609 snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id);
610 break;
611 case IMX_MEDIA_GRP_ID_IPU_VDIC:
612 snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1);
613 break;
614 case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
615 snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1);
616 break;
617 case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
618 snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1);
619 break;
620 case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
621 snprintf(sd_name, sz, "ipu%d_ic_prpvf", ipu_id + 1);
622 break;
623 default:
624 break;
625 }
626 }
627 EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name);
628
629 struct v4l2_subdev *
imx_media_find_subdev_by_fwnode(struct imx_media_dev * imxmd,struct fwnode_handle * fwnode)630 imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd,
631 struct fwnode_handle *fwnode)
632 {
633 struct v4l2_subdev *sd;
634
635 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
636 if (sd->fwnode == fwnode)
637 return sd;
638 }
639
640 return NULL;
641 }
642 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode);
643
644 struct v4l2_subdev *
imx_media_find_subdev_by_devname(struct imx_media_dev * imxmd,const char * devname)645 imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd,
646 const char *devname)
647 {
648 struct v4l2_subdev *sd;
649
650 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
651 if (!strcmp(devname, dev_name(sd->dev)))
652 return sd;
653 }
654
655 return NULL;
656 }
657 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname);
658
659 /*
660 * Adds a video device to the master video device list. This is called
661 * when a video device is registered.
662 */
imx_media_add_video_device(struct imx_media_dev * imxmd,struct imx_media_video_dev * vdev)663 void imx_media_add_video_device(struct imx_media_dev *imxmd,
664 struct imx_media_video_dev *vdev)
665 {
666 mutex_lock(&imxmd->mutex);
667
668 list_add_tail(&vdev->list, &imxmd->vdev_list);
669
670 mutex_unlock(&imxmd->mutex);
671 }
672 EXPORT_SYMBOL_GPL(imx_media_add_video_device);
673
674 /*
675 * Search upstream/downstream for a subdevice or video device pad in the
676 * current pipeline, starting from start_entity. Returns the device's
677 * source/sink pad that it was reached from. Must be called with
678 * mdev->graph_mutex held.
679 *
680 * If grp_id != 0, finds a subdevice's pad of given grp_id.
681 * Else If buftype != 0, finds a video device's pad of given buffer type.
682 * Else, returns the nearest source/sink pad to start_entity.
683 */
684 struct media_pad *
imx_media_pipeline_pad(struct media_entity * start_entity,u32 grp_id,enum v4l2_buf_type buftype,bool upstream)685 imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id,
686 enum v4l2_buf_type buftype, bool upstream)
687 {
688 struct media_entity *me = start_entity;
689 struct media_pad *pad = NULL;
690 struct video_device *vfd;
691 struct v4l2_subdev *sd;
692 int i;
693
694 for (i = 0; i < me->num_pads; i++) {
695 struct media_pad *spad = &me->pads[i];
696
697 if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) ||
698 (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE)))
699 continue;
700
701 pad = media_pad_remote_pad_first(spad);
702 if (!pad)
703 continue;
704
705 if (grp_id) {
706 if (is_media_entity_v4l2_subdev(pad->entity)) {
707 sd = media_entity_to_v4l2_subdev(pad->entity);
708 if (sd->grp_id & grp_id)
709 return pad;
710 }
711
712 return imx_media_pipeline_pad(pad->entity, grp_id,
713 buftype, upstream);
714 } else if (buftype) {
715 if (is_media_entity_v4l2_video_device(pad->entity)) {
716 vfd = media_entity_to_video_device(pad->entity);
717 if (buftype == vfd->queue->type)
718 return pad;
719 }
720
721 return imx_media_pipeline_pad(pad->entity, grp_id,
722 buftype, upstream);
723 } else {
724 return pad;
725 }
726 }
727
728 return NULL;
729 }
730 EXPORT_SYMBOL_GPL(imx_media_pipeline_pad);
731
732 /*
733 * Search upstream/downstream for a subdev or video device in the current
734 * pipeline. Must be called with mdev->graph_mutex held.
735 */
736 static struct media_entity *
find_pipeline_entity(struct media_entity * start,u32 grp_id,enum v4l2_buf_type buftype,bool upstream)737 find_pipeline_entity(struct media_entity *start, u32 grp_id,
738 enum v4l2_buf_type buftype, bool upstream)
739 {
740 struct media_pad *pad = NULL;
741 struct video_device *vfd;
742 struct v4l2_subdev *sd;
743
744 if (grp_id && is_media_entity_v4l2_subdev(start)) {
745 sd = media_entity_to_v4l2_subdev(start);
746 if (sd->grp_id & grp_id)
747 return &sd->entity;
748 } else if (buftype && is_media_entity_v4l2_video_device(start)) {
749 vfd = media_entity_to_video_device(start);
750 if (buftype == vfd->queue->type)
751 return &vfd->entity;
752 }
753
754 pad = imx_media_pipeline_pad(start, grp_id, buftype, upstream);
755
756 return pad ? pad->entity : NULL;
757 }
758
759 /*
760 * Find the upstream mipi-csi2 virtual channel reached from the given
761 * start entity in the current pipeline.
762 * Must be called with mdev->graph_mutex held.
763 */
imx_media_pipeline_csi2_channel(struct media_entity * start_entity)764 int imx_media_pipeline_csi2_channel(struct media_entity *start_entity)
765 {
766 struct media_pad *pad;
767 int ret = -EPIPE;
768
769 pad = imx_media_pipeline_pad(start_entity, IMX_MEDIA_GRP_ID_CSI2,
770 0, true);
771 if (pad)
772 ret = pad->index - 1;
773
774 return ret;
775 }
776 EXPORT_SYMBOL_GPL(imx_media_pipeline_csi2_channel);
777
778 /*
779 * Find a subdev reached upstream from the given start entity in
780 * the current pipeline.
781 * Must be called with mdev->graph_mutex held.
782 */
783 struct v4l2_subdev *
imx_media_pipeline_subdev(struct media_entity * start_entity,u32 grp_id,bool upstream)784 imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id,
785 bool upstream)
786 {
787 struct media_entity *me;
788
789 me = find_pipeline_entity(start_entity, grp_id, 0, upstream);
790 if (!me)
791 return ERR_PTR(-ENODEV);
792
793 return media_entity_to_v4l2_subdev(me);
794 }
795 EXPORT_SYMBOL_GPL(imx_media_pipeline_subdev);
796
797 /*
798 * Find a subdev reached upstream from the given start entity in
799 * the current pipeline.
800 * Must be called with mdev->graph_mutex held.
801 */
802 struct video_device *
imx_media_pipeline_video_device(struct media_entity * start_entity,enum v4l2_buf_type buftype,bool upstream)803 imx_media_pipeline_video_device(struct media_entity *start_entity,
804 enum v4l2_buf_type buftype, bool upstream)
805 {
806 struct media_entity *me;
807
808 me = find_pipeline_entity(start_entity, 0, buftype, upstream);
809 if (!me)
810 return ERR_PTR(-ENODEV);
811
812 return media_entity_to_video_device(me);
813 }
814 EXPORT_SYMBOL_GPL(imx_media_pipeline_video_device);
815
816 /*
817 * Turn current pipeline streaming on/off starting from entity.
818 */
imx_media_pipeline_set_stream(struct imx_media_dev * imxmd,struct media_entity * entity,bool on)819 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
820 struct media_entity *entity,
821 bool on)
822 {
823 struct v4l2_subdev *sd;
824 int ret = 0;
825
826 if (!is_media_entity_v4l2_subdev(entity))
827 return -EINVAL;
828 sd = media_entity_to_v4l2_subdev(entity);
829
830 mutex_lock(&imxmd->md.graph_mutex);
831
832 if (on) {
833 ret = __media_pipeline_start(entity->pads, &imxmd->pipe);
834 if (ret)
835 goto out;
836 ret = v4l2_subdev_call(sd, video, s_stream, 1);
837 if (ret)
838 __media_pipeline_stop(entity->pads);
839 } else {
840 v4l2_subdev_call(sd, video, s_stream, 0);
841 if (media_pad_pipeline(entity->pads))
842 __media_pipeline_stop(entity->pads);
843 }
844
845 out:
846 mutex_unlock(&imxmd->md.graph_mutex);
847 return ret;
848 }
849 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
850
851 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
852 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
853 MODULE_LICENSE("GPL");
854