RE: [PATCH 7/9] media: MFC: Add MFC v5.1 V4L2 driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



My review also imply Kamil's original patch.

Jeongtae Park wrote:
> Multi Format Codec v5.1 is a module available on S5PC110 and S5PC210
> Samsung SoCs. Hardware is capable of handling a range of video codecs
> and this driver provides V4L2 interface for video decoding & encoding.
> 
> Reviewed-by: Peter Oh <jaeryul.oh@xxxxxxxxxxx>
> Signed-off-by: Jeongtae Park <jtp.park@xxxxxxxxxxx>
> ---

<snip>
> +
> +/* Display status */
> +#define S5P_FIMV_DEC_STATUS_DECODING_ONLY		0
> +#define S5P_FIMV_DEC_STATUS_DECODING_DISPLAY		1
> +#define S5P_FIMV_DEC_STATUS_DISPLAY_ONLY		2
> +#define S5P_FIMV_DEC_STATUS_DECODING_EMPTY		3
> +#define S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK	7
> +#define S5P_FIMV_DEC_STATUS_PROGRESSIVE			(0<<3)
> +#define S5P_FIMV_DEC_STATUS_INTERLACE			(1<<3)
> +#define S5P_FIMV_DEC_STATUS_INTERLACE_MASK		(1<<3)
> +#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_TWO		(0<<4)
> +#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_FOUR		(1<<4)
> +#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_MASK		(1<<4)
> +#define S5P_FIMV_DEC_STATUS_CRC_GENERATED		(1<<5)
> +#define S5P_FIMV_DEC_STATUS_CRC_NOT_GENERATED		(0<<5)
> +#define S5P_FIMV_DEC_STATUS_CRC_MASK			(1<<5)


Use like (0 << 3), (1 << 3) ...

<snip>

> +/* Enumerate format */
> +static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out,
> +						enum s5p_mfc_node_type
> node)
> +{
> +	struct s5p_mfc_fmt *fmt;
> +	int i, j = 0;
> +
> +	if (node == MFCNODE_INVALID)
> +		return 0;
> +
> +	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
> +		if (mplane && formats[i].num_planes == 1)
> +			continue;
> +		else if (!mplane && formats[i].num_planes > 1)
> +			continue;
> +		if (node == MFCNODE_DECODER) {
> +			if (out && formats[i].type != MFC_FMT_DEC)
> +				continue;
> +			else if (!out && formats[i].type != MFC_FMT_RAW)
> +				continue;
> +		} else if (node == MFCNODE_ENCODER) {
> +			if (out && formats[i].type != MFC_FMT_RAW)
> +				continue;
> +			else if (!out && formats[i].type != MFC_FMT_ENC)
> +				continue;
> +		}
> +
> +		if (j == f->index) {
> +			fmt = &formats[i];
> +			strlcpy(f->description, fmt->name,
> +				sizeof(f->description));
> +			f->pixelformat = fmt->fourcc;
> +
> +			return 0;
> +		}
> +
> +		++j;
> +	}
> +
> +	return -EINVAL;
> +}
> +

At a glance, no needed to use j variable.
if (i == f->index) instead of if (j == f->index)

<snip>

> +/* Get format */
> +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format
*f)
> +{
> +	struct s5p_mfc_ctx *ctx = priv;
> +
> +	mfc_debug_enter();
> +	mfc_debug("f->type = %d ctx->state = %d\n", f->type, ctx->state);
> +	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
> +	    ctx->state == MFCINST_GOT_INST) {
> +		/* If the MFC is parsing the header,
> +		 * so wait until it is finished */
> +		s5p_mfc_clean_ctx_int_flags(ctx);
> +		s5p_mfc_wait_for_done_ctx(ctx,
> S5P_FIMV_R2H_CMD_SEQ_DONE_RET,
> +									1);
> +	}
> +	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
> +	    ctx->state >= MFCINST_HEAD_PARSED &&
> +	    ctx->state <= MFCINST_ABORT) {
> +		/* This is run on CAPTURE (deocde output) */
> +		/* Width and height are set to the dimensions
> +		   of the movie, the buffer is bigger and
> +		   further processing stages should crop to this
> +		   rectangle. */
> +		f->fmt.pix_mp.width = ctx->buf_width;
> +		f->fmt.pix_mp.height = ctx->buf_height;
> +		f->fmt.pix_mp.field = V4L2_FIELD_NONE;
> +		f->fmt.pix_mp.num_planes = 2;
> +		/* Set pixelformat to the format in which MFC
> +		   outputs the decoded frame */
> +		f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT;
> +		f->fmt.pix_mp.plane_fmt[0].bytesperline = ctx->buf_width;
> +		f->fmt.pix_mp.plane_fmt[0].sizeimage = ctx->luma_size;
> +		f->fmt.pix_mp.plane_fmt[1].bytesperline = ctx->buf_width;
> +		f->fmt.pix_mp.plane_fmt[1].sizeimage = ctx->chroma_size;
> +	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
> +		/* This is run on OUTPUT
> +		   The buffer contains compressed image
> +		   so width and height have no meaning */
> +		f->fmt.pix_mp.width = 1;
> +		f->fmt.pix_mp.height = 1;
> +		f->fmt.pix_mp.field = V4L2_FIELD_NONE;
> +		f->fmt.pix_mp.plane_fmt[0].bytesperline = ctx-
> >dec_src_buf_size;
> +		f->fmt.pix_mp.plane_fmt[0].sizeimage =
ctx->dec_src_buf_size;
> +		f->fmt.pix_mp.pixelformat = ctx->src_fmt->fourcc;
> +		f->fmt.pix_mp.num_planes = ctx->src_fmt->num_planes;
> +	} else {
> +		mfc_err("Format could not be read\n");
> +		mfc_debug("%s-- with error\n", __func__);
> +		return -EINVAL;
> +	}
> +	mfc_debug_leave();
> +	return 0;
> +}
> +

