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 .cycles = 2, 82 }, { 83 .fourcc = V4L2_PIX_FMT_RGB24, 84 .codes = { 85 MEDIA_BUS_FMT_RGB888_1X24, 86 MEDIA_BUS_FMT_RGB888_2X12_LE 87 }, 88 .cs = IPUV3_COLORSPACE_RGB, 89 .bpp = 24, 90 }, { 91 .fourcc = V4L2_PIX_FMT_XRGB32, 92 .codes = {MEDIA_BUS_FMT_ARGB8888_1X32}, 93 .cs = IPUV3_COLORSPACE_RGB, 94 .bpp = 32, 95 .ipufmt = true, 96 }, 97 /*** raw bayer and grayscale formats start here ***/ 98 { 99 .fourcc = V4L2_PIX_FMT_SBGGR8, 100 .codes = {MEDIA_BUS_FMT_SBGGR8_1X8}, 101 .cs = IPUV3_COLORSPACE_RGB, 102 .bpp = 8, 103 .bayer = true, 104 }, { 105 .fourcc = V4L2_PIX_FMT_SGBRG8, 106 .codes = {MEDIA_BUS_FMT_SGBRG8_1X8}, 107 .cs = IPUV3_COLORSPACE_RGB, 108 .bpp = 8, 109 .bayer = true, 110 }, { 111 .fourcc = V4L2_PIX_FMT_SGRBG8, 112 .codes = {MEDIA_BUS_FMT_SGRBG8_1X8}, 113 .cs = IPUV3_COLORSPACE_RGB, 114 .bpp = 8, 115 .bayer = true, 116 }, { 117 .fourcc = V4L2_PIX_FMT_SRGGB8, 118 .codes = {MEDIA_BUS_FMT_SRGGB8_1X8}, 119 .cs = IPUV3_COLORSPACE_RGB, 120 .bpp = 8, 121 .bayer = true, 122 }, { 123 .fourcc = V4L2_PIX_FMT_SBGGR16, 124 .codes = { 125 MEDIA_BUS_FMT_SBGGR10_1X10, 126 MEDIA_BUS_FMT_SBGGR12_1X12, 127 MEDIA_BUS_FMT_SBGGR14_1X14, 128 MEDIA_BUS_FMT_SBGGR16_1X16 129 }, 130 .cs = IPUV3_COLORSPACE_RGB, 131 .bpp = 16, 132 .bayer = true, 133 }, { 134 .fourcc = V4L2_PIX_FMT_SGBRG16, 135 .codes = { 136 MEDIA_BUS_FMT_SGBRG10_1X10, 137 MEDIA_BUS_FMT_SGBRG12_1X12, 138 MEDIA_BUS_FMT_SGBRG14_1X14, 139 MEDIA_BUS_FMT_SGBRG16_1X16, 140 }, 141 .cs = IPUV3_COLORSPACE_RGB, 142 .bpp = 16, 143 .bayer = true, 144 }, { 145 .fourcc = V4L2_PIX_FMT_SGRBG16, 146 .codes = { 147 MEDIA_BUS_FMT_SGRBG10_1X10, 148 MEDIA_BUS_FMT_SGRBG12_1X12, 149 MEDIA_BUS_FMT_SGRBG14_1X14, 150 MEDIA_BUS_FMT_SGRBG16_1X16, 151 }, 152 .cs = IPUV3_COLORSPACE_RGB, 153 .bpp = 16, 154 .bayer = true, 155 }, { 156 .fourcc = V4L2_PIX_FMT_SRGGB16, 157 .codes = { 158 MEDIA_BUS_FMT_SRGGB10_1X10, 159 MEDIA_BUS_FMT_SRGGB12_1X12, 160 MEDIA_BUS_FMT_SRGGB14_1X14, 161 MEDIA_BUS_FMT_SRGGB16_1X16, 162 }, 163 .cs = IPUV3_COLORSPACE_RGB, 164 .bpp = 16, 165 .bayer = true, 166 }, { 167 .fourcc = V4L2_PIX_FMT_GREY, 168 .codes = {MEDIA_BUS_FMT_Y8_1X8}, 169 .cs = IPUV3_COLORSPACE_RGB, 170 .bpp = 8, 171 .bayer = true, 172 }, { 173 .fourcc = V4L2_PIX_FMT_Y16, 174 .codes = { 175 MEDIA_BUS_FMT_Y10_1X10, 176 MEDIA_BUS_FMT_Y12_1X12, 177 }, 178 .cs = IPUV3_COLORSPACE_RGB, 179 .bpp = 16, 180 .bayer = true, 181 }, 182 /*** 183 * non-mbus RGB formats start here. NOTE! when adding non-mbus 184 * formats, NUM_NON_MBUS_RGB_FORMATS must be updated below. 185 ***/ 186 { 187 .fourcc = V4L2_PIX_FMT_BGR24, 188 .cs = IPUV3_COLORSPACE_RGB, 189 .bpp = 24, 190 }, { 191 .fourcc = V4L2_PIX_FMT_BGR32, 192 .cs = IPUV3_COLORSPACE_RGB, 193 .bpp = 32, 194 }, 195 }; 196 197 #define NUM_NON_MBUS_RGB_FORMATS 2 198 #define NUM_RGB_FORMATS ARRAY_SIZE(rgb_formats) 199 #define NUM_MBUS_RGB_FORMATS (NUM_RGB_FORMATS - NUM_NON_MBUS_RGB_FORMATS) 200 201 static const struct imx_media_pixfmt ipu_yuv_formats[] = { 202 { 203 .fourcc = V4L2_PIX_FMT_YUV32, 204 .codes = {MEDIA_BUS_FMT_AYUV8_1X32}, 205 .cs = IPUV3_COLORSPACE_YUV, 206 .bpp = 32, 207 .ipufmt = true, 208 }, 209 }; 210 211 #define NUM_IPU_YUV_FORMATS ARRAY_SIZE(ipu_yuv_formats) 212 213 static const struct imx_media_pixfmt ipu_rgb_formats[] = { 214 { 215 .fourcc = V4L2_PIX_FMT_XRGB32, 216 .codes = {MEDIA_BUS_FMT_ARGB8888_1X32}, 217 .cs = IPUV3_COLORSPACE_RGB, 218 .bpp = 32, 219 .ipufmt = true, 220 }, 221 }; 222 223 #define NUM_IPU_RGB_FORMATS ARRAY_SIZE(ipu_rgb_formats) 224 225 static void init_mbus_colorimetry(struct v4l2_mbus_framefmt *mbus, 226 const struct imx_media_pixfmt *fmt) 227 { 228 mbus->colorspace = (fmt->cs == IPUV3_COLORSPACE_RGB) ? 229 V4L2_COLORSPACE_SRGB : V4L2_COLORSPACE_SMPTE170M; 230 mbus->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mbus->colorspace); 231 mbus->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mbus->colorspace); 232 mbus->quantization = 233 V4L2_MAP_QUANTIZATION_DEFAULT(fmt->cs == IPUV3_COLORSPACE_RGB, 234 mbus->colorspace, 235 mbus->ycbcr_enc); 236 } 237 238 static const 239 struct imx_media_pixfmt *__find_format(u32 fourcc, 240 u32 code, 241 bool allow_non_mbus, 242 bool allow_bayer, 243 const struct imx_media_pixfmt *array, 244 u32 array_size) 245 { 246 const struct imx_media_pixfmt *fmt; 247 int i, j; 248 249 for (i = 0; i < array_size; i++) { 250 fmt = &array[i]; 251 252 if ((!allow_non_mbus && !fmt->codes[0]) || 253 (!allow_bayer && fmt->bayer)) 254 continue; 255 256 if (fourcc && fmt->fourcc == fourcc) 257 return fmt; 258 259 if (!code) 260 continue; 261 262 for (j = 0; fmt->codes[j]; j++) { 263 if (code == fmt->codes[j]) 264 return fmt; 265 } 266 } 267 return NULL; 268 } 269 270 static const struct imx_media_pixfmt *find_format(u32 fourcc, 271 u32 code, 272 enum codespace_sel cs_sel, 273 bool allow_non_mbus, 274 bool allow_bayer) 275 { 276 const struct imx_media_pixfmt *ret; 277 278 switch (cs_sel) { 279 case CS_SEL_YUV: 280 return __find_format(fourcc, code, allow_non_mbus, allow_bayer, 281 yuv_formats, NUM_YUV_FORMATS); 282 case CS_SEL_RGB: 283 return __find_format(fourcc, code, allow_non_mbus, allow_bayer, 284 rgb_formats, NUM_RGB_FORMATS); 285 case CS_SEL_ANY: 286 ret = __find_format(fourcc, code, allow_non_mbus, allow_bayer, 287 yuv_formats, NUM_YUV_FORMATS); 288 if (ret) 289 return ret; 290 return __find_format(fourcc, code, allow_non_mbus, allow_bayer, 291 rgb_formats, NUM_RGB_FORMATS); 292 default: 293 return NULL; 294 } 295 } 296 297 static int enum_format(u32 *fourcc, u32 *code, u32 index, 298 enum codespace_sel cs_sel, 299 bool allow_non_mbus, 300 bool allow_bayer) 301 { 302 const struct imx_media_pixfmt *fmt; 303 u32 mbus_yuv_sz = NUM_MBUS_YUV_FORMATS; 304 u32 mbus_rgb_sz = NUM_MBUS_RGB_FORMATS; 305 u32 yuv_sz = NUM_YUV_FORMATS; 306 u32 rgb_sz = NUM_RGB_FORMATS; 307 308 switch (cs_sel) { 309 case CS_SEL_YUV: 310 if (index >= yuv_sz || 311 (!allow_non_mbus && index >= mbus_yuv_sz)) 312 return -EINVAL; 313 fmt = &yuv_formats[index]; 314 break; 315 case CS_SEL_RGB: 316 if (index >= rgb_sz || 317 (!allow_non_mbus && index >= mbus_rgb_sz)) 318 return -EINVAL; 319 fmt = &rgb_formats[index]; 320 if (!allow_bayer && fmt->bayer) 321 return -EINVAL; 322 break; 323 case CS_SEL_ANY: 324 if (!allow_non_mbus) { 325 if (index >= mbus_yuv_sz) { 326 index -= mbus_yuv_sz; 327 if (index >= mbus_rgb_sz) 328 return -EINVAL; 329 fmt = &rgb_formats[index]; 330 if (!allow_bayer && fmt->bayer) 331 return -EINVAL; 332 } else { 333 fmt = &yuv_formats[index]; 334 } 335 } else { 336 if (index >= yuv_sz + rgb_sz) 337 return -EINVAL; 338 if (index >= yuv_sz) { 339 fmt = &rgb_formats[index - yuv_sz]; 340 if (!allow_bayer && fmt->bayer) 341 return -EINVAL; 342 } else { 343 fmt = &yuv_formats[index]; 344 } 345 } 346 break; 347 default: 348 return -EINVAL; 349 } 350 351 if (fourcc) 352 *fourcc = fmt->fourcc; 353 if (code) 354 *code = fmt->codes[0]; 355 356 return 0; 357 } 358 359 const struct imx_media_pixfmt * 360 imx_media_find_format(u32 fourcc, enum codespace_sel cs_sel, bool allow_bayer) 361 { 362 return find_format(fourcc, 0, cs_sel, true, allow_bayer); 363 } 364 EXPORT_SYMBOL_GPL(imx_media_find_format); 365 366 int imx_media_enum_format(u32 *fourcc, u32 index, enum codespace_sel cs_sel) 367 { 368 return enum_format(fourcc, NULL, index, cs_sel, true, false); 369 } 370 EXPORT_SYMBOL_GPL(imx_media_enum_format); 371 372 const struct imx_media_pixfmt * 373 imx_media_find_mbus_format(u32 code, enum codespace_sel cs_sel, 374 bool allow_bayer) 375 { 376 return find_format(0, code, cs_sel, false, allow_bayer); 377 } 378 EXPORT_SYMBOL_GPL(imx_media_find_mbus_format); 379 380 int imx_media_enum_mbus_format(u32 *code, u32 index, enum codespace_sel cs_sel, 381 bool allow_bayer) 382 { 383 return enum_format(NULL, code, index, cs_sel, false, allow_bayer); 384 } 385 EXPORT_SYMBOL_GPL(imx_media_enum_mbus_format); 386 387 const struct imx_media_pixfmt * 388 imx_media_find_ipu_format(u32 code, enum codespace_sel cs_sel) 389 { 390 const struct imx_media_pixfmt *array, *fmt, *ret = NULL; 391 u32 array_size; 392 int i, j; 393 394 switch (cs_sel) { 395 case CS_SEL_YUV: 396 array_size = NUM_IPU_YUV_FORMATS; 397 array = ipu_yuv_formats; 398 break; 399 case CS_SEL_RGB: 400 array_size = NUM_IPU_RGB_FORMATS; 401 array = ipu_rgb_formats; 402 break; 403 case CS_SEL_ANY: 404 array_size = NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS; 405 array = ipu_yuv_formats; 406 break; 407 default: 408 return NULL; 409 } 410 411 for (i = 0; i < array_size; i++) { 412 if (cs_sel == CS_SEL_ANY && i >= NUM_IPU_YUV_FORMATS) 413 fmt = &ipu_rgb_formats[i - NUM_IPU_YUV_FORMATS]; 414 else 415 fmt = &array[i]; 416 417 for (j = 0; code && fmt->codes[j]; j++) { 418 if (code == fmt->codes[j]) { 419 ret = fmt; 420 goto out; 421 } 422 } 423 } 424 425 out: 426 return ret; 427 } 428 EXPORT_SYMBOL_GPL(imx_media_find_ipu_format); 429 430 int imx_media_enum_ipu_format(u32 *code, u32 index, enum codespace_sel cs_sel) 431 { 432 switch (cs_sel) { 433 case CS_SEL_YUV: 434 if (index >= NUM_IPU_YUV_FORMATS) 435 return -EINVAL; 436 *code = ipu_yuv_formats[index].codes[0]; 437 break; 438 case CS_SEL_RGB: 439 if (index >= NUM_IPU_RGB_FORMATS) 440 return -EINVAL; 441 *code = ipu_rgb_formats[index].codes[0]; 442 break; 443 case CS_SEL_ANY: 444 if (index >= NUM_IPU_YUV_FORMATS + NUM_IPU_RGB_FORMATS) 445 return -EINVAL; 446 if (index >= NUM_IPU_YUV_FORMATS) { 447 index -= NUM_IPU_YUV_FORMATS; 448 *code = ipu_rgb_formats[index].codes[0]; 449 } else { 450 *code = ipu_yuv_formats[index].codes[0]; 451 } 452 break; 453 default: 454 return -EINVAL; 455 } 456 457 return 0; 458 } 459 EXPORT_SYMBOL_GPL(imx_media_enum_ipu_format); 460 461 int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus, 462 u32 width, u32 height, u32 code, u32 field, 463 const struct imx_media_pixfmt **cc) 464 { 465 const struct imx_media_pixfmt *lcc; 466 467 mbus->width = width; 468 mbus->height = height; 469 mbus->field = field; 470 if (code == 0) 471 imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false); 472 lcc = imx_media_find_mbus_format(code, CS_SEL_ANY, false); 473 if (!lcc) { 474 lcc = imx_media_find_ipu_format(code, CS_SEL_ANY); 475 if (!lcc) 476 return -EINVAL; 477 } 478 479 mbus->code = code; 480 init_mbus_colorimetry(mbus, lcc); 481 if (cc) 482 *cc = lcc; 483 484 return 0; 485 } 486 EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt); 487 488 /* 489 * Initializes the TRY format to the ACTIVE format on all pads 490 * of a subdev. Can be used as the .init_cfg pad operation. 491 */ 492 int imx_media_init_cfg(struct v4l2_subdev *sd, 493 struct v4l2_subdev_pad_config *cfg) 494 { 495 struct v4l2_mbus_framefmt *mf_try; 496 struct v4l2_subdev_format format; 497 unsigned int pad; 498 int ret; 499 500 for (pad = 0; pad < sd->entity.num_pads; pad++) { 501 memset(&format, 0, sizeof(format)); 502 503 format.pad = pad; 504 format.which = V4L2_SUBDEV_FORMAT_ACTIVE; 505 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format); 506 if (ret) 507 continue; 508 509 mf_try = v4l2_subdev_get_try_format(sd, cfg, pad); 510 *mf_try = format.format; 511 } 512 513 return 0; 514 } 515 EXPORT_SYMBOL_GPL(imx_media_init_cfg); 516 517 /* 518 * Check whether the field and colorimetry parameters in tryfmt are 519 * uninitialized, and if so fill them with the values from fmt, 520 * or if tryfmt->colorspace has been initialized, all the default 521 * colorimetry params can be derived from tryfmt->colorspace. 522 * 523 * tryfmt->code must be set on entry. 524 * 525 * If this format is destined to be routed through the Image Converter, 526 * quantization and Y`CbCr encoding must be fixed. The IC expects and 527 * produces fixed quantization and Y`CbCr encoding at its input and output 528 * (full range for RGB, limited range for YUV, and V4L2_YCBCR_ENC_601). 529 */ 530 void imx_media_fill_default_mbus_fields(struct v4l2_mbus_framefmt *tryfmt, 531 struct v4l2_mbus_framefmt *fmt, 532 bool ic_route) 533 { 534 const struct imx_media_pixfmt *cc; 535 bool is_rgb = false; 536 537 cc = imx_media_find_mbus_format(tryfmt->code, CS_SEL_ANY, true); 538 if (!cc) 539 cc = imx_media_find_ipu_format(tryfmt->code, CS_SEL_ANY); 540 if (cc && cc->cs != IPUV3_COLORSPACE_YUV) 541 is_rgb = true; 542 543 /* fill field if necessary */ 544 if (tryfmt->field == V4L2_FIELD_ANY) 545 tryfmt->field = fmt->field; 546 547 /* fill colorimetry if necessary */ 548 if (tryfmt->colorspace == V4L2_COLORSPACE_DEFAULT) { 549 tryfmt->colorspace = fmt->colorspace; 550 tryfmt->xfer_func = fmt->xfer_func; 551 tryfmt->ycbcr_enc = fmt->ycbcr_enc; 552 tryfmt->quantization = fmt->quantization; 553 } else { 554 if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT) { 555 tryfmt->xfer_func = 556 V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace); 557 } 558 if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) { 559 tryfmt->ycbcr_enc = 560 V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace); 561 } 562 if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT) { 563 tryfmt->quantization = 564 V4L2_MAP_QUANTIZATION_DEFAULT( 565 is_rgb, tryfmt->colorspace, 566 tryfmt->ycbcr_enc); 567 } 568 } 569 570 if (ic_route) { 571 tryfmt->quantization = is_rgb ? 572 V4L2_QUANTIZATION_FULL_RANGE : 573 V4L2_QUANTIZATION_LIM_RANGE; 574 tryfmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 575 } 576 } 577 EXPORT_SYMBOL_GPL(imx_media_fill_default_mbus_fields); 578 579 int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix, 580 struct v4l2_rect *compose, 581 const struct v4l2_mbus_framefmt *mbus, 582 const struct imx_media_pixfmt *cc) 583 { 584 u32 width; 585 u32 stride; 586 587 if (!cc) { 588 cc = imx_media_find_ipu_format(mbus->code, CS_SEL_ANY); 589 if (!cc) 590 cc = imx_media_find_mbus_format(mbus->code, CS_SEL_ANY, 591 true); 592 if (!cc) 593 return -EINVAL; 594 } 595 596 /* 597 * TODO: the IPU currently does not support the AYUV32 format, 598 * so until it does convert to a supported YUV format. 599 */ 600 if (cc->ipufmt && cc->cs == IPUV3_COLORSPACE_YUV) { 601 u32 code; 602 603 imx_media_enum_mbus_format(&code, 0, CS_SEL_YUV, false); 604 cc = imx_media_find_mbus_format(code, CS_SEL_YUV, false); 605 } 606 607 /* Round up width for minimum burst size */ 608 width = round_up(mbus->width, 8); 609 610 /* Round up stride for IDMAC line start address alignment */ 611 if (cc->planar) 612 stride = round_up(width, 16); 613 else 614 stride = round_up((width * cc->bpp) >> 3, 8); 615 616 pix->width = width; 617 pix->height = mbus->height; 618 pix->pixelformat = cc->fourcc; 619 pix->colorspace = mbus->colorspace; 620 pix->xfer_func = mbus->xfer_func; 621 pix->ycbcr_enc = mbus->ycbcr_enc; 622 pix->quantization = mbus->quantization; 623 pix->field = mbus->field; 624 pix->bytesperline = stride; 625 pix->sizeimage = cc->planar ? ((stride * pix->height * cc->bpp) >> 3) : 626 stride * pix->height; 627 628 /* 629 * set capture compose rectangle, which is fixed to the 630 * source subdevice mbus format. 631 */ 632 if (compose) { 633 compose->left = 0; 634 compose->top = 0; 635 compose->width = mbus->width; 636 compose->height = mbus->height; 637 } 638 639 return 0; 640 } 641 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt); 642 643 int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image, 644 struct v4l2_mbus_framefmt *mbus) 645 { 646 int ret; 647 648 memset(image, 0, sizeof(*image)); 649 650 ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, &image->rect, 651 mbus, NULL); 652 if (ret) 653 return ret; 654 655 return 0; 656 } 657 EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image); 658 659 int imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt *mbus, 660 struct ipu_image *image) 661 { 662 const struct imx_media_pixfmt *fmt; 663 664 fmt = imx_media_find_format(image->pix.pixelformat, CS_SEL_ANY, true); 665 if (!fmt) 666 return -EINVAL; 667 668 memset(mbus, 0, sizeof(*mbus)); 669 mbus->width = image->pix.width; 670 mbus->height = image->pix.height; 671 mbus->code = fmt->codes[0]; 672 mbus->field = image->pix.field; 673 mbus->colorspace = image->pix.colorspace; 674 mbus->xfer_func = image->pix.xfer_func; 675 mbus->ycbcr_enc = image->pix.ycbcr_enc; 676 mbus->quantization = image->pix.quantization; 677 678 return 0; 679 } 680 EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt); 681 682 void imx_media_free_dma_buf(struct imx_media_dev *imxmd, 683 struct imx_media_dma_buf *buf) 684 { 685 if (buf->virt) 686 dma_free_coherent(imxmd->md.dev, buf->len, 687 buf->virt, buf->phys); 688 689 buf->virt = NULL; 690 buf->phys = 0; 691 } 692 EXPORT_SYMBOL_GPL(imx_media_free_dma_buf); 693 694 int imx_media_alloc_dma_buf(struct imx_media_dev *imxmd, 695 struct imx_media_dma_buf *buf, 696 int size) 697 { 698 imx_media_free_dma_buf(imxmd, buf); 699 700 buf->len = PAGE_ALIGN(size); 701 buf->virt = dma_alloc_coherent(imxmd->md.dev, buf->len, &buf->phys, 702 GFP_DMA | GFP_KERNEL); 703 if (!buf->virt) { 704 dev_err(imxmd->md.dev, "failed to alloc dma buffer\n"); 705 return -ENOMEM; 706 } 707 708 return 0; 709 } 710 EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf); 711 712 /* form a subdev name given a group id and ipu id */ 713 void imx_media_grp_id_to_sd_name(char *sd_name, int sz, u32 grp_id, int ipu_id) 714 { 715 int id; 716 717 switch (grp_id) { 718 case IMX_MEDIA_GRP_ID_IPU_CSI0...IMX_MEDIA_GRP_ID_IPU_CSI1: 719 id = (grp_id >> IMX_MEDIA_GRP_ID_IPU_CSI_BIT) - 1; 720 snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id); 721 break; 722 case IMX_MEDIA_GRP_ID_IPU_VDIC: 723 snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1); 724 break; 725 case IMX_MEDIA_GRP_ID_IPU_IC_PRP: 726 snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1); 727 break; 728 case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC: 729 snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1); 730 break; 731 case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF: 732 snprintf(sd_name, sz, "ipu%d_ic_prpvf", ipu_id + 1); 733 break; 734 default: 735 break; 736 } 737 } 738 EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name); 739 740 struct v4l2_subdev * 741 imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd, 742 struct fwnode_handle *fwnode) 743 { 744 struct v4l2_subdev *sd; 745 746 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) { 747 if (sd->fwnode == fwnode) 748 return sd; 749 } 750 751 return NULL; 752 } 753 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode); 754 755 struct v4l2_subdev * 756 imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd, 757 const char *devname) 758 { 759 struct v4l2_subdev *sd; 760 761 list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) { 762 if (!strcmp(devname, dev_name(sd->dev))) 763 return sd; 764 } 765 766 return NULL; 767 } 768 EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname); 769 770 /* 771 * Adds a video device to the master video device list. This is called by 772 * an async subdev that owns a video device when it is registered. 773 */ 774 int imx_media_add_video_device(struct imx_media_dev *imxmd, 775 struct imx_media_video_dev *vdev) 776 { 777 mutex_lock(&imxmd->mutex); 778 779 list_add_tail(&vdev->list, &imxmd->vdev_list); 780 781 mutex_unlock(&imxmd->mutex); 782 return 0; 783 } 784 EXPORT_SYMBOL_GPL(imx_media_add_video_device); 785 786 /* 787 * Search upstream/downstream for a subdevice in the current pipeline 788 * with given grp_id, starting from start_entity. Returns the subdev's 789 * source/sink pad that it was reached from. If grp_id is zero, just 790 * returns the nearest source/sink pad to start_entity. Must be called 791 * with mdev->graph_mutex held. 792 */ 793 static struct media_pad * 794 find_pipeline_pad(struct imx_media_dev *imxmd, 795 struct media_entity *start_entity, 796 u32 grp_id, bool upstream) 797 { 798 struct media_entity *me = start_entity; 799 struct media_pad *pad = NULL; 800 struct v4l2_subdev *sd; 801 int i; 802 803 for (i = 0; i < me->num_pads; i++) { 804 struct media_pad *spad = &me->pads[i]; 805 806 if ((upstream && !(spad->flags & MEDIA_PAD_FL_SINK)) || 807 (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE))) 808 continue; 809 810 pad = media_entity_remote_pad(spad); 811 if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) 812 continue; 813 814 if (grp_id != 0) { 815 sd = media_entity_to_v4l2_subdev(pad->entity); 816 if (sd->grp_id & grp_id) 817 return pad; 818 819 return find_pipeline_pad(imxmd, pad->entity, 820 grp_id, upstream); 821 } else { 822 return pad; 823 } 824 } 825 826 return NULL; 827 } 828 829 /* 830 * Search upstream for a subdev in the current pipeline with 831 * given grp_id. Must be called with mdev->graph_mutex held. 832 */ 833 static struct v4l2_subdev * 834 find_upstream_subdev(struct imx_media_dev *imxmd, 835 struct media_entity *start_entity, 836 u32 grp_id) 837 { 838 struct v4l2_subdev *sd; 839 struct media_pad *pad; 840 841 if (is_media_entity_v4l2_subdev(start_entity)) { 842 sd = media_entity_to_v4l2_subdev(start_entity); 843 if (sd->grp_id & grp_id) 844 return sd; 845 } 846 847 pad = find_pipeline_pad(imxmd, start_entity, grp_id, true); 848 849 return pad ? media_entity_to_v4l2_subdev(pad->entity) : NULL; 850 } 851 852 /* 853 * Find the upstream mipi-csi2 virtual channel reached from the given 854 * start entity in the current pipeline. 855 * Must be called with mdev->graph_mutex held. 856 */ 857 int imx_media_find_mipi_csi2_channel(struct imx_media_dev *imxmd, 858 struct media_entity *start_entity) 859 { 860 struct media_pad *pad; 861 int ret = -EPIPE; 862 863 pad = find_pipeline_pad(imxmd, start_entity, IMX_MEDIA_GRP_ID_CSI2, 864 true); 865 if (pad) { 866 ret = pad->index - 1; 867 dev_dbg(imxmd->md.dev, "found vc%d from %s\n", 868 ret, start_entity->name); 869 } 870 871 return ret; 872 } 873 EXPORT_SYMBOL_GPL(imx_media_find_mipi_csi2_channel); 874 875 /* 876 * Find a source pad reached upstream from the given start entity in 877 * the current pipeline. Must be called with mdev->graph_mutex held. 878 */ 879 struct media_pad * 880 imx_media_find_upstream_pad(struct imx_media_dev *imxmd, 881 struct media_entity *start_entity, 882 u32 grp_id) 883 { 884 struct media_pad *pad; 885 886 pad = find_pipeline_pad(imxmd, start_entity, grp_id, true); 887 if (!pad) 888 return ERR_PTR(-ENODEV); 889 890 return pad; 891 } 892 EXPORT_SYMBOL_GPL(imx_media_find_upstream_pad); 893 894 /* 895 * Find a subdev reached upstream from the given start entity in 896 * the current pipeline. 897 * Must be called with mdev->graph_mutex held. 898 */ 899 struct v4l2_subdev * 900 imx_media_find_upstream_subdev(struct imx_media_dev *imxmd, 901 struct media_entity *start_entity, 902 u32 grp_id) 903 { 904 struct v4l2_subdev *sd; 905 906 sd = find_upstream_subdev(imxmd, start_entity, grp_id); 907 if (!sd) 908 return ERR_PTR(-ENODEV); 909 910 return sd; 911 } 912 EXPORT_SYMBOL_GPL(imx_media_find_upstream_subdev); 913 914 /* 915 * Turn current pipeline streaming on/off starting from entity. 916 */ 917 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd, 918 struct media_entity *entity, 919 bool on) 920 { 921 struct v4l2_subdev *sd; 922 int ret = 0; 923 924 if (!is_media_entity_v4l2_subdev(entity)) 925 return -EINVAL; 926 sd = media_entity_to_v4l2_subdev(entity); 927 928 mutex_lock(&imxmd->md.graph_mutex); 929 930 if (on) { 931 ret = __media_pipeline_start(entity, &imxmd->pipe); 932 if (ret) 933 goto out; 934 ret = v4l2_subdev_call(sd, video, s_stream, 1); 935 if (ret) 936 __media_pipeline_stop(entity); 937 } else { 938 v4l2_subdev_call(sd, video, s_stream, 0); 939 if (entity->pipe) 940 __media_pipeline_stop(entity); 941 } 942 943 out: 944 mutex_unlock(&imxmd->md.graph_mutex); 945 return ret; 946 } 947 EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream); 948 949 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver"); 950 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>"); 951 MODULE_LICENSE("GPL"); 952