Skip to content

Commit 1e4c77f

Browse files
committed
media: imx355: Support 2 lane readout.
The sensor supports 2 or 4 lane readout, but the driver only allowed for 4 lanes. Add 2 lane support. The clock tree was set to use single PLL mode to feed both IOP (MIPI) and IVT (Pixel array). 2 lane mode supports a MIPI link frequency of up to 445MHz (890Mbit/s) cf 360MHz (720Mbit/s) for 4lane, but that requires switching to dual PLL mode as the rates can't be achieved with simple divisors. The LLP values are extended for each mode to account for the increased time per line over the MIPI link. Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
1 parent b9b576a commit 1e4c77f

1 file changed

Lines changed: 81 additions & 50 deletions

File tree

drivers/media/i2c/imx355.c

Lines changed: 81 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@
2727
#define IMX355_REG_CHIP_ID CCI_REG16(0x0016)
2828
#define IMX355_CHIP_ID 0x0355
2929

30+
#define IMX355_REG_LANE_SEL CCI_REG8(0x0114)
31+
3032
/* PLL registers that depend on the external clock frequency */
3133
#define IMX355_REG_EXTCLK_FREQ CCI_REG16(0x0136)
3234
#define IMX355_REG_PLL_VT_MUL CCI_REG16(0x0306)
3335
#define IMX355_REG_PLL_OP_MUL CCI_REG16(0x030e)
36+
#define IMX355_REG_PLL_MODE CCI_REG8(0x0310)
3437

3538
/* V_TIMING internal */
3639
#define IMX355_REG_FLL CCI_REG16(0x0340)
@@ -77,6 +80,8 @@
7780
#define IMX355_TEST_PATTERN_GRAY_COLOR_BARS 3
7881
#define IMX355_TEST_PATTERN_PN9 4
7982

83+
#define IMX355_REG_REQ_LINK_BIT_RATE CCI_REG16(0x0820)
84+
8085
#define IMX355_REG_BINNING_MODE CCI_REG8(0x0900)
8186
#define IMX355_REG_BINNING_TYPE CCI_REG8(0x0901)
8287
#define IMX355_REG_BINNING_WEIGHTING CCI_REG8(0x0902)
@@ -85,10 +90,10 @@
8590
#define IMX355_REG_ORIENTATION CCI_REG8(0x0101)
8691

8792
/* default link frequency and external clock */
88-
#define IMX355_LINK_FREQ_DEFAULT 360000000LL
93+
#define IMX355_LINK_FREQ_4LANE 360000000LL
94+
#define IMX355_LINK_FREQ_2LANE 445000000LL
8995

90-
/* number of data lanes */
91-
#define IMX355_DATA_LANES 4
96+
#define IMX355_PIXEL_RATE 288000000
9297

