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)
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)
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
126131struct 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 */
138145static 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
153160struct imx355_hwcfg {
154161 unsigned long link_freq_bitmap ;
162+ unsigned int num_lanes ;
155163};
156164
157165struct 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 */
358370static 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