Commit 86caab29 authored by Paul Kocialkowski's avatar Paul Kocialkowski Committed by Mauro Carvalho Chehab

media: cedrus: Add HEVC/H.265 decoding support

This introduces support for HEVC/H.265 to the Cedrus VPU driver, with
both uni-directional and bi-directional prediction modes supported.

Field-coded (interlaced) pictures, custom quantization matrices and
10-bit output are not supported at this point.
Signed-off-by: default avatarPaul Kocialkowski <paul.kocialkowski@bootlin.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent de06f289
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus.o obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus.o
sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o \ sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o \
cedrus_mpeg2.o cedrus_h264.o cedrus_mpeg2.o cedrus_h264.o cedrus_h265.o
...@@ -95,6 +95,45 @@ static const struct cedrus_control cedrus_controls[] = { ...@@ -95,6 +95,45 @@ static const struct cedrus_control cedrus_controls[] = {
.codec = CEDRUS_CODEC_H264, .codec = CEDRUS_CODEC_H264,
.required = false, .required = false,
}, },
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_HEVC_SPS,
},
.codec = CEDRUS_CODEC_H265,
.required = true,
},
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_HEVC_PPS,
},
.codec = CEDRUS_CODEC_H265,
.required = true,
},
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS,
},
.codec = CEDRUS_CODEC_H265,
.required = true,
},
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE,
.max = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
.def = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
},
.codec = CEDRUS_CODEC_H265,
.required = false,
},
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE,
.max = V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE,
.def = V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE,
},
.codec = CEDRUS_CODEC_H265,
.required = false,
},
}; };
#define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls) #define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls)
...@@ -340,6 +379,7 @@ static int cedrus_probe(struct platform_device *pdev) ...@@ -340,6 +379,7 @@ static int cedrus_probe(struct platform_device *pdev)
dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2; dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2;
dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264; dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264;
dev->dec_ops[CEDRUS_CODEC_H265] = &cedrus_dec_ops_h265;
mutex_init(&dev->dev_mutex); mutex_init(&dev->dev_mutex);
...@@ -450,22 +490,26 @@ static const struct cedrus_variant sun8i_a33_cedrus_variant = { ...@@ -450,22 +490,26 @@ static const struct cedrus_variant sun8i_a33_cedrus_variant = {
}; };
static const struct cedrus_variant sun8i_h3_cedrus_variant = { static const struct cedrus_variant sun8i_h3_cedrus_variant = {
.capabilities = CEDRUS_CAPABILITY_UNTILED, .capabilities = CEDRUS_CAPABILITY_UNTILED |
CEDRUS_CAPABILITY_H265_DEC,
.mod_rate = 402000000, .mod_rate = 402000000,
}; };
static const struct cedrus_variant sun50i_a64_cedrus_variant = { static const struct cedrus_variant sun50i_a64_cedrus_variant = {
.capabilities = CEDRUS_CAPABILITY_UNTILED, .capabilities = CEDRUS_CAPABILITY_UNTILED |
CEDRUS_CAPABILITY_H265_DEC,
.mod_rate = 402000000, .mod_rate = 402000000,
}; };
static const struct cedrus_variant sun50i_h5_cedrus_variant = { static const struct cedrus_variant sun50i_h5_cedrus_variant = {
.capabilities = CEDRUS_CAPABILITY_UNTILED, .capabilities = CEDRUS_CAPABILITY_UNTILED |
CEDRUS_CAPABILITY_H265_DEC,
.mod_rate = 402000000, .mod_rate = 402000000,
}; };
static const struct cedrus_variant sun50i_h6_cedrus_variant = { static const struct cedrus_variant sun50i_h6_cedrus_variant = {
.capabilities = CEDRUS_CAPABILITY_UNTILED, .capabilities = CEDRUS_CAPABILITY_UNTILED |
CEDRUS_CAPABILITY_H265_DEC,
.quirks = CEDRUS_QUIRK_NO_DMA_OFFSET, .quirks = CEDRUS_QUIRK_NO_DMA_OFFSET,
.mod_rate = 600000000, .mod_rate = 600000000,
}; };
......
...@@ -27,12 +27,14 @@ ...@@ -27,12 +27,14 @@
#define CEDRUS_NAME "cedrus" #define CEDRUS_NAME "cedrus"
#define CEDRUS_CAPABILITY_UNTILED BIT(0) #define CEDRUS_CAPABILITY_UNTILED BIT(0)
#define CEDRUS_CAPABILITY_H265_DEC BIT(1)
#define CEDRUS_QUIRK_NO_DMA_OFFSET BIT(0) #define CEDRUS_QUIRK_NO_DMA_OFFSET BIT(0)
enum cedrus_codec { enum cedrus_codec {
CEDRUS_CODEC_MPEG2, CEDRUS_CODEC_MPEG2,
CEDRUS_CODEC_H264, CEDRUS_CODEC_H264,
CEDRUS_CODEC_H265,
CEDRUS_CODEC_LAST, CEDRUS_CODEC_LAST,
}; };
...@@ -67,6 +69,12 @@ struct cedrus_mpeg2_run { ...@@ -67,6 +69,12 @@ struct cedrus_mpeg2_run {
const struct v4l2_ctrl_mpeg2_quantization *quantization; const struct v4l2_ctrl_mpeg2_quantization *quantization;
}; };
struct cedrus_h265_run {
const struct v4l2_ctrl_hevc_sps *sps;
const struct v4l2_ctrl_hevc_pps *pps;
const struct v4l2_ctrl_hevc_slice_params *slice_params;
};
struct cedrus_run { struct cedrus_run {
struct vb2_v4l2_buffer *src; struct vb2_v4l2_buffer *src;
struct vb2_v4l2_buffer *dst; struct vb2_v4l2_buffer *dst;
...@@ -74,6 +82,7 @@ struct cedrus_run { ...@@ -74,6 +82,7 @@ struct cedrus_run {
union { union {
struct cedrus_h264_run h264; struct cedrus_h264_run h264;
struct cedrus_mpeg2_run mpeg2; struct cedrus_mpeg2_run mpeg2;
struct cedrus_h265_run h265;
}; };
}; };
...@@ -110,6 +119,14 @@ struct cedrus_ctx { ...@@ -110,6 +119,14 @@ struct cedrus_ctx {
void *neighbor_info_buf; void *neighbor_info_buf;
dma_addr_t neighbor_info_buf_dma; dma_addr_t neighbor_info_buf_dma;
} h264; } h264;
struct {
void *mv_col_buf;
dma_addr_t mv_col_buf_addr;
ssize_t mv_col_buf_size;
ssize_t mv_col_buf_unit_size;
void *neighbor_info_buf;
dma_addr_t neighbor_info_buf_addr;
} h265;
} codec; } codec;
}; };
...@@ -155,6 +172,7 @@ struct cedrus_dev { ...@@ -155,6 +172,7 @@ struct cedrus_dev {
extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2; extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2;
extern struct cedrus_dec_ops cedrus_dec_ops_h264; extern struct cedrus_dec_ops cedrus_dec_ops_h264;
extern struct cedrus_dec_ops cedrus_dec_ops_h265;
static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val) static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val)
{ {
......
...@@ -59,6 +59,15 @@ void cedrus_device_run(void *priv) ...@@ -59,6 +59,15 @@ void cedrus_device_run(void *priv)
V4L2_CID_MPEG_VIDEO_H264_SPS); V4L2_CID_MPEG_VIDEO_H264_SPS);
break; break;
case V4L2_PIX_FMT_HEVC_SLICE:
run.h265.sps = cedrus_find_control_data(ctx,
V4L2_CID_MPEG_VIDEO_HEVC_SPS);
run.h265.pps = cedrus_find_control_data(ctx,
V4L2_CID_MPEG_VIDEO_HEVC_PPS);
run.h265.slice_params = cedrus_find_control_data(ctx,
V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS);
break;
default: default:
break; break;
} }
......
This diff is collapsed.
...@@ -50,6 +50,10 @@ int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_codec codec) ...@@ -50,6 +50,10 @@ int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_codec codec)
reg |= VE_MODE_DEC_H264; reg |= VE_MODE_DEC_H264;
break; break;
case CEDRUS_CODEC_H265:
reg |= VE_MODE_DEC_H265;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
......
...@@ -41,6 +41,11 @@ static struct cedrus_format cedrus_formats[] = { ...@@ -41,6 +41,11 @@ static struct cedrus_format cedrus_formats[] = {
.pixelformat = V4L2_PIX_FMT_H264_SLICE, .pixelformat = V4L2_PIX_FMT_H264_SLICE,
.directions = CEDRUS_DECODE_SRC, .directions = CEDRUS_DECODE_SRC,
}, },
{
.pixelformat = V4L2_PIX_FMT_HEVC_SLICE,
.directions = CEDRUS_DECODE_SRC,
.capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{ {
.pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12, .pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12,
.directions = CEDRUS_DECODE_DST, .directions = CEDRUS_DECODE_DST,
...@@ -102,6 +107,7 @@ void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) ...@@ -102,6 +107,7 @@ void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt)
switch (pix_fmt->pixelformat) { switch (pix_fmt->pixelformat) {
case V4L2_PIX_FMT_MPEG2_SLICE: case V4L2_PIX_FMT_MPEG2_SLICE:
case V4L2_PIX_FMT_H264_SLICE: case V4L2_PIX_FMT_H264_SLICE:
case V4L2_PIX_FMT_HEVC_SLICE:
/* Zero bytes per line for encoded source. */ /* Zero bytes per line for encoded source. */
bytesperline = 0; bytesperline = 0;
/* Choose some minimum size since this can't be 0 */ /* Choose some minimum size since this can't be 0 */
...@@ -439,6 +445,10 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count) ...@@ -439,6 +445,10 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
ctx->current_codec = CEDRUS_CODEC_H264; ctx->current_codec = CEDRUS_CODEC_H264;
break; break;
case V4L2_PIX_FMT_HEVC_SLICE:
ctx->current_codec = CEDRUS_CODEC_H265;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
......
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