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