diff options
author | Álvaro Fernández Rojas <noltari@gmail.com> | 2021-02-18 18:04:33 +0100 |
---|---|---|
committer | Álvaro Fernández Rojas <noltari@gmail.com> | 2021-02-18 23:42:32 +0100 |
commit | f07e572f6447465d8938679533d604e402b0f066 (patch) | |
tree | cb333bd2a67e59e7c07659514850a0fd55fc825e /target/linux/bcm27xx/patches-5.4/950-0820-media-i2c-imx290-Add-support-for-2-data-lanes.patch | |
parent | 5d3a6fd970619dfc55f8259035c3027d7613a2a6 (diff) | |
download | upstream-f07e572f6447465d8938679533d604e402b0f066.tar.gz upstream-f07e572f6447465d8938679533d604e402b0f066.tar.bz2 upstream-f07e572f6447465d8938679533d604e402b0f066.zip |
bcm27xx: import latest patches from the RPi foundation
bcm2708: boot tested on RPi B+ v1.2
bcm2709: boot tested on RPi 3B v1.2 and RPi 4B v1.1 4G
bcm2710: boot tested on RPi 3B v1.2
bcm2711: boot tested on RPi 4B v1.1 4G
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Diffstat (limited to 'target/linux/bcm27xx/patches-5.4/950-0820-media-i2c-imx290-Add-support-for-2-data-lanes.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.4/950-0820-media-i2c-imx290-Add-support-for-2-data-lanes.patch | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0820-media-i2c-imx290-Add-support-for-2-data-lanes.patch b/target/linux/bcm27xx/patches-5.4/950-0820-media-i2c-imx290-Add-support-for-2-data-lanes.patch new file mode 100644 index 0000000000..68b89999c5 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0820-media-i2c-imx290-Add-support-for-2-data-lanes.patch @@ -0,0 +1,314 @@ +From 78d867300b5026ab31c9a3fbd37b6590b7940f66 Mon Sep 17 00:00:00 2001 +From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> +Date: Fri, 12 Jun 2020 15:53:49 +0200 +Subject: [PATCH] media: i2c: imx290: Add support for 2 data lanes + +Commit 97589ad61c730e0f486635c6c19fa25ab8e8f29d upstream. + +The IMX290 sensor can output frames with 2/4 CSI2 data lanes. This commit +adds support for 2 lane mode in addition to the 4 lane and also +configuring the data lane settings in the driver based on system +configuration. + +Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> +Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org> +Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> +Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> +--- + drivers/media/i2c/imx290.c | 147 +++++++++++++++++++++++++++++++++---- + 1 file changed, 133 insertions(+), 14 deletions(-) + +--- a/drivers/media/i2c/imx290.c ++++ b/drivers/media/i2c/imx290.c +@@ -25,7 +25,12 @@ + #define IMX290_STANDBY 0x3000 + #define IMX290_REGHOLD 0x3001 + #define IMX290_XMSTA 0x3002 ++#define IMX290_FR_FDG_SEL 0x3009 + #define IMX290_GAIN 0x3014 ++#define IMX290_HMAX_LOW 0x301c ++#define IMX290_HMAX_HIGH 0x301d ++#define IMX290_PHY_LANE_NUM 0x3407 ++#define IMX290_CSI_LANE_MODE 0x3443 + + #define IMX290_DEFAULT_LINK_FREQ 445500000 + +@@ -45,6 +50,7 @@ struct imx290_regval { + struct imx290_mode { + u32 width; + u32 height; ++ u32 hmax; + u32 pixel_rate; + u32 link_freq_index; + +@@ -56,6 +62,7 @@ struct imx290 { + struct device *dev; + struct clk *xclk; + struct regmap *regmap; ++ u8 nlanes; + + struct v4l2_subdev sd; + struct v4l2_fwnode_endpoint ep; +@@ -89,14 +96,11 @@ static const struct regmap_config imx290 + + static const struct imx290_regval imx290_global_init_settings[] = { + { 0x3007, 0x00 }, +- { 0x3009, 0x00 }, + { 0x3018, 0x65 }, + { 0x3019, 0x04 }, + { 0x301a, 0x00 }, +- { 0x3443, 0x03 }, + { 0x3444, 0x20 }, + { 0x3445, 0x25 }, +- { 0x3407, 0x03 }, + { 0x303a, 0x0c }, + { 0x3040, 0x00 }, + { 0x3041, 0x00 }, +@@ -169,7 +173,6 @@ static const struct imx290_regval imx290 + { 0x3164, 0x1a }, + { 0x3480, 0x49 }, + /* data rate settings */ +- { 0x3009, 0x01 }, + { 0x3405, 0x10 }, + { 0x3446, 0x57 }, + { 0x3447, 0x00 }, +@@ -187,8 +190,6 @@ static const struct imx290_regval imx290 + { 0x3453, 0x00 }, + { 0x3454, 0x17 }, + { 0x3455, 0x00 }, +- { 0x301c, 0x98 }, +- { 0x301d, 0x08 }, + }; + + static const struct imx290_regval imx290_720p_settings[] = { +@@ -210,7 +211,6 @@ static const struct imx290_regval imx290 + { 0x3164, 0x1a }, + { 0x3480, 0x49 }, + /* data rate settings */ +- { 0x3009, 0x01 }, + { 0x3405, 0x10 }, + { 0x3446, 0x4f }, + { 0x3447, 0x00 }, +@@ -228,8 +228,6 @@ static const struct imx290_regval imx290 + { 0x3453, 0x00 }, + { 0x3454, 0x17 }, + { 0x3455, 0x00 }, +- { 0x301c, 0xe4 }, +- { 0x301d, 0x0c }, + }; + + static const struct imx290_regval imx290_10bit_settings[] = { +@@ -250,10 +248,11 @@ static const s64 imx290_link_freq[] = { + }; + + /* Mode configs */ +-static const struct imx290_mode imx290_modes[] = { ++static const struct imx290_mode imx290_modes_2lanes[] = { + { + .width = 1920, + .height = 1080, ++ .hmax = 0x1130, + .data = imx290_1080p_settings, + .data_size = ARRAY_SIZE(imx290_1080p_settings), + .pixel_rate = 178200000, +@@ -262,6 +261,7 @@ static const struct imx290_mode imx290_m + { + .width = 1280, + .height = 720, ++ .hmax = 0x19c8, + .data = imx290_720p_settings, + .data_size = ARRAY_SIZE(imx290_720p_settings), + .pixel_rate = 178200000, +@@ -269,6 +269,44 @@ static const struct imx290_mode imx290_m + }, + }; + ++static const struct imx290_mode imx290_modes_4lanes[] = { ++ { ++ .width = 1920, ++ .height = 1080, ++ .hmax = 0x0898, ++ .data = imx290_1080p_settings, ++ .data_size = ARRAY_SIZE(imx290_1080p_settings), ++ .pixel_rate = 178200000, ++ .link_freq_index = 0, ++ }, ++ { ++ .width = 1280, ++ .height = 720, ++ .hmax = 0x0ce4, ++ .data = imx290_720p_settings, ++ .data_size = ARRAY_SIZE(imx290_720p_settings), ++ .pixel_rate = 178200000, ++ .link_freq_index = 0, ++ }, ++}; ++ ++static inline const struct imx290_mode *imx290_modes_ptr(const struct imx290 *imx290) ++{ ++ /* We rely on imx290_probe() to ensure that nlanes is either 2 or 4 */ ++ if (imx290->nlanes == 2) ++ return imx290_modes_2lanes; ++ else ++ return imx290_modes_4lanes; ++} ++ ++static inline int imx290_modes_num(const struct imx290 *imx290) ++{ ++ if (imx290->nlanes == 2) ++ return ARRAY_SIZE(imx290_modes_2lanes); ++ else ++ return ARRAY_SIZE(imx290_modes_4lanes); ++} ++ + static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) + { + return container_of(_sd, struct imx290, sd); +@@ -450,9 +488,8 @@ static int imx290_set_fmt(struct v4l2_su + + mutex_lock(&imx290->lock); + +- mode = v4l2_find_nearest_size(imx290_modes, +- ARRAY_SIZE(imx290_modes), +- width, height, ++ mode = v4l2_find_nearest_size(imx290_modes_ptr(imx290), ++ imx290_modes_num(imx290), width, height, + fmt->format.width, fmt->format.height); + + fmt->format.width = mode->width; +@@ -522,6 +559,25 @@ static int imx290_write_current_format(s + return 0; + } + ++static int imx290_set_hmax(struct imx290 *imx290, u32 val) ++{ ++ int ret; ++ ++ ret = imx290_write_reg(imx290, IMX290_HMAX_LOW, (val & 0xff)); ++ if (ret) { ++ dev_err(imx290->dev, "Error setting HMAX register\n"); ++ return ret; ++ } ++ ++ ret = imx290_write_reg(imx290, IMX290_HMAX_HIGH, ((val >> 8) & 0xff)); ++ if (ret) { ++ dev_err(imx290->dev, "Error setting HMAX register\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ + /* Start streaming */ + static int imx290_start_streaming(struct imx290 *imx290) + { +@@ -550,6 +606,9 @@ static int imx290_start_streaming(struct + dev_err(imx290->dev, "Could not set current mode\n"); + return ret; + } ++ ret = imx290_set_hmax(imx290, imx290->current_mode->hmax); ++ if (ret < 0) ++ return ret; + + /* Apply customized values from user */ + ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); +@@ -607,6 +666,49 @@ 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 i2c_client *client = to_i2c_client(dev); +@@ -631,6 +733,9 @@ 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; + } + +@@ -677,6 +782,7 @@ static int imx290_probe(struct i2c_clien + struct fwnode_handle *endpoint; + struct imx290 *imx290; + u32 xclk_freq; ++ u32 default_pixel_rate; + int ret; + + imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL); +@@ -703,6 +809,16 @@ static int imx290_probe(struct i2c_clien + goto free_err; + } + ++ /* Get number of data lanes */ ++ imx290->nlanes = imx290->ep.bus.mipi_csi2.num_data_lanes; ++ if (imx290->nlanes != 2 && imx290->nlanes != 4) { ++ dev_err(dev, "Invalid data lanes: %d\n", imx290->nlanes); ++ ret = -EINVAL; ++ goto free_err; ++ } ++ ++ dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes); ++ + if (!imx290->ep.nr_of_link_frequencies) { + dev_err(dev, "link-frequency property not found in DT\n"); + ret = -EINVAL; +@@ -780,10 +896,13 @@ static int imx290_probe(struct i2c_clien + if (imx290->link_freq) + imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + ++ default_pixel_rate = imx290->nlanes == 2 ? ++ imx290_modes_2lanes[0].pixel_rate : ++ imx290_modes_4lanes[0].pixel_rate; + imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_PIXEL_RATE, 1, + INT_MAX, 1, +- imx290_modes[0].pixel_rate); ++ default_pixel_rate); + + imx290->sd.ctrl_handler = &imx290->ctrls; + |