[PATCH v7 04/17] media: rkvdec: Switch to using structs instead of writel

Detlev Casanova
2025-12-18T23:28:46Z

In an effort to merge the rkvdec2 driver [1] with this one, switch from
writel() calls to using structs to represent the register mappings.

This is done in order to have all supported decoders use the same format
in the future and ease reading of the code.

Using structs also improves stability as the hardware is tested and
validated downstream using a similar method.
It was noticed, on decoders, that:
- Some registers require to be writen in increasing order [2]
- Some registers, even if unrelated, need to be written to their reset
values (it was the case here for axi_ddr_[rw]data).

Using structs can also help improving performance later when, e.g.
multicore support is added on RK3588.

Performance seems to be slightly improved, but at least, not made worse.
Running fluster's JVT-AVC_V1 test suite with GStreamer on the Radxa ROCK
PI 4 SE gives the following times:

Before this patch:

- --jobs 1: Ran 129/135 tests successfully in 77.167 secs
- --jobs 6: Ran 129/135 tests successfully in 23.046 secs

With this patch:
- --jobs 1: Ran 129/135 tests successfully in 70.698 secs
- --jobs 6: Ran 129/135 tests successfully in 22.917 secs

This also shows that the fluster score hasn't changed.

[1]: https://lore.kernel.org/all/20250325213303.826925-1-detlev.casanova@collabora.com/
[2]: https://lore.kernel.org/all/20200127143009.15677-5-andrzej.p@collabora.com/

Tested-by: Diederik de Haas <didi.debian@cknow.org> # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
---
.../platform/rockchip/rkvdec/rkvdec-h264.c | 166 +++--
.../platform/rockchip/rkvdec/rkvdec-hevc.c | 64 +-
.../platform/rockchip/rkvdec/rkvdec-regs.h | 586 ++++++++++++------
.../platform/rockchip/rkvdec/rkvdec-vp9.c | 232 +++----
.../media/platform/rockchip/rkvdec/rkvdec.c | 10 +-
.../media/platform/rockchip/rkvdec/rkvdec.h | 1 +
6 files changed, 604 insertions(+), 455 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
index d14b4d173448d..68e20cb81a885 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
@@ -115,6 +115,7 @@ struct rkvdec_h264_run {
struct rkvdec_h264_ctx {
struct rkvdec_aux_buf priv_tbl;
struct rkvdec_h264_reflists reflists;
+ struct rkvdec_regs regs;
};

#define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n, \
@@ -841,45 +842,41 @@ static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
}

/*
- * dpb poc related registers table
+ * Set the ref POC in the correct register.
+ *
+ * The 32 registers are spread across 3 regions, each alternating top and bottom ref POCs:
+ * - 1: ref 0 to 14 contain top 0 to 7 and bottoms 0 to 6
+ * - 2: ref 15 to 29 contain top 8 to 14 and bottoms 7 to 14
+ * - 3: ref 30 and 31 which correspond to top 15 and bottom 15 respectively.
*/
-static const u32 poc_reg_tbl_top_field[16] = {
- RKVDEC_REG_H264_POC_REFER0(0),
- RKVDEC_REG_H264_POC_REFER0(2),
- RKVDEC_REG_H264_POC_REFER0(4),
- RKVDEC_REG_H264_POC_REFER0(6),
- RKVDEC_REG_H264_POC_REFER0(8),
- RKVDEC_REG_H264_POC_REFER0(10),
- RKVDEC_REG_H264_POC_REFER0(12),
- RKVDEC_REG_H264_POC_REFER0(14),
- RKVDEC_REG_H264_POC_REFER1(1),
- RKVDEC_REG_H264_POC_REFER1(3),
- RKVDEC_REG_H264_POC_REFER1(5),
- RKVDEC_REG_H264_POC_REFER1(7),
- RKVDEC_REG_H264_POC_REFER1(9),
- RKVDEC_REG_H264_POC_REFER1(11),
- RKVDEC_REG_H264_POC_REFER1(13),
- RKVDEC_REG_H264_POC_REFER2(0)
-};
-
-static const u32 poc_reg_tbl_bottom_field[16] = {
- RKVDEC_REG_H264_POC_REFER0(1),
- RKVDEC_REG_H264_POC_REFER0(3),
- RKVDEC_REG_H264_POC_REFER0(5),
- RKVDEC_REG_H264_POC_REFER0(7),
- RKVDEC_REG_H264_POC_REFER0(9),
- RKVDEC_REG_H264_POC_REFER0(11),
- RKVDEC_REG_H264_POC_REFER0(13),
- RKVDEC_REG_H264_POC_REFER1(0),
- RKVDEC_REG_H264_POC_REFER1(2),
- RKVDEC_REG_H264_POC_REFER1(4),
- RKVDEC_REG_H264_POC_REFER1(6),
- RKVDEC_REG_H264_POC_REFER1(8),
- RKVDEC_REG_H264_POC_REFER1(10),
- RKVDEC_REG_H264_POC_REFER1(12),
- RKVDEC_REG_H264_POC_REFER1(14),
- RKVDEC_REG_H264_POC_REFER2(1)
-};
+static void set_poc_reg(struct rkvdec_regs *regs, uint32_t poc, int id, bool bottom)
+{
+ if (!bottom) {
+ switch (id) {
+ case 0 ... 7:
+ regs->h26x.ref0_14_poc[id * 2] = poc;
+ break;
+ case 8 ... 14:
+ regs->h26x.ref15_29_poc[(id - 8) * 2 + 1] = poc;
+ break;
+ case 15:
+ regs->h26x.ref30_poc = poc;
+ break;
+ }
+ } else {
+ switch (id) {
+ case 0 ... 6:
+ regs->h26x.ref0_14_poc[id * 2 + 1] = poc;
+ break;
+ case 7 ... 14:
+ regs->h26x.ref15_29_poc[(id - 7) * 2] = poc;
+ break;
+ case 15:
+ regs->h26x.ref31_poc = poc;
+ break;
+ }
+ }
+}

static void config_registers(struct rkvdec_ctx *ctx,
struct rkvdec_h264_run *run)
@@ -894,6 +891,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
const struct v4l2_format *f;
+ struct rkvdec_regs *regs = &h264_ctx->regs;
dma_addr_t rlc_addr;
dma_addr_t refer_addr;
u32 rlc_len;
@@ -903,10 +901,11 @@ static void config_registers(struct rkvdec_ctx *ctx,
u32 yuv_virstride = 0;
u32 offset;
dma_addr_t dst_addr;
- u32 reg, i;
+ u32 i;

- reg = RKVDEC_MODE(RKVDEC_MODE_H264);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL);
+ memset(regs, 0, sizeof(*regs));
+
+ regs->common.reg02.dec_mode = RKVDEC_MODE_H264;

f = &ctx->decoded_fmt;
dst_fmt = &f->fmt.pix_mp;
@@ -921,39 +920,35 @@ static void config_registers(struct rkvdec_ctx *ctx,
else if (sps->chroma_format_idc == 2)
yuv_virstride = 2 * y_virstride;

- reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) |
- RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) |
- RKVDEC_SLICE_NUM_HIGHBIT |
- RKVDEC_SLICE_NUM_LOWBITS(0x7ff);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR);
+ regs->common.reg03.uv_hor_virstride = hor_virstride / 16;
+ regs->common.reg03.y_hor_virstride = hor_virstride / 16;
+ regs->common.reg03.slice_num_highbit = 1;
+ regs->common.reg03.slice_num_lowbits = 0x7ff;

