[PATCH v4 07/15] media: rkvdec: Move hevc functions to common file

Detlev Casanova posted 15 patches 3 months, 2 weeks ago
There is a newer version of this series
[PATCH v4 07/15] media: rkvdec: Move hevc functions to common file
Posted by Detlev Casanova 3 months, 2 weeks ago
This is a preparation commit to add support for new variants of the
decoder.

The functions will later be shared with vdpu381 (rk3588) and vdpu383
(rk3576).

Tested-by: Diederik de Haas <didi.debian@cknow.org>  # Rock 5B
Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../rockchip/rkvdec/rkvdec-hevc-common.c      | 233 +++++++++++++++++
 .../rockchip/rkvdec/rkvdec-hevc-common.h      |  51 ++++
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    | 243 +-----------------
 4 files changed, 291 insertions(+), 237 deletions(-)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index d2ba7a7c15e5..1b4bc44be23e 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -6,4 +6,5 @@ rockchip-vdec-y += \
 		   rkvdec-h264.o \
 		   rkvdec-h264-common.o \
 		   rkvdec-hevc.o \
+		   rkvdec-hevc-common.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
new file mode 100644
index 000000000000..d571107f2242
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip video decoder hevc common functions
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *      Detlev Casanova <detlev.casanova@collabora.com>
+ *
+ * Copyright (C) 2023 Collabora, Ltd.
+ *      Sebastian Fricke <sebastian.fricke@collabora.com>
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *	Boris Brezillon <boris.brezillon@collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ *	Jeffy Chen <jeffy.chen@rock-chips.com>
+ */
+
+#include <linux/v4l2-common.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+#include "rkvdec-hevc-common.h"
+
+/*
+ * Flip one or more matrices along their main diagonal and flatten them
+ * before writing it to the memory.
+ * Convert:
+ * ABCD         AEIM
+ * EFGH     =>  BFJN     =>     AEIMBFJNCGKODHLP
+ * IJKL         CGKO
+ * MNOP         DHLP
+ */
+static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
+					   int matrices, int row_length)
+{
+	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
+
+	matrix_size = row_length * row_length;
+	for (i = 0; i < matrices; i++) {
+		row = 0;
+		x_offset = 0;
+		matrix_offset = i * matrix_size;
+		for (j = 0; j < matrix_size; j++) {
+			y_offset = j - (row * row_length);
+			rot_index = y_offset * row_length + x_offset;
+			new_value = *(input + i * matrix_size + j);
+			output[matrix_offset + rot_index] = new_value;
+			if ((j + 1) % row_length == 0) {
+				row += 1;
+				x_offset += 1;
+			}
+		}
+	}
+}
+
+static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
+{
+	int offset = 0;
+
+	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
+	offset = 6 * 16 * sizeof(u8);
+	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
+	offset += 6 * 64 * sizeof(u8);
+	transpose_and_flatten_matrices(output + offset,
+				       (const u8 *)input->scaling_list_16x16, 6, 8);
+	offset += 6 * 64 * sizeof(u8);
+	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
+	transpose_and_flatten_matrices(output + offset,
+				       (const u8 *)input->scaling_list_32x32, 1, 8);
+	offset += 64 * sizeof(u8);
+	memset(output + offset, 0, 128);
+	offset += 128 * sizeof(u8);
+	transpose_and_flatten_matrices(output + offset,
+				       (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
+				       1, 8);
+	offset += 64 * sizeof(u8);
+	memset(output + offset, 0, 128);
+}
+
+/*
+ * Required layout:
+ * A = scaling_list_dc_coef_16x16
+ * B = scaling_list_dc_coef_32x32
+ * 0 = Padding
+ *
+ * A, A, A, A, A, A, B, 0, 0, B, 0, 0
+ */
+static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
+{
+	u8 list_32x32[6] = {0};
+
+	memcpy(output, input->scaling_list_dc_coef_16x16, 6 * sizeof(u8));
+	list_32x32[0] = input->scaling_list_dc_coef_32x32[0];
+	list_32x32[3] = input->scaling_list_dc_coef_32x32[1];
+	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
+}
+
+static void translate_scaling_list(struct scaling_factor *output,
+				   const struct v4l2_ctrl_hevc_scaling_matrix *input)
+{
+	assemble_scalingfactor0(output->scalingfactor0, input);
+	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
+	assemble_scalingdc(output->scalingdc, input);
+	memset(output->reserved, 0, 4 * sizeof(u8));
+}
+
+void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
+					  struct scaling_factor *scaling_factor,
+					  struct v4l2_ctrl_hevc_scaling_matrix *cache)
+{
+	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
+
+	if (!memcmp(cache, scaling,
+		    sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
+		return;
+
+	translate_scaling_list(scaling_factor, scaling);
+
+	memcpy(cache, scaling,
+	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
+}
+
+struct vb2_buffer *
+get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
+	    unsigned int dpb_idx)
+{
+	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
+	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
+	struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
+	struct vb2_buffer *buf = NULL;
+
+	if (dpb_idx < decode_params->num_active_dpb_entries)
+		buf = vb2_find_buffer(cap_q, dpb[dpb_idx].timestamp);
+
+	/*
+	 * If a DPB entry is unused or invalid, the address of current destination
+	 * buffer is returned.
+	 */
+	if (!buf)
+		return &run->base.bufs.dst->vb2_buf;
+
+	return buf;
+}
+
+#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
+
+int rkvdec_hevc_adjust_fmt(struct rkvdec_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_HEVC_MAX_DEPTH_IN_BYTES;
+	return 0;
+}
+
+enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
+						struct v4l2_ctrl *ctrl)
+{
+	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
+
+	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
+		return RKVDEC_IMG_FMT_ANY;
+
+	if (sps->bit_depth_luma_minus8 == 0) {
+		if (sps->chroma_format_idc == 2)
+			return RKVDEC_IMG_FMT_422_8BIT;
+		else
+			return RKVDEC_IMG_FMT_420_8BIT;
+	} else if (sps->bit_depth_luma_minus8 == 2) {
+		if (sps->chroma_format_idc == 2)
+			return RKVDEC_IMG_FMT_422_10BIT;
+		else
+			return RKVDEC_IMG_FMT_420_10BIT;
+	}
+
+	return RKVDEC_IMG_FMT_ANY;
+}
+
+static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
+			     const struct v4l2_ctrl_hevc_sps *sps)
+{
+	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 && sps->bit_depth_luma_minus8 != 2)
+		/* Only 8-bit and 10-bit are supported */
+		return -EINVAL;
+
+	if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
+	    sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height)
+		return -EINVAL;
+
+	return 0;
+}
+
+void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
+			      struct rkvdec_hevc_run *run)
+{
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
+	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
+	run->slices_params = ctrl ? ctrl->p_cur.p : NULL;
+	run->num_slices = ctrl ? ctrl->new_elems : 0;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_SPS);
+	run->sps = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_PPS);
+	run->pps = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
+	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
+
+	rkvdec_run_preamble(ctx, &run->base);
+}
+
+int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+	if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS)
+		return rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
+
+	return 0;
+}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
new file mode 100644
index 000000000000..746b1bd73c08
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip video decoder hevc common functions
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *      Detlev Casanova <detlev.casanova@collabora.com>
+ *
+ * Copyright (C) 2023 Collabora, Ltd.
+ *      Sebastian Fricke <sebastian.fricke@collabora.com>
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *	Boris Brezillon <boris.brezillon@collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ *	Jeffy Chen <jeffy.chen@rock-chips.com>
+ */
+
+#include <media/v4l2-mem2mem.h>
+#include "rkvdec.h"
+
+#define RKV_HEVC_CABAC_TABLE_SIZE		27456
+extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
+
+struct rkvdec_hevc_run {
+	struct rkvdec_run base;
+	const struct v4l2_ctrl_hevc_slice_params *slices_params;
+	const struct v4l2_ctrl_hevc_decode_params *decode_params;
+	const struct v4l2_ctrl_hevc_sps *sps;
+	const struct v4l2_ctrl_hevc_pps *pps;
+	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
+	int num_slices;
+};
+
+struct scaling_factor {
+	u8 scalingfactor0[1248];
+	u8 scalingfactor1[96];	/*4X4 TU Rotate, total 16X4*/
+	u8 scalingdc[12];	/*N1005 Vienna Meeting*/
+	u8 reserved[4];		/*16Bytes align*/
+};
+
+enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
+						struct v4l2_ctrl *ctrl);
+void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
+					  struct scaling_factor *scaling_factor,
+					  struct v4l2_ctrl_hevc_scaling_matrix *cache);
+struct vb2_buffer *get_ref_buf(struct rkvdec_ctx *ctx,
+			       struct rkvdec_hevc_run *run,
+			       unsigned int dpb_idx);
+int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f);
+int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl);
+void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index b01c1bb52a04..31a979698578 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -16,6 +16,7 @@
 
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
+#include "rkvdec-hevc-common.h"
 
 /* Size in u8/u32 units. */
 #define RKV_SCALING_LIST_SIZE		1360
