[PATCH 10/12] media: rkvdec: Add H264 support for the VDPU383 variant

From: Detlev Casanova
Date: Tue Jul 08 2025 - 11:22:30 EST


This variant is used on the RK3576 SoC.

The moving vectors size requirements are slightly different so support
for a colmv_size function per variant is added.

Also, the link registers are used to start the decoder and read IRQ status.
Per variant support for named register sections is added.

The fluster score is 128/135 for JVT-AVC_V1.
The other test suites are not supported yet.

Signed-off-by: Detlev Casanova <detlev.casanova@xxxxxxxxxxxxx>
---
.../media/platform/rockchip/rkvdec/Makefile | 1 +
.../rockchip/rkvdec/rkvdec-vdpu383-h264.c | 583 ++++++++++++++++++
.../rockchip/rkvdec/rkvdec-vdpu383-regs.h | 284 +++++++++
.../media/platform/rockchip/rkvdec/rkvdec.c | 111 +++-
.../media/platform/rockchip/rkvdec/rkvdec.h | 8 +
5 files changed, 981 insertions(+), 6 deletions(-)
create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index 20128bb6e35dc..c38ce1e8d3601 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -7,4 +7,5 @@ rockchip-vdec-y += \
rkvdec-h264-common.o \
rkvdec-rcb.o \
rkvdec-vdpu381-h264.o \
+ rkvdec-vdpu383-h264.o \
rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
new file mode 100644
index 0000000000000..366ac0c64696a
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
@@ -0,0 +1,583 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip Video Decoder VDPU383 H264 backend
+ *
+ * Copyright (C) 2024 Collabora, Ltd.
+ * Detlev Casanova <detlev.casanova@xxxxxxxxxxxxx>
+ */
+
+#include <media/v4l2-h264.h>
+#include <media/v4l2-mem2mem.h>
+
+#include <linux/iopoll.h>
+
+#include "rkvdec-rcb.h"
+#include "rkvdec-vdpu383-regs.h"
+#include "rkvdec-h264-common.h"
+
+struct rkvdec_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: 16;
+ u16 pic_height_in_mbs: 16;
+
+ 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 view_id0: 10;
+ u16 view_id1: 10;
+} __packed;
+
+struct rkvdec_pps {
+ u32 pic_parameter_set_id: 8;
+ u32 pps_seq_parameter_set_id: 5;
+ u32 entropy_coding_mode_flag: 1;
+ u32 bottom_field_pic_order_in_frame_present_flag: 1;
+ u32 num_ref_idx_l0_default_active_minus1: 5;
+ u32 num_ref_idx_l1_default_active_minus1: 5;
+ u32 weighted_pred_flag: 1;
+ u32 weighted_bipred_idc: 2;
+ u32 pic_init_qp_minus26: 7;
+ u32 pic_init_qs_minus26: 6;
+ u32 chroma_qp_index_offset: 5;
+ u32 deblocking_filter_control_present_flag: 1;
+ u32 constrained_intra_pred_flag: 1;
+ u32 redundant_pic_cnt_present: 1;
+ u32 transform_8x8_mode_flag: 1;
+ u32 second_chroma_qp_index_offset: 5;
+ u32 scaling_list_enable_flag: 1;
+ u32 is_longterm: 16;
+ u32 voidx: 16;
+
+ // dpb
+ u32 pic_field_flag: 1;
+ u32 pic_associated_flag: 1;
+ u32 cur_top_field: 32;
+ u32 cur_bot_field: 32;
+
+ u32 top_field_order_cnt0: 32;
+ u32 bot_field_order_cnt0: 32;
+ u32 top_field_order_cnt1: 32;
+ u32 bot_field_order_cnt1: 32;
+ u32 top_field_order_cnt2: 32;
+ u32 bot_field_order_cnt2: 32;
+ u32 top_field_order_cnt3: 32;
+ u32 bot_field_order_cnt3: 32;
+ u32 top_field_order_cnt4: 32;
+ u32 bot_field_order_cnt4: 32;
+ u32 top_field_order_cnt5: 32;
+ u32 bot_field_order_cnt5: 32;
+ u32 top_field_order_cnt6: 32;
+ u32 bot_field_order_cnt6: 32;
+ u32 top_field_order_cnt7: 32;
+ u32 bot_field_order_cnt7: 32;
+ u32 top_field_order_cnt8: 32;
+ u32 bot_field_order_cnt8: 32;
+ u32 top_field_order_cnt9: 32;
+ u32 bot_field_order_cnt9: 32;
+ u32 top_field_order_cnt10: 32;
+ u32 bot_field_order_cnt10: 32;
+ u32 top_field_order_cnt11: 32;
+ u32 bot_field_order_cnt11: 32;
+ u32 top_field_order_cnt12: 32;
+ u32 bot_field_order_cnt12: 32;
+ u32 top_field_order_cnt13: 32;
+ u32 bot_field_order_cnt13: 32;
+ u32 top_field_order_cnt14: 32;
+ u32 bot_field_order_cnt14: 32;
+ u32 top_field_order_cnt15: 32;
+ u32 bot_field_order_cnt15: 32;
+
+ u32 ref_field_flags: 16;
+ u32 ref_topfield_used: 16;
+ u32 ref_botfield_used: 16;
+ u32 ref_colmv_use_flag: 16;
+
+ u32 reserved0: 30;
+ u32 reserved[3];
+} __packed;
+
+struct rkvdec_sps_pps {
+ struct rkvdec_sps sps;
+ struct rkvdec_pps pps;
+} __packed;
+
+/* Data structure describing auxiliary buffer format. */
+struct rkvdec_h264_priv_tbl {
+ s8 cabac_table[4][464][2];
+ struct rkvdec_h264_scaling_list scaling_list;
+ struct rkvdec_sps_pps param_set[256];
+ struct rkvdec_rps rps;
+} __packed;
+
+struct rkvdec_h264_ctx {
+ struct rkvdec_aux_buf priv_tbl;
+ struct rkvdec_h264_reflists reflists;
+ struct vdpu383_regs_h26x regs;
+};
+
+static void set_field_order_cnt(struct rkvdec_sps_pps *hw_ps, int id, u32 top, u32 bottom)
+{
+ switch (id) {
+ case 0:
+ hw_ps->pps.top_field_order_cnt0 = top;
+ hw_ps->pps.bot_field_order_cnt0 = bottom;
+ break;
+ case 1:
+ hw_ps->pps.top_field_order_cnt1 = top;
+ hw_ps->pps.bot_field_order_cnt1 = bottom;
+ break;
+ case 2:
+ hw_ps->pps.top_field_order_cnt2 = top;
+ hw_ps->pps.bot_field_order_cnt2 = bottom;
+ break;
+ case 3:
+ hw_ps->pps.top_field_order_cnt3 = top;
+ hw_ps->pps.bot_field_order_cnt3 = bottom;
+ break;
+ case 4:
+ hw_ps->pps.top_field_order_cnt4 = top;
+ hw_ps->pps.bot_field_order_cnt4 = bottom;
+ break;
+ case 5:
+ hw_ps->pps.top_field_order_cnt5 = top;
+ hw_ps->pps.bot_field_order_cnt5 = bottom;
+ break;
+ case 6:
+ hw_ps->pps.top_field_order_cnt6 = top;
+ hw_ps->pps.bot_field_order_cnt6 = bottom;
+ break;
+ case 7:
+ hw_ps->pps.top_field_order_cnt7 = top;
+ hw_ps->pps.bot_field_order_cnt7 = bottom;
+ break;
+ case 8:
+ hw_ps->pps.top_field_order_cnt8 = top;
+ hw_ps->pps.bot_field_order_cnt8 = bottom;
+ break;
+ case 9:
+ hw_ps->pps.top_field_order_cnt9 = top;
+ hw_ps->pps.bot_field_order_cnt9 = bottom;
+ break;
+ case 10:
+ hw_ps->pps.top_field_order_cnt10 = top;
+ hw_ps->pps.bot_field_order_cnt10 = bottom;
+ break;
+ case 11:
+ hw_ps->pps.top_field_order_cnt11 = top;
+ hw_ps->pps.bot_field_order_cnt11 = bottom;
+ break;
+ case 12:
+ hw_ps->pps.top_field_order_cnt12 = top;
+ hw_ps->pps.bot_field_order_cnt12 = bottom;
+ break;
+ case 13:
+ hw_ps->pps.top_field_order_cnt13 = top;
+ hw_ps->pps.bot_field_order_cnt13 = bottom;
+ break;
+ case 14:
+ hw_ps->pps.top_field_order_cnt14 = top;
+ hw_ps->pps.bot_field_order_cnt14 = bottom;
+ break;
+ case 15:
+ hw_ps->pps.top_field_order_cnt15 = top;
+ hw_ps->pps.bot_field_order_cnt15 = bottom;
+ break;
+ }
+}
+
+static void assemble_hw_pps(struct rkvdec_ctx *ctx,
+ struct rkvdec_h264_run *run)
+{
+ struct rkvdec_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 rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
+ struct rkvdec_sps_pps *hw_ps;
+ u32 pic_width, pic_height;
+ 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 = sps->seq_parameter_set_id;
+ hw_ps->sps.profile_idc = sps->profile_idc;
+ hw_ps->sps.constraint_set3_flag = !!(sps->constraint_set_flags & (1 << 3));
+ 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 =
+ !!(sps->flags & V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS);
+ 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 = 0;
+ hw_ps->sps.num_views = 0;
+
+ /*
+ * 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.
+ */
+ pic_width = 16 * (sps->pic_width_in_mbs_minus1 + 1);
+ pic_height = 16 * (sps->pic_height_in_map_units_minus1 + 1);
+ if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
+ pic_height *= 2;
+ if (!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC))
+ pic_height /= 2;
+
+ hw_ps->sps.pic_width_in_mbs = pic_width;
+ hw_ps->sps.pic_height_in_mbs = pic_height;
+
+ 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 = pps->pic_parameter_set_id;
+ hw_ps->pps.pps_seq_parameter_set_id = pps->seq_parameter_set_id;
+ 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);
+
+ 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);
+
+ set_field_order_cnt(hw_ps, i, dpb[i].top_field_order_cnt,
+ dpb[i].bottom_field_order_cnt);
+
+ hw_ps->pps.ref_field_flags |=
+ (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) << i;
+ hw_ps->pps.ref_colmv_use_flag |=
+ (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) << i;
+ hw_ps->pps.ref_topfield_used |=
+ (!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF)) << i;
+ hw_ps->pps.ref_botfield_used |=
+ (!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)) << i;
+ }
+
+ hw_ps->pps.pic_field_flag =
+ !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC);
+ hw_ps->pps.pic_associated_flag =
+ !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD);
+
+ hw_ps->pps.cur_top_field = dec_params->top_field_order_cnt;
+ hw_ps->pps.cur_bot_field = dec_params->bottom_field_order_cnt;
+}
+
+static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
+{
+ struct rkvdec_dev *rkvdec = ctx->dev;
+ struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+
+ rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_REGS,
+ &h264_ctx->regs.common,
+ sizeof(h264_ctx->regs.common));
+ rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_ADDR_REGS,
+ &h264_ctx->regs.common_addr,
+ sizeof(h264_ctx->regs.common_addr));
+ rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS,
+ &h264_ctx->regs.h26x_params,
+ sizeof(h264_ctx->regs.h26x_params));
+ rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_ADDR_REGS,
+ &h264_ctx->regs.h26x_addr,
+ sizeof(h264_ctx->regs.h26x_addr));
+}
+
+static void config_registers(struct rkvdec_ctx *ctx,
+ struct rkvdec_h264_run *run)
+{
+ const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
+ struct rkvdec_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 vdpu383_regs_h26x *regs = &h264_ctx->regs;
+ const struct v4l2_format *f;
+ dma_addr_t rlc_addr;
+ dma_addr_t dst_addr;
+ u32 hor_virstride;
+ u32 ver_virstride;
+ u32 y_virstride;
+ u32 offset;
+ u32 pixels;
+ u32 i;
+
+ memset(regs, 0, sizeof(*regs));
+
+ /* Set H264 mode */
+ regs->common.reg008_dec_mode = VDPU383_MODE_H264;
+
+ /* Set input stream length */
+ regs->h26x_params.reg066_stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+
+ /* Set strides */
+ f = &ctx->decoded_fmt;
+ dst_fmt = &f->fmt.pix_mp;
+ hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
+ ver_virstride = dst_fmt->height;
+ y_virstride = hor_virstride * ver_virstride;
+
+ pixels = dst_fmt->height * dst_fmt->width;
+
+ regs->h26x_params.reg068_hor_virstride = hor_virstride / 16;
+ regs->h26x_params.reg069_raster_uv_hor_virstride = hor_virstride / 16;
+ regs->h26x_params.reg070_y_virstride = y_virstride / 16;
+
+ /* Activate block gating */
+ regs->common.reg010.strmd_auto_gating_e = 1;
+ regs->common.reg010.inter_auto_gating_e = 1;
+ regs->common.reg010.intra_auto_gating_e = 1;
+ regs->common.reg010.transd_auto_gating_e = 1;
+ regs->common.reg010.recon_auto_gating_e = 1;
+ regs->common.reg010.filterd_auto_gating_e = 1;
+ regs->common.reg010.bus_auto_gating_e = 1;
+ regs->common.reg010.ctrl_auto_gating_e = 1;
+ regs->common.reg010.rcb_auto_gating_e = 1;
+ regs->common.reg010.err_prc_auto_gating_e = 1;
+
+ /* Set timeout threshold */
+ if (pixels < VDPU383_1080P_PIXELS)
+ regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_1080p;
+ else if (pixels < VDPU383_4K_PIXELS)
+ regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_4K;
+ else if (pixels < VDPU383_8K_PIXELS)
+ regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_8K;
+ else
+ regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_MAX;
+
+ regs->common.reg016.error_proc_disable = 1;
+
+ /* 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->h26x_addr.reg170_185_ref_base[i] = buf_dma;
+ regs->h26x_addr.reg195_210_payload_st_ref_base[i] = buf_dma;
+
+ /* Set COLMV addresses */
+ regs->h26x_addr.reg217_232_colmv_ref_base[i] = buf_dma + ctx->colmv_offset;
+ }
+
+ /* Set rlc base address (input stream) */
+ rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+ regs->common_addr.reg128_strm_base = rlc_addr;
+
+ /* Set output base address */
+ dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+ regs->h26x_addr.reg168_decout_base = dst_addr;
+ regs->h26x_addr.reg169_error_ref_base = dst_addr;
+ regs->h26x_addr.reg192_payload_st_cur_base = dst_addr;
+
+ /* Set colmv address */
+ regs->h26x_addr.reg216_colmv_cur_base = dst_addr + ctx->colmv_offset;
+
+ /* Set RCB addresses */
+ for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++) {
+ regs->common_addr.reg140_162_rcb_info[i].offset = rkvdec_rcb_buf_dma_addr(ctx, i);
+ regs->common_addr.reg140_162_rcb_info[i].size = rkvdec_rcb_buf_size(ctx, i);
+ }
+
+ /* Set hw pps address */
+ offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
+ regs->common_addr.reg131_gbl_base = priv_start_addr + offset;
+ regs->h26x_params.reg067_global_len = sizeof(struct rkvdec_sps_pps) / 16;
+
+ /* Set hw rps address */
+ offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
+ regs->common_addr.reg129_rps_base = priv_start_addr + offset;
+
+ /* Set cabac table */
+ offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
+ regs->common_addr.reg130_cabactbl_base = priv_start_addr + offset;
+
+ /* Set scaling list address */
+ offset = offsetof(struct rkvdec_h264_priv_tbl, scaling_list);
+ regs->common_addr.reg132_scanlist_addr = priv_start_addr + offset;
+
+ rkvdec_write_regs(ctx);
+}
+
+static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
+{
+ struct rkvdec_dev *rkvdec = ctx->dev;
+ struct rkvdec_h264_priv_tbl *priv_tbl;
+ struct rkvdec_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 = rkvdec_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, rkvdec_h264_cabac_table,
+ sizeof(rkvdec_h264_cabac_table));
+
+ ctx->priv = h264_ctx;
+
+ return 0;
+
+err_free_ctx:
+ kfree(h264_ctx);
+ return ret;
+}
+
+static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
+{
+ struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+ struct rkvdec_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 int rkvdec_h264_run(struct rkvdec_ctx *ctx)
+{
+ struct v4l2_h264_reflist_builder reflist_builder;
+ struct rkvdec_dev *rkvdec = ctx->dev;
+ struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+ struct rkvdec_h264_run run;
+ struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
+ uint32_t watchdog_time;
+ u64 timeout_threshold;
+ unsigned long axi_rate;
+
+ rkvdec_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(&run, &tbl->scaling_list);
+ assemble_hw_pps(ctx, &run);
+ lookup_ref_buf_idx(ctx, &run);
+ assemble_hw_rps(&reflist_builder, &run, &h264_ctx->reflists, &tbl->rps);
+
+ config_registers(ctx, &run);
+
+ rkvdec_run_postamble(ctx, &run.base);
+
+ /* Set watchdog at 2 times the hardware timeout threshold */
+ timeout_threshold = h264_ctx->regs.common.reg013_core_timeout_threshold;
+ axi_rate = clk_get_rate(rkvdec->axi_clk);
+
+ if (axi_rate)
+ watchdog_time = 2 * (1000 * timeout_threshold) / axi_rate;
+ else
+ watchdog_time = 2000;
+ schedule_delayed_work(&rkvdec->watchdog_work,
+ msecs_to_jiffies(watchdog_time));
+
+
+ /* Start decoding! */
+ writel(timeout_threshold, rkvdec->link + VDPU383_LINK_TIMEOUT_THRESHOLD);
+ writel(0, rkvdec->link + VDPU383_LINK_IP_ENABLE);
+ writel(VDPU383_DEC_E_BIT, rkvdec->link + VDPU383_LINK_DEC_ENABLE);
+
+ return 0;
+}
+
+static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+ if (ctrl->id == V4L2_CID_STATELESS_H264_SPS)
+ return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
+
+ return 0;
+}
+
+const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops = {
+ .adjust_fmt = rkvdec_h264_adjust_fmt,
+ .get_image_fmt = rkvdec_h264_get_image_fmt,
+ .start = rkvdec_h264_start,
+ .stop = rkvdec_h264_stop,
+ .run = rkvdec_h264_run,
+ .try_ctrl = rkvdec_h264_try_ctrl,
+};
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h
new file mode 100644
index 0000000000000..2b614393a3afa
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h
@@ -0,0 +1,284 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip Video Decoder VDPU383 driver registers description
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ * Detlev Casanova <detlev.casanova@xxxxxxxxxxxxx>
+ */
+
+#ifndef _RKVDEC_VDPU838_REGS_H_
+#define _RKVDEC_VDPU838_REGS_H_
+
+#include <linux/types.h>
+
+#define VDPU383_OFFSET_COMMON_REGS (8 * sizeof(u32))
+#define VDPU383_OFFSET_CODEC_PARAMS_REGS (64 * sizeof(u32))
+#define VDPU383_OFFSET_COMMON_ADDR_REGS (128 * sizeof(u32))
+#define VDPU383_OFFSET_CODEC_ADDR_REGS (168 * sizeof(u32))
+#define VDPU383_OFFSET_POC_HIGHBIT_REGS (200 * sizeof(u32))
+
+#define VDPU383_MODE_HEVC 0
+#define VDPU383_MODE_H264 1
+
+#define VDPU383_1080P_PIXELS (1920 * 1080)
+#define VDPU383_4K_PIXELS (4096 * 2304)
+#define VDPU383_8K_PIXELS (7680 * 4320)
+#define VDPU383_TIMEOUT_1080p (0xffffff)
+#define VDPU383_TIMEOUT_4K (0x2cfffff)
+#define VDPU383_TIMEOUT_8K (0x4ffffff)
+#define VDPU383_TIMEOUT_MAX (0xffffffff)
+
+#define VDPU383_LINK_TIMEOUT_THRESHOLD 0x54
+
+#define VDPU383_LINK_IP_ENABLE 0x58
+#define VDPU383_IP_CRU_MODE BIT(24)
+
+#define VDPU383_LINK_DEC_ENABLE 0x40
+#define VDPU383_DEC_E_BIT BIT(0)
+
+#define VDPU383_LINK_INT_EN 0x048
+#define VDPU383_INT_EN_IRQ BIT(0)
+#define VDPU383_INT_EN_LINE_IRQ BIT(1)
+
+#define VDPU383_LINK_STA_INT 0x04c
+#define VDPU383_STA_INT_DEC_RDY_STA BIT(0)
+#define VDPU383_STA_INT_SOFTRESET_RDY (BIT(10) | BIT(11))
+#define VDPU383_STA_INT_ALL 0x3ff
+
+struct vdpu383_regs_common {
+ u32 reg008_dec_mode;
+
+ struct swreg9_important_en {
+ u32 fbc_e : 1;
+ u32 tile_e : 1;
+ u32 reserve0 : 2;
+ u32 buf_empty_en : 1;
+ u32 scale_down_en : 1;
+ u32 reserve1 : 1;
+ u32 pix_range_det_e : 1;
+ u32 av1_fgs_en : 1;
+ u32 reserve2 : 7;
+ u32 line_irq_en : 1;
+ u32 out_cbcr_swap : 1;
+ u32 fbc_force_uncompress : 1;
+ u32 fbc_sparse_mode : 1;
+ u32 reserve3 : 12;
+ } reg009;
+
+ struct swreg010_block_gating_en {
+ u32 strmd_auto_gating_e : 1;
+ u32 inter_auto_gating_e : 1;
+ u32 intra_auto_gating_e : 1;
+ u32 transd_auto_gating_e : 1;
+ u32 recon_auto_gating_e : 1;
+ u32 filterd_auto_gating_e : 1;
+ u32 bus_auto_gating_e : 1;
+ u32 ctrl_auto_gating_e : 1;
+ u32 rcb_auto_gating_e : 1;
+ u32 err_prc_auto_gating_e : 1;
+ u32 reserve0 : 22;
+ } reg010;
+
+ struct swreg011_cfg_para {
+ u32 reserve0 : 9;
+ u32 dec_timeout_dis : 1;
+ u32 reserve1 : 22;
+ } reg011;
+
+ struct swreg012_cache_hash_mask {
+ u32 reserve0 : 7;
+ u32 cache_hash_mask : 25;
+ } reg012;
+
+ u32 reg013_core_timeout_threshold;
+
+ struct swreg014_line_irq_ctrl {
+ u32 dec_line_irq_step : 16;
+ u32 dec_line_offset_y_st : 16;
+ } reg014;
+
+ struct swreg015_irq_sta {
+ u32 rkvdec_frame_rdy_sta : 1;
+ u32 rkvdec_strm_error_sta : 1;
+ u32 rkvdec_core_timeout_sta : 1;
+ u32 rkvdec_ip_timeout_sta : 1;
+ u32 rkvdec_bus_error_sta : 1;
+ u32 rkvdec_buffer_empty_sta : 1;
+ u32 rkvdec_colmv_ref_error_sta : 1;
+ u32 rkvdec_error_spread_sta : 1;
+ u32 create_core_timeout_sta : 1;
+ u32 wlast_miss_match_sta : 1;
+ u32 rkvdec_core_rst_rdy_sta : 1;
+ u32 rkvdec_ip_rst_rdy_sta : 1;
+ u32 force_busidle_rdy_sta : 1;
+ u32 ltb_pause_rdy_sta : 1;
+ u32 ltb_end_flag : 1;
+ u32 unsupport_decmode_error_sta : 1;
+ u32 wmask_bits : 15;
+ u32 reserve0 : 1;
+ } reg015;
+
+ struct swreg016_error_ctrl_set {
+ u32 error_proc_disable : 1;
+ u32 reserve0 : 7;
+ u32 error_spread_disable : 1;
+ u32 reserve1 : 15;
+ u32 roi_error_ctu_cal_en : 1;
+ u32 reserve2 : 7;
+ } reg016;
+
+ struct swreg017_err_roi_ctu_offset_start {
+ u32 roi_x_ctu_offset_st : 12;
+ u32 reserve0 : 4;
+ u32 roi_y_ctu_offset_st : 12;
+ u32 reserve1 : 4;
+ } reg017;
+
+ struct swreg018_err_roi_ctu_offset_end {
+ u32 roi_x_ctu_offset_end : 12;
+ u32 reserve0 : 4;
+ u32 roi_y_ctu_offset_end : 12;
+ u32 reserve1 : 4;
+ } reg018;
+
+ struct swreg019_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 reserve0 : 28;
+ } reg019;
+
+ u32 reg020_cabac_error_en_lowbits;
+ u32 reg021_cabac_error_en_highbits;
+
+ u32 reg022_reserved;
+
+ struct swreg023_invalid_pixel_fill {
+ u32 fill_y : 10;
+ u32 fill_u : 10;
+ u32 fill_v : 10;
+ u32 reserve0 : 2;
+ } reg023;
+
+ u32 reg024_026_reserved[3];
+
+ struct swreg027_align_en {
+ u32 reserve0 : 4;
+ u32 ctu_align_wr_en : 1;
+ u32 reserve1 : 27;
+ } reg027;
+
+ struct swreg028_debug_perf_latency_ctrl0 {
+ u32 axi_perf_work_e : 1;
+ u32 reserve0 : 2;
+ u32 axi_cnt_type : 1;
+ u32 rd_latency_id : 8;
+ u32 reserve1 : 4;
+ u32 rd_latency_thr : 12;
+ u32 reserve2 : 4;
+ } reg028;
+
+ struct swreg029_debug_perf_latency_ctrl1 {
+ u32 addr_align_type : 2;
+ u32 ar_cnt_id_type : 1;
+ u32 aw_cnt_id_type : 1;
+ u32 ar_count_id : 8;
+ u32 reserve0 : 4;
+ u32 aw_count_id : 8;
+ u32 rd_band_width_mode : 1;
+ u32 reserve1 : 7;
+ } reg029;
+
+ struct swreg030_qos_ctrl {
+ u32 axi_wr_qos_level : 4;
+ u32 reserve0 : 4;
+ u32 axi_wr_qos : 4;
+ u32 reserve1 : 4;
+ u32 axi_rd_qos_level : 4;
+ u32 reserve2 : 4;
+ u32 axi_rd_qos : 4;
+ u32 reserve3 : 4;
+ } reg030;
+};
+
+struct vdpu383_regs_common_addr {
+ u32 reg128_strm_base;
+ u32 reg129_rps_base;
+ u32 reg130_cabactbl_base;
+ u32 reg131_gbl_base;
+ u32 reg132_scanlist_addr;
+ u32 reg133_scale_down_base;
+ u32 reg134_fgs_base;
+ u32 reg135_139_reserved[5];
+
+ struct rcb_info {
+ u32 offset;
+ u32 size;
+ } reg140_162_rcb_info[11];
+};
+
+struct vdpu383_regs_h26x_addr {
+ u32 reg168_decout_base;
+ u32 reg169_error_ref_base;
+ u32 reg170_185_ref_base[16];
+ u32 reg186_191_reserved[6];
+ u32 reg192_payload_st_cur_base;
+ u32 reg193_fbc_payload_offset;
+ u32 reg194_payload_st_error_ref_base;
+ u32 reg195_210_payload_st_ref_base[16];
+ u32 reg211_215_reserved[5];
+ u32 reg216_colmv_cur_base;
+ u32 reg217_232_colmv_ref_base[16];
+};
+
+struct vdpu383_regs_h26x_params {
+ u32 reg064_start_decoder;
+ u32 reg065_strm_start_bit;
+ u32 reg066_stream_len;
+ u32 reg067_global_len;
+ u32 reg068_hor_virstride;
+ u32 reg069_raster_uv_hor_virstride;
+ u32 reg070_y_virstride;
+ u32 reg071_scl_ref_hor_virstride;
+ u32 reg072_scl_ref_raster_uv_hor_virstride;
+ u32 reg073_scl_ref_virstride;
+ u32 reg074_fgs_ref_hor_virstride;
+ u32 reg075_079_reserved[5];
+ u32 reg080_error_ref_hor_virstride;
+ u32 reg081_error_ref_raster_uv_hor_virstride;
+ u32 reg082_error_ref_virstride;
+ u32 reg083_ref0_hor_virstride;
+ u32 reg084_ref0_raster_uv_hor_virstride;
+ u32 reg085_ref0_virstride;
+ u32 reg086_ref1_hor_virstride;
+ u32 reg087_ref1_raster_uv_hor_virstride;
+ u32 reg088_ref1_virstride;
+ u32 reg089_ref2_hor_virstride;
+ u32 reg090_ref2_raster_uv_hor_virstride;
+ u32 reg091_ref2_virstride;
+ u32 reg092_ref3_hor_virstride;
+ u32 reg093_ref3_raster_uv_hor_virstride;
+ u32 reg094_ref3_virstride;
+ u32 reg095_ref4_hor_virstride;
+ u32 reg096_ref4_raster_uv_hor_virstride;
+ u32 reg097_ref4_virstride;
+ u32 reg098_ref5_hor_virstride;
+ u32 reg099_ref5_raster_uv_hor_virstride;
+ u32 reg100_ref5_virstride;
+ u32 reg101_ref6_hor_virstride;
+ u32 reg102_ref6_raster_uv_hor_virstride;
+ u32 reg103_ref6_virstride;
+ u32 reg104_ref7_hor_virstride;
+ u32 reg105_ref7_raster_uv_hor_virstride;
+ u32 reg106_ref7_virstride;
+};
+
+struct vdpu383_regs_h26x {
+ struct vdpu383_regs_common common; /* 8-30 */
+ struct vdpu383_regs_h26x_params h26x_params; /* 64-74, 80-106 */
+ struct vdpu383_regs_common_addr common_addr; /* 128-134, 140-161 */
+ struct vdpu383_regs_h26x_addr h26x_addr; /* 168-185, 192-210, 216-232 */
+} __packed;
+
+#endif /* __RKVDEC_VDPU838_REGS_H__ */
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 5e6b193f38a51..fcb4d1795c4d4 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -9,6 +9,7 @@
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
*/