/* config rlc base address */
rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
- writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
- writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_RLCWRITE_BASE);
+ regs->common.strm_rlc_base = rlc_addr;
+ regs->h26x.rlcwrite_base = rlc_addr;

rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
- reg = RKVDEC_STRM_LEN(rlc_len);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN);
+ regs->common.stream_len = rlc_len;

/* config cabac table */
offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
- writel_relaxed(priv_start_addr + offset,
- rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
+ regs->common.cabactbl_base = priv_start_addr + offset;

/* config output base address */
dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
- writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
+ regs->common.decout_base = dst_addr;

- reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
+ regs->common.reg08.y_virstride = y_virstride / 16;

- reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
+ regs->common.reg09.yuv_virstride = yuv_virstride / 16;

/* config ref pic address & poc */
for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
struct vb2_buffer *vb_buf = run->ref_buf[i];
+ struct ref_base *base;

/*
* If a DPB entry is unused or invalid, address of current destination
@@ -963,54 +958,37 @@ static void config_registers(struct rkvdec_ctx *ctx,
vb_buf = &dst_buf->vb2_buf;
refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);

- if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
- refer_addr |= RKVDEC_COLMV_USED_FLAG_REF;
- if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)
- refer_addr |= RKVDEC_FIELD_REF;
-
- if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF)
- refer_addr |= RKVDEC_TOPFIELD_USED_REF;
- if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)
- refer_addr |= RKVDEC_BOTFIELD_USED_REF;
-
- writel_relaxed(dpb[i].top_field_order_cnt,
- rkvdec->regs + poc_reg_tbl_top_field[i]);
- writel_relaxed(dpb[i].bottom_field_order_cnt,
- rkvdec->regs + poc_reg_tbl_bottom_field[i]);
-
if (i < V4L2_H264_NUM_DPB_ENTRIES - 1)
- writel_relaxed(refer_addr,
- rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i));
+ base = &regs->h26x.ref0_14_base[i];
else
- writel_relaxed(refer_addr,
- rkvdec->regs + RKVDEC_REG_H264_BASE_REFER15);
- }
+ base = &regs->h26x.ref15_base;

- reg = RKVDEC_CUR_POC(dec_params->top_field_order_cnt);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0);
+ base->base_addr = refer_addr >> 4;
+ base->field_ref = !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD);
+ base->colmv_use_flag_ref = !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE);
+ base->topfield_used_ref = !!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF);
+ base->botfield_used_ref = !!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF);

- reg = RKVDEC_CUR_POC(dec_params->bottom_field_order_cnt);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC1);
+ set_poc_reg(regs, dpb[i].top_field_order_cnt, i, false);
+ set_poc_reg(regs, dpb[i].bottom_field_order_cnt, i, true);
+ }
+
+ regs->h26x.cur_poc = dec_params->top_field_order_cnt;
+ regs->h26x.cur_poc1 = dec_params->bottom_field_order_cnt;

/* config hw pps address */
offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
- writel_relaxed(priv_start_addr + offset,
- rkvdec->regs + RKVDEC_REG_PPS_BASE);
+ regs->h26x.pps_base = priv_start_addr + offset;

/* config hw rps address */
offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
- writel_relaxed(priv_start_addr + offset,
- rkvdec->regs + RKVDEC_REG_RPS_BASE);
-
- reg = RKVDEC_AXI_DDR_RDATA(0);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA);
-
- reg = RKVDEC_AXI_DDR_WDATA(0);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA);
+ regs->h26x.rps_base = priv_start_addr + offset;

offset = offsetof(struct rkvdec_h264_priv_tbl, err_info);
- writel_relaxed(priv_start_addr + offset,
- rkvdec->regs + RKVDEC_REG_H264_ERRINFO_BASE);
+ regs->h26x.errorinfo_base = priv_start_addr + offset;
+
+ rkvdec_memcpy_toio(rkvdec->regs, regs,
+ MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs));
}

#define RKVDEC_H264_MAX_DEPTH_IN_BYTES 2
@@ -1181,8 +1159,6 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)

schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));

- writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
- writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index fc7e6a260b0a7..2d9e0e947a6dc 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -129,6 +129,7 @@ struct rkvdec_hevc_run {
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 {
@@ -548,6 +549,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
const struct v4l2_ctrl_hevc_slice_params *sl_params = &run->slices_params[0];
const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+ struct rkvdec_regs *regs = &hevc_ctx->regs;
dma_addr_t priv_start_addr = hevc_ctx->priv_tbl.dma;
const struct v4l2_pix_format_mplane *dst_fmt;
struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
@@ -564,8 +566,9 @@ static void config_registers(struct rkvdec_ctx *ctx,
dma_addr_t dst_addr;
u32 reg, i;

- reg = RKVDEC_MODE(RKVDEC_MODE_HEVC);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL);
+ memset(regs, 0, sizeof(*regs));
+
+ regs->common.reg02.dec_mode = RKVDEC_MODE_HEVC;

f = &ctx->decoded_fmt;
dst_fmt = &f->fmt.pix_mp;
@@ -580,33 +583,27 @@ static void config_registers(struct rkvdec_ctx *ctx,
else if (sps->chroma_format_idc == 2)
yuv_virstride = 2 * y_virstride;

- reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) |
- RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) |
- RKVDEC_SLICE_NUM_LOWBITS(run->num_slices);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR);
+ regs->common.reg03.slice_num_lowbits = run->num_slices;
+ regs->common.reg03.uv_hor_virstride = hor_virstride / 16;
+ regs->common.reg03.y_hor_virstride = hor_virstride / 16;

/* config rlc base address */
rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
- writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
+ regs->common.strm_rlc_base = rlc_addr;

rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
- reg = RKVDEC_STRM_LEN(round_up(rlc_len, 16) + 64);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN);
+ regs->common.stream_len = round_up(rlc_len, 16) + 64;

/* config cabac table */
offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table);
- writel_relaxed(priv_start_addr + offset,
- rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
+ regs->common.cabactbl_base = priv_start_addr + offset;

/* config output base address */
dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
- writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
-
- reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
+ regs->common.decout_base = dst_addr;

- reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
+ regs->common.reg08.y_virstride = y_virstride / 16;
+ regs->common.reg09.yuv_virstride = yuv_virstride / 16;

/* config ref pic address */
for (i = 0; i < 15; i++) {
@@ -620,33 +617,30 @@ static void config_registers(struct rkvdec_ctx *ctx,
}

refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
- writel_relaxed(refer_addr | reg,
- rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i));

- reg = RKVDEC_POC_REFER(i < decode_params->num_active_dpb_entries ?
- dpb[i].pic_order_cnt_val : 0);
- writel_relaxed(reg,
- rkvdec->regs + RKVDEC_REG_H264_POC_REFER0(i));
+ regs->h26x.ref0_14_base[i].base_addr = refer_addr >> 4;
+ regs->h26x.ref0_14_base[i].field_ref = !!(reg & 1);
+ regs->h26x.ref0_14_base[i].topfield_used_ref = !!(reg & 2);
+ regs->h26x.ref0_14_base[i].botfield_used_ref = !!(reg & 4);
+ regs->h26x.ref0_14_base[i].colmv_use_flag_ref = !!(reg & 8);
+
+ regs->h26x.ref0_14_poc[i] = i < decode_params->num_active_dpb_entries
+ ? dpb[i].pic_order_cnt_val
+ : 0;
}

- reg = RKVDEC_CUR_POC(sl_params->slice_pic_order_cnt);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0);
+ regs->h26x.cur_poc = sl_params->slice_pic_order_cnt;

