diff options
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.patch | 309 |
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); + |