diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index 0dbf4b5101f19e..ca1a489191e514 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -2857,6 +2857,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: imx462 @@ -2901,6 +2902,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 17d5b4aa204211..4da523b2390e05 100644 --- a/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi +++ b/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi @@ -81,6 +81,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 317f9adf9f6ba2..4ef886ace8d135 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 @@ -112,6 +119,8 @@ MODULE_PARM_DESC(trigger_mode, "Set vsync trigger mode: 1=source, 2=sink"); #define IMX477_REG_XVS_IO_CTRL 0x3040 #define IMX477_REG_EXTOUT_EN 0x4b81 +#define IMX477_REG_FRAME_BLANKSTOP_CLK 0xE000 + /* Embedded metadata stream structure */ #define IMX477_EMBEDDED_LINE_WIDTH 16384 #define IMX477_NUM_EMBEDDED_LINES 1 @@ -148,17 +157,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; @@ -171,12 +180,18 @@ enum { IMX477_LINK_FREQ_456MHZ, }; -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, }; +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}, @@ -212,7 +227,6 @@ static const struct imx477_reg mode_common_regs[] = { {0x0136, 0x18}, {0x0137, 0x00}, {0x0138, 0x01}, - {0xe000, 0x00}, {0xe07a, 0x01}, {0x0808, 0x02}, {0x4ae9, 0x18}, @@ -512,18 +526,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}, @@ -538,17 +590,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}, @@ -567,12 +610,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}, @@ -590,50 +627,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}, @@ -642,17 +712,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}, @@ -666,12 +727,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}, @@ -689,50 +744,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}, @@ -741,17 +765,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}, @@ -765,12 +780,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}, @@ -788,42 +797,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}, }; @@ -842,13 +822,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}, @@ -864,17 +837,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}, @@ -893,12 +857,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}, @@ -916,91 +874,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, @@ -1010,34 +942,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 @@ -1052,14 +974,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, @@ -1170,6 +1085,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; @@ -1185,33 +1111,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) { @@ -1307,7 +1206,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; } @@ -1323,8 +1222,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; @@ -1502,20 +1401,15 @@ 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; if (fse->code != imx477_get_format_code(imx477, fse->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) @@ -1593,44 +1487,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); @@ -1650,17 +1539,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); @@ -1669,7 +1553,8 @@ static int imx477_set_pad_format(struct v4l2_subdev *sd, framefmt = v4l2_subdev_get_try_format(sd, 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); @@ -1748,7 +1633,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, @@ -1771,6 +1656,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; } @@ -1782,6 +1677,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); @@ -2028,6 +1945,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; @@ -2049,10 +1967,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; @@ -2182,20 +2105,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: