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  */
imx_media_enum_pixel_formats(u32 * fourcc,u32 index,enum imx_pixfmt_sel fmt_sel)287 int imx_media_enum_pixel_formats(u32 *fourcc, u32 index,
288 				 enum imx_pixfmt_sel fmt_sel)
289 {
290 	bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
291 	unsigned int i;
292 
293 	fmt_sel &= ~PIXFMT_SEL_IPU;
294 
295 	for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
296 		const struct imx_media_pixfmt *fmt = &pixel_formats[i];
297 		enum imx_pixfmt_sel sel;
298 
299 		if (sel_ipu != fmt->ipufmt)
300 			continue;
301 
302 		sel = fmt->bayer ? PIXFMT_SEL_BAYER :
303 			((fmt->cs == IPUV3_COLORSPACE_YUV) ?
304 			 PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
305 
306 		if (!(fmt_sel & sel))
307 			continue;
308 
309 		if (index == 0) {
310 			*fourcc = fmt->fourcc;
311 			return 0;
312 		}
313 
314 		index--;
315 	}
316 
317 	return -EINVAL;
318 }
319 EXPORT_SYMBOL_GPL(imx_media_enum_pixel_formats);
320 
321 /*
322  * Enumerate entries in the pixel_formats[] array that match the
323  * requested search criteria. Return the media-bus code that matches
324  * the search criteria at the requested match index.
325  *
326  * @code: The returned media-bus code that matches the search criteria at
327  *        the requested match index.
328  * @index: The requested match index.
329  * @fmt_sel: Include in the enumeration entries with the given selection
330  *           criteria.
331  */
imx_media_enum_mbus_formats(u32 * code,u32 index,enum imx_pixfmt_sel fmt_sel)332 int imx_media_enum_mbus_formats(u32 *code, u32 index,
333 				enum imx_pixfmt_sel fmt_sel)
334 {
335 	bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
336 	unsigned int i;
337 
338 	fmt_sel &= ~PIXFMT_SEL_IPU;
339 
340 	for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
341 		const struct imx_media_pixfmt *fmt = &pixel_formats[i];
342 		enum imx_pixfmt_sel sel;
343 		unsigned int j;
344 
345 		if (sel_ipu != fmt->ipufmt)
346 			continue;
347 
348 		sel = fmt->bayer ? PIXFMT_SEL_BAYER :
349 			((fmt->cs == IPUV3_COLORSPACE_YUV) ?
350 			 PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
351 
352 		if (!(fmt_sel & sel) || !fmt->codes)
353 			continue;
354 
355 		for (j = 0; fmt->codes[j]; j++) {
356 			if (index == 0) {
357 				*code = fmt->codes[j];
358 				return 0;
359 			}
360 
361 			index--;
362 		}
363 	}
364 
365 	return -EINVAL;
366 }
367 EXPORT_SYMBOL_GPL(imx_media_enum_mbus_formats);
368 
imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt * mbus,u32 width,u32 height,u32 code,u32 field,const struct imx_media_pixfmt ** cc)369 int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
370 			    u32 width, u32 height, u32 code, u32 field,
371 			    const struct imx_media_pixfmt **cc)
372 {
373 	const struct imx_media_pixfmt *lcc;
374 
375 	mbus->width = width;
376 	mbus->height = height;
377 	mbus->field = field;
378 
379 	if (code == 0)
380 		imx_media_enum_mbus_formats(&code, 0, PIXFMT_SEL_YUV);
381 
382 	lcc = imx_media_find_mbus_format(code, PIXFMT_SEL_ANY);
383 	if (!lcc) {
384 		lcc = imx_media_find_ipu_format(code, PIXFMT_SEL_YUV_RGB);
385 		if (!lcc)
386 			return -EINVAL;
387 	}
388 
389 	mbus->code = code;
390 
391 	mbus->colorspace = V4L2_COLORSPACE_SRGB;
392 	mbus->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mbus->colorspace);
393 	mbus->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mbus->colorspace);
394 	mbus->quantization =
395 		V4L2_MAP_QUANTIZATION_DEFAULT(lcc->cs == IPUV3_COLORSPACE_RGB,
396 					      mbus->colorspace,
397 					      mbus->ycbcr_enc);
398 
399 	if (cc)
400 		*cc = lcc;
401 
402 	return 0;
403 }
404 EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
405 
406 /*
407  * Initializes the TRY format to the ACTIVE format on all pads
408  * of a subdev. Can be used as the .init_cfg pad operation.
409  */
imx_media_init_cfg(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg)410 int imx_media_init_cfg(struct v4l2_subdev *sd,
411 		       struct v4l2_subdev_pad_config *cfg)
412 {
413 	struct v4l2_mbus_framefmt *mf_try;
414 	struct v4l2_subdev_format format;
415 	unsigned int pad;
416 	int ret;
417 
418 	for (pad = 0; pad < sd->entity.num_pads; pad++) {
419 		memset(&format, 0, sizeof(format));
420 
421 		format.pad = pad;
422 		format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
423 		ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format);
424 		if (ret)
425 			continue;
426 
427 		mf_try = v4l2_subdev_get_try_format(sd, cfg, pad);
428 		*mf_try = format.format;
429 	}
430 
431 	return 0;
432 }
433 EXPORT_SYMBOL_GPL(imx_media_init_cfg);
434 
435 /*
436  * Default the colorspace in tryfmt to SRGB if set to an unsupported
437  * colorspace or not initialized. Then set the remaining colorimetry
438  * parameters based on the colorspace if they are uninitialized.
439  *
440  * tryfmt->code must be set on entry.
441  *
442  * If this format is destined to be routed through the Image Converter,
443  * Y`CbCr encoding must be fixed. The IC supports only BT.601 Y`CbCr
444  * or Rec.709 Y`CbCr encoding.
445  */
imx_media_try_colorimetry(struct v4l2_mbus_framefmt * tryfmt,bool ic_route)446 void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt,
447 			       bool ic_route)
448 {
449 	const struct imx_media_pixfmt *cc;
450 	bool is_rgb = false;
451 
452 	cc = imx_media_find_mbus_format(tryfmt->code, PIXFMT_SEL_ANY);
453 	if (!cc)
454 		cc = imx_media_find_ipu_format(tryfmt->code,
455 					       PIXFMT_SEL_YUV_RGB);
456 
457 	if (cc && cc->cs == IPUV3_COLORSPACE_RGB)
458 		is_rgb = true;
459 
460 	switch (tryfmt->colorspace) {
461 	case V4L2_COLORSPACE_SMPTE170M:
462 	case V4L2_COLORSPACE_REC709:
463 	case V4L2_COLORSPACE_JPEG:
464 	case V4L2_COLORSPACE_SRGB:
465 	case V4L2_COLORSPACE_BT2020:
466 	case V4L2_COLORSPACE_OPRGB:
467 	case V4L2_COLORSPACE_DCI_P3:
468 	case V4L2_COLORSPACE_RAW:
469 		break;
470 	default:
471 		tryfmt->colorspace = V4L2_COLORSPACE_SRGB;
472 		break;
473 	}
474 
475 	if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT)
476 		tryfmt->xfer_func =
477 			V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace);
478 
479 	if (ic_route) {
480 		if (tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_601 &&
481 		    tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_709)
482 			tryfmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
483 	} else {
484 		if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
485 			tryfmt->ycbcr_enc =
486 				V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace);
487 		}
488 	}
489 
490 	if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT)
491 		tryfmt->quantization =
492 			V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb,
493 						      tryfmt->colorspace,
494 						      tryfmt->ycbcr_enc);
495 }
496 EXPORT_SYMBOL_GPL(imx_media_try_colorimetry);
497 
imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format * pix,const struct v4l2_mbus_framefmt * mbus,const struct imx_media_pixfmt * cc)498 int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
499 				  const struct v4l2_mbus_framefmt *mbus,
500 				  const struct imx_media_pixfmt *cc)
501 {
502 	u32 width;
503 	u32 stride;
504 
505 	if (!cc) {
506 		cc = imx_media_find_ipu_format(mbus->code,
507 					       PIXFMT_SEL_YUV_RGB);
508 		if (!cc)
509 			cc = imx_media_find_mbus_format(mbus->code,
510 							PIXFMT_SEL_ANY);
511 		if (!cc)
512 			return -EINVAL;
513 	}
514 
515 	/*
516 	 * TODO: the IPU currently does not support the AYUV32 format,
517 	 * so until it does convert to a supported YUV format.
518 	 */
519 	if (cc->ipufmt && cc->cs == IPUV3_COLORSPACE_YUV) {
520 		u32 code;
521 
522 		imx_media_enum_mbus_formats(&code, 0, PIXFMT_SEL_YUV);
523 		cc = imx_media_find_mbus_format(code, PIXFMT_SEL_YUV);
524 	}
525 
526 	/* Round up width for minimum burst size */
527 	width = round_up(mbus->width, 8);
528 
529 	/* Round up stride for IDMAC line start address alignment */
530 	if (cc->planar)
531 		stride = round_up(width, 16);
532 	else
533 		stride = round_up((width * cc->bpp) >> 3, 8);
534 
535 	pix->width = width;
536 	pix->height = mbus->height;
537 	pix->pixelformat = cc->fourcc;
538 	pix->colorspace = mbus->colorspace;
539 	pix->xfer_func = mbus->xfer_func;
540 	pix->ycbcr_enc = mbus->ycbcr_enc;
541 	pix->quantization = mbus->quantization;
542 	pix->field = mbus->field;
543 	pix->bytesperline = stride;
544 	pix->sizeimage = cc->planar ? ((stride * pix->height * cc->bpp) >> 3) :
545 			 stride * pix->height;
546 
547 	return 0;
548 }
549 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt);
550 
imx_media_mbus_fmt_to_ipu_image(struct ipu_image * image,const struct v4l2_mbus_framefmt * mbus)551 int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image,
552 				    const struct v4l2_mbus_framefmt *mbus)
553 {
554 	int ret;
555 
556 	memset(image, 0, sizeof(*image));
557 
558 	ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, mbus, NULL);
559 	if (ret)
560 		return ret;
561 
562 	image->rect.width = mbus->width;
563 	image->rect.height = mbus->height;
564 
565 	return 0;
566 }
567 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image);
568 
imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt * mbus,const struct ipu_image * image)569 int imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
570 				    const struct ipu_image *image)
571 {
572 	const struct imx_media_pixfmt *fmt;
573 
574 	fmt = imx_media_find_pixel_format(image->pix.pixelformat,
575 					  PIXFMT_SEL_ANY);
576 	if (!fmt || !fmt->codes || !fmt->codes[0])
577 		return -EINVAL;
578 
579 	memset(mbus, 0, sizeof(*mbus));
580 	mbus->width = image->pix.width;
581 	mbus->height = image->pix.height;
582 	mbus->code = fmt->codes[0];
583 	mbus->field = image->pix.field;
584 	mbus->colorspace = image->pix.colorspace;
585 	mbus->xfer_func = image->pix.xfer_func;
586 	mbus->ycbcr_enc = image->pix.ycbcr_enc;
587 	mbus->quantization = image->pix.quantization;
588 
589 	return 0;
590 }
591 EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt);
592 
imx_media_free_dma_buf(struct device * dev,struct imx_media_dma_buf * buf)593 void imx_media_free_dma_buf(struct device *dev,
594 			    struct imx_media_dma_buf *buf)
595 {
596 	if (buf->virt)
597 		dma_free_coherent(dev, buf->len, buf->virt, buf->phys);
598 
599 	buf->virt = NULL;
600 	buf->phys = 0;
601 }
602 EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
603 
imx_media_alloc_dma_buf(struct device * dev,struct imx_media_dma_buf * buf,int size)604 int imx_media_alloc_dma_buf(struct device *dev,
605 			    struct imx_media_dma_buf *buf,
606 			    int size)
607 {
608 	imx_media_free_dma_buf(dev, buf);
609 
610 	buf->len = PAGE_ALIGN(size);
611 	buf->virt = dma_alloc_coherent(dev, buf->len, &buf->phys,
612 				       GFP_DMA | GFP_KERNEL);
613 	if (!buf->virt) {
614 		dev_err(dev, "%s: failed\n", __func__);
615 		return -ENOMEM;
616 	}
617 
618 	return 0;
619 }
620 EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf);
621 
622 /* 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)623 void imx_media_grp_id_to_sd_name(char *sd_name, int sz, u32 grp_id, int ipu_id)
624 {
625 	int id;
626 
627 	switch (grp_id) {
628 	case IMX_MEDIA_GRP_ID_IPU_CSI0...IMX_MEDIA_GRP_ID_IPU_CSI1:
629 		id = (grp_id >> IMX_MEDIA_GRP_ID_IPU_CSI_BIT) - 1;
630 		snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id);
631 		break;
632 	case IMX_MEDIA_GRP_ID_IPU_VDIC:
633 		snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1);
634 		break;
635 	case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
636 		snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1);
637 		break;
638 	case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
639 		snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1);
640 		break;
641 	case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
642 		snprintf(sd_name, sz, "ipu%d_ic_prpvf", ipu_id + 1);
643 		break;
644 	default:
645 		break;
646 	}
647 }
648 EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name);
649 
650 struct v4l2_subdev *
imx_media_find_subdev_by_fwnode(struct imx_media_dev * imxmd,struct fwnode_handle * fwnode)651 imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd,
652 				struct fwnode_handle *fwnode)
653 {
654 	struct v4l2_subdev *sd;
655 
656 	list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
657 		if (sd->fwnode == fwnode)
658 			return sd;
659 	}
660 
661 	return NULL;
662 }
663 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode);
664 
665 struct v4l2_subdev *
imx_media_find_subdev_by_devname(struct imx_media_dev * imxmd,const char * devname)666 imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd,
667 				 const char *devname)
668 {
669 	struct v4l2_subdev *sd;
670 
671 	list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
672 		if (!strcmp(devname, dev_name(sd->dev)))
673 			return sd;
674 	}
675 
676 	return NULL;
677 }
678 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname);
679 
680 /*
681  * Adds a video device to the master video device list. This is called
682  * when a video device is registered.
683  */
imx_media_add_video_device(struct imx_media_dev * imxmd,struct imx_media_video_dev * vdev)684 void imx_media_add_video_device(struct imx_media_dev *imxmd,
685 				struct imx_media_video_dev *vdev)
686 {
687 	mutex_lock(&imxmd->mutex);
688 
689 	list_add_tail(&vdev->list, &imxmd->vdev_list);
690 
691 	mutex_unlock(&imxmd->mutex);
692 }
693 EXPORT_SYMBOL_GPL(imx_media_add_video_device);
694 
695 /*
696  * Search upstream/downstream for a subdevice or video device pad in the
697  * current pipeline, starting from start_entity. Returns the device's
698  * source/sink pad that it was reached from. Must be called with
699  * mdev->graph_mutex held.
700  *
701  * If grp_id != 0, finds a subdevice's pad of given grp_id.
702  * Else If buftype != 0, finds a video device's pad of given buffer type.
703  * Else, returns the nearest source/sink pad to start_entity.
704  */
705 struct media_pad *
imx_media_pipeline_pad(struct media_entity * start_entity,u32 grp_id,enum v4l2_buf_type buftype,bool upstream)706 imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id,
707 		       enum v4l2_buf_type buftype, bool upstream)
708 {
709 	struct media_entity *me = start_entity;
710 	struct media_pad *pad = NULL;
711 	struct video_device *vfd;
712 	struct v4l2_subdev *sd;
713 	int i;
714 
715 	for (i = 0; i < me->num_pads; i++) {
716 		struct media_pad *spad = &me->pads[i];
717 
718 		if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) ||
719 		    (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE)))
720 			continue;
721 
722 		pad = media_entity_remote_pad(spad);
723 		if (!pad)
724 			continue;
725 
726 		if (grp_id) {
727 			if (is_media_entity_v4l2_subdev(pad->entity)) {
728 				sd = media_entity_to_v4l2_subdev(pad->entity);
729 				if (sd->grp_id & grp_id)
730 					return pad;
731 			}
732 
733 			return imx_media_pipeline_pad(pad->entity, grp_id,
734 						      buftype, upstream);
735 		} else if (buftype) {
736 			if (is_media_entity_v4l2_video_device(pad->entity)) {
737 				vfd = media_entity_to_video_device(pad->entity);
738 				if (buftype == vfd->queue->type)
739 					return pad;
740 			}
741 
742 			return imx_media_pipeline_pad(pad->entity, grp_id,
743 						      buftype, upstream);
744 		} else {
745 			return pad;
746 		}
747 	}
748 
749 	return NULL;
750 }
751 EXPORT_SYMBOL_GPL(imx_media_pipeline_pad);
752 
753 /*
754  * Search upstream/downstream for a subdev or video device in the current
755  * pipeline. Must be called with mdev->graph_mutex held.
756  */
757 static struct media_entity *
find_pipeline_entity(struct media_entity * start,u32 grp_id,enum v4l2_buf_type buftype,bool upstream)758 find_pipeline_entity(struct media_entity *start, u32 grp_id,
759 		     enum v4l2_buf_type buftype, bool upstream)
760 {
761 	struct media_pad *pad = NULL;
762 	struct video_device *vfd;
763 	struct v4l2_subdev *sd;
764 
765 	if (grp_id && is_media_entity_v4l2_subdev(start)) {
766 		sd = media_entity_to_v4l2_subdev(start);
767 		if (sd->grp_id & grp_id)
768 			return &sd->entity;
769 	} else if (buftype && is_media_entity_v4l2_video_device(start)) {
770 		vfd = media_entity_to_video_device(start);
771 		if (buftype == vfd->queue->type)
772 			return &vfd->entity;
773 	}
774 
775 	pad = imx_media_pipeline_pad(start, grp_id, buftype, upstream);
776 
777 	return pad ? pad->entity : NULL;
778 }
779 
780 /*
781  * Find the upstream mipi-csi2 virtual channel reached from the given
782  * start entity in the current pipeline.
783  * Must be called with mdev->graph_mutex held.
784  */
imx_media_pipeline_csi2_channel(struct media_entity * start_entity)785 int imx_media_pipeline_csi2_channel(struct media_entity *start_entity)
786 {
787 	struct media_pad *pad;
788 	int ret = -EPIPE;
789 
790 	pad = imx_media_pipeline_pad(start_entity, IMX_MEDIA_GRP_ID_CSI2,
791 				     0, true);
792 	if (pad)
793 		ret = pad->index - 1;
794 
795 	return ret;
796 }
797 EXPORT_SYMBOL_GPL(imx_media_pipeline_csi2_channel);
798 
799 /*
800  * Find a subdev reached upstream from the given start entity in
801  * the current pipeline.
802  * Must be called with mdev->graph_mutex held.
803  */
804 struct v4l2_subdev *
imx_media_pipeline_subdev(struct media_entity * start_entity,u32 grp_id,bool upstream)805 imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id,
806 			  bool upstream)
807 {
808 	struct media_entity *me;
809 
810 	me = find_pipeline_entity(start_entity, grp_id, 0, upstream);
811 	if (!me)
812 		return ERR_PTR(-ENODEV);
813 
814 	return media_entity_to_v4l2_subdev(me);
815 }
816 EXPORT_SYMBOL_GPL(imx_media_pipeline_subdev);
817 
818 /*
819  * Find a subdev reached upstream from the given start entity in
820  * the current pipeline.
821  * Must be called with mdev->graph_mutex held.
822  */
823 struct video_device *
imx_media_pipeline_video_device(struct media_entity * start_entity,enum v4l2_buf_type buftype,bool upstream)824 imx_media_pipeline_video_device(struct media_entity *start_entity,
825 				enum v4l2_buf_type buftype, bool upstream)
826 {
827 	struct media_entity *me;
828 
829 	me = find_pipeline_entity(start_entity, 0, buftype, upstream);
830 	if (!me)
831 		return ERR_PTR(-ENODEV);
832 
833 	return media_entity_to_video_device(me);
834 }
835 EXPORT_SYMBOL_GPL(imx_media_pipeline_video_device);
836 
837 /*
838  * Find a fwnode endpoint that maps to the given subdevice's pad.
839  * If there are multiple endpoints that map to the pad, only the
840  * first endpoint encountered is returned.
841  *
842  * On success the refcount of the returned fwnode endpoint is
843  * incremented.
844  */
imx_media_get_pad_fwnode(struct media_pad * pad)845 struct fwnode_handle *imx_media_get_pad_fwnode(struct media_pad *pad)
846 {
847 	struct fwnode_handle *endpoint;
848 	struct v4l2_subdev *sd;
849 
850 	if (!is_media_entity_v4l2_subdev(pad->entity))
851 		return ERR_PTR(-ENODEV);
852 
853 	sd = media_entity_to_v4l2_subdev(pad->entity);
854 
855 	fwnode_graph_for_each_endpoint(dev_fwnode(sd->dev), endpoint) {
856 		int pad_idx = media_entity_get_fwnode_pad(&sd->entity,
857 							  endpoint,
858 							  pad->flags);
859 		if (pad_idx < 0)
860 			continue;
861 
862 		if (pad_idx == pad->index)
863 			return endpoint;
864 	}
865 
866 	return ERR_PTR(-ENODEV);
867 }
868 EXPORT_SYMBOL_GPL(imx_media_get_pad_fwnode);
869 
870 /*
871  * Turn current pipeline streaming on/off starting from entity.
872  */
imx_media_pipeline_set_stream(struct imx_media_dev * imxmd,struct media_entity * entity,bool on)873 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
874 				  struct media_entity *entity,
875 				  bool on)
876 {
877 	struct v4l2_subdev *sd;
878 	int ret = 0;
879 
880 	if (!is_media_entity_v4l2_subdev(entity))
881 		return -EINVAL;
882 	sd = media_entity_to_v4l2_subdev(entity);
883 
884 	mutex_lock(&imxmd->md.graph_mutex);
885 
886 	if (on) {
887 		ret = __media_pipeline_start(entity, &imxmd->pipe);
888 		if (ret)
889 			goto out;
890 		ret = v4l2_subdev_call(sd, video, s_stream, 1);
891 		if (ret)
892 			__media_pipeline_stop(entity);
893 	} else {
894 		v4l2_subdev_call(sd, video, s_stream, 0);
895 		if (entity->pipe)
896 			__media_pipeline_stop(entity);
897 	}
898 
899 out:
900 	mutex_unlock(&imxmd->md.graph_mutex);
901 	return ret;
902 }
903 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
904 
905 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
906 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
907 MODULE_LICENSE("GPL");
908