RE: [PATCH] media: imx-jpeg: Encoder support to set jpeg quality

From: Ming Qian
Date: Thu Apr 14 2022 - 06:04:50 EST


> From: Mirela Rabulea (OSS)
> Sent: Thursday, April 14, 2022 5:42 PM
> To: Ming Qian <ming.qian@xxxxxxx>; mchehab@xxxxxxxxxx;
> shawnguo@xxxxxxxxxx; s.hauer@xxxxxxxxxxxxxx
> Cc: hverkuil-cisco@xxxxxxxxx; kernel@xxxxxxxxxxxxxx; festevam@xxxxxxxxx;
> dl-linux-imx <linux-imx@xxxxxxx>; linux-media@xxxxxxxxxxxxxxx;
> linux-kernel@xxxxxxxxxxxxxxx; devicetree@xxxxxxxxxxxxxxx;
> linux-arm-kernel@xxxxxxxxxxxxxxxxxxx
> Subject: Re: [PATCH] media: imx-jpeg: Encoder support to set jpeg quality
>
> Hi Ming,
>
> On 06.04.2022 12:46, Ming Qian wrote:
> > Implement V4L2_CID_JPEG_COMPRESSION_QUALITY to set jpeg quality
> >
> > Signed-off-by: Ming Qian <ming.qian@xxxxxxx>
> > ---
> > .../media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c | 11 ++--
> > .../media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h | 1 +
> > .../media/platform/nxp/imx-jpeg/mxc-jpeg.c | 50
> +++++++++++++++++++
> > .../media/platform/nxp/imx-jpeg/mxc-jpeg.h | 2 +
> > 4 files changed, 61 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
> > b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
> > index 29c604b1b179..c482228262a3 100644
> > --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
> > +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
> > @@ -100,9 +100,6 @@ void mxc_jpeg_enc_mode_conf(struct device *dev,
> > void __iomem *reg)
> >
> > /* all markers and segments */
> > writel(0x3ff, reg + CAST_CFG_MODE);
> > -
> > - /* quality factor */
> > - writel(0x4b, reg + CAST_QUALITY);
> > }
> >
> > void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg) @@
> > -114,6 +111,14 @@ void mxc_jpeg_enc_mode_go(struct device *dev, void
> __iomem *reg)
> > writel(0x140, reg + CAST_MODE);
> > }
> >
> > +void mxc_jpeg_enc_set_quality(struct device *dev, void __iomem *reg,
> > +u8 quality) {
> > + dev_dbg(dev, "CAST Encoder Quality %d...\n", quality);
> > +
> > + /* quality factor */
> > + writel(quality, reg + CAST_QUALITY); }
> > +
> > void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg)
> > {
> > dev_dbg(dev, "CAST Decoder GO...\n"); diff --git
> > a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
> > b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
> > index ae70d3a0dc24..356e40140987 100644
> > --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
> > +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
> > @@ -119,6 +119,7 @@ int mxc_jpeg_enable(void __iomem *reg);
> > void wait_frmdone(struct device *dev, void __iomem *reg);
> > void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg);
> > void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg);
> > +void mxc_jpeg_enc_set_quality(struct device *dev, void __iomem *reg,
> > +u8 quality);
> > void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg);
> > int mxc_jpeg_get_slot(void __iomem *reg);
> > u32 mxc_jpeg_get_offset(void __iomem *reg, int slot); diff --git
> > a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
> > b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
> > index 0c3a1efbeae7..ccc26372e178 100644
> > --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
> > +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
> > @@ -624,6 +624,7 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void
> *priv)
> > ctx->enc_state == MXC_JPEG_ENC_CONF) {
> > ctx->enc_state = MXC_JPEG_ENCODING;
> > dev_dbg(dev, "Encoder config finished. Start encoding...\n");
> > + mxc_jpeg_enc_set_quality(dev, reg, ctx->jpeg_quality);
>
> I think the setting of the quality should be moved in device_run, to keep the
> interrupt handler lean, I checked it works fine after:
> dev_dbg(dev, "Encoder config finished. Start encoding...\n");
>

Considering the multi-slot situation, the quality register is a global register for all slots.
So to avoid access it in the same time by different slots. It's safe to set after configure done but before encode.
And we only support yet, but I think we will support multi slots after we fix some issues.


> > mxc_jpeg_enc_mode_go(dev, reg);
> > goto job_unlock;
> > }
> > @@ -1563,6 +1564,44 @@ static void mxc_jpeg_set_default_params(struct
> mxc_jpeg_ctx *ctx)
> > }
> > }
> >
> > +static int mxc_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) {
> > + struct mxc_jpeg_ctx *ctx =
> > + container_of(ctrl->handler, struct mxc_jpeg_ctx, ctrl_handler);
> > +
> > + switch (ctrl->id) {
> > + case V4L2_CID_JPEG_COMPRESSION_QUALITY:
>
> Looks like this is allowed for decoder, which is not ok, maybe return -EINVAL
> for decoder.
>

This control is created for encoder only, so decoder has no chance to execute here

> > + ctx->jpeg_quality = ctrl->val;
> > + break;
> > + default:
> > + dev_err(ctx->mxc_jpeg->dev, "Invalid control, id = %d, val = %d\n",
> > + ctrl->id, ctrl->val);
> > + return -EINVAL;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static const struct v4l2_ctrl_ops mxc_jpeg_ctrl_ops = {
> > + .s_ctrl = mxc_jpeg_s_ctrl,
> > +};
> > +
> > +static void mxc_jpeg_encode_ctrls(struct mxc_jpeg_ctx *ctx) {
> > + v4l2_ctrl_new_std(&ctx->ctrl_handler, &mxc_jpeg_ctrl_ops,
> > + V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 75);
>
> The v4l2_ctrl_new_std may return an error, which is not checked here (NULL is
> returned and @hdl->error is set...), please fix.
>

Almost no driver check the return value of v4l2_ctrl_new_std. except some driver want to change some property of the created ctrl.
And if it return NULL, it won't bring some serious problems, just not support this control

> > +}
> > +
> > +static int mxc_jpeg_ctrls_setup(struct mxc_jpeg_ctx *ctx) {
> > + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 2);
>
> ctrl_handler has a lock member, which could be setup here.
>

The lock will be set in v4l2_ctrl_handler_init:
mutex_init(&hdl->_lock);
hdl->lock = &hdl->_lock;

> > +
> > + if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE)
> > + mxc_jpeg_encode_ctrls(ctx);
> > +
> > + return v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
> > +}
> > +
> > static int mxc_jpeg_open(struct file *file)
> > {
> > struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file); @@ -1594,6
> > +1633,12 @@ static int mxc_jpeg_open(struct file *file)
> > goto error;
> > }
> >
> > + ret = mxc_jpeg_ctrls_setup(ctx);
> > + if (ret) {
> > + dev_err(ctx->mxc_jpeg->dev, "failed to setup mxc jpeg controls\n");
> > + goto err_ctrls_setup;
> > + }
> > + ctx->fh.ctrl_handler = &ctx->ctrl_handler;
> > mxc_jpeg_set_default_params(ctx);
> > ctx->slot = MXC_MAX_SLOTS; /* slot not allocated yet */
> >
> > @@ -1605,6 +1650,8 @@ static int mxc_jpeg_open(struct file *file)
> >
> > return 0;
> >
> > +err_ctrls_setup:
> > + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
> > error:
> > v4l2_fh_del(&ctx->fh);
> > v4l2_fh_exit(&ctx->fh);
> > @@ -1962,6 +2009,8 @@ static int mxc_jpeg_subscribe_event(struct
> v4l2_fh *fh,
> > return v4l2_event_subscribe(fh, sub, 0, NULL);
> > case V4L2_EVENT_SOURCE_CHANGE:
> > return v4l2_src_change_event_subscribe(fh, sub);
> > + case V4L2_EVENT_CTRL:
> > + return v4l2_ctrl_subscribe_event(fh, sub);
> > default:
> > return -EINVAL;
> > }
> > @@ -2035,6 +2084,7 @@ static int mxc_jpeg_release(struct file *file)
> > else
> > dev_dbg(dev, "Release JPEG encoder instance on slot %d.",
> > ctx->slot);
> > + v4l2_ctrl_handler_free(&ctx->ctrl_handler);
> > v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
> > v4l2_fh_del(&ctx->fh);
> > v4l2_fh_exit(&ctx->fh);
> > diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
> > b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
> > index 9ae56e6e0fbe..9c9da32b2125 100644
> > --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
> > +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
> > @@ -96,6 +96,8 @@ struct mxc_jpeg_ctx {
> > unsigned int slot;
> > unsigned int source_change;
> > bool header_parsed;
> > + struct v4l2_ctrl_handler ctrl_handler;
> > + u8 jpeg_quality;
> > };
> >
> > struct mxc_jpeg_slot_data {