Commit e2da4654 authored by Andrzej Pietrasiewicz's avatar Andrzej Pietrasiewicz Committed by Mauro Carvalho Chehab

media: hantro: Support VP9 on the G2 core

VeriSilicon Hantro G2 core supports VP9 codec.

[hverkuil: add kerneldoc line for HANTRO_MODE_VP9_DEC]
Signed-off-by: default avatarAndrzej Pietrasiewicz <andrzej.p@collabora.com>
Reviewed-by: default avatarBenjamin Gaignard <benjamin.gaignard@collabora.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent cb1bbbd4
...@@ -9,6 +9,7 @@ config VIDEO_HANTRO ...@@ -9,6 +9,7 @@ config VIDEO_HANTRO
select VIDEOBUF2_VMALLOC select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV select V4L2_MEM2MEM_DEV
select V4L2_H264 select V4L2_H264
select V4L2_VP9
help help
Support for the Hantro IP based Video Processing Units present on Support for the Hantro IP based Video Processing Units present on
Rockchip and NXP i.MX8M SoCs, which accelerate video and image Rockchip and NXP i.MX8M SoCs, which accelerate video and image
......
...@@ -10,9 +10,10 @@ hantro-vpu-y += \ ...@@ -10,9 +10,10 @@ hantro-vpu-y += \
hantro_g1.o \ hantro_g1.o \
hantro_g1_h264_dec.o \ hantro_g1_h264_dec.o \
hantro_g1_mpeg2_dec.o \ hantro_g1_mpeg2_dec.o \
hantro_g2_hevc_dec.o \
hantro_g1_vp8_dec.o \ hantro_g1_vp8_dec.o \
hantro_g2.o \ hantro_g2.o \
hantro_g2_hevc_dec.o \
hantro_g2_vp9_dec.o \
rockchip_vpu2_hw_jpeg_enc.o \ rockchip_vpu2_hw_jpeg_enc.o \
rockchip_vpu2_hw_h264_dec.o \ rockchip_vpu2_hw_h264_dec.o \
rockchip_vpu2_hw_mpeg2_dec.o \ rockchip_vpu2_hw_mpeg2_dec.o \
...@@ -21,7 +22,8 @@ hantro-vpu-y += \ ...@@ -21,7 +22,8 @@ hantro-vpu-y += \
hantro_h264.o \ hantro_h264.o \
hantro_hevc.o \ hantro_hevc.o \
hantro_mpeg2.o \ hantro_mpeg2.o \
hantro_vp8.o hantro_vp8.o \
hantro_vp9.o
hantro-vpu-$(CONFIG_VIDEO_HANTRO_IMX8M) += \ hantro-vpu-$(CONFIG_VIDEO_HANTRO_IMX8M) += \
imx8m_vpu_hw.o imx8m_vpu_hw.o
......
...@@ -36,6 +36,7 @@ struct hantro_postproc_ops; ...@@ -36,6 +36,7 @@ struct hantro_postproc_ops;
#define HANTRO_VP8_DECODER BIT(17) #define HANTRO_VP8_DECODER BIT(17)
#define HANTRO_H264_DECODER BIT(18) #define HANTRO_H264_DECODER BIT(18)
#define HANTRO_HEVC_DECODER BIT(19) #define HANTRO_HEVC_DECODER BIT(19)
#define HANTRO_VP9_DECODER BIT(20)
#define HANTRO_DECODERS 0xffff0000 #define HANTRO_DECODERS 0xffff0000
/** /**
...@@ -102,6 +103,7 @@ struct hantro_variant { ...@@ -102,6 +103,7 @@ struct hantro_variant {
* @HANTRO_MODE_MPEG2_DEC: MPEG-2 decoder. * @HANTRO_MODE_MPEG2_DEC: MPEG-2 decoder.
* @HANTRO_MODE_VP8_DEC: VP8 decoder. * @HANTRO_MODE_VP8_DEC: VP8 decoder.
* @HANTRO_MODE_HEVC_DEC: HEVC decoder. * @HANTRO_MODE_HEVC_DEC: HEVC decoder.
* @HANTRO_MODE_VP9_DEC: VP9 decoder.
*/ */
enum hantro_codec_mode { enum hantro_codec_mode {
HANTRO_MODE_NONE = -1, HANTRO_MODE_NONE = -1,
...@@ -110,6 +112,7 @@ enum hantro_codec_mode { ...@@ -110,6 +112,7 @@ enum hantro_codec_mode {
HANTRO_MODE_MPEG2_DEC, HANTRO_MODE_MPEG2_DEC,
HANTRO_MODE_VP8_DEC, HANTRO_MODE_VP8_DEC,
HANTRO_MODE_HEVC_DEC, HANTRO_MODE_HEVC_DEC,
HANTRO_MODE_VP9_DEC,
}; };
/* /*
...@@ -223,6 +226,7 @@ struct hantro_dev { ...@@ -223,6 +226,7 @@ struct hantro_dev {
* @mpeg2_dec: MPEG-2-decoding context. * @mpeg2_dec: MPEG-2-decoding context.
* @vp8_dec: VP8-decoding context. * @vp8_dec: VP8-decoding context.
* @hevc_dec: HEVC-decoding context. * @hevc_dec: HEVC-decoding context.
* @vp9_dec: VP9-decoding context.
*/ */
struct hantro_ctx { struct hantro_ctx {
struct hantro_dev *dev; struct hantro_dev *dev;
...@@ -250,6 +254,7 @@ struct hantro_ctx { ...@@ -250,6 +254,7 @@ struct hantro_ctx {
struct hantro_mpeg2_dec_hw_ctx mpeg2_dec; struct hantro_mpeg2_dec_hw_ctx mpeg2_dec;
struct hantro_vp8_dec_hw_ctx vp8_dec; struct hantro_vp8_dec_hw_ctx vp8_dec;
struct hantro_hevc_dec_hw_ctx hevc_dec; struct hantro_hevc_dec_hw_ctx hevc_dec;
struct hantro_vp9_dec_hw_ctx vp9_dec;
}; };
}; };
...@@ -299,6 +304,22 @@ struct hantro_postproc_regs { ...@@ -299,6 +304,22 @@ struct hantro_postproc_regs {
struct hantro_reg display_width; struct hantro_reg display_width;
}; };
struct hantro_vp9_decoded_buffer_info {
/* Info needed when the decoded frame serves as a reference frame. */
unsigned short width;
unsigned short height;
u32 bit_depth : 4;
};
struct hantro_decoded_buffer {
/* Must be the first field in this struct. */
struct v4l2_m2m_buffer base;
union {
struct hantro_vp9_decoded_buffer_info vp9;
};
};
/* Logging helpers */ /* Logging helpers */
/** /**
...@@ -436,6 +457,12 @@ hantro_get_dec_buf_addr(struct hantro_ctx *ctx, struct vb2_buffer *vb) ...@@ -436,6 +457,12 @@ hantro_get_dec_buf_addr(struct hantro_ctx *ctx, struct vb2_buffer *vb)
return vb2_dma_contig_plane_dma_addr(vb, 0); return vb2_dma_contig_plane_dma_addr(vb, 0);
} }
static inline struct hantro_decoded_buffer *
vb2_to_hantro_decoded_buf(struct vb2_buffer *buf)
{
return container_of(buf, struct hantro_decoded_buffer, base.vb.vb2_buf);
}
void hantro_postproc_disable(struct hantro_ctx *ctx); void hantro_postproc_disable(struct hantro_ctx *ctx);
void hantro_postproc_enable(struct hantro_ctx *ctx); void hantro_postproc_enable(struct hantro_ctx *ctx);
void hantro_postproc_free(struct hantro_ctx *ctx); void hantro_postproc_free(struct hantro_ctx *ctx);
......
...@@ -232,7 +232,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) ...@@ -232,7 +232,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
dst_vq->drv_priv = ctx; dst_vq->drv_priv = ctx;
dst_vq->ops = &hantro_queue_ops; dst_vq->ops = &hantro_queue_ops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->buf_struct_size = sizeof(struct hantro_decoded_buffer);
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->dev->vpu_mutex; dst_vq->lock = &ctx->dev->vpu_mutex;
dst_vq->dev = ctx->dev->v4l2_dev.dev; dst_vq->dev = ctx->dev->v4l2_dev.dev;
...@@ -263,6 +263,12 @@ static int hantro_try_ctrl(struct v4l2_ctrl *ctrl) ...@@ -263,6 +263,12 @@ static int hantro_try_ctrl(struct v4l2_ctrl *ctrl)
if (sps->bit_depth_luma_minus8 != 0) if (sps->bit_depth_luma_minus8 != 0)
/* Only 8-bit is supported */ /* Only 8-bit is supported */
return -EINVAL; return -EINVAL;
} else if (ctrl->id == V4L2_CID_STATELESS_VP9_FRAME) {
const struct v4l2_ctrl_vp9_frame *dec_params = ctrl->p_new.p_vp9_frame;
/* We only support profile 0 */
if (dec_params->profile != 0)
return -EINVAL;
} }
return 0; return 0;
} }
...@@ -461,6 +467,16 @@ static const struct hantro_ctrl controls[] = { ...@@ -461,6 +467,16 @@ static const struct hantro_ctrl controls[] = {
.step = 1, .step = 1,
.ops = &hantro_hevc_ctrl_ops, .ops = &hantro_hevc_ctrl_ops,
}, },
}, {
.codec = HANTRO_VP9_DECODER,
.cfg = {
.id = V4L2_CID_STATELESS_VP9_FRAME,
},
}, {
.codec = HANTRO_VP9_DECODER,
.cfg = {
.id = V4L2_CID_STATELESS_VP9_COMPRESSED_HDR,
},
}, },
}; };
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#define G2_REG_INTERRUPT_DEC_E BIT(0) #define G2_REG_INTERRUPT_DEC_E BIT(0)
#define HEVC_DEC_MODE 0xc #define HEVC_DEC_MODE 0xc
#define VP9_DEC_MODE 0xd
#define BUS_WIDTH_32 0 #define BUS_WIDTH_32 0
#define BUS_WIDTH_64 1 #define BUS_WIDTH_64 1
...@@ -49,6 +50,7 @@ ...@@ -49,6 +50,7 @@
#define g2_pic_height_in_cbs G2_DEC_REG(4, 6, 0x1fff) #define g2_pic_height_in_cbs G2_DEC_REG(4, 6, 0x1fff)
#define g2_num_ref_frames G2_DEC_REG(4, 0, 0x1f) #define g2_num_ref_frames G2_DEC_REG(4, 0, 0x1f)
#define g2_start_bit G2_DEC_REG(5, 25, 0x7f)
#define g2_scaling_list_e G2_DEC_REG(5, 24, 0x1) #define g2_scaling_list_e G2_DEC_REG(5, 24, 0x1)
#define g2_cb_qp_offset G2_DEC_REG(5, 19, 0x1f) #define g2_cb_qp_offset G2_DEC_REG(5, 19, 0x1f)
#define g2_cr_qp_offset G2_DEC_REG(5, 14, 0x1f) #define g2_cr_qp_offset G2_DEC_REG(5, 14, 0x1f)
...@@ -84,6 +86,7 @@ ...@@ -84,6 +86,7 @@
#define g2_bit_depth_y_minus8 G2_DEC_REG(8, 6, 0x3) #define g2_bit_depth_y_minus8 G2_DEC_REG(8, 6, 0x3)
#define g2_bit_depth_c_minus8 G2_DEC_REG(8, 4, 0x3) #define g2_bit_depth_c_minus8 G2_DEC_REG(8, 4, 0x3)
#define g2_output_8_bits G2_DEC_REG(8, 3, 0x1) #define g2_output_8_bits G2_DEC_REG(8, 3, 0x1)
#define g2_output_format G2_DEC_REG(8, 0, 0x7)
#define g2_refidx1_active G2_DEC_REG(9, 19, 0x1f) #define g2_refidx1_active G2_DEC_REG(9, 19, 0x1f)
#define g2_refidx0_active G2_DEC_REG(9, 14, 0x1f) #define g2_refidx0_active G2_DEC_REG(9, 14, 0x1f)
...@@ -96,6 +99,14 @@ ...@@ -96,6 +99,14 @@
#define g2_tile_e G2_DEC_REG(10, 1, 0x1) #define g2_tile_e G2_DEC_REG(10, 1, 0x1)
#define g2_entropy_sync_e G2_DEC_REG(10, 0, 0x1) #define g2_entropy_sync_e G2_DEC_REG(10, 0, 0x1)
#define vp9_transform_mode G2_DEC_REG(11, 27, 0x7)
#define vp9_filt_sharpness G2_DEC_REG(11, 21, 0x7)
#define vp9_mcomp_filt_type G2_DEC_REG(11, 8, 0x7)
#define vp9_high_prec_mv_e G2_DEC_REG(11, 7, 0x1)
#define vp9_comp_pred_mode G2_DEC_REG(11, 4, 0x3)
#define vp9_gref_sign_bias G2_DEC_REG(11, 2, 0x1)
#define vp9_aref_sign_bias G2_DEC_REG(11, 0, 0x1)
#define g2_refer_lterm_e G2_DEC_REG(12, 16, 0xffff) #define g2_refer_lterm_e G2_DEC_REG(12, 16, 0xffff)
#define g2_min_cb_size G2_DEC_REG(12, 13, 0x7) #define g2_min_cb_size G2_DEC_REG(12, 13, 0x7)
#define g2_max_cb_size G2_DEC_REG(12, 10, 0x7) #define g2_max_cb_size G2_DEC_REG(12, 10, 0x7)
...@@ -154,6 +165,50 @@ ...@@ -154,6 +165,50 @@
#define g2_partial_ctb_y G2_DEC_REG(20, 30, 0x1) #define g2_partial_ctb_y G2_DEC_REG(20, 30, 0x1)
#define g2_pic_width_4x4 G2_DEC_REG(20, 16, 0xfff) #define g2_pic_width_4x4 G2_DEC_REG(20, 16, 0xfff)
#define g2_pic_height_4x4 G2_DEC_REG(20, 0, 0xfff) #define g2_pic_height_4x4 G2_DEC_REG(20, 0, 0xfff)
#define vp9_qp_delta_y_dc G2_DEC_REG(13, 23, 0x3f)
#define vp9_qp_delta_ch_dc G2_DEC_REG(13, 17, 0x3f)
#define vp9_qp_delta_ch_ac G2_DEC_REG(13, 11, 0x3f)
#define vp9_last_sign_bias G2_DEC_REG(13, 10, 0x1)
#define vp9_lossless_e G2_DEC_REG(13, 9, 0x1)
#define vp9_comp_pred_var_ref1 G2_DEC_REG(13, 7, 0x3)
#define vp9_comp_pred_var_ref0 G2_DEC_REG(13, 5, 0x3)
#define vp9_comp_pred_fixed_ref G2_DEC_REG(13, 3, 0x3)
#define vp9_segment_temp_upd_e G2_DEC_REG(13, 2, 0x1)
#define vp9_segment_upd_e G2_DEC_REG(13, 1, 0x1)
#define vp9_segment_e G2_DEC_REG(13, 0, 0x1)
#define vp9_filt_level G2_DEC_REG(14, 18, 0x3f)
#define vp9_refpic_seg0 G2_DEC_REG(14, 15, 0x7)
#define vp9_skip_seg0 G2_DEC_REG(14, 14, 0x1)
#define vp9_filt_level_seg0 G2_DEC_REG(14, 8, 0x3f)
#define vp9_quant_seg0 G2_DEC_REG(14, 0, 0xff)
#define vp9_refpic_seg1 G2_DEC_REG(15, 15, 0x7)
#define vp9_skip_seg1 G2_DEC_REG(15, 14, 0x1)
#define vp9_filt_level_seg1 G2_DEC_REG(15, 8, 0x3f)
#define vp9_quant_seg1 G2_DEC_REG(15, 0, 0xff)
#define vp9_refpic_seg2 G2_DEC_REG(16, 15, 0x7)
#define vp9_skip_seg2 G2_DEC_REG(16, 14, 0x1)
#define vp9_filt_level_seg2 G2_DEC_REG(16, 8, 0x3f)
#define vp9_quant_seg2 G2_DEC_REG(16, 0, 0xff)
#define vp9_refpic_seg3 G2_DEC_REG(17, 15, 0x7)
#define vp9_skip_seg3 G2_DEC_REG(17, 14, 0x1)
#define vp9_filt_level_seg3 G2_DEC_REG(17, 8, 0x3f)
#define vp9_quant_seg3 G2_DEC_REG(17, 0, 0xff)
#define vp9_refpic_seg4 G2_DEC_REG(18, 15, 0x7)
#define vp9_skip_seg4 G2_DEC_REG(18, 14, 0x1)
#define vp9_filt_level_seg4 G2_DEC_REG(18, 8, 0x3f)
#define vp9_quant_seg4 G2_DEC_REG(18, 0, 0xff)
#define vp9_refpic_seg5 G2_DEC_REG(19, 15, 0x7)
#define vp9_skip_seg5 G2_DEC_REG(19, 14, 0x1)
#define vp9_filt_level_seg5 G2_DEC_REG(19, 8, 0x3f)
#define vp9_quant_seg5 G2_DEC_REG(19, 0, 0xff)
#define hevc_cur_poc_00 G2_DEC_REG(46, 24, 0xff) #define hevc_cur_poc_00 G2_DEC_REG(46, 24, 0xff)
#define hevc_cur_poc_01 G2_DEC_REG(46, 16, 0xff) #define hevc_cur_poc_01 G2_DEC_REG(46, 16, 0xff)
#define hevc_cur_poc_02 G2_DEC_REG(46, 8, 0xff) #define hevc_cur_poc_02 G2_DEC_REG(46, 8, 0xff)
...@@ -174,6 +229,44 @@ ...@@ -174,6 +229,44 @@
#define hevc_cur_poc_14 G2_DEC_REG(49, 8, 0xff) #define hevc_cur_poc_14 G2_DEC_REG(49, 8, 0xff)
#define hevc_cur_poc_15 G2_DEC_REG(49, 0, 0xff) #define hevc_cur_poc_15 G2_DEC_REG(49, 0, 0xff)
#define vp9_refpic_seg6 G2_DEC_REG(31, 15, 0x7)
#define vp9_skip_seg6 G2_DEC_REG(31, 14, 0x1)
#define vp9_filt_level_seg6 G2_DEC_REG(31, 8, 0x3f)
#define vp9_quant_seg6 G2_DEC_REG(31, 0, 0xff)
#define vp9_refpic_seg7 G2_DEC_REG(32, 15, 0x7)
#define vp9_skip_seg7 G2_DEC_REG(32, 14, 0x1)
#define vp9_filt_level_seg7 G2_DEC_REG(32, 8, 0x3f)
#define vp9_quant_seg7 G2_DEC_REG(32, 0, 0xff)
#define vp9_lref_width G2_DEC_REG(33, 16, 0xffff)
#define vp9_lref_height G2_DEC_REG(33, 0, 0xffff)
#define vp9_gref_width G2_DEC_REG(34, 16, 0xffff)
#define vp9_gref_height G2_DEC_REG(34, 0, 0xffff)
#define vp9_aref_width G2_DEC_REG(35, 16, 0xffff)
#define vp9_aref_height G2_DEC_REG(35, 0, 0xffff)
#define vp9_lref_hor_scale G2_DEC_REG(36, 16, 0xffff)
#define vp9_lref_ver_scale G2_DEC_REG(36, 0, 0xffff)
#define vp9_gref_hor_scale G2_DEC_REG(37, 16, 0xffff)
#define vp9_gref_ver_scale G2_DEC_REG(37, 0, 0xffff)
#define vp9_aref_hor_scale G2_DEC_REG(38, 16, 0xffff)
#define vp9_aref_ver_scale G2_DEC_REG(38, 0, 0xffff)
#define vp9_filt_ref_adj_0 G2_DEC_REG(46, 24, 0x7f)
#define vp9_filt_ref_adj_1 G2_DEC_REG(46, 16, 0x7f)
#define vp9_filt_ref_adj_2 G2_DEC_REG(46, 8, 0x7f)
#define vp9_filt_ref_adj_3 G2_DEC_REG(46, 0, 0x7f)
#define vp9_filt_mb_adj_0 G2_DEC_REG(47, 24, 0x7f)
#define vp9_filt_mb_adj_1 G2_DEC_REG(47, 16, 0x7f)
#define vp9_filt_mb_adj_2 G2_DEC_REG(47, 8, 0x7f)
#define vp9_filt_mb_adj_3 G2_DEC_REG(47, 0, 0x7f)
#define g2_apf_threshold G2_DEC_REG(55, 0, 0xffff) #define g2_apf_threshold G2_DEC_REG(55, 0, 0xffff)
#define g2_clk_gate_e G2_DEC_REG(58, 16, 0x1) #define g2_clk_gate_e G2_DEC_REG(58, 16, 0x1)
...@@ -186,6 +279,8 @@ ...@@ -186,6 +279,8 @@
#define G2_OUT_LUMA_ADDR (G2_SWREG(65)) #define G2_OUT_LUMA_ADDR (G2_SWREG(65))
#define G2_REF_LUMA_ADDR(i) (G2_SWREG(67) + ((i) * 0x8)) #define G2_REF_LUMA_ADDR(i) (G2_SWREG(67) + ((i) * 0x8))
#define G2_VP9_SEGMENT_WRITE_ADDR (G2_SWREG(79))
#define G2_VP9_SEGMENT_READ_ADDR (G2_SWREG(81))
#define G2_OUT_CHROMA_ADDR (G2_SWREG(99)) #define G2_OUT_CHROMA_ADDR (G2_SWREG(99))
#define G2_REF_CHROMA_ADDR(i) (G2_SWREG(101) + ((i) * 0x8)) #define G2_REF_CHROMA_ADDR(i) (G2_SWREG(101) + ((i) * 0x8))
#define G2_OUT_MV_ADDR (G2_SWREG(133)) #define G2_OUT_MV_ADDR (G2_SWREG(133))
...@@ -193,6 +288,8 @@ ...@@ -193,6 +288,8 @@
#define G2_TILE_SIZES_ADDR (G2_SWREG(167)) #define G2_TILE_SIZES_ADDR (G2_SWREG(167))
#define G2_STREAM_ADDR (G2_SWREG(169)) #define G2_STREAM_ADDR (G2_SWREG(169))
#define G2_HEVC_SCALING_LIST_ADDR (G2_SWREG(171)) #define G2_HEVC_SCALING_LIST_ADDR (G2_SWREG(171))
#define G2_VP9_CTX_COUNT_ADDR (G2_SWREG(171))
#define G2_VP9_PROBS_ADDR (G2_SWREG(173))
#define G2_RS_OUT_LUMA_ADDR (G2_SWREG(175)) #define G2_RS_OUT_LUMA_ADDR (G2_SWREG(175))
#define G2_RS_OUT_CHROMA_ADDR (G2_SWREG(177)) #define G2_RS_OUT_CHROMA_ADDR (G2_SWREG(177))
#define G2_TILE_FILTER_ADDR (G2_SWREG(179)) #define G2_TILE_FILTER_ADDR (G2_SWREG(179))
......
This diff is collapsed.
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/v4l2-controls.h> #include <linux/v4l2-controls.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
#include <media/v4l2-vp9.h>
#include <media/videobuf2-core.h> #include <media/videobuf2-core.h>
#define DEC_8190_ALIGN_MASK 0x07U #define DEC_8190_ALIGN_MASK 0x07U
...@@ -165,6 +166,82 @@ struct hantro_vp8_dec_hw_ctx { ...@@ -165,6 +166,82 @@ struct hantro_vp8_dec_hw_ctx {
struct hantro_aux_buf prob_tbl; struct hantro_aux_buf prob_tbl;
}; };
/**
* struct hantro_vp9_frame_info
*
* @valid: frame info valid flag
* @frame_context_idx: index of frame context
* @reference_mode: inter prediction type
* @tx_mode: transform mode
* @interpolation_filter: filter selection for inter prediction
* @flags: frame flags
* @timestamp: frame timestamp
*/
struct hantro_vp9_frame_info {
u32 valid : 1;
u32 frame_context_idx : 2;
u32 reference_mode : 2;
u32 tx_mode : 3;
u32 interpolation_filter : 3;
u32 flags;
u64 timestamp;
};
#define MAX_SB_COLS 64
#define MAX_SB_ROWS 34
/**
* struct hantro_vp9_dec_hw_ctx
*
* @tile_edge: auxiliary DMA buffer for tile edge processing
* @segment_map: auxiliary DMA buffer for segment map
* @misc: auxiliary DMA buffer for tile info, probabilities and hw counters
* @cnts: vp9 library struct for abstracting hw counters access
* @probability_tables: VP9 probability tables implied by the spec
* @frame_context: VP9 frame contexts
* @cur: current frame information
* @last: last frame information
* @bsd_ctrl_offset: bsd offset into tile_edge
* @segment_map_size: size of segment map
* @ctx_counters_offset: hw counters offset into misc
* @tile_info_offset: tile info offset into misc
* @tile_r_info: per-tile information array
* @tile_c_info: per-tile information array
* @last_tile_r: last number of tile rows
* @last_tile_c: last number of tile cols
* @last_sbs_r: last number of superblock rows
* @last_sbs_c: last number of superblock cols
* @active_segment: number of active segment (alternating between 0 and 1)
* @feature_enabled: segmentation feature enabled flags
* @feature_data: segmentation feature data
*/
struct hantro_vp9_dec_hw_ctx {
struct hantro_aux_buf tile_edge;
struct hantro_aux_buf segment_map;
struct hantro_aux_buf misc;
struct v4l2_vp9_frame_symbol_counts cnts;
struct v4l2_vp9_frame_context probability_tables;
struct v4l2_vp9_frame_context frame_context[4];
struct hantro_vp9_frame_info cur;
struct hantro_vp9_frame_info last;
unsigned int bsd_ctrl_offset;
unsigned int segment_map_size;
unsigned int ctx_counters_offset;
unsigned int tile_info_offset;
unsigned short tile_r_info[MAX_SB_ROWS];
unsigned short tile_c_info[MAX_SB_COLS];
unsigned int last_tile_r;
unsigned int last_tile_c;
unsigned int last_sbs_r;
unsigned int last_sbs_c;
unsigned int active_segment;
u8 feature_enabled[8];
s16 feature_data[8][4];
};
/** /**
* struct hantro_postproc_ctx * struct hantro_postproc_ctx
* *
...@@ -271,6 +348,24 @@ void hantro_hevc_ref_remove_unused(struct hantro_ctx *ctx); ...@@ -271,6 +348,24 @@ void hantro_hevc_ref_remove_unused(struct hantro_ctx *ctx);
size_t hantro_hevc_chroma_offset(const struct v4l2_ctrl_hevc_sps *sps); size_t hantro_hevc_chroma_offset(const struct v4l2_ctrl_hevc_sps *sps);
size_t hantro_hevc_motion_vectors_offset(const struct v4l2_ctrl_hevc_sps *sps); size_t hantro_hevc_motion_vectors_offset(const struct v4l2_ctrl_hevc_sps *sps);
static inline unsigned short hantro_vp9_num_sbs(unsigned short dimension)
{
return (dimension + 63) / 64;
}
static inline size_t
hantro_vp9_mv_size(unsigned int width, unsigned int height)
{
int num_ctbs;
/*
* There can be up to (CTBs x 64) number of blocks,
* and the motion vector for each block needs 16 bytes.
*/
num_ctbs = hantro_vp9_num_sbs(width) * hantro_vp9_num_sbs(height);
return (num_ctbs * 64) * 16;
}
static inline size_t static inline size_t
hantro_h264_mv_size(unsigned int width, unsigned int height) hantro_h264_mv_size(unsigned int width, unsigned int height)
{ {
...@@ -312,6 +407,10 @@ void hantro_vp8_dec_exit(struct hantro_ctx *ctx); ...@@ -312,6 +407,10 @@ void hantro_vp8_dec_exit(struct hantro_ctx *ctx);
void hantro_vp8_prob_update(struct hantro_ctx *ctx, void hantro_vp8_prob_update(struct hantro_ctx *ctx,
const struct v4l2_ctrl_vp8_frame *hdr); const struct v4l2_ctrl_vp8_frame *hdr);
int hantro_g2_vp9_dec_run(struct hantro_ctx *ctx);
void hantro_g2_vp9_dec_done(struct hantro_ctx *ctx);
int hantro_vp9_dec_init(struct hantro_ctx *ctx);
void hantro_vp9_dec_exit(struct hantro_ctx *ctx);
void hantro_g2_check_idle(struct hantro_dev *vpu); void hantro_g2_check_idle(struct hantro_dev *vpu);
#endif /* HANTRO_HW_H_ */ #endif /* HANTRO_HW_H_ */
...@@ -299,6 +299,11 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx, ...@@ -299,6 +299,11 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx,
pix_mp->plane_fmt[0].sizeimage += pix_mp->plane_fmt[0].sizeimage +=
hantro_h264_mv_size(pix_mp->width, hantro_h264_mv_size(pix_mp->width,
pix_mp->height); pix_mp->height);
else if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_VP9_FRAME &&
!hantro_needs_postproc(ctx, fmt))
pix_mp->plane_fmt[0].sizeimage +=
hantro_vp9_mv_size(pix_mp->width,
pix_mp->height);
} else if (!pix_mp->plane_fmt[0].sizeimage) { } else if (!pix_mp->plane_fmt[0].sizeimage) {
/* /*
* For coded formats the application can specify * For coded formats the application can specify
...@@ -407,6 +412,7 @@ hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc) ...@@ -407,6 +412,7 @@ hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc)
case V4L2_PIX_FMT_VP8_FRAME: case V4L2_PIX_FMT_VP8_FRAME:
case V4L2_PIX_FMT_H264_SLICE: case V4L2_PIX_FMT_H264_SLICE:
case V4L2_PIX_FMT_HEVC_SLICE: case V4L2_PIX_FMT_HEVC_SLICE:
case V4L2_PIX_FMT_VP9_FRAME:
ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true; ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true;
break; break;
default: default:
......
// SPDX-License-Identifier: GPL-2.0
/*
* Hantro VP9 codec driver
*
* Copyright (C) 2021 Collabora Ltd.
*/
#include <linux/types.h>
#include <media/v4l2-mem2mem.h>
#include "hantro.h"
#include "hantro_hw.h"
#include "hantro_vp9.h"
#define POW2(x) (1 << (x))
#define MAX_LOG2_TILE_COLUMNS 6
#define MAX_NUM_TILE_COLS POW2(MAX_LOG2_TILE_COLUMNS)
#define MAX_TILE_COLS 20
#define MAX_TILE_ROWS 22
static size_t hantro_vp9_tile_filter_size(unsigned int height)
{
u32 h, height32, size;
h = roundup(height, 8);
height32 = roundup(h, 64);
size = 24 * height32 * (MAX_NUM_TILE_COLS - 1); /* luma: 8, chroma: 8 + 8 */
return size;
}
static size_t hantro_vp9_bsd_control_size(unsigned int height)
{
u32 h, height32;
h = roundup(height, 8);
height32 = roundup(h, 64);
return 16 * (height32 / 4) * (MAX_NUM_TILE_COLS - 1);
}
static size_t hantro_vp9_segment_map_size(unsigned int width, unsigned int height)
{
u32 w, h;
int num_ctbs;
w = roundup(width, 8);
h = roundup(height, 8);
num_ctbs = ((w + 63) / 64) * ((h + 63) / 64);
return num_ctbs * 32;
}
static inline size_t hantro_vp9_prob_tab_size(void)
{
return roundup(sizeof(struct hantro_g2_all_probs), 16);
}
static inline size_t hantro_vp9_count_tab_size(void)
{
return roundup(sizeof(struct symbol_counts), 16);
}
static inline size_t hantro_vp9_tile_info_size(void)
{
return roundup((MAX_TILE_COLS * MAX_TILE_ROWS * 4 * sizeof(u16) + 15 + 16) & ~0xf, 16);
}
static void *get_coeffs_arr(struct symbol_counts *cnts, int i, int j, int k, int l, int m)
{
if (i == 0)
return &cnts->count_coeffs[j][k][l][m];
if (i == 1)
return &cnts->count_coeffs8x8[j][k][l][m];
if (i == 2)
return &cnts->count_coeffs16x16[j][k][l][m];
if (i == 3)
return &cnts->count_coeffs32x32[j][k][l][m];
return NULL;
}
static void *get_eobs1(struct symbol_counts *cnts, int i, int j, int k, int l, int m)
{
if (i == 0)
return &cnts->count_coeffs[j][k][l][m][3];
if (i == 1)
return &cnts->count_coeffs8x8[j][k][l][m][3];
if (i == 2)
return &cnts->count_coeffs16x16[j][k][l][m][3];
if (i == 3)
return &cnts->count_coeffs32x32[j][k][l][m][3];
return NULL;
}
#define INNER_LOOP \
do { \
for (m = 0; m < ARRAY_SIZE(vp9_ctx->cnts.coeff[i][0][0][0]); ++m) { \
vp9_ctx->cnts.coeff[i][j][k][l][m] = \
get_coeffs_arr(cnts, i, j, k, l, m); \
vp9_ctx->cnts.eob[i][j][k][l][m][0] = \
&cnts->count_eobs[i][j][k][l][m]; \
vp9_ctx->cnts.eob[i][j][k][l][m][1] = \
get_eobs1(cnts, i, j, k, l, m); \
} \
} while (0)
static void init_v4l2_vp9_count_tbl(struct hantro_ctx *ctx)
{
struct hantro_vp9_dec_hw_ctx *vp9_ctx = &ctx->vp9_dec;
struct symbol_counts *cnts = vp9_ctx->misc.cpu + vp9_ctx->ctx_counters_offset;
int i, j, k, l, m;
vp9_ctx->cnts.partition = &cnts->partition_counts;
vp9_ctx->cnts.skip = &cnts->mbskip_count;
vp9_ctx->cnts.intra_inter = &cnts->intra_inter_count;
vp9_ctx->cnts.tx32p = &cnts->tx32x32_count;
/*
* g2 hardware uses tx16x16_count[2][3], while the api
* expects tx16p[2][4], so this must be explicitly copied
* into vp9_ctx->cnts.tx16p when passing the data to the
* vp9 library function
*/
vp9_ctx->cnts.tx8p = &cnts->tx8x8_count;
vp9_ctx->cnts.y_mode = &cnts->sb_ymode_counts;
vp9_ctx->cnts.uv_mode = &cnts->uv_mode_counts;
vp9_ctx->cnts.comp = &cnts->comp_inter_count;
vp9_ctx->cnts.comp_ref = &cnts->comp_ref_count;
vp9_ctx->cnts.single_ref = &cnts->single_ref_count;
vp9_ctx->cnts.filter = &cnts->switchable_interp_counts;
vp9_ctx->cnts.mv_joint = &cnts->mv_counts.joints;
vp9_ctx->cnts.sign = &cnts->mv_counts.sign;
vp9_ctx->cnts.classes = &cnts->mv_counts.classes;
vp9_ctx->cnts.class0 = &cnts->mv_counts.class0;
vp9_ctx->cnts.bits = &cnts->mv_counts.bits;
vp9_ctx->cnts.class0_fp = &cnts->mv_counts.class0_fp;
vp9_ctx->cnts.fp = &cnts->mv_counts.fp;
vp9_ctx->cnts.class0_hp = &cnts->mv_counts.class0_hp;
vp9_ctx->cnts.hp = &cnts->mv_counts.hp;
for (i = 0; i < ARRAY_SIZE(vp9_ctx->cnts.coeff); ++i)
for (j = 0; j < ARRAY_SIZE(vp9_ctx->cnts.coeff[i]); ++j)
for (k = 0; k < ARRAY_SIZE(vp9_ctx->cnts.coeff[i][0]); ++k)
for (l = 0; l < ARRAY_SIZE(vp9_ctx->cnts.coeff[i][0][0]); ++l)
INNER_LOOP;
}
int hantro_vp9_dec_init(struct hantro_ctx *ctx)
{
struct hantro_dev *vpu = ctx->dev;
const struct hantro_variant *variant = vpu->variant;
struct hantro_vp9_dec_hw_ctx *vp9_dec = &ctx->vp9_dec;
struct hantro_aux_buf *tile_edge = &vp9_dec->tile_edge;
struct hantro_aux_buf *segment_map = &vp9_dec->segment_map;
struct hantro_aux_buf *misc = &vp9_dec->misc;
u32 i, max_width, max_height, size;
if (variant->num_dec_fmts < 1)
return -EINVAL;
for (i = 0; i < variant->num_dec_fmts; ++i)
if (variant->dec_fmts[i].fourcc == V4L2_PIX_FMT_VP9_FRAME)
break;
if (i == variant->num_dec_fmts)
return -EINVAL;
max_width = vpu->variant->dec_fmts[i].frmsize.max_width;
max_height = vpu->variant->dec_fmts[i].frmsize.max_height;
size = hantro_vp9_tile_filter_size(max_height);
vp9_dec->bsd_ctrl_offset = size;
size += hantro_vp9_bsd_control_size(max_height);
tile_edge->cpu = dma_alloc_coherent(vpu->dev, size, &tile_edge->dma, GFP_KERNEL);
if (!tile_edge->cpu)
return -ENOMEM;
tile_edge->size = size;
memset(tile_edge->cpu, 0, size);
size = hantro_vp9_segment_map_size(max_width, max_height);
vp9_dec->segment_map_size = size;
size *= 2; /* we need two areas of this size, used alternately */
segment_map->cpu = dma_alloc_coherent(vpu->dev, size, &segment_map->dma, GFP_KERNEL);
if (!segment_map->cpu)
goto err_segment_map;
segment_map->size = size;
memset(segment_map->cpu, 0, size);
size = hantro_vp9_prob_tab_size();
vp9_dec->ctx_counters_offset = size;
size += hantro_vp9_count_tab_size();
vp9_dec->tile_info_offset = size;
size += hantro_vp9_tile_info_size();
misc->cpu = dma_alloc_coherent(vpu->dev, size, &misc->dma, GFP_KERNEL);
if (!misc->cpu)
goto err_misc;
misc->size = size;
memset(misc->cpu, 0, size);
init_v4l2_vp9_count_tbl(ctx);
return 0;
err_misc:
dma_free_coherent(vpu->dev, segment_map->size, segment_map->cpu, segment_map->dma);
err_segment_map:
dma_free_coherent(vpu->dev, tile_edge->size, tile_edge->cpu, tile_edge->dma);
return -ENOMEM;
}
void hantro_vp9_dec_exit(struct hantro_ctx *ctx)
{
struct hantro_dev *vpu = ctx->dev;
struct hantro_vp9_dec_hw_ctx *vp9_dec = &ctx->vp9_dec;
struct hantro_aux_buf *tile_edge = &vp9_dec->tile_edge;
struct hantro_aux_buf *segment_map = &vp9_dec->segment_map;
struct hantro_aux_buf *misc = &vp9_dec->misc;
dma_free_coherent(vpu->dev, misc->size, misc->cpu, misc->dma);
dma_free_coherent(vpu->dev, segment_map->size, segment_map->cpu, segment_map->dma);
dma_free_coherent(vpu->dev, tile_edge->size, tile_edge->cpu, tile_edge->dma);
}
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Hantro VP9 codec driver
*
* Copyright (C) 2021 Collabora Ltd.
*/
struct hantro_g2_mv_probs {
u8 joint[3];
u8 sign[2];
u8 class0_bit[2][1];
u8 fr[2][3];
u8 class0_hp[2];
u8 hp[2];
u8 classes[2][10];
u8 class0_fr[2][2][3];
u8 bits[2][10];
};
struct hantro_g2_probs {
u8 inter_mode[7][4];
u8 is_inter[4];
u8 uv_mode[10][8];
u8 tx8[2][1];
u8 tx16[2][2];
u8 tx32[2][3];
u8 y_mode_tail[4][1];
u8 y_mode[4][8];
u8 partition[2][16][4]; /* [keyframe][][], [inter][][] */
u8 uv_mode_tail[10][1];
u8 interp_filter[4][2];
u8 comp_mode[5];
u8 skip[3];
u8 pad1[1];
struct hantro_g2_mv_probs mv;
u8 single_ref[5][2];
u8 comp_ref[5];
u8 pad2[17];
u8 coef[4][2][2][6][6][4];
};
struct hantro_g2_all_probs {
u8 kf_y_mode_prob[10][10][8];
u8 kf_y_mode_prob_tail[10][10][1];
u8 ref_pred_probs[3];
u8 mb_segment_tree_probs[7];
u8 segment_pred_probs[3];
u8 ref_scores[4];
u8 prob_comppred[2];
u8 pad1[9];
u8 kf_uv_mode_prob[10][8];
u8 kf_uv_mode_prob_tail[10][1];
u8 pad2[6];
struct hantro_g2_probs probs;
};
struct mv_counts {
u32 joints[4];
u32 sign[2][2];
u32 classes[2][11];
u32 class0[2][2];
u32 bits[2][10][2];
u32 class0_fp[2][2][4];
u32 fp[2][4];
u32 class0_hp[2][2];
u32 hp[2][2];
};
struct symbol_counts {
u32 inter_mode_counts[7][3][2];
u32 sb_ymode_counts[4][10];
u32 uv_mode_counts[10][10];
u32 partition_counts[16][4];
u32 switchable_interp_counts[4][3];
u32 intra_inter_count[4][2];
u32 comp_inter_count[5][2];
u32 single_ref_count[5][2][2];
u32 comp_ref_count[5][2];
u32 tx32x32_count[2][4];
u32 tx16x16_count[2][3];
u32 tx8x8_count[2][2];
u32 mbskip_count[3][2];
struct mv_counts mv_counts;
u32 count_coeffs[2][2][6][6][4];
u32 count_coeffs8x8[2][2][6][6][4];
u32 count_coeffs16x16[2][2][6][6][4];
u32 count_coeffs32x32[2][2][6][6][4];
u32 count_eobs[4][2][2][6][6];
};
...@@ -150,6 +150,19 @@ static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = { ...@@ -150,6 +150,19 @@ static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = {
.step_height = MB_DIM, .step_height = MB_DIM,
}, },
}, },
{
.fourcc = V4L2_PIX_FMT_VP9_FRAME,
.codec_mode = HANTRO_MODE_VP9_DEC,
.max_depth = 2,
.frmsize = {
.min_width = 48,
.max_width = 3840,
.step_width = MB_DIM,
.min_height = 48,
.max_height = 2160,
.step_height = MB_DIM,
},
},
}; };
static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id) static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id)
...@@ -241,6 +254,13 @@ static const struct hantro_codec_ops imx8mq_vpu_g2_codec_ops[] = { ...@@ -241,6 +254,13 @@ static const struct hantro_codec_ops imx8mq_vpu_g2_codec_ops[] = {
.init = hantro_hevc_dec_init, .init = hantro_hevc_dec_init,
.exit = hantro_hevc_dec_exit, .exit = hantro_hevc_dec_exit,
}, },
[HANTRO_MODE_VP9_DEC] = {
.run = hantro_g2_vp9_dec_run,
.done = hantro_g2_vp9_dec_done,
.reset = imx8m_vpu_g2_reset,
.init = hantro_vp9_dec_init,
.exit = hantro_vp9_dec_exit,
},
}; };
/* /*
...@@ -281,7 +301,7 @@ const struct hantro_variant imx8mq_vpu_g2_variant = { ...@@ -281,7 +301,7 @@ const struct hantro_variant imx8mq_vpu_g2_variant = {
.dec_offset = 0x0, .dec_offset = 0x0,
.dec_fmts = imx8m_vpu_g2_dec_fmts, .dec_fmts = imx8m_vpu_g2_dec_fmts,
.num_dec_fmts = ARRAY_SIZE(imx8m_vpu_g2_dec_fmts), .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_g2_dec_fmts),
.codec = HANTRO_HEVC_DECODER, .codec = HANTRO_HEVC_DECODER | HANTRO_VP9_DECODER,
.codec_ops = imx8mq_vpu_g2_codec_ops, .codec_ops = imx8mq_vpu_g2_codec_ops,
.init = imx8mq_vpu_hw_init, .init = imx8mq_vpu_hw_init,
.runtime_resume = imx8mq_runtime_resume, .runtime_resume = imx8mq_runtime_resume,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment