All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jerry-ch Chen <Jerry-ch.Chen@mediatek.com>
To: Tomasz Figa <tfiga@chromium.org>
Cc: "devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	"Sean Cheng (鄭昇弘)" <Sean.Cheng@mediatek.com>,
	"laurent.pinchart+renesas@ideasonboard.com"
	<laurent.pinchart+renesas@ideasonboard.com>,
	"Rynn Wu (吳育恩)" <Rynn.Wu@mediatek.com>,
	srv_heupstream <srv_heupstream@mediatek.com>,
	"Po-Yang Huang (黃柏陽)" <po-yang.huang@mediatek.com>,
	"mchehab@kernel.org" <mchehab@kernel.org>,
	"suleiman@chromium.org" <suleiman@chromium.org>,
	"shik@chromium.org" <shik@chromium.org>,
	"Jungo Lin (林明俊)" <jungo.lin@mediatek.com>,
	"Sj Huang (黃信璋)" <sj.huang@mediatek.com>,
	"yuzhao@chromium.org" <yuzhao@chromium.org>,
	"linux-mediatek@lists.infradead.org"
	<linux-mediatek@lists.infradead.org>,
	zwisler@chromium.or
Subject: Re: [RFC PATCH V2 4/4] platform: mtk-isp: Add Mediatek FD driver
Date: Wed, 28 Aug 2019 10:00:25 +0800	[thread overview]
Message-ID: <1566957625.20680.33.camel@mtksdccf07> (raw)
In-Reply-To: <CAAFQd5Dw+jaT-+LAUEVeB8W1zdnOgPw7u+aCfDWhYW1SfbzO8g@mail.gmail.com>

Hi Tomasz,

On Mon, 2019-08-26 at 14:36 +0800, Tomasz Figa wrote:
> Hi Jerry,
> 
> On Sun, Aug 25, 2019 at 6:18 PM Jerry-ch Chen
> <Jerry-ch.Chen@mediatek.com> wrote:
> >
> > Hi Tomasz,
> >
> > On Fri, 2019-08-02 at 16:28 +0800, Tomasz Figa wrote:
> > > Hi Jerry,
> > >
> > > On Tue, Jul 09, 2019 at 04:41:12PM +0800, Jerry-ch Chen wrote:
> > > > From: Jerry-ch Chen <jerry-ch.chen@mediatek.com>
> > > >
> > > > This patch adds the driver of Face Detection (FD) unit in
> > > > Mediatek camera system, providing face detection function.
> > > >
> > > > The mtk-isp directory will contain drivers for multiple IP
> > > > blocks found in Mediatek ISP system. It will include ISP Pass 1
> > > > driver (CAM), sensor interface driver, DIP driver and face
> > > > detection driver.
> > > >
> > > > Signed-off-by: Jerry-ch Chen <jerry-ch.chen@mediatek.com>
> > > > ---
> > > >  drivers/media/platform/Makefile               |    2 +
> > > >  drivers/media/platform/mtk-isp/fd/Makefile    |    5 +
> > > >  drivers/media/platform/mtk-isp/fd/mtk_fd.h    |  157 +++
> > > >  drivers/media/platform/mtk-isp/fd/mtk_fd_40.c | 1259 +++++++++++++++++++++++++
> > > >  include/uapi/linux/v4l2-controls.h            |    4 +
> > > >  5 files changed, 1427 insertions(+)
> > > >  create mode 100644 drivers/media/platform/mtk-isp/fd/Makefile
> > > >  create mode 100644 drivers/media/platform/mtk-isp/fd/mtk_fd.h
> > > >  create mode 100644 drivers/media/platform/mtk-isp/fd/mtk_fd_40.c
> > > >
> > >
> > > Thanks for the patch! I finally got a chance to fully review the code. Sorry
> > > for the delay. Please check my comments inline.
> > >
> > I appreciate your comments.
> > I've fixed most of the comments and verifying them,
> > Sorry for the delay, here is the reply.
> >
> 
> Thanks for replying to all the comments, it's very helpful. I'll snip
> the parts that I don't have any further comments.
> 
> [snip]
> 
> > > > +   if (usercount == 1) {
> > > > +           pm_runtime_get_sync(&fd_dev->pdev->dev);
> > > > +           if (mtk_fd_hw_enable(fd_hw)) {
> > > > +                   pm_runtime_put_sync(&fd_dev->pdev->dev);
> > > > +                   atomic_dec_return(&fd_hw->fd_user_cnt);
> > > > +                   mutex_unlock(&fd_hw->fd_hw_lock);
> > > > +                   return -EINVAL;
> > > > +           }
> > > > +   }
> > >
> > > This is a simple mem-to-mem device, so there is no reason to keep it active
> > > all the time it's streaming. Please just get the runtime PM counter when
> > > queuing a job to the hardware and release it when the job finishes.
> > >
> > > I guess we might still want to do the costly operations like rproc_boot()
> > > when we start streaming, though.
> > >
> > Do you mean by moving the pm_runtime_get/put stuff to the job execution
> > and job finish place?
> 
> Yes.
> 
> > the rproc_boot() operation will be done here.
> >
> 
> How much time does the rproc_boot() operation take?
> 

About 0.7~1.3ms, average 0.8ms (14 measurements)

> [snip]
> 
> > > > +
> > > > +           pm_runtime_put_sync(&fd_dev->pdev->dev);
> > >
> > > Any reason to use pm_runtime_put_sync() over pm_runtime_put()?
> > >
> > No special reason to do so, the pm_runtime_put_sync here will be moved
> > to the place each job finished.
> >
> 
> If there is no reason, then the _sync() variant shouldn't be used, as
> it could affect the performance negatively.
> 

Ok, I will use pm_runtime_put();

