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");