linux/drivers/media/platform/ti-vpe/cal-video.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * TI Camera Access Layer (CAL) - Video Device
   4 *
   5 * Copyright (c) 2015-2020 Texas Instruments Inc.
   6 *
   7 * Authors:
   8 *      Benoit Parrot <bparrot@ti.com>
   9 *      Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  10 */
  11
  12#include <linux/ioctl.h>
  13#include <linux/pm_runtime.h>
  14#include <linux/videodev2.h>
  15
  16#include <media/media-device.h>
  17#include <media/v4l2-common.h>
  18#include <media/v4l2-ctrls.h>
  19#include <media/v4l2-device.h>
  20#include <media/v4l2-event.h>
  21#include <media/v4l2-fh.h>
  22#include <media/v4l2-ioctl.h>
  23#include <media/videobuf2-core.h>
  24#include <media/videobuf2-dma-contig.h>
  25
  26#include "cal.h"
  27
  28/*  Print Four-character-code (FOURCC) */
  29static char *fourcc_to_str(u32 fmt)
  30{
  31        static char code[5];
  32
  33        code[0] = (unsigned char)(fmt & 0xff);
  34        code[1] = (unsigned char)((fmt >> 8) & 0xff);
  35        code[2] = (unsigned char)((fmt >> 16) & 0xff);
  36        code[3] = (unsigned char)((fmt >> 24) & 0xff);
  37        code[4] = '\0';
  38
  39        return code;
  40}
  41
  42/* ------------------------------------------------------------------
  43 *      V4L2 Common IOCTLs
  44 * ------------------------------------------------------------------
  45 */
  46
  47static int cal_querycap(struct file *file, void *priv,
  48                        struct v4l2_capability *cap)
  49{
  50        struct cal_ctx *ctx = video_drvdata(file);
  51
  52        strscpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver));
  53        strscpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card));
  54
  55        snprintf(cap->bus_info, sizeof(cap->bus_info),
  56                 "platform:%s", dev_name(ctx->cal->dev));
  57        return 0;
  58}
  59
  60static int cal_g_fmt_vid_cap(struct file *file, void *priv,
  61                             struct v4l2_format *f)
  62{
  63        struct cal_ctx *ctx = video_drvdata(file);
  64
  65        *f = ctx->v_fmt;
  66
  67        return 0;
  68}
  69
  70/* ------------------------------------------------------------------
  71 *      V4L2 Video Node Centric IOCTLs
  72 * ------------------------------------------------------------------
  73 */
  74
  75static const struct cal_format_info *find_format_by_pix(struct cal_ctx *ctx,
  76                                                        u32 pixelformat)
  77{
  78        const struct cal_format_info *fmtinfo;
  79        unsigned int k;
  80
  81        for (k = 0; k < ctx->num_active_fmt; k++) {
  82                fmtinfo = ctx->active_fmt[k];
  83                if (fmtinfo->fourcc == pixelformat)
  84                        return fmtinfo;
  85        }
  86
  87        return NULL;
  88}
  89
  90static const struct cal_format_info *find_format_by_code(struct cal_ctx *ctx,
  91                                                         u32 code)
  92{
  93        const struct cal_format_info *fmtinfo;
  94        unsigned int k;
  95
  96        for (k = 0; k < ctx->num_active_fmt; k++) {
  97                fmtinfo = ctx->active_fmt[k];
  98                if (fmtinfo->code == code)
  99                        return fmtinfo;
 100        }
 101
 102        return NULL;
 103}
 104
 105static int cal_enum_fmt_vid_cap(struct file *file, void  *priv,
 106                                struct v4l2_fmtdesc *f)
 107{
 108        struct cal_ctx *ctx = video_drvdata(file);
 109        const struct cal_format_info *fmtinfo;
 110
 111        if (f->index >= ctx->num_active_fmt)
 112                return -EINVAL;
 113
 114        fmtinfo = ctx->active_fmt[f->index];
 115
 116        f->pixelformat = fmtinfo->fourcc;
 117        f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 118        return 0;
 119}
 120
 121static int __subdev_get_format(struct cal_ctx *ctx,
 122                               struct v4l2_mbus_framefmt *fmt)
 123{
 124        struct v4l2_subdev_format sd_fmt;
 125        struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
 126        int ret;
 127
 128        sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 129        sd_fmt.pad = 0;
 130
 131        ret = v4l2_subdev_call(ctx->phy->sensor, pad, get_fmt, NULL, &sd_fmt);
 132        if (ret)
 133                return ret;
 134
 135        *fmt = *mbus_fmt;
 136
 137        ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__,
 138                fmt->width, fmt->height, fmt->code);
 139
 140        return 0;
 141}
 142
 143static int __subdev_set_format(struct cal_ctx *ctx,
 144                               struct v4l2_mbus_framefmt *fmt)
 145{
 146        struct v4l2_subdev_format sd_fmt;
 147        struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
 148        int ret;
 149
 150        sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 151        sd_fmt.pad = 0;
 152        *mbus_fmt = *fmt;
 153
 154        ret = v4l2_subdev_call(ctx->phy->sensor, pad, set_fmt, NULL, &sd_fmt);
 155        if (ret)
 156                return ret;
 157
 158        ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__,
 159                fmt->width, fmt->height, fmt->code);
 160
 161        return 0;
 162}
 163
 164static void cal_calc_format_size(struct cal_ctx *ctx,
 165                                 const struct cal_format_info *fmtinfo,
 166                                 struct v4l2_format *f)
 167{
 168        u32 bpl, max_width;
 169
 170        /*
 171         * Maximum width is bound by the DMA max width in bytes.
 172         * We need to recalculate the actual maxi width depending on the
 173         * number of bytes per pixels required.
 174         */
 175        max_width = CAL_MAX_WIDTH_BYTES / (ALIGN(fmtinfo->bpp, 8) >> 3);
 176        v4l_bound_align_image(&f->fmt.pix.width, 48, max_width, 2,
 177                              &f->fmt.pix.height, 32, CAL_MAX_HEIGHT_LINES,
 178                              0, 0);
 179
 180        bpl = (f->fmt.pix.width * ALIGN(fmtinfo->bpp, 8)) >> 3;
 181        f->fmt.pix.bytesperline = ALIGN(bpl, 16);
 182
 183        f->fmt.pix.sizeimage = f->fmt.pix.height *
 184                               f->fmt.pix.bytesperline;
 185
 186        ctx_dbg(3, ctx, "%s: fourcc: %s size: %dx%d bpl:%d img_size:%d\n",
 187                __func__, fourcc_to_str(f->fmt.pix.pixelformat),
 188                f->fmt.pix.width, f->fmt.pix.height,
 189                f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
 190}
 191
 192static int cal_try_fmt_vid_cap(struct file *file, void *priv,
 193                               struct v4l2_format *f)
 194{
 195        struct cal_ctx *ctx = video_drvdata(file);
 196        const struct cal_format_info *fmtinfo;
 197        struct v4l2_subdev_frame_size_enum fse;
 198        int ret, found;
 199
 200        fmtinfo = find_format_by_pix(ctx, f->fmt.pix.pixelformat);
 201        if (!fmtinfo) {
 202                ctx_dbg(3, ctx, "Fourcc format (0x%08x) not found.\n",
 203                        f->fmt.pix.pixelformat);
 204
 205                /* Just get the first one enumerated */
 206                fmtinfo = ctx->active_fmt[0];
 207                f->fmt.pix.pixelformat = fmtinfo->fourcc;
 208        }
 209
 210        f->fmt.pix.field = ctx->v_fmt.fmt.pix.field;
 211
 212        /* check for/find a valid width/height */
 213        ret = 0;
 214        found = false;
 215        fse.pad = 0;
 216        fse.code = fmtinfo->code;
 217        fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 218        for (fse.index = 0; ; fse.index++) {
 219                ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_size,
 220                                       NULL, &fse);
 221                if (ret)
 222                        break;
 223
 224                if ((f->fmt.pix.width == fse.max_width) &&
 225                    (f->fmt.pix.height == fse.max_height)) {
 226                        found = true;
 227                        break;
 228                } else if ((f->fmt.pix.width >= fse.min_width) &&
 229                         (f->fmt.pix.width <= fse.max_width) &&
 230                         (f->fmt.pix.height >= fse.min_height) &&
 231                         (f->fmt.pix.height <= fse.max_height)) {
 232                        found = true;
 233                        break;
 234                }
 235        }
 236
 237        if (!found) {
 238                /* use existing values as default */
 239                f->fmt.pix.width = ctx->v_fmt.fmt.pix.width;
 240                f->fmt.pix.height =  ctx->v_fmt.fmt.pix.height;
 241        }
 242
 243        /*
 244         * Use current colorspace for now, it will get
 245         * updated properly during s_fmt
 246         */
 247        f->fmt.pix.colorspace = ctx->v_fmt.fmt.pix.colorspace;
 248        cal_calc_format_size(ctx, fmtinfo, f);
 249        return 0;
 250}
 251
 252static int cal_s_fmt_vid_cap(struct file *file, void *priv,
 253                             struct v4l2_format *f)
 254{
 255        struct cal_ctx *ctx = video_drvdata(file);
 256        struct vb2_queue *q = &ctx->vb_vidq;
 257        struct v4l2_subdev_format sd_fmt = {
 258                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
 259                .pad = CAL_CAMERARX_PAD_SINK,
 260        };
 261        const struct cal_format_info *fmtinfo;
 262        int ret;
 263
 264        if (vb2_is_busy(q)) {
 265                ctx_dbg(3, ctx, "%s device busy\n", __func__);
 266                return -EBUSY;
 267        }
 268
 269        ret = cal_try_fmt_vid_cap(file, priv, f);
 270        if (ret < 0)
 271                return ret;
 272
 273        fmtinfo = find_format_by_pix(ctx, f->fmt.pix.pixelformat);
 274
 275        v4l2_fill_mbus_format(&sd_fmt.format, &f->fmt.pix, fmtinfo->code);
 276
 277        ret = __subdev_set_format(ctx, &sd_fmt.format);
 278        if (ret)
 279                return ret;
 280
 281        /* Just double check nothing has gone wrong */
 282        if (sd_fmt.format.code != fmtinfo->code) {
 283                ctx_dbg(3, ctx,
 284                        "%s subdev changed format on us, this should not happen\n",
 285                        __func__);
 286                return -EINVAL;
 287        }
 288
 289        v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &sd_fmt.format);
 290        ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 291        ctx->v_fmt.fmt.pix.pixelformat = fmtinfo->fourcc;
 292        ctx->v_fmt.fmt.pix.field = sd_fmt.format.field;
 293        cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt);
 294
 295        v4l2_subdev_call(&ctx->phy->subdev, pad, set_fmt, NULL, &sd_fmt);
 296
 297        ctx->fmtinfo = fmtinfo;
 298        *f = ctx->v_fmt;
 299
 300        return 0;
 301}
 302
 303static int cal_enum_framesizes(struct file *file, void *fh,
 304                               struct v4l2_frmsizeenum *fsize)
 305{
 306        struct cal_ctx *ctx = video_drvdata(file);
 307        const struct cal_format_info *fmtinfo;
 308        struct v4l2_subdev_frame_size_enum fse;
 309        int ret;
 310
 311        /* check for valid format */
 312        fmtinfo = find_format_by_pix(ctx, fsize->pixel_format);
 313        if (!fmtinfo) {
 314                ctx_dbg(3, ctx, "Invalid pixel code: %x\n",
 315                        fsize->pixel_format);
 316                return -EINVAL;
 317        }
 318
 319        fse.index = fsize->index;
 320        fse.pad = 0;
 321        fse.code = fmtinfo->code;
 322        fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 323
 324        ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_size, NULL,
 325                               &fse);
 326        if (ret)
 327                return ret;
 328
 329        ctx_dbg(1, ctx, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
 330                __func__, fse.index, fse.code, fse.min_width, fse.max_width,
 331                fse.min_height, fse.max_height);
 332
 333        fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
 334        fsize->discrete.width = fse.max_width;
 335        fsize->discrete.height = fse.max_height;
 336
 337        return 0;
 338}
 339
 340static int cal_enum_input(struct file *file, void *priv,
 341                          struct v4l2_input *inp)
 342{
 343        if (inp->index > 0)
 344                return -EINVAL;
 345
 346        inp->type = V4L2_INPUT_TYPE_CAMERA;
 347        sprintf(inp->name, "Camera %u", inp->index);
 348        return 0;
 349}
 350
 351static int cal_g_input(struct file *file, void *priv, unsigned int *i)
 352{
 353        *i = 0;
 354        return 0;
 355}
 356
 357static int cal_s_input(struct file *file, void *priv, unsigned int i)
 358{
 359        return i > 0 ? -EINVAL : 0;
 360}
 361
 362/* timeperframe is arbitrary and continuous */
 363static int cal_enum_frameintervals(struct file *file, void *priv,
 364                                   struct v4l2_frmivalenum *fival)
 365{
 366        struct cal_ctx *ctx = video_drvdata(file);
 367        const struct cal_format_info *fmtinfo;
 368        struct v4l2_subdev_frame_interval_enum fie = {
 369                .index = fival->index,
 370                .width = fival->width,
 371                .height = fival->height,
 372                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
 373        };
 374        int ret;
 375
 376        fmtinfo = find_format_by_pix(ctx, fival->pixel_format);
 377        if (!fmtinfo)
 378                return -EINVAL;
 379
 380        fie.code = fmtinfo->code;
 381        ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_interval,
 382                               NULL, &fie);
 383        if (ret)
 384                return ret;
 385        fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
 386        fival->discrete = fie.interval;
 387
 388        return 0;
 389}
 390
 391static const struct v4l2_ioctl_ops cal_ioctl_video_ops = {
 392        .vidioc_querycap      = cal_querycap,
 393        .vidioc_enum_fmt_vid_cap  = cal_enum_fmt_vid_cap,
 394        .vidioc_g_fmt_vid_cap     = cal_g_fmt_vid_cap,
 395        .vidioc_try_fmt_vid_cap   = cal_try_fmt_vid_cap,
 396        .vidioc_s_fmt_vid_cap     = cal_s_fmt_vid_cap,
 397        .vidioc_enum_framesizes   = cal_enum_framesizes,
 398        .vidioc_reqbufs       = vb2_ioctl_reqbufs,
 399        .vidioc_create_bufs   = vb2_ioctl_create_bufs,
 400        .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
 401        .vidioc_querybuf      = vb2_ioctl_querybuf,
 402        .vidioc_qbuf          = vb2_ioctl_qbuf,
 403        .vidioc_dqbuf         = vb2_ioctl_dqbuf,
 404        .vidioc_expbuf        = vb2_ioctl_expbuf,
 405        .vidioc_enum_input    = cal_enum_input,
 406        .vidioc_g_input       = cal_g_input,
 407        .vidioc_s_input       = cal_s_input,
 408        .vidioc_enum_frameintervals = cal_enum_frameintervals,
 409        .vidioc_streamon      = vb2_ioctl_streamon,
 410        .vidioc_streamoff     = vb2_ioctl_streamoff,
 411        .vidioc_log_status    = v4l2_ctrl_log_status,
 412        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 413        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 414};
 415
 416/* ------------------------------------------------------------------
 417 *      V4L2 Media Controller Centric IOCTLs
 418 * ------------------------------------------------------------------
 419 */
 420
 421static int cal_mc_enum_fmt_vid_cap(struct file *file, void  *priv,
 422                                   struct v4l2_fmtdesc *f)
 423{
 424        if (f->index >= cal_num_formats)
 425                return -EINVAL;
 426
 427        f->pixelformat = cal_formats[f->index].fourcc;
 428        f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 429
 430        return 0;
 431}
 432
 433static void cal_mc_try_fmt(struct cal_ctx *ctx, struct v4l2_format *f,
 434                           const struct cal_format_info **info)
 435{
 436        struct v4l2_pix_format *format = &f->fmt.pix;
 437        const struct cal_format_info *fmtinfo;
 438        unsigned int bpp;
 439
 440        /*
 441         * Default to the first format if the requested pixel format code isn't
 442         * supported.
 443         */
 444        fmtinfo = cal_format_by_fourcc(f->fmt.pix.pixelformat);
 445        if (!fmtinfo)
 446                fmtinfo = &cal_formats[0];
 447
 448        /*
 449         * Clamp the size, update the pixel format. The field and colorspace are
 450         * accepted as-is, except for V4L2_FIELD_ANY that is turned into
 451         * V4L2_FIELD_NONE.
 452         */
 453        bpp = ALIGN(fmtinfo->bpp, 8);
 454
 455        format->width = clamp_t(unsigned int, format->width,
 456                                CAL_MIN_WIDTH_BYTES * 8 / bpp,
 457                                CAL_MAX_WIDTH_BYTES * 8 / bpp);
 458        format->height = clamp_t(unsigned int, format->height,
 459                                 CAL_MIN_HEIGHT_LINES, CAL_MAX_HEIGHT_LINES);
 460        format->pixelformat = fmtinfo->fourcc;
 461
 462        if (format->field == V4L2_FIELD_ANY)
 463                format->field = V4L2_FIELD_NONE;
 464
 465        /*
 466         * Calculate the number of bytes per line and the image size. The
 467         * hardware stores the stride as a number of 16 bytes words, in a
 468         * signed 15-bit value. Only 14 bits are thus usable.
 469         */
 470        format->bytesperline = ALIGN(clamp(format->bytesperline,
 471                                           format->width * bpp / 8,
 472                                           ((1U << 14) - 1) * 16), 16);
 473
 474        format->sizeimage = format->height * format->bytesperline;
 475
 476        format->colorspace = ctx->v_fmt.fmt.pix.colorspace;
 477
 478        if (info)
 479                *info = fmtinfo;
 480
 481        ctx_dbg(3, ctx, "%s: %s %ux%u (bytesperline %u sizeimage %u)\n",
 482                __func__, fourcc_to_str(format->pixelformat),
 483                format->width, format->height,
 484                format->bytesperline, format->sizeimage);
 485}
 486
 487static int cal_mc_try_fmt_vid_cap(struct file *file, void *priv,
 488                                  struct v4l2_format *f)
 489{
 490        struct cal_ctx *ctx = video_drvdata(file);
 491
 492        cal_mc_try_fmt(ctx, f, NULL);
 493        return 0;
 494}
 495
 496static int cal_mc_s_fmt_vid_cap(struct file *file, void *priv,
 497                                struct v4l2_format *f)
 498{
 499        struct cal_ctx *ctx = video_drvdata(file);
 500        const struct cal_format_info *fmtinfo;
 501
 502        if (vb2_is_busy(&ctx->vb_vidq)) {
 503                ctx_dbg(3, ctx, "%s device busy\n", __func__);
 504                return -EBUSY;
 505        }
 506
 507        cal_mc_try_fmt(ctx, f, &fmtinfo);
 508
 509        ctx->v_fmt = *f;
 510        ctx->fmtinfo = fmtinfo;
 511
 512        return 0;
 513}
 514
 515static int cal_mc_enum_framesizes(struct file *file, void *fh,
 516                                  struct v4l2_frmsizeenum *fsize)
 517{
 518        struct cal_ctx *ctx = video_drvdata(file);
 519        const struct cal_format_info *fmtinfo;
 520        unsigned int bpp;
 521
 522        if (fsize->index > 0)
 523                return -EINVAL;
 524
 525        fmtinfo = cal_format_by_fourcc(fsize->pixel_format);
 526        if (!fmtinfo) {
 527                ctx_dbg(3, ctx, "Invalid pixel format 0x%08x\n",
 528                        fsize->pixel_format);
 529                return -EINVAL;
 530        }
 531
 532        bpp = ALIGN(fmtinfo->bpp, 8);
 533
 534        fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
 535        fsize->stepwise.min_width = CAL_MIN_WIDTH_BYTES * 8 / bpp;
 536        fsize->stepwise.max_width = CAL_MAX_WIDTH_BYTES * 8 / bpp;
 537        fsize->stepwise.step_width = 64 / bpp;
 538        fsize->stepwise.min_height = CAL_MIN_HEIGHT_LINES;
 539        fsize->stepwise.max_height = CAL_MAX_HEIGHT_LINES;
 540        fsize->stepwise.step_height = 1;
 541
 542        return 0;
 543}
 544
 545static const struct v4l2_ioctl_ops cal_ioctl_mc_ops = {
 546        .vidioc_querycap      = cal_querycap,
 547        .vidioc_enum_fmt_vid_cap  = cal_mc_enum_fmt_vid_cap,
 548        .vidioc_g_fmt_vid_cap     = cal_g_fmt_vid_cap,
 549        .vidioc_try_fmt_vid_cap   = cal_mc_try_fmt_vid_cap,
 550        .vidioc_s_fmt_vid_cap     = cal_mc_s_fmt_vid_cap,
 551        .vidioc_enum_framesizes   = cal_mc_enum_framesizes,
 552        .vidioc_reqbufs       = vb2_ioctl_reqbufs,
 553        .vidioc_create_bufs   = vb2_ioctl_create_bufs,
 554        .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
 555        .vidioc_querybuf      = vb2_ioctl_querybuf,
 556        .vidioc_qbuf          = vb2_ioctl_qbuf,
 557        .vidioc_dqbuf         = vb2_ioctl_dqbuf,
 558        .vidioc_expbuf        = vb2_ioctl_expbuf,
 559        .vidioc_streamon      = vb2_ioctl_streamon,
 560        .vidioc_streamoff     = vb2_ioctl_streamoff,
 561        .vidioc_log_status    = v4l2_ctrl_log_status,
 562};
 563
 564/* ------------------------------------------------------------------
 565 *      videobuf2 Common Operations
 566 * ------------------------------------------------------------------
 567 */
 568
 569static int cal_queue_setup(struct vb2_queue *vq,
 570                           unsigned int *nbuffers, unsigned int *nplanes,
 571                           unsigned int sizes[], struct device *alloc_devs[])
 572{
 573        struct cal_ctx *ctx = vb2_get_drv_priv(vq);
 574        unsigned int size = ctx->v_fmt.fmt.pix.sizeimage;
 575
 576        if (vq->num_buffers + *nbuffers < 3)
 577                *nbuffers = 3 - vq->num_buffers;
 578
 579        if (*nplanes) {
 580                if (sizes[0] < size)
 581                        return -EINVAL;
 582                size = sizes[0];
 583        }
 584
 585        *nplanes = 1;
 586        sizes[0] = size;
 587
 588        ctx_dbg(3, ctx, "nbuffers=%d, size=%d\n", *nbuffers, sizes[0]);
 589
 590        return 0;
 591}
 592
 593static int cal_buffer_prepare(struct vb2_buffer *vb)
 594{
 595        struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 596        struct cal_buffer *buf = container_of(vb, struct cal_buffer,
 597                                              vb.vb2_buf);
 598        unsigned long size;
 599
 600        size = ctx->v_fmt.fmt.pix.sizeimage;
 601        if (vb2_plane_size(vb, 0) < size) {
 602                ctx_err(ctx,
 603                        "data will not fit into plane (%lu < %lu)\n",
 604                        vb2_plane_size(vb, 0), size);
 605                return -EINVAL;
 606        }
 607
 608        vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
 609        return 0;
 610}
 611
 612static void cal_buffer_queue(struct vb2_buffer *vb)
 613{
 614        struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 615        struct cal_buffer *buf = container_of(vb, struct cal_buffer,
 616                                              vb.vb2_buf);
 617        unsigned long flags;
 618
 619        /* recheck locking */
 620        spin_lock_irqsave(&ctx->dma.lock, flags);
 621        list_add_tail(&buf->list, &ctx->dma.queue);
 622        spin_unlock_irqrestore(&ctx->dma.lock, flags);
 623}
 624
 625static void cal_release_buffers(struct cal_ctx *ctx,
 626                                enum vb2_buffer_state state)
 627{
 628        struct cal_buffer *buf, *tmp;
 629
 630        /* Release all queued buffers. */
 631        spin_lock_irq(&ctx->dma.lock);
 632
 633        list_for_each_entry_safe(buf, tmp, &ctx->dma.queue, list) {
 634                list_del(&buf->list);
 635                vb2_buffer_done(&buf->vb.vb2_buf, state);
 636        }
 637
 638        if (ctx->dma.pending) {
 639                vb2_buffer_done(&ctx->dma.pending->vb.vb2_buf, state);
 640                ctx->dma.pending = NULL;
 641        }
 642
 643        if (ctx->dma.active) {
 644                vb2_buffer_done(&ctx->dma.active->vb.vb2_buf, state);
 645                ctx->dma.active = NULL;
 646        }
 647
 648        spin_unlock_irq(&ctx->dma.lock);
 649}
 650
 651/* ------------------------------------------------------------------
 652 *      videobuf2 Operations
 653 * ------------------------------------------------------------------
 654 */
 655
 656static int cal_video_check_format(struct cal_ctx *ctx)
 657{
 658        const struct v4l2_mbus_framefmt *format;
 659
 660        format = &ctx->phy->formats[CAL_CAMERARX_PAD_SOURCE];
 661
 662        if (ctx->fmtinfo->code != format->code ||
 663            ctx->v_fmt.fmt.pix.height != format->height ||
 664            ctx->v_fmt.fmt.pix.width != format->width ||
 665            ctx->v_fmt.fmt.pix.field != format->field)
 666                return -EPIPE;
 667
 668        return 0;
 669}
 670
 671static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
 672{
 673        struct cal_ctx *ctx = vb2_get_drv_priv(vq);
 674        struct cal_buffer *buf;
 675        dma_addr_t addr;
 676        int ret;
 677
 678        ret = media_pipeline_start(&ctx->vdev.entity, &ctx->phy->pipe);
 679        if (ret < 0) {
 680                ctx_err(ctx, "Failed to start media pipeline: %d\n", ret);
 681                goto error_release_buffers;
 682        }
 683
 684        /*
 685         * Verify that the currently configured format matches the output of
 686         * the connected CAMERARX.
 687         */
 688        ret = cal_video_check_format(ctx);
 689        if (ret < 0) {
 690                ctx_dbg(3, ctx,
 691                        "Format mismatch between CAMERARX and video node\n");
 692                goto error_pipeline;
 693        }
 694
 695        spin_lock_irq(&ctx->dma.lock);
 696        buf = list_first_entry(&ctx->dma.queue, struct cal_buffer, list);
 697        ctx->dma.pending = buf;
 698        list_del(&buf->list);
 699        spin_unlock_irq(&ctx->dma.lock);
 700
 701        addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
 702
 703        ret = pm_runtime_resume_and_get(ctx->cal->dev);
 704        if (ret < 0)
 705                goto error_pipeline;
 706
 707        cal_ctx_set_dma_addr(ctx, addr);
 708        cal_ctx_start(ctx);
 709
 710        ret = v4l2_subdev_call(&ctx->phy->subdev, video, s_stream, 1);
 711        if (ret)
 712                goto error_stop;
 713
 714        if (cal_debug >= 4)
 715                cal_quickdump_regs(ctx->cal);
 716
 717        return 0;
 718
 719error_stop:
 720        cal_ctx_stop(ctx);
 721        pm_runtime_put_sync(ctx->cal->dev);
 722
 723error_pipeline:
 724        media_pipeline_stop(&ctx->vdev.entity);
 725error_release_buffers:
 726        cal_release_buffers(ctx, VB2_BUF_STATE_QUEUED);
 727
 728        return ret;
 729}
 730
 731static void cal_stop_streaming(struct vb2_queue *vq)
 732{
 733        struct cal_ctx *ctx = vb2_get_drv_priv(vq);
 734
 735        cal_ctx_stop(ctx);
 736
 737        v4l2_subdev_call(&ctx->phy->subdev, video, s_stream, 0);
 738
 739        pm_runtime_put_sync(ctx->cal->dev);
 740
 741        cal_release_buffers(ctx, VB2_BUF_STATE_ERROR);
 742
 743        media_pipeline_stop(&ctx->vdev.entity);
 744}
 745
 746static const struct vb2_ops cal_video_qops = {
 747        .queue_setup            = cal_queue_setup,
 748        .buf_prepare            = cal_buffer_prepare,
 749        .buf_queue              = cal_buffer_queue,
 750        .start_streaming        = cal_start_streaming,
 751        .stop_streaming         = cal_stop_streaming,
 752        .wait_prepare           = vb2_ops_wait_prepare,
 753        .wait_finish            = vb2_ops_wait_finish,
 754};
 755
 756/* ------------------------------------------------------------------
 757 *      V4L2 Initialization and Registration
 758 * ------------------------------------------------------------------
 759 */
 760
 761static const struct v4l2_file_operations cal_fops = {
 762        .owner          = THIS_MODULE,
 763        .open           = v4l2_fh_open,
 764        .release        = vb2_fop_release,
 765        .poll           = vb2_fop_poll,
 766        .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
 767        .mmap           = vb2_fop_mmap,
 768};
 769
 770static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
 771{
 772        struct v4l2_subdev_mbus_code_enum mbus_code;
 773        struct v4l2_mbus_framefmt mbus_fmt;
 774        const struct cal_format_info *fmtinfo;
 775        unsigned int i, j, k;
 776        int ret = 0;
 777
 778        /* Enumerate sub device formats and enable all matching local formats */
 779        ctx->active_fmt = devm_kcalloc(ctx->cal->dev, cal_num_formats,
 780                                       sizeof(*ctx->active_fmt), GFP_KERNEL);
 781        ctx->num_active_fmt = 0;
 782
 783        for (j = 0, i = 0; ; ++j) {
 784
 785                memset(&mbus_code, 0, sizeof(mbus_code));
 786                mbus_code.index = j;
 787                mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 788                ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_mbus_code,
 789                                       NULL, &mbus_code);
 790                if (ret == -EINVAL)
 791                        break;
 792
 793                if (ret) {
 794                        ctx_err(ctx, "Error enumerating mbus codes in subdev %s: %d\n",
 795                                ctx->phy->sensor->name, ret);
 796                        return ret;
 797                }
 798
 799                ctx_dbg(2, ctx,
 800                        "subdev %s: code: %04x idx: %u\n",
 801                        ctx->phy->sensor->name, mbus_code.code, j);
 802
 803                for (k = 0; k < cal_num_formats; k++) {
 804                        fmtinfo = &cal_formats[k];
 805
 806                        if (mbus_code.code == fmtinfo->code) {
 807                                ctx->active_fmt[i] = fmtinfo;
 808                                ctx_dbg(2, ctx,
 809                                        "matched fourcc: %s: code: %04x idx: %u\n",
 810                                        fourcc_to_str(fmtinfo->fourcc),
 811                                        fmtinfo->code, i);
 812                                ctx->num_active_fmt = ++i;
 813                        }
 814                }
 815        }
 816
 817        if (i == 0) {
 818                ctx_err(ctx, "No suitable format reported by subdev %s\n",
 819                        ctx->phy->sensor->name);
 820                return -EINVAL;
 821        }
 822
 823        ret = __subdev_get_format(ctx, &mbus_fmt);
 824        if (ret)
 825                return ret;
 826
 827        fmtinfo = find_format_by_code(ctx, mbus_fmt.code);
 828        if (!fmtinfo) {
 829                ctx_dbg(3, ctx, "mbus code format (0x%08x) not found.\n",
 830                        mbus_fmt.code);
 831                return -EINVAL;
 832        }
 833
 834        /* Save current format */
 835        v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt);
 836        ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 837        ctx->v_fmt.fmt.pix.pixelformat = fmtinfo->fourcc;
 838        cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt);
 839        ctx->fmtinfo = fmtinfo;
 840
 841        return 0;
 842}
 843
 844int cal_ctx_v4l2_register(struct cal_ctx *ctx)
 845{
 846        struct video_device *vfd = &ctx->vdev;
 847        int ret;
 848
 849        ret = cal_ctx_v4l2_init_formats(ctx);
 850        if (ret)
 851                return ret;
 852
 853        if (!cal_mc_api) {
 854                struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler;
 855
 856                ret = v4l2_ctrl_add_handler(hdl, ctx->phy->sensor->ctrl_handler,
 857                                            NULL, true);
 858                if (ret < 0) {
 859                        ctx_err(ctx, "Failed to add sensor ctrl handler\n");
 860                        return ret;
 861                }
 862        }
 863
 864        ret = video_register_device(vfd, VFL_TYPE_VIDEO, cal_video_nr);
 865        if (ret < 0) {
 866                ctx_err(ctx, "Failed to register video device\n");
 867                return ret;
 868        }
 869
 870        ret = media_create_pad_link(&ctx->phy->subdev.entity,
 871                                    CAL_CAMERARX_PAD_SOURCE,
 872                                    &vfd->entity, 0,
 873                                    MEDIA_LNK_FL_IMMUTABLE |
 874                                    MEDIA_LNK_FL_ENABLED);
 875        if (ret) {
 876                ctx_err(ctx, "Failed to create media link for context %u\n",
 877                        ctx->index);
 878                video_unregister_device(vfd);
 879                return ret;
 880        }
 881
 882        ctx_info(ctx, "V4L2 device registered as %s\n",
 883                 video_device_node_name(vfd));
 884
 885        return 0;
 886}
 887
 888void cal_ctx_v4l2_unregister(struct cal_ctx *ctx)
 889{
 890        ctx_dbg(1, ctx, "unregistering %s\n",
 891                video_device_node_name(&ctx->vdev));
 892
 893        video_unregister_device(&ctx->vdev);
 894}
 895
 896int cal_ctx_v4l2_init(struct cal_ctx *ctx)
 897{
 898        struct video_device *vfd = &ctx->vdev;
 899        struct vb2_queue *q = &ctx->vb_vidq;
 900        int ret;
 901
 902        INIT_LIST_HEAD(&ctx->dma.queue);
 903        spin_lock_init(&ctx->dma.lock);
 904        mutex_init(&ctx->mutex);
 905        init_waitqueue_head(&ctx->dma.wait);
 906
 907        /* Initialize the vb2 queue. */
 908        q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 909        q->io_modes = VB2_MMAP | VB2_DMABUF;
 910        q->drv_priv = ctx;
 911        q->buf_struct_size = sizeof(struct cal_buffer);
 912        q->ops = &cal_video_qops;
 913        q->mem_ops = &vb2_dma_contig_memops;
 914        q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
 915        q->lock = &ctx->mutex;
 916        q->min_buffers_needed = 3;
 917        q->dev = ctx->cal->dev;
 918
 919        ret = vb2_queue_init(q);
 920        if (ret)
 921                return ret;
 922
 923        /* Initialize the video device and media entity. */
 924        vfd->fops = &cal_fops;
 925        vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING
 926                         | (cal_mc_api ? V4L2_CAP_IO_MC : 0);
 927        vfd->v4l2_dev = &ctx->cal->v4l2_dev;
 928        vfd->queue = q;
 929        snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->index);
 930        vfd->release = video_device_release_empty;
 931        vfd->ioctl_ops = cal_mc_api ? &cal_ioctl_mc_ops : &cal_ioctl_video_ops;
 932        vfd->lock = &ctx->mutex;
 933        video_set_drvdata(vfd, ctx);
 934
 935        ctx->pad.flags = MEDIA_PAD_FL_SINK;
 936        ret = media_entity_pads_init(&vfd->entity, 1, &ctx->pad);
 937        if (ret < 0)
 938                return ret;
 939
 940        if (!cal_mc_api) {
 941                /* Initialize the control handler. */
 942                struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler;
 943
 944                ret = v4l2_ctrl_handler_init(hdl, 11);
 945                if (ret < 0) {
 946                        ctx_err(ctx, "Failed to init ctrl handler\n");
 947                        goto error;
 948                }
 949
 950                vfd->ctrl_handler = hdl;
 951        }
 952
 953        return 0;
 954
 955error:
 956        media_entity_cleanup(&vfd->entity);
 957        return ret;
 958}
 959
 960void cal_ctx_v4l2_cleanup(struct cal_ctx *ctx)
 961{
 962        if (!cal_mc_api)
 963                v4l2_ctrl_handler_free(&ctx->ctrl_handler);
 964
 965        media_entity_cleanup(&ctx->vdev.entity);
 966}
 967