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