/* config hw pps address */
offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set);
- writel_relaxed(priv_start_addr + offset,
- rkvdec->regs + RKVDEC_REG_PPS_BASE);
+ regs->h26x.pps_base = priv_start_addr + offset;

/* config hw rps address */
offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
- writel_relaxed(priv_start_addr + offset,
- rkvdec->regs + RKVDEC_REG_RPS_BASE);
-
- reg = RKVDEC_AXI_DDR_RDATA(0);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA);
+ regs->h26x.rps_base = priv_start_addr + offset;

- reg = RKVDEC_AXI_DDR_WDATA(0);
- writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA);
+ rkvdec_memcpy_toio(rkvdec->regs, regs,
+ MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs));
}

#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES 2
@@ -784,8 +778,6 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)

schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));

- writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
- writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
index c627b6b6f53a1..1af66c5f1c9b6 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
@@ -3,7 +3,12 @@
#ifndef RKVDEC_REGS_H_
#define RKVDEC_REGS_H_

-/* rkvcodec registers */
+#include <linux/types.h>
+
+/*
+ * REG_INTERRUPT is accessed via writel to enable the decoder after
+ * configuring it and clear interrupt strmd_error_status
+ */
#define RKVDEC_REG_INTERRUPT 0x004
#define RKVDEC_INTERRUPT_DEC_E BIT(0)
#define RKVDEC_CONFIG_DEC_CLK_GATE_E BIT(1)
@@ -30,198 +35,399 @@
#define RKVDEC_SOFTRESET_RDY BIT(22)
#define RKVDEC_WR_DDR_ALIGN_EN BIT(23)