9398
#define IMX355_PIXEL_ARRAY_TOP 0
9499
#define IMX355_PIXEL_ARRAY_LEFT 0
@@ -111,7 +116,7 @@ struct imx355_mode {
111116
u32 fll_def;
112117

113118
/* H-timing */
114-
u32 llp;
119+
u32 llp[2];
115120

116121
/* Default register values */
117122
struct imx355_reg_list reg_list;
@@ -125,33 +130,36 @@ struct imx355_mode {
125130

126131
struct imx355_clk_params {
127132
u32 ext_clk;
128-
u16 extclk_freq; /* External clock (MHz) in 8.8 fixed point) */
129-
u16 pll_vt_mpy; /* VT system PLL multiplier */
130-
u16 pll_op_mpy; /* OP system PLL multiplier */
133+
u16 extclk_freq; /* External clock (MHz) in 8.8 fixed point) */
134+
u16 pll_vt_mpy[2]; /* VT system PLL multiplier */
135+
u16 pll_op_mpy[2]; /* OP system PLL multiplier */
131136
};
132137

133138
/*
134-
* All modes use the same PLL dividers (PREPLLCK_VT_DIV=2, PREPLLCK_OP_DIV=2),
135-
* so the multipliers are adjusted to produce the same VCO frequencies:
136-
* VT VCO = 1152 MHz, OP VCO = 720 MHz
139+
* For backwards compatibility, 4 lane mode uses the single PLL clock tree
140+
* where only IOP matters. MIPI rate is 360Mhz (720Mbit/s), and pixel rate is
141+
* 288MPix/s.
142+
* 2 lane mode has a maximum MIPI rate of 445MHz (890Mbit/s) which requires
143+
* switching to dual PLL mode if the pixel rate is to be kept the same.
137144
*/
138145
static const struct imx355_clk_params imx355_clk_params[] = {
139146
{
140147
.ext_clk = 19200000,
141-
.extclk_freq = 0x1333, /* 19.2 MHz */
142-
.pll_vt_mpy = 120, /* 19.2 / 2 * 120 = 1152 MHz */
143-
.pll_op_mpy = 75, /* 19.2 / 2 * 75 = 720 MHz */
148+
.extclk_freq = 0x1333,
149+
.pll_vt_mpy = { 0, 75 },
150+
.pll_op_mpy = { 75, 93 },
144151
},
145152
{
146153
.ext_clk = 24000000,
147-
.extclk_freq = 0x1800, /* 24.0 MHz */
148-
.pll_vt_mpy = 96, /* 24.0 / 2 * 96 = 1152 MHz */
149-
.pll_op_mpy = 60, /* 24.0 / 2 * 60 = 720 MHz */
154+
.extclk_freq = 0x1800,
155+
.pll_vt_mpy = { 0, 60 },
156+
.pll_op_mpy = { 60, 74 },
150157
},
151158
};
152159

153160
struct imx355_hwcfg {
154161
unsigned long link_freq_bitmap;
162+
unsigned int num_lanes;
155163
};
156164

157165
struct imx355 {
@@ -247,17 +255,13 @@ static const struct cci_reg_sequence imx355_global_regs[] = {
247255
{ CCI_REG8(0x305a), 0x00 },
248256
{ CCI_REG8(0x0112), 0x0a },
249257
{ CCI_REG8(0x0113), 0x0a },
250-
{ CCI_REG8(0x0114), 0x03 },
251258
{ CCI_REG8(0x0301), 0x05 },
252259
{ CCI_REG8(0x0303), 0x01 },
253260
{ CCI_REG8(0x0305), 0x02 },
254261
{ CCI_REG8(0x030b), 0x01 },
255262
{ CCI_REG8(0x030d), 0x02 },
256-
{ CCI_REG8(0x0310), 0x00 },
257263
{ CCI_REG8(0x0220), 0x00 },
258264
{ CCI_REG8(0x0222), 0x01 },
259-
{ CCI_REG8(0x0820), 0x0b },
260-
{ CCI_REG8(0x0821), 0x40 },
261265
{ CCI_REG8(0x3088), 0x04 },
262266
{ CCI_REG8(0x6813), 0x02 },
263267
{ CCI_REG8(0x6835), 0x07 },
@@ -350,17 +354,25 @@ static const char * const imx355_test_pattern_menu[] = {
350354
* When adding more than the one below, make sure the disallowed ones will
351355
* actually be disabled in the LINK_FREQ control.
352356
*/
353-
static const s64 link_freq_menu_items[] = {
354-
IMX355_LINK_FREQ_DEFAULT,
357+
static const s64 link_freq_menu_items_4lane[] = {
358+
IMX355_LINK_FREQ_4LANE,
355359
};
356360

361+
static const s64 link_freq_menu_items_2lane[] = {
362+
IMX355_LINK_FREQ_2LANE,
363+
};
364+
365+
/* Avoid the two arrays getting out of sync */
366+
static_assert(ARRAY_SIZE(link_freq_menu_items_4lane) ==
367+
ARRAY_SIZE(link_freq_menu_items_2lane));
368+
357369
/* Mode configs */
358370
static const struct imx355_mode supported_modes[] = {
359371
{
360372
.width = 3280,
361373
.height = 2464,
362374
.fll_def = 2615,
363-
.llp = 3672,
375+
.llp = { 3672, 5942 },
364376
.reg_list = {
365377
.num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
366378
.regs = mode_3280x2464_regs,
@@ -375,7 +387,7 @@ static const struct imx355_mode supported_modes[] = {
375387
.width = 3268,
376388
.height = 2448,
377389
.fll_def = 2615,
378-
.llp = 3672,
390+
.llp = { 3672, 5942 },
379391
.reg_list = {
380392
.num_of_regs = ARRAY_SIZE(mode_3268x2448_regs),
381393
.regs = mode_3268x2448_regs,
@@ -390,7 +402,7 @@ static const struct imx355_mode supported_modes[] = {
390402
.width = 3264,
391403
.height = 2448,
392404
.fll_def = 2615,
393-
.llp = 3672,
405+
.llp = { 3672, 5942 },
394406
.reg_list = {
395407
.num_of_regs = ARRAY_SIZE(mode_3264x2448_regs),
396408
.regs = mode_3264x2448_regs,
@@ -405,7 +417,7 @@ static const struct imx355_mode supported_modes[] = {
405417
.width = 1940,
406418
.height = 1096,
407419
.fll_def = 1306,
408-
.llp = 3672,
420+
.llp = { 3672, 5942 },
409421
.reg_list = {
410422
.num_of_regs = ARRAY_SIZE(mode_1940x1096_regs),
411423
.regs = mode_1940x1096_regs,
@@ -420,7 +432,7 @@ static const struct imx355_mode supported_modes[] = {
420432
.width = 1936,
421433
.height = 1096,
422434
.fll_def = 1306,
423-
.llp = 3672,
435+
.llp = { 3672, 5942 },
424436
.reg_list = {
425437
.num_of_regs = ARRAY_SIZE(mode_1936x1096_regs),
426438
.regs = mode_1936x1096_regs,
@@ -435,7 +447,7 @@ static const struct imx355_mode supported_modes[] = {
435447
.width = 1924,
436448
.height = 1080,
437449
.fll_def = 1306,
438-
.llp = 3672,
450+
.llp = { 3672, 5942 },
439451
.reg_list = {
440452
.num_of_regs = ARRAY_SIZE(mode_1924x1080_regs),
441453
.regs = mode_1924x1080_regs,
@@ -450,7 +462,7 @@ static const struct imx355_mode supported_modes[] = {
450462
.width = 1920,
451463
.height = 1080,
452464
.fll_def = 1306,
453-
.llp = 3672,
465+
.llp = { 3672, 5942 },
454466
.reg_list = {
455467
.num_of_regs = ARRAY_SIZE(mode_1920x1080_regs),
456468
.regs = mode_1920x1080_regs,
@@ -465,7 +477,7 @@ static const struct imx355_mode supported_modes[] = {
465477
.width = 1640,
466478
.height = 1232,
467479
.fll_def = 1306,
468-
.llp = 1836,
480+
.llp = { 1836, 2970 },
469481
.reg_list = {
470482
.num_of_regs = ARRAY_SIZE(mode_1640x1232_regs),
471483
.regs = mode_1640x1232_regs,
@@ -480,7 +492,7 @@ static const struct imx355_mode supported_modes[] = {
480492
.width = 1640,
481493
.height = 922,
482494
.fll_def = 1306,
483-
.llp = 1836,
495+
.llp = { 1836, 2970 },
484496
.reg_list = {
485497
.num_of_regs = ARRAY_SIZE(mode_1640x922_regs),
486498
.regs = mode_1640x922_regs,
@@ -495,7 +507,7 @@ static const struct imx355_mode supported_modes[] = {
495507
.width = 1300,
496508
.height = 736,
497509
.fll_def = 1306,
498-
.llp = 1836,
510+
.llp = { 1836, 2970 },
499511
.reg_list = {
500512
.num_of_regs = ARRAY_SIZE(mode_1300x736_regs),
501513
.regs = mode_1300x736_regs,
@@ -510,7 +522,7 @@ static const struct imx355_mode supported_modes[] = {
510522
.width = 1296,
511523
.height = 736,
512524
.fll_def = 1306,
513-
.llp = 1836,
525+
.llp = { 1836, 2970 },
514526
.reg_list = {
515527
.num_of_regs = ARRAY_SIZE(mode_1296x736_regs),
516528
.regs = mode_1296x736_regs,
@@ -525,7 +537,7 @@ static const struct imx355_mode supported_modes[] = {
525537
.width = 1284,
526538
.height = 720,
527539
.fll_def = 1306,
528-
.llp = 1836,
540+
.llp = { 1836, 2970 },
529541
.reg_list = {
530542
.num_of_regs = ARRAY_SIZE(mode_1284x720_regs),
531543
.regs = mode_1284x720_regs,
@@ -540,7 +552,7 @@ static const struct imx355_mode supported_modes[] = {
540552
.width = 1280,
541553
.height = 720,
542554
.fll_def = 1306,
543-
.llp = 1836,
555+
.llp = { 1836, 2970 },
544556
.reg_list = {
545557
.num_of_regs = ARRAY_SIZE(mode_1280x720_regs),
546558
.regs = mode_1280x720_regs,
@@ -555,7 +567,7 @@ static const struct imx355_mode supported_modes[] = {
555567
.width = 820,
556568
.height = 616,
557569
.fll_def = 652,
558-
.llp = 3672,
570+
.llp = { 3672, 5942 },
559571
.reg_list = {
560572
.num_of_regs = ARRAY_SIZE(mode_820x616_regs),
561573
.regs = mode_820x616_regs,
@@ -805,7 +817,8 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
805817
__v4l2_ctrl_modify_range(imx355->vblank, IMX355_FLL_OFFSET,
806818
height, 1, vblank_def);
807819
__v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def);
808-
h_blank = mode->llp - imx355->cur_mode->width;
820+
h_blank = mode->llp[imx355->hwcfg->num_lanes == 4 ? 0 : 1] -
821+
imx355->cur_mode->width;
809822
/*
810823
* Currently hblank is not changeable.
811824
* So FPS control is done only by vblank.
@@ -876,6 +889,7 @@ static int imx355_start_streaming(struct imx355 *imx355)
876889
{
877890
const struct imx355_reg_list *reg_list;
878891
const struct imx355_mode *mode;
892+
int lane_idx = imx355->hwcfg->num_lanes == 4 ? 0 : 1;
879893
int ret = 0;
880894

881895
/* Global Setting */
@@ -907,9 +921,19 @@ static int imx355_start_streaming(struct imx355 *imx355)
907921
cci_write(imx355->regmap, IMX355_REG_EXTCLK_FREQ,
908922
imx355->clk_params->extclk_freq, &ret);
909923
cci_write(imx355->regmap, IMX355_REG_PLL_VT_MUL,
910-
imx355->clk_params->pll_vt_mpy, &ret);
924+
imx355->clk_params->pll_vt_mpy[lane_idx], &ret);
911925
cci_write(imx355->regmap, IMX355_REG_PLL_OP_MUL,
912-
imx355->clk_params->pll_op_mpy, &ret);
926+
imx355->clk_params->pll_op_mpy[lane_idx], &ret);
927+
cci_write(imx355->regmap, IMX355_REG_PLL_MODE, lane_idx ? 0x01 : 0x00,
928+
&ret);
929+
930+
/* Set MIPI configuration */
931+
cci_write(imx355->regmap, IMX355_REG_LANE_SEL,
932+
imx355->hwcfg->num_lanes - 1, &ret);
933+
934+
cci_write(imx355->regmap, IMX355_REG_REQ_LINK_BIT_RATE,
935+
(imx355->link_freq->qmenu_int[imx355->link_freq->val] *
936+
imx355->hwcfg->num_lanes * 2) / 1000000, &ret);
913937

914938
/* set digital gain control to all color mode */
915939
cci_write(imx355->regmap, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, &ret);
@@ -1079,8 +1103,8 @@ static int imx355_init_controls(struct imx355 *imx355)
10791103
s64 exposure_max;
10801104
s64 vblank_def;
10811105
s64 hblank;
1082-
u64 pixel_rate;
10831106
const struct imx355_mode *mode;
1107+
const s64 *link_freq_menu;
10841108
u32 max;
10851109
int ret;
10861110

@@ -1090,19 +1114,21 @@ static int imx355_init_controls(struct imx355 *imx355)
10901114
return ret;
10911115

10921116
ctrl_hdlr->lock = &imx355->mutex;
1093-
max = ARRAY_SIZE(link_freq_menu_items) - 1;
1117+
link_freq_menu = imx355->hwcfg->num_lanes == 4 ?
1118+
link_freq_menu_items_4lane :
1119+
link_freq_menu_items_2lane;
1120+
1121+
max = ARRAY_SIZE(link_freq_menu_items_4lane) - 1;
10941122
imx355->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx355_ctrl_ops,
10951123
V4L2_CID_LINK_FREQ, max, 0,
1096-
link_freq_menu_items);
1124+
link_freq_menu);
10971125
if (imx355->link_freq)
10981126
imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
10991127

1100-
/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
1101-
pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4;
1102-
do_div(pixel_rate, 10);
11031128
/* By default, PIXEL_RATE is read only */
11041129
v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_PIXEL_RATE,
1105-
pixel_rate, pixel_rate, 1, pixel_rate);
1130+
IMX355_PIXEL_RATE, IMX355_PIXEL_RATE, 1,
1131+
IMX355_PIXEL_RATE);
11061132

11071133
/* Initialize vblank/hblank/exposure parameters based on current mode */
11081134
mode = imx355->cur_mode;
@@ -1112,7 +1138,7 @@ static int imx355_init_controls(struct imx355 *imx355)
11121138
IMX355_FLL_MAX - mode->height,
11131139
1, vblank_def);
11141140

1115-
hblank = mode->llp - mode->width;
1141+
hblank = mode->llp[imx355->hwcfg->num_lanes == 4 ? 0 : 1] - mode->width;
11161142
imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
11171143
V4L2_CID_HBLANK, hblank, hblank,
11181144
1, hblank);
@@ -1199,13 +1225,18 @@ static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev)
11991225
if (!cfg)
12001226
goto out_err;
12011227

1202-
if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX355_DATA_LANES)
1228+
if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2 &&
1229+
bus_cfg.bus.mipi_csi2.num_data_lanes != 4)
12031230
goto out_err;
12041231

1232+
cfg->num_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
1233+
12051234
ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies,
12061235
bus_cfg.nr_of_link_frequencies,
1207-
link_freq_menu_items,
1208-
ARRAY_SIZE(link_freq_menu_items),
1236+
cfg->num_lanes == 4 ?
1237+
link_freq_menu_items_4lane :
1238+
link_freq_menu_items_2lane,
1239+
ARRAY_SIZE(link_freq_menu_items_4lane),
12091240
&cfg->link_freq_bitmap);
12101241
if (ret)
12111242
goto out_err;

0 commit comments

Comments
 (0)