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