Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
#include <media/v4l2-event.h>#include <media/v4l2-mem2mem.h>
#include "iris_buffer.h"#include "iris_instance.h"#include "iris_power.h"#include "iris_vpu_buffer.h"
#define PIXELS_4K 4096#define MAX_WIDTH 4096#define MAX_HEIGHT 2304#define Y_STRIDE_ALIGN 128#define Y_STRIDE_ALIGN_P010 256#define UV_STRIDE_ALIGN 128#define UV_STRIDE_ALIGN_P010 256#define Y_SCANLINE_ALIGN 32#define Y_SCANLINE_ALIGN_QC10C 16#define UV_SCANLINE_ALIGN 16#define UV_SCANLINE_ALIGN_QC08C 32#define META_STRIDE_ALIGNED 64#define META_SCANLINE_ALIGNED 16#define NUM_MBS_4K (DIV_ROUND_UP(MAX_WIDTH, 16) * DIV_ROUND_UP(MAX_HEIGHT, 16))
/* * NV12: * YUV 4:2:0 image with a plane of 8 bit Y samples followed * by an interleaved U/V plane containing 8 bit 2x2 subsampled * colour difference samples. * * <-Y/UV_Stride (aligned to 128)-> * <------- Width -------> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | y_scanlines (aligned to 32) * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . V * U V U V U V U V U V U V . . . . ^ * U V U V U V U V U V U V . . . . | * U V U V U V U V U V U V . . . . | * U V U V U V U V U V U V . . . . uv_scanlines (aligned to 16) * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . V * . . . . . . . . . . . . . . . . --> Buffer size aligned to 4K * * y_stride : Width aligned to 128 * uv_stride : Width aligned to 128 * y_scanlines: Height aligned to 32 * uv_scanlines: Height/2 aligned to 16 * Total size = align((y_stride * y_scanlines * + uv_stride * uv_scanlines , 4096) * * Note: All the alignments are hardware requirements. */static u32 iris_yuv_buffer_size_nv12(struct iris_inst *inst){ u32 y_plane, uv_plane, y_stride, uv_stride, y_scanlines, uv_scanlines; struct v4l2_format *f;
if (inst->domain == DECODER) f = inst->fmt_dst; else f = inst->fmt_src;
y_stride = ALIGN(f->fmt.pix_mp.width, Y_STRIDE_ALIGN); uv_stride = ALIGN(f->fmt.pix_mp.width, UV_STRIDE_ALIGN); y_scanlines = ALIGN(f->fmt.pix_mp.height, Y_SCANLINE_ALIGN); uv_scanlines = ALIGN((f->fmt.pix_mp.height + 1) >> 1, UV_SCANLINE_ALIGN); y_plane = y_stride * y_scanlines; uv_plane = uv_stride * uv_scanlines;
return ALIGN(y_plane + uv_plane, PIXELS_4K);}
/* * P010: * YUV 4:2:0 image with a plane of 10 bit Y samples followed * by an interleaved U/V plane containing 10 bit 2x2 subsampled * colour difference samples. * * <-Y/UV_Stride (aligned to 256)-> * <----- Width*2 -------> * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | y_scanlines (aligned to 32) * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . V * U V U V U V U V U V U V . . . . ^ * U V U V U V U V U V U V . . . . | * U V U V U V U V U V U V . . . . | * U V U V U V U V U V U V . . . . uv_scanlines (aligned to 16) * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . V * . . . . . . . . . . . . . . . . --> Buffer size aligned to 4K * * y_stride : Width*2 aligned to 256 * uv_stride : Width*2 aligned to 256 * y_scanlines: Height aligned to 32 * uv_scanlines: Height/2 aligned to 16 * Total size = align((y_stride * y_scanlines * + uv_stride * uv_scanlines , 4096) * * Note: All the alignments are hardware requirements. */static u32 iris_yuv_buffer_size_p010(struct iris_inst *inst){ u32 y_plane, uv_plane, y_stride, uv_stride, y_scanlines, uv_scanlines; struct v4l2_format *f;
if (inst->domain == DECODER) f = inst->fmt_dst; else f = inst->fmt_src;
y_stride = ALIGN(f->fmt.pix_mp.width * 2, Y_STRIDE_ALIGN_P010); uv_stride = ALIGN(f->fmt.pix_mp.width * 2, UV_STRIDE_ALIGN_P010); y_scanlines = ALIGN(f->fmt.pix_mp.height, Y_SCANLINE_ALIGN); uv_scanlines = ALIGN((f->fmt.pix_mp.height + 1) >> 1, UV_SCANLINE_ALIGN); y_plane = y_stride * y_scanlines; uv_plane = uv_stride * uv_scanlines;
return ALIGN(y_plane + uv_plane, PIXELS_4K);}
/* * QC08C: * Compressed Macro-tile format for NV12. * Contains 4 planes in the following order - * (A) Y_Meta_Plane * (B) Y_UBWC_Plane * (C) UV_Meta_Plane * (D) UV_UBWC_Plane * * Y_Meta_Plane consists of meta information to decode compressed * tile data in Y_UBWC_Plane. * Y_UBWC_Plane consists of Y data in compressed macro-tile format. * UBWC decoder block will use the Y_Meta_Plane data together with * Y_UBWC_Plane data to produce loss-less uncompressed 8 bit Y samples. * * UV_Meta_Plane consists of meta information to decode compressed * tile data in UV_UBWC_Plane. * UV_UBWC_Plane consists of UV data in compressed macro-tile format. * UBWC decoder block will use UV_Meta_Plane data together with * UV_UBWC_Plane data to produce loss-less uncompressed 8 bit 2x2 * subsampled color difference samples. * * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable * and randomly accessible. There is no dependency between tiles. * * <----- y_meta_stride ----> (aligned to 64) * <-------- Width ------> * M M M M M M M M M M M M . . ^ ^ * M M M M M M M M M M M M . . | | * M M M M M M M M M M M M . . Height | * M M M M M M M M M M M M . . | y_meta_scanlines (aligned to 16) * M M M M M M M M M M M M . . | | * M M M M M M M M M M M M . . | | * M M M M M M M M M M M M . . | | * M M M M M M M M M M M M . . V | * . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k * . . . . . . . . . . . . . . V * <--Compressed tile y_stride---> (aligned to 128) * <------- Width -------> * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height | * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile y_scanlines (aligned to 32) * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k * . . . . . . . . . . . . . . . . V * <----- uv_meta_stride ----> (aligned to 64) * M M M M M M M M M M M M . . ^ * M M M M M M M M M M M M . . | * M M M M M M M M M M M M . . | * M M M M M M M M M M M M . . uv_meta_scanlines (aligned to 16) * . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . V * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k * <--Compressed tile uv_stride---> (aligned to 128) * U* V* U* V* U* V* U* V* . . . . ^ * U* V* U* V* U* V* U* V* . . . . | * U* V* U* V* U* V* U* V* . . . . | * U* V* U* V* U* V* U* V* . . . . uv_scanlines (aligned to 32) * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . V * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k * * y_stride: width aligned to 128 * uv_stride: width aligned to 128 * y_scanlines: height aligned to 32 * uv_scanlines: height aligned to 32 * y_plane: buffer size aligned to 4096 * uv_plane: buffer size aligned to 4096 * y_meta_stride: width aligned to 64 * y_meta_scanlines: height aligned to 16 * y_meta_plane: buffer size aligned to 4096 * uv_meta_stride: width aligned to 64 * uv_meta_scanlines: height aligned to 16 * uv_meta_plane: buffer size aligned to 4096 * * Total size = align( y_plane + uv_plane + * y_meta_plane + uv_meta_plane, 4096) * * Note: All the alignments are hardware requirements. */static u32 iris_yuv_buffer_size_qc08c(struct iris_inst *inst){ u32 y_plane, uv_plane, y_stride, uv_stride; u32 uv_meta_stride, uv_meta_plane; u32 y_meta_stride, y_meta_plane; struct v4l2_format *f = NULL;
if (inst->domain == DECODER) f = inst->fmt_dst; else f = inst->fmt_src;
y_meta_stride = ALIGN(DIV_ROUND_UP(f->fmt.pix_mp.width, META_STRIDE_ALIGNED >> 1), META_STRIDE_ALIGNED); y_meta_plane = y_meta_stride * ALIGN(DIV_ROUND_UP(f->fmt.pix_mp.height, META_SCANLINE_ALIGNED >> 1), META_SCANLINE_ALIGNED); y_meta_plane = ALIGN(y_meta_plane, PIXELS_4K);
y_stride = ALIGN(f->fmt.pix_mp.width, Y_STRIDE_ALIGN); y_plane = ALIGN(y_stride * ALIGN(f->fmt.pix_mp.height, Y_SCANLINE_ALIGN), PIXELS_4K);
uv_meta_stride = ALIGN(DIV_ROUND_UP(f->fmt.pix_mp.width / 2, META_STRIDE_ALIGNED >> 2), META_STRIDE_ALIGNED); uv_meta_plane = uv_meta_stride * ALIGN(DIV_ROUND_UP(f->fmt.pix_mp.height / 2, META_SCANLINE_ALIGNED >> 1), META_SCANLINE_ALIGNED); uv_meta_plane = ALIGN(uv_meta_plane, PIXELS_4K);
uv_stride = ALIGN(f->fmt.pix_mp.width, UV_STRIDE_ALIGN); uv_plane = ALIGN(uv_stride * ALIGN(f->fmt.pix_mp.height / 2, UV_SCANLINE_ALIGN_QC08C), PIXELS_4K);
return ALIGN(y_meta_plane + y_plane + uv_meta_plane + uv_plane, PIXELS_4K);}
/* * QC10C: * UBWC-compressed format for P010. * Contains 4 planes in the following order - * (A) Y_Meta_Plane * (B) Y_UBWC_Plane * (C) UV_Meta_Plane * (D) UV_UBWC_Plane * * Y_Meta_Plane consists of meta information to decode compressed * tile data in Y_UBWC_Plane. * Y_UBWC_Plane consists of Y data in compressed macro-tile format. * UBWC decoder block will use the Y_Meta_Plane data together with * Y_UBWC_Plane data to produce loss-less uncompressed 10 bit Y samples. * * UV_Meta_Plane consists of meta information to decode compressed * tile data in UV_UBWC_Plane. * UV_UBWC_Plane consists of UV data in compressed macro-tile format. * UBWC decoder block will use UV_Meta_Plane data together with * UV_UBWC_Plane data to produce loss-less uncompressed 10 bit 2x2 * subsampled color difference samples. * * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable * and randomly accessible. There is no dependency between tiles. * * <----- Y Meta stride -----> (aligned to 64) * <-------- Width ----------> (aligned to 48) * M M M M M M M M M M M M . . ^ ^ * M M M M M M M M M M M M . . | | * M M M M M M M M M M M M . . Height | * M M M M M M M M M M M M . . | Meta_Y_Scanlines (aligned to 16) * M M M M M M M M M M M M . . | | * M M M M M M M M M M M M . . | | * M M M M M M M M M M M M . . | | * M M M M M M M M M M M M . . V | * . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k * . . . . . . . . . . . . . . V * <--Compressed tile Y stride --> (aligned to 256) * <------- Width * 4/3 ---------> (aligned to 48) * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height | * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines (aligned to 16) * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k * . . . . . . . . . . . . . . . . V * <---- UV Meta stride ----> (aligned to 64) * <----- Width / 2 --------> (aligned to 24) * M M M M M M M M M M M M . . ^ ^ * M M M M M M M M M M M M . . | | * M M M M M M M M M M M M . . Height/2 | * M M M M M M M M M M M M . . V M_UV_Scanlines (aligned to 16) * . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . V * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k * <--Compressed tile UV stride--> (aligned to 256) * <------- Width * 4/3 ---------> (aligned to 48) * U* V* U* V* U* V* U* V* . . . . ^ * U* V* U* V* U* V* U* V* . . . . | * U* V* U* V* U* V* U* V* . . . . | * U* V* U* V* U* V* U* V* . . . . UV_Scanlines (aligned to 16) * . . . . . . . . . . . . . . . . | * . . . . . . . . . . . . . . . . V * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k * * y_stride: width aligned to 256 * uv_stride: width aligned to 256 * y_scanlines: height aligned to 16 * uv_scanlines: height aligned to 16 * y_plane: buffer size aligned to 4096 * uv_plane: buffer size aligned to 4096 * y_meta_stride: width aligned to 64 * y_meta_scanlines: height aligned to 16 * y_meta_plane: buffer size aligned to 4096 * uv_meta_stride: width aligned to 64 * uv_meta_scanlines: height aligned to 16 * uv_meta_plane: buffer size aligned to 4096 * * Total size = align( y_plane + uv_plane + * y_meta_plane + uv_meta_plane, 4096) * * Note: All the alignments are hardware requirements. */static u32 iris_yuv_buffer_size_qc10c(struct iris_inst *inst){ u32 y_plane, uv_plane, y_stride, uv_stride; u32 uv_meta_stride, uv_meta_plane; u32 y_meta_stride, y_meta_plane; struct v4l2_format *f;
if (inst->domain == DECODER) f = inst->fmt_dst; else f = inst->fmt_src;
y_meta_stride = ALIGN(DIV_ROUND_UP(f->fmt.pix_mp.width, 48), META_STRIDE_ALIGNED); y_meta_plane = y_meta_stride * ALIGN(DIV_ROUND_UP(f->fmt.pix_mp.height, 4), META_SCANLINE_ALIGNED); y_meta_plane = ALIGN(y_meta_plane, PIXELS_4K);
y_stride = ALIGN(f->fmt.pix_mp.width * 4 / 3, Y_STRIDE_ALIGN_P010); y_plane = ALIGN(y_stride * ALIGN(f->fmt.pix_mp.height, Y_SCANLINE_ALIGN_QC10C), PIXELS_4K);
uv_meta_stride = ALIGN(DIV_ROUND_UP((f->fmt.pix_mp.width + 1) >> 1, 24), META_STRIDE_ALIGNED); uv_meta_plane = uv_meta_stride * ALIGN(DIV_ROUND_UP((f->fmt.pix_mp.height + 1) >> 1, 4), META_SCANLINE_ALIGNED); uv_meta_plane = ALIGN(uv_meta_plane, PIXELS_4K);
uv_stride = ALIGN(f->fmt.pix_mp.width * 4 / 3, UV_STRIDE_ALIGN_P010); uv_plane = ALIGN(uv_stride * ALIGN((f->fmt.pix_mp.height + 1) >> 1, UV_SCANLINE_ALIGN), PIXELS_4K);
return ALIGN(y_meta_plane + y_plane + uv_meta_plane + uv_plane, PIXELS_4K);}
static u32 iris_dec_bitstream_buffer_size(struct iris_inst *inst){ struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; u32 base_res_mbs = NUM_MBS_4K; u32 frame_size, num_mbs; u32 div_factor = 2;
num_mbs = iris_get_mbpf(inst); if (num_mbs > NUM_MBS_4K) { div_factor = 4; base_res_mbs = caps->max_mbpf; } else { if (inst->codec == V4L2_PIX_FMT_VP9) div_factor = 1; }
/* * frame_size = YUVsize / div_factor * where YUVsize = resolution_in_MBs * MBs_in_pixel * 3 / 2 */ frame_size = base_res_mbs * (16 * 16) * 3 / 2 / div_factor;
return ALIGN(frame_size, PIXELS_4K);}
static u32 iris_enc_bitstream_buffer_size(struct iris_inst *inst){ u32 aligned_width, aligned_height, bitstream_size, yuv_size; int bitrate_mode, frame_rc; struct v4l2_format *f;
f = inst->fmt_dst;
bitrate_mode = inst->fw_caps[BITRATE_MODE].value; frame_rc = inst->fw_caps[FRAME_RC_ENABLE].value;
aligned_width = ALIGN(f->fmt.pix_mp.width, 32); aligned_height = ALIGN(f->fmt.pix_mp.height, 32); bitstream_size = aligned_width * aligned_height * 3; yuv_size = (aligned_width * aligned_height * 3) >> 1; if (aligned_width * aligned_height > (4096 * 2176)) /* bitstream_size = 0.25 * yuv_size; */ bitstream_size = (bitstream_size >> 3); else if (aligned_width * aligned_height > (1280 * 720)) /* bitstream_size = 0.5 * yuv_size; */ bitstream_size = (bitstream_size >> 2);
if ((!frame_rc || bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) && bitstream_size < yuv_size) bitstream_size = (bitstream_size << 1);
return ALIGN(bitstream_size, 4096);}
int iris_get_buffer_size(struct iris_inst *inst, enum iris_buffer_type buffer_type){ if (inst->domain == DECODER) { switch (buffer_type) { case BUF_INPUT: return iris_dec_bitstream_buffer_size(inst); case BUF_OUTPUT: if (inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC08C) return iris_yuv_buffer_size_qc08c(inst); else if (inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC10C) return iris_yuv_buffer_size_qc10c(inst); else if (inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_P010) return iris_yuv_buffer_size_p010(inst); else return iris_yuv_buffer_size_nv12(inst); case BUF_DPB: if (iris_fmt_is_10bit(inst->fmt_dst->fmt.pix_mp.pixelformat)) return iris_yuv_buffer_size_qc10c(inst); else return iris_yuv_buffer_size_qc08c(inst); default: return 0; } } else { switch (buffer_type) { case BUF_INPUT: if (inst->fmt_src->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC08C) return iris_yuv_buffer_size_qc08c(inst); else return iris_yuv_buffer_size_nv12(inst); case BUF_OUTPUT: return iris_enc_bitstream_buffer_size(inst); default: return 0; } }}
static void iris_fill_internal_buf_info(struct iris_inst *inst, enum iris_buffer_type buffer_type){ struct iris_buffers *buffers = &inst->buffers[buffer_type];
buffers->size = inst->core->iris_firmware_desc->get_vpu_buffer_size(inst, buffer_type); buffers->min_count = iris_vpu_buf_count(inst, buffer_type);}
static void iris_get_int_buf_tbl(struct iris_inst *inst, u32 plane, const u32 **internal_buf_type, u32 *internal_buffer_count){ const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data;
if (inst->domain == DECODER) { if (V4L2_TYPE_IS_OUTPUT(plane)) { *internal_buf_type = firmware_data->dec_ip_int_buf_tbl; *internal_buffer_count = firmware_data->dec_ip_int_buf_tbl_size; } else { *internal_buf_type = firmware_data->dec_op_int_buf_tbl; *internal_buffer_count = firmware_data->dec_op_int_buf_tbl_size; } } else { if (V4L2_TYPE_IS_OUTPUT(plane)) { *internal_buf_type = firmware_data->enc_ip_int_buf_tbl; *internal_buffer_count = firmware_data->enc_ip_int_buf_tbl_size; } else { *internal_buf_type = firmware_data->enc_op_int_buf_tbl; *internal_buffer_count = firmware_data->enc_op_int_buf_tbl_size; } }}
void iris_get_internal_buffers(struct iris_inst *inst, u32 plane){ const u32 *internal_buf_type; u32 internal_buffer_count, i;
iris_get_int_buf_tbl(inst, plane, &internal_buf_type, &internal_buffer_count);
for (i = 0; i < internal_buffer_count; i++) iris_fill_internal_buf_info(inst, internal_buf_type[i]);}
static int iris_create_internal_buffer(struct iris_inst *inst, enum iris_buffer_type buffer_type, u32 index){ struct iris_buffers *buffers = &inst->buffers[buffer_type]; struct iris_core *core = inst->core; struct iris_buffer *buffer;
if (!buffers->size) return 0;
buffer = kzalloc_obj(*buffer); if (!buffer) return -ENOMEM;
INIT_LIST_HEAD(&buffer->list); buffer->type = buffer_type; buffer->index = index; buffer->buffer_size = buffers->size; buffer->dma_attrs = DMA_ATTR_WRITE_COMBINE | DMA_ATTR_NO_KERNEL_MAPPING;
buffer->kvaddr = dma_alloc_attrs(core->dev, buffer->buffer_size, &buffer->device_addr, GFP_KERNEL, buffer->dma_attrs); if (!buffer->kvaddr) { kfree(buffer); return -ENOMEM; }
list_add_tail(&buffer->list, &buffers->list);
return 0;}
int iris_create_internal_buffers(struct iris_inst *inst, u32 plane){ u32 internal_buffer_count, i, j; struct iris_buffers *buffers; const u32 *internal_buf_type; int ret;
iris_get_int_buf_tbl(inst, plane, &internal_buf_type, &internal_buffer_count);
for (i = 0; i < internal_buffer_count; i++) { buffers = &inst->buffers[internal_buf_type[i]]; for (j = 0; j < buffers->min_count; j++) { ret = iris_create_internal_buffer(inst, internal_buf_type[i], j); if (ret) return ret; } }
return 0;}
int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf){ const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; int ret;
ret = hfi_ops->session_queue_buf(inst, buf); if (ret) return ret;
buf->attr &= ~BUF_ATTR_DEFERRED; buf->attr |= BUF_ATTR_QUEUED;
return 0;}
int iris_queue_internal_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buffer_type){ struct iris_buffer *buffer, *next; struct iris_buffers *buffers; int ret = 0;
buffers = &inst->buffers[buffer_type]; list_for_each_entry_safe(buffer, next, &buffers->list, list) { if (buffer->attr & BUF_ATTR_PENDING_RELEASE) continue; if (buffer->attr & BUF_ATTR_QUEUED) continue;
if (buffer->attr & BUF_ATTR_DEFERRED) { ret = iris_queue_buffer(inst, buffer); if (ret) return ret; } }
return ret;}
int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane){ struct iris_buffer *buffer, *next; struct iris_buffers *buffers; const u32 *internal_buf_type; u32 internal_buffer_count, i; int ret;
iris_get_int_buf_tbl(inst, plane, &internal_buf_type, &internal_buffer_count);
for (i = 0; i < internal_buffer_count; i++) { buffers = &inst->buffers[internal_buf_type[i]]; list_for_each_entry_safe(buffer, next, &buffers->list, list) { if (buffer->attr & BUF_ATTR_PENDING_RELEASE) continue; if (buffer->attr & BUF_ATTR_QUEUED) continue; if (buffer->type == BUF_DPB && inst->state != IRIS_INST_STREAMING) { buffer->attr |= BUF_ATTR_DEFERRED; continue; } ret = iris_queue_buffer(inst, buffer); if (ret) return ret; } }
return 0;}
void iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer){ struct iris_core *core = inst->core;
list_del(&buffer->list); dma_free_attrs(core->dev, buffer->buffer_size, buffer->kvaddr, buffer->device_addr, buffer->dma_attrs); kfree(buffer);}
static int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane, bool force){ struct iris_buffer *buf, *next; struct iris_buffers *buffers; const u32 *internal_buf_type; u32 i, len;
iris_get_int_buf_tbl(inst, plane, &internal_buf_type, &len);
for (i = 0; i < len; i++) { buffers = &inst->buffers[internal_buf_type[i]]; list_for_each_entry_safe(buf, next, &buffers->list, list) { /* * during stream on, skip destroying internal(DPB) buffer * if firmware did not return it. * during close, destroy all buffers irrespectively. */ if (!force && buf->attr & BUF_ATTR_QUEUED) continue;
iris_destroy_internal_buffer(inst, buf); } }
if (force) { if (inst->domain == DECODER) buffers = &inst->buffers[BUF_PERSIST]; else buffers = &inst->buffers[BUF_ARP];
list_for_each_entry_safe(buf, next, &buffers->list, list) iris_destroy_internal_buffer(inst, buf); }
return 0;}
int iris_destroy_all_internal_buffers(struct iris_inst *inst, u32 plane){ return iris_destroy_internal_buffers(inst, plane, true);}
int iris_destroy_dequeued_internal_buffers(struct iris_inst *inst, u32 plane){ return iris_destroy_internal_buffers(inst, plane, false);}
static int iris_release_internal_buffers(struct iris_inst *inst, enum iris_buffer_type buffer_type){ const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; struct iris_buffers *buffers = &inst->buffers[buffer_type]; struct iris_buffer *buffer, *next; int ret;
list_for_each_entry_safe(buffer, next, &buffers->list, list) { if (buffer->attr & BUF_ATTR_PENDING_RELEASE) continue; if (!(buffer->attr & BUF_ATTR_QUEUED)) continue; buffer->attr |= BUF_ATTR_PENDING_RELEASE; ret = hfi_ops->session_release_buf(inst, buffer); if (ret) { buffer->attr &= ~BUF_ATTR_PENDING_RELEASE; return ret; } }
return 0;}
static int iris_release_input_internal_buffers(struct iris_inst *inst){ const u32 *internal_buf_type; u32 internal_buffer_count, i; int ret;
iris_get_int_buf_tbl(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, &internal_buf_type, &internal_buffer_count);
for (i = 0; i < internal_buffer_count; i++) { ret = iris_release_internal_buffers(inst, internal_buf_type[i]); if (ret) return ret; }
return 0;}
int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst, enum iris_buffer_type buffer_type){ struct iris_buffers *buffers = &inst->buffers[buffer_type]; struct iris_buffer *buffer, *next; int ret; u32 i;
if (!list_empty(&buffers->list)) return 0;
iris_fill_internal_buf_info(inst, buffer_type);
for (i = 0; i < buffers->min_count; i++) { ret = iris_create_internal_buffer(inst, buffer_type, i); if (ret) return ret; }
list_for_each_entry_safe(buffer, next, &buffers->list, list) { if (buffer->attr & BUF_ATTR_PENDING_RELEASE) continue; if (buffer->attr & BUF_ATTR_QUEUED) continue; ret = iris_queue_buffer(inst, buffer); if (ret) return ret; }
return 0;}
int iris_alloc_and_queue_input_int_bufs(struct iris_inst *inst){ int ret;
iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
ret = iris_release_input_internal_buffers(inst); if (ret) return ret;
ret = iris_create_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); if (ret) return ret;
return iris_queue_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);}
int iris_queue_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buf_type){ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; struct v4l2_m2m_buffer *buffer, *n; struct iris_buffer *buf; int ret;
iris_scale_power(inst);
if (buf_type == BUF_INPUT) { v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buffer, n) { buf = to_iris_buffer(&buffer->vb); if (!(buf->attr & BUF_ATTR_DEFERRED)) continue; ret = iris_queue_buffer(inst, buf); if (ret) return ret; } } else { v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) { buf = to_iris_buffer(&buffer->vb); if (!(buf->attr & BUF_ATTR_DEFERRED)) continue; ret = iris_queue_buffer(inst, buf); if (ret) return ret; } }
return 0;}
void iris_vb2_queue_error(struct iris_inst *inst){ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; struct vb2_queue *q;
q = v4l2_m2m_get_src_vq(m2m_ctx); vb2_queue_error(q); q = v4l2_m2m_get_dst_vq(m2m_ctx); vb2_queue_error(q);}
static struct vb2_v4l2_buffer *iris_helper_find_buf(struct iris_inst *inst, u32 type, u32 idx){ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
if (V4L2_TYPE_IS_OUTPUT(type)) return v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, idx); else return v4l2_m2m_dst_buf_remove_by_idx(m2m_ctx, idx);}
static void iris_get_ts_metadata(struct iris_inst *inst, u64 timestamp_ns, struct vb2_v4l2_buffer *vbuf){ u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK; u32 i;
for (i = 0; i < ARRAY_SIZE(inst->tss); ++i) { if (inst->tss[i].ts_ns != timestamp_ns) continue;
vbuf->flags &= ~mask; vbuf->flags |= inst->tss[i].flags; vbuf->timecode = inst->tss[i].tc; return; }
vbuf->flags &= ~mask; vbuf->flags |= inst->tss[inst->metadata_idx].flags; vbuf->timecode = inst->tss[inst->metadata_idx].tc;}
int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf){ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; struct vb2_v4l2_buffer *vbuf; struct vb2_buffer *vb2; u32 type, state;
switch (buf->type) { case BUF_INPUT: type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; break; case BUF_OUTPUT: type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; break; default: return 0; /* Internal DPB Buffers */ }
vbuf = iris_helper_find_buf(inst, type, buf->index); if (!vbuf) return -EINVAL;
vb2 = &vbuf->vb2_buf;
vbuf->flags |= buf->flags;
if (buf->flags & V4L2_BUF_FLAG_ERROR) { state = VB2_BUF_STATE_ERROR; vb2_set_plane_payload(vb2, 0, 0); vb2->timestamp = 0; v4l2_m2m_buf_done(vbuf, state); return 0; }
if (V4L2_TYPE_IS_CAPTURE(type)) { vb2_set_plane_payload(vb2, 0, buf->data_size); vbuf->sequence = inst->sequence_cap++; iris_get_ts_metadata(inst, buf->timestamp, vbuf); } else { vbuf->sequence = inst->sequence_out++; }
if (vbuf->flags & V4L2_BUF_FLAG_LAST) { if (!v4l2_m2m_has_stopped(m2m_ctx)) { const struct v4l2_event ev = { .type = V4L2_EVENT_EOS };
v4l2_event_queue_fh(&inst->fh, &ev); v4l2_m2m_mark_stopped(m2m_ctx); } inst->last_buffer_dequeued = true; }
state = VB2_BUF_STATE_DONE; vb2->timestamp = buf->timestamp; v4l2_m2m_buf_done(vbuf, state);
return 0;}