> [snip]
> 
> > > > +static int mtk_fd_hw_job_exec(struct mtk_fd_hw *fd_hw,
> > > > +                         struct fd_hw_param *fd_param,
> > > > +                         void *output_vaddr)
> > > > +{
> > > > +   struct fd_user_output *fd_output;
> > > > +   struct ipi_message fd_ipi_msg;
> > > > +   int ret;
> > > > +   u32 num;
> > > > +
> > > > +   if (fd_param->user_param.src_img_fmt == FMT_UNKNOWN)
> > > > +           goto param_err;
> > >
> > > Is this possible?
> > >
> > Only if user set wrong format, I will remove this.
> >
> 
> It shouldn't be possible to set a wrong format, because TRY_/S_FMT
> should adjust what the user set to something that is valid.
> 

Ok, this will be removed.

> > > > +
> > > > +   mutex_lock(&fd_hw->fd_hw_lock);
> > > > +   fd_hw->state = FD_ENQ;
> > >
> > > What is this state for?
> > >
> > It was for checking status, if a job is processing, the state is
> > FD_ENQ,
> > then we should wait for the last job to be done when pm_suspend().
> >
> 
> If so, would it be possible to make it a bool and call is_processing?
> 
> [snip]
> 
> > > > +static int mtk_fd_vb2_queue_setup(struct vb2_queue *vq,
> > > > +                             unsigned int *num_buffers,
> > > > +                             unsigned int *num_planes,
> > > > +                             unsigned int sizes[],
> > > > +                             struct device *alloc_devs[])
> > > > +{
> > > > +   struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vq);
> > > > +   struct device *dev = ctx->dev;
> > > > +   unsigned int size;
> > > > +
> > > > +   switch (vq->type) {
> > > > +   case V4L2_BUF_TYPE_META_CAPTURE:
> > > > +           size = ctx->dst_fmt.buffersize;
> > > > +           break;
> > > > +   case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> > > > +           size = ctx->src_fmt.plane_fmt[0].sizeimage;
> > > > +           break;
> > > > +   default:
> > > > +           dev_err(dev, "invalid queue type: %d\n", vq->type);
> > >
> > > We should need to handle this.
> > >
> > Do you mean by giving a size instead of return -EINVAL?
> >
> 
> Sorry, typo. I meant we shouldn't need to handle it, because we can't
> get any other queue type here.
> 

Ok, I see, I will remove it.
also, this function will be updated as following due to the 2 plane
case.

static int mtk_fd_vb2_queue_setup(struct vb2_queue *vq,
				  unsigned int *num_buffers,
				  unsigned int *num_planes,
				  unsigned int sizes[],
				  struct device *alloc_devs[])
{
	struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vq);
	struct device *dev = ctx->dev;
	unsigned int size[2];

	switch (vq->type) {
	case V4L2_BUF_TYPE_META_CAPTURE:
		size[0] = ctx->dst_fmt.buffersize;
		break;
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
		size[0] = ctx->src_fmt.plane_fmt[0].sizeimage;
		if (*num_planes == 2)
			size[1] = ctx->src_fmt.plane_fmt[1].sizeimage;
		break;
	}

	if (*num_planes == 1) {
		if (sizes[0] < size[0])
			return -EINVAL;
	} else if (*num_planes == 2) {
		if ((sizes[0] < size[0]) && (sizes[1] < size[1]))
			return -EINVAL;
	} else {
		*num_planes = 1;
		sizes[0] = size[0];
	}

	return 0;
}

> [snip]
> 
> > > > +static void mtk_fd_vb2_stop_streaming(struct vb2_queue *vq)
> > > > +{
> > > > +   struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vq);
> > > > +   struct vb2_buffer *vb;
> > >
> > > How do we guarantee here that the hardware isn't still accessing the buffers
> > > removed below?
> > >
> > Maybe we can check the driver state flag and aborting the unfinished
> > jobs?
> > (fd_hw->state == FD_ENQ)
> >
> 
> Yes, we need to either cancel or wait for the currently processing
> job. It depends on hardware capabilities, but cancelling is generally
> preferred for the lower latency.
> 
Ok, it the state is ENQ, then we can disable the FD hw by controlling
the registers.

for example:
	writel(0x0, fd->fd_base + FD_HW_ENABLE);
	writel(0x0, fd->fd_base + FD_INT_EN);

> > > > +
> > > > +   if (V4L2_TYPE_IS_OUTPUT(vq->type))
> > > > +           vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > > > +   else
> > > > +           vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> > > > +
> > > > +   while (vb) {
> > > > +           v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR);
> > > > +           if (V4L2_TYPE_IS_OUTPUT(vq->type))
> > > > +                   vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > > > +           else
> > > > +                   vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> > > > +   }
> > >
> > > We can use v4l2_m2m_buf_remove(). Also we can move the call into the loop
> > > condition:
> > >
> > > while ((vb == v4l2_m2m_buf_remove(...)))
> > >       v4l2_m2m_buf_done(...);
> > >
> > Ok, I will refine as following:
> >
> > while ((vb = v4l2_m2m_buf_remove(V4L2_TYPE_IS_OUTPUT(vq->type)?
> >   &m2m_ctx->out_q_ctx :
> >   &m2m_ctx->cap_q_ctx)))
> > v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
> 
> Please move the queue type check before the loop and save the queue
> context in a local variable.
> 

Ok, I will refine as following:

	struct v4l2_m2m_queue_ctx *queue_ctx;

	queue_ctx = V4L2_TYPE_IS_OUTPUT(vq->type) ?
					&m2m_ctx->out_q_ctx :
					&m2m_ctx->cap_q_ctx;
	while ((vb = v4l2_m2m_buf_remove(queue_ctx)))
		v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);

> [snip]
> 
> > > > +}
> > > > +
> > > > +static void mtk_fd_vb2_request_complete(struct vb2_buffer *vb)
> > > > +{
> > > > +   struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> > > > +
> > > > +   v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
> > > > +}
> > > > +
> > > > +static void mtk_fd_fill_pixfmt_mp(struct v4l2_pix_format_mplane *dfmt,
> > > > +                             const struct v4l2_pix_format_mplane *sfmt)
> > > > +{
> > > > +   dfmt->width = sfmt->width;
> > > > +   dfmt->height = sfmt->height;
> > > > +   dfmt->pixelformat = sfmt->pixelformat;
> > > > +   dfmt->field = sfmt->field;
> > > > +   dfmt->colorspace = sfmt->colorspace;
> > > > +   dfmt->num_planes = sfmt->num_planes;
> > > > +
> > > > +   /* Use default */
> > > > +   dfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> > > > +   dfmt->quantization = V4L2_QUANTIZATION_DEFAULT;
> > > > +   dfmt->xfer_func =
> > > > +           V4L2_MAP_XFER_FUNC_DEFAULT(dfmt->colorspace);
> > > > +   dfmt->plane_fmt[0].bytesperline = dfmt->width * 2;
> > > > +   dfmt->plane_fmt[0].sizeimage =
> > > > +           dfmt->height * dfmt->plane_fmt[0].bytesperline;
> > > > +   memset(dfmt->reserved, 0, sizeof(dfmt->reserved));
> > > > +}
> > >
> > > Could we unify this function with mtk_fd_m2m_try_fmt_out_mp()? That function
> > > should be almost directly reusable for the default format initialization +/-
> > > the arguments passed to it.
> > >
> > Ok, I will try to reuse it as following:
> >
> > static void mtk_fd_fill_pixfmt_mp(struct v4l2_pix_format_mplane *dfmt,
> >   const struct v4l2_pix_format_mplane *sfmt)
> > {
> > dfmt->field = V4L2_FIELD_NONE;
> > dfmt->colorspace = V4L2_COLORSPACE_BT2020;
> > dfmt->num_planes = sfmt->num_planes;
> > dfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> > dfmt->quantization = V4L2_QUANTIZATION_DEFAULT;
> > dfmt->xfer_func =
> > V4L2_MAP_XFER_FUNC_DEFAULT(dfmt->colorspace);
> >
> > /* Keep user setting as possible */
> > dfmt->width = clamp(dfmt->width,
> >     MTK_FD_OUTPUT_MIN_WIDTH,
> >     MTK_FD_OUTPUT_MAX_WIDTH);
> > dfmt->height = clamp(dfmt->height,
> >      MTK_FD_OUTPUT_MIN_HEIGHT,
> >      MTK_FD_OUTPUT_MAX_HEIGHT);
> >
> > if (sfmt->num_planes == 2) {
> > /* NV16M and NV61M has 1 byte per pixel */
> > dfmt->plane_fmt[0].bytesperline = dfmt->width;
> > dfmt->plane_fmt[1].bytesperline = dfmt->width;
> > } else {
> > /* 2 bytes per pixel */
> > dfmt->plane_fmt[0].bytesperline = dfmt->width * 2;
> > }
> >
> > dfmt->plane_fmt[0].sizeimage =
> > dfmt->height * dfmt->plane_fmt[0].bytesperline;
> > }
> 
> How would the implementation of TRY_FMT look in this case?
> 

It will be looked like:

static int mtk_fd_try_fmt_out_mp(struct file *file,
				     void *fh,
				     struct v4l2_format *f)
{
	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
	const struct v4l2_pix_format_mplane *fmt;

	fmt = mtk_fd_find_fmt(pix_mp->pixelformat);
	if (!fmt)
		fmt = &mtk_fd_img_fmts[0];	/* Get default img fmt */

	mtk_fd_fill_pixfmt_mp(pix_mp, fmt);
	return 0;
}

> [snip]
> 
> > > > +static int mtk_fd_m2m_enum_fmt_out_mp(struct file *file, void *fh,
> > > > +                                 struct v4l2_fmtdesc *f)
> > > > +{
> > > > +   int i;
> > > > +
> > > > +   for (i = 0; i < NUM_FORMATS; ++i) {
> > > > +           if (i == f->index) {
> > > > +                   f->pixelformat = in_img_fmts[i].pixelformat;
> > > > +                   return 0;
> > > > +           }
> > > > +   }
> > >
> > > Why don't we just check if f->index is within the [0, ARRAY_SIZE()-1] bounds
> > > and then just use it to index the array directly?
> > >
> > I will refine as :
> >
> > static int mtk_fd_m2m_enum_fmt_out_mp(struct file *file, void *fh,
> >       struct v4l2_fmtdesc *f)
> > {
> > if ((f->index >= 0) && (f->index < NUM_FORMATS)) {
> 
> f->index is unsigned
> 
> > f->pixelformat = in_img_fmts[f->index].pixelformat;
> > return 0;
> > }
> >
> > return -EINVAL;
> > }
> 
> nit: The usual convention is to check for invalid values and return early, i.e.
> 
> if (f->index >= NUM_FORMATS)
>     return -EINVAL;
> 
> f->pixelformat = in_img_fmts[f->index].pixelformat;
> return 0;
> 
Ok, Done.

> > > > +
> > > > +   return -EINVAL;
> > > > +}
> > > > +
> > > > +static int mtk_fd_m2m_try_fmt_out_mp(struct file *file,
> > > > +                                void *fh,
> > > > +                                struct v4l2_format *f)
> > >
> > > I think we could just shorten the function prefixes to "mtk_fd_".
> > >
> > Do you mean by replace mtk_fd_m2m_* with mtk_fd_ ?
> >
> 
> Yes.
> 
Done.

