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