@@ -24,9 +25,6 @@
 #define RKV_RPS_SIZE			(32 / 4)
 #define RKV_RPS_LEN			600
 
-#define RKV_HEVC_CABAC_TABLE_SIZE		27456
-extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
-
 struct rkvdec_sps_pps_packet {
 	u32 info[RKV_PPS_SIZE];
 };
@@ -113,34 +111,17 @@ struct rkvdec_ps_field {
 /* Data structure describing auxiliary buffer format. */
 struct rkvdec_hevc_priv_tbl {
 	u8 cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
-	u8 scaling_list[RKV_SCALING_LIST_SIZE];
+	struct scaling_factor scaling_list;
 	struct rkvdec_sps_pps_packet param_set[RKV_PPS_LEN];
 	struct rkvdec_rps_packet rps[RKV_RPS_LEN];
 };
 
-struct rkvdec_hevc_run {
-	struct rkvdec_run base;
-	const struct v4l2_ctrl_hevc_slice_params *slices_params;
-	const struct v4l2_ctrl_hevc_decode_params *decode_params;
-	const struct v4l2_ctrl_hevc_sps *sps;
-	const struct v4l2_ctrl_hevc_pps *pps;
-	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
-	int num_slices;
-};
-
 struct rkvdec_hevc_ctx {
 	struct rkvdec_aux_buf priv_tbl;
 	struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache;
 	struct rkvdec_regs regs;
 };
 
-struct scaling_factor {
-	u8 scalingfactor0[1248];
-	u8 scalingfactor1[96];		/*4X4 TU Rotate, total 16X4*/
-	u8 scalingdc[12];		/*N1005 Vienna Meeting*/
-	u8 reserved[4];		/*16Bytes align*/
-};
-
 static void set_ps_field(u32 *buf, struct rkvdec_ps_field field, u32 value)
 {
 	u8 bit = field.offset % 32, word = field.offset / 32;
@@ -417,131 +398,6 @@ static void assemble_sw_rps(struct rkvdec_ctx *ctx,
 	}
 }
 
-/*
- * Flip one or more matrices along their main diagonal and flatten them
- * before writing it to the memory.
- * Convert:
- * ABCD         AEIM
- * EFGH     =>  BFJN     =>     AEIMBFJNCGKODHLP
- * IJKL         CGKO
- * MNOP         DHLP
- */
-static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
-					   int matrices, int row_length)
-{
-	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
-
-	matrix_size = row_length * row_length;
-	for (i = 0; i < matrices; i++) {
-		row = 0;
-		x_offset = 0;
-		matrix_offset = i * matrix_size;
-		for (j = 0; j < matrix_size; j++) {
-			y_offset = j - (row * row_length);
-			rot_index = y_offset * row_length + x_offset;
-			new_value = *(input + i * matrix_size + j);
-			output[matrix_offset + rot_index] = new_value;
-			if ((j + 1) % row_length == 0) {
-				row += 1;
-				x_offset += 1;
-			}
-		}
-	}
-}
-
-static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
-{
-	int offset = 0;
-
-	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
-	offset = 6 * 16 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
-	offset += 6 * 64 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset,
-				       (const u8 *)input->scaling_list_16x16, 6, 8);
-	offset += 6 * 64 * sizeof(u8);
-	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
-	transpose_and_flatten_matrices(output + offset,
-				       (const u8 *)input->scaling_list_32x32, 1, 8);
-	offset += 64 * sizeof(u8);
-	memset(output + offset, 0, 128);
-	offset += 128 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset,
-				       (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
-				       1, 8);
-	offset += 64 * sizeof(u8);
-	memset(output + offset, 0, 128);
-}
-
-/*
- * Required layout:
- * A = scaling_list_dc_coef_16x16
- * B = scaling_list_dc_coef_32x32
- * 0 = Padding
- *
- * A, A, A, A, A, A, B, 0, 0, B, 0, 0
- */
-static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
-{
-	u8 list_32x32[6] = {0};
-
-	memcpy(output, input->scaling_list_dc_coef_16x16, 6 * sizeof(u8));
-	list_32x32[0] = input->scaling_list_dc_coef_32x32[0];
-	list_32x32[3] = input->scaling_list_dc_coef_32x32[1];
-	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
-}
-
-static void translate_scaling_list(struct scaling_factor *output,
-				   const struct v4l2_ctrl_hevc_scaling_matrix *input)
-{
-	assemble_scalingfactor0(output->scalingfactor0, input);
-	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
-	assemble_scalingdc(output->scalingdc, input);
-	memset(output->reserved, 0, 4 * sizeof(u8));
-}
-
-static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
-				     struct rkvdec_hevc_run *run)
-{
-	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
-	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
-	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
-	u8 *dst;
-
-	if (!memcmp((void *)&hevc_ctx->scaling_matrix_cache, scaling,
-		    sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
-		return;
-
-	dst = tbl->scaling_list;
-	translate_scaling_list((struct scaling_factor *)dst, scaling);
-
-	memcpy((void *)&hevc_ctx->scaling_matrix_cache, scaling,
-	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
-}
-
-static struct vb2_buffer *
-get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
-	    unsigned int dpb_idx)
-{
-	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
-	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
-	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
-	struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
-	struct vb2_buffer *buf = NULL;
-
-	if (dpb_idx < decode_params->num_active_dpb_entries)
-		buf = vb2_find_buffer(cap_q, dpb[dpb_idx].timestamp);
-
-	/*
-	 * If a DPB entry is unused or invalid, the address of current destination
-	 * buffer is returned.
-	 */
-	if (!buf)
-		return &run->base.bufs.dst->vb2_buf;
-
-	return buf;
-}
-
 static void config_registers(struct rkvdec_ctx *ctx,
 			     struct rkvdec_hevc_run *run)
 {
@@ -644,63 +500,6 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));
 }
 
