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_state internal operation. 430 */ 431int imx_media_init_state(struct v4l2_subdev *sd, 432 struct v4l2_subdev_state *sd_state) 433{ 434 struct v4l2_mbus_framefmt *mf_try; 435 unsigned int pad; 436 int ret; 437 438 for (pad = 0; pad < sd->entity.num_pads; pad++) { 439 struct v4l2_subdev_format format = { 440 .pad = pad, 441 .which = V4L2_SUBDEV_FORMAT_ACTIVE, 442 }; 443 444 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format); 445 if (ret) 446 continue; 447 448 mf_try = v4l2_subdev_state_get_format(sd_state, pad); 449 *mf_try = format.format; 450 } 451 452 return 0; 453} 454EXPORT_SYMBOL_GPL(imx_media_init_state); 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 629/* 630 * Adds a video device to the master video device list. This is called 631 * when a video device is registered. 632 */ 633void imx_media_add_video_device(struct imx_media_dev *imxmd, 634 struct imx_media_video_dev *vdev) 635{ 636 mutex_lock(&imxmd->mutex); 637 638 list_add_tail(&vdev->list, &imxmd->vdev_list); 639 640 mutex_unlock(&imxmd->mutex); 641} 642EXPORT_SYMBOL_GPL(imx_media_add_video_device); 643 644/* 645 * Search upstream/downstream for a subdevice or video device pad in the 646 * current pipeline, starting from start_entity. Returns the device's 647 * source/sink pad that it was reached from. Must be called with 648 * mdev->graph_mutex held. 649 * 650 * If grp_id != 0, finds a subdevice's pad of given grp_id. 651 * Else If buftype != 0, finds a video device's pad of given buffer type. 652 * Else, returns the nearest source/sink pad to start_entity. 653 */ 654struct media_pad * 655imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id, 656 enum v4l2_buf_type buftype, bool upstream) 657{ 658 struct media_entity *me = start_entity; 659 struct media_pad *pad = NULL; 660 struct video_device *vfd; 661 struct v4l2_subdev *sd; 662 int i; 663 664 for (i = 0; i < me->num_pads; i++) { 665 struct media_pad *spad = &me->pads[i]; 666 667 if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) || 668 (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE))) 669 continue; 670 671 pad = media_pad_remote_pad_first(spad); 672 if (!pad) 673 continue; 674 675 if (grp_id) { 676 if (is_media_entity_v4l2_subdev(pad->entity)) { 677 sd = media_entity_to_v4l2_subdev(pad->entity); 678 if (sd->grp_id & grp_id) 679 return pad; 680 } 681 682 return imx_media_pipeline_pad(pad->entity, grp_id, 683 buftype, upstream); 684 } else if (buftype) { 685 if (is_media_entity_v4l2_video_device(pad->entity)) { 686 vfd = media_entity_to_video_device(pad->entity); 687 if (buftype == vfd->queue->type) 688 return pad; 689 } 690 691 return imx_media_pipeline_pad(pad->entity, grp_id, 692 buftype, upstream); 693 } else { 694 return pad; 695 } 696 } 697 698 return NULL; 699} 700EXPORT_SYMBOL_GPL(imx_media_pipeline_pad); 701 702/* 703 * Search upstream/downstream for a subdev or video device in the current 704 * pipeline. Must be called with mdev->graph_mutex held. 705 */ 706static struct media_entity * 707find_pipeline_entity(struct media_entity *start, u32 grp_id, 708 enum v4l2_buf_type buftype, bool upstream) 709{ 710 struct media_pad *pad = NULL; 711 struct video_device *vfd; 712 struct v4l2_subdev *sd; 713 714 if (grp_id && is_media_entity_v4l2_subdev(start)) { 715 sd = media_entity_to_v4l2_subdev(start); 716 if (sd->grp_id & grp_id) 717 return &sd->entity; 718 } else if (buftype && is_media_entity_v4l2_video_device(start)) { 719 vfd = media_entity_to_video_device(start); 720 if (buftype == vfd->queue->type) 721 return &vfd->entity; 722 } 723 724 pad = imx_media_pipeline_pad(start, grp_id, buftype, upstream); 725 726 return pad ? pad->entity : NULL; 727} 728 729/* 730 * Find a subdev reached upstream from the given start entity in 731 * the current pipeline. 732 * Must be called with mdev->graph_mutex held. 733 */ 734struct v4l2_subdev * 735imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id, 736 bool upstream) 737{ 738 struct media_entity *me; 739 740 me = find_pipeline_entity(start_entity, grp_id, 0, upstream); 741 if (!me) 742 return ERR_PTR(-ENODEV); 743 744 return media_entity_to_v4l2_subdev(me); 745} 746EXPORT_SYMBOL_GPL(imx_media_pipeline_subdev); 747 748/* 749 * Turn current pipeline streaming on/off starting from entity. 750 */ 751int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd, 752 struct media_entity *entity, 753 bool on) 754{ 755 struct v4l2_subdev *sd; 756 int ret = 0; 757 758 if (!is_media_entity_v4l2_subdev(entity)) 759 return -EINVAL; 760 sd = media_entity_to_v4l2_subdev(entity); 761 762 mutex_lock(&imxmd->md.graph_mutex); 763 764 if (on) { 765 ret = __media_pipeline_start(entity->pads, &imxmd->pipe); 766 if (ret) 767 goto out; 768 ret = v4l2_subdev_call(sd, video, s_stream, 1); 769 if (ret) 770 __media_pipeline_stop(entity->pads); 771 } else { 772 v4l2_subdev_call(sd, video, s_stream, 0); 773 if (media_pad_pipeline(entity->pads)) 774 __media_pipeline_stop(entity->pads); 775 } 776 777out: 778 mutex_unlock(&imxmd->md.graph_mutex); 779 return ret; 780} 781EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream); 782 783MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver"); 784MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>"); 785MODULE_LICENSE("GPL"); 786