linux/drivers/media/platform/qcom/venus/venc.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
   3 * Copyright (C) 2017 Linaro Ltd.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 and
   7 * only version 2 as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 */
  15#include <linux/clk.h>
  16#include <linux/module.h>
  17#include <linux/platform_device.h>
  18#include <linux/pm_runtime.h>
  19#include <linux/slab.h>
  20#include <media/v4l2-mem2mem.h>
  21#include <media/videobuf2-dma-sg.h>
  22#include <media/v4l2-ioctl.h>
  23#include <media/v4l2-event.h>
  24#include <media/v4l2-ctrls.h>
  25
  26#include "hfi_venus_io.h"
  27#include "core.h"
  28#include "helpers.h"
  29#include "venc.h"
  30
  31#define NUM_B_FRAMES_MAX        4
  32
  33static u32 get_framesize_uncompressed(unsigned int plane, u32 width, u32 height)
  34{
  35        u32 y_stride, uv_stride, y_plane;
  36        u32 y_sclines, uv_sclines, uv_plane;
  37        u32 size;
  38
  39        y_stride = ALIGN(width, 128);
  40        uv_stride = ALIGN(width, 128);
  41        y_sclines = ALIGN(height, 32);
  42        uv_sclines = ALIGN(((height + 1) >> 1), 16);
  43
  44        y_plane = y_stride * y_sclines;
  45        uv_plane = uv_stride * uv_sclines + SZ_4K;
  46        size = y_plane + uv_plane + SZ_8K;
  47        size = ALIGN(size, SZ_4K);
  48
  49        return size;
  50}
  51
  52static u32 get_framesize_compressed(u32 width, u32 height)
  53{
  54        u32 sz = ALIGN(height, 32) * ALIGN(width, 32) * 3 / 2 / 2;
  55
  56        return ALIGN(sz, SZ_4K);
  57}
  58
  59/*
  60 * Three resons to keep MPLANE formats (despite that the number of planes
  61 * currently is one):
  62 * - the MPLANE formats allow only one plane to be used
  63 * - the downstream driver use MPLANE formats too
  64 * - future firmware versions could add support for >1 planes
  65 */
  66static const struct venus_format venc_formats[] = {
  67        {
  68                .pixfmt = V4L2_PIX_FMT_NV12,
  69                .num_planes = 1,
  70                .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
  71        }, {
  72                .pixfmt = V4L2_PIX_FMT_MPEG4,
  73                .num_planes = 1,
  74                .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
  75        }, {
  76                .pixfmt = V4L2_PIX_FMT_H263,
  77                .num_planes = 1,
  78                .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
  79        }, {
  80                .pixfmt = V4L2_PIX_FMT_H264,
  81                .num_planes = 1,
  82                .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
  83        }, {
  84                .pixfmt = V4L2_PIX_FMT_VP8,
  85                .num_planes = 1,
  86                .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
  87        },
  88};
  89
  90static const struct venus_format *
  91find_format(struct venus_inst *inst, u32 pixfmt, u32 type)
  92{
  93        const struct venus_format *fmt = venc_formats;
  94        unsigned int size = ARRAY_SIZE(venc_formats);
  95        unsigned int i;
  96
  97        for (i = 0; i < size; i++) {
  98                if (fmt[i].pixfmt == pixfmt)
  99                        break;
 100        }
 101
 102        if (i == size || fmt[i].type != type)
 103                return NULL;
 104
 105        if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
 106            !venus_helper_check_codec(inst, fmt[i].pixfmt))
 107                return NULL;
 108
 109        return &fmt[i];
 110}
 111
 112static const struct venus_format *
 113find_format_by_index(struct venus_inst *inst, unsigned int index, u32 type)
 114{
 115        const struct venus_format *fmt = venc_formats;
 116        unsigned int size = ARRAY_SIZE(venc_formats);
 117        unsigned int i, k = 0;
 118
 119        if (index > size)
 120                return NULL;
 121
 122        for (i = 0; i < size; i++) {
 123                bool valid;
 124
 125                if (fmt[i].type != type)
 126                        continue;
 127                valid = type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
 128                        venus_helper_check_codec(inst, fmt[i].pixfmt);
 129                if (k == index && valid)
 130                        break;
 131                if (valid)
 132                        k++;
 133        }
 134
 135        if (i == size)
 136                return NULL;
 137
 138        return &fmt[i];
 139}
 140
 141static int venc_v4l2_to_hfi(int id, int value)
 142{
 143        switch (id) {
 144        case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
 145                switch (value) {
 146                case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0:
 147                default:
 148                        return HFI_MPEG4_LEVEL_0;
 149                case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B:
 150                        return HFI_MPEG4_LEVEL_0b;
 151                case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1:
 152                        return HFI_MPEG4_LEVEL_1;
 153                case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2:
 154                        return HFI_MPEG4_LEVEL_2;
 155                case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3:
 156                        return HFI_MPEG4_LEVEL_3;
 157                case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4:
 158                        return HFI_MPEG4_LEVEL_4;
 159                case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5:
 160                        return HFI_MPEG4_LEVEL_5;
 161                }
 162        case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
 163                switch (value) {
 164                case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
 165                default:
 166                        return HFI_MPEG4_PROFILE_SIMPLE;
 167                case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
 168                        return HFI_MPEG4_PROFILE_ADVANCEDSIMPLE;
 169                }
 170        case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
 171                switch (value) {
 172                case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
 173                        return HFI_H264_PROFILE_BASELINE;
 174                case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
 175                        return HFI_H264_PROFILE_CONSTRAINED_BASE;
 176                case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
 177                        return HFI_H264_PROFILE_MAIN;
 178                case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
 179                default:
 180                        return HFI_H264_PROFILE_HIGH;
 181                }
 182        case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
 183                switch (value) {
 184                case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
 185                        return HFI_H264_LEVEL_1;
 186                case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
 187                        return HFI_H264_LEVEL_1b;
 188                case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
 189                        return HFI_H264_LEVEL_11;
 190                case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
 191                        return HFI_H264_LEVEL_12;
 192                case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
 193                        return HFI_H264_LEVEL_13;
 194                case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
 195                        return HFI_H264_LEVEL_2;
 196                case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
 197                        return HFI_H264_LEVEL_21;
 198                case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
 199                        return HFI_H264_LEVEL_22;
 200                case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
 201                        return HFI_H264_LEVEL_3;
 202                case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
 203                        return HFI_H264_LEVEL_31;
 204                case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
 205                        return HFI_H264_LEVEL_32;
 206                case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
 207                        return HFI_H264_LEVEL_4;
 208                case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
 209                        return HFI_H264_LEVEL_41;
 210                case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
 211                        return HFI_H264_LEVEL_42;
 212                case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
 213                default:
 214                        return HFI_H264_LEVEL_5;
 215                case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
 216                        return HFI_H264_LEVEL_51;
 217                }
 218        case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
 219                switch (value) {
 220                case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC:
 221                default:
 222                        return HFI_H264_ENTROPY_CAVLC;
 223                case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC:
 224                        return HFI_H264_ENTROPY_CABAC;
 225                }
 226        case V4L2_CID_MPEG_VIDEO_VPX_PROFILE:
 227                switch (value) {
 228                case 0:
 229                default:
 230                        return HFI_VPX_PROFILE_VERSION_0;
 231                case 1:
 232                        return HFI_VPX_PROFILE_VERSION_1;
 233                case 2:
 234                        return HFI_VPX_PROFILE_VERSION_2;
 235                case 3:
 236                        return HFI_VPX_PROFILE_VERSION_3;
 237                }
 238        case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
 239                switch (value) {
 240                case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED:
 241                default:
 242                        return HFI_H264_DB_MODE_ALL_BOUNDARY;
 243                case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED:
 244                        return HFI_H264_DB_MODE_DISABLE;
 245                case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY:
 246                        return HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY;
 247                }
 248        }
 249
 250        return 0;
 251}
 252
 253static int
 254venc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
 255{
 256        strlcpy(cap->driver, "qcom-venus", sizeof(cap->driver));
 257        strlcpy(cap->card, "Qualcomm Venus video encoder", sizeof(cap->card));
 258        strlcpy(cap->bus_info, "platform:qcom-venus", sizeof(cap->bus_info));
 259
 260        return 0;
 261}
 262
 263static int venc_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
 264{
 265        struct venus_inst *inst = to_inst(file);
 266        const struct venus_format *fmt;
 267
 268        fmt = find_format_by_index(inst, f->index, f->type);
 269
 270        memset(f->reserved, 0, sizeof(f->reserved));
 271
 272        if (!fmt)
 273                return -EINVAL;
 274
 275        f->pixelformat = fmt->pixfmt;
 276
 277        return 0;
 278}
 279
 280static const struct venus_format *
 281venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f)
 282{
 283        struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
 284        struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt;
 285        const struct venus_format *fmt;
 286        unsigned int p;
 287
 288        memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved));
 289        memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
 290
 291        fmt = find_format(inst, pixmp->pixelformat, f->type);
 292        if (!fmt) {
 293                if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
 294                        pixmp->pixelformat = V4L2_PIX_FMT_H264;
 295                else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 296                        pixmp->pixelformat = V4L2_PIX_FMT_NV12;
 297                else
 298                        return NULL;
 299                fmt = find_format(inst, pixmp->pixelformat, f->type);
 300                pixmp->width = 1280;
 301                pixmp->height = 720;
 302        }
 303
 304        pixmp->width = clamp(pixmp->width, inst->cap_width.min,
 305                             inst->cap_width.max);
 306        pixmp->height = clamp(pixmp->height, inst->cap_height.min,
 307                              inst->cap_height.max);
 308
 309        if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 310                pixmp->height = ALIGN(pixmp->height, 32);
 311
 312        pixmp->width = ALIGN(pixmp->width, 2);
 313        pixmp->height = ALIGN(pixmp->height, 2);
 314
 315        if (pixmp->field == V4L2_FIELD_ANY)
 316                pixmp->field = V4L2_FIELD_NONE;
 317        pixmp->num_planes = fmt->num_planes;
 318        pixmp->flags = 0;
 319
 320        if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 321                for (p = 0; p < pixmp->num_planes; p++) {
 322                        pfmt[p].sizeimage =
 323                                get_framesize_uncompressed(p, pixmp->width,
 324                                                           pixmp->height);
 325
 326                        pfmt[p].bytesperline = ALIGN(pixmp->width, 128);
 327                }
 328        } else {
 329                pfmt[0].sizeimage = get_framesize_compressed(pixmp->width,
 330                                                             pixmp->height);
 331                pfmt[0].bytesperline = 0;
 332        }
 333
 334        return fmt;
 335}
 336
 337static int venc_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
 338{
 339        struct venus_inst *inst = to_inst(file);
 340
 341        venc_try_fmt_common(inst, f);
 342
 343        return 0;
 344}
 345
 346static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
 347{
 348        struct venus_inst *inst = to_inst(file);
 349        struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
 350        struct v4l2_pix_format_mplane orig_pixmp;
 351        const struct venus_format *fmt;
 352        struct v4l2_format format;
 353        u32 pixfmt_out = 0, pixfmt_cap = 0;
 354
 355        orig_pixmp = *pixmp;
 356
 357        fmt = venc_try_fmt_common(inst, f);
 358        if (!fmt)
 359                return -EINVAL;
 360
 361        if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 362                pixfmt_out = pixmp->pixelformat;
 363                pixfmt_cap = inst->fmt_cap->pixfmt;
 364        } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 365                pixfmt_cap = pixmp->pixelformat;
 366                pixfmt_out = inst->fmt_out->pixfmt;
 367        }
 368
 369        memset(&format, 0, sizeof(format));
 370
 371        format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
 372        format.fmt.pix_mp.pixelformat = pixfmt_out;
 373        format.fmt.pix_mp.width = orig_pixmp.width;
 374        format.fmt.pix_mp.height = orig_pixmp.height;
 375        venc_try_fmt_common(inst, &format);
 376
 377        if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 378                inst->out_width = format.fmt.pix_mp.width;
 379                inst->out_height = format.fmt.pix_mp.height;
 380                inst->colorspace = pixmp->colorspace;
 381                inst->ycbcr_enc = pixmp->ycbcr_enc;
 382                inst->quantization = pixmp->quantization;
 383                inst->xfer_func = pixmp->xfer_func;
 384        }
 385
 386        memset(&format, 0, sizeof(format));
 387
 388        format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 389        format.fmt.pix_mp.pixelformat = pixfmt_cap;
 390        format.fmt.pix_mp.width = orig_pixmp.width;
 391        format.fmt.pix_mp.height = orig_pixmp.height;
 392        venc_try_fmt_common(inst, &format);
 393
 394        inst->width = format.fmt.pix_mp.width;
 395        inst->height = format.fmt.pix_mp.height;
 396
 397        if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 398                inst->fmt_out = fmt;
 399        else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
 400                inst->fmt_cap = fmt;
 401
 402        return 0;
 403}
 404
 405static int venc_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
 406{
 407        struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
 408        struct venus_inst *inst = to_inst(file);
 409        const struct venus_format *fmt;
 410
 411        if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
 412                fmt = inst->fmt_cap;
 413        else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 414                fmt = inst->fmt_out;
 415        else
 416                return -EINVAL;
 417
 418        pixmp->pixelformat = fmt->pixfmt;
 419
 420        if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 421                pixmp->width = inst->width;
 422                pixmp->height = inst->height;
 423                pixmp->colorspace = inst->colorspace;
 424                pixmp->ycbcr_enc = inst->ycbcr_enc;
 425                pixmp->quantization = inst->quantization;
 426                pixmp->xfer_func = inst->xfer_func;
 427        } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 428                pixmp->width = inst->out_width;
 429                pixmp->height = inst->out_height;
 430        }
 431
 432        venc_try_fmt_common(inst, f);
 433
 434        return 0;
 435}
 436
 437static int
 438venc_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
 439{
 440        struct venus_inst *inst = to_inst(file);
 441
 442        if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
 443                return -EINVAL;
 444
 445        switch (s->target) {
 446        case V4L2_SEL_TGT_CROP_DEFAULT:
 447        case V4L2_SEL_TGT_CROP_BOUNDS:
 448                s->r.width = inst->width;
 449                s->r.height = inst->height;
 450                break;
 451        case V4L2_SEL_TGT_CROP:
 452                s->r.width = inst->out_width;
 453                s->r.height = inst->out_height;
 454                break;
 455        default:
 456                return -EINVAL;
 457        }
 458
 459        s->r.top = 0;
 460        s->r.left = 0;
 461
 462        return 0;
 463}
 464
 465static int
 466venc_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
 467{
 468        struct venus_inst *inst = to_inst(file);
 469
 470        if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
 471                return -EINVAL;
 472
 473        switch (s->target) {
 474        case V4L2_SEL_TGT_CROP:
 475                if (s->r.width != inst->out_width ||
 476                    s->r.height != inst->out_height ||
 477                    s->r.top != 0 || s->r.left != 0)
 478                        return -EINVAL;
 479                break;
 480        default:
 481                return -EINVAL;
 482        }
 483
 484        return 0;
 485}
 486
 487static int venc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
 488{
 489        struct venus_inst *inst = to_inst(file);
 490        struct v4l2_outputparm *out = &a->parm.output;
 491        struct v4l2_fract *timeperframe = &out->timeperframe;
 492        u64 us_per_frame, fps;
 493
 494        if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
 495            a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 496                return -EINVAL;
 497
 498        memset(out->reserved, 0, sizeof(out->reserved));
 499
 500        if (!timeperframe->denominator)
 501                timeperframe->denominator = inst->timeperframe.denominator;
 502        if (!timeperframe->numerator)
 503                timeperframe->numerator = inst->timeperframe.numerator;
 504
 505        out->capability = V4L2_CAP_TIMEPERFRAME;
 506
 507        us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC;
 508        do_div(us_per_frame, timeperframe->denominator);
 509
 510        if (!us_per_frame)
 511                return -EINVAL;
 512
 513        fps = (u64)USEC_PER_SEC;
 514        do_div(fps, us_per_frame);
 515
 516        inst->timeperframe = *timeperframe;
 517        inst->fps = fps;
 518
 519        return 0;
 520}
 521
 522static int venc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
 523{
 524        struct venus_inst *inst = to_inst(file);
 525
 526        if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
 527            a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 528                return -EINVAL;
 529
 530        a->parm.output.capability |= V4L2_CAP_TIMEPERFRAME;
 531        a->parm.output.timeperframe = inst->timeperframe;
 532
 533        return 0;
 534}
 535
 536static int venc_enum_framesizes(struct file *file, void *fh,
 537                                struct v4l2_frmsizeenum *fsize)
 538{
 539        struct venus_inst *inst = to_inst(file);
 540        const struct venus_format *fmt;
 541
 542        fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
 543
 544        fmt = find_format(inst, fsize->pixel_format,
 545                          V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 546        if (!fmt) {
 547                fmt = find_format(inst, fsize->pixel_format,
 548                                  V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
 549                if (!fmt)
 550                        return -EINVAL;
 551        }
 552
 553        if (fsize->index)
 554                return -EINVAL;
 555
 556        fsize->stepwise.min_width = inst->cap_width.min;
 557        fsize->stepwise.max_width = inst->cap_width.max;
 558        fsize->stepwise.step_width = inst->cap_width.step_size;
 559        fsize->stepwise.min_height = inst->cap_height.min;
 560        fsize->stepwise.max_height = inst->cap_height.max;
 561        fsize->stepwise.step_height = inst->cap_height.step_size;
 562
 563        return 0;
 564}
 565
 566static int venc_enum_frameintervals(struct file *file, void *fh,
 567                                    struct v4l2_frmivalenum *fival)
 568{
 569        struct venus_inst *inst = to_inst(file);
 570        const struct venus_format *fmt;
 571
 572        fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
 573
 574        fmt = find_format(inst, fival->pixel_format,
 575                          V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 576        if (!fmt) {
 577                fmt = find_format(inst, fival->pixel_format,
 578                                  V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
 579                if (!fmt)
 580                        return -EINVAL;
 581        }
 582
 583        if (fival->index)
 584                return -EINVAL;
 585
 586        if (!fival->width || !fival->height)
 587                return -EINVAL;
 588
 589        if (fival->width > inst->cap_width.max ||
 590            fival->width < inst->cap_width.min ||
 591            fival->height > inst->cap_height.max ||
 592            fival->height < inst->cap_height.min)
 593                return -EINVAL;
 594
 595        fival->stepwise.min.numerator = 1;
 596        fival->stepwise.min.denominator = inst->cap_framerate.max;
 597        fival->stepwise.max.numerator = 1;
 598        fival->stepwise.max.denominator = inst->cap_framerate.min;
 599        fival->stepwise.step.numerator = 1;
 600        fival->stepwise.step.denominator = inst->cap_framerate.max;
 601
 602        return 0;
 603}
 604
 605static const struct v4l2_ioctl_ops venc_ioctl_ops = {
 606        .vidioc_querycap = venc_querycap,
 607        .vidioc_enum_fmt_vid_cap_mplane = venc_enum_fmt,
 608        .vidioc_enum_fmt_vid_out_mplane = venc_enum_fmt,
 609        .vidioc_s_fmt_vid_cap_mplane = venc_s_fmt,
 610        .vidioc_s_fmt_vid_out_mplane = venc_s_fmt,
 611        .vidioc_g_fmt_vid_cap_mplane = venc_g_fmt,
 612        .vidioc_g_fmt_vid_out_mplane = venc_g_fmt,
 613        .vidioc_try_fmt_vid_cap_mplane = venc_try_fmt,
 614        .vidioc_try_fmt_vid_out_mplane = venc_try_fmt,
 615        .vidioc_g_selection = venc_g_selection,
 616        .vidioc_s_selection = venc_s_selection,
 617        .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
 618        .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
 619        .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
 620        .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
 621        .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
 622        .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
 623        .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
 624        .vidioc_streamon = v4l2_m2m_ioctl_streamon,
 625        .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
 626        .vidioc_s_parm = venc_s_parm,
 627        .vidioc_g_parm = venc_g_parm,
 628        .vidioc_enum_framesizes = venc_enum_framesizes,
 629        .vidioc_enum_frameintervals = venc_enum_frameintervals,
 630        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 631        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 632};
 633
 634static int venc_set_properties(struct venus_inst *inst)
 635{
 636        struct venc_controls *ctr = &inst->controls.enc;
 637        struct hfi_intra_period intra_period;
 638        struct hfi_profile_level pl;
 639        struct hfi_framerate frate;
 640        struct hfi_bitrate brate;
 641        struct hfi_idr_period idrp;
 642        u32 ptype, rate_control, bitrate, profile = 0, level = 0;
 643        int ret;
 644
 645        ptype = HFI_PROPERTY_CONFIG_FRAME_RATE;
 646        frate.buffer_type = HFI_BUFFER_OUTPUT;
 647        frate.framerate = inst->fps * (1 << 16);
 648
 649        ret = hfi_session_set_property(inst, ptype, &frate);
 650        if (ret)
 651                return ret;
 652
 653        if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264) {
 654                struct hfi_h264_vui_timing_info info;
 655                struct hfi_h264_entropy_control entropy;
 656                struct hfi_h264_db_control deblock;
 657
 658                ptype = HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO;
 659                info.enable = 1;
 660                info.fixed_framerate = 1;
 661                info.time_scale = NSEC_PER_SEC;
 662
 663                ret = hfi_session_set_property(inst, ptype, &info);
 664                if (ret)
 665                        return ret;
 666
 667                ptype = HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL;
 668                entropy.entropy_mode = venc_v4l2_to_hfi(
 669                                          V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
 670                                          ctr->h264_entropy_mode);
 671                entropy.cabac_model = HFI_H264_CABAC_MODEL_0;
 672
 673                ret = hfi_session_set_property(inst, ptype, &entropy);
 674                if (ret)
 675                        return ret;
 676
 677                ptype = HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL;
 678                deblock.mode = venc_v4l2_to_hfi(
 679                                      V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
 680                                      ctr->h264_loop_filter_mode);
 681                deblock.slice_alpha_offset = ctr->h264_loop_filter_alpha;
 682                deblock.slice_beta_offset = ctr->h264_loop_filter_beta;
 683
 684                ret = hfi_session_set_property(inst, ptype, &deblock);
 685                if (ret)
 686                        return ret;
 687        }
 688
 689        /* IDR periodicity, n:
 690         * n = 0 - only the first I-frame is IDR frame
 691         * n = 1 - all I-frames will be IDR frames
 692         * n > 1 - every n-th I-frame will be IDR frame
 693         */
 694        ptype = HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD;
 695        idrp.idr_period = 0;
 696        ret = hfi_session_set_property(inst, ptype, &idrp);
 697        if (ret)
 698                return ret;
 699
 700        if (ctr->num_b_frames) {
 701                u32 max_num_b_frames = NUM_B_FRAMES_MAX;
 702
 703                ptype = HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES;
 704                ret = hfi_session_set_property(inst, ptype, &max_num_b_frames);
 705                if (ret)
 706                        return ret;
 707        }
 708
 709        ptype = HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD;
 710        intra_period.pframes = ctr->num_p_frames;
 711        intra_period.bframes = ctr->num_b_frames;
 712
 713        ret = hfi_session_set_property(inst, ptype, &intra_period);
 714        if (ret)
 715                return ret;
 716
 717        if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
 718                rate_control = HFI_RATE_CONTROL_VBR_CFR;
 719        else
 720                rate_control = HFI_RATE_CONTROL_CBR_CFR;
 721
 722        ptype = HFI_PROPERTY_PARAM_VENC_RATE_CONTROL;
 723        ret = hfi_session_set_property(inst, ptype, &rate_control);
 724        if (ret)
 725                return ret;
 726
 727        if (!ctr->bitrate)
 728                bitrate = 64000;
 729        else
 730                bitrate = ctr->bitrate;
 731
 732        ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
 733        brate.bitrate = bitrate;
 734        brate.layer_id = 0;
 735
 736        ret = hfi_session_set_property(inst, ptype, &brate);
 737        if (ret)
 738                return ret;
 739
 740        if (!ctr->bitrate_peak)
 741                bitrate *= 2;
 742        else
 743                bitrate = ctr->bitrate_peak;
 744
 745        ptype = HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE;
 746        brate.bitrate = bitrate;
 747        brate.layer_id = 0;
 748
 749        ret = hfi_session_set_property(inst, ptype, &brate);
 750        if (ret)
 751                return ret;
 752
 753        if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264) {
 754                profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_H264_PROFILE,
 755                                           ctr->profile.h264);
 756                level = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_H264_LEVEL,
 757                                         ctr->level.h264);
 758        } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_VP8) {
 759                profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_VPX_PROFILE,
 760                                           ctr->profile.vpx);
 761                level = 0;
 762        } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_MPEG4) {
 763                profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
 764                                           ctr->profile.mpeg4);
 765                level = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
 766                                         ctr->level.mpeg4);
 767        } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H263) {
 768                profile = 0;
 769                level = 0;
 770        }
 771
 772        ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
 773        pl.profile = profile;
 774        pl.level = level;
 775
 776        ret = hfi_session_set_property(inst, ptype, &pl);
 777        if (ret)
 778                return ret;
 779
 780        return 0;
 781}
 782
 783static int venc_init_session(struct venus_inst *inst)
 784{
 785        int ret;
 786
 787        ret = hfi_session_init(inst, inst->fmt_cap->pixfmt);
 788        if (ret)
 789                return ret;
 790
 791        ret = venus_helper_set_input_resolution(inst, inst->width,
 792                                                inst->height);
 793        if (ret)
 794                goto deinit;
 795
 796        ret = venus_helper_set_output_resolution(inst, inst->width,
 797                                                 inst->height);
 798        if (ret)
 799                goto deinit;
 800
 801        ret = venus_helper_set_color_format(inst, inst->fmt_out->pixfmt);
 802        if (ret)
 803                goto deinit;
 804
 805        ret = venc_set_properties(inst);
 806        if (ret)
 807                goto deinit;
 808
 809        return 0;
 810deinit:
 811        hfi_session_deinit(inst);
 812        return ret;
 813}
 814
 815static int venc_out_num_buffers(struct venus_inst *inst, unsigned int *num)
 816{
 817        struct hfi_buffer_requirements bufreq;
 818        int ret;
 819
 820        ret = venc_init_session(inst);
 821        if (ret)
 822                return ret;
 823
 824        ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq);
 825
 826        *num = bufreq.count_actual;
 827
 828        hfi_session_deinit(inst);
 829
 830        return ret;
 831}
 832
 833static int venc_queue_setup(struct vb2_queue *q,
 834                            unsigned int *num_buffers, unsigned int *num_planes,
 835                            unsigned int sizes[], struct device *alloc_devs[])
 836{
 837        struct venus_inst *inst = vb2_get_drv_priv(q);
 838        unsigned int p, num, min = 4;
 839        int ret = 0;
 840
 841        if (*num_planes) {
 842                if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
 843                    *num_planes != inst->fmt_out->num_planes)
 844                        return -EINVAL;
 845
 846                if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
 847                    *num_planes != inst->fmt_cap->num_planes)
 848                        return -EINVAL;
 849
 850                if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
 851                    sizes[0] < inst->input_buf_size)
 852                        return -EINVAL;
 853
 854                if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
 855                    sizes[0] < inst->output_buf_size)
 856                        return -EINVAL;
 857
 858                return 0;
 859        }
 860
 861        switch (q->type) {
 862        case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 863                *num_planes = inst->fmt_out->num_planes;
 864
 865                ret = venc_out_num_buffers(inst, &num);
 866                if (ret)
 867                        break;
 868
 869                num = max(num, min);
 870                *num_buffers = max(*num_buffers, num);
 871                inst->num_input_bufs = *num_buffers;
 872
 873                for (p = 0; p < *num_planes; ++p)
 874                        sizes[p] = get_framesize_uncompressed(p, inst->width,
 875                                                              inst->height);
 876                inst->input_buf_size = sizes[0];
 877                break;
 878        case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 879                *num_planes = inst->fmt_cap->num_planes;
 880                *num_buffers = max(*num_buffers, min);
 881                inst->num_output_bufs = *num_buffers;
 882                sizes[0] = get_framesize_compressed(inst->width, inst->height);
 883                inst->output_buf_size = sizes[0];
 884                break;
 885        default:
 886                ret = -EINVAL;
 887                break;
 888        }
 889
 890        return ret;
 891}
 892
 893static int venc_verify_conf(struct venus_inst *inst)
 894{
 895        struct hfi_buffer_requirements bufreq;
 896        int ret;
 897
 898        if (!inst->num_input_bufs || !inst->num_output_bufs)
 899                return -EINVAL;
 900
 901        ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq);
 902        if (ret)
 903                return ret;
 904
 905        if (inst->num_output_bufs < bufreq.count_actual ||
 906            inst->num_output_bufs < bufreq.count_min)
 907                return -EINVAL;
 908
 909        ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq);
 910        if (ret)
 911                return ret;
 912
 913        if (inst->num_input_bufs < bufreq.count_actual ||
 914            inst->num_input_bufs < bufreq.count_min)
 915                return -EINVAL;
 916
 917        return 0;
 918}
 919
 920static int venc_start_streaming(struct vb2_queue *q, unsigned int count)
 921{
 922        struct venus_inst *inst = vb2_get_drv_priv(q);
 923        int ret;
 924
 925        mutex_lock(&inst->lock);
 926
 927        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 928                inst->streamon_out = 1;
 929        else
 930                inst->streamon_cap = 1;
 931
 932        if (!(inst->streamon_out & inst->streamon_cap)) {
 933                mutex_unlock(&inst->lock);
 934                return 0;
 935        }
 936
 937        venus_helper_init_instance(inst);
 938
 939        inst->sequence_cap = 0;
 940        inst->sequence_out = 0;
 941
 942        ret = venc_init_session(inst);
 943        if (ret)
 944                goto bufs_done;
 945
 946        ret = venc_set_properties(inst);
 947        if (ret)
 948                goto deinit_sess;
 949
 950        ret = venc_verify_conf(inst);
 951        if (ret)
 952                goto deinit_sess;
 953
 954        ret = venus_helper_set_num_bufs(inst, inst->num_input_bufs,
 955                                        inst->num_output_bufs);
 956        if (ret)
 957                goto deinit_sess;
 958
 959        ret = venus_helper_vb2_start_streaming(inst);
 960        if (ret)
 961                goto deinit_sess;
 962
 963        mutex_unlock(&inst->lock);
 964
 965        return 0;
 966
 967deinit_sess:
 968        hfi_session_deinit(inst);
 969bufs_done:
 970        venus_helper_buffers_done(inst, VB2_BUF_STATE_QUEUED);
 971        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 972                inst->streamon_out = 0;
 973        else
 974                inst->streamon_cap = 0;
 975        mutex_unlock(&inst->lock);
 976        return ret;
 977}
 978
 979static const struct vb2_ops venc_vb2_ops = {
 980        .queue_setup = venc_queue_setup,
 981        .buf_init = venus_helper_vb2_buf_init,
 982        .buf_prepare = venus_helper_vb2_buf_prepare,
 983        .start_streaming = venc_start_streaming,
 984        .stop_streaming = venus_helper_vb2_stop_streaming,
 985        .buf_queue = venus_helper_vb2_buf_queue,
 986};
 987
 988static void venc_buf_done(struct venus_inst *inst, unsigned int buf_type,
 989                          u32 tag, u32 bytesused, u32 data_offset, u32 flags,
 990                          u32 hfi_flags, u64 timestamp_us)
 991{
 992        struct vb2_v4l2_buffer *vbuf;
 993        struct vb2_buffer *vb;
 994        unsigned int type;
 995
 996        if (buf_type == HFI_BUFFER_INPUT)
 997                type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
 998        else
 999                type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1000
1001        vbuf = venus_helper_find_buf(inst, type, tag);
1002        if (!vbuf)
1003                return;
1004
1005        vbuf->flags = flags;
1006
1007        if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
1008                vb = &vbuf->vb2_buf;
1009                vb2_set_plane_payload(vb, 0, bytesused + data_offset);
1010                vb->planes[0].data_offset = data_offset;
1011                vb->timestamp = timestamp_us * NSEC_PER_USEC;
1012                vbuf->sequence = inst->sequence_cap++;
1013        } else {
1014                vbuf->sequence = inst->sequence_out++;
1015        }
1016
1017        v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
1018}
1019
1020static void venc_event_notify(struct venus_inst *inst, u32 event,
1021                              struct hfi_event_data *data)
1022{
1023        struct device *dev = inst->core->dev_enc;
1024
1025        if (event == EVT_SESSION_ERROR) {
1026                inst->session_error = true;
1027                dev_err(dev, "enc: event session error %x\n", inst->error);
1028        }
1029}
1030
1031static const struct hfi_inst_ops venc_hfi_ops = {
1032        .buf_done = venc_buf_done,
1033        .event_notify = venc_event_notify,
1034};
1035
1036static const struct v4l2_m2m_ops venc_m2m_ops = {
1037        .device_run = venus_helper_m2m_device_run,
1038        .job_abort = venus_helper_m2m_job_abort,
1039};
1040
1041static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
1042                          struct vb2_queue *dst_vq)
1043{
1044        struct venus_inst *inst = priv;
1045        int ret;
1046
1047        src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1048        src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
1049        src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1050        src_vq->ops = &venc_vb2_ops;
1051        src_vq->mem_ops = &vb2_dma_sg_memops;
1052        src_vq->drv_priv = inst;
1053        src_vq->buf_struct_size = sizeof(struct venus_buffer);
1054        src_vq->allow_zero_bytesused = 1;
1055        src_vq->min_buffers_needed = 1;
1056        src_vq->dev = inst->core->dev;
1057        if (inst->core->res->hfi_version == HFI_VERSION_1XX)
1058                src_vq->bidirectional = 1;
1059        ret = vb2_queue_init(src_vq);
1060        if (ret)
1061                return ret;
1062
1063        dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1064        dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
1065        dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1066        dst_vq->ops = &venc_vb2_ops;
1067        dst_vq->mem_ops = &vb2_dma_sg_memops;
1068        dst_vq->drv_priv = inst;
1069        dst_vq->buf_struct_size = sizeof(struct venus_buffer);
1070        dst_vq->allow_zero_bytesused = 1;
1071        dst_vq->min_buffers_needed = 1;
1072        dst_vq->dev = inst->core->dev;
1073        ret = vb2_queue_init(dst_vq);
1074        if (ret) {
1075                vb2_queue_release(src_vq);
1076                return ret;
1077        }
1078
1079        return 0;
1080}
1081
1082static void venc_inst_init(struct venus_inst *inst)
1083{
1084        inst->fmt_cap = &venc_formats[2];
1085        inst->fmt_out = &venc_formats[0];
1086        inst->width = 1280;
1087        inst->height = ALIGN(720, 32);
1088        inst->out_width = 1280;
1089        inst->out_height = 720;
1090        inst->fps = 15;
1091        inst->timeperframe.numerator = 1;
1092        inst->timeperframe.denominator = 15;
1093
1094        inst->cap_width.min = 96;
1095        inst->cap_width.max = 1920;
1096        if (inst->core->res->hfi_version == HFI_VERSION_3XX)
1097                inst->cap_width.max = 3840;
1098        inst->cap_width.step_size = 2;
1099        inst->cap_height.min = 64;
1100        inst->cap_height.max = ALIGN(1080, 32);
1101        if (inst->core->res->hfi_version == HFI_VERSION_3XX)
1102                inst->cap_height.max = ALIGN(2160, 32);
1103        inst->cap_height.step_size = 2;
1104        inst->cap_framerate.min = 1;
1105        inst->cap_framerate.max = 30;
1106        inst->cap_framerate.step_size = 1;
1107        inst->cap_mbs_per_frame.min = 24;
1108        inst->cap_mbs_per_frame.max = 8160;
1109}
1110
1111static int venc_open(struct file *file)
1112{
1113        struct venus_core *core = video_drvdata(file);
1114        struct venus_inst *inst;
1115        int ret;
1116
1117        inst = kzalloc(sizeof(*inst), GFP_KERNEL);
1118        if (!inst)
1119                return -ENOMEM;
1120
1121        INIT_LIST_HEAD(&inst->registeredbufs);
1122        INIT_LIST_HEAD(&inst->internalbufs);
1123        INIT_LIST_HEAD(&inst->list);
1124        mutex_init(&inst->lock);
1125
1126        inst->core = core;
1127        inst->session_type = VIDC_SESSION_TYPE_ENC;
1128
1129        venus_helper_init_instance(inst);
1130
1131        ret = pm_runtime_get_sync(core->dev_enc);
1132        if (ret < 0)
1133                goto err_free_inst;
1134
1135        ret = venc_ctrl_init(inst);
1136        if (ret)
1137                goto err_put_sync;
1138
1139        ret = hfi_session_create(inst, &venc_hfi_ops);
1140        if (ret)
1141                goto err_ctrl_deinit;
1142
1143        venc_inst_init(inst);
1144
1145        /*
1146         * create m2m device for every instance, the m2m context scheduling
1147         * is made by firmware side so we do not need to care about.
1148         */
1149        inst->m2m_dev = v4l2_m2m_init(&venc_m2m_ops);
1150        if (IS_ERR(inst->m2m_dev)) {
1151                ret = PTR_ERR(inst->m2m_dev);
1152                goto err_session_destroy;
1153        }
1154
1155        inst->m2m_ctx = v4l2_m2m_ctx_init(inst->m2m_dev, inst, m2m_queue_init);
1156        if (IS_ERR(inst->m2m_ctx)) {
1157                ret = PTR_ERR(inst->m2m_ctx);
1158                goto err_m2m_release;
1159        }
1160
1161        v4l2_fh_init(&inst->fh, core->vdev_enc);
1162
1163        inst->fh.ctrl_handler = &inst->ctrl_handler;
1164        v4l2_fh_add(&inst->fh);
1165        inst->fh.m2m_ctx = inst->m2m_ctx;
1166        file->private_data = &inst->fh;
1167
1168        return 0;
1169
1170err_m2m_release:
1171        v4l2_m2m_release(inst->m2m_dev);
1172err_session_destroy:
1173        hfi_session_destroy(inst);
1174err_ctrl_deinit:
1175        venc_ctrl_deinit(inst);
1176err_put_sync:
1177        pm_runtime_put_sync(core->dev_enc);
1178err_free_inst:
1179        kfree(inst);
1180        return ret;
1181}
1182
1183static int venc_close(struct file *file)
1184{
1185        struct venus_inst *inst = to_inst(file);
1186
1187        v4l2_m2m_ctx_release(inst->m2m_ctx);
1188        v4l2_m2m_release(inst->m2m_dev);
1189        venc_ctrl_deinit(inst);
1190        hfi_session_destroy(inst);
1191        mutex_destroy(&inst->lock);
1192        v4l2_fh_del(&inst->fh);
1193        v4l2_fh_exit(&inst->fh);
1194
1195        pm_runtime_put_sync(inst->core->dev_enc);
1196
1197        kfree(inst);
1198        return 0;
1199}
1200
1201static const struct v4l2_file_operations venc_fops = {
1202        .owner = THIS_MODULE,
1203        .open = venc_open,
1204        .release = venc_close,
1205        .unlocked_ioctl = video_ioctl2,
1206        .poll = v4l2_m2m_fop_poll,
1207        .mmap = v4l2_m2m_fop_mmap,
1208#ifdef CONFIG_COMPAT
1209        .compat_ioctl32 = v4l2_compat_ioctl32,
1210#endif
1211};
1212
1213static int venc_probe(struct platform_device *pdev)
1214{
1215        struct device *dev = &pdev->dev;
1216        struct video_device *vdev;
1217        struct venus_core *core;
1218        int ret;
1219
1220        if (!dev->parent)
1221                return -EPROBE_DEFER;
1222
1223        core = dev_get_drvdata(dev->parent);
1224        if (!core)
1225                return -EPROBE_DEFER;
1226
1227        if (core->res->hfi_version == HFI_VERSION_3XX) {
1228                core->core1_clk = devm_clk_get(dev, "core");
1229                if (IS_ERR(core->core1_clk))
1230                        return PTR_ERR(core->core1_clk);
1231        }
1232
1233        platform_set_drvdata(pdev, core);
1234
1235        vdev = video_device_alloc();
1236        if (!vdev)
1237                return -ENOMEM;
1238
1239        strlcpy(vdev->name, "qcom-venus-encoder", sizeof(vdev->name));
1240        vdev->release = video_device_release;
1241        vdev->fops = &venc_fops;
1242        vdev->ioctl_ops = &venc_ioctl_ops;
1243        vdev->vfl_dir = VFL_DIR_M2M;
1244        vdev->v4l2_dev = &core->v4l2_dev;
1245        vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
1246
1247        ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
1248        if (ret)
1249                goto err_vdev_release;
1250
1251        core->vdev_enc = vdev;
1252        core->dev_enc = dev;
1253
1254        video_set_drvdata(vdev, core);
1255        pm_runtime_enable(dev);
1256
1257        return 0;
1258
1259err_vdev_release:
1260        video_device_release(vdev);
1261        return ret;
1262}
1263
1264static int venc_remove(struct platform_device *pdev)
1265{
1266        struct venus_core *core = dev_get_drvdata(pdev->dev.parent);
1267
1268        video_unregister_device(core->vdev_enc);
1269        pm_runtime_disable(core->dev_enc);
1270
1271        return 0;
1272}
1273
1274static __maybe_unused int venc_runtime_suspend(struct device *dev)
1275{
1276        struct venus_core *core = dev_get_drvdata(dev);
1277
1278        if (core->res->hfi_version == HFI_VERSION_1XX)
1279                return 0;
1280
1281        writel(0, core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL);
1282        clk_disable_unprepare(core->core1_clk);
1283        writel(1, core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL);
1284
1285        return 0;
1286}
1287
1288static __maybe_unused int venc_runtime_resume(struct device *dev)
1289{
1290        struct venus_core *core = dev_get_drvdata(dev);
1291        int ret;
1292
1293        if (core->res->hfi_version == HFI_VERSION_1XX)
1294                return 0;
1295
1296        writel(0, core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL);
1297        ret = clk_prepare_enable(core->core1_clk);
1298        writel(1, core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL);
1299
1300        return ret;
1301}
1302
1303static const struct dev_pm_ops venc_pm_ops = {
1304        SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
1305                                pm_runtime_force_resume)
1306        SET_RUNTIME_PM_OPS(venc_runtime_suspend, venc_runtime_resume, NULL)
1307};
1308
1309static const struct of_device_id venc_dt_match[] = {
1310        { .compatible = "venus-encoder" },
1311        { }
1312};
1313MODULE_DEVICE_TABLE(of, venc_dt_match);
1314
1315static struct platform_driver qcom_venus_enc_driver = {
1316        .probe = venc_probe,
1317        .remove = venc_remove,
1318        .driver = {
1319                .name = "qcom-venus-encoder",
1320                .of_match_table = venc_dt_match,
1321                .pm = &venc_pm_ops,
1322        },
1323};
1324module_platform_driver(qcom_venus_enc_driver);
1325
1326MODULE_ALIAS("platform:qcom-venus-encoder");
1327MODULE_DESCRIPTION("Qualcomm Venus video encoder driver");
1328MODULE_LICENSE("GPL v2");
1329