Skip to content

IMX415 higher link rate support #6807

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: rpi-6.12.y
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 166 additions & 13 deletions drivers/media/i2c/imx415.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 },
Expand Down Expand Up @@ -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;
Expand All @@ -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 },
Expand All @@ -512,6 +587,14 @@ static const struct imx415_mode supported_modes[] = {
.regs = imx415_linkrate_720mbps,
},
},
{
.lane_rate = 891000000,
.hmax_min = { 2200, 1100 },
.reg_list = {
.num_of_regs = ARRAY_SIZE(imx415_linkrate_891mbps),
.regs = imx415_linkrate_891mbps,
},
},
{
.lane_rate = 1440000000,
.hmax_min = { 1066, 533 },
Expand All @@ -521,15 +604,51 @@ static const struct imx415_mode supported_modes[] = {
},
},
{
.lane_rate = 891000000,
.hmax_min = { 2200, 1100 },
.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_891mbps),
.regs = imx415_linkrate_891mbps,
.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 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",
Expand Down Expand Up @@ -579,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 },
Expand Down Expand Up @@ -890,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,
Expand All @@ -899,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);
}

Expand Down Expand Up @@ -994,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;
}
Expand All @@ -1010,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;
Expand All @@ -1030,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;
Expand Down Expand Up @@ -1300,6 +1449,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;
}
Expand Down