> [snip]
> 
> > > > +static int mtk_fd_request_validate(struct media_request *req)
> > > > +{
> > > > +   unsigned int count;
> > > > +
> > > > +   count = vb2_request_buffer_cnt(req);
> > > > +   if (!count)
> > > > +           return -ENOENT;
> > >
> > > Why -ENOENT?
> > >
> > Reference the return code in vb2_request_validate()
> 
> You're right, -ENOENT seems to be the right error code here.
> 
> > I consider refining as following:
> > static int mtk_fd_request_validate(struct media_request *req)
> > {
> > if (vb2_request_buffer_cnt(req) > 1)
> > return -EINVAL;
> >
> > return vb2_request_validate(req);
> > }
> > or maybe I don't need to worry the request count greater than 1,
> > just remove this function and set vb2_request_validate as .req_validate
> > directly?
> >
> 
> Given that we only have 1 queue handling requests, we should be able
> to just use vb2_request_validate() indeed.
> 

Ok, it will be refined as following:

static const struct media_device_ops fd_m2m_media_ops = {
	.req_validate	= vb2_request_validate,
	.req_queue	= v4l2_m2m_request_queue,
};

Thanks and best regards,
Jerry

> Best regards,
> Tomasz

WARNING: multiple messages have this Message-ID (diff)
From: Jerry-ch Chen <Jerry-ch.Chen@mediatek.com>
To: Tomasz Figa <tfiga@chromium.org>
Cc: "yuzhao@chromium.org" <yuzhao@chromium.org>,
	"zwisler@chromium.org" <zwisler@chromium.org>,
	"linux-mediatek@lists.infradead.org"
	<linux-mediatek@lists.infradead.org>,
	"linux-arm-kernel@lists.infradead.org"
	<linux-arm-kernel@lists.infradead.org>,
	"Sean Cheng (鄭昇弘)" <Sean.Cheng@mediatek.com>,
	"Sj Huang (黃信璋)" <sj.huang@mediatek.com>,
	"Christie Yu (游雅惠)" <christie.yu@mediatek.com>,
	"Frederic Chen (陳俊元)" <Frederic.Chen@mediatek.com>,
	"Jungo Lin (林明俊)" <jungo.lin@mediatek.com>,
	"Rynn Wu (吳育恩)" <Rynn.Wu@mediatek.com>,
	"Po-Yang Huang (黃柏陽)" <po-yang.huang@mediatek.com>,
	"shik@chromium.org" <shik@chromium.org>,
	"suleiman@chromium.org" <suleiman@chromium.org>,
	"linux-media@vger.kernel.org" <linux-media@vger.kernel.org>,
	srv_heupstream <srv_heupstream@mediatek.com>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	"laurent.pinchart+renesas@ideasonboard.com"
	<laurent.pinchart+renesas@ideasonboard.com>,
	"hans.verkuil@cisco.com" <hans.verkuil@cisco.com>,
	"mchehab@kernel.org" <mchehab@kernel.org>,
	"matthias.bgg@gmail.com" <matthias.bgg@gmail.com>
Subject: Re: [RFC PATCH V2 4/4] platform: mtk-isp: Add Mediatek FD driver
Date: Wed, 28 Aug 2019 10:00:25 +0800	[thread overview]
Message-ID: <1566957625.20680.33.camel@mtksdccf07> (raw)
In-Reply-To: <CAAFQd5Dw+jaT-+LAUEVeB8W1zdnOgPw7u+aCfDWhYW1SfbzO8g@mail.gmail.com>

Hi Tomasz,

On Mon, 2019-08-26 at 14:36 +0800, Tomasz Figa wrote:
> Hi Jerry,
> 
> On Sun, Aug 25, 2019 at 6:18 PM Jerry-ch Chen
> <Jerry-ch.Chen@mediatek.com> wrote:
> >
> > Hi Tomasz,
> >
> > On Fri, 2019-08-02 at 16:28 +0800, Tomasz Figa wrote:
> > > Hi Jerry,
> > >
> > > On Tue, Jul 09, 2019 at 04:41:12PM +0800, Jerry-ch Chen wrote:
> > > > From: Jerry-ch Chen <jerry-ch.chen@mediatek.com>
> > > >
> > > > This patch adds the driver of Face Detection (FD) unit in
> > > > Mediatek camera system, providing face detection function.
> > > >
> > > > The mtk-isp directory will contain drivers for multiple IP
> > > > blocks found in Mediatek ISP system. It will include ISP Pass 1
> > > > driver (CAM), sensor interface driver, DIP driver and face
> > > > detection driver.
> > > >
> > > > Signed-off-by: Jerry-ch Chen <jerry-ch.chen@mediatek.com>
> > > > ---
> > > >  drivers/media/platform/Makefile               |    2 +
> > > >  drivers/media/platform/mtk-isp/fd/Makefile    |    5 +
> > > >  drivers/media/platform/mtk-isp/fd/mtk_fd.h    |  157 +++
> > > >  drivers/media/platform/mtk-isp/fd/mtk_fd_40.c | 1259 +++++++++++++++++++++++++
> > > >  include/uapi/linux/v4l2-controls.h            |    4 +
> > > >  5 files changed, 1427 insertions(+)
> > > >  create mode 100644 drivers/media/platform/mtk-isp/fd/Makefile
> > > >  create mode 100644 drivers/media/platform/mtk-isp/fd/mtk_fd.h
> > > >  create mode 100644 drivers/media/platform/mtk-isp/fd/mtk_fd_40.c
> > > >
> > >
> > > Thanks for the patch! I finally got a chance to fully review the code. Sorry
> > > for the delay. Please check my comments inline.
> > >
> > I appreciate your comments.
> > I've fixed most of the comments and verifying them,
> > Sorry for the delay, here is the reply.
> >
> 
> Thanks for replying to all the comments, it's very helpful. I'll snip
> the parts that I don't have any further comments.
> 
> [snip]
> 
> > > > +   if (usercount == 1) {
> > > > +           pm_runtime_get_sync(&fd_dev->pdev->dev);
> > > > +           if (mtk_fd_hw_enable(fd_hw)) {
> > > > +                   pm_runtime_put_sync(&fd_dev->pdev->dev);
> > > > +                   atomic_dec_return(&fd_hw->fd_user_cnt);
> > > > +                   mutex_unlock(&fd_hw->fd_hw_lock);
> > > > +                   return -EINVAL;
> > > > +           }
> > > > +   }
> > >
> > > This is a simple mem-to-mem device, so there is no reason to keep it active
> > > all the time it's streaming. Please just get the runtime PM counter when
> > > queuing a job to the hardware and release it when the job finishes.
> > >
> > > I guess we might still want to do the costly operations like rproc_boot()
> > > when we start streaming, though.
> > >
> > Do you mean by moving the pm_runtime_get/put stuff to the job execution
> > and job finish place?
> 
> Yes.
> 
> > the rproc_boot() operation will be done here.
> >
> 
> How much time does the rproc_boot() operation take?
> 

About 0.7~1.3ms, average 0.8ms (14 measurements)

> [snip]
> 
> > > > +
> > > > +           pm_runtime_put_sync(&fd_dev->pdev->dev);
> > >
> > > Any reason to use pm_runtime_put_sync() over pm_runtime_put()?
> > >
> > No special reason to do so, the pm_runtime_put_sync here will be moved
> > to the place each job finished.
> >
> 
> If there is no reason, then the _sync() variant shouldn't be used, as
> it could affect the performance negatively.
> 

Ok, I will use pm_runtime_put();

> [snip]
> 
> > > > +static int mtk_fd_hw_job_exec(struct mtk_fd_hw *fd_hw,
> > > > +                         struct fd_hw_param *fd_param,
> > > > +                         void *output_vaddr)
> > > > +{
> > > > +   struct fd_user_output *fd_output;
> > > > +   struct ipi_message fd_ipi_msg;
> > > > +   int ret;
> > > > +   u32 num;
> > > > +
> > > > +   if (fd_param->user_param.src_img_fmt == FMT_UNKNOWN)
> > > > +           goto param_err;
> > >
> > > Is this possible?
> > >
> > Only if user set wrong format, I will remove this.
> >
> 
> It shouldn't be possible to set a wrong format, because TRY_/S_FMT
> should adjust what the user set to something that is valid.
> 

Ok, this will be removed.

> > > > +
> > > > +   mutex_lock(&fd_hw->fd_hw_lock);
> > > > +   fd_hw->state = FD_ENQ;
> > >
> > > What is this state for?
> > >
> > It was for checking status, if a job is processing, the state is
> > FD_ENQ,
> > then we should wait for the last job to be done when pm_suspend().
> >
> 
> If so, would it be possible to make it a bool and call is_processing?
> 
> [snip]
> 
> > > > +static int mtk_fd_vb2_queue_setup(struct vb2_queue *vq,
> > > > +                             unsigned int *num_buffers,
> > > > +                             unsigned int *num_planes,
> > > > +                             unsigned int sizes[],
> > > > +                             struct device *alloc_devs[])
> > > > +{
> > > > +   struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vq);
> > > > +   struct device *dev = ctx->dev;
> > > > +   unsigned int size;
> > > > +
> > > > +   switch (vq->type) {
> > > > +   case V4L2_BUF_TYPE_META_CAPTURE:
> > > > +           size = ctx->dst_fmt.buffersize;
> > > > +           break;
> > > > +   case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> > > > +           size = ctx->src_fmt.plane_fmt[0].sizeimage;
> > > > +           break;
> > > > +   default:
> > > > +           dev_err(dev, "invalid queue type: %d\n", vq->type);
> > >
> > > We should need to handle this.
> > >
> > Do you mean by giving a size instead of return -EINVAL?
> >
> 
> Sorry, typo. I meant we shouldn't need to handle it, because we can't
> get any other queue type here.
> 

Ok, I see, I will remove it.
also, this function will be updated as following due to the 2 plane
case.

static int mtk_fd_vb2_queue_setup(struct vb2_queue *vq,
				  unsigned int *num_buffers,
				  unsigned int *num_planes,
				  unsigned int sizes[],
				  struct device *alloc_devs[])
{
	struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vq);
	struct device *dev = ctx->dev;
	unsigned int size[2];

	switch (vq->type) {
	case V4L2_BUF_TYPE_META_CAPTURE:
		size[0] = ctx->dst_fmt.buffersize;
		break;
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
		size[0] = ctx->src_fmt.plane_fmt[0].sizeimage;
		if (*num_planes == 2)
			size[1] = ctx->src_fmt.plane_fmt[1].sizeimage;
		break;
	}

	if (*num_planes == 1) {
		if (sizes[0] < size[0])
			return -EINVAL;
	} else if (*num_planes == 2) {
		if ((sizes[0] < size[0]) && (sizes[1] < size[1]))
			return -EINVAL;
	} else {
		*num_planes = 1;
		sizes[0] = size[0];
	}

	return 0;
}

> [snip]
> 
> > > > +static void mtk_fd_vb2_stop_streaming(struct vb2_queue *vq)
> > > > +{
> > > > +   struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vq);
> > > > +   struct vb2_buffer *vb;
> > >
> > > How do we guarantee here that the hardware isn't still accessing the buffers
> > > removed below?
> > >
> > Maybe we can check the driver state flag and aborting the unfinished
> > jobs?
> > (fd_hw->state == FD_ENQ)
> >
> 
> Yes, we need to either cancel or wait for the currently processing
> job. It depends on hardware capabilities, but cancelling is generally
> preferred for the lower latency.
> 
Ok, it the state is ENQ, then we can disable the FD hw by controlling
the registers.

for example:
	writel(0x0, fd->fd_base + FD_HW_ENABLE);
	writel(0x0, fd->fd_base + FD_INT_EN);

> > > > +
> > > > +   if (V4L2_TYPE_IS_OUTPUT(vq->type))
> > > > +           vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > > > +   else
> > > > +           vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> > > > +
> > > > +   while (vb) {
> > > > +           v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR);
> > > > +           if (V4L2_TYPE_IS_OUTPUT(vq->type))
> > > > +                   vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > > > +           else
> > > > +                   vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> > > > +   }
> > >
> > > We can use v4l2_m2m_buf_remove(). Also we can move the call into the loop
> > > condition:
> > >
> > > while ((vb == v4l2_m2m_buf_remove(...)))
> > >       v4l2_m2m_buf_done(...);
> > >
> > Ok, I will refine as following:
> >
> > while ((vb = v4l2_m2m_buf_remove(V4L2_TYPE_IS_OUTPUT(vq->type)?
> >   &m2m_ctx->out_q_ctx :
> >   &m2m_ctx->cap_q_ctx)))
> > v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
> 
> Please move the queue type check before the loop and save the queue
> context in a local variable.
> 

Ok, I will refine as following:

	struct v4l2_m2m_queue_ctx *queue_ctx;

	queue_ctx = V4L2_TYPE_IS_OUTPUT(vq->type) ?
					&m2m_ctx->out_q_ctx :
					&m2m_ctx->cap_q_ctx;
	while ((vb = v4l2_m2m_buf_remove(queue_ctx)))
		v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);

