From e4bcd6accc0ba44313e0b196d2a5a5d640e46616 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 22 Apr 2025 18:31:36 +0100 Subject: [PATCH 1/3] media: i2c: imx415: Reorder supported_modes by lane rate Before adding additional modes, sort the list by lane rate as that make most sense. Signed-off-by: Dave Stevenson --- drivers/media/i2c/imx415.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 806daac844769f..7b7dfd957dd731 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -512,14 +512,6 @@ static const struct imx415_mode supported_modes[] = { .regs = imx415_linkrate_720mbps, }, }, - { - .lane_rate = 1440000000, - .hmax_min = { 1066, 533 }, - .reg_list = { - .num_of_regs = ARRAY_SIZE(imx415_linkrate_1440mbps), - .regs = imx415_linkrate_1440mbps, - }, - }, { .lane_rate = 891000000, .hmax_min = { 2200, 1100 }, @@ -528,6 +520,14 @@ static const struct imx415_mode supported_modes[] = { .regs = imx415_linkrate_891mbps, }, }, + { + .lane_rate = 1440000000, + .hmax_min = { 1066, 533 }, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_linkrate_1440mbps), + .regs = imx415_linkrate_1440mbps, + }, + }, }; static const char *const imx415_test_pattern_menu[] = { From 8637b97aaa8bff64d4c971244117f35f3d18e167 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 22 Apr 2025 18:33:50 +0100 Subject: [PATCH 2/3] media: i2c: imx415: Add support for further link rates The sensor supports more link rates than the 3 currently supported, although some are only listed as being valid when running with 2 data lanes. Add these additional modes, with setting hblank_min to 0 to denote that it is invalid in that mode. Signed-off-by: Dave Stevenson --- I'm unable to successfully test 2376Mbit/s mode as it exceeds the hardware specs of the Pi5 CSI2 block. I get an image, but it's got incorrect colours, even with the horizontal timings extended significantly. All the register values follow the datasheet though. I have a suspicion that the modes listed as not permitted in a 2 lanes configuration will work, but I haven't the time to test it at present. Likewise the hmax_min values can almost certainly be decreased as it looks like Sony are just listing values for nice round frame rate values, not the limits. I can't determine the limits easily as Pi5 is limited to a maximum rate of approx 380MPix/s so can't run this sensor above 43fps. --- drivers/media/i2c/imx415.c | 115 ++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 7b7dfd957dd731..a9208477207b0f 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -109,7 +109,8 @@ static const char *const imx415_supply_names[] = { */ static const s64 link_freq_menu_items[] = { 594000000 / 2, 720000000 / 2, 891000000 / 2, - 1440000000 / 2, 1485000000 / 2, + 1440000000 / 2, 1485000000 / 2, 1782000000 / 2, + 2079000000 / 2, 2376000000 / 2, }; struct imx415_clk_params { @@ -452,6 +453,19 @@ static const struct imx415_clk_params imx415_clk_params[] = { }, }; +/* 594 Mbps CSI configuration */ +static const struct cci_reg_sequence imx415_linkrate_594mbps[] = { + { IMX415_TCLKPOST, 0x0067 }, + { IMX415_TCLKPREPARE, 0x0027 }, + { IMX415_TCLKTRAIL, 0x0027 }, + { IMX415_TCLKZERO, 0x00B7 }, + { IMX415_THSPREPARE, 0x002F }, + { IMX415_THSZERO, 0x004F }, + { IMX415_THSTRAIL, 0x002F }, + { IMX415_THSEXIT, 0x0047 }, + { IMX415_TLPX, 0x0027 }, +}; + /* 720 Mbps CSI configuration */ static const struct cci_reg_sequence imx415_linkrate_720mbps[] = { { IMX415_TCLKPOST, 0x006F }, @@ -491,6 +505,58 @@ static const struct cci_reg_sequence imx415_linkrate_891mbps[] = { { IMX415_TLPX, 0x002F }, }; +/* 1485 Mbps CSI configuration */ +static const struct cci_reg_sequence imx415_linkrate_1485mbps[] = { + { IMX415_TCLKPOST, 0x00A7 }, + { IMX415_TCLKPREPARE, 0x0057 }, + { IMX415_TCLKTRAIL, 0x005F }, + { IMX415_TCLKZERO, 0x0197 }, + { IMX415_THSPREPARE, 0x005F }, + { IMX415_THSZERO, 0x00AF }, + { IMX415_THSTRAIL, 0x005F }, + { IMX415_THSEXIT, 0x009F }, + { IMX415_TLPX, 0x004F }, +}; + +/* 1782 Mbps CSI configuration */ +static const struct cci_reg_sequence imx415_linkrate_1782mbps[] = { + { IMX415_TCLKPOST, 0x00B7 }, + { IMX415_TCLKPREPARE, 0x0067 }, + { IMX415_TCLKTRAIL, 0x006F }, + { IMX415_TCLKZERO, 0x01DF }, + { IMX415_THSPREPARE, 0x006F }, + { IMX415_THSZERO, 0x00CF }, + { IMX415_THSTRAIL, 0x006F }, + { IMX415_THSEXIT, 0x00B7 }, + { IMX415_TLPX, 0x005F }, +}; + +/* 2079 Mbps CSI configuration */ +static const struct cci_reg_sequence imx415_linkrate_2079mbps[] = { + { IMX415_TCLKPOST, 0x00D7 }, + { IMX415_TCLKPREPARE, 0x007F }, + { IMX415_TCLKTRAIL, 0x007F }, + { IMX415_TCLKZERO, 0x0237 }, + { IMX415_THSPREPARE, 0x0087 }, + { IMX415_THSZERO, 0x00EF }, + { IMX415_THSTRAIL, 0x0087 }, + { IMX415_THSEXIT, 0x00DF }, + { IMX415_TLPX, 0x006F }, +}; + +/* 2376 Mbps CSI configuration */ +static const struct cci_reg_sequence imx415_linkrate_2376mbps[] = { + { IMX415_TCLKPOST, 0x00E7 }, + { IMX415_TCLKPREPARE, 0x008F }, + { IMX415_TCLKTRAIL, 0x008F }, + { IMX415_TCLKZERO, 0x027F }, + { IMX415_THSPREPARE, 0x0097 }, + { IMX415_THSZERO, 0x010F }, + { IMX415_THSTRAIL, 0x0097 }, + { IMX415_THSEXIT, 0x00F7 }, + { IMX415_TLPX, 0x007F }, +}; + struct imx415_mode_reg_list { u32 num_of_regs; const struct cci_reg_sequence *regs; @@ -504,6 +570,15 @@ struct imx415_mode { /* mode configs */ static const struct imx415_mode supported_modes[] = { + { + .lane_rate = 594000000, + /* 2 lane mode lists 10fps. 4 lane mode lists 25fps */ + .hmax_min = { 3300, 1320 }, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_linkrate_594mbps), + .regs = imx415_linkrate_594mbps, + }, + }, { .lane_rate = 720000000, .hmax_min = { 2032, 1066 }, @@ -528,6 +603,40 @@ static const struct imx415_mode supported_modes[] = { .regs = imx415_linkrate_1440mbps, }, }, + { + .lane_rate = 1485000000, + /* Datasheet says this lane rate is only supported on 4 lanes */ + .hmax_min = { 0, 550 }, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_linkrate_1485mbps), + .regs = imx415_linkrate_1485mbps, + }, + }, + { + .lane_rate = 1782000000, + .hmax_min = { 1100, 550 }, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_linkrate_1782mbps), + .regs = imx415_linkrate_1782mbps, + }, + }, + { + .lane_rate = 2079000000, + .hmax_min = { 1100, 550 }, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_linkrate_2079mbps), + .regs = imx415_linkrate_2079mbps, + }, + }, + { + .lane_rate = 2376000000, + /* Datasheet says this lane rate is only supported on 4 lanes */ + .hmax_min = { 0, 366 }, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_linkrate_2376mbps), + .regs = imx415_linkrate_2376mbps, + }, + }, }; static const char *const imx415_test_pattern_menu[] = { @@ -1300,6 +1409,10 @@ static int imx415_parse_hw_config(struct imx415 *sensor) if (bus_cfg.link_frequencies[i] * 2 != supported_modes[j].lane_rate) continue; + if (sensor->num_data_lanes == 2 && + !supported_modes[j].hmax_min[0]) + continue; + sensor->cur_mode = j; break; } From 042d997da57dad7d30a1da058503898a82b6eef4 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 22 Apr 2025 19:20:54 +0100 Subject: [PATCH 3/3] media: i2c: imx415: Add support for 12bit readout The sensor supports conversion and readout as either 10 or 12 bit data, but the driver only supported 10 bit mode. Add support for 12 bit conversion. Signed-off-by: Dave Stevenson --- drivers/media/i2c/imx415.c | 56 ++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index a9208477207b0f..190e7dbd52e7de 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -639,6 +639,16 @@ static const struct imx415_mode supported_modes[] = { }, }; +static const struct cci_reg_sequence imx415_10bit_readout[] = { + { IMX415_ADBIT, 0x00 }, + { IMX415_MDBIT, 0x00 }, +}; + +static const struct cci_reg_sequence imx415_12bit_readout[] = { + { IMX415_ADBIT, 0x01 }, + { IMX415_MDBIT, 0x01 }, +}; + static const char *const imx415_test_pattern_menu[] = { "disabled", "solid black", @@ -688,9 +698,6 @@ static const struct cci_reg_sequence imx415_init_table[] = { { IMX415_WINMODE, 0x00 }, { IMX415_ADDMODE, 0x00 }, { IMX415_REVERSE, 0x00 }, - /* use RAW 10-bit mode */ - { IMX415_ADBIT, 0x00 }, - { IMX415_MDBIT, 0x00 }, /* output VSYNC on XVS and low on XHS */ { IMX415_OUTSEL, 0x22 }, { IMX415_DRV, 0x00 }, @@ -999,6 +1006,7 @@ static int imx415_set_mode(struct imx415 *sensor, int mode) static int imx415_setup(struct imx415 *sensor, struct v4l2_subdev_state *state) { + struct v4l2_mbus_framefmt *format; int ret; ret = cci_multi_reg_write(sensor->regmap, @@ -1008,6 +1016,24 @@ static int imx415_setup(struct imx415 *sensor, struct v4l2_subdev_state *state) if (ret) return ret; + format = v4l2_subdev_state_get_format(state, 0); + switch (format->code) { + case MEDIA_BUS_FMT_SGBRG10_1X10: + ret = cci_multi_reg_write(sensor->regmap, + imx415_10bit_readout, + ARRAY_SIZE(imx415_10bit_readout), + NULL); + break; + case MEDIA_BUS_FMT_SGBRG12_1X12: + ret = cci_multi_reg_write(sensor->regmap, + imx415_12bit_readout, + ARRAY_SIZE(imx415_12bit_readout), + NULL); + break; + } + if (ret) + return ret; + return imx415_set_mode(sensor, sensor->cur_mode); } @@ -1103,10 +1129,16 @@ static int imx415_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_mbus_code_enum *code) { - if (code->index != 0) + switch (code->index) { + default: return -EINVAL; - - code->code = MEDIA_BUS_FMT_SGBRG10_1X10; + case 0: + code->code = MEDIA_BUS_FMT_SGBRG10_1X10; + break; + case 1: + code->code = MEDIA_BUS_FMT_SGBRG12_1X12; + break; + } return 0; } @@ -1119,7 +1151,8 @@ static int imx415_enum_frame_size(struct v4l2_subdev *sd, format = v4l2_subdev_state_get_format(state, fse->pad); - if (fse->index > 0 || fse->code != format->code) + if (fse->index > 0 || (fse->code != MEDIA_BUS_FMT_SGBRG10_1X10 && + fse->code != MEDIA_BUS_FMT_SGBRG12_1X12)) return -EINVAL; fse->min_width = IMX415_PIXEL_ARRAY_WIDTH; @@ -1139,7 +1172,14 @@ static int imx415_set_format(struct v4l2_subdev *sd, format->width = fmt->format.width; format->height = fmt->format.height; - format->code = MEDIA_BUS_FMT_SGBRG10_1X10; + switch (fmt->format.code) { + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGBRG12_1X12: + format->code = fmt->format.code; + break; + default: + format->code = MEDIA_BUS_FMT_SGBRG10_1X10; + } format->field = V4L2_FIELD_NONE; format->colorspace = V4L2_COLORSPACE_RAW; format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;