-#define RKVDEC_REG_SYSCTRL 0x008
-#define RKVDEC_IN_ENDIAN BIT(0)
-#define RKVDEC_IN_SWAP32_E BIT(1)
-#define RKVDEC_IN_SWAP64_E BIT(2)
-#define RKVDEC_STR_ENDIAN BIT(3)
-#define RKVDEC_STR_SWAP32_E BIT(4)
-#define RKVDEC_STR_SWAP64_E BIT(5)
-#define RKVDEC_OUT_ENDIAN BIT(6)
-#define RKVDEC_OUT_SWAP32_E BIT(7)
-#define RKVDEC_OUT_CBCR_SWAP BIT(8)
-#define RKVDEC_RLC_MODE_DIRECT_WRITE BIT(10)
-#define RKVDEC_RLC_MODE BIT(11)
-#define RKVDEC_STRM_START_BIT(x) (((x) & 0x7f) << 12)
-#define RKVDEC_MODE(x) (((x) & 0x03) << 20)
-#define RKVDEC_MODE_HEVC 0
-#define RKVDEC_MODE_H264 1
-#define RKVDEC_MODE_VP9 2
-#define RKVDEC_RPS_MODE BIT(24)
-#define RKVDEC_STRM_MODE BIT(25)
-#define RKVDEC_H264_STRM_LASTPKT BIT(26)
-#define RKVDEC_H264_FIRSTSLICE_FLAG BIT(27)
-#define RKVDEC_H264_FRAME_ORSLICE BIT(28)
-#define RKVDEC_BUSPR_SLOT_DIS BIT(29)
-
-#define RKVDEC_REG_PICPAR 0x00C
-#define RKVDEC_Y_HOR_VIRSTRIDE(x) ((x) & 0x1ff)
-#define RKVDEC_SLICE_NUM_HIGHBIT BIT(11)
-#define RKVDEC_UV_HOR_VIRSTRIDE(x) (((x) & 0x1ff) << 12)
-#define RKVDEC_SLICE_NUM_LOWBITS(x) (((x) & 0x7ff) << 21)
-
-#define RKVDEC_REG_STRM_RLC_BASE 0x010
-
-#define RKVDEC_REG_STRM_LEN 0x014
-#define RKVDEC_STRM_LEN(x) ((x) & 0x7ffffff)
-
-#define RKVDEC_REG_CABACTBL_PROB_BASE 0x018
-#define RKVDEC_REG_DECOUT_BASE 0x01C
-
-#define RKVDEC_REG_Y_VIRSTRIDE 0x020
-#define RKVDEC_Y_VIRSTRIDE(x) ((x) & 0xfffff)
-
-#define RKVDEC_REG_YUV_VIRSTRIDE 0x024
-#define RKVDEC_YUV_VIRSTRIDE(x) ((x) & 0x1fffff)
-#define RKVDEC_REG_H264_BASE_REFER(i) (((i) * 0x04) + 0x028)
-
-#define RKVDEC_REG_H264_BASE_REFER15 0x0C0
-#define RKVDEC_FIELD_REF BIT(0)
-#define RKVDEC_TOPFIELD_USED_REF BIT(1)
-#define RKVDEC_BOTFIELD_USED_REF BIT(2)
-#define RKVDEC_COLMV_USED_FLAG_REF BIT(3)
-
-#define RKVDEC_REG_VP9_LAST_FRAME_BASE 0x02c
-#define RKVDEC_REG_VP9_GOLDEN_FRAME_BASE 0x030
-#define RKVDEC_REG_VP9_ALTREF_FRAME_BASE 0x034
-
-#define RKVDEC_REG_VP9_CPRHEADER_OFFSET 0x028
-#define RKVDEC_VP9_CPRHEADER_OFFSET(x) ((x) & 0xffff)
-
-#define RKVDEC_REG_VP9_REFERLAST_BASE 0x02C
-#define RKVDEC_REG_VP9_REFERGOLDEN_BASE 0x030
-#define RKVDEC_REG_VP9_REFERALFTER_BASE 0x034
-
-#define RKVDEC_REG_VP9COUNT_BASE 0x038
-#define RKVDEC_VP9COUNT_UPDATE_EN BIT(0)
-
-#define RKVDEC_REG_VP9_SEGIDLAST_BASE 0x03C
-#define RKVDEC_REG_VP9_SEGIDCUR_BASE 0x040
-#define RKVDEC_REG_VP9_FRAME_SIZE(i) ((i) * 0x04 + 0x044)
-#define RKVDEC_VP9_FRAMEWIDTH(x) (((x) & 0xffff) << 0)
-#define RKVDEC_VP9_FRAMEHEIGHT(x) (((x) & 0xffff) << 16)
-
-#define RKVDEC_VP9_SEGID_GRP(i) ((i) * 0x04 + 0x050)
-#define RKVDEC_SEGID_ABS_DELTA(x) ((x) & 0x1)
-#define RKVDEC_SEGID_FRAME_QP_DELTA_EN(x) (((x) & 0x1) << 1)
-#define RKVDEC_SEGID_FRAME_QP_DELTA(x) (((x) & 0x1ff) << 2)
-#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(x) (((x) & 0x1) << 11)
-#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(x) (((x) & 0x7f) << 12)
-#define RKVDEC_SEGID_REFERINFO_EN(x) (((x) & 0x1) << 19)
-#define RKVDEC_SEGID_REFERINFO(x) (((x) & 0x03) << 20)
-#define RKVDEC_SEGID_FRAME_SKIP_EN(x) (((x) & 0x1) << 22)
-
-#define RKVDEC_VP9_CPRHEADER_CONFIG 0x070
-#define RKVDEC_VP9_TX_MODE(x) ((x) & 0x07)
-#define RKVDEC_VP9_FRAME_REF_MODE(x) (((x) & 0x03) << 3)
-
-#define RKVDEC_VP9_REF_SCALE(i) ((i) * 0x04 + 0x074)
-#define RKVDEC_VP9_REF_HOR_SCALE(x) ((x) & 0xffff)
-#define RKVDEC_VP9_REF_VER_SCALE(x) (((x) & 0xffff) << 16)
-
-#define RKVDEC_VP9_REF_DELTAS_LASTFRAME 0x080
-#define RKVDEC_REF_DELTAS_LASTFRAME(pos, val) (((val) & 0x7f) << ((pos) * 7))
-
-#define RKVDEC_VP9_INFO_LASTFRAME 0x084
-#define RKVDEC_MODE_DELTAS_LASTFRAME(pos, val) (((val) & 0x7f) << ((pos) * 7))
-#define RKVDEC_SEG_EN_LASTFRAME BIT(16)
-#define RKVDEC_LAST_SHOW_FRAME BIT(17)
-#define RKVDEC_LAST_INTRA_ONLY BIT(18)
-#define RKVDEC_LAST_WIDHHEIGHT_EQCUR BIT(19)
-#define RKVDEC_COLOR_SPACE_LASTKEYFRAME(x) (((x) & 0x07) << 20)
-
-#define RKVDEC_VP9_INTERCMD_BASE 0x088
-
-#define RKVDEC_VP9_INTERCMD_NUM 0x08C
-#define RKVDEC_INTERCMD_NUM(x) ((x) & 0xffffff)
-
-#define RKVDEC_VP9_LASTTILE_SIZE 0x090
-#define RKVDEC_LASTTILE_SIZE(x) ((x) & 0xffffff)
-
-#define RKVDEC_VP9_HOR_VIRSTRIDE(i) ((i) * 0x04 + 0x094)
-#define RKVDEC_HOR_Y_VIRSTRIDE(x) ((x) & 0x1ff)
-#define RKVDEC_HOR_UV_VIRSTRIDE(x) (((x) & 0x1ff) << 16)
-
-#define RKVDEC_REG_H264_POC_REFER0(i) (((i) * 0x04) + 0x064)
-#define RKVDEC_REG_H264_POC_REFER1(i) (((i) * 0x04) + 0x0C4)
-#define RKVDEC_REG_H264_POC_REFER2(i) (((i) * 0x04) + 0x120)
-#define RKVDEC_POC_REFER(x) ((x) & 0xffffffff)
-
-#define RKVDEC_REG_CUR_POC0 0x0A0
-#define RKVDEC_REG_CUR_POC1 0x128
-#define RKVDEC_CUR_POC(x) ((x) & 0xffffffff)
-
-#define RKVDEC_REG_RLCWRITE_BASE 0x0A4
-#define RKVDEC_REG_PPS_BASE 0x0A8
-#define RKVDEC_REG_RPS_BASE 0x0AC
-
-#define RKVDEC_REG_STRMD_ERR_EN 0x0B0
-#define RKVDEC_STRMD_ERR_EN(x) ((x) & 0xffffffff)
-
-#define RKVDEC_REG_STRMD_ERR_STA 0x0B4
-#define RKVDEC_STRMD_ERR_STA(x) ((x) & 0xfffffff)
-#define RKVDEC_COLMV_ERR_REF_PICIDX(x) (((x) & 0x0f) << 28)
-
-#define RKVDEC_REG_STRMD_ERR_CTU 0x0B8
-#define RKVDEC_STRMD_ERR_CTU(x) ((x) & 0xff)
-#define RKVDEC_STRMD_ERR_CTU_YOFFSET(x) (((x) & 0xff) << 8)
-#define RKVDEC_STRMFIFO_SPACE2FULL(x) (((x) & 0x7f) << 16)
-#define RKVDEC_VP9_ERR_EN_CTU0 BIT(24)
-
-#define RKVDEC_REG_SAO_CTU_POS 0x0BC
-#define RKVDEC_SAOWR_XOFFSET(x) ((x) & 0x1ff)
-#define RKVDEC_SAOWR_YOFFSET(x) (((x) & 0x3ff) << 16)
-
-#define RKVDEC_VP9_LAST_FRAME_YSTRIDE 0x0C0
-#define RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE 0x0C4
-#define RKVDEC_VP9_ALTREF_FRAME_YSTRIDE 0x0C8
-#define RKVDEC_VP9_REF_YSTRIDE(x) (((x) & 0xfffff) << 0)
-
-#define RKVDEC_VP9_LAST_FRAME_YUVSTRIDE 0x0CC
-#define RKVDEC_VP9_REF_YUVSTRIDE(x) (((x) & 0x1fffff) << 0)
-
-#define RKVDEC_VP9_REF_COLMV_BASE 0x0D0
-
-#define RKVDEC_REG_PERFORMANCE_CYCLE 0x100
-#define RKVDEC_PERFORMANCE_CYCLE(x) ((x) & 0xffffffff)
-
-#define RKVDEC_REG_AXI_DDR_RDATA 0x104
-#define RKVDEC_AXI_DDR_RDATA(x) ((x) & 0xffffffff)
-
-#define RKVDEC_REG_AXI_DDR_WDATA 0x108
-#define RKVDEC_AXI_DDR_WDATA(x) ((x) & 0xffffffff)
-
-#define RKVDEC_REG_FPGADEBUG_RESET 0x10C
-#define RKVDEC_BUSIFD_RESETN BIT(0)
-#define RKVDEC_CABAC_RESETN BIT(1)
-#define RKVDEC_DEC_CTRL_RESETN BIT(2)
-#define RKVDEC_TRANSD_RESETN BIT(3)
-#define RKVDEC_INTRA_RESETN BIT(4)
-#define RKVDEC_INTER_RESETN BIT(5)
-#define RKVDEC_RECON_RESETN BIT(6)
-#define RKVDEC_FILER_RESETN BIT(7)
-
-#define RKVDEC_REG_PERFORMANCE_SEL 0x110
-#define RKVDEC_PERF_SEL_CNT0(x) ((x) & 0x3f)
-#define RKVDEC_PERF_SEL_CNT1(x) (((x) & 0x3f) << 8)
-#define RKVDEC_PERF_SEL_CNT2(x) (((x) & 0x3f) << 16)
-
-#define RKVDEC_REG_PERFORMANCE_CNT(i) ((i) * 0x04 + 0x114)
-#define RKVDEC_PERF_CNT(x) ((x) & 0xffffffff)
-
-#define RKVDEC_REG_H264_ERRINFO_BASE 0x12C
-
-#define RKVDEC_REG_H264_ERRINFO_NUM 0x130
-#define RKVDEC_SLICEDEC_NUM(x) ((x) & 0x3fff)
-#define RKVDEC_STRMD_DECT_ERR_FLAG BIT(15)
-#define RKVDEC_ERR_PKT_NUM(x) (((x) & 0x3fff) << 16)
-
-#define RKVDEC_REG_H264_ERR_E 0x134
-#define RKVDEC_H264_ERR_EN_HIGHBITS(x) ((x) & 0x3fffffff)
-
#define RKVDEC_REG_QOS_CTRL 0x18C

+/*
+ * Cache configuration is not covered in the range of the register struct
+ */
#define RKVDEC_REG_PREF_LUMA_CACHE_COMMAND 0x410
#define RKVDEC_REG_PREF_CHR_CACHE_COMMAND 0x450

