diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index 32e08d6d06561..79cd266cf48b0 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -2915,6 +2915,7 @@ Params: rotation Mounting rotation of the camera sensor (0 or sync-sink Configure as vsync sink link-frequency Allowable link frequency values to use in Hz: 450000000 (default), 453000000, 456000000. + pi5 Sets the CSI2 link frequency to 900MHz. Name: imx415 @@ -2993,6 +2994,7 @@ Params: rotation Mounting rotation of the camera sensor (0 or sync-sink Configure as vsync sink link-frequency Allowable link frequency values to use in Hz: 450000000 (default), 453000000, 456000000. + pi5 Sets the CSI2 link frequency to 900MHz Name: imx500 diff --git a/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi b/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi index 686289f550297..5e9b963148583 100644 --- a/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi +++ b/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi @@ -87,6 +87,7 @@ <&cam_node>, "VANA-supply:0=",<&cam0_reg>; always-on = <0>, "+99"; link-frequency = <&cam_endpoint>,"link-frequencies#0"; + pi5 = <&cam_endpoint>, "link-frequencies#0=900000000"; }; }; diff --git a/drivers/media/i2c/imx477.c b/drivers/media/i2c/imx477.c index aa70341a87a26..f7c930170b1d8 100644 --- a/drivers/media/i2c/imx477.c +++ b/drivers/media/i2c/imx477.c @@ -43,6 +43,9 @@ MODULE_PARM_DESC(trigger_mode, "Set vsync trigger mode: 1=source, 2=sink"); #define IMX477_REG_ORIENTATION 0x101 +#define IMX477_REG_CSI_DT_FMT_H 0x0112 +#define IMX477_REG_CSI_DT_FMT_L 0x0113 + #define IMX477_XCLK_FREQ 24000000 #define IMX477_DEFAULT_LINK_FREQ 450000000 @@ -53,6 +56,7 @@ MODULE_PARM_DESC(trigger_mode, "Set vsync trigger mode: 1=source, 2=sink"); /* V_TIMING internal */ #define IMX477_REG_FRAME_LENGTH 0x0340 #define IMX477_FRAME_LENGTH_MAX 0xffdc +#define IMX477_VBLANK_MIN 4 /* H_TIMING internal */ #define IMX477_REG_LINE_LENGTH 0x0342 @@ -85,6 +89,9 @@ MODULE_PARM_DESC(trigger_mode, "Set vsync trigger mode: 1=source, 2=sink"); #define IMX477_DGTL_GAIN_DEFAULT 0x0100 #define IMX477_DGTL_GAIN_STEP 1 +#define IMX477_REG_IOP_PXCK_DIV 0x0309 +#define IMX477_REG_DIV_IOP_PX 0x030b + /* Test Pattern Control */ #define IMX477_REG_TEST_PATTERN 0x0600 #define IMX477_TEST_PATTERN_DISABLE 0 @@ -115,6 +122,8 @@ MODULE_PARM_DESC(trigger_mode, "Set vsync trigger mode: 1=source, 2=sink"); /* Temperature sensor */ #define IMX477_REG_TEMP_SEN_CTL 0x0138 +#define IMX477_REG_FRAME_BLANKSTOP_CLK 0xE000 + /* Embedded metadata stream structure */ #define IMX477_EMBEDDED_LINE_WIDTH 16384 #define IMX477_NUM_EMBEDDED_LINES 1 @@ -151,17 +160,17 @@ struct imx477_mode { /* Frame height */ unsigned int height; - /* H-timing in pixels */ - unsigned int line_length_pix; + /* + * H-timing in pixels when at 450MHz link freq + * Index 0 is for 12bpp. Index 1 is for 10bpp. + */ + unsigned int line_length_pix[2]; /* Analog crop rectangle. */ struct v4l2_rect crop; - /* Highest possible framerate. */ - struct v4l2_fract timeperframe_min; - /* Default framerate. */ - struct v4l2_fract timeperframe_default; + unsigned int framerate_default; /* Default register values */ struct imx477_reg_list reg_list; @@ -177,7 +186,7 @@ enum { IMX477_LINK_FREQ_498MHZ, }; -static const s64 link_freqs[] = { +static const u64 imx477_link_freq_menu[] = { [IMX477_LINK_FREQ_450MHZ] = 450000000, [IMX477_LINK_FREQ_453MHZ] = 453000000, [IMX477_LINK_FREQ_456MHZ] = 456000000, @@ -186,6 +195,12 @@ static const s64 link_freqs[] = { [IMX477_LINK_FREQ_498MHZ] = 498000000, }; +static const u64 imx477_double_link_freq_menu[] = { + [IMX477_LINK_FREQ_450MHZ] = 450000000 * 2, + [IMX477_LINK_FREQ_453MHZ] = 453000000 * 2, + [IMX477_LINK_FREQ_456MHZ] = 456000000 * 2, +}; + /* 450MHz is the nominal "default" link frequency */ static const struct imx477_reg link_450Mhz_regs[] = { {0x030E, 0x00}, @@ -248,7 +263,6 @@ static const struct imx477_reg mode_common_regs[] = { {0x0136, 0x18}, {0x0137, 0x00}, {0x0138, 0x01}, - {0xe000, 0x00}, {0xe07a, 0x01}, {0x0808, 0x02}, {0x4ae9, 0x18}, @@ -548,18 +562,56 @@ static const struct imx477_reg mode_common_regs[] = { {0xb21f, 0x04}, {0xb35c, 0x00}, {0xb35e, 0x08}, - {0x0112, 0x0c}, - {0x0113, 0x0c}, {0x0114, 0x01}, {0x0350, 0x00}, {0xbcf1, 0x02}, {0x3ff9, 0x01}, + {0x0220, 0x00}, + {0x0221, 0x11}, + {0x0381, 0x01}, + {0x0383, 0x01}, + {0x0385, 0x01}, + {0x0387, 0x01}, + {0x0902, 0x02}, + {0x3140, 0x02}, + {0x3c00, 0x00}, + {0x9e9a, 0x2f}, + {0x9e9b, 0x2f}, + {0x9e9c, 0x2f}, + {0x9e9d, 0x00}, + {0x9e9e, 0x00}, + {0x9e9f, 0x00}, + {0x0301, 0x05}, + {0x0303, 0x02}, + {0x030d, 0x02}, + {0x0310, 0x01}, + {0x0820, 0x07}, + {0x0821, 0x08}, + {0x0822, 0x00}, + {0x0823, 0x00}, + {0x080a, 0x00}, + {0x080b, 0x7f}, + {0x080c, 0x00}, + {0x080d, 0x4f}, + {0x080e, 0x00}, + {0x080f, 0x77}, + {0x0810, 0x00}, + {0x0811, 0x5f}, + {0x0812, 0x00}, + {0x0813, 0x57}, + {0x0814, 0x00}, + {0x0815, 0x4f}, + {0x0816, 0x01}, + {0x0817, 0x27}, + {0x0818, 0x00}, + {0x0819, 0x3f}, + {0x3e20, 0x01}, + {0x3e37, 0x00}, + {0x3f50, 0x00}, }; /* 12 mpix 10fps */ static const struct imx477_reg mode_4056x3040_regs[] = { - {0x0342, 0x5d}, - {0x0343, 0xc0}, {0x0344, 0x00}, {0x0345, 0x00}, {0x0346, 0x00}, @@ -574,17 +626,8 @@ static const struct imx477_reg mode_4056x3040_regs[] = { {0x00fd, 0x0a}, {0x00fe, 0x0a}, {0x00ff, 0x0a}, - {0x0220, 0x00}, - {0x0221, 0x11}, - {0x0381, 0x01}, - {0x0383, 0x01}, - {0x0385, 0x01}, - {0x0387, 0x01}, {0x0900, 0x00}, {0x0901, 0x11}, - {0x0902, 0x02}, - {0x3140, 0x02}, - {0x3c00, 0x00}, {0x3c01, 0x03}, {0x3c02, 0xa2}, {0x3f0d, 0x01}, @@ -603,12 +646,6 @@ static const struct imx477_reg mode_4056x3040_regs[] = { {0x936d, 0x28}, {0x9304, 0x00}, {0x9305, 0x00}, - {0x9e9a, 0x2f}, - {0x9e9b, 0x2f}, - {0x9e9c, 0x2f}, - {0x9e9d, 0x00}, - {0x9e9e, 0x00}, - {0x9e9f, 0x00}, {0xa2a9, 0x60}, {0xa2b7, 0x00}, {0x0401, 0x00}, @@ -626,50 +663,83 @@ static const struct imx477_reg mode_4056x3040_regs[] = { {0x034d, 0xd8}, {0x034e, 0x0b}, {0x034f, 0xe0}, - {0x0301, 0x05}, - {0x0303, 0x02}, {0x0305, 0x04}, {0x0306, 0x01}, {0x0307, 0x5e}, - {0x0309, 0x0c}, - {0x030b, 0x02}, - {0x030d, 0x02}, - {0x0310, 0x01}, - {0x0820, 0x07}, - {0x0821, 0x08}, - {0x0822, 0x00}, - {0x0823, 0x00}, - {0x080a, 0x00}, - {0x080b, 0x7f}, - {0x080c, 0x00}, - {0x080d, 0x4f}, - {0x080e, 0x00}, - {0x080f, 0x77}, - {0x0810, 0x00}, - {0x0811, 0x5f}, - {0x0812, 0x00}, - {0x0813, 0x57}, - {0x0814, 0x00}, - {0x0815, 0x4f}, - {0x0816, 0x01}, - {0x0817, 0x27}, - {0x0818, 0x00}, - {0x0819, 0x3f}, {0xe04c, 0x00}, {0xe04d, 0x7f}, {0xe04e, 0x00}, {0xe04f, 0x1f}, - {0x3e20, 0x01}, - {0x3e37, 0x00}, - {0x3f50, 0x00}, + {0x3f56, 0x02}, + {0x3f57, 0xae}, +}; + +/* 12 mpix cropped to 16:9 10fps */ +static const struct imx477_reg mode_4056x2160_regs[] = { + {0x0344, 0x00}, + {0x0345, 0x00}, + {0x0346, 0x01}, + {0x0347, 0xb8}, + {0x0348, 0x0f}, + {0x0349, 0xd7}, + {0x034a, 0x0a}, + {0x034b, 0x27}, + {0x00e3, 0x00}, + {0x00e4, 0x00}, + {0x00fc, 0x0a}, + {0x00fd, 0x0a}, + {0x00fe, 0x0a}, + {0x00ff, 0x0a}, + {0x0900, 0x00}, + {0x0901, 0x11}, + {0x3c01, 0x03}, + {0x3c02, 0xa2}, + {0x3f0d, 0x01}, + {0x5748, 0x07}, + {0x5749, 0xff}, + {0x574a, 0x00}, + {0x574b, 0x00}, + {0x7b75, 0x0a}, + {0x7b76, 0x0c}, + {0x7b77, 0x07}, + {0x7b78, 0x06}, + {0x7b79, 0x3c}, + {0x7b53, 0x01}, + {0x9369, 0x5a}, + {0x936b, 0x55}, + {0x936d, 0x28}, + {0x9304, 0x00}, + {0x9305, 0x00}, + {0xa2a9, 0x60}, + {0xa2b7, 0x00}, + {0x0401, 0x00}, + {0x0404, 0x00}, + {0x0405, 0x10}, + {0x0408, 0x00}, + {0x0409, 0x00}, + {0x040a, 0x00}, + {0x040b, 0x00}, + {0x040c, 0x0f}, + {0x040d, 0xd8}, + {0x040e, 0x08}, + {0x040f, 0x70}, + {0x034c, 0x0f}, + {0x034d, 0xd8}, + {0x034e, 0x08}, + {0x034f, 0x70}, + {0x0305, 0x04}, + {0x0306, 0x01}, + {0x0307, 0x5e}, + {0xe04c, 0x00}, + {0xe04d, 0x7f}, + {0xe04e, 0x00}, + {0xe04f, 0x1f}, {0x3f56, 0x02}, {0x3f57, 0xae}, }; /* 2x2 binned. 40fps */ static const struct imx477_reg mode_2028x1520_regs[] = { - {0x0342, 0x31}, - {0x0343, 0xc4}, {0x0344, 0x00}, {0x0345, 0x00}, {0x0346, 0x00}, @@ -678,17 +748,8 @@ static const struct imx477_reg mode_2028x1520_regs[] = { {0x0349, 0xd7}, {0x034a, 0x0b}, {0x034b, 0xdf}, - {0x0220, 0x00}, - {0x0221, 0x11}, - {0x0381, 0x01}, - {0x0383, 0x01}, - {0x0385, 0x01}, - {0x0387, 0x01}, {0x0900, 0x01}, {0x0901, 0x22}, - {0x0902, 0x02}, - {0x3140, 0x02}, - {0x3c00, 0x00}, {0x3c01, 0x03}, {0x3c02, 0xa2}, {0x3f0d, 0x01}, @@ -702,12 +763,6 @@ static const struct imx477_reg mode_2028x1520_regs[] = { {0x936d, 0x5f}, {0x9304, 0x00}, {0x9305, 0x00}, - {0x9e9a, 0x2f}, - {0x9e9b, 0x2f}, - {0x9e9c, 0x2f}, - {0x9e9d, 0x00}, - {0x9e9e, 0x00}, - {0x9e9f, 0x00}, {0xa2a9, 0x60}, {0xa2b7, 0x00}, {0x0401, 0x00}, @@ -725,50 +780,19 @@ static const struct imx477_reg mode_2028x1520_regs[] = { {0x034d, 0xec}, {0x034e, 0x05}, {0x034f, 0xf0}, - {0x0301, 0x05}, - {0x0303, 0x02}, {0x0305, 0x04}, {0x0306, 0x01}, {0x0307, 0x5e}, - {0x0309, 0x0c}, - {0x030b, 0x02}, - {0x030d, 0x02}, - {0x0310, 0x01}, - {0x0820, 0x07}, - {0x0821, 0x08}, - {0x0822, 0x00}, - {0x0823, 0x00}, - {0x080a, 0x00}, - {0x080b, 0x7f}, - {0x080c, 0x00}, - {0x080d, 0x4f}, - {0x080e, 0x00}, - {0x080f, 0x77}, - {0x0810, 0x00}, - {0x0811, 0x5f}, - {0x0812, 0x00}, - {0x0813, 0x57}, - {0x0814, 0x00}, - {0x0815, 0x4f}, - {0x0816, 0x01}, - {0x0817, 0x27}, - {0x0818, 0x00}, - {0x0819, 0x3f}, {0xe04c, 0x00}, {0xe04d, 0x7f}, {0xe04e, 0x00}, {0xe04f, 0x1f}, - {0x3e20, 0x01}, - {0x3e37, 0x00}, - {0x3f50, 0x00}, {0x3f56, 0x01}, {0x3f57, 0x6c}, }; /* 1080p cropped mode */ static const struct imx477_reg mode_2028x1080_regs[] = { - {0x0342, 0x31}, - {0x0343, 0xc4}, {0x0344, 0x00}, {0x0345, 0x00}, {0x0346, 0x01}, @@ -777,17 +801,8 @@ static const struct imx477_reg mode_2028x1080_regs[] = { {0x0349, 0xd7}, {0x034a, 0x0a}, {0x034b, 0x27}, - {0x0220, 0x00}, - {0x0221, 0x11}, - {0x0381, 0x01}, - {0x0383, 0x01}, - {0x0385, 0x01}, - {0x0387, 0x01}, {0x0900, 0x01}, {0x0901, 0x22}, - {0x0902, 0x02}, - {0x3140, 0x02}, - {0x3c00, 0x00}, {0x3c01, 0x03}, {0x3c02, 0xa2}, {0x3f0d, 0x01}, @@ -801,12 +816,6 @@ static const struct imx477_reg mode_2028x1080_regs[] = { {0x936d, 0x5f}, {0x9304, 0x00}, {0x9305, 0x00}, - {0x9e9a, 0x2f}, - {0x9e9b, 0x2f}, - {0x9e9c, 0x2f}, - {0x9e9d, 0x00}, - {0x9e9e, 0x00}, - {0x9e9f, 0x00}, {0xa2a9, 0x60}, {0xa2b7, 0x00}, {0x0401, 0x00}, @@ -824,42 +833,13 @@ static const struct imx477_reg mode_2028x1080_regs[] = { {0x034d, 0xec}, {0x034e, 0x04}, {0x034f, 0x38}, - {0x0301, 0x05}, - {0x0303, 0x02}, {0x0305, 0x04}, {0x0306, 0x01}, {0x0307, 0x5e}, - {0x0309, 0x0c}, - {0x030b, 0x02}, - {0x030d, 0x02}, - {0x0310, 0x01}, - {0x0820, 0x07}, - {0x0821, 0x08}, - {0x0822, 0x00}, - {0x0823, 0x00}, - {0x080a, 0x00}, - {0x080b, 0x7f}, - {0x080c, 0x00}, - {0x080d, 0x4f}, - {0x080e, 0x00}, - {0x080f, 0x77}, - {0x0810, 0x00}, - {0x0811, 0x5f}, - {0x0812, 0x00}, - {0x0813, 0x57}, - {0x0814, 0x00}, - {0x0815, 0x4f}, - {0x0816, 0x01}, - {0x0817, 0x27}, - {0x0818, 0x00}, - {0x0819, 0x3f}, {0xe04c, 0x00}, {0xe04d, 0x7f}, {0xe04e, 0x00}, {0xe04f, 0x1f}, - {0x3e20, 0x01}, - {0x3e37, 0x00}, - {0x3f50, 0x00}, {0x3f56, 0x01}, {0x3f57, 0x6c}, }; @@ -878,13 +858,6 @@ static const struct imx477_reg mode_1332x990_regs[] = { {0x9a4b, 0x06}, {0x9a4c, 0x06}, {0x9a4d, 0x06}, - {0x0112, 0x0a}, - {0x0113, 0x0a}, - {0x0114, 0x01}, - {0x0342, 0x1a}, - {0x0343, 0x08}, - {0x0340, 0x04}, - {0x0341, 0x1a}, {0x0344, 0x00}, {0x0345, 0x00}, {0x0346, 0x02}, @@ -900,17 +873,8 @@ static const struct imx477_reg mode_1332x990_regs[] = { {0x00fe, 0x0a}, {0x00ff, 0x0a}, {0xe013, 0x00}, - {0x0220, 0x00}, - {0x0221, 0x11}, - {0x0381, 0x01}, - {0x0383, 0x01}, - {0x0385, 0x01}, - {0x0387, 0x01}, {0x0900, 0x01}, {0x0901, 0x22}, - {0x0902, 0x02}, - {0x3140, 0x02}, - {0x3c00, 0x00}, {0x3c01, 0x01}, {0x3c02, 0x9c}, {0x3f0d, 0x00}, @@ -929,12 +893,6 @@ static const struct imx477_reg mode_1332x990_regs[] = { {0x936d, 0x5f}, {0x9304, 0x03}, {0x9305, 0x80}, - {0x9e9a, 0x2f}, - {0x9e9b, 0x2f}, - {0x9e9c, 0x2f}, - {0x9e9d, 0x00}, - {0x9e9e, 0x00}, - {0x9e9f, 0x00}, {0xa2a9, 0x27}, {0xa2b7, 0x03}, {0x0401, 0x00}, @@ -952,91 +910,65 @@ static const struct imx477_reg mode_1332x990_regs[] = { {0x034d, 0x34}, {0x034e, 0x03}, {0x034f, 0xde}, - {0x0301, 0x05}, - {0x0303, 0x02}, {0x0305, 0x02}, {0x0306, 0x00}, {0x0307, 0xaf}, - {0x0309, 0x0a}, - {0x030b, 0x02}, - {0x030d, 0x02}, - {0x0310, 0x01}, - {0x0820, 0x07}, - {0x0821, 0x08}, - {0x0822, 0x00}, - {0x0823, 0x00}, - {0x080a, 0x00}, - {0x080b, 0x7f}, - {0x080c, 0x00}, - {0x080d, 0x4f}, - {0x080e, 0x00}, - {0x080f, 0x77}, - {0x0810, 0x00}, - {0x0811, 0x5f}, - {0x0812, 0x00}, - {0x0813, 0x57}, - {0x0814, 0x00}, - {0x0815, 0x4f}, - {0x0816, 0x01}, - {0x0817, 0x27}, - {0x0818, 0x00}, - {0x0819, 0x3f}, {0xe04c, 0x00}, {0xe04d, 0x5f}, {0xe04e, 0x00}, {0xe04f, 0x1f}, - {0x3e20, 0x01}, - {0x3e37, 0x00}, - {0x3f50, 0x00}, {0x3f56, 0x00}, {0x3f57, 0xbf}, }; /* Mode configs */ -static const struct imx477_mode supported_modes_12bit[] = { +static const struct imx477_mode supported_modes[] = { { /* 12MPix 10fps mode */ .width = 4056, .height = 3040, - .line_length_pix = 0x5dc0, + .line_length_pix = { 24000, 20000 }, .crop = { .left = IMX477_PIXEL_ARRAY_LEFT, .top = IMX477_PIXEL_ARRAY_TOP, .width = 4056, .height = 3040, }, - .timeperframe_min = { - .numerator = 100, - .denominator = 1000 - }, - .timeperframe_default = { - .numerator = 100, - .denominator = 1000 - }, + .framerate_default = 10, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_4056x3040_regs), .regs = mode_4056x3040_regs, }, }, + { + /* 12MPix cropped 16:9 mode */ + .width = 4056, + .height = 2160, + .line_length_pix = { 24000, 20000 }, + .crop = { + .left = IMX477_PIXEL_ARRAY_LEFT, + .top = IMX477_PIXEL_ARRAY_TOP + 440, + .width = 4056, + .height = 3040, + }, + .framerate_default = 10, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_4056x2160_regs), + .regs = mode_4056x2160_regs, + }, + }, { /* 2x2 binned 40fps mode */ .width = 2028, .height = 1520, - .line_length_pix = 0x31c4, + .line_length_pix = { 12740, 10616 }, .crop = { .left = IMX477_PIXEL_ARRAY_LEFT, .top = IMX477_PIXEL_ARRAY_TOP, .width = 4056, .height = 3040, }, - .timeperframe_min = { - .numerator = 100, - .denominator = 4000 - }, - .timeperframe_default = { - .numerator = 100, - .denominator = 3000 - }, + .framerate_default = 30, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_2028x1520_regs), .regs = mode_2028x1520_regs, @@ -1046,34 +978,24 @@ static const struct imx477_mode supported_modes_12bit[] = { /* 1080p 50fps cropped mode */ .width = 2028, .height = 1080, - .line_length_pix = 0x31c4, + .line_length_pix = { 12740, 10616 }, .crop = { .left = IMX477_PIXEL_ARRAY_LEFT, .top = IMX477_PIXEL_ARRAY_TOP + 440, .width = 4056, .height = 2160, }, - .timeperframe_min = { - .numerator = 100, - .denominator = 5000 - }, - .timeperframe_default = { - .numerator = 100, - .denominator = 3000 - }, + .framerate_default = 30, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_2028x1080_regs), .regs = mode_2028x1080_regs, }, - } -}; - -static const struct imx477_mode supported_modes_10bit[] = { + }, { /* 120fps. 2x2 binned and cropped */ .width = 1332, .height = 990, - .line_length_pix = 6664, + .line_length_pix = { 7997, 6664 }, .crop = { /* * FIXME: the analog crop rectangle is actually @@ -1088,14 +1010,7 @@ static const struct imx477_mode supported_modes_10bit[] = { .width = 2664, .height = 1980, }, - .timeperframe_min = { - .numerator = 100, - .denominator = 12000 - }, - .timeperframe_default = { - .numerator = 100, - .denominator = 12000 - }, + .framerate_default = 120, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1332x990_regs), .regs = mode_1332x990_regs, @@ -1206,6 +1121,17 @@ struct imx477 { /* Streaming on/off */ bool streaming; + /* Flags field from parsing the endpoint - used for (non)continuous + * clock mode + */ + unsigned int csi2_flags; + + /* + * Flag that CSI2 link is running at twice IMX477_DEFAULT_LINK_FREQ. + * line_length_pix can be halved in that case. + */ + bool double_link_freq; + /* Rewrite common registers on stream on? */ bool common_regs_written; @@ -1221,33 +1147,6 @@ static inline struct imx477 *to_imx477(struct v4l2_subdev *_sd) return container_of(_sd, struct imx477, sd); } -static inline void get_mode_table(unsigned int code, - const struct imx477_mode **mode_list, - unsigned int *num_modes) -{ - switch (code) { - /* 12-bit */ - case MEDIA_BUS_FMT_SRGGB12_1X12: - case MEDIA_BUS_FMT_SGRBG12_1X12: - case MEDIA_BUS_FMT_SGBRG12_1X12: - case MEDIA_BUS_FMT_SBGGR12_1X12: - *mode_list = supported_modes_12bit; - *num_modes = ARRAY_SIZE(supported_modes_12bit); - break; - /* 10-bit */ - case MEDIA_BUS_FMT_SRGGB10_1X10: - case MEDIA_BUS_FMT_SGRBG10_1X10: - case MEDIA_BUS_FMT_SGBRG10_1X10: - case MEDIA_BUS_FMT_SBGGR10_1X10: - *mode_list = supported_modes_10bit; - *num_modes = ARRAY_SIZE(supported_modes_10bit); - break; - default: - *mode_list = NULL; - *num_modes = 0; - } -} - /* Read registers up to 2 at a time */ static int imx477_read_reg(struct imx477 *imx477, u16 reg, u32 len, u32 *val) { @@ -1343,7 +1242,7 @@ static u32 imx477_get_format_code(struct imx477 *imx477, u32 code) static void imx477_set_default_format(struct imx477 *imx477) { /* Set default mode to max resolution */ - imx477->mode = &supported_modes_12bit[0]; + imx477->mode = &supported_modes[0]; imx477->fmt_code = MEDIA_BUS_FMT_SRGGB12_1X12; } @@ -1359,8 +1258,8 @@ static int imx477_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_lock(&imx477->mutex); /* Initialize try_fmt for the image pad */ - try_fmt_img->width = supported_modes_12bit[0].width; - try_fmt_img->height = supported_modes_12bit[0].height; + try_fmt_img->width = supported_modes[0].width; + try_fmt_img->height = supported_modes[0].height; try_fmt_img->code = imx477_get_format_code(imx477, MEDIA_BUS_FMT_SRGGB12_1X12); try_fmt_img->field = V4L2_FIELD_NONE; @@ -1541,12 +1440,7 @@ static int imx477_enum_frame_size(struct v4l2_subdev *sd, return -EINVAL; if (fse->pad == IMAGE_PAD) { - const struct imx477_mode *mode_list; - unsigned int num_modes; - - get_mode_table(fse->code, &mode_list, &num_modes); - - if (fse->index >= num_modes) + if (fse->index >= ARRAY_SIZE(supported_modes)) return -EINVAL; mutex_lock(&imx477->mutex); @@ -1556,9 +1450,9 @@ static int imx477_enum_frame_size(struct v4l2_subdev *sd, if (fse->code != code) return -EINVAL; - fse->min_width = mode_list[fse->index].width; + fse->min_width = supported_modes[fse->index].width; fse->max_width = fse->min_width; - fse->min_height = mode_list[fse->index].height; + fse->min_height = supported_modes[fse->index].height; fse->max_height = fse->min_height; } else { if (fse->code != MEDIA_BUS_FMT_SENSOR_DATA || fse->index > 0) @@ -1636,44 +1530,39 @@ static int imx477_get_pad_format(struct v4l2_subdev *sd, return 0; } -static -unsigned int imx477_get_frame_length(const struct imx477_mode *mode, - const struct v4l2_fract *timeperframe) -{ - u64 frame_length; - - frame_length = (u64)timeperframe->numerator * IMX477_PIXEL_RATE; - do_div(frame_length, - (u64)timeperframe->denominator * mode->line_length_pix); - - if (WARN_ON(frame_length > IMX477_FRAME_LENGTH_MAX)) - frame_length = IMX477_FRAME_LENGTH_MAX; - - return max_t(unsigned int, frame_length, mode->height); -} - static void imx477_set_framing_limits(struct imx477 *imx477) { - unsigned int frm_length_min, frm_length_default, hblank_min; + unsigned int hblank_min; const struct imx477_mode *mode = imx477->mode; - - frm_length_min = imx477_get_frame_length(mode, &mode->timeperframe_min); - frm_length_default = - imx477_get_frame_length(mode, &mode->timeperframe_default); + unsigned int line_length_pix; /* Default to no long exposure multiplier. */ imx477->long_exp_shift = 0; /* Update limits and set FPS to default */ - __v4l2_ctrl_modify_range(imx477->vblank, frm_length_min - mode->height, + __v4l2_ctrl_modify_range(imx477->vblank, 1, ((1 << IMX477_LONG_EXP_SHIFT_MAX) * IMX477_FRAME_LENGTH_MAX) - mode->height, - 1, frm_length_default - mode->height); - - /* Setting this will adjust the exposure limits as well. */ - __v4l2_ctrl_s_ctrl(imx477->vblank, frm_length_default - mode->height); + IMX477_VBLANK_MIN, IMX477_VBLANK_MIN); - hblank_min = mode->line_length_pix - mode->width; + switch (imx477->fmt_code) { + case MEDIA_BUS_FMT_SRGGB12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SBGGR12_1X12: + line_length_pix = mode->line_length_pix[0]; + break; + /* 10-bit */ + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SBGGR10_1X10: + line_length_pix = mode->line_length_pix[1]; + break; + } + if (imx477->double_link_freq) + line_length_pix /= 2; + hblank_min = line_length_pix - mode->width; __v4l2_ctrl_modify_range(imx477->hblank, hblank_min, IMX477_LINE_LENGTH_MAX, 1, hblank_min); __v4l2_ctrl_s_ctrl(imx477->hblank, hblank_min); @@ -1693,17 +1582,12 @@ static int imx477_set_pad_format(struct v4l2_subdev *sd, mutex_lock(&imx477->mutex); if (fmt->pad == IMAGE_PAD) { - const struct imx477_mode *mode_list; - unsigned int num_modes; - /* Bayer order varies with flips */ fmt->format.code = imx477_get_format_code(imx477, fmt->format.code); - get_mode_table(fmt->format.code, &mode_list, &num_modes); - - mode = v4l2_find_nearest_size(mode_list, - num_modes, + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), width, height, fmt->format.width, fmt->format.height); @@ -1712,7 +1596,8 @@ static int imx477_set_pad_format(struct v4l2_subdev *sd, framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); *framefmt = fmt->format; - } else if (imx477->mode != mode) { + } else if (imx477->mode != mode || + fmt->format.code != imx477->fmt_code) { imx477->mode = mode; imx477->fmt_code = fmt->format.code; imx477_set_framing_limits(imx477); @@ -1791,7 +1676,7 @@ static int imx477_start_streaming(struct imx477 *imx477) struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd); const struct imx477_reg_list *reg_list, *freq_regs; const struct imx477_reg_list *extra_regs; - int ret, tm; + int ret, tm, val; if (!imx477->common_regs_written) { ret = imx477_write_regs(imx477, mode_common_regs, @@ -1814,6 +1699,16 @@ static int imx477_start_streaming(struct imx477 *imx477) __func__); return ret; } + + imx477_write_reg(imx477, IMX477_REG_FRAME_BLANKSTOP_CLK, + IMX477_REG_VALUE_08BIT, + imx477->csi2_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK ? + 1 : 0); + + imx477_write_reg(imx477, IMX477_REG_DIV_IOP_PX, + IMX477_REG_VALUE_08BIT, + imx477->double_link_freq ? 1 : 2); + imx477->common_regs_written = true; } @@ -1825,6 +1720,28 @@ static int imx477_start_streaming(struct imx477 *imx477) return ret; } + switch (imx477->fmt_code) { + case MEDIA_BUS_FMT_SRGGB12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SBGGR12_1X12: + val = 0x0c; + break; + /* 10-bit */ + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SBGGR10_1X10: + val = 0x0a; + break; + } + imx477_write_reg(imx477, IMX477_REG_CSI_DT_FMT_H, + IMX477_REG_VALUE_08BIT, val); + imx477_write_reg(imx477, IMX477_REG_CSI_DT_FMT_L, + IMX477_REG_VALUE_08BIT, val); + imx477_write_reg(imx477, IMX477_REG_IOP_PXCK_DIV, + IMX477_REG_VALUE_08BIT, val); + /* Set on-sensor DPC. */ imx477_write_reg(imx477, 0x0b05, IMX477_REG_VALUE_08BIT, !!dpc_enable); imx477_write_reg(imx477, 0x0b06, IMX477_REG_VALUE_08BIT, !!dpc_enable); @@ -2081,6 +1998,7 @@ static int imx477_init_controls(struct imx477 *imx477) struct v4l2_ctrl_handler *ctrl_hdlr; struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd); struct v4l2_fwnode_device_properties props; + const u64 *link_freq_menu; unsigned int i; int ret; @@ -2102,10 +2020,15 @@ static int imx477_init_controls(struct imx477 *imx477) imx477->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; /* LINK_FREQ is also read only */ + if (imx477->double_link_freq) + link_freq_menu = &imx477_double_link_freq_menu[imx477->link_freq_idx]; + else + link_freq_menu = &imx477_link_freq_menu[imx477->link_freq_idx]; + imx477->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx477_ctrl_ops, V4L2_CID_LINK_FREQ, 0, 0, - &link_freqs[imx477->link_freq_idx]); + link_freq_menu); if (imx477->link_freq) imx477->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; @@ -2235,20 +2158,29 @@ static int imx477_check_hwcfg(struct device *dev, struct imx477 *imx477) goto error_out; } - for (i = 0; i < ARRAY_SIZE(link_freqs); i++) { - if (link_freqs[i] == ep_cfg.link_frequencies[0]) { + for (i = 0; i < ARRAY_SIZE(imx477_link_freq_menu); i++) { + if (imx477_link_freq_menu[i] == ep_cfg.link_frequencies[0] || + imx477_double_link_freq_menu[i] == + ep_cfg.link_frequencies[0]) { imx477->link_freq_idx = i; + + if (imx477_double_link_freq_menu[i] == + ep_cfg.link_frequencies[0]) + imx477->double_link_freq = true; + break; } } - if (i == ARRAY_SIZE(link_freqs)) { + if (i == ARRAY_SIZE(imx477_link_freq_menu)) { dev_err(dev, "Link frequency not supported: %lld\n", ep_cfg.link_frequencies[0]); ret = -EINVAL; goto error_out; } + imx477->csi2_flags = ep_cfg.bus.mipi_csi2.flags; + ret = 0; error_out: