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#define IMX_BUS_FMTS(fmt...) (const u32[]) {fmt, 0}
  11
  12/*
  13 * List of supported pixel formats for the subdevs.
  14 */
  15static const struct imx_media_pixfmt pixel_formats[] = {
  16        /*** YUV formats start here ***/
  17        {
  18                .fourcc = V4L2_PIX_FMT_UYVY,
  19                .codes  = IMX_BUS_FMTS(
  20                        MEDIA_BUS_FMT_UYVY8_2X8,
  21                        MEDIA_BUS_FMT_UYVY8_1X16
  22                ),
  23                .cs     = IPUV3_COLORSPACE_YUV,
  24                .bpp    = 16,
  25        }, {
  26                .fourcc = V4L2_PIX_FMT_YUYV,
  27                .codes  = IMX_BUS_FMTS(
  28                        MEDIA_BUS_FMT_YUYV8_2X8,
  29                        MEDIA_BUS_FMT_YUYV8_1X16
  30                ),
  31                .cs     = IPUV3_COLORSPACE_YUV,
  32                .bpp    = 16,
  33        }, {
  34                .fourcc = V4L2_PIX_FMT_YUV420,
  35                .cs     = IPUV3_COLORSPACE_YUV,
  36                .bpp    = 12,
  37                .planar = true,
  38        }, {
  39                .fourcc = V4L2_PIX_FMT_YVU420,
  40                .cs     = IPUV3_COLORSPACE_YUV,
  41                .bpp    = 12,
  42                .planar = true,
  43        }, {
  44                .fourcc = V4L2_PIX_FMT_YUV422P,
  45                .cs     = IPUV3_COLORSPACE_YUV,
  46                .bpp    = 16,
  47                .planar = true,
  48        }, {
  49                .fourcc = V4L2_PIX_FMT_NV12,
  50                .cs     = IPUV3_COLORSPACE_YUV,
  51                .bpp    = 12,
  52                .planar = true,
  53        }, {
  54                .fourcc = V4L2_PIX_FMT_NV16,
  55                .cs     = IPUV3_COLORSPACE_YUV,
  56                .bpp    = 16,
  57                .planar = true,
  58        }, {
  59                .fourcc = V4L2_PIX_FMT_YUV32,
  60                .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_AYUV8_1X32),
  61                .cs     = IPUV3_COLORSPACE_YUV,
  62                .bpp    = 32,
  63                .ipufmt = true,
  64        },
  65        /*** RGB formats start here ***/
  66        {
  67                .fourcc = V4L2_PIX_FMT_RGB565,
  68                .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_RGB565_2X8_LE),
  69                .cs     = IPUV3_COLORSPACE_RGB,
  70                .bpp    = 16,
  71                .cycles = 2,
  72        }, {
  73                .fourcc = V4L2_PIX_FMT_RGB24,
  74                .codes  = IMX_BUS_FMTS(
  75                        MEDIA_BUS_FMT_RGB888_1X24,
  76                        MEDIA_BUS_FMT_RGB888_2X12_LE
  77                ),
  78                .cs     = IPUV3_COLORSPACE_RGB,
  79                .bpp    = 24,
  80        }, {
  81                .fourcc = V4L2_PIX_FMT_BGR24,
  82                .cs     = IPUV3_COLORSPACE_RGB,
  83                .bpp    = 24,
  84        }, {
  85                .fourcc = V4L2_PIX_FMT_XRGB32,
  86                .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_ARGB8888_1X32),
  87                .cs     = IPUV3_COLORSPACE_RGB,
  88                .bpp    = 32,
  89        }, {
  90                .fourcc = V4L2_PIX_FMT_XRGB32,
  91                .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_ARGB8888_1X32),
  92                .cs     = IPUV3_COLORSPACE_RGB,
  93                .bpp    = 32,
  94                .ipufmt = true,
  95        }, {
  96                .fourcc = V4L2_PIX_FMT_XBGR32,
  97                .cs     = IPUV3_COLORSPACE_RGB,
  98                .bpp    = 32,
  99        }, {
 100                .fourcc = V4L2_PIX_FMT_BGRX32,
 101                .cs     = IPUV3_COLORSPACE_RGB,
 102                .bpp    = 32,
 103        }, {
 104                .fourcc = V4L2_PIX_FMT_RGBX32,
 105                .cs     = IPUV3_COLORSPACE_RGB,
 106                .bpp    = 32,
 107        },
 108        /*** raw bayer and grayscale formats start here ***/
 109        {
 110                .fourcc = V4L2_PIX_FMT_SBGGR8,
 111                .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SBGGR8_1X8),
 112                .cs     = IPUV3_COLORSPACE_RGB,
 113                .bpp    = 8,
 114                .bayer  = true,
 115        }, {
 116                .fourcc = V4L2_PIX_FMT_SGBRG8,
 117                .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGBRG8_1X8),
 118                .cs     = IPUV3_COLORSPACE_RGB,
 119                .bpp    = 8,
 120                .bayer  = true,
 121        }, {
 122                .fourcc = V4L2_PIX_FMT_SGRBG8,
 123                .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGRBG8_1X8),
 124                .cs     = IPUV3_COLORSPACE_RGB,
 125                .bpp    = 8,
 126                .bayer  = true,
 127        }, {
 128                .fourcc = V4L2_PIX_FMT_SRGGB8,
 129                .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SRGGB8_1X8),
 130                .cs     = IPUV3_COLORSPACE_RGB,
 131                .bpp    = 8,
 132                .bayer  = true,
 133        }, {
 134                .fourcc = V4L2_PIX_FMT_SBGGR16,
 135                .codes  = IMX_BUS_FMTS(
 136                        MEDIA_BUS_FMT_SBGGR10_1X10,
 137                        MEDIA_BUS_FMT_SBGGR12_1X12,
 138                        MEDIA_BUS_FMT_SBGGR14_1X14,
 139                        MEDIA_BUS_FMT_SBGGR16_1X16
 140                ),
 141                .cs     = IPUV3_COLORSPACE_RGB,
 142                .bpp    = 16,
 143                .bayer  = true,
 144        }, {
 145                .fourcc = V4L2_PIX_FMT_SGBRG16,
 146                .codes  = IMX_BUS_FMTS(
 147                        MEDIA_BUS_FMT_SGBRG10_1X10,
 148                        MEDIA_BUS_FMT_SGBRG12_1X12,
 149                        MEDIA_BUS_FMT_SGBRG14_1X14,
 150                        MEDIA_BUS_FMT_SGBRG16_1X16
 151                ),
 152                .cs     = IPUV3_COLORSPACE_RGB,
 153                .bpp    = 16,
 154                .bayer  = true,
 155        }, {
 156                .fourcc = V4L2_PIX_FMT_SGRBG16,
 157                .codes  = IMX_BUS_FMTS(
 158                        MEDIA_BUS_FMT_SGRBG10_1X10,
 159                        MEDIA_BUS_FMT_SGRBG12_1X12,
 160                        MEDIA_BUS_FMT_SGRBG14_1X14,
 161                        MEDIA_BUS_FMT_SGRBG16_1X16
 162                ),
 163                .cs     = IPUV3_COLORSPACE_RGB,
 164                .bpp    = 16,
 165                .bayer  = true,
 166        }, {
 167                .fourcc = V4L2_PIX_FMT_SRGGB16,
 168                .codes  = IMX_BUS_FMTS(
 169                        MEDIA_BUS_FMT_SRGGB10_1X10,
 170                        MEDIA_BUS_FMT_SRGGB12_1X12,
 171                        MEDIA_BUS_FMT_SRGGB14_1X14,
 172                        MEDIA_BUS_FMT_SRGGB16_1X16
 173                ),
 174                .cs     = IPUV3_COLORSPACE_RGB,
 175                .bpp    = 16,
 176                .bayer  = true,
 177        }, {
 178                .fourcc = V4L2_PIX_FMT_GREY,
 179                .codes = IMX_BUS_FMTS(
 180                        MEDIA_BUS_FMT_Y8_1X8,
 181                        MEDIA_BUS_FMT_Y10_1X10,
 182                        MEDIA_BUS_FMT_Y12_1X12
 183                ),
 184                .cs     = IPUV3_COLORSPACE_RGB,
 185                .bpp    = 8,
 186                .bayer  = true,
 187        }, {
 188                .fourcc = V4L2_PIX_FMT_Y10,
 189                .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y10_1X10),
 190                .cs     = IPUV3_COLORSPACE_RGB,
 191                .bpp    = 16,
 192                .bayer  = true,
 193        }, {
 194                .fourcc = V4L2_PIX_FMT_Y12,
 195                .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y12_1X12),
 196                .cs     = IPUV3_COLORSPACE_RGB,
 197                .bpp    = 16,
 198                .bayer  = true,
 199        },
 200};
 201
 202/*
 203 * Search in the pixel_formats[] array for an entry with the given fourcc
 204 * that matches the requested selection criteria and return it.
 205 *
 206 * @fourcc: Search for an entry with the given fourcc pixel format.
 207 * @fmt_sel: Allow entries only with the given selection criteria.
 208 */
 209const struct imx_media_pixfmt *
 210imx_media_find_pixel_format(u32 fourcc, enum imx_pixfmt_sel fmt_sel)
 211{
 212        bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
 213        unsigned int i;
 214
 215        fmt_sel &= ~PIXFMT_SEL_IPU;
 216
 217        for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
 218                const struct imx_media_pixfmt *fmt = &pixel_formats[i];
 219                enum imx_pixfmt_sel sel;
 220
 221                if (sel_ipu != fmt->ipufmt)
 222                        continue;
 223
 224                sel = fmt->bayer ? PIXFMT_SEL_BAYER :
 225                        ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
 226                         PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
 227
 228                if ((fmt_sel & sel) && fmt->fourcc == fourcc)
 229                        return fmt;
 230        }
 231
 232        return NULL;
 233}
 234EXPORT_SYMBOL_GPL(imx_media_find_pixel_format);
 235
 236/*
 237 * Search in the pixel_formats[] array for an entry with the given media
 238 * bus code that matches the requested selection criteria and return it.
 239 *
 240 * @code: Search for an entry with the given media-bus code.
 241 * @fmt_sel: Allow entries only with the given selection criteria.
 242 */
 243const struct imx_media_pixfmt *
 244imx_media_find_mbus_format(u32 code, enum imx_pixfmt_sel fmt_sel)
 245{
 246        bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
 247        unsigned int i;
 248
 249        fmt_sel &= ~PIXFMT_SEL_IPU;
 250
 251        for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
 252                const struct imx_media_pixfmt *fmt = &pixel_formats[i];
 253                enum imx_pixfmt_sel sel;
 254                unsigned int j;
 255
 256                if (sel_ipu != fmt->ipufmt)
 257                        continue;
 258
 259                sel = fmt->bayer ? PIXFMT_SEL_BAYER :
 260                        ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
 261                         PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
 262
 263                if (!(fmt_sel & sel) || !fmt->codes)
 264                        continue;
 265
 266                for (j = 0; fmt->codes[j]; j++) {
 267                        if (code == fmt->codes[j])
 268                                return fmt;
 269                }
 270        }
 271
 272        return NULL;
 273}
 274EXPORT_SYMBOL_GPL(imx_media_find_mbus_format);
 275
 276/*
 277 * Enumerate entries in the pixel_formats[] array that match the
 278 * requested selection criteria. Return the fourcc that matches the
 279 * selection criteria at the requested match index.
 280 *
 281 * @fourcc: The returned fourcc that matches the search criteria at
 282 *          the requested match index.
 283 * @index: The requested match index.
 284 * @fmt_sel: Include in the enumeration entries with the given selection
 285 *           criteria.
 286 * @code: If non-zero, only include in the enumeration entries matching this
 287 *      media bus code.
 288 */
 289int imx_media_enum_pixel_formats(u32 *fourcc, u32 index,
 290                                 enum imx_pixfmt_sel fmt_sel, u32 code)
 291{
 292        bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
 293        unsigned int i;
 294
 295        fmt_sel &= ~PIXFMT_SEL_IPU;
 296
 297        for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
 298                const struct imx_media_pixfmt *fmt = &pixel_formats[i];
 299                enum imx_pixfmt_sel sel;
 300
 301                if (sel_ipu != fmt->ipufmt)
 302                        continue;
 303
 304                sel = fmt->bayer ? PIXFMT_SEL_BAYER :
 305                        ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
 306                         PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
 307
 308                if (!(fmt_sel & sel))
 309                        continue;
 310
 311                /*
 312                 * If a media bus code is specified, only consider formats that
 313                 * match it.
 314                 */
 315                if (code) {
 316                        unsigned int j;
 317
 318                        if (!fmt->codes)
 319                                continue;
 320
 321                        for (j = 0; fmt->codes[j]; j++) {
 322                                if (code == fmt->codes[j])
 323                                        break;
 324                        }
 325
 326                        if (!fmt->codes[j])
 327                                continue;
 328                }
 329
 330                if (index == 0) {
 331                        *fourcc = fmt->fourcc;
 332                        return 0;
 333                }
 334
 335                index--;
 336        }
 337
 338        return -EINVAL;
 339}
 340EXPORT_SYMBOL_GPL(imx_media_enum_pixel_formats);
 341
 342/*
 343 * Enumerate entries in the pixel_formats[] array that match the
 344 * requested search criteria. Return the media-bus code that matches
 345 * the search criteria at the requested match index.
 346 *
 347 * @code: The returned media-bus code that matches the search criteria at
 348 *        the requested match index.
 349 * @index: The requested match index.
 350 * @fmt_sel: Include in the enumeration entries with the given selection
 351 *           criteria.
 352 */
 353int imx_media_enum_mbus_formats(u32 *code, u32 index,
 354                                enum imx_pixfmt_sel fmt_sel)
 355{
 356        bool sel_ipu = fmt_sel & PIXFMT_SEL_IPU;
 357        unsigned int i;
 358
 359        fmt_sel &= ~PIXFMT_SEL_IPU;
 360
 361        for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
 362                const struct imx_media_pixfmt *fmt = &pixel_formats[i];
 363                enum imx_pixfmt_sel sel;
 364                unsigned int j;
 365
 366                if (sel_ipu != fmt->ipufmt)
 367                        continue;
 368
 369                sel = fmt->bayer ? PIXFMT_SEL_BAYER :
 370                        ((fmt->cs == IPUV3_COLORSPACE_YUV) ?
 371                         PIXFMT_SEL_YUV : PIXFMT_SEL_RGB);
 372
 373                if (!(fmt_sel & sel) || !fmt->codes)
 374                        continue;
 375
 376                for (j = 0; fmt->codes[j]; j++) {
 377                        if (index == 0) {
 378                                *code = fmt->codes[j];
 379                                return 0;
 380                        }
 381
 382                        index--;
 383                }
 384        }
 385
 386        return -EINVAL;
 387}
 388EXPORT_SYMBOL_GPL(imx_media_enum_mbus_formats);
 389
 390int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
 391                            u32 width, u32 height, u32 code, u32 field,
 392                            const struct imx_media_pixfmt **cc)
 393{
 394        const struct imx_media_pixfmt *lcc;
 395
 396        mbus->width = width;
 397        mbus->height = height;
 398        mbus->field = field;
 399
 400        if (code == 0)
 401                imx_media_enum_mbus_formats(&code, 0, PIXFMT_SEL_YUV);
 402
 403        lcc = imx_media_find_mbus_format(code, PIXFMT_SEL_ANY);
 404        if (!lcc) {
 405                lcc = imx_media_find_ipu_format(code, PIXFMT_SEL_YUV_RGB);
 406                if (!lcc)
 407                        return -EINVAL;
 408        }
 409
 410        mbus->code = code;
 411
 412        mbus->colorspace = V4L2_COLORSPACE_SRGB;
 413        mbus->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mbus->colorspace);
 414        mbus->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mbus->colorspace);
 415        mbus->quantization =
 416                V4L2_MAP_QUANTIZATION_DEFAULT(lcc->cs == IPUV3_COLORSPACE_RGB,
 417                                              mbus->colorspace,
 418                                              mbus->ycbcr_enc);
 419
 420        if (cc)
 421                *cc = lcc;
 422
 423        return 0;
 424}
 425EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
 426
 427/*
 428 * Initializes the TRY format to the ACTIVE format on all pads
 429 * of a subdev. Can be used as the .init_cfg pad operation.
 430 */
 431int imx_media_init_cfg(struct v4l2_subdev *sd,
 432                       struct v4l2_subdev_state *sd_state)
 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, sd_state, pad);
 449                *mf_try = format.format;
 450        }
 451
 452        return 0;
 453}
 454EXPORT_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 */
 467void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt,
 468                               bool ic_route)
 469{
 470        const struct imx_media_pixfmt *cc;
 471        bool is_rgb = false;
 472
 473        cc = imx_media_find_mbus_format(tryfmt->code, PIXFMT_SEL_ANY);
 474        if (!cc)
 475                cc = imx_media_find_ipu_format(tryfmt->code,
 476                                               PIXFMT_SEL_YUV_RGB);
 477
 478        if (cc && cc->cs == IPUV3_COLORSPACE_RGB)
 479                is_rgb = true;
 480
 481        switch (tryfmt->colorspace) {
 482        case V4L2_COLORSPACE_SMPTE170M:
 483        case V4L2_COLORSPACE_REC709:
 484        case V4L2_COLORSPACE_JPEG:
 485        case V4L2_COLORSPACE_SRGB:
 486        case V4L2_COLORSPACE_BT2020:
 487        case V4L2_COLORSPACE_OPRGB:
 488        case V4L2_COLORSPACE_DCI_P3:
 489        case V4L2_COLORSPACE_RAW:
 490                break;
 491        default:
 492                tryfmt->colorspace = V4L2_COLORSPACE_SRGB;
 493                break;
 494        }
 495
 496        if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT)
 497                tryfmt->xfer_func =
 498                        V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace);
 499
 500        if (ic_route) {
 501                if (tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_601 &&
 502                    tryfmt->ycbcr_enc != V4L2_YCBCR_ENC_709)
 503                        tryfmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
 504        } else {
 505                if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
 506                        tryfmt->ycbcr_enc =
 507                                V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace);
 508                }
 509        }
 510
 511        if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT)
 512                tryfmt->quantization =
 513                        V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb,
 514                                                      tryfmt->colorspace,
 515                                                      tryfmt->ycbcr_enc);
 516}
 517EXPORT_SYMBOL_GPL(imx_media_try_colorimetry);
 518
 519int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
 520                                  const struct v4l2_mbus_framefmt *mbus,
 521                                  const struct imx_media_pixfmt *cc)
 522{
 523        u32 width;
 524        u32 stride;
 525
 526        if (!cc) {
 527                cc = imx_media_find_ipu_format(mbus->code,
 528                                               PIXFMT_SEL_YUV_RGB);
 529                if (!cc)
 530                        cc = imx_media_find_mbus_format(mbus->code,
 531                                                        PIXFMT_SEL_ANY);
 532                if (!cc)
 533                        return -EINVAL;
 534        }
 535
 536        /*
 537         * TODO: the IPU currently does not support the AYUV32 format,
 538         * so until it does convert to a supported YUV format.
 539         */
 540        if (cc->ipufmt && cc->cs == IPUV3_COLORSPACE_YUV) {
 541                u32 code;
 542
 543                imx_media_enum_mbus_formats(&code, 0, PIXFMT_SEL_YUV);
 544                cc = imx_media_find_mbus_format(code, PIXFMT_SEL_YUV);
 545        }
 546
 547        /* Round up width for minimum burst size */
 548        width = round_up(mbus->width, 8);
 549
 550        /* Round up stride for IDMAC line start address alignment */
 551        if (cc->planar)
 552                stride = round_up(width, 16);
 553        else
 554                stride = round_up((width * cc->bpp) >> 3, 8);
 555
 556        pix->width = width;
 557        pix->height = mbus->height;
 558        pix->pixelformat = cc->fourcc;
 559        pix->colorspace = mbus->colorspace;
 560        pix->xfer_func = mbus->xfer_func;
 561        pix->ycbcr_enc = mbus->ycbcr_enc;
 562        pix->quantization = mbus->quantization;
 563        pix->field = mbus->field;
 564        pix->bytesperline = stride;
 565        pix->sizeimage = cc->planar ? ((stride * pix->height * cc->bpp) >> 3) :
 566                         stride * pix->height;
 567
 568        return 0;
 569}
 570EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt);
 571
 572int 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}
 588EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image);
 589
 590int 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}
 612EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt);
 613
 614void 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}
 623EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
 624
 625int 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}
 641EXPORT_SYMBOL_GPL(imx_media_alloc_dma_buf);
 642
 643/* form a subdev name given a group id and ipu id */
 644void 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}
 669EXPORT_SYMBOL_GPL(imx_media_grp_id_to_sd_name);
 670
 671struct v4l2_subdev *
 672imx_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}
 684EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_fwnode);
 685
 686struct v4l2_subdev *
 687imx_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}
 699EXPORT_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 */
 705void 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}
 714EXPORT_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 */
 726struct media_pad *
 727imx_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}
 772EXPORT_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 */
 778static struct media_entity *
 779find_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 */
 806int 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}
 818EXPORT_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 */
 825struct v4l2_subdev *
 826imx_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}
 837EXPORT_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 */
 844struct video_device *
 845imx_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}
 856EXPORT_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 */
 866struct 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}
 889EXPORT_SYMBOL_GPL(imx_media_get_pad_fwnode);
 890
 891/*
 892 * Turn current pipeline streaming on/off starting from entity.
 893 */
 894int 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
 920out:
 921        mutex_unlock(&imxmd->md.graph_mutex);
 922        return ret;
 923}
 924EXPORT_SYMBOL_GPL(imx_media_pipeline_set_stream);
 925
 926MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
 927MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
 928MODULE_LICENSE("GPL");
 929