mbox series

[v5,0/5] media: i2c: imx219: Fixes for blanking, pixel rate and binning

Message ID 20241230-imx219_fixes-v5-0-98446d816489@ideasonboard.com
Headers show
Series media: i2c: imx219: Fixes for blanking, pixel rate and binning | expand

Message

Jai Luthra Dec. 30, 2024, 6:11 a.m. UTC
This series has a few fixes for improving h/v blanking, pixel rate
reporting and binning modes for the IMX219 sensor.

These patches are picked and modified (and squashed where applicable)
from the rpi-6.6.y vendor tree.

On top of those changes, this series also updates the minimum line
length to fix some issues seen when using analog binning with RAW10
format on higher resolutions (like 1640x1232).

Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>
---
Changes in v5:
- PATCH 2/5: Rename .vts_def to .fll_def
- PATCH 4/5: Don't change PLL multipliers, only update the minimum LLP
  size
- PATCH 5/5: Update binned mode comments: s/30fps/60fps
- Link to v4: https://lore.kernel.org/r/20241226-imx219_fixes-v4-0-dd28383f06f7@ideasonboard.com

Changes in v4:
- Add PATCH 2/5 to rename VTS to FRM_LENGTH
- PATCH 3/5:
    - Match macro names to datasheet (LINE_LENGTH instead of HTS/PPL)
    - Improve comments in init_controls()
    - Use prev_line_len instead of prev_hts
- Add PATCH 4/5 to update PLL settings that fix artefacts seen when
  using analog binning with RAW10 mode
- PATCH 5/5:
    - Use special "analog" binning for all resolutions and bitdepths,
      simplifying the binning logic
    - Don't store bin_h/bin_v in imx219 state, instead compute it
      everytime it is needed using the crop and format.
- Link to v3: https://lore.kernel.org/r/20241125-imx219_fixes-v3-0-434fc0b541c8@ideasonboard.com

Changes in v3:
- PATCH 3/3: Calculate binning mode to use instead of hardcoding
  per-resolution
- Link to v2: https://lore.kernel.org/r/20241121-imx219_fixes-v2-0-7b068a60ea40@ideasonboard.com

Changes in v2:
- PATCH 1/3: Add R-By from Jacopo, Dave
- PATCH 2/3:
    - Keep IMX219_PPL_MIN macro value in hex, matching the datasheet
    - Fix prev_hts calculation, by moving it before updating pad format
- PATCH 3/3:
    - Store binning register values in enum binning_mode directly
    - Remove unnecessary pixel_rate variable in imx219_init_controls()
- Link to v1: https://lore.kernel.org/r/20241029-imx219_fixes-v1-0-b45dc3658b4e@ideasonboard.com

---
Dave Stevenson (1):
      media: i2c: imx219: make HBLANK r/w to allow longer exposures

David Plowman (1):
      media: i2c: imx219: Correct the minimum vblanking value

Jai Luthra (3):
      media: i2c: imx219: Rename VTS to FRM_LENGTH
      media: i2c: imx219: Increase minimum LLP to fix blocky artefacts
      media: i2c: imx219: Scale the pixel rate for analog binning

 drivers/media/i2c/imx219.c | 208 +++++++++++++++++++++++++++------------------
 1 file changed, 126 insertions(+), 82 deletions(-)
---
base-commit: 40384c840ea1944d7c5a392e8975ed088ecf0b37
change-id: 20241029-imx219_fixes-bfaac4a56200

Best regards,

Comments

Dave Stevenson Jan. 2, 2025, 4:48 p.m. UTC | #1
Hi Jai

On Mon, 30 Dec 2024 at 06:12, Jai Luthra <jai.luthra@ideasonboard.com> wrote:
>
> From: Dave Stevenson <dave.stevenson@raspberrypi.com>
>
> The HBLANK control was read-only, and always configured such that the
> sensor line length register was 3448. This limited the maximum exposure
> time that could be achieved to around 1.26 secs.
>
> Make HBLANK read/write so that the line time can be extended, and
> thereby allow longer exposures (and slower frame rates). Retain the
> overall line length setting when changing modes rather than resetting it
> to a default.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>
> ---
>  drivers/media/i2c/imx219.c | 49 +++++++++++++++++++++++++++-------------------
>  1 file changed, 29 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
> index 8565b1b030be2ee24bcc37415e99ee4ef83cc683..9682a74feb3b7b74cd2ca54779323396c77cd5a5 100644
> --- a/drivers/media/i2c/imx219.c
> +++ b/drivers/media/i2c/imx219.c
> @@ -73,11 +73,10 @@
>  #define IMX219_REG_FRM_LENGTH          CCI_REG16(0x0160)
>  #define IMX219_FLL_MAX                 0xffff
>  #define IMX219_VBLANK_MIN              32
> +#define IMX219_REG_LINE_LENGTH         CCI_REG16(0x0162)

The datasheet calls the register LINE_LENGTH_A as it has an A and B
back of settings for quick switching between the two. Whilst we don't
use the quick mode switching, IMHO using the correct name is sensible.

Same is true for 0x0160 being FRM_LENGTH_A, not just FRM_LENGTH
(should be part of 2/5 if adopted).

