Skip to content

Commit 552c16b

Browse files
jailuthranaushir
authored andcommitted
media: i2c: imx219: Scale the pixel rate for analog binning
When the analog binning mode is used for high framerate operation, the pixel rate is effectively doubled. Account for this when setting up the pixel clock rate, and applying the vblank and exposure controls. The previous logic only used analog binning for RAW8, but normal binning limits the framerate on RAW10 480p [1]. So with this patch we switch to using special binning (with 2x pixel rate) wherever possible. Backport of commit f513997 upstream. [1]: #5493 Co-developed-by: Naushir Patuck <[email protected]> Signed-off-by: Naushir Patuck <[email protected]> Co-developed-by: Vinay Varma <[email protected]> Signed-off-by: Vinay Varma <[email protected]> Signed-off-by: Jai Luthra <[email protected]> Signed-off-by: Sakari Ailus <[email protected]> Signed-off-by: Hans Verkuil <[email protected]>
1 parent 8bab73c commit 552c16b

File tree

1 file changed

+81
-45
lines changed

1 file changed

+81
-45
lines changed

drivers/media/i2c/imx219.c

Lines changed: 81 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@
148148
#define IMX219_PIXEL_ARRAY_WIDTH 3280U
149149
#define IMX219_PIXEL_ARRAY_HEIGHT 2464U
150150

151+
enum binning_mode {
152+
BINNING_NONE = IMX219_BINNING_NONE,
153+
BINNING_X2 = IMX219_BINNING_X2,
154+
BINNING_ANALOG_X2 = IMX219_BINNING_X2_ANALOG,
155+
};
156+
151157
/* Mode : resolution and related config&values */
152158
struct imx219_mode {
153159
/* Frame width */
@@ -324,13 +330,13 @@ static const struct imx219_mode supported_modes[] = {
324330
.vts_def = 1763,
325331
},
326332
{
327-
/* 2x2 binned 30fps mode */
333+
/* 2x2 binned 60fps mode */
328334
.width = 1640,
329335
.height = 1232,
330336
.vts_def = 1763,
331337
},
332338
{
333-
/* 640x480 30fps mode */
339+
/* 640x480 60fps mode */
334340
.width = 640,
335341
.height = 480,
336342
.vts_def = 1763,
@@ -385,6 +391,59 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
385391
return imx219_mbus_formats[i];
386392
}
387393

394+
static u32 imx219_get_format_bpp(const struct v4l2_mbus_framefmt *format)
395+
{
396+
switch (format->code) {
397+
case MEDIA_BUS_FMT_SRGGB8_1X8:
398+
case MEDIA_BUS_FMT_SGRBG8_1X8:
399+
case MEDIA_BUS_FMT_SGBRG8_1X8:
400+
case MEDIA_BUS_FMT_SBGGR8_1X8:
401+
return 8;
402+
403+
case MEDIA_BUS_FMT_SRGGB10_1X10:
404+
case MEDIA_BUS_FMT_SGRBG10_1X10:
405+
case MEDIA_BUS_FMT_SGBRG10_1X10:
406+
case MEDIA_BUS_FMT_SBGGR10_1X10:
407+
default:
408+
return 10;
409+
}
410+
}
411+
412+
static enum binning_mode imx219_get_binning(struct imx219 *imx219, u8 *bin_h,
413+
u8 *bin_v)
414+
{
415+
struct v4l2_subdev_state *state =
416+
v4l2_subdev_get_locked_active_state(&imx219->sd);
417+
const struct v4l2_mbus_framefmt *format =
418+
v4l2_subdev_state_get_format(state, 0);
419+
const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0);
420+
421+
*bin_h = crop->width / format->width;
422+
*bin_v = crop->height / format->height;
423+
424+
if (*bin_h == 2 && *bin_v == 2)
425+
return BINNING_ANALOG_X2;
426+
else if (*bin_h == 2 || *bin_v == 2)
427+
/*
428+
* Don't use analog binning if only one dimension
429+
* is binned, as it crops the other dimension
430+
*/
431+
return BINNING_X2;
432+
else
433+
return BINNING_NONE;
434+
}
435+
436+
static inline u32 imx219_get_rate_factor(struct imx219 *imx219)
437+
{
438+
u8 bin_h, bin_v;
439+
enum binning_mode binning = imx219_get_binning(imx219, &bin_h, &bin_v);
440+
441+
if (binning == BINNING_ANALOG_X2)
442+
return 2;
443+
444+
return 1;
445+
}
446+
388447
/* -----------------------------------------------------------------------------
389448
* Controls
390449
*/
@@ -396,10 +455,12 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
396455
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
397456
const struct v4l2_mbus_framefmt *format;
398457
struct v4l2_subdev_state *state;
458+
u32 rate_factor;
399459
int ret = 0;
400460

401461
state = v4l2_subdev_get_locked_active_state(&imx219->sd);
402462
format = v4l2_subdev_state_get_format(state, 0);
463+
rate_factor = imx219_get_rate_factor(imx219);
403464

404465
if (ctrl->id == V4L2_CID_VBLANK) {
405466
int exposure_max, exposure_def;
@@ -428,7 +489,7 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
428489
break;
429490
case V4L2_CID_EXPOSURE:
430491
cci_write(imx219->regmap, IMX219_REG_EXPOSURE,
431-
ctrl->val, &ret);
492+
ctrl->val / rate_factor, &ret);
432493
break;
433494
case V4L2_CID_DIGITAL_GAIN:
434495
cci_write(imx219->regmap, IMX219_REG_DIGITAL_GAIN,
@@ -445,7 +506,7 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
445506
break;
446507
case V4L2_CID_VBLANK:
447508
cci_write(imx219->regmap, IMX219_REG_VTS,
448-
format->height + ctrl->val, &ret);
509+
(format->height + ctrl->val) / rate_factor, &ret);
449510
break;
450511
case V4L2_CID_TEST_PATTERN_RED:
451512
cci_write(imx219->regmap, IMX219_REG_TESTP_RED,
@@ -613,29 +674,14 @@ static int imx219_set_framefmt(struct imx219 *imx219,
613674
{
614675
const struct v4l2_mbus_framefmt *format;
615676
const struct v4l2_rect *crop;
616-
unsigned int bpp;
617-
u64 bin_h, bin_v;
677+
enum binning_mode binning;
678+
u8 bin_h, bin_v;
679+
u32 bpp;
618680
int ret = 0;
619681

620682
format = v4l2_subdev_state_get_format(state, 0);
621683
crop = v4l2_subdev_state_get_crop(state, 0);
622-
623-
switch (format->code) {
624-
case MEDIA_BUS_FMT_SRGGB8_1X8:
625-
case MEDIA_BUS_FMT_SGRBG8_1X8:
626-
case MEDIA_BUS_FMT_SGBRG8_1X8:
627-
case MEDIA_BUS_FMT_SBGGR8_1X8:
628-
bpp = 8;
629-
break;
630-
631-
case MEDIA_BUS_FMT_SRGGB10_1X10:
632-
case MEDIA_BUS_FMT_SGRBG10_1X10:
633-
case MEDIA_BUS_FMT_SGBRG10_1X10:
634-
case MEDIA_BUS_FMT_SBGGR10_1X10:
635-
default:
636-
bpp = 10;
637-
break;
638-
}
684+
bpp = imx219_get_format_bpp(format);
639685

640686
cci_write(imx219->regmap, IMX219_REG_X_ADD_STA_A,
641687
crop->left - IMX219_PIXEL_ARRAY_LEFT, &ret);
@@ -646,28 +692,11 @@ static int imx219_set_framefmt(struct imx219 *imx219,
646692
cci_write(imx219->regmap, IMX219_REG_Y_ADD_END_A,
647693
crop->top - IMX219_PIXEL_ARRAY_TOP + crop->height - 1, &ret);
648694

649-
switch (crop->width / format->width) {
650-
case 1:
651-
default:
652-
bin_h = IMX219_BINNING_NONE;
653-
break;
654-
case 2:
655-
bin_h = bpp == 8 ? IMX219_BINNING_X2_ANALOG : IMX219_BINNING_X2;
656-
break;
657-
}
658-
659-
switch (crop->height / format->height) {
660-
case 1:
661-
default:
662-
bin_v = IMX219_BINNING_NONE;
663-
break;
664-
case 2:
665-
bin_v = bpp == 8 ? IMX219_BINNING_X2_ANALOG : IMX219_BINNING_X2;
666-
break;
667-
}
668-
669-
cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_H, bin_h, &ret);
670-
cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_V, bin_v, &ret);
695+
binning = imx219_get_binning(imx219, &bin_h, &bin_v);
696+
cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_H,
697+
(bin_h == 2) ? binning : BINNING_NONE, &ret);
698+
cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_V,
699+
(bin_v == 2) ? binning : BINNING_NONE, &ret);
671700

672701
cci_write(imx219->regmap, IMX219_REG_X_OUTPUT_SIZE,
673702
format->width, &ret);
@@ -873,6 +902,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
873902
int exposure_max;
874903
int exposure_def;
875904
int hblank;
905+
int pixel_rate;
876906

877907
/* Update limits and set FPS to default */
878908
__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
@@ -896,6 +926,12 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
896926
hblank = IMX219_PPL_DEFAULT - mode->width;
897927
__v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1,
898928
hblank);
929+
930+
/* Scale the pixel rate based on the mode specific factor */
931+
pixel_rate = imx219_get_pixel_rate(imx219) *
932+
imx219_get_rate_factor(imx219);
933+
__v4l2_ctrl_modify_range(imx219->pixel_rate, pixel_rate,
934+
pixel_rate, 1, pixel_rate);
899935
}
900936

901937
return 0;

0 commit comments

Comments
 (0)