1 /* 2 * V4L2 Media Controller Driver for Freescale i.MX5/6 SOC 3 * 4 * Copyright (c) 2016 Mentor Graphics Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 */ 11 #include <linux/module.h> 12 #include "imx-media.h" 13 14 /* 15 * List of supported pixel formats for the subdevs. 16 * 17 * In all of these tables, the non-mbus formats (with no 18 * mbus codes) must all fall at the end of the table. 19 */ 20 21 static const struct imx_media_pixfmt yuv_formats[] = { 22 { 23 .fourcc = V4L2_PIX_FMT_UYVY, 24 .codes = { 25 MEDIA_BUS_FMT_UYVY8_2X8, 26 MEDIA_BUS_FMT_UYVY8_1X16 27 }, 28 .cs = IPUV3_COLORSPACE_YUV, 29 .bpp = 16, 30 }, { 31 .fourcc = V4L2_PIX_FMT_YUYV, 32 .codes = { 33 MEDIA_BUS_FMT_YUYV8_2X8, 34 MEDIA_BUS_FMT_YUYV8_1X16 35 }, 36 .cs = IPUV3_COLORSPACE_YUV, 37 .bpp = 16, 38 }, 39 /*** 40 * non-mbus YUV formats start here. NOTE! when adding non-mbus 41 * formats, NUM_NON_MBUS_YUV_FORMATS must be updated below. 42 ***/ 43 { 44 .fourcc = V4L2_PIX_FMT_YUV420, 45 .cs = IPUV3_COLORSPACE_YUV, 46 .bpp = 12, 47 .planar = true, 48 }, { 49 .fourcc = V4L2_PIX_FMT_YVU420, 50 .cs = IPUV3_COLORSPACE_YUV, 51 .bpp = 12, 52 .planar = true, 53 }, { 54 .fourcc = V4L2_PIX_FMT_YUV422P, 55 .cs = IPUV3_COLORSPACE_YUV, 56 .bpp = 16, 57 .planar = true, 58 }, { 59 .fourcc = V4L2_PIX_FMT_NV12, 60 .cs = IPUV3_COLORSPACE_YUV, 61 .bpp = 12, 62 .planar = true, 63 }, { 64 .fourcc = V4L2_PIX_FMT_NV16, 65 .cs = IPUV3_COLORSPACE_YUV, 66 .bpp = 16, 67 .planar = true, 68 }, 69 }; 70 71 #define NUM_NON_MBUS_YUV_FORMATS 5 72 #define NUM_YUV_FORMATS ARRAY_SIZE(yuv_formats) 73 #define NUM_MBUS_YUV_FORMATS (NUM_YUV_FORMATS - NUM_NON_MBUS_YUV_FORMATS) 74 75 static const struct imx_media_pixfmt rgb_formats[] = { 76 { 77 .fourcc = V4L2_PIX_FMT_RGB565, 78 .codes = {MEDIA_BUS_FMT_RGB565_2X8_LE}, 79 .cs = IPUV3_COLORSPACE_RGB, 80 .bpp = 16, 81 }, { 82 .fourcc = V4L2_PIX_FMT_RGB24, 83 .codes = { 84 MEDIA_BUS_FMT_RGB888_1X24, 85 MEDIA_BUS_FMT_RGB888_2X12_LE 86 }, 87 .cs = IPUV3_COLORSPACE_RGB, 88 .bpp = 24, 89 }, { 90 .fourcc = V4L2_PIX_FMT_RGB32, 91 .codes = {MEDIA_BUS_FMT_ARGB8888_1X32}, 92 .cs = IPUV3_COLORSPACE_RGB, 93 .bpp = 32, 94 .ipufmt = true, 95 }, 96 /*** raw bayer formats start here ***/ 97 { 98 .fourcc = V4L2_PIX_FMT_SBGGR8, 99 .codes = {MEDIA_BUS_FMT_SBGGR8_1X8}, 100 .cs = IPUV3_COLORSPACE_RGB, 101 .bpp = 8, 102 .bayer = true, 103 }, { 104 .fourcc = V4L2_PIX_FMT_SGBRG8, 105 .codes = {MEDIA_BUS_FMT_SGBRG8_1X8}, 106 .cs = IPUV3_COLORSPACE_RGB, 107 .bpp = 8, 108 .bayer = true, 109 }, { 110 .fourcc = V4L2_PIX_FMT_SGRBG8, 111 .codes = {MEDIA_BUS_FMT_SGRBG8_1X8}, 112 .cs = IPUV3_COLORSPACE_RGB, 113 .bpp = 8, 114 .bayer = true, 115 }, { 116 .fourcc = V4L2_PIX_FMT_SRGGB8, 117 .codes = {MEDIA_BUS_FMT_SRGGB8_1X8}, 118 .cs = IPUV3_COLORSPACE_RGB, 119 .bpp = 8, 120 .bayer = true, 121 }, { 122 .fourcc = V4L2_PIX_FMT_SBGGR16, 123 .codes = { 124 MEDIA_BUS_FMT_SBGGR10_1X10, 125 MEDIA_BUS_FMT_SBGGR12_1X12, 126 MEDIA_BUS_FMT_SBGGR14_1X14, 127 MEDIA_BUS_FMT_SBGGR16_1X16 128 }, 129 .cs = IPUV3_COLORSPACE_RGB, 130 .bpp = 16, 131 .bayer = true, 132 }, { 133 .fourcc = V4L2_PIX_FMT_SGBRG16, 134 .codes = { 135 MEDIA_BUS_FMT_SGBRG10_1X10, 136 MEDIA_BUS_FMT_SGBRG12_1X12, 137 MEDIA_BUS_FMT_SGBRG14_1X14, 138 MEDIA_BUS_FMT_SGBRG16_1X16, 139 }, 140 .cs = IPUV3_COLORSPACE_RGB, 141 .bpp = 16, 142 .bayer = true, 143 }, { 144 .fourcc = V4L2_PIX_FMT_SGRBG16, 145 .codes = { 146 MEDIA_BUS_FMT_SGRBG10_1X10, 147 MEDIA_BUS_FMT_SGRBG12_1X12, 148 MEDIA_BUS_FMT_SGRBG14_1X14, 149 MEDIA_BUS_FMT_SGRBG16_1X16, 150 }, 151 .cs = IPUV3_COLORSPACE_RGB, 152 .bpp = 16, 153 .bayer = true, 154 }, { 155 .fourcc = V4L2_PIX_FMT_SRGGB16, 156 .codes = { 157 MEDIA_BUS_FMT_SRGGB10_1X10, 158 MEDIA_BUS_FMT_SRGGB12_1X12, 159 MEDIA_BUS_FMT_SRGGB14_1X14, 160 MEDIA_BUS_FMT_SRGGB16_1X16, 161 }, 162 .cs = IPUV3_COLORSPACE_RGB, 163 .bpp = 16, 164 .bayer = true, 165 }, 166 /*** 167 * non-mbus RGB formats start here. NOTE! when adding non-mbus 168 * formats, NUM_NON_MBUS_RGB_FORMATS must be updated below. 169 ***/ 170 { 171 .fourcc = V4L2_PIX_FMT_BGR24, 172 .cs = IPUV3_COLORSPACE_RGB, 173 .bpp = 24, 174 }, { 175 .fourcc = V4L2_PIX_FMT_BGR32, 176 .cs = IPUV3_COLORSPACE_RGB, 177 .bpp = 32, 178 }, 179 }; 180 181 #define NUM_NON_MBUS_RGB_FORMATS 2 182 #define NUM_RGB_FORMATS ARRAY_SIZE(rgb_formats) 183 #define NUM_MBUS_RGB_FORMATS (NUM_RGB_FORMATS - NUM_NON_MBUS_RGB_FORMATS) 184 185 static const struct imx_media_pixfmt ipu_yuv_formats[] = { 186 { 187 .fourcc = V4L2_PIX_FMT_YUV32, 188 .codes = {MEDIA_BUS_FMT_AYUV8_1X32}, 189 .cs = IPUV3_COLORSPACE_YUV, 190 .bpp = 32, 191 .ipufmt = true, 192 }, 193 }; 194 195 #define NUM_IPU_YUV_FORMATS ARRAY_SIZE(ipu_yuv_formats) 196 197 static const struct imx_media_pixfmt ipu_rgb_formats[] = { 198 { 199 .fourcc = V4L2_PIX_FMT_RGB32, 200 .codes = {MEDIA_BUS_FMT_ARGB8888_1X32}, 201 .cs = IPUV3_COLORSPACE_RGB, 202 .bpp = 32, 203 .ipufmt = true, 204 }, 205 }; 206 207 #define NUM_IPU_RGB_FORMATS ARRAY_SIZE(ipu_rgb_formats) 208 209 static void init_mbus_colorimetry(struct v4l2_mbus_framefmt *mbus, 210 const struct imx_media_pixfmt *fmt) 211 { 212 mbus->colorspace = (fmt->cs == IPUV3_COLORSPACE_RGB) ? 213 V4L2_COLORSPACE_SRGB : V4L2_COLORSPACE_SMPTE170M; 214 mbus->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mbus->colorspace); 215 mbus->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mbus->colorspace); 216 mbus->quantization = 217 V4L2_MAP_QUANTIZATION_DEFAULT(fmt->cs == IPUV3_COLORSPACE_RGB, 218 mbus->colorspace, 219 mbus->ycbcr_enc); 220 } 221 222 static const struct imx_media_pixfmt *find_format(u32 fourcc, 223 u32 code, 224 enum codespace_sel cs_sel, 225 bool allow_non_mbus, 226 bool allow_bayer) 227 { 228 const struct imx_media_pixfmt *array, *fmt, *ret = NULL; 229 u32 array_size; 230 int i, j; 231 232 switch (cs_sel) { 233 case CS_SEL_YUV: 234 array_size = NUM_YUV_FORMATS; 235 array = yuv_formats; 236 break; 237 case CS_SEL_RGB: 238 array_size = NUM_RGB_FORMATS; 239 array = rgb_formats; 240 break; 241 case CS_SEL_ANY: 242 array_size = NUM_YUV_FORMATS + NUM_RGB_FORMATS; 243 array = yuv_formats; 244 break; 245 default: 246 return NULL; 247 } 248 249 for (i = 0; i < array_size; i++) { 250 if (cs_sel == CS_SEL_ANY && i >= NUM_YUV_FORMATS) 251 fmt = &rgb_formats[i - NUM_YUV_FORMATS]; 252 else 253 fmt = &array[i]; 254 255 if ((!allow_non_mbus && fmt->codes[0] == 0) || 256 (!allow_bayer && fmt->bayer)) 257 continue; 258 259 if (fourcc && fmt->fourcc == fourcc) { 260 ret = fmt; 261 goto out; 262 } 263 264 for (j = 0; code && fmt->codes[j]; j++) { 265 if (code == fmt->codes[j]) { 266 ret = fmt; 267 goto out; 268 } 269 } 270 } 271 272 out: 273 return ret; 274 } 275 276 static int enum_format(u32 *fourcc, u32 *code, u32 index, 277 enum codespace_sel cs_sel, 278 bool allow_non_mbus, 279 bool allow_bayer) 280 { 281 const struct imx_media_pixfmt *fmt; 282 u32 mbus_yuv_sz = NUM_MBUS_YUV_FORMATS; 283 u32 mbus_rgb_sz = NUM_MBUS_RGB_FORMATS; 284 u32 yuv_sz = NUM_YUV_FORMATS; 285 u32 rgb_sz = NUM_RGB_FORMATS; 286 287 switch (cs_sel) { 288 case CS_SEL_YUV: 289 if (index >= yuv_sz || 290 (!allow_non_mbus && index >= mbus_yuv_sz)) 291 return -EINVAL; 292 fmt = &yuv_formats[index]; 293 break; 294 case CS_SEL_RGB: 295 if (index >= rgb_sz || 296 (!allow_non_mbus && index >= mbus_rgb_sz)) 297 return -EINVAL; 298 fmt = &rgb_formats[index]; 299 if (!allow_bayer && fmt->bayer) 300 return -EINVAL; 301 break; 302 case CS_SEL_ANY: 303 if (!allow_non_mbus) { 304 if (index >= mbus_yuv_sz) { 305 index -= mbus_yuv_sz; 306 if (index >= mbus_rgb_sz) 307 return -EINVAL; 308 fmt = &rgb_formats[index]; 309 if (!allow_bayer && fmt->bayer) 310 return -EINVAL; 311 } else { 312 fmt = &yuv_formats[index]; 313 } 314 } else { 315 if (index >= yuv_sz + rgb_sz) 316 return -EINVAL; 317 if (index >= yuv_sz) { 318 fmt = &rgb_formats[index - yuv_sz]; 319 if (!allow_bayer && fmt->bayer) 320 return -EINVAL; 321 } else { 322 fmt = &yuv_formats[index]; 323 } 324 } 325 break; 326 default: 327 return -EINVAL; 328 } 329 330 if (fourcc) 331 *fourcc = fmt->fourcc; 332 if (code) 333 *code = fmt->codes[0]; 334 335 return 0; 336 } 337 338 const struct imx_media_pixfmt * 339 imx_media_find_format(u32 fourcc, enum codespace_sel cs_sel, bool allow_bayer) 340 { 341 return find_format(fourcc, 0, cs_sel, true, allow_bayer); 342 } 343 EXPORT_SYMBOL_GPL(imx_media_find_format); 344 345 int imx_media_enum_format(u32 *fourcc, u32 index, enum codespace_sel cs_sel) 346 { 347 return enum_format(fourcc, NULL, index, cs_sel, true, false); 348 } 349 EXPORT_SYMBOL_GPL(imx_media_enum_format); 350 351 const struct imx_media_pixfmt * 352 imx_media_find_mbus_format(u32 code, enum codespace_sel cs_sel, 353 bool allow_bayer) 354 { 355 return find_format(0, code, cs_sel, false, allow_bayer); 356 } 357 EXPORT_SYMBOL_GPL(imx_media_find_mbus_format); 358 359 int imx_media_enum_mbus_format(u32 *code, u32 index, enum codespace_sel cs_sel, 360 bool allow_bayer) 361 { 362 return enum_format(NULL, code, index, cs_sel, false, allow_bayer); 363 } 364 EXPORT_SYMBOL_GPL(imx_media_enum_mbus_format); 365 366 const struct imx_media_pixfmt * 367 imx_media_find_ipu_format(u32 code, enum codespace_sel cs_sel) 368 { 369 const struct imx_media_pixfmt *array, *fmt, *ret = NULL; 370 u32 array_size; 371 int i, j; 372 373 switch (cs_sel) { 374 case CS_SEL_YUV: 375 array_size = NUM_IPU_YUV_FORMATS; 376 array = ipu_yuv_formats; 377 break; 378 case CS_SEL_RGB: 379 array_size = NUM_IPU_RGB_FORMATS; 380 array = ipu_rgb_formats; 381 break; 382 case CS_SEL_ANY: 383 array_size = NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS; 384 array = ipu_yuv_formats; 385 break; 386 default: 387 return NULL; 388 } 389 390 for (i = 0; i < array_size; i++) { 391 if (cs_sel == CS_SEL_ANY && i >= NUM_IPU_YUV_FORMATS) 392 fmt = &ipu_rgb_formats[i - NUM_IPU_YUV_FORMATS]; 393 else 394 fmt = &array[i]; 395 396 for (j = 0; code && fmt->codes[j]; j++) { 397 if (code == fmt->codes[j]) { 398 ret = fmt; 399 goto out; 400 } 401 } 402 } 403 404 out: 405 return ret; 406 } 407 EXPORT_SYMBOL_GPL(imx_media_find_ipu_format); 408 409 int imx_media_enum_ipu_format(u32 *code, u32 index, enum codespace_sel cs_sel) 410 { 411 switch (cs_sel) { 412 case CS_SEL_YUV: 413 if (index >= NUM_IPU_YUV_FORMATS) 414 return -EINVAL; 415 *code = ipu_yuv_formats[index].codes[0]; 416 break; 417 case CS_SEL_RGB: 418 if (index >= NUM_IPU_RGB_FORMATS) 419 return -EINVAL; 420 *code = ipu_rgb_formats[index].codes[0]; 421 break; 422 case CS_SEL_ANY: 423 if (index >= NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS) 424 return -EINVAL; 425 if (index >= NUM_IPU_YUV_FORMATS) { 426 index -= NUM_IPU_YUV_FORMATS; 427 *code = ipu_rgb_formats[index].codes[0]; 428 } else { 429 *code = ipu_yuv_formats[index].codes[0]; 430 } 431 break; 432 default: 433 return -EINVAL; 434 } 435 436 return 0; 437 } 438 EXPORT_SYMBOL_GPL(imx_media_enum_ipu_format); 439 440 int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus, 441 u32 width, u32 height, u32 code, u32 field, 442 const struct imx_media_pixfmt **cc) 443 { 444 const struct imx_media_pixfmt *lcc; 445 446 mbus->width = width; 447 mbus->height = height; 448 mbus->field = field; 449 if (code == 0) 450 imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false); 451 lcc = imx_media_find_mbus_format(code, CS_SEL_ANY, false); 452 if (!lcc) { 453 lcc = imx_media_find_ipu_format(code, CS_SEL_ANY); 454 if (!lcc) 455 return -EINVAL; 456 } 457 458 mbus->code = code; 459 init_mbus_colorimetry(mbus, lcc); 460 if (cc) 461 *cc = lcc; 462 463 return 0; 464 } 465 EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt); 466 467 /* 468 * Check whether the field and colorimetry parameters in tryfmt are 469 * uninitialized, and if so fill them with the values from fmt, 470 * or if tryfmt->colorspace has been initialized, all the default 471 * colorimetry params can be derived from tryfmt->colorspace. 472 * 473 * tryfmt->code must be set on entry. 474 * 475 * If this format is destined to be routed through the Image Converter, 476 * quantization and Y`CbCr encoding must be fixed. The IC expects and 477 * produces fixed quantization and Y`CbCr encoding at its input and output 478 * (full range for RGB, limited range for YUV, and V4L2_YCBCR_ENC_601). 479 */ 480 void imx_media_fill_default_mbus_fields(struct v4l2_mbus_framefmt *tryfmt, 481 struct v4l2_mbus_framefmt *fmt, 482 bool ic_route) 483 { 484 const struct imx_media_pixfmt *cc; 485 bool is_rgb = false; 486 487 cc = imx_media_find_mbus_format(tryfmt->code, CS_SEL_ANY, true); 488 if (!cc) 489 cc = imx_media_find_ipu_format(tryfmt->code, CS_SEL_ANY); 490 if (cc && cc->cs != IPUV3_COLORSPACE_YUV) 491 is_rgb = true; 492 493 /* fill field if necessary */ 494 if (tryfmt->field == V4L2_FIELD_ANY) 495 tryfmt->field = fmt->field; 496 497 /* fill colorimetry if necessary */ 498 if (tryfmt->colorspace == V4L2_COLORSPACE_DEFAULT) { 499 tryfmt->colorspace = fmt->colorspace; 500 tryfmt->xfer_func = fmt->xfer_func; 501 tryfmt->ycbcr_enc = fmt->ycbcr_enc; 502 tryfmt->quantization = fmt->quantization; 503 } else { 504 if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT) { 505 tryfmt->xfer_func = 506 V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace); 507 } 508 if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) { 509 tryfmt->ycbcr_enc = 510 V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace); 511 } 512 if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT) { 513 tryfmt->quantization = 514 V4L2_MAP_QUANTIZATION_DEFAULT( 515 is_rgb, tryfmt->colorspace, 516 tryfmt->ycbcr_enc); 517 } 518 } 519 520 if (ic_route) { 521 tryfmt->quantization = is_rgb ? 522 V4L2_QUANTIZATION_FULL_RANGE : 523 V4L2_QUANTIZATION_LIM_RANGE; 524 tryfmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 525 } 526 } 527 EXPORT_SYMBOL_GPL(imx_media_fill_default_mbus_fields); 528 529 int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix, 530 struct v4l2_mbus_framefmt *mbus, 531 const struct imx_media_pixfmt *cc) 532 { 533 u32 stride; 534 535 if (!cc) { 536 cc = imx_media_find_ipu_format(mbus->code, CS_SEL_ANY); 537 if (!cc) 538 cc = imx_media_find_mbus_format(mbus->code, CS_SEL_ANY, 539 true); 540 if (!cc) 541 return -EINVAL; 542 } 543 544 /* 545 * TODO: the IPU currently does not support the AYUV32 format, 546 * so until it does convert to a supported YUV format. 547 */ 548 if (cc->ipufmt && cc->cs == IPUV3_COLORSPACE_YUV) { 549 u32 code; 550 551 imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false); 552 cc = imx_media_find_mbus_format(code, CS_SEL_YUV, false); 553 } 554 555 stride = cc->planar ? mbus->width : (mbus->width * cc->bpp) >> 3; 556 557 pix->width = mbus->width; 558 pix->height = mbus->height; 559 pix->pixelformat = cc->fourcc; 560 pix->colorspace = mbus->colorspace; 561 pix->xfer_func = mbus->xfer_func; 562 pix->ycbcr_enc = mbus->ycbcr_enc; 563 pix->quantization = mbus->quantization; 564 pix->field = mbus->field; 565 pix->bytesperline = stride; 566 pix->sizeimage = (pix->width * pix->height * cc->bpp) >> 3; 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 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 struct ipu_image *image) 592 { 593 const struct imx_media_pixfmt *fmt; 594 595 fmt = imx_media_find_format(image->pix.pixelformat, CS_SEL_ANY, true); 596 if (!fmt) 597 return -EINVAL; 598 599 memset(mbus, 0, sizeof(*mbus)); 600 mbus->width = image->pix.width; 601 mbus->height = image->pix.height; 602 mbus->code = fmt->codes[0]; 603 mbus->field = image->pix.field; 604 mbus->colorspace = image->pix.colorspace; 605 mbus->xfer_func = image->pix.xfer_func; 606 mbus->ycbcr_enc = image->pix.ycbcr_enc; 607 mbus->quantization = image->pix.quantization; 608 609 return 0; 610 } 611 EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt); 612 613 void imx_media_free_dma_buf(struct imx_media_dev *imxmd, 614 struct imx_media_dma_buf *buf) 615 { 616 if (buf->virt) 617 dma_free_coherent(imxmd->md.dev, buf->len, 618 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 imx_media_dev *imxmd, 626 struct imx_media_dma_buf *buf, 627 int size) 628 { 629 imx_media_free_dma_buf(imxmd, buf); 630 631 buf->len = PAGE_ALIGN(size); 632 buf->virt = dma_alloc_coherent(imxmd->md.dev, buf->len, &buf->phys, 633 GFP_DMA | GFP_KERNEL); 634 if (!buf->virt) { 635 dev_err(imxmd->md.dev, "failed to alloc dma buffer\n"); 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_CSI0...IMX_MEDIA_GRP_ID_CSI1: 650 id = (grp_id >> IMX_MEDIA_GRP_ID_CSI_BIT) - 1; 651 snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id); 652 break; 653 case IMX_MEDIA_GRP_ID_VDIC: 654 snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1); 655 break; 656 case IMX_MEDIA_GRP_ID_IC_PRP: 657 snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1); 658 break; 659 case IMX_MEDIA_GRP_ID_IC_PRPENC: 660 snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1); 661 break; 662 case IMX_MEDIA_GRP_ID_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 by 703 * an async subdev that owns a video device when it is registered. 704 */ 705 int 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 return 0; 714 } 715 EXPORT_SYMBOL_GPL(imx_media_add_video_device); 716 717 /* 718 * Search upstream/downstream for a subdevice in the current pipeline 719 * with given grp_id, starting from start_entity. Returns the subdev's 720 * source/sink pad that it was reached from. If grp_id is zero, just 721 * returns the nearest source/sink pad to start_entity. Must be called 722 * with mdev->graph_mutex held. 723 */ 724 static struct media_pad * 725 find_pipeline_pad(struct imx_media_dev *imxmd, 726 struct media_entity *start_entity, 727 u32 grp_id, bool upstream) 728 { 729 struct media_entity *me = start_entity; 730 struct media_pad *pad = NULL; 731 struct v4l2_subdev *sd; 732 int i; 733 734 for (i = 0; i < me->num_pads; i++) { 735 struct media_pad *spad = &me->pads[i]; 736 737 if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) || 738 (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE))) 739 continue; 740 741 pad = media_entity_remote_pad(spad); 742 if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) 743 continue; 744 745 if (grp_id != 0) { 746 sd = media_entity_to_v4l2_subdev(pad->entity); 747 if (sd->grp_id & grp_id) 748 return pad; 749 750 return find_pipeline_pad(imxmd, pad->entity, 751 grp_id, upstream); 752 } else { 753 return pad; 754 } 755 } 756 757 return NULL; 758 } 759 760 /* 761 * Search upstream for a subdev in the current pipeline with 762 * given grp_id. Must be called with mdev->graph_mutex held. 763 */ 764 static struct v4l2_subdev * 765 find_upstream_subdev(struct imx_media_dev *imxmd, 766 struct media_entity *start_entity, 767 u32 grp_id) 768 { 769 struct v4l2_subdev *sd; 770 struct media_pad *pad; 771 772 if (is_media_entity_v4l2_subdev(start_entity)) { 773 sd = media_entity_to_v4l2_subdev(start_entity); 774 if (sd->grp_id & grp_id) 775 return sd; 776 } 777 778 pad = find_pipeline_pad(imxmd, start_entity, grp_id, true); 779 780 return pad ? media_entity_to_v4l2_subdev(pad->entity) : NULL; 781 } 782 783 /* 784 * Find the upstream mipi-csi2 virtual channel reached from the given 785 * start entity in the current pipeline. 786 * Must be called with mdev->graph_mutex held. 787 */ 788 int imx_media_find_mipi_csi2_channel(struct imx_media_dev *imxmd, 789 struct media_entity *start_entity) 790 { 791 struct media_pad *pad; 792 int ret = -EPIPE; 793 794 pad = find_pipeline_pad(imxmd, start_entity, IMX_MEDIA_GRP_ID_CSI2, 795 true); 796 if (pad) { 797 ret = pad->index - 1; 798 dev_dbg(imxmd->md.dev, "found vc%d from %s\n", 799 ret, start_entity->name); 800 } 801 802 return ret; 803 } 804 EXPORT_SYMBOL_GPL(imx_media_find_mipi_csi2_channel); 805 806 /* 807 * Find a source pad reached upstream from the given start entity in 808 * the current pipeline. Must be called with mdev->graph_mutex held. 809 */ 810 struct media_pad * 811 imx_media_find_upstream_pad(struct imx_media_dev *imxmd, 812 struct media_entity *start_entity, 813 u32 grp_id) 814 { 815 struct media_pad *pad; 816 817 pad = find_pipeline_pad(imxmd, start_entity, grp_id, true); 818 if (!pad) 819 return ERR_PTR(-ENODEV); 820 821 return pad; 822 } 823 EXPORT_SYMBOL_GPL(imx_media_find_upstream_pad); 824 825 /* 826 * Find a subdev reached upstream from the given start entity in 827 * the current pipeline. 828 * Must be called with mdev->graph_mutex held. 829 */ 830 struct v4l2_subdev * 831 imx_media_find_upstream_subdev(struct imx_media_dev *imxmd, 832 struct media_entity *start_entity, 833 u32 grp_id) 834 { 835 struct v4l2_subdev *sd; 836 837 sd = find_upstream_subdev(imxmd, start_entity, grp_id); 838 if (!sd) 839 return ERR_PTR(-ENODEV); 840 841 return sd; 842 } 843 EXPORT_SYMBOL_GPL(imx_media_find_upstream_subdev); 844 845 /* 846 * Turn current pipeline streaming on/off starting from entity. 847 */ 848 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd, 849 struct media_entity *entity, 850 bool on) 851 { 852 struct v4l2_subdev *sd; 853 int ret = 0; 854 855 if (!is_media_entity_v4l2_subdev(entity)) 856 return -EINVAL; 857 sd = media_entity_to_v4l2_subdev(entity); 858 859 mutex_lock(&imxmd->md.graph_mutex); 860 861 if (on) { 862 ret = __media_pipeline_start(entity, &imxmd->pipe); 863 if (ret) 864 goto out; 865 ret = v4l2_subdev_call(sd, video, s_stream, 1); 866 if (ret) 867 __media_pipeline_stop(entity); 868 } else { 869 v4l2_subdev_call(sd, video, s_stream, 0); 870 if (entity->pipe) 871 __media_pipeline_stop(entity); 872 } 873 874 out: 875 mutex_unlock(&imxmd->md.graph_mutex); 876 return ret; 877 } 878 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream); 879 880 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver"); 881 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>"); 882 MODULE_LICENSE("GPL"); 883