> [snip]
> 
> > > > +}
> > > > +
> > > > +static void mtk_fd_vb2_request_complete(struct vb2_buffer *vb)
> > > > +{
> > > > +   struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> > > > +
> > > > +   v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
> > > > +}
> > > > +
> > > > +static void mtk_fd_fill_pixfmt_mp(struct v4l2_pix_format_mplane *dfmt,
> > > > +                             const struct v4l2_pix_format_mplane *sfmt)
> > > > +{
> > > > +   dfmt->width = sfmt->width;
> > > > +   dfmt->height = sfmt->height;
> > > > +   dfmt->pixelformat = sfmt->pixelformat;
> > > > +   dfmt->field = sfmt->field;
> > > > +   dfmt->colorspace = sfmt->colorspace;
> > > > +   dfmt->num_planes = sfmt->num_planes;
> > > > +
> > > > +   /* Use default */
> > > > +   dfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> > > > +   dfmt->quantization = V4L2_QUANTIZATION_DEFAULT;
> > > > +   dfmt->xfer_func =
> > > > +           V4L2_MAP_XFER_FUNC_DEFAULT(dfmt->colorspace);
> > > > +   dfmt->plane_fmt[0].bytesperline = dfmt->width * 2;
> > > > +   dfmt->plane_fmt[0].sizeimage =
> > > > +           dfmt->height * dfmt->plane_fmt[0].bytesperline;
> > > > +   memset(dfmt->reserved, 0, sizeof(dfmt->reserved));
> > > > +}
> > >
> > > Could we unify this function with mtk_fd_m2m_try_fmt_out_mp()? That function
> > > should be almost directly reusable for the default format initialization +/-
> > > the arguments passed to it.
> > >
> > Ok, I will try to reuse it as following:
> >
> > static void mtk_fd_fill_pixfmt_mp(struct v4l2_pix_format_mplane *dfmt,
> >   const struct v4l2_pix_format_mplane *sfmt)
> > {
> > dfmt->field = V4L2_FIELD_NONE;
> > dfmt->colorspace = V4L2_COLORSPACE_BT2020;
> > dfmt->num_planes = sfmt->num_planes;
> > dfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> > dfmt->quantization = V4L2_QUANTIZATION_DEFAULT;
> > dfmt->xfer_func =
> > V4L2_MAP_XFER_FUNC_DEFAULT(dfmt->colorspace);
> >
> > /* Keep user setting as possible */
> > dfmt->width = clamp(dfmt->width,
> >     MTK_FD_OUTPUT_MIN_WIDTH,
> >     MTK_FD_OUTPUT_MAX_WIDTH);
> > dfmt->height = clamp(dfmt->height,
> >      MTK_FD_OUTPUT_MIN_HEIGHT,
> >      MTK_FD_OUTPUT_MAX_HEIGHT);
> >
> > if (sfmt->num_planes == 2) {
> > /* NV16M and NV61M has 1 byte per pixel */
> > dfmt->plane_fmt[0].bytesperline = dfmt->width;
> > dfmt->plane_fmt[1].bytesperline = dfmt->width;
> > } else {
> > /* 2 bytes per pixel */
> > dfmt->plane_fmt[0].bytesperline = dfmt->width * 2;
> > }
> >
> > dfmt->plane_fmt[0].sizeimage =
> > dfmt->height * dfmt->plane_fmt[0].bytesperline;
> > }
> 
> How would the implementation of TRY_FMT look in this case?
> 

