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