diff options
| -rw-r--r-- | drivers/media/platform/rockchip/rkvdec/Makefile | 1 | ||||
| -rw-r--r-- | drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c | 469 | ||||
| -rw-r--r-- | drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h | 430 | ||||
| -rw-r--r-- | drivers/media/platform/rockchip/rkvdec/rkvdec.c | 158 | ||||
| -rw-r--r-- | drivers/media/platform/rockchip/rkvdec/rkvdec.h | 12 |
5 files changed, 1067 insertions, 3 deletions
diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile index 3d75103e536d..7bfd95151e40 100644 --- a/drivers/media/platform/rockchip/rkvdec/Makefile +++ b/drivers/media/platform/rockchip/rkvdec/Makefile @@ -8,4 +8,5 @@ rockchip-vdec-y += \ rkvdec-hevc.o \ rkvdec-hevc-common.o \ rkvdec-rcb.o \ + rkvdec-vdpu381-h264.o \ rkvdec-vp9.o diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c new file mode 100644 index 000000000000..cd0aa3f3a13d --- /dev/null +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip VDPU381 Video Decoder H264 backend + * + * Copyright (C) 2024 Collabora, Ltd. + * Detlev Casanova <detlev.casanova@collabora.com> + */ + +#include <media/v4l2-h264.h> +#include <media/v4l2-mem2mem.h> + +#include "rkvdec.h" +#include "rkvdec-cabac.h" +#include "rkvdec-rcb.h" +#include "rkvdec-h264-common.h" +#include "rkvdec-vdpu381-regs.h" + +struct rkvdec_sps { + u16 seq_parameter_set_id: 4; + u16 profile_idc: 8; + u16 constraint_set3_flag: 1; + u16 chroma_format_idc: 2; + u16 bit_depth_luma: 3; + u16 bit_depth_chroma: 3; + u16 qpprime_y_zero_transform_bypass_flag: 1; + u16 log2_max_frame_num_minus4: 4; + u16 max_num_ref_frames: 5; + u16 pic_order_cnt_type: 2; + u16 log2_max_pic_order_cnt_lsb_minus4: 4; + u16 delta_pic_order_always_zero_flag: 1; + u16 pic_width_in_mbs: 12; + u16 pic_height_in_mbs: 12; + u16 frame_mbs_only_flag: 1; + u16 mb_adaptive_frame_field_flag: 1; + u16 direct_8x8_inference_flag: 1; + u16 mvc_extension_enable: 1; + u16 num_views: 2; + + u16 reserved_bits: 12; + u16 reserved[11]; +} __packed; + +struct rkvdec_pps { + u16 pic_parameter_set_id: 8; + u16 pps_seq_parameter_set_id: 5; + u16 entropy_coding_mode_flag: 1; + u16 bottom_field_pic_order_in_frame_present_flag: 1; + u16 num_ref_idx_l0_default_active_minus1: 5; + u16 num_ref_idx_l1_default_active_minus1: 5; + u16 weighted_pred_flag: 1; + u16 weighted_bipred_idc: 2; + u16 pic_init_qp_minus26: 7; + u16 pic_init_qs_minus26: 6; + u16 chroma_qp_index_offset: 5; + u16 deblocking_filter_control_present_flag: 1; + u16 constrained_intra_pred_flag: 1; + u16 redundant_pic_cnt_present: 1; + u16 transform_8x8_mode_flag: 1; + u16 second_chroma_qp_index_offset: 5; + u16 scaling_list_enable_flag: 1; + u32 scaling_list_address; + u16 is_longterm; + + u8 reserved[3]; +} __packed; + +struct rkvdec_sps_pps { + struct rkvdec_sps sps; + struct rkvdec_pps pps; +} __packed; + +/* Data structure describing auxiliary buffer format. */ +struct rkvdec_h264_priv_tbl { + s8 cabac_table[4][464][2]; + struct rkvdec_h264_scaling_list scaling_list; + struct rkvdec_sps_pps param_set[256]; + struct rkvdec_rps rps; +}; + +struct rkvdec_h264_ctx { + struct rkvdec_aux_buf priv_tbl; + struct rkvdec_h264_reflists reflists; + struct rkvdec_vdpu381_regs_h264 regs; +}; + +static void assemble_hw_pps(struct rkvdec_ctx *ctx, + struct rkvdec_h264_run *run) +{ + struct rkvdec_h264_ctx *h264_ctx = ctx->priv; + const struct v4l2_ctrl_h264_sps *sps = run->sps; + const struct v4l2_ctrl_h264_pps *pps = run->pps; + const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params; + const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb; + struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu; + struct rkvdec_sps_pps *hw_ps; + dma_addr_t scaling_list_address; + u32 scaling_distance; + u32 i; + + /* + * HW read the SPS/PPS information from PPS packet index by PPS id. + * offset from the base can be calculated by PPS_id * 32 (size per PPS + * packet unit). so the driver copy SPS/PPS information to the exact PPS + * packet unit for HW accessing. + */ + hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id]; + memset(hw_ps, 0, sizeof(*hw_ps)); + + /* write sps */ + hw_ps->sps.seq_parameter_set_id = sps->seq_parameter_set_id; + hw_ps->sps.profile_idc = sps->profile_idc; + hw_ps->sps.constraint_set3_flag = !!(sps->constraint_set_flags & (1 << 3)); + hw_ps->sps.chroma_format_idc = sps->chroma_format_idc; + hw_ps->sps.bit_depth_luma = sps->bit_depth_luma_minus8; + hw_ps->sps.bit_depth_chroma = sps->bit_depth_chroma_minus8; + hw_ps->sps.qpprime_y_zero_transform_bypass_flag = + !!(sps->flags & V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS); + hw_ps->sps.log2_max_frame_num_minus4 = sps->log2_max_frame_num_minus4; + hw_ps->sps.max_num_ref_frames = sps->max_num_ref_frames; + hw_ps->sps.pic_order_cnt_type = sps->pic_order_cnt_type; + hw_ps->sps.log2_max_pic_order_cnt_lsb_minus4 = + sps->log2_max_pic_order_cnt_lsb_minus4; + hw_ps->sps.delta_pic_order_always_zero_flag = + !!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO); + hw_ps->sps.mvc_extension_enable = 1; + hw_ps->sps.num_views = 1; + + /* + * Use the SPS values since they are already in macroblocks + * dimensions, height can be field height (halved) if + * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is not set and also it allows + * decoding smaller images into larger allocation which can be used + * to implementing SVC spatial layer support. + */ + hw_ps->sps.pic_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1; + hw_ps->sps.pic_height_in_mbs = sps->pic_height_in_map_units_minus1 + 1; + hw_ps->sps.frame_mbs_only_flag = + !!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY); + hw_ps->sps.mb_adaptive_frame_field_flag = + !!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD); + hw_ps->sps.direct_8x8_inference_flag = + !!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE); + + /* write pps */ + hw_ps->pps.pic_parameter_set_id = pps->pic_parameter_set_id; + hw_ps->pps.pps_seq_parameter_set_id = pps->seq_parameter_set_id; + hw_ps->pps.entropy_coding_mode_flag = + !!(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE); + hw_ps->pps.bottom_field_pic_order_in_frame_present_flag = + !!(pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT); + hw_ps->pps.num_ref_idx_l0_default_active_minus1 = + pps->num_ref_idx_l0_default_active_minus1; + hw_ps->pps.num_ref_idx_l1_default_active_minus1 = + pps->num_ref_idx_l1_default_active_minus1; + hw_ps->pps.weighted_pred_flag = + !!(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED); + hw_ps->pps.weighted_bipred_idc = pps->weighted_bipred_idc; + hw_ps->pps.pic_init_qp_minus26 = pps->pic_init_qp_minus26; + hw_ps->pps.pic_init_qs_minus26 = pps->pic_init_qs_minus26; + hw_ps->pps.chroma_qp_index_offset = pps->chroma_qp_index_offset; + hw_ps->pps.deblocking_filter_control_present_flag = + !!(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT); + hw_ps->pps.constrained_intra_pred_flag = + !!(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED); + hw_ps->pps.redundant_pic_cnt_present = + !!(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT); + hw_ps->pps.transform_8x8_mode_flag = + !!(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE); + hw_ps->pps.second_chroma_qp_index_offset = pps->second_chroma_qp_index_offset; + hw_ps->pps.scaling_list_enable_flag = + !!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT); + + /* + * To be on the safe side, program the scaling matrix address + */ + scaling_distance = offsetof(struct rkvdec_h264_priv_tbl, scaling_list); + scaling_list_address = h264_ctx->priv_tbl.dma + scaling_distance; + hw_ps->pps.scaling_list_address = scaling_list_address; + + for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + hw_ps->pps.is_longterm |= (1 << i); + } +} + +static void rkvdec_write_regs(struct rkvdec_ctx *ctx) +{ + struct rkvdec_dev *rkvdec = ctx->dev; + struct rkvdec_h264_ctx *h264_ctx = ctx->priv; + + rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS, + &h264_ctx->regs.common, + sizeof(h264_ctx->regs.common)); + rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS, + &h264_ctx->regs.h264_param, + sizeof(h264_ctx->regs.h264_param)); + rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS, + &h264_ctx->regs.common_addr, + sizeof(h264_ctx->regs.common_addr)); + rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS, + &h264_ctx->regs.h264_addr, + sizeof(h264_ctx->regs.h264_addr)); + rkvdec_memcpy_toio(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS, + &h264_ctx->regs.h264_highpoc, + sizeof(h264_ctx->regs.h264_highpoc)); +} + +static void config_registers(struct rkvdec_ctx *ctx, + struct rkvdec_h264_run *run) +{ + const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params; + const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb; + struct rkvdec_h264_ctx *h264_ctx = ctx->priv; + dma_addr_t priv_start_addr = h264_ctx->priv_tbl.dma; + const struct v4l2_pix_format_mplane *dst_fmt; + struct vb2_v4l2_buffer *src_buf = run->base.bufs.src; + struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst; + struct rkvdec_vdpu381_regs_h264 *regs = &h264_ctx->regs; + const struct v4l2_format *f; + dma_addr_t rlc_addr; + dma_addr_t dst_addr; + u32 hor_virstride; + u32 ver_virstride; + u32 y_virstride; + u32 offset; + u32 pixels; + u32 i; + + memset(regs, 0, sizeof(*regs)); + + /* Set H264 mode */ + regs->common.reg009_dec_mode.dec_mode = VDPU381_MODE_H264; + + /* Set config */ + regs->common.reg011_important_en.buf_empty_en = 1; + regs->common.reg011_important_en.dec_clkgate_e = 1; + regs->common.reg011_important_en.dec_timeout_e = 1; + regs->common.reg011_important_en.pix_range_det_e = 1; + + /* + * Even though the scan list address can be set in RPS, + * with some frames, it will try to use the address set in the register. + */ + regs->common.reg012_secondary_en.scanlist_addr_valid_en = 1; + + /* Set IDR flag */ + regs->common.reg013_en_mode_set.cur_pic_is_idr = + !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC); + + /* Set input stream length */ + regs->common.reg016_stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0); + + /* Set max slice number */ + regs->common.reg017_slice_number.slice_num = MAX_SLICE_NUMBER; + + /* Set strides */ + f = &ctx->decoded_fmt; + dst_fmt = &f->fmt.pix_mp; + hor_virstride = dst_fmt->plane_fmt[0].bytesperline; + ver_virstride = dst_fmt->height; + y_virstride = hor_virstride * ver_virstride; + + regs->common.reg018_y_hor_stride.y_hor_virstride = hor_virstride / 16; + regs->common.reg019_uv_hor_stride.uv_hor_virstride = hor_virstride / 16; + regs->common.reg020_y_stride.y_virstride = y_virstride / 16; + + /* Activate block gating */ + regs->common.reg026_block_gating_en.inter_auto_gating_e = 1; + regs->common.reg026_block_gating_en.filterd_auto_gating_e = 1; + regs->common.reg026_block_gating_en.strmd_auto_gating_e = 1; + regs->common.reg026_block_gating_en.mcp_auto_gating_e = 1; + regs->common.reg026_block_gating_en.busifd_auto_gating_e = 0; + regs->common.reg026_block_gating_en.dec_ctrl_auto_gating_e = 1; + regs->common.reg026_block_gating_en.intra_auto_gating_e = 1; + regs->common.reg026_block_gating_en.mc_auto_gating_e = 1; + regs->common.reg026_block_gating_en.transd_auto_gating_e = 1; + regs->common.reg026_block_gating_en.sram_auto_gating_e = 1; + regs->common.reg026_block_gating_en.cru_auto_gating_e = 1; + regs->common.reg026_block_gating_en.reg_cfg_gating_en = 1; + + /* Set timeout threshold */ + pixels = dst_fmt->height * dst_fmt->width; + if (pixels < RKVDEC_1080P_PIXELS) + regs->common.reg032_timeout_threshold = RKVDEC_TIMEOUT_1080p; + else if (pixels < RKVDEC_4K_PIXELS) + regs->common.reg032_timeout_threshold = RKVDEC_TIMEOUT_4K; + else if (pixels < RKVDEC_8K_PIXELS) + regs->common.reg032_timeout_threshold = RKVDEC_TIMEOUT_8K; + else + regs->common.reg032_timeout_threshold = RKVDEC_TIMEOUT_MAX; + + /* Set TOP and BOTTOM POCs */ + regs->h264_param.reg065_cur_top_poc = dec_params->top_field_order_cnt; + regs->h264_param.reg066_cur_bot_poc = dec_params->bottom_field_order_cnt; + + /* Set ref pic address & poc */ + for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { + struct vb2_buffer *vb_buf = run->ref_buf[i]; + dma_addr_t buf_dma; + + /* + * If a DPB entry is unused or invalid, address of current destination + * buffer is returned. + */ + if (!vb_buf) + vb_buf = &dst_buf->vb2_buf; + + buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0); + + /* Set reference addresses */ + regs->h264_addr.reg164_180_ref_base[i] = buf_dma; + + /* Set COLMV addresses */ + regs->h264_addr.reg182_198_colmv_base[i] = buf_dma + ctx->colmv_offset; + + struct rkvdec_vdpu381_h264_ref_info *ref_info = + ®s->h264_param.reg099_102_ref_info_regs[i / 4].ref_info[i % 4]; + + ref_info->ref_field = + !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD); + ref_info->ref_colmv_use_flag = + !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE); + ref_info->ref_topfield_used = + !!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF); + ref_info->ref_botfield_used = + !!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF); + + regs->h264_param.reg067_098_ref_poc[i * 2] = + dpb[i].top_field_order_cnt; + regs->h264_param.reg067_098_ref_poc[i * 2 + 1] = + dpb[i].bottom_field_order_cnt; + } + + /* Set rlc base address (input stream) */ + rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + regs->common_addr.rlc_base = rlc_addr; + regs->common_addr.rlcwrite_base = rlc_addr; + + /* Set output base address */ + dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + regs->common_addr.decout_base = dst_addr; + regs->common_addr.error_ref_base = dst_addr; + + /* Set colmv address */ + regs->common_addr.colmv_cur_base = dst_addr + ctx->colmv_offset; + + /* Set RCB addresses */ + for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++) + regs->common_addr.rcb_base[i] = rkvdec_rcb_buf_dma_addr(ctx, i); + + /* Set hw pps address */ + offset = offsetof(struct rkvdec_h264_priv_tbl, param_set); + regs->h264_addr.reg161_pps_base = priv_start_addr + offset; + + /* Set hw rps address */ + offset = offsetof(struct rkvdec_h264_priv_tbl, rps); + regs->h264_addr.reg163_rps_base = priv_start_addr + offset; + + /* Set cabac table */ + offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table); + regs->h264_addr.reg199_cabactbl_base = priv_start_addr + offset; + + offset = offsetof(struct rkvdec_h264_priv_tbl, scaling_list); + regs->h264_addr.reg181_scanlist_addr = priv_start_addr + offset; + + rkvdec_write_regs(ctx); +} + +static int rkvdec_h264_start(struct rkvdec_ctx *ctx) +{ + struct rkvdec_dev *rkvdec = ctx->dev; + struct rkvdec_h264_priv_tbl *priv_tbl; + struct rkvdec_h264_ctx *h264_ctx; + struct v4l2_ctrl *ctrl; + int ret; + + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, + V4L2_CID_STATELESS_H264_SPS); + if (!ctrl) + return -EINVAL; + + ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps); + if (ret) + return ret; + + h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL); + if (!h264_ctx) + return -ENOMEM; + + priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), + &h264_ctx->priv_tbl.dma, GFP_KERNEL); + if (!priv_tbl) { + ret = -ENOMEM; + goto err_free_ctx; + } + + h264_ctx->priv_tbl.size = sizeof(*priv_tbl); + h264_ctx->priv_tbl.cpu = priv_tbl; + memcpy(priv_tbl->cabac_table, rkvdec_h264_cabac_table, + sizeof(rkvdec_h264_cabac_table)); + + ctx->priv = h264_ctx; + return 0; + +err_free_ctx: + kfree(h264_ctx); + return ret; +} + +static void rkvdec_h264_stop(struct rkvdec_ctx *ctx) +{ + struct rkvdec_h264_ctx *h264_ctx = ctx->priv; + struct rkvdec_dev *rkvdec = ctx->dev; + + dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size, + h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma); + kfree(h264_ctx); +} + +static int rkvdec_h264_run(struct rkvdec_ctx *ctx) +{ + struct v4l2_h264_reflist_builder reflist_builder; + struct rkvdec_dev *rkvdec = ctx->dev; + struct rkvdec_h264_ctx *h264_ctx = ctx->priv; + struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu; + struct rkvdec_h264_run run; + + rkvdec_h264_run_preamble(ctx, &run); + + /* Build the P/B{0,1} ref lists. */ + v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params, + run.sps, run.decode_params->dpb); + v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p); + v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0, + h264_ctx->reflists.b1); + + assemble_hw_scaling_list(&run, &tbl->scaling_list); + assemble_hw_pps(ctx, &run); + lookup_ref_buf_idx(ctx, &run); + assemble_hw_rps(&reflist_builder, &run, &h264_ctx->reflists, &tbl->rps); + + config_registers(ctx, &run); + + rkvdec_run_postamble(ctx, &run.base); + + rkvdec_schedule_watchdog(rkvdec, h264_ctx->regs.common.reg032_timeout_threshold); + + /* Start decoding! */ + writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E); + + return 0; +} + +static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl) +{ + if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) + return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps); + + return 0; +} + +const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops = { + .adjust_fmt = rkvdec_h264_adjust_fmt, + .get_image_fmt = rkvdec_h264_get_image_fmt, + .start = rkvdec_h264_start, + .stop = rkvdec_h264_stop, + .run = rkvdec_h264_run, + .try_ctrl = rkvdec_h264_try_ctrl, +}; diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h new file mode 100644 index 000000000000..6da36031df2d --- /dev/null +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h @@ -0,0 +1,430 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip VDPU381 Video Decoder driver registers description + * + * Copyright (C) 2024 Collabora, Ltd. + * Detlev Casanova <detlev.casanova@collabora.com> + */ + +#include <linux/types.h> + +#ifndef _RKVDEC_REGS_H_ +#define _RKVDEC_REGS_H_ + +#define OFFSET_COMMON_REGS (8 * sizeof(u32)) +#define OFFSET_CODEC_PARAMS_REGS (64 * sizeof(u32)) +#define OFFSET_COMMON_ADDR_REGS (128 * sizeof(u32)) +#define OFFSET_CODEC_ADDR_REGS (160 * sizeof(u32)) +#define OFFSET_POC_HIGHBIT_REGS (200 * sizeof(u32)) + +#define VDPU381_MODE_HEVC 0 +#define VDPU381_MODE_H264 1 +#define VDPU381_MODE_VP9 2 +#define VDPU381_MODE_AVS2 3 + +#define MAX_SLICE_NUMBER 0x3fff + +#define RKVDEC_TIMEOUT_1080p (0xefffff) +#define RKVDEC_TIMEOUT_4K (0x2cfffff) +#define RKVDEC_TIMEOUT_8K (0x4ffffff) +#define RKVDEC_TIMEOUT_MAX (0xffffffff) + +#define VDPU381_REG_DEC_E 0x028 +#define VDPU381_DEC_E_BIT 1 + +#define VDPU381_REG_IMPORTANT_EN 0x02c +#define VDPU381_DEC_IRQ_DISABLE BIT(4) + +#define VDPU381_REG_STA_INT 0x380 +#define VDPU381_STA_INT_DEC_RDY_STA BIT(2) +#define VDPU381_STA_INT_ERROR BIT(4) +#define VDPU381_STA_INT_TIMEOUT BIT(5) +#define VDPU381_STA_INT_SOFTRESET_RDY BIT(9) + +/* base: OFFSET_COMMON_REGS */ +struct rkvdec_vdpu381_regs_common { + struct { + 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 out_swap64_e : 1; + u32 reserved : 22; + } reg008_in_out; + + struct { + u32 dec_mode : 10; + u32 reserved : 22; + } reg009_dec_mode; + + struct { + u32 dec_e : 1; + u32 reserved : 31; + } reg010_dec_e; + + struct { + u32 reserved0 : 1; + u32 dec_clkgate_e : 1; + u32 dec_e_strmd_clkgate_dis : 1; + u32 reserved1 : 1; + + u32 dec_irq_dis : 1; + u32 dec_timeout_e : 1; + u32 buf_empty_en : 1; + u32 reserved2 : 3; + + u32 dec_e_rewrite_valid : 1; + u32 reserved3 : 9; + u32 softrst_en_p : 1; + u32 force_softreset_valid : 1; + u32 reserved4 : 2; + u32 pix_range_det_e : 1; + u32 reserved5 : 7; + } reg011_important_en; + + struct { + u32 reserved0 : 1; + u32 colmv_compress_en : 1; + u32 fbc_e : 1; + u32 reserved1 : 1; + + u32 buspr_slot_disable : 1; + u32 error_info_en : 1; + u32 collect_info_en : 1; + u32 error_auto_rst_disable : 1; + + u32 scanlist_addr_valid_en : 1; + u32 scale_down_en : 1; + u32 error_cfg_wr_disable : 1; + u32 reserved2 : 21; + } reg012_secondary_en; + + struct { + u32 reserved0 : 1; + u32 req_timeout_rst_sel : 1; + u32 reserved1 : 1; + u32 dec_commonirq_mode : 1; + u32 reserved2 : 2; + u32 stmerror_waitdecfifo_empty : 1; + u32 reserved3 : 5; + u32 allow_not_wr_unref_bframe : 1; + u32 fbc_output_wr_disable : 1; + u32 reserved4 : 4; + u32 error_mode : 1; + u32 reserved5 : 2; + u32 ycacherd_prior : 1; + u32 reserved6 : 2; + u32 cur_pic_is_idr : 1; + u32 reserved7 : 1; + u32 right_auto_rst_disable : 1; + u32 frame_end_err_rst_flag : 1; + u32 rd_prior_mode : 1; + u32 rd_ctrl_prior_mode : 1; + u32 reserved8 : 1; + u32 filter_outbuf_mode : 1; + } reg013_en_mode_set; + + struct { + u32 fbc_force_uncompress : 1; + + u32 reserved0 : 2; + u32 allow_16x8_cp_flag : 1; + u32 reserved1 : 2; + + u32 fbc_h264_exten_4or8_flag : 1; + u32 reserved2 : 25; + } reg014_fbc_param_set; + + struct { + u32 rlc_mode_direct_write : 1; + u32 rlc_mode : 1; + u32 reserved0 : 3; + + u32 strm_start_bit : 7; + u32 reserved1 : 20; + } reg015_stream_param_set; + + u32 reg016_stream_len; + + struct { + u32 slice_num : 25; + u32 reserved : 7; + } reg017_slice_number; + + struct { + u32 y_hor_virstride : 16; + u32 reserved : 16; + } reg018_y_hor_stride; + + struct { + u32 uv_hor_virstride : 16; + u32 reserved : 16; + } reg019_uv_hor_stride; + + struct { + u32 y_virstride : 28; + u32 reserved : 4; + } reg020_y_stride; + + struct { + u32 inter_error_prc_mode : 1; + u32 error_intra_mode : 1; + u32 error_deb_en : 1; + u32 picidx_replace : 5; + u32 error_spread_e : 1; + u32 reserved0 : 3; + u32 error_inter_pred_cross_slice : 1; + u32 reserved1 : 11; + u32 roi_error_ctu_cal_en : 1; + u32 reserved2 : 7; + } reg021_error_ctrl_set; + + struct { + u32 roi_x_ctu_offset_st : 12; + u32 reserved0 : 4; + u32 roi_y_ctu_offset_st : 12; + u32 reserved1 : 4; + } reg022_err_roi_ctu_offset_start; + + struct { + u32 roi_x_ctu_offset_end : 12; + u32 reserved0 : 4; + u32 roi_y_ctu_offset_end : 12; + u32 reserved1 : 4; + } reg023_err_roi_ctu_offset_end; + + struct { + u32 cabac_err_en_lowbits : 32; + } reg024_cabac_error_en_lowbits; + + struct { + u32 cabac_err_en_highbits : 30; + u32 reserved : 2; + } reg025_cabac_error_en_highbits; + + struct { + u32 inter_auto_gating_e : 1; + u32 filterd_auto_gating_e : 1; + u32 strmd_auto_gating_e : 1; + u32 mcp_auto_gating_e : 1; + u32 busifd_auto_gating_e : 1; + u32 reserved0 : 3; + u32 dec_ctrl_auto_gating_e : 1; + u32 intra_auto_gating_e : 1; + u32 mc_auto_gating_e : 1; + u32 transd_auto_gating_e : 1; + u32 reserved1 : 4; + u32 sram_auto_gating_e : 1; + u32 cru_auto_gating_e : 1; + u32 reserved2 : 13; + u32 reg_cfg_gating_en : 1; + } reg026_block_gating_en; + + struct { + u32 core_safe_x_pixels : 16; + u32 core_safe_y_pixels : 16; + } reg027_core_safe_pixels; + + struct { + u32 vp9_wr_prob_idx : 3; + u32 reserved0 : 1; + u32 vp9_rd_prob_idx : 3; + u32 reserved1 : 1; + + u32 ref_req_advance_flag : 1; + u32 colmv_req_advance_flag : 1; + u32 poc_only_highbit_flag : 1; + u32 poc_arb_flag : 1; + + u32 reserved2 : 4; + u32 film_idx : 10; + u32 reserved3 : 2; + u32 pu_req_mismatch_dis : 1; + u32 colmv_req_mismatch_dis : 1; + u32 reserved4 : 2; + } reg028_multiply_core_ctrl; + + struct { + u32 scale_down_hor_ratio : 2; + u32 reserved0 : 6; + u32 scale_down_vrz_ratio : 2; + u32 reserved1 : 22; + } reg029_scale_down_ctrl; + + struct { + u32 y_scale_down_tile8x8_hor_stride : 20; + u32 reserved0 : 12; + } reg030_y_scale_down_tile8x8_hor_stride; + + struct { + u32 uv_scale_down8x8_tile_hor_stride : 20; + u32 reserved0 : 12; + } reg031_uv_scale_down_tile8x8_hor_stride; + + u32 reg032_timeout_threshold; +} __packed; + +/* base: OFFSET_COMMON_ADDR_REGS */ +struct rkvdec_vdpu381_regs_common_addr { + u32 rlc_base; + u32 rlcwrite_base; + u32 decout_base; + u32 colmv_cur_base; + u32 error_ref_base; + u32 rcb_base[10]; +} __packed; + +struct rkvdec_vdpu381_h26x_set { + u32 h26x_frame_orslice : 1; + u32 h26x_rps_mode : 1; + u32 h26x_stream_mode : 1; + u32 h26x_stream_lastpacket : 1; + u32 h264_firstslice_flag : 1; + u32 reserved : 27; +} __packed; + +/* base: OFFSET_CODEC_PARAMS_REGS */ +struct rkvdec_vdpu381_regs_h264_params { + struct rkvdec_vdpu381_h26x_set reg064_h26x_set; + + u32 reg065_cur_top_poc; + u32 reg066_cur_bot_poc; + u32 reg067_098_ref_poc[32]; + + struct rkvdec_vdpu381_h264_info { + struct rkvdec_vdpu381_h264_ref_info { + u32 ref_field : 1; + u32 ref_topfield_used : 1; + u32 ref_botfield_used : 1; + u32 ref_colmv_use_flag : 1; + u32 reserved : 4; + } __packed ref_info[4]; + } __packed reg099_102_ref_info_regs[4]; + + u32 reserved_103_111[9]; + + struct { + u32 avs2_ref_error_field : 1; + u32 avs2_ref_error_topfield : 1; + u32 ref_error_topfield_used : 1; + u32 ref_error_botfield_used : 1; + u32 reserved : 28; + } reg112_error_ref_info; +} __packed; + +struct rkvdec_vdpu381_regs_hevc_params { + struct rkvdec_vdpu381_h26x_set reg064_h26x_set; + + u32 reg065_cur_top_poc; + u32 reg066_cur_bot_poc; + u32 reg067_082_ref_poc[16]; + + u32 reserved_083_098[16]; + + struct { + u32 hevc_ref_valid_0 : 1; + u32 hevc_ref_valid_1 : 1; + u32 hevc_ref_valid_2 : 1; + u32 hevc_ref_valid_3 : 1; + u32 reserve0 : 4; + u32 hevc_ref_valid_4 : 1; + u32 hevc_ref_valid_5 : 1; + u32 hevc_ref_valid_6 : 1; + u32 hevc_ref_valid_7 : 1; + u32 reserve1 : 4; + u32 hevc_ref_valid_8 : 1; + u32 hevc_ref_valid_9 : 1; + u32 hevc_ref_valid_10 : 1; + u32 hevc_ref_valid_11 : 1; + u32 reserve2 : 4; + u32 hevc_ref_valid_12 : 1; + u32 hevc_ref_valid_13 : 1; + u32 hevc_ref_valid_14 : 1; + u32 reserve3 : 5; + } reg099_hevc_ref_valid; + + u32 reserved_100_102[3]; + + struct { + u32 ref_pic_layer_same_with_cur : 16; + u32 reserve : 16; + } reg103_hevc_mvc0; + + struct { + u32 poc_lsb_not_present_flag : 1; + u32 num_direct_ref_layers : 6; + u32 reserve0 : 1; + + u32 num_reflayer_pics : 6; + u32 default_ref_layers_active_flag : 1; + u32 max_one_active_ref_layer_flag : 1; + + u32 poc_reset_info_present_flag : 1; + u32 vps_poc_lsb_aligned_flag : 1; + u32 mvc_poc15_valid_flag : 1; + u32 reserve1 : 13; + } reg104_hevc_mvc1; + + u32 reserved_105_111[7]; + + struct { + u32 avs2_ref_error_field : 1; + u32 avs2_ref_error_topfield : 1; + u32 ref_error_topfield_used : 1; + u32 ref_error_botfield_used : 1; + u32 reserve : 28; + } reg112_hevc_ref_info; + +} __packed; + +/* base: OFFSET_CODEC_ADDR_REGS */ +struct rkvdec_vdpu381_regs_h26x_addr { + u32 reserved_160; + u32 reg161_pps_base; + u32 reserved_162; + u32 reg163_rps_base; + u32 reg164_180_ref_base[16]; + u32 reg181_scanlist_addr; + u32 reg182_198_colmv_base[16]; + u32 reg199_cabactbl_base; +} __packed; + +struct rkvdec_vdpu381_regs_h26x_highpoc { + struct { + u32 ref0_poc_highbit : 4; + u32 ref1_poc_highbit : 4; + u32 ref2_poc_highbit : 4; + u32 ref3_poc_highbit : 4; + u32 ref4_poc_highbit : 4; + u32 ref5_poc_highbit : 4; + u32 ref6_poc_highbit : 4; + u32 ref7_poc_highbit : 4; + } reg200_203_ref_poc_highbit[4]; + struct { + u32 cur_poc_highbit : 4; + u32 reserved : 28; + } reg204_cur_poc_highbit; +} __packed; + +struct rkvdec_vdpu381_regs_h264 { + struct rkvdec_vdpu381_regs_common common; + struct rkvdec_vdpu381_regs_h264_params h264_param; + struct rkvdec_vdpu381_regs_common_addr common_addr; + struct rkvdec_vdpu381_regs_h26x_addr h264_addr; + struct rkvdec_vdpu381_regs_h26x_highpoc h264_highpoc; +} __packed; + +struct rkvdec_vdpu381_regs_hevc { + struct rkvdec_vdpu381_regs_common common; + struct rkvdec_vdpu381_regs_hevc_params hevc_param; + struct rkvdec_vdpu381_regs_common_addr common_addr; + struct rkvdec_vdpu381_regs_h26x_addr hevc_addr; + struct rkvdec_vdpu381_regs_h26x_highpoc hevc_highpoc; +} __packed; + +#endif /* __RKVDEC_REGS_H__ */ diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c index af2eced90026..da192c866e2e 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -29,6 +29,7 @@ #include "rkvdec.h" #include "rkvdec-regs.h" +#include "rkvdec-vdpu381-regs.h" #include "rkvdec-rcb.h" static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1, @@ -90,6 +91,9 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx, { v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, pix_mp->width, pix_mp->height); + + ctx->colmv_offset = pix_mp->plane_fmt[0].sizeimage; + pix_mp->plane_fmt[0].sizeimage += 128 * DIV_ROUND_UP(pix_mp->width, 16) * DIV_ROUND_UP(pix_mp->height, 16); @@ -269,6 +273,53 @@ static const struct rkvdec_ctrls rkvdec_h264_ctrls = { .num_ctrls = ARRAY_SIZE(rkvdec_h264_ctrl_descs), }; +static const struct rkvdec_ctrl_desc vdpu38x_h264_ctrl_descs[] = { + { + .cfg.id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, + }, + { + .cfg.id = V4L2_CID_STATELESS_H264_SPS, + .cfg.ops = &rkvdec_ctrl_ops, + }, + { + .cfg.id = V4L2_CID_STATELESS_H264_PPS, + }, + { + .cfg.id = V4L2_CID_STATELESS_H264_SCALING_MATRIX, + }, + { + .cfg.id = V4L2_CID_STATELESS_H264_DECODE_MODE, + .cfg.min = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + .cfg.max = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + .cfg.def = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + }, + { + .cfg.id = V4L2_CID_STATELESS_H264_START_CODE, + .cfg.min = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + .cfg.def = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + .cfg.max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + }, + { + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .cfg.min = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE, + .cfg.max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA, + .cfg.menu_skip_mask = + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE), + .cfg.def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, + }, + { + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, + .cfg.min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .cfg.max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + }, +}; + +static const struct rkvdec_ctrls vdpu38x_h264_ctrls = { + .ctrls = vdpu38x_h264_ctrl_descs, + .num_ctrls = ARRAY_SIZE(vdpu38x_h264_ctrl_descs), +}; + static const struct rkvdec_decoded_fmt_desc rkvdec_h264_decoded_fmts[] = { { .fourcc = V4L2_PIX_FMT_NV12, @@ -382,6 +433,25 @@ static const struct rkvdec_coded_fmt_desc rk3288_coded_fmts[] = { } }; +static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .frmsize = { + .min_width = 64, + .max_width = 65520, + .step_width = 64, + .min_height = 64, + .max_height = 65520, + .step_height = 16, + }, + .ctrls = &vdpu38x_h264_ctrls, + .ops = &rkvdec_vdpu381_h264_fmt_ops, + .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts), + .decoded_fmts = rkvdec_h264_decoded_fmts, + .subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF, + }, +}; + static const struct rkvdec_coded_fmt_desc * rkvdec_enum_coded_fmt_desc(struct rkvdec_ctx *ctx, int index) { @@ -946,6 +1016,20 @@ void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len) #endif } +void rkvdec_schedule_watchdog(struct rkvdec_dev *rkvdec, u32 timeout_threshold) +{ + /* Set watchdog at 2 times the hardware timeout threshold */ + u32 watchdog_time; + unsigned long axi_rate = clk_get_rate(rkvdec->axi_clk); + + if (axi_rate) + watchdog_time = 2 * div_u64(1000 * (u64)timeout_threshold, axi_rate); + else + watchdog_time = 2000; + + schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(watchdog_time)); +} + static void rkvdec_device_run(void *priv) { struct rkvdec_ctx *ctx = priv; @@ -1245,6 +1329,35 @@ static irqreturn_t rk3399_irq_handler(struct rkvdec_ctx *ctx) return IRQ_HANDLED; } +static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx) +{ + struct rkvdec_dev *rkvdec = ctx->dev; + enum vb2_buffer_state state; + bool need_reset = 0; + u32 status; + + status = readl(rkvdec->regs + VDPU381_REG_STA_INT); + writel(0, rkvdec->regs + VDPU381_REG_STA_INT); + + if (status & VDPU381_STA_INT_DEC_RDY_STA) { + state = VB2_BUF_STATE_DONE; + } else { + state = VB2_BUF_STATE_ERROR; + if (status & (VDPU381_STA_INT_SOFTRESET_RDY | + VDPU381_STA_INT_TIMEOUT | + VDPU381_STA_INT_ERROR)) + rkvdec_iommu_restore(rkvdec); + } + + if (need_reset) + rkvdec_iommu_restore(rkvdec); + + if (cancel_delayed_work(&rkvdec->watchdog_work)) + rkvdec_job_finish(ctx, state); + + return IRQ_HANDLED; +} + static irqreturn_t rkvdec_irq_handler(int irq, void *priv) { struct rkvdec_dev *rkvdec = priv; @@ -1321,6 +1434,7 @@ static const struct rkvdec_variant rk3288_rkvdec_variant = { .coded_fmts = rk3288_coded_fmts, .num_coded_fmts = ARRAY_SIZE(rk3288_coded_fmts), .ops = &rk3399_variant_ops, + .has_single_reg_region = true, }; static const struct rkvdec_variant rk3328_rkvdec_variant = { @@ -1328,6 +1442,7 @@ static const struct rkvdec_variant rk3328_rkvdec_variant = { .coded_fmts = rkvdec_coded_fmts, .num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts), .ops = &rk3399_variant_ops, + .has_single_reg_region = true, .quirks = RKVDEC_QUIRK_DISABLE_QOS, }; @@ -1336,6 +1451,32 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = { .coded_fmts = rkvdec_coded_fmts, .num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts), .ops = &rk3399_variant_ops, + .has_single_reg_region = true, +}; + +static const struct rcb_size_info vdpu381_rcb_sizes[] = { + {6, PIC_WIDTH}, // intrar + {1, PIC_WIDTH}, // transdr (Is actually 0.4*pic_width) + {1, PIC_HEIGHT}, // transdc (Is actually 0.1*pic_height) + {3, PIC_WIDTH}, // streamdr + {6, PIC_WIDTH}, // interr + {3, PIC_HEIGHT}, // interc + {22, PIC_WIDTH}, // dblkr + {6, PIC_WIDTH}, // saor + {11, PIC_WIDTH}, // fbcr + {67, PIC_HEIGHT}, // filtc col +}; + +static const struct rkvdec_variant_ops vdpu381_variant_ops = { + .irq_handler = vdpu381_irq_handler, +}; + +static const struct rkvdec_variant vdpu381_variant = { + .coded_fmts = vdpu381_coded_fmts, + .num_coded_fmts = ARRAY_SIZE(vdpu381_coded_fmts), + .rcb_sizes = vdpu381_rcb_sizes, + .num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes), + .ops = &vdpu381_variant_ops, }; static const struct of_device_id of_rkvdec_match[] = { @@ -1351,6 +1492,10 @@ static const struct of_device_id of_rkvdec_match[] = { .compatible = "rockchip,rk3399-vdec", .data = &rk3399_rkvdec_variant, }, + { + .compatible = "rockchip,rk3588-vdec", + .data = &vdpu381_variant, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, of_rkvdec_match); @@ -1384,10 +1529,17 @@ static int rkvdec_probe(struct platform_device *pdev) return ret; rkvdec->num_clocks = ret; + rkvdec->axi_clk = devm_clk_get(&pdev->dev, "axi"); - rkvdec->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(rkvdec->regs)) - return PTR_ERR(rkvdec->regs); + if (rkvdec->variant->has_single_reg_region) { + rkvdec->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rkvdec->regs)) + return PTR_ERR(rkvdec->regs); + } else { + rkvdec->regs = devm_platform_ioremap_resource_byname(pdev, "function"); + if (IS_ERR(rkvdec->regs)) + return PTR_ERR(rkvdec->regs); + } ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) { diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h index 7766a79caf68..4afa9cd690d5 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h @@ -25,6 +25,10 @@ #define RKVDEC_QUIRK_DISABLE_QOS BIT(0) +#define RKVDEC_1080P_PIXELS (1920 * 1088) +#define RKVDEC_4K_PIXELS (4096 * 2304) +#define RKVDEC_8K_PIXELS (7680 * 4320) + struct rkvdec_ctx; struct rkvdec_rcb_config; @@ -78,6 +82,7 @@ struct rkvdec_variant { const struct rcb_size_info *rcb_sizes; size_t num_rcb_sizes; const struct rkvdec_variant_ops *ops; + bool has_single_reg_region; unsigned int quirks; }; @@ -126,6 +131,7 @@ struct rkvdec_dev { struct device *dev; struct clk_bulk_data *clocks; unsigned int num_clocks; + struct clk *axi_clk; void __iomem *regs; struct mutex vdev_lock; /* serializes ioctls */ struct delayed_work watchdog_work; @@ -144,6 +150,7 @@ struct rkvdec_ctx { struct rkvdec_dev *dev; enum rkvdec_image_fmt image_fmt; struct rkvdec_rcb_config *rcb_config; + u32 colmv_offset; void *priv; }; @@ -167,11 +174,16 @@ 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_schedule_watchdog(struct rkvdec_dev *rkvdec, u32 timeout_threshold); void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx); +/* RKVDEC ops */ extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops; extern const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops; extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops; +/* VDPU381 ops */ +extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops; + #endif /* RKVDEC_H_ */ |