It will be looked like:

static int mtk_fd_try_fmt_out_mp(struct file *file,
				     void *fh,
				     struct v4l2_format *f)
{
	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
	const struct v4l2_pix_format_mplane *fmt;

	fmt = mtk_fd_find_fmt(pix_mp->pixelformat);
	if (!fmt)
		fmt = &mtk_fd_img_fmts[0];	/* Get default img fmt */

	mtk_fd_fill_pixfmt_mp(pix_mp, fmt);
	return 0;
}

> [snip]
> 
> > > > +static int mtk_fd_m2m_enum_fmt_out_mp(struct file *file, void *fh,
> > > > +                                 struct v4l2_fmtdesc *f)
> > > > +{
> > > > +   int i;
> > > > +
> > > > +   for (i = 0; i < NUM_FORMATS; ++i) {
> > > > +           if (i == f->index) {
> > > > +                   f->pixelformat = in_img_fmts[i].pixelformat;
> > > > +                   return 0;
> > > > +           }
> > > > +   }
> > >
> > > Why don't we just check if f->index is within the [0, ARRAY_SIZE()-1] bounds
> > > and then just use it to index the array directly?
> > >
> > I will refine as :
> >
> > static int mtk_fd_m2m_enum_fmt_out_mp(struct file *file, void *fh,
> >       struct v4l2_fmtdesc *f)
> > {
> > if ((f->index >= 0) && (f->index < NUM_FORMATS)) {
> 
> f->index is unsigned
> 
> > f->pixelformat = in_img_fmts[f->index].pixelformat;
> > return 0;
> > }
> >
> > return -EINVAL;
> > }
> 
> nit: The usual convention is to check for invalid values and return early, i.e.
> 
> if (f->index >= NUM_FORMATS)
>     return -EINVAL;
> 
> f->pixelformat = in_img_fmts[f->index].pixelformat;
> return 0;
> 
Ok, Done.

> > > > +
> > > > +   return -EINVAL;
> > > > +}
> > > > +
> > > > +static int mtk_fd_m2m_try_fmt_out_mp(struct file *file,
> > > > +                                void *fh,
> > > > +                                struct v4l2_format *f)
> > >
> > > I think we could just shorten the function prefixes to "mtk_fd_".
> > >
> > Do you mean by replace mtk_fd_m2m_* with mtk_fd_ ?
> >
> 
> Yes.
> 
Done.

