cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

imx-media-utils.c (22255B)


      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 */
     15static 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 */
    209const struct imx_media_pixfmt *
    210imx_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}
    234EXPORT_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 */
    243const struct imx_media_pixfmt *
    244imx_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}
    274EXPORT_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 */
    289int 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}
    340EXPORT_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 */
    353int 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}
    388EXPORT_SYMBOL_GPL(imx_media_enum_mbus_formats);
    389
    390int 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}
    425EXPORT_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 */
    431int 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}
    454EXPORT_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 */
    467void 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}
    517EXPORT_SYMBOL_GPL(imx_media_try_colorimetry);
    518
    519int 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}
    570EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt);
    571
    572void 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}
    581EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
    582
    583int 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}
    599EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf);
    600
    601/* form a subdev name given a group id and ipu id */
    602void 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}
    627EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name);
    628
    629struct v4l2_subdev *
    630imx_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}
    642EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode);
    643
    644struct v4l2_subdev *
    645imx_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}
    657EXPORT_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 */
    663void 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}
    672EXPORT_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 */
    684struct media_pad *
    685imx_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_entity_remote_pad(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}
    730EXPORT_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 */
    736static struct media_entity *
    737find_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 */
    764int 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}
    776EXPORT_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 */
    783struct v4l2_subdev *
    784imx_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}
    795EXPORT_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 */
    802struct video_device *
    803imx_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}
    814EXPORT_SYMBOL_GPL(imx_media_pipeline_video_device);
    815
    816/*
    817 * Find a fwnode endpoint that maps to the given subdevice's pad.
    818 * If there are multiple endpoints that map to the pad, only the
    819 * first endpoint encountered is returned.
    820 *
    821 * On success the refcount of the returned fwnode endpoint is
    822 * incremented.
    823 */
    824struct fwnode_handle *imx_media_get_pad_fwnode(struct media_pad *pad)
    825{
    826	struct fwnode_handle *endpoint;
    827	struct v4l2_subdev *sd;
    828
    829	if (!is_media_entity_v4l2_subdev(pad->entity))
    830		return ERR_PTR(-ENODEV);
    831
    832	sd = media_entity_to_v4l2_subdev(pad->entity);
    833
    834	fwnode_graph_for_each_endpoint(dev_fwnode(sd->dev), endpoint) {
    835		int pad_idx = media_entity_get_fwnode_pad(&sd->entity,
    836							  endpoint,
    837							  pad->flags);
    838		if (pad_idx < 0)
    839			continue;
    840
    841		if (pad_idx == pad->index)
    842			return endpoint;
    843	}
    844
    845	return ERR_PTR(-ENODEV);
    846}
    847EXPORT_SYMBOL_GPL(imx_media_get_pad_fwnode);
    848
    849/*
    850 * Turn current pipeline streaming on/off starting from entity.
    851 */
    852int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
    853				  struct media_entity *entity,
    854				  bool on)
    855{
    856	struct v4l2_subdev *sd;
    857	int ret = 0;
    858
    859	if (!is_media_entity_v4l2_subdev(entity))
    860		return -EINVAL;
    861	sd = media_entity_to_v4l2_subdev(entity);
    862
    863	mutex_lock(&imxmd->md.graph_mutex);
    864
    865	if (on) {
    866		ret = __media_pipeline_start(entity, &imxmd->pipe);
    867		if (ret)
    868			goto out;
    869		ret = v4l2_subdev_call(sd, video, s_stream, 1);
    870		if (ret)
    871			__media_pipeline_stop(entity);
    872	} else {
    873		v4l2_subdev_call(sd, video, s_stream, 0);
    874		if (entity->pipe)
    875			__media_pipeline_stop(entity);
    876	}
    877
    878out:
    879	mutex_unlock(&imxmd->md.graph_mutex);
    880	return ret;
    881}
    882EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
    883
    884MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
    885MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
    886MODULE_LICENSE("GPL");