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