> [snip]
> 
> > > > +static int mtk_fd_request_validate(struct media_request *req)
> > > > +{
> > > > +   unsigned int count;
> > > > +
> > > > +   count = vb2_request_buffer_cnt(req);
> > > > +   if (!count)
> > > > +           return -ENOENT;
> > >
> > > Why -ENOENT?
> > >
> > Reference the return code in vb2_request_validate()
> 
> You're right, -ENOENT seems to be the right error code here.
> 
> > I consider refining as following:
> > static int mtk_fd_request_validate(struct media_request *req)
> > {
> > if (vb2_request_buffer_cnt(req) > 1)
> > return -EINVAL;
> >
> > return vb2_request_validate(req);
> > }
> > or maybe I don't need to worry the request count greater than 1,
> > just remove this function and set vb2_request_validate as .req_validate
> > directly?
> >
> 
> Given that we only have 1 queue handling requests, we should be able
> to just use vb2_request_validate() indeed.
> 

Ok, it will be refined as following:

static const struct media_device_ops fd_m2m_media_ops = {
	.req_validate	= vb2_request_validate,
	.req_queue	= v4l2_m2m_request_queue,
};

Thanks and best regards,
Jerry

> Best regards,
> Tomasz



WARNING: multiple messages have this Message-ID (diff)
From: Jerry-ch Chen <Jerry-ch.Chen@mediatek.com>
To: Tomasz Figa <tfiga@chromium.org>
Cc: "devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	"Sean Cheng (鄭昇弘)" <Sean.Cheng@mediatek.com>,
	"laurent.pinchart+renesas@ideasonboard.com"
	<laurent.pinchart+renesas@ideasonboard.com>,
	"Rynn Wu (吳育恩)" <Rynn.Wu@mediatek.com>,
	srv_heupstream <srv_heupstream@mediatek.com>,
	"Po-Yang Huang (黃柏陽)" <po-yang.huang@mediatek.com>,
	"mchehab@kernel.org" <mchehab@kernel.org>,
	"suleiman@chromium.org" <suleiman@chromium.org>,
	"shik@chromium.org" <shik@chromium.org>,
	"Jungo Lin (林明俊)" <jungo.lin@mediatek.com>,
	"Sj Huang (黃信璋)" <sj.huang@mediatek.com>,
	"yuzhao@chromium.org" <yuzhao@chromium.org>,
	"linux-mediatek@lists.infradead.org"
	<linux-mediatek@lists.infradead.org>,
	"zwisler@chromium.org" <zwisler@chromium.org>,
	"matthias.bgg@gmail.com" <matthias.bgg@gmail.com>,
	"Christie Yu (游雅惠)" <christie.yu@mediatek.com>,
	"Frederic Chen (陳俊元)" <Frederic.Chen@mediatek.com>,
	"hans.verkuil@cisco.com" <hans.verkuil@cisco.com>,
	"linux-arm-kernel@lists.infradead.org"
	<linux-arm-kernel@lists.infradead.org>,
	"linux-media@vger.kernel.org" <linux-media@vger.kernel.org>
Subject: Re: [RFC PATCH V2 4/4] platform: mtk-isp: Add Mediatek FD driver
Date: Wed, 28 Aug 2019 10:00:25 +0800	[thread overview]
Message-ID: <1566957625.20680.33.camel@mtksdccf07> (raw)
In-Reply-To: <CAAFQd5Dw+jaT-+LAUEVeB8W1zdnOgPw7u+aCfDWhYW1SfbzO8g@mail.gmail.com>

Hi Tomasz,

On Mon, 2019-08-26 at 14:36 +0800, Tomasz Figa wrote:
> Hi Jerry,
> 
> On Sun, Aug 25, 2019 at 6:18 PM Jerry-ch Chen
> <Jerry-ch.Chen@mediatek.com> wrote:
> >
> > Hi Tomasz,
> >
> > On Fri, 2019-08-02 at 16:28 +0800, Tomasz Figa wrote:
> > > Hi Jerry,
> > >
> > > On Tue, Jul 09, 2019 at 04:41:12PM +0800, Jerry-ch Chen wrote:
> > > > From: Jerry-ch Chen <jerry-ch.chen@mediatek.com>
> > > >
> > > > This patch adds the driver of Face Detection (FD) unit in
> > > > Mediatek camera system, providing face detection function.
> > > >
> > > > The mtk-isp directory will contain drivers for multiple IP
> > > > blocks found in Mediatek ISP system. It will include ISP Pass 1
> > > > driver (CAM), sensor interface driver, DIP driver and face
> > > > detection driver.
> > > >
> > > > Signed-off-by: Jerry-ch Chen <jerry-ch.chen@mediatek.com>
> > > > ---
> > > >  drivers/media/platform/Makefile               |    2 +
> > > >  drivers/media/platform/mtk-isp/fd/Makefile    |    5 +
> > > >  drivers/media/platform/mtk-isp/fd/mtk_fd.h    |  157 +++
> > > >  drivers/media/platform/mtk-isp/fd/mtk_fd_40.c | 1259 +++++++++++++++++++++++++
> > > >  include/uapi/linux/v4l2-controls.h            |    4 +
> > > >  5 files changed, 1427 insertions(+)
> > > >  create mode 100644 drivers/media/platform/mtk-isp/fd/Makefile
> > > >  create mode 100644 drivers/media/platform/mtk-isp/fd/mtk_fd.h
> > > >  create mode 100644 drivers/media/platform/mtk-isp/fd/mtk_fd_40.c
> > > >
> > >
> > > Thanks for the patch! I finally got a chance to fully review the code. Sorry
> > > for the delay. Please check my comments inline.
> > >
> > I appreciate your comments.
> > I've fixed most of the comments and verifying them,
> > Sorry for the delay, here is the reply.
> >
> 
> Thanks for replying to all the comments, it's very helpful. I'll snip
> the parts that I don't have any further comments.
> 
> [snip]
> 
> > > > +   if (usercount == 1) {
> > > > +           pm_runtime_get_sync(&fd_dev->pdev->dev);
> > > > +           if (mtk_fd_hw_enable(fd_hw)) {
> > > > +                   pm_runtime_put_sync(&fd_dev->pdev->dev);
> > > > +                   atomic_dec_return(&fd_hw->fd_user_cnt);
> > > > +                   mutex_unlock(&fd_hw->fd_hw_lock);
> > > > +                   return -EINVAL;
> > > > +           }
> > > > +   }
> > >
> > > This is a simple mem-to-mem device, so there is no reason to keep it active
> > > all the time it's streaming. Please just get the runtime PM counter when
> > > queuing a job to the hardware and release it when the job finishes.
> > >
> > > I guess we might still want to do the costly operations like rproc_boot()
> > > when we start streaming, though.
> > >
> > Do you mean by moving the pm_runtime_get/put stuff to the job execution
> > and job finish place?
> 
> Yes.
> 
> > the rproc_boot() operation will be done here.
> >
> 
> How much time does the rproc_boot() operation take?
> 

About 0.7~1.3ms, average 0.8ms (14 measurements)

> [snip]
> 
> > > > +
> > > > +           pm_runtime_put_sync(&fd_dev->pdev->dev);
> > >
> > > Any reason to use pm_runtime_put_sync() over pm_runtime_put()?
> > >
> > No special reason to do so, the pm_runtime_put_sync here will be moved
> > to the place each job finished.
> >
> 
> If there is no reason, then the _sync() variant shouldn't be used, as
> it could affect the performance negatively.
> 

Ok, I will use pm_runtime_put();

> [snip]
> 
> > > > +static int mtk_fd_hw_job_exec(struct mtk_fd_hw *fd_hw,
> > > > +                         struct fd_hw_param *fd_param,
> > > > +                         void *output_vaddr)
> > > > +{
> > > > +   struct fd_user_output *fd_output;
> > > > +   struct ipi_message fd_ipi_msg;
> > > > +   int ret;
> > > > +   u32 num;
> > > > +
> > > > +   if (fd_param->user_param.src_img_fmt == FMT_UNKNOWN)
> > > > +           goto param_err;
> > >
> > > Is this possible?
> > >
> > Only if user set wrong format, I will remove this.
> >
> 
> It shouldn't be possible to set a wrong format, because TRY_/S_FMT
> should adjust what the user set to something that is valid.
> 

Ok, this will be removed.

> > > > +
> > > > +   mutex_lock(&fd_hw->fd_hw_lock);
> > > > +   fd_hw->state = FD_ENQ;
> > >
> > > What is this state for?
> > >
> > It was for checking status, if a job is processing, the state is
> > FD_ENQ,
> > then we should wait for the last job to be done when pm_suspend().
> >
> 
> If so, would it be possible to make it a bool and call is_processing?
> 
> [snip]
> 
> > > > +static int mtk_fd_vb2_queue_setup(struct vb2_queue *vq,
> > > > +                             unsigned int *num_buffers,
> > > > +                             unsigned int *num_planes,
> > > > +                             unsigned int sizes[],
> > > > +                             struct device *alloc_devs[])
> > > > +{
> > > > +   struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vq);
> > > > +   struct device *dev = ctx->dev;
> > > > +   unsigned int size;
> > > > +
> > > > +   switch (vq->type) {
> > > > +   case V4L2_BUF_TYPE_META_CAPTURE:
> > > > +           size = ctx->dst_fmt.buffersize;
> > > > +           break;
> > > > +   case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> > > > +           size = ctx->src_fmt.plane_fmt[0].sizeimage;
> > > > +           break;
> > > > +   default:
> > > > +           dev_err(dev, "invalid queue type: %d\n", vq->type);
> > >
> > > We should need to handle this.
> > >
> > Do you mean by giving a size instead of return -EINVAL?
> >
> 
> Sorry, typo. I meant we shouldn't need to handle it, because we can't
> get any other queue type here.
> 

Ok, I see, I will remove it.
also, this function will be updated as following due to the 2 plane
case.

static int mtk_fd_vb2_queue_setup(struct vb2_queue *vq,
				  unsigned int *num_buffers,
				  unsigned int *num_planes,
				  unsigned int sizes[],
				  struct device *alloc_devs[])
{
	struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vq);
	struct device *dev = ctx->dev;
	unsigned int size[2];

	switch (vq->type) {
	case V4L2_BUF_TYPE_META_CAPTURE:
		size[0] = ctx->dst_fmt.buffersize;
		break;
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
		size[0] = ctx->src_fmt.plane_fmt[0].sizeimage;
		if (*num_planes == 2)
			size[1] = ctx->src_fmt.plane_fmt[1].sizeimage;
		break;
	}

	if (*num_planes == 1) {
		if (sizes[0] < size[0])
			return -EINVAL;
	} else if (*num_planes == 2) {
		if ((sizes[0] < size[0]) && (sizes[1] < size[1]))
			return -EINVAL;
	} else {
		*num_planes = 1;
		sizes[0] = size[0];
	}

	return 0;
}

> [snip]
> 
> > > > +static void mtk_fd_vb2_stop_streaming(struct vb2_queue *vq)
> > > > +{
> > > > +   struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vq);
> > > > +   struct vb2_buffer *vb;
> > >
> > > How do we guarantee here that the hardware isn't still accessing the buffers
> > > removed below?
> > >
> > Maybe we can check the driver state flag and aborting the unfinished
> > jobs?
> > (fd_hw->state == FD_ENQ)
> >
> 
> Yes, we need to either cancel or wait for the currently processing
> job. It depends on hardware capabilities, but cancelling is generally
> preferred for the lower latency.
> 
Ok, it the state is ENQ, then we can disable the FD hw by controlling
the registers.

for example:
	writel(0x0, fd->fd_base + FD_HW_ENABLE);
	writel(0x0, fd->fd_base + FD_INT_EN);

> > > > +
> > > > +   if (V4L2_TYPE_IS_OUTPUT(vq->type))
> > > > +           vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > > > +   else
> > > > +           vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> > > > +
> > > > +   while (vb) {
> > > > +           v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR);
> > > > +           if (V4L2_TYPE_IS_OUTPUT(vq->type))
> > > > +                   vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > > > +           else
> > > > +                   vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> > > > +   }
> > >
> > > We can use v4l2_m2m_buf_remove(). Also we can move the call into the loop
> > > condition:
> > >
> > > while ((vb == v4l2_m2m_buf_remove(...)))
> > >       v4l2_m2m_buf_done(...);
> > >
> > Ok, I will refine as following:
> >
> > while ((vb = v4l2_m2m_buf_remove(V4L2_TYPE_IS_OUTPUT(vq->type)?
> >   &m2m_ctx->out_q_ctx :
> >   &m2m_ctx->cap_q_ctx)))
> > v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
> 
> Please move the queue type check before the loop and save the queue
> context in a local variable.
> 

Ok, I will refine as following:

	struct v4l2_m2m_queue_ctx *queue_ctx;

	queue_ctx = V4L2_TYPE_IS_OUTPUT(vq->type) ?
					&m2m_ctx->out_q_ctx :
					&m2m_ctx->cap_q_ctx;
	while ((vb = v4l2_m2m_buf_remove(queue_ctx)))
		v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);

