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_legacy_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->source, 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->source, 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_legacy_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->source, 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_legacy_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_legacy_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_legacy_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->source, 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_legacy_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_legacy_g_input(struct file *file, void *priv, unsigned int *i)
 352{
 353        *i = 0;
 354        return 0;
 355}
 356
 357static int cal_legacy_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_legacy_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->source, 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 int cal_legacy_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
 392{
 393        struct cal_ctx *ctx = video_drvdata(file);
 394
 395        return v4l2_g_parm_cap(video_devdata(file), ctx->phy->source, a);
 396}
 397
 398static int cal_legacy_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
 399{
 400        struct cal_ctx *ctx = video_drvdata(file);
 401
 402        return v4l2_s_parm_cap(video_devdata(file), ctx->phy->source, a);
 403}
 404
 405static const struct v4l2_ioctl_ops cal_ioctl_legacy_ops = {
 406        .vidioc_querycap      = cal_querycap,
 407        .vidioc_enum_fmt_vid_cap  = cal_legacy_enum_fmt_vid_cap,
 408        .vidioc_g_fmt_vid_cap     = cal_g_fmt_vid_cap,
 409        .vidioc_try_fmt_vid_cap   = cal_legacy_try_fmt_vid_cap,
 410        .vidioc_s_fmt_vid_cap     = cal_legacy_s_fmt_vid_cap,
 411        .vidioc_enum_framesizes   = cal_legacy_enum_framesizes,
 412        .vidioc_reqbufs       = vb2_ioctl_reqbufs,
 413        .vidioc_create_bufs   = vb2_ioctl_create_bufs,
 414        .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
 415        .vidioc_querybuf      = vb2_ioctl_querybuf,
 416        .vidioc_qbuf          = vb2_ioctl_qbuf,
 417        .vidioc_dqbuf         = vb2_ioctl_dqbuf,
 418        .vidioc_expbuf        = vb2_ioctl_expbuf,
 419        .vidioc_enum_input    = cal_legacy_enum_input,
 420        .vidioc_g_input       = cal_legacy_g_input,
 421        .vidioc_s_input       = cal_legacy_s_input,
 422        .vidioc_enum_frameintervals = cal_legacy_enum_frameintervals,
 423        .vidioc_streamon      = vb2_ioctl_streamon,
 424        .vidioc_streamoff     = vb2_ioctl_streamoff,
 425        .vidioc_log_status    = v4l2_ctrl_log_status,
 426        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 427        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 428        .vidioc_g_parm          = cal_legacy_g_parm,
 429        .vidioc_s_parm          = cal_legacy_s_parm,
 430};
 431
 432/* ------------------------------------------------------------------
 433 *      V4L2 Media Controller Centric IOCTLs
 434 * ------------------------------------------------------------------
 435 */
 436
 437static int cal_mc_enum_fmt_vid_cap(struct file *file, void  *priv,
 438                                   struct v4l2_fmtdesc *f)
 439{
 440        unsigned int i;
 441        unsigned int idx;
 442
 443        if (f->index >= cal_num_formats)
 444                return -EINVAL;
 445
 446        idx = 0;
 447
 448        for (i = 0; i < cal_num_formats; ++i) {
 449                if (f->mbus_code && cal_formats[i].code != f->mbus_code)
 450                        continue;
 451
 452                if (idx == f->index) {
 453                        f->pixelformat = cal_formats[i].fourcc;
 454                        f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 455                        return 0;
 456                }
 457
 458                idx++;
 459        }
 460
 461        return -EINVAL;
 462}
 463
 464static void cal_mc_try_fmt(struct cal_ctx *ctx, struct v4l2_format *f,
 465                           const struct cal_format_info **info)
 466{
 467        struct v4l2_pix_format *format = &f->fmt.pix;
 468        const struct cal_format_info *fmtinfo;
 469        unsigned int bpp;
 470
 471        /*
 472         * Default to the first format if the requested pixel format code isn't
 473         * supported.
 474         */
 475        fmtinfo = cal_format_by_fourcc(f->fmt.pix.pixelformat);
 476        if (!fmtinfo)
 477                fmtinfo = &cal_formats[0];
 478
 479        /*
 480         * Clamp the size, update the pixel format. The field and colorspace are
 481         * accepted as-is, except for V4L2_FIELD_ANY that is turned into
 482         * V4L2_FIELD_NONE.
 483         */
 484        bpp = ALIGN(fmtinfo->bpp, 8);
 485
 486        format->width = clamp_t(unsigned int, format->width,
 487                                CAL_MIN_WIDTH_BYTES * 8 / bpp,
 488                                CAL_MAX_WIDTH_BYTES * 8 / bpp);
 489        format->height = clamp_t(unsigned int, format->height,
 490                                 CAL_MIN_HEIGHT_LINES, CAL_MAX_HEIGHT_LINES);
 491        format->pixelformat = fmtinfo->fourcc;
 492
 493        if (format->field == V4L2_FIELD_ANY)
 494                format->field = V4L2_FIELD_NONE;
 495
 496        /*
 497         * Calculate the number of bytes per line and the image size. The
 498         * hardware stores the stride as a number of 16 bytes words, in a
 499         * signed 15-bit value. Only 14 bits are thus usable.
 500         */
 501        format->bytesperline = ALIGN(clamp(format->bytesperline,
 502                                           format->width * bpp / 8,
 503                                           ((1U << 14) - 1) * 16), 16);
 504
 505        format->sizeimage = format->height * format->bytesperline;
 506
 507        format->colorspace = ctx->v_fmt.fmt.pix.colorspace;
 508
 509        if (info)
 510                *info = fmtinfo;
 511
 512        ctx_dbg(3, ctx, "%s: %s %ux%u (bytesperline %u sizeimage %u)\n",
 513                __func__, fourcc_to_str(format->pixelformat),
 514                format->width, format->height,
 515                format->bytesperline, format->sizeimage);
 516}
 517
 518static int cal_mc_try_fmt_vid_cap(struct file *file, void *priv,
 519                                  struct v4l2_format *f)
 520{
 521        struct cal_ctx *ctx = video_drvdata(file);
 522
 523        cal_mc_try_fmt(ctx, f, NULL);
 524        return 0;
 525}
 526
 527static int cal_mc_s_fmt_vid_cap(struct file *file, void *priv,
 528                                struct v4l2_format *f)
 529{
 530        struct cal_ctx *ctx = video_drvdata(file);
 531        const struct cal_format_info *fmtinfo;
 532
 533        if (vb2_is_busy(&ctx->vb_vidq)) {
 534                ctx_dbg(3, ctx, "%s device busy\n", __func__);
 535                return -EBUSY;
 536        }
 537
 538        cal_mc_try_fmt(ctx, f, &fmtinfo);
 539
 540        ctx->v_fmt = *f;
 541        ctx->fmtinfo = fmtinfo;
 542
 543        return 0;
 544}
 545
 546static int cal_mc_enum_framesizes(struct file *file, void *fh,
 547                                  struct v4l2_frmsizeenum *fsize)
 548{
 549        struct cal_ctx *ctx = video_drvdata(file);
 550        const struct cal_format_info *fmtinfo;
 551        unsigned int bpp;
 552
 553        if (fsize->index > 0)
 554                return -EINVAL;
 555
 556        fmtinfo = cal_format_by_fourcc(fsize->pixel_format);
 557        if (!fmtinfo) {
 558                ctx_dbg(3, ctx, "Invalid pixel format 0x%08x\n",
 559                        fsize->pixel_format);
 560                return -EINVAL;
 561        }
 562
 563        bpp = ALIGN(fmtinfo->bpp, 8);
 564
 565        fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
 566        fsize->stepwise.min_width = CAL_MIN_WIDTH_BYTES * 8 / bpp;
 567        fsize->stepwise.max_width = CAL_MAX_WIDTH_BYTES * 8 / bpp;
 568        fsize->stepwise.step_width = 64 / bpp;
 569        fsize->stepwise.min_height = CAL_MIN_HEIGHT_LINES;
 570        fsize->stepwise.max_height = CAL_MAX_HEIGHT_LINES;
 571        fsize->stepwise.step_height = 1;
 572
 573        return 0;
 574}
 575
 576static const struct v4l2_ioctl_ops cal_ioctl_mc_ops = {
 577        .vidioc_querycap      = cal_querycap,
 578        .vidioc_enum_fmt_vid_cap  = cal_mc_enum_fmt_vid_cap,
 579        .vidioc_g_fmt_vid_cap     = cal_g_fmt_vid_cap,
 580        .vidioc_try_fmt_vid_cap   = cal_mc_try_fmt_vid_cap,
 581        .vidioc_s_fmt_vid_cap     = cal_mc_s_fmt_vid_cap,
 582        .vidioc_enum_framesizes   = cal_mc_enum_framesizes,
 583        .vidioc_reqbufs       = vb2_ioctl_reqbufs,
 584        .vidioc_create_bufs   = vb2_ioctl_create_bufs,
 585        .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
 586        .vidioc_querybuf      = vb2_ioctl_querybuf,
 587        .vidioc_qbuf          = vb2_ioctl_qbuf,
 588        .vidioc_dqbuf         = vb2_ioctl_dqbuf,
 589        .vidioc_expbuf        = vb2_ioctl_expbuf,
 590        .vidioc_streamon      = vb2_ioctl_streamon,
 591        .vidioc_streamoff     = vb2_ioctl_streamoff,
 592        .vidioc_log_status    = v4l2_ctrl_log_status,
 593};
 594
 595/* ------------------------------------------------------------------
 596 *      videobuf2 Common Operations
 597 * ------------------------------------------------------------------
 598 */
 599
 600static int cal_queue_setup(struct vb2_queue *vq,
 601                           unsigned int *nbuffers, unsigned int *nplanes,
 602                           unsigned int sizes[], struct device *alloc_devs[])
 603{
 604        struct cal_ctx *ctx = vb2_get_drv_priv(vq);
 605        unsigned int size = ctx->v_fmt.fmt.pix.sizeimage;
 606
 607        if (vq->num_buffers + *nbuffers < 3)
 608                *nbuffers = 3 - vq->num_buffers;
 609
 610        if (*nplanes) {
 611                if (sizes[0] < size)
 612                        return -EINVAL;
 613                size = sizes[0];
 614        }
 615
 616        *nplanes = 1;
 617        sizes[0] = size;
 618
 619        ctx_dbg(3, ctx, "nbuffers=%d, size=%d\n", *nbuffers, sizes[0]);
 620
 621        return 0;
 622}
 623
 624static int cal_buffer_prepare(struct vb2_buffer *vb)
 625{
 626        struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 627        struct cal_buffer *buf = container_of(vb, struct cal_buffer,
 628                                              vb.vb2_buf);
 629        unsigned long size;
 630
 631        size = ctx->v_fmt.fmt.pix.sizeimage;
 632        if (vb2_plane_size(vb, 0) < size) {
 633                ctx_err(ctx,
 634                        "data will not fit into plane (%lu < %lu)\n",
 635                        vb2_plane_size(vb, 0), size);
 636                return -EINVAL;
 637        }
 638
 639        vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
 640        return 0;
 641}
 642
 643static void cal_buffer_queue(struct vb2_buffer *vb)
 644{
 645        struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 646        struct cal_buffer *buf = container_of(vb, struct cal_buffer,
 647                                              vb.vb2_buf);
 648        unsigned long flags;
 649
 650        /* recheck locking */
 651        spin_lock_irqsave(&ctx->dma.lock, flags);
 652        list_add_tail(&buf->list, &ctx->dma.queue);
 653        spin_unlock_irqrestore(&ctx->dma.lock, flags);
 654}
 655
 656static void cal_release_buffers(struct cal_ctx *ctx,
 657                                enum vb2_buffer_state state)
 658{
 659        struct cal_buffer *buf, *tmp;
 660
 661        /* Release all queued buffers. */
 662        spin_lock_irq(&ctx->dma.lock);
 663
 664        list_for_each_entry_safe(buf, tmp, &ctx->dma.queue, list) {
 665                list_del(&buf->list);
 666                vb2_buffer_done(&buf->vb.vb2_buf, state);
 667        }
 668
 669        if (ctx->dma.pending) {
 670                vb2_buffer_done(&ctx->dma.pending->vb.vb2_buf, state);
 671                ctx->dma.pending = NULL;
 672        }
 673
 674        if (ctx->dma.active) {
 675                vb2_buffer_done(&ctx->dma.active->vb.vb2_buf, state);
 676                ctx->dma.active = NULL;
 677        }
 678
 679        spin_unlock_irq(&ctx->dma.lock);
 680}
 681
 682/* ------------------------------------------------------------------
 683 *      videobuf2 Operations
 684 * ------------------------------------------------------------------
 685 */
 686
 687static int cal_video_check_format(struct cal_ctx *ctx)
 688{
 689        const struct v4l2_mbus_framefmt *format;
 690        struct media_pad *remote_pad;
 691
 692        remote_pad = media_entity_remote_pad(&ctx->pad);
 693        if (!remote_pad)
 694                return -ENODEV;
 695
 696        format = &ctx->phy->formats[remote_pad->index];
 697
 698        if (ctx->fmtinfo->code != format->code ||
 699            ctx->v_fmt.fmt.pix.height != format->height ||
 700            ctx->v_fmt.fmt.pix.width != format->width ||
 701            ctx->v_fmt.fmt.pix.field != format->field)
 702                return -EPIPE;
 703
 704        return 0;
 705}
 706
 707static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
 708{
 709        struct cal_ctx *ctx = vb2_get_drv_priv(vq);
 710        struct cal_buffer *buf;
 711        dma_addr_t addr;
 712        int ret;
 713
 714        ret = media_pipeline_start(&ctx->vdev.entity, &ctx->phy->pipe);
 715        if (ret < 0) {
 716                ctx_err(ctx, "Failed to start media pipeline: %d\n", ret);
 717                goto error_release_buffers;
 718        }
 719
 720        /*
 721         * Verify that the currently configured format matches the output of
 722         * the connected CAMERARX.
 723         */
 724        ret = cal_video_check_format(ctx);
 725        if (ret < 0) {
 726                ctx_dbg(3, ctx,
 727                        "Format mismatch between CAMERARX and video node\n");
 728                goto error_pipeline;
 729        }
 730
 731        ret = cal_ctx_prepare(ctx);
 732        if (ret) {
 733                ctx_err(ctx, "Failed to prepare context: %d\n", ret);
 734                goto error_pipeline;
 735        }
 736
 737        spin_lock_irq(&ctx->dma.lock);
 738        buf = list_first_entry(&ctx->dma.queue, struct cal_buffer, list);
 739        ctx->dma.active = buf;
 740        list_del(&buf->list);
 741        spin_unlock_irq(&ctx->dma.lock);
 742
 743        addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
 744
 745        ret = pm_runtime_resume_and_get(ctx->cal->dev);
 746        if (ret < 0)
 747                goto error_pipeline;
 748
 749        cal_ctx_set_dma_addr(ctx, addr);
 750        cal_ctx_start(ctx);
 751
 752        ret = v4l2_subdev_call(&ctx->phy->subdev, video, s_stream, 1);
 753        if (ret)
 754                goto error_stop;
 755
 756        if (cal_debug >= 4)
 757                cal_quickdump_regs(ctx->cal);
 758
 759        return 0;
 760
 761error_stop:
 762        cal_ctx_stop(ctx);
 763        pm_runtime_put_sync(ctx->cal->dev);
 764        cal_ctx_unprepare(ctx);
 765
 766error_pipeline:
 767        media_pipeline_stop(&ctx->vdev.entity);
 768error_release_buffers:
 769        cal_release_buffers(ctx, VB2_BUF_STATE_QUEUED);
 770
 771        return ret;
 772}
 773
 774static void cal_stop_streaming(struct vb2_queue *vq)
 775{
 776        struct cal_ctx *ctx = vb2_get_drv_priv(vq);
 777
 778        cal_ctx_stop(ctx);
 779
 780        v4l2_subdev_call(&ctx->phy->subdev, video, s_stream, 0);
 781
 782        pm_runtime_put_sync(ctx->cal->dev);
 783
 784        cal_ctx_unprepare(ctx);
 785
 786        cal_release_buffers(ctx, VB2_BUF_STATE_ERROR);
 787
 788        media_pipeline_stop(&ctx->vdev.entity);
 789}
 790
 791static const struct vb2_ops cal_video_qops = {
 792        .queue_setup            = cal_queue_setup,
 793        .buf_prepare            = cal_buffer_prepare,
 794        .buf_queue              = cal_buffer_queue,
 795        .start_streaming        = cal_start_streaming,
 796        .stop_streaming         = cal_stop_streaming,
 797        .wait_prepare           = vb2_ops_wait_prepare,
 798        .wait_finish            = vb2_ops_wait_finish,
 799};
 800
 801/* ------------------------------------------------------------------
 802 *      V4L2 Initialization and Registration
 803 * ------------------------------------------------------------------
 804 */
 805
 806static const struct v4l2_file_operations cal_fops = {
 807        .owner          = THIS_MODULE,
 808        .open           = v4l2_fh_open,
 809        .release        = vb2_fop_release,
 810        .poll           = vb2_fop_poll,
 811        .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
 812        .mmap           = vb2_fop_mmap,
 813};
 814
 815static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
 816{
 817        struct v4l2_subdev_mbus_code_enum mbus_code;
 818        struct v4l2_mbus_framefmt mbus_fmt;
 819        const struct cal_format_info *fmtinfo;
 820        unsigned int i, j, k;
 821        int ret = 0;
 822
 823        /* Enumerate sub device formats and enable all matching local formats */
 824        ctx->active_fmt = devm_kcalloc(ctx->cal->dev, cal_num_formats,
 825                                       sizeof(*ctx->active_fmt), GFP_KERNEL);
 826        ctx->num_active_fmt = 0;
 827
 828        for (j = 0, i = 0; ; ++j) {
 829
 830                memset(&mbus_code, 0, sizeof(mbus_code));
 831                mbus_code.index = j;
 832                mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 833                ret = v4l2_subdev_call(ctx->phy->source, pad, enum_mbus_code,
 834                                       NULL, &mbus_code);
 835                if (ret == -EINVAL)
 836                        break;
 837
 838                if (ret) {
 839                        ctx_err(ctx, "Error enumerating mbus codes in subdev %s: %d\n",
 840                                ctx->phy->source->name, ret);
 841                        return ret;
 842                }
 843
 844                ctx_dbg(2, ctx,
 845                        "subdev %s: code: %04x idx: %u\n",
 846                        ctx->phy->source->name, mbus_code.code, j);
 847
 848                for (k = 0; k < cal_num_formats; k++) {
 849                        fmtinfo = &cal_formats[k];
 850
 851                        if (mbus_code.code == fmtinfo->code) {
 852                                ctx->active_fmt[i] = fmtinfo;
 853                                ctx_dbg(2, ctx,
 854                                        "matched fourcc: %s: code: %04x idx: %u\n",
 855                                        fourcc_to_str(fmtinfo->fourcc),
 856                                        fmtinfo->code, i);
 857                                ctx->num_active_fmt = ++i;
 858                        }
 859                }
 860        }
 861
 862        if (i == 0) {
 863                ctx_err(ctx, "No suitable format reported by subdev %s\n",
 864                        ctx->phy->source->name);
 865                return -EINVAL;
 866        }
 867
 868        ret = __subdev_get_format(ctx, &mbus_fmt);
 869        if (ret)
 870                return ret;
 871
 872        fmtinfo = find_format_by_code(ctx, mbus_fmt.code);
 873        if (!fmtinfo) {
 874                ctx_dbg(3, ctx, "mbus code format (0x%08x) not found.\n",
 875                        mbus_fmt.code);
 876                return -EINVAL;
 877        }
 878
 879        /* Save current format */
 880        v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt);
 881        ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 882        ctx->v_fmt.fmt.pix.pixelformat = fmtinfo->fourcc;
 883        cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt);
 884        ctx->fmtinfo = fmtinfo;
 885
 886        return 0;
 887}
 888
 889static int cal_ctx_v4l2_init_mc_format(struct cal_ctx *ctx)
 890{
 891        const struct cal_format_info *fmtinfo;
 892        struct v4l2_pix_format *pix_fmt = &ctx->v_fmt.fmt.pix;
 893
 894        fmtinfo = cal_format_by_code(MEDIA_BUS_FMT_UYVY8_2X8);
 895        if (!fmtinfo)
 896                return -EINVAL;
 897
 898        pix_fmt->width = 640;
 899        pix_fmt->height = 480;
 900        pix_fmt->field = V4L2_FIELD_NONE;
 901        pix_fmt->colorspace = V4L2_COLORSPACE_SRGB;
 902        pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
 903        pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE;
 904        pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB;
 905        pix_fmt->pixelformat = fmtinfo->fourcc;
 906
 907        ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 908
 909        /* Save current format */
 910        cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt);
 911        ctx->fmtinfo = fmtinfo;
 912
 913        return 0;
 914}
 915
 916int cal_ctx_v4l2_register(struct cal_ctx *ctx)
 917{
 918        struct video_device *vfd = &ctx->vdev;
 919        int ret;
 920
 921        if (!cal_mc_api) {
 922                struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler;
 923
 924                ret = cal_ctx_v4l2_init_formats(ctx);
 925                if (ret) {
 926                        ctx_err(ctx, "Failed to init formats: %d\n", ret);
 927                        return ret;
 928                }
 929
 930                ret = v4l2_ctrl_add_handler(hdl, ctx->phy->source->ctrl_handler,
 931                                            NULL, true);
 932                if (ret < 0) {
 933                        ctx_err(ctx, "Failed to add source ctrl handler\n");
 934                        return ret;
 935                }
 936        } else {
 937                ret = cal_ctx_v4l2_init_mc_format(ctx);
 938                if (ret) {
 939                        ctx_err(ctx, "Failed to init format: %d\n", ret);
 940                        return ret;
 941                }
 942        }
 943
 944        ret = video_register_device(vfd, VFL_TYPE_VIDEO, cal_video_nr);
 945        if (ret < 0) {
 946                ctx_err(ctx, "Failed to register video device\n");
 947                return ret;
 948        }
 949
 950        ret = media_create_pad_link(&ctx->phy->subdev.entity,
 951                                    CAL_CAMERARX_PAD_FIRST_SOURCE,
 952                                    &vfd->entity, 0,
 953                                    MEDIA_LNK_FL_IMMUTABLE |
 954                                    MEDIA_LNK_FL_ENABLED);
 955        if (ret) {
 956                ctx_err(ctx, "Failed to create media link for context %u\n",
 957                        ctx->dma_ctx);
 958                video_unregister_device(vfd);
 959                return ret;
 960        }
 961
 962        ctx_info(ctx, "V4L2 device registered as %s\n",
 963                 video_device_node_name(vfd));
 964
 965        return 0;
 966}
 967
 968void cal_ctx_v4l2_unregister(struct cal_ctx *ctx)
 969{
 970        ctx_dbg(1, ctx, "unregistering %s\n",
 971                video_device_node_name(&ctx->vdev));
 972
 973        video_unregister_device(&ctx->vdev);
 974}
 975
 976int cal_ctx_v4l2_init(struct cal_ctx *ctx)
 977{
 978        struct video_device *vfd = &ctx->vdev;
 979        struct vb2_queue *q = &ctx->vb_vidq;
 980        int ret;
 981
 982        INIT_LIST_HEAD(&ctx->dma.queue);
 983        spin_lock_init(&ctx->dma.lock);
 984        mutex_init(&ctx->mutex);
 985        init_waitqueue_head(&ctx->dma.wait);
 986
 987        /* Initialize the vb2 queue. */
 988        q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 989        q->io_modes = VB2_MMAP | VB2_DMABUF;
 990        q->drv_priv = ctx;
 991        q->buf_struct_size = sizeof(struct cal_buffer);
 992        q->ops = &cal_video_qops;
 993        q->mem_ops = &vb2_dma_contig_memops;
 994        q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
 995        q->lock = &ctx->mutex;
 996        q->min_buffers_needed = 3;
 997        q->dev = ctx->cal->dev;
 998
 999        ret = vb2_queue_init(q);
1000        if (ret)
1001                return ret;
1002
1003        /* Initialize the video device and media entity. */
1004        vfd->fops = &cal_fops;
1005        vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING
1006                         | (cal_mc_api ? V4L2_CAP_IO_MC : 0);
1007        vfd->v4l2_dev = &ctx->cal->v4l2_dev;
1008        vfd->queue = q;
1009        snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->dma_ctx);
1010        vfd->release = video_device_release_empty;
1011        vfd->ioctl_ops = cal_mc_api ? &cal_ioctl_mc_ops : &cal_ioctl_legacy_ops;
1012        vfd->lock = &ctx->mutex;
1013        video_set_drvdata(vfd, ctx);
1014
1015        ctx->pad.flags = MEDIA_PAD_FL_SINK;
1016        ret = media_entity_pads_init(&vfd->entity, 1, &ctx->pad);
1017        if (ret < 0)
1018                return ret;
1019
1020        if (!cal_mc_api) {
1021                /* Initialize the control handler. */
1022                struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler;
1023
1024                ret = v4l2_ctrl_handler_init(hdl, 11);
1025                if (ret < 0) {
1026                        ctx_err(ctx, "Failed to init ctrl handler\n");
1027                        goto error;
1028                }
1029
1030                vfd->ctrl_handler = hdl;
1031        }
1032
1033        return 0;
1034
1035error:
1036        media_entity_cleanup(&vfd->entity);
1037        return ret;
1038}
1039
1040void cal_ctx_v4l2_cleanup(struct cal_ctx *ctx)
1041{
1042        if (!cal_mc_api)
1043                v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1044
1045        media_entity_cleanup(&ctx->vdev.entity);
1046}
1047