> +#define IMX219_LLP_MIN                 0x0d78
> +#define IMX219_LLP_MAX                 0x7ff0
>
> -/* HBLANK control - read only */
> -#define IMX219_PPL_DEFAULT             3448
> -
> -#define IMX219_REG_LINE_LENGTH_A       CCI_REG16(0x0162)
>  #define IMX219_REG_X_ADD_STA_A         CCI_REG16(0x0164)
>  #define IMX219_REG_X_ADD_END_A         CCI_REG16(0x0166)
>  #define IMX219_REG_Y_ADD_STA_A         CCI_REG16(0x0168)
> @@ -191,7 +190,7 @@ static const struct cci_reg_sequence imx219_common_regs[] = {
>         { CCI_REG8(0x479b), 0x0e },
>
>         /* Frame Bank Register Group "A" */
> -       { IMX219_REG_LINE_LENGTH_A, 3448 },
> +       { IMX219_REG_LINE_LENGTH, IMX219_LLP_MIN },

LINE_LENGTH is also set from imx219_set_ctrl for V4L2_CID_HBLANK, so
this line is redundant and should be removed.
(I'm aware that I missed removing it in the downstream version of this
patch - it's only your rename that highlighted it).

Otherwise this looks good to me.

  Dave

>         { IMX219_REG_X_ODD_INC_A, 1 },
>         { IMX219_REG_Y_ODD_INC_A, 1 },
>
> @@ -420,6 +419,10 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
>                 cci_write(imx219->regmap, IMX219_REG_FRM_LENGTH,
>                           format->height + ctrl->val, &ret);
>                 break;
> +       case V4L2_CID_HBLANK:
> +               cci_write(imx219->regmap, IMX219_REG_LINE_LENGTH,
> +                         format->width + ctrl->val, &ret);
> +               break;
>         case V4L2_CID_TEST_PATTERN_RED:
>                 cci_write(imx219->regmap, IMX219_REG_TESTP_RED,
>                           ctrl->val, &ret);
> @@ -465,7 +468,7 @@ static int imx219_init_controls(struct imx219 *imx219)
>         const struct imx219_mode *mode = &supported_modes[0];
>         struct v4l2_ctrl_handler *ctrl_hdlr;
>         struct v4l2_fwnode_device_properties props;
> -       int exposure_max, exposure_def, hblank;
> +       int exposure_max, exposure_def;
>         int i, ret;
>
>         ctrl_hdlr = &imx219->ctrl_handler;
> @@ -489,17 +492,16 @@ static int imx219_init_controls(struct imx219 *imx219)
>         if (imx219->link_freq)
>                 imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>
> -       /* Initial vblank/hblank/exposure parameters based on current mode */
> +       /* Initial blanking and exposure. Limits are updated during set_fmt */
>         imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
>                                            V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
>                                            IMX219_FLL_MAX - mode->height, 1,
>                                            mode->fll_def - mode->height);
> -       hblank = IMX219_PPL_DEFAULT - mode->width;
>         imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
> -                                          V4L2_CID_HBLANK, hblank, hblank,
> -                                          1, hblank);
> -       if (imx219->hblank)
> -               imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +                                          V4L2_CID_HBLANK,
> +                                          IMX219_LLP_MIN - mode->width,
> +                                          IMX219_LLP_MAX - mode->width, 1,
> +                                          IMX219_LLP_MIN - mode->width);
>         exposure_max = mode->fll_def - 4;
>         exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
>                 exposure_max : IMX219_EXPOSURE_DEFAULT;
> @@ -815,6 +817,10 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
>         struct v4l2_mbus_framefmt *format;
>         struct v4l2_rect *crop;
>         unsigned int bin_h, bin_v;
> +       u32 prev_line_len;
> +
> +       format = v4l2_subdev_state_get_format(state, 0);
> +       prev_line_len = format->width + imx219->hblank->val;
>
>         mode = v4l2_find_nearest_size(supported_modes,
>                                       ARRAY_SIZE(supported_modes),
> @@ -822,8 +828,6 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
>                                       fmt->format.width, fmt->format.height);
>
>         imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code);
> -
> -       format = v4l2_subdev_state_get_format(state, 0);
>         *format = fmt->format;
>
>         /*
> @@ -859,13 +863,18 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
>                                          exposure_max, imx219->exposure->step,
>                                          exposure_def);
>                 /*
> -                * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
> -                * depends on mode->width only, and is not changeble in any
> -                * way other than changing the mode.
> +                * Retain PPL setting from previous mode so that the
> +                * line time does not change on a mode change.
> +                * Limits have to be recomputed as the controls define
> +                * the blanking only, so PPL values need to have the
> +                * mode width subtracted.
>                  */
> -               hblank = IMX219_PPL_DEFAULT - mode->width;
> -               __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1,
> -                                        hblank);
> +               hblank = prev_line_len - mode->width;
> +               __v4l2_ctrl_modify_range(imx219->hblank,
> +                                        IMX219_LLP_MIN - mode->width,
> +                                        IMX219_LLP_MAX - mode->width, 1,
> +                                        IMX219_LLP_MIN - mode->width);
> +               __v4l2_ctrl_s_ctrl(imx219->hblank, hblank);
>         }
>
>         return 0;
>
> --
> 2.47.1
>