build/patch/kernel/sunxi-current/0622-media-cedrus-improvements.patch
Igor Pečovnik fc23107e1c
[Allwinner] Add analogue audio to H6, enable Cedrus (#1750)
* [Allwinner] Add analogue audio to H6, enable Cedrus, remove deprecated patches, adjust config
* Cleanup
2020-01-19 00:03:54 +01:00

1395 lines
51 KiB
Diff

From 4d25b2ae236bf42f5f9ef1d57cbc2523222a4422 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 26 Oct 2019 13:55:15 +0200
Subject: [PATCH 04/14] media: uapi: hevc: Add scaling matrix control
HEVC has a scaling matrix concept. Add support for it.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../media/uapi/v4l/ext-ctrls-codec.rst | 41 +++++++++++++++++++
.../media/uapi/v4l/pixfmt-compressed.rst | 1 +
drivers/media/v4l2-core/v4l2-ctrls.c | 10 +++++
include/media/hevc-ctrls.h | 11 +++++
4 files changed, 63 insertions(+)
diff --git a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst
index a1209f68c5e8..382e85e16444 100644
--- a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst
+++ b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst
@@ -4176,6 +4176,47 @@ enum v4l2_mpeg_video_hevc_size_of_length_field -
- ``padding[6]``
- Applications and drivers must set this to zero.
+``V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (struct)``
+ Specifies the scaling matrix (as extracted from the bitstream) for
+ the associated HEVC slice data. The bitstream parameters are
+ defined according to :ref:`hevc`, section 7.4.5 "Scaling list
+ data semantics". For further documentation, refer to the above
+ specification, unless there is an explicit comment stating
+ otherwise.
+
+ .. note::
+
+ This compound control is not yet part of the public kernel API and
+ it is expected to change.
+
+.. c:type:: v4l2_ctrl_hevc_scaling_matrix
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_ctrl_hevc_scaling_matrix
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 1 2
+
+ * - __u8
+ - ``scaling_list_4x4[6][16]``
+ -
+ * - __u8
+ - ``scaling_list_8x8[6][64]``
+ -
+ * - __u8
+ - ``scaling_list_16x16[6][64]``
+ -
+ * - __u8
+ - ``scaling_list_32x32[2][64]``
+ -
+ * - __u8
+ - ``scaling_list_dc_coef_16x16[6]``
+ -
+ * - __u8
+ - ``scaling_list_dc_coef_32x32[2]``
+ -
+
``V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (enum)``
Specifies the decoding mode to use. Currently exposes slice-based and
frame-based decoding but new modes might be added later on.
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index b4caf2d4d076..2803165cbc6a 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -975,6 +975,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_HEVC_SPS: return "HEVC Sequence Parameter Set";
case V4L2_CID_MPEG_VIDEO_HEVC_PPS: return "HEVC Picture Parameter Set";
case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters";
+ case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX: return "HEVC Scaling Matrix";
case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: return "HEVC Decode Mode";
case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return "HEVC Start Code";
@@ -1407,6 +1408,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS:
*type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS;
break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX:
+ *type = V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX;
+ break;
case V4L2_CID_UNIT_CELL_SIZE:
*type = V4L2_CTRL_TYPE_AREA;
*flags |= V4L2_CTRL_FLAG_READ_ONLY;
@@ -1856,6 +1860,9 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
zero_padding(*p_hevc_slice_params);
break;
+ case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
+ break;
+
case V4L2_CTRL_TYPE_AREA:
area = p;
if (!area->width || !area->height)
@@ -2545,6 +2552,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params);
break;
+ case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
+ elem_size = sizeof(struct v4l2_ctrl_hevc_scaling_matrix);
+ break;
case V4L2_CTRL_TYPE_AREA:
elem_size = sizeof(struct v4l2_area);
break;
diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h
index 1009cf0891cc..1592e52c3614 100644
--- a/include/media/hevc-ctrls.h
+++ b/include/media/hevc-ctrls.h
@@ -19,6 +19,7 @@
#define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_MPEG_BASE + 1008)
#define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_MPEG_BASE + 1009)
#define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_MPEG_BASE + 1010)
+#define V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (V4L2_CID_MPEG_BASE + 1011)
#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (V4L2_CID_MPEG_BASE + 1015)
#define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (V4L2_CID_MPEG_BASE + 1016)
@@ -26,6 +27,7 @@
#define V4L2_CTRL_TYPE_HEVC_SPS 0x0120
#define V4L2_CTRL_TYPE_HEVC_PPS 0x0121
#define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122
+#define V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX 0x0123
enum v4l2_mpeg_video_hevc_decode_mode {
V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
@@ -209,4 +211,13 @@ struct v4l2_ctrl_hevc_slice_params {
__u64 flags;
};
+struct v4l2_ctrl_hevc_scaling_matrix {
+ __u8 scaling_list_4x4[6][16];
+ __u8 scaling_list_8x8[6][64];
+ __u8 scaling_list_16x16[6][64];
+ __u8 scaling_list_32x32[2][64];
+ __u8 scaling_list_dc_coef_16x16[6];
+ __u8 scaling_list_dc_coef_32x32[2];
+};
+
#endif
--
2.24.0
From 000a33e20cc53fa82e3bc116d411135e93d5ab95 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 26 Oct 2019 13:58:49 +0200
Subject: [PATCH 05/14] media: cedrus: hevc: Add support for scaling matrix
HEVC frames may use scaling list feature. Add support for it.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus.c | 7 ++
drivers/staging/media/sunxi/cedrus/cedrus.h | 1 +
.../staging/media/sunxi/cedrus/cedrus_dec.c | 2 +
.../staging/media/sunxi/cedrus/cedrus_h265.c | 70 ++++++++++++++++++-
.../staging/media/sunxi/cedrus/cedrus_regs.h | 2 +
5 files changed, 81 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
index c6ddd46eff82..bf68bc6b20c8 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -116,6 +116,13 @@ static const struct cedrus_control cedrus_controls[] = {
.codec = CEDRUS_CODEC_H265,
.required = true,
},
+ {
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX,
+ },
+ .codec = CEDRUS_CODEC_H265,
+ .required = true,
+ },
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE,
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index 96765555ab8a..d945f4f0ff2d 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -73,6 +73,7 @@ struct cedrus_h265_run {
const struct v4l2_ctrl_hevc_sps *sps;
const struct v4l2_ctrl_hevc_pps *pps;
const struct v4l2_ctrl_hevc_slice_params *slice_params;
+ const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
};
struct cedrus_run {
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
index 4a2fc33a1d79..327ed6c264dc 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
@@ -66,6 +66,8 @@ void cedrus_device_run(void *priv)
V4L2_CID_MPEG_VIDEO_HEVC_PPS);
run.h265.slice_params = cedrus_find_control_data(ctx,
V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS);
+ run.h265.scaling_matrix = cedrus_find_control_data(ctx,
+ V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX);
break;
default:
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
index 6945dc74e1d7..888bfd5ca224 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -220,6 +220,69 @@ static void cedrus_h265_pred_weight_write(struct cedrus_dev *dev,
}
}
+static void cedrus_h265_write_scaling_list(struct cedrus_ctx *ctx,
+ struct cedrus_run *run)
+{
+ const struct v4l2_ctrl_hevc_scaling_matrix *scaling;
+ struct cedrus_dev *dev = ctx->dev;
+ u32 i, j, k, val;
+
+ scaling = run->h265.scaling_matrix;
+
+ cedrus_write(dev, VE_DEC_H265_SCALING_LIST_DC_COEF0,
+ (scaling->scaling_list_dc_coef_32x32[1] << 24) |
+ (scaling->scaling_list_dc_coef_32x32[0] << 16) |
+ (scaling->scaling_list_dc_coef_16x16[1] << 8) |
+ (scaling->scaling_list_dc_coef_16x16[0] << 0));
+
+ cedrus_write(dev, VE_DEC_H265_SCALING_LIST_DC_COEF1,
+ (scaling->scaling_list_dc_coef_16x16[5] << 24) |
+ (scaling->scaling_list_dc_coef_16x16[4] << 16) |
+ (scaling->scaling_list_dc_coef_16x16[3] << 8) |
+ (scaling->scaling_list_dc_coef_16x16[2] << 0));
+
+ cedrus_h265_sram_write_offset(dev, VE_DEC_H265_SRAM_OFFSET_SCALING_LISTS);
+
+ for (i = 0; i < 6; i++)
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 8; k += 4) {
+ val = ((u32)scaling->scaling_list_8x8[i][j + (k + 3) * 8] << 24) |
+ ((u32)scaling->scaling_list_8x8[i][j + (k + 2) * 8] << 16) |
+ ((u32)scaling->scaling_list_8x8[i][j + (k + 1) * 8] << 8) |
+ scaling->scaling_list_8x8[i][j + k * 8];
+ cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val);
+ }
+
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 8; k += 4) {
+ val = ((u32)scaling->scaling_list_32x32[i][j + (k + 3) * 8] << 24) |
+ ((u32)scaling->scaling_list_32x32[i][j + (k + 2) * 8] << 16) |
+ ((u32)scaling->scaling_list_32x32[i][j + (k + 1) * 8] << 8) |
+ scaling->scaling_list_32x32[i][j + k * 8];
+ cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val);
+ }
+
+ for (i = 0; i < 6; i++)
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 8; k += 4) {
+ val = ((u32)scaling->scaling_list_16x16[i][j + (k + 3) * 8] << 24) |
+ ((u32)scaling->scaling_list_16x16[i][j + (k + 2) * 8] << 16) |
+ ((u32)scaling->scaling_list_16x16[i][j + (k + 1) * 8] << 8) |
+ scaling->scaling_list_16x16[i][j + k * 8];
+ cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val);
+ }
+
+ for (i = 0; i < 6; i++)
+ for (j = 0; j < 4; j++) {
+ val = ((u32)scaling->scaling_list_4x4[i][j + 12] << 24) |
+ ((u32)scaling->scaling_list_4x4[i][j + 8] << 16) |
+ ((u32)scaling->scaling_list_4x4[i][j + 4] << 8) |
+ scaling->scaling_list_4x4[i][j];
+ cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val);
+ }
+}
+
static void cedrus_h265_setup(struct cedrus_ctx *ctx,
struct cedrus_run *run)
{
@@ -499,7 +562,12 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
/* Scaling list. */
- reg = VE_DEC_H265_SCALING_LIST_CTRL0_DEFAULT;
+ if (sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED) {
+ cedrus_h265_write_scaling_list(ctx, run);
+ reg = VE_DEC_H265_SCALING_LIST_CTRL0_FLAG_ENABLED;
+ } else {
+ reg = VE_DEC_H265_SCALING_LIST_CTRL0_DEFAULT;
+ }
cedrus_write(dev, VE_DEC_H265_SCALING_LIST_CTRL0, reg);
/* Neightbor information address. */
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
index 7beb03d3bb39..0d9449fe2b28 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
@@ -492,6 +492,8 @@
#define VE_DEC_H265_ENTRY_POINT_OFFSET_ADDR (VE_ENGINE_DEC_H265 + 0x64)
#define VE_DEC_H265_TILE_START_CTB (VE_ENGINE_DEC_H265 + 0x68)
#define VE_DEC_H265_TILE_END_CTB (VE_ENGINE_DEC_H265 + 0x6c)
+#define VE_DEC_H265_SCALING_LIST_DC_COEF0 (VE_ENGINE_DEC_H265 + 0x78)
+#define VE_DEC_H265_SCALING_LIST_DC_COEF1 (VE_ENGINE_DEC_H265 + 0x7c)
#define VE_DEC_H265_LOW_ADDR (VE_ENGINE_DEC_H265 + 0x80)
--
2.24.0
From 48f70ba58e4df3bd9b9cb9c7969ba93f95e25e75 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 26 Oct 2019 15:42:28 +0200
Subject: [PATCH 06/14] media: uapi: hevc: Add segment address field
If HEVC frame consists of multiple slices, segment address has to be
known in order to properly decode it.
Add segment address field to slice parameters.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
Documentation/media/uapi/v4l/ext-ctrls-codec.rst | 5 ++++-
include/media/hevc-ctrls.h | 5 ++++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst
index 382e85e16444..99e4a7099614 100644
--- a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst
+++ b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst
@@ -3971,6 +3971,9 @@ enum v4l2_mpeg_video_hevc_size_of_length_field -
* - __u32
- ``data_bit_offset``
- Offset (in bits) to the video data in the current slice data.
+ * - __u32
+ - ``slice_segment_addr``
+ -
* - __u8
- ``nal_unit_type``
-
@@ -4048,7 +4051,7 @@ enum v4l2_mpeg_video_hevc_size_of_length_field -
- ``num_rps_poc_lt_curr``
- The number of reference pictures in the long-term set.
* - __u8
- - ``padding[7]``
+ - ``padding[5]``
- Applications and drivers must set this to zero.
* - struct :c:type:`v4l2_hevc_dpb_entry`
- ``dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h
index 1592e52c3614..3e2e32098312 100644
--- a/include/media/hevc-ctrls.h
+++ b/include/media/hevc-ctrls.h
@@ -167,6 +167,9 @@ struct v4l2_ctrl_hevc_slice_params {
__u32 bit_size;
__u32 data_bit_offset;
+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
+ __u32 slice_segment_addr;
+
/* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */
__u8 nal_unit_type;
__u8 nuh_temporal_id_plus1;
@@ -200,7 +203,7 @@ struct v4l2_ctrl_hevc_slice_params {
__u8 num_rps_poc_st_curr_after;
__u8 num_rps_poc_lt_curr;
- __u8 padding;
+ __u8 padding[5];
/* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
--
2.24.0
From 468a7019d3475a6dbdf368519c75f9e6625f2a1a Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 26 Oct 2019 15:44:15 +0200
Subject: [PATCH 07/14] media: cedrus: hevc: Add support for multiple slices
Now that segment address is available, support for multi-slice frames
can be easily added.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../staging/media/sunxi/cedrus/cedrus_h265.c | 26 ++++++++++++-------
.../staging/media/sunxi/cedrus/cedrus_video.c | 1 +
2 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
index 888bfd5ca224..109d3289418c 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -291,6 +291,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
const struct v4l2_ctrl_hevc_pps *pps;
const struct v4l2_ctrl_hevc_slice_params *slice_params;
const struct v4l2_hevc_pred_weight_table *pred_weight_table;
+ unsigned int width_in_ctb_luma, ctb_size_luma;
+ unsigned int log2_max_luma_coding_block_size;
dma_addr_t src_buf_addr;
dma_addr_t src_buf_end_addr;
u32 chroma_log2_weight_denom;
@@ -303,15 +305,17 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
slice_params = run->h265.slice_params;
pred_weight_table = &slice_params->pred_weight_table;
+ log2_max_luma_coding_block_size =
+ sps->log2_min_luma_coding_block_size_minus3 + 3 +
+ sps->log2_diff_max_min_luma_coding_block_size;
+ ctb_size_luma = 1UL << log2_max_luma_coding_block_size;
+ width_in_ctb_luma =
+ DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_luma);
+
/* MV column buffer size and allocation. */
if (!ctx->codec.h265.mv_col_buf_size) {
unsigned int num_buffers =
run->dst->vb2_buf.vb2_queue->num_buffers;
- unsigned int log2_max_luma_coding_block_size =
- sps->log2_min_luma_coding_block_size_minus3 + 3 +
- sps->log2_diff_max_min_luma_coding_block_size;
- unsigned int ctb_size_luma =
- 1UL << log2_max_luma_coding_block_size;
/*
* Each CTB requires a MV col buffer with a specific unit size.
@@ -366,15 +370,17 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
reg = VE_DEC_H265_BITS_END_ADDR_BASE(src_buf_end_addr);
cedrus_write(dev, VE_DEC_H265_BITS_END_ADDR, reg);
- /* Coding tree block address: start at the beginning. */
- reg = VE_DEC_H265_DEC_CTB_ADDR_X(0) | VE_DEC_H265_DEC_CTB_ADDR_Y(0);
+ /* Coding tree block address */
+ reg = VE_DEC_H265_DEC_CTB_ADDR_X(slice_params->slice_segment_addr % width_in_ctb_luma);
+ reg |= VE_DEC_H265_DEC_CTB_ADDR_Y(slice_params->slice_segment_addr / width_in_ctb_luma);
cedrus_write(dev, VE_DEC_H265_DEC_CTB_ADDR, reg);
cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, 0);
cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, 0);
/* Clear the number of correctly-decoded coding tree blocks. */
- cedrus_write(dev, VE_DEC_H265_DEC_CTB_NUM, 0);
+ if (ctx->fh.m2m_ctx->new_frame)
+ cedrus_write(dev, VE_DEC_H265_DEC_CTB_NUM, 0);
/* Initialize bitstream access. */
cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_INIT_SWDEC);
@@ -523,8 +529,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT,
pps->flags);
- /* FIXME: For multi-slice support. */
- reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC;
+ if (ctx->fh.m2m_ctx->new_frame)
+ reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC;
cedrus_write(dev, VE_DEC_H265_DEC_SLICE_HDR_INFO0, reg);
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
index 15cf1f10221b..497b1199d3fe 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -311,6 +311,7 @@ static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
switch (ctx->src_fmt.pixelformat) {
case V4L2_PIX_FMT_H264_SLICE:
+ case V4L2_PIX_FMT_HEVC_SLICE:
vq->subsystem_flags |=
VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
break;
--
2.24.0
From 3be57e9b0d05bbe59aa60eb037d46b523a8a4103 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sun, 3 Nov 2019 12:36:52 +0100
Subject: [PATCH 08/14] media: cedrus: Fix decoding for some HEVC videos
It seems that for some HEVC videos at least one bitstream parsing
trigger must be called in order to be decoded correctly. There is no
explanation why this helps, but it was observed that several videos
with this fix are now decoded correctly and there is no regression with
others.
Without this fix, those same videos totaly crash HEVC decoder (others
are unaffected). After decoding those problematic videos, HEVC decoder
always returns only green image (all zeros). Only complete HW reset
helps.
This fix is similar to that for H264.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../staging/media/sunxi/cedrus/cedrus_h265.c | 25 ++++++++++++++++---
.../staging/media/sunxi/cedrus/cedrus_regs.h | 1 +
2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
index 109d3289418c..5a207f1e137c 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -7,6 +7,7 @@
* Copyright (C) 2018 Bootlin
*/
+#include <linux/delay.h>
#include <linux/types.h>
#include <media/videobuf2-dma-contig.h>
@@ -283,6 +284,23 @@ static void cedrus_h265_write_scaling_list(struct cedrus_ctx *ctx,
}
}
+static void cedrus_h265_skip_bits(struct cedrus_dev *dev, int num)
+{
+ int count = 0;
+
+ while (count < num) {
+ int tmp = min(num - count, 32);
+
+ cedrus_write(dev, VE_DEC_H265_TRIGGER,
+ VE_DEC_H265_TRIGGER_FLUSH_BITS |
+ VE_DEC_H265_TRIGGER_TYPE_N_BITS(tmp));
+ while (cedrus_read(dev, VE_DEC_H265_STATUS) & VE_DEC_H265_STATUS_VLD_BUSY)
+ udelay(1);
+
+ count += tmp;
+ }
+}
+
static void cedrus_h265_setup(struct cedrus_ctx *ctx,
struct cedrus_run *run)
{
@@ -347,10 +365,9 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
/* Source offset and length in bits. */
- reg = slice_params->data_bit_offset;
- cedrus_write(dev, VE_DEC_H265_BITS_OFFSET, reg);
+ cedrus_write(dev, VE_DEC_H265_BITS_OFFSET, 0);
- reg = slice_params->bit_size - slice_params->data_bit_offset;
+ reg = slice_params->bit_size;
cedrus_write(dev, VE_DEC_H265_BITS_LEN, reg);
/* Source beginning and end addresses. */
@@ -385,6 +402,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
/* Initialize bitstream access. */
cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_INIT_SWDEC);
+ cedrus_h265_skip_bits(dev, slice_params->data_bit_offset);
+
/* Bitstream parameters. */
reg = VE_DEC_H265_DEC_NAL_HDR_NAL_UNIT_TYPE(slice_params->nal_unit_type) |
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
index 0d9449fe2b28..df1cceef8d93 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
@@ -424,6 +424,7 @@
#define VE_DEC_H265_TRIGGER (VE_ENGINE_DEC_H265 + 0x34)
+#define VE_DEC_H265_TRIGGER_TYPE_N_BITS(x) (((x) & 0x3f) << 8)
#define VE_DEC_H265_TRIGGER_STCD_VC1 (0x02 << 4)
#define VE_DEC_H265_TRIGGER_STCD_AVS (0x01 << 4)
#define VE_DEC_H265_TRIGGER_STCD_HEVC (0x00 << 4)
--
2.24.0
From cf4ceb6095f67569dc22b09a150176d42ded09a5 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 26 Oct 2019 21:23:55 +0200
Subject: [PATCH 09/14] media: cedrus: hevc: tiles hack
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus.h | 2 +
.../staging/media/sunxi/cedrus/cedrus_h265.c | 93 +++++++++++++++++--
include/media/hevc-ctrls.h | 5 +-
3 files changed, 93 insertions(+), 7 deletions(-)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index d945f4f0ff2d..1204e32d83bc 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -134,6 +134,8 @@ struct cedrus_ctx {
ssize_t mv_col_buf_unit_size;
void *neighbor_info_buf;
dma_addr_t neighbor_info_buf_addr;
+ void *entry_points_buf;
+ dma_addr_t entry_points_buf_addr;
} h265;
} codec;
};
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
index 5a207f1e137c..97dce6ffbbc5 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -284,6 +284,61 @@ static void cedrus_h265_write_scaling_list(struct cedrus_ctx *ctx,
}
}
+static void write_entry_point_list(struct cedrus_ctx *ctx,
+ struct cedrus_run *run,
+ unsigned int ctb_addr_x,
+ unsigned int ctb_addr_y)
+{
+ const struct v4l2_ctrl_hevc_slice_params *slice_params;
+ const struct v4l2_ctrl_hevc_pps *pps;
+ struct cedrus_dev *dev = ctx->dev;
+ int i, x, tx, y, ty;
+ u32 *entry_points;
+
+ pps = run->h265.pps;
+ slice_params = run->h265.slice_params;
+
+ for (x = 0, tx = 0; tx < pps->num_tile_columns_minus1 + 1; tx++) {
+ if (x + pps->column_width_minus1[tx] + 1 > ctb_addr_x)
+ break;
+
+ x += pps->column_width_minus1[tx] + 1;
+ }
+
+ for (y = 0, ty = 0; ty < pps->num_tile_rows_minus1 + 1; ty++) {
+ if (y + pps->row_height_minus1[ty] + 1 > ctb_addr_y)
+ break;
+
+ y += pps->row_height_minus1[ty] + 1;
+ }
+
+ cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, (y << 16) | (x << 0));
+ cedrus_write(dev, VE_DEC_H265_TILE_END_CTB,
+ ((y + pps->row_height_minus1[ty]) << 16) |
+ ((x + pps->column_width_minus1[tx]) << 0));
+
+ entry_points = ctx->codec.h265.entry_points_buf;
+ if (pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED) {
+ for (i = 0; i < slice_params->num_entry_point_offsets; i++)
+ entry_points[i] = slice_params->entry_point_offset_minus1[i] + 1;
+ } else {
+ for (i = 0; i < slice_params->num_entry_point_offsets; i++) {
+ if (tx + 1 >= pps->num_tile_columns_minus1 + 1) {
+ x = 0;
+ tx = 0;
+ y += pps->row_height_minus1[ty++] + 1;
+ } else {
+ x += pps->column_width_minus1[tx++] + 1;
+ }
+
+ entry_points[i * 4 + 0] = slice_params->entry_point_offset_minus1[i] + 1;
+ entry_points[i * 4 + 1] = 0x0;
+ entry_points[i * 4 + 2] = (y << 16) | (x << 0);
+ entry_points[i * 4 + 3] = ((y + pps->row_height_minus1[ty]) << 16) | ((x + pps->column_width_minus1[tx]) << 0);
+ }
+ }
+}
+
static void cedrus_h265_skip_bits(struct cedrus_dev *dev, int num)
{
int count = 0;
@@ -311,6 +366,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
const struct v4l2_hevc_pred_weight_table *pred_weight_table;
unsigned int width_in_ctb_luma, ctb_size_luma;
unsigned int log2_max_luma_coding_block_size;
+ unsigned int ctb_addr_x, ctb_addr_y;
dma_addr_t src_buf_addr;
dma_addr_t src_buf_end_addr;
u32 chroma_log2_weight_denom;
@@ -388,12 +444,19 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
cedrus_write(dev, VE_DEC_H265_BITS_END_ADDR, reg);
/* Coding tree block address */
- reg = VE_DEC_H265_DEC_CTB_ADDR_X(slice_params->slice_segment_addr % width_in_ctb_luma);
- reg |= VE_DEC_H265_DEC_CTB_ADDR_Y(slice_params->slice_segment_addr / width_in_ctb_luma);
+ ctb_addr_x = slice_params->slice_segment_addr % width_in_ctb_luma;
+ ctb_addr_y = slice_params->slice_segment_addr / width_in_ctb_luma;
+ reg = VE_DEC_H265_DEC_CTB_ADDR_X(ctb_addr_x);
+ reg |= VE_DEC_H265_DEC_CTB_ADDR_Y(ctb_addr_y);
cedrus_write(dev, VE_DEC_H265_DEC_CTB_ADDR, reg);
- cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, 0);
- cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, 0);
+ if ((pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) ||
+ (pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED)) {
+ write_entry_point_list(ctx, run, ctb_addr_x, ctb_addr_y);
+ } else {
+ cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, 0);
+ cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, 0);
+ }
/* Clear the number of correctly-decoded coding tree blocks. */
if (ctx->fh.m2m_ctx->new_frame)
@@ -496,7 +559,9 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED,
pps->flags);
- /* TODO: VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TILES_ENABLED */
+ reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TILES_ENABLED,
+ V4L2_HEVC_PPS_FLAG_TILES_ENABLED,
+ pps->flags);
reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TRANSQUANT_BYPASS_ENABLED,
V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED,
@@ -572,12 +637,14 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
chroma_log2_weight_denom = pred_weight_table->luma_log2_weight_denom +
pred_weight_table->delta_chroma_log2_weight_denom;
- reg = VE_DEC_H265_DEC_SLICE_HDR_INFO2_NUM_ENTRY_POINT_OFFSETS(0) |
+ reg = VE_DEC_H265_DEC_SLICE_HDR_INFO2_NUM_ENTRY_POINT_OFFSETS(slice_params->num_entry_point_offsets) |
VE_DEC_H265_DEC_SLICE_HDR_INFO2_CHROMA_LOG2_WEIGHT_DENOM(chroma_log2_weight_denom) |
VE_DEC_H265_DEC_SLICE_HDR_INFO2_LUMA_LOG2_WEIGHT_DENOM(pred_weight_table->luma_log2_weight_denom);
cedrus_write(dev, VE_DEC_H265_DEC_SLICE_HDR_INFO2, reg);
+ cedrus_write(dev, VE_DEC_H265_ENTRY_POINT_OFFSET_ADDR, ctx->codec.h265.entry_points_buf_addr >> 8);
+
/* Decoded picture size. */
reg = VE_DEC_H265_DEC_PIC_SIZE_WIDTH(ctx->src_fmt.width) |
@@ -671,6 +738,17 @@ static int cedrus_h265_start(struct cedrus_ctx *ctx)
if (!ctx->codec.h265.neighbor_info_buf)
return -ENOMEM;
+ ctx->codec.h265.entry_points_buf =
+ dma_alloc_coherent(dev->dev, CEDRUS_H265_ENTRY_POINTS_BUF_SIZE,
+ &ctx->codec.h265.entry_points_buf_addr,
+ GFP_KERNEL);
+ if (!ctx->codec.h265.entry_points_buf) {
+ dma_free_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE,
+ ctx->codec.h265.neighbor_info_buf,
+ ctx->codec.h265.neighbor_info_buf_addr);
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -689,6 +767,9 @@ static void cedrus_h265_stop(struct cedrus_ctx *ctx)
dma_free_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE,
ctx->codec.h265.neighbor_info_buf,
ctx->codec.h265.neighbor_info_buf_addr);
+ dma_free_coherent(dev->dev, CEDRUS_H265_ENTRY_POINTS_BUF_SIZE,
+ ctx->codec.h265.entry_points_buf,
+ ctx->codec.h265.entry_points_buf_addr);
}
static void cedrus_h265_trigger(struct cedrus_ctx *ctx)
diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h
index 3e2e32098312..d1b094c8aaeb 100644
--- a/include/media/hevc-ctrls.h
+++ b/include/media/hevc-ctrls.h
@@ -169,6 +169,7 @@ struct v4l2_ctrl_hevc_slice_params {
/* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
__u32 slice_segment_addr;
+ __u32 num_entry_point_offsets;
/* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */
__u8 nal_unit_type;
@@ -203,7 +204,9 @@ struct v4l2_ctrl_hevc_slice_params {
__u8 num_rps_poc_st_curr_after;
__u8 num_rps_poc_lt_curr;
- __u8 padding[5];
+ __u8 padding;
+
+ __u32 entry_point_offset_minus1[256];
/* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
--
2.24.0
From 42b71243ef0c15e1d940583ef3fce99ec79a1975 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Thu, 14 Feb 2019 22:50:12 +0100
Subject: [PATCH 10/14] media: cedrus: H264 interlace hack
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../staging/media/sunxi/cedrus/cedrus_h264.c | 24 ++++++++++++-------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index ab83a6f1f921..b0ee4aed79f9 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -102,7 +102,7 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
struct cedrus_dev *dev = ctx->dev;
unsigned long used_dpbs = 0;
unsigned int position;
- unsigned int output = 0;
+ int output = -1;
unsigned int i;
cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
@@ -125,6 +125,11 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
position = cedrus_buf->codec.h264.position;
used_dpbs |= BIT(position);
+ if (run->dst->vb2_buf.timestamp == dpb->reference_ts) {
+ output = position;
+ continue;
+ }
+
if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
continue;
@@ -132,13 +137,11 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
dpb->top_field_order_cnt,
dpb->bottom_field_order_cnt,
&pic_list[position]);
-
- output = max(position, output);
}
- position = find_next_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM,
- output);
- if (position >= CEDRUS_H264_FRAME_NUM)
+ if (output >= 0)
+ position = output;
+ else
position = find_first_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM);
output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf);
@@ -164,6 +167,10 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
#define CEDRUS_MAX_REF_IDX 32
+#define REF_IDX(v) (v & GENMASK(5, 0))
+#define REF_FIELD(v) (v >> 6)
+#define REF_FIELD_BOTTOM 2
+
static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
struct cedrus_run *run,
const u8 *ref_list, u8 num_ref,
@@ -188,7 +195,7 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
int buf_idx;
u8 dpb_idx;
- dpb_idx = ref_list[i];
+ dpb_idx = REF_IDX(ref_list[i]);
dpb = &decode->dpb[dpb_idx];
if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
@@ -203,7 +210,8 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
position = cedrus_buf->codec.h264.position;
sram_array[i] |= position << 1;
- if (ref_buf->field == V4L2_FIELD_BOTTOM)
+ /* set bottom field flag when reference is to bottom field */
+ if (REF_FIELD(ref_list[i]) == REF_FIELD_BOTTOM)
sram_array[i] |= BIT(0);
}
--
2.24.0
From 6c1b98710d93611eec39bbcfcf07b3fc48e11459 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 9 Nov 2019 11:50:40 +0100
Subject: [PATCH 11/14] media: cedrus: hevc: Add luma bit depth
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
index 97dce6ffbbc5..89e269cc066d 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -483,6 +483,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
VE_DEC_H265_DEC_SPS_HDR_LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE(sps->log2_diff_max_min_luma_coding_block_size) |
VE_DEC_H265_DEC_SPS_HDR_LOG2_MIN_LUMA_CODING_BLOCK_SIZE_MINUS3(sps->log2_min_luma_coding_block_size_minus3) |
VE_DEC_H265_DEC_SPS_HDR_BIT_DEPTH_CHROMA_MINUS8(sps->bit_depth_chroma_minus8) |
+ VE_DEC_H265_DEC_SPS_HDR_BIT_DEPTH_LUMA_MINUS8(sps->bit_depth_luma_minus8) |
VE_DEC_H265_DEC_SPS_HDR_CHROMA_FORMAT_IDC(sps->chroma_format_idc);
reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SPS_HDR_FLAG_STRONG_INTRA_SMOOTHING_ENABLE,
--
2.24.0
From 187e20b079317e312a1be425ff4c19f838b9e625 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 9 Nov 2019 13:06:15 +0100
Subject: [PATCH 12/14] media: cedrus: Add callback for buffer cleanup
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus.h | 1 +
drivers/staging/media/sunxi/cedrus/cedrus_video.c | 13 +++++++++++++
2 files changed, 14 insertions(+)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index 1204e32d83bc..9298aa5f229d 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -148,6 +148,7 @@ struct cedrus_dec_ops {
int (*start)(struct cedrus_ctx *ctx);
void (*stop)(struct cedrus_ctx *ctx);
void (*trigger)(struct cedrus_ctx *ctx);
+ void (*buf_cleanup)(struct cedrus_ctx *ctx, struct cedrus_buffer *buf);
};
struct cedrus_variant {
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
index 497b1199d3fe..7f95216a552e 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -431,6 +431,18 @@ static int cedrus_buf_prepare(struct vb2_buffer *vb)
return 0;
}
+static void cedrus_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
+ struct cedrus_dev *dev = ctx->dev;
+ struct cedrus_dec_ops *ops = dev->dec_ops[ctx->current_codec];
+
+ if (!V4L2_TYPE_IS_OUTPUT(vq->type) && ops->buf_cleanup)
+ ops->buf_cleanup(ctx,
+ vb2_to_cedrus_buffer(vq->bufs[vb->index]));
+}
+
static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
@@ -494,6 +506,7 @@ static void cedrus_buf_request_complete(struct vb2_buffer *vb)
static struct vb2_ops cedrus_qops = {
.queue_setup = cedrus_queue_setup,
.buf_prepare = cedrus_buf_prepare,
+ .buf_cleanup = cedrus_buf_cleanup,
.buf_queue = cedrus_buf_queue,
.buf_out_validate = cedrus_buf_out_validate,
.buf_request_complete = cedrus_buf_request_complete,
--
2.24.0
From 024630941ade1aa57b4c16a5577ee9cf4f62be18 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 9 Nov 2019 13:22:05 +0100
Subject: [PATCH 13/14] media: cedrus: hevc: Improve buffer management
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus.h | 9 +-
.../staging/media/sunxi/cedrus/cedrus_h265.c | 117 ++++++++++--------
2 files changed, 69 insertions(+), 57 deletions(-)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index 9298aa5f229d..d8a4f8e83f94 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -95,6 +95,11 @@ struct cedrus_buffer {
unsigned int position;
enum cedrus_h264_pic_type pic_type;
} h264;
+ struct {
+ void *mv_col_buf;
+ dma_addr_t mv_col_buf_dma;
+ ssize_t mv_col_buf_size;
+ } h265;
} codec;
};
@@ -128,10 +133,6 @@ struct cedrus_ctx {
ssize_t intra_pred_buf_size;
} h264;
struct {
- void *mv_col_buf;
- dma_addr_t mv_col_buf_addr;
- ssize_t mv_col_buf_size;
- ssize_t mv_col_buf_unit_size;
void *neighbor_info_buf;
dma_addr_t neighbor_info_buf_addr;
void *entry_points_buf;
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
index 89e269cc066d..7c806ef6e8ef 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -91,26 +91,66 @@ static void cedrus_h265_sram_write_data(struct cedrus_dev *dev, void *data,
static inline dma_addr_t
cedrus_h265_frame_info_mv_col_buf_addr(struct cedrus_ctx *ctx,
- unsigned int index, unsigned int field)
+ unsigned int index,
+ const struct v4l2_ctrl_hevc_sps *sps)
{
- return ctx->codec.h265.mv_col_buf_addr + index *
- ctx->codec.h265.mv_col_buf_unit_size +
- field * ctx->codec.h265.mv_col_buf_unit_size / 2;
+ struct cedrus_buffer *cedrus_buf = NULL;
+ struct vb2_buffer *buf = NULL;
+ struct vb2_queue *vq;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (vq)
+ buf = vb2_get_buffer(vq, index);
+
+ if (buf)
+ cedrus_buf = vb2_to_cedrus_buffer(buf);
+
+ if (!cedrus_buf)
+ return 0;
+
+ if (!cedrus_buf->codec.h265.mv_col_buf_size) {
+ unsigned int ctb_size_luma, width_in_ctb_luma;
+ unsigned int log2_max_luma_coding_block_size;
+
+ log2_max_luma_coding_block_size =
+ sps->log2_min_luma_coding_block_size_minus3 + 3 +
+ sps->log2_diff_max_min_luma_coding_block_size;
+ ctb_size_luma = 1 << log2_max_luma_coding_block_size;
+ width_in_ctb_luma = DIV_ROUND_UP(sps->pic_width_in_luma_samples,
+ ctb_size_luma);
+
+ cedrus_buf->codec.h265.mv_col_buf_size = ALIGN(width_in_ctb_luma *
+ DIV_ROUND_UP(sps->pic_height_in_luma_samples, ctb_size_luma) *
+ CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE, 1024);
+
+ cedrus_buf->codec.h265.mv_col_buf =
+ dma_alloc_coherent(ctx->dev->dev,
+ cedrus_buf->codec.h265.mv_col_buf_size,
+ &cedrus_buf->codec.h265.mv_col_buf_dma,
+ GFP_KERNEL);
+
+ if (!cedrus_buf->codec.h265.mv_col_buf) {
+ cedrus_buf->codec.h265.mv_col_buf_size = 0;
+ cedrus_buf->codec.h265.mv_col_buf_dma = 0;
+ }
+ }
+
+ return cedrus_buf->codec.h265.mv_col_buf_dma;
}
static void cedrus_h265_frame_info_write_single(struct cedrus_ctx *ctx,
unsigned int index,
bool field_pic,
u32 pic_order_cnt[],
- int buffer_index)
+ int buffer_index,
+ const struct v4l2_ctrl_hevc_sps *sps)
{
struct cedrus_dev *dev = ctx->dev;
dma_addr_t dst_luma_addr = cedrus_dst_buf_addr(ctx, buffer_index, 0);
dma_addr_t dst_chroma_addr = cedrus_dst_buf_addr(ctx, buffer_index, 1);
dma_addr_t mv_col_buf_addr[2] = {
- cedrus_h265_frame_info_mv_col_buf_addr(ctx, buffer_index, 0),
- cedrus_h265_frame_info_mv_col_buf_addr(ctx, buffer_index,
- field_pic ? 1 : 0)
+ cedrus_h265_frame_info_mv_col_buf_addr(ctx, buffer_index, sps),
+ cedrus_h265_frame_info_mv_col_buf_addr(ctx, buffer_index, sps)
};
u32 offset = VE_DEC_H265_SRAM_OFFSET_FRAME_INFO +
VE_DEC_H265_SRAM_OFFSET_FRAME_INFO_UNIT * index;
@@ -134,7 +174,8 @@ static void cedrus_h265_frame_info_write_single(struct cedrus_ctx *ctx,
static void cedrus_h265_frame_info_write_dpb(struct cedrus_ctx *ctx,
const struct v4l2_hevc_dpb_entry *dpb,
- u8 num_active_dpb_entries)
+ u8 num_active_dpb_entries,
+ const struct v4l2_ctrl_hevc_sps *sps)
{
struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
V4L2_BUF_TYPE_VIDEO_CAPTURE);
@@ -149,7 +190,7 @@ static void cedrus_h265_frame_info_write_dpb(struct cedrus_ctx *ctx,
cedrus_h265_frame_info_write_single(ctx, i, dpb[i].field_pic,
pic_order_cnt,
- buffer_index);
+ buffer_index, sps);
}
}
@@ -386,36 +427,6 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
width_in_ctb_luma =
DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_luma);
- /* MV column buffer size and allocation. */
- if (!ctx->codec.h265.mv_col_buf_size) {
- unsigned int num_buffers =
- run->dst->vb2_buf.vb2_queue->num_buffers;
-
- /*
- * Each CTB requires a MV col buffer with a specific unit size.
- * Since the address is given with missing lsb bits, 1 KiB is
- * added to each buffer to ensure proper alignment.
- */
- ctx->codec.h265.mv_col_buf_unit_size =
- DIV_ROUND_UP(ctx->src_fmt.width, ctb_size_luma) *
- DIV_ROUND_UP(ctx->src_fmt.height, ctb_size_luma) *
- CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE + SZ_1K;
-
- ctx->codec.h265.mv_col_buf_size = num_buffers *
- ctx->codec.h265.mv_col_buf_unit_size;
-
- ctx->codec.h265.mv_col_buf =
- dma_alloc_coherent(dev->dev,
- ctx->codec.h265.mv_col_buf_size,
- &ctx->codec.h265.mv_col_buf_addr,
- GFP_KERNEL);
- if (!ctx->codec.h265.mv_col_buf) {
- ctx->codec.h265.mv_col_buf_size = 0;
- // TODO: Abort the process here.
- return;
- }
- }
-
/* Activate H265 engine. */
cedrus_engine_enable(ctx, CEDRUS_CODEC_H265);
@@ -669,7 +680,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
/* Write decoded picture buffer in pic list. */
cedrus_h265_frame_info_write_dpb(ctx, slice_params->dpb,
- slice_params->num_active_dpb_entries);
+ slice_params->num_active_dpb_entries, sps);
/* Output frame. */
@@ -680,7 +691,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
cedrus_h265_frame_info_write_single(ctx, output_pic_list_index,
slice_params->pic_struct != 0,
pic_order_cnt,
- run->dst->vb2_buf.index);
+ run->dst->vb2_buf.index, sps);
cedrus_write(dev, VE_DEC_H265_OUTPUT_FRAME_IDX, output_pic_list_index);
@@ -729,9 +740,6 @@ static int cedrus_h265_start(struct cedrus_ctx *ctx)
{
struct cedrus_dev *dev = ctx->dev;
- /* The buffer size is calculated at setup time. */
- ctx->codec.h265.mv_col_buf_size = 0;
-
ctx->codec.h265.neighbor_info_buf =
dma_alloc_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE,
&ctx->codec.h265.neighbor_info_buf_addr,
@@ -757,14 +765,6 @@ static void cedrus_h265_stop(struct cedrus_ctx *ctx)
{
struct cedrus_dev *dev = ctx->dev;
- if (ctx->codec.h265.mv_col_buf_size > 0) {
- dma_free_coherent(dev->dev, ctx->codec.h265.mv_col_buf_size,
- ctx->codec.h265.mv_col_buf,
- ctx->codec.h265.mv_col_buf_addr);
-
- ctx->codec.h265.mv_col_buf_size = 0;
- }
-
dma_free_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE,
ctx->codec.h265.neighbor_info_buf,
ctx->codec.h265.neighbor_info_buf_addr);
@@ -780,6 +780,16 @@ static void cedrus_h265_trigger(struct cedrus_ctx *ctx)
cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_DEC_SLICE);
}
+static void cedrus_h265_buf_cleanup(struct cedrus_ctx *ctx,
+ struct cedrus_buffer *buf)
+{
+ if (buf->codec.h265.mv_col_buf_size)
+ dma_free_coherent(ctx->dev->dev,
+ buf->codec.h265.mv_col_buf_size,
+ buf->codec.h265.mv_col_buf,
+ buf->codec.h265.mv_col_buf_dma);
+}
+
struct cedrus_dec_ops cedrus_dec_ops_h265 = {
.irq_clear = cedrus_h265_irq_clear,
.irq_disable = cedrus_h265_irq_disable,
@@ -788,4 +798,5 @@ struct cedrus_dec_ops cedrus_dec_ops_h265 = {
.start = cedrus_h265_start,
.stop = cedrus_h265_stop,
.trigger = cedrus_h265_trigger,
+ .buf_cleanup = cedrus_h265_buf_cleanup,
};
--
2.24.0
From b38b517739880462a43a1f4b36cf9384ffdae66c Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 9 Nov 2019 14:12:42 +0100
Subject: [PATCH 14/14] media: cedrus: h264: Improve buffer management
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus.h | 3 +
.../staging/media/sunxi/cedrus/cedrus_h264.c | 93 ++++++++-----------
2 files changed, 44 insertions(+), 52 deletions(-)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index d8a4f8e83f94..f8264953dd04 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -94,6 +94,9 @@ struct cedrus_buffer {
struct {
unsigned int position;
enum cedrus_h264_pic_type pic_type;
+ void *mv_col_buf;
+ dma_addr_t mv_col_buf_dma;
+ ssize_t mv_col_buf_size;
} h264;
struct {
void *mv_col_buf;
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index b0ee4aed79f9..aa5bd181cdaf 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -55,16 +55,14 @@ static void cedrus_h264_write_sram(struct cedrus_dev *dev,
}
static dma_addr_t cedrus_h264_mv_col_buf_addr(struct cedrus_ctx *ctx,
- unsigned int position,
+ struct cedrus_buffer *buf,
unsigned int field)
{
- dma_addr_t addr = ctx->codec.h264.mv_col_buf_dma;
+ dma_addr_t addr = buf->codec.h264.mv_col_buf_dma;
- /* Adjust for the position */
- addr += position * ctx->codec.h264.mv_col_buf_field_size * 2;
-
- /* Adjust for the field */
- addr += field * ctx->codec.h264.mv_col_buf_field_size;
+ /* Adjust for the field */
+ if (field)
+ addr += buf->codec.h264.mv_col_buf_size / 2;
return addr;
}
@@ -76,7 +74,6 @@ static void cedrus_fill_ref_pic(struct cedrus_ctx *ctx,
struct cedrus_h264_sram_ref_pic *pic)
{
struct vb2_buffer *vbuf = &buf->m2m_buf.vb.vb2_buf;
- unsigned int position = buf->codec.h264.position;
pic->top_field_order_cnt = cpu_to_le32(top_field_order_cnt);
pic->bottom_field_order_cnt = cpu_to_le32(bottom_field_order_cnt);
@@ -85,9 +82,9 @@ static void cedrus_fill_ref_pic(struct cedrus_ctx *ctx,
pic->luma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 0));
pic->chroma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 1));
pic->mv_col_top_ptr =
- cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 0));
+ cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, buf, 0));
pic->mv_col_bot_ptr =
- cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 1));
+ cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, buf, 1));
}
static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
@@ -147,6 +144,28 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf);
output_buf->codec.h264.position = position;
+ if (!output_buf->codec.h264.mv_col_buf_size) {
+ const struct v4l2_ctrl_h264_sps *sps = run->h264.sps;
+ unsigned int field_size;
+
+ field_size = DIV_ROUND_UP(ctx->src_fmt.width, 16) *
+ DIV_ROUND_UP(ctx->src_fmt.height, 16) * 16;
+ if (!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE))
+ field_size = field_size * 2;
+ if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
+ field_size = field_size * 2;
+
+ output_buf->codec.h264.mv_col_buf_size = field_size * 2;
+ output_buf->codec.h264.mv_col_buf =
+ dma_alloc_coherent(dev->dev,
+ output_buf->codec.h264.mv_col_buf_size,
+ &output_buf->codec.h264.mv_col_buf_dma,
+ GFP_KERNEL);
+
+ if (!output_buf->codec.h264.mv_col_buf)
+ output_buf->codec.h264.mv_col_buf_size = 0;
+ }
+
if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)
output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FIELD;
else if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)
@@ -525,8 +544,6 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx)
{
struct cedrus_dev *dev = ctx->dev;
unsigned int pic_info_size;
- unsigned int field_size;
- unsigned int mv_col_size;
int ret;
/* Formula for picture buffer size is taken from CedarX source. */
@@ -569,37 +586,6 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx)
goto err_pic_buf;
}
- field_size = DIV_ROUND_UP(ctx->src_fmt.width, 16) *
- DIV_ROUND_UP(ctx->src_fmt.height, 16) * 16;
-
- /*
- * FIXME: This is actually conditional to
- * V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE not being set, we
- * might have to rework this if memory efficiency ever is
- * something we need to work on.
- */
- field_size = field_size * 2;
-
- /*
- * FIXME: This is actually conditional to
- * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY not being set, we might
- * have to rework this if memory efficiency ever is something
- * we need to work on.
- */
- field_size = field_size * 2;
- ctx->codec.h264.mv_col_buf_field_size = field_size;
-
- mv_col_size = field_size * 2 * CEDRUS_H264_FRAME_NUM;
- ctx->codec.h264.mv_col_buf_size = mv_col_size;
- ctx->codec.h264.mv_col_buf = dma_alloc_coherent(dev->dev,
- ctx->codec.h264.mv_col_buf_size,
- &ctx->codec.h264.mv_col_buf_dma,
- GFP_KERNEL);
- if (!ctx->codec.h264.mv_col_buf) {
- ret = -ENOMEM;
- goto err_neighbor_buf;
- }
-
if (ctx->src_fmt.width > 2048) {
/*
* Formulas for deblock and intra prediction buffer sizes
@@ -615,7 +601,7 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx)
GFP_KERNEL);
if (!ctx->codec.h264.deblk_buf) {
ret = -ENOMEM;
- goto err_mv_col_buf;
+ goto err_neighbor_buf;
}
ctx->codec.h264.intra_pred_buf_size =
@@ -638,11 +624,6 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx)
ctx->codec.h264.deblk_buf,
ctx->codec.h264.deblk_buf_dma);
-err_mv_col_buf:
- dma_free_coherent(dev->dev, ctx->codec.h264.mv_col_buf_size,
- ctx->codec.h264.mv_col_buf,
- ctx->codec.h264.mv_col_buf_dma);
-
err_neighbor_buf:
dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
ctx->codec.h264.neighbor_info_buf,
@@ -659,9 +640,6 @@ static void cedrus_h264_stop(struct cedrus_ctx *ctx)
{
struct cedrus_dev *dev = ctx->dev;
- dma_free_coherent(dev->dev, ctx->codec.h264.mv_col_buf_size,
- ctx->codec.h264.mv_col_buf,
- ctx->codec.h264.mv_col_buf_dma);
dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
ctx->codec.h264.neighbor_info_buf,
ctx->codec.h264.neighbor_info_buf_dma);
@@ -686,6 +664,16 @@ static void cedrus_h264_trigger(struct cedrus_ctx *ctx)
VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE);
}
+static void cedrus_h264_buf_cleanup(struct cedrus_ctx *ctx,
+ struct cedrus_buffer *buf)
+{
+ if (buf->codec.h264.mv_col_buf_size)
+ dma_free_coherent(ctx->dev->dev,
+ buf->codec.h264.mv_col_buf_size,
+ buf->codec.h264.mv_col_buf,
+ buf->codec.h264.mv_col_buf_dma);
+}
+
struct cedrus_dec_ops cedrus_dec_ops_h264 = {
.irq_clear = cedrus_h264_irq_clear,
.irq_disable = cedrus_h264_irq_disable,
@@ -694,4 +682,5 @@ struct cedrus_dec_ops cedrus_dec_ops_h264 = {
.start = cedrus_h264_start,
.stop = cedrus_h264_stop,
.trigger = cedrus_h264_trigger,
+ .buf_cleanup = cedrus_h264_buf_cleanup,
};
--
2.24.0