Commit 03e612e7 authored by Jernej Skrabec's avatar Jernej Skrabec Committed by Mauro Carvalho Chehab
Browse files

media: cedrus: Fix H264 4k support



H264 decoder needs additional or bigger buffers in order to decode 4k
videos.

Signed-off-by: default avatarJernej Skrabec <jernej.skrabec@siol.net>
Acked-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 3aef46bd
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -116,8 +116,15 @@ struct cedrus_ctx {
			ssize_t		mv_col_buf_size;
			void		*pic_info_buf;
			dma_addr_t	pic_info_buf_dma;
			ssize_t		pic_info_buf_size;
			void		*neighbor_info_buf;
			dma_addr_t	neighbor_info_buf_dma;
			void		*deblk_buf;
			dma_addr_t	deblk_buf_dma;
			ssize_t		deblk_buf_size;
			void		*intra_pred_buf;
			dma_addr_t	intra_pred_buf_dma;
			ssize_t		intra_pred_buf_size;
		} h264;
		struct {
			void		*mv_col_buf;
+83 −8
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ struct cedrus_h264_sram_ref_pic {
#define CEDRUS_H264_FRAME_NUM		18

#define CEDRUS_NEIGHBOR_INFO_BUF_SIZE	(16 * SZ_1K)
#define CEDRUS_PIC_INFO_BUF_SIZE	(128 * SZ_1K)
#define CEDRUS_MIN_PIC_INFO_BUF_SIZE       (130 * SZ_1K)

static void cedrus_h264_write_sram(struct cedrus_dev *dev,
				   enum cedrus_h264_sram_off off,
@@ -342,6 +342,20 @@ static void cedrus_set_params(struct cedrus_ctx *ctx,
		     VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID |
		     VE_H264_VLD_ADDR_LAST);

	if (ctx->src_fmt.width > 2048) {
		cedrus_write(dev, VE_BUF_CTRL,
			     VE_BUF_CTRL_INTRAPRED_MIXED_RAM |
			     VE_BUF_CTRL_DBLK_MIXED_RAM);
		cedrus_write(dev, VE_DBLK_DRAM_BUF_ADDR,
			     ctx->codec.h264.deblk_buf_dma);
		cedrus_write(dev, VE_INTRAPRED_DRAM_BUF_ADDR,
			     ctx->codec.h264.intra_pred_buf_dma);
	} else {
		cedrus_write(dev, VE_BUF_CTRL,
			     VE_BUF_CTRL_INTRAPRED_INT_SRAM |
			     VE_BUF_CTRL_DBLK_INT_SRAM);
	}

	/*
	 * FIXME: Since the bitstream parsing is done in software, and
	 * in userspace, this shouldn't be needed anymore. But it
@@ -502,18 +516,30 @@ static void cedrus_h264_setup(struct cedrus_ctx *ctx,
static int cedrus_h264_start(struct cedrus_ctx *ctx)
{
	struct cedrus_dev *dev = ctx->dev;
	unsigned int pic_info_size;
	unsigned int field_size;
	unsigned int mv_col_size;
	int ret;

	/* Formula for picture buffer size is taken from CedarX source. */

	if (ctx->src_fmt.width > 2048)
		pic_info_size = CEDRUS_H264_FRAME_NUM * 0x4000;
	else
		pic_info_size = CEDRUS_H264_FRAME_NUM * 0x1000;

	/*
	 * FIXME: It seems that the H6 cedarX code is using a formula
	 * here based on the size of the frame, while all the older
	 * code is using a fixed size, so that might need to be
	 * changed at some point.
	 * FIXME: If V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is set,
	 * there is no need to multiply by 2.
	 */
	pic_info_size += ctx->src_fmt.height * 2 * 64;

	if (pic_info_size < CEDRUS_MIN_PIC_INFO_BUF_SIZE)
		pic_info_size = CEDRUS_MIN_PIC_INFO_BUF_SIZE;

	ctx->codec.h264.pic_info_buf_size = pic_info_size;
	ctx->codec.h264.pic_info_buf =
		dma_alloc_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE,
		dma_alloc_coherent(dev->dev, ctx->codec.h264.pic_info_buf_size,
				   &ctx->codec.h264.pic_info_buf_dma,
				   GFP_KERNEL);
	if (!ctx->codec.h264.pic_info_buf)
@@ -566,15 +592,56 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx)
		goto err_neighbor_buf;
	}

	if (ctx->src_fmt.width > 2048) {
		/*
		 * Formulas for deblock and intra prediction buffer sizes
		 * are taken from CedarX source.
		 */

		ctx->codec.h264.deblk_buf_size =
			ALIGN(ctx->src_fmt.width, 32) * 12;
		ctx->codec.h264.deblk_buf =
			dma_alloc_coherent(dev->dev,
					   ctx->codec.h264.deblk_buf_size,
					   &ctx->codec.h264.deblk_buf_dma,
					   GFP_KERNEL);
		if (!ctx->codec.h264.deblk_buf) {
			ret = -ENOMEM;
			goto err_mv_col_buf;
		}

		ctx->codec.h264.intra_pred_buf_size =
			ALIGN(ctx->src_fmt.width, 64) * 5;
		ctx->codec.h264.intra_pred_buf =
			dma_alloc_coherent(dev->dev,
					   ctx->codec.h264.intra_pred_buf_size,
					   &ctx->codec.h264.intra_pred_buf_dma,
					   GFP_KERNEL);
		if (!ctx->codec.h264.intra_pred_buf) {
			ret = -ENOMEM;
			goto err_deblk_buf;
		}
	}

	return 0;

err_deblk_buf:
	dma_free_coherent(dev->dev, ctx->codec.h264.deblk_buf_size,
			  ctx->codec.h264.deblk_buf,
			  ctx->codec.h264.deblk_buf_dma);

err_mv_col_buf:
	dma_free_coherent(dev->dev, ctx->codec.h264.mv_col_buf_size,
			  ctx->codec.h264.mv_col_buf,
			  ctx->codec.h264.mv_col_buf_dma);

err_neighbor_buf:
	dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
			  ctx->codec.h264.neighbor_info_buf,
			  ctx->codec.h264.neighbor_info_buf_dma);

