Commit 65429ba8 authored by Jernej Skrabec's avatar Jernej Skrabec Committed by Mauro Carvalho Chehab
Browse files

media: cedrus: h265: Support decoding 10-bit frames



10-bit frames needs extra buffer space when 8-bit capture format is
used. Use previously prepared infrastructure to adjust buffer size.

Signed-off-by: default avatarJernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent 3d273e81
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ static int cedrus_try_ctrl(struct v4l2_ctrl *ctrl)
	} else if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS) {
		const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
		struct cedrus_ctx *ctx = container_of(ctrl->handler, struct cedrus_ctx, hdl);
		unsigned int bit_depth;
		struct vb2_queue *vq;

		if (sps->chroma_format_idc != 1)
			/* Only 4:2:0 is supported */
@@ -63,6 +65,24 @@ static int cedrus_try_ctrl(struct v4l2_ctrl *ctrl)
				/* Only 8-bit is supported */
				return -EINVAL;
		}

		bit_depth = max(sps->bit_depth_luma_minus8,
				sps->bit_depth_chroma_minus8) + 8;

		vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
				     V4L2_BUF_TYPE_VIDEO_CAPTURE);

		/*
		 * Bit depth can't be higher than currently set once
		 * buffers are allocated.
		 */
		if (vb2_is_busy(vq)) {
			if (ctx->bit_depth < bit_depth)
				return -EINVAL;
		} else {
			ctx->bit_depth = bit_depth;
			cedrus_reset_cap_format(ctx);
		}
	}

	return 0;
@@ -354,6 +374,7 @@ static int cedrus_open(struct file *file)
	v4l2_fh_init(&ctx->fh, video_devdata(file));
	file->private_data = &ctx->fh;
	ctx->dev = dev;
	ctx->bit_depth = 8;

	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
					    &cedrus_queue_init);
+1 −0
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@ struct cedrus_ctx {
	struct v4l2_pix_format		src_fmt;
	struct v4l2_pix_format		dst_fmt;
	struct cedrus_dec_ops		*current_codec;
	unsigned int			bit_depth;

	struct v4l2_ctrl_handler	hdl;
	struct v4l2_ctrl		**ctrls;
+35 −0
Original line number Diff line number Diff line
@@ -41,6 +41,19 @@ struct cedrus_h265_sram_pred_weight {
	__s8	offset;
} __packed;

static unsigned int cedrus_h265_2bit_size(unsigned int width,
					  unsigned int height)
{
	/*
	 * Vendor library additionally aligns width and height to 16,
	 * but all capture formats are already aligned to that anyway,
	 * so we can skip that here. All formats are also one form of
	 * YUV 4:2:0 or another, so we can safely assume multiplication
	 * factor of 1.5.
	 */
	return ALIGN(width / 4, 32) * height * 3 / 2;
}

static enum cedrus_irq_status cedrus_h265_irq_status(struct cedrus_ctx *ctx)
{
	struct cedrus_dev *dev = ctx->dev;
@@ -802,6 +815,18 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
						      VE_DEC_H265_SRAM_OFFSET_PRED_WEIGHT_CHROMA_L1);
	}

	if (ctx->bit_depth > 8) {
		unsigned int stride = ALIGN(ctx->dst_fmt.width / 4, 32);

		reg = ctx->dst_fmt.sizeimage -
		      cedrus_h265_2bit_size(ctx->dst_fmt.width,
					    ctx->dst_fmt.height);
		cedrus_write(dev, VE_DEC_H265_OFFSET_ADDR_FIRST_OUT, reg);

		reg = VE_DEC_H265_10BIT_CONFIGURE_FIRST_2BIT_STRIDE(stride);
		cedrus_write(dev, VE_DEC_H265_10BIT_CONFIGURE, reg);
	}

	/* Enable appropriate interruptions. */
	cedrus_write(dev, VE_DEC_H265_CTRL, VE_DEC_H265_CTRL_IRQ_MASK);

@@ -874,6 +899,15 @@ static void cedrus_h265_trigger(struct cedrus_ctx *ctx)
	cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_DEC_SLICE);
}

static unsigned int cedrus_h265_extra_cap_size(struct cedrus_ctx *ctx,
					       struct v4l2_pix_format *pix_fmt)
{
	if (ctx->bit_depth > 8)
		return cedrus_h265_2bit_size(pix_fmt->width, pix_fmt->height);

	return 0;
}

struct cedrus_dec_ops cedrus_dec_ops_h265 = {
	.irq_clear	= cedrus_h265_irq_clear,
	.irq_disable	= cedrus_h265_irq_disable,
@@ -882,4 +916,5 @@ struct cedrus_dec_ops cedrus_dec_ops_h265 = {
	.start		= cedrus_h265_start,
	.stop		= cedrus_h265_stop,
	.trigger	= cedrus_h265_trigger,
	.extra_cap_size	= cedrus_h265_extra_cap_size,
};
+16 −0
Original line number Diff line number Diff line
@@ -498,6 +498,22 @@

#define VE_DEC_H265_LOW_ADDR			(VE_ENGINE_DEC_H265 + 0x80)

#define VE_DEC_H265_OFFSET_ADDR_FIRST_OUT	(VE_ENGINE_DEC_H265 + 0x84)
#define VE_DEC_H265_OFFSET_ADDR_SECOND_OUT	(VE_ENGINE_DEC_H265 + 0x88)

#define VE_DEC_H265_SECOND_OUT_FMT_8BIT_PLUS_2BIT	0
#define VE_DEC_H265_SECOND_OUT_FMT_P010			1
#define VE_DEC_H265_SECOND_OUT_FMT_10BIT_4x4_TILED	2

#define VE_DEC_H265_10BIT_CONFIGURE_SECOND_OUT_FMT(v) \
	SHIFT_AND_MASK_BITS(v, 24, 23)
#define VE_DEC_H265_10BIT_CONFIGURE_SECOND_2BIT_ENABLE	BIT(22)
#define VE_DEC_H265_10BIT_CONFIGURE_SECOND_2BIT_STRIDE(v) \
	SHIFT_AND_MASK_BITS(v, 21, 11)
#define VE_DEC_H265_10BIT_CONFIGURE_FIRST_2BIT_STRIDE(v) \
	SHIFT_AND_MASK_BITS(v, 10, 0)
#define VE_DEC_H265_10BIT_CONFIGURE		(VE_ENGINE_DEC_H265 + 0x8c)

#define VE_DEC_H265_LOW_ADDR_PRIMARY_CHROMA(a) \
	SHIFT_AND_MASK_BITS(a, 31, 24)
#define VE_DEC_H265_LOW_ADDR_SECONDARY_CHROMA(a) \