aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.15/950-0407-media-i2c-imx290-Support-60fps-in-2-lane-operation.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/bcm27xx/patches-5.15/950-0407-media-i2c-imx290-Support-60fps-in-2-lane-operation.patch')
-rw-r--r--target/linux/bcm27xx/patches-5.15/950-0407-media-i2c-imx290-Support-60fps-in-2-lane-operation.patch309
1 files changed, 309 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.15/950-0407-media-i2c-imx290-Support-60fps-in-2-lane-operation.patch b/target/linux/bcm27xx/patches-5.15/950-0407-media-i2c-imx290-Support-60fps-in-2-lane-operation.patch
new file mode 100644
index 0000000000..454e50932b
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.15/950-0407-media-i2c-imx290-Support-60fps-in-2-lane-operation.patch
@@ -0,0 +1,309 @@
+From 9a1509cc97e4329475cbd0c45258dcdf5d49a7f1 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Thu, 17 Jun 2021 12:05:25 +0100
+Subject: [PATCH] media: i2c: imx290: Support 60fps in 2 lane operation
+
+Commit "97589ad61c73 media: i2c: imx290: Add support for 2 data lanes"
+added support for running in two lane mode (instead of 4), but
+without changing the link frequency that resulted in a max of 30fps.
+
+Commit "98e0500eadb7 media: i2c: imx290: Add configurable link frequency
+and pixel rate" then doubled the link frequency when in 2 lane mode,
+but didn't undo the correction for running at only 30fps, just extending
+horizontal blanking instead.
+It also didn't update the CSI timing registers in accordance with the
+datasheet.
+
+Remove the 30fps limit on 2 lane by correcting the register config
+in accordance with the datasheet for 60fps operation over 2 lanes.
+Frame rate control (via V4L2_CID_VBLANK or HBLANK) can still reduce
+the frame rate on 2 lanes back to 30fps.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/media/i2c/imx290.c | 163 ++++++++++++++++++++++---------------
+ 1 file changed, 97 insertions(+), 66 deletions(-)
+
+--- a/drivers/media/i2c/imx290.c
++++ b/drivers/media/i2c/imx290.c
+@@ -46,8 +46,7 @@ enum imx290_clk_index {
+ #define IMX290_VMAX_MAX 0x3fff
+ #define IMX290_HMAX_LOW 0x301c
+ #define IMX290_HMAX_HIGH 0x301d
+-#define IMX290_HMAX_MIN_2LANE 4400 /* Min of 4400 pixels = 30fps */
+-#define IMX290_HMAX_MIN_4LANE 2200 /* Min of 2200 pixels = 60fps */
++#define IMX290_HMAX_MIN 2200 /* Min of 2200 pixels = 60fps */
+ #define IMX290_HMAX_MAX 0xffff
+
+ #define IMX290_EXPOSURE_MIN 1
+@@ -89,8 +88,11 @@ struct imx290_mode {
+ u8 link_freq_index;
+ struct v4l2_rect crop;
+
+- const struct imx290_regval *data;
+- u32 data_size;
++ const struct imx290_regval *mode_data;
++ u32 mode_data_size;
++ const struct imx290_regval *lane_data;
++ u32 lane_data_size;
++
+
+ /* Clock setup can vary. Index as enum imx290_clk_index */
+ const struct imx290_regval *clk_data[2];
+@@ -242,8 +244,9 @@ static const struct imx290_regval imx290
+ { 0x3480, 0x92 },
+ };
+
+-static const struct imx290_regval imx290_1080p_settings[] = {
++static const struct imx290_regval imx290_1080p_common_settings[] = {
+ /* mode settings */
++ { IMX290_FR_FDG_SEL, 0x01 },
+ { 0x3007, 0x00 },
+ { 0x303a, 0x0c },
+ { 0x3414, 0x0a },
+@@ -253,8 +256,36 @@ static const struct imx290_regval imx290
+ { 0x3419, 0x04 },
+ { 0x3012, 0x64 },
+ { 0x3013, 0x00 },
++};
++
++static const struct imx290_regval imx290_1080p_2lane_settings[] = {
++ { 0x3405, 0x00 },
+ /* data rate settings */
++ { IMX290_PHY_LANE_NUM, 0x01 },
++ { IMX290_CSI_LANE_MODE, 0x01 },
++ { 0x3446, 0x77 },
++ { 0x3447, 0x00 },
++ { 0x3448, 0x67 },
++ { 0x3449, 0x00 },
++ { 0x344a, 0x47 },
++ { 0x344b, 0x00 },
++ { 0x344c, 0x37 },
++ { 0x344d, 0x00 },
++ { 0x344e, 0x3f },
++ { 0x344f, 0x00 },
++ { 0x3450, 0xff },
++ { 0x3451, 0x00 },
++ { 0x3452, 0x3f },
++ { 0x3453, 0x00 },
++ { 0x3454, 0x37 },
++ { 0x3455, 0x00 },
++};
++
++static const struct imx290_regval imx290_1080p_4lane_settings[] = {
+ { 0x3405, 0x10 },
++ /* data rate settings */
++ { IMX290_PHY_LANE_NUM, 0x03 },
++ { IMX290_CSI_LANE_MODE, 0x03 },
+ { 0x3446, 0x57 },
+ { 0x3447, 0x00 },
+ { 0x3448, 0x37 },
+@@ -297,8 +328,9 @@ static const struct imx290_regval imx290
+ { 0x3480, 0x92 },
+ };
+
+-static const struct imx290_regval imx290_720p_settings[] = {
++static const struct imx290_regval imx290_720p_common_settings[] = {
+ /* mode settings */
++ { IMX290_FR_FDG_SEL, 0x01 },
+ { 0x3007, 0x10 },
+ { 0x303a, 0x06 },
+ { 0x3414, 0x04 },
+@@ -308,8 +340,36 @@ static const struct imx290_regval imx290
+ { 0x3419, 0x02 },
+ { 0x3012, 0x64 },
+ { 0x3013, 0x00 },
++};
++
++static const struct imx290_regval imx290_720p_2lane_settings[] = {
++ { 0x3405, 0x00 },
++ { IMX290_PHY_LANE_NUM, 0x01 },
++ { IMX290_CSI_LANE_MODE, 0x01 },
+ /* data rate settings */
++ { 0x3446, 0x67 },
++ { 0x3447, 0x00 },
++ { 0x3448, 0x57 },
++ { 0x3449, 0x00 },
++ { 0x344a, 0x2f },
++ { 0x344b, 0x00 },
++ { 0x344c, 0x27 },
++ { 0x344d, 0x00 },
++ { 0x344e, 0x2f },
++ { 0x344f, 0x00 },
++ { 0x3450, 0xbf },
++ { 0x3451, 0x00 },
++ { 0x3452, 0x2f },
++ { 0x3453, 0x00 },
++ { 0x3454, 0x27 },
++ { 0x3455, 0x00 },
++};
++
++static const struct imx290_regval imx290_720p_4lane_settings[] = {
+ { 0x3405, 0x10 },
++ { IMX290_PHY_LANE_NUM, 0x03 },
++ { IMX290_CSI_LANE_MODE, 0x03 },
++ /* data rate settings */
+ { 0x3446, 0x4f },
+ { 0x3447, 0x00 },
+ { 0x3448, 0x2f },
+@@ -389,7 +449,7 @@ static const struct imx290_mode imx290_m
+ {
+ .width = 1920,
+ .height = 1080,
+- .hmax = 0x1130,
++ .hmax = 0x0898,
+ .vmax = 0x0465,
+ .link_freq_index = FREQ_INDEX_1080P,
+ .crop = {
+@@ -398,8 +458,10 @@ static const struct imx290_mode imx290_m
+ .width = 1920,
+ .height = 1080,
+ },
+- .data = imx290_1080p_settings,
+- .data_size = ARRAY_SIZE(imx290_1080p_settings),
++ .mode_data = imx290_1080p_common_settings,
++ .mode_data_size = ARRAY_SIZE(imx290_1080p_common_settings),
++ .lane_data = imx290_1080p_2lane_settings,
++ .lane_data_size = ARRAY_SIZE(imx290_1080p_2lane_settings),
+ .clk_data = {
+ [CLK_37_125] = imx290_37_125mhz_clock_1080p,
+ [CLK_74_25] = imx290_74_250mhz_clock_1080p,
+@@ -409,7 +471,7 @@ static const struct imx290_mode imx290_m
+ {
+ .width = 1280,
+ .height = 720,
+- .hmax = 0x19c8,
++ .hmax = 0x0ce4,
+ .vmax = 0x02ee,
+ .link_freq_index = FREQ_INDEX_720P,
+ .crop = {
+@@ -418,8 +480,10 @@ static const struct imx290_mode imx290_m
+ .width = 1280,
+ .height = 720,
+ },
+- .data = imx290_720p_settings,
+- .data_size = ARRAY_SIZE(imx290_720p_settings),
++ .mode_data = imx290_720p_common_settings,
++ .mode_data_size = ARRAY_SIZE(imx290_720p_common_settings),
++ .lane_data = imx290_720p_2lane_settings,
++ .lane_data_size = ARRAY_SIZE(imx290_720p_2lane_settings),
+ .clk_data = {
+ [CLK_37_125] = imx290_37_125mhz_clock_1080p,
+ [CLK_74_25] = imx290_74_250mhz_clock_1080p,
+@@ -441,8 +505,10 @@ static const struct imx290_mode imx290_m
+ .width = 1920,
+ .height = 1080,
+ },
+- .data = imx290_1080p_settings,
+- .data_size = ARRAY_SIZE(imx290_1080p_settings),
++ .mode_data = imx290_1080p_common_settings,
++ .mode_data_size = ARRAY_SIZE(imx290_1080p_common_settings),
++ .lane_data = imx290_1080p_4lane_settings,
++ .lane_data_size = ARRAY_SIZE(imx290_1080p_4lane_settings),
+ .clk_data = {
+ [CLK_37_125] = imx290_37_125mhz_clock_720p,
+ [CLK_74_25] = imx290_74_250mhz_clock_720p,
+@@ -461,8 +527,10 @@ static const struct imx290_mode imx290_m
+ .width = 1280,
+ .height = 720,
+ },
+- .data = imx290_720p_settings,
+- .data_size = ARRAY_SIZE(imx290_720p_settings),
++ .mode_data = imx290_720p_common_settings,
++ .mode_data_size = ARRAY_SIZE(imx290_720p_common_settings),
++ .lane_data = imx290_720p_4lane_settings,
++ .lane_data_size = ARRAY_SIZE(imx290_720p_4lane_settings),
+ .clk_data = {
+ [CLK_37_125] = imx290_37_125mhz_clock_720p,
+ [CLK_74_25] = imx290_74_250mhz_clock_720p,
+@@ -1016,8 +1084,18 @@ static int imx290_start_streaming(struct
+ }
+
+ /* Apply default values of current mode */
+- ret = imx290_set_register_array(imx290, imx290->current_mode->data,
+- imx290->current_mode->data_size);
++ ret = imx290_set_register_array(imx290,
++ imx290->current_mode->mode_data,
++ imx290->current_mode->mode_data_size);
++ if (ret < 0) {
++ dev_err(imx290->dev, "Could not set current mode\n");
++ return ret;
++ }
++
++ /* Apply lane config registers of current mode */
++ ret = imx290_set_register_array(imx290,
++ imx290->current_mode->lane_data,
++ imx290->current_mode->lane_data_size);
+ if (ret < 0) {
+ dev_err(imx290->dev, "Could not set current mode\n");
+ return ret;
+@@ -1080,49 +1158,6 @@ static int imx290_get_regulators(struct
+ imx290->supplies);
+ }
+
+-static int imx290_set_data_lanes(struct imx290 *imx290)
+-{
+- int ret = 0, laneval, frsel;
+-
+- switch (imx290->nlanes) {
+- case 2:
+- laneval = 0x01;
+- frsel = 0x02;
+- break;
+- case 4:
+- laneval = 0x03;
+- frsel = 0x01;
+- break;
+- default:
+- /*
+- * We should never hit this since the data lane count is
+- * validated in probe itself
+- */
+- dev_err(imx290->dev, "Lane configuration not supported\n");
+- ret = -EINVAL;
+- goto exit;
+- }
+-
+- ret = imx290_write_reg(imx290, IMX290_PHY_LANE_NUM, laneval);
+- if (ret) {
+- dev_err(imx290->dev, "Error setting Physical Lane number register\n");
+- goto exit;
+- }
+-
+- ret = imx290_write_reg(imx290, IMX290_CSI_LANE_MODE, laneval);
+- if (ret) {
+- dev_err(imx290->dev, "Error setting CSI Lane mode register\n");
+- goto exit;
+- }
+-
+- ret = imx290_write_reg(imx290, IMX290_FR_FDG_SEL, frsel);
+- if (ret)
+- dev_err(imx290->dev, "Error setting FR/FDG SEL register\n");
+-
+-exit:
+- return ret;
+-}
+-
+ static int imx290_power_on(struct device *dev)
+ {
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+@@ -1146,9 +1181,6 @@ static int imx290_power_on(struct device
+ gpiod_set_value_cansleep(imx290->rst_gpio, 0);
+ usleep_range(30000, 31000);
+
+- /* Set data lane count */
+- imx290_set_data_lanes(imx290);
+-
+ return 0;
+ }
+
+@@ -1271,8 +1303,7 @@ static int imx290_probe(struct i2c_clien
+ ret = -EINVAL;
+ goto free_err;
+ }
+- imx290->hmax_min = (imx290->nlanes == 2) ? IMX290_HMAX_MIN_2LANE :
+- IMX290_HMAX_MIN_4LANE;
++ imx290->hmax_min = IMX290_HMAX_MIN;
+
+ dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes);
+