err_pic_buf:
	dma_free_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE,
	dma_free_coherent(dev->dev, ctx->codec.h264.pic_info_buf_size,
			  ctx->codec.h264.pic_info_buf,
			  ctx->codec.h264.pic_info_buf_dma);
	return ret;
@@ -590,9 +657,17 @@ static void cedrus_h264_stop(struct cedrus_ctx *ctx)
	dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
			  ctx->codec.h264.neighbor_info_buf,
			  ctx->codec.h264.neighbor_info_buf_dma);
	dma_free_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE,
	dma_free_coherent(dev->dev, ctx->codec.h264.pic_info_buf_size,
			  ctx->codec.h264.pic_info_buf,
			  ctx->codec.h264.pic_info_buf_dma);
	if (ctx->codec.h264.deblk_buf_size)
		dma_free_coherent(dev->dev, ctx->codec.h264.deblk_buf_size,
				  ctx->codec.h264.deblk_buf,
				  ctx->codec.h264.deblk_buf_dma);
	if (ctx->codec.h264.intra_pred_buf_size)
		dma_free_coherent(dev->dev, ctx->codec.h264.intra_pred_buf_size,
				  ctx->codec.h264.intra_pred_buf,
				  ctx->codec.h264.intra_pred_buf_dma);
}

static void cedrus_h264_trigger(struct cedrus_ctx *ctx)
+11 −0
Original line number Diff line number Diff line
@@ -46,6 +46,17 @@
#define VE_MODE_DEC_H264			(0x01 << 0)
#define VE_MODE_DEC_MPEG			(0x00 << 0)

#define VE_BUF_CTRL				0x50

#define VE_BUF_CTRL_INTRAPRED_EXT_RAM		(0x02 << 2)
#define VE_BUF_CTRL_INTRAPRED_MIXED_RAM		(0x01 << 2)
#define VE_BUF_CTRL_INTRAPRED_INT_SRAM		(0x00 << 2)
#define VE_BUF_CTRL_DBLK_EXT_RAM		(0x02 << 0)
#define VE_BUF_CTRL_DBLK_MIXED_RAM		(0x01 << 0)
#define VE_BUF_CTRL_DBLK_INT_SRAM		(0x00 << 0)

#define VE_DBLK_DRAM_BUF_ADDR			0x54
#define VE_INTRAPRED_DRAM_BUF_ADDR		0x58
#define VE_PRIMARY_CHROMA_BUF_LEN		0xc4
#define VE_PRIMARY_FB_LINE_STRIDE		0xc8