+/*
+ * Define the mode values
+ */
+#define RKVDEC_MODE_HEVC 0
+#define RKVDEC_MODE_H264 1
+#define RKVDEC_MODE_VP9 2
+
+/* rkvcodec registers */
+struct rkvdec_common_regs {
+ struct rkvdec_id {
+ u32 minor_ver : 8;
+ u32 level : 1;
+ u32 dec_support : 3;
+ u32 profile : 1;
+ u32 reserved0 : 1;
+ u32 codec_flag : 1;
+ u32 reserved1 : 1;
+ u32 prod_num : 16;
+ } reg00;
+
+ struct rkvdec_int {
+ u32 dec_e : 1;
+ u32 dec_clkgate_e : 1;
+ u32 dec_e_strmd_clkgate_dis : 1;
+ u32 timeout_mode : 1;
+ u32 dec_irq_dis : 1;
+ u32 dec_timeout_e : 1;
+ u32 buf_empty_en : 1;
+ u32 stmerror_waitdecfifo_empty : 1;
+ u32 dec_irq : 1;
+ u32 dec_irq_raw : 1;
+ u32 reserved2 : 2;
+ u32 dec_rdy_sta : 1;
+ u32 dec_bus_sta : 1;
+ u32 dec_error_sta : 1;
+ u32 dec_timeout_sta : 1;
+ u32 dec_empty_sta : 1;
+ u32 colmv_ref_error_sta : 1;
+ u32 cabu_end_sta : 1;
+ u32 h264orvp9_error_mode : 1;
+ u32 softrst_en_p : 1;
+ u32 force_softreset_valid : 1;
+ u32 softreset_rdy : 1;
+ u32 wr_ddr_align_en : 1;
+ u32 scl_down_en : 1;
+ u32 allow_not_wr_unref_bframe : 1;
+ u32 reserved1 : 6;
+ } reg01;
+
+ struct rkvdec_sysctrl {
+ u32 in_endian : 1;
+ u32 in_swap32_e : 1;
+ u32 in_swap64_e : 1;
+ u32 str_endian : 1;
+ u32 str_swap32_e : 1;
+ u32 str_swap64_e : 1;
+ u32 out_endian : 1;
+ u32 out_swap32_e : 1;
+ u32 out_cbcr_swap : 1;
+ u32 reserved0 : 1;
+ u32 rlc_mode_direct_write : 1;
+ u32 rlc_mode : 1;
+ u32 strm_start_bit : 7;
+ u32 reserved1 : 1;
+ u32 dec_mode : 2;
+ u32 reserved2 : 2;
+ u32 rps_mode : 1;
+ u32 stream_mode : 1;
+ u32 stream_lastpacket : 1;
+ u32 firstslice_flag : 1;
+ u32 frame_orslice : 1;
+ u32 buspr_slot_disable : 1;
+ u32 colmv_mode : 1;
+ u32 ycacherd_prior : 1;
+ } reg02;
+
+ struct rkvdec_picpar {
+ u32 y_hor_virstride : 9;
+ u32 reserved : 2;
+ u32 slice_num_highbit : 1;
+ u32 uv_hor_virstride : 9;
+ u32 slice_num_lowbits : 11;
+ } reg03;
+
+ u32 strm_rlc_base;
+ u32 stream_len;
+ u32 cabactbl_base;
+ u32 decout_base;
+
+ struct rkvdec_y_virstride {
+ u32 y_virstride : 20;
+ u32 reserved0 : 12;
+ } reg08;
+
+ struct rkvdec_yuv_virstride {
+ u32 yuv_virstride : 21;
+ u32 reserved0 : 11;
+ } reg09;
+} __packed;
+
+struct ref_base {
+ u32 field_ref : 1;
+ u32 topfield_used_ref : 1;
+ u32 botfield_used_ref : 1;
+ u32 colmv_use_flag_ref : 1;
+ u32 base_addr : 28;
+};
+
+struct rkvdec_h26x_regs {
+ struct ref_base ref0_14_base[15];
+ u32 ref0_14_poc[15];
+
+ u32 cur_poc;
+ u32 rlcwrite_base;
+ u32 pps_base;
+ u32 rps_base;
+
+ u32 strmd_error_e;
+
+ struct {
+ u32 strmd_error_status : 28;
+ u32 colmv_error_ref_picidx : 4;
+ } reg45;
+
+ struct {
+ u32 strmd_error_ctu_xoffset : 8;
+ u32 strmd_error_ctu_yoffset : 8;
+ u32 streamfifo_space2full : 7;
+ u32 reserved0 : 1;
+ u32 vp9_error_ctu0_en : 1;
+ u32 reserved1 : 7;
+ } reg46;
+
+ struct {
+ u32 saowr_xoffet : 9;
+ u32 reserved0 : 7;
+ u32 saowr_yoffset : 10;
+ u32 reserved1 : 6;
+ } reg47;
+
+ struct ref_base ref15_base;
+
+ u32 ref15_29_poc[15];
+
+ u32 performance_cycle;
+ u32 axi_ddr_rdata;
+ u32 axi_ddr_wdata;
+
+ struct {
+ u32 busifd_resetn : 1;
+ u32 cabac_resetn : 1;
+ u32 dec_ctrl_resetn : 1;
+ u32 transd_resetn : 1;
+ u32 intra_resetn : 1;
+ u32 inter_resetn : 1;
+ u32 recon_resetn : 1;
+ u32 filer_resetn : 1;
+ u32 reserved0 : 24;
+ } reg67;
+
+ struct {
+ u32 perf_cnt0_sel : 6;
+ u32 reserved0 : 2;
+ u32 perf_cnt1_sel : 6;
+ u32 reserved1 : 2;
+ u32 perf_cnt2_sel : 6;
+ u32 reserved2 : 10;
+ } reg68;
+
+ u32 perf_cnt0;
+ u32 perf_cnt1;
+ u32 perf_cnt2;
+ u32 ref30_poc;
+ u32 ref31_poc;
+ u32 cur_poc1;
+ u32 errorinfo_base;
+
+ struct {
+ u32 slicedec_num : 14;
+ u32 reserved0 : 1;
+ u32 strmd_detect_error_flag : 1;
+ u32 error_packet_num : 14;
+ u32 reserved1 : 2;
+ } reg76;
+
+ struct {
+ u32 error_en_highbits : 30;
+ u32 strmd_error_slice_en : 1;
+ u32 strmd_error_frame_en : 1;
+ } reg77;
+
+ u32 colmv_cur_base;
+ u32 colmv_ref_base[16];
+ u32 scanlist_addr;
+ u32 reg96_sd_decout_base;
+ u32 sd_y_virstride;
+ u32 sd_hor_stride;
+ u32 qos_ctrl;
+ u32 perf[8];
+ u32 qos1;
+} __packed;
+
+struct rkvdec_vp9_regs {
+ struct cprheader_offset {
+ u32 cprheader_offset : 16;
+ u32 reserved : 16;
+ } reg10;
+
+ u32 refer_bases[3];
+ u32 count_base;
+ u32 segidlast_base;
+ u32 segidcur_base;
+
+ struct frame_sizes {
+ u32 framewidth : 16;
+ u32 frameheight : 16;
+ } reg17_19[3];
+
+ struct segid_grp {
+ u32 segid_abs_delta : 1;
+ u32 segid_frame_qp_delta_en : 1;
+ u32 segid_frame_qp_delta : 9;
+ u32 segid_frame_loopfilter_value_en : 1;
+ u32 segid_frame_loopfilter_value : 7;
+ u32 segid_referinfo_en : 1;
+ u32 segid_referinfo : 2;
+ u32 segid_frame_skip_en : 1;
+ u32 reserved : 9;
+ } reg20_27[8];
+
+ struct cprheader_config {
+ u32 tx_mode : 3;
+ u32 frame_reference_mode : 2;
+ u32 reserved : 27;
+ } reg28;
+
+ struct ref_scale {
+ u32 ref_hor_scale : 16;
+ u32 ref_ver_scale : 16;
+ } reg29_31[3];
+
+ struct ref_deltas_lastframe {
+ u32 ref_deltas_lastframe0 : 7;
+ u32 ref_deltas_lastframe1 : 7;
+ u32 ref_deltas_lastframe2 : 7;
+ u32 ref_deltas_lastframe3 : 7;
+ u32 reserved : 4;
+ } reg32;
+
+ struct info_lastframe {
+ u32 mode_deltas_lastframe0 : 7;
+ u32 mode_deltas_lastframe1 : 7;
+ u32 reserved0 : 2;
+ u32 segmentation_enable_lstframe : 1;
+ u32 last_show_frame : 1;
+ u32 last_intra_only : 1;
+ u32 last_widthheight_eqcur : 1;
+ u32 color_space_lastkeyframe : 3;
+ u32 reserved1 : 9;
+ } reg33;
+
+ u32 intercmd_base;
+
+ struct intercmd_num {
+ u32 intercmd_num : 24;
+ u32 reserved : 8;
+ } reg35;
+
+ struct lasttile_size {
+ u32 lasttile_size : 24;
+ u32 reserved : 8;
+ } reg36;
+
+ struct hor_virstride {
+ u32 y_hor_virstride : 9;
+ u32 reserved0 : 7;
+ u32 uv_hor_virstride : 9;
+ u32 reserved1 : 7;
+ } reg37_39[3];
+
+ u32 cur_poc;
+
+ struct rlcwrite_base {
+ u32 reserved : 3;
+ u32 rlcwrite_base : 29;
+ } reg41;
+
+ struct pps_base {
+ u32 reserved : 4;
+ u32 pps_base : 28;
+ } reg42;
+
+ struct rps_base {
+ u32 reserved : 4;
+ u32 rps_base : 28;
+ } reg43;
+
+ struct strmd_error_en {
+ u32 strmd_error_e : 28;
+ u32 reserved : 4;
+ } reg44;
+
+ u32 vp9_error_info0;
+
+ struct strmd_error_ctu {
+ u32 strmd_error_ctu_xoffset : 8;
+ u32 strmd_error_ctu_yoffset : 8;
+ u32 streamfifo_space2full : 7;
+ u32 reserved0 : 1;
+ u32 error_ctu0_en : 1;
+ u32 reserved1 : 7;
+ } reg46;
+
+ struct sao_ctu_position {
+ u32 saowr_xoffet : 9;
+ u32 reserved0 : 7;
+ u32 saowr_yoffset : 10;
+ u32 reserved1 : 6;
+ } reg47;
+
+ struct ystride {
+ u32 virstride : 20;
+ u32 reserved : 12;
+ } reg48_50[3];
+
+ struct lastref_yuvstride {
+ u32 lastref_yuv_virstride : 21;
+ u32 reserved : 11;
+ } reg51;
+
+ u32 refcolmv_base;
+
+ u32 reserved0[11];
+
+ u32 performance_cycle;
+ u32 axi_ddr_rdata;
+ u32 axi_ddr_wdata;
+
+ struct fpgadebug_reset {
+ u32 busifd_resetn : 1;
+ u32 cabac_resetn : 1;
+ u32 dec_ctrl_resetn : 1;
+ u32 transd_resetn : 1;
+ u32 intra_resetn : 1;
+ u32 inter_resetn : 1;
+ u32 recon_resetn : 1;
+ u32 filer_resetn : 1;
+ u32 reserved : 24;
+ } reg67;
+
+ struct performance_sel {
+ u32 perf_cnt0_sel : 6;
+ u32 reserved0 : 2;
+ u32 perf_cnt1_sel : 6;
+ u32 reserved1 : 2;
+ u32 perf_cnt2_sel : 6;
+ u32 reserved : 10;
+ } reg68;
+
+ u32 perf_cnt0;
+ u32 perf_cnt1;
+ u32 perf_cnt2;
+
+ u32 reserved1[3];
+
+ u32 vp9_error_info1;
+
+ struct error_ctu1 {
+ u32 vp9_error_ctu1_x : 6;
+ u32 reserved0 : 2;
+ u32 vp9_error_ctu1_y : 6;
+ u32 reserved1 : 1;
+ u32 vp9_error_ctu1_en : 1;
+ u32 reserved2 : 16;
+ } reg76;
+
+ u32 reserved2;
+} __packed;
+
+struct rkvdec_regs {
+ struct rkvdec_common_regs common;
+ union {
+ struct rkvdec_h26x_regs h26x;
+ struct rkvdec_vp9_regs vp9;
+ };
+} __packed;
+
#endif /* RKVDEC_REGS_H_ */
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
index b4bf01e839eff..ba51a7c2fe555 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
@@ -163,6 +163,7 @@ struct rkvdec_vp9_ctx {
struct v4l2_vp9_frame_context frame_context[4];
struct rkvdec_vp9_frame_info cur;
struct rkvdec_vp9_frame_info last;
+ struct rkvdec_regs regs;
};