How about using size 0 instead of 1 for no meaning value?

In my opinion f->fmt.pix_mp.plane_fmt[1].bytesperline should be
(ctx->buf_width >> 1), isn't it ?

<snip>

> +static int vidioc_try_fmt_enc(struct file *file, void *priv, struct
v4l2_format *f)
> +{
> +	struct s5p_mfc_fmt *fmt;
> +
> +	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
> +		fmt = find_format(f, MFC_FMT_ENC);
> +		if (!fmt) {
> +			mfc_err("failed to try output format\n");
> +			return -EINVAL;
> +		}
> +
> +		if (f->fmt.pix_mp.plane_fmt[0].sizeimage == 0) {
> +			mfc_err("must be set encoding output size\n");
> +			return -EINVAL;
> +		}
> +
> +		f->fmt.pix_mp.plane_fmt[0].bytesperline =
> +			f->fmt.pix_mp.plane_fmt[0].sizeimage;
> +	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
> +		fmt = find_format(f, MFC_FMT_RAW);
> +		if (!fmt) {
> +			mfc_err("failed to try output format\n");
> +			return -EINVAL;
> +		}
> +
> +		if (fmt->num_planes != f->fmt.pix_mp.num_planes) {
> +			mfc_err("failed to try output format\n");
> +			return -EINVAL;
> +		}
> +	} else {
> +		mfc_err("invalid buf type\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +

How about check the valid range ?
This driver already has pix_limit variable in variant structure.

<snip>

> +static int vidioc_s_fmt_enc(struct file *file, void *priv, struct
v4l2_format *f)
> +{
> +	struct s5p_mfc_ctx *ctx = priv;
> +	unsigned long flags;
> +	int ret = 0;
> +	struct s5p_mfc_fmt *fmt;
> +
> +	mfc_debug_enter();
> +
> +	ret = vidioc_try_fmt_enc(file, priv, f);
> +	if (ret)
> +		return ret;
> +
> +	if (ctx->vq_src.streaming || ctx->vq_dst.streaming) {
> +		v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
> +		fmt = find_format(f, MFC_FMT_ENC);
> +		if (!fmt) {
> +			mfc_err("failed to set capture format\n");
> +			return -EINVAL;
> +		}
> +		ctx->state = MFCINST_INIT;
> +
> +		ctx->dst_fmt = fmt;
> +		ctx->codec_mode = ctx->dst_fmt->codec_mode;
> +		mfc_debug("codec number: %d\n", ctx->dst_fmt->codec_mode);
> +
> +		ctx->enc_dst_buf_size =
f->fmt.pix_mp.plane_fmt[0].sizeimage;
> +		f->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
> +
> +		ctx->dst_bufs_cnt = 0;
> +		ctx->capture_state = QUEUE_FREE;
> +
> +		s5p_mfc_alloc_instance_buffer(ctx);
> +
> +		spin_lock_irqsave(&dev->condlock, flags);
> +		set_bit(ctx->num, &dev->ctx_work_bits);
> +		spin_unlock_irqrestore(&dev->condlock, flags);
> +
> +		s5p_mfc_clean_ctx_int_flags(ctx);
> +		s5p_mfc_try_run();
> +		if (s5p_mfc_wait_for_done_ctx(ctx, \
> +				S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET,
> 1)) {
> +			/* Error or timeout */
> +			mfc_err("Error getting instance from hardware.\n");
> +			s5p_mfc_release_instance_buffer(ctx);
> +			ret = -EIO;
> +			goto out;
> +		}
> +		mfc_debug("Got instance number: %d\n", ctx->inst_no);
> +	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
> +		fmt = find_format(f, MFC_FMT_RAW);
> +		if (!fmt) {
> +			mfc_err("failed to set output format\n");
> +			return -EINVAL;
> +		}
> +
> +		if (fmt->num_planes != f->fmt.pix_mp.num_planes) {
> +			mfc_err("failed to set output format\n");
> +			ret = -EINVAL;
> +			goto out;
> +		}
> +
> +		ctx->src_fmt = fmt;
> +		ctx->img_width = f->fmt.pix_mp.width;
> +		ctx->img_height = f->fmt.pix_mp.height;
> +
> +		mfc_debug("codec number: %d\n", ctx->src_fmt->codec_mode);
> +		mfc_debug("fmt - w: %d, h: %d, ctx - w: %d, h: %d\n",
> +			f->fmt.pix_mp.width, f->fmt.pix_mp.height,
> +			ctx->img_width, ctx->img_height);
> +
> +		ctx->buf_width = f->fmt.pix_mp.plane_fmt[0].bytesperline;
> +		ctx->luma_size = f->fmt.pix_mp.plane_fmt[0].sizeimage;
> +		ctx->buf_width = f->fmt.pix_mp.plane_fmt[1].bytesperline;
> +		ctx->chroma_size = f->fmt.pix_mp.plane_fmt[1].sizeimage;
> +
> +		ctx->src_bufs_cnt = 0;
> +		ctx->output_state = QUEUE_FREE;
> +	} else {
> +		mfc_err("invalid buf type\n");
> +		return -EINVAL;
> +	}
> +out:
> +	mfc_debug_leave();
> +	return ret;
> +}
> +

ctx->buf_width is overwritten by " f->fmt.pix_mp.plane_fmt[1].bytesperline".

<snip>

> +static int vidioc_reqbufs_enc(struct file *file, void *priv,
> +					  struct v4l2_requestbuffers
*reqbufs)
> +{
> +	struct s5p_mfc_ctx *ctx = priv;
> +	int ret = 0;
> +
> +	mfc_debug_enter();
> +
> +	mfc_debug("type: %d\n", reqbufs->memory);
> +
> +	/* if memory is not mmp or userptr return error */
> +	if ((reqbufs->memory != V4L2_MEMORY_MMAP) &&
> +		(reqbufs->memory != V4L2_MEMORY_USERPTR))
> +		return -EINVAL;
> +
> +	if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
> +		if (ctx->capture_state != QUEUE_FREE) {
> +			mfc_err("invalid capture state: %d\n", ctx-
> >capture_state);
> +			return -EINVAL;
> +		}
> +
> +		ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
> +		if (ret != 0) {
> +			mfc_err("error in vb2_reqbufs() for E(D)\n");
> +			return ret;
> +		}
> +		ctx->capture_state = QUEUE_BUFS_REQUESTED;
> +
> +		ret = s5p_mfc_alloc_codec_buffers(ctx);
> +		if (ret) {
> +			mfc_err("Failed to allocate encoding buffers.\n");
> +			reqbufs->count = 0;
> +			ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
> +			return -ENOMEM;
> +		}
> +	} else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
> {
> +		if (ctx->output_state != QUEUE_FREE) {
> +			mfc_err("invalid output state: %d\n",
ctx->output_state);
> +			return -EINVAL;
> +		}
> +
> +		ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
> +		if (ret != 0) {
> +			mfc_err("error in vb2_reqbufs() for E(S)\n");
> +			return ret;
> +		}
> +		ctx->output_state = QUEUE_BUFS_REQUESTED;
> +	} else {
> +		mfc_err("invalid buf type\n");
> +		return -EINVAL;
> +	}
> +
> +	mfc_debug("--\n");
> +
> +	return ret;
> +}
> +

if (ctx->capture_state != QUEUE_FREE), conditional statement looks strange.
If REQBUFS(0) directly follows REQBUFS(n), state is QUEUE_BUFS_REQUESTED.
So in that case REQBUFS(0) will be failed.

<snip>

> +static int set_ctrl_val_enc(struct s5p_mfc_ctx *ctx, struct v4l2_control
*ctrl)
> +{
> +	struct s5p_mfc_enc_params *p = &ctx->enc_params;
> +	int ret = 0;
> +
> +	switch (ctrl->id) {
> +	case V4L2_CID_CODEC_MFC51_ENC_GOP_SIZE:
> +		p->gop_size = ctrl->value;
> +		break;
> +	case V4L2_CID_CODEC_MFC51_ENC_MULTI_SLICE_MODE:
> +		p->slice_mode = ctrl->value;
> +		break;
> +	case V4L2_CID_CODEC_MFC51_ENC_MULTI_SLICE_MB:
> +		p->slice_mb = ctrl->value;
> +		break;
> +	case V4L2_CID_CODEC_MFC51_ENC_MULTI_SLICE_BIT:
> +		p->slice_bit = ctrl->value;
> +		break;
> +	case V4L2_CID_CODEC_MFC51_ENC_INTRA_REFRESH_MB:
> +		p->intra_refresh_mb = ctrl->value;
> +		break;
> +	case V4L2_CID_CODEC_MFC51_ENC_PAD_CTRL_ENABLE:
> +		p->pad = ctrl->value;
> +		break;
<snip>
> +	case V4L2_CID_CODEC_MFC51_ENC_H264_I_PERIOD:
> +		p->codec.h264.open_gop_size = ctrl->value;
> +		break;
> +	default:
> +		v4l2_err(&dev->v4l2_dev, "Invalid control\n");
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +

How about use MACRO like cmd_input_size in
./drivers/media/video/v4l2-ioctl.c.

<snip>

> +static int vidioc_g_ext_ctrls(struct file *file, void *priv,
> +				struct v4l2_ext_controls *f)
> +{
> +	struct s5p_mfc_ctx *ctx = priv;
> +	struct v4l2_ext_control *ext_ctrl;
> +	struct v4l2_control ctrl;
> +	int i;
> +	int ret = 0;
> +
> +	if (s5p_mfc_get_node_type(file) != MFCNODE_ENCODER)
> +		return -EINVAL;
> +
> +	if (f->ctrl_class != V4L2_CTRL_CLASS_CODEC)
> +		return -EINVAL;
> +
> +	for (i = 0; i < f->count; i++) {
> +		ext_ctrl = (f->controls + i);
> +
> +		ctrl.id = ext_ctrl->id;
> +
> +		ret = get_ctrl_val_enc(ctx, &ctrl);
> +		if (ret == 0) {
> +			ext_ctrl->value = ctrl.value;
> +		} else {
> +			f->error_idx = i;
> +			break;
> +		}
> +
> +		mfc_debug("[%d] id: 0x%08x, value: %d", i, ext_ctrl->id,
> +				ext_ctrl->value);
> +	}
> +
> +	return ret;
> +}
> +

How about use vidioc_g_ext_ctrls_enc instead of vidioc_g_ext_ctrls ?
Because the function is only for encoder.
vidioc_s_ext_ctrls also.

<snip>

> +/* Get cropping information */
> +static int vidioc_g_crop(struct file *file, void *priv,
> +		struct v4l2_crop *cr)
> +{
> +	struct s5p_mfc_ctx *ctx = priv;
> +	u32 left, right, top, bottom;
> +
> +	mfc_debug_enter();
> +	if (ctx->state != MFCINST_HEAD_PARSED &&
> +	ctx->state != MFCINST_RUNNING && ctx->state != MFCINST_FINISHING
> +					&& ctx->state != MFCINST_FINISHED)
> {
> +			mfc_debug("%s-- with error\n", __func__);
> +			return -EINVAL;
> +		}

Keep indent "}"

<snip>

> +static int s5p_mfc_enc_queue_setup(struct vb2_queue *vq,
> +		unsigned int *buf_count, unsigned int *plane_count,
> +		unsigned long psize[], void *allocators[])
> +{
> +	struct s5p_mfc_ctx *ctx = vq->drv_priv;
> +	int i;
> +
> +	mfc_debug_enter();
> +
> +	if (ctx->state != MFCINST_GOT_INST) {
> +		mfc_err("inavlid state: %d\n", ctx->state);
> +		return -EINVAL;
> +	}
> +
> +	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
> +		if (ctx->dst_fmt)
> +			*plane_count = ctx->dst_fmt->num_planes;
> +		else
> +			*plane_count = MFC_ENC_CAP_PLANE_COUNT;
> +
> +		if (*buf_count < 1)
> +			*buf_count = 1;
> +		if (*buf_count > MFC_MAX_BUFFERS)
> +			*buf_count = MFC_MAX_BUFFERS;
> +
> +		psize[0] = ctx->enc_dst_buf_size;
> +		allocators[0] = ctx->dev-
> >alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX];
> +	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
> +		if (ctx->src_fmt)
> +			*plane_count = ctx->src_fmt->num_planes;
> +		else
> +			*plane_count = MFC_ENC_OUT_PLANE_COUNT;
> +
> +		if (*buf_count < 1)
> +			*buf_count = 1;
> +		if (*buf_count > MFC_MAX_BUFFERS)
> +			*buf_count = MFC_MAX_BUFFERS;
> +
> +		psize[0] = ctx->luma_size;
> +		psize[1] = ctx->chroma_size;
> +		allocators[0] = ctx->dev-
> >alloc_ctx[MFC_CMA_BANK2_ALLOC_CTX];
> +		allocators[1] = ctx->dev-
> >alloc_ctx[MFC_CMA_BANK2_ALLOC_CTX];
> +
> +	} else {
> +		mfc_err("inavlid queue type: %d\n", vq->type);
> +		return -EINVAL;
> +	}
> +
> +	mfc_debug("buf_count: %d, plane_count: %d\n", *buf_count,
> *plane_count);
> +	for (i = 0; i < *plane_count; i++)
> +		mfc_debug("plane[%d] size=%lu\n", i, psize[i]);
> +
> +	mfc_debug_leave();
> +
> +	return 0;
> +}
> +

Below two lines are dead line.
		else
			*plane_count = MFC_ENC_OUT_PLANE_COUNT;
Because ctx->src_fmt is set in s5p_mfc_open.

<snip>

> +/* Let the streaming begin. */
> +static int s5p_mfc_start_streaming(struct vb2_queue *q)
> +{
> +	struct s5p_mfc_ctx *ctx = q->drv_priv;
> +
> +	unsigned long flags;
> +	/* If context is ready then schedule it to run */
> +	if (s5p_mfc_ctx_ready(ctx)) {
> +		spin_lock_irqsave(&dev->condlock, flags);
> +		set_bit(ctx->num, &dev->ctx_work_bits);
> +		spin_unlock_irqrestore(&dev->condlock, flags);
> +	}
> +
> +	s5p_mfc_try_run();
> +	return 0;
> +}
> +

In my opinion s5p_mfc_start_streaming is useless.
Because in the following sequence s5p_mfc_try_run will be called in
s5p_mfc_enc_buf_queue without s5p_mfc_start_streaming.
VIDIOC_STREAMON -> vidioc_streamon -> vb2_streamon -> __enqueue_in_driver ->
buf_queue -> s5p_mfc_enc_buf_queue

<snip>

> +/* Open an MFC node */
> +static int s5p_mfc_open(struct file *file)
> +{
> +	struct s5p_mfc_ctx *ctx = NULL;
> +	struct vb2_queue *q;
> +	unsigned long flags;
> +	int ret = 0;
> +
> +	mfc_debug_enter();
> +	dev->num_inst++;	/* It is guarded by mfc_mutex in vfd */
> +	/* Allocate memory for context */
> +	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
> +	if (!ctx) {
> +		mfc_err("Not enough memory.\n");
> +		ret = -ENOMEM;
> +		goto out_open;
> +	}
> +	file->private_data = ctx;
> +	ctx->dev = dev;
> +	INIT_LIST_HEAD(&ctx->src_queue);
> +	INIT_LIST_HEAD(&ctx->dst_queue);
> +	ctx->src_queue_cnt = 0;
> +	ctx->dst_queue_cnt = 0;
> +	/* Get context number */
> +	ctx->num = 0;
> +	while (dev->ctx[ctx->num]) {
> +		ctx->num++;
> +		if (ctx->num >= MFC_NUM_CONTEXTS) {
> +			mfc_err("Too many open contexts.\n");
> +			ret = -EAGAIN;
> +			goto out_open;
> +		}
> +	}
> +	/* Mark context as idle */
> +	spin_lock_irqsave(&dev->condlock, flags);
> +	clear_bit(ctx->num, &dev->ctx_work_bits);
> +	spin_unlock_irqrestore(&dev->condlock, flags);
> +	dev->ctx[ctx->num] = ctx;
> +	if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
> +		ctx->type = MFCINST_DECODER;
> +		ctx->c_ops = &decoder_codec_ops;
> +		/* Default format */
> +		ctx->src_fmt = &formats[DEC_DEF_SRC_FMT];
> +		ctx->dst_fmt = &formats[DEC_DEF_DST_FMT];
> +	} else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
> +		ctx->type = MFCINST_ENCODER;
> +		ctx->c_ops = &encoder_codec_ops;
> +		/* Default format */
> +		ctx->src_fmt = &formats[ENC_DEF_SRC_FMT];
> +		ctx->dst_fmt = &formats[ENC_DEF_DST_FMT];
> +	} else {
> +		ret = -ENOENT;
> +		goto out_open;
> +	}
> +	ctx->inst_no = -1;
> +	/* Load firmware if this is the first instance */
> +	if (dev->num_inst == 1) {
> +		dev->watchdog_timer.expires = jiffies +
> +
> 	msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
> +		add_timer(&dev->watchdog_timer);
> +
> +		/* Load the FW */
> +		ret = s5p_mfc_alloc_firmware(dev);
> +		if (ret != 0)
> +			goto out_open_2a;
> +		ret = s5p_mfc_load_firmware(dev);
> +		if (ret != 0)
> +			goto out_open_2;
> +		mfc_debug("Enabling clocks.\n");
> +		clk_enable(dev->clock1);
> +		clk_enable(dev->clock2);
> +		/* Init the FW */
> +		ret = s5p_mfc_init_hw(dev);
> +		if (ret != 0)
> +			goto out_open_3;
> +	}
> +
> +	/* Init videobuf2 queue for CAPTURE */
> +	q = &ctx->vq_dst;
> +	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> +	q->drv_priv = ctx;
> +	if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
> +		q->io_modes = VB2_MMAP;
> +		q->ops = &s5p_mfc_qops;
> +	} else {
> +		q->io_modes = VB2_MMAP | VB2_USERPTR;
> +		q->ops = &s5p_mfc_enc_qops;
> +	}
> +	q->mem_ops = &vb2_cma_memops;
> +	ret = vb2_queue_init(q);
> +	if (ret) {
> +		mfc_err("Failed to initialize videobuf2 queue(capture)\n");
> +		goto out_open_3;
> +	}
> +
> +	/* Init videobuf2 queue for OUTPUT */
> +	q = &ctx->vq_src;
> +	q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> +	q->io_modes = VB2_MMAP;
> +	q->drv_priv = ctx;
> +	if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
> +		q->io_modes = VB2_MMAP;
> +		q->ops = &s5p_mfc_qops;
> +	} else {
> +		q->io_modes = VB2_MMAP | VB2_USERPTR;
> +		q->ops = &s5p_mfc_enc_qops;
> +	}
> +	q->mem_ops = &vb2_cma_memops;
> +	ret = vb2_queue_init(q);
> +	if (ret) {
> +		mfc_err("Failed to initialize videobuf2 queue(output)\n");
> +		goto out_open_3;
> +	}
> +	init_waitqueue_head(&ctx->queue);
> +	mfc_debug("%s-- (via irq_cleanup_hw)\n", __func__);
> +	return ret;
> +	/* Deinit when failure occured */
> +out_open_3:
> +	if (dev->num_inst == 1) {
> +		clk_disable(dev->clock1);
> +		clk_disable(dev->clock2);
> +		s5p_mfc_release_firmware(dev);
> +	}
> +out_open_2:
> +	s5p_mfc_release_firmware(dev);
> +out_open_2a:
> +	dev->ctx[ctx->num] = 0;
> +	kfree(ctx);
> +	del_timer_sync(&dev->watchdog_timer);
> +out_open:
> +	dev->num_inst--;
> +	mfc_debug_leave();
> +	return ret;
> +}

