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 */ 15 static 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 */ 209 const struct imx_media_pixfmt * 210 imx_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 } 234 EXPORT_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 */ 243 const struct imx_media_pixfmt * 244 imx_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 } 274 EXPORT_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 */ 289 int 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 } 340 EXPORT_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 */ 353 int 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 } 388 EXPORT_SYMBOL_GPL(imx_media_enum_mbus_formats); 389 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) 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 } 425 EXPORT_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 */ 431 int imx_media_init_cfg(struct v4l2_subdev *sd, 432 struct v4l2_subdev_pad_config *cfg) 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, cfg, pad); 449 *mf_try = format.format; 450 } 451 452 return 0; 453 } 454 EXPORT_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 */ 467 void 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 } 517 EXPORT_SYMBOL_GPL(imx_media_try_colorimetry); 518 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) 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 } 570 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt); 571 572 int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image, 573 const struct v4l2_mbus_framefmt *mbus) 574 { 575 int ret; 576 577 memset(image, 0, sizeof(*image)); 578 579 ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, mbus, NULL); 580 if (ret) 581 return ret; 582 583 image->rect.width = mbus->width; 584 image->rect.height = mbus->height; 585 586 return 0; 587 } 588 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image); 589 590 int imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt *mbus, 591 const struct ipu_image *image) 592 { 593 const struct imx_media_pixfmt *fmt; 594 595 fmt = imx_media_find_pixel_format(image->pix.pixelformat, 596 PIXFMT_SEL_ANY); 597 if (!fmt || !fmt->codes || !fmt->codes[0]) 598 return -EINVAL; 599 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; 609 610 return 0; 611 } 612 EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt); 613 614 void imx_media_free_dma_buf(struct device *dev, 615 struct imx_media_dma_buf *buf) 616 { 617 if (buf->virt) 618 dma_free_coherent(dev, buf->len, buf->virt, buf->phys); 619 620 buf->virt = NULL; 621 buf->phys = 0; 622 } 623 EXPORT_SYMBOL_GPL(imx_media_free_dma_buf); 624 625 int imx_media_alloc_dma_buf(struct device *dev, 626 struct imx_media_dma_buf *buf, 627 int size) 628 { 629 imx_media_free_dma_buf(dev, buf); 630 631 buf->len = PAGE_ALIGN(size); 632 buf->virt = dma_alloc_coherent(dev, buf->len, &buf->phys, 633 GFP_DMA | GFP_KERNEL); 634 if (!buf->virt) { 635 dev_err(dev, "%s: failed\n", __func__); 636 return -ENOMEM; 637 } 638 639 return 0; 640 } 641 EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf); 642 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) 645 { 646 int id; 647 648 switch (grp_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); 652 break; 653 case IMX_MEDIA_GRP_ID_IPU_VDIC: 654 snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1); 655 break; 656 case IMX_MEDIA_GRP_ID_IPU_IC_PRP: 657 snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1); 658 break; 659 case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC: 660 snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1); 661 break; 662 case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF: 663 snprintf(sd_name, sz, "ipu%d_ic_prpvf", ipu_id + 1); 664 break; 665 default: 666 break; 667 } 668 } 669 EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name); 670 671 struct v4l2_subdev * 672 imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd, 673 struct fwnode_handle *fwnode) 674 { 675 struct v4l2_subdev *sd; 676 677 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) { 678 if (sd->fwnode == fwnode) 679 return sd; 680 } 681 682 return NULL; 683 } 684 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode); 685 686 struct v4l2_subdev * 687 imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd, 688 const char *devname) 689 { 690 struct v4l2_subdev *sd; 691 692 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) { 693 if (!strcmp(devname, dev_name(sd->dev))) 694 return sd; 695 } 696 697 return NULL; 698 } 699 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname); 700 701 /* 702 * Adds a video device to the master video device list. This is called 703 * when a video device is registered. 704 */ 705 void imx_media_add_video_device(struct imx_media_dev *imxmd, 706 struct imx_media_video_dev *vdev) 707 { 708 mutex_lock(&imxmd->mutex); 709 710 list_add_tail(&vdev->list, &imxmd->vdev_list); 711 712 mutex_unlock(&imxmd->mutex); 713 } 714 EXPORT_SYMBOL_GPL(imx_media_add_video_device); 715 716 /* 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. 721 * 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. 725 */ 726 struct media_pad * 727 imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id, 728 enum v4l2_buf_type buftype, bool upstream) 729 { 730 struct media_entity *me = start_entity; 731 struct media_pad *pad = NULL; 732 struct video_device *vfd; 733 struct v4l2_subdev *sd; 734 int i; 735 736 for (i = 0; i < me->num_pads; i++) { 737 struct media_pad *spad = &me->pads[i]; 738 739 if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) || 740 (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE))) 741 continue; 742 743 pad = media_entity_remote_pad(spad); 744 if (!pad) 745 continue; 746 747 if (grp_id) { 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) 751 return pad; 752 } 753 754 return imx_media_pipeline_pad(pad->entity, grp_id, 755 buftype, upstream); 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) 760 return pad; 761 } 762 763 return imx_media_pipeline_pad(pad->entity, grp_id, 764 buftype, upstream); 765 } else { 766 return pad; 767 } 768 } 769 770 return NULL; 771 } 772 EXPORT_SYMBOL_GPL(imx_media_pipeline_pad); 773 774 /* 775 * Search upstream/downstream for a subdev or video device in the current 776 * pipeline. Must be called with mdev->graph_mutex held. 777 */ 778 static struct media_entity * 779 find_pipeline_entity(struct media_entity *start, u32 grp_id, 780 enum v4l2_buf_type buftype, bool upstream) 781 { 782 struct media_pad *pad = NULL; 783 struct video_device *vfd; 784 struct v4l2_subdev *sd; 785 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) 789 return &sd->entity; 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) 793 return &vfd->entity; 794 } 795 796 pad = imx_media_pipeline_pad(start, grp_id, buftype, upstream); 797 798 return pad ? pad->entity : NULL; 799 } 800 801 /* 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. 805 */ 806 int imx_media_pipeline_csi2_channel(struct media_entity *start_entity) 807 { 808 struct media_pad *pad; 809 int ret = -EPIPE; 810 811 pad = imx_media_pipeline_pad(start_entity, IMX_MEDIA_GRP_ID_CSI2, 812 0, true); 813 if (pad) 814 ret = pad->index - 1; 815 816 return ret; 817 } 818 EXPORT_SYMBOL_GPL(imx_media_pipeline_csi2_channel); 819 820 /* 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. 824 */ 825 struct v4l2_subdev * 826 imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id, 827 bool upstream) 828 { 829 struct media_entity *me; 830 831 me = find_pipeline_entity(start_entity, grp_id, 0, upstream); 832 if (!me) 833 return ERR_PTR(-ENODEV); 834 835 return media_entity_to_v4l2_subdev(me); 836 } 837 EXPORT_SYMBOL_GPL(imx_media_pipeline_subdev); 838 839 /* 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. 843 */ 844 struct video_device * 845 imx_media_pipeline_video_device(struct media_entity *start_entity, 846 enum v4l2_buf_type buftype, bool upstream) 847 { 848 struct media_entity *me; 849 850 me = find_pipeline_entity(start_entity, 0, buftype, upstream); 851 if (!me) 852 return ERR_PTR(-ENODEV); 853 854 return media_entity_to_video_device(me); 855 } 856 EXPORT_SYMBOL_GPL(imx_media_pipeline_video_device); 857 858 /* 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. 862 * 863 * On success the refcount of the returned fwnode endpoint is 864 * incremented. 865 */ 866 struct fwnode_handle *imx_media_get_pad_fwnode(struct media_pad *pad) 867 { 868 struct fwnode_handle *endpoint; 869 struct v4l2_subdev *sd; 870 871 if (!is_media_entity_v4l2_subdev(pad->entity)) 872 return ERR_PTR(-ENODEV); 873 874 sd = media_entity_to_v4l2_subdev(pad->entity); 875 876 fwnode_graph_for_each_endpoint(dev_fwnode(sd->dev), endpoint) { 877 int pad_idx = media_entity_get_fwnode_pad(&sd->entity, 878 endpoint, 879 pad->flags); 880 if (pad_idx < 0) 881 continue; 882 883 if (pad_idx == pad->index) 884 return endpoint; 885 } 886 887 return ERR_PTR(-ENODEV); 888 } 889 EXPORT_SYMBOL_GPL(imx_media_get_pad_fwnode); 890 891 /* 892 * Turn current pipeline streaming on/off starting from entity. 893 */ 894 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd, 895 struct media_entity *entity, 896 bool on) 897 { 898 struct v4l2_subdev *sd; 899 int ret = 0; 900 901 if (!is_media_entity_v4l2_subdev(entity)) 902 return -EINVAL; 903 sd = media_entity_to_v4l2_subdev(entity); 904 905 mutex_lock(&imxmd->md.graph_mutex); 906 907 if (on) { 908 ret = __media_pipeline_start(entity, &imxmd->pipe); 909 if (ret) 910 goto out; 911 ret = v4l2_subdev_call(sd, video, s_stream, 1); 912 if (ret) 913 __media_pipeline_stop(entity); 914 } else { 915 v4l2_subdev_call(sd, video, s_stream, 0); 916 if (entity->pipe) 917 __media_pipeline_stop(entity); 918 } 919 920 out: 921 mutex_unlock(&imxmd->md.graph_mutex); 922 return ret; 923 } 924 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream); 925 926 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver"); 927 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>"); 928 MODULE_LICENSE("GPL"); 929