[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20241021-imx214-v2-9-fbd23e99541e@apitzsch.eu>
Date: Mon, 21 Oct 2024 00:13:29 +0200
From: André Apitzsch via B4 Relay <devnull+git.apitzsch.eu@...nel.org>
To: Ricardo Ribalda <ribalda@...nel.org>,
Mauro Carvalho Chehab <mchehab@...nel.org>,
Sakari Ailus <sakari.ailus@...ux.intel.com>
Cc: ~postmarketos/upstreaming@...ts.sr.ht, phone-devel@...r.kernel.org,
linux-media@...r.kernel.org, linux-kernel@...r.kernel.org,
Dave Stevenson <dave.stevenson@...pberrypi.com>,
André Apitzsch <git@...tzsch.eu>
Subject: [PATCH v2 09/13] media: i2c: imx214: Extract format and crop
settings
From: André Apitzsch <git@...tzsch.eu>
Remove format and crop settings from register sequences and set them
programmatically.
Signed-off-by: André Apitzsch <git@...tzsch.eu>
---
drivers/media/i2c/imx214.c | 129 ++++++++++++++++++++++++++++++++++-----------
1 file changed, 97 insertions(+), 32 deletions(-)
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index cb443d8bee6fe72dc9378b2c2d3caae09f8642c5..87a03e292e19ccd71f1b2dcee3409826b2f5cb6f 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -96,6 +96,9 @@
#define IMX214_REG_PREPLLCK_VT_DIV CCI_REG8(0x0305)
#define IMX214_REG_PLL_VT_MPY CCI_REG16(0x0306)
#define IMX214_REG_OPPXCK_DIV CCI_REG8(0x0309)
+#define IMX214_OPPXCK_DIV_COMP6 6
+#define IMX214_OPPXCK_DIV_COMP8 8
+#define IMX214_OPPXCK_DIV_RAW10 10
#define IMX214_REG_OPSYCK_DIV CCI_REG8(0x030b)
#define IMX214_REG_PLL_MULT_DRIV CCI_REG8(0x0310)
#define IMX214_PLL_SINGLE 0
@@ -132,6 +135,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
@@ -211,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 },
@@ -281,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 },
@@ -623,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 +616,32 @@ static int imx214_set_format(struct v4l2_subdev *sd,
*__format = format->format;
+ /*
+ * Use binning to maximize the crop rectangle size, and centre it in the
+ * sensor.
+ */
+ 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;
@@ -847,7 +849,62 @@ static int imx214_ctrls_init(struct imx214 *imx214)
return 0;
};
-static int imx214_start_streaming(struct imx214 *imx214)
+static int imx214_set_framefmt(struct imx214 *imx214,
+ struct v4l2_subdev_state *state)
+{
+ const struct v4l2_mbus_framefmt *format;
+ const struct v4l2_rect *crop;
+ 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);
+
+ 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,
+ IMX214_CSI_DATA_FORMAT_RAW10, &ret);
+ cci_write(imx214->regmap, IMX214_REG_OPPXCK_DIV, IMX214_OPPXCK_DIV_RAW10, &ret);
+
+ return ret;
+};
+
+static int imx214_start_streaming(struct imx214 *imx214,
+ struct v4l2_subdev_state *state)
{
int ret;
@@ -865,6 +922,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;
+ }
+
ret = cci_multi_reg_write(imx214->regmap, imx214->cur_mode->reg_table,
imx214->cur_mode->num_of_regs, NULL);
if (ret < 0) {
@@ -913,7 +978,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.47.0
Powered by blists - more mailing lists