0001
0002
0003
0004
0005
0006
0007 #include <linux/module.h>
0008 #include "imx-media.h"
0009
0010 #define IMX_BUS_FMTS(fmt...) (const u32[]) {fmt, 0}
0011
0012
0013
0014
0015 static const struct imx_media_pixfmt pixel_formats[] = {
0016
0017 {
0018 .fourcc = V4L2_PIX_FMT_UYVY,
0019 .codes = IMX_BUS_FMTS(
0020 MEDIA_BUS_FMT_UYVY8_2X8,
0021 MEDIA_BUS_FMT_UYVY8_1X16
0022 ),
0023 .cs = IPUV3_COLORSPACE_YUV,
0024 .bpp = 16,
0025 }, {
0026 .fourcc = V4L2_PIX_FMT_YUYV,
0027 .codes = IMX_BUS_FMTS(
0028 MEDIA_BUS_FMT_YUYV8_2X8,
0029 MEDIA_BUS_FMT_YUYV8_1X16
0030 ),
0031 .cs = IPUV3_COLORSPACE_YUV,
0032 .bpp = 16,
0033 }, {
0034 .fourcc = V4L2_PIX_FMT_YUV420,
0035 .cs = IPUV3_COLORSPACE_YUV,
0036 .bpp = 12,
0037 .planar = true,
0038 }, {
0039 .fourcc = V4L2_PIX_FMT_YVU420,
0040 .cs = IPUV3_COLORSPACE_YUV,
0041 .bpp = 12,
0042 .planar = true,
0043 }, {
0044 .fourcc = V4L2_PIX_FMT_YUV422P,
0045 .cs = IPUV3_COLORSPACE_YUV,
0046 .bpp = 16,
0047 .planar = true,
0048 }, {
0049 .fourcc = V4L2_PIX_FMT_NV12,
0050 .cs = IPUV3_COLORSPACE_YUV,
0051 .bpp = 12,
0052 .planar = true,
0053 }, {
0054 .fourcc = V4L2_PIX_FMT_NV16,
0055 .cs = IPUV3_COLORSPACE_YUV,
0056 .bpp = 16,
0057 .planar = true,
0058 }, {
0059 .fourcc = V4L2_PIX_FMT_YUV32,
0060 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_AYUV8_1X32),
0061 .cs = IPUV3_COLORSPACE_YUV,
0062 .bpp = 32,
0063 .ipufmt = true,
0064 },
0065
0066 {
0067 .fourcc = V4L2_PIX_FMT_RGB565,
0068 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_RGB565_2X8_LE),
0069 .cs = IPUV3_COLORSPACE_RGB,
0070 .bpp = 16,
0071 .cycles = 2,
0072 }, {
0073 .fourcc = V4L2_PIX_FMT_RGB24,
0074 .codes = IMX_BUS_FMTS(
0075 MEDIA_BUS_FMT_RGB888_1X24,
0076 MEDIA_BUS_FMT_RGB888_2X12_LE
0077 ),
0078 .cs = IPUV3_COLORSPACE_RGB,
0079 .bpp = 24,
0080 }, {
0081 .fourcc = V4L2_PIX_FMT_BGR24,
0082 .cs = IPUV3_COLORSPACE_RGB,
0083 .bpp = 24,
0084 }, {
0085 .fourcc = V4L2_PIX_FMT_XRGB32,
0086 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_ARGB8888_1X32),
0087 .cs = IPUV3_COLORSPACE_RGB,
0088 .bpp = 32,
0089 }, {
0090 .fourcc = V4L2_PIX_FMT_XRGB32,
0091 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_ARGB8888_1X32),
0092 .cs = IPUV3_COLORSPACE_RGB,
0093 .bpp = 32,
0094 .ipufmt = true,
0095 }, {
0096 .fourcc = V4L2_PIX_FMT_XBGR32,
0097 .cs = IPUV3_COLORSPACE_RGB,
0098 .bpp = 32,
0099 }, {
0100 .fourcc = V4L2_PIX_FMT_BGRX32,
0101 .cs = IPUV3_COLORSPACE_RGB,
0102 .bpp = 32,
0103 }, {
0104 .fourcc = V4L2_PIX_FMT_RGBX32,
0105 .cs = IPUV3_COLORSPACE_RGB,
0106 .bpp = 32,
0107 },
0108
0109 {
0110 .fourcc = V4L2_PIX_FMT_SBGGR8,
0111 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SBGGR8_1X8),
0112 .cs = IPUV3_COLORSPACE_RGB,
0113 .bpp = 8,
0114 .bayer = true,
0115 }, {
0116 .fourcc = V4L2_PIX_FMT_SGBRG8,
0117 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGBRG8_1X8),
0118 .cs = IPUV3_COLORSPACE_RGB,
0119 .bpp = 8,
0120 .bayer = true,
0121 }, {
0122 .fourcc = V4L2_PIX_FMT_SGRBG8,
0123 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGRBG8_1X8),
0124 .cs = IPUV3_COLORSPACE_RGB,
0125 .bpp = 8,
0126 .bayer = true,
0127 }, {
0128 .fourcc = V4L2_PIX_FMT_SRGGB8,
0129 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SRGGB8_1X8),
0130 .cs = IPUV3_COLORSPACE_RGB,
0131 .bpp = 8,
0132 .bayer = true,
0133 }, {
0134 .fourcc = V4L2_PIX_FMT_SBGGR16,
0135 .codes = IMX_BUS_FMTS(
0136 MEDIA_BUS_FMT_SBGGR10_1X10,
0137 MEDIA_BUS_FMT_SBGGR12_1X12,
0138 MEDIA_BUS_FMT_SBGGR14_1X14,
0139 MEDIA_BUS_FMT_SBGGR16_1X16
0140 ),
0141 .cs = IPUV3_COLORSPACE_RGB,
0142 .bpp = 16,
0143 .bayer = true,
0144 }, {
0145 .fourcc = V4L2_PIX_FMT_SGBRG16,
0146 .codes = IMX_BUS_FMTS(
0147 MEDIA_BUS_FMT_SGBRG10_1X10,
0148 MEDIA_BUS_FMT_SGBRG12_1X12,
0149 MEDIA_BUS_FMT_SGBRG14_1X14,
0150 MEDIA_BUS_FMT_SGBRG16_1X16
0151 ),
0152 .cs = IPUV3_COLORSPACE_RGB,
0153 .bpp = 16,
0154 .bayer = true,
0155 }, {
0156 .fourcc = V4L2_PIX_FMT_SGRBG16,
0157 .codes = IMX_BUS_FMTS(
0158 MEDIA_BUS_FMT_SGRBG10_1X10,
0159 MEDIA_BUS_FMT_SGRBG12_1X12,
0160 MEDIA_BUS_FMT_SGRBG14_1X14,
0161 MEDIA_BUS_FMT_SGRBG16_1X16
0162 ),
0163 .cs = IPUV3_COLORSPACE_RGB,
0164 .bpp = 16,
0165 .bayer = true,
0166 }, {
0167 .fourcc = V4L2_PIX_FMT_SRGGB16,
0168 .codes = IMX_BUS_FMTS(
0169 MEDIA_BUS_FMT_SRGGB10_1X10,
0170 MEDIA_BUS_FMT_SRGGB12_1X12,
0171 MEDIA_BUS_FMT_SRGGB14_1X14,
0172 MEDIA_BUS_FMT_SRGGB16_1X16
0173 ),
0174 .cs = IPUV3_COLORSPACE_RGB,
0175 .bpp = 16,
0176 .bayer = true,
0177 }, {
0178 .fourcc = V4L2_PIX_FMT_GREY,
0179 .codes = IMX_BUS_FMTS(
0180 MEDIA_BUS_FMT_Y8_1X8,
0181 MEDIA_BUS_FMT_Y10_1X10,
0182 MEDIA_BUS_FMT_Y12_1X12
0183 ),
0184 .cs = IPUV3_COLORSPACE_RGB,
0185 .bpp = 8,
0186 .bayer = true,
0187 }, {
0188 .fourcc = V4L2_PIX_FMT_Y10,
0189 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y10_1X10),
0190 .cs = IPUV3_COLORSPACE_RGB,
0191 .bpp = 16,
0192 .bayer = true,
0193 }, {
0194 .fourcc = V4L2_PIX_FMT_Y12,
0195 .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y12_1X12),
0196 .cs = IPUV3_COLORSPACE_RGB,
0197 .bpp = 16,
0198 .bayer = true,
0199 },
0200 };
0201
0202
0203
0204
0205
0206
0207
0208
0209 const struct imx_media_pixfmt *
0210 imx_media_find_pixel_format(u32 fourcc, enum imx_pixfmt_sel fmt_sel)
0211 {
0212 bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
0213 unsigned int i;
0214
0215 fmt_sel &= ~PIXFMT_SEL_IPU;
0216
0217 for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
0218 const struct imx_media_pixfmt *fmt = &pixel_formats[i];
0219 enum imx_pixfmt_sel sel;
0220
0221 if (sel_ipu != fmt->ipufmt)
0222 continue;
0223
0224 sel = fmt->bayer ? PIXFMT_SEL_BAYER :
0225 ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
0226 PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
0227
0228 if ((fmt_sel & sel) && fmt->fourcc == fourcc)
0229 return fmt;
0230 }
0231
0232 return NULL;
0233 }
0234 EXPORT_SYMBOL_GPL(imx_media_find_pixel_format);
0235
0236
0237
0238
0239
0240
0241
0242
0243 const struct imx_media_pixfmt *
0244 imx_media_find_mbus_format(u32 code, enum imx_pixfmt_sel fmt_sel)
0245 {
0246 bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
0247 unsigned int i;
0248
0249 fmt_sel &= ~PIXFMT_SEL_IPU;
0250
0251 for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
0252 const struct imx_media_pixfmt *fmt = &pixel_formats[i];
0253 enum imx_pixfmt_sel sel;
0254 unsigned int j;
0255
0256 if (sel_ipu != fmt->ipufmt)
0257 continue;
0258
0259 sel = fmt->bayer ? PIXFMT_SEL_BAYER :
0260 ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
0261 PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
0262
0263 if (!(fmt_sel & sel) || !fmt->codes)
0264 continue;
0265
0266 for (j = 0; fmt->codes[j]; j++) {
0267 if (code == fmt->codes[j])
0268 return fmt;
0269 }
0270 }
0271
0272 return NULL;
0273 }
0274 EXPORT_SYMBOL_GPL(imx_media_find_mbus_format);
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289 int imx_media_enum_pixel_formats(u32 *fourcc, u32 index,
0290 enum imx_pixfmt_sel fmt_sel, u32 code)
0291 {
0292 bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
0293 unsigned int i;
0294
0295 fmt_sel &= ~PIXFMT_SEL_IPU;
0296
0297 for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
0298 const struct imx_media_pixfmt *fmt = &pixel_formats[i];
0299 enum imx_pixfmt_sel sel;
0300
0301 if (sel_ipu != fmt->ipufmt)
0302 continue;
0303
0304 sel = fmt->bayer ? PIXFMT_SEL_BAYER :
0305 ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
0306 PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
0307
0308 if (!(fmt_sel & sel))
0309 continue;
0310
0311
0312
0313
0314
0315 if (code) {
0316 unsigned int j;
0317
0318 if (!fmt->codes)
0319 continue;
0320
0321 for (j = 0; fmt->codes[j]; j++) {
0322 if (code == fmt->codes[j])
0323 break;
0324 }
0325
0326 if (!fmt->codes[j])
0327 continue;
0328 }
0329
0330 if (index == 0) {
0331 *fourcc = fmt->fourcc;
0332 return 0;
0333 }
0334
0335 index--;
0336 }
0337
0338 return -EINVAL;
0339 }
0340 EXPORT_SYMBOL_GPL(imx_media_enum_pixel_formats);
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353 int imx_media_enum_mbus_formats(u32 *code, u32 index,
0354 enum imx_pixfmt_sel fmt_sel)
0355 {
0356 bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
0357 unsigned int i;
0358
0359 fmt_sel &= ~PIXFMT_SEL_IPU;
0360
0361 for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
0362 const struct imx_media_pixfmt *fmt = &pixel_formats[i];
0363 enum imx_pixfmt_sel sel;
0364 unsigned int j;
0365
0366 if (sel_ipu != fmt->ipufmt)
0367 continue;
0368
0369 sel = fmt->bayer ? PIXFMT_SEL_BAYER :
0370 ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
0371 PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
0372
0373 if (!(fmt_sel & sel) || !fmt->codes)
0374 continue;
0375
0376 for (j = 0; fmt->codes[j]; j++) {
0377 if (index == 0) {
0378 *code = fmt->codes[j];
0379 return 0;
0380 }
0381
0382 index--;
0383 }
0384 }
0385
0386 return -EINVAL;
0387 }
0388 EXPORT_SYMBOL_GPL(imx_media_enum_mbus_formats);
0389
0390 int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
0391 u32 width, u32 height, u32 code, u32 field,
0392 const struct imx_media_pixfmt **cc)
0393 {
0394 const struct imx_media_pixfmt *lcc;
0395
0396 mbus->width = width;
0397 mbus->height = height;
0398 mbus->field = field;
0399
0400 if (code == 0)
0401 imx_media_enum_mbus_formats(&code, 0, PIXFMT_SEL_YUV);
0402
0403 lcc = imx_media_find_mbus_format(code, PIXFMT_SEL_ANY);
0404 if (!lcc) {
0405 lcc = imx_media_find_ipu_format(code, PIXFMT_SEL_YUV_RGB);
0406 if (!lcc)
0407 return -EINVAL;
0408 }
0409
0410 mbus->code = code;
0411
0412 mbus->colorspace = V4L2_COLORSPACE_SRGB;
0413 mbus->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mbus->colorspace);
0414 mbus->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mbus->colorspace);
0415 mbus->quantization =
0416 V4L2_MAP_QUANTIZATION_DEFAULT(lcc->cs == IPUV3_COLORSPACE_RGB,
0417 mbus->colorspace,
0418 mbus->ycbcr_enc);
0419
0420 if (cc)
0421 *cc = lcc;
0422
0423 return 0;
0424 }
0425 EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
0426
0427
0428
0429
0430
0431 int imx_media_init_cfg(struct v4l2_subdev *sd,
0432 struct v4l2_subdev_state *sd_state)
0433 {
0434 struct v4l2_mbus_framefmt *mf_try;
0435 struct v4l2_subdev_format format;
0436 unsigned int pad;
0437 int ret;
0438
0439 for (pad = 0; pad < sd->entity.num_pads; pad++) {
0440 memset(&format, 0, sizeof(format));
0441
0442 format.pad = pad;
0443 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
0444 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format);
0445 if (ret)
0446 continue;
0447
0448 mf_try = v4l2_subdev_get_try_format(sd, sd_state, pad);
0449 *mf_try = format.format;
0450 }
0451
0452 return 0;
0453 }
0454 EXPORT_SYMBOL_GPL(imx_media_init_cfg);
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467 void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt,
0468 bool ic_route)
0469 {
0470 const struct imx_media_pixfmt *cc;
0471 bool is_rgb = false;
0472
0473 cc = imx_media_find_mbus_format(tryfmt->code, PIXFMT_SEL_ANY);
0474 if (!cc)
0475 cc = imx_media_find_ipu_format(tryfmt->code,
0476 PIXFMT_SEL_YUV_RGB);
0477
0478 if (cc && cc->cs == IPUV3_COLORSPACE_RGB)
0479 is_rgb = true;
0480
0481 switch (tryfmt->colorspace) {
0482 case V4L2_COLORSPACE_SMPTE170M:
0483 case V4L2_COLORSPACE_REC709:
0484 case V4L2_COLORSPACE_JPEG:
0485 case V4L2_COLORSPACE_SRGB:
0486 case V4L2_COLORSPACE_BT2020:
0487 case V4L2_COLORSPACE_OPRGB:
0488 case V4L2_COLORSPACE_DCI_P3:
0489 case V4L2_COLORSPACE_RAW:
0490 break;
0491 default:
0492 tryfmt->colorspace = V4L2_COLORSPACE_SRGB;
0493 break;
0494 }
0495
0496 if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT)
0497 tryfmt->xfer_func =
0498 V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace);
0499
0500 if (ic_route) {
0501 if (tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_601 &&
0502 tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_709)
0503 tryfmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
0504 } else {
0505 if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
0506 tryfmt->ycbcr_enc =
0507 V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace);
0508 }
0509 }
0510
0511 if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT)
0512 tryfmt->quantization =
0513 V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb,
0514 tryfmt->colorspace,
0515 tryfmt->ycbcr_enc);
0516 }
0517 EXPORT_SYMBOL_GPL(imx_media_try_colorimetry);
0518
0519 int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
0520 const struct v4l2_mbus_framefmt *mbus,
0521 const struct imx_media_pixfmt *cc)
0522 {
0523 u32 width;
0524 u32 stride;
0525
0526 if (!cc) {
0527 cc = imx_media_find_ipu_format(mbus->code,
0528 PIXFMT_SEL_YUV_RGB);
0529 if (!cc)
0530 cc = imx_media_find_mbus_format(mbus->code,
0531 PIXFMT_SEL_ANY);
0532 if (!cc)
0533 return -EINVAL;
0534 }
0535
0536
0537
0538
0539
0540 if (cc->ipufmt && cc->cs == IPUV3_COLORSPACE_YUV) {
0541 u32 code;
0542
0543 imx_media_enum_mbus_formats(&code, 0, PIXFMT_SEL_YUV);
0544 cc = imx_media_find_mbus_format(code, PIXFMT_SEL_YUV);
0545 }
0546
0547
0548 width = round_up(mbus->width, 8);
0549
0550
0551 if (cc->planar)
0552 stride = round_up(width, 16);
0553 else
0554 stride = round_up((width * cc->bpp) >> 3, 8);
0555
0556 pix->width = width;
0557 pix->height = mbus->height;
0558 pix->pixelformat = cc->fourcc;
0559 pix->colorspace = mbus->colorspace;
0560 pix->xfer_func = mbus->xfer_func;
0561 pix->ycbcr_enc = mbus->ycbcr_enc;
0562 pix->quantization = mbus->quantization;
0563 pix->field = mbus->field;
0564 pix->bytesperline = stride;
0565 pix->sizeimage = cc->planar ? ((stride * pix->height * cc->bpp) >> 3) :
0566 stride * pix->height;
0567
0568 return 0;
0569 }
0570 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt);
0571
0572 void imx_media_free_dma_buf(struct device *dev,
0573 struct imx_media_dma_buf *buf)
0574 {
0575 if (buf->virt)
0576 dma_free_coherent(dev, buf->len, buf->virt, buf->phys);
0577
0578 buf->virt = NULL;
0579 buf->phys = 0;
0580 }
0581 EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
0582
0583 int imx_media_alloc_dma_buf(struct device *dev,
0584 struct imx_media_dma_buf *buf,
0585 int size)
0586 {
0587 imx_media_free_dma_buf(dev, buf);
0588
0589 buf->len = PAGE_ALIGN(size);
0590 buf->virt = dma_alloc_coherent(dev, buf->len, &buf->phys,
0591 GFP_DMA | GFP_KERNEL);
0592 if (!buf->virt) {
0593 dev_err(dev, "%s: failed\n", __func__);
0594 return -ENOMEM;
0595 }
0596
0597 return 0;
0598 }
0599 EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf);
0600
0601
0602 void imx_media_grp_id_to_sd_name(char *sd_name, int sz, u32 grp_id, int ipu_id)
0603 {
0604 int id;
0605
0606 switch (grp_id) {
0607 case IMX_MEDIA_GRP_ID_IPU_CSI0...IMX_MEDIA_GRP_ID_IPU_CSI1:
0608 id = (grp_id >> IMX_MEDIA_GRP_ID_IPU_CSI_BIT) - 1;
0609 snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id);
0610 break;
0611 case IMX_MEDIA_GRP_ID_IPU_VDIC:
0612 snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1);
0613 break;
0614 case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
0615 snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1);
0616 break;
0617 case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
0618 snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1);
0619 break;
0620 case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
0621 snprintf(sd_name, sz, "ipu%d_ic_prpvf", ipu_id + 1);
0622 break;
0623 default:
0624 break;
0625 }
0626 }
0627 EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name);
0628
0629 struct v4l2_subdev *
0630 imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd,
0631 struct fwnode_handle *fwnode)
0632 {
0633 struct v4l2_subdev *sd;
0634
0635 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
0636 if (sd->fwnode == fwnode)
0637 return sd;
0638 }
0639
0640 return NULL;
0641 }
0642 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode);
0643
0644 struct v4l2_subdev *
0645 imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd,
0646 const char *devname)
0647 {
0648 struct v4l2_subdev *sd;
0649
0650 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
0651 if (!strcmp(devname, dev_name(sd->dev)))
0652 return sd;
0653 }
0654
0655 return NULL;
0656 }
0657 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname);
0658
0659
0660
0661
0662
0663 void imx_media_add_video_device(struct imx_media_dev *imxmd,
0664 struct imx_media_video_dev *vdev)
0665 {
0666 mutex_lock(&imxmd->mutex);
0667
0668 list_add_tail(&vdev->list, &imxmd->vdev_list);
0669
0670 mutex_unlock(&imxmd->mutex);
0671 }
0672 EXPORT_SYMBOL_GPL(imx_media_add_video_device);
0673
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684 struct media_pad *
0685 imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id,
0686 enum v4l2_buf_type buftype, bool upstream)
0687 {
0688 struct media_entity *me = start_entity;
0689 struct media_pad *pad = NULL;
0690 struct video_device *vfd;
0691 struct v4l2_subdev *sd;
0692 int i;
0693
0694 for (i = 0; i < me->num_pads; i++) {
0695 struct media_pad *spad = &me->pads[i];
0696
0697 if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) ||
0698 (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE)))
0699 continue;
0700
0701 pad = media_pad_remote_pad_first(spad);
0702 if (!pad)
0703 continue;
0704
0705 if (grp_id) {
0706 if (is_media_entity_v4l2_subdev(pad->entity)) {
0707 sd = media_entity_to_v4l2_subdev(pad->entity);
0708 if (sd->grp_id & grp_id)
0709 return pad;
0710 }
0711
0712 return imx_media_pipeline_pad(pad->entity, grp_id,
0713 buftype, upstream);
0714 } else if (buftype) {
0715 if (is_media_entity_v4l2_video_device(pad->entity)) {
0716 vfd = media_entity_to_video_device(pad->entity);
0717 if (buftype == vfd->queue->type)
0718 return pad;
0719 }
0720
0721 return imx_media_pipeline_pad(pad->entity, grp_id,
0722 buftype, upstream);
0723 } else {
0724 return pad;
0725 }
0726 }
0727
0728 return NULL;
0729 }
0730 EXPORT_SYMBOL_GPL(imx_media_pipeline_pad);
0731
0732
0733
0734
0735
0736 static struct media_entity *
0737 find_pipeline_entity(struct media_entity *start, u32 grp_id,
0738 enum v4l2_buf_type buftype, bool upstream)
0739 {
0740 struct media_pad *pad = NULL;
0741 struct video_device *vfd;
0742 struct v4l2_subdev *sd;
0743
0744 if (grp_id && is_media_entity_v4l2_subdev(start)) {
0745 sd = media_entity_to_v4l2_subdev(start);
0746 if (sd->grp_id & grp_id)
0747 return &sd->entity;
0748 } else if (buftype && is_media_entity_v4l2_video_device(start)) {
0749 vfd = media_entity_to_video_device(start);
0750 if (buftype == vfd->queue->type)
0751 return &vfd->entity;
0752 }
0753
0754 pad = imx_media_pipeline_pad(start, grp_id, buftype, upstream);
0755
0756 return pad ? pad->entity : NULL;
0757 }
0758
0759
0760
0761
0762
0763
0764 int imx_media_pipeline_csi2_channel(struct media_entity *start_entity)
0765 {
0766 struct media_pad *pad;
0767 int ret = -EPIPE;
0768
0769 pad = imx_media_pipeline_pad(start_entity, IMX_MEDIA_GRP_ID_CSI2,
0770 0, true);
0771 if (pad)
0772 ret = pad->index - 1;
0773
0774 return ret;
0775 }
0776 EXPORT_SYMBOL_GPL(imx_media_pipeline_csi2_channel);
0777
0778
0779
0780
0781
0782
0783 struct v4l2_subdev *
0784 imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id,
0785 bool upstream)
0786 {
0787 struct media_entity *me;
0788
0789 me = find_pipeline_entity(start_entity, grp_id, 0, upstream);
0790 if (!me)
0791 return ERR_PTR(-ENODEV);
0792
0793 return media_entity_to_v4l2_subdev(me);
0794 }
0795 EXPORT_SYMBOL_GPL(imx_media_pipeline_subdev);
0796
0797
0798
0799
0800
0801
0802 struct video_device *
0803 imx_media_pipeline_video_device(struct media_entity *start_entity,
0804 enum v4l2_buf_type buftype, bool upstream)
0805 {
0806 struct media_entity *me;
0807
0808 me = find_pipeline_entity(start_entity, 0, buftype, upstream);
0809 if (!me)
0810 return ERR_PTR(-ENODEV);
0811
0812 return media_entity_to_video_device(me);
0813 }
0814 EXPORT_SYMBOL_GPL(imx_media_pipeline_video_device);
0815
0816
0817
0818
0819
0820
0821
0822
0823
0824 struct fwnode_handle *imx_media_get_pad_fwnode(struct media_pad *pad)
0825 {
0826 struct fwnode_handle *endpoint;
0827 struct v4l2_subdev *sd;
0828
0829 if (!is_media_entity_v4l2_subdev(pad->entity))
0830 return ERR_PTR(-ENODEV);
0831
0832 sd = media_entity_to_v4l2_subdev(pad->entity);
0833
0834 fwnode_graph_for_each_endpoint(dev_fwnode(sd->dev), endpoint) {
0835 int pad_idx = media_entity_get_fwnode_pad(&sd->entity,
0836 endpoint,
0837 pad->flags);
0838 if (pad_idx < 0)
0839 continue;
0840
0841 if (pad_idx == pad->index)
0842 return endpoint;
0843 }
0844
0845 return ERR_PTR(-ENODEV);
0846 }
0847 EXPORT_SYMBOL_GPL(imx_media_get_pad_fwnode);
0848
0849
0850
0851
0852 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
0853 struct media_entity *entity,
0854 bool on)
0855 {
0856 struct v4l2_subdev *sd;
0857 int ret = 0;
0858
0859 if (!is_media_entity_v4l2_subdev(entity))
0860 return -EINVAL;
0861 sd = media_entity_to_v4l2_subdev(entity);
0862
0863 mutex_lock(&imxmd->md.graph_mutex);
0864
0865 if (on) {
0866 ret = __media_pipeline_start(entity, &imxmd->pipe);
0867 if (ret)
0868 goto out;
0869 ret = v4l2_subdev_call(sd, video, s_stream, 1);
0870 if (ret)
0871 __media_pipeline_stop(entity);
0872 } else {
0873 v4l2_subdev_call(sd, video, s_stream, 0);
0874 if (entity->pipe)
0875 __media_pipeline_stop(entity);
0876 }
0877
0878 out:
0879 mutex_unlock(&imxmd->md.graph_mutex);
0880 return ret;
0881 }
0882 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
0883
0884 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
0885 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
0886 MODULE_LICENSE("GPL");