linux/drivers/media/platform/qcom/venus/helpers.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
   4 * Copyright (C) 2017 Linaro Ltd.
   5 */
   6#include <linux/list.h>
   7#include <linux/mutex.h>
   8#include <linux/slab.h>
   9#include <media/videobuf2-dma-sg.h>
  10#include <media/v4l2-mem2mem.h>
  11#include <asm/div64.h>
  12
  13#include "core.h"
  14#include "helpers.h"
  15#include "hfi_helper.h"
  16#include "pm_helpers.h"
  17
  18struct intbuf {
  19        struct list_head list;
  20        u32 type;
  21        size_t size;
  22        void *va;
  23        dma_addr_t da;
  24        unsigned long attrs;
  25};
  26
  27bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt)
  28{
  29        struct venus_core *core = inst->core;
  30        u32 session_type = inst->session_type;
  31        u32 codec;
  32
  33        switch (v4l2_pixfmt) {
  34        case V4L2_PIX_FMT_H264:
  35                codec = HFI_VIDEO_CODEC_H264;
  36                break;
  37        case V4L2_PIX_FMT_H263:
  38                codec = HFI_VIDEO_CODEC_H263;
  39                break;
  40        case V4L2_PIX_FMT_MPEG1:
  41                codec = HFI_VIDEO_CODEC_MPEG1;
  42                break;
  43        case V4L2_PIX_FMT_MPEG2:
  44                codec = HFI_VIDEO_CODEC_MPEG2;
  45                break;
  46        case V4L2_PIX_FMT_MPEG4:
  47                codec = HFI_VIDEO_CODEC_MPEG4;
  48                break;
  49        case V4L2_PIX_FMT_VC1_ANNEX_G:
  50        case V4L2_PIX_FMT_VC1_ANNEX_L:
  51                codec = HFI_VIDEO_CODEC_VC1;
  52                break;
  53        case V4L2_PIX_FMT_VP8:
  54                codec = HFI_VIDEO_CODEC_VP8;
  55                break;
  56        case V4L2_PIX_FMT_VP9:
  57                codec = HFI_VIDEO_CODEC_VP9;
  58                break;
  59        case V4L2_PIX_FMT_XVID:
  60                codec = HFI_VIDEO_CODEC_DIVX;
  61                break;
  62        case V4L2_PIX_FMT_HEVC:
  63                codec = HFI_VIDEO_CODEC_HEVC;
  64                break;
  65        default:
  66                return false;
  67        }
  68
  69        if (session_type == VIDC_SESSION_TYPE_ENC && core->enc_codecs & codec)
  70                return true;
  71
  72        if (session_type == VIDC_SESSION_TYPE_DEC && core->dec_codecs & codec)
  73                return true;
  74
  75        return false;
  76}
  77EXPORT_SYMBOL_GPL(venus_helper_check_codec);
  78
  79int venus_helper_queue_dpb_bufs(struct venus_inst *inst)
  80{
  81        struct intbuf *buf;
  82        int ret = 0;
  83
  84        list_for_each_entry(buf, &inst->dpbbufs, list) {
  85                struct hfi_frame_data fdata;
  86
  87                memset(&fdata, 0, sizeof(fdata));
  88                fdata.alloc_len = buf->size;
  89                fdata.device_addr = buf->da;
  90                fdata.buffer_type = buf->type;
  91
  92                ret = hfi_session_process_buf(inst, &fdata);
  93                if (ret)
  94                        goto fail;
  95        }
  96
  97fail:
  98        return ret;
  99}
 100EXPORT_SYMBOL_GPL(venus_helper_queue_dpb_bufs);
 101
 102int venus_helper_free_dpb_bufs(struct venus_inst *inst)
 103{
 104        struct intbuf *buf, *n;
 105
 106        list_for_each_entry_safe(buf, n, &inst->dpbbufs, list) {
 107                list_del_init(&buf->list);
 108                dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da,
 109                               buf->attrs);
 110                kfree(buf);
 111        }
 112
 113        INIT_LIST_HEAD(&inst->dpbbufs);
 114
 115        return 0;
 116}
 117EXPORT_SYMBOL_GPL(venus_helper_free_dpb_bufs);
 118
 119int venus_helper_alloc_dpb_bufs(struct venus_inst *inst)
 120{
 121        struct venus_core *core = inst->core;
 122        struct device *dev = core->dev;
 123        enum hfi_version ver = core->res->hfi_version;
 124        struct hfi_buffer_requirements bufreq;
 125        u32 buftype = inst->dpb_buftype;
 126        unsigned int dpb_size = 0;
 127        struct intbuf *buf;
 128        unsigned int i;
 129        u32 count;
 130        int ret;
 131
 132        /* no need to allocate dpb buffers */
 133        if (!inst->dpb_fmt)
 134                return 0;
 135
 136        if (inst->dpb_buftype == HFI_BUFFER_OUTPUT)
 137                dpb_size = inst->output_buf_size;
 138        else if (inst->dpb_buftype == HFI_BUFFER_OUTPUT2)
 139                dpb_size = inst->output2_buf_size;
 140
 141        if (!dpb_size)
 142                return 0;
 143
 144        ret = venus_helper_get_bufreq(inst, buftype, &bufreq);
 145        if (ret)
 146                return ret;
 147
 148        count = HFI_BUFREQ_COUNT_MIN(&bufreq, ver);
 149
 150        for (i = 0; i < count; i++) {
 151                buf = kzalloc(sizeof(*buf), GFP_KERNEL);
 152                if (!buf) {
 153                        ret = -ENOMEM;
 154                        goto fail;
 155                }
 156
 157                buf->type = buftype;
 158                buf->size = dpb_size;
 159                buf->attrs = DMA_ATTR_WRITE_COMBINE |
 160                             DMA_ATTR_NO_KERNEL_MAPPING;
 161                buf->va = dma_alloc_attrs(dev, buf->size, &buf->da, GFP_KERNEL,
 162                                          buf->attrs);
 163                if (!buf->va) {
 164                        kfree(buf);
 165                        ret = -ENOMEM;
 166                        goto fail;
 167                }
 168
 169                list_add_tail(&buf->list, &inst->dpbbufs);
 170        }
 171
 172        return 0;
 173
 174fail:
 175        venus_helper_free_dpb_bufs(inst);
 176        return ret;
 177}
 178EXPORT_SYMBOL_GPL(venus_helper_alloc_dpb_bufs);
 179
 180static int intbufs_set_buffer(struct venus_inst *inst, u32 type)
 181{
 182        struct venus_core *core = inst->core;
 183        struct device *dev = core->dev;
 184        struct hfi_buffer_requirements bufreq;
 185        struct hfi_buffer_desc bd;
 186        struct intbuf *buf;
 187        unsigned int i;
 188        int ret;
 189
 190        ret = venus_helper_get_bufreq(inst, type, &bufreq);
 191        if (ret)
 192                return 0;
 193
 194        if (!bufreq.size)
 195                return 0;
 196
 197        for (i = 0; i < bufreq.count_actual; i++) {
 198                buf = kzalloc(sizeof(*buf), GFP_KERNEL);
 199                if (!buf) {
 200                        ret = -ENOMEM;
 201                        goto fail;
 202                }
 203
 204                buf->type = bufreq.type;
 205                buf->size = bufreq.size;
 206                buf->attrs = DMA_ATTR_WRITE_COMBINE |
 207                             DMA_ATTR_NO_KERNEL_MAPPING;
 208                buf->va = dma_alloc_attrs(dev, buf->size, &buf->da, GFP_KERNEL,
 209                                          buf->attrs);
 210                if (!buf->va) {
 211                        ret = -ENOMEM;
 212                        goto fail;
 213                }
 214
 215                memset(&bd, 0, sizeof(bd));
 216                bd.buffer_size = buf->size;
 217                bd.buffer_type = buf->type;
 218                bd.num_buffers = 1;
 219                bd.device_addr = buf->da;
 220
 221                ret = hfi_session_set_buffers(inst, &bd);
 222                if (ret) {
 223                        dev_err(dev, "set session buffers failed\n");
 224                        goto dma_free;
 225                }
 226
 227                list_add_tail(&buf->list, &inst->internalbufs);
 228        }
 229
 230        return 0;
 231
 232dma_free:
 233        dma_free_attrs(dev, buf->size, buf->va, buf->da, buf->attrs);
 234fail:
 235        kfree(buf);
 236        return ret;
 237}
 238
 239static int intbufs_unset_buffers(struct venus_inst *inst)
 240{
 241        struct hfi_buffer_desc bd = {0};
 242        struct intbuf *buf, *n;
 243        int ret = 0;
 244
 245        list_for_each_entry_safe(buf, n, &inst->internalbufs, list) {
 246                bd.buffer_size = buf->size;
 247                bd.buffer_type = buf->type;
 248                bd.num_buffers = 1;
 249                bd.device_addr = buf->da;
 250                bd.response_required = true;
 251
 252                ret = hfi_session_unset_buffers(inst, &bd);
 253
 254                list_del_init(&buf->list);
 255                dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da,
 256                               buf->attrs);
 257                kfree(buf);
 258        }
 259
 260        return ret;
 261}
 262
 263static const unsigned int intbuf_types_1xx[] = {
 264        HFI_BUFFER_INTERNAL_SCRATCH(HFI_VERSION_1XX),
 265        HFI_BUFFER_INTERNAL_SCRATCH_1(HFI_VERSION_1XX),
 266        HFI_BUFFER_INTERNAL_SCRATCH_2(HFI_VERSION_1XX),
 267        HFI_BUFFER_INTERNAL_PERSIST,
 268        HFI_BUFFER_INTERNAL_PERSIST_1,
 269};
 270
 271static const unsigned int intbuf_types_4xx[] = {
 272        HFI_BUFFER_INTERNAL_SCRATCH(HFI_VERSION_4XX),
 273        HFI_BUFFER_INTERNAL_SCRATCH_1(HFI_VERSION_4XX),
 274        HFI_BUFFER_INTERNAL_SCRATCH_2(HFI_VERSION_4XX),
 275        HFI_BUFFER_INTERNAL_PERSIST,
 276        HFI_BUFFER_INTERNAL_PERSIST_1,
 277};
 278
 279int venus_helper_intbufs_alloc(struct venus_inst *inst)
 280{
 281        const unsigned int *intbuf;
 282        size_t arr_sz, i;
 283        int ret;
 284
 285        if (IS_V4(inst->core)) {
 286                arr_sz = ARRAY_SIZE(intbuf_types_4xx);
 287                intbuf = intbuf_types_4xx;
 288        } else {
 289                arr_sz = ARRAY_SIZE(intbuf_types_1xx);
 290                intbuf = intbuf_types_1xx;
 291        }
 292
 293        for (i = 0; i < arr_sz; i++) {
 294                ret = intbufs_set_buffer(inst, intbuf[i]);
 295                if (ret)
 296                        goto error;
 297        }
 298
 299        return 0;
 300
 301error:
 302        intbufs_unset_buffers(inst);
 303        return ret;
 304}
 305EXPORT_SYMBOL_GPL(venus_helper_intbufs_alloc);
 306
 307int venus_helper_intbufs_free(struct venus_inst *inst)
 308{
 309        return intbufs_unset_buffers(inst);
 310}
 311EXPORT_SYMBOL_GPL(venus_helper_intbufs_free);
 312
 313int venus_helper_intbufs_realloc(struct venus_inst *inst)
 314{
 315        enum hfi_version ver = inst->core->res->hfi_version;
 316        struct hfi_buffer_desc bd;
 317        struct intbuf *buf, *n;
 318        int ret;
 319
 320        list_for_each_entry_safe(buf, n, &inst->internalbufs, list) {
 321                if (buf->type == HFI_BUFFER_INTERNAL_PERSIST ||
 322                    buf->type == HFI_BUFFER_INTERNAL_PERSIST_1)
 323                        continue;
 324
 325                memset(&bd, 0, sizeof(bd));
 326                bd.buffer_size = buf->size;
 327                bd.buffer_type = buf->type;
 328                bd.num_buffers = 1;
 329                bd.device_addr = buf->da;
 330                bd.response_required = true;
 331
 332                ret = hfi_session_unset_buffers(inst, &bd);
 333
 334                dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da,
 335                               buf->attrs);
 336
 337                list_del_init(&buf->list);
 338                kfree(buf);
 339        }
 340
 341        ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH(ver));
 342        if (ret)
 343                goto err;
 344
 345        ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH_1(ver));
 346        if (ret)
 347                goto err;
 348
 349        ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH_2(ver));
 350        if (ret)
 351                goto err;
 352
 353        return 0;
 354err:
 355        return ret;
 356}
 357EXPORT_SYMBOL_GPL(venus_helper_intbufs_realloc);
 358
 359static void fill_buffer_desc(const struct venus_buffer *buf,
 360                             struct hfi_buffer_desc *bd, bool response)
 361{
 362        memset(bd, 0, sizeof(*bd));
 363        bd->buffer_type = HFI_BUFFER_OUTPUT;
 364        bd->buffer_size = buf->size;
 365        bd->num_buffers = 1;
 366        bd->device_addr = buf->dma_addr;
 367        bd->response_required = response;
 368}
 369
 370static void return_buf_error(struct venus_inst *inst,
 371                             struct vb2_v4l2_buffer *vbuf)
 372{
 373        struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
 374
 375        if (vbuf->vb2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 376                v4l2_m2m_src_buf_remove_by_buf(m2m_ctx, vbuf);
 377        else
 378                v4l2_m2m_dst_buf_remove_by_buf(m2m_ctx, vbuf);
 379
 380        v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
 381}
 382
 383static void
 384put_ts_metadata(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
 385{
 386        struct vb2_buffer *vb = &vbuf->vb2_buf;
 387        unsigned int i;
 388        int slot = -1;
 389        u64 ts_us = vb->timestamp;
 390
 391        for (i = 0; i < ARRAY_SIZE(inst->tss); i++) {
 392                if (!inst->tss[i].used) {
 393                        slot = i;
 394                        break;
 395                }
 396        }
 397
 398        if (slot == -1) {
 399                dev_dbg(inst->core->dev, "%s: no free slot\n", __func__);
 400                return;
 401        }
 402
 403        do_div(ts_us, NSEC_PER_USEC);
 404
 405        inst->tss[slot].used = true;
 406        inst->tss[slot].flags = vbuf->flags;
 407        inst->tss[slot].tc = vbuf->timecode;
 408        inst->tss[slot].ts_us = ts_us;
 409        inst->tss[slot].ts_ns = vb->timestamp;
 410}
 411
 412void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us,
 413                                  struct vb2_v4l2_buffer *vbuf)
 414{
 415        struct vb2_buffer *vb = &vbuf->vb2_buf;
 416        unsigned int i;
 417
 418        for (i = 0; i < ARRAY_SIZE(inst->tss); ++i) {
 419                if (!inst->tss[i].used)
 420                        continue;
 421
 422                if (inst->tss[i].ts_us != timestamp_us)
 423                        continue;
 424
 425                inst->tss[i].used = false;
 426                vbuf->flags |= inst->tss[i].flags;
 427                vbuf->timecode = inst->tss[i].tc;
 428                vb->timestamp = inst->tss[i].ts_ns;
 429                break;
 430        }
 431}
 432EXPORT_SYMBOL_GPL(venus_helper_get_ts_metadata);
 433
 434static int
 435session_process_buf(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
 436{
 437        struct venus_buffer *buf = to_venus_buffer(vbuf);
 438        struct vb2_buffer *vb = &vbuf->vb2_buf;
 439        unsigned int type = vb->type;
 440        struct hfi_frame_data fdata;
 441        int ret;
 442
 443        memset(&fdata, 0, sizeof(fdata));
 444        fdata.alloc_len = buf->size;
 445        fdata.device_addr = buf->dma_addr;
 446        fdata.timestamp = vb->timestamp;
 447        do_div(fdata.timestamp, NSEC_PER_USEC);
 448        fdata.flags = 0;
 449        fdata.clnt_data = vbuf->vb2_buf.index;
 450
 451        if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 452                fdata.buffer_type = HFI_BUFFER_INPUT;
 453                fdata.filled_len = vb2_get_plane_payload(vb, 0);
 454                fdata.offset = vb->planes[0].data_offset;
 455
 456                if (vbuf->flags & V4L2_BUF_FLAG_LAST || !fdata.filled_len)
 457                        fdata.flags |= HFI_BUFFERFLAG_EOS;
 458
 459                if (inst->session_type == VIDC_SESSION_TYPE_DEC)
 460                        put_ts_metadata(inst, vbuf);
 461
 462                venus_pm_load_scale(inst);
 463        } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 464                if (inst->session_type == VIDC_SESSION_TYPE_ENC)
 465                        fdata.buffer_type = HFI_BUFFER_OUTPUT;
 466                else
 467                        fdata.buffer_type = inst->opb_buftype;
 468                fdata.filled_len = 0;
 469                fdata.offset = 0;
 470        }
 471
 472        ret = hfi_session_process_buf(inst, &fdata);
 473        if (ret)
 474                return ret;
 475
 476        return 0;
 477}
 478
 479static bool is_dynamic_bufmode(struct venus_inst *inst)
 480{
 481        struct venus_core *core = inst->core;
 482        struct venus_caps *caps;
 483
 484        /*
 485         * v4 doesn't send BUFFER_ALLOC_MODE_SUPPORTED property and supports
 486         * dynamic buffer mode by default for HFI_BUFFER_OUTPUT/OUTPUT2.
 487         */
 488        if (IS_V4(core))
 489                return true;
 490
 491        caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type);
 492        if (!caps)
 493                return false;
 494
 495        return caps->cap_bufs_mode_dynamic;
 496}
 497
 498int venus_helper_unregister_bufs(struct venus_inst *inst)
 499{
 500        struct venus_buffer *buf, *n;
 501        struct hfi_buffer_desc bd;
 502        int ret = 0;
 503
 504        if (is_dynamic_bufmode(inst))
 505                return 0;
 506
 507        list_for_each_entry_safe(buf, n, &inst->registeredbufs, reg_list) {
 508                fill_buffer_desc(buf, &bd, true);
 509                ret = hfi_session_unset_buffers(inst, &bd);
 510                list_del_init(&buf->reg_list);
 511        }
 512
 513        return ret;
 514}
 515EXPORT_SYMBOL_GPL(venus_helper_unregister_bufs);
 516
 517static int session_register_bufs(struct venus_inst *inst)
 518{
 519        struct venus_core *core = inst->core;
 520        struct device *dev = core->dev;
 521        struct hfi_buffer_desc bd;
 522        struct venus_buffer *buf;
 523        int ret = 0;
 524
 525        if (is_dynamic_bufmode(inst))
 526                return 0;
 527
 528        list_for_each_entry(buf, &inst->registeredbufs, reg_list) {
 529                fill_buffer_desc(buf, &bd, false);
 530                ret = hfi_session_set_buffers(inst, &bd);
 531                if (ret) {
 532                        dev_err(dev, "%s: set buffer failed\n", __func__);
 533                        break;
 534                }
 535        }
 536
 537        return ret;
 538}
 539
 540static u32 to_hfi_raw_fmt(u32 v4l2_fmt)
 541{
 542        switch (v4l2_fmt) {
 543        case V4L2_PIX_FMT_NV12:
 544                return HFI_COLOR_FORMAT_NV12;
 545        case V4L2_PIX_FMT_NV21:
 546                return HFI_COLOR_FORMAT_NV21;
 547        default:
 548                break;
 549        }
 550
 551        return 0;
 552}
 553
 554int venus_helper_get_bufreq(struct venus_inst *inst, u32 type,
 555                            struct hfi_buffer_requirements *req)
 556{
 557        u32 ptype = HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS;
 558        union hfi_get_property hprop;
 559        unsigned int i;
 560        int ret;
 561
 562        if (req)
 563                memset(req, 0, sizeof(*req));
 564
 565        ret = hfi_session_get_property(inst, ptype, &hprop);
 566        if (ret)
 567                return ret;
 568
 569        ret = -EINVAL;
 570
 571        for (i = 0; i < HFI_BUFFER_TYPE_MAX; i++) {
 572                if (hprop.bufreq[i].type != type)
 573                        continue;
 574
 575                if (req)
 576                        memcpy(req, &hprop.bufreq[i], sizeof(*req));
 577                ret = 0;
 578                break;
 579        }
 580
 581        return ret;
 582}
 583EXPORT_SYMBOL_GPL(venus_helper_get_bufreq);
 584
 585static u32 get_framesize_raw_nv12(u32 width, u32 height)
 586{
 587        u32 y_stride, uv_stride, y_plane;
 588        u32 y_sclines, uv_sclines, uv_plane;
 589        u32 size;
 590
 591        y_stride = ALIGN(width, 128);
 592        uv_stride = ALIGN(width, 128);
 593        y_sclines = ALIGN(height, 32);
 594        uv_sclines = ALIGN(((height + 1) >> 1), 16);
 595
 596        y_plane = y_stride * y_sclines;
 597        uv_plane = uv_stride * uv_sclines + SZ_4K;
 598        size = y_plane + uv_plane + SZ_8K;
 599
 600        return ALIGN(size, SZ_4K);
 601}
 602
 603static u32 get_framesize_raw_nv12_ubwc(u32 width, u32 height)
 604{
 605        u32 y_meta_stride, y_meta_plane;
 606        u32 y_stride, y_plane;
 607        u32 uv_meta_stride, uv_meta_plane;
 608        u32 uv_stride, uv_plane;
 609        u32 extradata = SZ_16K;
 610
 611        y_meta_stride = ALIGN(DIV_ROUND_UP(width, 32), 64);
 612        y_meta_plane = y_meta_stride * ALIGN(DIV_ROUND_UP(height, 8), 16);
 613        y_meta_plane = ALIGN(y_meta_plane, SZ_4K);
 614
 615        y_stride = ALIGN(width, 128);
 616        y_plane = ALIGN(y_stride * ALIGN(height, 32), SZ_4K);
 617
 618        uv_meta_stride = ALIGN(DIV_ROUND_UP(width / 2, 16), 64);
 619        uv_meta_plane = uv_meta_stride * ALIGN(DIV_ROUND_UP(height / 2, 8), 16);
 620        uv_meta_plane = ALIGN(uv_meta_plane, SZ_4K);
 621
 622        uv_stride = ALIGN(width, 128);
 623        uv_plane = ALIGN(uv_stride * ALIGN(height / 2, 32), SZ_4K);
 624
 625        return ALIGN(y_meta_plane + y_plane + uv_meta_plane + uv_plane +
 626                     max(extradata, y_stride * 48), SZ_4K);
 627}
 628
 629static u32 get_framesize_raw_p010(u32 width, u32 height)
 630{
 631        u32 y_plane, uv_plane, y_stride, uv_stride, y_sclines, uv_sclines;
 632
 633        y_stride = ALIGN(width * 2, 256);
 634        uv_stride = ALIGN(width * 2, 256);
 635        y_sclines = ALIGN(height, 32);
 636        uv_sclines = ALIGN((height + 1) >> 1, 16);
 637        y_plane = y_stride * y_sclines;
 638        uv_plane = uv_stride * uv_sclines;
 639
 640        return ALIGN((y_plane + uv_plane), SZ_4K);
 641}
 642
 643static u32 get_framesize_raw_p010_ubwc(u32 width, u32 height)
 644{
 645        u32 y_stride, uv_stride, y_sclines, uv_sclines;
 646        u32 y_ubwc_plane, uv_ubwc_plane;
 647        u32 y_meta_stride, y_meta_scanlines;
 648        u32 uv_meta_stride, uv_meta_scanlines;
 649        u32 y_meta_plane, uv_meta_plane;
 650        u32 size;
 651
 652        y_stride = ALIGN(width * 2, 256);
 653        uv_stride = ALIGN(width * 2, 256);
 654        y_sclines = ALIGN(height, 16);
 655        uv_sclines = ALIGN((height + 1) >> 1, 16);
 656
 657        y_ubwc_plane = ALIGN(y_stride * y_sclines, SZ_4K);
 658        uv_ubwc_plane = ALIGN(uv_stride * uv_sclines, SZ_4K);
 659        y_meta_stride = ALIGN(DIV_ROUND_UP(width, 32), 64);
 660        y_meta_scanlines = ALIGN(DIV_ROUND_UP(height, 4), 16);
 661        y_meta_plane = ALIGN(y_meta_stride * y_meta_scanlines, SZ_4K);
 662        uv_meta_stride = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 16), 64);
 663        uv_meta_scanlines = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 4), 16);
 664        uv_meta_plane = ALIGN(uv_meta_stride * uv_meta_scanlines, SZ_4K);
 665
 666        size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane;
 667
 668        return ALIGN(size, SZ_4K);
 669}
 670
 671static u32 get_framesize_raw_yuv420_tp10_ubwc(u32 width, u32 height)
 672{
 673        u32 y_stride, uv_stride, y_sclines, uv_sclines;
 674        u32 y_ubwc_plane, uv_ubwc_plane;
 675        u32 y_meta_stride, y_meta_scanlines;
 676        u32 uv_meta_stride, uv_meta_scanlines;
 677        u32 y_meta_plane, uv_meta_plane;
 678        u32 extradata = SZ_16K;
 679        u32 size;
 680
 681        y_stride = ALIGN(ALIGN(width, 192) * 4 / 3, 256);
 682        uv_stride = ALIGN(ALIGN(width, 192) * 4 / 3, 256);
 683        y_sclines = ALIGN(height, 16);
 684        uv_sclines = ALIGN((height + 1) >> 1, 16);
 685
 686        y_ubwc_plane = ALIGN(y_stride * y_sclines, SZ_4K);
 687        uv_ubwc_plane = ALIGN(uv_stride * uv_sclines, SZ_4K);
 688        y_meta_stride = ALIGN(DIV_ROUND_UP(width, 48), 64);
 689        y_meta_scanlines = ALIGN(DIV_ROUND_UP(height, 4), 16);
 690        y_meta_plane = ALIGN(y_meta_stride * y_meta_scanlines, SZ_4K);
 691        uv_meta_stride = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 24), 64);
 692        uv_meta_scanlines = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 4), 16);
 693        uv_meta_plane = ALIGN(uv_meta_stride * uv_meta_scanlines, SZ_4K);
 694
 695        size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane;
 696        size += max(extradata + SZ_8K, y_stride * 48);
 697
 698        return ALIGN(size, SZ_4K);
 699}
 700
 701u32 venus_helper_get_framesz_raw(u32 hfi_fmt, u32 width, u32 height)
 702{
 703        switch (hfi_fmt) {
 704        case HFI_COLOR_FORMAT_NV12:
 705        case HFI_COLOR_FORMAT_NV21:
 706                return get_framesize_raw_nv12(width, height);
 707        case HFI_COLOR_FORMAT_NV12_UBWC:
 708                return get_framesize_raw_nv12_ubwc(width, height);
 709        case HFI_COLOR_FORMAT_P010:
 710                return get_framesize_raw_p010(width, height);
 711        case HFI_COLOR_FORMAT_P010_UBWC:
 712                return get_framesize_raw_p010_ubwc(width, height);
 713        case HFI_COLOR_FORMAT_YUV420_TP10_UBWC:
 714                return get_framesize_raw_yuv420_tp10_ubwc(width, height);
 715        default:
 716                return 0;
 717        }
 718}
 719EXPORT_SYMBOL_GPL(venus_helper_get_framesz_raw);
 720
 721u32 venus_helper_get_framesz(u32 v4l2_fmt, u32 width, u32 height)
 722{
 723        u32 hfi_fmt, sz;
 724        bool compressed;
 725
 726        switch (v4l2_fmt) {
 727        case V4L2_PIX_FMT_MPEG:
 728        case V4L2_PIX_FMT_H264:
 729        case V4L2_PIX_FMT_H264_NO_SC:
 730        case V4L2_PIX_FMT_H264_MVC:
 731        case V4L2_PIX_FMT_H263:
 732        case V4L2_PIX_FMT_MPEG1:
 733        case V4L2_PIX_FMT_MPEG2:
 734        case V4L2_PIX_FMT_MPEG4:
 735        case V4L2_PIX_FMT_XVID:
 736        case V4L2_PIX_FMT_VC1_ANNEX_G:
 737        case V4L2_PIX_FMT_VC1_ANNEX_L:
 738        case V4L2_PIX_FMT_VP8:
 739        case V4L2_PIX_FMT_VP9:
 740        case V4L2_PIX_FMT_HEVC:
 741                compressed = true;
 742                break;
 743        default:
 744                compressed = false;
 745                break;
 746        }
 747
 748        if (compressed) {
 749                sz = ALIGN(height, 32) * ALIGN(width, 32) * 3 / 2 / 2;
 750                return ALIGN(sz, SZ_4K);
 751        }
 752
 753        hfi_fmt = to_hfi_raw_fmt(v4l2_fmt);
 754        if (!hfi_fmt)
 755                return 0;
 756
 757        return venus_helper_get_framesz_raw(hfi_fmt, width, height);
 758}
 759EXPORT_SYMBOL_GPL(venus_helper_get_framesz);
 760
 761int venus_helper_set_input_resolution(struct venus_inst *inst,
 762                                      unsigned int width, unsigned int height)
 763{
 764        u32 ptype = HFI_PROPERTY_PARAM_FRAME_SIZE;
 765        struct hfi_framesize fs;
 766
 767        fs.buffer_type = HFI_BUFFER_INPUT;
 768        fs.width = width;
 769        fs.height = height;
 770
 771        return hfi_session_set_property(inst, ptype, &fs);
 772}
 773EXPORT_SYMBOL_GPL(venus_helper_set_input_resolution);
 774
 775int venus_helper_set_output_resolution(struct venus_inst *inst,
 776                                       unsigned int width, unsigned int height,
 777                                       u32 buftype)
 778{
 779        u32 ptype = HFI_PROPERTY_PARAM_FRAME_SIZE;
 780        struct hfi_framesize fs;
 781
 782        fs.buffer_type = buftype;
 783        fs.width = width;
 784        fs.height = height;
 785
 786        return hfi_session_set_property(inst, ptype, &fs);
 787}
 788EXPORT_SYMBOL_GPL(venus_helper_set_output_resolution);
 789
 790int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode)
 791{
 792        const u32 ptype = HFI_PROPERTY_PARAM_WORK_MODE;
 793        struct hfi_video_work_mode wm;
 794
 795        if (!IS_V4(inst->core))
 796                return 0;
 797
 798        wm.video_work_mode = mode;
 799
 800        return hfi_session_set_property(inst, ptype, &wm);
 801}
 802EXPORT_SYMBOL_GPL(venus_helper_set_work_mode);
 803
 804int venus_helper_init_codec_freq_data(struct venus_inst *inst)
 805{
 806        const struct codec_freq_data *data;
 807        unsigned int i, data_size;
 808        u32 pixfmt;
 809        int ret = 0;
 810
 811        if (!IS_V4(inst->core))
 812                return 0;
 813
 814        data = inst->core->res->codec_freq_data;
 815        data_size = inst->core->res->codec_freq_data_size;
 816        pixfmt = inst->session_type == VIDC_SESSION_TYPE_DEC ?
 817                        inst->fmt_out->pixfmt : inst->fmt_cap->pixfmt;
 818
 819        for (i = 0; i < data_size; i++) {
 820                if (data[i].pixfmt == pixfmt &&
 821                    data[i].session_type == inst->session_type) {
 822                        inst->clk_data.codec_freq_data = &data[i];
 823                        break;
 824                }
 825        }
 826
 827        if (!inst->clk_data.codec_freq_data)
 828                ret = -EINVAL;
 829
 830        return ret;
 831}
 832EXPORT_SYMBOL_GPL(venus_helper_init_codec_freq_data);
 833
 834int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs,
 835                              unsigned int output_bufs,
 836                              unsigned int output2_bufs)
 837{
 838        u32 ptype = HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL;
 839        struct hfi_buffer_count_actual buf_count;
 840        int ret;
 841
 842        buf_count.type = HFI_BUFFER_INPUT;
 843        buf_count.count_actual = input_bufs;
 844
 845        ret = hfi_session_set_property(inst, ptype, &buf_count);
 846        if (ret)
 847                return ret;
 848
 849        buf_count.type = HFI_BUFFER_OUTPUT;
 850        buf_count.count_actual = output_bufs;
 851
 852        ret = hfi_session_set_property(inst, ptype, &buf_count);
 853        if (ret)
 854                return ret;
 855
 856        if (output2_bufs) {
 857                buf_count.type = HFI_BUFFER_OUTPUT2;
 858                buf_count.count_actual = output2_bufs;
 859
 860                ret = hfi_session_set_property(inst, ptype, &buf_count);
 861        }
 862
 863        return ret;
 864}
 865EXPORT_SYMBOL_GPL(venus_helper_set_num_bufs);
 866
 867int venus_helper_set_raw_format(struct venus_inst *inst, u32 hfi_format,
 868                                u32 buftype)
 869{
 870        const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT;
 871        struct hfi_uncompressed_format_select fmt;
 872
 873        fmt.buffer_type = buftype;
 874        fmt.format = hfi_format;
 875
 876        return hfi_session_set_property(inst, ptype, &fmt);
 877}
 878EXPORT_SYMBOL_GPL(venus_helper_set_raw_format);
 879
 880int venus_helper_set_color_format(struct venus_inst *inst, u32 pixfmt)
 881{
 882        u32 hfi_format, buftype;
 883
 884        if (inst->session_type == VIDC_SESSION_TYPE_DEC)
 885                buftype = HFI_BUFFER_OUTPUT;
 886        else if (inst->session_type == VIDC_SESSION_TYPE_ENC)
 887                buftype = HFI_BUFFER_INPUT;
 888        else
 889                return -EINVAL;
 890
 891        hfi_format = to_hfi_raw_fmt(pixfmt);
 892        if (!hfi_format)
 893                return -EINVAL;
 894
 895        return venus_helper_set_raw_format(inst, hfi_format, buftype);
 896}
 897EXPORT_SYMBOL_GPL(venus_helper_set_color_format);
 898
 899int venus_helper_set_multistream(struct venus_inst *inst, bool out_en,
 900                                 bool out2_en)
 901{
 902        struct hfi_multi_stream multi = {0};
 903        u32 ptype = HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM;
 904        int ret;
 905
 906        multi.buffer_type = HFI_BUFFER_OUTPUT;
 907        multi.enable = out_en;
 908
 909        ret = hfi_session_set_property(inst, ptype, &multi);
 910        if (ret)
 911                return ret;
 912
 913        multi.buffer_type = HFI_BUFFER_OUTPUT2;
 914        multi.enable = out2_en;
 915
 916        return hfi_session_set_property(inst, ptype, &multi);
 917}
 918EXPORT_SYMBOL_GPL(venus_helper_set_multistream);
 919
 920int venus_helper_set_dyn_bufmode(struct venus_inst *inst)
 921{
 922        const u32 ptype = HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE;
 923        struct hfi_buffer_alloc_mode mode;
 924        int ret;
 925
 926        if (!is_dynamic_bufmode(inst))
 927                return 0;
 928
 929        mode.type = HFI_BUFFER_OUTPUT;
 930        mode.mode = HFI_BUFFER_MODE_DYNAMIC;
 931
 932        ret = hfi_session_set_property(inst, ptype, &mode);
 933        if (ret)
 934                return ret;
 935
 936        mode.type = HFI_BUFFER_OUTPUT2;
 937
 938        return hfi_session_set_property(inst, ptype, &mode);
 939}
 940EXPORT_SYMBOL_GPL(venus_helper_set_dyn_bufmode);
 941
 942int venus_helper_set_bufsize(struct venus_inst *inst, u32 bufsize, u32 buftype)
 943{
 944        const u32 ptype = HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL;
 945        struct hfi_buffer_size_actual bufsz;
 946
 947        bufsz.type = buftype;
 948        bufsz.size = bufsize;
 949
 950        return hfi_session_set_property(inst, ptype, &bufsz);
 951}
 952EXPORT_SYMBOL_GPL(venus_helper_set_bufsize);
 953
 954unsigned int venus_helper_get_opb_size(struct venus_inst *inst)
 955{
 956        /* the encoder has only one output */
 957        if (inst->session_type == VIDC_SESSION_TYPE_ENC)
 958                return inst->output_buf_size;
 959
 960        if (inst->opb_buftype == HFI_BUFFER_OUTPUT)
 961                return inst->output_buf_size;
 962        else if (inst->opb_buftype == HFI_BUFFER_OUTPUT2)
 963                return inst->output2_buf_size;
 964
 965        return 0;
 966}
 967EXPORT_SYMBOL_GPL(venus_helper_get_opb_size);
 968
 969static void delayed_process_buf_func(struct work_struct *work)
 970{
 971        struct venus_buffer *buf, *n;
 972        struct venus_inst *inst;
 973        int ret;
 974
 975        inst = container_of(work, struct venus_inst, delayed_process_work);
 976
 977        mutex_lock(&inst->lock);
 978
 979        if (!(inst->streamon_out & inst->streamon_cap))
 980                goto unlock;
 981
 982        list_for_each_entry_safe(buf, n, &inst->delayed_process, ref_list) {
 983                if (buf->flags & HFI_BUFFERFLAG_READONLY)
 984                        continue;
 985
 986                ret = session_process_buf(inst, &buf->vb);
 987                if (ret)
 988                        return_buf_error(inst, &buf->vb);
 989
 990                list_del_init(&buf->ref_list);
 991        }
 992unlock:
 993        mutex_unlock(&inst->lock);
 994}
 995
 996void venus_helper_release_buf_ref(struct venus_inst *inst, unsigned int idx)
 997{
 998        struct venus_buffer *buf;
 999
1000        list_for_each_entry(buf, &inst->registeredbufs, reg_list) {
1001                if (buf->vb.vb2_buf.index == idx) {
1002                        buf->flags &= ~HFI_BUFFERFLAG_READONLY;
1003                        schedule_work(&inst->delayed_process_work);
1004                        break;
1005                }
1006        }
1007}
1008EXPORT_SYMBOL_GPL(venus_helper_release_buf_ref);
1009
1010void venus_helper_acquire_buf_ref(struct vb2_v4l2_buffer *vbuf)
1011{
1012        struct venus_buffer *buf = to_venus_buffer(vbuf);
1013
1014        buf->flags |= HFI_BUFFERFLAG_READONLY;
1015}
1016EXPORT_SYMBOL_GPL(venus_helper_acquire_buf_ref);
1017
1018static int is_buf_refed(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
1019{
1020        struct venus_buffer *buf = to_venus_buffer(vbuf);
1021
1022        if (buf->flags & HFI_BUFFERFLAG_READONLY) {
1023                list_add_tail(&buf->ref_list, &inst->delayed_process);
1024                schedule_work(&inst->delayed_process_work);
1025                return 1;
1026        }
1027
1028        return 0;
1029}
1030
1031struct vb2_v4l2_buffer *
1032venus_helper_find_buf(struct venus_inst *inst, unsigned int type, u32 idx)
1033{
1034        struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1035
1036        if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
1037                return v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, idx);
1038        else
1039                return v4l2_m2m_dst_buf_remove_by_idx(m2m_ctx, idx);
1040}
1041EXPORT_SYMBOL_GPL(venus_helper_find_buf);
1042
1043int venus_helper_vb2_buf_init(struct vb2_buffer *vb)
1044{
1045        struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
1046        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1047        struct venus_buffer *buf = to_venus_buffer(vbuf);
1048        struct sg_table *sgt;
1049
1050        sgt = vb2_dma_sg_plane_desc(vb, 0);
1051        if (!sgt)
1052                return -EFAULT;
1053
1054        buf->size = vb2_plane_size(vb, 0);
1055        buf->dma_addr = sg_dma_address(sgt->sgl);
1056
1057        if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
1058                list_add_tail(&buf->reg_list, &inst->registeredbufs);
1059
1060        return 0;
1061}
1062EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_init);
1063
1064int venus_helper_vb2_buf_prepare(struct vb2_buffer *vb)
1065{
1066        struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
1067        unsigned int out_buf_size = venus_helper_get_opb_size(inst);
1068        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1069
1070        if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1071                if (vbuf->field == V4L2_FIELD_ANY)
1072                        vbuf->field = V4L2_FIELD_NONE;
1073                if (vbuf->field != V4L2_FIELD_NONE) {
1074                        dev_err(inst->core->dev, "%s field isn't supported\n",
1075                                __func__);
1076                        return -EINVAL;
1077                }
1078        }
1079
1080        if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
1081            vb2_plane_size(vb, 0) < out_buf_size)
1082                return -EINVAL;
1083        if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
1084            vb2_plane_size(vb, 0) < inst->input_buf_size)
1085                return -EINVAL;
1086
1087        return 0;
1088}
1089EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_prepare);
1090
1091static void cache_payload(struct venus_inst *inst, struct vb2_buffer *vb)
1092{
1093        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1094        unsigned int idx = vbuf->vb2_buf.index;
1095
1096        if (vbuf->vb2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
1097                inst->payloads[idx] = vb2_get_plane_payload(vb, 0);
1098}
1099
1100void venus_helper_vb2_buf_queue(struct vb2_buffer *vb)
1101{
1102        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1103        struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
1104        struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1105        int ret;
1106
1107        mutex_lock(&inst->lock);
1108
1109        v4l2_m2m_buf_queue(m2m_ctx, vbuf);
1110
1111        cache_payload(inst, vb);
1112
1113        if (inst->session_type == VIDC_SESSION_TYPE_ENC &&
1114            !(inst->streamon_out && inst->streamon_cap))
1115                goto unlock;
1116
1117        if (vb2_start_streaming_called(vb->vb2_queue)) {
1118                ret = is_buf_refed(inst, vbuf);
1119                if (ret)
1120                        goto unlock;
1121
1122                ret = session_process_buf(inst, vbuf);
1123                if (ret)
1124                        return_buf_error(inst, vbuf);
1125        }
1126
1127unlock:
1128        mutex_unlock(&inst->lock);
1129}
1130EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_queue);
1131
1132void venus_helper_buffers_done(struct venus_inst *inst, unsigned int type,
1133                               enum vb2_buffer_state state)
1134{
1135        struct vb2_v4l2_buffer *buf;
1136
1137        if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
1138                while ((buf = v4l2_m2m_src_buf_remove(inst->m2m_ctx)))
1139                        v4l2_m2m_buf_done(buf, state);
1140        } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
1141                while ((buf = v4l2_m2m_dst_buf_remove(inst->m2m_ctx)))
1142                        v4l2_m2m_buf_done(buf, state);
1143        }
1144}
1145EXPORT_SYMBOL_GPL(venus_helper_buffers_done);
1146
1147void venus_helper_vb2_stop_streaming(struct vb2_queue *q)
1148{
1149        struct venus_inst *inst = vb2_get_drv_priv(q);
1150        struct venus_core *core = inst->core;
1151        int ret;
1152
1153        mutex_lock(&inst->lock);
1154
1155        if (inst->streamon_out & inst->streamon_cap) {
1156                ret = hfi_session_stop(inst);
1157                ret |= hfi_session_unload_res(inst);
1158                ret |= venus_helper_unregister_bufs(inst);
1159                ret |= venus_helper_intbufs_free(inst);
1160                ret |= hfi_session_deinit(inst);
1161
1162                if (inst->session_error || core->sys_error)
1163                        ret = -EIO;
1164
1165                if (ret)
1166                        hfi_session_abort(inst);
1167
1168                venus_helper_free_dpb_bufs(inst);
1169
1170                venus_pm_load_scale(inst);
1171                INIT_LIST_HEAD(&inst->registeredbufs);
1172        }
1173
1174        venus_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
1175                                  VB2_BUF_STATE_ERROR);
1176        venus_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
1177                                  VB2_BUF_STATE_ERROR);
1178
1179        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
1180                inst->streamon_out = 0;
1181        else
1182                inst->streamon_cap = 0;
1183
1184        venus_pm_release_core(inst);
1185
1186        mutex_unlock(&inst->lock);
1187}
1188EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming);
1189
1190int venus_helper_process_initial_cap_bufs(struct venus_inst *inst)
1191{
1192        struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1193        struct v4l2_m2m_buffer *buf, *n;
1194        int ret;
1195
1196        v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n) {
1197                ret = session_process_buf(inst, &buf->vb);
1198                if (ret) {
1199                        return_buf_error(inst, &buf->vb);
1200                        return ret;
1201                }
1202        }
1203
1204        return 0;
1205}
1206EXPORT_SYMBOL_GPL(venus_helper_process_initial_cap_bufs);
1207
1208int venus_helper_process_initial_out_bufs(struct venus_inst *inst)
1209{
1210        struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1211        struct v4l2_m2m_buffer *buf, *n;
1212        int ret;
1213
1214        v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
1215                ret = session_process_buf(inst, &buf->vb);
1216                if (ret) {
1217                        return_buf_error(inst, &buf->vb);
1218                        return ret;
1219                }
1220        }
1221
1222        return 0;
1223}
1224EXPORT_SYMBOL_GPL(venus_helper_process_initial_out_bufs);
1225
1226int venus_helper_vb2_start_streaming(struct venus_inst *inst)
1227{
1228        int ret;
1229
1230        ret = venus_helper_intbufs_alloc(inst);
1231        if (ret)
1232                return ret;
1233
1234        ret = session_register_bufs(inst);
1235        if (ret)
1236                goto err_bufs_free;
1237
1238        venus_pm_load_scale(inst);
1239
1240        ret = hfi_session_load_res(inst);
1241        if (ret)
1242                goto err_unreg_bufs;
1243
1244        ret = hfi_session_start(inst);
1245        if (ret)
1246                goto err_unload_res;
1247
1248        return 0;
1249
1250err_unload_res:
1251        hfi_session_unload_res(inst);
1252err_unreg_bufs:
1253        venus_helper_unregister_bufs(inst);
1254err_bufs_free:
1255        venus_helper_intbufs_free(inst);
1256        return ret;
1257}
1258EXPORT_SYMBOL_GPL(venus_helper_vb2_start_streaming);
1259
1260void venus_helper_m2m_device_run(void *priv)
1261{
1262        struct venus_inst *inst = priv;
1263        struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
1264        struct v4l2_m2m_buffer *buf, *n;
1265        int ret;
1266
1267        mutex_lock(&inst->lock);
1268
1269        v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n) {
1270                ret = session_process_buf(inst, &buf->vb);
1271                if (ret)
1272                        return_buf_error(inst, &buf->vb);
1273        }
1274
1275        v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
1276                ret = session_process_buf(inst, &buf->vb);
1277                if (ret)
1278                        return_buf_error(inst, &buf->vb);
1279        }
1280
1281        mutex_unlock(&inst->lock);
1282}
1283EXPORT_SYMBOL_GPL(venus_helper_m2m_device_run);
1284
1285void venus_helper_m2m_job_abort(void *priv)
1286{
1287        struct venus_inst *inst = priv;
1288
1289        v4l2_m2m_job_finish(inst->m2m_dev, inst->m2m_ctx);
1290}
1291EXPORT_SYMBOL_GPL(venus_helper_m2m_job_abort);
1292
1293void venus_helper_init_instance(struct venus_inst *inst)
1294{
1295        if (inst->session_type == VIDC_SESSION_TYPE_DEC) {
1296                INIT_LIST_HEAD(&inst->delayed_process);
1297                INIT_WORK(&inst->delayed_process_work,
1298                          delayed_process_buf_func);
1299        }
1300}
1301EXPORT_SYMBOL_GPL(venus_helper_init_instance);
1302
1303static bool find_fmt_from_caps(struct venus_caps *caps, u32 buftype, u32 fmt)
1304{
1305        unsigned int i;
1306
1307        for (i = 0; i < caps->num_fmts; i++) {
1308                if (caps->fmts[i].buftype == buftype &&
1309                    caps->fmts[i].fmt == fmt)
1310                        return true;
1311        }
1312
1313        return false;
1314}
1315
1316int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt,
1317                              u32 *out_fmt, u32 *out2_fmt, bool ubwc)
1318{
1319        struct venus_core *core = inst->core;
1320        struct venus_caps *caps;
1321        u32 ubwc_fmt, fmt = to_hfi_raw_fmt(v4l2_fmt);
1322        bool found, found_ubwc;
1323
1324        *out_fmt = *out2_fmt = 0;
1325
1326        if (!fmt)
1327                return -EINVAL;
1328
1329        caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type);
1330        if (!caps)
1331                return -EINVAL;
1332
1333        if (inst->bit_depth == VIDC_BITDEPTH_10 &&
1334            inst->session_type == VIDC_SESSION_TYPE_DEC) {
1335                found_ubwc =
1336                        find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT,
1337                                           HFI_COLOR_FORMAT_YUV420_TP10_UBWC);
1338                found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2,
1339                                           HFI_COLOR_FORMAT_NV12);
1340                if (found_ubwc && found) {
1341                        /*
1342                         * Hard-code DPB buffers to be 10bit UBWC and decoder
1343                         * output buffers in 8bit NV12 until V4L2 is able to
1344                         * expose compressed/tiled formats to applications.
1345                         */
1346                        *out_fmt = HFI_COLOR_FORMAT_YUV420_TP10_UBWC;
1347                        *out2_fmt = HFI_COLOR_FORMAT_NV12;
1348                        return 0;
1349                }
1350
1351                return -EINVAL;
1352        }
1353
1354        if (ubwc) {
1355                ubwc_fmt = fmt | HFI_COLOR_FORMAT_UBWC_BASE;
1356                found_ubwc = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT,
1357                                                ubwc_fmt);
1358                found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2, fmt);
1359
1360                if (found_ubwc && found) {
1361                        *out_fmt = ubwc_fmt;
1362                        *out2_fmt = fmt;
1363                        return 0;
1364                }
1365        }
1366
1367        found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT, fmt);
1368        if (found) {
1369                *out_fmt = fmt;
1370                *out2_fmt = 0;
1371                return 0;
1372        }
1373
1374        found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2, fmt);
1375        if (found) {
1376                *out_fmt = 0;
1377                *out2_fmt = fmt;
1378                return 0;
1379        }
1380
1381        return -EINVAL;
1382}
1383EXPORT_SYMBOL_GPL(venus_helper_get_out_fmts);
1384