mirror of
https://github.com/LibreELEC/LibreELEC.tv
synced 2025-09-24 19:46:01 +07:00
617 lines
20 KiB
Diff
617 lines
20 KiB
Diff
From 64bf8c3a0864e3965fd98cac14c2ef78a378487e Mon Sep 17 00:00:00 2001
|
|
From: Detlev Casanova <detlev.casanova@collabora.com>
|
|
Date: Fri, 15 Aug 2025 17:24:37 -0400
|
|
Subject: [PATCH 071/110] DETLEV(v3): media: rkvdec: Move hevc functions to
|
|
common file
|
|
|
|
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).
|
|
|
|
Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
|
|
---
|
|
.../rockchip/rkvdec/rkvdec-hevc-common.c | 230 +++++++++++++++++
|
|
.../rockchip/rkvdec/rkvdec-hevc-common.h | 46 ++++
|
|
.../platform/rockchip/rkvdec/rkvdec-hevc.c | 240 +-----------------
|
|
3 files changed, 282 insertions(+), 234 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/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
|
|
new file mode 100644
|
|
index 000000000000..6fd3b703ac11
|
|
--- /dev/null
|
|
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
|
|
@@ -0,0 +1,230 @@
|
|
+// 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 "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 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 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;
|
|
+}
|
|
+
|
|
+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..bebab62a861e
|
|
--- /dev/null
|
|
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
|
|
@@ -0,0 +1,46 @@
|
|
+/* 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>
|
|
+ */
|
|
+
|
|
+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_validate_sps(struct rkvdec_ctx *ctx, const struct v4l2_ctrl_hevc_sps *sps);
|
|
+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 e8b8b7bc6cdc..887b6c165a7e 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
|
|
@@ -113,34 +114,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 +401,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)
|
|
{
|
|
@@ -645,63 +504,6 @@ static void config_registers(struct rkvdec_ctx *ctx,
|
|
rkvdec_memcpy_toio(rkvdec->regs, regs, sizeof(*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;
|
|
@@ -738,40 +540,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);
|
|
@@ -796,14 +576,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.34.1
|
|
|