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