static void write_coeff_plane(const u8 coef[6][6][3], u8 *coeff_plane)
@@ -347,38 +348,6 @@ static void init_probs(struct rkvdec_ctx *ctx,
init_inter_probs(ctx, run);
}

-struct rkvdec_vp9_ref_reg {
- u32 reg_frm_size;
- u32 reg_hor_stride;
- u32 reg_y_stride;
- u32 reg_yuv_stride;
- u32 reg_ref_base;
-};
-
-static struct rkvdec_vp9_ref_reg ref_regs[] = {
- {
- .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(0),
- .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(0),
- .reg_y_stride = RKVDEC_VP9_LAST_FRAME_YSTRIDE,
- .reg_yuv_stride = RKVDEC_VP9_LAST_FRAME_YUVSTRIDE,
- .reg_ref_base = RKVDEC_REG_VP9_LAST_FRAME_BASE,
- },
- {
- .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(1),
- .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(1),
- .reg_y_stride = RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE,
- .reg_yuv_stride = 0,
- .reg_ref_base = RKVDEC_REG_VP9_GOLDEN_FRAME_BASE,
- },
- {
- .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(2),
- .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(2),
- .reg_y_stride = RKVDEC_VP9_ALTREF_FRAME_YSTRIDE,
- .reg_yuv_stride = 0,
- .reg_ref_base = RKVDEC_REG_VP9_ALTREF_FRAME_BASE,
- }
-};
-
static struct rkvdec_decoded_buffer *
get_ref_buf(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
{
@@ -412,18 +381,17 @@ static dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf)
static void config_ref_registers(struct rkvdec_ctx *ctx,
const struct rkvdec_vp9_run *run,
struct rkvdec_decoded_buffer *ref_buf,
- struct rkvdec_vp9_ref_reg *ref_reg)
+ int i)
{
unsigned int aligned_pitch, aligned_height, y_len, yuv_len;
- struct rkvdec_dev *rkvdec = ctx->dev;
+ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+ struct rkvdec_regs *regs = &vp9_ctx->regs;

aligned_height = round_up(ref_buf->vp9.height, 64);
- writel_relaxed(RKVDEC_VP9_FRAMEWIDTH(ref_buf->vp9.width) |
- RKVDEC_VP9_FRAMEHEIGHT(ref_buf->vp9.height),
- rkvdec->regs + ref_reg->reg_frm_size);
+ regs->vp9.reg17_19[i].frameheight = ref_buf->vp9.height;
+ regs->vp9.reg17_19[i].framewidth = ref_buf->vp9.width;

- writel_relaxed(vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0),
- rkvdec->regs + ref_reg->reg_ref_base);
+ regs->vp9.refer_bases[i] = vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0);

if (&ref_buf->base.vb == run->base.bufs.dst)
return;
@@ -432,59 +400,50 @@ static void config_ref_registers(struct rkvdec_ctx *ctx,
y_len = aligned_height * aligned_pitch;
yuv_len = (y_len * 3) / 2;

- writel_relaxed(RKVDEC_HOR_Y_VIRSTRIDE(aligned_pitch / 16) |
- RKVDEC_HOR_UV_VIRSTRIDE(aligned_pitch / 16),
- rkvdec->regs + ref_reg->reg_hor_stride);
- writel_relaxed(RKVDEC_VP9_REF_YSTRIDE(y_len / 16),
- rkvdec->regs + ref_reg->reg_y_stride);
-
- if (!ref_reg->reg_yuv_stride)
- return;
+ regs->vp9.reg37_39[i].y_hor_virstride = aligned_pitch / 16;
+ regs->vp9.reg37_39[i].uv_hor_virstride = aligned_pitch / 16;
+ regs->vp9.reg48_50[i].virstride = y_len / 16;

- writel_relaxed(RKVDEC_VP9_REF_YUVSTRIDE(yuv_len / 16),
- rkvdec->regs + ref_reg->reg_yuv_stride);
+ if (!i)
+ regs->vp9.reg51.lastref_yuv_virstride = yuv_len / 16;
}

static void config_seg_registers(struct rkvdec_ctx *ctx, unsigned int segid)
{
struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+ struct rkvdec_regs *regs = &vp9_ctx->regs;
const struct v4l2_vp9_segmentation *seg;
- struct rkvdec_dev *rkvdec = ctx->dev;
s16 feature_val;
int feature_id;
- u32 val = 0;

seg = vp9_ctx->last.valid ? &vp9_ctx->last.seg : &vp9_ctx->cur.seg;
feature_id = V4L2_VP9_SEG_LVL_ALT_Q;
if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
feature_val = seg->feature_data[segid][feature_id];
- val |= RKVDEC_SEGID_FRAME_QP_DELTA_EN(1) |
- RKVDEC_SEGID_FRAME_QP_DELTA(feature_val);
+ regs->vp9.reg20_27[segid].segid_frame_qp_delta_en = 1;
+ regs->vp9.reg20_27[segid].segid_frame_qp_delta = feature_val;
}

feature_id = V4L2_VP9_SEG_LVL_ALT_L;
if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
feature_val = seg->feature_data[segid][feature_id];
- val |= RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(1) |
- RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(feature_val);
+ regs->vp9.reg20_27[segid].segid_frame_loopfilter_value_en = 1;
+ regs->vp9.reg20_27[segid].segid_frame_loopfilter_value = feature_val;
}

feature_id = V4L2_VP9_SEG_LVL_REF_FRAME;
if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
feature_val = seg->feature_data[segid][feature_id];
- val |= RKVDEC_SEGID_REFERINFO_EN(1) |
- RKVDEC_SEGID_REFERINFO(feature_val);
+ regs->vp9.reg20_27[segid].segid_referinfo_en = 1;
+ regs->vp9.reg20_27[segid].segid_referinfo = feature_val;
}

feature_id = V4L2_VP9_SEG_LVL_SKIP;
- if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid))
- val |= RKVDEC_SEGID_FRAME_SKIP_EN(1);
-
- if (!segid &&
- (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE))
- val |= RKVDEC_SEGID_ABS_DELTA(1);
+ regs->vp9.reg20_27[segid].segid_frame_skip_en =
+ v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid);

- writel_relaxed(val, rkvdec->regs + RKVDEC_VP9_SEGID_GRP(segid));
+ regs->vp9.reg20_27[segid].segid_abs_delta = !segid &&
+ (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE);
}

static void update_dec_buf_info(struct rkvdec_decoded_buffer *buf,
@@ -521,7 +480,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
struct rkvdec_decoded_buffer *ref_bufs[3];
struct rkvdec_decoded_buffer *dst, *last, *mv_ref;
struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
- u32 val, last_frame_info = 0;
+ struct rkvdec_regs *regs = &vp9_ctx->regs;
const struct v4l2_vp9_segmentation *seg;
struct rkvdec_dev *rkvdec = ctx->dev;
dma_addr_t addr;
@@ -547,8 +506,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
(V4L2_VP9_FRAME_FLAG_KEY_FRAME |
V4L2_VP9_FRAME_FLAG_INTRA_ONLY));

- writel_relaxed(RKVDEC_MODE(RKVDEC_MODE_VP9),
- rkvdec->regs + RKVDEC_REG_SYSCTRL);
+ regs->common.reg02.dec_mode = RKVDEC_MODE_VP9;

