1 /*
2  * V4L2 Media Controller Driver for Freescale i.MX5/6 SOC
3  *
4  * Copyright (c) 2016 Mentor Graphics Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  */
11 #include <linux/module.h>
12 #include "imx-media.h"
13 
14 /*
15  * List of supported pixel formats for the subdevs.
16  *
17  * In all of these tables, the non-mbus formats (with no
18  * mbus codes) must all fall at the end of the table.
19  */
20 
21 static const struct imx_media_pixfmt yuv_formats[] = {
22 	{
23 		.fourcc	= V4L2_PIX_FMT_UYVY,
24 		.codes  = {
25 			MEDIA_BUS_FMT_UYVY8_2X8,
26 			MEDIA_BUS_FMT_UYVY8_1X16
27 		},
28 		.cs     = IPUV3_COLORSPACE_YUV,
29 		.bpp    = 16,
30 	}, {
31 		.fourcc	= V4L2_PIX_FMT_YUYV,
32 		.codes  = {
33 			MEDIA_BUS_FMT_YUYV8_2X8,
34 			MEDIA_BUS_FMT_YUYV8_1X16
35 		},
36 		.cs     = IPUV3_COLORSPACE_YUV,
37 		.bpp    = 16,
38 	},
39 	/***
40 	 * non-mbus YUV formats start here. NOTE! when adding non-mbus
41 	 * formats, NUM_NON_MBUS_YUV_FORMATS must be updated below.
42 	 ***/
43 	{
44 		.fourcc	= V4L2_PIX_FMT_YUV420,
45 		.cs     = IPUV3_COLORSPACE_YUV,
46 		.bpp    = 12,
47 		.planar = true,
48 	}, {
49 		.fourcc = V4L2_PIX_FMT_YVU420,
50 		.cs     = IPUV3_COLORSPACE_YUV,
51 		.bpp    = 12,
52 		.planar = true,
53 	}, {
54 		.fourcc = V4L2_PIX_FMT_YUV422P,
55 		.cs     = IPUV3_COLORSPACE_YUV,
56 		.bpp    = 16,
57 		.planar = true,
58 	}, {
59 		.fourcc = V4L2_PIX_FMT_NV12,
60 		.cs     = IPUV3_COLORSPACE_YUV,
61 		.bpp    = 12,
62 		.planar = true,
63 	}, {
64 		.fourcc = V4L2_PIX_FMT_NV16,
65 		.cs     = IPUV3_COLORSPACE_YUV,
66 		.bpp    = 16,
67 		.planar = true,
68 	},
69 };
70 
71 #define NUM_NON_MBUS_YUV_FORMATS 5
72 #define NUM_YUV_FORMATS ARRAY_SIZE(yuv_formats)
73 #define NUM_MBUS_YUV_FORMATS (NUM_YUV_FORMATS - NUM_NON_MBUS_YUV_FORMATS)
74 
75 static const struct imx_media_pixfmt rgb_formats[] = {
76 	{
77 		.fourcc	= V4L2_PIX_FMT_RGB565,
78 		.codes  = {MEDIA_BUS_FMT_RGB565_2X8_LE},
79 		.cs     = IPUV3_COLORSPACE_RGB,
80 		.bpp    = 16,
81 	}, {
82 		.fourcc	= V4L2_PIX_FMT_RGB24,
83 		.codes  = {
84 			MEDIA_BUS_FMT_RGB888_1X24,
85 			MEDIA_BUS_FMT_RGB888_2X12_LE
86 		},
87 		.cs     = IPUV3_COLORSPACE_RGB,
88 		.bpp    = 24,
89 	}, {
90 		.fourcc	= V4L2_PIX_FMT_RGB32,
91 		.codes  = {MEDIA_BUS_FMT_ARGB8888_1X32},
92 		.cs     = IPUV3_COLORSPACE_RGB,
93 		.bpp    = 32,
94 		.ipufmt = true,
95 	},
96 	/*** raw bayer formats start here ***/
97 	{
98 		.fourcc = V4L2_PIX_FMT_SBGGR8,
99 		.codes  = {MEDIA_BUS_FMT_SBGGR8_1X8},
100 		.cs     = IPUV3_COLORSPACE_RGB,
101 		.bpp    = 8,
102 		.bayer  = true,
103 	}, {
104 		.fourcc = V4L2_PIX_FMT_SGBRG8,
105 		.codes  = {MEDIA_BUS_FMT_SGBRG8_1X8},
106 		.cs     = IPUV3_COLORSPACE_RGB,
107 		.bpp    = 8,
108 		.bayer  = true,
109 	}, {
110 		.fourcc = V4L2_PIX_FMT_SGRBG8,
111 		.codes  = {MEDIA_BUS_FMT_SGRBG8_1X8},
112 		.cs     = IPUV3_COLORSPACE_RGB,
113 		.bpp    = 8,
114 		.bayer  = true,
115 	}, {
116 		.fourcc = V4L2_PIX_FMT_SRGGB8,
117 		.codes  = {MEDIA_BUS_FMT_SRGGB8_1X8},
118 		.cs     = IPUV3_COLORSPACE_RGB,
119 		.bpp    = 8,
120 		.bayer  = true,
121 	}, {
122 		.fourcc = V4L2_PIX_FMT_SBGGR16,
123 		.codes  = {
124 			MEDIA_BUS_FMT_SBGGR10_1X10,
125 			MEDIA_BUS_FMT_SBGGR12_1X12,
126 			MEDIA_BUS_FMT_SBGGR14_1X14,
127 			MEDIA_BUS_FMT_SBGGR16_1X16
128 		},
129 		.cs     = IPUV3_COLORSPACE_RGB,
130 		.bpp    = 16,
131 		.bayer  = true,
132 	}, {
133 		.fourcc = V4L2_PIX_FMT_SGBRG16,
134 		.codes  = {
135 			MEDIA_BUS_FMT_SGBRG10_1X10,
136 			MEDIA_BUS_FMT_SGBRG12_1X12,
137 			MEDIA_BUS_FMT_SGBRG14_1X14,
138 			MEDIA_BUS_FMT_SGBRG16_1X16,
139 		},
140 		.cs     = IPUV3_COLORSPACE_RGB,
141 		.bpp    = 16,
142 		.bayer  = true,
143 	}, {
144 		.fourcc = V4L2_PIX_FMT_SGRBG16,
145 		.codes  = {
146 			MEDIA_BUS_FMT_SGRBG10_1X10,
147 			MEDIA_BUS_FMT_SGRBG12_1X12,
148 			MEDIA_BUS_FMT_SGRBG14_1X14,
149 			MEDIA_BUS_FMT_SGRBG16_1X16,
150 		},
151 		.cs     = IPUV3_COLORSPACE_RGB,
152 		.bpp    = 16,
153 		.bayer  = true,
154 	}, {
155 		.fourcc = V4L2_PIX_FMT_SRGGB16,
156 		.codes  = {
157 			MEDIA_BUS_FMT_SRGGB10_1X10,
158 			MEDIA_BUS_FMT_SRGGB12_1X12,
159 			MEDIA_BUS_FMT_SRGGB14_1X14,
160 			MEDIA_BUS_FMT_SRGGB16_1X16,
161 		},
162 		.cs     = IPUV3_COLORSPACE_RGB,
163 		.bpp    = 16,
164 		.bayer  = true,
165 	},
166 	/***
167 	 * non-mbus RGB formats start here. NOTE! when adding non-mbus
168 	 * formats, NUM_NON_MBUS_RGB_FORMATS must be updated below.
169 	 ***/
170 	{
171 		.fourcc	= V4L2_PIX_FMT_BGR24,
172 		.cs     = IPUV3_COLORSPACE_RGB,
173 		.bpp    = 24,
174 	}, {
175 		.fourcc	= V4L2_PIX_FMT_BGR32,
176 		.cs     = IPUV3_COLORSPACE_RGB,
177 		.bpp    = 32,
178 	},
179 };
180 
181 #define NUM_NON_MBUS_RGB_FORMATS 2
182 #define NUM_RGB_FORMATS ARRAY_SIZE(rgb_formats)
183 #define NUM_MBUS_RGB_FORMATS (NUM_RGB_FORMATS - NUM_NON_MBUS_RGB_FORMATS)
184 
185 static const struct imx_media_pixfmt ipu_yuv_formats[] = {
186 	{
187 		.fourcc = V4L2_PIX_FMT_YUV32,
188 		.codes  = {MEDIA_BUS_FMT_AYUV8_1X32},
189 		.cs     = IPUV3_COLORSPACE_YUV,
190 		.bpp    = 32,
191 		.ipufmt = true,
192 	},
193 };
194 
195 #define NUM_IPU_YUV_FORMATS ARRAY_SIZE(ipu_yuv_formats)
196 
197 static const struct imx_media_pixfmt ipu_rgb_formats[] = {
198 	{
199 		.fourcc	= V4L2_PIX_FMT_RGB32,
200 		.codes  = {MEDIA_BUS_FMT_ARGB8888_1X32},
201 		.cs     = IPUV3_COLORSPACE_RGB,
202 		.bpp    = 32,
203 		.ipufmt = true,
204 	},
205 };
206 
207 #define NUM_IPU_RGB_FORMATS ARRAY_SIZE(ipu_rgb_formats)
208 
209 static void init_mbus_colorimetry(struct v4l2_mbus_framefmt *mbus,
210 				  const struct imx_media_pixfmt *fmt)
211 {
212 	mbus->colorspace = (fmt->cs == IPUV3_COLORSPACE_RGB) ?
213 		V4L2_COLORSPACE_SRGB : V4L2_COLORSPACE_SMPTE170M;
214 	mbus->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mbus->colorspace);
215 	mbus->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mbus->colorspace);
216 	mbus->quantization =
217 		V4L2_MAP_QUANTIZATION_DEFAULT(fmt->cs == IPUV3_COLORSPACE_RGB,
218 					      mbus->colorspace,
219 					      mbus->ycbcr_enc);
220 }
221 
222 static const struct imx_media_pixfmt *find_format(u32 fourcc,
223 						  u32 code,
224 						  enum codespace_sel cs_sel,
225 						  bool allow_non_mbus,
226 						  bool allow_bayer)
227 {
228 	const struct imx_media_pixfmt *array, *fmt, *ret = NULL;
229 	u32 array_size;
230 	int i, j;
231 
232 	switch (cs_sel) {
233 	case CS_SEL_YUV:
234 		array_size = NUM_YUV_FORMATS;
235 		array = yuv_formats;
236 		break;
237 	case CS_SEL_RGB:
238 		array_size = NUM_RGB_FORMATS;
239 		array = rgb_formats;
240 		break;
241 	case CS_SEL_ANY:
242 		array_size = NUM_YUV_FORMATS + NUM_RGB_FORMATS;
243 		array = yuv_formats;
244 		break;
245 	default:
246 		return NULL;
247 	}
248 
249 	for (i = 0; i < array_size; i++) {
250 		if (cs_sel == CS_SEL_ANY && i >= NUM_YUV_FORMATS)
251 			fmt = &rgb_formats[i - NUM_YUV_FORMATS];
252 		else
253 			fmt = &array[i];
254 
255 		if ((!allow_non_mbus && fmt->codes[0] == 0) ||
256 		    (!allow_bayer && fmt->bayer))
257 			continue;
258 
259 		if (fourcc && fmt->fourcc == fourcc) {
260 			ret = fmt;
261 			goto out;
262 		}
263 
264 		for (j = 0; code && fmt->codes[j]; j++) {
265 			if (code == fmt->codes[j]) {
266 				ret = fmt;
267 				goto out;
268 			}
269 		}
270 	}
271 
272 out:
273 	return ret;
274 }
275 
276 static int enum_format(u32 *fourcc, u32 *code, u32 index,
277 		       enum codespace_sel cs_sel,
278 		       bool allow_non_mbus,
279 		       bool allow_bayer)
280 {
281 	const struct imx_media_pixfmt *fmt;
282 	u32 mbus_yuv_sz = NUM_MBUS_YUV_FORMATS;
283 	u32 mbus_rgb_sz = NUM_MBUS_RGB_FORMATS;
284 	u32 yuv_sz = NUM_YUV_FORMATS;
285 	u32 rgb_sz = NUM_RGB_FORMATS;
286 
287 	switch (cs_sel) {
288 	case CS_SEL_YUV:
289 		if (index >= yuv_sz ||
290 		    (!allow_non_mbus && index >= mbus_yuv_sz))
291 			return -EINVAL;
292 		fmt = &yuv_formats[index];
293 		break;
294 	case CS_SEL_RGB:
295 		if (index >= rgb_sz ||
296 		    (!allow_non_mbus && index >= mbus_rgb_sz))
297 			return -EINVAL;
298 		fmt = &rgb_formats[index];
299 		if (!allow_bayer && fmt->bayer)
300 			return -EINVAL;
301 		break;
302 	case CS_SEL_ANY:
303 		if (!allow_non_mbus) {
304 			if (index >= mbus_yuv_sz) {
305 				index -= mbus_yuv_sz;
306 				if (index >= mbus_rgb_sz)
307 					return -EINVAL;
308 				fmt = &rgb_formats[index];
309 				if (!allow_bayer && fmt->bayer)
310 					return -EINVAL;
311 			} else {
312 				fmt = &yuv_formats[index];
313 			}
314 		} else {
315 			if (index >= yuv_sz + rgb_sz)
316 				return -EINVAL;
317 			if (index >= yuv_sz) {
318 				fmt = &rgb_formats[index - yuv_sz];
319 				if (!allow_bayer && fmt->bayer)
320 					return -EINVAL;
321 			} else {
322 				fmt = &yuv_formats[index];
323 			}
324 		}
325 		break;
326 	default:
327 		return -EINVAL;
328 	}
329 
330 	if (fourcc)
331 		*fourcc = fmt->fourcc;
332 	if (code)
333 		*code = fmt->codes[0];
334 
335 	return 0;
336 }
337 
338 const struct imx_media_pixfmt *
339 imx_media_find_format(u32 fourcc, enum codespace_sel cs_sel, bool allow_bayer)
340 {
341 	return find_format(fourcc, 0, cs_sel, true, allow_bayer);
342 }
343 EXPORT_SYMBOL_GPL(imx_media_find_format);
344 
345 int imx_media_enum_format(u32 *fourcc, u32 index, enum codespace_sel cs_sel)
346 {
347 	return enum_format(fourcc, NULL, index, cs_sel, true, false);
348 }
349 EXPORT_SYMBOL_GPL(imx_media_enum_format);
350 
351 const struct imx_media_pixfmt *
352 imx_media_find_mbus_format(u32 code, enum codespace_sel cs_sel,
353 			   bool allow_bayer)
354 {
355 	return find_format(0, code, cs_sel, false, allow_bayer);
356 }
357 EXPORT_SYMBOL_GPL(imx_media_find_mbus_format);
358 
359 int imx_media_enum_mbus_format(u32 *code, u32 index, enum codespace_sel cs_sel,
360 			       bool allow_bayer)
361 {
362 	return enum_format(NULL, code, index, cs_sel, false, allow_bayer);
363 }
364 EXPORT_SYMBOL_GPL(imx_media_enum_mbus_format);
365 
366 const struct imx_media_pixfmt *
367 imx_media_find_ipu_format(u32 code, enum codespace_sel cs_sel)
368 {
369 	const struct imx_media_pixfmt *array, *fmt, *ret = NULL;
370 	u32 array_size;
371 	int i, j;
372 
373 	switch (cs_sel) {
374 	case CS_SEL_YUV:
375 		array_size = NUM_IPU_YUV_FORMATS;
376 		array = ipu_yuv_formats;
377 		break;
378 	case CS_SEL_RGB:
379 		array_size = NUM_IPU_RGB_FORMATS;
380 		array = ipu_rgb_formats;
381 		break;
382 	case CS_SEL_ANY:
383 		array_size = NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS;
384 		array = ipu_yuv_formats;
385 		break;
386 	default:
387 		return NULL;
388 	}
389 
390 	for (i = 0; i < array_size; i++) {
391 		if (cs_sel == CS_SEL_ANY && i >= NUM_IPU_YUV_FORMATS)
392 			fmt = &ipu_rgb_formats[i - NUM_IPU_YUV_FORMATS];
393 		else
394 			fmt = &array[i];
395 
396 		for (j = 0; code && fmt->codes[j]; j++) {
397 			if (code == fmt->codes[j]) {
398 				ret = fmt;
399 				goto out;
400 			}
401 		}
402 	}
403 
404 out:
405 	return ret;
406 }
407 EXPORT_SYMBOL_GPL(imx_media_find_ipu_format);
408 
409 int imx_media_enum_ipu_format(u32 *code, u32 index, enum codespace_sel cs_sel)
410 {
411 	switch (cs_sel) {
412 	case CS_SEL_YUV:
413 		if (index >= NUM_IPU_YUV_FORMATS)
414 			return -EINVAL;
415 		*code = ipu_yuv_formats[index].codes[0];
416 		break;
417 	case CS_SEL_RGB:
418 		if (index >= NUM_IPU_RGB_FORMATS)
419 			return -EINVAL;
420 		*code = ipu_rgb_formats[index].codes[0];
421 		break;
422 	case CS_SEL_ANY:
423 		if (index >= NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS)
424 			return -EINVAL;
425 		if (index >= NUM_IPU_YUV_FORMATS) {
426 			index -= NUM_IPU_YUV_FORMATS;
427 			*code = ipu_rgb_formats[index].codes[0];
428 		} else {
429 			*code = ipu_yuv_formats[index].codes[0];
430 		}
431 		break;
432 	default:
433 		return -EINVAL;
434 	}
435 
436 	return 0;
437 }
438 EXPORT_SYMBOL_GPL(imx_media_enum_ipu_format);
439 
440 int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
441 			    u32 width, u32 height, u32 code, u32 field,
442 			    const struct imx_media_pixfmt **cc)
443 {
444 	const struct imx_media_pixfmt *lcc;
445 
446 	mbus->width = width;
447 	mbus->height = height;
448 	mbus->field = field;
449 	if (code == 0)
450 		imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false);
451 	lcc = imx_media_find_mbus_format(code, CS_SEL_ANY, false);
452 	if (!lcc) {
453 		lcc = imx_media_find_ipu_format(code, CS_SEL_ANY);
454 		if (!lcc)
455 			return -EINVAL;
456 	}
457 
458 	mbus->code = code;
459 	init_mbus_colorimetry(mbus, lcc);
460 	if (cc)
461 		*cc = lcc;
462 
463 	return 0;
464 }
465 EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
466 
467 /*
468  * Check whether the field and colorimetry parameters in tryfmt are
469  * uninitialized, and if so fill them with the values from fmt,
470  * or if tryfmt->colorspace has been initialized, all the default
471  * colorimetry params can be derived from tryfmt->colorspace.
472  *
473  * tryfmt->code must be set on entry.
474  *
475  * If this format is destined to be routed through the Image Converter,
476  * quantization and Y`CbCr encoding must be fixed. The IC expects and
477  * produces fixed quantization and Y`CbCr encoding at its input and output
478  * (full range for RGB, limited range for YUV, and V4L2_YCBCR_ENC_601).
479  */
480 void imx_media_fill_default_mbus_fields(struct v4l2_mbus_framefmt *tryfmt,
481 					struct v4l2_mbus_framefmt *fmt,
482 					bool ic_route)
483 {
484 	const struct imx_media_pixfmt *cc;
485 	bool is_rgb = false;
486 
487 	cc = imx_media_find_mbus_format(tryfmt->code, CS_SEL_ANY, true);
488 	if (!cc)
489 		cc = imx_media_find_ipu_format(tryfmt->code, CS_SEL_ANY);
490 	if (cc && cc->cs != IPUV3_COLORSPACE_YUV)
491 		is_rgb = true;
492 
493 	/* fill field if necessary */
494 	if (tryfmt->field == V4L2_FIELD_ANY)
495 		tryfmt->field = fmt->field;
496 
497 	/* fill colorimetry if necessary */
498 	if (tryfmt->colorspace == V4L2_COLORSPACE_DEFAULT) {
499 		tryfmt->colorspace = fmt->colorspace;
500 		tryfmt->xfer_func = fmt->xfer_func;
501 		tryfmt->ycbcr_enc = fmt->ycbcr_enc;
502 		tryfmt->quantization = fmt->quantization;
503 	} else {
504 		if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT) {
505 			tryfmt->xfer_func =
506 				V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace);
507 		}
508 		if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
509 			tryfmt->ycbcr_enc =
510 				V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace);
511 		}
512 		if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT) {
513 			tryfmt->quantization =
514 				V4L2_MAP_QUANTIZATION_DEFAULT(
515 					is_rgb, tryfmt->colorspace,
516 					tryfmt->ycbcr_enc);
517 		}
518 	}
519 
520 	if (ic_route) {
521 		tryfmt->quantization = is_rgb ?
522 			V4L2_QUANTIZATION_FULL_RANGE :
523 			V4L2_QUANTIZATION_LIM_RANGE;
524 		tryfmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
525 	}
526 }
527 EXPORT_SYMBOL_GPL(imx_media_fill_default_mbus_fields);
528 
529 int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
530 				  struct v4l2_mbus_framefmt *mbus,
531 				  const struct imx_media_pixfmt *cc)
532 {
533 	u32 stride;
534 
535 	if (!cc) {
536 		cc = imx_media_find_ipu_format(mbus->code, CS_SEL_ANY);
537 		if (!cc)
538 			cc = imx_media_find_mbus_format(mbus->code, CS_SEL_ANY,
539 							true);
540 		if (!cc)
541 			return -EINVAL;
542 	}
543 
544 	/*
545 	 * TODO: the IPU currently does not support the AYUV32 format,
546 	 * so until it does convert to a supported YUV format.
547 	 */
548 	if (cc->ipufmt && cc->cs == IPUV3_COLORSPACE_YUV) {
549 		u32 code;
550 
551 		imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false);
552 		cc = imx_media_find_mbus_format(code, CS_SEL_YUV, false);
553 	}
554 
555 	stride = cc->planar ? mbus->width : (mbus->width * cc->bpp) >> 3;
556 
557 	pix->width = mbus->width;
558 	pix->height = mbus->height;
559 	pix->pixelformat = cc->fourcc;
560 	pix->colorspace = mbus->colorspace;
561 	pix->xfer_func = mbus->xfer_func;
562 	pix->ycbcr_enc = mbus->ycbcr_enc;
563 	pix->quantization = mbus->quantization;
564 	pix->field = mbus->field;
565 	pix->bytesperline = stride;
566 	pix->sizeimage = (pix->width * pix->height * cc->bpp) >> 3;
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 				    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 				    struct ipu_image *image)
592 {
593 	const struct imx_media_pixfmt *fmt;
594 
595 	fmt = imx_media_find_format(image->pix.pixelformat, CS_SEL_ANY, true);
596 	if (!fmt)
597 		return -EINVAL;
598 
599 	memset(mbus, 0, sizeof(*mbus));
600 	mbus->width = image->pix.width;
601 	mbus->height = image->pix.height;
602 	mbus->code = fmt->codes[0];
603 	mbus->field = image->pix.field;
604 	mbus->colorspace = image->pix.colorspace;
605 	mbus->xfer_func = image->pix.xfer_func;
606 	mbus->ycbcr_enc = image->pix.ycbcr_enc;
607 	mbus->quantization = image->pix.quantization;
608 
609 	return 0;
610 }
611 EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt);
612 
613 void imx_media_free_dma_buf(struct imx_media_dev *imxmd,
614 			    struct imx_media_dma_buf *buf)
615 {
616 	if (buf->virt)
617 		dma_free_coherent(imxmd->md.dev, buf->len,
618 				  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 imx_media_dev *imxmd,
626 			    struct imx_media_dma_buf *buf,
627 			    int size)
628 {
629 	imx_media_free_dma_buf(imxmd, buf);
630 
631 	buf->len = PAGE_ALIGN(size);
632 	buf->virt = dma_alloc_coherent(imxmd->md.dev, buf->len, &buf->phys,
633 				       GFP_DMA | GFP_KERNEL);
634 	if (!buf->virt) {
635 		dev_err(imxmd->md.dev, "failed to alloc dma buffer\n");
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_CSI0...IMX_MEDIA_GRP_ID_CSI1:
650 		id = (grp_id >> IMX_MEDIA_GRP_ID_CSI_BIT) - 1;
651 		snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id);
652 		break;
653 	case IMX_MEDIA_GRP_ID_VDIC:
654 		snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1);
655 		break;
656 	case IMX_MEDIA_GRP_ID_IC_PRP:
657 		snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1);
658 		break;
659 	case IMX_MEDIA_GRP_ID_IC_PRPENC:
660 		snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1);
661 		break;
662 	case IMX_MEDIA_GRP_ID_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 by
703  * an async subdev that owns a video device when it is registered.
704  */
705 int 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 	return 0;
714 }
715 EXPORT_SYMBOL_GPL(imx_media_add_video_device);
716 
717 /*
718  * Search upstream/downstream for a subdevice in the current pipeline
719  * with given grp_id, starting from start_entity. Returns the subdev's
720  * source/sink pad that it was reached from. If grp_id is zero, just
721  * returns the nearest source/sink pad to start_entity. Must be called
722  * with mdev->graph_mutex held.
723  */
724 static struct media_pad *
725 find_pipeline_pad(struct imx_media_dev *imxmd,
726 		  struct media_entity *start_entity,
727 		  u32 grp_id, bool upstream)
728 {
729 	struct media_entity *me = start_entity;
730 	struct media_pad *pad = NULL;
731 	struct v4l2_subdev *sd;
732 	int i;
733 
734 	for (i = 0; i < me->num_pads; i++) {
735 		struct media_pad *spad = &me->pads[i];
736 
737 		if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) ||
738 		    (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE)))
739 			continue;
740 
741 		pad = media_entity_remote_pad(spad);
742 		if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
743 			continue;
744 
745 		if (grp_id != 0) {
746 			sd = media_entity_to_v4l2_subdev(pad->entity);
747 			if (sd->grp_id & grp_id)
748 				return pad;
749 
750 			return find_pipeline_pad(imxmd, pad->entity,
751 						 grp_id, upstream);
752 		} else {
753 			return pad;
754 		}
755 	}
756 
757 	return NULL;
758 }
759 
760 /*
761  * Search upstream for a subdev in the current pipeline with
762  * given grp_id. Must be called with mdev->graph_mutex held.
763  */
764 static struct v4l2_subdev *
765 find_upstream_subdev(struct imx_media_dev *imxmd,
766 		     struct media_entity *start_entity,
767 		     u32 grp_id)
768 {
769 	struct v4l2_subdev *sd;
770 	struct media_pad *pad;
771 
772 	if (is_media_entity_v4l2_subdev(start_entity)) {
773 		sd = media_entity_to_v4l2_subdev(start_entity);
774 		if (sd->grp_id & grp_id)
775 			return sd;
776 	}
777 
778 	pad = find_pipeline_pad(imxmd, start_entity, grp_id, true);
779 
780 	return pad ? media_entity_to_v4l2_subdev(pad->entity) : NULL;
781 }
782 
783 /*
784  * Find the upstream mipi-csi2 virtual channel reached from the given
785  * start entity in the current pipeline.
786  * Must be called with mdev->graph_mutex held.
787  */
788 int imx_media_find_mipi_csi2_channel(struct imx_media_dev *imxmd,
789 				     struct media_entity *start_entity)
790 {
791 	struct media_pad *pad;
792 	int ret = -EPIPE;
793 
794 	pad = find_pipeline_pad(imxmd, start_entity, IMX_MEDIA_GRP_ID_CSI2,
795 				true);
796 	if (pad) {
797 		ret = pad->index - 1;
798 		dev_dbg(imxmd->md.dev, "found vc%d from %s\n",
799 			ret, start_entity->name);
800 	}
801 
802 	return ret;
803 }
804 EXPORT_SYMBOL_GPL(imx_media_find_mipi_csi2_channel);
805 
806 /*
807  * Find a source pad reached upstream from the given start entity in
808  * the current pipeline. Must be called with mdev->graph_mutex held.
809  */
810 struct media_pad *
811 imx_media_find_upstream_pad(struct imx_media_dev *imxmd,
812 			    struct media_entity *start_entity,
813 			    u32 grp_id)
814 {
815 	struct media_pad *pad;
816 
817 	pad = find_pipeline_pad(imxmd, start_entity, grp_id, true);
818 	if (!pad)
819 		return ERR_PTR(-ENODEV);
820 
821 	return pad;
822 }
823 EXPORT_SYMBOL_GPL(imx_media_find_upstream_pad);
824 
825 /*
826  * Find a subdev reached upstream from the given start entity in
827  * the current pipeline.
828  * Must be called with mdev->graph_mutex held.
829  */
830 struct v4l2_subdev *
831 imx_media_find_upstream_subdev(struct imx_media_dev *imxmd,
832 			       struct media_entity *start_entity,
833 			       u32 grp_id)
834 {
835 	struct v4l2_subdev *sd;
836 
837 	sd = find_upstream_subdev(imxmd, start_entity, grp_id);
838 	if (!sd)
839 		return ERR_PTR(-ENODEV);
840 
841 	return sd;
842 }
843 EXPORT_SYMBOL_GPL(imx_media_find_upstream_subdev);
844 
845 /*
846  * Turn current pipeline streaming on/off starting from entity.
847  */
848 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
849 				  struct media_entity *entity,
850 				  bool on)
851 {
852 	struct v4l2_subdev *sd;
853 	int ret = 0;
854 
855 	if (!is_media_entity_v4l2_subdev(entity))
856 		return -EINVAL;
857 	sd = media_entity_to_v4l2_subdev(entity);
858 
859 	mutex_lock(&imxmd->md.graph_mutex);
860 
861 	if (on) {
862 		ret = __media_pipeline_start(entity, &imxmd->pipe);
863 		if (ret)
864 			goto out;
865 		ret = v4l2_subdev_call(sd, video, s_stream, 1);
866 		if (ret)
867 			__media_pipeline_stop(entity);
868 	} else {
869 		v4l2_subdev_call(sd, video, s_stream, 0);
870 		if (entity->pipe)
871 			__media_pipeline_stop(entity);
872 	}
873 
874 out:
875 	mutex_unlock(&imxmd->md.graph_mutex);
876 	return ret;
877 }
878 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
879 
880 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
881 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
882 MODULE_LICENSE("GPL");
883