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>
11 * List of supported pixel formats for the subdevs.
13 * In all of these tables, the non-mbus formats (with no
14 * mbus codes) must all fall at the end of the table.
17 static const struct imx_media_pixfmt yuv_formats[] = {
19 .fourcc = V4L2_PIX_FMT_UYVY,
21 MEDIA_BUS_FMT_UYVY8_2X8,
22 MEDIA_BUS_FMT_UYVY8_1X16
24 .cs = IPUV3_COLORSPACE_YUV,
27 .fourcc = V4L2_PIX_FMT_YUYV,
29 MEDIA_BUS_FMT_YUYV8_2X8,
30 MEDIA_BUS_FMT_YUYV8_1X16
32 .cs = IPUV3_COLORSPACE_YUV,
36 * non-mbus YUV formats start here. NOTE! when adding non-mbus
37 * formats, NUM_NON_MBUS_YUV_FORMATS must be updated below.
40 .fourcc = V4L2_PIX_FMT_YUV420,
41 .cs = IPUV3_COLORSPACE_YUV,
45 .fourcc = V4L2_PIX_FMT_YVU420,
46 .cs = IPUV3_COLORSPACE_YUV,
50 .fourcc = V4L2_PIX_FMT_YUV422P,
51 .cs = IPUV3_COLORSPACE_YUV,
55 .fourcc = V4L2_PIX_FMT_NV12,
56 .cs = IPUV3_COLORSPACE_YUV,
60 .fourcc = V4L2_PIX_FMT_NV16,
61 .cs = IPUV3_COLORSPACE_YUV,
67 #define NUM_NON_MBUS_YUV_FORMATS 5
68 #define NUM_YUV_FORMATS ARRAY_SIZE(yuv_formats)
69 #define NUM_MBUS_YUV_FORMATS (NUM_YUV_FORMATS - NUM_NON_MBUS_YUV_FORMATS)
71 static const struct imx_media_pixfmt rgb_formats[] = {
73 .fourcc = V4L2_PIX_FMT_RGB565,
74 .codes = {MEDIA_BUS_FMT_RGB565_2X8_LE},
75 .cs = IPUV3_COLORSPACE_RGB,
79 .fourcc = V4L2_PIX_FMT_RGB24,
81 MEDIA_BUS_FMT_RGB888_1X24,
82 MEDIA_BUS_FMT_RGB888_2X12_LE
84 .cs = IPUV3_COLORSPACE_RGB,
87 .fourcc = V4L2_PIX_FMT_XRGB32,
88 .codes = {MEDIA_BUS_FMT_ARGB8888_1X32},
89 .cs = IPUV3_COLORSPACE_RGB,
93 /*** raw bayer and grayscale formats start here ***/
95 .fourcc = V4L2_PIX_FMT_SBGGR8,
96 .codes = {MEDIA_BUS_FMT_SBGGR8_1X8},
97 .cs = IPUV3_COLORSPACE_RGB,
101 .fourcc = V4L2_PIX_FMT_SGBRG8,
102 .codes = {MEDIA_BUS_FMT_SGBRG8_1X8},
103 .cs = IPUV3_COLORSPACE_RGB,
107 .fourcc = V4L2_PIX_FMT_SGRBG8,
108 .codes = {MEDIA_BUS_FMT_SGRBG8_1X8},
109 .cs = IPUV3_COLORSPACE_RGB,
113 .fourcc = V4L2_PIX_FMT_SRGGB8,
114 .codes = {MEDIA_BUS_FMT_SRGGB8_1X8},
115 .cs = IPUV3_COLORSPACE_RGB,
119 .fourcc = V4L2_PIX_FMT_SBGGR16,
121 MEDIA_BUS_FMT_SBGGR10_1X10,
122 MEDIA_BUS_FMT_SBGGR12_1X12,
123 MEDIA_BUS_FMT_SBGGR14_1X14,
124 MEDIA_BUS_FMT_SBGGR16_1X16
126 .cs = IPUV3_COLORSPACE_RGB,
130 .fourcc = V4L2_PIX_FMT_SGBRG16,
132 MEDIA_BUS_FMT_SGBRG10_1X10,
133 MEDIA_BUS_FMT_SGBRG12_1X12,
134 MEDIA_BUS_FMT_SGBRG14_1X14,
135 MEDIA_BUS_FMT_SGBRG16_1X16,
137 .cs = IPUV3_COLORSPACE_RGB,
141 .fourcc = V4L2_PIX_FMT_SGRBG16,
143 MEDIA_BUS_FMT_SGRBG10_1X10,
144 MEDIA_BUS_FMT_SGRBG12_1X12,
145 MEDIA_BUS_FMT_SGRBG14_1X14,
146 MEDIA_BUS_FMT_SGRBG16_1X16,
148 .cs = IPUV3_COLORSPACE_RGB,
152 .fourcc = V4L2_PIX_FMT_SRGGB16,
154 MEDIA_BUS_FMT_SRGGB10_1X10,
155 MEDIA_BUS_FMT_SRGGB12_1X12,
156 MEDIA_BUS_FMT_SRGGB14_1X14,
157 MEDIA_BUS_FMT_SRGGB16_1X16,
159 .cs = IPUV3_COLORSPACE_RGB,
163 .fourcc = V4L2_PIX_FMT_GREY,
164 .codes = {MEDIA_BUS_FMT_Y8_1X8},
165 .cs = IPUV3_COLORSPACE_RGB,
169 .fourcc = V4L2_PIX_FMT_Y16,
171 MEDIA_BUS_FMT_Y10_1X10,
172 MEDIA_BUS_FMT_Y12_1X12,
174 .cs = IPUV3_COLORSPACE_RGB,
179 * non-mbus RGB formats start here. NOTE! when adding non-mbus
180 * formats, NUM_NON_MBUS_RGB_FORMATS must be updated below.
183 .fourcc = V4L2_PIX_FMT_BGR24,
184 .cs = IPUV3_COLORSPACE_RGB,
187 .fourcc = V4L2_PIX_FMT_BGR32,
188 .cs = IPUV3_COLORSPACE_RGB,
193 #define NUM_NON_MBUS_RGB_FORMATS 2
194 #define NUM_RGB_FORMATS ARRAY_SIZE(rgb_formats)
195 #define NUM_MBUS_RGB_FORMATS (NUM_RGB_FORMATS - NUM_NON_MBUS_RGB_FORMATS)
197 static const struct imx_media_pixfmt ipu_yuv_formats[] = {
199 .fourcc = V4L2_PIX_FMT_YUV32,
200 .codes = {MEDIA_BUS_FMT_AYUV8_1X32},
201 .cs = IPUV3_COLORSPACE_YUV,
207 #define NUM_IPU_YUV_FORMATS ARRAY_SIZE(ipu_yuv_formats)
209 static const struct imx_media_pixfmt ipu_rgb_formats[] = {
211 .fourcc = V4L2_PIX_FMT_XRGB32,
212 .codes = {MEDIA_BUS_FMT_ARGB8888_1X32},
213 .cs = IPUV3_COLORSPACE_RGB,
219 #define NUM_IPU_RGB_FORMATS ARRAY_SIZE(ipu_rgb_formats)
221 static void init_mbus_colorimetry(struct v4l2_mbus_framefmt *mbus,
222 const struct imx_media_pixfmt *fmt)
224 mbus->colorspace = (fmt->cs == IPUV3_COLORSPACE_RGB) ?
225 V4L2_COLORSPACE_SRGB : V4L2_COLORSPACE_SMPTE170M;
226 mbus->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mbus->colorspace);
227 mbus->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mbus->colorspace);
229 V4L2_MAP_QUANTIZATION_DEFAULT(fmt->cs == IPUV3_COLORSPACE_RGB,
235 struct imx_media_pixfmt *__find_format(u32 fourcc,
239 const struct imx_media_pixfmt *array,
242 const struct imx_media_pixfmt *fmt;
245 for (i = 0; i < array_size; i++) {
248 if ((!allow_non_mbus && !fmt->codes[0]) ||
249 (!allow_bayer && fmt->bayer))
252 if (fourcc && fmt->fourcc == fourcc)
258 for (j = 0; fmt->codes[j]; j++) {
259 if (code == fmt->codes[j])
266 static const struct imx_media_pixfmt *find_format(u32 fourcc,
268 enum codespace_sel cs_sel,
272 const struct imx_media_pixfmt *ret;
276 return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
277 yuv_formats, NUM_YUV_FORMATS);
279 return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
280 rgb_formats, NUM_RGB_FORMATS);
282 ret = __find_format(fourcc, code, allow_non_mbus, allow_bayer,
283 yuv_formats, NUM_YUV_FORMATS);
286 return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
287 rgb_formats, NUM_RGB_FORMATS);
293 static int enum_format(u32 *fourcc, u32 *code, u32 index,
294 enum codespace_sel cs_sel,
298 const struct imx_media_pixfmt *fmt;
299 u32 mbus_yuv_sz = NUM_MBUS_YUV_FORMATS;
300 u32 mbus_rgb_sz = NUM_MBUS_RGB_FORMATS;
301 u32 yuv_sz = NUM_YUV_FORMATS;
302 u32 rgb_sz = NUM_RGB_FORMATS;
306 if (index >= yuv_sz ||
307 (!allow_non_mbus && index >= mbus_yuv_sz))
309 fmt = &yuv_formats[index];
312 if (index >= rgb_sz ||
313 (!allow_non_mbus && index >= mbus_rgb_sz))
315 fmt = &rgb_formats[index];
316 if (!allow_bayer && fmt->bayer)
320 if (!allow_non_mbus) {
321 if (index >= mbus_yuv_sz) {
322 index -= mbus_yuv_sz;
323 if (index >= mbus_rgb_sz)
325 fmt = &rgb_formats[index];
326 if (!allow_bayer && fmt->bayer)
329 fmt = &yuv_formats[index];
332 if (index >= yuv_sz + rgb_sz)
334 if (index >= yuv_sz) {
335 fmt = &rgb_formats[index - yuv_sz];
336 if (!allow_bayer && fmt->bayer)
339 fmt = &yuv_formats[index];
348 *fourcc = fmt->fourcc;
350 *code = fmt->codes[0];
355 const struct imx_media_pixfmt *
356 imx_media_find_format(u32 fourcc, enum codespace_sel cs_sel, bool allow_bayer)
358 return find_format(fourcc, 0, cs_sel, true, allow_bayer);
360 EXPORT_SYMBOL_GPL(imx_media_find_format);
362 int imx_media_enum_format(u32 *fourcc, u32 index, enum codespace_sel cs_sel)
364 return enum_format(fourcc, NULL, index, cs_sel, true, false);
366 EXPORT_SYMBOL_GPL(imx_media_enum_format);
368 const struct imx_media_pixfmt *
369 imx_media_find_mbus_format(u32 code, enum codespace_sel cs_sel,
372 return find_format(0, code, cs_sel, false, allow_bayer);
374 EXPORT_SYMBOL_GPL(imx_media_find_mbus_format);
376 int imx_media_enum_mbus_format(u32 *code, u32 index, enum codespace_sel cs_sel,
379 return enum_format(NULL, code, index, cs_sel, false, allow_bayer);
381 EXPORT_SYMBOL_GPL(imx_media_enum_mbus_format);
383 const struct imx_media_pixfmt *
384 imx_media_find_ipu_format(u32 code, enum codespace_sel cs_sel)
386 const struct imx_media_pixfmt *array, *fmt, *ret = NULL;
392 array_size = NUM_IPU_YUV_FORMATS;
393 array = ipu_yuv_formats;
396 array_size = NUM_IPU_RGB_FORMATS;
397 array = ipu_rgb_formats;
400 array_size = NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS;
401 array = ipu_yuv_formats;
407 for (i = 0; i < array_size; i++) {
408 if (cs_sel == CS_SEL_ANY && i >= NUM_IPU_YUV_FORMATS)
409 fmt = &ipu_rgb_formats[i - NUM_IPU_YUV_FORMATS];
413 for (j = 0; code && fmt->codes[j]; j++) {
414 if (code == fmt->codes[j]) {
424 EXPORT_SYMBOL_GPL(imx_media_find_ipu_format);
426 int imx_media_enum_ipu_format(u32 *code, u32 index, enum codespace_sel cs_sel)
430 if (index >= NUM_IPU_YUV_FORMATS)
432 *code = ipu_yuv_formats[index].codes[0];
435 if (index >= NUM_IPU_RGB_FORMATS)
437 *code = ipu_rgb_formats[index].codes[0];
440 if (index >= NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS)
442 if (index >= NUM_IPU_YUV_FORMATS) {
443 index -= NUM_IPU_YUV_FORMATS;
444 *code = ipu_rgb_formats[index].codes[0];
446 *code = ipu_yuv_formats[index].codes[0];
455 EXPORT_SYMBOL_GPL(imx_media_enum_ipu_format);
457 int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
458 u32 width, u32 height, u32 code, u32 field,
459 const struct imx_media_pixfmt **cc)
461 const struct imx_media_pixfmt *lcc;
464 mbus->height = height;
467 imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false);
468 lcc = imx_media_find_mbus_format(code, CS_SEL_ANY, false);
470 lcc = imx_media_find_ipu_format(code, CS_SEL_ANY);
476 init_mbus_colorimetry(mbus, lcc);
482 EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
485 * Initializes the TRY format to the ACTIVE format on all pads
486 * of a subdev. Can be used as the .init_cfg pad operation.
488 int imx_media_init_cfg(struct v4l2_subdev *sd,
489 struct v4l2_subdev_pad_config *cfg)
491 struct v4l2_mbus_framefmt *mf_try;
492 struct v4l2_subdev_format format;
496 for (pad = 0; pad < sd->entity.num_pads; pad++) {
497 memset(&format, 0, sizeof(format));
500 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
501 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format);
505 mf_try = v4l2_subdev_get_try_format(sd, cfg, pad);
506 *mf_try = format.format;
511 EXPORT_SYMBOL_GPL(imx_media_init_cfg);
514 * Default the colorspace in tryfmt to SRGB if set to an unsupported
515 * colorspace or not initialized. Then set the remaining colorimetry
516 * parameters based on the colorspace if they are uninitialized.
518 * tryfmt->code must be set on entry.
520 * If this format is destined to be routed through the Image Converter,
521 * Y`CbCr encoding must be fixed. The IC supports only BT.601 Y`CbCr
522 * or Rec.709 Y`CbCr encoding.
524 void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt,
527 const struct imx_media_pixfmt *cc;
530 cc = imx_media_find_mbus_format(tryfmt->code, CS_SEL_ANY, true);
532 cc = imx_media_find_ipu_format(tryfmt->code, CS_SEL_ANY);
533 if (cc && cc->cs == IPUV3_COLORSPACE_RGB)
536 switch (tryfmt->colorspace) {
537 case V4L2_COLORSPACE_SMPTE170M:
538 case V4L2_COLORSPACE_REC709:
539 case V4L2_COLORSPACE_JPEG:
540 case V4L2_COLORSPACE_SRGB:
541 case V4L2_COLORSPACE_BT2020:
542 case V4L2_COLORSPACE_OPRGB:
543 case V4L2_COLORSPACE_DCI_P3:
544 case V4L2_COLORSPACE_RAW:
547 tryfmt->colorspace = V4L2_COLORSPACE_SRGB;
551 if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT)
553 V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace);
556 if (tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_601 &&
557 tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_709)
558 tryfmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
560 if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
562 V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace);
566 if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT)
567 tryfmt->quantization =
568 V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb,
572 EXPORT_SYMBOL_GPL(imx_media_try_colorimetry);
574 int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
575 struct v4l2_mbus_framefmt *mbus,
576 const struct imx_media_pixfmt *cc)
582 cc = imx_media_find_ipu_format(mbus->code, CS_SEL_ANY);
584 cc = imx_media_find_mbus_format(mbus->code, CS_SEL_ANY,
591 * TODO: the IPU currently does not support the AYUV32 format,
592 * so until it does convert to a supported YUV format.
594 if (cc->ipufmt && cc->cs == IPUV3_COLORSPACE_YUV) {
597 imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false);
598 cc = imx_media_find_mbus_format(code, CS_SEL_YUV, false);
601 /* Round up width for minimum burst size */
602 width = round_up(mbus->width, 8);
604 /* Round up stride for IDMAC line start address alignment */
606 stride = round_up(width, 16);
608 stride = round_up((width * cc->bpp) >> 3, 8);
611 pix->height = mbus->height;
612 pix->pixelformat = cc->fourcc;
613 pix->colorspace = mbus->colorspace;
614 pix->xfer_func = mbus->xfer_func;
615 pix->ycbcr_enc = mbus->ycbcr_enc;
616 pix->quantization = mbus->quantization;
617 pix->field = mbus->field;
618 pix->bytesperline = stride;
619 pix->sizeimage = cc->planar ? ((stride * pix->height * cc->bpp) >> 3) :
620 stride * pix->height;
624 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt);
626 int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image,
627 struct v4l2_mbus_framefmt *mbus)
631 memset(image, 0, sizeof(*image));
633 ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, mbus, NULL);
637 image->rect.width = mbus->width;
638 image->rect.height = mbus->height;
642 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image);
644 int imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
645 struct ipu_image *image)
647 const struct imx_media_pixfmt *fmt;
649 fmt = imx_media_find_format(image->pix.pixelformat, CS_SEL_ANY, true);
653 memset(mbus, 0, sizeof(*mbus));
654 mbus->width = image->pix.width;
655 mbus->height = image->pix.height;
656 mbus->code = fmt->codes[0];
657 mbus->field = image->pix.field;
658 mbus->colorspace = image->pix.colorspace;
659 mbus->xfer_func = image->pix.xfer_func;
660 mbus->ycbcr_enc = image->pix.ycbcr_enc;
661 mbus->quantization = image->pix.quantization;
665 EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt);
667 void imx_media_free_dma_buf(struct device *dev,
668 struct imx_media_dma_buf *buf)
671 dma_free_coherent(dev, buf->len, buf->virt, buf->phys);
676 EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
678 int imx_media_alloc_dma_buf(struct device *dev,
679 struct imx_media_dma_buf *buf,
682 imx_media_free_dma_buf(dev, buf);
684 buf->len = PAGE_ALIGN(size);
685 buf->virt = dma_alloc_coherent(dev, buf->len, &buf->phys,
686 GFP_DMA | GFP_KERNEL);
688 dev_err(dev, "%s: failed\n", __func__);
694 EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf);
696 /* form a subdev name given a group id and ipu id */
697 void imx_media_grp_id_to_sd_name(char *sd_name, int sz, u32 grp_id, int ipu_id)
702 case IMX_MEDIA_GRP_ID_IPU_CSI0...IMX_MEDIA_GRP_ID_IPU_CSI1:
703 id = (grp_id >> IMX_MEDIA_GRP_ID_IPU_CSI_BIT) - 1;
704 snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id);
706 case IMX_MEDIA_GRP_ID_IPU_VDIC:
707 snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1);
709 case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
710 snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1);
712 case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
713 snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1);
715 case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
716 snprintf(sd_name, sz, "ipu%d_ic_prpvf", ipu_id + 1);
722 EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name);
725 imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd,
726 struct fwnode_handle *fwnode)
728 struct v4l2_subdev *sd;
730 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
731 if (sd->fwnode == fwnode)
737 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode);
740 imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd,
743 struct v4l2_subdev *sd;
745 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
746 if (!strcmp(devname, dev_name(sd->dev)))
752 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname);
755 * Adds a video device to the master video device list. This is called
756 * when a video device is registered.
758 void imx_media_add_video_device(struct imx_media_dev *imxmd,
759 struct imx_media_video_dev *vdev)
761 mutex_lock(&imxmd->mutex);
763 list_add_tail(&vdev->list, &imxmd->vdev_list);
765 mutex_unlock(&imxmd->mutex);
767 EXPORT_SYMBOL_GPL(imx_media_add_video_device);
770 * Search upstream/downstream for a subdevice or video device pad in the
771 * current pipeline, starting from start_entity. Returns the device's
772 * source/sink pad that it was reached from. Must be called with
773 * mdev->graph_mutex held.
775 * If grp_id != 0, finds a subdevice's pad of given grp_id.
776 * Else If buftype != 0, finds a video device's pad of given buffer type.
777 * Else, returns the nearest source/sink pad to start_entity.
780 imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id,
781 enum v4l2_buf_type buftype, bool upstream)
783 struct media_entity *me = start_entity;
784 struct media_pad *pad = NULL;
785 struct video_device *vfd;
786 struct v4l2_subdev *sd;
789 for (i = 0; i < me->num_pads; i++) {
790 struct media_pad *spad = &me->pads[i];
792 if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) ||
793 (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE)))
796 pad = media_entity_remote_pad(spad);
801 if (is_media_entity_v4l2_subdev(pad->entity)) {
802 sd = media_entity_to_v4l2_subdev(pad->entity);
803 if (sd->grp_id & grp_id)
807 return imx_media_pipeline_pad(pad->entity, grp_id,
809 } else if (buftype) {
810 if (is_media_entity_v4l2_video_device(pad->entity)) {
811 vfd = media_entity_to_video_device(pad->entity);
812 if (buftype == vfd->queue->type)
816 return imx_media_pipeline_pad(pad->entity, grp_id,
825 EXPORT_SYMBOL_GPL(imx_media_pipeline_pad);
828 * Search upstream/downstream for a subdev or video device in the current
829 * pipeline. Must be called with mdev->graph_mutex held.
831 static struct media_entity *
832 find_pipeline_entity(struct media_entity *start, u32 grp_id,
833 enum v4l2_buf_type buftype, bool upstream)
835 struct media_pad *pad = NULL;
836 struct video_device *vfd;
837 struct v4l2_subdev *sd;
839 if (grp_id && is_media_entity_v4l2_subdev(start)) {
840 sd = media_entity_to_v4l2_subdev(start);
841 if (sd->grp_id & grp_id)
843 } else if (buftype && is_media_entity_v4l2_video_device(start)) {
844 vfd = media_entity_to_video_device(pad->entity);
845 if (buftype == vfd->queue->type)
849 pad = imx_media_pipeline_pad(start, grp_id, buftype, upstream);
851 return pad ? pad->entity : NULL;
855 * Find the upstream mipi-csi2 virtual channel reached from the given
856 * start entity in the current pipeline.
857 * Must be called with mdev->graph_mutex held.
859 int imx_media_pipeline_csi2_channel(struct media_entity *start_entity)
861 struct media_pad *pad;
864 pad = imx_media_pipeline_pad(start_entity, IMX_MEDIA_GRP_ID_CSI2,
867 ret = pad->index - 1;
871 EXPORT_SYMBOL_GPL(imx_media_pipeline_csi2_channel);
874 * Find a subdev reached upstream from the given start entity in
875 * the current pipeline.
876 * Must be called with mdev->graph_mutex held.
879 imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id,
882 struct media_entity *me;
884 me = find_pipeline_entity(start_entity, grp_id, 0, upstream);
886 return ERR_PTR(-ENODEV);
888 return media_entity_to_v4l2_subdev(me);
890 EXPORT_SYMBOL_GPL(imx_media_pipeline_subdev);
893 * Find a subdev reached upstream from the given start entity in
894 * the current pipeline.
895 * Must be called with mdev->graph_mutex held.
897 struct video_device *
898 imx_media_pipeline_video_device(struct media_entity *start_entity,
899 enum v4l2_buf_type buftype, bool upstream)
901 struct media_entity *me;
903 me = find_pipeline_entity(start_entity, 0, buftype, upstream);
905 return ERR_PTR(-ENODEV);
907 return media_entity_to_video_device(me);
909 EXPORT_SYMBOL_GPL(imx_media_pipeline_video_device);
912 * Turn current pipeline streaming on/off starting from entity.
914 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
915 struct media_entity *entity,
918 struct v4l2_subdev *sd;
921 if (!is_media_entity_v4l2_subdev(entity))
923 sd = media_entity_to_v4l2_subdev(entity);
925 mutex_lock(&imxmd->md.graph_mutex);
928 ret = __media_pipeline_start(entity, &imxmd->pipe);
931 ret = v4l2_subdev_call(sd, video, s_stream, 1);
933 __media_pipeline_stop(entity);
935 v4l2_subdev_call(sd, video, s_stream, 0);
937 __media_pipeline_stop(entity);
941 mutex_unlock(&imxmd->md.graph_mutex);
944 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
946 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
947 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
948 MODULE_LICENSE("GPL");