bit_depth = dec_params->bit_depth;
aligned_height = round_up(ctx->decoded_fmt.fmt.pix_mp.height, 64);
@@ -560,17 +518,14 @@ static void config_registers(struct rkvdec_ctx *ctx,
uv_len = y_len / 2;
yuv_len = y_len + uv_len;

- writel_relaxed(RKVDEC_Y_HOR_VIRSTRIDE(aligned_pitch / 16) |
- RKVDEC_UV_HOR_VIRSTRIDE(aligned_pitch / 16),
- rkvdec->regs + RKVDEC_REG_PICPAR);
- writel_relaxed(RKVDEC_Y_VIRSTRIDE(y_len / 16),
- rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
- writel_relaxed(RKVDEC_YUV_VIRSTRIDE(yuv_len / 16),
- rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
+ regs->common.reg03.y_hor_virstride = aligned_pitch / 16;
+ regs->common.reg03.uv_hor_virstride = aligned_pitch / 16;
+ regs->common.reg08.y_virstride = y_len / 16;
+ regs->common.reg09.yuv_virstride = yuv_len / 16;

stream_len = vb2_get_plane_payload(&run->base.bufs.src->vb2_buf, 0);
- writel_relaxed(RKVDEC_STRM_LEN(stream_len),
- rkvdec->regs + RKVDEC_REG_STRM_LEN);
+
+ regs->common.stream_len = stream_len;

/*
* Reset count buffer, because decoder only output intra related syntax
@@ -588,14 +543,13 @@ static void config_registers(struct rkvdec_ctx *ctx,
vp9_ctx->cur.segmapid++;

for (i = 0; i < ARRAY_SIZE(ref_bufs); i++)
- config_ref_registers(ctx, run, ref_bufs[i], &ref_regs[i]);
+ config_ref_registers(ctx, run, ref_bufs[i], i);

for (i = 0; i < 8; i++)
config_seg_registers(ctx, i);

- writel_relaxed(RKVDEC_VP9_TX_MODE(vp9_ctx->cur.tx_mode) |
- RKVDEC_VP9_FRAME_REF_MODE(dec_params->reference_mode),
- rkvdec->regs + RKVDEC_VP9_CPRHEADER_CONFIG);
+ regs->vp9.reg28.tx_mode = vp9_ctx->cur.tx_mode;
+ regs->vp9.reg28.frame_reference_mode = dec_params->reference_mode;

if (!intra_only) {
const struct v4l2_vp9_loop_filter *lf;
@@ -606,46 +560,58 @@ static void config_registers(struct rkvdec_ctx *ctx,
else
lf = &vp9_ctx->cur.lf;

- val = 0;
for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) {
delta = lf->ref_deltas[i];
- val |= RKVDEC_REF_DELTAS_LASTFRAME(i, delta);
+ switch (i) {
+ case 0:
+ regs->vp9.reg32.ref_deltas_lastframe0 = delta;
+ break;
+ case 1:
+ regs->vp9.reg32.ref_deltas_lastframe1 = delta;
+ break;
+ case 2:
+ regs->vp9.reg32.ref_deltas_lastframe2 = delta;
+ break;
+ case 3:
+ regs->vp9.reg32.ref_deltas_lastframe3 = delta;
+ break;
+ }
}

- writel_relaxed(val,
- rkvdec->regs + RKVDEC_VP9_REF_DELTAS_LASTFRAME);
-
for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) {
delta = lf->mode_deltas[i];
- last_frame_info |= RKVDEC_MODE_DELTAS_LASTFRAME(i,
- delta);
+ switch (i) {
+ case 0:
+ regs->vp9.reg33.mode_deltas_lastframe0 = delta;
+ break;
+ case 1:
+ regs->vp9.reg33.mode_deltas_lastframe1 = delta;
+ break;
+ }
}
}

- if (vp9_ctx->last.valid && !intra_only &&
- vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED)
- last_frame_info |= RKVDEC_SEG_EN_LASTFRAME;
+ regs->vp9.reg33.segmentation_enable_lstframe =
+ vp9_ctx->last.valid && !intra_only &&
+ vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED;

- if (vp9_ctx->last.valid &&
- vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME)
- last_frame_info |= RKVDEC_LAST_SHOW_FRAME;
+ regs->vp9.reg33.last_show_frame =
+ vp9_ctx->last.valid &&
+ vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME;

- if (vp9_ctx->last.valid &&
- vp9_ctx->last.flags &
- (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY))
- last_frame_info |= RKVDEC_LAST_INTRA_ONLY;
+ regs->vp9.reg33.last_intra_only =
+ vp9_ctx->last.valid &&
+ vp9_ctx->last.flags &
+ (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY);

- if (vp9_ctx->last.valid &&
- last->vp9.width == dst->vp9.width &&
- last->vp9.height == dst->vp9.height)
- last_frame_info |= RKVDEC_LAST_WIDHHEIGHT_EQCUR;
+ regs->vp9.reg33.last_widthheight_eqcur =
+ vp9_ctx->last.valid &&
+ last->vp9.width == dst->vp9.width &&
+ last->vp9.height == dst->vp9.height;

- writel_relaxed(last_frame_info,
- rkvdec->regs + RKVDEC_VP9_INFO_LASTFRAME);
-
- writel_relaxed(stream_len - dec_params->compressed_header_size -
- dec_params->uncompressed_header_size,
- rkvdec->regs + RKVDEC_VP9_LASTTILE_SIZE);
+ regs->vp9.reg36.lasttile_size =
+ stream_len - dec_params->compressed_header_size -
+ dec_params->uncompressed_header_size;

for (i = 0; !intra_only && i < ARRAY_SIZE(ref_bufs); i++) {
unsigned int refw = ref_bufs[i]->vp9.width;
@@ -654,29 +620,28 @@ static void config_registers(struct rkvdec_ctx *ctx,

hscale = (refw << 14) / dst->vp9.width;
vscale = (refh << 14) / dst->vp9.height;
- writel_relaxed(RKVDEC_VP9_REF_HOR_SCALE(hscale) |
- RKVDEC_VP9_REF_VER_SCALE(vscale),
- rkvdec->regs + RKVDEC_VP9_REF_SCALE(i));
+
+ regs->vp9.reg29_31[i].ref_hor_scale = hscale;
+ regs->vp9.reg29_31[i].ref_ver_scale = vscale;
}

addr = vb2_dma_contig_plane_dma_addr(&dst->base.vb.vb2_buf, 0);
- writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
+ regs->common.decout_base = addr;
addr = vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0);
- writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
- writel_relaxed(vp9_ctx->priv_tbl.dma +
- offsetof(struct rkvdec_vp9_priv_tbl, probs),
- rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
- writel_relaxed(vp9_ctx->count_tbl.dma,
- rkvdec->regs + RKVDEC_REG_VP9COUNT_BASE);
-
- writel_relaxed(vp9_ctx->priv_tbl.dma +
- offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
- (RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid),
- rkvdec->regs + RKVDEC_REG_VP9_SEGIDCUR_BASE);
- writel_relaxed(vp9_ctx->priv_tbl.dma +
- offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
- (RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid)),
- rkvdec->regs + RKVDEC_REG_VP9_SEGIDLAST_BASE);
+ regs->common.strm_rlc_base = addr;
+
+ regs->common.cabactbl_base = vp9_ctx->priv_tbl.dma +
+ offsetof(struct rkvdec_vp9_priv_tbl, probs);
+
+ regs->vp9.count_base = vp9_ctx->count_tbl.dma;
+
+ regs->vp9.segidlast_base = vp9_ctx->priv_tbl.dma +
+ offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
+ (RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid));
+
+ regs->vp9.segidcur_base = vp9_ctx->priv_tbl.dma +
+ offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
+ (RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid);

if (!intra_only &&
!(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) &&
@@ -685,12 +650,15 @@ static void config_registers(struct rkvdec_ctx *ctx,
else
mv_ref = dst;

- writel_relaxed(get_mv_base_addr(mv_ref),
- rkvdec->regs + RKVDEC_VP9_REF_COLMV_BASE);
+ regs->vp9.refcolmv_base = get_mv_base_addr(mv_ref);

- writel_relaxed(ctx->decoded_fmt.fmt.pix_mp.width |
- (ctx->decoded_fmt.fmt.pix_mp.height << 16),
- rkvdec->regs + RKVDEC_REG_PERFORMANCE_CYCLE);
+ regs->vp9.performance_cycle = ctx->decoded_fmt.fmt.pix_mp.width |
+ (ctx->decoded_fmt.fmt.pix_mp.height << 16);
+
+ regs->vp9.reg44.strmd_error_e = 0xe;
+
+ rkvdec_memcpy_toio(rkvdec->regs, regs,
+ MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs));
}

static int validate_dec_params(struct rkvdec_ctx *ctx,
@@ -823,8 +791,6 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);

- writel(0xe, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
-
if (rkvdec->variant->quirks & RKVDEC_QUIRK_DISABLE_QOS)
rkvdec_quirks_disable_qos(ctx);

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 5af9aa5ab353b..776149f871b09 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -914,6 +914,15 @@ void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx)
writel(reg, rkvdec->regs + RKVDEC_REG_QOS_CTRL);
}

+void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len)
+{
+#ifdef CONFIG_ARM64
+ __iowrite32_copy(dst, src, len / 4);
+#else
+ memcpy_toio(dst, src, len);
+#endif
+}
+
static void rkvdec_device_run(void *priv)
{
struct rkvdec_ctx *ctx = priv;
@@ -1227,7 +1236,6 @@ static void rkvdec_watchdog_func(struct work_struct *work)
if (ctx) {
dev_err(rkvdec->dev, "Frame processing timed out!\n");
writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT);
- writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL);
rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR);
}
}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 566e06fa2b1ed..f35f6e80ea2e3 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -151,6 +151,7 @@ struct rkvdec_aux_buf {

void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
+void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len);

void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx);

--
2.52.0