-#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
-
-static int rkvdec_hevc_adjust_fmt(struct rkvdec_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_HEVC_MAX_DEPTH_IN_BYTES;
-	return 0;
-}
-
-static enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
-						       struct v4l2_ctrl *ctrl)
-{
-	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
-
-	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
-		return RKVDEC_IMG_FMT_ANY;
-
-	if (sps->bit_depth_luma_minus8 == 0) {
-		if (sps->chroma_format_idc == 2)
-			return RKVDEC_IMG_FMT_422_8BIT;
-		else
-			return RKVDEC_IMG_FMT_420_8BIT;
-	} else if (sps->bit_depth_luma_minus8 == 2) {
-		if (sps->chroma_format_idc == 2)
-			return RKVDEC_IMG_FMT_422_10BIT;
-		else
-			return RKVDEC_IMG_FMT_420_10BIT;
-	}
-
-	return RKVDEC_IMG_FMT_ANY;
-}
-
-static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
-				    const struct v4l2_ctrl_hevc_sps *sps)
-{
-	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 && sps->bit_depth_luma_minus8 != 2)
-		/* Only 8-bit and 10-bit is supported */
-		return -EINVAL;
-
-	if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
-	    sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height)
-		return -EINVAL;
-
-	return 0;
-}
-
 static int rkvdec_hevc_start(struct rkvdec_ctx *ctx)
 {
 	struct rkvdec_dev *rkvdec = ctx->dev;
@@ -737,40 +536,18 @@ static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
 	kfree(hevc_ctx);
 }
 
