1 // SPDX-License-Identifier: GPL-2.0+
3 * V4L2 Media Controller Driver for Freescale i.MX5/6 SOC
5 * Copyright (c) 2016 Mentor Graphics Inc.
7 #include <linux/module.h>
10 #define IMX_BUS_FMTS(fmt...) (const u32[]) {fmt, 0}
13 * List of supported pixel formats for the subdevs.
15 static const struct imx_media_pixfmt pixel_formats[] = {
16 /*** YUV formats start here ***/
18 .fourcc = V4L2_PIX_FMT_UYVY,
19 .codes = IMX_BUS_FMTS(
20 MEDIA_BUS_FMT_UYVY8_2X8,
21 MEDIA_BUS_FMT_UYVY8_1X16
23 .cs = IPUV3_COLORSPACE_YUV,
26 .fourcc = V4L2_PIX_FMT_YUYV,
27 .codes = IMX_BUS_FMTS(
28 MEDIA_BUS_FMT_YUYV8_2X8,
29 MEDIA_BUS_FMT_YUYV8_1X16
31 .cs = IPUV3_COLORSPACE_YUV,
34 .fourcc = V4L2_PIX_FMT_YUV420,
35 .cs = IPUV3_COLORSPACE_YUV,
39 .fourcc = V4L2_PIX_FMT_YVU420,
40 .cs = IPUV3_COLORSPACE_YUV,
44 .fourcc = V4L2_PIX_FMT_YUV422P,
45 .cs = IPUV3_COLORSPACE_YUV,
49 .fourcc = V4L2_PIX_FMT_NV12,
50 .cs = IPUV3_COLORSPACE_YUV,
54 .fourcc = V4L2_PIX_FMT_NV16,
55 .cs = IPUV3_COLORSPACE_YUV,
59 .fourcc = V4L2_PIX_FMT_YUV32,
60 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_AYUV8_1X32),
61 .cs = IPUV3_COLORSPACE_YUV,
65 /*** RGB formats start here ***/
67 .fourcc = V4L2_PIX_FMT_RGB565,
68 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_RGB565_2X8_LE),
69 .cs = IPUV3_COLORSPACE_RGB,
73 .fourcc = V4L2_PIX_FMT_RGB24,
74 .codes = IMX_BUS_FMTS(
75 MEDIA_BUS_FMT_RGB888_1X24,
76 MEDIA_BUS_FMT_RGB888_2X12_LE
78 .cs = IPUV3_COLORSPACE_RGB,
81 .fourcc = V4L2_PIX_FMT_BGR24,
82 .cs = IPUV3_COLORSPACE_RGB,
85 .fourcc = V4L2_PIX_FMT_XRGB32,
86 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_ARGB8888_1X32),
87 .cs = IPUV3_COLORSPACE_RGB,
90 .fourcc = V4L2_PIX_FMT_XRGB32,
91 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_ARGB8888_1X32),
92 .cs = IPUV3_COLORSPACE_RGB,
96 .fourcc = V4L2_PIX_FMT_XBGR32,
97 .cs = IPUV3_COLORSPACE_RGB,
100 .fourcc = V4L2_PIX_FMT_BGRX32,
101 .cs = IPUV3_COLORSPACE_RGB,
104 .fourcc = V4L2_PIX_FMT_RGBX32,
105 .cs = IPUV3_COLORSPACE_RGB,
108 /*** raw bayer and grayscale formats start here ***/
110 .fourcc = V4L2_PIX_FMT_SBGGR8,
111 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SBGGR8_1X8),
112 .cs = IPUV3_COLORSPACE_RGB,
116 .fourcc = V4L2_PIX_FMT_SGBRG8,
117 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGBRG8_1X8),
118 .cs = IPUV3_COLORSPACE_RGB,
122 .fourcc = V4L2_PIX_FMT_SGRBG8,
123 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGRBG8_1X8),
124 .cs = IPUV3_COLORSPACE_RGB,
128 .fourcc = V4L2_PIX_FMT_SRGGB8,
129 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SRGGB8_1X8),
130 .cs = IPUV3_COLORSPACE_RGB,
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
141 .cs = IPUV3_COLORSPACE_RGB,
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
152 .cs = IPUV3_COLORSPACE_RGB,
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
163 .cs = IPUV3_COLORSPACE_RGB,
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
174 .cs = IPUV3_COLORSPACE_RGB,
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
184 .cs = IPUV3_COLORSPACE_RGB,
188 .fourcc = V4L2_PIX_FMT_Y10,
189 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y10_1X10),
190 .cs = IPUV3_COLORSPACE_RGB,
194 .fourcc = V4L2_PIX_FMT_Y12,
195 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y12_1X12),
196 .cs = IPUV3_COLORSPACE_RGB,
203 * Search in the pixel_formats[] array for an entry with the given fourcc
204 * that matches the requested selection criteria and return it.
206 * @fourcc: Search for an entry with the given fourcc pixel format.
207 * @fmt_sel: Allow entries only with the given selection criteria.
209 const struct imx_media_pixfmt *
210 imx_media_find_pixel_format(u32 fourcc, enum imx_pixfmt_sel fmt_sel)
212 bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
215 fmt_sel &= ~PIXFMT_SEL_IPU;
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;
221 if (sel_ipu != fmt->ipufmt)
224 sel = fmt->bayer ? PIXFMT_SEL_BAYER :
225 ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
226 PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
228 if ((fmt_sel & sel) && fmt->fourcc == fourcc)
234 EXPORT_SYMBOL_GPL(imx_media_find_pixel_format);
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.
240 * @code: Search for an entry with the given media-bus code.
241 * @fmt_sel: Allow entries only with the given selection criteria.
243 const struct imx_media_pixfmt *
244 imx_media_find_mbus_format(u32 code, enum imx_pixfmt_sel fmt_sel)
246 bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
249 fmt_sel &= ~PIXFMT_SEL_IPU;
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;
256 if (sel_ipu != fmt->ipufmt)
259 sel = fmt->bayer ? PIXFMT_SEL_BAYER :
260 ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
261 PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
263 if (!(fmt_sel & sel) || !fmt->codes)
266 for (j = 0; fmt->codes[j]; j++) {
267 if (code == fmt->codes[j])
274 EXPORT_SYMBOL_GPL(imx_media_find_mbus_format);
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.
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
286 * @code: If non-zero, only include in the enumeration entries matching this
289 int imx_media_enum_pixel_formats(u32 *fourcc, u32 index,
290 enum imx_pixfmt_sel fmt_sel, u32 code)
292 bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
295 fmt_sel &= ~PIXFMT_SEL_IPU;
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;
301 if (sel_ipu != fmt->ipufmt)
304 sel = fmt->bayer ? PIXFMT_SEL_BAYER :
305 ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
306 PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
308 if (!(fmt_sel & sel))
312 * If a media bus code is specified, only consider formats that
321 for (j = 0; fmt->codes[j]; j++) {
322 if (code == fmt->codes[j])
331 *fourcc = fmt->fourcc;
340 EXPORT_SYMBOL_GPL(imx_media_enum_pixel_formats);
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.
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
353 int imx_media_enum_mbus_formats(u32 *code, u32 index,
354 enum imx_pixfmt_sel fmt_sel)
356 bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
359 fmt_sel &= ~PIXFMT_SEL_IPU;
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;
366 if (sel_ipu != fmt->ipufmt)
369 sel = fmt->bayer ? PIXFMT_SEL_BAYER :
370 ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
371 PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
373 if (!(fmt_sel & sel) || !fmt->codes)
376 for (j = 0; fmt->codes[j]; j++) {
378 *code = fmt->codes[j];
388 EXPORT_SYMBOL_GPL(imx_media_enum_mbus_formats);
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)
394 const struct imx_media_pixfmt *lcc;
397 mbus->height = height;
401 imx_media_enum_mbus_formats(&code, 0, PIXFMT_SEL_YUV);
403 lcc = imx_media_find_mbus_format(code, PIXFMT_SEL_ANY);
405 lcc = imx_media_find_ipu_format(code, PIXFMT_SEL_YUV_RGB);
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);
416 V4L2_MAP_QUANTIZATION_DEFAULT(lcc->cs == IPUV3_COLORSPACE_RGB,
425 EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
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.
431 int imx_media_init_cfg(struct v4l2_subdev *sd,
432 struct v4l2_subdev_pad_config *cfg)
434 struct v4l2_mbus_framefmt *mf_try;
435 struct v4l2_subdev_format format;
439 for (pad = 0; pad < sd->entity.num_pads; pad++) {
440 memset(&format, 0, sizeof(format));
443 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
444 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format);
448 mf_try = v4l2_subdev_get_try_format(sd, cfg, pad);
449 *mf_try = format.format;
454 EXPORT_SYMBOL_GPL(imx_media_init_cfg);
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.
461 * tryfmt->code must be set on entry.
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.
467 void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt,
470 const struct imx_media_pixfmt *cc;
473 cc = imx_media_find_mbus_format(tryfmt->code, PIXFMT_SEL_ANY);
475 cc = imx_media_find_ipu_format(tryfmt->code,
478 if (cc && cc->cs == IPUV3_COLORSPACE_RGB)
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:
492 tryfmt->colorspace = V4L2_COLORSPACE_SRGB;
496 if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT)
498 V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace);
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;
505 if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
507 V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace);
511 if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT)
512 tryfmt->quantization =
513 V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb,
517 EXPORT_SYMBOL_GPL(imx_media_try_colorimetry);
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)
527 cc = imx_media_find_ipu_format(mbus->code,
530 cc = imx_media_find_mbus_format(mbus->code,
537 * TODO: the IPU currently does not support the AYUV32 format,
538 * so until it does convert to a supported YUV format.
540 if (cc->ipufmt && cc->cs == IPUV3_COLORSPACE_YUV) {
543 imx_media_enum_mbus_formats(&code, 0, PIXFMT_SEL_YUV);
544 cc = imx_media_find_mbus_format(code, PIXFMT_SEL_YUV);
547 /* Round up width for minimum burst size */
548 width = round_up(mbus->width, 8);
550 /* Round up stride for IDMAC line start address alignment */
552 stride = round_up(width, 16);
554 stride = round_up((width * cc->bpp) >> 3, 8);
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;
570 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt);
572 int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image,
573 const struct v4l2_mbus_framefmt *mbus)
577 memset(image, 0, sizeof(*image));
579 ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, mbus, NULL);
583 image->rect.width = mbus->width;
584 image->rect.height = mbus->height;
588 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image);
590 int imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
591 const struct ipu_image *image)
593 const struct imx_media_pixfmt *fmt;
595 fmt = imx_media_find_pixel_format(image->pix.pixelformat,
597 if (!fmt || !fmt->codes || !fmt->codes[0])
600 memset(mbus, 0, sizeof(*mbus));
601 mbus->width = image->pix.width;
602 mbus->height = image->pix.height;
603 mbus->code = fmt->codes[0];
604 mbus->field = image->pix.field;
605 mbus->colorspace = image->pix.colorspace;
606 mbus->xfer_func = image->pix.xfer_func;
607 mbus->ycbcr_enc = image->pix.ycbcr_enc;
608 mbus->quantization = image->pix.quantization;
612 EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt);
614 void imx_media_free_dma_buf(struct device *dev,
615 struct imx_media_dma_buf *buf)
618 dma_free_coherent(dev, buf->len, buf->virt, buf->phys);
623 EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
625 int imx_media_alloc_dma_buf(struct device *dev,
626 struct imx_media_dma_buf *buf,
629 imx_media_free_dma_buf(dev, buf);
631 buf->len = PAGE_ALIGN(size);
632 buf->virt = dma_alloc_coherent(dev, buf->len, &buf->phys,
633 GFP_DMA | GFP_KERNEL);
635 dev_err(dev, "%s: failed\n", __func__);
641 EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf);
643 /* form a subdev name given a group id and ipu id */
644 void imx_media_grp_id_to_sd_name(char *sd_name, int sz, u32 grp_id, int ipu_id)
649 case IMX_MEDIA_GRP_ID_IPU_CSI0...IMX_MEDIA_GRP_ID_IPU_CSI1:
650 id = (grp_id >> IMX_MEDIA_GRP_ID_IPU_CSI_BIT) - 1;
651 snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id);
653 case IMX_MEDIA_GRP_ID_IPU_VDIC:
654 snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1);
656 case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
657 snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1);
659 case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
660 snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1);
662 case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
663 snprintf(sd_name, sz, "ipu%d_ic_prpvf", ipu_id + 1);
669 EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name);
672 imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd,
673 struct fwnode_handle *fwnode)
675 struct v4l2_subdev *sd;
677 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
678 if (sd->fwnode == fwnode)
684 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode);
687 imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd,
690 struct v4l2_subdev *sd;
692 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
693 if (!strcmp(devname, dev_name(sd->dev)))
699 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname);
702 * Adds a video device to the master video device list. This is called
703 * when a video device is registered.
705 void imx_media_add_video_device(struct imx_media_dev *imxmd,
706 struct imx_media_video_dev *vdev)
708 mutex_lock(&imxmd->mutex);
710 list_add_tail(&vdev->list, &imxmd->vdev_list);
712 mutex_unlock(&imxmd->mutex);
714 EXPORT_SYMBOL_GPL(imx_media_add_video_device);
717 * Search upstream/downstream for a subdevice or video device pad in the
718 * current pipeline, starting from start_entity. Returns the device's
719 * source/sink pad that it was reached from. Must be called with
720 * mdev->graph_mutex held.
722 * If grp_id != 0, finds a subdevice's pad of given grp_id.
723 * Else If buftype != 0, finds a video device's pad of given buffer type.
724 * Else, returns the nearest source/sink pad to start_entity.
727 imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id,
728 enum v4l2_buf_type buftype, bool upstream)
730 struct media_entity *me = start_entity;
731 struct media_pad *pad = NULL;
732 struct video_device *vfd;
733 struct v4l2_subdev *sd;
736 for (i = 0; i < me->num_pads; i++) {
737 struct media_pad *spad = &me->pads[i];
739 if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) ||
740 (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE)))
743 pad = media_entity_remote_pad(spad);
748 if (is_media_entity_v4l2_subdev(pad->entity)) {
749 sd = media_entity_to_v4l2_subdev(pad->entity);
750 if (sd->grp_id & grp_id)
754 return imx_media_pipeline_pad(pad->entity, grp_id,
756 } else if (buftype) {
757 if (is_media_entity_v4l2_video_device(pad->entity)) {
758 vfd = media_entity_to_video_device(pad->entity);
759 if (buftype == vfd->queue->type)
763 return imx_media_pipeline_pad(pad->entity, grp_id,
772 EXPORT_SYMBOL_GPL(imx_media_pipeline_pad);
775 * Search upstream/downstream for a subdev or video device in the current
776 * pipeline. Must be called with mdev->graph_mutex held.
778 static struct media_entity *
779 find_pipeline_entity(struct media_entity *start, u32 grp_id,
780 enum v4l2_buf_type buftype, bool upstream)
782 struct media_pad *pad = NULL;
783 struct video_device *vfd;
784 struct v4l2_subdev *sd;
786 if (grp_id && is_media_entity_v4l2_subdev(start)) {
787 sd = media_entity_to_v4l2_subdev(start);
788 if (sd->grp_id & grp_id)
790 } else if (buftype && is_media_entity_v4l2_video_device(start)) {
791 vfd = media_entity_to_video_device(start);
792 if (buftype == vfd->queue->type)
796 pad = imx_media_pipeline_pad(start, grp_id, buftype, upstream);
798 return pad ? pad->entity : NULL;
802 * Find the upstream mipi-csi2 virtual channel reached from the given
803 * start entity in the current pipeline.
804 * Must be called with mdev->graph_mutex held.
806 int imx_media_pipeline_csi2_channel(struct media_entity *start_entity)
808 struct media_pad *pad;
811 pad = imx_media_pipeline_pad(start_entity, IMX_MEDIA_GRP_ID_CSI2,
814 ret = pad->index - 1;
818 EXPORT_SYMBOL_GPL(imx_media_pipeline_csi2_channel);
821 * Find a subdev reached upstream from the given start entity in
822 * the current pipeline.
823 * Must be called with mdev->graph_mutex held.
826 imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id,
829 struct media_entity *me;
831 me = find_pipeline_entity(start_entity, grp_id, 0, upstream);
833 return ERR_PTR(-ENODEV);
835 return media_entity_to_v4l2_subdev(me);
837 EXPORT_SYMBOL_GPL(imx_media_pipeline_subdev);
840 * Find a subdev reached upstream from the given start entity in
841 * the current pipeline.
842 * Must be called with mdev->graph_mutex held.
844 struct video_device *
845 imx_media_pipeline_video_device(struct media_entity *start_entity,
846 enum v4l2_buf_type buftype, bool upstream)
848 struct media_entity *me;
850 me = find_pipeline_entity(start_entity, 0, buftype, upstream);
852 return ERR_PTR(-ENODEV);
854 return media_entity_to_video_device(me);
856 EXPORT_SYMBOL_GPL(imx_media_pipeline_video_device);
859 * Find a fwnode endpoint that maps to the given subdevice's pad.
860 * If there are multiple endpoints that map to the pad, only the
861 * first endpoint encountered is returned.
863 * On success the refcount of the returned fwnode endpoint is
866 struct fwnode_handle *imx_media_get_pad_fwnode(struct media_pad *pad)
868 struct fwnode_handle *endpoint;
869 struct v4l2_subdev *sd;
871 if (!is_media_entity_v4l2_subdev(pad->entity))
872 return ERR_PTR(-ENODEV);
874 sd = media_entity_to_v4l2_subdev(pad->entity);
876 fwnode_graph_for_each_endpoint(dev_fwnode(sd->dev), endpoint) {
877 int pad_idx = media_entity_get_fwnode_pad(&sd->entity,
883 if (pad_idx == pad->index)
887 return ERR_PTR(-ENODEV);
889 EXPORT_SYMBOL_GPL(imx_media_get_pad_fwnode);
892 * Turn current pipeline streaming on/off starting from entity.
894 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
895 struct media_entity *entity,
898 struct v4l2_subdev *sd;
901 if (!is_media_entity_v4l2_subdev(entity))
903 sd = media_entity_to_v4l2_subdev(entity);
905 mutex_lock(&imxmd->md.graph_mutex);
908 ret = __media_pipeline_start(entity, &imxmd->pipe);
911 ret = v4l2_subdev_call(sd, video, s_stream, 1);
913 __media_pipeline_stop(entity);
915 v4l2_subdev_call(sd, video, s_stream, 0);
917 __media_pipeline_stop(entity);
921 mutex_unlock(&imxmd->md.graph_mutex);
924 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
926 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
927 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
928 MODULE_LICENSE("GPL");