From 4f29de580df01fd31ca166cf1c12227d45a1c9af Mon Sep 17 00:00:00 2001 From: MCC45TR Date: Tue, 25 Aug 2026 16:44:10 +0300 Subject: [PATCH 24/30] media: qcom: port Nabu Iris VA-API support to 6.17 Adapt the CFM880/nabu-iris kernel overlay at commit 4762dd9c594db58bcfa4a42997d9ec75866e98a1 to the current Nabu 6.17 line while preserving the existing v1.4.0.6 device changes. Add the SM8150 Iris1 DT node, Nabu firmware path, legacy Venus coordination, cached capture, firmware boot gating, session recovery, concurrent decode handling, and 10-bit decode support. Source: https://github.com/CFM880/nabu-iris/tree/4762dd9c594db58bcfa4a42997d9ec75866e98a1 Link: https://github.com/CFM880/iris-vaapi/blob/main/docs/video-decode-setup.en.md --- .../boot/dts/qcom/sm8150-xiaomi-nabu.dts | 5 + arch/arm64/boot/dts/qcom/sm8150.dtsi | 82 ++ drivers/media/platform/qcom/iris/Makefile | 7 +- .../media/platform/qcom/iris/iris_buffer.c | 369 +++---- .../media/platform/qcom/iris/iris_buffer.h | 2 - .../media/platform/qcom/iris/iris_common.c | 253 ++++- .../media/platform/qcom/iris/iris_common.h | 4 + drivers/media/platform/qcom/iris/iris_core.c | 63 +- drivers/media/platform/qcom/iris/iris_core.h | 19 +- drivers/media/platform/qcom/iris/iris_ctrls.c | 756 +++---------- drivers/media/platform/qcom/iris/iris_ctrls.h | 18 +- .../media/platform/qcom/iris/iris_firmware.c | 68 +- .../platform/qcom/iris/iris_hfi_common.c | 28 +- .../qcom/iris/iris_hfi_gen1_command.c | 609 ++++++++--- .../qcom/iris/iris_hfi_gen1_defines.h | 106 +- .../qcom/iris/iris_hfi_gen1_response.c | 305 +++++- .../qcom/iris/iris_hfi_gen2_command.c | 341 ++---- .../qcom/iris/iris_hfi_gen2_defines.h | 48 - .../media/platform/qcom/iris/iris_hfi_queue.c | 146 ++- .../media/platform/qcom/iris/iris_hfi_queue.h | 24 +- .../media/platform/qcom/iris/iris_instance.h | 88 +- .../platform/qcom/iris/iris_platform_common.h | 190 ++-- .../platform/qcom/iris/iris_platform_gen2.c | 995 ++++++++++++++++++ .../qcom/iris/iris_platform_qcs8300.h | 536 +++++++++- .../platform/qcom/iris/iris_platform_sm8250.c | 483 +++++++++ drivers/media/platform/qcom/iris/iris_power.c | 68 +- drivers/media/platform/qcom/iris/iris_power.h | 4 + drivers/media/platform/qcom/iris/iris_probe.c | 69 +- .../media/platform/qcom/iris/iris_resources.c | 24 +- drivers/media/platform/qcom/iris/iris_utils.c | 36 +- drivers/media/platform/qcom/iris/iris_utils.h | 3 - drivers/media/platform/qcom/iris/iris_vb2.c | 193 +++- drivers/media/platform/qcom/iris/iris_vb2.h | 2 + drivers/media/platform/qcom/iris/iris_vdec.c | 501 ++++++--- drivers/media/platform/qcom/iris/iris_vdec.h | 7 + drivers/media/platform/qcom/iris/iris_venc.c | 178 ++-- drivers/media/platform/qcom/iris/iris_venc.h | 1 + drivers/media/platform/qcom/iris/iris_vidc.c | 273 +++-- drivers/media/platform/qcom/iris/iris_vidc.h | 13 + drivers/media/platform/qcom/iris/iris_vpu2.c | 12 +- .../platform/qcom/iris/iris_vpu_buffer.c | 898 ++-------------- .../platform/qcom/iris/iris_vpu_buffer.h | 145 +-- .../platform/qcom/iris/iris_vpu_common.c | 730 ++++++++----- drivers/media/platform/qcom/venus/core.c | 237 ++--- drivers/media/platform/qcom/venus/core.h | 2 +- drivers/media/platform/qcom/venus/firmware.c | 14 +- drivers/media/platform/qcom/venus/hfi_venus.c | 10 + 47 files changed, 5553 insertions(+), 3412 deletions(-) create mode 100644 drivers/media/platform/qcom/iris/iris_platform_gen2.c create mode 100644 drivers/media/platform/qcom/iris/iris_platform_sm8250.c diff --git a/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts b/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts index 1327b2c547af..743bbcc2b314 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts @@ -1070,6 +1070,11 @@ bluetooth: bluetooth { }; }; +&venus { + firmware-name = "qcom/sm8150/xiaomi/nabu/venus.mbn"; + status = "okay"; +}; + &ufs_mem_hc { status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 310d299ee949..1add352d8008 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -3785,6 +3785,88 @@ usb_2_dwc3: usb@a800000 { }; }; + venus: video-codec@aa00000 { + compatible = "qcom,sm8150-iris"; + reg = <0 0x0aa00000 0 0x100000>; + interrupts = ; + + power-domains = <&videocc VENUS_GDSC>, + <&videocc VCODEC0_GDSC>, + <&videocc VCODEC1_GDSC>, + <&rpmhpd SM8150_CX>; + power-domain-names = "venus", "vcodec0", "vcodec1", "cx"; + operating-points-v2 = <&venus_opp_table>; + + clocks = <&videocc VIDEO_CC_MVSC_CORE_CLK>, + <&videocc VIDEO_CC_IRIS_AHB_CLK>, + <&gcc GCC_VIDEO_AXIC_CLK>, + <&videocc VIDEO_CC_MVS0_CORE_CLK>, + <&gcc GCC_VIDEO_AXI0_CLK>, + <&videocc VIDEO_CC_MVS1_CORE_CLK>, + <&gcc GCC_VIDEO_AXI1_CLK>; + clock-names = "core", "iface", "bus", + "vcodec0_core", "vcodec0_bus", + "vcodec1_core", "vcodec1_bus"; + + resets = <&gcc GCC_VIDEO_AXIC_CLK_BCR>, + <&videocc VIDEO_CC_MVSC_CORE_CLK_BCR>, + <&gcc GCC_VIDEO_AXI0_CLK_BCR>, + <&gcc GCC_VIDEO_AXI1_CLK_BCR>; + reset-names = "bus", "core", "vcodec0_bus", "vcodec1_bus"; + + interconnects = <&mmss_noc MASTER_VIDEO_P0 0 + &mc_virt SLAVE_EBI_CH0 0>, + <&gem_noc MASTER_AMPSS_M0 0 + &config_noc SLAVE_VENUS_CFG 0>; + interconnect-names = "video-mem", "cpu-cfg"; + + /* + * nabu is SM8150 v2.2. VIDC stream IDs moved from the + * v1 0x13xx range to 0x23xx on SM8150 v2. + */ + iommus = <&apps_smmu 0x2300 0x60>; + memory-region = <&venus_mem>; + + status = "disabled"; + + video-core0 { + compatible = "venus-decoder"; + }; + + video-core1 { + compatible = "venus-encoder"; + }; + + venus_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_min_svs>; + }; + + opp-240000000 { + opp-hz = /bits/ 64 <240000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-365000000 { + opp-hz = /bits/ 64 <365000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-444000000 { + opp-hz = /bits/ 64 <444000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-533000000 { + opp-hz = /bits/ 64 <533000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + videocc: clock-controller@ab00000 { compatible = "qcom,sm8150-videocc"; reg = <0 0x0ab00000 0 0x10000>; diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile index 48e415cbc439..963b4044fc57 100644 --- a/drivers/media/platform/qcom/iris/Makefile +++ b/drivers/media/platform/qcom/iris/Makefile @@ -4,16 +4,14 @@ qcom-iris-objs += iris_buffer.o \ iris_ctrls.o \ iris_firmware.o \ iris_hfi_common.o \ - iris_hfi_gen1.o \ iris_hfi_gen1_command.o \ iris_hfi_gen1_response.o \ - iris_hfi_gen2.o \ iris_hfi_gen2_command.o \ iris_hfi_gen2_packet.o \ iris_hfi_gen2_response.o \ iris_hfi_queue.o \ - iris_platform_vpu2.o \ - iris_platform_vpu3x.o \ + iris_platform_gen2.o \ + iris_platform_sm8250.o \ iris_power.o \ iris_probe.o \ iris_resources.o \ @@ -25,7 +23,6 @@ qcom-iris-objs += iris_buffer.o \ iris_venc.o \ iris_vpu2.o \ iris_vpu3x.o \ - iris_vpu4x.o \ iris_vpu_buffer.o \ iris_vpu_common.o \ diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c index 246ad0abbac3..13cdbc9b335d 100644 --- a/drivers/media/platform/qcom/iris/iris_buffer.c +++ b/drivers/media/platform/qcom/iris/iris_buffer.c @@ -15,11 +15,8 @@ #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 @@ -83,55 +80,13 @@ static u32 iris_yuv_buffer_size_nv12(struct iris_inst *inst) 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; + struct v4l2_format *f = inst->fmt_dst; - 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_stride = ALIGN(f->fmt.pix_mp.width * 2, Y_STRIDE_ALIGN); + uv_stride = ALIGN(f->fmt.pix_mp.width * 2, 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; @@ -231,14 +186,9 @@ static u32 iris_yuv_buffer_size_p010(struct iris_inst *inst) static u32 iris_yuv_buffer_size_qc08c(struct iris_inst *inst) { u32 y_plane, uv_plane, y_stride, uv_stride; + struct v4l2_format *f = inst->fmt_dst; 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); @@ -265,129 +215,36 @@ static u32 iris_yuv_buffer_size_qc08c(struct iris_inst *inst) } /* - * 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. + * TP10 UBWC is the firmware-owned DPB used while linear P010 is exposed on + * OUTPUT2. The layout matches the legacy Venus HFI contract used by VPU5. */ 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); + u32 y_stride, uv_stride, y_scanlines, uv_scanlines; + u32 y_plane, uv_plane, y_meta_stride, y_meta_scanlines; + u32 uv_meta_stride, uv_meta_scanlines, y_meta_plane, uv_meta_plane; + struct v4l2_format *f = inst->fmt_dst; + u32 extradata = SZ_16K; + u32 size; + + y_stride = ALIGN(f->fmt.pix_mp.width * 4 / 3, 256); + uv_stride = ALIGN(f->fmt.pix_mp.width * 4 / 3, 256); + y_scanlines = ALIGN(f->fmt.pix_mp.height, 16); + uv_scanlines = ALIGN((f->fmt.pix_mp.height + 1) >> 1, 16); + y_plane = ALIGN(y_stride * y_scanlines, SZ_4K); + uv_plane = ALIGN(uv_stride * uv_scanlines, SZ_4K); + + y_meta_stride = ALIGN(DIV_ROUND_UP(f->fmt.pix_mp.width, 48), 64); + y_meta_scanlines = ALIGN(DIV_ROUND_UP(f->fmt.pix_mp.height, 4), 16); + y_meta_plane = ALIGN(y_meta_stride * y_meta_scanlines, SZ_4K); + uv_meta_stride = ALIGN(DIV_ROUND_UP((f->fmt.pix_mp.width + 1) >> 1, 24), 64); + uv_meta_scanlines = ALIGN(DIV_ROUND_UP((f->fmt.pix_mp.height + 1) >> 1, 4), 16); + uv_meta_plane = ALIGN(uv_meta_stride * uv_meta_scanlines, SZ_4K); + + size = y_plane + uv_plane + y_meta_plane + uv_meta_plane; + size += max(extradata + SZ_8K, y_stride * 48); + + return ALIGN(size, SZ_4K); } static u32 iris_dec_bitstream_buffer_size(struct iris_inst *inst) @@ -452,29 +309,20 @@ int iris_get_buffer_size(struct iris_inst *inst, 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) + 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); + return iris_yuv_buffer_size_nv12(inst); case BUF_DPB: - if (iris_fmt_is_10bit(inst->fmt_dst->fmt.pix_mp.pixelformat)) + if (inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_P010) return iris_yuv_buffer_size_qc10c(inst); - else - return iris_yuv_buffer_size_qc08c(inst); + 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); + return iris_yuv_buffer_size_nv12(inst); case BUF_OUTPUT: return iris_enc_bitstream_buffer_size(inst); default: @@ -487,38 +335,69 @@ 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]; + bool exact_firmware_size; + u32 calculated_size; - buffers->size = inst->core->iris_firmware_desc->get_vpu_buffer_size(inst, buffer_type); + calculated_size = iris_vpu_buf_size(inst, buffer_type); + exact_firmware_size = inst->domain == DECODER && + inst->core->iris_platform_data->legacy_vpu5 && + inst->fw_buffer_sizes[buffer_type]; + /* + * VIDEO.IR.1.2 reports the exact internal allocation sizes after the + * session properties have been applied. The generic Iris formulas are + * for newer hardware and substantially overestimate VPU5 decoder scratch + * memory (272 MiB instead of 20 MiB for 4K HEVC), preventing two legal + * sessions from coexisting. Qualcomm's downstream VPU5 driver likewise + * allocates the firmware-reported size directly. Keep the formula as a + * fallback when no requirement was returned and for non-VPU5 hardware. + */ + if (exact_firmware_size) { + buffers->size = inst->fw_buffer_sizes[buffer_type]; + if (buffers->size != calculated_size) + dev_info(inst->core->dev, + "Iris1 v145: buffer type %u using exact firmware size %u instead of calculated %u\n", + buffer_type, buffers->size, calculated_size); + } else { + buffers->size = max(calculated_size, + inst->fw_buffer_sizes[buffer_type]); + } buffers->min_count = iris_vpu_buf_count(inst, buffer_type); + + if (!exact_firmware_size && + inst->fw_buffer_sizes[buffer_type] > calculated_size) + dev_info(inst->core->dev, + "Iris1 v58: buffer type %u using firmware size %u instead of calculated %u\n", + buffer_type, inst->fw_buffer_sizes[buffer_type], + calculated_size); } void iris_get_internal_buffers(struct iris_inst *inst, u32 plane) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; + const struct iris_platform_data *platform_data = inst->core->iris_platform_data; const u32 *internal_buf_type; u32 internal_buffer_count, i; 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; + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; for (i = 0; i < internal_buffer_count; i++) iris_fill_internal_buf_info(inst, internal_buf_type[i]); } else { - internal_buf_type = firmware_data->dec_op_int_buf_tbl; - internal_buffer_count = firmware_data->dec_op_int_buf_tbl_size; + internal_buf_type = platform_data->dec_op_int_buf_tbl; + internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; for (i = 0; i < internal_buffer_count; i++) iris_fill_internal_buf_info(inst, internal_buf_type[i]); } } 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; + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + internal_buffer_count = platform_data->enc_ip_int_buf_tbl_size; for (i = 0; i < internal_buffer_count; i++) iris_fill_internal_buf_info(inst, internal_buf_type[i]); } else { - internal_buf_type = firmware_data->enc_op_int_buf_tbl; - internal_buffer_count = firmware_data->enc_op_int_buf_tbl_size; + internal_buf_type = platform_data->enc_op_int_buf_tbl; + internal_buffer_count = platform_data->enc_op_int_buf_tbl_size; for (i = 0; i < internal_buffer_count; i++) iris_fill_internal_buf_info(inst, internal_buf_type[i]); } @@ -535,19 +414,30 @@ static int iris_create_internal_buffer(struct iris_inst *inst, if (!buffers->size) return 0; - buffer = kzalloc_obj(*buffer); + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); if (!buffer) return -ENOMEM; INIT_LIST_HEAD(&buffer->list); buffer->type = buffer_type; - buffer->index = index; + /* + * Split-mode DPBs and client capture buffers share the HFI output-tag + * namespace. Keep their tags disjoint, as the Venus driver does with + * ida_alloc_min(VB2_MAX_FRAME), or VP9 rejects both streams' FTBs. + */ + if (buffer_type == BUF_DPB) + buffer->index = VIDEO_MAX_FRAME + index; + else + 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) { + dev_err(core->dev, + "Iris1 v121: internal DMA allocation failed type=%u index=%u size=%zu\n", + buffer_type, index, buffer->buffer_size); kfree(buffer); return -ENOMEM; } @@ -559,7 +449,7 @@ static int iris_create_internal_buffer(struct iris_inst *inst, int iris_create_internal_buffers(struct iris_inst *inst, u32 plane) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; + const struct iris_platform_data *platform_data = inst->core->iris_platform_data; u32 internal_buffer_count, i, j; struct iris_buffers *buffers; const u32 *internal_buf_type; @@ -567,19 +457,19 @@ int iris_create_internal_buffers(struct iris_inst *inst, u32 plane) 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; + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_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; + internal_buf_type = platform_data->dec_op_int_buf_tbl; + internal_buffer_count = platform_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; + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + internal_buffer_count = platform_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; + internal_buf_type = platform_data->enc_op_int_buf_tbl; + internal_buffer_count = platform_data->enc_op_int_buf_tbl_size; } } @@ -597,7 +487,7 @@ int iris_create_internal_buffers(struct iris_inst *inst, u32 plane) int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; int ret; ret = hfi_ops->session_queue_buf(inst, buf); @@ -635,7 +525,7 @@ int iris_queue_internal_deferred_buffers(struct iris_inst *inst, enum iris_buffe int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; + const struct iris_platform_data *platform_data = inst->core->iris_platform_data; struct iris_buffer *buffer, *next; struct iris_buffers *buffers; const u32 *internal_buf_type; @@ -644,19 +534,19 @@ int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane) 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; + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_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; + internal_buf_type = platform_data->dec_op_int_buf_tbl; + internal_buffer_count = platform_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; + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + internal_buffer_count = platform_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; + internal_buf_type = platform_data->enc_op_int_buf_tbl; + internal_buffer_count = platform_data->enc_op_int_buf_tbl_size; } } @@ -694,7 +584,7 @@ int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buf static int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane, bool force) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; + const struct iris_platform_data *platform_data = inst->core->iris_platform_data; struct iris_buffer *buf, *next; struct iris_buffers *buffers; const u32 *internal_buf_type; @@ -703,19 +593,19 @@ static int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane, bool if (inst->domain == DECODER) { if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->dec_ip_int_buf_tbl; - len = firmware_data->dec_ip_int_buf_tbl_size; + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + len = platform_data->dec_ip_int_buf_tbl_size; } else { - internal_buf_type = firmware_data->dec_op_int_buf_tbl; - len = firmware_data->dec_op_int_buf_tbl_size; + internal_buf_type = platform_data->dec_op_int_buf_tbl; + len = platform_data->dec_op_int_buf_tbl_size; } } else { if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->enc_ip_int_buf_tbl; - len = firmware_data->enc_ip_int_buf_tbl_size; + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + len = platform_data->enc_ip_int_buf_tbl_size; } else { - internal_buf_type = firmware_data->enc_op_int_buf_tbl; - len = firmware_data->enc_op_int_buf_tbl_size; + internal_buf_type = platform_data->enc_op_int_buf_tbl; + len = platform_data->enc_op_int_buf_tbl_size; } } @@ -765,7 +655,7 @@ int iris_destroy_dequeued_internal_buffers(struct iris_inst *inst, u32 plane) 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; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; struct iris_buffers *buffers = &inst->buffers[buffer_type]; struct iris_buffer *buffer, *next; int ret; @@ -775,12 +665,10 @@ static int iris_release_internal_buffers(struct iris_inst *inst, 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; + if (ret) return ret; - } + buffer->attr |= BUF_ATTR_PENDING_RELEASE; } return 0; @@ -788,17 +676,17 @@ static int iris_release_internal_buffers(struct iris_inst *inst, static int iris_release_input_internal_buffers(struct iris_inst *inst) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; + const struct iris_platform_data *platform_data = inst->core->iris_platform_data; const u32 *internal_buf_type; u32 internal_buffer_count, i; int ret; if (inst->domain == DECODER) { - internal_buf_type = firmware_data->dec_ip_int_buf_tbl; - internal_buffer_count = firmware_data->dec_ip_int_buf_tbl_size; + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; } else { - internal_buf_type = firmware_data->enc_ip_int_buf_tbl; - internal_buffer_count = firmware_data->enc_ip_int_buf_tbl_size; + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + internal_buffer_count = platform_data->enc_ip_int_buf_tbl_size; } for (i = 0; i < internal_buffer_count; i++) { @@ -956,6 +844,11 @@ int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf) return -EINVAL; vb2 = &vbuf->vb2_buf; + if (inst->start_streaming_rollback_type == type) { + /* A failed start_streaming() must return every buffer as QUEUED. */ + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_QUEUED); + return 0; + } vbuf->flags |= buf->flags; diff --git a/drivers/media/platform/qcom/iris/iris_buffer.h b/drivers/media/platform/qcom/iris/iris_buffer.h index 75bb76776182..325d30fce5c9 100644 --- a/drivers/media/platform/qcom/iris/iris_buffer.h +++ b/drivers/media/platform/qcom/iris/iris_buffer.h @@ -27,7 +27,6 @@ struct iris_inst; * @BUF_SCRATCH_1: buffer to store decoding/encoding context data for HW * @BUF_SCRATCH_2: buffer to store encoding context data for HW * @BUF_VPSS: buffer to store VPSS context data for HW - * @BUF_PARTIAL: buffer for AV1 IBC data * @BUF_TYPE_MAX: max buffer types */ enum iris_buffer_type { @@ -43,7 +42,6 @@ enum iris_buffer_type { BUF_SCRATCH_1, BUF_SCRATCH_2, BUF_VPSS, - BUF_PARTIAL, BUF_TYPE_MAX, }; diff --git a/drivers/media/platform/qcom/iris/iris_common.c b/drivers/media/platform/qcom/iris/iris_common.c index 25836561bcf3..b39eefada534 100644 --- a/drivers/media/platform/qcom/iris/iris_common.c +++ b/drivers/media/platform/qcom/iris/iris_common.c @@ -9,6 +9,10 @@ #include "iris_ctrls.h" #include "iris_instance.h" #include "iris_power.h" +#include "iris_utils.h" + +#define IRIS1_4K_MBPF NUM_MBS_PER_FRAME(2160, 3840) +#define IRIS1_MAX_4K_SESSIONS 3 int iris_vb2_buffer_to_driver(struct vb2_buffer *vb2, struct iris_buffer *buf) { @@ -48,10 +52,12 @@ void iris_set_ts_metadata(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) int iris_process_streamon_input(struct iris_inst *inst) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; enum iris_inst_sub_state set_sub_state = 0; int ret; + inst->streamoff_pending = false; + iris_scale_power(inst); ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); @@ -90,15 +96,13 @@ int iris_process_streamon_input(struct iris_inst *inst) int iris_process_streamon_output(struct iris_inst *inst) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + bool drain_active = false, drc_active = false; enum iris_inst_sub_state clear_sub_state = 0; - bool drain_active, drc_active, first_ipsc; int ret = 0; iris_scale_power(inst); - first_ipsc = inst->sub_state & IRIS_INST_SUB_FIRST_IPSC; - drain_active = inst->sub_state & IRIS_INST_SUB_DRAIN && inst->sub_state & IRIS_INST_SUB_DRAIN_LAST; @@ -110,8 +114,7 @@ int iris_process_streamon_output(struct iris_inst *inst) else if (drain_active) clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST; - /* Input internal buffer reconfiguration required in case of resolution change */ - if (first_ipsc || drc_active) { + if (inst->domain == DECODER && inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { ret = iris_alloc_and_queue_input_int_bufs(inst); if (ret) return ret; @@ -189,7 +192,7 @@ static void iris_flush_deferred_buffers(struct iris_inst *inst, static void iris_kill_session(struct iris_inst *inst) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; if (!inst->session_id) return; @@ -198,9 +201,219 @@ static void iris_kill_session(struct iris_inst *inst) iris_inst_change_state(inst, IRIS_INST_ERROR); } +int iris_hfi_session_open(struct iris_inst *inst) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + struct iris_core *core = inst->core; + struct iris_inst *instance; + u64 active_mbpf = 0; + u32 active_sessions = 0; + int ret; + + if (inst->hfi_session_opened) + return 0; + + mutex_lock(&core->lock); + list_for_each_entry(instance, &core->instances, list) { + if (!instance->hfi_session_opened) + continue; + + active_sessions++; + active_mbpf += iris_get_mbpf(instance); + } + + if (active_sessions >= core->iris_platform_data->max_session_count) { + mutex_unlock(&core->lock); + return -EBUSY; + } + + active_mbpf += iris_get_mbpf(inst); + if (active_mbpf > core->iris_platform_data->max_core_mbpf) { + dev_warn(core->dev, + "Iris1 v154: rejecting session aggregate mbpf %llu above %u\n", + (unsigned long long)active_mbpf, + core->iris_platform_data->max_core_mbpf); + mutex_unlock(&core->lock); + return -ENOMEM; + } + + /* Reserve session count and frame capacity before issuing SESSION_INIT. */ + inst->hfi_session_opened = true; + mutex_unlock(&core->lock); + + ret = hfi_ops->session_open(inst); + if (ret) { + /* A timeout leaves firmware ownership uncertain until recovery. */ + if (inst->state == IRIS_INST_ERROR) + return ret; + goto release_slot; + } + + if (inst->state == IRIS_INST_ERROR) + return -EIO; + + ret = iris_inst_change_state(inst, IRIS_INST_INIT); + if (ret) + return ret; + + return 0; + +release_slot: + mutex_lock(&core->lock); + inst->hfi_session_opened = false; + inst->hfi_core_id = 0; + inst->core_load_reserved = false; + inst->core_load_rejected = false; + inst->admission_frame_rate = 0; + mutex_unlock(&core->lock); + + return ret; +} + +int iris_hfi_session_close(struct iris_inst *inst) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + struct iris_core *core = inst->core; + bool was_error; + int ret, power_ret; + + if (!inst->hfi_session_opened) { + iris_release_core_load(inst); + return 0; + } + + was_error = inst->state == IRIS_INST_ERROR; + reinit_completion(&inst->completion); + + ret = hfi_ops->session_close(inst); + if (ret) + goto cleanup; + + ret = iris_wait_for_session_response(inst, false); + if (ret) + goto cleanup; + + if (!was_error && inst->state == IRIS_INST_ERROR) { + ret = -EIO; + goto cleanup; + } + + if (inst->state != IRIS_INST_ERROR) { + ret = iris_inst_change_state(inst, IRIS_INST_DEINIT); + if (ret) + goto cleanup; + } + + ret = 0; + +cleanup: + /* + * A firmware or response failure (for example an already-errored + * session whose SESSION_END is not answered) must not leave the + * session registered. Clear the ownership flags unconditionally so a + * stale session can no longer hold a firmware slot, a core-load vote, + * or a power vote. + */ + mutex_lock(&core->lock); + inst->hfi_session_opened = false; + inst->hfi_core_id = 0; + inst->core_load_reserved = false; + inst->core_load_rejected = false; + inst->admission_frame_rate = 0; + mutex_unlock(&core->lock); + + inst->sub_state = 0; + inst->streamoff_pending = false; + inst->flush_responses_pending = 0; + inst->last_buffer_dequeued = false; + + power_ret = iris_unvote_power(inst); + if (power_ret) + dev_warn(core->dev, + "failed to remove stopped-session power vote: %d\n", + power_ret); + + return ret; +} + +int iris_reserve_core_load(struct iris_inst *inst, u32 frame_rate) +{ + struct iris_core *core = inst->core; + struct iris_inst *instance; + u64 total_mbps = 0; + u32 large_sessions = 0; + u32 mbpf; + + frame_rate = max(frame_rate, 1U); + mbpf = iris_get_mbpf(inst); + + mutex_lock(&core->lock); + if (inst->core_load_reserved) { + mutex_unlock(&core->lock); + return 0; + } + + list_for_each_entry(instance, &core->instances, list) { + if (!instance->core_load_reserved) + continue; + + total_mbps += (u64)iris_get_mbpf(instance) * + instance->admission_frame_rate; + if (iris_get_mbpf(instance) >= IRIS1_4K_MBPF) + large_sessions++; + } + + total_mbps += (u64)mbpf * frame_rate; + if (total_mbps > core->iris_platform_data->max_core_mbps) { + dev_warn(core->dev, + "Iris1 v154: rejecting aggregate load %llu mb/s above %u (session %u mb/f at %u fps)\n", + (unsigned long long)total_mbps, + core->iris_platform_data->max_core_mbps, + mbpf, frame_rate); + mutex_unlock(&core->lock); + return -ENOMEM; + } + + /* + * VIDEO.IR.1.2 exhausted its firmware VBUF object pool while the fourth + * 4K CAPTURE session was starting, before any throughput measurement + * could correct an optimistic rate. Three such sessions reached the + * allocation path; never expose the known-unsafe fourth allocation. + */ + if (core->iris_platform_data->legacy_vpu5 && + mbpf >= IRIS1_4K_MBPF && + large_sessions >= IRIS1_MAX_4K_SESSIONS) { + dev_warn(core->dev, + "Iris1 v154: rejecting fourth 4K-class firmware capture session\n"); + mutex_unlock(&core->lock); + return -ENOMEM; + } + + inst->admission_frame_rate = frame_rate; + inst->core_load_reserved = true; + mutex_unlock(&core->lock); + + dev_info(core->dev, + "Iris1 v154: reserved %u mb/f at %u fps; aggregate %llu/%u mb/s\n", + mbpf, frame_rate, (unsigned long long)total_mbps, + core->iris_platform_data->max_core_mbps); + + return 0; +} + +void iris_release_core_load(struct iris_inst *inst) +{ + struct iris_core *core = inst->core; + + mutex_lock(&core->lock); + inst->core_load_reserved = false; + inst->admission_frame_rate = 0; + mutex_unlock(&core->lock); +} + int iris_session_streamoff(struct iris_inst *inst, u32 plane) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; enum iris_buffer_type buffer_type; int ret; @@ -215,6 +428,9 @@ int iris_session_streamoff(struct iris_inst *inst, u32 plane) return -EINVAL; } + /* Set this before FLUSH/STOP while inst->state can still be STREAMING. */ + inst->streamoff_pending = true; + ret = hfi_ops->session_stop(inst, plane); if (ret) goto error; @@ -225,6 +441,25 @@ int iris_session_streamoff(struct iris_inst *inst, u32 plane) iris_flush_deferred_buffers(inst, buffer_type); + if (inst->state == IRIS_INST_INIT) { + ret = iris_destroy_all_internal_buffers(inst, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + + ret = iris_destroy_all_internal_buffers(inst, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret) + return ret; + + ret = iris_hfi_session_close(inst); + if (ret) + return ret; + + dev_info(inst->core->dev, + "Iris1 v135: released stopped-session DMA and HFI resources\n"); + } + return 0; error: diff --git a/drivers/media/platform/qcom/iris/iris_common.h b/drivers/media/platform/qcom/iris/iris_common.h index b2a27b781c9a..918787124f1f 100644 --- a/drivers/media/platform/qcom/iris/iris_common.h +++ b/drivers/media/platform/qcom/iris/iris_common.h @@ -13,6 +13,10 @@ int iris_vb2_buffer_to_driver(struct vb2_buffer *vb2, struct iris_buffer *buf); void iris_set_ts_metadata(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf); int iris_process_streamon_input(struct iris_inst *inst); int iris_process_streamon_output(struct iris_inst *inst); +int iris_hfi_session_open(struct iris_inst *inst); +int iris_hfi_session_close(struct iris_inst *inst); +int iris_reserve_core_load(struct iris_inst *inst, u32 frame_rate); +void iris_release_core_load(struct iris_inst *inst); int iris_session_streamoff(struct iris_inst *inst, u32 plane); #endif diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/qcom/iris/iris_core.c index 52bf56e517f9..61f36ad9a1cd 100644 --- a/drivers/media/platform/qcom/iris/iris_core.c +++ b/drivers/media/platform/qcom/iris/iris_core.c @@ -3,6 +3,7 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include #include #include "iris_core.h" @@ -12,15 +13,22 @@ void iris_core_deinit(struct iris_core *core) { + /* + * The core starts in DEINIT and remains there while allow_fw_boot is + * disabled. Do not resume power domains, issue PAS shutdown, or touch + * VPU registers when no firmware/HFI state was ever initialized. + * Qualcomm's current driver has the same state guard. + */ + if (READ_ONCE(core->state) == IRIS_CORE_DEINIT) + return; + pm_runtime_resume_and_get(core->dev); mutex_lock(&core->lock); - if (core->state != IRIS_CORE_DEINIT) { - iris_fw_unload(core); - iris_vpu_power_off(core); - iris_hfi_queues_deinit(core); - core->state = IRIS_CORE_DEINIT; - } + iris_fw_unload(core); + iris_vpu_power_off(core); + iris_hfi_queues_deinit(core); + core->state = IRIS_CORE_DEINIT; mutex_unlock(&core->lock); pm_runtime_put_sync(core->dev); @@ -28,15 +36,27 @@ void iris_core_deinit(struct iris_core *core) static int iris_wait_for_system_response(struct iris_core *core) { + u32 hw_response_timeout_val = core->iris_platform_data->hw_response_timeout; int ret; if (core->state == IRIS_CORE_ERROR) return -EIO; ret = wait_for_completion_timeout(&core->core_init_done, - msecs_to_jiffies(HW_RESPONSE_TIMEOUT_VALUE)); + msecs_to_jiffies(hw_response_timeout_val)); if (!ret) { + if (core->iris_platform_data->legacy_vpu5) { + dev_err(core->dev, + "HFI timeout queues: cmd r=%u w=%u, msg r=%u w=%u, dbg r=%u w=%u\n", + core->command_queue.qhdr->read_idx, + core->command_queue.qhdr->write_idx, + core->message_queue.qhdr->read_idx, + core->message_queue.qhdr->write_idx, + core->debug_queue.qhdr->read_idx, + core->debug_queue.qhdr->write_idx); + } core->state = IRIS_CORE_ERROR; + dev_err(core->dev, "timed out waiting for HFI system response\n"); return -ETIMEDOUT; } @@ -58,28 +78,45 @@ int iris_core_init(struct iris_core *core) core->state = IRIS_CORE_INIT; + dev_info(core->dev, "initializing HFI queues\n"); ret = iris_hfi_queues_init(core); if (ret) goto error; + dev_info(core->dev, "powering on Iris hardware\n"); ret = iris_vpu_power_on(core); if (ret) goto error_queue_deinit; + dev_info(core->dev, "loading Iris firmware\n"); ret = iris_fw_load(core); if (ret) goto error_power_off; - ret = iris_vpu_boot_firmware(core); - if (ret) - goto error_unload_fw; + /* + * SM8150's secure VPU5 path needs the explicit remote-state resume + * used by the legacy Venus driver after PAS authentication and before + * the host programs HFI/CTRL_INIT. The newer Iris platforms do not + * require this on their initial boot path. + */ + if (core->iris_platform_data->legacy_vpu5) { + dev_info(core->dev, "resuming secure VPU5 hardware state\n"); + ret = iris_set_hw_state(core, true); + if (ret) { + dev_err(core->dev, + "failed to resume secure VPU5 hardware state: %d\n", + ret); + goto error_unload_fw; + } + dev_info(core->dev, "secure VPU5 hardware state resumed\n"); + } - ret = iris_vpu_switch_to_hwmode(core); + dev_info(core->dev, "booting Iris firmware CPU\n"); + ret = iris_vpu_boot_firmware(core); if (ret) goto error_unload_fw; - core->iris_firmware_data->init_hfi_ops(core); - + dev_info(core->dev, "initializing HFI core\n"); ret = iris_hfi_core_init(core); if (ret) goto error_unload_fw; diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h index 24da60448cf2..d872ae9037e4 100644 --- a/drivers/media/platform/qcom/iris/iris_core.h +++ b/drivers/media/platform/qcom/iris/iris_core.h @@ -16,6 +16,8 @@ #include "iris_resources.h" #include "iris_state.h" +struct llcc_slice_desc; + struct icc_info { const char *name; u32 bw_min_kbps; @@ -30,8 +32,6 @@ enum domain_type { DECODER = BIT(1), }; -struct qcom_ubwc_cfg_data; - /** * struct iris_core - holds core parameters valid for all instances * @@ -54,9 +54,6 @@ struct qcom_ubwc_cfg_data; * @resets: table of iris reset clocks * @controller_resets: table of controller reset clocks * @iris_platform_data: a structure for platform data - * @iris_firmware_data: a pointer to the firmware (or HFI) specific data - * @iris_firmware_desc: a pointer to the firmware-specific descriptive data - * @ubwc_cfg: UBWC configuration for the platform * @state: current state of core * @iface_q_table_daddr: device address for interface queue table memory * @sfr_daddr: device address for SFR (Sub System Failure Reason) register memory @@ -70,7 +67,8 @@ struct qcom_ubwc_cfg_data; * @header_id: id of packet header * @packet_id: id of packet * @power: a structure for clock and bw information - * @hfi_sys_ops: iris HFI system ops + * @hfi_ops: iris hfi command ops + * @hfi_response_ops: iris hfi response ops * @core_init_done: structure of signal completion for system response * @intr_status: interrupt status * @sys_error_handler: a delayed work for handling system fatal error @@ -99,9 +97,6 @@ struct iris_core { struct reset_control_bulk_data *resets; struct reset_control_bulk_data *controller_resets; const struct iris_platform_data *iris_platform_data; - const struct iris_firmware_data *iris_firmware_data; - const struct iris_firmware_desc *iris_firmware_desc; - const struct qcom_ubwc_cfg_data *ubwc_cfg; enum iris_core_state state; dma_addr_t iface_q_table_daddr; dma_addr_t sfr_daddr; @@ -115,11 +110,15 @@ struct iris_core { u32 header_id; u32 packet_id; struct iris_core_power power; - const struct iris_hfi_sys_ops *hfi_sys_ops; + const struct iris_hfi_command_ops *hfi_ops; + const struct iris_hfi_response_ops *hfi_response_ops; struct completion core_init_done; u32 intr_status; struct delayed_work sys_error_handler; struct list_head instances; + struct llcc_slice_desc *llcc_slices[2]; + bool llcc_active; + bool syscache_set; /* encoder and decoder have overlapping caps, so two different arrays are required */ struct platform_inst_fw_cap inst_fw_caps_dec[INST_FW_CAP_MAX]; struct platform_inst_fw_cap inst_fw_caps_enc[INST_FW_CAP_MAX]; diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c index 10e33b8a73f6..6cc289a41884 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.c +++ b/drivers/media/platform/qcom/iris/iris_ctrls.c @@ -98,62 +98,6 @@ static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id) return B_FRAME_QP_H264; case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: return B_FRAME_QP_HEVC; - case V4L2_CID_MPEG_VIDEO_AV1_PROFILE: - return PROFILE_AV1; - case V4L2_CID_MPEG_VIDEO_AV1_LEVEL: - return LEVEL_AV1; - case V4L2_CID_ROTATE: - return ROTATION; - case V4L2_CID_HFLIP: - return HFLIP; - case V4L2_CID_VFLIP: - return VFLIP; - case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE: - return IR_TYPE; - case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: - return IR_PERIOD; - case V4L2_CID_MPEG_VIDEO_LTR_COUNT: - return LTR_COUNT; - case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: - return USE_LTR; - case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: - return MARK_LTR; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - return B_FRAME; - case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING: - return LAYER_ENABLE; - case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: - return LAYER_TYPE_H264; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: - return LAYER_TYPE_HEVC; - case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER: - return LAYER_COUNT_H264; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: - return LAYER_COUNT_HEVC; - case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR: - return LAYER0_BITRATE_H264; - case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR: - return LAYER1_BITRATE_H264; - case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR: - return LAYER2_BITRATE_H264; - case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR: - return LAYER3_BITRATE_H264; - case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR: - return LAYER4_BITRATE_H264; - case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR: - return LAYER5_BITRATE_H264; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: - return LAYER0_BITRATE_HEVC; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: - return LAYER1_BITRATE_HEVC; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: - return LAYER2_BITRATE_HEVC; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: - return LAYER3_BITRATE_HEVC; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: - return LAYER4_BITRATE_HEVC; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: - return LAYER5_BITRATE_HEVC; default: return INST_FW_CAP_MAX; } @@ -241,62 +185,6 @@ static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id) return V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP; case B_FRAME_QP_HEVC: return V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP; - case PROFILE_AV1: - return V4L2_CID_MPEG_VIDEO_AV1_PROFILE; - case LEVEL_AV1: - return V4L2_CID_MPEG_VIDEO_AV1_LEVEL; - case ROTATION: - return V4L2_CID_ROTATE; - case HFLIP: - return V4L2_CID_HFLIP; - case VFLIP: - return V4L2_CID_VFLIP; - case IR_TYPE: - return V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE; - case IR_PERIOD: - return V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD; - case LTR_COUNT: - return V4L2_CID_MPEG_VIDEO_LTR_COUNT; - case USE_LTR: - return V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES; - case MARK_LTR: - return V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX; - case B_FRAME: - return V4L2_CID_MPEG_VIDEO_B_FRAMES; - case LAYER_ENABLE: - return V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING; - case LAYER_TYPE_H264: - return V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE; - case LAYER_TYPE_HEVC: - return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE; - case LAYER_COUNT_H264: - return V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER; - case LAYER_COUNT_HEVC: - return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER; - case LAYER0_BITRATE_H264: - return V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR; - case LAYER1_BITRATE_H264: - return V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR; - case LAYER2_BITRATE_H264: - return V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR; - case LAYER3_BITRATE_H264: - return V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR; - case LAYER4_BITRATE_H264: - return V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR; - case LAYER5_BITRATE_H264: - return V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR; - case LAYER0_BITRATE_HEVC: - return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR; - case LAYER1_BITRATE_HEVC: - return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR; - case LAYER2_BITRATE_HEVC: - return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR; - case LAYER3_BITRATE_HEVC: - return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR; - case LAYER4_BITRATE_HEVC: - return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR; - case LAYER5_BITRATE_HEVC: - return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR; default: return 0; } @@ -309,12 +197,27 @@ static int iris_op_s_ctrl(struct v4l2_ctrl *ctrl) struct platform_inst_fw_cap *cap; struct vb2_queue *q; + q = v4l2_m2m_get_src_vq(inst->m2m_ctx); + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: + if (inst->domain != DECODER || vb2_is_streaming(q)) + return -EINVAL; + inst->display_delay = ctrl->val; + return 0; + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: + if (inst->domain != DECODER || vb2_is_streaming(q)) + return -EINVAL; + inst->display_delay_enable = ctrl->val; + return 0; + default: + break; + } + cap = &inst->fw_caps[0]; cap_id = iris_get_cap_id(ctrl->id); if (!iris_valid_cap_id(cap_id)) return -EINVAL; - q = v4l2_m2m_get_src_vq(inst->m2m_ctx); if (vb2_is_streaming(q) && (!(inst->fw_caps[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED))) return -EINVAL; @@ -338,7 +241,7 @@ static const struct v4l2_ctrl_ops iris_ctrl_ops = { int iris_ctrls_init(struct iris_inst *inst) { struct platform_inst_fw_cap *cap = &inst->fw_caps[0]; - u32 num_ctrls = 0, ctrl_idx = 0, idx = 0; + u32 num_ctrls = 0, handler_ctrls, ctrl_idx = 0, idx = 0; u32 v4l2_id; int ret; @@ -347,12 +250,19 @@ int iris_ctrls_init(struct iris_inst *inst) num_ctrls++; } - /* Adding 1 to num_ctrls to include + /* Add one read-only buffer-count control. Legacy VPU5 decoders also + * expose the two standard display-delay controls used to request + * decode-order output from firmware. + * * V4L2_CID_MIN_BUFFERS_FOR_CAPTURE for decoder and * V4L2_CID_MIN_BUFFERS_FOR_OUTPUT for encoder */ + handler_ctrls = num_ctrls + 1; + if (inst->domain == DECODER && + inst->core->iris_platform_data->legacy_vpu5) + handler_ctrls += 2; - ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, num_ctrls + 1); + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, handler_ctrls); if (ret) return ret; @@ -395,6 +305,15 @@ int iris_ctrls_init(struct iris_inst *inst) if (inst->domain == DECODER) { v4l2_ctrl_new_std(&inst->ctrl_handler, NULL, V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 4); + + if (inst->core->iris_platform_data->legacy_vpu5) { + v4l2_ctrl_new_std(&inst->ctrl_handler, &iris_ctrl_ops, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + 0, 16383, 1, 0); + v4l2_ctrl_new_std(&inst->ctrl_handler, &iris_ctrl_ops, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + 0, 1, 1, 0); + } } else { v4l2_ctrl_new_std(&inst->ctrl_handler, NULL, V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 4); @@ -413,11 +332,11 @@ int iris_ctrls_init(struct iris_inst *inst) void iris_session_init_caps(struct iris_core *core) { - const struct platform_inst_fw_cap *caps; + struct platform_inst_fw_cap *caps; u32 i, num_cap, cap_id; - caps = core->iris_firmware_data->inst_fw_caps_dec; - num_cap = core->iris_firmware_data->inst_fw_caps_dec_size; + caps = core->iris_platform_data->inst_fw_caps_dec; + num_cap = core->iris_platform_data->inst_fw_caps_dec_size; for (i = 0; i < num_cap; i++) { cap_id = caps[i].cap_id; @@ -425,27 +344,17 @@ void iris_session_init_caps(struct iris_core *core) continue; core->inst_fw_caps_dec[cap_id].cap_id = caps[i].cap_id; + core->inst_fw_caps_dec[cap_id].min = caps[i].min; + core->inst_fw_caps_dec[cap_id].max = caps[i].max; core->inst_fw_caps_dec[cap_id].step_or_mask = caps[i].step_or_mask; + core->inst_fw_caps_dec[cap_id].value = caps[i].value; core->inst_fw_caps_dec[cap_id].flags = caps[i].flags; core->inst_fw_caps_dec[cap_id].hfi_id = caps[i].hfi_id; core->inst_fw_caps_dec[cap_id].set = caps[i].set; - - if (cap_id == PIPE) { - core->inst_fw_caps_dec[cap_id].value = - core->iris_platform_data->num_vpp_pipe; - core->inst_fw_caps_dec[cap_id].min = - core->iris_platform_data->num_vpp_pipe; - core->inst_fw_caps_dec[cap_id].max = - core->iris_platform_data->num_vpp_pipe; - } else { - core->inst_fw_caps_dec[cap_id].min = caps[i].min; - core->inst_fw_caps_dec[cap_id].max = caps[i].max; - core->inst_fw_caps_dec[cap_id].value = caps[i].value; - } } - caps = core->iris_firmware_data->inst_fw_caps_enc; - num_cap = core->iris_firmware_data->inst_fw_caps_enc_size; + caps = core->iris_platform_data->inst_fw_caps_enc; + num_cap = core->iris_platform_data->inst_fw_caps_enc_size; for (i = 0; i < num_cap; i++) { cap_id = caps[i].cap_id; @@ -483,7 +392,7 @@ static u32 iris_get_port_info(struct iris_inst *inst, int iris_set_u32_enum(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 hfi_value = inst->fw_caps[cap_id].value; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; @@ -496,7 +405,7 @@ int iris_set_u32_enum(struct iris_inst *inst, enum platform_inst_fw_cap_type cap int iris_set_u32(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 hfi_value = inst->fw_caps[cap_id].value; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; @@ -509,7 +418,7 @@ int iris_set_u32(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) int iris_set_stage(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; struct v4l2_format *inp_f = inst->fmt_src; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; u32 height = inp_f->fmt.pix_mp.height; @@ -530,7 +439,7 @@ int iris_set_stage(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id int iris_set_pipe(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 work_route = inst->fw_caps[PIPE].value; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; @@ -543,7 +452,7 @@ int iris_set_pipe(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) int iris_set_profile(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 hfi_id, hfi_value; if (inst->codec == V4L2_PIX_FMT_H264) { @@ -563,7 +472,7 @@ int iris_set_profile(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_ int iris_set_level(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 hfi_id, hfi_value; if (inst->codec == V4L2_PIX_FMT_H264) { @@ -583,28 +492,66 @@ int iris_set_level(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id int iris_set_profile_level_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; struct hfi_profile_level pl; if (inst->codec == V4L2_PIX_FMT_H264) { - pl.profile = inst->fw_caps[PROFILE_H264].value; - pl.level = inst->fw_caps[LEVEL_H264].value; + switch (inst->fw_caps[PROFILE_H264].value) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + pl.profile = BIT(0); + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + pl.profile = BIT(1); + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + pl.profile = BIT(2); + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH: + pl.profile = BIT(3); + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH: + pl.profile = BIT(4); + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + pl.profile = BIT(5); + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH: + pl.profile = BIT(6); + break; + default: + return -EINVAL; + } + + pl.level = BIT(inst->fw_caps[LEVEL_H264].value); } else { - pl.profile = inst->fw_caps[PROFILE_HEVC].value; - pl.level = inst->fw_caps[LEVEL_HEVC].value; + switch (inst->fw_caps[PROFILE_HEVC].value) { + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: + pl.profile = BIT(0); + break; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10: + pl.profile = BIT(1); + break; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: + pl.profile = BIT(2); + break; + default: + return -EINVAL; + } + + pl.level = BIT(inst->fw_caps[LEVEL_HEVC].value); } return hfi_ops->session_set_property(inst, hfi_id, HFI_HOST_FLAGS_NONE, iris_get_port_info(inst, cap_id), HFI_PAYLOAD_U32_ENUM, - &pl, sizeof(u32)); + &pl, sizeof(pl)); } int iris_set_header_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 header_mode = inst->fw_caps[cap_id].value; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; u32 hfi_val; @@ -623,7 +570,7 @@ int iris_set_header_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_ int iris_set_header_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 prepend_sps_pps = inst->fw_caps[PREPEND_SPSPPS_TO_IDR].value; u32 header_mode = inst->fw_caps[cap_id].value; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; @@ -643,66 +590,9 @@ int iris_set_header_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_ &hfi_val, sizeof(u32)); } -int iris_set_bitrate_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - u32 entropy_mode = inst->fw_caps[ENTROPY_MODE].value; - u32 bitrate = inst->fw_caps[cap_id].value; - u32 hfi_id = inst->fw_caps[cap_id].hfi_id; - struct hfi_bitrate hfi_val; - u32 max_bitrate; - - if (!(inst->fw_caps[cap_id].flags & CAP_FLAG_CLIENT_SET) && cap_id != BITRATE) - return -EINVAL; - - if (inst->codec == V4L2_PIX_FMT_HEVC) { - max_bitrate = CABAC_MAX_BITRATE; - } else { - if (entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) - max_bitrate = CABAC_MAX_BITRATE; - else - max_bitrate = CAVLC_MAX_BITRATE; - } - - hfi_val.bitrate = min(bitrate, max_bitrate); - - switch (cap_id) { - case BITRATE: - case LAYER0_BITRATE_H264: - hfi_val.layer_id = 0; - break; - case LAYER1_BITRATE_H264: - hfi_val.layer_id = 1; - break; - case LAYER2_BITRATE_H264: - hfi_val.layer_id = 2; - break; - case LAYER3_BITRATE_H264: - hfi_val.layer_id = 3; - break; - case LAYER4_BITRATE_H264: - hfi_val.layer_id = 4; - break; - case LAYER5_BITRATE_H264: - hfi_val.layer_id = 5; - break; - default: - return -EINVAL; - } - - if (hfi_val.layer_id > 0 && !inst->fw_caps[LAYER_ENABLE].value) - return -EINVAL; - - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_STRUCTURE, - &hfi_val, sizeof(hfi_val)); -} - -int iris_set_bitrate_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +int iris_set_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 entropy_mode = inst->fw_caps[ENTROPY_MODE].value; u32 bitrate = inst->fw_caps[cap_id].value; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; @@ -725,9 +615,26 @@ int iris_set_bitrate_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type &bitrate, sizeof(u32)); } +int iris_set_gop_size_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 gop_size = inst->fw_caps[cap_id].value; + struct hfi_intra_period period = { + .pframes = gop_size ? gop_size - 1 : 0, + .bframes = 0, + }; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &period, sizeof(period)); +} + int iris_set_peak_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 rc_mode = inst->fw_caps[BITRATE_MODE].value; u32 peak_bitrate = inst->fw_caps[cap_id].value; u32 bitrate = inst->fw_caps[BITRATE].value; @@ -754,7 +661,7 @@ int iris_set_peak_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type int iris_set_bitrate_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 bitrate_mode = inst->fw_caps[BITRATE_MODE].value; u32 frame_rc = inst->fw_caps[FRAME_RC_ENABLE].value; u32 frame_skip = inst->fw_caps[FRAME_SKIP_MODE].value; @@ -781,7 +688,7 @@ int iris_set_bitrate_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap int iris_set_bitrate_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 bitrate_mode = inst->fw_caps[BITRATE_MODE].value; u32 frame_rc = inst->fw_caps[FRAME_RC_ENABLE].value; u32 frame_skip = inst->fw_caps[FRAME_SKIP_MODE].value; @@ -808,7 +715,7 @@ int iris_set_bitrate_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap int iris_set_entropy_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 entropy_mode = inst->fw_caps[cap_id].value; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; u32 hfi_val; @@ -828,7 +735,7 @@ int iris_set_entropy_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap int iris_set_entropy_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 entropy_mode = inst->fw_caps[cap_id].value; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; u32 profile; @@ -853,7 +760,7 @@ int iris_set_entropy_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap int iris_set_min_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0; u32 i_frame_qp = 0, p_frame_qp = 0, b_frame_qp = 0; u32 min_qp_enable = 0, client_qp_enable = 0; @@ -917,7 +824,7 @@ int iris_set_min_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_i int iris_set_max_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0; u32 max_qp_enable = 0, client_qp_enable; u32 i_frame_qp, p_frame_qp, b_frame_qp; @@ -982,7 +889,7 @@ int iris_set_max_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_i int iris_set_frame_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0, client_qp_enable; u32 i_frame_qp, p_frame_qp, b_frame_qp; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; @@ -1043,7 +950,7 @@ int iris_set_frame_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap int iris_set_qp_range(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; struct hfi_quantization_range_v2 range; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; @@ -1062,424 +969,9 @@ int iris_set_qp_range(struct iris_inst *inst, enum platform_inst_fw_cap_type cap &range, sizeof(range)); } -int iris_set_rotation(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - u32 hfi_id = inst->fw_caps[cap_id].hfi_id; - u32 hfi_val; - - switch (inst->fw_caps[cap_id].value) { - case 0: - hfi_val = HFI_ROTATION_NONE; - return 0; - case 90: - hfi_val = HFI_ROTATION_90; - break; - case 180: - hfi_val = HFI_ROTATION_180; - break; - case 270: - hfi_val = HFI_ROTATION_270; - break; - default: - return -EINVAL; - } - - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_U32, - &hfi_val, sizeof(u32)); -} - -int iris_set_flip(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - u32 hfi_id = inst->fw_caps[cap_id].hfi_id; - u32 hfi_val = HFI_DISABLE_FLIP; - - if (inst->fw_caps[HFLIP].value) - hfi_val |= HFI_HORIZONTAL_FLIP; - - if (inst->fw_caps[VFLIP].value) - hfi_val |= HFI_VERTICAL_FLIP; - - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_U32_ENUM, - &hfi_val, sizeof(u32)); -} - -int iris_set_ir_period_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - struct v4l2_pix_format_mplane *fmt = &inst->fmt_dst->fmt.pix_mp; - u32 codec_align = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; - u32 ir_period = inst->fw_caps[cap_id].value; - u32 hfi_id = inst->fw_caps[cap_id].hfi_id; - struct hfi_intra_refresh hfi_val; - - if (!ir_period) - return -EINVAL; - - if (inst->fw_caps[IR_TYPE].value == - V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) { - hfi_val.mode = HFI_INTRA_REFRESH_RANDOM; - } else if (inst->fw_caps[IR_TYPE].value == - V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC) { - hfi_val.mode = HFI_INTRA_REFRESH_CYCLIC; - } else { - return -EINVAL; - } - - /* - * Calculate the number of macroblocks in a frame, - * then determine how many macroblocks need to be - * refreshed within one ir_period. - */ - hfi_val.mbs = (fmt->width / codec_align) * (fmt->height / codec_align); - hfi_val.mbs /= ir_period; - - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_STRUCTURE, - &hfi_val, sizeof(hfi_val)); -} - -int iris_set_ir_period_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - struct vb2_queue *q = v4l2_m2m_get_dst_vq(inst->m2m_ctx); - u32 ir_period = inst->fw_caps[cap_id].value; - u32 ir_type = 0; - - if (inst->fw_caps[IR_TYPE].value == - V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) { - if (vb2_is_streaming(q)) - return 0; - ir_type = HFI_PROP_IR_RANDOM_PERIOD; - } else if (inst->fw_caps[IR_TYPE].value == - V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC) { - ir_type = HFI_PROP_IR_CYCLIC_PERIOD; - } else { - return -EINVAL; - } - - return hfi_ops->session_set_property(inst, ir_type, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_U32, - &ir_period, sizeof(u32)); -} - -int iris_set_ltr_count_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - u32 ltr_count = inst->fw_caps[cap_id].value; - u32 hfi_id = inst->fw_caps[cap_id].hfi_id; - struct hfi_ltr_mode ltr_mode; - - if (!ltr_count) - return -EINVAL; - - ltr_mode.count = ltr_count; - ltr_mode.mode = HFI_LTR_MODE_MANUAL; - ltr_mode.trust_mode = 1; - - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_STRUCTURE, - <r_mode, sizeof(ltr_mode)); -} - -int iris_set_use_ltr(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - struct vb2_queue *sq = v4l2_m2m_get_src_vq(inst->m2m_ctx); - struct vb2_queue *dq = v4l2_m2m_get_dst_vq(inst->m2m_ctx); - u32 ltr_count = inst->fw_caps[LTR_COUNT].value; - u32 hfi_id = inst->fw_caps[cap_id].hfi_id; - struct hfi_ltr_use ltr_use; - - if (!vb2_is_streaming(sq) && !vb2_is_streaming(dq)) - return -EINVAL; - - if (!ltr_count) - return -EINVAL; - - ltr_use.ref_ltr = inst->fw_caps[cap_id].value; - ltr_use.use_constrnt = true; - ltr_use.frames = 0; - - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_STRUCTURE, - <r_use, sizeof(ltr_use)); -} - -int iris_set_mark_ltr(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - struct vb2_queue *sq = v4l2_m2m_get_src_vq(inst->m2m_ctx); - struct vb2_queue *dq = v4l2_m2m_get_dst_vq(inst->m2m_ctx); - u32 ltr_count = inst->fw_caps[LTR_COUNT].value; - u32 hfi_id = inst->fw_caps[cap_id].hfi_id; - struct hfi_ltr_mark ltr_mark; - - if (!vb2_is_streaming(sq) && !vb2_is_streaming(dq)) - return -EINVAL; - - if (!ltr_count) - return -EINVAL; - - ltr_mark.mark_frame = inst->fw_caps[cap_id].value; - - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_STRUCTURE, - <r_mark, sizeof(ltr_mark)); -} - -int iris_set_ltr_count_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - u32 ltr_count = inst->fw_caps[cap_id].value; - u32 hfi_id = inst->fw_caps[cap_id].hfi_id; - - if (!ltr_count) - return -EINVAL; - - if (inst->hfi_rc_type == HFI_RC_CBR_VFR || - inst->hfi_rc_type == HFI_RC_CBR_CFR || - inst->hfi_rc_type == HFI_RC_OFF) { - inst->fw_caps[LTR_COUNT].value = 0; - return -EINVAL; - } - - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_U32, - <r_count, sizeof(u32)); -} - -int iris_set_use_and_mark_ltr(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - struct vb2_queue *sq = v4l2_m2m_get_src_vq(inst->m2m_ctx); - struct vb2_queue *dq = v4l2_m2m_get_dst_vq(inst->m2m_ctx); - u32 ltr_count = inst->fw_caps[LTR_COUNT].value; - u32 hfi_val = inst->fw_caps[cap_id].value; - u32 hfi_id = inst->fw_caps[cap_id].hfi_id; - - if (!vb2_is_streaming(sq) && !vb2_is_streaming(dq)) - return -EINVAL; - - if (!ltr_count || hfi_val == INVALID_DEFAULT_MARK_OR_USE_LTR) - return -EINVAL; - - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_U32, - &hfi_val, sizeof(u32)); -} - -int iris_set_intra_period(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - u32 gop_size = inst->fw_caps[GOP_SIZE].value; - u32 b_frame = inst->fw_caps[B_FRAME].value; - u32 hfi_id = inst->fw_caps[cap_id].hfi_id; - struct hfi_intra_period intra_period; - - if (!gop_size || b_frame >= gop_size) - return -EINVAL; - - /* - * intra_period represents the length of a GOP, which includes both P-frames - * and B-frames. The counts of P-frames and B-frames within a GOP must be - * communicated to the firmware. - */ - intra_period.pframes = (gop_size - 1) / (b_frame + 1); - intra_period.bframes = b_frame; - - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_STRUCTURE, - &intra_period, sizeof(intra_period)); -} - -int iris_set_layer_type(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - u32 layer_enable = inst->fw_caps[LAYER_ENABLE].value; - u32 hfi_id = inst->fw_caps[cap_id].hfi_id; - u32 layer_type; - - if (inst->hfi_rc_type == HFI_RATE_CONTROL_CQ || - inst->hfi_rc_type == HFI_RATE_CONTROL_OFF) - return -EINVAL; - - if (inst->codec == V4L2_PIX_FMT_H264) { - if (!layer_enable || !inst->fw_caps[LAYER_COUNT_H264].value) - return -EINVAL; - - if (inst->fw_caps[LAYER_TYPE_H264].value == - V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P) { - if (inst->hfi_rc_type == HFI_RC_VBR_CFR) - layer_type = HFI_HIER_P_HYBRID_LTR; - else - layer_type = HFI_HIER_P_SLIDING_WINDOW; - } else if (inst->fw_caps[LAYER_TYPE_H264].value == - V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) { - if (inst->hfi_rc_type == HFI_RC_VBR_CFR) - layer_type = HFI_HIER_B; - else - return -EINVAL; - } else { - return -EINVAL; - } - } else if (inst->codec == V4L2_PIX_FMT_HEVC) { - if (!inst->fw_caps[LAYER_COUNT_HEVC].value) - return -EINVAL; - - if (inst->fw_caps[LAYER_TYPE_HEVC].value == - V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P) { - layer_type = HFI_HIER_P_SLIDING_WINDOW; - } else if (inst->fw_caps[LAYER_TYPE_HEVC].value == - V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) { - if (inst->hfi_rc_type == HFI_RC_VBR_CFR) - layer_type = HFI_HIER_B; - else - return -EINVAL; - } else { - return -EINVAL; - } - } else { - return -EINVAL; - } - - inst->hfi_layer_type = layer_type; - - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_U32_ENUM, - &layer_type, sizeof(u32)); -} - -int iris_set_layer_count_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - struct vb2_queue *sq = v4l2_m2m_get_src_vq(inst->m2m_ctx); - struct vb2_queue *dq = v4l2_m2m_get_dst_vq(inst->m2m_ctx); - u32 layer_enable = inst->fw_caps[LAYER_ENABLE].value; - u32 layer_count = inst->fw_caps[cap_id].value; - u32 hfi_id, ret; - - if (!layer_enable || !layer_count) - return -EINVAL; - - inst->hfi_layer_count = layer_count; - - if (!vb2_is_streaming(sq) && !vb2_is_streaming(dq)) { - hfi_id = HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER; - ret = hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_U32, - &layer_count, sizeof(u32)); - if (ret) - return ret; - } - - hfi_id = inst->fw_caps[cap_id].hfi_id; - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_U32, - &layer_count, sizeof(u32)); -} - -int iris_set_layer_count_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - u32 hfi_id = inst->fw_caps[cap_id].hfi_id; - u32 layer_type = inst->hfi_layer_type; - u32 layer_count, layer_count_max; - - layer_count = (inst->codec == V4L2_PIX_FMT_H264) ? - inst->fw_caps[LAYER_COUNT_H264].value : - inst->fw_caps[LAYER_COUNT_HEVC].value; - - if (!layer_count) - return -EINVAL; - - if (layer_type == HFI_HIER_B) { - layer_count_max = MAX_LAYER_HB; - } else if (layer_type == HFI_HIER_P_HYBRID_LTR) { - layer_count_max = MAX_AVC_LAYER_HP_HYBRID_LTR; - } else if (layer_type == HFI_HIER_P_SLIDING_WINDOW) { - if (inst->codec == V4L2_PIX_FMT_H264) { - layer_count_max = MAX_AVC_LAYER_HP_SLIDING_WINDOW; - } else { - if (inst->hfi_rc_type == HFI_RC_VBR_CFR) - layer_count_max = MAX_HEVC_VBR_LAYER_HP_SLIDING_WINDOW; - else - layer_count_max = MAX_HEVC_LAYER_HP_SLIDING_WINDOW; - } - } else { - return -EINVAL; - } - - if (layer_count > layer_count_max) - layer_count = layer_count_max; - - layer_count += 1; /* base layer */ - inst->hfi_layer_count = layer_count; - - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_U32, - &layer_count, sizeof(u32)); -} - -int iris_set_layer_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - struct vb2_queue *sq = v4l2_m2m_get_src_vq(inst->m2m_ctx); - struct vb2_queue *dq = v4l2_m2m_get_dst_vq(inst->m2m_ctx); - u32 hfi_id = inst->fw_caps[cap_id].hfi_id; - u32 bitrate = inst->fw_caps[cap_id].value; - - /* ignore layer bitrate when total bitrate is set */ - if (inst->fw_caps[BITRATE].flags & CAP_FLAG_CLIENT_SET) - return 0; - - if (!(inst->fw_caps[cap_id].flags & CAP_FLAG_CLIENT_SET)) - return -EINVAL; - - if (!vb2_is_streaming(sq) && !vb2_is_streaming(dq)) - return -EINVAL; - - return hfi_ops->session_set_property(inst, hfi_id, - HFI_HOST_FLAGS_NONE, - iris_get_port_info(inst, cap_id), - HFI_PAYLOAD_U32, - &bitrate, sizeof(u32)); -} - int iris_set_properties(struct iris_inst *inst, u32 plane) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; struct platform_inst_fw_cap *cap; int ret; u32 i; diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.h b/drivers/media/platform/qcom/iris/iris_ctrls.h index 3c462ec9190b..0fcc79bfbf8b 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.h +++ b/drivers/media/platform/qcom/iris/iris_ctrls.h @@ -22,8 +22,8 @@ int iris_set_level(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id int iris_set_profile_level_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_header_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_header_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_bitrate_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_bitrate_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_gop_size_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_peak_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_bitrate_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_bitrate_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); @@ -33,20 +33,6 @@ int iris_set_min_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_i int iris_set_max_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_frame_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_qp_range(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_rotation(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_flip(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_ir_period_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_ir_period_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_ltr_count_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_ltr_count_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_use_ltr(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_mark_ltr(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_use_and_mark_ltr(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_intra_period(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_layer_type(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_layer_count_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_layer_count_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); -int iris_set_layer_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_properties(struct iris_inst *inst, u32 plane); #endif diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index 1a476146d758..18fd4017d7f7 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -12,15 +12,15 @@ #include "iris_core.h" #include "iris_firmware.h" -#define IRIS_PAS_ID 9 - #define MAX_FIRMWARE_NAME_SIZE 128 static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) { + u32 pas_id = core->iris_platform_data->pas_id; const struct firmware *firmware = NULL; struct device *dev = core->dev; - struct resource res; + struct reserved_mem *rmem; + struct device_node *node; phys_addr_t mem_phys; size_t res_size; ssize_t fw_size; @@ -30,12 +30,17 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) if (strlen(fw_name) >= MAX_FIRMWARE_NAME_SIZE - 4) return -EINVAL; - ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); - if (ret) - return ret; + node = of_parse_phandle(dev->of_node, "memory-region", 0); + if (!node) + return -EINVAL; + + rmem = of_reserved_mem_lookup(node); + of_node_put(node); + if (!rmem) + return -EINVAL; - mem_phys = res.start; - res_size = resource_size(&res); + mem_phys = rmem->base; + res_size = rmem->size; ret = request_firmware(&firmware, fw_name, dev); if (ret) @@ -54,57 +59,58 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) } ret = qcom_mdt_load(dev, firmware, fw_name, - IRIS_PAS_ID, mem_virt, mem_phys, res_size, NULL); - + pas_id, mem_virt, mem_phys, res_size, NULL); memunmap(mem_virt); -err_release_fw: release_firmware(firmware); + if (ret) + return ret; + dev_info(dev, "firmware image copied; starting PAS authentication (id %u)\n", + pas_id); + ret = qcom_scm_pas_auth_and_reset(pas_id); + dev_info(dev, "PAS authentication returned %d\n", ret); + + return ret; + +err_release_fw: + release_firmware(firmware); return ret; } int iris_fw_load(struct iris_core *core) { - const struct tz_cp_config *cp_config; + struct tz_cp_config *cp_config = core->iris_platform_data->tz_cp_config_data; const char *fwpath = NULL; - int i, ret; + int ret; ret = of_property_read_string_index(core->dev->of_node, "firmware-name", 0, &fwpath); if (ret) - fwpath = core->iris_firmware_desc->fwname; + fwpath = core->iris_platform_data->fwname; + dev_info(core->dev, "requesting firmware '%s'\n", fwpath); ret = iris_load_fw_to_memory(core, fwpath); if (ret) { dev_err(core->dev, "firmware download failed\n"); return -ENOMEM; } - ret = qcom_scm_pas_auth_and_reset(IRIS_PAS_ID); - if (ret) { - dev_err(core->dev, "auth and reset failed: %d\n", ret); + ret = qcom_scm_mem_protect_video_var(cp_config->cp_start, + cp_config->cp_size, + cp_config->cp_nonpixel_start, + cp_config->cp_nonpixel_size); + if (ret) { + dev_err(core->dev, "protect memory failed\n"); + qcom_scm_pas_shutdown(core->iris_platform_data->pas_id); return ret; } - for (i = 0; i < core->iris_platform_data->tz_cp_config_data_size; i++) { - cp_config = &core->iris_platform_data->tz_cp_config_data[i]; - ret = qcom_scm_mem_protect_video_var(cp_config->cp_start, - cp_config->cp_size, - cp_config->cp_nonpixel_start, - cp_config->cp_nonpixel_size); - if (ret) { - dev_err(core->dev, "qcom_scm_mem_protect_video_var failed: %d\n", ret); - qcom_scm_pas_shutdown(IRIS_PAS_ID); - return ret; - } - } - return ret; } int iris_fw_unload(struct iris_core *core) { - return qcom_scm_pas_shutdown(IRIS_PAS_ID); + return qcom_scm_pas_shutdown(core->iris_platform_data->pas_id); } int iris_set_hw_state(struct iris_core *core, bool resume) diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.c b/drivers/media/platform/qcom/iris/iris_hfi_common.c index 8769ec61f117..a4c35c773411 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_common.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_common.c @@ -79,6 +79,17 @@ int iris_hfi_core_init(struct iris_core *core) const struct iris_hfi_sys_ops *hfi_ops = core->hfi_sys_ops; int ret; + /* + * Wait for the VPU5 SYS_INIT response before sending any further + * command. The downstream Venus driver sends its default system + * properties later, immediately before SESSION_INIT. + */ + if (core->iris_platform_data->legacy_vpu5) { + dev_info(core->dev, + "Iris1 v88: sending SYS_INIT through legacy HFI queue\n"); + return hfi_ops->sys_init(core); + } + ret = hfi_ops->sys_init(core); if (ret) return ret; @@ -92,8 +103,19 @@ int iris_hfi_core_init(struct iris_core *core) irqreturn_t iris_hfi_isr(int irq, void *data) { + struct iris_core *core = data; + disable_irq_nosync(irq); + /* + * SM8150 VPU5 signals a level-high interrupt. Clear the source in + * the hard IRQ handler, as the legacy Venus driver does. Deferring + * the clear leaves the source asserted during firmware boot because + * iris_core_init() owns core->lock while the threaded handler waits. + */ + if (core && core->iris_platform_data->legacy_vpu5) + iris_vpu_clear_interrupt(core); + return IRQ_WAKE_THREAD; } @@ -106,7 +128,8 @@ irqreturn_t iris_hfi_isr_handler(int irq, void *data) mutex_lock(&core->lock); pm_runtime_mark_last_busy(core->dev); - iris_vpu_clear_interrupt(core); + if (!core->iris_platform_data->legacy_vpu5) + iris_vpu_clear_interrupt(core); mutex_unlock(&core->lock); core->hfi_sys_ops->sys_hfi_response_handler(core); @@ -137,7 +160,8 @@ int iris_hfi_pm_suspend(struct iris_core *core) return 0; error: - dev_err(core->dev, "failed to suspend\n"); + dev_err_once(core->dev, + "failed to suspend (%d); suppressing repeated messages\n", ret); return ret; } diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c index 7674b47ad6c4..d1b458ece77f 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c @@ -6,8 +6,12 @@ #include "iris_hfi_gen1.h" #include "iris_hfi_gen1_defines.h" #include "iris_instance.h" +#include "iris_utils.h" #include "iris_vpu_buffer.h" +#include +#include + static u32 iris_hfi_gen1_buf_type_from_driver(enum iris_buffer_type buffer_type) { switch (buffer_type) { @@ -53,7 +57,7 @@ static int iris_hfi_gen1_sys_image_version(struct iris_core *core) return iris_hfi_queue_cmd_write_locked(core, &packet, packet.hdr.size); } -static int iris_hfi_gen1_sys_interframe_powercollapse(struct iris_core *core) +static int iris_hfi_gen1_sys_power_control(struct iris_core *core, bool enable) { struct hfi_sys_set_property_pkt *pkt; struct hfi_enable *hfi; @@ -71,7 +75,7 @@ static int iris_hfi_gen1_sys_interframe_powercollapse(struct iris_core *core) pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY; pkt->num_properties = 1; pkt->data[0] = HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL; - hfi->enable = true; + hfi->enable = enable; ret = iris_hfi_queue_cmd_write_locked(core, pkt, pkt->hdr.size); kfree(pkt); @@ -79,6 +83,119 @@ static int iris_hfi_gen1_sys_interframe_powercollapse(struct iris_core *core) return ret; } +static int iris_hfi_gen1_sys_debug_config(struct iris_core *core) +{ + struct hfi_sys_set_property_pkt *pkt; + struct hfi_debug_config *config; + u32 packet_size; + int ret; + + packet_size = struct_size(pkt, data, 1) + sizeof(*config); + pkt = kzalloc(packet_size, GFP_KERNEL); + if (!pkt) + return -ENOMEM; + + config = (struct hfi_debug_config *)&pkt->data[1]; + pkt->hdr.size = packet_size; + pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY; + pkt->num_properties = 1; + pkt->data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG; + config->debug_config = HFI_DEBUG_MSG_ERROR | HFI_DEBUG_MSG_FATAL; + config->debug_mode = HFI_DEBUG_MODE_QUEUE; + + dev_info(core->dev, + "Iris1 v57: enabling firmware error/fatal debug queue\n"); + ret = iris_hfi_queue_cmd_write(core, pkt, packet_size); + kfree(pkt); + + return ret; +} + +static int iris_hfi_gen1_syscache_config(struct iris_core *core) +{ + static const u32 usecase_ids[] = { LLCC_VIDSC0, LLCC_VIDSC1 }; + struct hfi_sys_set_resource_pkt *pkt; + u32 packet_size, i; + int ret; + + if (core->syscache_set) + return 0; + + for (i = 0; i < ARRAY_SIZE(usecase_ids); i++) { + core->llcc_slices[i] = llcc_slice_getd(usecase_ids[i]); + if (IS_ERR(core->llcc_slices[i])) { + ret = PTR_ERR(core->llcc_slices[i]); + core->llcc_slices[i] = NULL; + dev_err(core->dev, + "Iris1 LLCC: failed to get VIDSC%u slice: %d\n", + i, ret); + goto error_put; + } + } + + for (i = 0; i < ARRAY_SIZE(usecase_ids); i++) { + ret = llcc_slice_activate(core->llcc_slices[i]); + if (ret) { + dev_err(core->dev, + "Iris1 LLCC: failed to activate VIDSC%u: %d\n", + i, ret); + goto error_deactivate; + } + } + core->llcc_active = true; + + /* + * data[0] is num_entries, followed by two { size, slice_id } pairs. + * Sizes are expressed in KiB, matching the downstream Venus ABI. + */ + packet_size = struct_size(pkt, data, 5); + pkt = kzalloc(packet_size, GFP_KERNEL); + if (!pkt) { + ret = -ENOMEM; + goto error_deactivate; + } + + pkt->hdr.size = packet_size; + pkt->hdr.pkt_type = HFI_CMD_SYS_SET_RESOURCE; + pkt->resource_handle = 1; + pkt->resource_type = HFI_RESOURCE_SYSCACHE; + pkt->data[0] = ARRAY_SIZE(usecase_ids); + for (i = 0; i < ARRAY_SIZE(usecase_ids); i++) { + pkt->data[1 + (i * 2)] = + llcc_get_slice_size(core->llcc_slices[i]); + pkt->data[2 + (i * 2)] = + llcc_get_slice_id(core->llcc_slices[i]); + } + + dev_info(core->dev, + "Iris1 v57: setting LLCC resources: id=%u size=%u KiB, id=%u size=%u KiB\n", + pkt->data[2], pkt->data[1], pkt->data[4], pkt->data[3]); + ret = iris_hfi_queue_cmd_write(core, pkt, packet_size); + kfree(pkt); + if (ret) + goto error_deactivate; + + core->syscache_set = true; + return 0; + +error_deactivate: + while (i--) + llcc_slice_deactivate(core->llcc_slices[i]); + core->llcc_active = false; +error_put: + for (i = 0; i < ARRAY_SIZE(usecase_ids); i++) { + llcc_slice_putd(core->llcc_slices[i]); + core->llcc_slices[i] = NULL; + } + + return ret; +} + +static int iris_hfi_gen1_sys_interframe_powercollapse(struct iris_core *core) +{ + return iris_hfi_gen1_sys_power_control(core, true); +} + static int iris_hfi_gen1_sys_pc_prep(struct iris_core *core) { struct hfi_sys_pc_prep_pkt pkt; @@ -98,6 +215,29 @@ static int iris_hfi_gen1_session_open(struct iris_inst *inst) if (inst->state != IRIS_INST_DEINIT) return -EALREADY; + /* + * SYS_INIT has already completed by the time session_open() runs. + * Explicitly keep firmware power-plane collapse disabled while SM8150 + * is using the software-controlled GDSC fallback. Enabling collapse + * here lets firmware power down the codec before the host has safely + * transferred the GDSC and clocks to hardware control. + */ + if (inst->core->iris_platform_data->legacy_vpu5) { + dev_info(inst->core->dev, + "Iris1 v57: preparing SM8150 system resources before SESSION_INIT\n"); + ret = iris_hfi_gen1_sys_debug_config(inst->core); + if (ret) + return ret; + ret = iris_hfi_gen1_syscache_config(inst->core); + if (ret) + return ret; + dev_info(inst->core->dev, + "Iris1 v57: disabling codec power-plane collapse before SESSION_INIT\n"); + ret = iris_hfi_gen1_sys_power_control(inst->core, false); + if (ret) + return ret; + } + switch (inst->codec) { case V4L2_PIX_FMT_H264: codec = HFI_VIDEO_CODEC_H264; @@ -154,6 +294,12 @@ static int iris_hfi_gen1_session_start(struct iris_inst *inst, u32 plane) struct hfi_session_pkt packet; int ret; + dev_info(core->dev, + "Iris1 v107: session_start plane=%s state=%u substate=%#x load_resources=%u\n", + V4L2_TYPE_IS_OUTPUT(plane) ? "OUTPUT" : "CAPTURE", + inst->state, inst->sub_state, + !!(inst->sub_state & IRIS_INST_SUB_LOAD_RESOURCES)); + if (!V4L2_TYPE_IS_OUTPUT(plane)) return 0; @@ -193,6 +339,11 @@ static int iris_hfi_gen1_session_stop(struct iris_inst *inst, u32 plane) u32 flush_type = 0; int ret = 0; + dev_info(core->dev, + "Iris1 v107: session_stop plane=%s state=%u substate=%#x streamoff=%u\n", + V4L2_TYPE_IS_OUTPUT(plane) ? "OUTPUT" : "CAPTURE", + inst->state, inst->sub_state, inst->streamoff_pending); + if (inst->domain == DECODER) { if (inst->state == IRIS_INST_STREAMING) { if (V4L2_TYPE_IS_OUTPUT(plane)) @@ -207,11 +358,21 @@ static int iris_hfi_gen1_session_stop(struct iris_inst *inst, u32 plane) flush_pkt.shdr.session_id = inst->session_id; flush_pkt.flush_type = flush_type; + dev_info(core->dev, + "Iris1 v107: sending SESSION_FLUSH plane=%s type=%#x pending=%u\n", + V4L2_TYPE_IS_OUTPUT(plane) ? "OUTPUT" : "CAPTURE", + flush_type, inst->flush_responses_pending); + ret = iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size); if (!ret) { inst->flush_responses_pending++; ret = iris_wait_for_session_response(inst, true); } + + dev_info(core->dev, + "Iris1 v107: SESSION_FLUSH done plane=%s type=%#x ret=%d pending=%u\n", + V4L2_TYPE_IS_OUTPUT(plane) ? "OUTPUT" : "CAPTURE", + flush_type, ret, inst->flush_responses_pending); } else if (inst->sub_state & IRIS_INST_SUB_LOAD_RESOURCES) { reinit_completion(&inst->completion); iris_hfi_gen1_packet_session_cmd(inst, &pkt, HFI_CMD_SESSION_STOP); @@ -273,8 +434,8 @@ static int iris_hfi_gen1_session_continue(struct iris_inst *inst, u32 plane) static int iris_hfi_gen1_queue_input_buffer(struct iris_inst *inst, struct iris_buffer *buf) { - struct hfi_session_empty_buffer_compressed_pkt com_ip_pkt; - struct hfi_session_empty_buffer_uncompressed_pkt uncom_ip_pkt; + struct hfi_session_empty_buffer_compressed_pkt com_ip_pkt = { 0 }; + struct hfi_session_empty_buffer_uncompressed_pkt uncom_ip_pkt = { 0 }; if (inst->domain == DECODER) { com_ip_pkt.shdr.hdr.size = sizeof(struct hfi_session_empty_buffer_compressed_pkt); @@ -282,6 +443,7 @@ static int iris_hfi_gen1_queue_input_buffer(struct iris_inst *inst, struct iris_ com_ip_pkt.shdr.session_id = inst->session_id; com_ip_pkt.time_stamp_hi = upper_32_bits(buf->timestamp); com_ip_pkt.time_stamp_lo = lower_32_bits(buf->timestamp); + /* V4L2 buffer flag bits are not legacy HFI input flag bits. */ com_ip_pkt.flags = 0; com_ip_pkt.mark_target = 0; com_ip_pkt.mark_data = 0; @@ -290,6 +452,12 @@ static int iris_hfi_gen1_queue_input_buffer(struct iris_inst *inst, struct iris_ com_ip_pkt.filled_len = buf->data_size; com_ip_pkt.input_tag = buf->index; com_ip_pkt.packet_buffer = buf->device_addr; + + dev_dbg(inst->core->dev, + "Iris1 v57 ETB: index=%u dma=%pad alloc=%zu filled=%zu offset=%u v4l2_flags=%#x hfi_flags=%#x timestamp=%llu\n", + buf->index, &buf->device_addr, buf->buffer_size, buf->data_size, + buf->data_offset, buf->flags, com_ip_pkt.flags, buf->timestamp); + return iris_hfi_queue_cmd_write(inst->core, &com_ip_pkt, com_ip_pkt.shdr.hdr.size); } else { @@ -315,7 +483,7 @@ static int iris_hfi_gen1_queue_input_buffer(struct iris_inst *inst, struct iris_ static int iris_hfi_gen1_queue_output_buffer(struct iris_inst *inst, struct iris_buffer *buf) { - struct hfi_session_fill_buffer_pkt op_pkt; + struct hfi_session_fill_buffer_pkt op_pkt = { 0 }; op_pkt.shdr.hdr.size = sizeof(struct hfi_session_fill_buffer_pkt); op_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FILL_BUFFER; @@ -333,6 +501,20 @@ static int iris_hfi_gen1_queue_output_buffer(struct iris_inst *inst, struct iris else op_pkt.stream_id = 0; + /* + * Downstream msm_vidc points legacy split-mode output FTBs at the byte + * immediately following the image even when the firmware reports a zero + * extradata size. Iris1 validates that pointer independently of the size. + */ + if (inst->core->iris_platform_data->legacy_vpu5 && + inst->codec == V4L2_PIX_FMT_VP9) + op_pkt.extradata_buffer = buf->device_addr + buf->buffer_size; + + dev_dbg(inst->core->dev, + "Iris1 v57 FTB: index=%u dma=%pad alloc=%zu filled=%zu offset=%u\n", + buf->index, &buf->device_addr, buf->buffer_size, buf->data_size, + buf->data_offset); + return iris_hfi_queue_cmd_write(inst->core, &op_pkt, op_pkt.shdr.hdr.size); } @@ -364,6 +546,10 @@ static int iris_hfi_gen1_queue_internal_buffer(struct iris_inst *inst, struct ir } int_pkt->buffer_type = buffer_type; + dev_dbg(inst->core->dev, + "Iris1 v57 internal: driver_type=%u hfi_type=%#x dma=%pad size=%zu end=%pad\n", + buf->type, buffer_type, &buf->device_addr, buf->buffer_size, + &(dma_addr_t){ buf->device_addr + buf->buffer_size }); ret = iris_hfi_queue_cmd_write(inst->core, int_pkt, int_pkt->shdr.hdr.size); exit: @@ -441,8 +627,6 @@ static int iris_hfi_gen1_session_unset_buffers(struct iris_inst *inst, struct ir goto exit; ret = iris_wait_for_session_response(inst, false); - if (!ret) - ret = iris_destroy_internal_buffer(inst, buf); exit: kfree(pkt); @@ -485,7 +669,7 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p { void *prop_data = &packet->data[1]; - packet->shdr.hdr.size = sizeof(*packet) + sizeof(ptype); + packet->shdr.hdr.size = sizeof(*packet); packet->shdr.hdr.pkt_type = HFI_CMD_SESSION_SET_PROPERTY; packet->shdr.session_id = inst->session_id; packet->num_properties = 1; @@ -498,14 +682,14 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p fsize->buffer_type = in->buffer_type; fsize->height = in->height; fsize->width = in->width; - packet->shdr.hdr.size += sizeof(*fsize); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*fsize); break; } case HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE: { struct hfi_videocores_usage_type *in = pdata, *cu = prop_data; cu->video_core_enable_mask = in->video_core_enable_mask; - packet->shdr.hdr.size += sizeof(*cu); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*cu); break; } case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT: { @@ -514,26 +698,30 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p hfi->buffer_type = in->buffer_type; hfi->format = in->format; - packet->shdr.hdr.size += sizeof(*hfi); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*hfi); break; } case HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO: { struct hfi_uncompressed_plane_actual_constraints_info *info = prop_data; + u32 stride_multiple; + + stride_multiple = inst->fmt_dst->fmt.pix_mp.pixelformat == + V4L2_PIX_FMT_P010 ? 256 : 128; info->buffer_type = HFI_BUFFER_OUTPUT2; info->num_planes = 2; - info->plane_format[0].stride_multiples = 128; + info->plane_format[0].stride_multiples = stride_multiple; info->plane_format[0].max_stride = 8192; info->plane_format[0].min_plane_buffer_height_multiple = 32; info->plane_format[0].buffer_alignment = 256; if (info->num_planes > 1) { - info->plane_format[1].stride_multiples = 128; + info->plane_format[1].stride_multiples = stride_multiple; info->plane_format[1].max_stride = 8192; info->plane_format[1].min_plane_buffer_height_multiple = 16; info->plane_format[1].buffer_alignment = 256; } - packet->shdr.hdr.size += sizeof(*info); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*info); break; } case HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL: { @@ -543,7 +731,7 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p count->type = in->type; count->count_actual = in->count_actual; count->count_min_host = in->count_min_host; - packet->shdr.hdr.size += sizeof(*count); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*count); break; } case HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM: { @@ -552,7 +740,18 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p multi->buffer_type = in->buffer_type; multi->enable = in->enable; - packet->shdr.hdr.size += sizeof(*multi); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*multi); + break; + } + case HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER: { + u32 *order = pdata; + + if (*order != HFI_OUTPUT_ORDER_DECODE && + *order != HFI_OUTPUT_ORDER_DISPLAY) + return -EINVAL; + + packet->data[1] = *order; + packet->shdr.hdr.size += sizeof(u32) * 2; break; } case HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL: { @@ -560,7 +759,7 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p sz->size = in->size; sz->type = in->type; - packet->shdr.hdr.size += sizeof(*sz); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*sz); break; } case HFI_PROPERTY_PARAM_WORK_ROUTE: { @@ -568,7 +767,7 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p u32 *in = pdata; wr->video_work_route = *in; - packet->shdr.hdr.size += sizeof(*wr); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*wr); break; } case HFI_PROPERTY_PARAM_WORK_MODE: { @@ -576,7 +775,7 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p u32 *in = pdata; wm->video_work_mode = *in; - packet->shdr.hdr.size += sizeof(*wm); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*wm); break; } case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: { @@ -586,13 +785,13 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p pl->profile = in->profile; if (pl->profile <= 0) /* Profile not supported, falling back to high */ - pl->profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; + pl->profile = BIT(2); if (!pl->level) /* Level not supported, falling back to 1 */ pl->level = 1; - packet->shdr.hdr.size += sizeof(*pl); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*pl); break; } case HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER: { @@ -600,15 +799,24 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p u32 *in = pdata; en->enable = *in; - packet->shdr.hdr.size += sizeof(*en); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*en); break; } case HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE: { - struct hfi_bitrate *in = pdata, *brate = prop_data; + struct hfi_bitrate *brate = prop_data; + u32 *in = pdata; + + brate->bitrate = *in; + brate->layer_id = 0; + packet->shdr.hdr.size += sizeof(u32) + sizeof(*brate); + break; + } + case HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD: { + struct hfi_intra_period *in = pdata, *period = prop_data; - brate->bitrate = in->bitrate; - brate->layer_id = in->layer_id; - packet->shdr.hdr.size += sizeof(*brate); + period->pframes = in->pframes; + period->bframes = in->bframes; + packet->shdr.hdr.size += sizeof(u32) + sizeof(*period); break; } case HFI_PROPERTY_PARAM_VENC_RATE_CONTROL: { @@ -627,7 +835,7 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p } packet->data[1] = *in; - packet->shdr.hdr.size += sizeof(u32); + packet->shdr.hdr.size += sizeof(u32) * 2; break; } case HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL: { @@ -637,7 +845,7 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p entropy->entropy_mode = *in; if (entropy->entropy_mode == HFI_H264_ENTROPY_CABAC) entropy->cabac_model = HFI_H264_CABAC_MODEL_0; - packet->shdr.hdr.size += sizeof(*entropy); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*entropy); break; } case HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2: { @@ -662,7 +870,7 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p ((max_qp & 0xFF) << 16); range->min_qp.enable = 7; range->max_qp.enable = 7; - packet->shdr.hdr.size += sizeof(*range); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*range); break; } case HFI_PROPERTY_CONFIG_FRAME_RATE: { @@ -671,7 +879,7 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p frate->buffer_type = in->buffer_type; frate->framerate = in->framerate; - packet->shdr.hdr.size += sizeof(*frate); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*frate); break; } case HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO: { @@ -683,62 +891,7 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p plane_actual_info->plane_format[0] = in->plane_format[0]; if (in->num_planes > 1) plane_actual_info->plane_format[1] = in->plane_format[1]; - packet->shdr.hdr.size += sizeof(*plane_actual_info); - break; - } - case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH: { - struct hfi_intra_refresh *in = pdata, *intra_refresh = prop_data; - - intra_refresh->mode = in->mode; - intra_refresh->mbs = in->mbs; - packet->shdr.hdr.size += sizeof(*intra_refresh); - break; - } - case HFI_PROPERTY_PARAM_VENC_LTRMODE: { - struct hfi_ltr_mode *in = pdata, *ltr_mode = prop_data; - - ltr_mode->mode = in->mode; - ltr_mode->count = in->count; - ltr_mode->trust_mode = in->trust_mode; - packet->shdr.hdr.size += sizeof(*ltr_mode); - break; - } - case HFI_PROPERTY_CONFIG_VENC_USELTRFRAME: { - struct hfi_ltr_use *in = pdata, *ltr_use = prop_data; - - ltr_use->frames = in->frames; - ltr_use->ref_ltr = in->ref_ltr; - ltr_use->use_constrnt = in->use_constrnt; - packet->shdr.hdr.size += sizeof(*ltr_use); - break; - } - case HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME: { - struct hfi_ltr_mark *in = pdata, *ltr_mark = prop_data; - - ltr_mark->mark_frame = in->mark_frame; - packet->shdr.hdr.size += sizeof(*ltr_mark); - break; - } - case HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD: { - struct hfi_intra_period *in = pdata, *intra_period = prop_data; - - intra_period->pframes = in->pframes; - intra_period->bframes = in->bframes; - packet->shdr.hdr.size += sizeof(*intra_period); - break; - } - case HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER: { - u32 *in = pdata; - - packet->data[1] = *in; - packet->shdr.hdr.size += sizeof(u32); - break; - } - case HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER: { - u32 *in = pdata; - - packet->data[1] = *in; - packet->shdr.hdr.size += sizeof(u32); + packet->shdr.hdr.size += sizeof(u32) + sizeof(*plane_actual_info); break; } default: @@ -789,7 +942,7 @@ static int iris_hfi_gen1_set_resolution(struct iris_inst *inst, u32 plane) struct hfi_framesize fs; int ret; - if (!iris_drc_pending(inst) && !(inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)) { + if (!iris_drc_pending(inst)) { fs.buffer_type = HFI_BUFFER_INPUT; fs.width = inst->fmt_src->fmt.pix_mp.width; fs.height = inst->fmt_src->fmt.pix_mp.height; @@ -812,11 +965,72 @@ static int iris_hfi_gen1_set_resolution(struct iris_inst *inst, u32 plane) static int iris_hfi_gen1_decide_core(struct iris_inst *inst, u32 plane) { const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE; + struct iris_core *core = inst->core; struct hfi_videocores_usage_type cu; + struct iris_inst *instance; + u64 core1_load = 0; + u64 core2_load = 0; + bool new_assignment = false; + u32 fps; + int ret; - cu.video_core_enable_mask = HFI_CORE_ID_1; + /* + * VIDEO.IR.1.2 exposes two independently selectable video cores. Keep + * each decoder session on one core and place new sessions on the less + * loaded core, matching the downstream msm_vidc policy. Reserve the + * assignment while holding core->lock so concurrent STREAMON calls cannot + * both observe an empty core. + */ + mutex_lock(&core->lock); + if (!inst->hfi_core_id) { + list_for_each_entry(instance, &core->instances, list) { + if (instance == inst || !instance->hfi_session_opened || + instance->domain != DECODER) + continue; + + fps = max(instance->frame_rate, instance->operating_rate); + /* + * A freshly opened session starts at the MAXIMUM_FPS + * placeholder until its first one-second QBUF window + * lands. Using that value here overstates a 4K session + * about eightfold and would pin every later session onto + * the remaining core. Fall back to the default rate + * until a measurement arrives. + */ + if (fps == MAXIMUM_FPS) + fps = DEFAULT_FPS; + fps = max(fps, 1U); + if (instance->hfi_core_id == HFI_CORE_ID_1) + core1_load += (u64)iris_get_mbpf(instance) * fps; + else if (instance->hfi_core_id == HFI_CORE_ID_2) + core2_load += (u64)iris_get_mbpf(instance) * fps; + } - return hfi_gen1_set_property(inst, ptype, &cu, sizeof(cu)); + if (core->iris_platform_data->legacy_vpu5 && + core->iris_platform_data->num_vpp_pipe > 1 && + core1_load > core2_load) + inst->hfi_core_id = HFI_CORE_ID_2; + else + inst->hfi_core_id = HFI_CORE_ID_1; + new_assignment = true; + } + cu.video_core_enable_mask = inst->hfi_core_id; + mutex_unlock(&core->lock); + + ret = hfi_gen1_set_property(inst, ptype, &cu, sizeof(cu)); + if (ret && new_assignment) { + mutex_lock(&core->lock); + if (inst->hfi_core_id == cu.video_core_enable_mask) + inst->hfi_core_id = 0; + mutex_unlock(&core->lock); + return ret; + } + + dev_info(core->dev, + "Iris1 v144: decoder codec=%p4cc assigned core=%u (loads %llu/%llu)\n", + &inst->codec, cu.video_core_enable_mask, core1_load, core2_load); + + return ret; } static int iris_hfi_gen1_set_raw_format(struct iris_inst *inst, u32 plane) @@ -830,29 +1044,30 @@ static int iris_hfi_gen1_set_raw_format(struct iris_inst *inst, u32 plane) pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; if (iris_split_mode_enabled(inst)) { fmt.buffer_type = HFI_BUFFER_OUTPUT; - fmt.format = HFI_COLOR_FORMAT_NV12_UBWC; + fmt.format = pixelformat == V4L2_PIX_FMT_P010 ? + HFI_COLOR_FORMAT_YUV420_TP10_UBWC : + HFI_COLOR_FORMAT_NV12_UBWC; ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); if (ret) return ret; fmt.buffer_type = HFI_BUFFER_OUTPUT2; - fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? - HFI_COLOR_FORMAT_NV12 : HFI_COLOR_FORMAT_NV12_UBWC; + fmt.format = pixelformat == V4L2_PIX_FMT_P010 ? + HFI_COLOR_FORMAT_P010 : HFI_COLOR_FORMAT_NV12; ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); } else { fmt.buffer_type = HFI_BUFFER_OUTPUT; - fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? - HFI_COLOR_FORMAT_NV12 : HFI_COLOR_FORMAT_NV12_UBWC; + fmt.format = pixelformat == V4L2_PIX_FMT_P010 ? + HFI_COLOR_FORMAT_P010 : HFI_COLOR_FORMAT_NV12; ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); } } else { pixelformat = inst->fmt_src->fmt.pix_mp.pixelformat; fmt.buffer_type = HFI_BUFFER_INPUT; - fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? - HFI_COLOR_FORMAT_NV12 : HFI_COLOR_FORMAT_NV12_UBWC; + fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12 : 0; ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); } @@ -863,18 +1078,19 @@ static int iris_hfi_gen1_set_format_constraints(struct iris_inst *inst, u32 plan { const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO; struct hfi_uncompressed_plane_actual_constraints_info pconstraint; + u32 stride_multiple; - if (inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC08C) - return 0; + stride_multiple = inst->fmt_dst->fmt.pix_mp.pixelformat == + V4L2_PIX_FMT_P010 ? 256 : 128; pconstraint.buffer_type = HFI_BUFFER_OUTPUT2; pconstraint.num_planes = 2; - pconstraint.plane_format[0].stride_multiples = 128; + pconstraint.plane_format[0].stride_multiples = stride_multiple; pconstraint.plane_format[0].max_stride = 8192; pconstraint.plane_format[0].min_plane_buffer_height_multiple = 32; pconstraint.plane_format[0].buffer_alignment = 256; - pconstraint.plane_format[1].stride_multiples = 128; + pconstraint.plane_format[1].stride_multiples = stride_multiple; pconstraint.plane_format[1].max_stride = 8192; pconstraint.plane_format[1].min_plane_buffer_height_multiple = 16; pconstraint.plane_format[1].buffer_alignment = 256; @@ -936,15 +1152,16 @@ static int iris_hfi_gen1_set_multistream(struct iris_inst *inst, u32 plane) int ret; if (iris_split_mode_enabled(inst)) { - multi.buffer_type = HFI_BUFFER_OUTPUT; - multi.enable = 0; + /* Keep one output enabled throughout the split-mode transition. */ + multi.buffer_type = HFI_BUFFER_OUTPUT2; + multi.enable = 1; ret = hfi_gen1_set_property(inst, ptype, &multi, sizeof(multi)); if (ret) return ret; - multi.buffer_type = HFI_BUFFER_OUTPUT2; - multi.enable = 1; + multi.buffer_type = HFI_BUFFER_OUTPUT; + multi.enable = 0; ret = hfi_gen1_set_property(inst, ptype, &multi, sizeof(multi)); } else { @@ -972,7 +1189,7 @@ static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst, u32 plane) if (iris_split_mode_enabled(inst)) { bufsz.type = HFI_BUFFER_OUTPUT; - bufsz.size = inst->core->iris_firmware_desc->get_vpu_buffer_size(inst, BUF_DPB); + bufsz.size = iris_vpu_buf_size(inst, BUF_DPB); ret = hfi_gen1_set_property(inst, ptype, &bufsz, sizeof(bufsz)); if (ret) @@ -999,6 +1216,124 @@ static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst, u32 plane) return ret; } +static int iris_hfi_gen1_get_buffer_requirements(struct iris_inst *inst) +{ + struct hfi_session_get_property_pkt packet = { + .shdr.hdr.size = sizeof(packet), + .shdr.hdr.pkt_type = HFI_CMD_SESSION_GET_PROPERTY, + .shdr.session_id = inst->session_id, + .num_properties = 1, + .data = HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS, + }; + int ret; + + dev_info(inst->core->dev, + "Iris1 v58: querying firmware buffer requirements before LOAD_RESOURCES\n"); + + reinit_completion(&inst->completion); + ret = iris_hfi_queue_cmd_write(inst->core, &packet, packet.shdr.hdr.size); + if (ret) + return ret; + + return iris_wait_for_session_response(inst, false); +} + +static int iris_hfi_gen1_set_first_capture_config(struct iris_inst *inst) +{ + struct vb2_queue *dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx); + const u32 count_ptype = HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL; + const u32 size_ptype = HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL; + const u32 frame_ptype = HFI_PROPERTY_PARAM_FRAME_SIZE; + struct hfi_buffer_count_actual count; + struct hfi_buffer_size_actual size; + struct hfi_framesize frame; + u32 dpb_count, output2_count; + int ret; + + dpb_count = iris_vpu_buf_count(inst, BUF_DPB); + output2_count = vb2_get_num_buffers(dst_q); + + if (!dpb_count || output2_count < dpb_count) { + dev_err(inst->core->dev, + "Iris1 v64: invalid first capture counts: codec=%p4cc output2=%u dpb=%u\n", + &inst->codec, output2_count, dpb_count); + return -EINVAL; + } + + /* + * SM8150 refreshes sequence-dependent requirements immediately before + * applying the capture sizes/counts and issuing SESSION_CONTINUE. */ + ret = iris_hfi_gen1_get_buffer_requirements(inst); + if (ret) + return ret; + + frame.buffer_type = HFI_BUFFER_OUTPUT2; + frame.width = inst->fmt_src->fmt.pix_mp.width; + frame.height = inst->fmt_src->fmt.pix_mp.height; + + ret = hfi_gen1_set_property(inst, frame_ptype, &frame, sizeof(frame)); + if (ret) + return ret; + + count.type = HFI_BUFFER_OUTPUT2; + count.count_actual = output2_count; + count.count_min_host = output2_count; + + ret = hfi_gen1_set_property(inst, count_ptype, &count, sizeof(count)); + if (ret) + return ret; + + size.type = HFI_BUFFER_OUTPUT2; + size.size = inst->buffers[BUF_OUTPUT].size; + + dev_info(inst->core->dev, + "Iris1 v65: codec=%p4cc output2 width=%u height=%u actual=%u min_host=%u size=%u\n", + &inst->codec, + frame.width, frame.height, count.count_actual, + count.count_min_host, size.size); + + ret = hfi_gen1_set_property(inst, size_ptype, &size, sizeof(size)); + if (ret) + return ret; + + /* + * A sequence change clears both decoder output sizes in VIDEO.IR.1.2. + * HEVC happens to retain the compressed OUTPUT size, but VP9 rejects + * SESSION_CONTINUE unless the host restores both OUTPUT and OUTPUT2. + */ + size.type = HFI_BUFFER_OUTPUT; + size.size = inst->fw_buffer_sizes[BUF_DPB] ?: + iris_vpu_buf_size(inst, BUF_DPB); + + dev_info(inst->core->dev, + "Iris1 v65: codec=%p4cc internal dpb size=%u\n", + &inst->codec, size.size); + + ret = hfi_gen1_set_property(inst, size_ptype, &size, sizeof(size)); + if (ret) + return ret; + + /* + * In split mode HFI_BUFFER_OUTPUT is the firmware-owned compressed + * DPB, while OUTPUT2 is the client-visible linear capture stream. + * The initial configuration uses VIDEO_MAX_FRAME before firmware has + * reported the sequence requirements. Before SESSION_CONTINUE, + * replace that placeholder with the exact minimum number of DPBs which + * iris_create_internal_buffers() is about to allocate and queue. The + * downstream SM8150 driver makes the same adjustment for split-mode DPBs. + */ + count.type = HFI_BUFFER_OUTPUT; + count.count_actual = dpb_count; + count.count_min_host = dpb_count; + + dev_info(inst->core->dev, + "Iris1 v65: codec=%p4cc internal dpb actual=%u min_host=%u queued=%u\n", + &inst->codec, count.count_actual, + count.count_min_host, dpb_count); + + return hfi_gen1_set_property(inst, count_ptype, &count, sizeof(count)); +} + static int iris_hfi_gen1_set_frame_rate(struct iris_inst *inst, u32 plane) { const u32 ptype = HFI_PROPERTY_CONFIG_FRAME_RATE; @@ -1041,6 +1376,26 @@ static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 p const u32 *config_params; int ret; + /* + * The initial input configuration already describes both decoder + * output streams. VIDEO.IR.1.2 accepts the duplicate configuration + * after the first H.264 sequence change, but fatally asserts when the + * same input/count/multistream properties are resent for HEVC or VP9. + * Downstream configures the capture format before streaming and does + * not replay the complete input property list at capture STREAMON. + * Update only the client-visible output2 geometry/count/size and the + * firmware-owned DPB count after the sequence-change event. + */ + if (inst->domain == DECODER && V4L2_TYPE_IS_CAPTURE(plane) && + (inst->codec == V4L2_PIX_FMT_HEVC || + inst->codec == V4L2_PIX_FMT_VP9) && + inst->sub_state & IRIS_INST_SUB_FIRST_IPSC) { + dev_info(inst->core->dev, + "Iris1 v65: applying first capture config for codec %p4cc\n", + &inst->codec); + return iris_hfi_gen1_set_first_capture_config(inst); + } + static const struct iris_hfi_prop_type_handle vdec_prop_type_handle_inp_arr[] = { {HFI_PROPERTY_PARAM_FRAME_SIZE, iris_hfi_gen1_set_resolution}, @@ -1087,8 +1442,8 @@ static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 p }; if (inst->domain == DECODER) { - config_params = core->iris_firmware_data->dec_input_config_params_default; - config_params_size = core->iris_firmware_data->dec_input_config_params_default_size; + config_params = core->iris_platform_data->dec_input_config_params_default; + config_params_size = core->iris_platform_data->dec_input_config_params_default_size; if (V4L2_TYPE_IS_OUTPUT(plane)) { handler = vdec_prop_type_handle_inp_arr; handler_size = ARRAY_SIZE(vdec_prop_type_handle_inp_arr); @@ -1097,8 +1452,8 @@ static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 p handler_size = ARRAY_SIZE(vdec_prop_type_handle_out_arr); } } else { - config_params = core->iris_firmware_data->enc_input_config_params; - config_params_size = core->iris_firmware_data->enc_input_config_params_size; + config_params = core->iris_platform_data->enc_input_config_params; + config_params_size = core->iris_platform_data->enc_input_config_params_size; handler = venc_prop_type_handle_inp_arr; handler_size = ARRAY_SIZE(venc_prop_type_handle_inp_arr); } @@ -1114,10 +1469,17 @@ static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 p } } + if (V4L2_TYPE_IS_OUTPUT(plane)) + return iris_hfi_gen1_get_buffer_requirements(inst); + return 0; } -static const struct iris_hfi_session_ops iris_hfi_gen1_session_ops = { +static const struct iris_hfi_command_ops iris_hfi_gen1_command_ops = { + .sys_init = iris_hfi_gen1_sys_init, + .sys_image_version = iris_hfi_gen1_sys_image_version, + .sys_interframe_powercollapse = iris_hfi_gen1_sys_interframe_powercollapse, + .sys_pc_prep = iris_hfi_gen1_sys_pc_prep, .session_open = iris_hfi_gen1_session_open, .session_set_config_params = iris_hfi_gen1_session_set_config_params, .session_set_property = iris_hfi_gen1_session_set_property, @@ -1130,31 +1492,12 @@ static const struct iris_hfi_session_ops iris_hfi_gen1_session_ops = { .session_close = iris_hfi_gen1_session_close, }; -static struct iris_inst *iris_hfi_gen1_get_instance(void) +void iris_hfi_gen1_command_ops_init(struct iris_core *core) { - struct iris_inst *out; - - out = kzalloc_obj(*out); - if (!out) - return NULL; - - out->hfi_session_ops = &iris_hfi_gen1_session_ops; - - return out; + core->hfi_ops = &iris_hfi_gen1_command_ops; } -static const struct iris_hfi_sys_ops iris_hfi_gen1_sys_ops = { - .sys_init = iris_hfi_gen1_sys_init, - .sys_image_version = iris_hfi_gen1_sys_image_version, - .sys_interframe_powercollapse = iris_hfi_gen1_sys_interframe_powercollapse, - .sys_pc_prep = iris_hfi_gen1_sys_pc_prep, - - .sys_hfi_response_handler = iris_hfi_gen1_response_handler, - - .sys_get_instance = iris_hfi_gen1_get_instance, -}; - -void iris_hfi_gen1_sys_ops_init(struct iris_core *core) +struct iris_inst *iris_hfi_gen1_get_instance(void) { - core->hfi_sys_ops = &iris_hfi_gen1_sys_ops; + return kzalloc(sizeof(struct iris_inst), GFP_KERNEL); } diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h index 0e4dee192384..95c5d5f78cb0 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h @@ -18,9 +18,12 @@ #define HFI_VIDEO_CODEC_VP9 0x00004000 #define HFI_ERR_NONE 0x0 +#define HFI_ERR_SESSION_INCORRECT_STATE_OPERATION 0x1006 +#define HFI_ERR_SESSION_SAME_STATE_OPERATION 0x1001002 #define HFI_CMD_SYS_INIT 0x10001 #define HFI_CMD_SYS_PC_PREP 0x10002 +#define HFI_CMD_SYS_SET_RESOURCE 0x10003 #define HFI_CMD_SYS_SET_PROPERTY 0x10005 #define HFI_CMD_SYS_GET_PROPERTY 0x10006 #define HFI_CMD_SYS_SESSION_INIT 0x10007 @@ -35,6 +38,7 @@ #define HFI_CMD_SESSION_EMPTY_BUFFER 0x211004 #define HFI_CMD_SESSION_FILL_BUFFER 0x211005 #define HFI_CMD_SESSION_FLUSH 0x211008 +#define HFI_CMD_SESSION_GET_PROPERTY 0x211009 #define HFI_CMD_SESSION_RELEASE_BUFFERS 0x21100b #define HFI_CMD_SESSION_RELEASE_RESOURCES 0x21100c #define HFI_CMD_SESSION_CONTINUE 0x21100d @@ -68,9 +72,13 @@ #define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS 0x202001 +#define HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER 0x1203005 #define HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS 0x120300e #define HFI_PROPERTY_CONFIG_VDEC_ENTROPY 0x1204004 +#define HFI_OUTPUT_ORDER_DISPLAY 0x1000001 +#define HFI_OUTPUT_ORDER_DECODE 0x1000002 + #define HFI_BUFFER_INPUT 0x1 #define HFI_BUFFER_OUTPUT 0x2 #define HFI_BUFFER_OUTPUT2 0x3 @@ -78,11 +86,19 @@ #define HFI_BUFFER_INTERNAL_PERSIST_1 0x5 #define HFI_BUFFER_INTERNAL_SCRATCH 0x6 #define HFI_BUFFER_INTERNAL_SCRATCH_1 0x7 +#define HFI_BUFFER_MODE_DYNAMIC 0x1000003 #define HFI_BUFFER_INTERNAL_SCRATCH_2 0x8 +#define HFI_PROPERTY_SYS_DEBUG_CONFIG 0x1 #define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL 0x5 #define HFI_PROPERTY_SYS_IMAGE_VERSION 0x6 +#define HFI_DEBUG_MSG_ERROR 0x00000008 +#define HFI_DEBUG_MSG_FATAL 0x00000010 +#define HFI_DEBUG_MODE_QUEUE 0x00000001 + +#define HFI_RESOURCE_SYSCACHE 0x00000002 + #define HFI_PROPERTY_PARAM_FRAME_SIZE 0x1001 #define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO 0x1002 #define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT 0x1003 @@ -97,8 +113,14 @@ #define HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT 0x1003009 #define HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE 0x100300a #define HFI_CORE_ID_1 1 +#define HFI_CORE_ID_2 2 #define HFI_COLOR_FORMAT_NV12 0x02 #define HFI_COLOR_FORMAT_NV12_UBWC 0x8002 +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC 0xc002 +#define HFI_COLOR_FORMAT_P010 0x4003 + +#define HFI_BIT_DEPTH_8 0x00000 +#define HFI_BIT_DEPTH_10 0x20002 #define HFI_MSG_SYS_INIT 0x20001 #define HFI_MSG_SYS_SESSION_INIT 0x20006 @@ -113,6 +135,7 @@ #define HFI_MSG_SESSION_FLUSH 0x221006 #define HFI_MSG_SESSION_EMPTY_BUFFER 0x221007 #define HFI_MSG_SESSION_FILL_BUFFER 0x221008 +#define HFI_MSG_SESSION_PROPERTY_INFO 0x221009 #define HFI_MSG_SESSION_RELEASE_RESOURCES 0x22100a #define HFI_MSG_SESSION_RELEASE_BUFFERS 0x22100c @@ -139,28 +162,10 @@ #define HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL 0x2005003 #define HFI_PROPERTY_PARAM_VENC_RATE_CONTROL 0x2005004 #define HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2 0x2005009 - -#define HFI_INTRA_REFRESH_NONE 0x1 -#define HFI_INTRA_REFRESH_CYCLIC 0x2 -#define HFI_INTRA_REFRESH_ADAPTIVE 0x3 -#define HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE 0x4 -#define HFI_INTRA_REFRESH_RANDOM 0x5 - -#define HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH 0x200500d - -#define HFI_LTR_MODE_DISABLE 0x0 -#define HFI_LTR_MODE_MANUAL 0x1 -#define HFI_LTR_MODE_PERIODIC 0x2 - -#define HFI_PROPERTY_PARAM_VENC_LTRMODE 0x200501c #define HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES 0x2005020 -#define HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER 0x2005026 #define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE 0x2006001 #define HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD 0x2006003 -#define HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME 0x2006009 -#define HFI_PROPERTY_CONFIG_VENC_USELTRFRAME 0x200600a #define HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER 0x2006008 -#define HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER 0x200600b struct hfi_pkt_hdr { u32 size; @@ -193,6 +198,13 @@ struct hfi_sys_set_property_pkt { u32 data[]; }; +struct hfi_sys_set_resource_pkt { + struct hfi_pkt_hdr hdr; + u32 resource_handle; + u32 resource_type; + u32 data[]; +}; + struct hfi_sys_get_property_pkt { struct hfi_pkt_hdr hdr; u32 num_properties; @@ -205,6 +217,12 @@ struct hfi_session_set_property_pkt { u32 data[]; }; +struct hfi_session_get_property_pkt { + struct hfi_session_hdr_pkt shdr; + u32 num_properties; + u32 data; +}; + struct hfi_sys_pc_prep_pkt { struct hfi_pkt_hdr hdr; }; @@ -310,6 +328,13 @@ struct hfi_msg_session_init_done_pkt { u32 data[]; }; +struct hfi_msg_session_property_info_pkt { + struct hfi_session_hdr_pkt shdr; + u32 num_properties; + u32 property; + u8 data[]; +}; + struct hfi_msg_sys_property_info_pkt { struct hfi_pkt_hdr hdr; u32 num_properties; @@ -326,6 +351,11 @@ struct hfi_enable { u32 enable; }; +struct hfi_debug_config { + u32 debug_config; + u32 debug_mode; +}; + struct hfi_profile_level { u32 profile; u32 level; @@ -420,6 +450,11 @@ struct hfi_buffer_size_actual { u32 size; }; +struct hfi_buffer_alloc_mode { + u32 type; + u32 mode; +}; + struct hfi_multi_stream { u32 buffer_type; u32 enable; @@ -441,6 +476,11 @@ struct hfi_bitrate { u32 layer_id; }; +struct hfi_intra_period { + u32 pframes; + u32 bframes; +}; + #define HFI_H264_CABAC_MODEL_0 0x1 struct hfi_h264_entropy_control { @@ -466,36 +506,6 @@ struct hfi_framerate { u32 framerate; }; -struct hfi_intra_refresh { - u32 mode; - u32 mbs; -}; - -struct hfi_ltr_mode { - u32 mode; - u32 count; - u32 trust_mode; -}; - -struct hfi_ltr_use { - u32 ref_ltr; - u32 use_constrnt; - u32 frames; -}; - -struct hfi_ltr_mark { - u32 mark_frame; -}; - -struct hfi_max_num_b_frames { - u32 max_num_b_frames; -}; - -struct hfi_intra_period { - u32 pframes; - u32 bframes; -}; - struct hfi_event_data { u32 error; u32 height; diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c index bfd7495bf44f..db8033e1a804 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c @@ -4,14 +4,35 @@ */ #include +#include +#include #include #include "iris_hfi_gen1.h" #include "iris_hfi_gen1_defines.h" #include "iris_instance.h" +#include "iris_utils.h" +#include "iris_vb2.h" #include "iris_vdec.h" #include "iris_vpu_buffer.h" +#define IRIS1_MAX_CORRUPT_OUTPUT_DROPS 8 + +static u32 +iris_hfi_gen1_bufreq_count_min(struct iris_inst *inst, + const struct hfi_buffer_requirements *bufreq) +{ + /* + * HFI 4xx swaps the display hold count and minimum-count fields. + * SM8150's VIDEO.IR.1.2 firmware uses that legacy layout, while + * SM8250 uses the layout represented by the Iris Gen1 structure. + */ + if (inst->core->iris_platform_data->legacy_vpu5) + return bufreq->hold_count; + + return bufreq->count_min; +} + static void iris_hfi_gen1_read_changed_params(struct iris_inst *inst, struct hfi_msg_event_notify_pkt *pkt) { @@ -79,7 +100,13 @@ static void iris_hfi_gen1_read_changed_params(struct iris_inst *inst, case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: data_ptr += sizeof(u32); bufreq = (struct hfi_buffer_requirements *)data_ptr; - event.buf_count = bufreq->count_min; + event.buf_count = + iris_hfi_gen1_bufreq_count_min(inst, bufreq); + if (inst->core->iris_platform_data->legacy_vpu5) + dev_info(inst->core->dev, + "Iris1 v64: HFI 4xx buffer minimum=%u (raw hold=%u min=%u)\n", + event.buf_count, bufreq->hold_count, + bufreq->count_min); data_ptr += sizeof(*bufreq); break; case HFI_INDEX_EXTRADATA_INPUT_CROP: @@ -108,7 +135,8 @@ static void iris_hfi_gen1_read_changed_params(struct iris_inst *inst, pixmp_op->width = ALIGN(event.width, 128); pixmp_op->height = ALIGN(event.height, 32); - pixmp_op->plane_fmt[0].bytesperline = ALIGN(event.width, 128); + pixmp_op->plane_fmt[0].bytesperline = + ALIGN(event.width * (pixmp_op->pixelformat == V4L2_PIX_FMT_P010 ? 2 : 1), 128); pixmp_op->plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT); matrix_coeff = FIELD_GET(GENMASK(7, 0), event.colour_space); @@ -165,7 +193,11 @@ static void iris_hfi_gen1_read_changed_params(struct iris_inst *inst, dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx); dst_q->min_reqbufs_allocation = inst->buffers[BUF_OUTPUT].min_count; - if (event.bit_depth || !event.pic_struct) { + if ((event.bit_depth != HFI_BIT_DEPTH_8 && + event.bit_depth != HFI_BIT_DEPTH_10) || + (event.bit_depth == HFI_BIT_DEPTH_10 && + pixmp_op->pixelformat != V4L2_PIX_FMT_P010) || + !event.pic_struct) { dev_err(core->dev, "unsupported content, bit depth: %x, pic_struct = %x\n", event.bit_depth, event.pic_struct); iris_inst_change_state(inst, IRIS_INST_ERROR); @@ -200,6 +232,14 @@ static void iris_hfi_gen1_event_seq_changed(struct iris_inst *inst, iris_hfi_gen1_read_changed_params(inst, pkt); + /* + * Drop the VP9 high-IOVA placeholder now that the sequence is known, + * so the top-down allocator hands the freed high region to the + * CAPTURE/DPB buffers userspace and the capture-path internal-buffer + * allocator are about to create. + */ + iris_vb2_vp9_release_high_iova_hole(inst); + if (inst->state != IRIS_INST_ERROR && !(inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)) { flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt); @@ -220,11 +260,37 @@ iris_hfi_gen1_sys_event_notify(struct iris_core *core, void *packet) struct hfi_msg_event_notify_pkt *pkt = packet; struct iris_inst *instance; - if (pkt->event_id == HFI_EVENT_SYS_ERROR) + if (pkt->event_id == HFI_EVENT_SYS_ERROR) { + u32 sfr_size; + size_t message_len; + char *message; + dev_err(core->dev, "sys error (type: %x, session id:%x, data1:%x, data2:%x)\n", pkt->event_id, pkt->shdr.session_id, pkt->event_data1, pkt->event_data2); + /* + * The delayed recovery worker frees the SFR allocation. Copy its + * diagnostic to dmesg while the firmware-owned buffer is still + * valid, following the downstream Venus driver's failure path. + */ + if (core->sfr_vaddr) { + dma_rmb(); + sfr_size = READ_ONCE(*(u32 *)core->sfr_vaddr); + if (sfr_size > sizeof(u32) && sfr_size <= SZ_4K) { + message = core->sfr_vaddr + sizeof(u32); + message_len = strnlen(message, + sfr_size - sizeof(u32)); + dev_err(core->dev, "Iris1 v57 SFR: %.*s\n", + (int)message_len, message); + } else { + dev_err(core->dev, + "Iris1 v57 SFR has invalid size %u\n", + sfr_size); + } + } + } + core->state = IRIS_CORE_ERROR; mutex_lock(&core->lock); @@ -348,9 +414,17 @@ static void iris_hfi_gen1_session_etb_done(struct iris_inst *inst, void *packet) struct iris_buffer *buf = NULL; bool found = false; - /* EOS buffer sent via drain won't be in v4l2 buffer list */ - if (pkt->packet_buffer == 0xdeadb000) + /* + * The EOS buffer sent by session_drain() is synthetic and is not in + * the V4L2 source buffer list. H.264/HEVC use address zero while VP9 + * uses the legacy sentinel address. + */ + if (!pkt->packet_buffer || pkt->packet_buffer == 0xdeadb000) { + dev_dbg(inst->core->dev, + "Iris1 ETB done: ignoring drain EOS tag=%u packet=%#x error=%#x\n", + pkt->input_tag, pkt->packet_buffer, pkt->shdr.error_type); return; + } v4l2_m2m_for_each_src_buf_safe(m2m_ctx, m2m_buffer, n) { buf = to_iris_buffer(&m2m_buffer->vb); @@ -362,6 +436,11 @@ static void iris_hfi_gen1_session_etb_done(struct iris_inst *inst, void *packet) if (!found) goto error; + dev_dbg(inst->core->dev, + "Iris1 ETB done: tag=%u packet=%#x offset=%u filled=%u error=%#x\n", + pkt->input_tag, pkt->packet_buffer, pkt->offset, pkt->filled_len, + pkt->shdr.error_type); + if (pkt->shdr.error_type == HFI_ERR_SESSION_UNSUPPORTED_STREAM) { buf->flags = V4L2_BUF_FLAG_ERROR; iris_vb2_queue_error(inst); @@ -382,7 +461,10 @@ static void iris_hfi_gen1_session_etb_done(struct iris_inst *inst, void *packet) error: iris_inst_change_state(inst, IRIS_INST_ERROR); - dev_err(inst->core->dev, "error in etb done\n"); + dev_err(inst->core->dev, + "Iris1 ETB done unmatched: tag=%u packet=%#x offset=%u filled=%u error=%#x\n", + pkt->input_tag, pkt->packet_buffer, pkt->offset, pkt->filled_len, + pkt->shdr.error_type); } static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) @@ -403,8 +485,12 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) u32 hfi_flags; u32 offset; u64 timestamp_us = 0; + bool m2m_stopped; + bool recycle_output = false; + bool seek_was_pending = false; bool found = false; u32 flags = 0; + int ret; if (inst->domain == DECODER) { timestamp_hi = uncom_pkt->time_stamp_hi; @@ -494,6 +580,47 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) } buf->timestamp = timestamp_us; + if (inst->domain == DECODER && buf->type == BUF_OUTPUT && + inst->core->iris_platform_data->legacy_vpu5) { + ret = iris_vdec_complete_pending_output(inst); + if (ret) + goto error; + seek_was_pending = inst->seek_timestamp_pending; + if (inst->seek_hold_frames) + inst->seek_hold_frames--; + } + + if (inst->domain == DECODER && buf->type == BUF_OUTPUT && filled_len) { + if (inst->core->iris_platform_data->legacy_vpu5 && + (hfi_flags & (HFI_BUFFERFLAG_DATACORRUPT | + HFI_BUFFERFLAG_DROP_FRAME)) && + inst->corrupt_output_drops < IRIS1_MAX_CORRUPT_OUTPUT_DROPS) { + inst->corrupt_output_drops++; + recycle_output = true; + dev_info(inst->core->dev, + "Iris1 v137: recycling corrupt output timestamp %llu ns flags %#x (drop %u/%u)\n", + timestamp_us, hfi_flags, + inst->corrupt_output_drops, + IRIS1_MAX_CORRUPT_OUTPUT_DROPS); + } else { + inst->corrupt_output_drops = 0; + recycle_output = iris_vdec_discard_stale_frame(inst, + timestamp_us); + } + } + + if (recycle_output) { + buf->data_size = 0; + buf->flags = 0; + buf->timestamp = 0; + buf->attr &= ~(BUF_ATTR_QUEUED | BUF_ATTR_DEQUEUED | + BUF_ATTR_BUFFER_DONE); + ret = iris_queue_buffer(inst, buf); + if (ret) + goto error; + return; + } + switch (pic_type) { case HFI_GEN1_PICTURE_IDR: case HFI_GEN1_PICTURE_I: @@ -524,13 +651,113 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) buf->flags |= flags; + if (inst->domain == DECODER && buf->type == BUF_OUTPUT && filled_len && + inst->core->iris_platform_data->legacy_vpu5 && + !(hfi_flags & (HFI_BUFFERFLAG_DATACORRUPT | + HFI_BUFFERFLAG_DROP_FRAME)) && + !seek_was_pending && inst->seek_hold_frames) { + ret = iris_vdec_hold_output(inst, buf); + if (ret) + goto error; + return; + } + iris_vb2_buffer_done(inst, buf); return; error: + /* + * A terminal EOS/LAST or flush completion and its final FTB done can be + * adjacent in the HFI response queue. Once mem2mem has delivered LAST it + * marks the context stopped, but userspace may not have issued STREAMOFF + * yet. The terminal buffer can therefore already be off the destination + * list while streamoff_pending is still false. + * + * There is no userspace buffer left to complete after LAST/stopped or + * during STREAMOFF. Keep unmatched FTBs fatal in every other state so a + * genuine buffer bookkeeping failure during playback is not hidden. + */ + m2m_stopped = v4l2_m2m_has_stopped(m2m_ctx); + if (inst->streamoff_pending || inst->last_buffer_dequeued || m2m_stopped) { + dev_info(core->dev, + "Iris1 v99: ignoring terminal late FTB: tag=%u offset=%u filled=%u flags=%#x state=%u substate=%#x streamoff=%u last=%u stopped=%u\n", + output_tag, offset, filled_len, hfi_flags, inst->state, + inst->sub_state, inst->streamoff_pending, + inst->last_buffer_dequeued, m2m_stopped); + return; + } + + dev_err(core->dev, + "Iris1 v99: FTB done unmatched: tag=%u offset=%u filled=%u flags=%#x state=%u substate=%#x\n", + output_tag, offset, filled_len, hfi_flags, inst->state, + inst->sub_state); iris_inst_change_state(inst, IRIS_INST_ERROR); - dev_err(core->dev, "error in ftb done\n"); +} + +static void +iris_hfi_gen1_session_property_info(struct iris_inst *inst, void *packet) +{ + struct hfi_msg_session_property_info_pkt *pkt = packet; + struct hfi_buffer_requirements *req; + enum iris_buffer_type buffer_type; + u32 req_bytes, count, i; + + req_bytes = pkt->shdr.hdr.size - sizeof(*pkt); + dev_info(inst->core->dev, + "Iris1 v58: SESSION_PROPERTY_INFO properties=%u property=%#x payload=%u bytes\n", + pkt->num_properties, pkt->property, req_bytes); + + if (pkt->num_properties != 1 || + pkt->property != HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS || + !req_bytes || req_bytes % sizeof(*req)) { + dev_err(inst->core->dev, + "Iris1 v58: malformed buffer requirements response\n"); + complete(&inst->completion); + return; + } + + count = req_bytes / sizeof(*req); + req = (struct hfi_buffer_requirements *)pkt->data; + for (i = 0; i < count; i++, req++) { + dev_info(inst->core->dev, + "Iris1 v58: bufreq[%u] type=%#x size=%u region=%u hold=%u min=%u actual=%u contiguous=%u align=%u\n", + i, req->type, req->size, req->region_size, + req->hold_count, req->count_min, req->count_actual, + req->contiguous, req->alignment); + + switch (req->type) { + case HFI_BUFFER_OUTPUT: + /* + * In decoder split mode OUTPUT is the firmware-owned UBWC + * DPB. VIDEO.IR.1.2 reports its exact allocation size and + * validates BUFFER_SIZE_ACTUAL strictly at SESSION_CONTINUE; + * the generic layout helper includes newer-HFI tail padding + * and can therefore be larger than the VPU5 requirement. + */ + if (inst->domain != DECODER || + !iris_split_mode_enabled(inst)) + continue; + buffer_type = BUF_DPB; + break; + case HFI_BUFFER_INTERNAL_PERSIST_1: + buffer_type = BUF_PERSIST; + break; + case HFI_BUFFER_INTERNAL_SCRATCH: + buffer_type = BUF_BIN; + break; + case HFI_BUFFER_INTERNAL_SCRATCH_1: + buffer_type = BUF_SCRATCH_1; + break; + default: + continue; + } + + inst->fw_buffer_sizes[buffer_type] = + max(inst->fw_buffer_sizes[buffer_type], req->size); + } + + complete(&inst->completion); } struct iris_hfi_gen1_response_pkt_info { @@ -579,6 +806,10 @@ static const struct iris_hfi_gen1_response_pkt_info pkt_infos[] = { .pkt = HFI_MSG_SESSION_FILL_BUFFER, .pkt_sz = sizeof(struct hfi_msg_session_fbd_compressed_pkt), }, + { + .pkt = HFI_MSG_SESSION_PROPERTY_INFO, + .pkt_sz = sizeof(struct hfi_msg_session_property_info_pkt), + }, { .pkt = HFI_MSG_SESSION_FLUSH, .pkt_sz = sizeof(struct hfi_msg_session_flush_done_pkt), @@ -652,12 +883,40 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response iris_hfi_gen1_session_etb_done(inst, hdr); } else if (hdr->pkt_type == HFI_MSG_SESSION_FILL_BUFFER) { iris_hfi_gen1_session_ftb_done(inst, hdr); + } else if (hdr->pkt_type == HFI_MSG_SESSION_PROPERTY_INFO) { + iris_hfi_gen1_session_property_info(inst, hdr); } else { struct hfi_msg_session_hdr_pkt *shdr; shdr = (struct hfi_msg_session_hdr_pkt *)hdr; - if (shdr->error_type != HFI_ERR_NONE) + dev_dbg(dev, + "Iris1 response: type=%#x size=%u session=%#x error=%#x\n", + hdr->pkt_type, hdr->size, shdr->shdr.session_id, + shdr->error_type); + /* + * HFI teardown is idempotent. SM8150 can report STOP as already + * outside START after drain/flush, followed by RELEASE_RESOURCES + * as already released. Accept only these command/state-specific + * statuses; the same errors remain fatal during normal streaming. + */ + if (shdr->error_type == HFI_ERR_SESSION_SAME_STATE_OPERATION && + inst->streamoff_pending) { + dev_dbg(dev, + "Iris1 v99: idempotent response type=%#x error=%#x\n", + hdr->pkt_type, shdr->error_type); + } else if (hdr->pkt_type == HFI_MSG_SESSION_STOP && + shdr->error_type == + HFI_ERR_SESSION_INCORRECT_STATE_OPERATION && + inst->streamoff_pending) { + dev_dbg(dev, + "Iris1 v99: STOP already complete during streamoff\n"); + } else if (shdr->error_type != HFI_ERR_NONE) { + dev_err(dev, + "Iris1 response error: type=%#x session=%#x error=%#x\n", + hdr->pkt_type, shdr->shdr.session_id, + shdr->error_type); iris_inst_change_state(inst, IRIS_INST_ERROR); + } if (pkt_info->pkt == HFI_MSG_SESSION_FLUSH) { if (!(--inst->flush_responses_pending)) @@ -682,13 +941,26 @@ static void iris_hfi_gen1_flush_debug_queue(struct iris_core *core, u8 *packet) if (pkt->hdr.pkt_type != HFI_MSG_SYS_COV) { struct hfi_msg_sys_debug_pkt *pkt = (struct hfi_msg_sys_debug_pkt *)packet; - - dev_dbg(core->dev, "%s", pkt->msg_data); + u32 msg_size; + + /* + * VPU5 reports the useful reason for a deferred session + * failure on the debug queue. Keep it visible while + * bringing up SM8150: dev_dbg() consumes the packet but + * normally hides it unless dynamic debug was enabled + * before the interrupt arrived. + */ + if (pkt->hdr.size <= sizeof(*pkt)) + continue; + msg_size = min_t(u32, pkt->msg_size, + pkt->hdr.size - sizeof(*pkt)); + dev_dbg(core->dev, "Iris1 FW: %.*s", + (int)msg_size, pkt->msg_data); } } } -void iris_hfi_gen1_response_handler(struct iris_core *core) +static void iris_hfi_gen1_response_handler(struct iris_core *core) { memset(core->response_packet, 0, sizeof(struct hfi_pkt_hdr)); while (!iris_hfi_queue_msg_read(core, core->response_packet)) { @@ -698,3 +970,12 @@ void iris_hfi_gen1_response_handler(struct iris_core *core) iris_hfi_gen1_flush_debug_queue(core, core->response_packet); } + +static const struct iris_hfi_response_ops iris_hfi_gen1_response_ops = { + .hfi_response_handler = iris_hfi_gen1_response_handler, +}; + +void iris_hfi_gen1_response_ops_init(struct iris_core *core) +{ + core->hfi_response_ops = &iris_hfi_gen1_response_ops; +} diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c index ca2954f8bd3a..4ce71a142508 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c @@ -121,7 +121,6 @@ static u32 iris_hfi_gen2_get_port_from_buf_type(struct iris_inst *inst, case BUF_COMV: case BUF_NON_COMV: case BUF_LINE: - case BUF_PARTIAL: return HFI_PORT_BITSTREAM; case BUF_OUTPUT: case BUF_DPB: @@ -169,7 +168,8 @@ static int iris_hfi_gen2_session_set_property(struct iris_inst *inst, u32 packet static int iris_hfi_gen2_set_raw_resolution(struct iris_inst *inst, u32 plane) { - u32 resolution = inst->enc_raw_width << 16 | inst->enc_raw_height; + u32 resolution = inst->fmt_src->fmt.pix_mp.width << 16 | + inst->fmt_src->fmt.pix_mp.height; u32 port = iris_hfi_gen2_get_port(inst, plane); return iris_hfi_gen2_session_set_property(inst, @@ -181,36 +181,22 @@ static int iris_hfi_gen2_set_raw_resolution(struct iris_inst *inst, u32 plane) sizeof(u32)); } -static inline u32 iris_hfi_get_aligned_resolution(struct iris_inst *inst, u32 width, u32 height) -{ - u32 codec_align = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; - - return (ALIGN(width, codec_align) << 16 | ALIGN(height, codec_align)); -} - static int iris_hfi_gen2_set_bitstream_resolution(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); u32 port = iris_hfi_gen2_get_port(inst, plane); enum hfi_packet_payload_info payload_type; - u32 width, height; - u32 resolution; + u32 resolution, codec_align; if (inst->domain == DECODER) { - width = inst->fmt_src->fmt.pix_mp.width; - height = inst->fmt_src->fmt.pix_mp.height; - resolution = iris_hfi_get_aligned_resolution(inst, width, height); + resolution = inst->fmt_src->fmt.pix_mp.width << 16 | + inst->fmt_src->fmt.pix_mp.height; inst_hfi_gen2->src_subcr_params.bitstream_resolution = resolution; payload_type = HFI_PAYLOAD_U32; } else { - if (is_rotation_90_or_270(inst)) { - width = inst->enc_scale_height; - height = inst->enc_scale_width; - } else { - width = inst->enc_scale_width; - height = inst->enc_scale_height; - } - resolution = iris_hfi_get_aligned_resolution(inst, width, height); + codec_align = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; + resolution = ALIGN(inst->fmt_dst->fmt.pix_mp.width, codec_align) << 16 | + ALIGN(inst->fmt_dst->fmt.pix_mp.height, codec_align); inst_hfi_gen2->dst_subcr_params.bitstream_resolution = resolution; payload_type = HFI_PAYLOAD_32_PACKED; } @@ -230,7 +216,7 @@ static int iris_hfi_gen2_set_crop_offsets(struct iris_inst *inst, u32 plane) u32 port = iris_hfi_gen2_get_port(inst, plane); u32 bottom_offset, right_offset; u32 left_offset, top_offset; - u32 payload[2], codec_align; + u32 payload[2]; if (inst->domain == DECODER) { if (V4L2_TYPE_IS_OUTPUT(plane)) { @@ -245,27 +231,10 @@ static int iris_hfi_gen2_set_crop_offsets(struct iris_inst *inst, u32 plane) top_offset = inst->compose.top; } } else { - codec_align = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; - if (V4L2_TYPE_IS_OUTPUT(plane)) { - bottom_offset = (inst->enc_raw_height - inst->crop.height); - right_offset = (inst->enc_raw_width - inst->crop.width); - left_offset = inst->crop.left; - top_offset = inst->crop.top; - } else { - if (is_rotation_90_or_270(inst)) { - bottom_offset = (ALIGN(inst->enc_scale_width, codec_align) - - inst->enc_scale_width); - right_offset = (ALIGN(inst->enc_scale_height, codec_align) - - inst->enc_scale_height); - } else { - bottom_offset = (ALIGN(inst->enc_scale_height, codec_align) - - inst->enc_scale_height); - right_offset = (ALIGN(inst->enc_scale_width, codec_align) - - inst->enc_scale_width); - } - left_offset = 0; - top_offset = 0; - } + bottom_offset = (inst->fmt_src->fmt.pix_mp.height - inst->crop.height); + right_offset = (inst->fmt_src->fmt.pix_mp.width - inst->crop.width); + left_offset = inst->crop.left; + top_offset = inst->crop.top; } payload[0] = FIELD_PREP(GENMASK(31, 16), left_offset) | top_offset; @@ -411,9 +380,6 @@ static int iris_hfi_gen2_set_profile(struct iris_inst *inst, u32 plane) case V4L2_PIX_FMT_H264: profile = inst->fw_caps[PROFILE_H264].value; break; - case V4L2_PIX_FMT_AV1: - profile = inst->fw_caps[PROFILE_AV1].value; - break; } inst_hfi_gen2->src_subcr_params.profile = profile; @@ -443,9 +409,6 @@ static int iris_hfi_gen2_set_level(struct iris_inst *inst, u32 plane) case V4L2_PIX_FMT_H264: level = inst->fw_caps[LEVEL_H264].value; break; - case V4L2_PIX_FMT_AV1: - level = inst->fw_caps[LEVEL_AV1].value; - break; } inst_hfi_gen2->src_subcr_params.level = level; @@ -459,20 +422,6 @@ static int iris_hfi_gen2_set_level(struct iris_inst *inst, u32 plane) sizeof(u32)); } -static int iris_hfi_gen2_set_opb_enable(struct iris_inst *inst, u32 plane) -{ - u32 port = iris_hfi_gen2_get_port(inst, plane); - u32 opb_enable = iris_split_mode_enabled(inst); - - return iris_hfi_gen2_session_set_property(inst, - HFI_PROP_OPB_ENABLE, - HFI_HOST_FLAGS_NONE, - port, - HFI_PAYLOAD_U32, - &opb_enable, - sizeof(u32)); -} - static int iris_hfi_gen2_set_colorformat(struct iris_inst *inst, u32 plane) { u32 port = iris_hfi_gen2_get_port(inst, plane); @@ -480,24 +429,10 @@ static int iris_hfi_gen2_set_colorformat(struct iris_inst *inst, u32 plane) if (inst->domain == DECODER) { pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; - switch (pixelformat) { - case V4L2_PIX_FMT_NV12: - hfi_colorformat = HFI_COLOR_FMT_NV12; - break; - case V4L2_PIX_FMT_QC08C: - hfi_colorformat = HFI_COLOR_FMT_NV12_UBWC; - break; - case V4L2_PIX_FMT_P010: - hfi_colorformat = HFI_COLOR_FMT_P010; - break; - case V4L2_PIX_FMT_QC10C: - hfi_colorformat = HFI_COLOR_FMT_TP10_UBWC; - break; - } + hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FMT_NV12 : 0; } else { pixelformat = inst->fmt_src->fmt.pix_mp.pixelformat; - hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? - HFI_COLOR_FMT_NV12 : HFI_COLOR_FMT_NV12_UBWC; + hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FMT_NV12 : 0; } return iris_hfi_gen2_session_set_property(inst, @@ -528,8 +463,7 @@ static int iris_hfi_gen2_set_linear_stride_scanline(struct iris_inst *inst, u32 stride_uv = stride_y; scanline_uv = scanline_y / 2; - if (pixelformat != V4L2_PIX_FMT_NV12 && - pixelformat != V4L2_PIX_FMT_P010) + if (pixelformat != V4L2_PIX_FMT_NV12) return 0; payload[0] = stride_y << 16 | scanline_y; @@ -544,69 +478,12 @@ static int iris_hfi_gen2_set_linear_stride_scanline(struct iris_inst *inst, u32 sizeof(u64)); } -static int iris_hfi_gen2_set_ubwc_stride_scanline(struct iris_inst *inst, u32 plane) -{ - u32 meta_stride_y, meta_scanline_y, meta_stride_uv, meta_scanline_uv; - u32 stride_y, scanline_y, stride_uv, scanline_uv; - u32 port = iris_hfi_gen2_get_port(inst, plane); - u32 pixelformat, width, height; - u32 payload[4]; - - if (inst->domain != DECODER || - inst->fmt_src->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_AV1) - return 0; - - pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; - width = inst->fmt_dst->fmt.pix_mp.width; - height = inst->fmt_dst->fmt.pix_mp.height; - - switch (pixelformat) { - case V4L2_PIX_FMT_QC08C: - stride_y = ALIGN(width, 128); - scanline_y = ALIGN(height, 32); - stride_uv = ALIGN(width, 128); - scanline_uv = ALIGN((height + 1) >> 1, 32); - meta_stride_y = ALIGN(DIV_ROUND_UP(width, 32), 64); - meta_scanline_y = ALIGN(DIV_ROUND_UP(height, 8), 16); - meta_stride_uv = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 16), 64); - meta_scanline_uv = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 8), 16); - break; - case V4L2_PIX_FMT_QC10C: - stride_y = ALIGN(width * 4 / 3, 256); - scanline_y = ALIGN(height, 16); - stride_uv = ALIGN(width * 4 / 3, 256); - scanline_uv = ALIGN((height + 1) >> 1, 16); - meta_stride_y = ALIGN(DIV_ROUND_UP(width, 48), 64); - meta_scanline_y = ALIGN(DIV_ROUND_UP(height, 4), 16); - meta_stride_uv = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 24), 64); - meta_scanline_uv = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 4), 16); - break; - default: - return 0; - } - - payload[0] = stride_y << 16 | scanline_y; - payload[1] = stride_uv << 16 | scanline_uv; - payload[2] = meta_stride_y << 16 | meta_scanline_y; - payload[3] = meta_stride_uv << 16 | meta_scanline_uv; - - return iris_hfi_gen2_session_set_property(inst, - HFI_PROP_UBWC_STRIDE_SCANLINE, - HFI_HOST_FLAGS_NONE, - port, - HFI_PAYLOAD_U32_ARRAY, - &payload[0], - sizeof(u32) * 4); -} - static int iris_hfi_gen2_set_tier(struct iris_inst *inst, u32 plane) { - u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); + u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); u32 tier = inst->fw_caps[TIER].value; - tier = (inst->codec == V4L2_PIX_FMT_AV1) ? inst->fw_caps[TIER_AV1].value : - inst->fw_caps[TIER].value; inst_hfi_gen2->src_subcr_params.tier = tier; return iris_hfi_gen2_session_set_property(inst, @@ -632,43 +509,9 @@ static int iris_hfi_gen2_set_frame_rate(struct iris_inst *inst, u32 plane) sizeof(u32)); } -static int iris_hfi_gen2_set_film_grain(struct iris_inst *inst, u32 plane) -{ - u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 film_grain = inst->fw_caps[FILM_GRAIN].value; - - inst_hfi_gen2->src_subcr_params.film_grain = film_grain; - - return iris_hfi_gen2_session_set_property(inst, - HFI_PROP_AV1_FILM_GRAIN_PRESENT, - HFI_HOST_FLAGS_NONE, - port, - HFI_PAYLOAD_U32_ENUM, - &film_grain, - sizeof(u32)); -} - -static int iris_hfi_gen2_set_super_block(struct iris_inst *inst, u32 plane) -{ - u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 super_block = inst->fw_caps[SUPER_BLOCK].value; - - inst_hfi_gen2->src_subcr_params.super_block = super_block; - - return iris_hfi_gen2_session_set_property(inst, - HFI_PROP_AV1_SUPER_BLOCK_ENABLED, - HFI_HOST_FLAGS_NONE, - port, - HFI_PAYLOAD_U32_ENUM, - &super_block, - sizeof(u32)); -} - static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 plane) { - const struct iris_firmware_data *fdata = inst->core->iris_firmware_data; + const struct iris_platform_data *pdata = inst->core->iris_platform_data; u32 config_params_size = 0, i, j; const u32 *config_params = NULL; int ret; @@ -684,45 +527,37 @@ static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 p {HFI_PROP_SIGNAL_COLOR_INFO, iris_hfi_gen2_set_colorspace }, {HFI_PROP_PROFILE, iris_hfi_gen2_set_profile }, {HFI_PROP_LEVEL, iris_hfi_gen2_set_level }, - {HFI_PROP_OPB_ENABLE, iris_hfi_gen2_set_opb_enable }, {HFI_PROP_COLOR_FORMAT, iris_hfi_gen2_set_colorformat }, {HFI_PROP_LINEAR_STRIDE_SCANLINE, iris_hfi_gen2_set_linear_stride_scanline }, - {HFI_PROP_UBWC_STRIDE_SCANLINE, iris_hfi_gen2_set_ubwc_stride_scanline }, {HFI_PROP_TIER, iris_hfi_gen2_set_tier }, {HFI_PROP_FRAME_RATE, iris_hfi_gen2_set_frame_rate }, - {HFI_PROP_AV1_FILM_GRAIN_PRESENT, iris_hfi_gen2_set_film_grain }, - {HFI_PROP_AV1_SUPER_BLOCK_ENABLED, iris_hfi_gen2_set_super_block }, - {HFI_PROP_OPB_ENABLE, iris_hfi_gen2_set_opb_enable }, }; if (inst->domain == DECODER) { if (V4L2_TYPE_IS_OUTPUT(plane)) { if (inst->codec == V4L2_PIX_FMT_H264) { - config_params = fdata->dec_input_config_params_default; - config_params_size = fdata->dec_input_config_params_default_size; + config_params = pdata->dec_input_config_params_default; + config_params_size = pdata->dec_input_config_params_default_size; } else if (inst->codec == V4L2_PIX_FMT_HEVC) { - config_params = fdata->dec_input_config_params_hevc; - config_params_size = fdata->dec_input_config_params_hevc_size; + config_params = pdata->dec_input_config_params_hevc; + config_params_size = pdata->dec_input_config_params_hevc_size; } else if (inst->codec == V4L2_PIX_FMT_VP9) { - config_params = fdata->dec_input_config_params_vp9; - config_params_size = fdata->dec_input_config_params_vp9_size; - } else if (inst->codec == V4L2_PIX_FMT_AV1) { - config_params = fdata->dec_input_config_params_av1; - config_params_size = fdata->dec_input_config_params_av1_size; + config_params = pdata->dec_input_config_params_vp9; + config_params_size = pdata->dec_input_config_params_vp9_size; } else { return -EINVAL; } } else { - config_params = fdata->dec_output_config_params; - config_params_size = fdata->dec_output_config_params_size; + config_params = pdata->dec_output_config_params; + config_params_size = pdata->dec_output_config_params_size; } } else { if (V4L2_TYPE_IS_OUTPUT(plane)) { - config_params = fdata->enc_input_config_params; - config_params_size = fdata->enc_input_config_params_size; + config_params = pdata->enc_input_config_params; + config_params_size = pdata->enc_input_config_params_size; } else { - config_params = fdata->enc_output_config_params; - config_params_size = fdata->enc_output_config_params_size; + config_params = pdata->enc_output_config_params; + config_params_size = pdata->enc_output_config_params_size; } } @@ -763,9 +598,6 @@ static int iris_hfi_gen2_session_set_codec(struct iris_inst *inst) break; case V4L2_PIX_FMT_VP9: codec = HFI_CODEC_DECODE_VP9; - break; - case V4L2_PIX_FMT_AV1: - codec = HFI_CODEC_DECODE_AV1; } iris_hfi_gen2_packet_session_property(inst, @@ -911,30 +743,25 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan if ((V4L2_TYPE_IS_OUTPUT(plane) && inst_hfi_gen2->ipsc_properties_set) || (V4L2_TYPE_IS_CAPTURE(plane) && inst_hfi_gen2->opsc_properties_set)) { - dev_dbg(core->dev, "%cPSC already set\n", V4L2_TYPE_IS_OUTPUT(plane) ? 'I' : 'O'); + dev_err(core->dev, "invalid plane\n"); return 0; } switch (inst->codec) { case V4L2_PIX_FMT_H264: - change_param = core->iris_firmware_data->dec_input_config_params_default; + change_param = core->iris_platform_data->dec_input_config_params_default; change_param_size = - core->iris_firmware_data->dec_input_config_params_default_size; + core->iris_platform_data->dec_input_config_params_default_size; break; case V4L2_PIX_FMT_HEVC: - change_param = core->iris_firmware_data->dec_input_config_params_hevc; + change_param = core->iris_platform_data->dec_input_config_params_hevc; change_param_size = - core->iris_firmware_data->dec_input_config_params_hevc_size; + core->iris_platform_data->dec_input_config_params_hevc_size; break; case V4L2_PIX_FMT_VP9: - change_param = core->iris_firmware_data->dec_input_config_params_vp9; - change_param_size = - core->iris_firmware_data->dec_input_config_params_vp9_size; - break; - case V4L2_PIX_FMT_AV1: - change_param = core->iris_firmware_data->dec_input_config_params_av1; + change_param = core->iris_platform_data->dec_input_config_params_vp9; change_param_size = - core->iris_firmware_data->dec_input_config_params_av1_size; + core->iris_platform_data->dec_input_config_params_vp9_size; break; } @@ -1018,16 +845,6 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan payload_size = sizeof(u32); payload_type = HFI_PAYLOAD_U32; break; - case HFI_PROP_AV1_FILM_GRAIN_PRESENT: - payload[0] = subsc_params.film_grain; - payload_size = sizeof(u32); - payload_type = HFI_PAYLOAD_U32; - break; - case HFI_PROP_AV1_SUPER_BLOCK_ENABLED: - payload[0] = subsc_params.super_block; - payload_size = sizeof(u32); - payload_type = HFI_PAYLOAD_U32; - break; default: prop_type = 0; ret = -EINVAL; @@ -1064,29 +881,24 @@ static int iris_hfi_gen2_subscribe_property(struct iris_inst *inst, u32 plane) return 0; if (V4L2_TYPE_IS_OUTPUT(plane)) { - subscribe_prop_size = core->iris_firmware_data->dec_input_prop_size; - subcribe_prop = core->iris_firmware_data->dec_input_prop; + subscribe_prop_size = core->iris_platform_data->dec_input_prop_size; + subcribe_prop = core->iris_platform_data->dec_input_prop; } else { switch (inst->codec) { case V4L2_PIX_FMT_H264: - subcribe_prop = core->iris_firmware_data->dec_output_prop_avc; + subcribe_prop = core->iris_platform_data->dec_output_prop_avc; subscribe_prop_size = - core->iris_firmware_data->dec_output_prop_avc_size; + core->iris_platform_data->dec_output_prop_avc_size; break; case V4L2_PIX_FMT_HEVC: - subcribe_prop = core->iris_firmware_data->dec_output_prop_hevc; + subcribe_prop = core->iris_platform_data->dec_output_prop_hevc; subscribe_prop_size = - core->iris_firmware_data->dec_output_prop_hevc_size; + core->iris_platform_data->dec_output_prop_hevc_size; break; case V4L2_PIX_FMT_VP9: - subcribe_prop = core->iris_firmware_data->dec_output_prop_vp9; + subcribe_prop = core->iris_platform_data->dec_output_prop_vp9; subscribe_prop_size = - core->iris_firmware_data->dec_output_prop_vp9_size; - break; - case V4L2_PIX_FMT_AV1: - subcribe_prop = core->iris_firmware_data->dec_output_prop_av1; - subscribe_prop_size = - core->iris_firmware_data->dec_output_prop_av1_size; + core->iris_platform_data->dec_output_prop_vp9_size; break; } } @@ -1134,9 +946,6 @@ static int iris_hfi_gen2_session_stop(struct iris_inst *inst, u32 plane) struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); int ret = 0; - if (!inst_hfi_gen2->packet) - return -EINVAL; - reinit_completion(&inst->completion); iris_hfi_gen2_packet_session_command(inst, @@ -1266,26 +1075,26 @@ static u32 iris_hfi_gen2_buf_type_from_driver(u32 domain, enum iris_buffer_type return HFI_BUFFER_ARP; case BUF_VPSS: return HFI_BUFFER_VPSS; - case BUF_PARTIAL: - return HFI_BUFFER_PARTIAL_DATA; default: return 0; } } -static int iris_hfi_gen2_set_num_comv(struct iris_inst *inst) +static int iris_set_num_comv(struct iris_inst *inst) { - u32 num_comv = inst->buffers[BUF_OUTPUT].min_count; + struct platform_inst_caps *caps; + struct iris_core *core = inst->core; + u32 num_comv; - if (inst->fw_min_count) - num_comv = inst->fw_min_count; + caps = core->iris_platform_data->inst_caps; + num_comv = caps->num_comv; - return iris_hfi_gen2_session_set_property(inst, - HFI_PROP_COMV_BUFFER_COUNT, - HFI_HOST_FLAGS_NONE, - HFI_PORT_BITSTREAM, - HFI_PAYLOAD_U32, - &num_comv, sizeof(u32)); + return core->hfi_ops->session_set_property(inst, + HFI_PROP_COMV_BUFFER_COUNT, + HFI_HOST_FLAGS_NONE, + HFI_PORT_BITSTREAM, + HFI_PAYLOAD_U32, + &num_comv, sizeof(u32)); } static void iris_hfi_gen2_get_buffer(u32 domain, struct iris_buffer *buffer, @@ -1317,7 +1126,7 @@ static int iris_hfi_gen2_session_queue_buffer(struct iris_inst *inst, struct iri iris_hfi_gen2_get_buffer(inst->domain, buffer, &hfi_buffer); if (buffer->type == BUF_COMV) { - ret = iris_hfi_gen2_set_num_comv(inst); + ret = iris_set_num_comv(inst); if (ret) return ret; } @@ -1360,7 +1169,11 @@ static int iris_hfi_gen2_session_release_buffer(struct iris_inst *inst, struct i inst_hfi_gen2->packet->size); } -static const struct iris_hfi_session_ops iris_hfi_gen2_session_ops = { +static const struct iris_hfi_command_ops iris_hfi_gen2_command_ops = { + .sys_init = iris_hfi_gen2_sys_init, + .sys_image_version = iris_hfi_gen2_sys_image_version, + .sys_interframe_powercollapse = iris_hfi_gen2_sys_interframe_powercollapse, + .sys_pc_prep = iris_hfi_gen2_sys_pc_prep, .session_open = iris_hfi_gen2_session_open, .session_set_config_params = iris_hfi_gen2_session_set_config_params, .session_set_property = iris_hfi_gen2_session_set_property, @@ -1375,32 +1188,12 @@ static const struct iris_hfi_session_ops iris_hfi_gen2_session_ops = { .session_close = iris_hfi_gen2_session_close, }; -static struct iris_inst *iris_hfi_gen2_get_instance(void) +void iris_hfi_gen2_command_ops_init(struct iris_core *core) { - struct iris_inst_hfi_gen2 *out; - - /* The allocation is intentionally larger than struct iris_inst. */ - out = kzalloc_obj(*out); - if (!out) - return NULL; - - out->inst.hfi_session_ops = &iris_hfi_gen2_session_ops; - - return &out->inst; + core->hfi_ops = &iris_hfi_gen2_command_ops; } -static const struct iris_hfi_sys_ops iris_hfi_gen2_sys_ops = { - .sys_init = iris_hfi_gen2_sys_init, - .sys_image_version = iris_hfi_gen2_sys_image_version, - .sys_interframe_powercollapse = iris_hfi_gen2_sys_interframe_powercollapse, - .sys_pc_prep = iris_hfi_gen2_sys_pc_prep, - - .sys_hfi_response_handler = iris_hfi_gen2_response_handler, - - .sys_get_instance = iris_hfi_gen2_get_instance, -}; - -void iris_hfi_gen2_sys_ops_init(struct iris_core *core) +struct iris_inst *iris_hfi_gen2_get_instance(void) { - core->hfi_sys_ops = &iris_hfi_gen2_sys_ops; + return kzalloc(sizeof(struct iris_inst_hfi_gen2), GFP_KERNEL); } diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h index 776b21cd11b2..aa1f795f5626 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h @@ -70,26 +70,7 @@ enum hfi_rate_control { #define HFI_PROP_QP_PACKED 0x0300012e #define HFI_PROP_MIN_QP_PACKED 0x0300012f #define HFI_PROP_MAX_QP_PACKED 0x03000130 -#define HFI_PROP_IR_RANDOM_PERIOD 0x03000131 -#define HFI_PROP_LTR_COUNT 0x03000134 -#define HFI_PROP_LTR_MARK 0x03000135 -#define HFI_PROP_LTR_USE 0x03000136 - -enum hfi_layer_encoding_type { - HFI_HIER_P_SLIDING_WINDOW = 0x1, - HFI_HIER_P_HYBRID_LTR = 0x2, - HFI_HIER_B = 0x3, -}; - -#define HFI_PROP_LAYER_ENCODING_TYPE 0x03000138 -#define HFI_PROP_LAYER_COUNT 0x03000139 #define HFI_PROP_TOTAL_BITRATE 0x0300013b -#define HFI_PROP_BITRATE_LAYER1 0x0300013c -#define HFI_PROP_BITRATE_LAYER2 0x0300013d -#define HFI_PROP_BITRATE_LAYER3 0x0300013e -#define HFI_PROP_BITRATE_LAYER4 0x0300013f -#define HFI_PROP_BITRATE_LAYER5 0x03000140 -#define HFI_PROP_BITRATE_LAYER6 0x03000141 #define HFI_PROP_MAX_GOP_FRAMES 0x03000146 #define HFI_PROP_MAX_B_FRAMES 0x03000147 #define HFI_PROP_QUALITY_MODE 0x03000148 @@ -102,43 +83,15 @@ enum hfi_seq_header_mode { }; #define HFI_PROP_SEQ_HEADER_MODE 0x03000149 - -enum hfi_rotation { - HFI_ROTATION_NONE = 0x00000000, - HFI_ROTATION_90 = 0x00000001, - HFI_ROTATION_180 = 0x00000002, - HFI_ROTATION_270 = 0x00000003, -}; - -#define HFI_PROP_ROTATION 0x0300014b - -enum hfi_flip { - HFI_DISABLE_FLIP = 0x00000000, - HFI_HORIZONTAL_FLIP = 0x00000001, - HFI_VERTICAL_FLIP = 0x00000002, -}; - -#define HFI_PROP_FLIP 0x0300014c #define HFI_PROP_SIGNAL_COLOR_INFO 0x03000155 #define HFI_PROP_PICTURE_TYPE 0x03000162 #define HFI_PROP_DEC_DEFAULT_HEADER 0x03000168 #define HFI_PROP_DEC_START_FROM_RAP_FRAME 0x03000169 #define HFI_PROP_NO_OUTPUT 0x0300016a #define HFI_PROP_BUFFER_MARK 0x0300016c -#define HFI_PROP_WORST_COMPRESSION_RATIO 0x03000174 -#define HFI_PROP_WORST_COMPLEXITY_FACTOR 0x03000175 #define HFI_PROP_RAW_RESOLUTION 0x03000178 #define HFI_PROP_TOTAL_PEAK_BITRATE 0x0300017C -#define HFI_PROP_AV1_FILM_GRAIN_PRESENT 0x03000180 -#define HFI_PROP_AV1_SUPER_BLOCK_ENABLED 0x03000181 -#define HFI_PROP_AV1_OP_POINT 0x03000182 -#define HFI_PROP_IR_CYCLIC_PERIOD 0x0300017E -#define HFI_PROP_OPB_ENABLE 0x03000184 -#define HFI_PROP_AV1_TILE_ROWS_COLUMNS 0x03000187 -#define HFI_PROP_AV1_DRAP_CONFIG 0x03000189 -#define HFI_PROP_UBWC_STRIDE_SCANLINE 0x03000190 #define HFI_PROP_COMV_BUFFER_COUNT 0x03000193 -#define HFI_PROP_AV1_UNIFORM_TILE_SPACING 0x03000197 #define HFI_PROP_END 0x03FFFFFF #define HFI_SESSION_ERROR_BEGIN 0x04000000 @@ -185,7 +138,6 @@ enum hfi_codec_type { HFI_CODEC_DECODE_HEVC = 3, HFI_CODEC_ENCODE_HEVC = 4, HFI_CODEC_DECODE_VP9 = 5, - HFI_CODEC_DECODE_AV1 = 7, }; enum hfi_picture_type { diff --git a/drivers/media/platform/qcom/iris/iris_hfi_queue.c b/drivers/media/platform/qcom/iris/iris_hfi_queue.c index bf6db23b53e2..c28e8c866f3c 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_queue.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_queue.c @@ -3,12 +3,42 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include +#include #include #include "iris_core.h" #include "iris_hfi_queue.h" #include "iris_vpu_common.h" +static u32 iris_hfi_queue_table_size(struct iris_core *core) +{ + if (core->iris_platform_data->legacy_vpu5) + return sizeof(struct iris_hfi_legacy_queue_table_header); + + return sizeof(struct iris_hfi_queue_table_header); +} + +static u32 iris_hfi_queue_alloc_size(struct iris_core *core) +{ + u32 queue_size; + + queue_size = ALIGN(iris_hfi_queue_table_size(core) + + (IFACEQ_QUEUE_SIZE * IFACEQ_NUMQ), SZ_4K); + + /* + * VPU5 firmware is given a 1 MiB-aligned UC region size. Unlike the + * downstream allocator, dma_alloc_attrs() does not guarantee that the + * separately allocated SFR and the unused tail are adjacent to the + * queue IOVA. Map the complete advertised region so speculative or + * bounds-checking firmware accesses cannot fault in its unmapped tail. + */ + if (core->iris_platform_data->legacy_vpu5) + return ALIGN(SFR_SIZE + queue_size, SZ_1M); + + return queue_size; +} + static int iris_hfi_queue_write(struct iris_iface_q_info *qinfo, void *packet, u32 packet_size) { struct iris_hfi_queue_header *queue = qinfo->qhdr; @@ -112,11 +142,23 @@ static int iris_hfi_queue_read(struct iris_iface_q_info *qinfo, void *packet) int iris_hfi_queue_cmd_write_locked(struct iris_core *core, void *pkt, u32 pkt_size) { struct iris_iface_q_info *q_info = &core->command_queue; + struct iris_hfi_queue_header *qhdr = q_info->qhdr; + u32 *words = pkt; if (core->state == IRIS_CORE_ERROR || core->state == IRIS_CORE_DEINIT) return -EINVAL; if (!iris_hfi_queue_write(q_info, pkt, pkt_size)) { + dev_dbg(core->dev, + "HFI cmd: bytes=%u words=%#x,%#x,%#x,%#x,%#x; q status=%#x start=%#x type=%#x size=%u rx_req=%u tx_req=%u r=%u w=%u\n", + pkt_size, words[0], words[1], + pkt_size >= 3 * sizeof(*words) ? words[2] : 0, + pkt_size >= 4 * sizeof(*words) ? words[3] : 0, + pkt_size >= 5 * sizeof(*words) ? words[4] : 0, + qhdr->status, qhdr->start_addr, + ((u32)qhdr->header_type << 16) | qhdr->queue_type, + qhdr->q_size, qhdr->rx_req, qhdr->tx_req, + qhdr->read_idx, qhdr->write_idx); iris_vpu_raise_interrupt(core); } else { dev_err(core->dev, "queue full\n"); @@ -226,12 +268,18 @@ static void iris_hfi_queue_init(struct iris_core *core, u32 queue_id, struct iris_iface_q_info *iface_q) { struct iris_hfi_queue_table_header *q_tbl_hdr = core->iface_q_table_vaddr; - u32 offset = sizeof(*q_tbl_hdr) + (queue_id * IFACEQ_QUEUE_SIZE); + struct iris_hfi_legacy_queue_table_header *legacy_tbl_hdr = + core->iface_q_table_vaddr; + u32 offset = iris_hfi_queue_table_size(core) + + (queue_id * IFACEQ_QUEUE_SIZE); iface_q->device_addr = core->iface_q_table_daddr + offset; iface_q->kernel_vaddr = (void *)((char *)core->iface_q_table_vaddr + offset); - iface_q->qhdr = &q_tbl_hdr->q_hdr[queue_id]; + if (core->iris_platform_data->legacy_vpu5) + iface_q->qhdr = &legacy_tbl_hdr->q_hdr[queue_id]; + else + iface_q->qhdr = &q_tbl_hdr->q_hdr[queue_id]; iris_hfi_queue_set_header(core, queue_id, iface_q); } @@ -246,10 +294,18 @@ static void iris_hfi_queue_deinit(struct iris_iface_q_info *iface_q) int iris_hfi_queues_init(struct iris_core *core) { struct iris_hfi_queue_table_header *q_tbl_hdr; - u32 queue_size; + struct iris_hfi_legacy_queue_table_header *legacy_tbl_hdr; + struct iommu_domain *domain; + phys_addr_t first_phys, last_phys; + u32 queue_size, queue_used; /* Iris hardware requires 4K queue alignment */ - queue_size = ALIGN((sizeof(*q_tbl_hdr) + (IFACEQ_QUEUE_SIZE * IFACEQ_NUMQ)), SZ_4K); + queue_used = ALIGN(iris_hfi_queue_table_size(core) + + (IFACEQ_QUEUE_SIZE * IFACEQ_NUMQ), SZ_4K); + queue_size = iris_hfi_queue_alloc_size(core); + dev_info(core->dev, + "HFI queues: allocating %u-byte queue region (%u bytes used)\n", + queue_size, queue_used); core->iface_q_table_vaddr = dma_alloc_attrs(core->dev, queue_size, &core->iface_q_table_daddr, GFP_KERNEL, DMA_ATTR_WRITE_COMBINE); @@ -257,7 +313,36 @@ int iris_hfi_queues_init(struct iris_core *core) dev_err(core->dev, "queues alloc and map failed\n"); return -ENOMEM; } + memset(core->iface_q_table_vaddr, 0, queue_size); + dev_info(core->dev, "HFI queues: queue table allocated at %pad\n", + &core->iface_q_table_daddr); + + if (core->iris_platform_data->legacy_vpu5) { + domain = iommu_get_domain_for_dev(core->dev); + if (!domain) { + dev_warn(core->dev, + "HFI queues: no IOMMU domain attached to video device\n"); + } else { + first_phys = iommu_iova_to_phys(domain, + core->iface_q_table_daddr); + last_phys = iommu_iova_to_phys(domain, + core->iface_q_table_daddr + + queue_size - 1); + dev_info(core->dev, + "HFI queues: IOMMU coverage IOVA %pad..%pad -> phys %pa..%pa\n", + &core->iface_q_table_daddr, + &(dma_addr_t) { + core->iface_q_table_daddr + queue_size - 1 + }, + &first_phys, &last_phys); + if (!first_phys || !last_phys) + dev_err(core->dev, + "HFI queues: queue IOVA is not fully mapped\n"); + } + } + dev_info(core->dev, "HFI queues: allocating %u-byte SFR buffer\n", + SFR_SIZE); core->sfr_vaddr = dma_alloc_attrs(core->dev, SFR_SIZE, &core->sfr_daddr, GFP_KERNEL, DMA_ATTR_WRITE_COMBINE); @@ -267,24 +352,54 @@ int iris_hfi_queues_init(struct iris_core *core) core->iface_q_table_daddr, DMA_ATTR_WRITE_COMBINE); return -ENOMEM; } + dev_info(core->dev, "HFI queues: SFR buffer allocated at %pad\n", + &core->sfr_daddr); + dev_info(core->dev, "HFI queues: initializing command queue\n"); iris_hfi_queue_init(core, IFACEQ_CMDQ_ID, &core->command_queue); + dev_info(core->dev, "HFI queues: initializing message queue\n"); iris_hfi_queue_init(core, IFACEQ_MSGQ_ID, &core->message_queue); + dev_info(core->dev, "HFI queues: initializing debug queue\n"); iris_hfi_queue_init(core, IFACEQ_DBGQ_ID, &core->debug_queue); - q_tbl_hdr = (struct iris_hfi_queue_table_header *)core->iface_q_table_vaddr; - q_tbl_hdr->version = 0; - q_tbl_hdr->device_addr = (void *)core; - strscpy(q_tbl_hdr->name, "iris-hfi-queues", sizeof(q_tbl_hdr->name)); - q_tbl_hdr->size = sizeof(*q_tbl_hdr); - q_tbl_hdr->qhdr0_offset = sizeof(*q_tbl_hdr) - - (IFACEQ_NUMQ * sizeof(struct iris_hfi_queue_header)); - q_tbl_hdr->qhdr_size = sizeof(q_tbl_hdr->q_hdr[0]); - q_tbl_hdr->num_q = IFACEQ_NUMQ; - q_tbl_hdr->num_active_q = IFACEQ_NUMQ; + dev_info(core->dev, "HFI queues: initializing table header\n"); + if (core->iris_platform_data->legacy_vpu5) { + legacy_tbl_hdr = core->iface_q_table_vaddr; + legacy_tbl_hdr->version = 0; + legacy_tbl_hdr->size = sizeof(*legacy_tbl_hdr); + legacy_tbl_hdr->qhdr0_offset = + offsetof(struct iris_hfi_legacy_queue_table_header, q_hdr); + legacy_tbl_hdr->qhdr_size = + sizeof(legacy_tbl_hdr->q_hdr[0]); + legacy_tbl_hdr->num_q = IFACEQ_NUMQ; + legacy_tbl_hdr->num_active_q = IFACEQ_NUMQ; + dev_info(core->dev, + "HFI queues: legacy Venus table size %zu, first header offset %u\n", + sizeof(*legacy_tbl_hdr), + legacy_tbl_hdr->qhdr0_offset); + } else { + q_tbl_hdr = core->iface_q_table_vaddr; + q_tbl_hdr->version = 0; + q_tbl_hdr->device_addr = (void *)core; + strscpy(q_tbl_hdr->name, "msm_v4l2_vidc", + sizeof(q_tbl_hdr->name)); + q_tbl_hdr->size = sizeof(*q_tbl_hdr); + q_tbl_hdr->qhdr0_offset = sizeof(*q_tbl_hdr) - + (IFACEQ_NUMQ * sizeof(struct iris_hfi_queue_header)); + q_tbl_hdr->qhdr_size = sizeof(q_tbl_hdr->q_hdr[0]); + q_tbl_hdr->num_q = IFACEQ_NUMQ; + q_tbl_hdr->num_active_q = IFACEQ_NUMQ; + } /* Write sfr size in first word to be used by firmware */ *((u32 *)core->sfr_vaddr) = SFR_SIZE; + /* + * Publish the complete legacy table, all queue headers and the SFR + * header before the firmware is allowed to fetch them. The Venus + * HFI Gen1 implementation has the same final barrier. + */ + wmb(); + dev_info(core->dev, "HFI queues: initialization complete\n"); return 0; } @@ -306,8 +421,7 @@ void iris_hfi_queues_deinit(struct iris_core *core) core->sfr_vaddr = NULL; core->sfr_daddr = 0; - queue_size = ALIGN(sizeof(struct iris_hfi_queue_table_header) + - (IFACEQ_QUEUE_SIZE * IFACEQ_NUMQ), SZ_4K); + queue_size = iris_hfi_queue_alloc_size(core); dma_free_attrs(core->dev, queue_size, core->iface_q_table_vaddr, core->iface_q_table_daddr, DMA_ATTR_WRITE_COMBINE); diff --git a/drivers/media/platform/qcom/iris/iris_hfi_queue.h b/drivers/media/platform/qcom/iris/iris_hfi_queue.h index 2174fc5ce618..b084d872fb7e 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_queue.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_queue.h @@ -9,10 +9,13 @@ struct iris_core; /* - * Max 64 Buffers ( 32 input buffers and 32 output buffers) - * can be queued by v4l2 framework at any given time. + * The SM8150 VPU5 HFI Gen1 firmware uses the legacy Venus queue ABI: + * 50 buffers per session. Using the newer Iris value of 64 expands the + * advertised UC region from 3 MiB to 4 MiB, beyond the memory actually + * allocated for the three queues, and can lock up the multimedia + * interconnect as soon as the firmware CPU starts touching the queues. */ -#define IFACEQ_MAX_BUF_COUNT 64 +#define IFACEQ_MAX_BUF_COUNT 50 /* * Max session supported are 16. * this value is used to calcualte the size of @@ -165,6 +168,21 @@ struct iris_hfi_queue_table_header { struct iris_hfi_queue_header q_hdr[IFACEQ_NUMQ]; }; +/* + * VPU5/HFI Gen1 predates the extended Iris queue-table header. Its + * firmware expects the first queue header immediately after the six common + * u32 fields (offset 24), with no host pointer or name in between. + */ +struct iris_hfi_legacy_queue_table_header { + u32 version; + u32 size; + u32 qhdr0_offset; + u32 qhdr_size; + u32 num_q; + u32 num_active_q; + struct iris_hfi_queue_header q_hdr[IFACEQ_NUMQ]; +}; + struct iris_iface_q_info { struct iris_hfi_queue_header *qhdr; dma_addr_t device_addr; diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h index a770331d1675..8aa0da43e10a 100644 --- a/drivers/media/platform/qcom/iris/iris_instance.h +++ b/drivers/media/platform/qcom/iris/iris_instance.h @@ -15,20 +15,15 @@ #define DEFAULT_WIDTH 320 #define DEFAULT_HEIGHT 240 -struct iris_hfi_session_ops; - -enum iris_fmt_type_out { +enum iris_fmt_type { IRIS_FMT_H264, IRIS_FMT_HEVC, IRIS_FMT_VP9, - IRIS_FMT_AV1, }; -enum iris_fmt_type_cap { - IRIS_FMT_NV12, - IRIS_FMT_QC08C, - IRIS_FMT_TP10, - IRIS_FMT_QC10C, +struct iris_fmt { + u32 pixfmt; + u32 type; }; /** @@ -37,7 +32,6 @@ enum iris_fmt_type_cap { * @list: used for attach an instance to the core * @core: pointer to core structure * @session_id: id of current video session - * @hfi_session_ops: iris HFI session ops * @ctx_q_lock: lock to serialize queues related ioctls * @lock: lock to seralise forward and reverse threads * @fh: reference of v4l2 file handler @@ -55,7 +49,11 @@ enum iris_fmt_type_cap { * @fw_min_count: minimnum count of buffers needed by fw * @state: instance state * @sub_state: instance sub state - * @once_per_session_set: boolean to set once per session property + * @hfi_session_opened: whether this instance owns an active firmware session + * @hfi_core_id: video core mask assigned to this firmware session + * @core_load_reserved: whether this instance owns an aggregate throughput slot + * @core_load_rejected: whether this active session already failed admission + * @admission_frame_rate: frame rate used for aggregate throughput admission * @max_input_data_size: max size of input data * @power: structure of power info * @icc_data: structure of interconnect data @@ -67,24 +65,37 @@ enum iris_fmt_type_cap { * @metadata_idx: index for metadata buffer * @codec: codec type * @last_buffer_dequeued: a flag to indicate that last buffer is sent by driver - * @last_buf_ns: start time of received input buffer for current one second FPS window - * @frame_counter: input buffer counter for current one second FPS window - * @frame_rate: frame rate of current instance - * @operating_rate: operating rate of current instance + * @last_buf_ns: start time of the current one-second input-rate window + * @rate_min_timestamp: lowest input timestamp in the current rate window + * @rate_max_timestamp: highest input timestamp in the current rate window + * @frame_counter: input buffer counter for the current rate window + * @frame_rate: measured input rate used for clock and interconnect votes + * @frame_rate_down_count: consecutive lower-rate windows before reducing votes + * @operating_rate: requested operating rate for the encoder + * @streamoff_pending: a vb2 STREAMOFF is flushing or stopping this session + * @start_streaming_rollback_type: queue whose failed STREAMON is being rolled back + * @last_input_timestamp: most recent compressed-input timestamp + * @seek_timestamp: first compressed-input timestamp after a discontinuity + * @input_timestamp_valid: whether last_input_timestamp has been initialized + * @seek_timestamp_pending: discard old-epoch output until seek_timestamp arrives + * @corrupt_output_drops: consecutive corrupt legacy output frames recycled + * @pending_output: legacy output held for one frame to detect a timestamp jump + * @seek_hold_frames: output frames held after a seek before resuming in-place delivery + * @display_delay: requested firmware display delay + * @display_delay_enable: whether the requested display delay is active + * @surface_fences: pending CPU-write fences attached to exported surfaces + * @surface_fence_context: dma_fence context for this decoder instance + * @surface_fence_seqno: last allocated surface-fence sequence number + * @vp9_iova_hole_vaddr: kernel mapping of the high-IOVA placeholder reservation + * @vp9_iova_hole_daddr: IOVA at which the placeholder was mapped + * @vp9_iova_hole_size: size of the placeholder reservation (0 when not held) * @hfi_rc_type: rate control type - * @enc_raw_width: source image width for encoder instance - * @enc_raw_height: source image height for encoder instance - * @enc_scale_width: scale width for encoder instance - * @enc_scale_height: scale height for encoder instance - * @hfi_layer_type: hierarchical coding layer type - * @hfi_layer_count: hierarchical coding layer count */ struct iris_inst { struct list_head list; struct iris_core *core; u32 session_id; - const struct iris_hfi_session_ops *hfi_session_ops; struct mutex ctx_q_lock;/* lock to serialize queues related ioctls */ struct mutex lock; /* lock to serialize forward and reverse threads */ struct v4l2_fh fh; @@ -99,10 +110,15 @@ struct iris_inst { u32 flush_responses_pending; struct platform_inst_fw_cap fw_caps[INST_FW_CAP_MAX]; struct iris_buffers buffers[BUF_TYPE_MAX]; + u32 fw_buffer_sizes[BUF_TYPE_MAX]; u32 fw_min_count; enum iris_inst_state state; enum iris_inst_sub_state sub_state; - bool once_per_session_set; + bool hfi_session_opened; + u32 hfi_core_id; + bool core_load_reserved; + bool core_load_rejected; + u32 admission_frame_rate; size_t max_input_data_size; struct iris_inst_power power; struct icc_vote_data icc_data; @@ -115,16 +131,30 @@ struct iris_inst { u32 codec; bool last_buffer_dequeued; u64 last_buf_ns; + u64 rate_min_timestamp; + u64 rate_max_timestamp; u32 frame_counter; u32 frame_rate; + u32 frame_rate_down_count; u32 operating_rate; + bool streamoff_pending; + u32 start_streaming_rollback_type; + u64 last_input_timestamp; + u64 seek_timestamp; + bool input_timestamp_valid; + bool seek_timestamp_pending; + u32 corrupt_output_drops; + struct iris_buffer *pending_output; + u32 seek_hold_frames; + u32 display_delay; + bool display_delay_enable; + struct list_head surface_fences; + u64 surface_fence_context; + u64 surface_fence_seqno; + void *vp9_iova_hole_vaddr; + dma_addr_t vp9_iova_hole_daddr; + size_t vp9_iova_hole_size; u32 hfi_rc_type; - u32 enc_raw_width; - u32 enc_raw_height; - u32 enc_scale_width; - u32 enc_scale_height; - u32 hfi_layer_type; - u32 hfi_layer_count; }; #endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h index c9256f2323dc..6775ffd5b29a 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_common.h +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h @@ -7,37 +7,27 @@ #define __IRIS_PLATFORM_COMMON_H__ #include -#include "iris_buffer.h" struct iris_core; struct iris_inst; +#define IRIS_PAS_ID 9 #define HW_RESPONSE_TIMEOUT_VALUE (1000) /* milliseconds */ #define AUTOSUSPEND_DELAY_VALUE (HW_RESPONSE_TIMEOUT_VALUE + 500) /* milliseconds */ #define REGISTER_BIT_DEPTH(luma, chroma) ((luma) << 16 | (chroma)) #define BIT_DEPTH_8 REGISTER_BIT_DEPTH(8, 8) -#define BIT_DEPTH_10 REGISTER_BIT_DEPTH(10, 10) #define CODED_FRAMES_PROGRESSIVE 0x0 #define DEFAULT_MAX_HOST_BUF_COUNT 64 #define DEFAULT_MAX_HOST_BURST_BUF_COUNT 256 #define DEFAULT_FPS 30 #define MAXIMUM_FPS 480 -#define NUM_MBS_8K ((8192 * 4352) / 256) +#define NUM_MBS_8K ((8192 * 4352) / 256) #define MIN_QP_8BIT 1 #define MAX_QP 51 #define MAX_QP_HEVC 63 #define DEFAULT_QP 20 #define BITRATE_DEFAULT 20000000 -#define INVALID_DEFAULT_MARK_OR_USE_LTR -1 -#define MAX_LTR_FRAME_COUNT_GEN1 4 -#define MAX_LTR_FRAME_COUNT_GEN2 2 -#define MAX_LAYER_HB 3 -#define MAX_AVC_LAYER_HP_HYBRID_LTR 5 -#define MAX_AVC_LAYER_HP_SLIDING_WINDOW 3 -#define MAX_HEVC_LAYER_HP_SLIDING_WINDOW 3 -#define MAX_HEVC_VBR_LAYER_HP_SLIDING_WINDOW 5 -#define MAX_HIER_CODING_LAYER_GEN1 6 enum stage_type { STAGE_1 = 1, @@ -50,30 +40,20 @@ enum pipe_type { PIPE_4 = 4, }; -extern const struct iris_firmware_data iris_hfi_gen1_data; -extern const struct iris_firmware_data iris_hfi_gen2_data; - -extern const struct iris_platform_data qcs8300_data; -extern const struct iris_platform_data sc7280_data; -extern const struct iris_platform_data sm8250_data; -extern const struct iris_platform_data sm8550_data; -extern const struct iris_platform_data sm8650_data; -extern const struct iris_platform_data sm8750_data; -extern const struct iris_platform_data x1p42100_data; +extern struct iris_platform_data qcs8300_data; +extern struct iris_platform_data sm8150_data; +extern struct iris_platform_data sm8250_data; +extern struct iris_platform_data sm8550_data; +extern struct iris_platform_data sm8650_data; enum platform_clk_type { - IRIS_AXI_CLK, /* AXI0 in case of platforms with multiple AXI clocks */ + IRIS_AXI_CLK, + IRIS_BUS_CLK, IRIS_CTRL_CLK, - IRIS_AHB_CLK, + IRIS_HW_AXI_CLK, IRIS_HW_CLK, - IRIS_HW_AHB_CLK, - IRIS_AXI1_CLK, - IRIS_CTRL_FREERUN_CLK, - IRIS_HW_FREERUN_CLK, - IRIS_BSE_HW_CLK, - IRIS_VPP0_HW_CLK, - IRIS_VPP1_HW_CLK, - IRIS_APV_HW_CLK, + IRIS_AUX_HW_AXI_CLK, + IRIS_AUX_HW_CLK, }; struct platform_clk_data { @@ -88,6 +68,16 @@ struct tz_cp_config { u32 cp_nonpixel_size; }; +struct ubwc_config_data { + u32 max_channels; + u32 mal_length; + u32 highest_bank_bit; + u32 bank_swzl_level; + u32 bank_swz2_level; + u32 bank_swz3_level; + u32 bank_spreading; +}; + struct platform_inst_caps { u32 min_frame_width; u32 max_frame_width; @@ -98,6 +88,7 @@ struct platform_inst_caps { u32 mb_cycles_vpp; u32 mb_cycles_fw; u32 mb_cycles_fw_vpp; + u32 num_comv; u32 max_frame_rate; u32 max_operating_rate; }; @@ -109,13 +100,6 @@ enum platform_inst_fw_cap_type { LEVEL_H264, LEVEL_HEVC, LEVEL_VP9, - PROFILE_AV1, - LEVEL_AV1, - TIER_AV1, - DRAP, - FILM_GRAIN, - SUPER_BLOCK, - ENH_LAYER_COUNT, INPUT_BUF_HOST_MAX_COUNT, OUTPUT_BUF_HOST_MAX_COUNT, STAGE, @@ -156,33 +140,6 @@ enum platform_inst_fw_cap_type { P_FRAME_QP_HEVC, B_FRAME_QP_H264, B_FRAME_QP_HEVC, - ROTATION, - HFLIP, - VFLIP, - IR_TYPE, - IR_PERIOD, - LTR_COUNT, - USE_LTR, - MARK_LTR, - B_FRAME, - INTRA_PERIOD, - LAYER_ENABLE, - LAYER_TYPE_H264, - LAYER_TYPE_HEVC, - LAYER_COUNT_H264, - LAYER_COUNT_HEVC, - LAYER0_BITRATE_H264, - LAYER1_BITRATE_H264, - LAYER2_BITRATE_H264, - LAYER3_BITRATE_H264, - LAYER4_BITRATE_H264, - LAYER5_BITRATE_H264, - LAYER0_BITRATE_HEVC, - LAYER1_BITRATE_HEVC, - LAYER2_BITRATE_HEVC, - LAYER3_BITRATE_HEVC, - LAYER4_BITRATE_HEVC, - LAYER5_BITRATE_HEVC, INST_FW_CAP_MAX, }; @@ -231,36 +188,62 @@ struct icc_vote_data { enum platform_pm_domain_type { IRIS_CTRL_POWER_DOMAIN, IRIS_HW_POWER_DOMAIN, - IRIS_VPP0_HW_POWER_DOMAIN, - IRIS_VPP1_HW_POWER_DOMAIN, - IRIS_APV_HW_POWER_DOMAIN, + IRIS_AUX_HW_POWER_DOMAIN, }; -struct iris_firmware_data { - void (*init_hfi_ops)(struct iris_core *core); - - u32 core_arch; - - const struct platform_inst_fw_cap *inst_fw_caps_dec; +struct iris_platform_data { + void (*init_hfi_command_ops)(struct iris_core *core); + void (*init_hfi_response_ops)(struct iris_core *core); + struct iris_inst *(*get_instance)(void); + const struct vpu_ops *vpu_ops; + void (*set_preset_registers)(struct iris_core *core); + const struct icc_info *icc_tbl; + unsigned int icc_tbl_size; + const struct bw_info *bw_tbl_dec; + unsigned int bw_tbl_dec_size; + const char * const *pmdomain_tbl; + unsigned int pmdomain_tbl_size; + const char * const *opp_pd_tbl; + unsigned int opp_pd_tbl_size; + const struct platform_clk_data *clk_tbl; + unsigned int clk_tbl_size; + const char * const *clk_rst_tbl; + unsigned int clk_rst_tbl_size; + const char * const *controller_rst_tbl; + unsigned int controller_rst_tbl_size; + u64 dma_mask; + const char *fwname; + u32 pas_id; + struct platform_inst_caps *inst_caps; + struct platform_inst_fw_cap *inst_fw_caps_dec; u32 inst_fw_caps_dec_size; - const struct platform_inst_fw_cap *inst_fw_caps_enc; + struct platform_inst_fw_cap *inst_fw_caps_enc; u32 inst_fw_caps_enc_size; - + struct tz_cp_config *tz_cp_config_data; + u32 core_arch; + bool use_vcodec_hw_control; + bool defer_vcodec_power; + bool legacy_vpu5; + u32 hw_response_timeout; + struct ubwc_config_data *ubwc_config; + u32 num_vpp_pipe; + u32 max_session_count; + /* max number of macroblocks per frame supported */ + u32 max_core_mbpf; + /* max number of macroblocks per second supported */ + u32 max_core_mbps; const u32 *dec_input_config_params_default; unsigned int dec_input_config_params_default_size; const u32 *dec_input_config_params_hevc; unsigned int dec_input_config_params_hevc_size; const u32 *dec_input_config_params_vp9; unsigned int dec_input_config_params_vp9_size; - const u32 *dec_input_config_params_av1; - unsigned int dec_input_config_params_av1_size; const u32 *dec_output_config_params; unsigned int dec_output_config_params_size; const u32 *enc_input_config_params; unsigned int enc_input_config_params_size; const u32 *enc_output_config_params; unsigned int enc_output_config_params_size; - const u32 *dec_input_prop; unsigned int dec_input_prop_size; const u32 *dec_output_prop_avc; @@ -269,9 +252,6 @@ struct iris_firmware_data { unsigned int dec_output_prop_hevc_size; const u32 *dec_output_prop_vp9; unsigned int dec_output_prop_vp9_size; - const u32 *dec_output_prop_av1; - unsigned int dec_output_prop_av1_size; - const u32 *dec_ip_int_buf_tbl; unsigned int dec_ip_int_buf_tbl_size; const u32 *dec_op_int_buf_tbl; @@ -282,48 +262,4 @@ struct iris_firmware_data { unsigned int enc_op_int_buf_tbl_size; }; -struct iris_firmware_desc { - const struct iris_firmware_data *firmware_data; - u32 (*get_vpu_buffer_size)(struct iris_inst *inst, enum iris_buffer_type buffer_type); - const char *fwname; -}; - -struct iris_platform_data { - /* - * XXX: replace with gen1 / gen2 pointers once we have platforms - * supporting both firmware kinds. - */ - const struct iris_firmware_desc *firmware_desc; - - const struct vpu_ops *vpu_ops; - const struct icc_info *icc_tbl; - unsigned int icc_tbl_size; - const struct bw_info *bw_tbl_dec; - unsigned int bw_tbl_dec_size; - const char * const *pmdomain_tbl; - unsigned int pmdomain_tbl_size; - const char * const *opp_pd_tbl; - unsigned int opp_pd_tbl_size; - const struct platform_clk_data *clk_tbl; - const char * const *opp_clk_tbl; - unsigned int clk_tbl_size; - const char * const *clk_rst_tbl; - unsigned int clk_rst_tbl_size; - const char * const *controller_rst_tbl; - unsigned int controller_rst_tbl_size; - u64 dma_mask; - const u32 *inst_iris_fmts; - u32 inst_iris_fmts_size; - struct platform_inst_caps *inst_caps; - const struct tz_cp_config *tz_cp_config_data; - u32 tz_cp_config_data_size; - u32 num_vpp_pipe; - bool no_aon; - u32 max_session_count; - /* max number of macroblocks per frame supported */ - u32 max_core_mbpf; - /* max number of macroblocks per second supported */ - u32 max_core_mbps; -}; - #endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen2.c b/drivers/media/platform/qcom/iris/iris_platform_gen2.c new file mode 100644 index 000000000000..cf4b92f534b2 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_platform_gen2.c @@ -0,0 +1,995 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "iris_core.h" +#include "iris_ctrls.h" +#include "iris_hfi_gen2.h" +#include "iris_hfi_gen2_defines.h" +#include "iris_platform_common.h" +#include "iris_vpu_common.h" + +#include "iris_platform_qcs8300.h" +#include "iris_platform_sm8650.h" + +#define VIDEO_ARCH_LX 1 +#define BITRATE_MAX 245000000 + +static struct platform_inst_fw_cap inst_fw_cap_sm8550_dec[] = { + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = PROFILE_VP9, + .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + .value = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_6_1, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_VP9, + .min = V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0), + .value = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = TIER, + .min = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + .value = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .hfi_id = HFI_PROP_TIER, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = INPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROP_STAGE, + .set = iris_set_stage, + }, + { + .cap_id = PIPE, + .min = PIPE_1, + .max = PIPE_4, + .step_or_mask = 1, + .value = PIPE_4, + .hfi_id = HFI_PROP_PIPE, + .set = iris_set_pipe, + }, + { + .cap_id = POC, + .min = 0, + .max = 2, + .step_or_mask = 1, + .value = 1, + .hfi_id = HFI_PROP_PIC_ORDER_CNT_TYPE, + }, + { + .cap_id = CODED_FRAMES, + .min = CODED_FRAMES_PROGRESSIVE, + .max = CODED_FRAMES_PROGRESSIVE, + .step_or_mask = 0, + .value = CODED_FRAMES_PROGRESSIVE, + .hfi_id = HFI_PROP_CODED_FRAMES, + }, + { + .cap_id = BIT_DEPTH, + .min = BIT_DEPTH_8, + .max = BIT_DEPTH_8, + .step_or_mask = 1, + .value = BIT_DEPTH_8, + .hfi_id = HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + }, + { + .cap_id = RAP_FRAME, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + .hfi_id = HFI_PROP_DEC_START_FROM_RAP_FRAME, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, +}; + +static struct platform_inst_fw_cap inst_fw_cap_sm8550_enc[] = { + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_5_0, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_level, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_level, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROP_STAGE, + .set = iris_set_stage, + }, + { + .cap_id = HEADER_MODE, + .min = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .max = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + .value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .hfi_id = HFI_PROP_SEQ_HEADER_MODE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_header_mode_gen2, + }, + { + .cap_id = PREPEND_SPSPPS_TO_IDR, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + }, + { + .cap_id = BITRATE, + .min = 1, + .max = BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_bitrate, + }, + { + .cap_id = BITRATE_PEAK, + .min = 1, + .max = BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_PEAK_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_peak_bitrate, + }, + { + .cap_id = BITRATE_MODE, + .min = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + .value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .hfi_id = HFI_PROP_RATE_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_bitrate_mode_gen2, + }, + { + .cap_id = FRAME_SKIP_MODE, + .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + .value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = FRAME_RC_ENABLE, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + }, + { + .cap_id = GOP_SIZE, + .min = 0, + .max = INT_MAX, + .step_or_mask = 1, + .value = 2 * DEFAULT_FPS - 1, + .hfi_id = HFI_PROP_MAX_GOP_FRAMES, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_u32, + }, + { + .cap_id = ENTROPY_MODE, + .min = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .max = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + .value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .hfi_id = HFI_PROP_CABAC_SESSION, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_entropy_mode_gen2, + }, + { + .cap_id = MIN_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_min_qp, + }, + { + .cap_id = MIN_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_min_qp, + }, + { + .cap_id = MAX_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_max_qp, + }, + { + .cap_id = MAX_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_max_qp, + }, + { + .cap_id = I_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = I_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = P_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = P_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = B_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = B_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = INPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = OUTPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_u32, + }, +}; + +static struct platform_inst_caps platform_inst_cap_sm8550 = { + .min_frame_width = 96, + .max_frame_width = 8192, + .min_frame_height = 96, + .max_frame_height = 8192, + .max_mbpf = (8192 * 4352) / 256, + .mb_cycles_vpp = 200, + .mb_cycles_fw = 489583, + .mb_cycles_fw_vpp = 66234, + .num_comv = 0, + .max_frame_rate = MAXIMUM_FPS, + .max_operating_rate = MAXIMUM_FPS, +}; + +static void iris_set_sm8550_preset_registers(struct iris_core *core) +{ + writel(0x0, core->reg_base + 0xB0088); +} + +static const struct icc_info sm8550_icc_table[] = { + { "cpu-cfg", 1000, 1000 }, + { "video-mem", 1000, 15000000 }, +}; + +static const char * const sm8550_clk_reset_table[] = { "bus" }; + +static const struct bw_info sm8550_bw_table_dec[] = { + { ((4096 * 2160) / 256) * 60, 1608000 }, + { ((4096 * 2160) / 256) * 30, 826000 }, + { ((1920 * 1080) / 256) * 60, 567000 }, + { ((1920 * 1080) / 256) * 30, 294000 }, +}; + +static const char * const sm8550_pmdomain_table[] = { "venus", "vcodec0" }; + +static const char * const sm8550_opp_pd_table[] = { "mxc", "mmcx" }; + +static const struct platform_clk_data sm8550_clk_table[] = { + {IRIS_AXI_CLK, "iface" }, + {IRIS_CTRL_CLK, "core" }, + {IRIS_HW_CLK, "vcodec0_core" }, +}; + +static struct ubwc_config_data ubwc_config_sm8550 = { + .max_channels = 8, + .mal_length = 32, + .highest_bank_bit = 16, + .bank_swzl_level = 0, + .bank_swz2_level = 1, + .bank_swz3_level = 1, + .bank_spreading = 1, +}; + +static struct tz_cp_config tz_cp_config_sm8550 = { + .cp_start = 0, + .cp_size = 0x25800000, + .cp_nonpixel_start = 0x01000000, + .cp_nonpixel_size = 0x24800000, +}; + +static const u32 sm8550_vdec_input_config_params_default[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_CODED_FRAMES, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PIC_ORDER_CNT_TYPE, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + +static const u32 sm8550_vdec_input_config_param_hevc[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_TIER, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + +static const u32 sm8550_vdec_input_config_param_vp9[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, +}; + +static const u32 sm8550_venc_input_config_params[] = { + HFI_PROP_COLOR_FORMAT, + HFI_PROP_RAW_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LINEAR_STRIDE_SCANLINE, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + +static const u32 sm8550_vdec_output_config_params[] = { + HFI_PROP_COLOR_FORMAT, + HFI_PROP_LINEAR_STRIDE_SCANLINE, +}; + +static const u32 sm8550_venc_output_config_params[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_FRAME_RATE, +}; + +static const u32 sm8550_vdec_subscribe_input_properties[] = { + HFI_PROP_NO_OUTPUT, +}; + +static const u32 sm8550_vdec_subscribe_output_properties_avc[] = { + HFI_PROP_PICTURE_TYPE, + HFI_PROP_CABAC_SESSION, +}; + +static const u32 sm8550_vdec_subscribe_output_properties_hevc[] = { + HFI_PROP_PICTURE_TYPE, +}; + +static const u32 sm8550_vdec_subscribe_output_properties_vp9[] = { + HFI_PROP_PICTURE_TYPE, +}; + +static const u32 sm8550_dec_ip_int_buf_tbl[] = { + BUF_BIN, + BUF_COMV, + BUF_NON_COMV, + BUF_LINE, +}; + +static const u32 sm8550_dec_op_int_buf_tbl[] = { + BUF_DPB, +}; + +static const u32 sm8550_enc_op_int_buf_tbl[] = { + BUF_BIN, + BUF_COMV, + BUF_NON_COMV, + BUF_LINE, + BUF_SCRATCH_2, +}; + +struct iris_platform_data sm8550_data = { + .get_instance = iris_hfi_gen2_get_instance, + .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, + .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .vpu_ops = &iris_vpu3_ops, + .set_preset_registers = iris_set_sm8550_preset_registers, + .icc_tbl = sm8550_icc_table, + .icc_tbl_size = ARRAY_SIZE(sm8550_icc_table), + .clk_rst_tbl = sm8550_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(sm8550_clk_reset_table), + .bw_tbl_dec = sm8550_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sm8550_bw_table_dec), + .pmdomain_tbl = sm8550_pmdomain_table, + .pmdomain_tbl_size = ARRAY_SIZE(sm8550_pmdomain_table), + .opp_pd_tbl = sm8550_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table), + .clk_tbl = sm8550_clk_table, + .clk_tbl_size = ARRAY_SIZE(sm8550_clk_table), + /* Upper bound of DMA address range */ + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/vpu/vpu30_p4.mbn", + .pas_id = IRIS_PAS_ID, + .inst_caps = &platform_inst_cap_sm8550, + .inst_fw_caps_dec = inst_fw_cap_sm8550_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), + .tz_cp_config_data = &tz_cp_config_sm8550, + .core_arch = VIDEO_ARCH_LX, + .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, + .ubwc_config = &ubwc_config_sm8550, + .num_vpp_pipe = 4, + .max_session_count = 16, + .max_core_mbpf = NUM_MBS_8K * 2, + .max_core_mbps = ((7680 * 4320) / 256) * 60, + .dec_input_config_params_default = + sm8550_vdec_input_config_params_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8550_vdec_input_config_params_default), + .dec_input_config_params_hevc = + sm8550_vdec_input_config_param_hevc, + .dec_input_config_params_hevc_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), + .dec_input_config_params_vp9 = + sm8550_vdec_input_config_param_vp9, + .dec_input_config_params_vp9_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), + .dec_output_config_params = + sm8550_vdec_output_config_params, + .dec_output_config_params_size = + ARRAY_SIZE(sm8550_vdec_output_config_params), + + .enc_input_config_params = + sm8550_venc_input_config_params, + .enc_input_config_params_size = + ARRAY_SIZE(sm8550_venc_input_config_params), + .enc_output_config_params = + sm8550_venc_output_config_params, + .enc_output_config_params_size = + ARRAY_SIZE(sm8550_venc_output_config_params), + + .dec_input_prop = sm8550_vdec_subscribe_input_properties, + .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, + .dec_output_prop_avc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc), + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc, + .dec_output_prop_hevc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc), + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9, + .dec_output_prop_vp9_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9), + + .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), +}; + +/* + * Shares most of SM8550 data except: + * - vpu_ops to iris_vpu33_ops + * - clk_rst_tbl to sm8650_clk_reset_table + * - controller_rst_tbl to sm8650_controller_reset_table + * - fwname to "qcom/vpu/vpu33_p4.mbn" + */ +struct iris_platform_data sm8650_data = { + .get_instance = iris_hfi_gen2_get_instance, + .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, + .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .vpu_ops = &iris_vpu33_ops, + .set_preset_registers = iris_set_sm8550_preset_registers, + .icc_tbl = sm8550_icc_table, + .icc_tbl_size = ARRAY_SIZE(sm8550_icc_table), + .clk_rst_tbl = sm8650_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(sm8650_clk_reset_table), + .controller_rst_tbl = sm8650_controller_reset_table, + .controller_rst_tbl_size = ARRAY_SIZE(sm8650_controller_reset_table), + .bw_tbl_dec = sm8550_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sm8550_bw_table_dec), + .pmdomain_tbl = sm8550_pmdomain_table, + .pmdomain_tbl_size = ARRAY_SIZE(sm8550_pmdomain_table), + .opp_pd_tbl = sm8550_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table), + .clk_tbl = sm8550_clk_table, + .clk_tbl_size = ARRAY_SIZE(sm8550_clk_table), + /* Upper bound of DMA address range */ + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/vpu/vpu33_p4.mbn", + .pas_id = IRIS_PAS_ID, + .inst_caps = &platform_inst_cap_sm8550, + .inst_fw_caps_dec = inst_fw_cap_sm8550_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), + .tz_cp_config_data = &tz_cp_config_sm8550, + .core_arch = VIDEO_ARCH_LX, + .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, + .ubwc_config = &ubwc_config_sm8550, + .num_vpp_pipe = 4, + .max_session_count = 16, + .max_core_mbpf = NUM_MBS_8K * 2, + .max_core_mbps = ((7680 * 4320) / 256) * 60, + .dec_input_config_params_default = + sm8550_vdec_input_config_params_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8550_vdec_input_config_params_default), + .dec_input_config_params_hevc = + sm8550_vdec_input_config_param_hevc, + .dec_input_config_params_hevc_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), + .dec_input_config_params_vp9 = + sm8550_vdec_input_config_param_vp9, + .dec_input_config_params_vp9_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), + .dec_output_config_params = + sm8550_vdec_output_config_params, + .dec_output_config_params_size = + ARRAY_SIZE(sm8550_vdec_output_config_params), + + .enc_input_config_params = + sm8550_venc_input_config_params, + .enc_input_config_params_size = + ARRAY_SIZE(sm8550_venc_input_config_params), + .enc_output_config_params = + sm8550_venc_output_config_params, + .enc_output_config_params_size = + ARRAY_SIZE(sm8550_venc_output_config_params), + + .dec_input_prop = sm8550_vdec_subscribe_input_properties, + .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, + .dec_output_prop_avc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc), + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc, + .dec_output_prop_hevc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc), + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9, + .dec_output_prop_vp9_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9), + + .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), +}; + +/* + * Shares most of SM8550 data except: + * - inst_caps to platform_inst_cap_qcs8300 + * - inst_fw_caps to inst_fw_cap_qcs8300 + */ +struct iris_platform_data qcs8300_data = { + .get_instance = iris_hfi_gen2_get_instance, + .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, + .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .vpu_ops = &iris_vpu3_ops, + .set_preset_registers = iris_set_sm8550_preset_registers, + .icc_tbl = sm8550_icc_table, + .icc_tbl_size = ARRAY_SIZE(sm8550_icc_table), + .clk_rst_tbl = sm8550_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(sm8550_clk_reset_table), + .bw_tbl_dec = sm8550_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sm8550_bw_table_dec), + .pmdomain_tbl = sm8550_pmdomain_table, + .pmdomain_tbl_size = ARRAY_SIZE(sm8550_pmdomain_table), + .opp_pd_tbl = sm8550_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table), + .clk_tbl = sm8550_clk_table, + .clk_tbl_size = ARRAY_SIZE(sm8550_clk_table), + /* Upper bound of DMA address range */ + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/vpu/vpu30_p4_s6.mbn", + .pas_id = IRIS_PAS_ID, + .inst_caps = &platform_inst_cap_qcs8300, + .inst_fw_caps_dec = inst_fw_cap_qcs8300_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_qcs8300_dec), + .inst_fw_caps_enc = inst_fw_cap_qcs8300_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_qcs8300_enc), + .tz_cp_config_data = &tz_cp_config_sm8550, + .core_arch = VIDEO_ARCH_LX, + .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, + .ubwc_config = &ubwc_config_sm8550, + .num_vpp_pipe = 2, + .max_session_count = 16, + .max_core_mbpf = ((4096 * 2176) / 256) * 4, + .max_core_mbps = (((3840 * 2176) / 256) * 120), + .dec_input_config_params_default = + sm8550_vdec_input_config_params_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8550_vdec_input_config_params_default), + .dec_input_config_params_hevc = + sm8550_vdec_input_config_param_hevc, + .dec_input_config_params_hevc_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), + .dec_input_config_params_vp9 = + sm8550_vdec_input_config_param_vp9, + .dec_input_config_params_vp9_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), + .dec_output_config_params = + sm8550_vdec_output_config_params, + .dec_output_config_params_size = + ARRAY_SIZE(sm8550_vdec_output_config_params), + + .enc_input_config_params = + sm8550_venc_input_config_params, + .enc_input_config_params_size = + ARRAY_SIZE(sm8550_venc_input_config_params), + .enc_output_config_params = + sm8550_venc_output_config_params, + .enc_output_config_params_size = + ARRAY_SIZE(sm8550_venc_output_config_params), + + .dec_input_prop = sm8550_vdec_subscribe_input_properties, + .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, + .dec_output_prop_avc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc), + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc, + .dec_output_prop_hevc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc), + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9, + .dec_output_prop_vp9_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9), + + .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), +}; diff --git a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h index 3cfecae80d1e..35ea0efade73 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h +++ b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h @@ -3,8 +3,537 @@ * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ -#ifndef __IRIS_PLATFORM_QCS8300_H__ -#define __IRIS_PLATFORM_QCS8300_H__ +#define BITRATE_MAX 245000000 + +static struct platform_inst_fw_cap inst_fw_cap_qcs8300_dec[] = { + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = PROFILE_VP9, + .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + .value = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_6_1, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_VP9, + .min = V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0), + .value = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = TIER, + .min = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + .value = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .hfi_id = HFI_PROP_TIER, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = INPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROP_STAGE, + .set = iris_set_stage, + }, + { + .cap_id = PIPE, + .min = PIPE_1, + .max = PIPE_2, + .step_or_mask = 1, + .value = PIPE_2, + .hfi_id = HFI_PROP_PIPE, + .set = iris_set_pipe, + }, + { + .cap_id = POC, + .min = 0, + .max = 2, + .step_or_mask = 1, + .value = 1, + .hfi_id = HFI_PROP_PIC_ORDER_CNT_TYPE, + }, + { + .cap_id = CODED_FRAMES, + .min = CODED_FRAMES_PROGRESSIVE, + .max = CODED_FRAMES_PROGRESSIVE, + .step_or_mask = 0, + .value = CODED_FRAMES_PROGRESSIVE, + .hfi_id = HFI_PROP_CODED_FRAMES, + }, + { + .cap_id = BIT_DEPTH, + .min = BIT_DEPTH_8, + .max = BIT_DEPTH_8, + .step_or_mask = 1, + .value = BIT_DEPTH_8, + .hfi_id = HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + }, + { + .cap_id = RAP_FRAME, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + .hfi_id = HFI_PROP_DEC_START_FROM_RAP_FRAME, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, +}; + +static struct platform_inst_fw_cap inst_fw_cap_qcs8300_enc[] = { + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_5_0, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROP_STAGE, + }, + { + .cap_id = HEADER_MODE, + .min = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .max = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + .value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .hfi_id = HFI_PROP_SEQ_HEADER_MODE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = PREPEND_SPSPPS_TO_IDR, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + }, + { + .cap_id = BITRATE, + .min = 1, + .max = BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = BITRATE_PEAK, + .min = 1, + .max = BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_PEAK_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = BITRATE_MODE, + .min = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + .value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .hfi_id = HFI_PROP_RATE_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = FRAME_SKIP_MODE, + .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + .value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = FRAME_RC_ENABLE, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + }, + { + .cap_id = GOP_SIZE, + .min = 0, + .max = INT_MAX, + .step_or_mask = 1, + .value = 2 * DEFAULT_FPS - 1, + .hfi_id = HFI_PROP_MAX_GOP_FRAMES, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = ENTROPY_MODE, + .min = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .max = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + .value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .hfi_id = HFI_PROP_CABAC_SESSION, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = MIN_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + }, + { + .cap_id = MIN_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + }, + { + .cap_id = MAX_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + }, + { + .cap_id = MAX_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + }, + { + .cap_id = I_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = I_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = P_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = P_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = B_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = B_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, +}; static struct platform_inst_caps platform_inst_cap_qcs8300 = { .min_frame_width = 96, @@ -15,8 +544,7 @@ static struct platform_inst_caps platform_inst_cap_qcs8300 = { .mb_cycles_vpp = 200, .mb_cycles_fw = 326389, .mb_cycles_fw_vpp = 44156, + .num_comv = 0, .max_frame_rate = MAXIMUM_FPS, .max_operating_rate = MAXIMUM_FPS, }; - -#endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8250.c b/drivers/media/platform/qcom/iris/iris_platform_sm8250.c new file mode 100644 index 000000000000..6c40d20c67ea --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8250.c @@ -0,0 +1,483 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "iris_core.h" +#include "iris_ctrls.h" +#include "iris_platform_common.h" +#include "iris_resources.h" +#include "iris_hfi_gen1.h" +#include "iris_hfi_gen1_defines.h" +#include "iris_vpu_common.h" + +#define BITRATE_MIN 32000 +#define BITRATE_MAX 160000000 +#define BITRATE_PEAK_DEFAULT (BITRATE_DEFAULT * 2) +#define BITRATE_STEP 100 + +#define SM8150_MAX_CORE_MBPS (((3840 * 2176) / 256) * 120) + +static struct platform_inst_fw_cap inst_fw_cap_sm8250_dec[] = { + { + .cap_id = PIPE, + .min = PIPE_1, + .max = PIPE_4, + .step_or_mask = 1, + .value = PIPE_4, + .hfi_id = HFI_PROPERTY_PARAM_WORK_ROUTE, + .set = iris_set_pipe, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROPERTY_PARAM_WORK_MODE, + .set = iris_set_stage, + }, +}; + +static struct platform_inst_fw_cap inst_fw_cap_sm8150_dec[] = { + { + .cap_id = PIPE, + .min = PIPE_1, + .max = PIPE_2, + .step_or_mask = 1, + .value = PIPE_2, + .hfi_id = HFI_PROPERTY_PARAM_WORK_ROUTE, + .set = iris_set_pipe, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROPERTY_PARAM_WORK_MODE, + .set = iris_set_stage, + }, +}; + +static struct platform_inst_fw_cap inst_fw_cap_sm8250_enc[] = { + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROPERTY_PARAM_WORK_MODE, + .set = iris_set_stage, + }, + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile_level_gen1, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile_level_gen1, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile_level_gen1, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile_level_gen1, + }, + { + .cap_id = HEADER_MODE, + .min = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .max = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + .value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .hfi_id = HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_header_mode_gen1, + }, + { + .cap_id = BITRATE, + .min = BITRATE_MIN, + .max = BITRATE_MAX, + .step_or_mask = BITRATE_STEP, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_bitrate, + }, + { + .cap_id = BITRATE_MODE, + .min = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + .value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .hfi_id = HFI_PROPERTY_PARAM_VENC_RATE_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_bitrate_mode_gen1, + }, + { + .cap_id = FRAME_SKIP_MODE, + .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + .value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = FRAME_RC_ENABLE, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + }, + { + .cap_id = GOP_SIZE, + .min = 0, + .max = (1 << 16) - 1, + .step_or_mask = 1, + .value = 30, + .hfi_id = HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD, + .set = iris_set_gop_size_gen1, + }, + { + .cap_id = ENTROPY_MODE, + .min = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .max = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + .value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .hfi_id = HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_entropy_mode_gen1, + }, + { + .cap_id = MIN_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_qp_range, + }, + { + .cap_id = MIN_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP_HEVC, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_qp_range, + }, + { + .cap_id = MAX_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_qp_range, + }, + { + .cap_id = MAX_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP_HEVC, + .step_or_mask = 1, + .value = MAX_QP_HEVC, + .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_qp_range, + }, +}; + +static struct platform_inst_caps platform_inst_cap_sm8250 = { + .min_frame_width = 128, + .max_frame_width = 8192, + .min_frame_height = 128, + .max_frame_height = 8192, + .max_mbpf = 138240, + .mb_cycles_vsp = 25, + .mb_cycles_vpp = 200, + .max_frame_rate = MAXIMUM_FPS, + .max_operating_rate = MAXIMUM_FPS, +}; + +static struct platform_inst_caps platform_inst_cap_sm8150 = { + .min_frame_width = 128, + .max_frame_width = 8192, + .min_frame_height = 128, + .max_frame_height = 8192, + .max_mbpf = 138240, + .mb_cycles_vsp = 10, + .mb_cycles_vpp = 200, + .max_frame_rate = MAXIMUM_FPS, + .max_operating_rate = MAXIMUM_FPS, +}; + +static void iris_set_sm8250_preset_registers(struct iris_core *core) +{ + writel(0x0, core->reg_base + 0xB0088); +} + +static void iris_set_sm8150_preset_registers(struct iris_core *core) +{ + /* + * Iris1 requires both controller clock-gating registers to be cleared + * after the clocks are enabled. This is the sequence used by the + * Qualcomm SM8150 downstream driver and the legacy Venus driver. + */ + writel(0, core->reg_base + 0xE2010); + writel(0, core->reg_base + 0xE2000); +} + +static const struct icc_info sm8250_icc_table[] = { + { "cpu-cfg", 1000, 1000 }, + { "video-mem", 1000, 15000000 }, +}; + +static const char * const sm8250_clk_reset_table[] = { "bus", "core" }; +static const char * const sm8150_clk_reset_table[] = { + "bus", "core", "vcodec0_bus", "vcodec1_bus" +}; + +static const struct bw_info sm8250_bw_table_dec[] = { + { ((4096 * 2160) / 256) * 60, 2403000 }, + { ((4096 * 2160) / 256) * 30, 1224000 }, + { ((1920 * 1080) / 256) * 60, 812000 }, + { ((1920 * 1080) / 256) * 30, 416000 }, +}; + +static const char * const sm8250_pmdomain_table[] = { "venus", "vcodec0" }; +static const char * const sm8150_pmdomain_table[] = { + "venus", "vcodec0", "vcodec1" +}; + +static const char * const sm8250_opp_pd_table[] = { "mx" }; +static const char * const sm8150_opp_pd_table[] = { "cx" }; + +static const struct platform_clk_data sm8250_clk_table[] = { + {IRIS_AXI_CLK, "iface" }, + {IRIS_CTRL_CLK, "core" }, + {IRIS_HW_CLK, "vcodec0_core" }, +}; + +static const struct platform_clk_data sm8150_clk_table[] = { + {IRIS_AXI_CLK, "iface" }, + {IRIS_BUS_CLK, "bus" }, + {IRIS_CTRL_CLK, "core" }, + {IRIS_HW_AXI_CLK, "vcodec0_bus" }, + {IRIS_HW_CLK, "vcodec0_core" }, + {IRIS_AUX_HW_AXI_CLK, "vcodec1_bus" }, + {IRIS_AUX_HW_CLK, "vcodec1_core" }, +}; + +static struct tz_cp_config tz_cp_config_sm8250 = { + .cp_start = 0, + .cp_size = 0x25800000, + .cp_nonpixel_start = 0x01000000, + .cp_nonpixel_size = 0x24800000, +}; + +static const u32 sm8250_vdec_input_config_param_default[] = { + HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE, + HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT, + HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO, + HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL, + HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM, + HFI_PROPERTY_PARAM_FRAME_SIZE, + HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL, + HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE, +}; + +static const u32 sm8250_venc_input_config_param[] = { + HFI_PROPERTY_CONFIG_FRAME_RATE, + HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO, + HFI_PROPERTY_PARAM_FRAME_SIZE, + HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT, + HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL, +}; + +static const u32 sm8250_dec_ip_int_buf_tbl[] = { + BUF_BIN, + BUF_SCRATCH_1, +}; + +static const u32 sm8250_dec_op_int_buf_tbl[] = { + BUF_DPB, +}; + +static const u32 sm8250_enc_ip_int_buf_tbl[] = { + BUF_BIN, + BUF_SCRATCH_1, + BUF_SCRATCH_2, +}; + +struct iris_platform_data sm8250_data = { + .get_instance = iris_hfi_gen1_get_instance, + .init_hfi_command_ops = &iris_hfi_gen1_command_ops_init, + .init_hfi_response_ops = iris_hfi_gen1_response_ops_init, + .vpu_ops = &iris_vpu2_ops, + .set_preset_registers = iris_set_sm8250_preset_registers, + .icc_tbl = sm8250_icc_table, + .icc_tbl_size = ARRAY_SIZE(sm8250_icc_table), + .clk_rst_tbl = sm8250_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(sm8250_clk_reset_table), + .bw_tbl_dec = sm8250_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sm8250_bw_table_dec), + .pmdomain_tbl = sm8250_pmdomain_table, + .pmdomain_tbl_size = ARRAY_SIZE(sm8250_pmdomain_table), + .opp_pd_tbl = sm8250_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(sm8250_opp_pd_table), + .clk_tbl = sm8250_clk_table, + .clk_tbl_size = ARRAY_SIZE(sm8250_clk_table), + /* Upper bound of DMA address range */ + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/vpu-1.0/venus.mbn", + .pas_id = IRIS_PAS_ID, + .inst_caps = &platform_inst_cap_sm8250, + .inst_fw_caps_dec = inst_fw_cap_sm8250_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8250_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8250_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8250_enc), + .tz_cp_config_data = &tz_cp_config_sm8250, + .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, + .num_vpp_pipe = 4, + .max_session_count = 16, + .max_core_mbpf = NUM_MBS_8K, + .max_core_mbps = ((7680 * 4320) / 256) * 60, + .dec_input_config_params_default = + sm8250_vdec_input_config_param_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8250_vdec_input_config_param_default), + .enc_input_config_params = sm8250_venc_input_config_param, + .enc_input_config_params_size = + ARRAY_SIZE(sm8250_venc_input_config_param), + + .dec_ip_int_buf_tbl = sm8250_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8250_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_op_int_buf_tbl), + + .enc_ip_int_buf_tbl = sm8250_enc_ip_int_buf_tbl, + .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_enc_ip_int_buf_tbl), +}; + +/* + * SM8150 uses HFI Gen1 with the legacy VPU5 register layout, has two VPP + * pipes and votes the CX performance domain. The nabu DT supplies its + * board firmware path through firmware-name. + */ +struct iris_platform_data sm8150_data = { + .get_instance = iris_hfi_gen1_get_instance, + .init_hfi_command_ops = &iris_hfi_gen1_command_ops_init, + .init_hfi_response_ops = iris_hfi_gen1_response_ops_init, + .vpu_ops = &iris_vpu2_ops, + .set_preset_registers = iris_set_sm8150_preset_registers, + .icc_tbl = sm8250_icc_table, + .icc_tbl_size = ARRAY_SIZE(sm8250_icc_table), + .clk_rst_tbl = sm8150_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(sm8150_clk_reset_table), + .bw_tbl_dec = sm8250_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sm8250_bw_table_dec), + .pmdomain_tbl = sm8150_pmdomain_table, + .pmdomain_tbl_size = ARRAY_SIZE(sm8150_pmdomain_table), + .opp_pd_tbl = sm8150_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(sm8150_opp_pd_table), + .clk_tbl = sm8150_clk_table, + .clk_tbl_size = ARRAY_SIZE(sm8150_clk_table), + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/sm8150/xiaomi/nabu/venus.mbn", + .pas_id = IRIS_PAS_ID, + .inst_caps = &platform_inst_cap_sm8150, + .inst_fw_caps_dec = inst_fw_cap_sm8150_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8150_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8250_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8250_enc), + .tz_cp_config_data = &tz_cp_config_sm8250, + .use_vcodec_hw_control = true, + .defer_vcodec_power = true, + .legacy_vpu5 = true, + .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, + .num_vpp_pipe = 2, + .max_session_count = 16, + .max_core_mbpf = NUM_MBS_8K, + .max_core_mbps = SM8150_MAX_CORE_MBPS, + .dec_input_config_params_default = + sm8250_vdec_input_config_param_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8250_vdec_input_config_param_default), + .enc_input_config_params = sm8250_venc_input_config_param, + .enc_input_config_params_size = + ARRAY_SIZE(sm8250_venc_input_config_param), + .dec_ip_int_buf_tbl = sm8250_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8250_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_op_int_buf_tbl), + .enc_ip_int_buf_tbl = sm8250_enc_ip_int_buf_tbl, + .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_enc_ip_int_buf_tbl), +}; diff --git a/drivers/media/platform/qcom/iris/iris_power.c b/drivers/media/platform/qcom/iris/iris_power.c index 91aa21d4070e..b8d45ff4024f 100644 --- a/drivers/media/platform/qcom/iris/iris_power.c +++ b/drivers/media/platform/qcom/iris/iris_power.c @@ -13,6 +13,11 @@ #include "iris_resources.h" #include "iris_vpu_common.h" +u32 iris_get_operating_fps(struct iris_inst *inst) +{ + return inst->frame_rate ?: DEFAULT_FPS; +} + static u32 iris_calc_bw(struct iris_inst *inst, struct icc_vote_data *data) { const struct bw_info *bw_tbl = NULL; @@ -46,9 +51,20 @@ static int iris_set_interconnects(struct iris_inst *inst) u64 total_bw_ddr = 0; int ret; + /* + * The legacy VPU5 RPMh path can stop completing active interconnect + * votes when several 4K sessions are running. iris_vpu_power_on() + * already establishes the maximum video-mem vote before firmware boot, + * so retain that vote until iris_vpu_power_off() removes it. Runtime + * scaling remains enabled for newer hardware. + */ + if (core->iris_platform_data->legacy_vpu5) + return 0; + mutex_lock(&core->lock); list_for_each_entry(instance, &core->instances, list) { - if (!instance->max_input_data_size) + if (!instance->hfi_session_opened || + !instance->max_input_data_size) continue; total_bw_ddr += instance->power.icc_bw; @@ -68,7 +84,7 @@ static int iris_vote_interconnects(struct iris_inst *inst) vote_data->width = inp_f->fmt.pix_mp.width; vote_data->height = inp_f->fmt.pix_mp.height; - vote_data->fps = DEFAULT_FPS; + vote_data->fps = iris_get_operating_fps(inst); inst->power.icc_bw = iris_calc_bw(inst, vote_data); @@ -82,16 +98,34 @@ static int iris_set_clocks(struct iris_inst *inst) u64 freq = 0; int ret; + /* + * iris_vpu_power_on() already selects the maximum OPP for legacy VPU5. + * Changing that OPP while VideoCC/MMCX is active can wedge the RPMh TCS, + * so keep it until iris_vpu_power_off() clears the vote. Newer hardware + * continues to use per-session runtime clock scaling. + */ + if (core->iris_platform_data->legacy_vpu5) + return 0; + mutex_lock(&core->lock); list_for_each_entry(instance, &core->instances, list) { - if (!instance->max_input_data_size) + if (!instance->hfi_session_opened || + !instance->max_input_data_size) continue; freq += instance->power.min_freq; } - core->power.clk_freq = freq; - ret = iris_opp_set_rate(core->dev, freq); + if (freq == core->power.clk_freq) { + ret = 0; + goto unlock; + } + + ret = dev_pm_opp_set_rate(core->dev, freq); + if (!ret) + core->power.clk_freq = freq; + +unlock: mutex_unlock(&core->lock); return ret; @@ -132,9 +166,33 @@ int iris_scale_power(struct iris_inst *inst) pm_runtime_put_autosuspend(core->dev); } + /* + * Legacy VPU5 holds the maximum OPP and interconnect vote for the whole + * power session, so per-qbuf clock/interconnect scaling is a no-op there + * (iris_set_clocks() and iris_set_interconnects() both return early). + * Skipping the per-qbuf input-buffer scan avoids an O(N) walk on every + * QBUF in the decode path. + */ + if (core->iris_platform_data->legacy_vpu5) + return 0; + ret = iris_scale_clocks(inst); if (ret) return ret; return iris_vote_interconnects(inst); } + +int iris_unvote_power(struct iris_inst *inst) +{ + int ret, ret2; + + inst->max_input_data_size = 0; + inst->power.min_freq = 0; + inst->power.icc_bw = 0; + + ret = iris_set_clocks(inst); + ret2 = iris_set_interconnects(inst); + + return ret ?: ret2; +} diff --git a/drivers/media/platform/qcom/iris/iris_power.h b/drivers/media/platform/qcom/iris/iris_power.h index 55212660e72d..fef96dc222d3 100644 --- a/drivers/media/platform/qcom/iris/iris_power.h +++ b/drivers/media/platform/qcom/iris/iris_power.h @@ -6,8 +6,12 @@ #ifndef __IRIS_POWER_H__ #define __IRIS_POWER_H__ +#include + struct iris_inst; +u32 iris_get_operating_fps(struct iris_inst *inst); int iris_scale_power(struct iris_inst *inst); +int iris_unvote_power(struct iris_inst *inst); #endif diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c index c2dcb50a2782..38946cad35ca 100644 --- a/drivers/media/platform/qcom/iris/iris_probe.c +++ b/drivers/media/platform/qcom/iris/iris_probe.c @@ -10,7 +10,6 @@ #include #include #include -#include #include "iris_core.h" #include "iris_ctrls.h" @@ -41,6 +40,8 @@ static int iris_init_icc(struct iris_core *core) static int iris_init_power_domains(struct iris_core *core) { + const struct platform_clk_data *clk_tbl; + u32 clk_cnt, i; int ret; struct dev_pm_domain_attach_data iris_pd_data = { @@ -55,29 +56,24 @@ static int iris_init_power_domains(struct iris_core *core) .pd_flags = PD_FLAG_DEV_LINK_ON | PD_FLAG_REQUIRED_OPP, }; - struct dev_pm_opp_config iris_opp_clk_data = { - .clk_names = core->iris_platform_data->opp_clk_tbl, - .config_clks = dev_pm_opp_config_clks_simple, - }; - ret = devm_pm_domain_attach_list(core->dev, &iris_pd_data, &core->pmdomain_tbl); if (ret < 0) return ret; ret = devm_pm_domain_attach_list(core->dev, &iris_opp_pd_data, &core->opp_pmdomain_tbl); - /* backwards compatibility for incomplete ABI SM8250 */ - if (ret == -ENODEV && - of_device_is_compatible(core->dev->of_node, "qcom,sm8250-venus")) { - iris_opp_pd_data.num_pd_names--; - ret = devm_pm_domain_attach_list(core->dev, &iris_opp_pd_data, - &core->opp_pmdomain_tbl); - } if (ret < 0) return ret; - ret = devm_pm_opp_set_config(core->dev, &iris_opp_clk_data); - if (ret) - return ret; + clk_tbl = core->iris_platform_data->clk_tbl; + clk_cnt = core->iris_platform_data->clk_tbl_size; + + for (i = 0; i < clk_cnt; i++) { + if (clk_tbl[i].clk_type == IRIS_HW_CLK) { + ret = devm_pm_opp_set_clkname(core->dev, clk_tbl[i].clk_name); + if (ret) + return ret; + } + } return devm_pm_opp_of_add_table(core->dev); } @@ -251,21 +247,17 @@ static int iris_probe(struct platform_device *pdev) return core->irq; core->iris_platform_data = of_device_get_match_data(core->dev); - core->iris_firmware_desc = core->iris_platform_data->firmware_desc; - core->iris_firmware_data = core->iris_firmware_desc->firmware_data; - - core->ubwc_cfg = qcom_ubwc_config_get_data(); - if (IS_ERR(core->ubwc_cfg)) - return PTR_ERR(core->ubwc_cfg); ret = devm_request_threaded_irq(core->dev, core->irq, iris_hfi_isr, - iris_hfi_isr_handler, - IRQF_TRIGGER_HIGH | IRQF_NO_AUTOEN, - "iris", core); + iris_hfi_isr_handler, IRQF_TRIGGER_HIGH, "iris", core); if (ret) return ret; + disable_irq_nosync(core->irq); + iris_init_ops(core); + core->iris_platform_data->init_hfi_command_ops(core); + core->iris_platform_data->init_hfi_response_ops(core); ret = iris_init_resources(core); if (ret) @@ -302,6 +294,16 @@ static int iris_probe(struct platform_device *pdev) if (ret) goto err_vdev_unreg_enc; + /* + * The legacy VPU5 power-collapse sequence is not implemented yet: + * iris_vpu_prepare_pc() deliberately returns -EAGAIN to keep the + * controller powered. Do not let runtime PM retry that unsupported + * transition after every autosuspend delay, since it creates a + * permanent workqueue/printk loop while the device is otherwise idle. + */ + if (core->iris_platform_data->legacy_vpu5) + pm_runtime_forbid(core->dev); + return 0; err_vdev_unreg_enc: @@ -364,14 +366,14 @@ static const struct of_device_id iris_dt_match[] = { .compatible = "qcom,qcs8300-iris", .data = &qcs8300_data, }, - { - .compatible = "qcom,sc7280-venus", - .data = &sc7280_data, - }, { .compatible = "qcom,sm8250-venus", .data = &sm8250_data, }, + { + .compatible = "qcom,sm8150-iris", + .data = &sm8150_data, + }, { .compatible = "qcom,sm8550-iris", .data = &sm8550_data, @@ -380,14 +382,6 @@ static const struct of_device_id iris_dt_match[] = { .compatible = "qcom,sm8650-iris", .data = &sm8650_data, }, - { - .compatible = "qcom,sm8750-iris", - .data = &sm8750_data, - }, - { - .compatible = "qcom,x1p42100-iris", - .data = &x1p42100_data, - }, { }, }; MODULE_DEVICE_TABLE(of, iris_dt_match); @@ -405,3 +399,4 @@ static struct platform_driver qcom_iris_driver = { module_platform_driver(qcom_iris_driver); MODULE_DESCRIPTION("Qualcomm iris video driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("DMA_BUF"); diff --git a/drivers/media/platform/qcom/iris/iris_resources.c b/drivers/media/platform/qcom/iris/iris_resources.c index 773f6548370a..8d8ddd398eea 100644 --- a/drivers/media/platform/qcom/iris/iris_resources.c +++ b/drivers/media/platform/qcom/iris/iris_resources.c @@ -20,6 +20,7 @@ int iris_set_icc_bw(struct iris_core *core, unsigned long icc_bw) { unsigned long bw_kbps = 0, bw_prev = 0; const struct icc_info *icc_tbl; + int video_mem_idx = -1; int ret = 0, i; icc_tbl = core->iris_platform_data->icc_tbl; @@ -32,17 +33,24 @@ int iris_set_icc_bw(struct iris_core *core, unsigned long icc_bw) bw_kbps = clamp_t(typeof(bw_kbps), bw_kbps, icc_tbl[i].bw_min_kbps, icc_tbl[i].bw_max_kbps); - if (abs(bw_kbps - bw_prev) < BW_THRESHOLD && bw_prev) + if (bw_prev && + (bw_kbps > bw_prev ? bw_kbps - bw_prev : + bw_prev - bw_kbps) < BW_THRESHOLD) return ret; core->icc_tbl[i].avg_bw = bw_kbps; - - core->power.icc_bw = bw_kbps; + video_mem_idx = i; break; } } - return icc_bulk_set_bw(core->icc_count, core->icc_tbl); + ret = icc_bulk_set_bw(core->icc_count, core->icc_tbl); + if (!ret && video_mem_idx >= 0) + core->power.icc_bw = bw_kbps; + else if (ret && video_mem_idx >= 0) + core->icc_tbl[video_mem_idx].avg_bw = bw_prev; + + return ret; } int iris_unset_icc_bw(struct iris_core *core) @@ -121,12 +129,18 @@ static struct clk *iris_get_clk_by_type(struct iris_core *core, enum platform_cl int iris_prepare_enable_clock(struct iris_core *core, enum platform_clk_type clk_type) { struct clk *clock; + int ret; clock = iris_get_clk_by_type(core, clk_type); if (!clock) return -ENOENT; - return clk_prepare_enable(clock); + ret = clk_prepare_enable(clock); + if (!ret) + dev_info(core->dev, "clock type %u enabled at %lu Hz\n", + clk_type, clk_get_rate(clock)); + + return ret; } int iris_disable_unprepare_clock(struct iris_core *core, enum platform_clk_type clk_type) diff --git a/drivers/media/platform/qcom/iris/iris_utils.c b/drivers/media/platform/qcom/iris/iris_utils.c index ba5c8dc1280c..2829508527fd 100644 --- a/drivers/media/platform/qcom/iris/iris_utils.c +++ b/drivers/media/platform/qcom/iris/iris_utils.c @@ -34,22 +34,10 @@ int iris_get_mbpf(struct iris_inst *inst) bool iris_split_mode_enabled(struct iris_inst *inst) { - return inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_NV12 || - inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC08C || - inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_P010 || - inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC10C; -} + u32 pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; -bool iris_fmt_is_8bit(u32 pixelformat) -{ return pixelformat == V4L2_PIX_FMT_NV12 || - pixelformat == V4L2_PIX_FMT_QC08C; -} - -bool iris_fmt_is_10bit(u32 pixelformat) -{ - return pixelformat == V4L2_PIX_FMT_P010 || - pixelformat == V4L2_PIX_FMT_QC10C; + pixelformat == V4L2_PIX_FMT_P010; } void iris_helper_buffers_done(struct iris_inst *inst, unsigned int type, @@ -69,13 +57,16 @@ void iris_helper_buffers_done(struct iris_inst *inst, unsigned int type, int iris_wait_for_session_response(struct iris_inst *inst, bool is_flush) { + struct iris_core *core = inst->core; + u32 hw_response_timeout_val; struct completion *done; int ret; + hw_response_timeout_val = core->iris_platform_data->hw_response_timeout; done = is_flush ? &inst->flush_completion : &inst->completion; mutex_unlock(&inst->lock); - ret = wait_for_completion_timeout(done, msecs_to_jiffies(HW_RESPONSE_TIMEOUT_VALUE)); + ret = wait_for_completion_timeout(done, msecs_to_jiffies(hw_response_timeout_val)); mutex_lock(&inst->lock); if (!ret) { iris_inst_change_state(inst, IRIS_INST_ERROR); @@ -108,8 +99,12 @@ int iris_check_core_mbpf(struct iris_inst *inst) u32 total_mbpf = 0; mutex_lock(&core->lock); - list_for_each_entry(instance, &core->instances, list) + list_for_each_entry(instance, &core->instances, list) { + if (instance != inst && !instance->hfi_session_opened) + continue; + total_mbpf += iris_get_mbpf(instance); + } mutex_unlock(&core->lock); if (total_mbpf > core->iris_platform_data->max_core_mbpf) @@ -126,6 +121,9 @@ int iris_check_core_mbps(struct iris_inst *inst) mutex_lock(&core->lock); list_for_each_entry(instance, &core->instances, list) { + if (instance != inst && !instance->hfi_session_opened) + continue; + fps = max(instance->frame_rate, instance->operating_rate); total_mbps += iris_get_mbpf(instance) * fps; } @@ -136,9 +134,3 @@ int iris_check_core_mbps(struct iris_inst *inst) return 0; } - -bool is_rotation_90_or_270(struct iris_inst *inst) -{ - return inst->fw_caps[ROTATION].value == 90 || - inst->fw_caps[ROTATION].value == 270; -} diff --git a/drivers/media/platform/qcom/iris/iris_utils.h b/drivers/media/platform/qcom/iris/iris_utils.h index 228a5f963812..75740181122f 100644 --- a/drivers/media/platform/qcom/iris/iris_utils.h +++ b/drivers/media/platform/qcom/iris/iris_utils.h @@ -45,14 +45,11 @@ bool iris_res_is_less_than(u32 width, u32 height, u32 ref_width, u32 ref_height); int iris_get_mbpf(struct iris_inst *inst); bool iris_split_mode_enabled(struct iris_inst *inst); -bool iris_fmt_is_8bit(u32 pixelformat); -bool iris_fmt_is_10bit(u32 pixelformat); struct iris_inst *iris_get_instance(struct iris_core *core, u32 session_id); void iris_helper_buffers_done(struct iris_inst *inst, unsigned int type, enum vb2_buffer_state state); int iris_wait_for_session_response(struct iris_inst *inst, bool is_flush); int iris_check_core_mbpf(struct iris_inst *inst); int iris_check_core_mbps(struct iris_inst *inst); -bool is_rotation_90_or_270(struct iris_inst *inst); #endif diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c index a2ea2d67f60d..a1067129f46d 100644 --- a/drivers/media/platform/qcom/iris/iris_vb2.c +++ b/drivers/media/platform/qcom/iris/iris_vb2.c @@ -3,6 +3,8 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include +#include #include #include #include @@ -14,6 +16,105 @@ #include "iris_venc.h" #include "iris_power.h" +/* + * On SM8150 Venus (VIDEO.IR.1.2) the firmware validates OUTPUT/OUTPUT2 + * (capture and split-mode DPB) IOVAs against an output-address boundary near + * the top of the non-secure aperture (~0xd0000000). The attached SMMU uses a + * single shared iommu-dma allocator that is top-down within [0, 0xdfffffff]. + * + * FFmpeg's m2m flow allocates the OUTPUT (bitstream) queue and the + * firmware-internal BIN/SCRATCH/PERSIST buffers before the CAPTURE queue and + * the internal DPBs. Those early allocations therefore consume the IOVAs + * the firmware requires for OUTPUT/OUTPUT2, pushing the later CAPTURE/DPB + * allocations down to 0xb/0xc... where the firmware rejects them. + * + * Reserve the high IOVA region with a throwaway placeholder allocation taken + * while the input side is set up, then release it right before the CAPTURE + * queue is allocated so the top-down allocator hands the freshly freed high + * region to the output buffers instead. This keeps the device DMA mask + * stable for the whole session, unlike the v80/v81 mask-toggling experiment. + */ +#define IRIS1_VP9_IOVA_HOLE_SIZE 0x04000000ULL /* 64 MiB placeholder */ + +static bool cached_capture; +module_param(cached_capture, bool, 0444); +MODULE_PARM_DESC(cached_capture, + "Use cacheable H.264/HEVC CAPTURE MMAP buffers on legacy Iris1"); + +static bool iris1_use_cached_capture(struct iris_inst *inst, + struct vb2_queue *q) +{ + return cached_capture && + inst->core->iris_platform_data->legacy_vpu5 && + (inst->codec == V4L2_PIX_FMT_H264 || + inst->codec == V4L2_PIX_FMT_HEVC) && + V4L2_TYPE_IS_CAPTURE(q->type) && + q->memory == VB2_MEMORY_MMAP; +} + +static bool iris1_vp9_needs_iova_hole(struct iris_inst *inst) +{ + return inst->core->iris_platform_data->legacy_vpu5 && + inst->codec == V4L2_PIX_FMT_VP9; +} + +int iris_vb2_vp9_alloc_high_iova_hole(struct iris_inst *inst) +{ + struct iris_core *core = inst->core; + size_t size = IRIS1_VP9_IOVA_HOLE_SIZE; + dma_addr_t daddr; + void *vaddr; + + if (!iris1_vp9_needs_iova_hole(inst) || inst->vp9_iova_hole_size) + return 0; + + vaddr = dma_alloc_attrs(core->dev, size, &daddr, GFP_KERNEL, + DMA_ATTR_WRITE_COMBINE); + if (!vaddr) { + dev_err(core->dev, + "Iris1 v85: VP9 IOVA hole alloc of %#zx failed\n", + size); + return -ENOMEM; + } + + inst->vp9_iova_hole_vaddr = vaddr; + inst->vp9_iova_hole_daddr = daddr; + inst->vp9_iova_hole_size = size; + + dev_info(core->dev, + "Iris1 v85: VP9 reserved high IOVA hole %#llx-%#llx (size %#zx)\n", + (unsigned long long)daddr, + (unsigned long long)daddr + size - 1, size); + + return 0; +} + +void iris_vb2_vp9_release_high_iova_hole(struct iris_inst *inst) +{ + struct iris_core *core = inst->core; + dma_addr_t daddr; + void *vaddr; + size_t size; + + if (!inst->vp9_iova_hole_size) + return; + + vaddr = inst->vp9_iova_hole_vaddr; + daddr = inst->vp9_iova_hole_daddr; + size = inst->vp9_iova_hole_size; + + inst->vp9_iova_hole_vaddr = NULL; + inst->vp9_iova_hole_daddr = 0; + inst->vp9_iova_hole_size = 0; + + dma_free_attrs(core->dev, size, vaddr, daddr, DMA_ATTR_WRITE_COMBINE); + + dev_info(core->dev, + "Iris1 v85: VP9 released high IOVA hole %#llx-%#llx\n", + (unsigned long long)daddr, + (unsigned long long)daddr + size - 1); +} + static int iris_check_inst_mbpf(struct iris_inst *inst) { struct platform_inst_caps *caps; @@ -56,10 +157,12 @@ static int iris_check_session_supported(struct iris_inst *inst) bool found = false; int ret; + mutex_lock(&core->lock); list_for_each_entry(instance, &core->instances, list) { if (instance == inst) found = true; } + mutex_unlock(&core->lock); if (!found) { ret = -EINVAL; @@ -102,12 +205,16 @@ int iris_vb2_queue_setup(struct vb2_queue *q, struct iris_inst *inst; struct iris_core *core; struct v4l2_format *f; + u32 admission_fps; int ret = 0; inst = vb2_get_drv_priv(q); mutex_lock(&inst->lock); if (inst->state == IRIS_INST_ERROR) { + dev_err_ratelimited(inst->core->dev, + "queue setup rejected: instance is in error state (queue type %u)\n", + q->type); ret = -EBUSY; goto unlock; } @@ -115,30 +222,76 @@ int iris_vb2_queue_setup(struct vb2_queue *q, core = inst->core; f = V4L2_TYPE_IS_OUTPUT(q->type) ? inst->fmt_src : inst->fmt_dst; + /* + * FFmpeg's v4l2m2m-copy path maps CAPTURE buffers into the CPU and + * uploads every decoded frame to the display API. Coherent DMA memory + * is expensive to read on SM8150, especially for 4K60 NV12. For this + * opt-in Iris1/H.264/HEVC path, allocate cacheable streaming DMA memory + * and let vb2_dma_contig perform the required post-DMA cache maintenance + * before each completed frame is returned to userspace. + * + * Keep this limited to MMAP: imported DMABUF ownership and cache policy + * belong to the exporter. VP9 is deliberately excluded because its IOVA + * placement work depends on the existing allocation lifecycle. + */ + if (iris1_use_cached_capture(inst, q)) { + q->dma_dir = DMA_FROM_DEVICE; + q->non_coherent_mem = true; + dev_info(core->dev, + "Iris1 v99: using cacheable %s CAPTURE MMAP buffers; dynamic power vote starts at %u fps\n", + inst->codec == V4L2_PIX_FMT_H264 ? "H.264" : "HEVC", + iris_get_operating_fps(inst)); + } + if (*num_planes) { if (*num_planes != f->fmt.pix_mp.num_planes || sizes[0] < f->fmt.pix_mp.plane_fmt[0].sizeimage) ret = -EINVAL; goto unlock; } + if (V4L2_TYPE_IS_CAPTURE(q->type) && inst->core_load_rejected) { + ret = -ENOMEM; + goto unlock; + } ret = iris_check_session_supported(inst); if (ret) goto unlock; - if (!inst->once_per_session_set) { - inst->once_per_session_set = true; + ret = iris_hfi_session_open(inst); + if (ret) { + dev_err(core->dev, "session open failed: %d\n", ret); + goto unlock; + } - ret = inst->hfi_session_ops->session_open(inst); + if (V4L2_TYPE_IS_CAPTURE(q->type) && !inst->core_load_reserved) { + if (inst->domain == DECODER) + admission_fps = iris_vdec_get_admission_fps(inst); + else + admission_fps = max(inst->frame_rate, + inst->operating_rate); + + ret = iris_reserve_core_load(inst, admission_fps); if (ret) { - ret = -EINVAL; - dev_err(core->dev, "session open failed\n"); + inst->core_load_rejected = true; goto unlock; } + } - ret = iris_inst_change_state(inst, IRIS_INST_INIT); + /* + * Hold the high IOVA region across input-side allocations so the + * top-down allocator returns high IOVAs to the CAPTURE/DPB buffers + * queued later. Allocate the placeholder when the OUTPUT queue is + * set up (before bitstream buffers are allocated) and release it on + * the first CAPTURE queue_setup so the released high region is the + * next IOVA handed out by the allocator. + */ + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + ret = iris_vb2_vp9_alloc_high_iova_hole(inst); if (ret) goto unlock; + } else if (V4L2_TYPE_IS_CAPTURE(q->type)) { + iris_vb2_vp9_release_high_iova_hole(inst); } *num_planes = 1; @@ -170,12 +323,16 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) goto error; } - iris_scale_power(inst); - ret = iris_check_session_supported(inst); if (ret) goto error; + ret = iris_hfi_session_open(inst); + if (ret) + goto error; + + iris_scale_power(inst); + if (V4L2_TYPE_IS_OUTPUT(q->type)) { if (inst->domain == DECODER) ret = iris_vdec_streamon_input(inst); @@ -187,8 +344,12 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) else ret = iris_venc_streamon_output(inst); } - if (ret) + if (ret) { + dev_err(inst->core->dev, + "Iris1 v119: start_streaming failed queue=%u count=%u state=%u ret=%d\n", + q->type, count, inst->state, ret); goto error; + } buf_type = iris_v4l2_type_to_driver(q->type); @@ -209,8 +370,12 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) } } - if (ret) + if (ret) { + dev_err(inst->core->dev, + "Iris1 v119: deferred buffer queue failed queue=%u count=%u state=%u ret=%d\n", + q->type, count, inst->state, ret); goto error; + } mutex_unlock(&inst->lock); @@ -231,10 +396,14 @@ void iris_vb2_stop_streaming(struct vb2_queue *q) inst = vb2_get_drv_priv(q); - if (V4L2_TYPE_IS_CAPTURE(q->type) && inst->state == IRIS_INST_INIT) + if (V4L2_TYPE_IS_CAPTURE(q->type) && inst->state == IRIS_INST_INIT) { + iris_release_core_load(inst); return; + } mutex_lock(&inst->lock); + if (inst->domain == DECODER && V4L2_TYPE_IS_CAPTURE(q->type)) + iris_vdec_clear_pending_output(inst); if (!V4L2_TYPE_IS_OUTPUT(q->type) && !V4L2_TYPE_IS_CAPTURE(q->type)) @@ -243,6 +412,8 @@ void iris_vb2_stop_streaming(struct vb2_queue *q) ret = iris_session_streamoff(inst, q->type); if (ret) goto exit; + if (V4L2_TYPE_IS_CAPTURE(q->type)) + iris_release_core_load(inst); exit: iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR); diff --git a/drivers/media/platform/qcom/iris/iris_vb2.h b/drivers/media/platform/qcom/iris/iris_vb2.h index a88565fdd3e4..a772e9aa6987 100644 --- a/drivers/media/platform/qcom/iris/iris_vb2.h +++ b/drivers/media/platform/qcom/iris/iris_vb2.h @@ -7,6 +7,8 @@ #define __IRIS_VB2_H__ int iris_vb2_buf_init(struct vb2_buffer *vb2); +int iris_vb2_vp9_alloc_high_iova_hole(struct iris_inst *inst); +void iris_vb2_vp9_release_high_iova_hole(struct iris_inst *inst); int iris_vb2_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], struct device *alloc_devs[]); diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c index 9e228b70420e..ab080da75aec 100644 --- a/drivers/media/platform/qcom/iris/iris_vdec.c +++ b/drivers/media/platform/qcom/iris/iris_vdec.c @@ -3,28 +3,179 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include #include #include #include "iris_buffer.h" #include "iris_common.h" #include "iris_ctrls.h" +#include "iris_hfi_gen1_defines.h" #include "iris_instance.h" #include "iris_power.h" +#include "iris_utils.h" +#include "iris_vb2.h" #include "iris_vdec.h" #include "iris_vpu_buffer.h" #define DEFAULT_CODEC_ALIGNMENT 16 +#define IRIS1_TIMESTAMP_DISCONTINUITY_NS NSEC_PER_SEC +#define IRIS1_SEEK_TIMESTAMP_WINDOW_NS (5ULL * NSEC_PER_SEC) +#define IRIS1_SEEK_HOLD_FRAMES 30 +#define IRIS1_MAX_4K_MBPF NUM_MBS_PER_FRAME(2176, 4096) + +static int iris_vdec_recycle_pending_output(struct iris_inst *inst) +{ + struct iris_buffer *buf = inst->pending_output; + + if (!buf) + return 0; + + inst->pending_output = NULL; + dev_info(inst->core->dev, + "Iris1 v138: recycling pending old-epoch output timestamp %llu ns\n", + buf->timestamp); + buf->data_size = 0; + buf->flags = 0; + buf->timestamp = 0; + buf->attr &= ~(BUF_ATTR_QUEUED | BUF_ATTR_DEQUEUED | + BUF_ATTR_BUFFER_DONE); + + return iris_queue_buffer(inst, buf); +} + +static void iris_vdec_reset_rate_window(struct iris_inst *inst) +{ + inst->last_buf_ns = 0; + inst->rate_min_timestamp = 0; + inst->rate_max_timestamp = 0; + inst->frame_counter = 0; +} + +u32 iris_vdec_get_admission_fps(struct iris_inst *inst) +{ + u64 timestamp_delta_ns; + u32 frame_rate; + + if (inst->frame_counter > 1 && + inst->rate_max_timestamp > inst->rate_min_timestamp) { + timestamp_delta_ns = inst->rate_max_timestamp - + inst->rate_min_timestamp; + frame_rate = DIV_ROUND_UP_ULL((u64)(inst->frame_counter - 1) * + NSEC_PER_SEC, + timestamp_delta_ns); + + return clamp_t(u32, frame_rate, 1, MAXIMUM_FPS); + } + + /* Preserve 8K30 while treating an unknown 4K stream as 60 fps. */ + if (iris_get_mbpf(inst) > IRIS1_MAX_4K_MBPF) + return 30; + + return 60; +} + +int iris_vdec_complete_pending_output(struct iris_inst *inst) +{ + struct iris_buffer *buf = inst->pending_output; + + if (!buf) + return 0; + + inst->pending_output = NULL; + + return iris_vb2_buffer_done(inst, buf); +} + +int iris_vdec_hold_output(struct iris_inst *inst, struct iris_buffer *buf) +{ + if (inst->pending_output) + return -EBUSY; + + inst->pending_output = buf; + + return 0; +} + +void iris_vdec_clear_pending_output(struct iris_inst *inst) +{ + inst->pending_output = NULL; +} + +static int iris_vdec_track_input_timestamp(struct iris_inst *inst, u64 timestamp) +{ + u64 delta; + int ret; + + if (!inst->core->iris_platform_data->legacy_vpu5) + return 0; + + if (inst->input_timestamp_valid) { + delta = timestamp > inst->last_input_timestamp ? + timestamp - inst->last_input_timestamp : + inst->last_input_timestamp - timestamp; + if (delta > IRIS1_TIMESTAMP_DISCONTINUITY_NS) { + iris_vdec_reset_rate_window(inst); + inst->seek_timestamp = timestamp; + inst->seek_timestamp_pending = true; + inst->seek_hold_frames = IRIS1_SEEK_HOLD_FRAMES; + dev_info(inst->core->dev, + "Iris1 v136: input timestamp discontinuity %llu -> %llu ns; filtering stale output\n", + inst->last_input_timestamp, timestamp); + ret = iris_vdec_recycle_pending_output(inst); + if (ret) + return ret; + } + } + + inst->last_input_timestamp = timestamp; + inst->input_timestamp_valid = true; + + return 0; +} + +bool iris_vdec_discard_stale_frame(struct iris_inst *inst, u64 timestamp) +{ + u64 delta; + + if (!inst->seek_timestamp_pending) + return false; + + /* + * A frame decoded from pre-seek input carries a timestamp strictly + * before the seek anchor even when it lands within the window, because + * the anchor is the first post-seek compressed-input timestamp. Accept + * only new-epoch frames at or after the anchor; anything older would be + * delivered after the seek and trigger an invalid old/new-epoch + * transition in the consumer. + */ + if (timestamp >= inst->seek_timestamp) { + delta = timestamp - inst->seek_timestamp; + if (delta <= IRIS1_SEEK_TIMESTAMP_WINDOW_NS) { + dev_info(inst->core->dev, + "Iris1 v136: output synchronized at %llu ns after seek anchor %llu ns\n", + timestamp, inst->seek_timestamp); + inst->seek_timestamp_pending = false; + return false; + } + } + + dev_info(inst->core->dev, + "Iris1 v136: recycling stale output timestamp %llu ns (seek anchor %llu ns)\n", + timestamp, inst->seek_timestamp); + + return true; +} int iris_vdec_inst_init(struct iris_inst *inst) { struct iris_core *core = inst->core; struct v4l2_format *f; - inst->fmt_src = kzalloc_obj(*inst->fmt_src); - inst->fmt_dst = kzalloc_obj(*inst->fmt_dst); + inst->fmt_src = kzalloc(sizeof(*inst->fmt_src), GFP_KERNEL); + inst->fmt_dst = kzalloc(sizeof(*inst->fmt_dst), GFP_KERNEL); - inst->fw_min_count = 0; + inst->fw_min_count = MIN_BUFFERS; f = inst->fmt_src; f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; @@ -54,6 +205,7 @@ int iris_vdec_inst_init(struct iris_inst *inst) f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); inst->buffers[BUF_OUTPUT].size = f->fmt.pix_mp.plane_fmt[0].sizeimage; + /* Start conservatively, then qbuf throughput updates this once a second. */ inst->frame_rate = MAXIMUM_FPS; memcpy(&inst->fw_caps[0], &core->inst_fw_caps_dec[0], @@ -62,79 +214,71 @@ int iris_vdec_inst_init(struct iris_inst *inst) return iris_ctrls_init(inst); } -static const u32 iris_vdec_formats_cap[] = { - [IRIS_FMT_NV12] = V4L2_PIX_FMT_NV12, - [IRIS_FMT_QC08C] = V4L2_PIX_FMT_QC08C, - [IRIS_FMT_TP10] = V4L2_PIX_FMT_P010, - [IRIS_FMT_QC10C] = V4L2_PIX_FMT_QC10C, +void iris_vdec_inst_deinit(struct iris_inst *inst) +{ + iris_vdec_clear_pending_output(inst); + iris_vb2_vp9_release_high_iova_hole(inst); + kfree(inst->fmt_dst); + kfree(inst->fmt_src); +} + +static const struct iris_fmt iris_vdec_formats[] = { + [IRIS_FMT_H264] = { + .pixfmt = V4L2_PIX_FMT_H264, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + [IRIS_FMT_HEVC] = { + .pixfmt = V4L2_PIX_FMT_HEVC, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + [IRIS_FMT_VP9] = { + .pixfmt = V4L2_PIX_FMT_VP9, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, }; -static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type) +static bool iris_vdec_p010_supported(struct iris_inst *inst) { - unsigned int size, i; - const u32 *fmt; + /* + * P010 is wired through the HFI Gen1 raw-format contract below. HFI + * Gen2 still advertises an 8-bit-only BIT_DEPTH capability. + */ + return !inst->core->iris_platform_data->core_arch; +} - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - fmt = inst->core->iris_platform_data->inst_iris_fmts; - size = inst->core->iris_platform_data->inst_iris_fmts_size; - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - fmt = iris_vdec_formats_cap; - size = ARRAY_SIZE(iris_vdec_formats_cap); - break; - default: - return false; - } +static const struct iris_fmt * +find_format(struct iris_inst *inst, u32 pixfmt, u32 type) +{ + unsigned int size = ARRAY_SIZE(iris_vdec_formats); + const struct iris_fmt *fmt = iris_vdec_formats; + unsigned int i; for (i = 0; i < size; i++) { - if (fmt[i] == pixfmt) + if (fmt[i].pixfmt == pixfmt) break; } - if (i == size) - return false; - - if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - if (iris_fmt_is_8bit(pixfmt) && - inst->fw_caps[BIT_DEPTH].value == BIT_DEPTH_10) - return false; - - if (iris_fmt_is_10bit(pixfmt) && - inst->fw_caps[BIT_DEPTH].value != BIT_DEPTH_10) - return false; - } + if (i == size || fmt[i].type != type) + return NULL; - return true; + return &fmt[i]; } -static u32 find_format_by_index(struct iris_inst *inst, u32 index, u32 type) +static const struct iris_fmt * +find_format_by_index(struct iris_inst *inst, u32 index, u32 type) { - unsigned int size; - const u32 *fmt; - - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - fmt = inst->core->iris_platform_data->inst_iris_fmts; - size = inst->core->iris_platform_data->inst_iris_fmts_size; - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - fmt = iris_vdec_formats_cap; - size = ARRAY_SIZE(iris_vdec_formats_cap); - break; - default: - return 0; - } + const struct iris_fmt *fmt = iris_vdec_formats; + unsigned int size = ARRAY_SIZE(iris_vdec_formats); - if (index >= size) - return 0; + if (index >= size || fmt[index].type != type) + return NULL; - return fmt[index]; + return &fmt[index]; } int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f) { - u32 fmt; + const struct iris_fmt *fmt; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: @@ -142,14 +286,16 @@ int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f) if (!fmt) return -EINVAL; - f->pixelformat = fmt; + f->pixelformat = fmt->pixfmt; f->flags = V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_DYN_RESOLUTION; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - fmt = find_format_by_index(inst, f->index, f->type); - if (!fmt) + if (f->index == 0) + f->pixelformat = V4L2_PIX_FMT_NV12; + else if (f->index == 1 && iris_vdec_p010_supported(inst)) + f->pixelformat = V4L2_PIX_FMT_P010; + else return -EINVAL; - f->pixelformat = fmt; break; default: return -EINVAL; @@ -162,15 +308,15 @@ int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; + const struct iris_fmt *fmt; struct v4l2_format *f_inst; struct vb2_queue *src_q; - bool supported; memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); - supported = check_format(inst, pixmp->pixelformat, f->type); + fmt = find_format(inst, pixmp->pixelformat, f->type); switch (f->type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (!supported) { + if (!fmt) { f_inst = inst->fmt_src; f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; f->fmt.pix_mp.height = f_inst->fmt.pix_mp.height; @@ -178,7 +324,9 @@ int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f) } break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (!supported) { + if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12 && + (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_P010 || + !iris_vdec_p010_supported(inst))) { f_inst = inst->fmt_dst; f->fmt.pix_mp.pixelformat = f_inst->fmt.pix_mp.pixelformat; f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; @@ -211,23 +359,17 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f) u32 codec_align; q = v4l2_m2m_get_vq(inst->m2m_ctx, f->type); + if (!q) + return -EINVAL; if (vb2_is_busy(q)) return -EBUSY; - /* Width and height are optional, so fall back to a valid placeholder - * resolution until the real one is decoded from the bitstream. - */ - if (f->fmt.pix_mp.width == 0 && f->fmt.pix_mp.height == 0) { - f->fmt.pix_mp.width = DEFAULT_WIDTH; - f->fmt.pix_mp.height = DEFAULT_HEIGHT; - } - iris_vdec_try_fmt(inst, f); switch (f->type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (!check_format(inst, f->fmt.pix_mp.pixelformat, f->type)) + if (!(find_format(inst, f->fmt.pix_mp.pixelformat, f->type))) return -EINVAL; fmt = inst->fmt_src; @@ -257,7 +399,12 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f) /* Update capture format based on new ip w/h */ output_fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128); output_fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32); - inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); + output_fmt->fmt.pix_mp.plane_fmt[0].bytesperline = + ALIGN(f->fmt.pix_mp.width * + (output_fmt->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_P010 ? 2 : 1), + 128); + output_fmt->fmt.pix_mp.plane_fmt[0].sizeimage = + iris_get_buffer_size(inst, BUF_OUTPUT); inst->buffers[BUF_OUTPUT].size = iris_get_buffer_size(inst, BUF_OUTPUT); inst->crop.left = 0; @@ -266,34 +413,19 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f) inst->crop.height = f->fmt.pix_mp.height; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (!check_format(inst, f->fmt.pix_mp.pixelformat, f->type)) - return -EINVAL; - fmt = inst->fmt_dst; fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12 && + (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_P010 || + !iris_vdec_p010_supported(inst))) + return -EINVAL; fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat; + fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128); + fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32); fmt->fmt.pix_mp.num_planes = 1; - switch (f->fmt.pix_mp.pixelformat) { - case V4L2_PIX_FMT_P010: - fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128); - fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32); - fmt->fmt.pix_mp.plane_fmt[0].bytesperline = - ALIGN(f->fmt.pix_mp.width * 2, 256); - break; - case V4L2_PIX_FMT_QC10C: - fmt->fmt.pix_mp.width = roundup(f->fmt.pix_mp.width, 192); - fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16); - fmt->fmt.pix_mp.plane_fmt[0].bytesperline = - ALIGN(f->fmt.pix_mp.width * 4 / 3, 256); - break; - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_QC08C: - fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128); - fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32); - fmt->fmt.pix_mp.plane_fmt[0].bytesperline = - ALIGN(f->fmt.pix_mp.width, 128); - break; - } + fmt->fmt.pix_mp.plane_fmt[0].bytesperline = + ALIGN(f->fmt.pix_mp.width * + (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_P010 ? 2 : 1), 128); fmt->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT); inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); inst->buffers[BUF_OUTPUT].size = fmt->fmt.pix_mp.plane_fmt[0].sizeimage; @@ -313,13 +445,17 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f) int iris_vdec_validate_format(struct iris_inst *inst, u32 pixelformat) { - bool supported; + const struct iris_fmt *fmt = NULL; - supported = check_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (!supported) - supported = check_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (pixelformat != V4L2_PIX_FMT_NV12 && + (pixelformat != V4L2_PIX_FMT_P010 || + !iris_vdec_p010_supported(inst))) { + fmt = find_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (!fmt) + return -EINVAL; + } - return supported ? 0 : -EINVAL; + return 0; } int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub) @@ -360,66 +496,126 @@ void iris_vdec_src_change(struct iris_inst *inst) int iris_vdec_streamon_input(struct iris_inst *inst) { + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 output_order = HFI_OUTPUT_ORDER_DECODE; int ret; + inst->streamoff_pending = false; + inst->input_timestamp_valid = false; + inst->seek_timestamp_pending = false; + inst->corrupt_output_drops = 0; + inst->pending_output = NULL; + inst->seek_hold_frames = 0; + inst->frame_rate = MAXIMUM_FPS; + inst->frame_rate_down_count = 0; + ret = iris_set_properties(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (ret) + if (ret) { + dev_err(inst->core->dev, + "Iris1 v119: input streamon set_properties failed: %d\n", ret); return ret; + } + + if (inst->core->iris_platform_data->legacy_vpu5 && + inst->display_delay_enable && !inst->display_delay) { + ret = hfi_ops->session_set_property(inst, + HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER, + HFI_HOST_FLAGS_NONE, HFI_PORT_BITSTREAM, + HFI_PAYLOAD_U32_ENUM, &output_order, + sizeof(output_order)); + if (ret) { + dev_err(inst->core->dev, + "Iris1: setting decode-order output failed: %d\n", + ret); + return ret; + } + } ret = iris_alloc_and_queue_persist_bufs(inst, BUF_PERSIST); - if (ret) + if (ret) { + dev_err(inst->core->dev, + "Iris1 v119: input streamon persist buffers failed: %d\n", ret); return ret; + } iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); ret = iris_destroy_dequeued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (ret) + if (ret) { + dev_err(inst->core->dev, + "Iris1 v119: input streamon destroy buffers failed: %d\n", ret); return ret; + } ret = iris_create_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (ret) + if (ret) { + dev_err(inst->core->dev, + "Iris1 v119: input streamon create buffers failed: %d\n", ret); return ret; + } ret = iris_queue_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (ret) + if (ret) { + dev_err(inst->core->dev, + "Iris1 v119: input streamon queue buffers failed: %d\n", ret); return ret; + } - inst->frame_counter = 0; + iris_vdec_reset_rate_window(inst); return iris_process_streamon_input(inst); } int iris_vdec_streamon_output(struct iris_inst *inst) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; int ret; + inst->streamoff_pending = false; + ret = hfi_ops->session_set_config_params(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (ret) + if (ret) { + dev_err(inst->core->dev, + "Iris1 v119: capture streamon config failed: %d\n", ret); return ret; + } iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); ret = iris_destroy_dequeued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (ret) + if (ret) { + dev_err(inst->core->dev, + "Iris1 v119: capture streamon destroy buffers failed: %d\n", ret); return ret; + } ret = iris_create_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (ret) + if (ret) { + dev_err(inst->core->dev, + "Iris1 v119: capture streamon create buffers failed: %d\n", ret); return ret; + } ret = iris_process_streamon_output(inst); - if (ret) + if (ret) { + dev_err(inst->core->dev, + "Iris1 v119: capture streamon process failed: %d\n", ret); goto error; + } ret = iris_queue_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (ret) + if (ret) { + dev_err(inst->core->dev, + "Iris1 v119: capture streamon queue buffers failed: %d\n", ret); goto error; + } return ret; error: + inst->start_streaming_rollback_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; iris_session_streamoff(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + inst->start_streaming_rollback_type = 0; return ret; } @@ -428,7 +624,8 @@ int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) { struct iris_buffer *buf = to_iris_buffer(vbuf); struct vb2_buffer *vb2 = &vbuf->vb2_buf; - u64 cur_buf_ns, delta_ns; + u64 cur_buf_ns, delta_ns, timestamp_delta_ns; + u32 measured_fps, qbuf_fps, timestamp_fps, target_fps; struct vb2_queue *q; int ret; @@ -445,19 +642,77 @@ int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) return 0; } + if (buf->type == BUF_INPUT) { + ret = iris_vdec_track_input_timestamp(inst, buf->timestamp); + if (ret) + return ret; + } + + /* + * QBUF arrival can be bursty and, once the decoder or the consumer is + * under-provisioned, can be limited by CAPTURE backpressure. Using only + * that arrival rate creates a feedback loop: a 60 fps stream that falls + * behind is measured below 60 fps and receives an even lower power vote. + * + * Measure both wall-clock QBUF turnover and the coded timestamp span. + * Min/max timestamps tolerate normal B-frame reordering, and taking the + * larger estimate keeps a temporarily backpressured stream at its coded + * rate. Start every stream at the maximum vote and retain the existing + * hysteresis for sustained reductions. + */ if (buf->type == BUF_INPUT) { cur_buf_ns = ktime_get_ns(); - if (!inst->frame_counter) + if (!inst->frame_counter) { inst->last_buf_ns = cur_buf_ns; + inst->rate_min_timestamp = buf->timestamp; + inst->rate_max_timestamp = buf->timestamp; + } else { + inst->rate_min_timestamp = + min(inst->rate_min_timestamp, buf->timestamp); + inst->rate_max_timestamp = + max(inst->rate_max_timestamp, buf->timestamp); + } inst->frame_counter++; delta_ns = cur_buf_ns - inst->last_buf_ns; if (delta_ns >= NSEC_PER_SEC) { - inst->frame_rate = clamp_t(u32, inst->frame_counter, DEFAULT_FPS, - MAXIMUM_FPS); - inst->frame_counter = 0; + /* N frames contain N - 1 frame intervals. */ + qbuf_fps = div64_u64((u64)(inst->frame_counter - 1) * + NSEC_PER_SEC + delta_ns - 1, + delta_ns); + timestamp_delta_ns = inst->rate_max_timestamp - + inst->rate_min_timestamp; + timestamp_fps = 0; + if (inst->core->iris_platform_data->legacy_vpu5 && + timestamp_delta_ns && inst->frame_counter > 1) + timestamp_fps = div64_u64((u64)(inst->frame_counter - 1) * + NSEC_PER_SEC + + timestamp_delta_ns - 1, + timestamp_delta_ns); + + measured_fps = max(qbuf_fps, timestamp_fps); + measured_fps = clamp_t(u32, measured_fps, 1, MAXIMUM_FPS); + target_fps = clamp_t(u32, + DIV_ROUND_UP(measured_fps * 11, 10), + DEFAULT_FPS, MAXIMUM_FPS); + + /* Raise immediately; require three lower windows to reduce. */ + if (inst->frame_rate == MAXIMUM_FPS || + target_fps >= inst->frame_rate) { + inst->frame_rate = target_fps; + inst->frame_rate_down_count = 0; + } else if (++inst->frame_rate_down_count >= 3) { + inst->frame_rate = target_fps; + inst->frame_rate_down_count = 0; + } + + dev_info(inst->core->dev, + "Iris1 v140: measured input %u fps (qbuf %u, timestamps %u), voting %u fps (down windows %u)\n", + measured_fps, qbuf_fps, timestamp_fps, inst->frame_rate, + inst->frame_rate_down_count); + iris_vdec_reset_rate_window(inst); } } @@ -468,7 +723,7 @@ int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) int iris_vdec_start_cmd(struct iris_inst *inst) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; enum iris_inst_sub_state clear_sub_state = 0; struct vb2_queue *dst_vq; int ret; @@ -531,7 +786,7 @@ int iris_vdec_start_cmd(struct iris_inst *inst) int iris_vdec_stop_cmd(struct iris_inst *inst) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; int ret; ret = hfi_ops->session_drain(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); diff --git a/drivers/media/platform/qcom/iris/iris_vdec.h b/drivers/media/platform/qcom/iris/iris_vdec.h index 5123d2a340e1..53ed708e07bb 100644 --- a/drivers/media/platform/qcom/iris/iris_vdec.h +++ b/drivers/media/platform/qcom/iris/iris_vdec.h @@ -7,8 +7,10 @@ #define __IRIS_VDEC_H__ struct iris_inst; +struct iris_buffer; int iris_vdec_inst_init(struct iris_inst *inst); +void iris_vdec_inst_deinit(struct iris_inst *inst); int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f); int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f); int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f); @@ -17,7 +19,12 @@ int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_su void iris_vdec_src_change(struct iris_inst *inst); int iris_vdec_streamon_input(struct iris_inst *inst); int iris_vdec_streamon_output(struct iris_inst *inst); +u32 iris_vdec_get_admission_fps(struct iris_inst *inst); int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf); +bool iris_vdec_discard_stale_frame(struct iris_inst *inst, u64 timestamp); +int iris_vdec_complete_pending_output(struct iris_inst *inst); +int iris_vdec_hold_output(struct iris_inst *inst, struct iris_buffer *buf); +void iris_vdec_clear_pending_output(struct iris_inst *inst); int iris_vdec_start_cmd(struct iris_inst *inst); int iris_vdec_stop_cmd(struct iris_inst *inst); diff --git a/drivers/media/platform/qcom/iris/iris_venc.c b/drivers/media/platform/qcom/iris/iris_venc.c index a945992f63aa..22afb13ff0a5 100644 --- a/drivers/media/platform/qcom/iris/iris_venc.c +++ b/drivers/media/platform/qcom/iris/iris_venc.c @@ -19,8 +19,8 @@ int iris_venc_inst_init(struct iris_inst *inst) struct iris_core *core = inst->core; struct v4l2_format *f; - inst->fmt_src = kzalloc_obj(*inst->fmt_src); - inst->fmt_dst = kzalloc_obj(*inst->fmt_dst); + inst->fmt_src = kzalloc(sizeof(*inst->fmt_src), GFP_KERNEL); + inst->fmt_dst = kzalloc(sizeof(*inst->fmt_dst), GFP_KERNEL); if (!inst->fmt_src || !inst->fmt_dst) { kfree(inst->fmt_src); kfree(inst->fmt_dst); @@ -47,8 +47,8 @@ int iris_venc_inst_init(struct iris_inst *inst) f = inst->fmt_src; f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12; - f->fmt.pix_mp.width = ALIGN(DEFAULT_WIDTH, 128); - f->fmt.pix_mp.height = ALIGN(DEFAULT_HEIGHT, 32); + f->fmt.pix_mp.width = DEFAULT_WIDTH; + f->fmt.pix_mp.height = DEFAULT_HEIGHT; f->fmt.pix_mp.num_planes = 1; f->fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(DEFAULT_WIDTH, 128); f->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_INPUT); @@ -62,101 +62,81 @@ int iris_venc_inst_init(struct iris_inst *inst) inst->crop.left = 0; inst->crop.top = 0; - inst->crop.width = DEFAULT_WIDTH; - inst->crop.height = DEFAULT_HEIGHT; + inst->crop.width = f->fmt.pix_mp.width; + inst->crop.height = f->fmt.pix_mp.height; inst->operating_rate = DEFAULT_FPS; inst->frame_rate = DEFAULT_FPS; - inst->enc_raw_width = DEFAULT_WIDTH; - inst->enc_raw_height = DEFAULT_HEIGHT; - inst->enc_scale_width = DEFAULT_WIDTH; - inst->enc_scale_height = DEFAULT_HEIGHT; - memcpy(&inst->fw_caps[0], &core->inst_fw_caps_enc[0], INST_FW_CAP_MAX * sizeof(struct platform_inst_fw_cap)); return iris_ctrls_init(inst); } -static const u32 iris_venc_formats_cap[] = { - [IRIS_FMT_H264] = V4L2_PIX_FMT_H264, - [IRIS_FMT_HEVC] = V4L2_PIX_FMT_HEVC, -}; +void iris_venc_inst_deinit(struct iris_inst *inst) +{ + kfree(inst->fmt_dst); + kfree(inst->fmt_src); +} -static const u32 iris_venc_formats_out[] = { - [IRIS_FMT_NV12] = V4L2_PIX_FMT_NV12, - [IRIS_FMT_QC08C] = V4L2_PIX_FMT_QC08C, +static const struct iris_fmt iris_venc_formats[] = { + [IRIS_FMT_H264] = { + .pixfmt = V4L2_PIX_FMT_H264, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, + [IRIS_FMT_HEVC] = { + .pixfmt = V4L2_PIX_FMT_HEVC, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, }; -static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type) +static const struct iris_fmt * +find_format(struct iris_inst *inst, u32 pixfmt, u32 type) { - unsigned int size, i; - const u32 *fmt; - - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - fmt = iris_venc_formats_out; - size = ARRAY_SIZE(iris_venc_formats_out); - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - fmt = iris_venc_formats_cap; - size = ARRAY_SIZE(iris_venc_formats_cap); - break; - default: - return false; - } + const struct iris_fmt *fmt = iris_venc_formats; + unsigned int size = ARRAY_SIZE(iris_venc_formats); + unsigned int i; for (i = 0; i < size; i++) { - if (fmt[i] == pixfmt) - return true; + if (fmt[i].pixfmt == pixfmt) + break; } - return false; + if (i == size || fmt[i].type != type) + return NULL; + + return &fmt[i]; } -static u32 find_format_by_index(struct iris_inst *inst, u32 index, u32 type) +static const struct iris_fmt * +find_format_by_index(struct iris_inst *inst, u32 index, u32 type) { - unsigned int size; - const u32 *fmt; + const struct iris_fmt *fmt = iris_venc_formats; + unsigned int size = ARRAY_SIZE(iris_venc_formats); - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - fmt = iris_venc_formats_out; - size = ARRAY_SIZE(iris_venc_formats_out); - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - fmt = iris_venc_formats_cap; - size = ARRAY_SIZE(iris_venc_formats_cap); - break; - default: - return 0; - } - - if (index >= size) - return 0; + if (index >= size || fmt[index].type != type) + return NULL; - return fmt[index]; + return &fmt[index]; } int iris_venc_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f) { - u32 fmt; + const struct iris_fmt *fmt; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - fmt = find_format_by_index(inst, f->index, f->type); - if (!fmt) + if (f->index) return -EINVAL; - - f->pixelformat = fmt; + f->pixelformat = V4L2_PIX_FMT_NV12; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: fmt = find_format_by_index(inst, f->index, f->type); if (!fmt) return -EINVAL; - f->pixelformat = fmt; + f->pixelformat = fmt->pixfmt; f->flags = V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL; break; default: @@ -169,14 +149,14 @@ int iris_venc_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f) int iris_venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + const struct iris_fmt *fmt; struct v4l2_format *f_inst; - bool supported; memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); - supported = check_format(inst, pixmp->pixelformat, f->type); + fmt = find_format(inst, pixmp->pixelformat, f->type); switch (f->type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (!supported) { + if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12) { f_inst = inst->fmt_src; f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; f->fmt.pix_mp.height = f_inst->fmt.pix_mp.height; @@ -184,7 +164,7 @@ int iris_venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f) } break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (!supported) { + if (!fmt) { f_inst = inst->fmt_dst; f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; f->fmt.pix_mp.height = f_inst->fmt.pix_mp.height; @@ -206,31 +186,14 @@ int iris_venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f) static int iris_venc_s_fmt_output(struct iris_inst *inst, struct v4l2_format *f) { struct v4l2_format *fmt; - u32 codec_align; - bool supported; iris_venc_try_fmt(inst, f); - supported = check_format(inst, f->fmt.pix_mp.pixelformat, f->type); - if (!supported) + if (!(find_format(inst, f->fmt.pix_mp.pixelformat, f->type))) return -EINVAL; - codec_align = (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_HEVC) ? 32 : 16; - fmt = inst->fmt_dst; fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - /* - * If output format size != input format size, - * it is considered a scaling case, - * and the scaled size needs to be saved. - */ - if (f->fmt.pix_mp.width != inst->fmt_src->fmt.pix_mp.width || - f->fmt.pix_mp.height != inst->fmt_src->fmt.pix_mp.height) { - inst->enc_scale_width = f->fmt.pix_mp.width; - inst->enc_scale_height = f->fmt.pix_mp.height; - fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, codec_align); - fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, codec_align); - } fmt->fmt.pix_mp.num_planes = 1; fmt->fmt.pix_mp.plane_fmt[0].bytesperline = 0; fmt->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT); @@ -258,13 +221,14 @@ static int iris_venc_s_fmt_input(struct iris_inst *inst, struct v4l2_format *f) iris_venc_try_fmt(inst, f); - if (!check_format(inst, f->fmt.pix_mp.pixelformat, f->type)) + if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12) return -EINVAL; fmt = inst->fmt_src; fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128); - fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32); + /* Keep the visible dimensions separate from the DMA layout. */ + fmt->fmt.pix_mp.width = f->fmt.pix_mp.width; + fmt->fmt.pix_mp.height = f->fmt.pix_mp.height; fmt->fmt.pix_mp.num_planes = 1; fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat; fmt->fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(f->fmt.pix_mp.width, 128); @@ -286,11 +250,6 @@ static int iris_venc_s_fmt_input(struct iris_inst *inst, struct v4l2_format *f) inst->buffers[BUF_INPUT].min_count = iris_vpu_buf_count(inst, BUF_INPUT); inst->buffers[BUF_INPUT].size = fmt->fmt.pix_mp.plane_fmt[0].sizeimage; - inst->enc_raw_width = f->fmt.pix_mp.width; - inst->enc_raw_height = f->fmt.pix_mp.height; - inst->enc_scale_width = f->fmt.pix_mp.width; - inst->enc_scale_height = f->fmt.pix_mp.height; - if (f->fmt.pix_mp.width != inst->crop.width || f->fmt.pix_mp.height != inst->crop.height) { inst->crop.top = 0; @@ -311,6 +270,8 @@ int iris_venc_s_fmt(struct iris_inst *inst, struct v4l2_format *f) struct vb2_queue *q; q = v4l2_m2m_get_vq(inst->m2m_ctx, f->type); + if (!q) + return -EINVAL; if (vb2_is_busy(q)) return -EBUSY; @@ -327,13 +288,15 @@ int iris_venc_s_fmt(struct iris_inst *inst, struct v4l2_format *f) int iris_venc_validate_format(struct iris_inst *inst, u32 pixelformat) { - bool supported; + const struct iris_fmt *fmt = NULL; - supported = check_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (!supported) - supported = check_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (pixelformat != V4L2_PIX_FMT_NV12) { + fmt = find_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (!fmt) + return -EINVAL; + } - return supported ? 0 : -EINVAL; + return 0; } int iris_venc_subscribe_event(struct iris_inst *inst, @@ -383,7 +346,8 @@ int iris_venc_s_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm) struct v4l2_fract *timeperframe = NULL; u32 default_rate = DEFAULT_FPS; bool is_frame_rate = false; - u32 fps, max_rate; + u64 us_per_frame, fps; + u32 max_rate; int ret = 0; @@ -405,19 +369,23 @@ int iris_venc_s_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm) timeperframe->denominator = default_rate; } - fps = timeperframe->denominator / timeperframe->numerator; - if (!fps) + us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC; + do_div(us_per_frame, timeperframe->denominator); + + if (!us_per_frame) return -EINVAL; + fps = (u64)USEC_PER_SEC; + do_div(fps, us_per_frame); if (fps > max_rate) { ret = -ENOMEM; goto reset_rate; } if (is_frame_rate) - inst->frame_rate = fps; + inst->frame_rate = (u32)fps; else - inst->operating_rate = fps; + inst->operating_rate = (u32)fps; if ((s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && vb2_is_streaming(src_q)) || (s_parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && vb2_is_streaming(dst_q))) { @@ -523,7 +491,9 @@ int iris_venc_streamon_output(struct iris_inst *inst) return ret; error: + inst->start_streaming_rollback_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; iris_session_streamoff(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + inst->start_streaming_rollback_type = 0; return ret; } @@ -555,7 +525,7 @@ int iris_venc_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) int iris_venc_start_cmd(struct iris_inst *inst) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; enum iris_inst_sub_state clear_sub_state = 0; struct vb2_queue *dst_vq; int ret; @@ -597,7 +567,7 @@ int iris_venc_start_cmd(struct iris_inst *inst) int iris_venc_stop_cmd(struct iris_inst *inst) { - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; int ret; ret = hfi_ops->session_drain(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); diff --git a/drivers/media/platform/qcom/iris/iris_venc.h b/drivers/media/platform/qcom/iris/iris_venc.h index 00c1716b2747..c4db7433da53 100644 --- a/drivers/media/platform/qcom/iris/iris_venc.h +++ b/drivers/media/platform/qcom/iris/iris_venc.h @@ -9,6 +9,7 @@ struct iris_inst; int iris_venc_inst_init(struct iris_inst *inst); +void iris_venc_inst_deinit(struct iris_inst *inst); int iris_venc_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f); int iris_venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f); int iris_venc_s_fmt(struct iris_inst *inst, struct v4l2_format *f); diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index 14d63dc76c9b..8351b45369e9 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -3,12 +3,16 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include +#include +#include #include #include #include #include #include +#include "iris_common.h" #include "iris_vidc.h" #include "iris_instance.h" #include "iris_vdec.h" @@ -22,19 +26,167 @@ #define STEP_WIDTH 1 #define STEP_HEIGHT 1 -static void iris_v4l2_fh_init(struct iris_inst *inst, struct file *filp) +static bool allow_fw_boot; +module_param(allow_fw_boot, bool, 0644); +MODULE_PARM_DESC(allow_fw_boot, + "Allow opening the video node to boot Iris firmware"); + +static inline struct iris_inst *iris_get_inst(struct file *filp, void *fh) +{ + return container_of(filp->private_data, struct iris_inst, fh); +} + +struct iris_surface_fence { + struct dma_fence base; + spinlock_t lock; /* protects dma_fence signaling state */ + struct list_head list; + u64 token; +}; + +static const char *iris_surface_fence_get_name(struct dma_fence *fence) +{ + return "qcom-iris-cpu-copy"; +} + +static void iris_surface_fence_release(struct dma_fence *fence) +{ + struct iris_surface_fence *surface_fence = + container_of(fence, struct iris_surface_fence, base); + + kfree(surface_fence); +} + +static const struct dma_fence_ops iris_surface_fence_ops = { + .get_driver_name = iris_surface_fence_get_name, + .get_timeline_name = iris_surface_fence_get_name, + .release = iris_surface_fence_release, +}; + +static void iris_surface_fence_complete(struct iris_surface_fence *surface_fence) +{ + bool cookie; + + cookie = dma_fence_begin_signalling(); + dma_fence_signal(&surface_fence->base); + dma_fence_end_signalling(cookie); + dma_fence_put(&surface_fence->base); +} + +static int iris_surface_fence_attach(struct iris_inst *inst, + const struct iris_surface_fence_cmd *cmd) +{ + struct iris_surface_fence *surface_fence, *pending; + struct dma_buf *dmabuf; + int ret; + + if (cmd->dmabuf_fd < 0 || !cmd->token) + return -EINVAL; + + list_for_each_entry(pending, &inst->surface_fences, list) + if (pending->token == cmd->token) + return -EEXIST; + + dmabuf = dma_buf_get(cmd->dmabuf_fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + surface_fence = kzalloc(sizeof(*surface_fence), GFP_KERNEL); + if (!surface_fence) { + ret = -ENOMEM; + goto put_dmabuf; + } + + spin_lock_init(&surface_fence->lock); + surface_fence->token = cmd->token; + dma_fence_init(&surface_fence->base, &iris_surface_fence_ops, + &surface_fence->lock, inst->surface_fence_context, + ++inst->surface_fence_seqno); + + ret = dma_resv_lock_interruptible(dmabuf->resv, NULL); + if (ret) + goto put_fence; + ret = dma_resv_reserve_fences(dmabuf->resv, 1); + if (!ret) + dma_resv_add_fence(dmabuf->resv, &surface_fence->base, + DMA_RESV_USAGE_WRITE); + dma_resv_unlock(dmabuf->resv); + if (ret) + goto put_fence; + + list_add_tail(&surface_fence->list, &inst->surface_fences); + dma_buf_put(dmabuf); + return 0; + +put_fence: + dma_fence_put(&surface_fence->base); +put_dmabuf: + dma_buf_put(dmabuf); + return ret; +} + +static int iris_surface_fence_signal(struct iris_inst *inst, u64 token) +{ + struct iris_surface_fence *surface_fence; + + list_for_each_entry(surface_fence, &inst->surface_fences, list) { + if (surface_fence->token != token) + continue; + list_del(&surface_fence->list); + iris_surface_fence_complete(surface_fence); + return 0; + } + + return -ENOENT; +} + +static void iris_surface_fence_signal_all(struct iris_inst *inst) +{ + struct iris_surface_fence *surface_fence, *next; + + list_for_each_entry_safe(surface_fence, next, + &inst->surface_fences, list) { + list_del(&surface_fence->list); + iris_surface_fence_complete(surface_fence); + } +} + +static long iris_vidioc_default(struct file *file, void *fh, bool valid_prio, + unsigned int cmd, void *arg) +{ + struct iris_surface_fence_cmd *fence_cmd = arg; + struct iris_inst *inst = iris_get_inst(file, fh); + int ret; + + if (cmd != VIDIOC_IRIS_SURFACE_FENCE || inst->domain != DECODER) + return -ENOTTY; + if (!valid_prio) + return -EBUSY; + + mutex_lock(&inst->lock); + if (fence_cmd->op == IRIS_SURFACE_FENCE_ATTACH) + ret = iris_surface_fence_attach(inst, fence_cmd); + else if (fence_cmd->op == IRIS_SURFACE_FENCE_SIGNAL) + ret = iris_surface_fence_signal(inst, fence_cmd->token); + else + ret = -EINVAL; + mutex_unlock(&inst->lock); + + return ret; +} + +static void iris_v4l2_fh_init(struct iris_inst *inst) { if (inst->domain == ENCODER) v4l2_fh_init(&inst->fh, inst->core->vdev_enc); else if (inst->domain == DECODER) v4l2_fh_init(&inst->fh, inst->core->vdev_dec); inst->fh.ctrl_handler = &inst->ctrl_handler; - v4l2_fh_add(&inst->fh, filp); + v4l2_fh_add(&inst->fh); } -static void iris_v4l2_fh_deinit(struct iris_inst *inst, struct file *filp) +static void iris_v4l2_fh_deinit(struct iris_inst *inst) { - v4l2_fh_del(&inst->fh, filp); + v4l2_fh_del(&inst->fh); inst->fh.ctrl_handler = NULL; v4l2_fh_exit(&inst->fh); } @@ -42,40 +194,21 @@ static void iris_v4l2_fh_deinit(struct iris_inst *inst, struct file *filp) static void iris_add_session(struct iris_inst *inst) { struct iris_core *core = inst->core; - struct iris_inst *iter; - u32 count = 0; mutex_lock(&core->lock); - - list_for_each_entry(iter, &core->instances, list) - count++; - - if (count < core->iris_platform_data->max_session_count) - list_add_tail(&inst->list, &core->instances); - + list_add_tail(&inst->list, &core->instances); mutex_unlock(&core->lock); } static void iris_remove_session(struct iris_inst *inst) { struct iris_core *core = inst->core; - struct iris_inst *iter, *temp; mutex_lock(&core->lock); - list_for_each_entry_safe(iter, temp, &core->instances, list) { - if (iter->session_id == inst->session_id) { - list_del_init(&iter->list); - break; - } - } + list_del_init(&inst->list); mutex_unlock(&core->lock); } -static inline struct iris_inst *iris_get_inst(struct file *filp) -{ - return container_of(file_to_v4l2_fh(filp), struct iris_inst, fh); -} - static void iris_m2m_device_run(void *priv) { } @@ -135,6 +268,9 @@ int iris_open(struct file *filp) u32 session_type; int ret; + if (!READ_ONCE(allow_fw_boot)) + return -EACCES; + vdev = video_devdata(filp); if (strcmp(vdev->name, "qcom-iris-decoder") == 0) session_type = DECODER; @@ -156,7 +292,7 @@ int iris_open(struct file *filp) pm_runtime_put_sync(core->dev); - inst = core->hfi_sys_ops->sys_get_instance(); + inst = core->iris_platform_data->get_instance(); if (!inst) return -ENOMEM; @@ -164,6 +300,9 @@ int iris_open(struct file *filp) inst->domain = session_type; inst->session_id = hash32_ptr(inst); inst->state = IRIS_INST_DEINIT; + INIT_LIST_HEAD(&inst->list); + INIT_LIST_HEAD(&inst->surface_fences); + inst->surface_fence_context = dma_fence_context_alloc(1); mutex_init(&inst->lock); mutex_init(&inst->ctx_q_lock); @@ -178,11 +317,10 @@ int iris_open(struct file *filp) INIT_LIST_HEAD(&inst->buffers[BUF_SCRATCH_1].list); INIT_LIST_HEAD(&inst->buffers[BUF_SCRATCH_2].list); INIT_LIST_HEAD(&inst->buffers[BUF_VPSS].list); - INIT_LIST_HEAD(&inst->buffers[BUF_PARTIAL].list); init_completion(&inst->completion); init_completion(&inst->flush_completion); - iris_v4l2_fh_init(inst, filp); + iris_v4l2_fh_init(inst); inst->m2m_dev = v4l2_m2m_init(&iris_m2m_ops); if (IS_ERR_OR_NULL(inst->m2m_dev)) { @@ -206,6 +344,7 @@ int iris_open(struct file *filp) iris_add_session(inst); inst->fh.m2m_ctx = inst->m2m_ctx; + filp->private_data = &inst->fh; return 0; @@ -214,7 +353,7 @@ int iris_open(struct file *filp) fail_m2m_release: v4l2_m2m_release(inst->m2m_dev); fail_v4l2_fh_deinit: - iris_v4l2_fh_deinit(inst, filp); + iris_v4l2_fh_deinit(inst); mutex_destroy(&inst->ctx_q_lock); mutex_destroy(&inst->lock); kfree(inst); @@ -222,28 +361,9 @@ int iris_open(struct file *filp) return ret; } -static void iris_session_close(struct iris_inst *inst) -{ - const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - bool wait_for_response = true; - int ret; - - if (inst->state == IRIS_INST_DEINIT) - return; - - reinit_completion(&inst->completion); - - ret = hfi_ops->session_close(inst); - if (ret) - wait_for_response = false; - - if (wait_for_response) - iris_wait_for_session_response(inst, false); -} - static void iris_check_num_queued_internal_buffers(struct iris_inst *inst, u32 plane) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; + const struct iris_platform_data *platform_data = inst->core->iris_platform_data; struct iris_buffer *buf, *next; struct iris_buffers *buffers; const u32 *internal_buf_type; @@ -251,11 +371,11 @@ static void iris_check_num_queued_internal_buffers(struct iris_inst *inst, u32 p u32 count = 0; 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; + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_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; + internal_buf_type = platform_data->dec_op_int_buf_tbl; + internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; } for (i = 0; i < internal_buffer_count; i++) { @@ -283,33 +403,39 @@ static void iris_check_num_queued_internal_buffers(struct iris_inst *inst, u32 p int iris_close(struct file *filp) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = iris_get_inst(filp, NULL); + + mutex_lock(&inst->lock); + iris_surface_fence_signal_all(inst); + mutex_unlock(&inst->lock); v4l2_ctrl_handler_free(&inst->ctrl_handler); v4l2_m2m_ctx_release(inst->m2m_ctx); v4l2_m2m_release(inst->m2m_dev); mutex_lock(&inst->lock); - iris_session_close(inst); - iris_inst_change_state(inst, IRIS_INST_DEINIT); - iris_v4l2_fh_deinit(inst, filp); + iris_hfi_session_close(inst); + iris_v4l2_fh_deinit(inst); iris_destroy_all_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); iris_destroy_all_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); iris_check_num_queued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); iris_check_num_queued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); iris_remove_session(inst); mutex_unlock(&inst->lock); + if (inst->domain == DECODER) + iris_vdec_inst_deinit(inst); + else if (inst->domain == ENCODER) + iris_venc_inst_deinit(inst); mutex_destroy(&inst->ctx_q_lock); mutex_destroy(&inst->lock); - kfree(inst->fmt_src); - kfree(inst->fmt_dst); kfree(inst); + filp->private_data = NULL; return 0; } static int iris_enum_fmt(struct file *filp, void *fh, struct v4l2_fmtdesc *f) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = iris_get_inst(filp, NULL); if (inst->domain == DECODER) return iris_vdec_enum_fmt(inst, f); @@ -321,7 +447,7 @@ static int iris_enum_fmt(struct file *filp, void *fh, struct v4l2_fmtdesc *f) static int iris_try_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format *f) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = iris_get_inst(filp, NULL); int ret = 0; mutex_lock(&inst->lock); @@ -338,7 +464,7 @@ static int iris_try_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_form static int iris_s_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format *f) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = iris_get_inst(filp, NULL); int ret = 0; mutex_lock(&inst->lock); @@ -355,7 +481,7 @@ static int iris_s_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format static int iris_g_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format *f) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = iris_get_inst(filp, NULL); int ret = 0; mutex_lock(&inst->lock); @@ -374,7 +500,7 @@ static int iris_g_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format static int iris_enum_framesizes(struct file *filp, void *fh, struct v4l2_frmsizeenum *fsize) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = iris_get_inst(filp, NULL); struct platform_inst_caps *caps; int ret = 0; @@ -406,7 +532,7 @@ static int iris_enum_frameintervals(struct file *filp, void *fh, struct v4l2_frmivalenum *fival) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = iris_get_inst(filp, NULL); struct iris_core *core = inst->core; struct platform_inst_caps *caps; u32 fps, mbpf; @@ -449,7 +575,7 @@ static int iris_enum_frameintervals(struct file *filp, void *fh, static int iris_querycap(struct file *filp, void *fh, struct v4l2_capability *cap) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = iris_get_inst(filp, NULL); strscpy(cap->driver, IRIS_DRV_NAME, sizeof(cap->driver)); @@ -463,7 +589,7 @@ static int iris_querycap(struct file *filp, void *fh, struct v4l2_capability *ca static int iris_g_selection(struct file *filp, void *fh, struct v4l2_selection *s) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = iris_get_inst(filp, NULL); if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && inst->domain == DECODER) @@ -513,7 +639,7 @@ static int iris_g_selection(struct file *filp, void *fh, struct v4l2_selection * static int iris_s_selection(struct file *filp, void *fh, struct v4l2_selection *s) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = iris_get_inst(filp, NULL); if (inst->domain == DECODER) return -EINVAL; @@ -537,7 +663,7 @@ static int iris_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subs static int iris_s_parm(struct file *filp, void *fh, struct v4l2_streamparm *a) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = container_of(fh, struct iris_inst, fh); if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) @@ -551,7 +677,7 @@ static int iris_s_parm(struct file *filp, void *fh, struct v4l2_streamparm *a) static int iris_g_parm(struct file *filp, void *fh, struct v4l2_streamparm *a) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = container_of(fh, struct iris_inst, fh); if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) @@ -566,7 +692,7 @@ static int iris_g_parm(struct file *filp, void *fh, struct v4l2_streamparm *a) static int iris_dec_cmd(struct file *filp, void *fh, struct v4l2_decoder_cmd *dec) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = iris_get_inst(filp, NULL); int ret = 0; mutex_lock(&inst->lock); @@ -600,7 +726,7 @@ static int iris_dec_cmd(struct file *filp, void *fh, static int iris_enc_cmd(struct file *filp, void *fh, struct v4l2_encoder_cmd *enc) { - struct iris_inst *inst = iris_get_inst(filp); + struct iris_inst *inst = iris_get_inst(filp, NULL); int ret = 0; mutex_lock(&inst->lock); @@ -631,7 +757,7 @@ static int iris_enc_cmd(struct file *filp, void *fh, return ret; } -static const struct v4l2_file_operations iris_v4l2_file_ops = { +static struct v4l2_file_operations iris_v4l2_file_ops = { .owner = THIS_MODULE, .open = iris_open, .release = iris_close, @@ -676,6 +802,7 @@ static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops_dec = { .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, .vidioc_decoder_cmd = iris_dec_cmd, + .vidioc_default = iris_vidioc_default, }; static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops_enc = { diff --git a/drivers/media/platform/qcom/iris/iris_vidc.h b/drivers/media/platform/qcom/iris/iris_vidc.h index a26054ff55b5..3cc36266a760 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.h +++ b/drivers/media/platform/qcom/iris/iris_vidc.h @@ -6,8 +6,21 @@ #ifndef __IRIS_VIDC_H__ #define __IRIS_VIDC_H__ +#include + struct iris_core; +struct iris_surface_fence_cmd { + __u32 op; + __s32 dmabuf_fd; + __u64 token; +}; + +#define IRIS_SURFACE_FENCE_ATTACH 1 +#define IRIS_SURFACE_FENCE_SIGNAL 2 +#define VIDIOC_IRIS_SURFACE_FENCE \ + _IOW('V', BASE_VIDIOC_PRIVATE, struct iris_surface_fence_cmd) + void iris_init_ops(struct iris_core *core); int iris_open(struct file *filp); int iris_close(struct file *filp); diff --git a/drivers/media/platform/qcom/iris/iris_vpu2.c b/drivers/media/platform/qcom/iris/iris_vpu2.c index b8714dcbad10..5683948799b5 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu2.c +++ b/drivers/media/platform/qcom/iris/iris_vpu2.c @@ -3,22 +3,17 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ -#include -#include -#include - #include "iris_instance.h" +#include "iris_power.h" #include "iris_vpu_common.h" -#include "iris_vpu_register_defines.h" - static u64 iris_vpu2_calc_freq(struct iris_inst *inst, size_t data_size) { struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; struct v4l2_format *inp_f = inst->fmt_src; u32 mbs_per_second, mbpf, height, width; unsigned long vpp_freq, vsp_freq; - u32 fps = inst->frame_rate; + u32 fps = iris_get_operating_fps(inst); width = max(inp_f->fmt.pix_mp.width, inst->crop.width); height = max(inp_f->fmt.pix_mp.height, inst->crop.height); @@ -40,9 +35,6 @@ static u64 iris_vpu2_calc_freq(struct iris_inst *inst, size_t data_size) const struct vpu_ops iris_vpu2_ops = { .power_off_hw = iris_vpu_power_off_hw, - .power_on_hw = iris_vpu_power_on_hw, .power_off_controller = iris_vpu_power_off_controller, - .power_on_controller = iris_vpu_power_on_controller, .calc_freq = iris_vpu2_calc_freq, - .set_hwmode = iris_vpu_set_hwmode, }; diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c index fb6f1016415e..34a9094201cc 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c @@ -9,17 +9,6 @@ #include "iris_hfi_gen2_defines.h" #define HFI_MAX_COL_FRAME 6 -#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT (8) -#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH (32) -#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT (8) -#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH (16) -#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT (4) -#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH (48) -#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_HEIGHT (4) -#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_WIDTH (24) -#define AV1D_SIZE_BSE_COL_MV_64x64 512 -#define AV1D_SIZE_BSE_COL_MV_128x128 2816 -#define UBWC_TILE_SIZE 256 #ifndef SYSTEM_LAL_TILE10 #define SYSTEM_LAL_TILE10 192 @@ -50,31 +39,6 @@ static u32 hfi_buffer_bin_h264d(u32 frame_width, u32 frame_height, u32 num_vpp_p return size_h264d_hw_bin_buffer(n_aligned_w, n_aligned_h, num_vpp_pipes); } -static u32 size_av1d_hw_bin_buffer(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) -{ - u32 size_yuv, size_bin_hdr, size_bin_res; - - size_yuv = ((frame_width * frame_height) <= BIN_BUFFER_THRESHOLD) ? - ((BIN_BUFFER_THRESHOLD * 3) >> 1) : - ((frame_width * frame_height * 3) >> 1); - size_bin_hdr = size_yuv * AV1_CABAC_HDR_RATIO_HD_TOT; - size_bin_res = size_yuv * AV1_CABAC_RES_RATIO_HD_TOT; - size_bin_hdr = ALIGN(size_bin_hdr / num_vpp_pipes, - DMA_ALIGNMENT) * num_vpp_pipes; - size_bin_res = ALIGN(size_bin_res / num_vpp_pipes, - DMA_ALIGNMENT) * num_vpp_pipes; - - return size_bin_hdr + size_bin_res; -} - -static u32 hfi_buffer_bin_av1d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) -{ - u32 n_aligned_h = ALIGN(frame_height, 16); - u32 n_aligned_w = ALIGN(frame_width, 16); - - return size_av1d_hw_bin_buffer(n_aligned_w, n_aligned_h, num_vpp_pipes); -} - static u32 size_h265d_hw_bin_buffer(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) { u32 product = frame_width * frame_height; @@ -146,26 +110,6 @@ static u32 hfi_buffer_comv_h265d(u32 frame_width, u32 frame_height, u32 _comv_bu return (_size * (_comv_bufcount)) + 512; } -static u32 num_lcu(u32 frame_width, u32 frame_height, u32 lcu_size) -{ - return ((frame_width + lcu_size - 1) / lcu_size) * - ((frame_height + lcu_size - 1) / lcu_size); -} - -static u32 hfi_buffer_comv_av1d(u32 frame_width, u32 frame_height, u32 comv_bufcount) -{ - u32 size; - - size = 2 * ALIGN(max(num_lcu(frame_width, frame_height, 64) * - AV1D_SIZE_BSE_COL_MV_64x64, - num_lcu(frame_width, frame_height, 128) * - AV1D_SIZE_BSE_COL_MV_128x128), - DMA_ALIGNMENT); - size *= comv_bufcount; - - return size; -} - static u32 size_h264d_bse_cmd_buf(u32 frame_height) { u32 height = ALIGN(frame_height, 32); @@ -178,7 +122,7 @@ static u32 size_h265d_bse_cmd_buf(u32 frame_width, u32 frame_height) { u32 _size = ALIGN(((ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * (ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) * - NUM_HW_PIC_BUF, DMA_ALIGNMENT); + NUM_HW_PIC_BUF, DMA_ALIGNMENT); _size = min_t(u32, _size, H265D_MAX_SLICE + 1); _size = 2 * _size * SIZE_H265D_BSE_CMD_PER_BUF; @@ -230,20 +174,6 @@ static u32 hfi_buffer_persist_h264d(void) DMA_ALIGNMENT); } -static u32 hfi_buffer_persist_av1d(u32 max_width, u32 max_height, u32 total_ref_count) -{ - u32 comv_size, size; - - comv_size = hfi_buffer_comv_av1d(max_width, max_height, total_ref_count); - size = ALIGN((SIZE_AV1D_SEQUENCE_HEADER * 2 + SIZE_AV1D_METADATA + - AV1D_NUM_HW_PIC_BUF * (SIZE_AV1D_TILE_OFFSET + SIZE_AV1D_QM) + - AV1D_NUM_FRAME_HEADERS * (SIZE_AV1D_FRAME_HEADER + - 2 * SIZE_AV1D_PROB_TABLE) + comv_size + HDR10_HIST_EXTRADATA_SIZE + - SIZE_AV1D_METADATA * AV1D_NUM_HW_PIC_BUF), DMA_ALIGNMENT); - - return ALIGN(size, DMA_ALIGNMENT); -} - static u32 hfi_buffer_non_comv_h264d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) { u32 size_bse = size_h264d_bse_cmd_buf(frame_height); @@ -529,182 +459,6 @@ static u32 hfi_buffer_line_h264d(u32 frame_width, u32 frame_height, return ALIGN((size + vpss_lb_size), DMA_ALIGNMENT); } -static u32 size_av1d_lb_opb_wr1_nv12_ubwc(u32 frame_width, u32 frame_height) -{ - u32 size, y_width, y_width_a = 128; - - y_width = ALIGN(frame_width, y_width_a); - - size = ((y_width + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH - 1) / - HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH + - (AV1D_MAX_TILE_COLS - 1)); - return size * UBWC_TILE_SIZE; -} - -static u32 size_av1d_lb_opb_wr1_tp10_ubwc(u32 frame_width, u32 frame_height) -{ - u32 size, y_width, y_width_a = 256; - - y_width = ALIGN(frame_width, y_width_a); - - size = ((y_width + HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH - 1) / - HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH + - (AV1D_MAX_TILE_COLS - 1)); - - return size * UBWC_TILE_SIZE; -} - -static u32 hfi_buffer_line_av1d(u32 frame_width, u32 frame_height, - bool is_opb, u32 num_vpp_pipes) -{ - u32 size, vpss_lb_size, opbwrbufsize, opbwr8, opbwr10; - - size = ALIGN(size_av1d_lb_fe_top_data(frame_width, frame_height), - DMA_ALIGNMENT) + - ALIGN(size_av1d_lb_fe_top_ctrl(frame_width, frame_height), - DMA_ALIGNMENT) + - ALIGN(size_av1d_lb_fe_left_data(frame_width, frame_height), - DMA_ALIGNMENT) * num_vpp_pipes + - ALIGN(size_av1d_lb_fe_left_ctrl(frame_width, frame_height), - DMA_ALIGNMENT) * num_vpp_pipes + - ALIGN(size_av1d_lb_se_left_ctrl(frame_width, frame_height), - DMA_ALIGNMENT) * num_vpp_pipes + - ALIGN(size_av1d_lb_se_top_ctrl(frame_width, frame_height), - DMA_ALIGNMENT) + - ALIGN(size_av1d_lb_pe_top_data(frame_width, frame_height), - DMA_ALIGNMENT) + - ALIGN(size_av1d_lb_vsp_top(frame_width, frame_height), - DMA_ALIGNMENT) + - ALIGN(size_av1d_lb_recon_dma_metadata_wr - (frame_width, frame_height), DMA_ALIGNMENT) * 2 + - ALIGN(size_av1d_qp(frame_width, frame_height), DMA_ALIGNMENT); - opbwr8 = size_av1d_lb_opb_wr1_nv12_ubwc(frame_width, frame_height); - opbwr10 = size_av1d_lb_opb_wr1_tp10_ubwc(frame_width, frame_height); - opbwrbufsize = opbwr8 >= opbwr10 ? opbwr8 : opbwr10; - size = ALIGN((size + opbwrbufsize), DMA_ALIGNMENT); - if (is_opb) { - vpss_lb_size = size_vpss_lb(frame_width, frame_height); - size = ALIGN((size + vpss_lb_size) * 2, DMA_ALIGNMENT); - } - - return size; -} - -static u32 size_av1d_ibc_nv12_ubwc(u32 frame_width, u32 frame_height) -{ - u32 size; - u32 y_width_a = 128, y_height_a = 32; - u32 uv_width_a = 128, uv_height_a = 32; - u32 ybufsize, uvbufsize, y_width, y_height, uv_width, uv_height; - u32 y_meta_width_a = 64, y_meta_height_a = 16; - u32 uv_meta_width_a = 64, uv_meta_height_a = 16; - u32 meta_height, meta_stride, meta_size; - u32 tile_width_y = HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH; - u32 tile_height_y = HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT; - u32 tile_width_uv = HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH; - u32 tile_height_uv = HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT; - - y_width = ALIGN(frame_width, y_width_a); - y_height = ALIGN(frame_height, y_height_a); - uv_width = ALIGN(frame_width, uv_width_a); - uv_height = ALIGN(((frame_height + 1) >> 1), uv_height_a); - ybufsize = ALIGN((y_width * y_height), HFI_ALIGNMENT_4096); - uvbufsize = ALIGN(uv_width * uv_height, HFI_ALIGNMENT_4096); - size = ybufsize + uvbufsize; - meta_stride = ALIGN(((frame_width + (tile_width_y - 1)) / tile_width_y), - y_meta_width_a); - meta_height = ALIGN(((frame_height + (tile_height_y - 1)) / tile_height_y), - y_meta_height_a); - meta_size = ALIGN(meta_stride * meta_height, HFI_ALIGNMENT_4096); - size += meta_size; - meta_stride = ALIGN(((((frame_width + 1) >> 1) + (tile_width_uv - 1)) / - tile_width_uv), uv_meta_width_a); - meta_height = ALIGN(((((frame_height + 1) >> 1) + (tile_height_uv - 1)) / - tile_height_uv), uv_meta_height_a); - meta_size = ALIGN(meta_stride * meta_height, HFI_ALIGNMENT_4096); - size += meta_size; - - return size; -} - -static u32 hfi_yuv420_tp10_calc_y_stride(u32 frame_width, u32 stride_multiple) -{ - u32 stride; - - stride = ALIGN(frame_width, 192); - stride = ALIGN(stride * 4 / 3, stride_multiple); - - return stride; -} - -static u32 hfi_yuv420_tp10_calc_y_bufheight(u32 frame_height, u32 min_buf_height_multiple) -{ - return ALIGN(frame_height, min_buf_height_multiple); -} - -static u32 hfi_yuv420_tp10_calc_uv_stride(u32 frame_width, u32 stride_multiple) -{ - u32 stride; - - stride = ALIGN(frame_width, 192); - stride = ALIGN(stride * 4 / 3, stride_multiple); - - return stride; -} - -static u32 hfi_yuv420_tp10_calc_uv_bufheight(u32 frame_height, u32 min_buf_height_multiple) -{ - return ALIGN(((frame_height + 1) >> 1), min_buf_height_multiple); -} - -static u32 size_av1d_ibc_tp10_ubwc(u32 frame_width, u32 frame_height) -{ - u32 size; - u32 y_width_a = 256, y_height_a = 16, - uv_width_a = 256, uv_height_a = 16; - u32 ybufsize, uvbufsize, y_width, y_height, uv_width, uv_height; - u32 y_meta_width_a = 64, y_meta_height_a = 16, - uv_meta_width_a = 64, uv_meta_height_a = 16; - u32 meta_height, meta_stride, meta_size; - u32 tile_width_y = HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH; - u32 tile_height_y = HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT; - u32 tile_width_uv = HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_WIDTH; - u32 tile_height_uv = HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_HEIGHT; - - y_width = hfi_yuv420_tp10_calc_y_stride(frame_width, y_width_a); - y_height = hfi_yuv420_tp10_calc_y_bufheight(frame_height, y_height_a); - uv_width = hfi_yuv420_tp10_calc_uv_stride(frame_width, uv_width_a); - uv_height = hfi_yuv420_tp10_calc_uv_bufheight(frame_height, uv_height_a); - ybufsize = ALIGN(y_width * y_height, HFI_ALIGNMENT_4096); - uvbufsize = ALIGN(uv_width * uv_height, HFI_ALIGNMENT_4096); - size = ybufsize + uvbufsize; - meta_stride = ALIGN(((frame_width + (tile_width_y - 1)) / tile_width_y), - y_meta_width_a); - meta_height = ALIGN(((frame_height + (tile_height_y - 1)) / tile_height_y), - y_meta_height_a); - meta_size = ALIGN(meta_stride * meta_height, HFI_ALIGNMENT_4096); - size += meta_size; - meta_stride = ALIGN(((((frame_width + 1) >> 1) + (tile_width_uv - 1)) / - tile_width_uv), uv_meta_width_a); - meta_height = ALIGN(((((frame_height + 1) >> 1) + (tile_height_uv - 1)) / - tile_height_uv), uv_meta_height_a); - meta_size = ALIGN(meta_stride * meta_height, HFI_ALIGNMENT_4096); - size += meta_size; - - return size; -} - -static u32 hfi_buffer_ibc_av1d(u32 frame_width, u32 frame_height) -{ - u32 size, ibc8, ibc10; - - ibc8 = size_av1d_ibc_nv12_ubwc(frame_width, frame_height); - ibc10 = size_av1d_ibc_tp10_ubwc(frame_width, frame_height); - size = ibc8 >= ibc10 ? ibc8 : ibc10; - - return ALIGN(size, DMA_ALIGNMENT); -} - static u32 iris_vpu_dec_bin_size(struct iris_inst *inst) { u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; @@ -718,8 +472,6 @@ static u32 iris_vpu_dec_bin_size(struct iris_inst *inst) return hfi_buffer_bin_h265d(width, height, num_vpp_pipes); else if (inst->codec == V4L2_PIX_FMT_VP9) return hfi_buffer_bin_vp9d(width, height, num_vpp_pipes); - else if (inst->codec == V4L2_PIX_FMT_AV1) - return hfi_buffer_bin_av1d(width, height, num_vpp_pipes); return 0; } @@ -739,48 +491,14 @@ static u32 iris_vpu_dec_comv_size(struct iris_inst *inst) return 0; } -static u32 iris_vpu3x_4x_dec_comv_size(struct iris_inst *inst) -{ - u32 num_comv = inst->buffers[BUF_OUTPUT].min_count; - struct v4l2_format *f = inst->fmt_src; - u32 height = f->fmt.pix_mp.height; - u32 width = f->fmt.pix_mp.width; - - if (inst->fw_min_count) - num_comv = inst->fw_min_count; - - if (inst->codec == V4L2_PIX_FMT_H264) - return hfi_buffer_comv_h264d(width, height, num_comv); - else if (inst->codec == V4L2_PIX_FMT_HEVC) - return hfi_buffer_comv_h265d(width, height, num_comv); - else if (inst->codec == V4L2_PIX_FMT_AV1) { - if (inst->fw_caps[DRAP].value) - return 0; - else - return hfi_buffer_comv_av1d(width, height, num_comv); - } - - return 0; -} - static u32 iris_vpu_dec_persist_size(struct iris_inst *inst) { - struct platform_inst_caps *caps; - if (inst->codec == V4L2_PIX_FMT_H264) return hfi_buffer_persist_h264d(); else if (inst->codec == V4L2_PIX_FMT_HEVC) return hfi_buffer_persist_h265d(0); else if (inst->codec == V4L2_PIX_FMT_VP9) return hfi_buffer_persist_vp9d(); - else if (inst->codec == V4L2_PIX_FMT_AV1) { - caps = inst->core->iris_platform_data->inst_caps; - if (inst->fw_caps[DRAP].value) - return hfi_buffer_persist_av1d(caps->max_frame_width, - caps->max_frame_height, 16); - else - return hfi_buffer_persist_av1d(0, 0, 0); - } return 0; } @@ -827,8 +545,6 @@ static u32 iris_vpu_dec_line_size(struct iris_inst *inst) else if (inst->codec == V4L2_PIX_FMT_VP9) return hfi_buffer_line_vp9d(width, height, out_min_count, is_opb, num_vpp_pipes); - else if (inst->codec == V4L2_PIX_FMT_AV1) - return hfi_buffer_line_av1d(width, height, is_opb, num_vpp_pipes); return 0; } @@ -840,20 +556,27 @@ static u32 iris_vpu_dec_scratch1_size(struct iris_inst *inst) iris_vpu_dec_line_size(inst); } -static inline u32 iris_vpu_enc_get_bitstream_width(struct iris_inst *inst) -{ - if (is_rotation_90_or_270(inst)) - return inst->fmt_dst->fmt.pix_mp.height; +static inline +u32 size_enc_single_pipe(u32 rc_type, u32 bitbin_size, u32 num_vpp_pipes, + u32 frame_width, u32 frame_height, u32 lcu_size) +{ + u32 size_aligned_height = ALIGN((frame_height), lcu_size); + u32 size_aligned_width = ALIGN((frame_width), lcu_size); + u32 size_single_pipe_eval = 0, sao_bin_buffer_size = 0; + u32 padded_bin_sz; + + if ((size_aligned_width * size_aligned_height) > (3840 * 2160)) + size_single_pipe_eval = (bitbin_size / num_vpp_pipes); + else if (num_vpp_pipes > 2) + size_single_pipe_eval = bitbin_size / 2; else - return inst->fmt_dst->fmt.pix_mp.width; -} + size_single_pipe_eval = bitbin_size; -static inline u32 iris_vpu_enc_get_bitstream_height(struct iris_inst *inst) -{ - if (is_rotation_90_or_270(inst)) - return inst->fmt_dst->fmt.pix_mp.width; - else - return inst->fmt_dst->fmt.pix_mp.height; + sao_bin_buffer_size = (64 * ((((frame_width) + 32) * ((frame_height) + 32)) >> 10)) + 384; + padded_bin_sz = ALIGN(size_single_pipe_eval, 256); + size_single_pipe_eval = sao_bin_buffer_size + padded_bin_sz; + + return ALIGN(size_single_pipe_eval, 256); } static inline u32 size_bin_bitstream_enc(u32 width, u32 height, @@ -938,9 +661,10 @@ static inline u32 hfi_buffer_bin_enc(u32 width, u32 height, static u32 iris_vpu_enc_bin_size(struct iris_inst *inst) { u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; - u32 height = iris_vpu_enc_get_bitstream_height(inst); - u32 width = iris_vpu_enc_get_bitstream_width(inst); u32 stage = inst->fw_caps[STAGE].value; + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; u32 lcu_size; if (inst->codec == V4L2_PIX_FMT_HEVC) @@ -952,60 +676,6 @@ static u32 iris_vpu_enc_bin_size(struct iris_inst *inst) num_vpp_pipes, inst->hfi_rc_type); } -static inline u32 hfi_buffer_get_recon_count(struct iris_inst *inst) -{ - u32 layer_count = inst->hfi_layer_count; - u32 layer_type = inst->hfi_layer_type; - u32 bframe_count, ltr_count; - u32 num_ref = 1; - - bframe_count = inst->fw_caps[B_FRAME].value; - ltr_count = inst->fw_caps[LTR_COUNT].value; - - if (bframe_count) - num_ref = 2; - - /* The shift operation here is rounding logic, similar to [(x+1)/2]. */ - if (layer_type == HFI_HIER_P_HYBRID_LTR) - num_ref = (layer_count + 1) >> 1; - - if (layer_type == HFI_HIER_P_SLIDING_WINDOW) { - if (inst->codec == V4L2_PIX_FMT_HEVC) - num_ref = (layer_count + 1) >> 1; - else if (inst->codec == V4L2_PIX_FMT_H264 && layer_count < 4) - num_ref = (layer_count - 1); - else - num_ref = layer_count; - } - - if (ltr_count) - num_ref = num_ref + ltr_count; - - /* - * The expression (1 << layers - 2) + 1 accounts for the number of reference - * frames in the Adaptive Hierarchical B-frame encoding case. In this scheme, - * the number of frames in a sub-GOP is related to (2^(number of layers) - 1), - * hence the use of the shift operation. - */ - if (layer_type == HFI_HIER_B) { - if (inst->codec == V4L2_PIX_FMT_HEVC) - num_ref = layer_count; - else - num_ref = (1 << (layer_count - 2)) + 1; - } - - return num_ref; -} - -static u32 iris_vpu_dec_partial_size(struct iris_inst *inst) -{ - struct v4l2_format *f = inst->fmt_src; - u32 height = f->fmt.pix_mp.height; - u32 width = f->fmt.pix_mp.width; - - return hfi_buffer_ibc_av1d(width, height); -} - static inline u32 hfi_buffer_comv_enc(u32 frame_width, u32 frame_height, u32 lcu_size, u32 num_recon, u32 standard) @@ -1029,16 +699,20 @@ u32 hfi_buffer_comv_enc(u32 frame_width, u32 frame_height, u32 lcu_size, static u32 iris_vpu_enc_comv_size(struct iris_inst *inst) { - u32 height = iris_vpu_enc_get_bitstream_height(inst); - u32 width = iris_vpu_enc_get_bitstream_width(inst); - u32 num_recon = hfi_buffer_get_recon_count(inst); - u32 codec, lcu_size; + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + u32 num_recon = 1; + u32 lcu_size = 16; - codec = (inst->codec == V4L2_PIX_FMT_HEVC) ? - HFI_CODEC_ENCODE_HEVC : HFI_CODEC_ENCODE_AVC; - lcu_size = (inst->codec == V4L2_PIX_FMT_HEVC) ? 32 : 16; + if (inst->codec == V4L2_PIX_FMT_HEVC) { + lcu_size = 32; + return hfi_buffer_comv_enc(width, height, lcu_size, + num_recon + 1, HFI_CODEC_ENCODE_HEVC); + } - return hfi_buffer_comv_enc(width, height, lcu_size, num_recon + 1, codec); + return hfi_buffer_comv_enc(width, height, lcu_size, + num_recon + 1, HFI_CODEC_ENCODE_AVC); } static inline @@ -1193,27 +867,6 @@ u32 size_vpss_line_buf(u32 num_vpp_pipes_enc, u32 frame_height_coded, (((((max_t(u32, (frame_width_coded), (frame_height_coded)) + 3) >> 2) << 5) + 256) * 16)), 256); } -static inline -u32 size_vpss_line_buf_vpu33(u32 num_vpp_pipes_enc, u32 frame_height_coded, - u32 frame_width_coded) -{ - u32 vpss_4tap_top, vpss_4tap_left, vpss_div2_top; - u32 vpss_div2_left, vpss_top_lb, vpss_left_lb; - u32 size_left, size_top; - u32 max_width_height; - - max_width_height = max_t(u32, frame_width_coded, frame_height_coded); - vpss_4tap_top = ((((max_width_height * 2) + 3) >> 2) << 4) + 256; - vpss_4tap_left = (((8192 + 3) >> 2) << 5) + 64; - vpss_div2_top = (((max_width_height + 3) >> 2) << 4) + 256; - vpss_div2_left = ((((max_width_height * 2) + 3) >> 2) << 5) + 64; - vpss_top_lb = (frame_width_coded + 1) << 3; - vpss_left_lb = (frame_height_coded << 3) * num_vpp_pipes_enc; - size_left = (vpss_4tap_left + vpss_div2_left) * 2 * num_vpp_pipes_enc; - size_top = (vpss_4tap_top + vpss_div2_top) * 2; - - return ALIGN(size_left + size_top + vpss_top_lb + vpss_left_lb, DMA_ALIGNMENT); -} static inline u32 size_top_line_buf_first_stg_sao(u32 frame_width_coded) @@ -1307,8 +960,9 @@ u32 hfi_buffer_non_comv_enc(u32 frame_width, u32 frame_height, static u32 iris_vpu_enc_non_comv_size(struct iris_inst *inst) { u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; - u32 height = iris_vpu_enc_get_bitstream_height(inst); - u32 width = iris_vpu_enc_get_bitstream_width(inst); + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; u32 lcu_size = 16; if (inst->codec == V4L2_PIX_FMT_HEVC) { @@ -1323,8 +977,8 @@ static u32 iris_vpu_enc_non_comv_size(struct iris_inst *inst) } static inline -u32 hfi_buffer_line_enc_base(u32 frame_width, u32 frame_height, bool is_ten_bit, - u32 num_vpp_pipes_enc, u32 lcu_size, u32 standard) +u32 hfi_buffer_line_enc(u32 frame_width, u32 frame_height, bool is_ten_bit, + u32 num_vpp_pipes_enc, u32 lcu_size, u32 standard) { u32 width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); u32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); @@ -1364,43 +1018,16 @@ u32 hfi_buffer_line_enc_base(u32 frame_width, u32 frame_height, bool is_ten_bit, line_buff_recon_pix_size + size_left_linebuff_ctrl_fe(frame_height_coded, num_vpp_pipes_enc) + size_line_buf_sde(frame_width_coded) + + size_vpss_line_buf(num_vpp_pipes_enc, frame_height_coded, frame_width_coded) + size_top_line_buf_first_stg_sao(frame_width_coded); } -static inline -u32 hfi_buffer_line_enc(u32 frame_width, u32 frame_height, bool is_ten_bit, - u32 num_vpp_pipes_enc, u32 lcu_size, u32 standard) -{ - u32 width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); - u32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); - u32 frame_height_coded = height_in_lcus * (lcu_size); - u32 frame_width_coded = width_in_lcus * (lcu_size); - - return hfi_buffer_line_enc_base(frame_width, frame_height, is_ten_bit, - num_vpp_pipes_enc, lcu_size, standard) + - size_vpss_line_buf(num_vpp_pipes_enc, frame_height_coded, frame_width_coded); -} - -static inline -u32 hfi_buffer_line_enc_vpu33(u32 frame_width, u32 frame_height, bool is_ten_bit, - u32 num_vpp_pipes_enc, u32 lcu_size, u32 standard) -{ - u32 width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); - u32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); - u32 frame_height_coded = height_in_lcus * (lcu_size); - u32 frame_width_coded = width_in_lcus * (lcu_size); - - return hfi_buffer_line_enc_base(frame_width, frame_height, is_ten_bit, - num_vpp_pipes_enc, lcu_size, standard) + - size_vpss_line_buf_vpu33(num_vpp_pipes_enc, frame_height_coded, - frame_width_coded); -} - static u32 iris_vpu_enc_line_size(struct iris_inst *inst) { u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; - u32 height = iris_vpu_enc_get_bitstream_height(inst); - u32 width = iris_vpu_enc_get_bitstream_width(inst); + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; u32 lcu_size = 16; if (inst->codec == V4L2_PIX_FMT_HEVC) { @@ -1413,23 +1040,6 @@ static u32 iris_vpu_enc_line_size(struct iris_inst *inst) lcu_size, HFI_CODEC_ENCODE_AVC); } -static u32 iris_vpu33_enc_line_size(struct iris_inst *inst) -{ - u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; - u32 height = iris_vpu_enc_get_bitstream_height(inst); - u32 width = iris_vpu_enc_get_bitstream_width(inst); - u32 lcu_size = 16; - - if (inst->codec == V4L2_PIX_FMT_HEVC) { - lcu_size = 32; - return hfi_buffer_line_enc_vpu33(width, height, 0, num_vpp_pipes, - lcu_size, HFI_CODEC_ENCODE_HEVC); - } - - return hfi_buffer_line_enc_vpu33(width, height, 0, num_vpp_pipes, - lcu_size, HFI_CODEC_ENCODE_AVC); -} - static inline u32 hfi_buffer_dpb_enc(u32 frame_width, u32 frame_height, bool is_ten_bit) { @@ -1477,11 +1087,10 @@ static u32 iris_vpu_enc_arp_size(struct iris_inst *inst) inline bool is_scaling_enabled(struct iris_inst *inst) { - struct v4l2_pix_format_mplane *dst_fmt = &inst->fmt_dst->fmt.pix_mp; - struct v4l2_pix_format_mplane *src_fmt = &inst->fmt_src->fmt.pix_mp; - - return dst_fmt->width != src_fmt->width || - dst_fmt->height != src_fmt->height; + return inst->crop.left != inst->compose.left || + inst->crop.top != inst->compose.top || + inst->crop.width != inst->compose.width || + inst->crop.height != inst->compose.height; } static inline @@ -1638,8 +1247,9 @@ static inline u32 hfi_buffer_scratch1_enc(u32 frame_width, u32 frame_height, static u32 iris_vpu_enc_scratch1_size(struct iris_inst *inst) { u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; - u32 frame_height = iris_vpu_enc_get_bitstream_height(inst); - u32 frame_width = iris_vpu_enc_get_bitstream_width(inst); + struct v4l2_format *f = inst->fmt_dst; + u32 frame_height = f->fmt.pix_mp.height; + u32 frame_width = f->fmt.pix_mp.width; u32 num_ref = 1; u32 lcu_size; bool is_h265; @@ -1735,11 +1345,13 @@ static inline u32 hfi_buffer_scratch2_enc(u32 frame_width, u32 frame_height, static u32 iris_vpu_enc_scratch2_size(struct iris_inst *inst) { - u32 frame_height = iris_vpu_enc_get_bitstream_height(inst); - u32 frame_width = iris_vpu_enc_get_bitstream_width(inst); - u32 num_ref = hfi_buffer_get_recon_count(inst); + struct v4l2_format *f = inst->fmt_dst; + u32 frame_width = f->fmt.pix_mp.width; + u32 frame_height = f->fmt.pix_mp.height; + u32 num_ref = 1; - return hfi_buffer_scratch2_enc(frame_width, frame_height, num_ref, false); + return hfi_buffer_scratch2_enc(frame_width, frame_height, num_ref, + false); } static u32 iris_vpu_enc_vpss_size(struct iris_inst *inst) @@ -1752,313 +1364,13 @@ static u32 iris_vpu_enc_vpss_size(struct iris_inst *inst) return hfi_buffer_vpss_enc(width, height, ds_enable, 0, 0); } -static inline u32 size_dpb_opb(u32 height, u32 lcu_size) -{ - u32 max_tile_height = ((height + lcu_size - 1) / lcu_size) * lcu_size + 8; - u32 dpb_opb = 3 * ((max_tile_height >> 3) * DMA_ALIGNMENT); - u32 num_luma_chrome_plane = 2; - - return ALIGN(dpb_opb, DMA_ALIGNMENT) * num_luma_chrome_plane; -} - -static u32 hfi_vpu4x_vp9d_lb_size(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) -{ - u32 vp9_top_lb, vp9_fe_left_lb, vp9_se_left_lb, dpb_opb, vp9d_qp, num_lcu_per_pipe; - u32 lcu_size = 64; - - vp9_top_lb = ALIGN(size_vp9d_lb_vsp_top(frame_width, frame_height), DMA_ALIGNMENT); - vp9_top_lb += ALIGN(size_vpxd_lb_se_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT); - vp9_top_lb += max3(DIV_ROUND_UP(frame_width, BUFFER_ALIGNMENT_16_BYTES) * - MAX_PE_NBR_DATA_LCU16_LINE_BUFFER_SIZE, - DIV_ROUND_UP(frame_width, BUFFER_ALIGNMENT_32_BYTES) * - MAX_PE_NBR_DATA_LCU32_LINE_BUFFER_SIZE, - DIV_ROUND_UP(frame_width, BUFFER_ALIGNMENT_64_BYTES) * - MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE); - vp9_top_lb = ALIGN(vp9_top_lb, DMA_ALIGNMENT); - vp9_top_lb += ALIGN((DMA_ALIGNMENT * DIV_ROUND_UP(frame_width, lcu_size)), - DMA_ALIGNMENT) * FE_TOP_CTRL_LINE_NUMBERS; - vp9_top_lb += ALIGN(DMA_ALIGNMENT * 8 * DIV_ROUND_UP(frame_width, lcu_size), - DMA_ALIGNMENT) * (FE_TOP_DATA_LUMA_LINE_NUMBERS + - FE_TOP_DATA_CHROMA_LINE_NUMBERS); - - num_lcu_per_pipe = (DIV_ROUND_UP(frame_height, lcu_size) / num_vpp_pipes) + - (DIV_ROUND_UP(frame_height, lcu_size) % num_vpp_pipes); - vp9_fe_left_lb = ALIGN((DMA_ALIGNMENT * num_lcu_per_pipe), DMA_ALIGNMENT) * - FE_LFT_CTRL_LINE_NUMBERS; - vp9_fe_left_lb += ((ALIGN((DMA_ALIGNMENT * 8 * num_lcu_per_pipe), DMA_ALIGNMENT) * - FE_LFT_DB_DATA_LINE_NUMBERS) + - ALIGN((DMA_ALIGNMENT * 3 * num_lcu_per_pipe), DMA_ALIGNMENT) + - ALIGN((DMA_ALIGNMENT * 4 * num_lcu_per_pipe), DMA_ALIGNMENT) + - (ALIGN((DMA_ALIGNMENT * 24 * num_lcu_per_pipe), DMA_ALIGNMENT) * - FE_LFT_LR_DATA_LINE_NUMBERS)); - vp9_fe_left_lb = vp9_fe_left_lb * num_vpp_pipes; - - vp9_se_left_lb = ALIGN(size_vpxd_lb_se_left_ctrl(frame_width, frame_height), - DMA_ALIGNMENT); - dpb_opb = size_dpb_opb(frame_height, lcu_size); - vp9d_qp = ALIGN(size_vp9d_qp(frame_width, frame_height), DMA_ALIGNMENT); - - return vp9_top_lb + vp9_fe_left_lb + (vp9_se_left_lb * num_vpp_pipes) + - (dpb_opb * num_vpp_pipes) + vp9d_qp; -} - -static u32 hfi_vpu4x_buffer_line_vp9d(u32 frame_width, u32 frame_height, u32 _yuv_bufcount_min, - bool is_opb, u32 num_vpp_pipes) -{ - u32 lb_size = hfi_vpu4x_vp9d_lb_size(frame_width, frame_height, num_vpp_pipes); - u32 dpb_obp_size = 0, lcu_size = 64; - - if (is_opb) - dpb_obp_size = size_dpb_opb(frame_height, lcu_size) * num_vpp_pipes; - - return lb_size + dpb_obp_size; -} - -static u32 iris_vpu4x_dec_line_size(struct iris_inst *inst) -{ - u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; - u32 out_min_count = inst->buffers[BUF_OUTPUT].min_count; - struct v4l2_format *f = inst->fmt_src; - u32 height = f->fmt.pix_mp.height; - u32 width = f->fmt.pix_mp.width; - bool is_opb = false; - - if (iris_split_mode_enabled(inst)) - is_opb = true; - - if (inst->codec == V4L2_PIX_FMT_H264) - return hfi_buffer_line_h264d(width, height, is_opb, num_vpp_pipes); - else if (inst->codec == V4L2_PIX_FMT_HEVC) - return hfi_buffer_line_h265d(width, height, is_opb, num_vpp_pipes); - else if (inst->codec == V4L2_PIX_FMT_VP9) - return hfi_vpu4x_buffer_line_vp9d(width, height, out_min_count, is_opb, - num_vpp_pipes); - - return 0; -} - -static u32 hfi_vpu4x_buffer_persist_h265d(u32 rpu_enabled) -{ - return ALIGN((SIZE_SLIST_BUF_H265 * NUM_SLIST_BUF_H265 + H265_NUM_FRM_INFO * - H265_DISPLAY_BUF_SIZE + (H265_NUM_TILE * sizeof(u32)) + (NUM_HW_PIC_BUF * - (SIZE_SEI_USERDATA + SIZE_H265D_ARP + SIZE_THREE_DIMENSION_USERDATA)) + - rpu_enabled * NUM_HW_PIC_BUF * SIZE_DOLBY_RPU_METADATA), DMA_ALIGNMENT); -} - -static u32 hfi_vpu4x_buffer_persist_vp9d(void) -{ - return ALIGN(VP9_NUM_PROBABILITY_TABLE_BUF * VP9_PROB_TABLE_SIZE, DMA_ALIGNMENT) + - (ALIGN(hfi_iris3_vp9d_comv_size(), DMA_ALIGNMENT) * 2) + - ALIGN(MAX_SUPERFRAME_HEADER_LEN, DMA_ALIGNMENT) + - ALIGN(VP9_UDC_HEADER_BUF_SIZE, DMA_ALIGNMENT) + - ALIGN(VP9_NUM_FRAME_INFO_BUF * CCE_TILE_OFFSET_SIZE, DMA_ALIGNMENT) + - ALIGN(VP9_NUM_FRAME_INFO_BUF * VP9_FRAME_INFO_BUF_SIZE_VPU4X, DMA_ALIGNMENT) + - HDR10_HIST_EXTRADATA_SIZE; -} - -static u32 iris_vpu4x_dec_persist_size(struct iris_inst *inst) -{ - if (inst->codec == V4L2_PIX_FMT_H264) - return hfi_buffer_persist_h264d(); - else if (inst->codec == V4L2_PIX_FMT_HEVC) - return hfi_vpu4x_buffer_persist_h265d(0); - else if (inst->codec == V4L2_PIX_FMT_VP9) - return hfi_vpu4x_buffer_persist_vp9d(); - - return 0; -} - -static u32 size_se_lb(u32 standard, u32 num_vpp_pipes_enc, - u32 frame_width_coded, u32 frame_height_coded) -{ - u32 se_tlb_size = ALIGN(frame_width_coded, DMA_ALIGNMENT); - u32 se_llb_size = (standard == HFI_CODEC_ENCODE_HEVC) ? - ((frame_height_coded + BUFFER_ALIGNMENT_32_BYTES - 1) / - BUFFER_ALIGNMENT_32_BYTES) * LOG2_16 * LLB_UNIT_SIZE : - ((frame_height_coded + BUFFER_ALIGNMENT_16_BYTES - 1) / - BUFFER_ALIGNMENT_16_BYTES) * LOG2_32 * LLB_UNIT_SIZE; - - se_llb_size = ALIGN(se_llb_size, BUFFER_ALIGNMENT_32_BYTES); - - if (num_vpp_pipes_enc > 1) - se_llb_size = ALIGN(se_llb_size + BUFFER_ALIGNMENT_512_BYTES, - DMA_ALIGNMENT) * num_vpp_pipes_enc; - - return ALIGN(se_tlb_size + se_llb_size, DMA_ALIGNMENT); -} - -static u32 size_te_lb(bool is_ten_bit, u32 num_vpp_pipes_enc, u32 width_in_lcus, - u32 frame_height_coded, u32 frame_width_coded) -{ - u32 num_pixel_10_bit = 3, num_pixel_8_bit = 2, num_pixel_te_llb = 3; - u32 te_llb_col_rc_size = ALIGN(32 * width_in_lcus / num_vpp_pipes_enc, - DMA_ALIGNMENT) * num_vpp_pipes_enc; - u32 te_tlb_recon_data_size = ALIGN((is_ten_bit ? num_pixel_10_bit : num_pixel_8_bit) * - frame_width_coded, DMA_ALIGNMENT); - u32 te_llb_recon_data_size = ((1 + is_ten_bit) * num_pixel_te_llb * frame_height_coded + - num_vpp_pipes_enc - 1) / num_vpp_pipes_enc; - te_llb_recon_data_size = ALIGN(te_llb_recon_data_size, DMA_ALIGNMENT) * num_vpp_pipes_enc; - - return ALIGN(te_llb_recon_data_size + te_llb_col_rc_size + te_tlb_recon_data_size, - DMA_ALIGNMENT); -} - -static inline u32 calc_fe_tlb_size(u32 size_per_lcu, bool is_ten_bit) -{ - u32 num_pixels_fe_tlb_10_bit = 128, num_pixels_fe_tlb_8_bit = 64; - - return is_ten_bit ? (num_pixels_fe_tlb_10_bit * (size_per_lcu + 1)) : - (size_per_lcu * num_pixels_fe_tlb_8_bit); -} - -static u32 size_fe_lb(bool is_ten_bit, u32 standard, u32 num_vpp_pipes_enc, - u32 frame_height_coded, u32 frame_width_coded) -{ - u32 log2_lcu_size, num_cu_in_height_pipe, num_cu_in_width, - fb_llb_db_ctrl_size, fb_llb_db_luma_size, fb_llb_db_chroma_size, - fb_tlb_db_ctrl_size, fb_tlb_db_luma_size, fb_tlb_db_chroma_size, - fb_llb_sao_ctrl_size, fb_llb_sao_luma_size, fb_llb_sao_chroma_size, - fb_tlb_sao_ctrl_size, fb_tlb_sao_luma_size, fb_tlb_sao_chroma_size, - fb_lb_top_sdc_size, fb_lb_se_ctrl_size, fe_tlb_size, size_per_lcu; - - log2_lcu_size = (standard == HFI_CODEC_ENCODE_HEVC) ? 5 : 4; - num_cu_in_height_pipe = ((frame_height_coded >> log2_lcu_size) + num_vpp_pipes_enc - 1) / - num_vpp_pipes_enc; - num_cu_in_width = frame_width_coded >> log2_lcu_size; - - size_per_lcu = 2; - fe_tlb_size = calc_fe_tlb_size(size_per_lcu, 1); - fb_llb_db_ctrl_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_height_pipe; - fb_llb_db_ctrl_size = ALIGN(fb_llb_db_ctrl_size, DMA_ALIGNMENT) * num_vpp_pipes_enc; - - size_per_lcu = (1 << (log2_lcu_size - 3)); - fe_tlb_size = calc_fe_tlb_size(size_per_lcu, is_ten_bit); - fb_llb_db_luma_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_height_pipe; - fb_llb_db_luma_size = ALIGN(fb_llb_db_luma_size, DMA_ALIGNMENT) * num_vpp_pipes_enc; - - size_per_lcu = ((1 << (log2_lcu_size - 4)) * 2); - fe_tlb_size = calc_fe_tlb_size(size_per_lcu, is_ten_bit); - fb_llb_db_chroma_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_height_pipe; - fb_llb_db_chroma_size = ALIGN(fb_llb_db_chroma_size, DMA_ALIGNMENT) * num_vpp_pipes_enc; - - size_per_lcu = 1; - fe_tlb_size = calc_fe_tlb_size(size_per_lcu, 1); - fb_tlb_db_ctrl_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_width; - fb_llb_sao_ctrl_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_height_pipe; - fb_llb_sao_ctrl_size = fb_llb_sao_ctrl_size * num_vpp_pipes_enc; - fb_tlb_sao_ctrl_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_width; - - size_per_lcu = ((1 << (log2_lcu_size - 3)) + 1); - fe_tlb_size = calc_fe_tlb_size(size_per_lcu, is_ten_bit); - fb_tlb_db_luma_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_width; - - size_per_lcu = (2 * ((1 << (log2_lcu_size - 4)) + 1)); - fe_tlb_size = calc_fe_tlb_size(size_per_lcu, is_ten_bit); - fb_tlb_db_chroma_size = ALIGN(fe_tlb_size, DMA_ALIGNMENT) * num_cu_in_width; - - fb_llb_sao_luma_size = BUFFER_ALIGNMENT_256_BYTES * num_vpp_pipes_enc; - fb_llb_sao_chroma_size = BUFFER_ALIGNMENT_256_BYTES * num_vpp_pipes_enc; - fb_tlb_sao_luma_size = BUFFER_ALIGNMENT_256_BYTES; - fb_tlb_sao_chroma_size = BUFFER_ALIGNMENT_256_BYTES; - fb_lb_top_sdc_size = ALIGN((FE_SDC_DATA_PER_BLOCK * (frame_width_coded >> 5)), - DMA_ALIGNMENT); - fb_lb_se_ctrl_size = ALIGN((SE_CTRL_DATA_PER_BLOCK * (frame_width_coded >> 5)), - DMA_ALIGNMENT); - - return fb_llb_db_ctrl_size + fb_llb_db_luma_size + fb_llb_db_chroma_size + - fb_tlb_db_ctrl_size + fb_tlb_db_luma_size + fb_tlb_db_chroma_size + - fb_llb_sao_ctrl_size + fb_llb_sao_luma_size + fb_llb_sao_chroma_size + - fb_tlb_sao_ctrl_size + fb_tlb_sao_luma_size + fb_tlb_sao_chroma_size + - fb_lb_top_sdc_size + fb_lb_se_ctrl_size; -} - -static u32 size_md_lb(u32 standard, u32 frame_width_coded, - u32 frame_height_coded, u32 num_vpp_pipes_enc) -{ - u32 md_tlb_size = ALIGN(frame_width_coded, DMA_ALIGNMENT); - u32 md_llb_size = (standard == HFI_CODEC_ENCODE_HEVC) ? - ((frame_height_coded + BUFFER_ALIGNMENT_32_BYTES - 1) / - BUFFER_ALIGNMENT_32_BYTES) * LOG2_16 * LLB_UNIT_SIZE : - ((frame_height_coded + BUFFER_ALIGNMENT_16_BYTES - 1) / - BUFFER_ALIGNMENT_16_BYTES) * LOG2_32 * LLB_UNIT_SIZE; - - md_llb_size = ALIGN(md_llb_size, BUFFER_ALIGNMENT_32_BYTES); - - if (num_vpp_pipes_enc > 1) - md_llb_size = ALIGN(md_llb_size + BUFFER_ALIGNMENT_512_BYTES, - DMA_ALIGNMENT) * num_vpp_pipes_enc; - - md_llb_size = ALIGN(md_llb_size, DMA_ALIGNMENT); - - return ALIGN(md_tlb_size + md_llb_size, DMA_ALIGNMENT); -} - -static u32 size_dma_opb_lb(u32 num_vpp_pipes_enc, u32 frame_width_coded, - u32 frame_height_coded) -{ - u32 opb_packet_bytes = 128, opb_bpp = 128, opb_size_per_row = 6; - u32 dma_opb_wr_tlb_y_size = DIV_ROUND_UP(frame_width_coded, 16) * opb_packet_bytes; - u32 dma_opb_wr_tlb_uv_size = DIV_ROUND_UP(frame_width_coded, 16) * opb_packet_bytes; - u32 dma_opb_wr2_tlb_y_size = ALIGN((opb_bpp * opb_size_per_row * frame_height_coded / 8), - DMA_ALIGNMENT) * num_vpp_pipes_enc; - u32 dma_opb_wr2_tlb_uv_size = ALIGN((opb_bpp * opb_size_per_row * frame_height_coded / 8), - DMA_ALIGNMENT) * num_vpp_pipes_enc; - - dma_opb_wr2_tlb_y_size = max(dma_opb_wr2_tlb_y_size, dma_opb_wr_tlb_y_size << 1); - dma_opb_wr2_tlb_uv_size = max(dma_opb_wr2_tlb_uv_size, dma_opb_wr_tlb_uv_size << 1); - - return ALIGN(dma_opb_wr_tlb_y_size + dma_opb_wr_tlb_uv_size + dma_opb_wr2_tlb_y_size + - dma_opb_wr2_tlb_uv_size, DMA_ALIGNMENT); -} - -static u32 hfi_vpu4x_buffer_line_enc(u32 frame_width, u32 frame_height, - bool is_ten_bit, u32 num_vpp_pipes_enc, - u32 lcu_size, u32 standard) -{ - u32 width_in_lcus = (frame_width + lcu_size - 1) / lcu_size; - u32 height_in_lcus = (frame_height + lcu_size - 1) / lcu_size; - u32 frame_width_coded = width_in_lcus * lcu_size; - u32 frame_height_coded = height_in_lcus * lcu_size; - - u32 se_lb_size = size_se_lb(standard, num_vpp_pipes_enc, frame_width_coded, - frame_height_coded); - u32 te_lb_size = size_te_lb(is_ten_bit, num_vpp_pipes_enc, width_in_lcus, - frame_height_coded, frame_width_coded); - u32 fe_lb_size = size_fe_lb(is_ten_bit, standard, num_vpp_pipes_enc, frame_height_coded, - frame_width_coded); - u32 md_lb_size = size_md_lb(standard, frame_width_coded, frame_height_coded, - num_vpp_pipes_enc); - u32 dma_opb_lb_size = size_dma_opb_lb(num_vpp_pipes_enc, frame_width_coded, - frame_height_coded); - u32 dse_lb_size = ALIGN((256 + (16 * (frame_width_coded >> 4))), DMA_ALIGNMENT); - u32 size_vpss_lb_enc = size_vpss_line_buf_vpu33(num_vpp_pipes_enc, frame_width_coded, - frame_height_coded); - - return se_lb_size + te_lb_size + fe_lb_size + md_lb_size + dma_opb_lb_size + - dse_lb_size + size_vpss_lb_enc; -} - -static u32 iris_vpu4x_enc_line_size(struct iris_inst *inst) -{ - u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; - u32 lcu_size = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; - struct v4l2_format *f = inst->fmt_dst; - u32 height = f->fmt.pix_mp.height; - u32 width = f->fmt.pix_mp.width; - - return hfi_vpu4x_buffer_line_enc(width, height, 0, num_vpp_pipes, - lcu_size, inst->codec); -} - static int output_min_count(struct iris_inst *inst) { int output_min_count = 4; /* fw_min_count > 0 indicates reconfig event has already arrived */ if (inst->fw_min_count) { - if (iris_split_mode_enabled(inst) && - (inst->codec == V4L2_PIX_FMT_VP9 || - inst->codec == V4L2_PIX_FMT_AV1)) + if (iris_split_mode_enabled(inst) && inst->codec == V4L2_PIX_FMT_VP9) return min_t(u32, 4, inst->fw_min_count); else return inst->fw_min_count; @@ -2066,8 +1378,6 @@ static int output_min_count(struct iris_inst *inst) if (inst->codec == V4L2_PIX_FMT_VP9) output_min_count = 9; - else if (inst->codec == V4L2_PIX_FMT_AV1) - output_min_count = 11; return output_min_count; } @@ -2077,20 +1387,19 @@ struct iris_vpu_buf_type_handle { u32 (*handle)(struct iris_inst *inst); }; -u32 iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) +int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) { const struct iris_vpu_buf_type_handle *buf_type_handle_arr = NULL; u32 size = 0, buf_type_handle_size = 0, i; static const struct iris_vpu_buf_type_handle dec_internal_buf_type_handle[] = { {BUF_BIN, iris_vpu_dec_bin_size }, - {BUF_COMV, iris_vpu3x_4x_dec_comv_size }, + {BUF_COMV, iris_vpu_dec_comv_size }, {BUF_NON_COMV, iris_vpu_dec_non_comv_size }, {BUF_LINE, iris_vpu_dec_line_size }, {BUF_PERSIST, iris_vpu_dec_persist_size }, {BUF_DPB, iris_vpu_dec_dpb_size }, {BUF_SCRATCH_1, iris_vpu_dec_scratch1_size }, - {BUF_PARTIAL, iris_vpu_dec_partial_size }, }; static const struct iris_vpu_buf_type_handle enc_internal_buf_type_handle[] = { @@ -2122,78 +1431,6 @@ u32 iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) return size; } -u32 iris_vpu33_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) -{ - u32 size = 0, i; - - static const struct iris_vpu_buf_type_handle enc_internal_buf_type_handle[] = { - {BUF_BIN, iris_vpu_enc_bin_size }, - {BUF_COMV, iris_vpu_enc_comv_size }, - {BUF_NON_COMV, iris_vpu_enc_non_comv_size }, - {BUF_LINE, iris_vpu33_enc_line_size }, - {BUF_ARP, iris_vpu_enc_arp_size }, - {BUF_VPSS, iris_vpu_enc_vpss_size }, - {BUF_SCRATCH_1, iris_vpu_enc_scratch1_size }, - {BUF_SCRATCH_2, iris_vpu_enc_scratch2_size }, - }; - - if (inst->domain == DECODER) - return iris_vpu_buf_size(inst, buffer_type); - - for (i = 0; i < ARRAY_SIZE(enc_internal_buf_type_handle); i++) { - if (enc_internal_buf_type_handle[i].type == buffer_type) { - size = enc_internal_buf_type_handle[i].handle(inst); - break; - } - } - - return size; -} - -u32 iris_vpu4x_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) -{ - const struct iris_vpu_buf_type_handle *buf_type_handle_arr = NULL; - u32 size = 0, buf_type_handle_size = 0, i; - - static const struct iris_vpu_buf_type_handle dec_internal_buf_type_handle[] = { - {BUF_BIN, iris_vpu_dec_bin_size }, - {BUF_COMV, iris_vpu3x_4x_dec_comv_size }, - {BUF_NON_COMV, iris_vpu_dec_non_comv_size }, - {BUF_LINE, iris_vpu4x_dec_line_size }, - {BUF_PERSIST, iris_vpu4x_dec_persist_size }, - {BUF_DPB, iris_vpu_dec_dpb_size }, - {BUF_SCRATCH_1, iris_vpu_dec_scratch1_size }, - }; - - static const struct iris_vpu_buf_type_handle enc_internal_buf_type_handle[] = { - {BUF_BIN, iris_vpu_enc_bin_size }, - {BUF_COMV, iris_vpu_enc_comv_size }, - {BUF_NON_COMV, iris_vpu_enc_non_comv_size }, - {BUF_LINE, iris_vpu4x_enc_line_size }, - {BUF_ARP, iris_vpu_enc_arp_size }, - {BUF_VPSS, iris_vpu_enc_vpss_size }, - {BUF_SCRATCH_1, iris_vpu_enc_scratch1_size }, - {BUF_SCRATCH_2, iris_vpu_enc_scratch2_size }, - }; - - if (inst->domain == DECODER) { - buf_type_handle_size = ARRAY_SIZE(dec_internal_buf_type_handle); - buf_type_handle_arr = dec_internal_buf_type_handle; - } else if (inst->domain == ENCODER) { - buf_type_handle_size = ARRAY_SIZE(enc_internal_buf_type_handle); - buf_type_handle_arr = enc_internal_buf_type_handle; - } - - for (i = 0; i < buf_type_handle_size; i++) { - if (buf_type_handle_arr[i].type == buffer_type) { - size = buf_type_handle_arr[i].handle(inst); - break; - } - } - - return size; -} - static u32 internal_buffer_count(struct iris_inst *inst, enum iris_buffer_type buffer_type) { @@ -2201,20 +1438,14 @@ static u32 internal_buffer_count(struct iris_inst *inst, buffer_type == BUF_PERSIST) { return 1; } else if (buffer_type == BUF_COMV || buffer_type == BUF_NON_COMV) { - if (inst->codec == V4L2_PIX_FMT_H264 || - inst->codec == V4L2_PIX_FMT_HEVC || - inst->codec == V4L2_PIX_FMT_AV1) + if (inst->codec == V4L2_PIX_FMT_H264 || inst->codec == V4L2_PIX_FMT_HEVC) return 1; } - return 0; } static inline int iris_vpu_dpb_count(struct iris_inst *inst) { - if (inst->codec == V4L2_PIX_FMT_AV1) - return 11; - if (iris_split_mode_enabled(inst)) { return inst->fw_min_count ? inst->fw_min_count : inst->buffers[BUF_OUTPUT].min_count; @@ -2233,13 +1464,9 @@ int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type return MIN_BUFFERS; else return output_min_count(inst); - case BUF_NON_COMV: - if (inst->codec == V4L2_PIX_FMT_AV1) - return 0; - else - return 1; case BUF_BIN: case BUF_COMV: + case BUF_NON_COMV: case BUF_LINE: case BUF_PERSIST: return internal_buffer_count(inst, buffer_type); @@ -2247,7 +1474,6 @@ int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type case BUF_SCRATCH_2: case BUF_VPSS: case BUF_ARP: - case BUF_PARTIAL: return 1; /* internal buffer count needed by firmware is 1 */ case BUF_DPB: return iris_vpu_dpb_count(inst); diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h index 8c0d6b7b5de8..94668c5b3d15 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h +++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h @@ -11,7 +11,6 @@ struct iris_inst; #define MIN_BUFFERS 4 #define DMA_ALIGNMENT 256 -#define HFI_ALIGNMENT_4096 4096 #define NUM_HW_PIC_BUF 32 #define LCU_MAX_SIZE_PELS 64 @@ -48,12 +47,7 @@ struct iris_inst; #define VP9_NUM_PROBABILITY_TABLE_BUF (VP9_NUM_FRAME_INFO_BUF + 4) #define VP9_PROB_TABLE_SIZE (3840) #define VP9_FRAME_INFO_BUF_SIZE (6144) -#define VP9_FRAME_INFO_BUF_SIZE_VPU4X (6400) -#define BUFFER_ALIGNMENT_16_BYTES 16 #define BUFFER_ALIGNMENT_32_BYTES 32 -#define BUFFER_ALIGNMENT_64_BYTES 64 -#define BUFFER_ALIGNMENT_256_BYTES 256 -#define BUFFER_ALIGNMENT_512_BYTES 512 #define CCE_TILE_OFFSET_SIZE ALIGN(32 * 4 * 4, BUFFER_ALIGNMENT_32_BYTES) #define MAX_SUPERFRAME_HEADER_LEN (34) #define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64 @@ -67,13 +61,11 @@ struct iris_inst; #define SIZE_DOLBY_RPU_METADATA (41 * 1024) #define H264_CABAC_HDR_RATIO_HD_TOT 1 #define H264_CABAC_RES_RATIO_HD_TOT 3 -#define H265D_MAX_SLICE 3600 +#define H265D_MAX_SLICE 1200 #define SIZE_H265D_HW_PIC_T SIZE_H264D_HW_PIC_T #define H265_CABAC_HDR_RATIO_HD_TOT 2 #define H265_CABAC_RES_RATIO_HD_TOT 2 #define SIZE_H265D_VPP_CMD_PER_BUF (256) -#define SIZE_THREE_DIMENSION_USERDATA 768 -#define SIZE_H265D_ARP 9728 #define VPX_DECODER_FRAME_CONCURENCY_LVL (2) #define VPX_DECODER_FRAME_BIN_HDR_BUDGET 1 @@ -84,39 +76,11 @@ struct iris_inst; #define SIZE_H264D_HW_PIC_T (BIT(11)) -#define FE_LFT_CTRL_LINE_NUMBERS 4 -#define FE_LFT_DB_DATA_LINE_NUMBERS 2 -#define FE_LFT_LR_DATA_LINE_NUMBERS 4 -#define FE_TOP_CTRL_LINE_NUMBERS 3 -#define FE_TOP_DATA_LUMA_LINE_NUMBERS 2 -#define FE_TOP_DATA_CHROMA_LINE_NUMBERS 3 -#define FE_SDC_DATA_PER_BLOCK 16 -#define SE_CTRL_DATA_PER_BLOCK 2020 - -#define MAX_PE_NBR_DATA_LCU16_LINE_BUFFER_SIZE 96 -#define MAX_PE_NBR_DATA_LCU32_LINE_BUFFER_SIZE 192 - #define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64 #define MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 16 #define MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE 384 #define MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE 640 -#define AV1_CABAC_HDR_RATIO_HD_TOT 2 -#define AV1_CABAC_RES_RATIO_HD_TOT 2 -#define AV1D_LCU_MAX_SIZE_PELS 128 -#define AV1D_LCU_MIN_SIZE_PELS 64 -#define AV1D_MAX_TILE_COLS 64 -#define MAX_PE_NBR_DATA_LCU32_LINE_BUFFER_SIZE 192 -#define MAX_PE_NBR_DATA_LCU16_LINE_BUFFER_SIZE 96 -#define AV1D_NUM_HW_PIC_BUF 16 -#define AV1D_NUM_FRAME_HEADERS 16 -#define SIZE_AV1D_SEQUENCE_HEADER 768 -#define SIZE_AV1D_METADATA 512 -#define SIZE_AV1D_FRAME_HEADER 1280 -#define SIZE_AV1D_TILE_OFFSET 65536 -#define SIZE_AV1D_QM 3328 -#define SIZE_AV1D_PROB_TABLE 22784 - #define SIZE_SLICE_CMD_BUFFER (ALIGN(20480, 256)) #define SIZE_SPS_PPS_SLICE_HDR (2048 + 4096) #define SIZE_BSE_SLICE_CMD_BUF ((((8192 << 2) + 7) & (~7)) * 3) @@ -132,24 +96,11 @@ struct iris_inst; #define HFI_BUFFER_ARP_ENC 204800 -#define LOG2_16 4 -#define LOG2_32 5 -#define LLB_UNIT_SIZE 16 - #define MAX_WIDTH 4096 #define MAX_HEIGHT 2304 #define NUM_MBS_4K (DIV_ROUND_UP(MAX_WIDTH, 16) * DIV_ROUND_UP(MAX_HEIGHT, 16)) #define NUM_MBS_720P (((ALIGN(1280, 16)) >> 4) * ((ALIGN(736, 16)) >> 4)) -#define BITS_PER_PIX 16 -#define NUM_LINES_LUMA 10 -#define NUM_LINES_CHROMA 6 -#define AV1D_LCU_MAX_SIZE_PELS 128 -#define AV1D_LCU_MIN_SIZE_PELS 64 -#define AV1D_MAX_TILE_COLS 64 -#define BITS_PER_CTRL_PACK 128 -#define NUM_CTRL_PACK_LCU 10 - static inline u32 size_h264d_lb_fe_top_data(u32 frame_width) { return MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * ALIGN(frame_width, 16) * 3; @@ -195,99 +146,7 @@ static inline u32 size_h264d_qp(u32 frame_width, u32 frame_height) return DIV_ROUND_UP(frame_width, 64) * DIV_ROUND_UP(frame_height, 64) * 128; } -static inline u32 size_av1d_lb_fe_top_data(u32 frame_width, u32 frame_height) -{ - return (ALIGN(frame_width, AV1D_LCU_MAX_SIZE_PELS) * - ((BITS_PER_PIX * NUM_LINES_LUMA) >> 3) + - ALIGN(frame_width, AV1D_LCU_MAX_SIZE_PELS) / 2 * - ((BITS_PER_PIX * NUM_LINES_CHROMA) >> 3) * 2); -} - -static inline u32 size_av1d_lb_fe_left_data(u32 frame_width, u32 frame_height) -{ - return (32 * (ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) + - ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / - AV1D_LCU_MIN_SIZE_PELS * 16) + - 16 * (ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / 2 + - ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / - AV1D_LCU_MIN_SIZE_PELS * 8) * 2 + - 24 * (ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) + - ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / - AV1D_LCU_MIN_SIZE_PELS * 16) + - 24 * (ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / 2 + - ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / - AV1D_LCU_MIN_SIZE_PELS * 12) * 2 + - 24 * (ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) + - ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / - AV1D_LCU_MIN_SIZE_PELS * 16) + - 16 * (ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) + - ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / - AV1D_LCU_MIN_SIZE_PELS * 16) + - 16 * (ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / 2 + - ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / - AV1D_LCU_MIN_SIZE_PELS * 12) * 2); -} - -static inline u32 size_av1d_lb_fe_top_ctrl(u32 frame_width, u32 frame_height) -{ - return (NUM_CTRL_PACK_LCU * ((frame_width + AV1D_LCU_MIN_SIZE_PELS - 1) / - AV1D_LCU_MIN_SIZE_PELS) * BITS_PER_CTRL_PACK / 8); -} - -static inline u32 size_av1d_lb_fe_left_ctrl(u32 frame_width, u32 frame_height) -{ - return (16 * ((ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / 16) + - (ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / - AV1D_LCU_MIN_SIZE_PELS)) + - 3 * 16 * (ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / - AV1D_LCU_MIN_SIZE_PELS)); -} - -static inline u32 size_av1d_lb_se_top_ctrl(u32 frame_width, u32 frame_height) -{ - return (((frame_width + 7) / 8) * MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE); -} - -static inline u32 size_av1d_lb_se_left_ctrl(u32 frame_width, u32 frame_height) -{ - return (max(((frame_height + 15) / 16) * - MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, - max(((frame_height + 31) / 32) * - MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, - ((frame_height + 63) / 64) * - MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE))); -} - -static inline u32 size_av1d_lb_pe_top_data(u32 frame_width, u32 frame_height) -{ - return (max(((frame_width + 15) / 16) * - MAX_PE_NBR_DATA_LCU16_LINE_BUFFER_SIZE, - max(((frame_width + 31) / 32) * - MAX_PE_NBR_DATA_LCU32_LINE_BUFFER_SIZE, - ((frame_width + 63) / 64) * - MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE))); -} - -static inline u32 size_av1d_lb_vsp_top(u32 frame_width, u32 frame_height) -{ - return (max(((frame_width + 63) / 64) * 1280, - ((frame_width + 127) / 128) * MAX_HEIGHT)); -} - -static inline u32 size_av1d_lb_recon_dma_metadata_wr(u32 frame_width, - u32 frame_height) -{ - return ((ALIGN(frame_height, 8) / (4 / 2)) * 64); -} - -static inline u32 size_av1d_qp(u32 frame_width, u32 frame_height) -{ - return size_h264d_qp(frame_width, frame_height); -} - -u32 iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); -u32 iris_vpu33_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); -u32 iris_vpu4x_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); +int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type); #endif diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c index ab41da1f47c8..4084a31d9590 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c @@ -3,17 +3,25 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include #include #include +#include #include +#include #include "iris_core.h" -#include "iris_instance.h" +#include "iris_firmware.h" #include "iris_vpu_common.h" #include "iris_vpu_register_defines.h" -#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL (AON_BASE_OFFS + 0x2C) -#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS (AON_BASE_OFFS + 0x30) +#define WRAPPER_TZ_BASE_OFFS 0x000C0000 +#define AON_BASE_OFFS 0x000E0000 + +#define CPU_IC_BASE_OFFS (CPU_BASE_OFFS) + +#define CPU_CS_A2HSOFTINTCLR (CPU_CS_BASE_OFFS + 0x1C) +#define CLEAR_XTENSA2HOST_INTR BIT(0) #define CTRL_INIT (CPU_CS_BASE_OFFS + 0x48) #define CTRL_STATUS (CPU_CS_BASE_OFFS + 0x4C) @@ -31,57 +39,179 @@ #define UC_REGION_ADDR (CPU_CS_BASE_OFFS + 0x64) #define UC_REGION_SIZE (CPU_CS_BASE_OFFS + 0x68) +#define CPU_CS_H2XSOFTINTEN (CPU_CS_BASE_OFFS + 0x148) +#define HOST2XTENSA_INTR_ENABLE BIT(0) + +#define CPU_CS_X2RPMH (CPU_CS_BASE_OFFS + 0x168) +#define MSK_SIGNAL_FROM_TENSILICA BIT(0) +#define MSK_CORE_POWER_ON BIT(1) + +#define CPU_IC_SOFTINT (CPU_IC_BASE_OFFS + 0x150) +#define CPU_IC_SOFTINT_H2A_SHFT 0x0 + +#define WRAPPER_INTR_STATUS (WRAPPER_BASE_OFFS + 0x0C) +#define WRAPPER_INTR_STATUS_A2HWD_BMSK BIT(3) +#define WRAPPER_INTR_STATUS_A2H_BMSK BIT(2) + +#define WRAPPER_INTR_MASK (WRAPPER_BASE_OFFS + 0x10) +#define WRAPPER_INTR_MASK_A2HWD_BMSK BIT(3) +#define WRAPPER_INTR_MASK_A2HCPU_BMSK BIT(2) + +#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x54) +#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS (WRAPPER_BASE_OFFS + 0x58) +#define WRAPPER_IRIS_CPU_NOC_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x5C) +#define WRAPPER_IRIS_CPU_NOC_LPI_STATUS (WRAPPER_BASE_OFFS + 0x60) + +#define WRAPPER_VCODEC0_MMCC_POWER_STATUS (WRAPPER_BASE_OFFS + 0x90) +#define WRAPPER_VCODEC0_MMCC_POWER_CONTROL (WRAPPER_BASE_OFFS + 0x94) + +#define WRAPPER_TZ_CPU_STATUS (WRAPPER_TZ_BASE_OFFS + 0x10) +#define WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS + 0x14) +#define CTL_AXI_CLK_HALT BIT(0) +#define CTL_CLK_HALT BIT(1) + +#define WRAPPER_TZ_QNS4PDXFIFO_RESET (WRAPPER_TZ_BASE_OFFS + 0x18) +#define RESET_HIGH BIT(0) + +#define AON_WRAPPER_MVP_NOC_LPI_CONTROL (AON_BASE_OFFS) +#define REQ_POWER_DOWN_PREP BIT(0) + +#define AON_WRAPPER_MVP_NOC_LPI_STATUS (AON_BASE_OFFS + 0x4) + +/* Legacy VPU5 register layout used by SM8150. */ +#define VPU5_CPU_CS_BASE_OFFS 0x000D2000 +#define VPU5_CPU_IC_BASE_OFFS 0x000DF000 +#define VPU5_WRAPPER_BASE_OFFS 0x000E0000 + +static bool iris_vpu_uses_legacy_vpu5(struct iris_core *core) +{ + return core->iris_platform_data->legacy_vpu5; +} + +static u32 iris_vpu_cpu_cs_base(struct iris_core *core) +{ + if (iris_vpu_uses_legacy_vpu5(core)) + return VPU5_CPU_CS_BASE_OFFS; + + return CPU_CS_BASE_OFFS; +} + +static u32 iris_vpu_wrapper_base(struct iris_core *core) +{ + if (iris_vpu_uses_legacy_vpu5(core)) + return VPU5_WRAPPER_BASE_OFFS; + + return WRAPPER_BASE_OFFS; +} + static void iris_vpu_interrupt_init(struct iris_core *core) { + u32 wrapper_base = iris_vpu_wrapper_base(core); u32 mask_val; - mask_val = readl(core->reg_base + WRAPPER_INTR_MASK); - mask_val &= ~(WRAPPER_INTR_MASK_A2HWD_BMSK | - WRAPPER_INTR_MASK_A2HCPU_BMSK); - writel(mask_val, core->reg_base + WRAPPER_INTR_MASK); + if (iris_vpu_uses_legacy_vpu5(core)) { + /* + * Iris1 comes out of reset with reserved interrupt sources + * masked. Keep the firmware watchdog (BIT(4)) masked for this + * diagnostic and only unmask the normal A2H CPU interrupt. The + * previous CTRL_INIT-only tests consistently stalled one host + * CPU at the firmware watchdog interval, which is characteristic + * of an uncleared level interrupt. + */ + mask_val = readl(core->reg_base + wrapper_base + 0x10); + dev_info(core->dev, + "Iris1 interrupt mask before unmask: %#x\n", + mask_val); + mask_val |= BIT(4); + mask_val &= ~BIT(2); + } else { + mask_val = readl(core->reg_base + wrapper_base + 0x10); + mask_val &= ~(BIT(3) | BIT(2)); + } + writel(mask_val, core->reg_base + wrapper_base + 0x10); + if (iris_vpu_uses_legacy_vpu5(core)) + dev_info(core->dev, + "Iris1 interrupt mask after unmask: %#x\n", + mask_val); } static void iris_vpu_setup_ucregion_memory_map(struct iris_core *core) { - u32 queue_size, value; - const struct vpu_ops *vpu_ops = core->iris_platform_data->vpu_ops; + u32 cpu_cs_base = iris_vpu_cpu_cs_base(core); + u32 queue_size, region_size, value; + u32 queue_table_size; /* Iris hardware requires 4K queue alignment */ - queue_size = ALIGN(sizeof(struct iris_hfi_queue_table_header) + - (IFACEQ_QUEUE_SIZE * IFACEQ_NUMQ), SZ_4K); + queue_table_size = sizeof(struct iris_hfi_queue_table_header); + queue_size = ALIGN(queue_table_size + + (IFACEQ_QUEUE_SIZE * IFACEQ_NUMQ), SZ_4K); value = (u32)core->iface_q_table_daddr; - writel(value, core->reg_base + UC_REGION_ADDR); + dev_info(core->dev, "HFI registers: writing UC_REGION_ADDR %#x to %#x\n", + value, cpu_cs_base + 0x64); + writel(value, core->reg_base + cpu_cs_base + 0x64); + dev_info(core->dev, "HFI registers: UC_REGION_ADDR write complete\n"); /* Iris hardware requires 1M queue alignment */ - value = ALIGN(SFR_SIZE + queue_size, SZ_1M); - writel(value, core->reg_base + UC_REGION_SIZE); + region_size = ALIGN(SFR_SIZE + queue_size, SZ_1M); + dev_info(core->dev, "HFI registers: writing UC_REGION_SIZE %#x to %#x\n", + region_size, cpu_cs_base + 0x68); + writel(region_size, core->reg_base + cpu_cs_base + 0x68); + dev_info(core->dev, "HFI registers: UC_REGION_SIZE write complete\n"); value = (u32)core->iface_q_table_daddr; - writel(value, core->reg_base + QTBL_ADDR); - - writel(QTBL_ENABLE, core->reg_base + QTBL_INFO); + dev_info(core->dev, "HFI registers: writing QTBL_ADDR %#x to %#x\n", + value, cpu_cs_base + 0x54); + writel(value, core->reg_base + cpu_cs_base + 0x54); + dev_info(core->dev, "HFI registers: QTBL_ADDR write complete\n"); + + dev_info(core->dev, "HFI registers: enabling QTBL at %#x\n", + cpu_cs_base + 0x50); + writel(QTBL_ENABLE, core->reg_base + cpu_cs_base + 0x50); + dev_info(core->dev, "HFI registers: QTBL enable complete\n"); + + if (iris_vpu_uses_legacy_vpu5(core)) { + /* + * Iris1 has a second HFI queue view for its DSP. Qualcomm's + * downstream SM8150 driver initializes it with the CPU queues + * by default even when CVP is unused. + */ + value = (u32)core->iface_q_table_daddr; + dev_info(core->dev, + "HFI registers: writing DSP QTBL/UC region %#x size %#x\n", + value, region_size); + writel(value, core->reg_base + cpu_cs_base + 0x34); + writel(value, core->reg_base + cpu_cs_base + 0x38); + writel(region_size, core->reg_base + cpu_cs_base + 0x3c); + dev_info(core->dev, + "HFI registers: DSP QTBL/UC region writes complete\n"); + } if (core->sfr_daddr) { - value = (u32)core->sfr_daddr + core->iris_firmware_data->core_arch; - writel(value, core->reg_base + SFR_ADDR); + value = (u32)core->sfr_daddr + core->iris_platform_data->core_arch; + dev_info(core->dev, "HFI registers: writing SFR_ADDR %#x to %#x\n", + value, cpu_cs_base + 0x5c); + writel(value, core->reg_base + cpu_cs_base + 0x5c); + dev_info(core->dev, "HFI registers: SFR_ADDR write complete\n"); } - - if (vpu_ops->program_bootup_registers) - vpu_ops->program_bootup_registers(core); } int iris_vpu_boot_firmware(struct iris_core *core) { + u32 cpu_cs_base = iris_vpu_cpu_cs_base(core); u32 ctrl_init = BIT(0), ctrl_status = 0, count = 0, max_tries = 1000; iris_vpu_setup_ucregion_memory_map(core); - writel(ctrl_init, core->reg_base + CTRL_INIT); - writel(0x1, core->reg_base + CPU_CS_SCIACMDARG3); + dev_info(core->dev, "HFI registers: writing CTRL_INIT to %#x\n", + cpu_cs_base + 0x48); + writel(ctrl_init, core->reg_base + cpu_cs_base + 0x48); + dev_info(core->dev, "HFI registers: CTRL_INIT write complete\n"); + dev_info(core->dev, "HFI registers: polling CTRL_STATUS at %#x\n", + cpu_cs_base + 0x4c); while (!ctrl_status && count < max_tries) { - ctrl_status = readl(core->reg_base + CTRL_STATUS); + ctrl_status = readl(core->reg_base + cpu_cs_base + 0x4c); if ((ctrl_status & CTRL_ERROR_STATUS__M) == 0x4) { dev_err(core->dev, "invalid setting for uc_region\n"); break; @@ -90,13 +220,28 @@ int iris_vpu_boot_firmware(struct iris_core *core) usleep_range(50, 100); count++; } + dev_info(core->dev, "HFI registers: CTRL_STATUS %#x after %u polls\n", + ctrl_status, count); if (count >= max_tries) { dev_err(core->dev, "error booting up iris firmware\n"); return -ETIME; } - writel(HOST2XTENSA_INTR_ENABLE, core->reg_base + CPU_CS_H2XSOFTINTEN); + /* + * The SM8150 VPU5 downstream driver stops here. H2XSOFTINTEN and + * X2RPMH belong to the newer Iris register layout and must not be + * programmed through the VPU5 CPU_CS window. + */ + if (iris_vpu_uses_legacy_vpu5(core)) { + dev_info(core->dev, + "Iris1 firmware booted; leaving Iris2-only controls untouched\n"); + return 0; + } + + writel(0x1, core->reg_base + cpu_cs_base + 0x58); + writel(HOST2XTENSA_INTR_ENABLE, + core->reg_base + CPU_CS_H2XSOFTINTEN); writel(0x0, core->reg_base + CPU_CS_X2RPMH); return 0; @@ -104,27 +249,44 @@ int iris_vpu_boot_firmware(struct iris_core *core) void iris_vpu_raise_interrupt(struct iris_core *core) { - writel(1 << CPU_IC_SOFTINT_H2A_SHFT, core->reg_base + CPU_IC_SOFTINT); + if (iris_vpu_uses_legacy_vpu5(core)) { + dev_dbg(core->dev, + "HFI doorbell: writing BIT(15) to VPU5 CPU_IC %#x\n", + VPU5_CPU_IC_BASE_OFFS + 0x18); + writel(BIT(15), core->reg_base + VPU5_CPU_IC_BASE_OFFS + 0x18); + dev_dbg(core->dev, "HFI doorbell: write returned\n"); + } else { + writel(BIT(CPU_IC_SOFTINT_H2A_SHFT), + core->reg_base + CPU_IC_SOFTINT); + } } void iris_vpu_clear_interrupt(struct iris_core *core) { + u32 cpu_cs_base = iris_vpu_cpu_cs_base(core); + u32 wrapper_base = iris_vpu_wrapper_base(core); u32 intr_status, mask; - intr_status = readl(core->reg_base + WRAPPER_INTR_STATUS); - mask = (WRAPPER_INTR_STATUS_A2H_BMSK | - WRAPPER_INTR_STATUS_A2HWD_BMSK | - CTRL_INIT_IDLE_MSG_BMSK); + intr_status = readl(core->reg_base + wrapper_base + 0x0c); + mask = BIT(2) | CTRL_INIT_IDLE_MSG_BMSK; + if (iris_vpu_uses_legacy_vpu5(core)) + mask |= BIT(4); + else + mask |= BIT(3); if (intr_status & mask) core->intr_status |= intr_status; - writel(CLEAR_XTENSA2HOST_INTR, core->reg_base + CPU_CS_A2HSOFTINTCLR); + writel(CLEAR_XTENSA2HOST_INTR, core->reg_base + cpu_cs_base + 0x1c); + if (iris_vpu_uses_legacy_vpu5(core)) + writel(intr_status, core->reg_base + wrapper_base + 0x14); } int iris_vpu_watchdog(struct iris_core *core, u32 intr_status) { - if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK) { + u32 watchdog_mask = iris_vpu_uses_legacy_vpu5(core) ? BIT(4) : BIT(3); + + if (intr_status & watchdog_mask) { dev_err(core->dev, "received watchdog interrupt\n"); return -ETIME; } @@ -138,6 +300,14 @@ int iris_vpu_prepare_pc(struct iris_core *core) u32 ctrl_status, val = 0; int ret; + /* + * The Iris2 power-collapse sequence below addresses registers that do + * not exist in the SM8150 VPU5 layout. Keep the controller on while + * bringing up SM8150; streaming power collapse can be added separately. + */ + if (iris_vpu_uses_legacy_vpu5(core)) + return -EAGAIN; + ctrl_status = readl(core->reg_base + CTRL_STATUS); pc_ready = ctrl_status & CTRL_STATUS_PC_READY; idle_status = ctrl_status & BIT(30); @@ -149,7 +319,7 @@ int iris_vpu_prepare_pc(struct iris_core *core) if (!wfi_status || !idle_status) goto skip_power_off; - ret = core->hfi_sys_ops->sys_pc_prep(core); + ret = core->hfi_ops->sys_pc_prep(core); if (ret) goto skip_power_off; @@ -177,19 +347,29 @@ int iris_vpu_prepare_pc(struct iris_core *core) int iris_vpu_power_off_controller(struct iris_core *core) { + struct device *pd_dev = + core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]; u32 val = 0; int ret; + if (iris_vpu_uses_legacy_vpu5(core)) { + iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); + iris_disable_unprepare_clock(core, IRIS_AXI_CLK); + if (core->iris_platform_data->defer_vcodec_power) + iris_disable_unprepare_clock(core, IRIS_BUS_CLK); + pm_runtime_put_sync(pd_dev); + + return 0; + } + writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH); - if (!core->iris_platform_data->no_aon) { - writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); - ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS, - val, val & BIT(0), 200, 2000); - if (ret) - goto disable_power; - } + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); @@ -212,26 +392,94 @@ int iris_vpu_power_off_controller(struct iris_core *core) writel(0x0, core->reg_base + WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG); disable_power: - iris_disable_unprepare_clock(core, IRIS_AHB_CLK); iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); iris_disable_unprepare_clock(core, IRIS_AXI_CLK); - iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + if (core->iris_platform_data->defer_vcodec_power) + iris_disable_unprepare_clock(core, IRIS_BUS_CLK); + iris_disable_power_domains(core, pd_dev); return 0; } +static int iris_vpu_set_vcodec_hw_control(struct iris_core *core, bool enable) +{ + u32 val; + + writel(enable ? 0 : 1, + core->reg_base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL); + + return readl_poll_timeout(core->reg_base + + WRAPPER_VCODEC0_MMCC_POWER_STATUS, + val, + enable ? (val & BIT(1)) : !(val & BIT(1)), + 1, 100); +} + void iris_vpu_power_off_hw(struct iris_core *core) { - dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], false); - iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); - iris_disable_unprepare_clock(core, IRIS_BSE_HW_CLK); - iris_disable_unprepare_clock(core, IRIS_HW_AHB_CLK); - iris_disable_unprepare_clock(core, IRIS_HW_CLK); + struct device *pd_dev = + core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]; + struct device *aux_pd_dev = NULL; + + if (core->iris_platform_data->defer_vcodec_power && + core->iris_platform_data->pmdomain_tbl_size > + IRIS_AUX_HW_POWER_DOMAIN) + aux_pd_dev = + core->pmdomain_tbl->pd_devs[IRIS_AUX_HW_POWER_DOMAIN]; + + if (core->iris_platform_data->use_vcodec_hw_control && + !core->iris_platform_data->defer_vcodec_power) { + if (iris_vpu_set_vcodec_hw_control(core, true)) + dev_warn(core->dev, + "failed to take vcodec power control\n"); + + iris_disable_unprepare_clock(core, IRIS_HW_CLK); + + if (iris_vpu_set_vcodec_hw_control(core, false)) + dev_warn(core->dev, + "failed to release vcodec power control\n"); + } else if (core->iris_platform_data->defer_vcodec_power) { + /* + * SM8150 VideoCC uses HW_CTRL_TRIGGER, so pm_runtime_get() + * leaves both MVS GDSCs in software mode. Keep them there for + * now: touching the legacy wrapper handoff registers wedges + * nabu before the codec clocks are running. + */ + if (aux_pd_dev) + iris_disable_unprepare_clock(core, IRIS_AUX_HW_CLK); + iris_disable_unprepare_clock(core, IRIS_HW_CLK); + if (aux_pd_dev) + iris_disable_unprepare_clock(core, IRIS_AUX_HW_AXI_CLK); + iris_disable_unprepare_clock(core, IRIS_HW_AXI_CLK); + } else { + dev_pm_genpd_set_hwmode(pd_dev, false); + iris_disable_unprepare_clock(core, IRIS_HW_CLK); + } + + if (core->iris_platform_data->defer_vcodec_power) { + if (aux_pd_dev) + pm_runtime_put_sync(aux_pd_dev); + pm_runtime_put_sync(pd_dev); + } else { + iris_disable_power_domains(core, pd_dev); + } } void iris_vpu_power_off(struct iris_core *core) { - iris_opp_set_rate(core->dev, 0); + int i; + + if (core->llcc_active) { + for (i = ARRAY_SIZE(core->llcc_slices) - 1; i >= 0; i--) { + llcc_slice_deactivate(core->llcc_slices[i]); + llcc_slice_putd(core->llcc_slices[i]); + core->llcc_slices[i] = NULL; + } + core->llcc_active = false; + core->syscache_set = false; + } + + dev_pm_opp_set_rate(core->dev, 0); core->iris_platform_data->vpu_ops->power_off_hw(core); core->iris_platform_data->vpu_ops->power_off_controller(core); iris_unset_icc_bw(core); @@ -240,259 +488,266 @@ void iris_vpu_power_off(struct iris_core *core) disable_irq_nosync(core->irq); } -int iris_vpu_power_on_controller(struct iris_core *core) +static int iris_vpu_power_on_controller(struct iris_core *core) { u32 rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; + struct device *pd_dev = + core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]; + u32 i; int ret; - ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); - if (ret) + dev_info(core->dev, "vpu controller: enabling power domain\n"); + if (core->iris_platform_data->defer_vcodec_power) + ret = pm_runtime_get_sync(pd_dev); + else + ret = iris_enable_power_domains(core, pd_dev); + if (ret < 0) return ret; - ret = reset_control_bulk_reset(rst_tbl_size, core->resets); - if (ret) - goto err_disable_power; + dev_info(core->dev, "vpu controller: resetting clocks\n"); + if (core->iris_platform_data->defer_vcodec_power) { + for (i = 0; i < rst_tbl_size; i++) { + dev_info(core->dev, "vpu controller: reset %u (%s): assert begin\n", + i, core->resets[i].id); + ret = reset_control_assert(core->resets[i].rstc); + if (ret) + goto err_disable_power; + dev_info(core->dev, "vpu controller: reset %u (%s): assert done\n", + i, core->resets[i].id); + + usleep_range(150, 250); + + dev_info(core->dev, "vpu controller: reset %u (%s): deassert begin\n", + i, core->resets[i].id); + ret = reset_control_deassert(core->resets[i].rstc); + if (ret) + goto err_disable_power; + dev_info(core->dev, "vpu controller: reset %u (%s): deassert done\n", + i, core->resets[i].id); + } + } else { + ret = reset_control_bulk_reset(rst_tbl_size, core->resets); + if (ret) + goto err_disable_power; + } + + if (core->iris_platform_data->defer_vcodec_power) { + dev_info(core->dev, "vpu controller: enabling bus clock\n"); + ret = iris_prepare_enable_clock(core, IRIS_BUS_CLK); + if (ret) + goto err_disable_power; + } + dev_info(core->dev, "vpu controller: enabling AXI clock\n"); ret = iris_prepare_enable_clock(core, IRIS_AXI_CLK); if (ret) - goto err_disable_power; + goto err_disable_bus_clock; + dev_info(core->dev, "vpu controller: enabling core clock\n"); ret = iris_prepare_enable_clock(core, IRIS_CTRL_CLK); if (ret) - goto err_disable_axi_clock; - - ret = iris_prepare_enable_clock(core, IRIS_AHB_CLK); - if (ret && ret != -ENOENT) - goto err_disable_ctrl_clock; + goto err_disable_clock; + dev_info(core->dev, "vpu controller: power-on complete\n"); return 0; -err_disable_ctrl_clock: - iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); -err_disable_axi_clock: +err_disable_clock: iris_disable_unprepare_clock(core, IRIS_AXI_CLK); +err_disable_bus_clock: + if (core->iris_platform_data->defer_vcodec_power) + iris_disable_unprepare_clock(core, IRIS_BUS_CLK); err_disable_power: - iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + if (core->iris_platform_data->defer_vcodec_power) + pm_runtime_put_sync(pd_dev); + else + iris_disable_power_domains(core, pd_dev); return ret; } -int iris_vpu_power_on_hw(struct iris_core *core) +static int iris_vpu_power_on_hw(struct iris_core *core) { + struct device *pd_dev = + core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]; + struct device *aux_pd_dev = NULL; int ret; - ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); + if (core->iris_platform_data->defer_vcodec_power && + core->iris_platform_data->pmdomain_tbl_size > + IRIS_AUX_HW_POWER_DOMAIN) + aux_pd_dev = + core->pmdomain_tbl->pd_devs[IRIS_AUX_HW_POWER_DOMAIN]; + + /* + * The deferred SM8150 sequence has already raised the CX OPP before + * reaching this point. Do not call iris_enable_power_domains() here: + * it repeats dev_pm_opp_set_rate(ULONG_MAX), which can wedge the RPMh + * TCS while VideoCC/MMCX is active. The legacy Venus driver likewise + * acquires the vcodec GDSC directly at this stage. + */ + if (core->iris_platform_data->defer_vcodec_power) { + dev_info(core->dev, + "vcodec power: enabling GDSC without duplicate OPP vote\n"); + ret = pm_runtime_resume_and_get(pd_dev); + dev_info(core->dev, "vcodec power: GDSC enable returned %d\n", ret); + } else { + ret = iris_enable_power_domains(core, pd_dev); + } if (ret) return ret; - ret = iris_prepare_enable_clock(core, IRIS_HW_CLK); - if (ret) - goto err_disable_power; - - ret = iris_prepare_enable_clock(core, IRIS_HW_AHB_CLK); - if (ret && ret != -ENOENT) - goto err_disable_hw_clock; - - ret = iris_prepare_enable_clock(core, IRIS_BSE_HW_CLK); - if (ret && ret != -ENOENT) - goto err_disable_hw_ahb_clock; - - return 0; - -err_disable_hw_ahb_clock: - iris_disable_unprepare_clock(core, IRIS_HW_AHB_CLK); -err_disable_hw_clock: - iris_disable_unprepare_clock(core, IRIS_HW_CLK); -err_disable_power: - iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); - - return ret; -} - -int iris_vpu_set_hwmode(struct iris_core *core) -{ - return dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], true); -} - -int iris_vpu_switch_to_hwmode(struct iris_core *core) -{ - return core->iris_platform_data->vpu_ops->set_hwmode(core); -} - -int iris_vpu35_vpu4x_power_off_controller(struct iris_core *core) -{ - u32 clk_rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; - bool handshake_done, handshake_busy; - u32 count = 0, val = 0; - int ret; - - writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH); - - writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); - - ret = readl_poll_timeout(core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_STATUS, - val, val & BIT(0), 200, 2000); - if (ret) - goto disable_power; - - writel(0, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); - - /* Retry up to 1000 times as recommended by hardware documentation */ - do { - /* set MNoC to low power */ - writel(REQ_POWER_DOWN_PREP, core->reg_base + - AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); - usleep_range(10, 20); - val = readl(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS); - - handshake_done = val & NOC_LPI_STATUS_DONE; - handshake_busy = val & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE); - - if (handshake_done || !handshake_busy) - break; - - writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); - usleep_range(10, 20); - - } while (++count < 1000); - - if (!handshake_done && handshake_busy) - dev_err(core->dev, "LPI handshake timeout\n"); - - ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS, - val, val & BIT(0), 200, 2000); - if (ret) - goto disable_power; - - writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); - - writel(0, core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL); - - readl_poll_timeout(core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_STATUS, - val, val == 0, 200, 2000); - -disable_power: - iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); - iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); - iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); - - iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); - - reset_control_bulk_reset(clk_rst_tbl_size, core->resets); - - return 0; -} + if (aux_pd_dev) { + dev_info(core->dev, + "vcodec power: enabling auxiliary GDSC\n"); + ret = pm_runtime_resume_and_get(aux_pd_dev); + dev_info(core->dev, + "vcodec power: auxiliary GDSC enable returned %d\n", + ret); + if (ret) + goto err_disable_power; + } -int iris_vpu35_vpu4x_power_on_controller(struct iris_core *core) -{ - int ret; + if (core->iris_platform_data->defer_vcodec_power) { + dev_info(core->dev, "vcodec power: enabling codec0 AXI clock\n"); + ret = iris_prepare_enable_clock(core, IRIS_HW_AXI_CLK); + if (ret) + goto err_disable_aux_power; + dev_info(core->dev, "vcodec power: enabling codec1 AXI clock\n"); + ret = iris_prepare_enable_clock(core, IRIS_AUX_HW_AXI_CLK); + if (ret) + goto err_disable_hw_axi_clock; + } - ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); - if (ret) - return ret; + if (core->iris_platform_data->use_vcodec_hw_control && + !core->iris_platform_data->defer_vcodec_power) { + dev_info(core->dev, "vcodec power: requesting software control\n"); + ret = iris_vpu_set_vcodec_hw_control(core, true); + if (ret) + goto err_disable_aux_hw_axi_clock; + dev_info(core->dev, "vcodec power: software control acquired\n"); + } - ret = iris_prepare_enable_clock(core, IRIS_AXI1_CLK); + dev_info(core->dev, "vcodec power: enabling core clock\n"); + ret = iris_prepare_enable_clock(core, IRIS_HW_CLK); if (ret) - goto err_disable_power; + goto err_disable_aux_hw_axi_clock; + dev_info(core->dev, "vcodec power: core clock enabled\n"); - ret = iris_prepare_enable_clock(core, IRIS_CTRL_FREERUN_CLK); - if (ret) - goto err_disable_axi1_clk; + if (aux_pd_dev) { + dev_info(core->dev, + "vcodec power: enabling auxiliary core clock\n"); + ret = iris_prepare_enable_clock(core, IRIS_AUX_HW_CLK); + if (ret) + goto err_disable_clock; + dev_info(core->dev, + "vcodec power: auxiliary core clock enabled\n"); + } - ret = iris_prepare_enable_clock(core, IRIS_CTRL_CLK); + if (core->iris_platform_data->use_vcodec_hw_control && + !core->iris_platform_data->defer_vcodec_power) { + dev_info(core->dev, "vcodec power: releasing software control\n"); + ret = iris_vpu_set_vcodec_hw_control(core, false); + } else if (core->iris_platform_data->defer_vcodec_power) { + /* + * Keep vcodec0 software-powered for the first SM8150 bring-up. + * This deliberately trades power collapse for a stable decode + * path and avoids the inaccessible legacy wrapper registers. + */ + dev_info(core->dev, + "vcodec power: keeping both GDSCs in software mode\n"); + ret = 0; + } else { + ret = dev_pm_genpd_set_hwmode(pd_dev, true); + } if (ret) - goto err_disable_ctrl_free_clk; + goto err_disable_clock; + dev_info(core->dev, "vcodec power: hardware ready\n"); return 0; -err_disable_ctrl_free_clk: - iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); -err_disable_axi1_clk: - iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); +err_disable_clock: + if (aux_pd_dev) + iris_disable_unprepare_clock(core, IRIS_AUX_HW_CLK); + iris_disable_unprepare_clock(core, IRIS_HW_CLK); +err_disable_aux_hw_axi_clock: + if (core->iris_platform_data->defer_vcodec_power) + iris_disable_unprepare_clock(core, IRIS_AUX_HW_AXI_CLK); +err_disable_hw_axi_clock: + if (core->iris_platform_data->defer_vcodec_power) + iris_disable_unprepare_clock(core, IRIS_HW_AXI_CLK); +err_disable_aux_power: + if (aux_pd_dev) + pm_runtime_put_sync(aux_pd_dev); + if (core->iris_platform_data->use_vcodec_hw_control && + !core->iris_platform_data->defer_vcodec_power) + iris_vpu_set_vcodec_hw_control(core, false); err_disable_power: - iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + if (core->iris_platform_data->defer_vcodec_power) + pm_runtime_put_sync(pd_dev); + else + iris_disable_power_domains(core, pd_dev); return ret; } -void iris_vpu35_vpu4x_program_bootup_registers(struct iris_core *core) -{ - writel(0x1, core->reg_base + WRAPPER_IRIS_VCODEC_VPU_WRAPPER_SPARE_0); -} - -u64 iris_vpu3x_vpu4x_calculate_frequency(struct iris_inst *inst, size_t data_size) -{ - struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; - struct v4l2_format *inp_f = inst->fmt_src; - u32 height, width, mbs_per_second, mbpf; - u64 fw_cycles, fw_vpp_cycles; - u64 vsp_cycles, vpp_cycles; - u32 fps = inst->frame_rate; - - width = max(inp_f->fmt.pix_mp.width, inst->crop.width); - height = max(inp_f->fmt.pix_mp.height, inst->crop.height); - - mbpf = NUM_MBS_PER_FRAME(height, width); - mbs_per_second = mbpf * fps; - - fw_cycles = fps * caps->mb_cycles_fw; - fw_vpp_cycles = fps * caps->mb_cycles_fw_vpp; - - vpp_cycles = mult_frac(mbs_per_second, caps->mb_cycles_vpp, (u32)inst->fw_caps[PIPE].value); - /* 21 / 20 is minimum overhead factor */ - vpp_cycles += max(div_u64(vpp_cycles, 20), fw_vpp_cycles); - - /* 1.059 is multi-pipe overhead */ - if (inst->fw_caps[PIPE].value > 1) - vpp_cycles += div_u64(vpp_cycles * 59, 1000); - - /* 1.05 is VPP FW overhead */ - if (inst->fw_caps[STAGE].value == STAGE_2) - vpp_cycles += div_u64(vpp_cycles * 5, 100); - - vsp_cycles = fps * data_size * 8; - vsp_cycles = div_u64(vsp_cycles, 2); - /* VSP FW overhead 1.05 */ - vsp_cycles = div_u64(vsp_cycles * 21, 20); - - if (inst->fw_caps[STAGE].value == STAGE_1) - vsp_cycles = vsp_cycles * 3; - - return max3(vpp_cycles, vsp_cycles, fw_cycles); -} - int iris_vpu_power_on(struct iris_core *core) { u32 freq; int ret; + dev_info(core->dev, "vpu power: voting interconnect\n"); ret = iris_set_icc_bw(core, INT_MAX); if (ret) goto err; + if (core->iris_platform_data->legacy_vpu5) + dev_info(core->dev, + "Iris1 v154: retaining maximum clock and interconnect votes until power-off\n"); - ret = core->iris_platform_data->vpu_ops->power_on_controller(core); + dev_info(core->dev, "vpu power: enabling controller domain and clocks\n"); + ret = iris_vpu_power_on_controller(core); if (ret) goto err_unvote_icc; - ret = core->iris_platform_data->vpu_ops->power_on_hw(core); - if (ret) - goto err_power_off_ctrl; + if (!core->iris_platform_data->defer_vcodec_power) { + dev_info(core->dev, "vpu power: enabling codec domain and clock\n"); + ret = iris_vpu_power_on_hw(core); + if (ret) + goto err_power_off_ctrl; + } else { + dev_info(core->dev, + "vpu power: codec domain deferred until after OPP vote\n"); + } freq = core->power.clk_freq ? core->power.clk_freq : (u32)ULONG_MAX; - iris_opp_set_rate(core->dev, freq); + dev_info(core->dev, "vpu power: setting OPP rate\n"); + ret = dev_pm_opp_set_rate(core->dev, freq); + if (ret) + goto err_power_off_ctrl; + + if (core->iris_platform_data->defer_vcodec_power) { + dev_info(core->dev, + "vpu power: enabling codec domain after OPP vote\n"); + ret = iris_vpu_power_on_hw(core); + if (ret) + goto err_clear_opp; + } - iris_vpu_set_preset_registers(core); + dev_info(core->dev, "vpu power: programming preset registers\n"); + core->iris_platform_data->set_preset_registers(core); + dev_info(core->dev, "vpu power: enabling interrupt\n"); iris_vpu_interrupt_init(core); core->intr_status = 0; enable_irq(core->irq); return 0; +err_clear_opp: + dev_pm_opp_set_rate(core->dev, 0); err_power_off_ctrl: - core->iris_platform_data->vpu_ops->power_off_controller(core); + iris_vpu_power_off_controller(core); err_unvote_icc: iris_unset_icc_bw(core); err: @@ -500,8 +755,3 @@ int iris_vpu_power_on(struct iris_core *core) return ret; } - -void iris_vpu_set_preset_registers(struct iris_core *core) -{ - writel(0x0, core->reg_base + 0xb0088); -} diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 243e342b0ae7..0a41eed4a999 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -179,8 +178,6 @@ static void venus_sys_error_handler(struct work_struct *work) static u32 to_v4l2_codec_type(u32 codec) { switch (codec) { - case HFI_VIDEO_CODEC_HEVC: - return V4L2_PIX_FMT_HEVC; case HFI_VIDEO_CODEC_H264: return V4L2_PIX_FMT_H264; case HFI_VIDEO_CODEC_H263: @@ -216,7 +213,7 @@ static int venus_enumerate_codecs(struct venus_core *core, u32 type) if (core->res->hfi_version != HFI_VERSION_1XX) return 0; - inst = kzalloc_obj(*inst); + inst = kzalloc(sizeof(*inst), GFP_KERNEL); if (!inst) return -ENOMEM; @@ -257,19 +254,14 @@ static int venus_enumerate_codecs(struct venus_core *core, u32 type) static void venus_assign_register_offsets(struct venus_core *core) { - if (IS_IRIS2(core) || IS_IRIS2_1(core) || IS_AR50_LITE(core)) { + if (IS_IRIS2(core) || IS_IRIS2_1(core)) { + core->vbif_base = core->base + VBIF_BASE; core->cpu_base = core->base + CPU_BASE_V6; core->cpu_cs_base = core->base + CPU_CS_BASE_V6; core->cpu_ic_base = core->base + CPU_IC_BASE_V6; core->wrapper_base = core->base + WRAPPER_BASE_V6; core->wrapper_tz_base = core->base + WRAPPER_TZ_BASE_V6; - if (IS_AR50_LITE(core)) { - core->vbif_base = NULL; - core->aon_base = NULL; - } else { - core->vbif_base = core->base + VBIF_BASE; - core->aon_base = core->base + AON_BASE_V6; - } + core->aon_base = core->base + AON_BASE_V6; } else { core->vbif_base = core->base + VBIF_BASE; core->cpu_base = core->base + CPU_BASE; @@ -332,7 +324,7 @@ static int venus_add_dynamic_nodes(struct venus_core *core) struct device *dev = core->dev; int ret; - core->ocs = kmalloc_obj(*core->ocs); + core->ocs = kmalloc(sizeof(*core->ocs), GFP_KERNEL); if (!core->ocs) return -ENOMEM; @@ -380,6 +372,7 @@ static void venus_remove_dynamic_nodes(struct venus_core *core) {} static int venus_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + const char *stage = "allocate core"; struct venus_core *core; int ret; @@ -389,10 +382,12 @@ static int venus_probe(struct platform_device *pdev) core->dev = dev; + stage = "map registers"; core->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(core->base)) return PTR_ERR(core->base); + stage = "get interconnects"; core->video_path = devm_of_icc_get(dev, "video-mem"); if (IS_ERR(core->video_path)) return PTR_ERR(core->video_path); @@ -415,12 +410,14 @@ static int venus_probe(struct platform_device *pdev) if (!core->pm_ops) return -ENODEV; + stage = "get clocks, resets and power domains"; if (core->pm_ops->core_get) { ret = core->pm_ops->core_get(core); if (ret) return ret; } + stage = "set DMA mask"; ret = dma_set_mask_and_coherent(dev, core->res->dma_mask); if (ret) goto err_core_put; @@ -452,72 +449,75 @@ static int venus_probe(struct platform_device *pdev) pm_runtime_enable(dev); + stage = "runtime resume"; ret = pm_runtime_get_sync(dev); if (ret < 0) goto err_runtime_disable; + dev_info(dev, "diagnostic: runtime power enabled\n"); + + stage = "create child codec nodes"; + if (core->res->dec_nodename || core->res->enc_nodename) { + ret = venus_add_dynamic_nodes(core); + if (ret) + goto err_runtime_disable; + } + + stage = "populate child devices"; + ret = of_platform_populate(dev->of_node, NULL, NULL, dev); + if (ret) + goto err_remove_dynamic_nodes; + + stage = "initialize firmware mapping"; ret = venus_firmware_init(core); if (ret) - goto err_runtime_disable; + goto err_of_depopulate; + stage = "authenticate and boot firmware"; ret = venus_boot(core); if (ret) goto err_firmware_deinit; - ret = venus_firmware_cfg(core); - if (ret) - goto err_venus_shutdown; - + stage = "start HFI hardware"; ret = hfi_core_resume(core, true); if (ret) goto err_venus_shutdown; + stage = "initialize HFI protocol"; ret = hfi_core_init(core); if (ret) goto err_venus_shutdown; - ret = venus_firmware_check(core); - if (ret) - goto err_core_deinit; - - if (core->res->dec_nodename || core->res->enc_nodename) { - ret = venus_add_dynamic_nodes(core); - if (ret) - goto err_core_deinit; - } - - ret = of_platform_populate(dev->of_node, NULL, NULL, dev); - if (ret) - goto err_remove_dynamic_nodes; - + stage = "enumerate decoder codecs"; ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_DEC); if (ret) - goto err_of_depopulate; + goto err_core_deinit; + stage = "enumerate encoder codecs"; ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_ENC); if (ret) - goto err_of_depopulate; + goto err_core_deinit; ret = pm_runtime_put_sync(dev); if (ret) { pm_runtime_get_noresume(dev); - goto err_of_depopulate; + goto err_core_deinit; } venus_dbgfs_init(core); return 0; -err_of_depopulate: - of_platform_depopulate(dev); -err_remove_dynamic_nodes: - venus_remove_dynamic_nodes(core); err_core_deinit: hfi_core_deinit(core, false); err_venus_shutdown: venus_shutdown(core); err_firmware_deinit: venus_firmware_deinit(core); +err_of_depopulate: + of_platform_depopulate(dev); +err_remove_dynamic_nodes: + venus_remove_dynamic_nodes(core); err_runtime_disable: pm_runtime_put_noidle(dev); pm_runtime_disable(dev); @@ -528,6 +528,7 @@ static int venus_probe(struct platform_device *pdev) err_core_put: if (core->pm_ops->core_put) core->pm_ops->core_put(core); + dev_err(dev, "diagnostic: probe failed at '%s': %d\n", stage, ret); return ret; } @@ -612,7 +613,7 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev) return ret; } -void venus_close_common(struct venus_inst *inst, struct file *filp) +void venus_close_common(struct venus_inst *inst) { /* * Make sure we don't have IRQ/IRQ-thread currently running @@ -623,7 +624,7 @@ void venus_close_common(struct venus_inst *inst, struct file *filp) v4l2_m2m_ctx_release(inst->m2m_ctx); v4l2_m2m_release(inst->m2m_dev); hfi_session_destroy(inst); - v4l2_fh_del(&inst->fh, filp); + v4l2_fh_del(&inst->fh); v4l2_fh_exit(&inst->fh); v4l2_ctrl_handler_free(&inst->ctrl_handler); @@ -687,47 +688,6 @@ static const struct venus_resources msm8916_res = { .vmem_addr = 0, .dma_mask = 0xddc00000 - 1, .fwname = "qcom/venus-1.8/venus.mbn", - .dec_codec_blacklist = HFI_VIDEO_CODEC_HEVC | HFI_VIDEO_CODEC_SPARK, - .enc_codec_blacklist = HFI_VIDEO_CODEC_HEVC, - .dec_nodename = "video-decoder", - .enc_nodename = "video-encoder", -}; - -static const struct freq_tbl msm8939_freq_table[] = { - { 489600, 266670000 }, /* 1080p @ 60 */ - { 244800, 133330000 }, /* 1080p @ 30 */ - { 220800, 133330000 }, /* 720p @ 60 */ - { 108000, 133330000 }, /* 720p @ 30 */ - { 72000, 133330000 }, /* VGA @ 60 */ - { 36000, 133330000 }, /* VGA @ 30 */ -}; - -static const struct reg_val msm8939_reg_preset[] = { - { 0xe0020, 0x0aaaaaaa }, - { 0xe0024, 0x0aaaaaaa }, - { 0x80124, 0x00000003 }, -}; - -static const struct venus_resources msm8939_res = { - .freq_tbl = msm8939_freq_table, - .freq_tbl_size = ARRAY_SIZE(msm8939_freq_table), - .reg_tbl = msm8939_reg_preset, - .reg_tbl_size = ARRAY_SIZE(msm8939_reg_preset), - .clks = { "core", "iface", "bus", }, - .clks_num = 3, - .vcodec_clks = { "vcodec0_core", "vcodec1_core" }, - .vcodec_clks_num = 2, - .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0", "vcodec1" }, - .vcodec_pmdomains_num = 3, - .max_load = 489600, /* 1080p@30 + 1080p@30 */ - .hfi_version = HFI_VERSION_1XX, - .vmem_id = VIDC_RESOURCE_NONE, - .vmem_size = 0, - .vmem_addr = 0, - .dma_mask = 0xddc00000 - 1, - .fwname = "qcom/venus-1.8/venus.mbn", - .dec_codec_blacklist = HFI_VIDEO_CODEC_SPARK, - .enc_codec_blacklist = HFI_VIDEO_CODEC_HEVC, .dec_nodename = "video-decoder", .enc_nodename = "video-encoder", }; @@ -926,7 +886,6 @@ static const struct venus_resources sdm845_res_v2 = { .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0", "vcodec1" }, .vcodec_pmdomains_num = 3, .opp_pmdomain = (const char *[]) { "cx" }, - .opp_pmdomain_num = 1, .vcodec_num = 2, .max_load = 3110400, /* 4096x2160@90 */ .hfi_version = HFI_VERSION_4XX, @@ -944,6 +903,53 @@ static const struct venus_resources sdm845_res_v2 = { .enc_nodename = "video-core1", }; +/* + * SM8150 contains the first-generation Iris video block. It uses the HFI + * 4xx protocol and the same host register layout as AR50, but has separate + * MVSC, MVS0 and MVS1 clock and power domains. + */ +static const struct freq_tbl sm8150_freq_table[] = { + { 3916800, 533000000 }, /* 3840x2160@120 */ + { 3110400, 444000000 }, /* 4096x2160@90 */ + { 2073600, 365000000 }, /* 4096x2160@60 */ + { 972000, 240000000 }, /* 3840x2160@30 */ + { 489600, 200000000 }, /* 1920x1080@60 */ +}; + +static const struct venus_resources sm8150_res = { + .freq_tbl = sm8150_freq_table, + .freq_tbl_size = ARRAY_SIZE(sm8150_freq_table), + .bw_tbl_enc = sdm845_bw_table_enc, + .bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc), + .bw_tbl_dec = sdm845_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec), + .clks = { "core", "iface", "bus" }, + .clks_num = 3, + .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, + .vcodec1_clks = { "vcodec1_core", "vcodec1_bus" }, + .vcodec_clks_num = 2, + .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0", "vcodec1" }, + .vcodec_pmdomains_num = 3, + .opp_pmdomain = (const char *[]) { "cx" }, + .resets = { "bus", "core", "vcodec0_bus", "vcodec1_bus" }, + .resets_num = 4, + .vcodec_num = 2, + .max_load = 3916800, + .hfi_version = HFI_VERSION_4XX, + .vpu_version = VPU_VERSION_IRIS1, + .vmem_id = VIDC_RESOURCE_NONE, + .vmem_size = 0, + .vmem_addr = 0, + .dma_mask = 0xe0000000 - 1, + .cp_start = 0, + .cp_size = 0x25800000, + .cp_nonpixel_start = 0x1000000, + .cp_nonpixel_size = 0x24800000, + .fwname = "qcom/sm8150/venus.mbn", + .dec_nodename = "video-core0", + .enc_nodename = "video-core1", +}; + static const struct freq_tbl sc7180_freq_table[] = { { 0, 500000000 }, { 0, 434000000 }, @@ -978,7 +984,6 @@ static const struct venus_resources sc7180_res = { .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, .opp_pmdomain = (const char *[]) { "cx" }, - .opp_pmdomain_num = 1, .vcodec_num = 1, .hfi_version = HFI_VERSION_4XX, .vpu_version = VPU_VERSION_AR50, @@ -995,7 +1000,6 @@ static const struct venus_resources sc7180_res = { .enc_nodename = "video-encoder", }; -#if (!IS_ENABLED(CONFIG_VIDEO_QCOM_IRIS)) static const struct freq_tbl sm8250_freq_table[] = { { 0, 444000000 }, { 0, 366000000 }, @@ -1038,8 +1042,7 @@ static const struct venus_resources sm8250_res = { .vcodec_clks_num = 1, .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, - .opp_pmdomain = (const char *[]) { "mx", "mmcx" }, - .opp_pmdomain_num = 2, + .opp_pmdomain = (const char *[]) { "mx" }, .vcodec_num = 1, .max_load = 7833600, .hfi_version = HFI_VERSION_6XX, @@ -1101,7 +1104,6 @@ static const struct venus_resources sc7280_res = { .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, .opp_pmdomain = (const char *[]) { "cx" }, - .opp_pmdomain_num = 1, .vcodec_num = 1, .hfi_version = HFI_VERSION_6XX, .vpu_version = VPU_VERSION_IRIS2_1, @@ -1118,72 +1120,18 @@ static const struct venus_resources sc7280_res = { .dec_nodename = "video-decoder", .enc_nodename = "video-encoder", }; -#endif - -static const struct bw_tbl qcm2290_bw_table_dec[] = { - { 352800, 597000, 0, 746000, 0 }, /* 1080p@30 + 720p@30 */ - { 244800, 413000, 0, 516000, 0 }, /* 1080p@30 */ - { 216000, 364000, 0, 454000, 0 }, /* 720p@60 */ - { 108000, 182000, 0, 227000, 0 }, /* 720p@30 */ -}; - -static const struct bw_tbl qcm2290_bw_table_enc[] = { - { 352800, 396000, 0, 0, 0 }, /* 1080p@30 + 720p@30 */ - { 244800, 275000, 0, 0, 0 }, /* 1080p@30 */ - { 216000, 242000, 0, 0, 0 }, /* 720p@60 */ - { 108000, 121000, 0, 0, 0 }, /* 720p@30 */ -}; - -static const struct firmware_version min_fw = { - .major = 6, .minor = 0, .rev = 55, -}; - -static const struct venus_resources qcm2290_res = { - .bw_tbl_dec = qcm2290_bw_table_dec, - .bw_tbl_dec_size = ARRAY_SIZE(qcm2290_bw_table_dec), - .bw_tbl_enc = qcm2290_bw_table_enc, - .bw_tbl_enc_size = ARRAY_SIZE(qcm2290_bw_table_enc), - .clks = { "core", "iface", "bus", "throttle" }, - .clks_num = 4, - .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, - .vcodec_clks_num = 2, - .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, - .vcodec_pmdomains_num = 2, - .opp_pmdomain = (const char *[]) { "cx" }, - .opp_pmdomain_num = 1, - .vcodec_num = 1, - .hfi_version = HFI_VERSION_4XX, - .vpu_version = VPU_VERSION_AR50_LITE, - .max_load = 352800, - .num_vpp_pipes = 1, - .vmem_id = VIDC_RESOURCE_NONE, - .vmem_size = 0, - .vmem_addr = 0, - .cp_start = 0, - .cp_size = 0x70800000, - .cp_nonpixel_start = 0x1000000, - .cp_nonpixel_size = 0x24800000, - .dma_mask = 0xe0000000 - 1, - .fwname = "qcom/venus-6.0/venus.mbn", - .dec_nodename = "video-decoder", - .enc_nodename = "video-encoder", - .min_fw = &min_fw, -}; static const struct of_device_id venus_dt_match[] = { { .compatible = "qcom,msm8916-venus", .data = &msm8916_res, }, - { .compatible = "qcom,msm8939-venus", .data = &msm8939_res, }, { .compatible = "qcom,msm8996-venus", .data = &msm8996_res, }, { .compatible = "qcom,msm8998-venus", .data = &msm8998_res, }, - { .compatible = "qcom,qcm2290-venus", .data = &qcm2290_res, }, - { .compatible = "qcom,sc7180-venus", .data = &sc7180_res, }, { .compatible = "qcom,sdm660-venus", .data = &sdm660_res, }, { .compatible = "qcom,sdm845-venus", .data = &sdm845_res, }, { .compatible = "qcom,sdm845-venus-v2", .data = &sdm845_res_v2, }, -#if (!IS_ENABLED(CONFIG_VIDEO_QCOM_IRIS)) + { .compatible = "qcom,sm8150-venus", .data = &sm8150_res, }, + { .compatible = "qcom,sc7180-venus", .data = &sc7180_res, }, { .compatible = "qcom,sc7280-venus", .data = &sc7280_res, }, { .compatible = "qcom,sm8250-venus", .data = &sm8250_res, }, -#endif { } }; MODULE_DEVICE_TABLE(of, venus_dt_match); @@ -1200,5 +1148,6 @@ static struct platform_driver qcom_venus_driver = { }; module_platform_driver(qcom_venus_driver); +MODULE_ALIAS("platform:qcom-venus"); MODULE_DESCRIPTION("Qualcomm Venus video encoder and decoder driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 46705a666776..165f11d1eb52 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -25,7 +25,7 @@ #define VIDC_CLKS_NUM_MAX 4 #define VIDC_VCODEC_CLKS_NUM_MAX 2 -#define VIDC_RESETS_NUM_MAX 2 +#define VIDC_RESETS_NUM_MAX 4 #define VIDC_MAX_HIER_CODING_LAYER 6 #define VENUS_MAX_FPS 240 diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 1de7436713ed..9eaba13536ab 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -226,19 +226,26 @@ int venus_boot(struct venus_core *core) if (ret) fwpath = core->res->fwname; + dev_info(dev, "diagnostic: loading firmware '%s'\n", fwpath); ret = venus_load_fw(core, fwpath, &mem_phys, &mem_size); if (ret) { - dev_err(dev, "fail to load video firmware\n"); + dev_err(dev, "diagnostic: firmware load failed: %d\n", ret); return -EINVAL; } core->fw.mem_size = mem_size; core->fw.mem_phys = mem_phys; + dev_info(dev, "diagnostic: firmware loaded at %pa, size %zu\n", + &mem_phys, mem_size); - if (core->use_tz) + if (core->use_tz) { + dev_info(dev, "diagnostic: starting PAS authentication (id %u)\n", + VENUS_PAS_ID); ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID); - else + dev_info(dev, "diagnostic: PAS authentication returned %d\n", ret); + } else { ret = venus_boot_no_tz(core, mem_phys, mem_size); + } if (ret) return ret; @@ -254,6 +261,7 @@ int venus_boot(struct venus_core *core) * cp_nonpixel_start = venus_sec_non_pixel/virtual-addr-pool[0] * cp_nonpixel_size = venus_sec_non_pixel/virtual-addr-pool[1] */ + dev_info(dev, "diagnostic: configuring secure video ranges\n"); ret = qcom_scm_mem_protect_video_var(res->cp_start, res->cp_size, res->cp_nonpixel_start, diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index bd82066bb6e7..c36ce32cc6b0 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -498,6 +498,11 @@ static int venus_boot_core(struct venus_hfi_device *hdev) count++; } + if (count >= max_tries) + dev_err(dev, + "diagnostic: Venus CPU boot timed out, ctrl_status=%#x\n", + ctrl_status); + if (count >= max_tries) ret = -ETIMEDOUT; @@ -665,19 +670,24 @@ static int venus_power_off(struct venus_hfi_device *hdev) static int venus_power_on(struct venus_hfi_device *hdev) { + struct device *dev = hdev->core->dev; int ret; if (hdev->power_enabled) return 0; + dev_info(dev, "diagnostic: requesting secure hardware resume\n"); ret = venus_set_hw_state_resume(hdev->core); if (ret) goto err; + dev_info(dev, "diagnostic: secure hardware resume returned 0\n"); + dev_info(dev, "diagnostic: programming HFI queues and starting CPU\n"); ret = venus_run(hdev); if (ret) goto err_suspend; + dev_info(dev, "diagnostic: Venus CPU started\n"); hdev->power_enabled = true; return 0; -- 2.55.0