You had better use atomic operation for increment and decrement instead
dev->num_inst++.

In my opinion -EBUSY is good for return value instead of -EAGAIN if ctx->num
is exceed MFC_NUM_CONTEXTS.

In my opinion, " /* Load firmware if this is the first instance */" is not
suitable comment.
Because clk_enable is included in the conditional statements.

How about exchange init videobuf2 sequence OUTPUT, CAPTURE ?
Because OUTPUT is the source of device and CAPTURE is the destination of
device.

<snip>

> +/* MFC probe function */
> +static int s5p_mfc_probe(struct platform_device *pdev)
> +{
> +	struct video_device *vfd;
> +	struct resource *res;
> +	int ret = -ENOENT;
> +	size_t size;
> +
> +	pr_debug("%s++\n", __func__);
> +	dev = kzalloc(sizeof *dev, GFP_KERNEL);
> +	if (!dev) {
> +		dev_err(&pdev->dev, "Not enough memory for MFC device.\n");
> +		return -ENOMEM;
> +	}
> +
> +	spin_lock_init(&dev->irqlock);
> +	spin_lock_init(&dev->condlock);
> +	dev_dbg(&pdev->dev, "Initialised spin lock\n");
> +	dev->plat_dev = pdev;
> +	if (!dev->plat_dev) {
> +		dev_err(&pdev->dev, "No platform data specified\n");
> +		ret = -ENODEV;
> +		goto free_dev;
> +	}
> +	dev_dbg(&pdev->dev, "Getting clocks\n");
> +	dev->clock1 = clk_get(&pdev->dev, "sclk_mfc");
> +	dev->clock2 = clk_get(&pdev->dev, "mfc");
> +	if (IS_ERR(dev->clock1) || IS_ERR(dev->clock2)) {
> +		dev_err(&pdev->dev, "failed to get mfc clock source\n");
> +		goto free_clk;
> +	}
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (res == NULL) {
> +		dev_err(&pdev->dev, "failed to get memory region
resource.\n");
> +		ret = -ENOENT;
> +		goto probe_out1;
> +	}
> +	size = (res->end - res->start) + 1;
> +	dev->mfc_mem = request_mem_region(res->start, size, pdev->name);
> +	if (dev->mfc_mem == NULL) {
> +		dev_err(&pdev->dev, "failed to get memory region.\n");
> +		ret = -ENOENT;
> +		goto probe_out2;
> +	}
> +	dev->base_virt_addr = ioremap(dev->mfc_mem->start,
> +			      dev->mfc_mem->end - dev->mfc_mem->start + 1);
> +	if (dev->base_virt_addr == NULL) {
> +		dev_err(&pdev->dev, "failed to ioremap address region.\n");
> +		ret = -ENOENT;
> +		goto probe_out3;
> +	}
> +	dev->regs_base = dev->base_virt_addr;
> +	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +	if (res == NULL) {
> +		dev_err(&pdev->dev, "failed to get irq resource.\n");
> +		ret = -ENOENT;
> +		goto probe_out4;
> +	}
> +	dev->irq = res->start;
> +	ret = request_irq(dev->irq, s5p_mfc_irq, IRQF_DISABLED, pdev->name,
> +
> 	dev);
> +	if (ret != 0) {
> +		dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
> +		goto probe_out5;
> +	}
> +	dev->mfc_mutex = kmalloc(sizeof(struct mutex), GFP_KERNEL);
> +	if (dev->mfc_mutex == NULL) {
> +		dev_err(&pdev->dev, "Memory allocation failed\n");
> +		ret = -ENOMEM;
> +		goto probe_out6;
> +	}
> +	mutex_init(dev->mfc_mutex);
> +	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
> +	if (ret)
> +		goto probe_out7;
> +	init_waitqueue_head(&dev->queue);
> +
> +	/* decoder */
> +	vfd = video_device_alloc();
> +	if (!vfd) {
> +		v4l2_err(&dev->v4l2_dev, "Failed to allocate video
device\n");
> +		ret = -ENOMEM;
> +		goto unreg_dev;
> +	}
> +	*vfd = s5p_mfc_videodev;
> +	vfd->lock = dev->mfc_mutex;
> +	vfd->v4l2_dev = &dev->v4l2_dev;
> +	snprintf(vfd->name, sizeof(vfd->name), "%s", s5p_mfc_videodev.name);
> +
> +	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
> +	if (ret) {
> +		v4l2_err(&dev->v4l2_dev, "Failed to register video
device\n");
> +		video_device_release(vfd);
> +		goto rel_vdev_dec;
> +	}
> +	v4l2_info(&dev->v4l2_dev,
> +			"MFC decoder device registered as /dev/video%d\n",
> +			vfd->num);
> +
> +	dev->vfd_dec = vfd;
> +
> +	/* encoder */
> +	vfd = video_device_alloc();
> +	if (!vfd) {
> +		v4l2_err(&dev->v4l2_dev,
> +				"Failed to allocate video device\n");
> +		ret = -ENOMEM;
> +		goto unreg_vdev_dec;
> +	}
> +	*vfd = s5p_mfc_enc_videodev;
> +	vfd->lock = dev->mfc_mutex;
> +	vfd->v4l2_dev = &dev->v4l2_dev;
> +	snprintf(vfd->name, sizeof(vfd->name), "%s",
> s5p_mfc_enc_videodev.name);
> +
> +	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
> +	if (ret) {
> +		v4l2_err(&dev->v4l2_dev, "Failed to register video
device\n");
> +		video_device_release(vfd);
> +		goto rel_vdev_enc;
> +	}
> +	v4l2_info(&dev->v4l2_dev,
> +			"MFC encoder device registered as /dev/video%d\n",
> +			vfd->num);
> +
> +	dev->vfd_enc = vfd;
> +
> +	video_set_drvdata(vfd, dev);
> +
> +	platform_set_drvdata(pdev, dev);
> +	dev->hw_lock = 0;
> +	dev->watchdog_workqueue = create_singlethread_workqueue("s5p-mfc");
> +	INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker);
> +	atomic_set(&dev->watchdog_cnt, 0);
> +	init_timer(&dev->watchdog_timer);
> +	dev->watchdog_timer.data = 0;
> +	dev->watchdog_timer.function = s5p_mfc_watchdog;
> +
> +	dev->alloc_ctx = vb2_cma_init_multi(&pdev->dev,
> MFC_CMA_ALLOC_CTX_NUM,
> +					s5p_mem_types,
> s5p_mem_alignments);
> +	if (IS_ERR(dev->alloc_ctx)) {
> +		mfc_err("Couldn't prepare allocator ctx.\n");
> +		ret = PTR_ERR(dev->alloc_ctx);
> +		goto alloc_ctx_fail;
> +	}
> +
> +	pr_debug("%s--\n", __func__);
> +	return 0;
> +
> +/* Deinit MFC if probe had failed */
> +alloc_ctx_fail:
> +	video_unregister_device(dev->vfd_enc);
> +rel_vdev_enc:
> +	video_device_release(dev->vfd_enc);
> +unreg_vdev_dec:
> +	video_unregister_device(dev->vfd_dec);
> +rel_vdev_dec:
> +	video_device_release(dev->vfd_dec);
> +unreg_dev:
> +	v4l2_device_unregister(&dev->v4l2_dev);
> +probe_out7:
> +	if (dev->mfc_mutex) {
> +		mutex_destroy(dev->mfc_mutex);
> +		kfree(dev->mfc_mutex);
> +	}
> +probe_out6:
> +	free_irq(dev->irq, dev);
> +probe_out5:
> +probe_out4:
> +	iounmap(dev->base_virt_addr);
> +	dev->base_virt_addr = NULL;
> +probe_out3:
> +	release_resource(dev->mfc_mem);
> +	kfree(dev->mfc_mem);
> +probe_out2:
> +probe_out1:
> +	clk_put(dev->clock1);
> +	clk_put(dev->clock2);
> +free_clk:
> +
> +free_dev:
> +	kfree(dev);
> +	pr_debug("%s-- with error\n", __func__);
> +	return ret;
> +}
> +

What's the diff btw dev->regs_base and dev->base_virt_addr ?
In your implementation I cannot find video_get_drvdata.
Is video_set_drvdata needed ?

<snip>

> +#define MFC_NUM_CONTEXTS	4

How about use MFC_NUM_INSTANT instead MFC_NUM_CONTEXTS ?
Because too many terms can make confusion.

<snip>

> +/**
> + * struct s5p_mfc_buf - MFC buffer
> + *
> + */
> +struct s5p_mfc_buf {
> +	struct list_head list;
> +	struct vb2_buffer *b;
> +	union {
> +		struct {
> +			size_t luma;
> +			size_t chroma;
> +		} raw;
> +		size_t stream;
> +	} paddr;
> +};

How about use cookie instead paddr ?

<snip>

> +/**
> + * struct s5p_mfc_ctx - This struct contains the instance context
> + */
> +struct s5p_mfc_ctx {
> +	struct s5p_mfc_dev *dev;
> +	int num;
> +
> +	int int_cond;
> +	int int_type;
> +	unsigned int int_err;
> +	wait_queue_head_t queue;
> +
> +	struct s5p_mfc_fmt *src_fmt;
> +	struct s5p_mfc_fmt *dst_fmt;
> +
> +	struct vb2_queue vq_src;
> +	struct vb2_queue vq_dst;
> +
> +	struct list_head src_queue;
> +	struct list_head dst_queue;
> +
> +	unsigned int src_queue_cnt;
> +	unsigned int dst_queue_cnt;
> +
> +	enum s5p_mfc_inst_type type;
> +	enum s5p_mfc_inst_state state;
> +	int inst_no;
> +
> +	/* Decoder parameters */
> +	int img_width;
> +	int img_height;
> +	int buf_width;
> +	int buf_height;
> +	int dpb_count;
> +	int total_dpb_count;
> +
> +	int luma_size;
> +	int chroma_size;
> +	int mv_size;
> +
> +	unsigned long consumed_stream;
> +	int slice_interface;
> +
> +	/* Buffers */
> +	void *port_a_buf;
> +	size_t port_a_phys;
> +	size_t port_a_size;
> +
> +	void *port_b_buf;
> +	size_t port_b_phys;
> +	size_t port_b_size;
> +
> +
> +	enum s5p_mfc_queue_state capture_state;
> +	enum s5p_mfc_queue_state output_state;
> +
> +	struct s5p_mfc_buf src_bufs[MFC_MAX_BUFFERS];
> +	int src_bufs_cnt;
> +	struct s5p_mfc_buf dst_bufs[MFC_MAX_BUFFERS];
> +	int dst_bufs_cnt;
> +
> +	unsigned int sequence;
> +	unsigned long dec_dst_flag;
> +	size_t dec_src_buf_size;
> +
> +	/* Control values */
> +	int codec_mode;
> +	__u32 pix_format;
> +	int loop_filter_mpeg4;
> +	int display_delay;
> +
> +	/* Buffers */
> +	void *instance_buf;
> +	size_t instance_phys;
> +	size_t instance_size;
> +
> +	void *desc_buf;
> +	size_t desc_phys;
> +
> +	void *shared_buf;
> +	size_t shared_phys;
> +	void *shared_virt;
> +
> +	/* Encoder parameters */
> +	struct s5p_mfc_enc_params enc_params;
> +
> +	size_t enc_dst_buf_size;
> +
> +	int frame_count;
> +	enum v4l2_codec_mfc5x_enc_frame_type frame_type;
> +	enum v4l2_codec_mfc5x_enc_force_frame_type force_frame_type;
> +
> +	struct s5p_mfc_codec_ops *c_ops;
> +};
> +

Data structure is too big. How about split it like as below ?
struct s5p_mfc_ctx {
	struct s5p_mfc_dec *dec;
	struct s5p_mfc_dec *enc;
	....
};

Or like this:

struct s5p_mfc_ctx {
	union {
		struct s5p_mfc_dec *dec;
		struct s5p_mfc_dec *enc;
	};
	....
};

What's the difference btw num and inst_no ?
It looks very similar.

And how about define common data structure for source, destination about
size, format ...  like mfc_frame ?
It can make simplify the structure.

<snip>

> +static struct v4l2_queryctrl s5p_mfc_ctrls[] = {
> +/* For decoding */
> +	{
> +		.id = V4L2_CID_CODEC_DISPLAY_DELAY,
> +		.type = V4L2_CTRL_TYPE_INTEGER,
> +		.name = "",
> +		.minimum = 0,
> +		.maximum = 16383,
> +		.step = 1,
> +		.default_value = 0,
> +	},
> +	{
> +		.id = V4L2_CID_CODEC_LOOP_FILTER_MPEG4_ENABLE,
> +		.type = V4L2_CTRL_TYPE_BOOLEAN,
> +		.name = "Mpeg4 Loop Filter Enable",
> +		.minimum = 0,
> +		.maximum = 1,
> +		.step = 1,
> +		.default_value = 0,
> +	},
> +	{
> +		.id = V4L2_CID_CODEC_SLICE_INTERFACE,
> +		.type = V4L2_CTRL_TYPE_BOOLEAN,
> +		.name = "Slice Interface Enable",
> +		.minimum = 0,
> +		.maximum = 1,
> +		.step = 1,
> +		.default_value = 0,
> +	},
> +/* For encoding */
> +	{
> +		.id = V4L2_CID_CODEC_MFC51_ENC_GOP_SIZE,
> +		.type = V4L2_CTRL_TYPE_INTEGER,
> +		.name = "The period of intra frame",
> +		.minimum = 0,
> +		.maximum = (1 << 16) - 1,
> +		.step = 1,
> +		.default_value = 0,
> +	},

You had better use control-framework.

<snip>

> +/* Allocate firmware */
> +int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
> +{
> +	int err;
> +	struct cma_info mem_info_f, mem_info_a, mem_info_b;

How about exchange above two lines ?

<snip>

> --
> 1.6.2.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux