Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

media: imx335: Support 2x2 binning

Introduce 2x2 binning mode (1312x972@60fps). Since there are multiple
modes now, use v4l2_find_nearest_size() to select the appropriate mode
in .set_fmt().

For 2x2 binning the minimum shutter value supported is 17 instead of 9.
This effects the maximum allowed exposure time, and if not enforced then
the sensor produces very dark frames when the minimum shutter limit is
violated.

Lastly, update the crop size reported to the userspace. When trying 2x2
binning with the datasheet suggested pixel array size (i.e. 2592 / 2 =>
1296), on some platforms (Raspberry Pi 5) artefacts are introduced on
the right edge of the output image. Instead, using a higher width of
1312 works fine on all platforms.

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>

authored by

Jai Luthra and committed by
Hans Verkuil
8a2451bd df3ef05b

+216 -57
+216 -57
drivers/media/i2c/imx335.c
··· 35 35 36 36 /* Lines per frame */ 37 37 #define IMX335_REG_VMAX CCI_REG24_LE(0x3030) 38 + #define IMX335_REG_HMAX CCI_REG16_LE(0x3034) 38 39 39 40 #define IMX335_REG_OPB_SIZE_V CCI_REG8(0x304c) 40 41 #define IMX335_REG_ADBIT CCI_REG8(0x3050) ··· 43 42 44 43 #define IMX335_REG_SHUTTER CCI_REG24_LE(0x3058) 45 44 #define IMX335_EXPOSURE_MIN 1 46 - #define IMX335_EXPOSURE_OFFSET 9 45 + #define IMX335_SHUTTER_MIN 9 46 + #define IMX335_SHUTTER_MIN_BINNED 17 47 47 #define IMX335_EXPOSURE_STEP 1 48 48 #define IMX335_EXPOSURE_DEFAULT 0x0648 49 + 50 + #define IMX335_REG_AREA2_WIDTH_1 CCI_REG16_LE(0x3072) 49 51 50 52 #define IMX335_REG_AREA3_ST_ADR_1 CCI_REG16_LE(0x3074) 51 53 #define IMX335_REG_AREA3_WIDTH_1 CCI_REG16_LE(0x3076) ··· 137 133 138 134 static const struct v4l2_rect imx335_active_area = { 139 135 .top = 50, 140 - .left = 52, 141 - .width = 2592, 136 + .left = 36, 137 + .width = 2624, 142 138 .height = 1944, 143 139 }; 144 - 145 140 146 141 /** 147 142 * struct imx335_reg_list - imx335 sensor register list ··· 158 155 "dvdd", /* Digital Core (1.2V) supply */ 159 156 }; 160 157 158 + enum imx335_scan_mode { 159 + IMX335_ALL_PIXEL, 160 + IMX335_2_2_BINNING, 161 + }; 162 + 161 163 /** 162 164 * struct imx335_mode - imx335 sensor mode structure 165 + * @scan_mode: Configuration scan mode (All pixel / 2x2Binning) 163 166 * @width: Frame width 164 167 * @height: Frame height 165 168 * @code: Format code ··· 179 170 * @vflip_inverted: Register list vflip (inverted readout) 180 171 */ 181 172 struct imx335_mode { 173 + enum imx335_scan_mode scan_mode; 182 174 u32 width; 183 175 u32 height; 184 176 u32 code; ··· 281 271 { IMX335_REG_MODE_SELECT, IMX335_MODE_STANDBY }, 282 272 { IMX335_REG_MASTER_MODE, 0x00 }, 283 273 { IMX335_REG_WINMODE, 0x04 }, 274 + { IMX335_REG_HMAX, 550 }, 284 275 { IMX335_REG_HTRIMMING_START, 48 }, 285 276 { IMX335_REG_HNUM, 2592 }, 286 277 { IMX335_REG_Y_OUT_SIZE, 1944 }, 278 + { IMX335_REG_AREA2_WIDTH_1, 40 }, 287 279 { IMX335_REG_AREA3_WIDTH_1, 3928 }, 288 280 { IMX335_REG_OPB_SIZE_V, 0 }, 289 281 { IMX335_REG_XVS_XHS_DRV, 0x00 }, 282 + }; 283 + 284 + static const struct cci_reg_sequence mode_1312x972_regs[] = { 285 + { IMX335_REG_MODE_SELECT, IMX335_MODE_STANDBY }, 286 + { IMX335_REG_MASTER_MODE, 0x00 }, 287 + { IMX335_REG_WINMODE, 0x01 }, 288 + { IMX335_REG_HMAX, 275 }, 289 + { IMX335_REG_HTRIMMING_START, 48 }, 290 + { IMX335_REG_HNUM, 2600 }, 291 + { IMX335_REG_Y_OUT_SIZE, 972 }, 292 + { IMX335_REG_AREA2_WIDTH_1, 48 }, 293 + { IMX335_REG_AREA3_WIDTH_1, 3936 }, 294 + { IMX335_REG_OPB_SIZE_V, 0 }, 295 + { IMX335_REG_XVS_XHS_DRV, 0x00 }, 296 + { CCI_REG8(0x3300), 1 }, /* TCYCLE */ 297 + { CCI_REG8(0x3199), 0x30 }, /* HADD/VADD */ 298 + }; 299 + 300 + static const struct cci_reg_sequence imx335_common_regs[] = { 290 301 { CCI_REG8(0x3288), 0x21 }, 291 302 { CCI_REG8(0x328a), 0x02 }, 292 303 { CCI_REG8(0x3414), 0x05 }, ··· 398 367 { CCI_REG16_LE(0x3116), 0x002 }, 399 368 }; 400 369 401 - static const struct cci_reg_sequence raw10_framefmt_regs[] = { 402 - { IMX335_REG_ADBIT, 0x00 }, 403 - { IMX335_REG_MDBIT, 0x00 }, 404 - { IMX335_REG_ADBIT1, 0x1ff }, 370 + static const struct cci_reg_sequence mode_1312x972_vflip_normal[] = { 371 + { IMX335_REG_AREA3_ST_ADR_1, 176 }, 372 + 373 + /* Undocumented */ 374 + { CCI_REG8(0x3078), 0x04 }, 375 + { CCI_REG8(0x3079), 0xfd }, 376 + { CCI_REG8(0x307a), 0x04 }, 377 + { CCI_REG8(0x307b), 0xfe }, 378 + { CCI_REG8(0x307c), 0x04 }, 379 + { CCI_REG8(0x307d), 0xfb }, 380 + { CCI_REG8(0x307e), 0x04 }, 381 + { CCI_REG8(0x307f), 0x02 }, 382 + { CCI_REG8(0x3080), 0x04 }, 383 + { CCI_REG8(0x3081), 0xfd }, 384 + { CCI_REG8(0x3082), 0x04 }, 385 + { CCI_REG8(0x3083), 0xfe }, 386 + { CCI_REG8(0x3084), 0x04 }, 387 + { CCI_REG8(0x3085), 0xfb }, 388 + { CCI_REG8(0x3086), 0x04 }, 389 + { CCI_REG8(0x3087), 0x02 }, 390 + { CCI_REG8(0x30a4), 0x77 }, 391 + { CCI_REG8(0x30a8), 0x20 }, 392 + { CCI_REG8(0x30a9), 0x00 }, 393 + { CCI_REG8(0x30ac), 0x08 }, 394 + { CCI_REG8(0x30ad), 0x08 }, 395 + { CCI_REG8(0x30b0), 0x20 }, 396 + { CCI_REG8(0x30b1), 0x00 }, 397 + { CCI_REG8(0x30b4), 0x10 }, 398 + { CCI_REG8(0x30b5), 0x10 }, 399 + { CCI_REG16_LE(0x30b6), 0x00 }, 400 + { CCI_REG16_LE(0x3112), 0x10 }, 401 + { CCI_REG16_LE(0x3116), 0x10 }, 405 402 }; 406 403 407 - static const struct cci_reg_sequence raw12_framefmt_regs[] = { 408 - { IMX335_REG_ADBIT, 0x01 }, 409 - { IMX335_REG_MDBIT, 0x01 }, 410 - { IMX335_REG_ADBIT1, 0x47 }, 404 + static const struct cci_reg_sequence mode_1312x972_vflip_inverted[] = { 405 + { IMX335_REG_AREA3_ST_ADR_1, 4112 }, 406 + 407 + /* Undocumented */ 408 + { CCI_REG8(0x3078), 0x04 }, 409 + { CCI_REG8(0x3079), 0xfd }, 410 + { CCI_REG8(0x307a), 0x04 }, 411 + { CCI_REG8(0x307b), 0xfe }, 412 + { CCI_REG8(0x307c), 0x04 }, 413 + { CCI_REG8(0x307d), 0xfb }, 414 + { CCI_REG8(0x307e), 0x04 }, 415 + { CCI_REG8(0x307f), 0x02 }, 416 + { CCI_REG8(0x3080), 0xfc }, 417 + { CCI_REG8(0x3081), 0x05 }, 418 + { CCI_REG8(0x3082), 0xfc }, 419 + { CCI_REG8(0x3083), 0x02 }, 420 + { CCI_REG8(0x3084), 0xfc }, 421 + { CCI_REG8(0x3085), 0x03 }, 422 + { CCI_REG8(0x3086), 0xfc }, 423 + { CCI_REG8(0x3087), 0xfe }, 424 + { CCI_REG8(0x30a4), 0x77 }, 425 + { CCI_REG8(0x30a8), 0x20 }, 426 + { CCI_REG8(0x30a9), 0x00 }, 427 + { CCI_REG8(0x30ac), 0x08 }, 428 + { CCI_REG8(0x30ad), 0x78 }, 429 + { CCI_REG8(0x30b0), 0x20 }, 430 + { CCI_REG8(0x30b1), 0x00 }, 431 + { CCI_REG8(0x30b4), 0x10 }, 432 + { CCI_REG8(0x30b5), 0x70 }, 433 + { CCI_REG16_LE(0x30b6), 0x01f2 }, 434 + { CCI_REG16_LE(0x3112), 0x10 }, 435 + { CCI_REG16_LE(0x3116), 0x02 }, 411 436 }; 412 437 413 438 static const struct cci_reg_sequence mipi_data_rate_1188Mbps[] = { ··· 528 441 }; 529 442 530 443 /* Supported sensor mode configurations */ 531 - static const struct imx335_mode supported_mode = { 532 - .width = 2592, 533 - .height = 1944, 534 - .hblank = 342, 535 - .vblank = 2556, 536 - .vblank_min = 2556, 537 - .vblank_max = 133060, 538 - .pclk = 396000000, 539 - .reg_list = { 540 - .num_of_regs = ARRAY_SIZE(mode_2592x1944_regs), 541 - .regs = mode_2592x1944_regs, 542 - }, 543 - .vflip_normal = { 544 - .num_of_regs = ARRAY_SIZE(mode_2592x1944_vflip_normal), 545 - .regs = mode_2592x1944_vflip_normal, 546 - }, 547 - .vflip_inverted = { 548 - .num_of_regs = ARRAY_SIZE(mode_2592x1944_vflip_inverted), 549 - .regs = mode_2592x1944_vflip_inverted, 444 + static const struct imx335_mode supported_modes[] = { 445 + { 446 + .scan_mode = IMX335_ALL_PIXEL, 447 + .width = 2592, 448 + .height = 1944, 449 + .hblank = 342, 450 + .vblank = 2556, 451 + .vblank_min = 2556, 452 + .vblank_max = 133060, 453 + .pclk = 396000000, 454 + .reg_list = { 455 + .num_of_regs = ARRAY_SIZE(mode_2592x1944_regs), 456 + .regs = mode_2592x1944_regs, 457 + }, 458 + .vflip_normal = { 459 + .num_of_regs = ARRAY_SIZE(mode_2592x1944_vflip_normal), 460 + .regs = mode_2592x1944_vflip_normal, 461 + }, 462 + .vflip_inverted = { 463 + .num_of_regs = ARRAY_SIZE(mode_2592x1944_vflip_inverted), 464 + .regs = mode_2592x1944_vflip_inverted, 465 + } 466 + }, { 467 + .scan_mode = IMX335_2_2_BINNING, 468 + .width = 1312, 469 + .height = 972, 470 + .hblank = 155, 471 + .vblank = 3528, 472 + .vblank_min = 3528, 473 + .vblank_max = 133060, 474 + .pclk = 396000000, 475 + .reg_list = { 476 + .num_of_regs = ARRAY_SIZE(mode_1312x972_regs), 477 + .regs = mode_1312x972_regs, 478 + }, 479 + .vflip_normal = { 480 + .num_of_regs = ARRAY_SIZE(mode_1312x972_vflip_normal), 481 + .regs = mode_1312x972_vflip_normal, 482 + }, 483 + .vflip_inverted = { 484 + .num_of_regs = ARRAY_SIZE(mode_1312x972_vflip_inverted), 485 + .regs = mode_1312x972_vflip_inverted, 486 + }, 550 487 }, 551 488 }; 552 489 ··· 720 609 721 610 /* Propagate change of current control to all related controls */ 722 611 if (ctrl->id == V4L2_CID_VBLANK) { 612 + u32 shutter_min = IMX335_SHUTTER_MIN; 613 + u32 lpfr; 614 + 723 615 imx335->vblank = imx335->vblank_ctrl->val; 616 + lpfr = imx335->vblank + imx335->cur_mode->height; 724 617 725 618 dev_dbg(imx335->dev, "Received vblank %u, new lpfr %u\n", 726 - imx335->vblank, 727 - imx335->vblank + imx335->cur_mode->height); 619 + imx335->vblank, lpfr); 620 + 621 + if (imx335->cur_mode->scan_mode == IMX335_2_2_BINNING) 622 + shutter_min = IMX335_SHUTTER_MIN_BINNED; 728 623 729 624 ret = __v4l2_ctrl_modify_range(imx335->exp_ctrl, 730 625 IMX335_EXPOSURE_MIN, 731 - imx335->vblank + 732 - imx335->cur_mode->height - 733 - IMX335_EXPOSURE_OFFSET, 734 - 1, IMX335_EXPOSURE_DEFAULT); 626 + lpfr - shutter_min, 1, 627 + IMX335_EXPOSURE_DEFAULT); 735 628 if (ret) 736 629 return ret; 737 630 } ··· 835 720 struct imx335 *imx335 = to_imx335(sd); 836 721 u32 code; 837 722 838 - /* Only a single supported_mode available. */ 839 - if (fsize->index > 0) 723 + if (fsize->index >= ARRAY_SIZE(supported_modes)) 840 724 return -EINVAL; 841 725 842 726 code = imx335_get_format_code(imx335, fsize->code); 843 727 if (fsize->code != code) 844 728 return -EINVAL; 845 729 846 - fsize->min_width = supported_mode.width; 730 + fsize->min_width = supported_modes[fsize->index].width; 847 731 fsize->max_width = fsize->min_width; 848 - fsize->min_height = supported_mode.height; 732 + fsize->min_height = supported_modes[fsize->index].height; 849 733 fsize->max_height = fsize->min_height; 850 734 851 735 return 0; ··· 886 772 struct imx335 *imx335 = to_imx335(sd); 887 773 struct v4l2_mbus_framefmt *format; 888 774 const struct imx335_mode *mode; 775 + struct v4l2_rect *crop; 889 776 int i, ret = 0; 890 777 891 - mode = &supported_mode; 778 + mode = v4l2_find_nearest_size(supported_modes, 779 + ARRAY_SIZE(supported_modes), 780 + width, height, 781 + fmt->format.width, fmt->format.height); 892 782 893 783 for (i = 0; i < ARRAY_SIZE(imx335_mbus_codes); i++) { 894 784 if (imx335_mbus_codes[i] == fmt->format.code) ··· 903 785 904 786 format = v4l2_subdev_state_get_format(sd_state, fmt->pad); 905 787 *format = fmt->format; 788 + 789 + crop = v4l2_subdev_state_get_crop(sd_state, fmt->pad); 790 + crop->width = fmt->format.width; 791 + crop->height = fmt->format.height; 792 + if (mode->scan_mode == IMX335_2_2_BINNING) { 793 + crop->width *= 2; 794 + crop->height *= 2; 795 + } 796 + crop->left = (imx335_native_area.width - crop->width) / 2; 797 + crop->top = (imx335_native_area.height - crop->height) / 2; 906 798 907 799 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 908 800 ret = imx335_update_controls(imx335, mode); ··· 937 809 struct v4l2_subdev_format fmt = { 0 }; 938 810 939 811 fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 940 - imx335_fill_pad_format(imx335, &supported_mode, &fmt); 812 + imx335_fill_pad_format(imx335, &supported_modes[0], &fmt); 941 813 942 814 __v4l2_ctrl_modify_range(imx335->link_freq_ctrl, 0, 943 815 __fls(imx335->link_freq_bitmap), ··· 960 832 struct v4l2_subdev_selection *sel) 961 833 { 962 834 switch (sel->target) { 835 + case V4L2_SEL_TGT_CROP: 836 + sel->r = *v4l2_subdev_state_get_crop(sd_state, 0); 837 + 838 + return 0; 839 + 963 840 case V4L2_SEL_TGT_NATIVE_SIZE: 964 841 sel->r = imx335_native_area; 965 842 return 0; 966 843 967 - case V4L2_SEL_TGT_CROP: 968 844 case V4L2_SEL_TGT_CROP_DEFAULT: 969 845 case V4L2_SEL_TGT_CROP_BOUNDS: 970 846 sel->r = imx335_active_area; ··· 980 848 981 849 static int imx335_set_framefmt(struct imx335 *imx335) 982 850 { 983 - switch (imx335->cur_mbus_code) { 984 - case MEDIA_BUS_FMT_SRGGB10_1X10: 985 - return cci_multi_reg_write(imx335->cci, raw10_framefmt_regs, 986 - ARRAY_SIZE(raw10_framefmt_regs), 987 - NULL); 851 + /* 852 + * In the all-pixel scan mode the AD conversion shall match the output 853 + * bit width requested. 854 + * 855 + * However, when 2/2 binning is enabled, the AD conversion is always 856 + * 10-bit, so we ensure ADBIT is clear and ADBIT1 is assigned 0x1ff. 857 + * That's as much as the documentation gives us... 858 + */ 859 + int ret = 0; 860 + u8 bpp = imx335->cur_mbus_code == MEDIA_BUS_FMT_SRGGB10_1X10 ? 10 : 12; 861 + u8 ad_conv = bpp; 988 862 989 - case MEDIA_BUS_FMT_SRGGB12_1X12: 990 - return cci_multi_reg_write(imx335->cci, raw12_framefmt_regs, 991 - ARRAY_SIZE(raw12_framefmt_regs), 992 - NULL); 863 + /* Start with the output mode */ 864 + cci_write(imx335->cci, IMX335_REG_MDBIT, bpp == 12, &ret); 865 + 866 + /* Enforce 10 bit AD on binning modes */ 867 + if (imx335->cur_mode->scan_mode == IMX335_2_2_BINNING) 868 + ad_conv = 10; 869 + 870 + /* AD Conversion configuration */ 871 + if (ad_conv == 10) { 872 + cci_write(imx335->cci, IMX335_REG_ADBIT, 0x00, &ret); 873 + cci_write(imx335->cci, IMX335_REG_ADBIT1, 0x1ff, &ret); 874 + } else { /* 12 bit AD Conversion */ 875 + cci_write(imx335->cci, IMX335_REG_ADBIT, 0x01, &ret); 876 + cci_write(imx335->cci, IMX335_REG_ADBIT1, 0x47, &ret); 993 877 } 994 878 995 - return -EINVAL; 879 + return ret; 996 880 } 997 881 998 882 /** ··· 1039 891 reg_list = &imx335->cur_mode->reg_list; 1040 892 ret = cci_multi_reg_write(imx335->cci, reg_list->regs, 1041 893 reg_list->num_of_regs, NULL); 894 + if (ret) { 895 + dev_err(imx335->dev, "fail to write initial registers\n"); 896 + goto err_rpm_put; 897 + } 898 + 899 + /* Write sensor common registers */ 900 + ret = cci_multi_reg_write(imx335->cci, imx335_common_regs, 901 + ARRAY_SIZE(imx335_common_regs), NULL); 1042 902 if (ret) { 1043 903 dev_err(imx335->dev, "fail to write initial registers\n"); 1044 904 goto err_rpm_put; ··· 1333 1177 struct v4l2_ctrl_handler *ctrl_hdlr = &imx335->ctrl_handler; 1334 1178 const struct imx335_mode *mode = imx335->cur_mode; 1335 1179 struct v4l2_fwnode_device_properties props; 1336 - u32 lpfr; 1180 + u32 lpfr, shutter_min; 1337 1181 int ret; 1338 1182 1339 1183 ret = v4l2_fwnode_device_parse(imx335->dev, &props); ··· 1347 1191 1348 1192 /* Initialize exposure and gain */ 1349 1193 lpfr = mode->vblank + mode->height; 1194 + shutter_min = IMX335_SHUTTER_MIN; 1195 + if (mode->scan_mode == IMX335_2_2_BINNING) 1196 + shutter_min = IMX335_SHUTTER_MIN_BINNED; 1350 1197 imx335->exp_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, 1351 1198 &imx335_ctrl_ops, 1352 1199 V4L2_CID_EXPOSURE, 1353 1200 IMX335_EXPOSURE_MIN, 1354 - lpfr - IMX335_EXPOSURE_OFFSET, 1201 + lpfr - shutter_min, 1355 1202 IMX335_EXPOSURE_STEP, 1356 1203 IMX335_EXPOSURE_DEFAULT); 1357 1204 ··· 1481 1322 } 1482 1323 1483 1324 /* Set default mode to max resolution */ 1484 - imx335->cur_mode = &supported_mode; 1325 + imx335->cur_mode = &supported_modes[0]; 1485 1326 imx335->cur_mbus_code = imx335_mbus_codes[0]; 1486 1327 imx335->vblank = imx335->cur_mode->vblank; 1487 1328