> [snip]
> 
> > > > +}
> > > > +
> > > > +static void mtk_fd_vb2_request_complete(struct vb2_buffer *vb)
> > > > +{
> > > > +   struct mtk_fd_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> > > > +
> > > > +   v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
> > > > +}
> > > > +
> > > > +static void mtk_fd_fill_pixfmt_mp(struct v4l2_pix_format_mplane *dfmt,
> > > > +                             const struct v4l2_pix_format_mplane *sfmt)
> > > > +{
> > > > +   dfmt->width = sfmt->width;
> > > > +   dfmt->height = sfmt->height;
> > > > +   dfmt->pixelformat = sfmt->pixelformat;
> > > > +   dfmt->field = sfmt->field;
> > > > +   dfmt->colorspace = sfmt->colorspace;
> > > > +   dfmt->num_planes = sfmt->num_planes;
> > > > +
> > > > +   /* Use default */
> > > > +   dfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> > > > +   dfmt->quantization = V4L2_QUANTIZATION_DEFAULT;
> > > > +   dfmt->xfer_func =
> > > > +           V4L2_MAP_XFER_FUNC_DEFAULT(dfmt->colorspace);
> > > > +   dfmt->plane_fmt[0].bytesperline = dfmt->width * 2;
> > > > +   dfmt->plane_fmt[0].sizeimage =
> > > > +           dfmt->height * dfmt->plane_fmt[0].bytesperline;
> > > > +   memset(dfmt->reserved, 0, sizeof(dfmt->reserved));
> > > > +}
> > >
> > > Could we unify this function with mtk_fd_m2m_try_fmt_out_mp()? That function
> > > should be almost directly reusable for the default format initialization +/-
> > > the arguments passed to it.
> > >
> > Ok, I will try to reuse it as following:
> >
> > static void mtk_fd_fill_pixfmt_mp(struct v4l2_pix_format_mplane *dfmt,
> >   const struct v4l2_pix_format_mplane *sfmt)
> > {
> > dfmt->field = V4L2_FIELD_NONE;
> > dfmt->colorspace = V4L2_COLORSPACE_BT2020;
> > dfmt->num_planes = sfmt->num_planes;
> > dfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> > dfmt->quantization = V4L2_QUANTIZATION_DEFAULT;
> > dfmt->xfer_func =
> > V4L2_MAP_XFER_FUNC_DEFAULT(dfmt->colorspace);
> >
> > /* Keep user setting as possible */
> > dfmt->width = clamp(dfmt->width,
> >     MTK_FD_OUTPUT_MIN_WIDTH,
> >     MTK_FD_OUTPUT_MAX_WIDTH);
> > dfmt->height = clamp(dfmt->height,
> >      MTK_FD_OUTPUT_MIN_HEIGHT,
> >      MTK_FD_OUTPUT_MAX_HEIGHT);
> >
> > if (sfmt->num_planes == 2) {
> > /* NV16M and NV61M has 1 byte per pixel */
> > dfmt->plane_fmt[0].bytesperline = dfmt->width;
> > dfmt->plane_fmt[1].bytesperline = dfmt->width;
> > } else {
> > /* 2 bytes per pixel */
> > dfmt->plane_fmt[0].bytesperline = dfmt->width * 2;
> > }
> >
> > dfmt->plane_fmt[0].sizeimage =
> > dfmt->height * dfmt->plane_fmt[0].bytesperline;
> > }
> 
> How would the implementation of TRY_FMT look in this case?
> 

It will be looked like:

static int mtk_fd_try_fmt_out_mp(struct file *file,
				     void *fh,
				     struct v4l2_format *f)
{
	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
	const struct v4l2_pix_format_mplane *fmt;

	fmt = mtk_fd_find_fmt(pix_mp->pixelformat);
	if (!fmt)
		fmt = &mtk_fd_img_fmts[0];	/* Get default img fmt */

	mtk_fd_fill_pixfmt_mp(pix_mp, fmt);
	return 0;
}

> [snip]
> 
> > > > +static int mtk_fd_m2m_enum_fmt_out_mp(struct file *file, void *fh,
> > > > +                                 struct v4l2_fmtdesc *f)
> > > > +{
> > > > +   int i;
> > > > +
> > > > +   for (i = 0; i < NUM_FORMATS; ++i) {
> > > > +           if (i == f->index) {
> > > > +                   f->pixelformat = in_img_fmts[i].pixelformat;
> > > > +                   return 0;
> > > > +           }
> > > > +   }
> > >
> > > Why don't we just check if f->index is within the [0, ARRAY_SIZE()-1] bounds
> > > and then just use it to index the array directly?
> > >
> > I will refine as :
> >
> > static int mtk_fd_m2m_enum_fmt_out_mp(struct file *file, void *fh,
> >       struct v4l2_fmtdesc *f)
> > {
> > if ((f->index >= 0) && (f->index < NUM_FORMATS)) {
> 
> f->index is unsigned
> 
> > f->pixelformat = in_img_fmts[f->index].pixelformat;
> > return 0;
> > }
> >
> > return -EINVAL;
> > }
> 
> nit: The usual convention is to check for invalid values and return early, i.e.
> 
> if (f->index >= NUM_FORMATS)
>     return -EINVAL;
> 
> f->pixelformat = in_img_fmts[f->index].pixelformat;
> return 0;
> 
Ok, Done.

> > > > +
> > > > +   return -EINVAL;
> > > > +}
> > > > +
> > > > +static int mtk_fd_m2m_try_fmt_out_mp(struct file *file,
> > > > +                                void *fh,
> > > > +                                struct v4l2_format *f)
> > >
> > > I think we could just shorten the function prefixes to "mtk_fd_".
> > >
> > Do you mean by replace mtk_fd_m2m_* with mtk_fd_ ?
> >
> 
> Yes.
> 
Done.

> [snip]
> 
> > > > +static int mtk_fd_request_validate(struct media_request *req)
> > > > +{
> > > > +   unsigned int count;
> > > > +
> > > > +   count = vb2_request_buffer_cnt(req);
> > > > +   if (!count)
> > > > +           return -ENOENT;
> > >
> > > Why -ENOENT?
> > >
> > Reference the return code in vb2_request_validate()
> 
> You're right, -ENOENT seems to be the right error code here.
> 
> > I consider refining as following:
> > static int mtk_fd_request_validate(struct media_request *req)
> > {
> > if (vb2_request_buffer_cnt(req) > 1)
> > return -EINVAL;
> >
> > return vb2_request_validate(req);
> > }
> > or maybe I don't need to worry the request count greater than 1,
> > just remove this function and set vb2_request_validate as .req_validate
> > directly?
> >
> 
> Given that we only have 1 queue handling requests, we should be able
> to just use vb2_request_validate() indeed.
> 

Ok, it will be refined as following:

static const struct media_device_ops fd_m2m_media_ops = {
	.req_validate	= vb2_request_validate,
	.req_queue	= v4l2_m2m_request_queue,
};

Thanks and best regards,
Jerry

> Best regards,
> Tomasz



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2019-08-28  2:00 UTC|newest]

