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_RGB32,
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_RGB32,
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 
init_mbus_colorimetry(struct v4l2_mbus_framefmt * mbus,const struct imx_media_pixfmt * fmt)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
__find_format(u32 fourcc,u32 code,bool allow_non_mbus,bool allow_bayer,const struct imx_media_pixfmt * array,u32 array_size)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 
find_format(u32 fourcc,u32 code,enum codespace_sel cs_sel,bool allow_non_mbus,bool allow_bayer)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 
enum_format(u32 * fourcc,u32 * code,u32 index,enum codespace_sel cs_sel,bool allow_non_mbus,bool allow_bayer)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 *
imx_media_find_format(u32 fourcc,enum codespace_sel cs_sel,bool allow_bayer)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 
imx_media_enum_format(u32 * fourcc,u32 index,enum codespace_sel cs_sel)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 *
imx_media_find_mbus_format(u32 code,enum codespace_sel cs_sel,bool allow_bayer)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 
imx_media_enum_mbus_format(u32 * code,u32 index,enum codespace_sel cs_sel,bool allow_bayer)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 *
imx_media_find_ipu_format(u32 code,enum codespace_sel cs_sel)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 
imx_media_enum_ipu_format(u32 * code,u32 index,enum codespace_sel cs_sel)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 
imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt * mbus,u32 width,u32 height,u32 code,u32 field,const struct imx_media_pixfmt ** cc)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  */
imx_media_init_cfg(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg)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  */
imx_media_fill_default_mbus_fields(struct v4l2_mbus_framefmt * tryfmt,struct v4l2_mbus_framefmt * fmt,bool ic_route)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 
imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format * pix,struct v4l2_mbus_framefmt * mbus,const struct imx_media_pixfmt * cc)579 int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
580 				  struct v4l2_mbus_framefmt *mbus,
581 				  const struct imx_media_pixfmt *cc)
582 {
583 	u32 stride;
584 
585 	if (!cc) {
586 		cc = imx_media_find_ipu_format(mbus->code, CS_SEL_ANY);
587 		if (!cc)
588 			cc = imx_media_find_mbus_format(mbus->code, CS_SEL_ANY,
589 							true);
590 		if (!cc)
591 			return -EINVAL;
592 	}
593 
594 	/*
595 	 * TODO: the IPU currently does not support the AYUV32 format,
596 	 * so until it does convert to a supported YUV format.
597 	 */
598 	if (cc->ipufmt && cc->cs == IPUV3_COLORSPACE_YUV) {
599 		u32 code;
600 
601 		imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false);
602 		cc = imx_media_find_mbus_format(code, CS_SEL_YUV, false);
603 	}
604 
605 	stride = cc->planar ? mbus->width : (mbus->width * cc->bpp) >> 3;
606 
607 	pix->width = mbus->width;
608 	pix->height = mbus->height;
609 	pix->pixelformat = cc->fourcc;
610 	pix->colorspace = mbus->colorspace;
611 	pix->xfer_func = mbus->xfer_func;
612 	pix->ycbcr_enc = mbus->ycbcr_enc;
613 	pix->quantization = mbus->quantization;
614 	pix->field = mbus->field;
615 	pix->bytesperline = stride;
616 	pix->sizeimage = (pix->width * pix->height * cc->bpp) >> 3;
617 
618 	return 0;
619 }
620 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt);
621 
imx_media_mbus_fmt_to_ipu_image(struct ipu_image * image,struct v4l2_mbus_framefmt * mbus)622 int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image,
623 				    struct v4l2_mbus_framefmt *mbus)
624 {
625 	int ret;
626 
627 	memset(image, 0, sizeof(*image));
628 
629 	ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, mbus, NULL);
630 	if (ret)
631 		return ret;
632 
633 	image->rect.width = mbus->width;
634 	image->rect.height = mbus->height;
635 
636 	return 0;
637 }
638 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image);
639 
imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt * mbus,struct ipu_image * image)640 int imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
641 				    struct ipu_image *image)
642 {
643 	const struct imx_media_pixfmt *fmt;
644 
645 	fmt = imx_media_find_format(image->pix.pixelformat, CS_SEL_ANY, true);
646 	if (!fmt)
647 		return -EINVAL;
648 
649 	memset(mbus, 0, sizeof(*mbus));
650 	mbus->width = image->pix.width;
651 	mbus->height = image->pix.height;
652 	mbus->code = fmt->codes[0];
653 	mbus->field = image->pix.field;
654 	mbus->colorspace = image->pix.colorspace;
655 	mbus->xfer_func = image->pix.xfer_func;
656 	mbus->ycbcr_enc = image->pix.ycbcr_enc;
657 	mbus->quantization = image->pix.quantization;
658 
659 	return 0;
660 }
661 EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt);
662 
imx_media_free_dma_buf(struct imx_media_dev * imxmd,struct imx_media_dma_buf * buf)663 void imx_media_free_dma_buf(struct imx_media_dev *imxmd,
664 			    struct imx_media_dma_buf *buf)
665 {
666 	if (buf->virt)
667 		dma_free_coherent(imxmd->md.dev, buf->len,
668 				  buf->virt, buf->phys);
669 
670 	buf->virt = NULL;
671 	buf->phys = 0;
672 }
673 EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
674 
imx_media_alloc_dma_buf(struct imx_media_dev * imxmd,struct imx_media_dma_buf * buf,int size)675 int imx_media_alloc_dma_buf(struct imx_media_dev *imxmd,
676 			    struct imx_media_dma_buf *buf,
677 			    int size)
678 {
679 	imx_media_free_dma_buf(imxmd, buf);
680 
681 	buf->len = PAGE_ALIGN(size);
682 	buf->virt = dma_alloc_coherent(imxmd->md.dev, buf->len, &buf->phys,
683 				       GFP_DMA | GFP_KERNEL);
684 	if (!buf->virt) {
685 		dev_err(imxmd->md.dev, "failed to alloc dma buffer\n");
686 		return -ENOMEM;
687 	}
688 
689 	return 0;
690 }
691 EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf);
692 
693 /* 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)694 void imx_media_grp_id_to_sd_name(char *sd_name, int sz, u32 grp_id, int ipu_id)
695 {
696 	int id;
697 
698 	switch (grp_id) {
699 	case IMX_MEDIA_GRP_ID_CSI0...IMX_MEDIA_GRP_ID_CSI1:
700 		id = (grp_id >> IMX_MEDIA_GRP_ID_CSI_BIT) - 1;
701 		snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id);
702 		break;
703 	case IMX_MEDIA_GRP_ID_VDIC:
704 		snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1);
705 		break;
706 	case IMX_MEDIA_GRP_ID_IC_PRP:
707 		snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1);
708 		break;
709 	case IMX_MEDIA_GRP_ID_IC_PRPENC:
710 		snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1);
711 		break;
712 	case IMX_MEDIA_GRP_ID_IC_PRPVF:
713 		snprintf(sd_name, sz, "ipu%d_ic_prpvf", ipu_id + 1);
714 		break;
715 	default:
716 		break;
717 	}
718 }
719 EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name);
720 
721 struct v4l2_subdev *
imx_media_find_subdev_by_fwnode(struct imx_media_dev * imxmd,struct fwnode_handle * fwnode)722 imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd,
723 				struct fwnode_handle *fwnode)
724 {
725 	struct v4l2_subdev *sd;
726 
727 	list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
728 		if (sd->fwnode == fwnode)
729 			return sd;
730 	}
731 
732 	return NULL;
733 }
734 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode);
735 
736 struct v4l2_subdev *
imx_media_find_subdev_by_devname(struct imx_media_dev * imxmd,const char * devname)737 imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd,
738 				 const char *devname)
739 {
740 	struct v4l2_subdev *sd;
741 
742 	list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
743 		if (!strcmp(devname, dev_name(sd->dev)))
744 			return sd;
745 	}
746 
747 	return NULL;
748 }
749 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname);
750 
751 /*
752  * Adds a video device to the master video device list. This is called by
753  * an async subdev that owns a video device when it is registered.
754  */
imx_media_add_video_device(struct imx_media_dev * imxmd,struct imx_media_video_dev * vdev)755 int imx_media_add_video_device(struct imx_media_dev *imxmd,
756 			       struct imx_media_video_dev *vdev)
757 {
758 	mutex_lock(&imxmd->mutex);
759 
760 	list_add_tail(&vdev->list, &imxmd->vdev_list);
761 
762 	mutex_unlock(&imxmd->mutex);
763 	return 0;
764 }
765 EXPORT_SYMBOL_GPL(imx_media_add_video_device);
766 
767 /*
768  * Search upstream/downstream for a subdevice in the current pipeline
769  * with given grp_id, starting from start_entity. Returns the subdev's
770  * source/sink pad that it was reached from. If grp_id is zero, just
771  * returns the nearest source/sink pad to start_entity. Must be called
772  * with mdev->graph_mutex held.
773  */
774 static struct media_pad *
find_pipeline_pad(struct imx_media_dev * imxmd,struct media_entity * start_entity,u32 grp_id,bool upstream)775 find_pipeline_pad(struct imx_media_dev *imxmd,
776 		  struct media_entity *start_entity,
777 		  u32 grp_id, bool upstream)
778 {
779 	struct media_entity *me = start_entity;
780 	struct media_pad *pad = NULL;
781 	struct v4l2_subdev *sd;
782 	int i;
783 
784 	for (i = 0; i < me->num_pads; i++) {
785 		struct media_pad *spad = &me->pads[i];
786 
787 		if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) ||
788 		    (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE)))
789 			continue;
790 
791 		pad = media_entity_remote_pad(spad);
792 		if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
793 			continue;
794 
795 		if (grp_id != 0) {
796 			sd = media_entity_to_v4l2_subdev(pad->entity);
797 			if (sd->grp_id & grp_id)
798 				return pad;
799 
800 			return find_pipeline_pad(imxmd, pad->entity,
801 						 grp_id, upstream);
802 		} else {
803 			return pad;
804 		}
805 	}
806 
807 	return NULL;
808 }
809 
810 /*
811  * Search upstream for a subdev in the current pipeline with
812  * given grp_id. Must be called with mdev->graph_mutex held.
813  */
814 static struct v4l2_subdev *
find_upstream_subdev(struct imx_media_dev * imxmd,struct media_entity * start_entity,u32 grp_id)815 find_upstream_subdev(struct imx_media_dev *imxmd,
816 		     struct media_entity *start_entity,
817 		     u32 grp_id)
818 {
819 	struct v4l2_subdev *sd;
820 	struct media_pad *pad;
821 
822 	if (is_media_entity_v4l2_subdev(start_entity)) {
823 		sd = media_entity_to_v4l2_subdev(start_entity);
824 		if (sd->grp_id & grp_id)
825 			return sd;
826 	}
827 
828 	pad = find_pipeline_pad(imxmd, start_entity, grp_id, true);
829 
830 	return pad ? media_entity_to_v4l2_subdev(pad->entity) : NULL;
831 }
832 
833 /*
834  * Find the upstream mipi-csi2 virtual channel reached from the given
835  * start entity in the current pipeline.
836  * Must be called with mdev->graph_mutex held.
837  */
imx_media_find_mipi_csi2_channel(struct imx_media_dev * imxmd,struct media_entity * start_entity)838 int imx_media_find_mipi_csi2_channel(struct imx_media_dev *imxmd,
839 				     struct media_entity *start_entity)
840 {
841 	struct media_pad *pad;
842 	int ret = -EPIPE;
843 
844 	pad = find_pipeline_pad(imxmd, start_entity, IMX_MEDIA_GRP_ID_CSI2,
845 				true);
846 	if (pad) {
847 		ret = pad->index - 1;
848 		dev_dbg(imxmd->md.dev, "found vc%d from %s\n",
849 			ret, start_entity->name);
850 	}
851 
852 	return ret;
853 }
854 EXPORT_SYMBOL_GPL(imx_media_find_mipi_csi2_channel);
855 
856 /*
857  * Find a source pad reached upstream from the given start entity in
858  * the current pipeline. Must be called with mdev->graph_mutex held.
859  */
860 struct media_pad *
imx_media_find_upstream_pad(struct imx_media_dev * imxmd,struct media_entity * start_entity,u32 grp_id)861 imx_media_find_upstream_pad(struct imx_media_dev *imxmd,
862 			    struct media_entity *start_entity,
863 			    u32 grp_id)
864 {
865 	struct media_pad *pad;
866 
867 	pad = find_pipeline_pad(imxmd, start_entity, grp_id, true);
868 	if (!pad)
869 		return ERR_PTR(-ENODEV);
870 
871 	return pad;
872 }
873 EXPORT_SYMBOL_GPL(imx_media_find_upstream_pad);
874 
875 /*
876  * Find a subdev reached upstream from the given start entity in
877  * the current pipeline.
878  * Must be called with mdev->graph_mutex held.
879  */
880 struct v4l2_subdev *
imx_media_find_upstream_subdev(struct imx_media_dev * imxmd,struct media_entity * start_entity,u32 grp_id)881 imx_media_find_upstream_subdev(struct imx_media_dev *imxmd,
882 			       struct media_entity *start_entity,
883 			       u32 grp_id)
884 {
885 	struct v4l2_subdev *sd;
886 
887 	sd = find_upstream_subdev(imxmd, start_entity, grp_id);
888 	if (!sd)
889 		return ERR_PTR(-ENODEV);
890 
891 	return sd;
892 }
893 EXPORT_SYMBOL_GPL(imx_media_find_upstream_subdev);
894 
895 /*
896  * Turn current pipeline streaming on/off starting from entity.
897  */
imx_media_pipeline_set_stream(struct imx_media_dev * imxmd,struct media_entity * entity,bool on)898 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
899 				  struct media_entity *entity,
900 				  bool on)
901 {
902 	struct v4l2_subdev *sd;
903 	int ret = 0;
904 
905 	if (!is_media_entity_v4l2_subdev(entity))
906 		return -EINVAL;
907 	sd = media_entity_to_v4l2_subdev(entity);
908 
909 	mutex_lock(&imxmd->md.graph_mutex);
910 
911 	if (on) {
912 		ret = __media_pipeline_start(entity, &imxmd->pipe);
913 		if (ret)
914 			goto out;
915 		ret = v4l2_subdev_call(sd, video, s_stream, 1);
916 		if (ret)
917 			__media_pipeline_stop(entity);
918 	} else {
919 		v4l2_subdev_call(sd, video, s_stream, 0);
920 		if (entity->pipe)
921 			__media_pipeline_stop(entity);
922 	}
923 
924 out:
925 	mutex_unlock(&imxmd->md.graph_mutex);
926 	return ret;
927 }
928 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
929 
930 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
931 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
932 MODULE_LICENSE("GPL");
933