+#include <linux/hw_bitfield.h>
#include <linux/clk.h>
#include <linux/genalloc.h>
#include <linux/interrupt.h>
@@ -29,6 +30,7 @@
#include "rkvdec.h"
#include "rkvdec-regs.h"
#include "rkvdec-vdpu381-regs.h"
+#include "rkvdec-vdpu383-regs.h"
#include "rkvdec-rcb.h"

static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
@@ -120,6 +122,16 @@ static int vdpu38x_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pix_mp, u32 pix
return 0;
}

+static u32 rkvdec_colmv_size(u16 width, u16 height)
+{
+ return 128 * DIV_ROUND_UP(width, 16) * DIV_ROUND_UP(height, 16);
+}
+
+static u32 rkvdec_vdpu383_colmv_size(u16 width, u16 height)
+{
+ return ALIGN(width, 64) * ALIGN(height, 16);
+}
+
static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
struct v4l2_pix_format_mplane *pix_mp)
{
@@ -129,9 +141,7 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,

ctx->colmv_offset = pix_mp->plane_fmt[0].sizeimage;

- pix_mp->plane_fmt[0].sizeimage += 128 *
- DIV_ROUND_UP(pix_mp->width, 16) *
- DIV_ROUND_UP(pix_mp->height, 16);
+ pix_mp->plane_fmt[0].sizeimage += cfg->colmv_size(pix_mp->width, pix_mp->height);
}