-static void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
-				     struct rkvdec_hevc_run *run)
-{
-	struct v4l2_ctrl *ctrl;
-
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
-	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
-	run->slices_params = ctrl ? ctrl->p_cur.p : NULL;
-	run->num_slices = ctrl ? ctrl->new_elems : 0;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_SPS);
-	run->sps = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_PPS);
-	run->pps = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
-	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
-
-	rkvdec_run_preamble(ctx, &run->base);
-}
-
 static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 {
 	struct rkvdec_dev *rkvdec = ctx->dev;
 	struct rkvdec_hevc_run run;
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
 	u32 reg;
 
 	rkvdec_hevc_run_preamble(ctx, &run);
 
-	assemble_hw_scaling_list(ctx, &run);
+	rkvdec_hevc_assemble_hw_scaling_list(&run, &tbl->scaling_list,
+					     &hevc_ctx->scaling_matrix_cache);
 	assemble_hw_pps(ctx, &run);
 	assemble_sw_rps(ctx, &run);
 	config_registers(ctx, &run);
@@ -795,14 +572,6 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 	return 0;
 }
 
-static int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
-{
-	if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS)
-		return rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
-
-	return 0;
-}
-
 const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops = {
 	.adjust_fmt = rkvdec_hevc_adjust_fmt,
 	.start = rkvdec_hevc_start,
-- 
2.51.1.dirty
Re: [PATCH v4 07/15] media: rkvdec: Move hevc functions to common file
Posted by Nicolas Dufresne 2 months ago
Le mercredi 22 octobre 2025 à 13:44 -0400, Detlev Casanova a écrit :
> This is a preparation commit to add support for new variants of the
> decoder.
> 
> The functions will later be shared with vdpu381 (rk3588) and vdpu383
> (rk3576).
> 
> Tested-by: Diederik de Haas <didi.debian@cknow.org>  # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> ---
>  .../media/platform/rockchip/rkvdec/Makefile   |   1 +
>  .../rockchip/rkvdec/rkvdec-hevc-common.c      | 233 +++++++++++++++++
>  .../rockchip/rkvdec/rkvdec-hevc-common.h      |  51 ++++
>  .../platform/rockchip/rkvdec/rkvdec-hevc.c    | 243 +-----------------
>  4 files changed, 291 insertions(+), 237 deletions(-)
>  create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
>  create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index d2ba7a7c15e5..1b4bc44be23e 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -6,4 +6,5 @@ rockchip-vdec-y += \
>  		   rkvdec-h264.o \
>  		   rkvdec-h264-common.o \
>  		   rkvdec-hevc.o \
> +		   rkvdec-hevc-common.o \
>  		   rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> new file mode 100644
> index 000000000000..d571107f2242
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> @@ -0,0 +1,233 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Rockchip video decoder hevc common functions
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *      Detlev Casanova <detlev.casanova@collabora.com>
> + *
> + * Copyright (C) 2023 Collabora, Ltd.
> + *      Sebastian Fricke <sebastian.fricke@collabora.com>
> + *
> + * Copyright (C) 2019 Collabora, Ltd.
> + *	Boris Brezillon <boris.brezillon@collabora.com>
> + *
> + * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
> + *	Jeffy Chen <jeffy.chen@rock-chips.com>
> + */
> +
> +#include <linux/v4l2-common.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "rkvdec.h"
> +#include "rkvdec-hevc-common.h"
> +
> +/*
> + * Flip one or more matrices along their main diagonal and flatten them
> + * before writing it to the memory.
> + * Convert:
> + * ABCD         AEIM
> + * EFGH     =>  BFJN     =>     AEIMBFJNCGKODHLP
> + * IJKL         CGKO
> + * MNOP         DHLP
> + */
> +static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
> +					   int matrices, int row_length)
> +{
> +	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
> +
> +	matrix_size = row_length * row_length;
> +	for (i = 0; i < matrices; i++) {
> +		row = 0;
> +		x_offset = 0;
> +		matrix_offset = i * matrix_size;
> +		for (j = 0; j < matrix_size; j++) {
> +			y_offset = j - (row * row_length);
> +			rot_index = y_offset * row_length + x_offset;
> +			new_value = *(input + i * matrix_size + j);
> +			output[matrix_offset + rot_index] = new_value;
> +			if ((j + 1) % row_length == 0) {
> +				row += 1;
> +				x_offset += 1;
> +			}
> +		}
> +	}
> +}
> +
> +static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
> +{
> +	int offset = 0;
> +
> +	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
> +	offset = 6 * 16 * sizeof(u8);
> +	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
> +	offset += 6 * 64 * sizeof(u8);
> +	transpose_and_flatten_matrices(output + offset,
> +				       (const u8 *)input->scaling_list_16x16, 6, 8);
> +	offset += 6 * 64 * sizeof(u8);
> +	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
> +	transpose_and_flatten_matrices(output + offset,
> +				       (const u8 *)input->scaling_list_32x32, 1, 8);
> +	offset += 64 * sizeof(u8);
> +	memset(output + offset, 0, 128);
> +	offset += 128 * sizeof(u8);
> +	transpose_and_flatten_matrices(output + offset,
> +				       (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
> +				       1, 8);
> +	offset += 64 * sizeof(u8);
> +	memset(output + offset, 0, 128);
> +}
> +
> +/*
> + * Required layout:
> + * A = scaling_list_dc_coef_16x16
> + * B = scaling_list_dc_coef_32x32
> + * 0 = Padding
> + *
> + * A, A, A, A, A, A, B, 0, 0, B, 0, 0
> + */
> +static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
> +{
> +	u8 list_32x32[6] = {0};
> +
> +	memcpy(output, input->scaling_list_dc_coef_16x16, 6 * sizeof(u8));
> +	list_32x32[0] = input->scaling_list_dc_coef_32x32[0];
> +	list_32x32[3] = input->scaling_list_dc_coef_32x32[1];
> +	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
> +}
> +
> +static void translate_scaling_list(struct scaling_factor *output,
> +				   const struct v4l2_ctrl_hevc_scaling_matrix *input)
> +{
> +	assemble_scalingfactor0(output->scalingfactor0, input);
> +	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
> +	assemble_scalingdc(output->scalingdc, input);
> +	memset(output->reserved, 0, 4 * sizeof(u8));
> +}
> +
> +void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
> +					  struct scaling_factor *scaling_factor,
> +					  struct v4l2_ctrl_hevc_scaling_matrix *cache)
> +{
> +	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
> +
> +	if (!memcmp(cache, scaling,
> +		    sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
> +		return;
> +
> +	translate_scaling_list(scaling_factor, scaling);
> +
> +	memcpy(cache, scaling,
> +	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
> +}
> +
> +struct vb2_buffer *
> +get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
> +	    unsigned int dpb_idx)
> +{
> +	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
> +	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
> +	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
> +	struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
> +	struct vb2_buffer *buf = NULL;
> +
> +	if (dpb_idx < decode_params->num_active_dpb_entries)
> +		buf = vb2_find_buffer(cap_q, dpb[dpb_idx].timestamp);
> +
> +	/*
> +	 * If a DPB entry is unused or invalid, the address of current destination
> +	 * buffer is returned.
> +	 */
> +	if (!buf)
> +		return &run->base.bufs.dst->vb2_buf;
> +
> +	return buf;
> +}
> +
> +#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
> +
> +int rkvdec_hevc_adjust_fmt(struct rkvdec_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_HEVC_MAX_DEPTH_IN_BYTES;
> +	return 0;
> +}
> +
> +enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
> +						struct v4l2_ctrl *ctrl)
> +{
> +	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
> +
> +	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
> +		return RKVDEC_IMG_FMT_ANY;
> +
> +	if (sps->bit_depth_luma_minus8 == 0) {
> +		if (sps->chroma_format_idc == 2)
> +			return RKVDEC_IMG_FMT_422_8BIT;
> +		else
> +			return RKVDEC_IMG_FMT_420_8BIT;
> +	} else if (sps->bit_depth_luma_minus8 == 2) {
> +		if (sps->chroma_format_idc == 2)
> +			return RKVDEC_IMG_FMT_422_10BIT;
> +		else
> +			return RKVDEC_IMG_FMT_420_10BIT;
> +	}
> +
> +	return RKVDEC_IMG_FMT_ANY;
> +}
> +
> +static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
> +			     const struct v4l2_ctrl_hevc_sps *sps)
> +{
> +	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 && sps->bit_depth_luma_minus8 != 2)
> +		/* Only 8-bit and 10-bit are supported */
> +		return -EINVAL;
> +
> +	if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
> +	    sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
> +			      struct rkvdec_hevc_run *run)
> +{
> +	struct v4l2_ctrl *ctrl;
> +
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			      V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
> +	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			      V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
> +	run->slices_params = ctrl ? ctrl->p_cur.p : NULL;
> +	run->num_slices = ctrl ? ctrl->new_elems : 0;
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			      V4L2_CID_STATELESS_HEVC_SPS);
> +	run->sps = ctrl ? ctrl->p_cur.p : NULL;
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			      V4L2_CID_STATELESS_HEVC_PPS);
> +	run->pps = ctrl ? ctrl->p_cur.p : NULL;
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			      V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
> +	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
> +
> +	rkvdec_run_preamble(ctx, &run->base);
> +}
> +
> +int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
> +{
> +	if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS)
> +		return rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
> +
> +	return 0;
> +}
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> new file mode 100644
> index 000000000000..746b1bd73c08
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> @@ -0,0 +1,51 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Rockchip video decoder hevc common functions
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *      Detlev Casanova <detlev.casanova@collabora.com>
> + *
> + * Copyright (C) 2023 Collabora, Ltd.
> + *      Sebastian Fricke <sebastian.fricke@collabora.com>
> + *
> + * Copyright (C) 2019 Collabora, Ltd.
> + *	Boris Brezillon <boris.brezillon@collabora.com>
> + *
> + * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
> + *	Jeffy Chen <jeffy.chen@rock-chips.com>
> + */
> +
> +#include <media/v4l2-mem2mem.h>
> +#include "rkvdec.h"
> +
> +#define RKV_HEVC_CABAC_TABLE_SIZE		27456
> +extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
> +
> +struct rkvdec_hevc_run {
> +	struct rkvdec_run base;
> +	const struct v4l2_ctrl_hevc_slice_params *slices_params;
> +	const struct v4l2_ctrl_hevc_decode_params *decode_params;
> +	const struct v4l2_ctrl_hevc_sps *sps;
> +	const struct v4l2_ctrl_hevc_pps *pps;
> +	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
> +	int num_slices;
> +};
> +
> +struct scaling_factor {
> +	u8 scalingfactor0[1248];
> +	u8 scalingfactor1[96];	/*4X4 TU Rotate, total 16X4*/
> +	u8 scalingdc[12];	/*N1005 Vienna Meeting*/
> +	u8 reserved[4];		/*16Bytes align*/
> +};
> +
> +enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
> +						struct v4l2_ctrl *ctrl);
> +void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
> +					  struct scaling_factor *scaling_factor,
> +					  struct v4l2_ctrl_hevc_scaling_matrix *cache);
> +struct vb2_buffer *get_ref_buf(struct rkvdec_ctx *ctx,
> +			       struct rkvdec_hevc_run *run,
> +			       unsigned int dpb_idx);
> +int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f);
> +int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl);
> +void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run);
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> index b01c1bb52a04..31a979698578 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> @@ -16,6 +16,7 @@
>  
>  #include "rkvdec.h"
>  #include "rkvdec-regs.h"
> +#include "rkvdec-hevc-common.h"
>  
>  /* Size in u8/u32 units. */
>  #define RKV_SCALING_LIST_SIZE		1360
> @@ -24,9 +25,6 @@
>  #define RKV_RPS_SIZE			(32 / 4)
>  #define RKV_RPS_LEN			600
>  
> -#define RKV_HEVC_CABAC_TABLE_SIZE		27456
> -extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
> -
>  struct rkvdec_sps_pps_packet {
>  	u32 info[RKV_PPS_SIZE];
>  };
> @@ -113,34 +111,17 @@ struct rkvdec_ps_field {
>  /* Data structure describing auxiliary buffer format. */
>  struct rkvdec_hevc_priv_tbl {
>  	u8 cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
> -	u8 scaling_list[RKV_SCALING_LIST_SIZE];
> +	struct scaling_factor scaling_list;
>  	struct rkvdec_sps_pps_packet param_set[RKV_PPS_LEN];
>  	struct rkvdec_rps_packet rps[RKV_RPS_LEN];
>  };
>  
> -struct rkvdec_hevc_run {
> -	struct rkvdec_run base;
> -	const struct v4l2_ctrl_hevc_slice_params *slices_params;
> -	const struct v4l2_ctrl_hevc_decode_params *decode_params;
> -	const struct v4l2_ctrl_hevc_sps *sps;
> -	const struct v4l2_ctrl_hevc_pps *pps;
> -	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
> -	int num_slices;
> -};
> -
>  struct rkvdec_hevc_ctx {
>  	struct rkvdec_aux_buf priv_tbl;
>  	struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache;
>  	struct rkvdec_regs regs;
>  };
>  
> -struct scaling_factor {
> -	u8 scalingfactor0[1248];
> -	u8 scalingfactor1[96];		/*4X4 TU Rotate, total 16X4*/
> -	u8 scalingdc[12];		/*N1005 Vienna Meeting*/
> -	u8 reserved[4];		/*16Bytes align*/
> -};
> -
>  static void set_ps_field(u32 *buf, struct rkvdec_ps_field field, u32 value)
>  {
>  	u8 bit = field.offset % 32, word = field.offset / 32;
> @@ -417,131 +398,6 @@ static void assemble_sw_rps(struct rkvdec_ctx *ctx,
>  	}
>  }
>  
> -/*
> - * Flip one or more matrices along their main diagonal and flatten them
> - * before writing it to the memory.
> - * Convert:
> - * ABCD         AEIM
> - * EFGH     =>  BFJN     =>     AEIMBFJNCGKODHLP
> - * IJKL         CGKO
> - * MNOP         DHLP
> - */
> -static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
> -					   int matrices, int row_length)
> -{
> -	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
> -
> -	matrix_size = row_length * row_length;
> -	for (i = 0; i < matrices; i++) {
> -		row = 0;
> -		x_offset = 0;
> -		matrix_offset = i * matrix_size;
> -		for (j = 0; j < matrix_size; j++) {
> -			y_offset = j - (row * row_length);
> -			rot_index = y_offset * row_length + x_offset;
> -			new_value = *(input + i * matrix_size + j);
> -			output[matrix_offset + rot_index] = new_value;
> -			if ((j + 1) % row_length == 0) {
> -				row += 1;
> -				x_offset += 1;
> -			}
> -		}
> -	}
> -}
> -
> -static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
> -{
> -	int offset = 0;
> -
> -	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
> -	offset = 6 * 16 * sizeof(u8);
> -	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
> -	offset += 6 * 64 * sizeof(u8);
> -	transpose_and_flatten_matrices(output + offset,
> -				       (const u8 *)input->scaling_list_16x16, 6, 8);
> -	offset += 6 * 64 * sizeof(u8);
> -	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
> -	transpose_and_flatten_matrices(output + offset,
> -				       (const u8 *)input->scaling_list_32x32, 1, 8);
> -	offset += 64 * sizeof(u8);
> -	memset(output + offset, 0, 128);
> -	offset += 128 * sizeof(u8);
> -	transpose_and_flatten_matrices(output + offset,
> -				       (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
> -				       1, 8);
> -	offset += 64 * sizeof(u8);
> -	memset(output + offset, 0, 128);
> -}
> -
> -/*
> - * Required layout:
> - * A = scaling_list_dc_coef_16x16
> - * B = scaling_list_dc_coef_32x32
> - * 0 = Padding
> - *
> - * A, A, A, A, A, A, B, 0, 0, B, 0, 0
> - */
> -static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
> -{
> -	u8 list_32x32[6] = {0};
> -
> -	memcpy(output, input->scaling_list_dc_coef_16x16, 6 * sizeof(u8));
> -	list_32x32[0] = input->scaling_list_dc_coef_32x32[0];
> -	list_32x32[3] = input->scaling_list_dc_coef_32x32[1];
> -	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
> -}
> -
> -static void translate_scaling_list(struct scaling_factor *output,
> -				   const struct v4l2_ctrl_hevc_scaling_matrix *input)
> -{
> -	assemble_scalingfactor0(output->scalingfactor0, input);
> -	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
> -	assemble_scalingdc(output->scalingdc, input);
> -	memset(output->reserved, 0, 4 * sizeof(u8));
> -}
> -
> -static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
> -				     struct rkvdec_hevc_run *run)
> -{
> -	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
> -	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> -	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
> -	u8 *dst;
> -
> -	if (!memcmp((void *)&hevc_ctx->scaling_matrix_cache, scaling,
> -		    sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
> -		return;
> -
> -	dst = tbl->scaling_list;
> -	translate_scaling_list((struct scaling_factor *)dst, scaling);
> -
> -	memcpy((void *)&hevc_ctx->scaling_matrix_cache, scaling,
> -	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
> -}
> -
> -static struct vb2_buffer *
> -get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
> -	    unsigned int dpb_idx)
> -{
> -	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
> -	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
> -	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
> -	struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
> -	struct vb2_buffer *buf = NULL;
> -
> -	if (dpb_idx < decode_params->num_active_dpb_entries)
> -		buf = vb2_find_buffer(cap_q, dpb[dpb_idx].timestamp);
> -
> -	/*
> -	 * If a DPB entry is unused or invalid, the address of current destination
> -	 * buffer is returned.
> -	 */
> -	if (!buf)
> -		return &run->base.bufs.dst->vb2_buf;
> -
> -	return buf;
> -}
> -
>  static void config_registers(struct rkvdec_ctx *ctx,
>  			     struct rkvdec_hevc_run *run)
>  {
> @@ -644,63 +500,6 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));
>  }
>  
> -#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
> -
> -static int rkvdec_hevc_adjust_fmt(struct rkvdec_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_HEVC_MAX_DEPTH_IN_BYTES;
> -	return 0;
> -}
> -
> -static enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
> -						       struct v4l2_ctrl *ctrl)
> -{
> -	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
> -
> -	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
> -		return RKVDEC_IMG_FMT_ANY;
> -
> -	if (sps->bit_depth_luma_minus8 == 0) {
> -		if (sps->chroma_format_idc == 2)
> -			return RKVDEC_IMG_FMT_422_8BIT;
> -		else
> -			return RKVDEC_IMG_FMT_420_8BIT;
> -	} else if (sps->bit_depth_luma_minus8 == 2) {
> -		if (sps->chroma_format_idc == 2)
> -			return RKVDEC_IMG_FMT_422_10BIT;
> -		else
> -			return RKVDEC_IMG_FMT_420_10BIT;
> -	}
> -
> -	return RKVDEC_IMG_FMT_ANY;
> -}
> -
> -static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
> -				    const struct v4l2_ctrl_hevc_sps *sps)
> -{
> -	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 && sps->bit_depth_luma_minus8 != 2)
> -		/* Only 8-bit and 10-bit is supported */
> -		return -EINVAL;
> -
> -	if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
> -	    sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height)
> -		return -EINVAL;
> -
> -	return 0;
> -}
> -
>  static int rkvdec_hevc_start(struct rkvdec_ctx *ctx)
>  {
>  	struct rkvdec_dev *rkvdec = ctx->dev;
> @@ -737,40 +536,18 @@ static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
>  	kfree(hevc_ctx);
>  }
>  
> -static void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
> -				     struct rkvdec_hevc_run *run)
> -{
> -	struct v4l2_ctrl *ctrl;
> -
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			      V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
> -	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			      V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
> -	run->slices_params = ctrl ? ctrl->p_cur.p : NULL;
> -	run->num_slices = ctrl ? ctrl->new_elems : 0;
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			      V4L2_CID_STATELESS_HEVC_SPS);
> -	run->sps = ctrl ? ctrl->p_cur.p : NULL;
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			      V4L2_CID_STATELESS_HEVC_PPS);
> -	run->pps = ctrl ? ctrl->p_cur.p : NULL;
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			      V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
> -	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
> -
> -	rkvdec_run_preamble(ctx, &run->base);
> -}
> -
>  static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
>  {
>  	struct rkvdec_dev *rkvdec = ctx->dev;
>  	struct rkvdec_hevc_run run;
> +	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
>  	u32 reg;
>  
>  	rkvdec_hevc_run_preamble(ctx, &run);
>  
> -	assemble_hw_scaling_list(ctx, &run);
> +	rkvdec_hevc_assemble_hw_scaling_list(&run, &tbl->scaling_list,
> +					     &hevc_ctx->scaling_matrix_cache);
>  	assemble_hw_pps(ctx, &run);
>  	assemble_sw_rps(ctx, &run);
>  	config_registers(ctx, &run);
> @@ -795,14 +572,6 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
>  	return 0;
>  }
>  
> -static int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
> -{
> -	if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS)
> -		return rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
> -
> -	return 0;
> -}
> -
>  const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops = {
>  	.adjust_fmt = rkvdec_hevc_adjust_fmt,
>  	.start = rkvdec_hevc_start,
Re: [PATCH v4 07/15] media: rkvdec: Move hevc functions to common file
Posted by Jonas Karlman 3 months, 2 weeks ago
Hi Detlev,

On 10/22/2025 7:44 PM, Detlev Casanova wrote:
> This is a preparation commit to add support for new variants of the
> decoder.
> 
> The functions will later be shared with vdpu381 (rk3588) and vdpu383
> (rk3576).
> 
> Tested-by: Diederik de Haas <didi.debian@cknow.org>  # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
> ---
>  .../media/platform/rockchip/rkvdec/Makefile   |   1 +
>  .../rockchip/rkvdec/rkvdec-hevc-common.c      | 233 +++++++++++++++++
>  .../rockchip/rkvdec/rkvdec-hevc-common.h      |  51 ++++
>  .../platform/rockchip/rkvdec/rkvdec-hevc.c    | 243 +-----------------
>  4 files changed, 291 insertions(+), 237 deletions(-)
>  create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
>  create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index d2ba7a7c15e5..1b4bc44be23e 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -6,4 +6,5 @@ rockchip-vdec-y += \
>  		   rkvdec-h264.o \
>  		   rkvdec-h264-common.o \
>  		   rkvdec-hevc.o \
> +		   rkvdec-hevc-common.o \
>  		   rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> new file mode 100644
> index 000000000000..d571107f2242
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> @@ -0,0 +1,233 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Rockchip video decoder hevc common functions
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *      Detlev Casanova <detlev.casanova@collabora.com>
> + *
> + * Copyright (C) 2023 Collabora, Ltd.
> + *      Sebastian Fricke <sebastian.fricke@collabora.com>
> + *
> + * Copyright (C) 2019 Collabora, Ltd.
> + *	Boris Brezillon <boris.brezillon@collabora.com>
> + *
> + * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
> + *	Jeffy Chen <jeffy.chen@rock-chips.com>
> + */
> +
> +#include <linux/v4l2-common.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "rkvdec.h"
> +#include "rkvdec-hevc-common.h"
> +
> +/*
> + * Flip one or more matrices along their main diagonal and flatten them
> + * before writing it to the memory.
> + * Convert:
> + * ABCD         AEIM
> + * EFGH     =>  BFJN     =>     AEIMBFJNCGKODHLP
> + * IJKL         CGKO
> + * MNOP         DHLP
> + */
> +static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
> +					   int matrices, int row_length)
> +{
> +	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
> +
> +	matrix_size = row_length * row_length;
> +	for (i = 0; i < matrices; i++) {
> +		row = 0;
> +		x_offset = 0;
> +		matrix_offset = i * matrix_size;
> +		for (j = 0; j < matrix_size; j++) {
> +			y_offset = j - (row * row_length);
> +			rot_index = y_offset * row_length + x_offset;
> +			new_value = *(input + i * matrix_size + j);
> +			output[matrix_offset + rot_index] = new_value;
> +			if ((j + 1) % row_length == 0) {
> +				row += 1;
> +				x_offset += 1;
> +			}
> +		}
> +	}
> +}
> +
> +static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
> +{
> +	int offset = 0;
> +
> +	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
> +	offset = 6 * 16 * sizeof(u8);
> +	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
> +	offset += 6 * 64 * sizeof(u8);
> +	transpose_and_flatten_matrices(output + offset,
> +				       (const u8 *)input->scaling_list_16x16, 6, 8);
> +	offset += 6 * 64 * sizeof(u8);
> +	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
> +	transpose_and_flatten_matrices(output + offset,
> +				       (const u8 *)input->scaling_list_32x32, 1, 8);
> +	offset += 64 * sizeof(u8);
> +	memset(output + offset, 0, 128);
> +	offset += 128 * sizeof(u8);
> +	transpose_and_flatten_matrices(output + offset,
> +				       (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
> +				       1, 8);
> +	offset += 64 * sizeof(u8);
> +	memset(output + offset, 0, 128);
> +}
> +
> +/*
> + * Required layout:
> + * A = scaling_list_dc_coef_16x16
> + * B = scaling_list_dc_coef_32x32
> + * 0 = Padding
> + *
> + * A, A, A, A, A, A, B, 0, 0, B, 0, 0
> + */
> +static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
> +{
> +	u8 list_32x32[6] = {0};
> +
> +	memcpy(output, input->scaling_list_dc_coef_16x16, 6 * sizeof(u8));
> +	list_32x32[0] = input->scaling_list_dc_coef_32x32[0];
> +	list_32x32[3] = input->scaling_list_dc_coef_32x32[1];
> +	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
> +}
> +
> +static void translate_scaling_list(struct scaling_factor *output,
> +				   const struct v4l2_ctrl_hevc_scaling_matrix *input)
> +{
> +	assemble_scalingfactor0(output->scalingfactor0, input);
> +	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
> +	assemble_scalingdc(output->scalingdc, input);
> +	memset(output->reserved, 0, 4 * sizeof(u8));
> +}
> +
> +void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
> +					  struct scaling_factor *scaling_factor,
> +					  struct v4l2_ctrl_hevc_scaling_matrix *cache)
> +{
> +	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
> +
> +	if (!memcmp(cache, scaling,
> +		    sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
> +		return;
> +
> +	translate_scaling_list(scaling_factor, scaling);
> +
> +	memcpy(cache, scaling,
> +	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
> +}
> +
> +struct vb2_buffer *
> +get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
> +	    unsigned int dpb_idx)
> +{
> +	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
> +	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
> +	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
> +	struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
> +	struct vb2_buffer *buf = NULL;
> +
> +	if (dpb_idx < decode_params->num_active_dpb_entries)
> +		buf = vb2_find_buffer(cap_q, dpb[dpb_idx].timestamp);
> +
> +	/*
> +	 * If a DPB entry is unused or invalid, the address of current destination
> +	 * buffer is returned.
> +	 */
> +	if (!buf)
> +		return &run->base.bufs.dst->vb2_buf;
> +
> +	return buf;
> +}
> +
> +#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
> +
> +int rkvdec_hevc_adjust_fmt(struct rkvdec_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_HEVC_MAX_DEPTH_IN_BYTES;
> +	return 0;
> +}
> +
> +enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
> +						struct v4l2_ctrl *ctrl)
> +{
> +	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
> +
> +	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
> +		return RKVDEC_IMG_FMT_ANY;
> +
> +	if (sps->bit_depth_luma_minus8 == 0) {
> +		if (sps->chroma_format_idc == 2)
> +			return RKVDEC_IMG_FMT_422_8BIT;
> +		else
> +			return RKVDEC_IMG_FMT_420_8BIT;
> +	} else if (sps->bit_depth_luma_minus8 == 2) {
> +		if (sps->chroma_format_idc == 2)
> +			return RKVDEC_IMG_FMT_422_10BIT;
> +		else
> +			return RKVDEC_IMG_FMT_420_10BIT;
> +	}
> +
> +	return RKVDEC_IMG_FMT_ANY;
> +}

This function is moved here in this patch, and then later rewritten and
moved once more in a later patch. Please move the functions to final
position in this patch and do not rewrite the function in a later patch.

Regards,
Jonas

[snip]