Re: [PATCH 09/13] media: i2c: imx214: Extract format and crop settings
From: Ricardo Ribalda Delgado
Date: Thu Sep 12 2024 - 09:42:04 EST
On Mon, Sep 2, 2024 at 11:54 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@xxxxxxxxxx> wrote:
>
> From: André Apitzsch <git@xxxxxxxxxxx>
>
> Remove format and crop settings from register sequences and set them
> programmatically.
>
> Signed-off-by: André Apitzsch <git@xxxxxxxxxxx>
> ---
> drivers/media/i2c/imx214.c | 137 ++++++++++++++++++++++++++++++++++-----------
> 1 file changed, 105 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 9f5a57aebb86..733f55257585 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -132,6 +132,9 @@
> #define IMX214_BINNING_NONE 0
> #define IMX214_BINNING_ENABLE 1
> #define IMX214_REG_BINNING_TYPE CCI_REG8(0x0901)
> +#define IMX214_BINNING_1X1 0
> +#define IMX214_BINNING_2X2 0x22
> +#define IMX214_BINNING_4X4 0x44
> #define IMX214_REG_BINNING_WEIGHTING CCI_REG8(0x0902)
> #define IMX214_BINNING_AVERAGE 0x00
> #define IMX214_BINNING_SUMMED 0x01
> @@ -214,36 +217,22 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
> { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> { IMX214_REG_EXPOSURE_RATIO, 1 },
> - { IMX214_REG_X_ADD_STA, 56 },
> - { IMX214_REG_Y_ADD_STA, 408 },
> - { IMX214_REG_X_ADD_END, 4151 },
> - { IMX214_REG_Y_ADD_END, 2711 },
> { IMX214_REG_X_EVEN_INC, 1 },
> { IMX214_REG_X_ODD_INC, 1 },
> { IMX214_REG_Y_EVEN_INC, 1 },
> { IMX214_REG_Y_ODD_INC, 1 },
> - { IMX214_REG_BINNING_MODE, IMX214_BINNING_NONE },
> - { IMX214_REG_BINNING_TYPE, 0 },
> { IMX214_REG_BINNING_WEIGHTING, IMX214_BINNING_AVERAGE },
> { CCI_REG8(0x3000), 0x35 },
> { CCI_REG8(0x3054), 0x01 },
> { CCI_REG8(0x305C), 0x11 },
>
> - { IMX214_REG_CSI_DATA_FORMAT, IMX214_CSI_DATA_FORMAT_RAW10 },
> - { IMX214_REG_X_OUTPUT_SIZE, 4096 },
> - { IMX214_REG_Y_OUTPUT_SIZE, 2304 },
> { IMX214_REG_SCALE_MODE, IMX214_SCALE_NONE },
> { IMX214_REG_SCALE_M, 2 },
> - { IMX214_REG_DIG_CROP_X_OFFSET, 0 },
> - { IMX214_REG_DIG_CROP_Y_OFFSET, 0 },
> - { IMX214_REG_DIG_CROP_WIDTH, 4096 },
> - { IMX214_REG_DIG_CROP_HEIGHT, 2304 },
>
> { IMX214_REG_VTPXCK_DIV, 5 },
> { IMX214_REG_VTSYCK_DIV, 2 },
> { IMX214_REG_PREPLLCK_VT_DIV, 3 },
> { IMX214_REG_PLL_VT_MPY, 150 },
> - { IMX214_REG_OPPXCK_DIV, 10 },
> { IMX214_REG_OPSYCK_DIV, 1 },
> { IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
>
> @@ -284,36 +273,22 @@ static const struct cci_reg_sequence mode_1920x1080[] = {
> { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> { IMX214_REG_EXPOSURE_RATIO, 1 },
> - { IMX214_REG_X_ADD_STA, 1144 },
> - { IMX214_REG_Y_ADD_STA, 1020 },
> - { IMX214_REG_X_ADD_END, 3063 },
> - { IMX214_REG_Y_ADD_END, 2099 },
> { IMX214_REG_X_EVEN_INC, 1 },
> { IMX214_REG_X_ODD_INC, 1 },
> { IMX214_REG_Y_EVEN_INC, 1 },
> { IMX214_REG_Y_ODD_INC, 1 },
> - { IMX214_REG_BINNING_MODE, IMX214_BINNING_NONE },
> - { IMX214_REG_BINNING_TYPE, 0 },
> { IMX214_REG_BINNING_WEIGHTING, IMX214_BINNING_AVERAGE },
> { CCI_REG8(0x3000), 0x35 },
> { CCI_REG8(0x3054), 0x01 },
> { CCI_REG8(0x305C), 0x11 },
>
> - { IMX214_REG_CSI_DATA_FORMAT, IMX214_CSI_DATA_FORMAT_RAW10 },
> - { IMX214_REG_X_OUTPUT_SIZE, 1920 },
> - { IMX214_REG_Y_OUTPUT_SIZE, 1080 },
> { IMX214_REG_SCALE_MODE, IMX214_SCALE_NONE },
> { IMX214_REG_SCALE_M, 2 },
> - { IMX214_REG_DIG_CROP_X_OFFSET, 0 },
> - { IMX214_REG_DIG_CROP_Y_OFFSET, 0 },
> - { IMX214_REG_DIG_CROP_WIDTH, 1920 },
> - { IMX214_REG_DIG_CROP_HEIGHT, 1080 },
>
> { IMX214_REG_VTPXCK_DIV, 5 },
> { IMX214_REG_VTSYCK_DIV, 2 },
> { IMX214_REG_PREPLLCK_VT_DIV, 3 },
> { IMX214_REG_PLL_VT_MPY, 150 },
> - { IMX214_REG_OPPXCK_DIV, 10 },
> { IMX214_REG_OPSYCK_DIV, 1 },
> { IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
>
> @@ -626,6 +601,7 @@ static int imx214_set_format(struct v4l2_subdev *sd,
> struct v4l2_mbus_framefmt *__format;
> struct v4l2_rect *__crop;
> const struct imx214_mode *mode;
> + unsigned int bin_h, bin_v, bin;
>
> mode = v4l2_find_nearest_size(imx214_modes,
> ARRAY_SIZE(imx214_modes), width, height,
> @@ -637,9 +613,32 @@ static int imx214_set_format(struct v4l2_subdev *sd,
> __format = v4l2_subdev_state_get_format(sd_state, 0);
> *__format = format->format;
>
> + /*
> + * Use binning to maximize the crop rectangle size, and centre it in the
> + * sensor.
> + */
We only support two modes. Wouldn't it be easier to add a new
"binning" field to imx124_mode?
> + bin_h = IMX214_PIXEL_ARRAY_WIDTH / __format->width;
> + bin_v = IMX214_PIXEL_ARRAY_HEIGHT / __format->height;
> +
> + switch (min(bin_h, bin_v)) {
> + case 1:
> + bin = 1;
> + break;
> + case 2:
> + case 3:
> + bin = 2;
> + break;
> + case 4:
> + default:
> + bin = 4;
> + break;
> + }
> +
> __crop = v4l2_subdev_state_get_crop(sd_state, 0);
> - __crop->width = mode->width;
> - __crop->height = mode->height;
> + __crop->width = __format->width * bin;
> + __crop->height = __format->height * bin;
> + __crop->left = (IMX214_NATIVE_WIDTH - __crop->width) / 2;
> + __crop->top = (IMX214_NATIVE_HEIGHT - __crop->height) / 2;
>
> if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> int exposure_max;
> @@ -845,6 +844,71 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> return 0;
> };
>
> +static int imx214_set_framefmt(struct imx214 *imx214,
> + struct v4l2_subdev_state *state)
> +{
> + const struct v4l2_mbus_framefmt *format;
> + const struct v4l2_rect *crop;
> + unsigned int bpp;
> + u64 bin_mode;
> + u64 bin_type;
> + int ret = 0;
> +
> + format = v4l2_subdev_state_get_format(state, 0);
> + crop = v4l2_subdev_state_get_crop(state, 0);
> +
This code does not do anything, bpp is always 10.
We can remove the switch and setting IMX214_REG_CSI_DATA_FORMAT
IMX214_REG_OPPXCK_DIV programmatically
> + switch (format->code) {
> + case MEDIA_BUS_FMT_SRGGB10_1X10:
> + case MEDIA_BUS_FMT_SGRBG10_1X10:
> + case MEDIA_BUS_FMT_SGBRG10_1X10:
> + case MEDIA_BUS_FMT_SBGGR10_1X10:
> + default:
> + bpp = 10;
> + break;
> + }
> +
> + cci_write(imx214->regmap, IMX214_REG_X_ADD_STA,
> + crop->left - IMX214_PIXEL_ARRAY_LEFT, &ret);
> + cci_write(imx214->regmap, IMX214_REG_X_ADD_END,
> + crop->left - IMX214_PIXEL_ARRAY_LEFT + crop->width - 1, &ret);
> + cci_write(imx214->regmap, IMX214_REG_Y_ADD_STA,
> + crop->top - IMX214_PIXEL_ARRAY_TOP, &ret);
> + cci_write(imx214->regmap, IMX214_REG_Y_ADD_END,
> + crop->top - IMX214_PIXEL_ARRAY_TOP + crop->height - 1, &ret);
> +
> + /* Proper setting is required even if cropping is not used */
> + cci_write(imx214->regmap, IMX214_REG_DIG_CROP_WIDTH, crop->width, &ret);
> + cci_write(imx214->regmap, IMX214_REG_DIG_CROP_HEIGHT, crop->height, &ret);
> +
> + switch (crop->width / format->width) {
> + case 1:
> + default:
> + bin_mode = IMX214_BINNING_NONE;
> + bin_type = IMX214_BINNING_1X1;
> + break;
> + case 2:
> + bin_mode = IMX214_BINNING_ENABLE;
> + bin_type = IMX214_BINNING_2X2;
> + break;
> + case 4:
> + bin_mode = IMX214_BINNING_ENABLE;
> + bin_type = IMX214_BINNING_4X4;
> + break;
> + }
> +
> + cci_write(imx214->regmap, IMX214_REG_BINNING_MODE, bin_mode, &ret);
> + cci_write(imx214->regmap, IMX214_REG_BINNING_TYPE, bin_type, &ret);
> +
> + cci_write(imx214->regmap, IMX214_REG_X_OUTPUT_SIZE, format->width, &ret);
> + cci_write(imx214->regmap, IMX214_REG_Y_OUTPUT_SIZE, format->height, &ret);
> +
> + cci_write(imx214->regmap, IMX214_REG_CSI_DATA_FORMAT,
> + (bpp << 8) | bpp, &ret);
> + cci_write(imx214->regmap, IMX214_REG_OPPXCK_DIV, bpp, &ret);
> +
> + return ret;
> +};
> +
> static int imx214_configure_lanes(struct imx214 *imx214)
> {
> return cci_write(imx214->regmap, IMX214_REG_CSI_LANE_MODE,
> @@ -852,7 +916,8 @@ static int imx214_configure_lanes(struct imx214 *imx214)
> IMX214_CSI_4_LANE_MODE, NULL);
> };
>
> -static int imx214_start_streaming(struct imx214 *imx214)
> +static int imx214_start_streaming(struct imx214 *imx214,
> + struct v4l2_subdev_state *state)
> {
> const struct imx214_mode *mode;
> int ret;
> @@ -871,6 +936,14 @@ static int imx214_start_streaming(struct imx214 *imx214)
> return ret;
> }
>
> + /* Apply format and crop settings */
> + ret = imx214_set_framefmt(imx214, state);
> + if (ret) {
> + dev_err(imx214->dev, "%s failed to set frame format: %d\n",
> + __func__, ret);
> + return ret;
> + }
> +
> mode = v4l2_find_nearest_size(imx214_modes,
> ARRAY_SIZE(imx214_modes), width, height,
> imx214->fmt.width, imx214->fmt.height);
> @@ -922,7 +995,7 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable)
> return ret;
>
> state = v4l2_subdev_lock_and_get_active_state(subdev);
> - ret = imx214_start_streaming(imx214);
> + ret = imx214_start_streaming(imx214, state);
> v4l2_subdev_unlock_state(state);
> if (ret < 0)
> goto err_rpm_put;
>
> --
> 2.46.0
>
>
>