Thread overview: 123+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-09  8:41 [RFC PATCH V2 0/4] media: platform: Add support for Face Detection (FD) on mt8183 SoC Jerry-ch Chen
2019-07-09  8:41 ` Jerry-ch Chen
2019-07-09  8:41 ` Jerry-ch Chen
2019-07-09  8:41 ` [RFC PATCH V2 1/4] dt-bindings: mt8183: Added FD dt-bindings Jerry-ch Chen
2019-07-09  8:41   ` Jerry-ch Chen
2019-07-09  8:41   ` Jerry-ch Chen
2019-07-12  7:16   ` CK Hu
2019-07-12  7:16     ` CK Hu
2019-07-12  7:16     ` CK Hu
2019-07-09  8:41 ` [RFC PATCH V2 2/4] dts: arm64: mt8183: Add FD nodes Jerry-ch Chen
2019-07-09  8:41   ` Jerry-ch Chen
2019-07-09  8:41   ` Jerry-ch Chen
2019-07-09  8:41 ` [RFC PATCH V2 3/4] media: platform: Add Mediatek FD driver KConfig Jerry-ch Chen
2019-07-09  8:41   ` Jerry-ch Chen
2019-07-09  8:41   ` Jerry-ch Chen
2019-09-05 12:30   ` Laurent Pinchart
2019-09-05 12:30     ` Laurent Pinchart
2019-09-05 12:30     ` Laurent Pinchart
2019-09-05 14:14     ` Jerry-ch Chen
2019-09-05 14:14       ` Jerry-ch Chen
2019-09-05 14:14       ` Jerry-ch Chen
2019-07-09  8:41 ` [RFC PATCH V2 4/4] platform: mtk-isp: Add Mediatek FD driver Jerry-ch Chen
2019-07-09  8:41   ` Jerry-ch Chen
2019-07-09  8:41   ` Jerry-ch Chen
2019-07-09 10:56   ` Enrico Weigelt, metux IT consult
2019-07-09 10:56     ` Enrico Weigelt, metux IT consult
2019-07-09 10:56     ` Enrico Weigelt, metux IT consult
2019-07-29  6:01     ` Jerry-ch Chen
2019-07-29  6:01       ` Jerry-ch Chen
2019-07-29  6:01       ` Jerry-ch Chen
2019-07-29  9:57       ` Tomasz Figa
2019-07-29  9:57         ` Tomasz Figa
2019-07-29  9:57         ` Tomasz Figa
2019-07-29 11:58         ` Jerry-ch Chen
2019-07-29 11:58           ` Jerry-ch Chen
2019-07-29 11:58           ` Jerry-ch Chen
2019-08-09  8:07           ` Tomasz Figa
2019-08-09  8:07             ` Tomasz Figa
2019-08-09  8:07             ` Tomasz Figa
2019-09-05 12:35             ` Laurent Pinchart
2019-09-05 12:35               ` Laurent Pinchart
2019-09-05 12:35               ` Laurent Pinchart
2019-08-02  8:28   ` Tomasz Figa
2019-08-02  8:28     ` Tomasz Figa
2019-08-02  8:28     ` Tomasz Figa
2019-08-25  9:18     ` Jerry-ch Chen
2019-08-25  9:18       ` Jerry-ch Chen
2019-08-25  9:18       ` Jerry-ch Chen
2019-08-26  6:36       ` Tomasz Figa
2019-08-26  6:36         ` Tomasz Figa
2019-08-26  6:36         ` Tomasz Figa
2019-08-28  2:00         ` Jerry-ch Chen [this message]
2019-08-28  2:00           ` Jerry-ch Chen
2019-08-28  2:00           ` Jerry-ch Chen
2019-08-30  8:33           ` Tomasz Figa
2019-08-30  8:33             ` Tomasz Figa
2019-08-30  8:33             ` Tomasz Figa
2019-09-02 11:47             ` Jerry-ch Chen
2019-09-02 11:47               ` Jerry-ch Chen
2019-09-02 11:47               ` Jerry-ch Chen
2019-09-03  5:19               ` Tomasz Figa
2019-09-03  5:19                 ` Tomasz Figa
2019-09-03  5:19                 ` Tomasz Figa
2019-09-03  6:44                 ` Jerry-ch Chen
2019-09-03  6:44                   ` Jerry-ch Chen
2019-09-03  6:44                   ` Jerry-ch Chen
2019-09-03  7:04                   ` Tomasz Figa
2019-09-03  7:04                     ` Tomasz Figa
2019-09-03  7:04                     ` Tomasz Figa
     [not found]                     ` <CAAFQd5DWM=R7sFHYGhhR_rXrzgRnc4xtH_t8Pig-4tcP9KTSYg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2019-09-03 11:46                       ` Jerry-ch Chen
2019-09-03 11:46                         ` Jerry-ch Chen
2019-09-03 11:46                         ` Jerry-ch Chen
2019-09-03 12:05                         ` Tomasz Figa
2019-09-03 12:05                           ` Tomasz Figa
2019-09-03 12:05                           ` Tomasz Figa
2019-09-04  3:38                           ` Jerry-ch Chen
2019-09-04  3:38                             ` Jerry-ch Chen
2019-09-04  3:38                             ` Jerry-ch Chen
2019-09-04  4:15                             ` Tomasz Figa
2019-09-04  4:15                               ` Tomasz Figa
2019-09-04  4:15                               ` Tomasz Figa
     [not found]                               ` <CAAFQd5CRC2cyV30B4Qv59HdrJ7Cpe_yK5aY-BecQQ3J3i0PtCQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2019-09-04  6:09                                 ` Jerry-ch Chen
2019-09-04  6:09                                   ` Jerry-ch Chen
2019-09-04  6:09                                   ` Jerry-ch Chen
2019-09-04  6:34                                   ` Tomasz Figa
2019-09-04  6:34                                     ` Tomasz Figa
2019-09-04  6:34                                     ` Tomasz Figa
2019-09-04  8:09                                     ` Jerry-ch Chen
2019-09-04  8:09                                       ` Jerry-ch Chen
2019-09-04  8:09                                       ` Jerry-ch Chen
2019-09-04  8:25                                       ` Tomasz Figa
2019-09-04  8:25                                         ` Tomasz Figa
2019-09-04  8:25                                         ` Tomasz Figa
     [not found]                                         ` <CAAFQd5Dzxy10g-MKHMnNbVO6kp9_L_jm1m+gtN+p=YF2LyBiag-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2019-09-04  9:01                                           ` Jerry-ch Chen
2019-09-04  9:01                                             ` Jerry-ch Chen
2019-09-04  9:01                                             ` Jerry-ch Chen
2019-09-04  9:03                                             ` Tomasz Figa
2019-09-04  9:03                                               ` Tomasz Figa
2019-09-04  9:03                                               ` Tomasz Figa
     [not found]                                               ` <CAAFQd5DWfEEiGthPi=qoxD-mpAWa68GOCi55mqpmagS-tsGYkA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2019-09-04  9:26                                                 ` Jerry-ch Chen
2019-09-04  9:26                                                   ` Jerry-ch Chen
2019-09-04  9:26                                                   ` Jerry-ch Chen
2019-09-04 13:12                                                   ` Tomasz Figa
2019-09-04 13:12                                                     ` Tomasz Figa
2019-09-04 13:12                                                     ` Tomasz Figa
     [not found]                                                     ` <CAAFQd5Ckz9qH7AnLNM4HRTM2gJQP1HXRS09+o6Prf++D1PQhng-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2019-09-04 13:19                                                       ` Jerry-ch Chen
2019-09-04 13:19                                                         ` Jerry-ch Chen
2019-09-04 13:19                                                         ` Jerry-ch Chen
2019-09-05  7:02                                                         ` Jerry-ch Chen
2019-09-05  7:02                                                           ` Jerry-ch Chen
2019-09-05  7:02                                                           ` Jerry-ch Chen
2019-09-05  7:13                                                           ` Tomasz Figa
2019-09-05  7:13                                                             ` Tomasz Figa
2019-09-05  7:13                                                             ` Tomasz Figa
2019-09-05  8:16                                                             ` Jerry-ch Chen
2019-09-05  8:16                                                               ` Jerry-ch Chen
2019-09-05  8:16                                                               ` Jerry-ch Chen
2019-09-05  8:52                                                               ` Tomasz Figa
2019-09-05  8:52                                                                 ` Tomasz Figa
2019-09-05  8:52                                                                 ` Tomasz Figa
2019-09-05 13:36                                                                 ` Jerry-ch Chen
2019-09-05 13:36                                                                   ` Jerry-ch Chen
2019-09-05 13:36                                                                   ` Jerry-ch Chen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1566957625.20680.33.camel@mtksdccf07 \
    --to=jerry-ch.chen@mediatek.com \
    --cc=Rynn.Wu@mediatek.com \
    --cc=Sean.Cheng@mediatek.com \
    --cc=devicetree@vger.kernel.org \
    --cc=jungo.lin@mediatek.com \
    --cc=laurent.pinchart+renesas@ideasonboard.com \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=mchehab@kernel.org \
    --cc=po-yang.huang@mediatek.com \
    --cc=shik@chromium.org \
    --cc=sj.huang@mediatek.com \
    --cc=srv_heupstream@mediatek.com \
    --cc=suleiman@chromium.org \
    --cc=tfiga@chromium.org \
    --cc=yuzhao@chromium.org \
    --cc=zwisler@chromium.or \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.