static void rkvdec_reset_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f,
@@ -346,6 +356,25 @@ static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
},
};

+static const struct rkvdec_coded_fmt_desc vdpu383_coded_fmts[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_H264_SLICE,
+ .frmsize = {
+ .min_width = 64,
+ .max_width = 65520,
+ .step_width = 64,
+ .min_height = 16,
+ .max_height = 65520,
+ .step_height = 16,
+ },
+ .ctrls = &rkvdec_h264_ctrls,
+ .ops = &rkvdec_vdpu383_h264_fmt_ops,
+ .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
+ .decoded_fmts = rkvdec_h264_decoded_fmts,
+ .subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+ },
+};
+
static const struct rkvdec_coded_fmt_desc *
rkvdec_find_coded_fmt_desc(struct rkvdec_ctx *ctx, u32 fourcc)
{
@@ -1211,6 +1240,37 @@ static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx)
return IRQ_HANDLED;
}

+
+static irqreturn_t vdpu383_irq_handler(struct rkvdec_ctx *ctx)
+{
+ struct rkvdec_dev *rkvdec = ctx->dev;
+ enum vb2_buffer_state state;
+ bool need_reset = 0;
+ u32 status;
+
+ status = readl(rkvdec->link + VDPU383_LINK_STA_INT);
+ writel(FIELD_PREP_WM16(VDPU383_STA_INT_ALL, 0), rkvdec->link + VDPU383_LINK_STA_INT);
+ /* On vdpu383, the interrupts must be disabled */
+ writel(FIELD_PREP_WM16(VDPU383_INT_EN_IRQ | VDPU383_INT_EN_LINE_IRQ, 0),
+ rkvdec->link + VDPU383_LINK_INT_EN);
+
+ if (status & VDPU383_STA_INT_DEC_RDY_STA) {
+ state = VB2_BUF_STATE_DONE;
+ } else {
+ state = VB2_BUF_STATE_ERROR;
+ if (status & VDPU383_STA_INT_SOFTRESET_RDY)
+ rkvdec_iommu_restore(rkvdec);
+ }
+
+ if (need_reset)
+ rkvdec_iommu_restore(rkvdec);
+
+ if (cancel_delayed_work(&rkvdec->watchdog_work))
+ rkvdec_job_finish(ctx, state);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
{
struct rkvdec_dev *rkvdec = priv;
@@ -1283,6 +1343,7 @@ const struct rkvdec_config config_rkvdec = {
.coded_fmts_num = ARRAY_SIZE(rkvdec_coded_fmts),
.irq_handler = rk3399_irq_handler,
.fill_pixfmt_mp = v4l2_fill_pixfmt_mp,
+ .colmv_size = rkvdec_colmv_size,
};

static struct rcb_size_info vdpu381_rcb_sizes[] = {
@@ -1305,11 +1366,39 @@ const struct rkvdec_config config_vdpu381 = {
.rcb_num = ARRAY_SIZE(vdpu381_rcb_sizes),
.irq_handler = vdpu381_irq_handler,
.fill_pixfmt_mp = vdpu38x_fill_pixfmt_mp,
+ .colmv_size = rkvdec_colmv_size,
+ .named_regs = true,
+};
+
+static struct rcb_size_info vdpu383_rcb_sizes[] = {
+ {6, PIC_WIDTH}, // streamd
+ {6, PIC_WIDTH}, // streamd_tile
+ {12, PIC_WIDTH}, // inter
+ {12, PIC_WIDTH}, // inter_tile
+ {16, PIC_WIDTH}, // intra
+ {10, PIC_WIDTH}, // intra_tile
+ {120, PIC_WIDTH}, // filterd
+ {120, PIC_WIDTH}, // filterd_protect
+ {120, PIC_WIDTH}, // filterd_tile_row
+ {180, PIC_HEIGHT}, // filterd_tile_col
+};
+
+const struct rkvdec_config config_vdpu383 = {
+ .coded_fmts = (struct rkvdec_coded_fmt_desc *)vdpu383_coded_fmts,
+ .coded_fmts_num = ARRAY_SIZE(vdpu383_coded_fmts),
+ .rcb_size_info = vdpu383_rcb_sizes,
+ .rcb_num = ARRAY_SIZE(vdpu383_rcb_sizes),
+ .irq_handler = vdpu383_irq_handler,
+ .fill_pixfmt_mp = vdpu38x_fill_pixfmt_mp,
+ .colmv_size = rkvdec_vdpu383_colmv_size,
+ .fill_pixfmt_mp = vdpu38x_fill_pixfmt_mp,
+ .named_regs = true,
};

static const struct of_device_id of_rkvdec_match[] = {
{ .compatible = "rockchip,rk3399-vdec", .data = &config_rkvdec },
{ .compatible = "rockchip,rk3588-vdec", .data = &config_vdpu381 },
+ { .compatible = "rockchip,rk3576-vdec", .data = &config_vdpu383 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_rkvdec_match);
@@ -1342,9 +1431,19 @@ static int rkvdec_probe(struct platform_device *pdev)
rkvdec->clk_count = ret;
rkvdec->axi_clk = devm_clk_get(&pdev->dev, "axi");

- rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(rkvdec->regs))
- return PTR_ERR(rkvdec->regs);
+ if (rkvdec->config->named_regs) {
+ rkvdec->regs = devm_platform_ioremap_resource_byname(pdev, "function");
+ if (IS_ERR(rkvdec->regs))
+ return PTR_ERR(rkvdec->regs);
+
+ rkvdec->link = devm_platform_ioremap_resource_byname(pdev, "link");
+ if (IS_ERR(rkvdec->link))
+ return PTR_ERR(rkvdec->link);
+ } else {
+ 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) {
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 9e0fef2445abc..acb9d72b130bb 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -110,6 +110,8 @@ struct rkvdec_config {
irqreturn_t (*irq_handler)(struct rkvdec_ctx *ctx);
int (*fill_pixfmt_mp)(struct v4l2_pix_format_mplane *pix_mp, u32 pixelformat,
u32 width, u32 height);
+ u32 (*colmv_size)(u16 width, u16 height);
+ bool named_regs;
};

struct rkvdec_dev {
@@ -122,6 +124,7 @@ struct rkvdec_dev {
unsigned int clk_count;
struct clk *axi_clk;
void __iomem *regs;
+ void __iomem *link;
struct mutex vdev_lock; /* serializes ioctls */
struct delayed_work watchdog_work;
struct gen_pool *sram_pool;
@@ -164,9 +167,14 @@ void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len);

+/* RKVDEC ops */
extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops;
extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;

+/* VDPU381 ops */
extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;

+/* VDPU383 ops */
+extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops;
+
#endif /* RKVDEC_H_ */
--
2.50.0