On Sunday, June 16, 2024 2:58:20 A.M. EDT Andy Yan wrote: > Hi Detlev, > Thanks for your great work。 > How can I test these patches? Do they require any additional userspace > patches? Hi Andy, You should not need anything specific in userspace. A debian bookworm rootfs will provide the gstreamer tools you need to test with a h264 video file. You can also run fluster (https://github.com/fluendo/fluster) with the GStreamer- H.264-V4L2SL-Gst1.0 decoder: ./fluster.py run -d GStreamer-H.264-V4L2SL-Gst1.0 -ts JVT-AVC_V1 -j 8 You should expect 129/135 tests passing. Detlev. > At 2024-06-15 09:56:27, "Detlev Casanova" <detlev.casanova@xxxxxxxxxxxxx> wrote: > >This driver supports the second generation of the Rockchip Video > >decoder, also known as vdpu34x. > >It is currently only used on the RK3588(s) SoC. > > > >There are 2 decoders on the RK3588 SoC that can work in pair to decode > >8K video at 30 FPS but currently, only using one core at a time is > >supported. > > > >Scheduling requests between the two cores will be implemented later. > > > >The core supports H264, HEVC, VP9 and AVS2 decoding but this driver > >currently only supports H264. > > > >The driver is based on rkvdec and they may share some code in the > >future. > >The decision to make a different driver is mainly because rkvdec2 has > >more features and can work with multiple cores. > > > >The registers are mapped in a struct in RAM using bitfields. It is IO > >copied to the HW when all values are configured. > >The decision to use such a struct instead of writing buffers one by one > > > >is based on the following reasons: > > - Rockchip cores are known to misbehave when registers are not written > > > > in address order, > > > > - Those cores also need the software to write all registers, even if > > > > they are written their default values or are not related to the task > > (this core will not start decoding some H264 frames if some VP9 > > registers are not written to 0) > > > > - In the future, to support multiple cores, the scheduler could be > > > > optimized by storing the precomputed registers values and copy them > > to the HW as soos as a core becomes available. > > > >This makes the code more readable and may bring performance improvements > >in future features. > > > >Signed-off-by: Detlev Casanova <detlev.casanova@xxxxxxxxxxxxx> > >--- > > > > drivers/staging/media/Kconfig | 1 + > > drivers/staging/media/Makefile | 1 + > > drivers/staging/media/rkvdec2/Kconfig | 15 + > > drivers/staging/media/rkvdec2/Makefile | 3 + > > drivers/staging/media/rkvdec2/TODO | 13 + > > drivers/staging/media/rkvdec2/rkvdec2-h264.c | 899 ++++++++++++++ > > drivers/staging/media/rkvdec2/rkvdec2-regs.h | 372 ++++++ > > drivers/staging/media/rkvdec2/rkvdec2.c | 1160 ++++++++++++++++++ > > drivers/staging/media/rkvdec2/rkvdec2.h | 123 ++ > > 9 files changed, 2587 insertions(+) > > create mode 100644 drivers/staging/media/rkvdec2/Kconfig > > create mode 100644 drivers/staging/media/rkvdec2/Makefile > > create mode 100644 drivers/staging/media/rkvdec2/TODO > > create mode 100644 drivers/staging/media/rkvdec2/rkvdec2-h264.c > > create mode 100644 drivers/staging/media/rkvdec2/rkvdec2-regs.h > > create mode 100644 drivers/staging/media/rkvdec2/rkvdec2.c > > create mode 100644 drivers/staging/media/rkvdec2/rkvdec2.h > > > >diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig > >index 554c2e475ce3..7f377d37e670 100644 > >--- a/drivers/staging/media/Kconfig > >+++ b/drivers/staging/media/Kconfig > >@@ -35,6 +35,7 @@ source "drivers/staging/media/meson/vdec/Kconfig" > > > > source "drivers/staging/media/omap4iss/Kconfig" > > > > source "drivers/staging/media/rkvdec/Kconfig" > > > >+source "drivers/staging/media/rkvdec2/Kconfig" > > > > source "drivers/staging/media/starfive/Kconfig" > > > >diff --git a/drivers/staging/media/Makefile > >b/drivers/staging/media/Makefile index dcaeeca0ee6d..0a2d89db32b2 100644 > >--- a/drivers/staging/media/Makefile > >+++ b/drivers/staging/media/Makefile > >@@ -6,6 +6,7 @@ obj-$(CONFIG_VIDEO_MAX96712) += max96712/ > > > > obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ > > obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ > > obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/ > > > >+obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC2) += rkvdec2/ > > > > obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive/ > > obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ > > obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ > > > >diff --git a/drivers/staging/media/rkvdec2/Kconfig > >b/drivers/staging/media/rkvdec2/Kconfig new file mode 100644 > >index 000000000000..fd505cb7aff9 > >--- /dev/null > >+++ b/drivers/staging/media/rkvdec2/Kconfig > >@@ -0,0 +1,15 @@ > >+# SPDX-License-Identifier: GPL-2.0 > >+config VIDEO_ROCKCHIP_VDEC2 > >+ tristate "Rockchip Video Decoder driver 2" > >+ depends on ARCH_ROCKCHIP || COMPILE_TEST > >+ depends on VIDEO_DEV > >+ select MEDIA_CONTROLLER > >+ select VIDEOBUF2_DMA_CONTIG > >+ select VIDEOBUF2_VMALLOC > >+ select V4L2_MEM2MEM_DEV > >+ select V4L2_H264 > >+ help > >+ Support for the Rockchip Video Decoder 2 IP present on Rockchip SoCs, > >+ which accelerates video decoding. > >+ To compile this driver as a module, choose M here: the module > >+ will be called rockchip-vdec2. > >diff --git a/drivers/staging/media/rkvdec2/Makefile > >b/drivers/staging/media/rkvdec2/Makefile new file mode 100644 > >index 000000000000..b5a6ac701970 > >--- /dev/null > >+++ b/drivers/staging/media/rkvdec2/Makefile > >@@ -0,0 +1,3 @@ > >+obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC2) += rockchip-vdec2.o > >+ > >+rockchip-vdec2-y += rkvdec2.o rkvdec2-h264.o > >diff --git a/drivers/staging/media/rkvdec2/TODO > >b/drivers/staging/media/rkvdec2/TODO new file mode 100644 > >index 000000000000..8448fb20185e > >--- /dev/null > >+++ b/drivers/staging/media/rkvdec2/TODO > >@@ -0,0 +1,13 @@ > >+* H264 features > >+ > >+ - Fluster score currently is 129/135 for JVT-AVC_V1. > >+ This probably won't improve. > >+ - RCB is not stored in sram yet. > >+ > >+* Support for HEVC and VP9 are planned for this driver. > >+ > >+ First, the h264 backend needs to be stabilized. > >+ > >+* Evaluate sharing code with rkvdec > >+ > >+ As rkvdec is still in staging, this driver stays there as well. > >diff --git a/drivers/staging/media/rkvdec2/rkvdec2-h264.c > >b/drivers/staging/media/rkvdec2/rkvdec2-h264.c new file mode 100644 > >index 000000000000..484d32f15a42 > >--- /dev/null > >+++ b/drivers/staging/media/rkvdec2/rkvdec2-h264.c > >@@ -0,0 +1,899 @@ > >+// SPDX-License-Identifier: GPL-2.0 > >+/* > >+ * Rockchip Video Decoder 2 H264 backend > >+ * > >+ * Copyright (C) 2024 Collabora, Ltd. > >+ * Detlev Casanova <detlev.casanova@xxxxxxxxxxxxx> > >+ * > >+ * Based on rkvdec driver by Boris Brezillon > ><boris.brezillon@xxxxxxxxxxxxx> + */ > >+ > >+#include <media/v4l2-h264.h> > >+#include <media/v4l2-mem2mem.h> > >+ > >+#include "rkvdec2.h" > >+#include "rkvdec2-regs.h" > >+ > >+#define RKVDEC_NUM_REFLIST 3 > >+ > >+struct rkvdec2_h264_scaling_list { > >+ u8 scaling_list_4x4[6][16]; > >+ u8 scaling_list_8x8[6][64]; > >+ u8 padding[128]; > >+}; > >+ > >+struct rkvdec2_sps { > >+ u16 seq_parameter_set_id: 4; > >+ u16 profile_idc: 8; > >+ u16 constraint_set3_flag: 1; > >+ u16 chroma_format_idc: 2; > >+ u16 bit_depth_luma: 3; > >+ u16 bit_depth_chroma: 3; > >+ u16 qpprime_y_zero_transform_bypass_flag: 1; > >+ u16 log2_max_frame_num_minus4: 4; > >+ u16 max_num_ref_frames: 5; > >+ u16 pic_order_cnt_type: 2; > >+ u16 log2_max_pic_order_cnt_lsb_minus4: 4; > >+ u16 delta_pic_order_always_zero_flag: 1; > >+ u16 pic_width_in_mbs: 12; > >+ u16 pic_height_in_mbs: 12; > >+ u16 frame_mbs_only_flag: 1; > >+ u16 mb_adaptive_frame_field_flag: 1; > >+ u16 direct_8x8_inference_flag: 1; > >+ u16 mvc_extension_enable: 1; > >+ u16 num_views: 2; > >+ > >+ u16 reserved_bits: 12; > >+ u16 reserved[11]; > >+} __packed; > >+ > >+struct rkvdec2_pps { > >+ u16 pic_parameter_set_id: 8; > >+ u16 pps_seq_parameter_set_id: 5; > >+ u16 entropy_coding_mode_flag: 1; > >+ u16 bottom_field_pic_order_in_frame_present_flag: 1; > >+ u16 num_ref_idx_l0_default_active_minus1: 5; > >+ u16 num_ref_idx_l1_default_active_minus1: 5; > >+ u16 weighted_pred_flag: 1; > >+ u16 weighted_bipred_idc: 2; > >+ u16 pic_init_qp_minus26: 7; > >+ u16 pic_init_qs_minus26: 6; > >+ u16 chroma_qp_index_offset: 5; > >+ u16 deblocking_filter_control_present_flag: 1; > >+ u16 constrained_intra_pred_flag: 1; > >+ u16 redundant_pic_cnt_present: 1; > >+ u16 transform_8x8_mode_flag: 1; > >+ u16 second_chroma_qp_index_offset: 5; > >+ u16 scaling_list_enable_flag: 1; > >+ u32 scaling_list_address; > >+ u16 is_longterm; > >+ > >+ u8 reserved[3]; > >+} __packed; > >+ > >+struct rkvdec2_rps_entry { > >+ u32 dpb_info0: 5; > >+ u32 bottom_flag0: 1; > >+ u32 view_index_off0: 1; > >+ u32 dpb_info1: 5; > >+ u32 bottom_flag1: 1; > >+ u32 view_index_off1: 1; > >+ u32 dpb_info2: 5; > >+ u32 bottom_flag2: 1; > >+ u32 view_index_off2: 1; > >+ u32 dpb_info3: 5; > >+ u32 bottom_flag3: 1; > >+ u32 view_index_off3: 1; > >+ u32 dpb_info4: 5; > >+ u32 bottom_flag4: 1; > >+ u32 view_index_off4: 1; > >+ u32 dpb_info5: 5; > >+ u32 bottom_flag5: 1; > >+ u32 view_index_off5: 1; > >+ u32 dpb_info6: 5; > >+ u32 bottom_flag6: 1; > >+ u32 view_index_off6: 1; > >+ u32 dpb_info7: 5; > >+ u32 bottom_flag7: 1; > >+ u32 view_index_off7: 1; > >+} __packed; > >+ > >+struct rkvdec2_rps { > >+ u16 frame_num[16]; > >+ u32 reserved0; > >+ struct rkvdec2_rps_entry entries[12]; > >+ u32 reserved1[66]; > >+} __packed; > >+ > >+int a = sizeof(struct rkvdec2_rps); > >+ > >+struct rkvdec2_sps_pps { > >+ struct rkvdec2_sps sps; > >+ struct rkvdec2_pps pps; > >+} __packed; > >+ > >+/* Data structure describing auxiliary buffer format. */ > >+struct rkvdec2_h264_priv_tbl { > >+ u32 cabac_table[928]; > >+ struct rkvdec2_h264_scaling_list scaling_list; > >+ struct rkvdec2_sps_pps param_set[256]; > >+ struct rkvdec2_rps rps; > >+}; > >+ > >+struct rkvdec2_h264_reflists { > >+ struct v4l2_h264_reference p[V4L2_H264_REF_LIST_LEN]; > >+ struct v4l2_h264_reference b0[V4L2_H264_REF_LIST_LEN]; > >+ struct v4l2_h264_reference b1[V4L2_H264_REF_LIST_LEN]; > >+}; > >+ > >+struct rkvdec2_h264_run { > >+ struct rkvdec2_run base; > >+ const struct v4l2_ctrl_h264_decode_params *decode_params; > >+ const struct v4l2_ctrl_h264_sps *sps; > >+ const struct v4l2_ctrl_h264_pps *pps; > >+ const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; > >+ struct vb2_buffer *ref_buf[V4L2_H264_NUM_DPB_ENTRIES]; > >+}; > >+ > >+struct rkvdec2_h264_ctx { > >+ struct rkvdec2_aux_buf priv_tbl; > >+ struct rkvdec2_h264_reflists reflists; > >+ struct rkvdec2_regs_h264 regs; > >+}; > >+ > >+/* > >+ * Constant CABAC table. > >+ */ > >+static const u32 rkvdec2_h264_cabac_table[928] = { > >+ 0x3602f114, 0xf1144a03, 0x4a033602, 0x68e97fe4, 0x36ff35fa, 0x21173307, > >+ 0x00150217, 0x31000901, 0x390576db, 0x41f54ef3, 0x310c3e01, 0x321149fc, > >+ 0x2b094012, 0x431a001d, 0x68095a10, 0x68ec7fd2, 0x4ef34301, 0x3e0141f5, > >+ 0x5fef56fa, 0x2d093dfa, 0x51fa45fd, 0x370660f5, 0x56fb4307, 0x3a005802, > >+ 0x5ef64cfd, 0x45043605, 0x580051fd, 0x4afb43f9, 0x50fb4afc, 0x3a0148f9, > >+ 0x3f002900, 0x3f003f00, 0x560453f7, 0x48f96100, 0x3e03290d, 0x4efc2d00, > >+ 0x7ee560fd, 0x65e762e4, 0x52e443e9, 0x53f05eec, 0x5beb6eea, 0x5df366ee, > >+ 0x5cf97fe3, 0x60f959fb, 0x2efd6cf3, 0x39ff41ff, 0x4afd5df7, 0x57f85cf7, > >+ 0x36057ee9, 0x3b063c06, 0x30ff4506, 0x45fc4400, 0x55fe58f8, 0x4bff4efa, > >+ 0x36024df9, 0x44fd3205, 0x2a063201, 0x3f0151fc, 0x430046fc, 0x4cfe3902, > >+ 0x4004230b, 0x230b3d01, 0x180c1912, 0x240d1d0d, 0x49f95df6, 0x2e0d49fe, > >+ 0x64f93109, 0x35023509, 0x3dfe3505, 0x38003800, 0x3cfb3ff3, 0x39043eff, > >+ 0x390445fa, 0x3304270e, 0x4003440d, 0x3f093d01, 0x27103207, 0x34042c05, > >+ 0x3cfb300b, 0x3b003bff, 0x2c052116, 0x4eff2b0e, 0x45093c00, 0x28021c0b, > >+ 0x31002c03, 0x2c022e00, 0x2f003302, 0x3e022704, 0x36002e06, 0x3a023603, > >+ 0x33063f04, 0x35073906, 0x37063406, 0x240e2d0b, 0x52ff3508, 0x4efd3707, > >+ 0x1f162e0f, 0x071954ff, 0x031cf91e, 0x0020041c, 0x061eff22, 0x0920061e, > >+ 0x1b1a131f, 0x14251e1a, 0x4611221c, 0x3b054301, 0x1e104309, 0x23122012, > >+ 0x1f181d16, 0x2b122617, 0x3f0b2914, 0x40093b09, 0x59fe5eff, 0x4cfa6cf7, > >+ 0x2d002cfe, 0x40fd3400, 0x46fc3bfe, 0x52f84bfc, 0x4df766ef, 0x2a001803, > >+ 0x37003000, 0x47f93bfa, 0x57f553f4, 0x3a0177e2, 0x24ff1dfd, 0x2b022601, > >+ 0x3a0037fa, 0x4afd4000, 0x46005af6, 0x1f051dfc, 0x3b012a07, 0x48fd3afe, > >+ 0x61f551fd, 0x05083a00, 0x120e0e0a, 0x28021b0d, 0x46fd3a00, 0x55f84ffa, > >+ 0x6af30000, 0x57f66af0, 0x6eee72eb, 0x6eea62f2, 0x67ee6aeb, 0x6ce96beb, > >+ 0x60f670e6, 0x5bfb5ff4, 0x5eea5df7, 0x430956fb, 0x55f650fc, 0x3c0746ff, > >+ 0x3d053a09, 0x320f320c, 0x36113112, 0x2e07290a, 0x310733ff, 0x29093408, > >+ 0x37022f06, 0x2c0a290d, 0x35053206, 0x3f04310d, 0x45fe4006, 0x46063bfe, > >+ 0x1f092c0a, 0x35032b0c, 0x260a220e, 0x280d34fd, 0x2c072011, 0x320d2607, > >+ 0x2b1a390a, 0x0e0b0b0e, 0x0b120b09, 0xfe170915, 0xf120f120, 0xe927eb22, > >+ 0xe129df2a, 0xf426e42e, 0xe82d1d15, 0xe630d335, 0xed2bd541, 0x091ef627, > >+ 0x1b141a12, 0x52f23900, 0x61ed4bfb, 0x001b7ddd, 0xfc1f001c, 0x0822061b, > >+ 0x16180a1e, 0x20161321, 0x29151f1a, 0x2f172c1a, 0x470e4110, 0x3f063c08, > >+ 0x18154111, 0x171a1417, 0x171c201b, 0x2817181c, 0x1d1c2018, 0x39132a17, > >+ 0x3d163516, 0x280c560b, 0x3b0e330b, 0x47f94ffc, 0x46f745fb, 0x44f642f8, > >+ 0x45f449ed, 0x43f146f0, 0x46ed3eec, 0x41ea42f0, 0xfe093fec, 0xf721f71a, > >+ 0xfe29f927, 0x0931032d, 0x3b241b2d, 0x23f942fa, 0x2df82af9, 0x38f430fb, > >+ 0x3efb3cfa, 0x4cf842f8, 0x51fa55fb, 0x51f94df6, 0x49ee50ef, 0x53f64afc, > >+ 0x43f747f7, 0x42f83dff, 0x3b0042f2, 0xf3153b02, 0xf927f221, 0x0233fe2e, > >+ 0x113d063c, 0x3e2a2237, 0x00000000, 0x00000000, 0x3602f114, 0xf1144a03, > >+ 0x4a033602, 0x68e97fe4, 0x36ff35fa, 0x19163307, 0x00100022, 0x290409fe, > >+ 0x410276e3, 0x4ff347fa, 0x32093405, 0x360a46fd, 0x1613221a, 0x02390028, > >+ 0x451a2429, 0x65f17fd3, 0x47fa4cfc, 0x34054ff3, 0x5af34506, 0x2b083400, > >+ 0x52fb45fe, 0x3b0260f6, 0x57fd4b02, 0x380164fd, 0x55fa4afd, 0x51fd3b00, > >+ 0x5ffb56f9, 0x4dff42ff, 0x56fe4601, 0x3d0048fb, 0x3f002900, 0x3f003f00, > >+ 0x560453f7, 0x48f96100, 0x3e03290d, 0x33070f0d, 0x7fd95002, 0x60ef5bee, > >+ 0x62dd51e6, 0x61e966e8, 0x63e877e5, 0x66ee6eeb, 0x50007fdc, 0x5ef959fb, > >+ 0x27005cfc, 0x54f14100, 0x49fe7fdd, 0x5bf768f4, 0x37037fe1, 0x37073807, > >+ 0x35fd3d08, 0x4af94400, 0x67f358f7, 0x59f75bf3, 0x4cf85cf2, 0x6ee957f4, > >+ 0x4ef669e8, 0x63ef70ec, 0x7fba7fb2, 0x7fd27fce, 0x4efb42fc, 0x48f847fc, > >+ 0x37ff3b02, 0x4bfa46f9, 0x77de59f8, 0x14204bfd, 0x7fd4161e, 0x3dfb3600, > >+ 0x3cff3a00, 0x43f83dfd, 0x4af254e7, 0x340541fb, 0x3d003902, 0x46f545f7, > >+ 0x47fc3712, 0x3d073a00, 0x19122909, 0x2b052009, 0x2c002f09, 0x2e023300, > >+ 0x42fc2613, 0x2a0c260f, 0x59002209, 0x1c0a2d04, 0xf5211f0a, 0x0f12d534, > >+ 0xea23001c, 0x0022e726, 0xf420ee27, 0x0000a266, 0xfc21f138, 0xfb250a1d, > >+ 0xf727e333, 0xc645de34, 0xfb2cc143, 0xe3370720, 0x00000120, 0xe721241b, > >+ 0xe424e222, 0xe526e426, 0xf023ee22, 0xf820f222, 0x0023fa25, 0x121c0a1e, > >+ 0x291d191a, 0x48024b00, 0x230e4d08, 0x23111f12, 0x2d111e15, 0x2d122a14, > >+ 0x36101a1b, 0x38104207, 0x430a490b, 0x70e974f6, 0x3df947f1, 0x42fb3500, > >+ 0x50f74df5, 0x57f654f7, 0x65eb7fde, 0x35fb27fd, 0x4bf53df9, 0x5bef4df1, > >+ 0x6fe76be7, 0x4cf57ae4, 0x34f62cf6, 0x3af739f6, 0x45f948f0, 0x4afb45fc, > >+ 0x420256f7, 0x200122f7, 0x34051f0b, 0x43fe37fe, 0x59f84900, 0x04073403, > >+ 0x0811080a, 0x25031310, 0x49fb3dff, 0x4efc46ff, 0x7eeb0000, 0x6eec7ce9, > >+ 0x7ce77ee6, 0x79e569ef, 0x66ef75e5, 0x74e575e6, 0x5ff67adf, 0x5ff864f2, > >+ 0x72e46fef, 0x50fe59fa, 0x55f752fc, 0x48ff51f8, 0x43014005, 0x45003809, > >+ 0x45074501, 0x43fa45f9, 0x40fe4df0, 0x43fa3d02, 0x390240fd, 0x42fd41fd, > >+ 0x33093e00, 0x47fe42ff, 0x46ff4bfe, 0x3c0e48f7, 0x2f002510, 0x250b2312, > >+ 0x290a290c, 0x290c3002, 0x3b00290d, 0x28133203, 0x32124203, 0xfa12fa13, > >+ 0xf41a000e, 0xe721f01f, 0xe425ea21, 0xe22ae227, 0xdc2dd62f, 0xef29de31, > >+ 0xb9450920, 0xc042c13f, 0xd936b64d, 0xf629dd34, 0xff280024, 0x1a1c0e1e, > >+ 0x370c2517, 0xdf25410b, 0xdb28dc27, 0xdf2ee226, 0xe828e22a, 0xf426e331, > >+ 0xfd26f628, 0x141ffb2e, 0x2c191e1d, 0x310b300c, 0x16162d1a, 0x151b1617, > >+ 0x1c1a1421, 0x221b181e, 0x27192a12, 0x460c3212, 0x470e3615, 0x2019530b, > >+ 0x36153115, 0x51fa55fb, 0x51f94df6, 0x49ee50ef, 0x53f64afc, 0x43f747f7, > >+ 0x42f83dff, 0x3b0042f2, 0xf6113b02, 0xf72af320, 0x0035fb31, 0x0a440340, > >+ 0x392f1b42, 0x180047fb, 0x2afe24ff, 0x39f734fe, 0x41fc3ffa, 0x52f943fc, > >+ 0x4cfd51fd, 0x4efa48f9, 0x44f248f4, 0x4cfa46fd, 0x3efb42fb, 0x3dfc3900, > >+ 0x36013cf7, 0xf6113a02, 0xf72af320, 0x0035fb31, 0x0a440340, 0x392f1b42, > >+ 0x00000000, 0x00000000, 0x3602f114, 0xf1144a03, 0x4a033602, 0x68e97fe4, > >+ 0x36ff35fa, 0x101d3307, 0x000e0019, 0x3efd33f6, 0x101a63e5, 0x66e855fc, > >+ 0x39063905, 0x390e49ef, 0x0a142814, 0x0036001d, 0x610c2a25, 0x75ea7fe0, > >+ 0x55fc4afe, 0x390566e8, 0x58f25dfa, 0x37042cfa, 0x67f159f5, 0x391374eb, > >+ 0x54043a14, 0x3f016006, 0x6af355fb, 0x4b063f05, 0x65ff5afd, 0x4ffc3703, > >+ 0x61f44bfe, 0x3c0132f9, 0x3f002900, 0x3f003f00, 0x560453f7, 0x48f96100, > >+ 0x3e03290d, 0x58f72207, 0x7fdc7fec, 0x5ff25bef, 0x56e754e7, 0x5bef59f4, > >+ 0x4cf27fe1, 0x5af367ee, 0x500b7fdb, 0x54024c05, 0x37fa4e05, 0x53f23d04, > >+ 0x4ffb7fdb, 0x5bf568f5, 0x41007fe2, 0x48004ffe, 0x38fa5cfc, 0x47f84403, > >+ 0x56fc62f3, 0x52fb58f4, 0x43fc48fd, 0x59f048f8, 0x3bff45f7, 0x39044205, > >+ 0x47fe47fc, 0x4aff3a02, 0x45ff2cfc, 0x33f93e00, 0x2afa2ffc, 0x35fa29fd, > >+ 0x4ef74c08, 0x340953f5, 0x5afb4300, 0x48f14301, 0x50f84bfb, 0x40eb53eb, > >+ 0x40e71ff3, 0x4b095ee3, 0x4af83f11, 0x1bfe23fb, 0x41035b0d, 0x4d0845f9, > >+ 0x3e0342f6, 0x51ec44fd, 0x07011e00, 0x4aeb17fd, 0x7ce94210, 0xee2c2511, > >+ 0x7feade32, 0x2a002704, 0x1d0b2207, 0x25061f08, 0x28032a07, 0x2b0d2108, > >+ 0x2f04240d, 0x3a023703, 0x2c083c06, 0x2a0e2c0b, 0x38043007, 0x250d3404, > >+ 0x3a133109, 0x2d0c300a, 0x21144500, 0xee233f08, 0xfd1ce721, 0x001b0a18, > >+ 0xd434f222, 0x1113e827, 0x1d24191f, 0x0f222118, 0x4916141e, 0x1f132214, > >+ 0x10132c1b, 0x240f240f, 0x15191c15, 0x0c1f141e, 0x2a18101b, 0x380e5d00, > >+ 0x261a390f, 0x73e87fe8, 0x3ef752ea, 0x3b003500, 0x59f355f2, 0x5cf55ef3, > >+ 0x64eb7fe3, 0x43f439f2, 0x4df647f5, 0x58f055eb, 0x62f168e9, 0x52f67fdb, > >+ 0x3df830f8, 0x46f942f8, 0x4ff64bf2, 0x5cf453f7, 0x4ffc6cee, 0x4bf045ea, > >+ 0x3a013afe, 0x53f74ef3, 0x63f351fc, 0x26fa51f3, 0x3afa3ef3, 0x49f03bfe, > >+ 0x56f34cf6, 0x57f653f7, 0x7fea0000, 0x78e77fe7, 0x72ed7fe5, 0x76e775e9, > >+ 0x71e875e6, 0x78e176e4, 0x5ef67cdb, 0x63f666f1, 0x7fce6af3, 0x39115cfb, > >+ 0x5ef356fb, 0x4dfe5bf4, 0x49ff4700, 0x51f94004, 0x390f4005, 0x44004301, > >+ 0x440143f6, 0x40024d00, 0x4efb4400, 0x3b053707, 0x360e4102, 0x3c052c0f, > >+ 0x4cfe4602, 0x460c56ee, 0x46f44005, 0x3805370b, 0x41024500, 0x36054afa, > >+ 0x4cfa3607, 0x4dfe52f5, 0x2a194dfe, 0xf710f311, 0xeb1bf411, 0xd829e225, > >+ 0xd130d72a, 0xd82ee027, 0xd72ecd34, 0xed2bd934, 0xc93d0b20, 0xce3ed238, > >+ 0xec2dbd51, 0x0f1cfe23, 0x01270122, 0x2614111e, 0x360f2d12, 0xf0244f00, > >+ 0xef25f225, 0x0f220120, 0x19180f1d, 0x101f1622, 0x1c1f1223, 0x1c242921, > >+ 0x3e152f1b, 0x1a131f12, 0x17181824, 0x1e18101b, 0x29161d1f, 0x3c102a16, > >+ 0x3c0e340f, 0x7bf04e03, 0x38163515, 0x21153d19, 0x3d113213, 0x4af84efd, > >+ 0x48f648f7, 0x47f44bee, 0x46fb3ff5, 0x48f24bef, 0x35f843f0, 0x34f73bf2, > >+ 0xfe0944f5, 0xfc1ff61e, 0x0721ff21, 0x17250c1f, 0x4014261f, 0x25f947f7, > >+ 0x31f52cf8, 0x3bf438f6, 0x43f73ff8, 0x4ff644fa, 0x4af84efd, 0x48f648f7, > >+ 0x47f44bee, 0x46fb3ff5, 0x48f24bef, 0x35f843f0, 0x34f73bf2, 0xfe0944f5, > >+ 0xfc1ff61e, 0x0721ff21, 0x17250c1f, 0x4014261f, 0x00000000, 0x00000000, > >+ 0x3602f114, 0xf1144a03, 0x4a033602, 0x68e97fe4, 0x36ff35fa, 0x00003307, > >+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, > >+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, > >+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, > >+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, > >+ 0x3f002900, 0x3f003f00, 0x560453f7, 0x48f96100, 0x3e03290d, 0x37010b00, > >+ 0x7fef4500, 0x520066f3, 0x6beb4af9, 0x7fe17fe5, 0x5fee7fe8, 0x72eb7fe5, > >+ 0x7bef7fe2, 0x7af073f4, 0x3ff473f5, 0x54f144fe, 0x46fd68f3, 0x5af65df8, > >+ 0x4aff7fe2, 0x5bf961fa, 0x38fc7fec, 0x4cf952fb, 0x5df97dea, 0x4dfd57f5, > >+ 0x3ffc47fb, 0x54f444fc, 0x41f93ef9, 0x38053d08, 0x400142fe, 0x4efe3d00, > >+ 0x34073201, 0x2c00230a, 0x2d01260b, 0x2c052e00, 0x3301111f, 0x131c3207, > >+ 0x3e0e2110, 0x64f16cf3, 0x5bf365f3, 0x58f65ef4, 0x56f654f0, 0x57f353f9, > >+ 0x46015eed, 0x4afb4800, 0x66f83b12, 0x5f0064f1, 0x48024bfc, 0x47fd4bf5, > >+ 0x45f32e0f, 0x41003e00, 0x48f12515, 0x36103909, 0x480c3e00, 0x090f0018, > >+ 0x120d1908, 0x130d090f, 0x120c250a, 0x21141d06, 0x2d041e0f, 0x3e003a01, > >+ 0x260c3d07, 0x270f2d0b, 0x2c0d2a0b, 0x290c2d10, 0x221e310a, 0x370a2a12, > >+ 0x2e113311, 0xed1a5900, 0xef1aef16, 0xec1ce71e, 0xe525e921, 0xe428e921, > >+ 0xf521ef26, 0xfa29f128, 0x11290126, 0x031bfa1e, 0xf025161a, 0xf826fc23, > >+ 0x0325fd26, 0x002a0526, 0x16271023, 0x251b300e, 0x440c3c15, 0x47fd6102, > >+ 0x32fb2afa, 0x3efe36fd, 0x3f013a00, 0x4aff48fe, 0x43fb5bf7, 0x27fd1bfb, > >+ 0x2e002cfe, 0x44f840f0, 0x4dfa4ef6, 0x5cf456f6, 0x3cf637f1, 0x41fc3efa, > >+ 0x4cf849f4, 0x58f750f9, 0x61f56eef, 0x4ff554ec, 0x4afc49fa, 0x60f356f3, > >+ 0x75ed61f5, 0x21fb4ef8, 0x35fe30fc, 0x47f33efd, 0x56f44ff6, 0x61f25af3, > >+ 0x5dfa0000, 0x4ff854fa, 0x47ff4200, 0x3cfe3e00, 0x4bfb3bfe, 0x3afc3efd, > >+ 0x4fff42f7, 0x44034700, 0x3ef92c0a, 0x280e240f, 0x1d0c1b10, 0x24142c01, > >+ 0x2a052012, 0x3e0a3001, 0x40092e11, 0x61f568f4, 0x58f960f0, 0x55f955f8, > >+ 0x58f355f7, 0x4dfd4204, 0x4cfa4cfd, 0x4cff3a0a, 0x63f953ff, 0x5f025ff2, > >+ 0x4afb4c00, 0x4bf54600, 0x41004401, 0x3e0349f2, 0x44ff3e04, 0x370b4bf3, > >+ 0x460c4005, 0x1306060f, 0x0e0c1007, 0x0b0d0d12, 0x100f0f0d, 0x170d170c, > >+ 0x1a0e140f, 0x28112c0e, 0x11182f11, 0x16191515, 0x1d161b1f, 0x320e2313, > >+ 0x3f07390a, 0x52fc4dfe, 0x45095efd, 0xdd246df4, 0xe620de24, 0xe02ce225, > >+ 0xf122ee22, 0xf921f128, 0x0021fb23, 0x0d210226, 0x3a0d2317, 0x001afd1d, > >+ 0xf91f1e16, 0xfd22f123, 0xff240322, 0x0b200522, 0x0c220523, 0x1d1e0b27, > >+ 0x271d1a22, 0x151f4213, 0x32191f1f, 0x70ec78ef, 0x55f572ee, 0x59f25cf1, > >+ 0x51f147e6, 0x440050f2, 0x38e846f2, 0x32e844e9, 0xf3174af5, 0xf128f31a, > >+ 0x032cf231, 0x222c062d, 0x52133621, 0x17ff4bfd, 0x2b012201, 0x37fe3600, > >+ 0x40013d00, 0x5cf74400, 0x61f36af2, 0x5af45af1, 0x49f658ee, 0x56f24ff7, > >+ 0x46f649f6, 0x42fb45f6, 0x3afb40f7, 0xf6153b02, 0xf81cf518, 0x031dff1c, > >+ 0x1423091d, 0x430e241d, 0x00000000, 0x00000000 > >+}; > >+ > >+static void assemble_hw_pps(struct rkvdec2_ctx *ctx, > >+ struct rkvdec2_h264_run *run) > >+{ > >+ struct rkvdec2_h264_ctx *h264_ctx = ctx->priv; > >+ const struct v4l2_ctrl_h264_sps *sps = run->sps; > >+ const struct v4l2_ctrl_h264_pps *pps = run->pps; > >+ const struct v4l2_ctrl_h264_decode_params *dec_params = > >run->decode_params; + const struct v4l2_h264_dpb_entry *dpb = > >dec_params->dpb; > >+ struct rkvdec2_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu; > >+ struct rkvdec2_sps_pps *hw_ps; > >+ dma_addr_t scaling_list_address; > >+ u32 scaling_distance; > >+ u32 i; > >+ > >+ /* > >+ * HW read the SPS/PPS information from PPS packet index by PPS id. > >+ * offset from the base can be calculated by PPS_id * 32 (size per PPS > >+ * packet unit). so the driver copy SPS/PPS information to the exact PPS > >+ * packet unit for HW accessing. > >+ */ > >+ hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id]; > >+ memset(hw_ps, 0, sizeof(*hw_ps)); > >+ > >+ /* write sps */ > >+ hw_ps->sps.seq_parameter_set_id = 0xf; > >+ hw_ps->sps.profile_idc = 0xff; > >+ hw_ps->sps.constraint_set3_flag = 1; > >+ hw_ps->sps.chroma_format_idc = sps->chroma_format_idc; > >+ hw_ps->sps.bit_depth_luma = sps->bit_depth_luma_minus8; > >+ hw_ps->sps.bit_depth_chroma = sps->bit_depth_chroma_minus8; > >+ hw_ps->sps.qpprime_y_zero_transform_bypass_flag = 0; > >+ hw_ps->sps.log2_max_frame_num_minus4 = sps- >log2_max_frame_num_minus4; > >+ hw_ps->sps.max_num_ref_frames = sps->max_num_ref_frames; > >+ hw_ps->sps.pic_order_cnt_type = sps->pic_order_cnt_type; > >+ hw_ps->sps.log2_max_pic_order_cnt_lsb_minus4 = > >+ sps->log2_max_pic_order_cnt_lsb_minus4; > >+ hw_ps->sps.delta_pic_order_always_zero_flag = > >+ !!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO); > >+ hw_ps->sps.mvc_extension_enable = 1; > >+ hw_ps->sps.num_views = 1; > >+ > >+ /* > >+ * Use the SPS values since they are already in macroblocks > >+ * dimensions, height can be field height (halved) if > >+ * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is not set and also it allows > >+ * decoding smaller images into larger allocation which can be used > >+ * to implementing SVC spatial layer support. > >+ */ > >+ hw_ps->sps.pic_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1; > >+ hw_ps->sps.pic_height_in_mbs = sps->pic_height_in_map_units_minus1 + 1; > >+ hw_ps->sps.frame_mbs_only_flag = > >+ !!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY); > >+ hw_ps->sps.mb_adaptive_frame_field_flag = > >+ !!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD); > >+ hw_ps->sps.direct_8x8_inference_flag = > >+ !!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE); > >+ > >+ /* write pps */ > >+ hw_ps->pps.pic_parameter_set_id = 0xff; > >+ hw_ps->pps.pps_seq_parameter_set_id = 0x1f; > >+ hw_ps->pps.entropy_coding_mode_flag = > >+ !!(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE); > >+ hw_ps->pps.bottom_field_pic_order_in_frame_present_flag = > >+ !!(pps->flags & > >V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT); > >+ hw_ps->pps.num_ref_idx_l0_default_active_minus1 = > >+ pps->num_ref_idx_l0_default_active_minus1; > >+ hw_ps->pps.num_ref_idx_l1_default_active_minus1 = > >+ pps->num_ref_idx_l1_default_active_minus1; > >+ hw_ps->pps.weighted_pred_flag = > >+ !!(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED); > >+ hw_ps->pps.weighted_bipred_idc = pps->weighted_bipred_idc; > >+ hw_ps->pps.pic_init_qp_minus26 = pps->pic_init_qp_minus26; > >+ hw_ps->pps.pic_init_qs_minus26 = pps->pic_init_qs_minus26; > >+ hw_ps->pps.chroma_qp_index_offset = pps->chroma_qp_index_offset; > >+ hw_ps->pps.deblocking_filter_control_present_flag = > >+ !!(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT); > >+ hw_ps->pps.constrained_intra_pred_flag = > >+ !!(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED); > >+ hw_ps->pps.redundant_pic_cnt_present = > >+ !!(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT); > >+ hw_ps->pps.transform_8x8_mode_flag = > >+ !!(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE); > >+ hw_ps->pps.second_chroma_qp_index_offset = > >pps->second_chroma_qp_index_offset; + hw_ps- >pps.scaling_list_enable_flag > >= > >+ !!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT); > >+ > >+ /* > >+ * To be on the safe side, program the scaling matrix address > >+ * > >+ * With this set here, > >+ * RKVDEC_SWREG12_SENCODARY_EN:sw_scanlist_addr_valid_en > >+ * can stay at 0 > >+ */ > >+ scaling_distance = offsetof(struct rkvdec2_h264_priv_tbl, scaling_list); > >+ scaling_list_address = h264_ctx->priv_tbl.dma + scaling_distance; > >+ hw_ps->pps.scaling_list_address = scaling_list_address; > >+ > >+ for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { > >+ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) > >+ hw_ps->pps.is_longterm |= (1 << i); > >+ } > >+} > >+ > >+static void lookup_ref_buf_idx(struct rkvdec2_ctx *ctx, > >+ struct rkvdec2_h264_run *run) > >+{ > >+ const struct v4l2_ctrl_h264_decode_params *dec_params = > >run->decode_params; + u32 i; > >+ > >+ for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { > >+ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; > >+ const struct v4l2_h264_dpb_entry *dpb = run- >decode_params->dpb; > >+ struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; > >+ struct vb2_buffer *buf = NULL; > >+ > >+ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) { > >+ buf = vb2_find_buffer(cap_q, dpb[i].reference_ts); > >+ if (!buf) { > >+ dev_dbg(ctx->dev->dev, "No buffer for reference_ts %llu", > >+ dpb[i].reference_ts); > >+ } > >+ } > >+ > >+ run->ref_buf[i] = buf; > >+ } > >+} > >+ > >+static void set_dpb_info(struct rkvdec2_rps_entry *entries, > >+ u8 reflist, > >+ u8 refnum, > >+ u8 info, > >+ bool bottom) > >+{ > >+ struct rkvdec2_rps_entry *entry = &entries[(reflist * 4) + refnum / 8]; > >+ u8 idx = refnum % 8; > >+ > >+ switch (idx) { > >+ case 0: > >+ entry->dpb_info0 = info; > >+ entry->bottom_flag0 = bottom; > >+ break; > >+ case 1: > >+ entry->dpb_info1 = info; > >+ entry->bottom_flag1 = bottom; > >+ break; > >+ case 2: > >+ entry->dpb_info2 = info; > >+ entry->bottom_flag2 = bottom; > >+ break; > >+ case 3: > >+ entry->dpb_info3 = info; > >+ entry->bottom_flag3 = bottom; > >+ break; > >+ case 4: > >+ entry->dpb_info4 = info; > >+ entry->bottom_flag4 = bottom; > >+ break; > >+ case 5: > >+ entry->dpb_info5 = info; > >+ entry->bottom_flag5 = bottom; > >+ break; > >+ case 6: > >+ entry->dpb_info6 = info; > >+ entry->bottom_flag6 = bottom; > >+ break; > >+ case 7: > >+ entry->dpb_info7 = info; > >+ entry->bottom_flag7 = bottom; > >+ break; > >+ } > >+} > >+ > >+static void assemble_hw_rps(struct rkvdec2_ctx *ctx, > >+ struct v4l2_h264_reflist_builder *builder, > >+ struct rkvdec2_h264_run *run) > >+{ > >+ const struct v4l2_ctrl_h264_decode_params *dec_params = > >run->decode_params; + const struct v4l2_h264_dpb_entry *dpb = > >dec_params->dpb; > >+ struct rkvdec2_h264_ctx *h264_ctx = ctx->priv; > >+ struct rkvdec2_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu; > >+ > >+ struct rkvdec2_rps *hw_rps = &priv_tbl->rps; > >+ u32 i, j; > >+ > >+ memset(hw_rps, 0, sizeof(priv_tbl->rps)); > >+ > >+ /* > >+ * Assign an invalid pic_num if DPB entry at that position is inactive. > >+ * If we assign 0 in that position hardware will treat that as a real > >+ * reference picture with pic_num 0, triggering output picture > >+ * corruption. > >+ */ > >+ for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { > >+ if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) > >+ continue; > >+ > >+ hw_rps->frame_num[i] = builder->refs[i].frame_num; > >+ } > >+ > >+ for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { > >+ for (i = 0; i < builder->num_valid; i++) { > >+ struct v4l2_h264_reference *ref; > >+ bool dpb_valid; > >+ bool bottom; > >+ > >+ switch (j) { > >+ case 0: > >+ ref = &h264_ctx->reflists.p[i]; > >+ break; > >+ case 1: > >+ ref = &h264_ctx->reflists.b0[i]; > >+ break; > >+ case 2: > >+ ref = &h264_ctx->reflists.b1[i]; > >+ break; > >+ } > >+ > >+ if (WARN_ON(ref->index >= ARRAY_SIZE(dec_params->dpb))) > >+ continue; > >+ > >+ dpb_valid = !!(run->ref_buf[ref->index]); > >+ bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF; > >+ > >+ set_dpb_info(hw_rps->entries, j, i, ref- >index | (dpb_valid << 4), > >bottom); + } > >+ } > >+} > >+ > >+static void assemble_hw_scaling_list(struct rkvdec2_ctx *ctx, > >+ struct rkvdec2_h264_run *run) > >+{ > >+ const struct v4l2_ctrl_h264_scaling_matrix *scaling = > >run->scaling_matrix; + const struct v4l2_ctrl_h264_pps *pps = run->pps; > >+ struct rkvdec2_h264_ctx *h264_ctx = ctx->priv; > >+ struct rkvdec2_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu; > >+ > >+ if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)) > >+ return; > >+ > >+ BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_4x4) != > >+ sizeof(scaling->scaling_list_4x4)); > >+ BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_8x8) != > >+ sizeof(scaling->scaling_list_8x8)); > >+ > >+ memcpy(tbl->scaling_list.scaling_list_4x4, > >+ scaling->scaling_list_4x4, > >+ sizeof(scaling->scaling_list_4x4)); > >+ > >+ memcpy(tbl->scaling_list.scaling_list_8x8, > >+ scaling->scaling_list_8x8, > >+ sizeof(scaling->scaling_list_8x8)); > >+} > >+ > >+static void rkvdec2_write_regs(struct rkvdec2_ctx *ctx) > >+{ > >+ struct rkvdec2_dev *rkvdec = ctx->dev; > >+ struct rkvdec2_h264_ctx *h264_ctx = ctx->priv; > >+ > >+ __iowrite32_copy_full(rkvdec->regs + OFFSET_COMMON_REGS, > >+ &h264_ctx->regs.common, > >+ sizeof(h264_ctx->regs.common)); > >+ __iowrite32_copy_full(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS, > >+ &h264_ctx->regs.h264_param, > >+ sizeof(h264_ctx->regs.h264_param)); > >+ __iowrite32_copy_full(rkvdec->regs + OFFSET_COMMON_ADDR_REGS, > >+ &h264_ctx->regs.common_addr, > >+ sizeof(h264_ctx->regs.common_addr)); > >+ __iowrite32_copy_full(rkvdec->regs + OFFSET_CODEC_ADDR_REGS, > >+ &h264_ctx->regs.h264_addr, > >+ sizeof(h264_ctx->regs.h264_addr)); > >+ __iowrite32_copy_full(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS, > >+ &h264_ctx->regs.h264_highpoc, > >+ sizeof(h264_ctx->regs.h264_highpoc)); > >+} > >+ > >+static void config_registers(struct rkvdec2_ctx *ctx, > >+ struct rkvdec2_h264_run *run) > >+{ > >+ const struct v4l2_ctrl_h264_decode_params *dec_params = > >run->decode_params; + const struct v4l2_ctrl_h264_sps *sps = run- >sps; > >+ const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb; > >+ struct rkvdec2_h264_ctx *h264_ctx = ctx->priv; > >+ dma_addr_t priv_start_addr = h264_ctx->priv_tbl.dma; > >+ const struct v4l2_pix_format_mplane *dst_fmt; > >+ struct vb2_v4l2_buffer *src_buf = run->base.bufs.src; > >+ struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst; > >+ struct rkvdec2_regs_h264 *regs = &h264_ctx->regs; > >+ const struct v4l2_format *f; > >+ dma_addr_t rlc_addr; > >+ dma_addr_t dst_addr; > >+ u32 hor_virstride = 0; > >+ u32 ver_virstride = 0; > >+ u32 y_virstride = 0; > >+ u32 yuv_virstride = 0; > >+ u32 offset; > >+ u32 pixels; > >+ u32 i; > >+ > >+ memset(regs, 0, sizeof(*regs)); > >+ > >+ /* Set H264 mode */ > >+ regs->common.reg009.dec_mode = RKVDEC2_MODE_H264; > >+ > >+ /* Set config */ > >+ regs->common.reg011.buf_empty_en = 1; > >+ regs->common.reg011.dec_clkgate_e = 1; > >+ regs->common.reg011.dec_timeout_e = 1; > >+ regs->common.reg011.pix_range_detection_e = 1; > >+ > >+ /* Set IDR flag */ > >+ regs->common.reg013.cur_pic_is_idr = > >+ !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC); > >+ > >+ /* Set input stream length */ > >+ regs->common.reg016_str_len = vb2_get_plane_payload(&src_buf- >vb2_buf, > >0); + > >+ /* Set max slice number */ > >+ regs->common.reg017.slice_num = MAX_SLICE_NUMBER; > >+ > >+ /* Set strides */ > >+ f = &ctx->decoded_fmt; > >+ dst_fmt = &f->fmt.pix_mp; > >+ hor_virstride = (sps->bit_depth_luma_minus8 + 8) * dst_fmt->width / 8; > >+ ver_virstride = round_up(dst_fmt->height, 16); > >+ y_virstride = hor_virstride * ver_virstride; > >+ pixels = dst_fmt->height * dst_fmt->width; > >+ > >+ if (sps->chroma_format_idc == 0) > >+ yuv_virstride = y_virstride; > >+ else if (sps->chroma_format_idc == 1) > >+ yuv_virstride += y_virstride + y_virstride / 2; > >+ else if (sps->chroma_format_idc == 2) > >+ yuv_virstride += 2 * y_virstride; > >+ > >+ regs->common.reg018.y_hor_virstride = hor_virstride / 16; > >+ regs->common.reg019.uv_hor_virstride = hor_virstride / 16; > >+ regs->common.reg020_y_virstride.y_virstride = y_virstride / 16; > >+ > >+ /* Activate block gating */ > >+ regs->common.reg026.swreg_block_gating_e = 0xfffef; > >+ regs->common.reg026.reg_cfg_gating_en = 1; > >+ > >+ /* Set timeout threshold */ > >+ if (pixels < RKVDEC2_1080P_PIXELS) > >+ regs->common.reg032_timeout_threshold = RKVDEC2_TIMEOUT_1080p; > >+ else if (pixels < RKVDEC2_4K_PIXELS) > >+ regs->common.reg032_timeout_threshold = RKVDEC2_TIMEOUT_4K; > >+ else if (pixels < RKVDEC2_8K_PIXELS) > >+ regs->common.reg032_timeout_threshold = RKVDEC2_TIMEOUT_8K; > >+ > >+ /* Set TOP and BOTTOM POCs */ > >+ regs->h264_param.cur_top_poc = dec_params->top_field_order_cnt; > >+ regs->h264_param.cur_bot_poc = dec_params->bottom_field_order_cnt; > >+ > >+ /* Set ref pic address & poc */ > >+ for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { > >+ struct vb2_buffer *vb_buf = run->ref_buf[i]; > >+ dma_addr_t buf_dma; > >+ > >+ /* > >+ * If a DPB entry is unused or invalid, address of current destination > >+ * buffer is returned. > >+ */ > >+ if (!vb_buf) > >+ vb_buf = &dst_buf->vb2_buf; > >+ > >+ buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0); > >+ > >+ /* Set reference addresses */ > >+ regs->h264_addr.ref_base[i] = buf_dma; > >+ > >+ /* Set COLMV addresses */ > >+ regs->h264_addr.colmv_base[i] = buf_dma + ctx- >colmv_offset; > >+ > >+ struct rkvdec2_h264_ref_info *ref_info = > >+ ®s->h264_param.reg99_102_ref_info[i / 4].ref_info[i % 4]; > >+ > >+ ref_info->ref_field = > >+ !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD); > >+ ref_info->ref_colmv_use_flag = > >+ !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE); > >+ ref_info->ref_topfield_used = > >+ !!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF); > >+ ref_info->ref_botfield_used = > >+ !!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF); > >+ > >+ regs->h264_param.reg67_98_ref_poc[i * 2] = > >+ dpb[i].top_field_order_cnt; > >+ regs->h264_param.reg67_98_ref_poc[i * 2 + 1] = > >+ dpb[i].bottom_field_order_cnt; > >+ } > >+ > >+ /* Set rlc base address (input stream) */ > >+ rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); > >+ regs->common_addr.reg128_rlc_base = rlc_addr; > >+ regs->common_addr.reg129_rlcwrite_base = rlc_addr; > >+ > >+ /* Set output base address */ > >+ dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); > >+ regs->common_addr.reg130_decout_base = dst_addr; > >+ > >+ /* Set colmv address */ > >+ regs->common_addr.reg131_colmv_cur_base = dst_addr + ctx- >colmv_offset; > >+ > >+ /* Set RCB addresses */ > >+ for (i = 0; i < RKVDEC2_RCB_COUNT; i++) > >+ regs->common_addr.reg133_142_rcb_base[i] = ctx- >rcb_bufs[i].dma; > >+ > >+ /* Set hw pps address */ > >+ offset = offsetof(struct rkvdec2_h264_priv_tbl, param_set); > >+ regs->h264_addr.pps_base = priv_start_addr + offset; > >+ > >+ /* Set hw rps address */ > >+ offset = offsetof(struct rkvdec2_h264_priv_tbl, rps); > >+ regs->h264_addr.rps_base = priv_start_addr + offset; > >+ > >+ /* Set cabac table */ > >+ offset = offsetof(struct rkvdec2_h264_priv_tbl, cabac_table); > >+ regs->h264_addr.cabactbl_base = priv_start_addr + offset; > >+ > >+ rkvdec2_write_regs(ctx); > >+} > >+ > >+#define RKVDEC_H264_MAX_DEPTH_IN_BYTES 2 > >+ > >+static int rkvdec2_h264_adjust_fmt(struct rkvdec2_ctx *ctx, > >+ struct v4l2_format *f) > >+{ > >+ struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp; > >+ > >+ fmt->num_planes = 1; > >+ if (!fmt->plane_fmt[0].sizeimage) > >+ fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * > >+ RKVDEC_H264_MAX_DEPTH_IN_BYTES; > >+ return 0; > >+} > >+ > >+static int rkvdec2_h264_validate_sps(struct rkvdec2_ctx *ctx, > >+ const struct v4l2_ctrl_h264_sps *sps) > >+{ > >+ unsigned int width, height; > >+ > >+ /* FIXME: TBC > >+ * TODO: The hardware supports 10-bit and 4:2:2 profiles, > >+ * but it's currently broken in the driver. > >+ * Reject them for now, until it's fixed. > >+ */ > >+ if (sps->chroma_format_idc > 1) > >+ /* Only 4:0:0 and 4:2:0 are supported */ > >+ return -EINVAL; > >+ if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) > >+ /* Luma and chroma bit depth mismatch */ > >+ return -EINVAL; > >+ if (sps->bit_depth_luma_minus8 != 0) > >+ /* Only 8-bit is supported */ > >+ return -EINVAL; > >+ > >+ width = (sps->pic_width_in_mbs_minus1 + 1) * 16; > >+ height = (sps->pic_height_in_map_units_minus1 + 1) * 16; > >+ > >+ /* > >+ * When frame_mbs_only_flag is not set, this is field height, > >+ * which is half the final height (see (7-18) in the > >+ * specification) > >+ */ > >+ if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)) > >+ height *= 2; > >+ > >+ if (width > ctx->coded_fmt.fmt.pix_mp.width || > >+ height > ctx->coded_fmt.fmt.pix_mp.height) > >+ return -EINVAL; > >+ > >+ return 0; > >+} > >+ > >+static int rkvdec2_h264_start(struct rkvdec2_ctx *ctx) > >+{ > >+ struct rkvdec2_dev *rkvdec = ctx->dev; > >+ struct rkvdec2_h264_priv_tbl *priv_tbl; > >+ struct rkvdec2_h264_ctx *h264_ctx; > >+ struct v4l2_ctrl *ctrl; > >+ int ret; > >+ > >+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, > >+ V4L2_CID_STATELESS_H264_SPS); > >+ if (!ctrl) > >+ return -EINVAL; > >+ > >+ ret = rkvdec2_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps); > >+ if (ret) > >+ return ret; > >+ > >+ h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL); > >+ if (!h264_ctx) > >+ return -ENOMEM; > >+ > >+ priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), > >+ &h264_ctx->priv_tbl.dma, GFP_KERNEL); > >+ if (!priv_tbl) { > >+ ret = -ENOMEM; > >+ goto err_free_ctx; > >+ } > >+ > >+ h264_ctx->priv_tbl.size = sizeof(*priv_tbl); > >+ h264_ctx->priv_tbl.cpu = priv_tbl; > >+ memcpy(priv_tbl->cabac_table, rkvdec2_h264_cabac_table, > >+ sizeof(rkvdec2_h264_cabac_table)); > >+ > >+ ctx->priv = h264_ctx; > >+ return 0; > >+ > >+err_free_ctx: > >+ kfree(h264_ctx); > >+ return ret; > >+} > >+ > >+static void rkvdec2_h264_stop(struct rkvdec2_ctx *ctx) > >+{ > >+ struct rkvdec2_h264_ctx *h264_ctx = ctx->priv; > >+ struct rkvdec2_dev *rkvdec = ctx->dev; > >+ > >+ dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size, > >+ h264_ctx->priv_tbl.cpu, h264_ctx- >priv_tbl.dma); > >+ kfree(h264_ctx); > >+} > >+ > >+static void rkvdec2_h264_run_preamble(struct rkvdec2_ctx *ctx, > >+ struct rkvdec2_h264_run *run) > >+{ > >+ struct v4l2_ctrl *ctrl; > >+ > >+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, > >+ V4L2_CID_STATELESS_H264_DECODE_PARAMS); > >+ run->decode_params = ctrl ? ctrl->p_cur.p : NULL; > >+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, > >+ V4L2_CID_STATELESS_H264_SPS); > >+ run->sps = ctrl ? ctrl->p_cur.p : NULL; > >+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, > >+ V4L2_CID_STATELESS_H264_PPS); > >+ run->pps = ctrl ? ctrl->p_cur.p : NULL; > >+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, > >+ V4L2_CID_STATELESS_H264_SCALING_MATRIX); > >+ run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL; > >+ > >+ rkvdec2_run_preamble(ctx, &run->base); > >+} > >+ > >+static int rkvdec2_h264_run(struct rkvdec2_ctx *ctx) > >+{ > >+ struct v4l2_h264_reflist_builder reflist_builder; > >+ struct rkvdec2_dev *rkvdec = ctx->dev; > >+ struct rkvdec2_h264_ctx *h264_ctx = ctx->priv; > >+ struct rkvdec2_h264_run run; > >+ > >+ rkvdec2_h264_run_preamble(ctx, &run); > >+ > >+ /* Build the P/B{0,1} ref lists. */ > >+ v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params, > >+ run.sps, run.decode_params- >dpb); > >+ v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p); > >+ v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0, > >+ h264_ctx->reflists.b1); > >+ > >+ assemble_hw_scaling_list(ctx, &run); > >+ assemble_hw_pps(ctx, &run); > >+ lookup_ref_buf_idx(ctx, &run); > >+ assemble_hw_rps(ctx, &reflist_builder, &run); > >+ > >+ config_registers(ctx, &run); > >+ > >+ rkvdec2_run_postamble(ctx, &run.base); > >+ > >+ schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000)); > >+ > >+ /* Start decoding! */ > >+ writel(RKVDEC2_REG_DEC_E_BIT, rkvdec->regs + RKVDEC2_REG_DEC_E); > >+ > >+ return 0; > >+} > >+ > >+static int rkvdec2_h264_try_ctrl(struct rkvdec2_ctx *ctx, struct v4l2_ctrl > >*ctrl) +{ > >+ if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) > >+ return rkvdec2_h264_validate_sps(ctx, ctrl- >p_new.p_h264_sps); > >+ > >+ return 0; > >+} > >+ > >+const struct rkvdec2_coded_fmt_ops rkvdec2_h264_fmt_ops = { > >+ .adjust_fmt = rkvdec2_h264_adjust_fmt, > >+ .start = rkvdec2_h264_start, > >+ .stop = rkvdec2_h264_stop, > >+ .run = rkvdec2_h264_run, > >+ .try_ctrl = rkvdec2_h264_try_ctrl, > >+}; > >diff --git a/drivers/staging/media/rkvdec2/rkvdec2-regs.h > >b/drivers/staging/media/rkvdec2/rkvdec2-regs.h new file mode 100644 > >index 000000000000..a214597cdcdc > >--- /dev/null > >+++ b/drivers/staging/media/rkvdec2/rkvdec2-regs.h > >@@ -0,0 +1,372 @@ > >+// SPDX-License-Identifier: GPL-2.0 > >+/* > >+ * Rockchip Video Decoder 2 driver registers description > >+ * > >+ * Copyright (C) 2024 Collabora, Ltd. > >+ * Detlev Casanova <detlev.casanova@xxxxxxxxxxxxx> > >+ */ > >+ > >+#ifndef _RKVDEC_REGS_H_ > >+#define _RKVDEC_REGS_H_ > >+ > >+#define OFFSET_COMMON_REGS (8 * sizeof(u32)) > >+#define OFFSET_CODEC_PARAMS_REGS (64 * sizeof(u32)) > >+#define OFFSET_COMMON_ADDR_REGS (128 * sizeof(u32)) > >+#define OFFSET_CODEC_ADDR_REGS (160 * sizeof(u32)) > >+#define OFFSET_POC_HIGHBIT_REGS (200 * sizeof(u32)) > >+ > >+#define RKVDEC2_MODE_HEVC 0 > >+#define RKVDEC2_MODE_H264 1 > >+#define RKVDEC2_MODE_VP9 2 > >+#define RKVDEC2_MODE_AVS2 3 > >+ > >+#define MAX_SLICE_NUMBER 0x3fff > >+ > >+#define RKVDEC2_1080P_PIXELS (1920 * 1080) > >+#define RKVDEC2_4K_PIXELS (4096 * 2304) > >+#define RKVDEC2_8K_PIXELS (7680 * 4320) > >+#define RKVDEC2_TIMEOUT_1080p (0xefffff) > >+#define RKVDEC2_TIMEOUT_4K (0x2cfffff) > >+#define RKVDEC2_TIMEOUT_8K (0x4ffffff) > >+ > >+#define RKVDEC2_REG_DEC_E 0x028 > >+#define RKVDEC2_REG_DEC_E_BIT 1 > >+ > >+#define RKVDEC2_REG_IMPORTANT_EN 0x02c > >+#define RKVDEC2_REG_DEC_IRQ_DISABLE BIT(4) > >+ > >+#define RKVDEC2_REG_STA_INT 0x380 > >+#define STA_INT_DEC_RDY_STA BIT(2) > >+ > >+/* base: OFFSET_COMMON_REGS */ > >+struct rkvdec2_regs_common { > >+ struct rkvdec2_in_out { > >+ u32 in_endian : 1; > >+ u32 in_swap32_e : 1; > >+ u32 in_swap64_e : 1; > >+ u32 str_endian : 1; > >+ u32 str_swap32_e : 1; > >+ u32 str_swap64_e : 1; > >+ u32 out_endian : 1; > >+ u32 out_swap32_e : 1; > >+ u32 out_cbcr_swap : 1; > >+ u32 out_swap64_e : 1; > >+ u32 reserved : 22; > >+ } reg008; > >+ > >+ struct rkvdec2_dec_mode { > >+ u32 dec_mode : 10; > >+ u32 reserved : 22; > >+ } reg009; > >+ > >+ struct rkvdec2_dec_e { > >+ u32 dec_e : 1; > >+ u32 reserved : 31; > >+ } reg010; > >+ > >+ struct rkvdec2_important_en { > >+ u32 reserved : 1; > >+ u32 dec_clkgate_e : 1; > >+ u32 dec_e_strmd_clkgate_dis : 1; > >+ u32 reserved0 : 1; > >+ > >+ u32 dec_irq_dis : 1; > >+ u32 dec_timeout_e : 1; > >+ u32 buf_empty_en : 1; > >+ u32 reserved1 : 3; > >+ > >+ u32 dec_e_rewrite_valid : 1; > >+ u32 reserved2 : 9; > >+ u32 softrst_en_p : 1; > >+ u32 force_softreset_valid : 1; > >+ u32 reserved3 : 2; > >+ u32 pix_range_detection_e : 1; > >+ u32 reserved4 : 7; > >+ } reg011; > >+ > >+ struct rkvdec2_sencodary_en { > >+ u32 wr_ddr_align_en : 1; > >+ u32 colmv_compress_en : 1; > >+ u32 fbc_e : 1; > >+ u32 reserved0 : 1; > >+ > >+ u32 buspr_slot_disable : 1; > >+ u32 error_info_en : 1; > >+ u32 info_collect_en : 1; > >+ u32 wait_reset_en : 1; > >+ > >+ u32 scanlist_addr_valid_en : 1; > >+ u32 scale_down_en : 1; > >+ u32 error_cfg_wr_disable : 1; > >+ u32 reserved1 : 21; > >+ } reg012; > >+ > >+ struct rkvdec2_en_mode_set { > >+ u32 timeout_mode : 1; > >+ u32 req_timeout_rst_sel : 1; > >+ u32 reserved0 : 1; > >+ u32 dec_commonirq_mode : 1; > >+ u32 reserved1 : 2; > >+ u32 stmerror_waitdecfifo_empty : 1; > >+ u32 reserved2 : 2; > >+ u32 h26x_streamd_error_mode : 1; > >+ u32 reserved3 : 2; > >+ u32 allow_not_wr_unref_bframe : 1; > >+ u32 fbc_output_wr_disable : 1; > >+ u32 reserved4 : 1; > >+ u32 colmv_error_mode : 1; > >+ > >+ u32 reserved5 : 2; > >+ u32 h26x_error_mode : 1; > >+ u32 reserved6 : 2; > >+ u32 ycacherd_prior : 1; > >+ u32 reserved7 : 2; > >+ u32 cur_pic_is_idr : 1; > >+ u32 reserved8 : 1; > >+ u32 right_auto_rst_disable : 1; > >+ u32 frame_end_err_rst_flag : 1; > >+ u32 rd_prior_mode : 1; > >+ u32 rd_ctrl_prior_mode : 1; > >+ u32 reserved9 : 1; > >+ u32 filter_outbuf_mode : 1; > >+ } reg013; > >+ > >+ struct rkvdec2_fbc_param_set { > >+ u32 fbc_force_uncompress : 1; > >+ > >+ u32 reserved0 : 2; > >+ u32 allow_16x8_cp_flag : 1; > >+ u32 reserved1 : 2; > >+ > >+ u32 fbc_h264_exten_4or8_flag : 1; > >+ u32 reserved2 : 25; > >+ } reg014; > >+ > >+ struct rkvdec2_stream_param_set { > >+ u32 rlc_mode_direct_write : 1; > >+ u32 rlc_mode : 1; > >+ u32 reserved0 : 3; > >+ > >+ u32 strm_start_bit : 7; > >+ u32 reserved1 : 20; > >+ } reg015; > >+ > >+ u32 reg016_str_len; > >+ > >+ struct rkvdec2_slice_number { > >+ u32 slice_num : 25; > >+ u32 reserved : 7; > >+ } reg017; > >+ > >+ struct rkvdec2_y_hor_stride { > >+ u32 y_hor_virstride : 16; > >+ u32 reserved : 16; > >+ } reg018; > >+ > >+ struct rkvdec2_uv_hor_stride { > >+ u32 uv_hor_virstride : 16; > >+ u32 reserved : 16; > >+ } reg019; > >+ > >+ union { > >+ struct rkvdec2_y_stride { > >+ u32 y_virstride : 28; > >+ u32 reserved : 4; > >+ } reg020_y_virstride; > >+ > >+ struct rkvdec2_fbc_payload_offset { > >+ u32 reserved : 4; > >+ u32 payload_st_offset : 28; > >+ } reg020_fbc_payload_off; > >+ }; > >+ > >+ struct rkvdec2_error_ctrl_set { > >+ u32 inter_error_prc_mode : 1; > >+ u32 error_intra_mode : 1; > >+ u32 error_deb_en : 1; > >+ u32 picidx_replace : 5; > >+ u32 error_spread_e : 1; > >+ u32 reserved0 : 3; > >+ u32 error_inter_pred_cross_slice : 1; > >+ u32 reserved1 : 11; > >+ u32 roi_error_ctu_cal_en : 1; > >+ u32 reserved2 : 7; > >+ } reg021; > >+ > >+ struct rkvdec2_err_roi_ctu_offset_start { > >+ u32 roi_x_ctu_offset_st : 12; > >+ u32 reserved0 : 4; > >+ u32 roi_y_ctu_offset_st : 12; > >+ u32 reserved1 : 4; > >+ } reg022; > >+ > >+ struct rkvdec2_err_roi_ctu_offset_end { > >+ u32 roi_x_ctu_offset_end : 12; > >+ u32 reserved0 : 4; > >+ u32 roi_y_ctu_offset_end : 12; > >+ u32 reserved1 : 4; > >+ } reg023; > >+ > >+ struct rkvdec2_cabac_error_en_lowbits { > >+ u32 cabac_err_en_lowbits : 32; > >+ } reg024; > >+ > >+ struct rkvdec2_cabac_error_en_highbits { > >+ u32 cabac_err_en_highbits : 30; > >+ u32 reserved : 2; > >+ } reg025; > >+ > >+ struct rkvdec2_block_gating_en { > >+ u32 swreg_block_gating_e : 20; > >+ u32 reserved : 11; > >+ u32 reg_cfg_gating_en : 1; > >+ } reg026; > >+ > >+ /* NOTE: reg027 ~ reg032 are added in vdpu38x at rk3588 */ > >+ struct SW027_CORE_SAFE_PIXELS { > >+ // colmv and recon report coord x safe pixels > >+ u32 core_safe_x_pixels : 16; > >+ // colmv and recon report coord y safe pixels > >+ u32 core_safe_y_pixels : 16; > >+ } reg027; > >+ > >+ struct rkvdec2_multiply_core_ctrl { > >+ u32 swreg_vp9_wr_prob_idx : 3; > >+ u32 reserved0 : 1; > >+ u32 swreg_vp9_rd_prob_idx : 3; > >+ u32 reserved1 : 1; > >+ > >+ u32 swreg_ref_req_advance_flag : 1; > >+ u32 sw_colmv_req_advance_flag : 1; > >+ u32 sw_poc_only_highbit_flag : 1; > >+ u32 sw_poc_arb_flag : 1; > >+ > >+ u32 reserved2 : 4; > >+ u32 sw_film_idx : 10; > >+ u32 reserved3 : 2; > >+ u32 sw_pu_req_mismatch_dis : 1; > >+ u32 sw_colmv_req_mismatch_dis : 1; > >+ u32 reserved4 : 2; > >+ } reg028; > >+ > >+ struct SW029_SCALE_DOWN_CTRL { > >+ u32 scale_down_hor_ratio : 2; > >+ u32 reserved0 : 6; > >+ u32 scale_down_vrz_ratio : 2; > >+ u32 reserved1 : 22; > >+ } reg029; > >+ > >+ struct SW032_Y_SCALE_DOWN_TILE8x8_HOR_STRIDE { > >+ u32 y_scale_down_hor_stride : 20; > >+ u32 reserved0 : 12; > >+ } reg030; > >+ > >+ struct SW031_UV_SCALE_DOWN_TILE8x8_HOR_STRIDE { > >+ u32 uv_scale_down_hor_stride : 20; > >+ u32 reserved0 : 12; > >+ } reg031; > >+ > >+ u32 reg032_timeout_threshold; > >+} __packed; > >+ > >+/* base: OFFSET_COMMON_ADDR_REGS */ > >+struct rkvdec2_regs_common_addr { > >+ u32 reg128_rlc_base; > >+ u32 reg129_rlcwrite_base; > >+ u32 reg130_decout_base; > >+ u32 reg131_colmv_cur_base; > >+ u32 reg132_error_ref_base; > >+ u32 reg133_142_rcb_base[10]; > >+} __packed; > >+ > >+/* base: OFFSET_CODEC_PARAMS_REGS */ > >+struct rkvdec2_regs_h264_params { > >+ struct rkvdec2_h26x_set { > >+ u32 h26x_frame_orslice : 1; > >+ u32 h26x_rps_mode : 1; > >+ u32 h26x_stream_mode : 1; > >+ u32 h26x_stream_lastpacket : 1; > >+ u32 h264_firstslice_flag : 1; > >+ u32 reserved : 27; > >+ } reg64; > >+ > >+ u32 cur_top_poc; > >+ u32 cur_bot_poc; > >+ u32 reg67_98_ref_poc[32]; > >+ > >+ /* Regs 99 - 102 */ > >+ struct rkvdec2_h264_info { > >+ struct rkvdec2_h264_ref_info { > >+ u32 ref_field : 1; > >+ u32 ref_topfield_used : 1; > >+ u32 ref_botfield_used : 1; > >+ u32 ref_colmv_use_flag : 1; > >+ u32 ref_reserved : 4; > >+ } __packed ref_info[4]; > >+ } __packed reg99_102_ref_info[4]; > >+ > >+ u32 reserved_103_111[9]; > >+ > >+ struct rkvdec2_error_ref_info { > >+ u32 avs2_ref_error_field : 1; > >+ u32 avs2_ref_error_topfield : 1; > >+ u32 ref_error_topfield_used : 1; > >+ u32 ref_error_botfield_used : 1; > >+ u32 reserved : 28; > >+ } reg112; > >+} __packed; > >+ > >+/* base: OFFSET_CODEC_ADDR_REGS */ > >+struct rkvdec2_regs_h264_addr { > >+ /* SWREG160 */ > >+ u32 reg160_no_use; > >+ > >+ /* SWREG161 */ > >+ u32 pps_base; > >+ > >+ /* SWREG162 */ > >+ u32 reg162_no_use; > >+ > >+ /* SWREG163 */ > >+ u32 rps_base; > >+ > >+ /* SWREG164~179 */ > >+ u32 ref_base[16]; > >+ > >+ /* SWREG180 */ > >+ u32 scanlist_addr; > >+ > >+ /* SWREG181~196 */ > >+ u32 colmv_base[16]; > >+ > >+ /* SWREG197 */ > >+ u32 cabactbl_base; > >+} __packed; > >+ > >+struct rkvdec2_regs_h264_highpoc { > >+ /* SWREG200 */ > >+ struct rkvdec2_ref_poc_highbit { > >+ u32 ref0_poc_highbit : 4; > >+ u32 ref1_poc_highbit : 4; > >+ u32 ref2_poc_highbit : 4; > >+ u32 ref3_poc_highbit : 4; > >+ u32 ref4_poc_highbit : 4; > >+ u32 ref5_poc_highbit : 4; > >+ u32 ref6_poc_highbit : 4; > >+ u32 ref7_poc_highbit : 4; > >+ } reg200[4]; > >+ struct rkvdec2_cur_poc_highbit { > >+ u32 cur_poc_highbit : 4; > >+ u32 reserved : 28; > >+ } reg204; > >+} __packed; > >+ > >+struct rkvdec2_regs_h264 { > >+ struct rkvdec2_regs_common common; > >+ struct rkvdec2_regs_h264_params h264_param; > >+ struct rkvdec2_regs_common_addr common_addr; > >+ struct rkvdec2_regs_h264_addr h264_addr; > >+ struct rkvdec2_regs_h264_highpoc h264_highpoc; > >+} __packed; > >+ > >+#endif /* __RKVDEC_REGS_H__ */ > >diff --git a/drivers/staging/media/rkvdec2/rkvdec2.c > >b/drivers/staging/media/rkvdec2/rkvdec2.c new file mode 100644 > >index 000000000000..db37fdbfc366 > >--- /dev/null > >+++ b/drivers/staging/media/rkvdec2/rkvdec2.c > >@@ -0,0 +1,1160 @@ > >+/* SPDX-License-Identifier: GPL-2.0 */ > >+/* > >+ * Rockchip Video Decoder 2 driver > >+ * > >+ * Copyright (C) 2024 Collabora, Ltd. > >+ * Detlev Casanova <detlev.casanova@xxxxxxxxxxxxx> > >+ * > >+ * Based on rkvdec driver by Boris Brezillon > ><boris.brezillon@xxxxxxxxxxxxx> + */ > >+ > >+#include <linux/clk.h> > >+#include <linux/interrupt.h> > >+#include <linux/module.h> > >+#include <linux/of.h> > >+#include <linux/platform_device.h> > >+#include <linux/pm.h> > >+#include <linux/pm_runtime.h> > >+#include <linux/slab.h> > >+#include <linux/videodev2.h> > >+#include <linux/workqueue.h> > >+#include <media/v4l2-event.h> > >+#include <media/v4l2-mem2mem.h> > >+#include <media/videobuf2-core.h> > >+#include <media/videobuf2-vmalloc.h> > >+ > >+#include "rkvdec2.h" > >+ > >+static int rkvdec2_try_ctrl(struct v4l2_ctrl *ctrl) > >+{ > >+ struct rkvdec2_ctx *ctx = container_of(ctrl->handler, struct rkvdec2_ctx, > >ctrl_hdl); + const struct rkvdec2_coded_fmt_desc *desc = > >ctx->coded_fmt_desc; + > >+ if (desc->ops->try_ctrl) > >+ return desc->ops->try_ctrl(ctx, ctrl); > >+ > >+ return 0; > >+} > >+ > >+static const struct v4l2_ctrl_ops rkvdec2_ctrl_ops = { > >+ .try_ctrl = rkvdec2_try_ctrl, > >+}; > >+ > >+static const struct rkvdec2_ctrl_desc rkvdec2_h264_ctrl_descs[] = { > >+ { > >+ .cfg.id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, > >+ }, > >+ { > >+ .cfg.id = V4L2_CID_STATELESS_H264_SPS, > >+ .cfg.ops = &rkvdec2_ctrl_ops, > >+ }, > >+ { > >+ .cfg.id = V4L2_CID_STATELESS_H264_PPS, > >+ }, > >+ { > >+ .cfg.id = V4L2_CID_STATELESS_H264_SCALING_MATRIX, > >+ }, > >+ { > >+ .cfg.id = V4L2_CID_STATELESS_H264_DECODE_MODE, > >+ .cfg.min = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, > >+ .cfg.max = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, > >+ .cfg.def = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, > >+ }, > >+ { > >+ .cfg.id = V4L2_CID_STATELESS_H264_START_CODE, > >+ .cfg.min = V4L2_STATELESS_H264_START_CODE_ANNEX_B, > >+ .cfg.def = V4L2_STATELESS_H264_START_CODE_ANNEX_B, > >+ .cfg.max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, > >+ }, > >+ { > >+ .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, > >+ .cfg.min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, > >+ .cfg.max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10, > >+ .cfg.menu_skip_mask = > >+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED), > >+ .cfg.def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, > >+ }, > >+ { > >+ .cfg.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, > >+ .cfg.min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, > >+ .cfg.max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0, > >+ }, > >+}; > >+ > >+static const struct rkvdec2_ctrls rkvdec2_h264_ctrls = { > >+ .ctrls = rkvdec2_h264_ctrl_descs, > >+ .num_ctrls = ARRAY_SIZE(rkvdec2_h264_ctrl_descs), > >+}; > >+ > >+static const u32 rkvdec2_h264_decoded_fmts[] = { > >+ V4L2_PIX_FMT_NV12 > >+}; > >+ > >+static const struct rkvdec2_coded_fmt_desc rkvdec2_coded_fmts[] = { > >+ { > >+ .fourcc = V4L2_PIX_FMT_H264_SLICE, > >+ .frmsize = { > >+ .min_width = 16, > >+ .max_width = 65520, > >+ .step_width = 16, > >+ .min_height = 16, > >+ .max_height = 65520, > >+ .step_height = 16, > >+ }, > >+ .ctrls = &rkvdec2_h264_ctrls, > >+ .ops = &rkvdec2_h264_fmt_ops, > >+ .num_decoded_fmts = ARRAY_SIZE(rkvdec2_h264_decoded_fmts), > >+ .decoded_fmts = rkvdec2_h264_decoded_fmts, > >+ .subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF, > >+ }, > >+}; > >+ > >+enum rcb_axis { > >+ PIC_WIDTH = 0, > >+ PIC_HEIGHT = 1 > >+}; > >+ > >+struct rcb_size_info { > >+ u8 multiplier; > >+ enum rcb_axis axis; > >+}; > >+ > >+static struct rcb_size_info rcb_sizes[] = { > >+ {6, PIC_WIDTH}, // intrar > >+ {1, PIC_WIDTH}, // transdr (Is actually 0.4*pic_width) > >+ {1, PIC_HEIGHT}, // transdc (Is actually 0.1*pic_height) > >+ {3, PIC_WIDTH}, // streamdr > >+ {6, PIC_WIDTH}, // interr > >+ {3, PIC_HEIGHT}, // interc > >+ {22, PIC_WIDTH}, // dblkr > >+ {6, PIC_WIDTH}, // saor > >+ {11, PIC_WIDTH}, // fbcr > >+ {67, PIC_HEIGHT}, // filtc col > >+}; > >+ > >+#define RCB_SIZE(n) (rcb_sizes[(n)].multiplier * (rcb_sizes[(n)].axis ? > >height : width)) + > >+static const struct rkvdec2_coded_fmt_desc * > >+rkvdec2_find_coded_fmt_desc(u32 fourcc) > >+{ > >+ unsigned int i; > >+ > >+ for (i = 0; i < ARRAY_SIZE(rkvdec2_coded_fmts); i++) { > >+ if (rkvdec2_coded_fmts[i].fourcc == fourcc) > >+ return &rkvdec2_coded_fmts[i]; > >+ } > >+ > >+ return NULL; > >+} > >+ > >+static void rkvdec2_reset_fmt(struct rkvdec2_ctx *ctx, struct v4l2_format > >*f, + u32 fourcc) > >+{ > >+ memset(f, 0, sizeof(*f)); > >+ f->fmt.pix_mp.pixelformat = fourcc; > >+ f->fmt.pix_mp.field = V4L2_FIELD_NONE; > >+ f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; > >+ f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; > >+ f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; > >+ f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; > >+} > >+ > >+static void rkvdec2_reset_coded_fmt(struct rkvdec2_ctx *ctx) > >+{ > >+ struct v4l2_format *f = &ctx->coded_fmt; > >+ > >+ ctx->coded_fmt_desc = &rkvdec2_coded_fmts[0]; > >+ rkvdec2_reset_fmt(ctx, f, ctx->coded_fmt_desc->fourcc); > >+ > >+ f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; > >+ f->fmt.pix_mp.width = ctx->coded_fmt_desc->frmsize.min_width; > >+ f->fmt.pix_mp.height = ctx->coded_fmt_desc->frmsize.min_height; > >+ > >+ if (ctx->coded_fmt_desc->ops->adjust_fmt) > >+ ctx->coded_fmt_desc->ops->adjust_fmt(ctx, f); > >+} > >+ > >+static void rkvdec2_reset_decoded_fmt(struct rkvdec2_ctx *ctx) > >+{ > >+ struct v4l2_format *f = &ctx->decoded_fmt; > >+ > >+ rkvdec2_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]); > >+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; > >+ v4l2_fill_pixfmt_mp(&f->fmt.pix_mp, > >+ ctx->coded_fmt_desc->decoded_fmts[0], > >+ ctx->coded_fmt.fmt.pix_mp.width, > >+ ctx->coded_fmt.fmt.pix_mp.height); > >+ > >+ ctx->colmv_offset = f->fmt.pix_mp.plane_fmt[0].sizeimage; > >+ > >+ f->fmt.pix_mp.plane_fmt[0].sizeimage += 128 * > >+ DIV_ROUND_UP(f->fmt.pix_mp.width, 16) * > >+ DIV_ROUND_UP(f->fmt.pix_mp.height, 16); > >+} > >+ > >+static int rkvdec2_enum_framesizes(struct file *file, void *priv, > >+ struct v4l2_frmsizeenum *fsize) > >+{ > >+ const struct rkvdec2_coded_fmt_desc *fmt; > >+ > >+ if (fsize->index != 0) > >+ return -EINVAL; > >+ > >+ fmt = rkvdec2_find_coded_fmt_desc(fsize->pixel_format); > >+ if (!fmt) > >+ return -EINVAL; > >+ > >+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; > >+ fsize->stepwise = fmt->frmsize; > >+ return 0; > >+} > >+ > >+static int rkvdec2_querycap(struct file *file, void *priv, > >+ struct v4l2_capability *cap) > >+{ > >+ struct rkvdec2_dev *rkvdec = video_drvdata(file); > >+ struct video_device *vdev = video_devdata(file); > >+ > >+ strscpy(cap->driver, rkvdec->dev->driver->name, > >+ sizeof(cap->driver)); > >+ strscpy(cap->card, vdev->name, sizeof(cap->card)); > >+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", > >+ rkvdec->dev->driver->name); > >+ return 0; > >+} > >+ > >+static int rkvdec2_try_capture_fmt(struct file *file, void *priv, > >+ struct v4l2_format *f) > >+{ > >+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; > >+ struct rkvdec2_ctx *ctx = fh_to_rkvdec2_ctx(priv); > >+ const struct rkvdec2_coded_fmt_desc *coded_desc; > >+ unsigned int i; > >+ > >+ /* > >+ * The codec context should point to a coded format desc, if the format > >+ * on the coded end has not been set yet, it should point to the > >+ * default value. > >+ */ > >+ coded_desc = ctx->coded_fmt_desc; > >+ if (WARN_ON(!coded_desc)) > >+ return -EINVAL; > >+ > >+ for (i = 0; i < coded_desc->num_decoded_fmts; i++) { > >+ if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat) > >+ break; > >+ } > >+ > >+ if (i == coded_desc->num_decoded_fmts) > >+ pix_mp->pixelformat = coded_desc->decoded_fmts[0]; > >+ > >+ /* Always apply the frmsize constraint of the coded end. */ > >+ pix_mp->width = max(pix_mp->width, ctx- >coded_fmt.fmt.pix_mp.width); > >+ pix_mp->height = max(pix_mp->height, ctx- >coded_fmt.fmt.pix_mp.height); > >+ v4l2_apply_frmsize_constraints(&pix_mp->width, > >+ &pix_mp->height, > >+ &coded_desc->frmsize); > >+ > >+ v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, > >+ pix_mp->width, pix_mp->height); > >+ > >+ pix_mp->plane_fmt[0].sizeimage += > >+ 128 * > >+ DIV_ROUND_UP(pix_mp->width, 16) * > >+ DIV_ROUND_UP(pix_mp->height, 16); > >+ > >+ pix_mp->field = V4L2_FIELD_NONE; > >+ > >+ return 0; > >+} > >+ > >+static int rkvdec2_try_output_fmt(struct file *file, void *priv, > >+ struct v4l2_format *f) > >+{ > >+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; > >+ struct rkvdec2_ctx *ctx = fh_to_rkvdec2_ctx(priv); > >+ const struct rkvdec2_coded_fmt_desc *desc; > >+ > >+ desc = rkvdec2_find_coded_fmt_desc(pix_mp->pixelformat); > >+ if (!desc) { > >+ pix_mp->pixelformat = rkvdec2_coded_fmts[0].fourcc; > >+ desc = &rkvdec2_coded_fmts[0]; > >+ } > >+ > >+ v4l2_apply_frmsize_constraints(&pix_mp->width, > >+ &pix_mp->height, > >+ &desc->frmsize); > >+ > >+ pix_mp->field = V4L2_FIELD_NONE; > >+ /* All coded formats are considered single planar for now. */ > >+ pix_mp->num_planes = 1; > >+ > >+ if (desc->ops->adjust_fmt) { > >+ int ret; > >+ > >+ ret = desc->ops->adjust_fmt(ctx, f); > >+ if (ret) > >+ return ret; > >+ } > >+ > >+ return 0; > >+} > >+ > >+static int rkvdec2_s_capture_fmt(struct file *file, void *priv, > >+ struct v4l2_format *f) > >+{ > >+ struct rkvdec2_ctx *ctx = fh_to_rkvdec2_ctx(priv); > >+ struct vb2_queue *vq; > >+ int ret; > >+ > >+ /* Change not allowed if queue is busy */ > >+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, > >+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); > >+ if (vb2_is_busy(vq)) > >+ return -EBUSY; > >+ > >+ ret = rkvdec2_try_capture_fmt(file, priv, f); > >+ if (ret) > >+ return ret; > >+ > >+ ctx->decoded_fmt = *f; > >+ return 0; > >+} > >+ > >+static int rkvdec2_s_output_fmt(struct file *file, void *priv, > >+ struct v4l2_format *f) > >+{ > >+ struct rkvdec2_ctx *ctx = fh_to_rkvdec2_ctx(priv); > >+ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; > >+ const struct rkvdec2_coded_fmt_desc *desc; > >+ struct v4l2_format *cap_fmt; > >+ struct vb2_queue *peer_vq, *vq; > >+ int ret; > >+ > >+ /* > >+ * In order to support dynamic resolution change, the decoder admits > >+ * a resolution change, as long as the pixelformat remains. Can't be > >+ * done if streaming. > >+ */ > >+ vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); > >+ if (vb2_is_streaming(vq) || > >+ (vb2_is_busy(vq) && > >+ f->fmt.pix_mp.pixelformat != ctx- >coded_fmt.fmt.pix_mp.pixelformat)) > >+ return -EBUSY; > >+ > >+ /* > >+ * Since format change on the OUTPUT queue will reset the CAPTURE > >+ * queue, we can't allow doing so when the CAPTURE queue has buffers > >+ * allocated. > >+ */ > >+ peer_vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); > >+ if (vb2_is_busy(peer_vq)) > >+ return -EBUSY; > >+ > >+ ret = rkvdec2_try_output_fmt(file, priv, f); > >+ if (ret) > >+ return ret; > >+ > >+ desc = rkvdec2_find_coded_fmt_desc(f->fmt.pix_mp.pixelformat); > >+ if (!desc) > >+ return -EINVAL; > >+ ctx->coded_fmt_desc = desc; > >+ ctx->coded_fmt = *f; > >+ > >+ /* > >+ * Current decoded format might have become invalid with newly > >+ * selected codec, so reset it to default just to be safe and > >+ * keep internal driver state sane. User is mandated to set > >+ * the decoded format again after we return, so we don't need > >+ * anything smarter. > >+ * > >+ * Note that this will propagate any size changes to the decoded format. > >+ */ > >+ rkvdec2_reset_decoded_fmt(ctx); > >+ > >+ /* Propagate colorspace information to capture. */ > >+ cap_fmt = &ctx->decoded_fmt; > >+ cap_fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; > >+ cap_fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; > >+ cap_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; > >+ cap_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; > >+ > >+ /* Enable format specific queue features */ > >+ vq->subsystem_flags |= desc->subsystem_flags; > >+ > >+ return 0; > >+} > >+ > >+static int rkvdec2_g_output_fmt(struct file *file, void *priv, > >+ struct v4l2_format *f) > >+{ > >+ struct rkvdec2_ctx *ctx = fh_to_rkvdec2_ctx(priv); > >+ > >+ *f = ctx->coded_fmt; > >+ return 0; > >+} > >+ > >+static int rkvdec2_g_capture_fmt(struct file *file, void *priv, > >+ struct v4l2_format *f) > >+{ > >+ struct rkvdec2_ctx *ctx = fh_to_rkvdec2_ctx(priv); > >+ > >+ *f = ctx->decoded_fmt; > >+ return 0; > >+} > >+ > >+static int rkvdec2_enum_output_fmt(struct file *file, void *priv, > >+ struct v4l2_fmtdesc *f) > >+{ > >+ if (f->index >= ARRAY_SIZE(rkvdec2_coded_fmts)) > >+ return -EINVAL; > >+ > >+ f->pixelformat = rkvdec2_coded_fmts[f->index].fourcc; > >+ return 0; > >+} > >+ > >+static int rkvdec2_enum_capture_fmt(struct file *file, void *priv, > >+ struct v4l2_fmtdesc *f) > >+{ > >+ struct rkvdec2_ctx *ctx = fh_to_rkvdec2_ctx(priv); > >+ > >+ if (WARN_ON(!ctx->coded_fmt_desc)) > >+ return -EINVAL; > >+ > >+ if (f->index >= ctx->coded_fmt_desc->num_decoded_fmts) > >+ return -EINVAL; > >+ > >+ f->pixelformat = ctx->coded_fmt_desc->decoded_fmts[f->index]; > >+ return 0; > >+} > >+ > >+static const struct v4l2_ioctl_ops rkvdec2_ioctl_ops = { > >+ .vidioc_querycap = rkvdec2_querycap, > >+ .vidioc_enum_framesizes = rkvdec2_enum_framesizes, > >+ > >+ .vidioc_try_fmt_vid_cap_mplane = rkvdec2_try_capture_fmt, > >+ .vidioc_try_fmt_vid_out_mplane = rkvdec2_try_output_fmt, > >+ .vidioc_s_fmt_vid_out_mplane = rkvdec2_s_output_fmt, > >+ .vidioc_s_fmt_vid_cap_mplane = rkvdec2_s_capture_fmt, > >+ .vidioc_g_fmt_vid_out_mplane = rkvdec2_g_output_fmt, > >+ .vidioc_g_fmt_vid_cap_mplane = rkvdec2_g_capture_fmt, > >+ .vidioc_enum_fmt_vid_out = rkvdec2_enum_output_fmt, > >+ .vidioc_enum_fmt_vid_cap = rkvdec2_enum_capture_fmt, > >+ > >+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, > >+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, > >+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, > >+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, > >+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, > >+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, > >+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, > >+ > >+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, > >+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, > >+ > >+ .vidioc_streamon = v4l2_m2m_ioctl_streamon, > >+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, > >+ > >+ .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd, > >+ .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd, > >+}; > >+ > >+static int rkvdec2_queue_setup(struct vb2_queue *vq, unsigned int > >*num_buffers, + unsigned int *num_planes, unsigned int sizes[], > >+ struct device *alloc_devs[]) > >+{ > >+ struct rkvdec2_ctx *ctx = vb2_get_drv_priv(vq); > >+ struct v4l2_format *f; > >+ unsigned int i; > >+ > >+ if (V4L2_TYPE_IS_OUTPUT(vq->type)) > >+ f = &ctx->coded_fmt; > >+ else > >+ f = &ctx->decoded_fmt; > >+ > >+ if (*num_planes) { > >+ if (*num_planes != f->fmt.pix_mp.num_planes) > >+ return -EINVAL; > >+ > >+ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { > >+ if (sizes[i] < f- >fmt.pix_mp.plane_fmt[i].sizeimage) > >+ return -EINVAL; > >+ } > >+ } else { > >+ *num_planes = f->fmt.pix_mp.num_planes; > >+ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) > >+ sizes[i] = f- >fmt.pix_mp.plane_fmt[i].sizeimage; > >+ } > >+ > >+ return 0; > >+} > >+ > >+static int rkvdec2_buf_prepare(struct vb2_buffer *vb) > >+{ > >+ struct vb2_queue *vq = vb->vb2_queue; > >+ struct rkvdec2_ctx *ctx = vb2_get_drv_priv(vq); > >+ struct v4l2_format *f; > >+ unsigned int i; > >+ > >+ if (V4L2_TYPE_IS_OUTPUT(vq->type)) > >+ f = &ctx->coded_fmt; > >+ else > >+ f = &ctx->decoded_fmt; > >+ > >+ for (i = 0; i < f->fmt.pix_mp.num_planes; ++i) { > >+ u32 sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; > >+ > >+ if (vb2_plane_size(vb, i) < sizeimage) > >+ return -EINVAL; > >+ } > >+ > >+ /* > >+ * Buffer's bytesused must be written by driver for CAPTURE buffers. > >+ * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets > >+ * it to buffer length). > >+ */ > >+ if (V4L2_TYPE_IS_CAPTURE(vq->type)) > >+ vb2_set_plane_payload(vb, 0, f- >fmt.pix_mp.plane_fmt[0].sizeimage); > >+ > >+ return 0; > >+} > >+ > >+static void rkvdec2_buf_queue(struct vb2_buffer *vb) > >+{ > >+ struct rkvdec2_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); > >+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); > >+ > >+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); > >+} > >+ > >+static int rkvdec2_buf_out_validate(struct vb2_buffer *vb) > >+{ > >+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); > >+ > >+ vbuf->field = V4L2_FIELD_NONE; > >+ return 0; > >+} > >+ > >+static void rkvdec2_buf_request_complete(struct vb2_buffer *vb) > >+{ > >+ struct rkvdec2_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); > >+ > >+ v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->ctrl_hdl); > >+} > >+ > >+static int rkvdec2_start_streaming(struct vb2_queue *q, unsigned int > >count) +{ > >+ struct rkvdec2_ctx *ctx = vb2_get_drv_priv(q); > >+ const struct rkvdec2_coded_fmt_desc *desc; > >+ int ret, i; > >+ u32 width, height; > >+ > >+ if (V4L2_TYPE_IS_CAPTURE(q->type)) > >+ return 0; > >+ > >+ desc = ctx->coded_fmt_desc; > >+ if (WARN_ON(!desc)) > >+ return -EINVAL; > >+ > >+ width = ctx->decoded_fmt.fmt.pix_mp.width; > >+ height = ctx->decoded_fmt.fmt.pix_mp.height; > >+ for (i = 0; i < RKVDEC2_RCB_COUNT; i++) { > >+ ctx->rcb_bufs[i].cpu = > >+ dma_alloc_coherent(ctx->dev->dev, > >+ RCB_SIZE(i), > >+ &ctx- >rcb_bufs[i].dma, > >+ GFP_KERNEL); > >+ if (!ctx->rcb_bufs[i].cpu) { > >+ ret = -ENOMEM; > >+ goto err_rcb; > >+ } > >+ } > >+ > >+ if (desc->ops->start) { > >+ ret = desc->ops->start(ctx); > >+ if (ret) > >+ goto err_ops_start; > >+ } > >+ > >+ return 0; > >+ > >+err_ops_start: > >+err_rcb: > >+ i--; > >+ while (i) { > >+ dma_free_coherent(ctx->dev->dev, > >+ RCB_SIZE(i), > >+ ctx->rcb_bufs[i].cpu, > >+ ctx->rcb_bufs[i].dma); > >+ i--; > >+ } > >+ > >+ return ret; > >+} > >+ > >+static void rkvdec2_queue_cleanup(struct vb2_queue *vq, u32 state) > >+{ > >+ struct rkvdec2_ctx *ctx = vb2_get_drv_priv(vq); > >+ > >+ while (true) { > >+ struct vb2_v4l2_buffer *vbuf; > >+ > >+ if (V4L2_TYPE_IS_OUTPUT(vq->type)) > >+ vbuf = v4l2_m2m_src_buf_remove(ctx- >fh.m2m_ctx); > >+ else > >+ vbuf = v4l2_m2m_dst_buf_remove(ctx- >fh.m2m_ctx); > >+ > >+ if (!vbuf) > >+ break; > >+ > >+ v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, > >+ &ctx->ctrl_hdl); > >+ v4l2_m2m_buf_done(vbuf, state); > >+ } > >+} > >+ > >+static void rkvdec2_stop_streaming(struct vb2_queue *q) > >+{ > >+ struct rkvdec2_ctx *ctx = vb2_get_drv_priv(q); > >+ int i; > >+ > >+ if (V4L2_TYPE_IS_OUTPUT(q->type)) { > >+ const struct rkvdec2_coded_fmt_desc *desc = ctx- >coded_fmt_desc; > >+ > >+ if (WARN_ON(!desc)) > >+ return; > >+ > >+ if (desc->ops->stop) > >+ desc->ops->stop(ctx); > >+ } else { > >+ u32 width = ctx->decoded_fmt.fmt.pix_mp.width; > >+ u32 height = ctx->decoded_fmt.fmt.pix_mp.height; > >+ > >+ for (i = 0; i < RKVDEC2_RCB_COUNT; i++) { > >+ dma_free_coherent(ctx->dev->dev, > >+ RCB_SIZE(i), > >+ ctx->rcb_bufs[i].cpu, > >+ ctx- >rcb_bufs[i].dma); > >+ } > >+ } > >+ > >+ rkvdec2_queue_cleanup(q, VB2_BUF_STATE_ERROR); > >+} > >+ > >+static const struct vb2_ops rkvdec2_queue_ops = { > >+ .queue_setup = rkvdec2_queue_setup, > >+ .buf_prepare = rkvdec2_buf_prepare, > >+ .buf_queue = rkvdec2_buf_queue, > >+ .buf_out_validate = rkvdec2_buf_out_validate, > >+ .buf_request_complete = rkvdec2_buf_request_complete, > >+ .start_streaming = rkvdec2_start_streaming, > >+ .stop_streaming = rkvdec2_stop_streaming, > >+ .wait_prepare = vb2_ops_wait_prepare, > >+ .wait_finish = vb2_ops_wait_finish, > >+}; > >+ > >+static int rkvdec2_request_validate(struct media_request *req) > >+{ > >+ unsigned int count; > >+ > >+ count = vb2_request_buffer_cnt(req); > >+ if (!count) > >+ return -ENOENT; > >+ else if (count > 1) > >+ return -EINVAL; > >+ > >+ return vb2_request_validate(req); > >+} > >+ > >+static const struct media_device_ops rkvdec2_media_ops = { > >+ .req_validate = rkvdec2_request_validate, > >+ .req_queue = v4l2_m2m_request_queue, > >+}; > >+ > >+static void rkvdec2_job_finish_no_pm(struct rkvdec2_ctx *ctx, > >+ enum vb2_buffer_state result) > >+{ > >+ if (ctx->coded_fmt_desc->ops->done) { > >+ struct vb2_v4l2_buffer *src_buf, *dst_buf; > >+ > >+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); > >+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); > >+ ctx->coded_fmt_desc->ops->done(ctx, src_buf, dst_buf, result); > >+ } > >+ > >+ v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx, > >+ result); > >+} > >+ > >+static void rkvdec2_job_finish(struct rkvdec2_ctx *ctx, > >+ enum vb2_buffer_state result) > >+{ > >+ struct rkvdec2_dev *rkvdec = ctx->dev; > >+ > >+ pm_runtime_mark_last_busy(rkvdec->dev); > >+ pm_runtime_put_autosuspend(rkvdec->dev); > >+ rkvdec2_job_finish_no_pm(ctx, result); > >+} > >+ > >+void rkvdec2_run_preamble(struct rkvdec2_ctx *ctx, struct rkvdec2_run > >*run) +{ > >+ struct media_request *src_req; > >+ > >+ memset(run, 0, sizeof(*run)); > >+ > >+ run->bufs.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); > >+ run->bufs.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); > >+ > >+ /* Apply request(s) controls if needed. */ > >+ src_req = run->bufs.src->vb2_buf.req_obj.req; > >+ if (src_req) > >+ v4l2_ctrl_request_setup(src_req, &ctx->ctrl_hdl); > >+ > >+ v4l2_m2m_buf_copy_metadata(run->bufs.src, run->bufs.dst, true); > >+} > >+ > >+void rkvdec2_run_postamble(struct rkvdec2_ctx *ctx, struct rkvdec2_run > >*run) +{ > >+ struct media_request *src_req = run->bufs.src->vb2_buf.req_obj.req; > >+ > >+ if (src_req) > >+ v4l2_ctrl_request_complete(src_req, &ctx->ctrl_hdl); > >+} > >+ > >+static void rkvdec2_device_run(void *priv) > >+{ > >+ struct rkvdec2_ctx *ctx = priv; > >+ struct rkvdec2_dev *rkvdec = ctx->dev; > >+ const struct rkvdec2_coded_fmt_desc *desc = ctx->coded_fmt_desc; > >+ int ret; > >+ > >+ if (WARN_ON(!desc)) > >+ return; > >+ > >+ ret = pm_runtime_resume_and_get(rkvdec->dev); > >+ if (ret < 0) { > >+ rkvdec2_job_finish_no_pm(ctx, VB2_BUF_STATE_ERROR); > >+ return; > >+ } > >+ > >+ ret = desc->ops->run(ctx); > >+ if (ret) > >+ rkvdec2_job_finish(ctx, VB2_BUF_STATE_ERROR); > >+} > >+ > >+static const struct v4l2_m2m_ops rkvdec2_m2m_ops = { > >+ .device_run = rkvdec2_device_run, > >+}; > >+ > >+static int rkvdec2_queue_init(void *priv, > >+ struct vb2_queue *src_vq, > >+ struct vb2_queue *dst_vq) > >+{ > >+ struct rkvdec2_ctx *ctx = priv; > >+ struct rkvdec2_dev *rkvdec = ctx->dev; > >+ int ret; > >+ > >+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; > >+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF; > >+ src_vq->drv_priv = ctx; > >+ src_vq->ops = &rkvdec2_queue_ops; > >+ src_vq->mem_ops = &vb2_dma_contig_memops; > >+ > >+ /* > >+ * Driver does mostly sequential access, so sacrifice TLB efficiency > >+ * for faster allocation. Also, no CPU access on the source queue, > >+ * so no kernel mapping needed. > >+ */ > >+ src_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | > >+ DMA_ATTR_NO_KERNEL_MAPPING; > >+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); > >+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; > >+ src_vq->lock = &rkvdec->vdev_lock; > >+ src_vq->dev = rkvdec->v4l2_dev.dev; > >+ src_vq->supports_requests = true; > >+ src_vq->requires_requests = true; > >+ > >+ ret = vb2_queue_init(src_vq); > >+ if (ret) > >+ return ret; > >+ > >+ dst_vq->bidirectional = true; > >+ dst_vq->mem_ops = &vb2_dma_contig_memops; > >+ dst_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | > >+ DMA_ATTR_NO_KERNEL_MAPPING; > >+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; > >+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; > >+ dst_vq->drv_priv = ctx; > >+ dst_vq->ops = &rkvdec2_queue_ops; > >+ dst_vq->buf_struct_size = sizeof(struct rkvdec2_decoded_buffer); > >+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; > >+ dst_vq->lock = &rkvdec->vdev_lock; > >+ dst_vq->dev = rkvdec->v4l2_dev.dev; > >+ > >+ return vb2_queue_init(dst_vq); > >+} > >+ > >+static int rkvdec2_add_ctrls(struct rkvdec2_ctx *ctx, > >+ const struct rkvdec2_ctrls *ctrls) > >+{ > >+ unsigned int i; > >+ > >+ for (i = 0; i < ctrls->num_ctrls; i++) { > >+ const struct v4l2_ctrl_config *cfg = &ctrls- >ctrls[i].cfg; > >+ > >+ v4l2_ctrl_new_custom(&ctx->ctrl_hdl, cfg, ctx); > >+ if (ctx->ctrl_hdl.error) > >+ return ctx->ctrl_hdl.error; > >+ } > >+ > >+ return 0; > >+} > >+ > >+static int rkvdec2_init_ctrls(struct rkvdec2_ctx *ctx) > >+{ > >+ unsigned int i, nctrls = 0; > >+ int ret; > >+ > >+ for (i = 0; i < ARRAY_SIZE(rkvdec2_coded_fmts); i++) > >+ nctrls += rkvdec2_coded_fmts[i].ctrls->num_ctrls; > >+ > >+ v4l2_ctrl_handler_init(&ctx->ctrl_hdl, nctrls); > >+ > >+ for (i = 0; i < ARRAY_SIZE(rkvdec2_coded_fmts); i++) { > >+ ret = rkvdec2_add_ctrls(ctx, rkvdec2_coded_fmts[i].ctrls); > >+ if (ret) > >+ goto err_free_handler; > >+ } > >+ > >+ ret = v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); > >+ if (ret) > >+ goto err_free_handler; > >+ > >+ ctx->fh.ctrl_handler = &ctx->ctrl_hdl; > >+ return 0; > >+ > >+err_free_handler: > >+ v4l2_ctrl_handler_free(&ctx->ctrl_hdl); > >+ return ret; > >+} > >+ > >+static int rkvdec2_open(struct file *filp) > >+{ > >+ struct rkvdec2_dev *rkvdec = video_drvdata(filp); > >+ struct rkvdec2_ctx *ctx; > >+ int ret; > >+ > >+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); > >+ if (!ctx) > >+ return -ENOMEM; > >+ > >+ ctx->dev = rkvdec; > >+ rkvdec2_reset_coded_fmt(ctx); > >+ rkvdec2_reset_decoded_fmt(ctx); > >+ v4l2_fh_init(&ctx->fh, video_devdata(filp)); > >+ > >+ ret = rkvdec2_init_ctrls(ctx); > >+ if (ret) > >+ goto err_free_ctx; > >+ > >+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rkvdec->m2m_dev, ctx, > >+ rkvdec2_queue_init); > >+ if (IS_ERR(ctx->fh.m2m_ctx)) { > >+ ret = PTR_ERR(ctx->fh.m2m_ctx); > >+ goto err_cleanup_ctrls; > >+ } > >+ > >+ filp->private_data = &ctx->fh; > >+ v4l2_fh_add(&ctx->fh); > >+ > >+ return 0; > >+ > >+err_cleanup_ctrls: > >+ v4l2_ctrl_handler_free(&ctx->ctrl_hdl); > >+ > >+err_free_ctx: > >+ kfree(ctx); > >+ return ret; > >+} > >+ > >+static int rkvdec2_release(struct file *filp) > >+{ > >+ struct rkvdec2_ctx *ctx = fh_to_rkvdec2_ctx(filp->private_data); > >+ > >+ v4l2_fh_del(&ctx->fh); > >+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); > >+ v4l2_ctrl_handler_free(&ctx->ctrl_hdl); > >+ v4l2_fh_exit(&ctx->fh); > >+ kfree(ctx); > >+ > >+ return 0; > >+} > >+ > >+static const struct v4l2_file_operations rkvdec2_fops = { > >+ .owner = THIS_MODULE, > >+ .open = rkvdec2_open, > >+ .release = rkvdec2_release, > >+ .poll = v4l2_m2m_fop_poll, > >+ .unlocked_ioctl = video_ioctl2, > >+ .mmap = v4l2_m2m_fop_mmap, > >+}; > >+ > >+static int rkvdec2_v4l2_init(struct rkvdec2_dev *rkvdec) > >+{ > >+ int ret; > >+ > >+ ret = v4l2_device_register(rkvdec->dev, &rkvdec->v4l2_dev); > >+ if (ret) { > >+ dev_err(rkvdec->dev, "Failed to register V4L2 device\n"); > >+ return ret; > >+ } > >+ > >+ rkvdec->m2m_dev = v4l2_m2m_init(&rkvdec2_m2m_ops); > >+ if (IS_ERR(rkvdec->m2m_dev)) { > >+ v4l2_err(&rkvdec->v4l2_dev, "Failed to init mem2mem device\n"); > >+ ret = PTR_ERR(rkvdec->m2m_dev); > >+ goto err_unregister_v4l2; > >+ } > >+ > >+ rkvdec->mdev.dev = rkvdec->dev; > >+ strscpy(rkvdec->mdev.model, "rkvdec2", sizeof(rkvdec->mdev.model)); > >+ strscpy(rkvdec->mdev.bus_info, "platform:rkvdec2", > >+ sizeof(rkvdec->mdev.bus_info)); > >+ media_device_init(&rkvdec->mdev); > >+ rkvdec->mdev.ops = &rkvdec2_media_ops; > >+ rkvdec->v4l2_dev.mdev = &rkvdec->mdev; > >+ > >+ rkvdec->vdev.lock = &rkvdec->vdev_lock; > >+ rkvdec->vdev.v4l2_dev = &rkvdec->v4l2_dev; > >+ rkvdec->vdev.fops = &rkvdec2_fops; > >+ rkvdec->vdev.release = video_device_release_empty; > >+ rkvdec->vdev.vfl_dir = VFL_DIR_M2M; > >+ rkvdec->vdev.device_caps = V4L2_CAP_STREAMING | > >+ V4L2_CAP_VIDEO_M2M_MPLANE; > >+ rkvdec->vdev.ioctl_ops = &rkvdec2_ioctl_ops; > >+ video_set_drvdata(&rkvdec->vdev, rkvdec); > >+ strscpy(rkvdec->vdev.name, "rkvdec2", sizeof(rkvdec->vdev.name)); > >+ > >+ ret = video_register_device(&rkvdec->vdev, VFL_TYPE_VIDEO, -1); > >+ if (ret) { > >+ v4l2_err(&rkvdec->v4l2_dev, "Failed to register video device\n"); > >+ goto err_cleanup_mc; > >+ } > >+ > >+ ret = v4l2_m2m_register_media_controller(rkvdec->m2m_dev, &rkvdec- >vdev, > >+ MEDIA_ENT_F_PROC_VIDEO_DECODER); > >+ if (ret) { > >+ v4l2_err(&rkvdec->v4l2_dev, > >+ "Failed to initialize V4L2 M2M media controller\n"); > >+ goto err_unregister_vdev; > >+ } > >+ > >+ ret = media_device_register(&rkvdec->mdev); > >+ if (ret) { > >+ v4l2_err(&rkvdec->v4l2_dev, "Failed to register media device\n"); > >+ goto err_unregister_mc; > >+ } > >+ > >+ return 0; > >+ > >+err_unregister_mc: > >+ v4l2_m2m_unregister_media_controller(rkvdec->m2m_dev); > >+ > >+err_unregister_vdev: > >+ video_unregister_device(&rkvdec->vdev); > >+ > >+err_cleanup_mc: > >+ media_device_cleanup(&rkvdec->mdev); > >+ v4l2_m2m_release(rkvdec->m2m_dev); > >+ > >+err_unregister_v4l2: > >+ v4l2_device_unregister(&rkvdec->v4l2_dev); > >+ return ret; > >+} > >+ > >+static void rkvdec2_v4l2_cleanup(struct rkvdec2_dev *rkvdec) > >+{ > >+ media_device_unregister(&rkvdec->mdev); > >+ v4l2_m2m_unregister_media_controller(rkvdec->m2m_dev); > >+ video_unregister_device(&rkvdec->vdev); > >+ media_device_cleanup(&rkvdec->mdev); > >+ v4l2_m2m_release(rkvdec->m2m_dev); > >+ v4l2_device_unregister(&rkvdec->v4l2_dev); > >+} > >+ > >+static irqreturn_t rkvdec2_irq_handler(int irq, void *priv) > >+{ > >+ struct rkvdec2_dev *rkvdec = priv; > >+ enum vb2_buffer_state state; > >+ u32 status; > >+ > >+ status = readl(rkvdec->regs + RKVDEC2_REG_STA_INT); > >+ state = (status & STA_INT_DEC_RDY_STA) ? > >+ VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; > >+ > >+ /* Clear interrupt status */ > >+ writel(0, rkvdec->regs + RKVDEC2_REG_STA_INT); > >+ if (cancel_delayed_work(&rkvdec->watchdog_work)) { > >+ struct rkvdec2_ctx *ctx; > >+ > >+ ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); > >+ rkvdec2_job_finish(ctx, state); > >+ } > >+ > >+ return IRQ_HANDLED; > >+} > >+ > >+static void rkvdec2_watchdog_func(struct work_struct *work) > >+{ > >+ struct rkvdec2_dev *rkvdec = container_of(to_delayed_work(work), struct > >rkvdec2_dev, + watchdog_work); > >+ struct rkvdec2_ctx *ctx; > >+ > >+ ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); > >+ if (ctx) { > >+ dev_err(rkvdec->dev, "Frame processing timed out!\n"); > >+ writel(RKVDEC2_REG_DEC_IRQ_DISABLE, rkvdec->regs + > >RKVDEC2_REG_IMPORTANT_EN); + writel(0, rkvdec->regs + RKVDEC2_REG_DEC_E); > >+ rkvdec2_job_finish(ctx, VB2_BUF_STATE_ERROR); > >+ } > >+} > >+ > >+static const struct of_device_id of_rkvdec2_match[] = { > >+ { .compatible = "rockchip,rk3588-vdec2" }, > >+ { /* sentinel */ } > >+}; > >+MODULE_DEVICE_TABLE(of, of_rkvdec2_match); > >+ > >+static const char * const rkvdec2_clk_names[] = { > >+ "axi", > >+ "ahb", > >+ "core", > >+ "cabac", > >+ "hevc_cabac", > >+}; > >+ > >+static int rkvdec2_probe(struct platform_device *pdev) > >+{ > >+ struct rkvdec2_dev *rkvdec; > >+ unsigned int i; > >+ int ret, irq; > >+ > >+ rkvdec = devm_kzalloc(&pdev->dev, sizeof(*rkvdec), GFP_KERNEL); > >+ if (!rkvdec) > >+ return -ENOMEM; > >+ > >+ platform_set_drvdata(pdev, rkvdec); > >+ rkvdec->dev = &pdev->dev; > >+ > >+ mutex_init(&rkvdec->vdev_lock); > >+ INIT_DELAYED_WORK(&rkvdec->watchdog_work, rkvdec2_watchdog_func); > >+ > >+ rkvdec->clocks = devm_kcalloc(&pdev->dev, ARRAY_SIZE(rkvdec2_clk_names), > >+ sizeof(*rkvdec->clocks), GFP_KERNEL); > >+ if (!rkvdec->clocks) > >+ return -ENOMEM; > >+ > >+ for (i = 0; i < ARRAY_SIZE(rkvdec2_clk_names); i++) > >+ rkvdec->clocks[i].id = rkvdec2_clk_names[i]; > >+ > >+ ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(rkvdec2_clk_names), > >+ rkvdec->clocks); > >+ if (ret) > >+ return ret; > >+ > >+ rkvdec->regs = devm_platform_ioremap_resource(pdev, 0); > >+ if (IS_ERR(rkvdec->regs)) > >+ return PTR_ERR(rkvdec->regs); > >+ > >+ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); > >+ if (ret) { > >+ dev_err(&pdev->dev, "Could not set DMA coherent mask. \n"); > >+ return ret; > >+ } > >+ > >+ vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); > >+ > >+ irq = platform_get_irq(pdev, 0); > >+ if (irq <= 0) > >+ return -ENXIO; > >+ > >+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, > >+ rkvdec2_irq_handler, IRQF_ONESHOT, > >+ dev_name(&pdev->dev), rkvdec); > >+ if (ret) { > >+ dev_err(&pdev->dev, "Could not request vdec2 IRQ\n"); > >+ return ret; > >+ } > >+ > >+ pm_runtime_set_autosuspend_delay(&pdev->dev, 100); > >+ pm_runtime_use_autosuspend(&pdev->dev); > >+ pm_runtime_enable(&pdev->dev); > >+ > >+ ret = clk_bulk_prepare_enable(ARRAY_SIZE(rkvdec2_clk_names), > >rkvdec->clocks); + if (ret) { > >+ dev_err(&pdev->dev, "Could not start clocks\n"); > >+ return ret; > >+ } > >+ > >+ ret = rkvdec2_v4l2_init(rkvdec); > >+ if (ret) > >+ goto err_disable_runtime_pm; > >+ > >+ return 0; > >+ > >+err_disable_runtime_pm: > >+ pm_runtime_dont_use_autosuspend(&pdev->dev); > >+ pm_runtime_disable(&pdev->dev); > >+ return ret; > >+} > >+ > >+static void rkvdec2_remove(struct platform_device *pdev) > >+{ > >+ struct rkvdec2_dev *rkvdec = platform_get_drvdata(pdev); > >+ > >+ cancel_delayed_work_sync(&rkvdec->watchdog_work); > >+ > >+ rkvdec2_v4l2_cleanup(rkvdec); > >+ pm_runtime_disable(&pdev->dev); > >+ pm_runtime_dont_use_autosuspend(&pdev->dev); > >+} > >+ > >+#ifdef CONFIG_PM > >+static int rkvdec2_runtime_resume(struct device *dev) > >+{ > >+ struct rkvdec2_dev *rkvdec = dev_get_drvdata(dev); > >+ > >+ return clk_bulk_prepare_enable(ARRAY_SIZE(rkvdec2_clk_names), > >+ rkvdec->clocks); > >+} > >+ > >+static int rkvdec2_runtime_suspend(struct device *dev) > >+{ > >+ struct rkvdec2_dev *rkvdec = dev_get_drvdata(dev); > >+ > >+ clk_bulk_disable_unprepare(ARRAY_SIZE(rkvdec2_clk_names), > >+ rkvdec->clocks); > >+ return 0; > >+} > >+#endif > >+ > >+static const struct dev_pm_ops rkvdec2_pm_ops = { > >+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, > >+ pm_runtime_force_resume) > >+ SET_RUNTIME_PM_OPS(rkvdec2_runtime_suspend, rkvdec2_runtime_resume, NULL) > >+}; > >+ > >+static struct platform_driver rkvdec2_driver = { > >+ .probe = rkvdec2_probe, > >+ .remove_new = rkvdec2_remove, > >+ .driver = { > >+ .name = "rkvdec2", > >+ .of_match_table = of_rkvdec2_match, > >+ .pm = &rkvdec2_pm_ops, > >+ }, > >+}; > >+module_platform_driver(rkvdec2_driver); > >+ > >+MODULE_AUTHOR("Detlev Casanova <detlev.casanova@xxxxxxxxxxxxx>"); > >+MODULE_DESCRIPTION("Rockchip Video Decoder 2 driver"); > >+MODULE_LICENSE("GPL"); > >diff --git a/drivers/staging/media/rkvdec2/rkvdec2.h > >b/drivers/staging/media/rkvdec2/rkvdec2.h new file mode 100644 > >index 000000000000..3982c0387869 > >--- /dev/null > >+++ b/drivers/staging/media/rkvdec2/rkvdec2.h > >@@ -0,0 +1,123 @@ > >+// SPDX-License-Identifier: GPL-2.0 > >+/* > >+ * Rockchip Video Decoder 2 driver > >+ * > >+ * Copyright (C) 2024 Collabora, Ltd. > >+ * Detlev Casanova <detlev.casanova@xxxxxxxxxxxxx> > >+ * > >+ * Based on rkvdec driver by Boris Brezillon > ><boris.brezillon@xxxxxxxxxxxxx> + */ > >+#ifndef RKVDEC_H_ > >+#define RKVDEC_H_ > >+ > >+#include <linux/platform_device.h> > >+#include <linux/videodev2.h> > >+#include <linux/wait.h> > >+#include <linux/clk.h> > >+#include <linux/dma-mapping.h> > >+ > >+#include <media/v4l2-ctrls.h> > >+#include <media/v4l2-device.h> > >+#include <media/v4l2-ioctl.h> > >+#include <media/videobuf2-core.h> > >+#include <media/videobuf2-dma-contig.h> > >+ > >+#include "rkvdec2-regs.h" > >+ > >+#define RKVDEC2_RCB_COUNT 10 > >+ > >+struct rkvdec2_ctx; > >+ > >+struct rkvdec2_aux_buf { > >+ void *cpu; > >+ dma_addr_t dma; > >+ size_t size; > >+}; > >+ > >+struct rkvdec2_ctrl_desc { > >+ struct v4l2_ctrl_config cfg; > >+}; > >+ > >+struct rkvdec2_ctrls { > >+ const struct rkvdec2_ctrl_desc *ctrls; > >+ unsigned int num_ctrls; > >+}; > >+ > >+struct rkvdec2_run { > >+ struct { > >+ struct vb2_v4l2_buffer *src; > >+ struct vb2_v4l2_buffer *dst; > >+ } bufs; > >+}; > >+ > >+struct rkvdec2_decoded_buffer { > >+ /* Must be the first field in this struct. */ > >+ struct v4l2_m2m_buffer base; > >+}; > >+ > >+static inline struct rkvdec2_decoded_buffer * > >+vb2_to_rkvdec2_decoded_buf(struct vb2_buffer *buf) > >+{ > >+ return container_of(buf, struct rkvdec2_decoded_buffer, > >+ base.vb.vb2_buf); > >+} > >+ > >+struct rkvdec2_coded_fmt_ops { > >+ int (*adjust_fmt)(struct rkvdec2_ctx *ctx, > >+ struct v4l2_format *f); > >+ int (*start)(struct rkvdec2_ctx *ctx); > >+ void (*stop)(struct rkvdec2_ctx *ctx); > >+ int (*run)(struct rkvdec2_ctx *ctx); > >+ void (*done)(struct rkvdec2_ctx *ctx, struct vb2_v4l2_buffer *src_buf, > >+ struct vb2_v4l2_buffer *dst_buf, > >+ enum vb2_buffer_state result); > >+ int (*try_ctrl)(struct rkvdec2_ctx *ctx, struct v4l2_ctrl *ctrl); > >+}; > >+ > >+struct rkvdec2_coded_fmt_desc { > >+ u32 fourcc; > >+ struct v4l2_frmsize_stepwise frmsize; > >+ const struct rkvdec2_ctrls *ctrls; > >+ const struct rkvdec2_coded_fmt_ops *ops; > >+ unsigned int num_decoded_fmts; > >+ const u32 *decoded_fmts; > >+ u32 subsystem_flags; > >+}; > >+ > >+struct rkvdec2_dev { > >+ struct v4l2_device v4l2_dev; > >+ struct media_device mdev; > >+ struct video_device vdev; > >+ struct v4l2_m2m_dev *m2m_dev; > >+ struct device *dev; > >+ struct clk_bulk_data *clocks; > >+ void __iomem *regs; > >+ struct mutex vdev_lock; /* serializes ioctls */ > >+ struct delayed_work watchdog_work; > >+}; > >+ > >+struct rkvdec2_ctx { > >+ struct v4l2_fh fh; > >+ struct v4l2_format coded_fmt; > >+ struct v4l2_format decoded_fmt; > >+ const struct rkvdec2_coded_fmt_desc *coded_fmt_desc; > >+ struct v4l2_ctrl_handler ctrl_hdl; > >+ struct rkvdec2_dev *dev; > >+ struct rkvdec2_aux_buf rcb_bufs[RKVDEC2_RCB_COUNT]; > >+ > >+ u32 colmv_offset; > >+ > >+ void *priv; > >+}; > >+ > >+static inline struct rkvdec2_ctx *fh_to_rkvdec2_ctx(struct v4l2_fh *fh) > >+{ > >+ return container_of(fh, struct rkvdec2_ctx, fh); > >+} > >+ > >+void rkvdec2_run_preamble(struct rkvdec2_ctx *ctx, struct rkvdec2_run > >*run); +void rkvdec2_run_postamble(struct rkvdec2_ctx *ctx, struct > >rkvdec2_run *run); + > >+extern const struct rkvdec2_coded_fmt_ops rkvdec2_h264_fmt_ops; > >+ > >+#endif /* RKVDEC_H_ */
Attachment:
signature.asc
Description: This is a digitally signed message part.