Message ID | 20230530173000.3060865-10-dave.stevenson@raspberrypi.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | imx258 improvements series | expand |
On Tue, 30 May 2023 at 18:30, Dave Stevenson <dave.stevenson@raspberrypi.com> wrote: > > Extends the driver to also support 2 data lanes. > Frame rates are obviously more restricted on 2 lanes, but some > hardware simply hasn't wired more up. > > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com> > --- > drivers/media/i2c/imx258.c | 211 ++++++++++++++++++++++++++++++++----- > 1 file changed, 187 insertions(+), 24 deletions(-) > > diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c > index d40521f9a3c6..433dff7f1fa0 100644 > --- a/drivers/media/i2c/imx258.c > +++ b/drivers/media/i2c/imx258.c > @@ -86,13 +86,17 @@ struct imx258_reg_list { > const struct imx258_reg *regs; > }; > > +#define IMX258_LANE_CONFIGS 2 > +#define IMX258_2_LANE_MODE 0 > +#define IMX258_4_LANE_MODE 1 > + > /* Link frequency config */ > struct imx258_link_freq_config { > u64 link_frequency; > u32 pixels_per_line; > > /* PLL registers for this link frequency */ > - struct imx258_reg_list reg_list; > + struct imx258_reg_list reg_list[IMX258_LANE_CONFIGS]; > }; > > /* Mode : resolution and related config&values */ > @@ -112,8 +116,30 @@ struct imx258_mode { > struct imx258_reg_list reg_list; > }; > > -/* 4208x3120 needs 1267Mbps/lane, 4 lanes */ > -static const struct imx258_reg mipi_1267mbps_19_2mhz[] = { > +/* 4208x3120 needs 1267Mbps/lane, 4 lanes. Use that rate on 2 lanes as well */ > +static const struct imx258_reg mipi_1267mbps_19_2mhz_2l[] = { > + { 0x0136, 0x13 }, > + { 0x0137, 0x33 }, > + { 0x0301, 0x0A }, > + { 0x0303, 0x02 }, > + { 0x0305, 0x03 }, > + { 0x0306, 0x00 }, > + { 0x0307, 0xC6 }, > + { 0x0309, 0x0A }, > + { 0x030B, 0x01 }, > + { 0x030D, 0x02 }, > + { 0x030E, 0x00 }, > + { 0x030F, 0xD8 }, > + { 0x0310, 0x00 }, > + > + { 0x0114, 0x01 }, > + { 0x0820, 0x09 }, > + { 0x0821, 0xa6 }, > + { 0x0822, 0x66 }, > + { 0x0823, 0x66 }, > +}; > + > +static const struct imx258_reg mipi_1267mbps_19_2mhz_4l[] = { > { 0x0136, 0x13 }, > { 0x0137, 0x33 }, > { 0x0301, 0x05 }, > @@ -127,16 +153,18 @@ static const struct imx258_reg mipi_1267mbps_19_2mhz[] = { > { 0x030E, 0x00 }, > { 0x030F, 0xD8 }, > { 0x0310, 0x00 }, > + > + { 0x0114, 0x03 }, > { 0x0820, 0x13 }, > { 0x0821, 0x4C }, > { 0x0822, 0xCC }, > { 0x0823, 0xCC }, > }; > > -static const struct imx258_reg mipi_1272mbps_24mhz[] = { > +static const struct imx258_reg mipi_1272mbps_24mhz_2l[] = { > { 0x0136, 0x18 }, > { 0x0137, 0x00 }, > - { 0x0301, 0x05 }, > + { 0x0301, 0x0a }, > { 0x0303, 0x02 }, > { 0x0305, 0x04 }, > { 0x0306, 0x00 }, > @@ -147,13 +175,59 @@ static const struct imx258_reg mipi_1272mbps_24mhz[] = { > { 0x030E, 0x00 }, > { 0x030F, 0xD8 }, > { 0x0310, 0x00 }, > + > + { 0x0114, 0x01 }, > { 0x0820, 0x13 }, > { 0x0821, 0x4C }, > { 0x0822, 0xCC }, > { 0x0823, 0xCC }, > }; > > -static const struct imx258_reg mipi_640mbps_19_2mhz[] = { > +static const struct imx258_reg mipi_1272mbps_24mhz_4l[] = { > + { 0x0136, 0x18 }, > + { 0x0137, 0x00 }, > + { 0x0301, 0x05 }, > + { 0x0303, 0x02 }, > + { 0x0305, 0x04 }, > + { 0x0306, 0x00 }, > + { 0x0307, 0xD4 }, > + { 0x0309, 0x0A }, > + { 0x030B, 0x01 }, > + { 0x030D, 0x02 }, > + { 0x030E, 0x00 }, > + { 0x030F, 0xD8 }, > + { 0x0310, 0x00 }, > + > + { 0x0114, 0x03 }, > + { 0x0820, 0x13 }, > + { 0x0821, 0xE0 }, > + { 0x0822, 0x00 }, > + { 0x0823, 0x00 }, > +}; > + > +static const struct imx258_reg mipi_640mbps_19_2mhz_2l[] = { > + { 0x0136, 0x13 }, > + { 0x0137, 0x33 }, > + { 0x0301, 0x05 }, > + { 0x0303, 0x02 }, > + { 0x0305, 0x03 }, > + { 0x0306, 0x00 }, > + { 0x0307, 0x64 }, > + { 0x0309, 0x0A }, > + { 0x030B, 0x01 }, > + { 0x030D, 0x02 }, > + { 0x030E, 0x00 }, > + { 0x030F, 0xD8 }, > + { 0x0310, 0x00 }, > + > + { 0x0114, 0x01 }, > + { 0x0820, 0x05 }, > + { 0x0821, 0x00 }, > + { 0x0822, 0x00 }, > + { 0x0823, 0x00 }, > +}; > + > +static const struct imx258_reg mipi_640mbps_19_2mhz_4l[] = { > { 0x0136, 0x13 }, > { 0x0137, 0x33 }, > { 0x0301, 0x05 }, > @@ -167,13 +241,37 @@ static const struct imx258_reg mipi_640mbps_19_2mhz[] = { > { 0x030E, 0x00 }, > { 0x030F, 0xD8 }, > { 0x0310, 0x00 }, > + > + { 0x0114, 0x03 }, > { 0x0820, 0x0A }, > { 0x0821, 0x00 }, > { 0x0822, 0x00 }, > { 0x0823, 0x00 }, > }; > > -static const struct imx258_reg mipi_642mbps_24mhz[] = { > +static const struct imx258_reg mipi_642mbps_24mhz_2l[] = { > + { 0x0136, 0x18 }, > + { 0x0137, 0x00 }, > + { 0x0301, 0x0A }, > + { 0x0303, 0x02 }, > + { 0x0305, 0x04 }, > + { 0x0306, 0x00 }, > + { 0x0307, 0x6B }, > + { 0x0309, 0x0A }, > + { 0x030B, 0x01 }, > + { 0x030D, 0x02 }, > + { 0x030E, 0x00 }, > + { 0x030F, 0xD8 }, > + { 0x0310, 0x00 }, > + > + { 0x0114, 0x01 }, > + { 0x0820, 0x0A }, > + { 0x0821, 0x00 }, > + { 0x0822, 0x00 }, > + { 0x0823, 0x00 }, > +}; > + > +static const struct imx258_reg mipi_642mbps_24mhz_4l[] = { > { 0x0136, 0x18 }, > { 0x0137, 0x00 }, > { 0x0301, 0x05 }, > @@ -187,6 +285,8 @@ static const struct imx258_reg mipi_642mbps_24mhz[] = { > { 0x030E, 0x00 }, > { 0x030F, 0xD8 }, > { 0x0310, 0x00 }, > + > + { 0x0114, 0x03 }, > { 0x0820, 0x0A }, > { 0x0821, 0x00 }, > { 0x0822, 0x00 }, > @@ -241,7 +341,6 @@ static const struct imx258_reg mode_common_regs[] = { > { 0x5F05, 0xED }, > { 0x0112, 0x0A }, > { 0x0113, 0x0A }, > - { 0x0114, 0x03 }, > { 0x0342, 0x14 }, > { 0x0343, 0xE8 }, > { 0x0344, 0x00 }, > @@ -360,11 +459,13 @@ enum { > > /* > * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample > - * data rate => double data rate; number of lanes => 4; bits per pixel => 10 > + * data rate => double data rate; > + * number of lanes => (configurable 2 or 4); > + * bits per pixel => 10 > */ > -static u64 link_freq_to_pixel_rate(u64 f) > +static u64 link_freq_to_pixel_rate(u64 f, unsigned int nlanes) > { > - f *= 2 * 4; > + f *= 2 * nlanes; > do_div(f, 10); > > return f; > @@ -394,15 +495,27 @@ static const struct imx258_link_freq_config link_freq_configs_19_2[] = { > [IMX258_LINK_FREQ_1267MBPS] = { > .pixels_per_line = IMX258_PPL_DEFAULT, > .reg_list = { > - .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz), > - .regs = mipi_1267mbps_19_2mhz, > + [IMX258_2_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_2l), > + .regs = mipi_1267mbps_19_2mhz_2l, > + }, > + [IMX258_4_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_4l), > + .regs = mipi_1267mbps_19_2mhz_4l, > + }, > } > }, > [IMX258_LINK_FREQ_640MBPS] = { > .pixels_per_line = IMX258_PPL_DEFAULT, > .reg_list = { > - .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz), > - .regs = mipi_640mbps_19_2mhz, > + [IMX258_2_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_2l), > + .regs = mipi_640mbps_19_2mhz_2l, > + }, > + [IMX258_4_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_4l), > + .regs = mipi_640mbps_19_2mhz_4l, > + }, > } > }, > }; > @@ -411,15 +524,27 @@ static const struct imx258_link_freq_config link_freq_configs_24[] = { > [IMX258_LINK_FREQ_1267MBPS] = { > .pixels_per_line = IMX258_PPL_DEFAULT, > .reg_list = { > - .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz), > - .regs = mipi_1272mbps_24mhz, > + [IMX258_2_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_2l), > + .regs = mipi_1272mbps_24mhz_2l, > + }, > + [IMX258_4_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_4l), > + .regs = mipi_1272mbps_24mhz_4l, > + }, > } > }, > [IMX258_LINK_FREQ_640MBPS] = { > .pixels_per_line = IMX258_PPL_DEFAULT, > .reg_list = { > - .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz), > - .regs = mipi_642mbps_24mhz, > + [IMX258_2_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_2l), > + .regs = mipi_642mbps_24mhz_2l, > + }, > + [IMX258_4_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_4l), > + .regs = mipi_642mbps_24mhz_4l, > + }, > } > }, > }; > @@ -478,6 +603,7 @@ struct imx258 { > > const struct imx258_link_freq_config *link_freq_configs; > const s64 *link_freq_menu_items; > + unsigned int nlanes; > > /* > * Mutex for serialized access: > @@ -787,7 +913,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, > __v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index); > > link_freq = imx258->link_freq_menu_items[mode->link_freq_index]; > - pixel_rate = link_freq_to_pixel_rate(link_freq); > + pixel_rate = link_freq_to_pixel_rate(link_freq, imx258->nlanes); > __v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate); > /* Update limits and set FPS to default */ > vblank_def = imx258->cur_mode->vts_def - > @@ -816,11 +942,13 @@ static int imx258_start_streaming(struct imx258 *imx258) > { > struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); > const struct imx258_reg_list *reg_list; > + const struct imx258_link_freq_config *link_freq_cfg; > int ret, link_freq_index; > > /* Setup PLL */ > link_freq_index = imx258->cur_mode->link_freq_index; > - reg_list = &imx258->link_freq_configs[link_freq_index].reg_list; > + link_freq_cfg = &imx258->link_freq_configs[link_freq_index]; > + reg_list = &link_freq_cfg->reg_list[imx258->nlanes == 2 ? 0 : 1]; > ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs); > if (ret) { > dev_err(&client->dev, "%s failed to set plls\n", __func__); > @@ -1074,9 +1202,11 @@ static int imx258_init_controls(struct imx258 *imx258) > vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; > > pixel_rate_max = > - link_freq_to_pixel_rate(imx258->link_freq_menu_items[0]); > + link_freq_to_pixel_rate(imx258->link_freq_menu_items[0], > + imx258->nlanes); > pixel_rate_min = > - link_freq_to_pixel_rate(imx258->link_freq_menu_items[1]); > + link_freq_to_pixel_rate(imx258->link_freq_menu_items[1], > + imx258->nlanes); > /* By default, PIXEL_RATE is read only */ > imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, > V4L2_CID_PIXEL_RATE, > @@ -1174,6 +1304,10 @@ static int imx258_get_regulators(struct imx258 *imx258, > static int imx258_probe(struct i2c_client *client) > { > struct imx258 *imx258; > + struct fwnode_handle *endpoint; > + struct v4l2_fwnode_endpoint ep = { > + .bus_type = V4L2_MBUS_CSI2_DPHY > + }; > int ret; > u32 val = 0; > > @@ -1216,13 +1350,38 @@ static int imx258_probe(struct i2c_client *client) > return -EINVAL; > } > > + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); > + if (!endpoint) { > + dev_err(&client->dev, "Endpoint node not found\n"); > + return -EINVAL; > + } > + > + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); > + fwnode_handle_put(endpoint); > + if (ret == -ENXIO) { > + dev_err(&client->dev, "Unsupported bus type, should be CSI2\n"); > + goto error_endpoint_poweron; > + } else if (ret) { > + dev_err(&client->dev, "Parsing endpoint node failed\n"); > + goto error_endpoint_poweron; > + } > + > + /* Get number of data lanes */ > + imx258->nlanes = ep.bus.mipi_csi2.num_data_lanes; > + if (imx258->nlanes != 2 && imx258->nlanes != 4) { > + dev_err(&client->dev, "Invalid data lanes: %u\n", > + imx258->nlanes); > + ret = -EINVAL; > + goto error_endpoint_poweron; > + } > + > /* Initialize subdev */ > v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops); > > /* Will be powered off via pm_runtime_idle */ > ret = imx258_power_on(&client->dev); > if (ret) > - return ret; > + goto error_endpoint_poweron; > > /* Check module identity */ > ret = imx258_identify_module(imx258); > @@ -1255,6 +1414,7 @@ static int imx258_probe(struct i2c_client *client) > pm_runtime_set_active(&client->dev); > pm_runtime_enable(&client->dev); > pm_runtime_idle(&client->dev); > + v4l2_fwnode_endpoint_free(&endpoint); Apologies, I've messed up in making a last minute change to fix this leak, and didn't hit compile again :-( This should be v4l2_fwnode_endpoint_free(&ep); as in the error path below. I'll wait a few days to action any early review comments made, and then send a v2 fixing that up. Dave > > return 0; > > @@ -1267,6 +1427,9 @@ static int imx258_probe(struct i2c_client *client) > error_identify: > imx258_power_off(&client->dev); > > +error_endpoint_poweron: > + v4l2_fwnode_endpoint_free(&ep); > + > return ret; > } > > -- > 2.25.1 >
Hi Dave, kernel test robot noticed the following build errors: [auto build test ERROR on media-tree/master] [also build test ERROR on linus/master v6.4-rc4 next-20230531] [cannot apply to robh/for-next sailus-media-tree/streams] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Dave-Stevenson/media-i2c-imx258-Remove-unused-defines/20230531-013342 base: git://linuxtv.org/media_tree.git master patch link: https://lore.kernel.org/r/20230530173000.3060865-10-dave.stevenson%40raspberrypi.com patch subject: [PATCH 09/21] media: i2c: imx258: Add support for running on 2 CSI data lanes config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20230531/202305311525.0POx1Mzk-lkp@intel.com/config) compiler: m68k-linux-gcc (GCC) 12.3.0 reproduce (this is a W=1 build): mkdir -p ~/bin wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/e3fbe7eaf1c1b9f3b031308dbd3433a982bd3fe6 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Dave-Stevenson/media-i2c-imx258-Remove-unused-defines/20230531-013342 git checkout e3fbe7eaf1c1b9f3b031308dbd3433a982bd3fe6 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=m68k olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash drivers/media/i2c/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202305311525.0POx1Mzk-lkp@intel.com/ All errors (new ones prefixed by >>): drivers/media/i2c/imx258.c: In function 'imx258_probe': >> drivers/media/i2c/imx258.c:1417:35: error: passing argument 1 of 'v4l2_fwnode_endpoint_free' from incompatible pointer type [-Werror=incompatible-pointer-types] 1417 | v4l2_fwnode_endpoint_free(&endpoint); | ^~~~~~~~~ | | | struct fwnode_handle ** In file included from drivers/media/i2c/imx258.c:13: include/media/v4l2-fwnode.h:239:61: note: expected 'struct v4l2_fwnode_endpoint *' but argument is of type 'struct fwnode_handle **' 239 | void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~ cc1: some warnings being treated as errors vim +/v4l2_fwnode_endpoint_free +1417 drivers/media/i2c/imx258.c 1303 1304 static int imx258_probe(struct i2c_client *client) 1305 { 1306 struct imx258 *imx258; 1307 struct fwnode_handle *endpoint; 1308 struct v4l2_fwnode_endpoint ep = { 1309 .bus_type = V4L2_MBUS_CSI2_DPHY 1310 }; 1311 int ret; 1312 u32 val = 0; 1313 1314 imx258 = devm_kzalloc(&client->dev, sizeof(*imx258), GFP_KERNEL); 1315 if (!imx258) 1316 return -ENOMEM; 1317 1318 ret = imx258_get_regulators(imx258, client); 1319 if (ret) 1320 return ret; 1321 1322 imx258->clk = devm_clk_get_optional(&client->dev, NULL); 1323 if (IS_ERR(imx258->clk)) 1324 return dev_err_probe(&client->dev, PTR_ERR(imx258->clk), 1325 "error getting clock\n"); 1326 if (!imx258->clk) { 1327 dev_dbg(&client->dev, 1328 "no clock provided, using clock-frequency property\n"); 1329 1330 device_property_read_u32(&client->dev, "clock-frequency", &val); 1331 } else if (IS_ERR(imx258->clk)) { 1332 return dev_err_probe(&client->dev, PTR_ERR(imx258->clk), 1333 "error getting clock\n"); 1334 } else { 1335 val = clk_get_rate(imx258->clk); 1336 } 1337 1338 switch (val) { 1339 case 19200000: 1340 imx258->link_freq_configs = link_freq_configs_19_2; 1341 imx258->link_freq_menu_items = link_freq_menu_items_19_2; 1342 break; 1343 case 24000000: 1344 imx258->link_freq_configs = link_freq_configs_24; 1345 imx258->link_freq_menu_items = link_freq_menu_items_24; 1346 break; 1347 default: 1348 dev_err(&client->dev, "input clock frequency of %u not supported\n", 1349 val); 1350 return -EINVAL; 1351 } 1352 1353 endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); 1354 if (!endpoint) { 1355 dev_err(&client->dev, "Endpoint node not found\n"); 1356 return -EINVAL; 1357 } 1358 1359 ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); 1360 fwnode_handle_put(endpoint); 1361 if (ret == -ENXIO) { 1362 dev_err(&client->dev, "Unsupported bus type, should be CSI2\n"); 1363 goto error_endpoint_poweron; 1364 } else if (ret) { 1365 dev_err(&client->dev, "Parsing endpoint node failed\n"); 1366 goto error_endpoint_poweron; 1367 } 1368 1369 /* Get number of data lanes */ 1370 imx258->nlanes = ep.bus.mipi_csi2.num_data_lanes; 1371 if (imx258->nlanes != 2 && imx258->nlanes != 4) { 1372 dev_err(&client->dev, "Invalid data lanes: %u\n", 1373 imx258->nlanes); 1374 ret = -EINVAL; 1375 goto error_endpoint_poweron; 1376 } 1377 1378 /* Initialize subdev */ 1379 v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops); 1380 1381 /* Will be powered off via pm_runtime_idle */ 1382 ret = imx258_power_on(&client->dev); 1383 if (ret) 1384 goto error_endpoint_poweron; 1385 1386 /* Check module identity */ 1387 ret = imx258_identify_module(imx258); 1388 if (ret) 1389 goto error_identify; 1390 1391 /* Set default mode to max resolution */ 1392 imx258->cur_mode = &supported_modes[0]; 1393 1394 ret = imx258_init_controls(imx258); 1395 if (ret) 1396 goto error_identify; 1397 1398 /* Initialize subdev */ 1399 imx258->sd.internal_ops = &imx258_internal_ops; 1400 imx258->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1401 imx258->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 1402 1403 /* Initialize source pad */ 1404 imx258->pad.flags = MEDIA_PAD_FL_SOURCE; 1405 1406 ret = media_entity_pads_init(&imx258->sd.entity, 1, &imx258->pad); 1407 if (ret) 1408 goto error_handler_free; 1409 1410 ret = v4l2_async_register_subdev_sensor(&imx258->sd); 1411 if (ret < 0) 1412 goto error_media_entity; 1413 1414 pm_runtime_set_active(&client->dev); 1415 pm_runtime_enable(&client->dev); 1416 pm_runtime_idle(&client->dev); > 1417 v4l2_fwnode_endpoint_free(&endpoint); 1418 1419 return 0; 1420 1421 error_media_entity: 1422 media_entity_cleanup(&imx258->sd.entity); 1423 1424 error_handler_free: 1425 imx258_free_controls(imx258); 1426 1427 error_identify: 1428 imx258_power_off(&client->dev); 1429 1430 error_endpoint_poweron: 1431 v4l2_fwnode_endpoint_free(&ep); 1432 1433 return ret; 1434 } 1435
Hi Dave On Tue, May 30, 2023 at 06:29:48PM +0100, Dave Stevenson wrote: > Extends the driver to also support 2 data lanes. > Frame rates are obviously more restricted on 2 lanes, but some > hardware simply hasn't wired more up. > > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com> > --- > drivers/media/i2c/imx258.c | 211 ++++++++++++++++++++++++++++++++----- > 1 file changed, 187 insertions(+), 24 deletions(-) > > diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c > index d40521f9a3c6..433dff7f1fa0 100644 > --- a/drivers/media/i2c/imx258.c > +++ b/drivers/media/i2c/imx258.c > @@ -86,13 +86,17 @@ struct imx258_reg_list { > const struct imx258_reg *regs; > }; > > +#define IMX258_LANE_CONFIGS 2 > +#define IMX258_2_LANE_MODE 0 > +#define IMX258_4_LANE_MODE 1 > + nit: This might be better expressed as an enum... > /* Link frequency config */ > struct imx258_link_freq_config { > u64 link_frequency; > u32 pixels_per_line; > > /* PLL registers for this link frequency */ > - struct imx258_reg_list reg_list; > + struct imx258_reg_list reg_list[IMX258_LANE_CONFIGS]; > }; > > /* Mode : resolution and related config&values */ > @@ -112,8 +116,30 @@ struct imx258_mode { > struct imx258_reg_list reg_list; > }; > > -/* 4208x3120 needs 1267Mbps/lane, 4 lanes */ > -static const struct imx258_reg mipi_1267mbps_19_2mhz[] = { > +/* 4208x3120 needs 1267Mbps/lane, 4 lanes. Use that rate on 2 lanes as well */ I might be missing how the same link freq (and thus lane bandwidth) gives the same frame rate on 4 and 2 data lanes setup.. I get a total bandwidth with default VTS and PPL for 10bpp mode at 30 fps of vts * ppl * bpp * fps = 3152 * 5352 * 10 * 30 = 5060851200 bit/sec The resulting lane bandwidth for 4 lanes is 1.265.212.800 which ~= 1267 Mbps/lane you have above and results in a link frequency of 632606400 which matches your 634MHz/636MHz With 2 lanes either you double the bandwidth or you halve the frame rate. Seeing that now link_freq_to_pixel_rate() will give you a *2 result in 4 lanes configuration, I presume full res mode runs at 15FPS on 2 lanes ? If that's the case, should you remove '30FPS' from the VTS default value defines ? > +static const struct imx258_reg mipi_1267mbps_19_2mhz_2l[] = { > + { 0x0136, 0x13 }, > + { 0x0137, 0x33 }, > + { 0x0301, 0x0A }, > + { 0x0303, 0x02 }, > + { 0x0305, 0x03 }, > + { 0x0306, 0x00 }, > + { 0x0307, 0xC6 }, > + { 0x0309, 0x0A }, > + { 0x030B, 0x01 }, > + { 0x030D, 0x02 }, > + { 0x030E, 0x00 }, > + { 0x030F, 0xD8 }, > + { 0x0310, 0x00 }, > + > + { 0x0114, 0x01 }, > + { 0x0820, 0x09 }, > + { 0x0821, 0xa6 }, > + { 0x0822, 0x66 }, > + { 0x0823, 0x66 }, > +}; > + > +static const struct imx258_reg mipi_1267mbps_19_2mhz_4l[] = { > { 0x0136, 0x13 }, > { 0x0137, 0x33 }, > { 0x0301, 0x05 }, > @@ -127,16 +153,18 @@ static const struct imx258_reg mipi_1267mbps_19_2mhz[] = { > { 0x030E, 0x00 }, > { 0x030F, 0xD8 }, > { 0x0310, 0x00 }, > + > + { 0x0114, 0x03 }, > { 0x0820, 0x13 }, > { 0x0821, 0x4C }, > { 0x0822, 0xCC }, > { 0x0823, 0xCC }, > }; > > -static const struct imx258_reg mipi_1272mbps_24mhz[] = { > +static const struct imx258_reg mipi_1272mbps_24mhz_2l[] = { > { 0x0136, 0x18 }, > { 0x0137, 0x00 }, > - { 0x0301, 0x05 }, > + { 0x0301, 0x0a }, > { 0x0303, 0x02 }, > { 0x0305, 0x04 }, > { 0x0306, 0x00 }, > @@ -147,13 +175,59 @@ static const struct imx258_reg mipi_1272mbps_24mhz[] = { > { 0x030E, 0x00 }, > { 0x030F, 0xD8 }, > { 0x0310, 0x00 }, > + > + { 0x0114, 0x01 }, > { 0x0820, 0x13 }, > { 0x0821, 0x4C }, > { 0x0822, 0xCC }, > { 0x0823, 0xCC }, > }; > > -static const struct imx258_reg mipi_640mbps_19_2mhz[] = { > +static const struct imx258_reg mipi_1272mbps_24mhz_4l[] = { > + { 0x0136, 0x18 }, > + { 0x0137, 0x00 }, > + { 0x0301, 0x05 }, > + { 0x0303, 0x02 }, > + { 0x0305, 0x04 }, > + { 0x0306, 0x00 }, > + { 0x0307, 0xD4 }, > + { 0x0309, 0x0A }, > + { 0x030B, 0x01 }, > + { 0x030D, 0x02 }, > + { 0x030E, 0x00 }, > + { 0x030F, 0xD8 }, > + { 0x0310, 0x00 }, > + > + { 0x0114, 0x03 }, > + { 0x0820, 0x13 }, > + { 0x0821, 0xE0 }, > + { 0x0822, 0x00 }, > + { 0x0823, 0x00 }, > +}; > + > +static const struct imx258_reg mipi_640mbps_19_2mhz_2l[] = { > + { 0x0136, 0x13 }, > + { 0x0137, 0x33 }, > + { 0x0301, 0x05 }, > + { 0x0303, 0x02 }, > + { 0x0305, 0x03 }, > + { 0x0306, 0x00 }, > + { 0x0307, 0x64 }, > + { 0x0309, 0x0A }, > + { 0x030B, 0x01 }, > + { 0x030D, 0x02 }, > + { 0x030E, 0x00 }, > + { 0x030F, 0xD8 }, > + { 0x0310, 0x00 }, > + > + { 0x0114, 0x01 }, > + { 0x0820, 0x05 }, > + { 0x0821, 0x00 }, > + { 0x0822, 0x00 }, > + { 0x0823, 0x00 }, > +}; > + > +static const struct imx258_reg mipi_640mbps_19_2mhz_4l[] = { > { 0x0136, 0x13 }, > { 0x0137, 0x33 }, > { 0x0301, 0x05 }, > @@ -167,13 +241,37 @@ static const struct imx258_reg mipi_640mbps_19_2mhz[] = { > { 0x030E, 0x00 }, > { 0x030F, 0xD8 }, > { 0x0310, 0x00 }, > + > + { 0x0114, 0x03 }, > { 0x0820, 0x0A }, > { 0x0821, 0x00 }, > { 0x0822, 0x00 }, > { 0x0823, 0x00 }, > }; > > -static const struct imx258_reg mipi_642mbps_24mhz[] = { > +static const struct imx258_reg mipi_642mbps_24mhz_2l[] = { > + { 0x0136, 0x18 }, > + { 0x0137, 0x00 }, > + { 0x0301, 0x0A }, > + { 0x0303, 0x02 }, > + { 0x0305, 0x04 }, > + { 0x0306, 0x00 }, > + { 0x0307, 0x6B }, > + { 0x0309, 0x0A }, > + { 0x030B, 0x01 }, > + { 0x030D, 0x02 }, > + { 0x030E, 0x00 }, > + { 0x030F, 0xD8 }, > + { 0x0310, 0x00 }, > + > + { 0x0114, 0x01 }, > + { 0x0820, 0x0A }, > + { 0x0821, 0x00 }, > + { 0x0822, 0x00 }, > + { 0x0823, 0x00 }, > +}; > + > +static const struct imx258_reg mipi_642mbps_24mhz_4l[] = { > { 0x0136, 0x18 }, > { 0x0137, 0x00 }, > { 0x0301, 0x05 }, > @@ -187,6 +285,8 @@ static const struct imx258_reg mipi_642mbps_24mhz[] = { > { 0x030E, 0x00 }, > { 0x030F, 0xD8 }, > { 0x0310, 0x00 }, > + > + { 0x0114, 0x03 }, > { 0x0820, 0x0A }, > { 0x0821, 0x00 }, > { 0x0822, 0x00 }, > @@ -241,7 +341,6 @@ static const struct imx258_reg mode_common_regs[] = { > { 0x5F05, 0xED }, > { 0x0112, 0x0A }, > { 0x0113, 0x0A }, > - { 0x0114, 0x03 }, > { 0x0342, 0x14 }, > { 0x0343, 0xE8 }, > { 0x0344, 0x00 }, > @@ -360,11 +459,13 @@ enum { > > /* > * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample > - * data rate => double data rate; number of lanes => 4; bits per pixel => 10 > + * data rate => double data rate; > + * number of lanes => (configurable 2 or 4); > + * bits per pixel => 10 > */ > -static u64 link_freq_to_pixel_rate(u64 f) > +static u64 link_freq_to_pixel_rate(u64 f, unsigned int nlanes) > { > - f *= 2 * 4; > + f *= 2 * nlanes; > do_div(f, 10); > > return f; > @@ -394,15 +495,27 @@ static const struct imx258_link_freq_config link_freq_configs_19_2[] = { > [IMX258_LINK_FREQ_1267MBPS] = { > .pixels_per_line = IMX258_PPL_DEFAULT, > .reg_list = { > - .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz), > - .regs = mipi_1267mbps_19_2mhz, > + [IMX258_2_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_2l), > + .regs = mipi_1267mbps_19_2mhz_2l, > + }, > + [IMX258_4_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_4l), > + .regs = mipi_1267mbps_19_2mhz_4l, > + }, > } > }, > [IMX258_LINK_FREQ_640MBPS] = { > .pixels_per_line = IMX258_PPL_DEFAULT, > .reg_list = { > - .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz), > - .regs = mipi_640mbps_19_2mhz, > + [IMX258_2_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_2l), > + .regs = mipi_640mbps_19_2mhz_2l, > + }, > + [IMX258_4_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_4l), > + .regs = mipi_640mbps_19_2mhz_4l, > + }, > } > }, > }; > @@ -411,15 +524,27 @@ static const struct imx258_link_freq_config link_freq_configs_24[] = { > [IMX258_LINK_FREQ_1267MBPS] = { > .pixels_per_line = IMX258_PPL_DEFAULT, > .reg_list = { > - .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz), > - .regs = mipi_1272mbps_24mhz, > + [IMX258_2_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_2l), > + .regs = mipi_1272mbps_24mhz_2l, > + }, > + [IMX258_4_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_4l), > + .regs = mipi_1272mbps_24mhz_4l, > + }, > } > }, > [IMX258_LINK_FREQ_640MBPS] = { > .pixels_per_line = IMX258_PPL_DEFAULT, > .reg_list = { > - .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz), > - .regs = mipi_642mbps_24mhz, > + [IMX258_2_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_2l), > + .regs = mipi_642mbps_24mhz_2l, > + }, > + [IMX258_4_LANE_MODE] = { > + .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_4l), > + .regs = mipi_642mbps_24mhz_4l, > + }, > } > }, > }; > @@ -478,6 +603,7 @@ struct imx258 { > > const struct imx258_link_freq_config *link_freq_configs; > const s64 *link_freq_menu_items; > + unsigned int nlanes; > > /* > * Mutex for serialized access: > @@ -787,7 +913,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, > __v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index); > > link_freq = imx258->link_freq_menu_items[mode->link_freq_index]; > - pixel_rate = link_freq_to_pixel_rate(link_freq); > + pixel_rate = link_freq_to_pixel_rate(link_freq, imx258->nlanes); > __v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate); > /* Update limits and set FPS to default */ > vblank_def = imx258->cur_mode->vts_def - > @@ -816,11 +942,13 @@ static int imx258_start_streaming(struct imx258 *imx258) > { > struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); > const struct imx258_reg_list *reg_list; > + const struct imx258_link_freq_config *link_freq_cfg; > int ret, link_freq_index; > > /* Setup PLL */ > link_freq_index = imx258->cur_mode->link_freq_index; > - reg_list = &imx258->link_freq_configs[link_freq_index].reg_list; > + link_freq_cfg = &imx258->link_freq_configs[link_freq_index]; > + reg_list = &link_freq_cfg->reg_list[imx258->nlanes == 2 ? 0 : 1]; > ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs); > if (ret) { > dev_err(&client->dev, "%s failed to set plls\n", __func__); > @@ -1074,9 +1202,11 @@ static int imx258_init_controls(struct imx258 *imx258) > vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; > > pixel_rate_max = > - link_freq_to_pixel_rate(imx258->link_freq_menu_items[0]); > + link_freq_to_pixel_rate(imx258->link_freq_menu_items[0], > + imx258->nlanes); > pixel_rate_min = > - link_freq_to_pixel_rate(imx258->link_freq_menu_items[1]); > + link_freq_to_pixel_rate(imx258->link_freq_menu_items[1], > + imx258->nlanes); > /* By default, PIXEL_RATE is read only */ > imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, > V4L2_CID_PIXEL_RATE, > @@ -1174,6 +1304,10 @@ static int imx258_get_regulators(struct imx258 *imx258, > static int imx258_probe(struct i2c_client *client) > { > struct imx258 *imx258; > + struct fwnode_handle *endpoint; > + struct v4l2_fwnode_endpoint ep = { > + .bus_type = V4L2_MBUS_CSI2_DPHY > + }; > int ret; > u32 val = 0; > > @@ -1216,13 +1350,38 @@ static int imx258_probe(struct i2c_client *client) > return -EINVAL; > } > > + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); > + if (!endpoint) { > + dev_err(&client->dev, "Endpoint node not found\n"); > + return -EINVAL; > + } > + > + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); > + fwnode_handle_put(endpoint); > + if (ret == -ENXIO) { Doesn't the core warns you already ? Anywy, doesn't hurt I suppose > + dev_err(&client->dev, "Unsupported bus type, should be CSI2\n"); > + goto error_endpoint_poweron; > + } else if (ret) { > + dev_err(&client->dev, "Parsing endpoint node failed\n"); > + goto error_endpoint_poweron; It's a pretty peculiar name :) Why not 'error_endpoint_free' ? Anyway, if parsing fails, I don't think you need to v4l2_fwnode_endpoint_free() as the core should take care of doing so. > + } > + > + /* Get number of data lanes */ > + imx258->nlanes = ep.bus.mipi_csi2.num_data_lanes; > + if (imx258->nlanes != 2 && imx258->nlanes != 4) { > + dev_err(&client->dev, "Invalid data lanes: %u\n", > + imx258->nlanes); > + ret = -EINVAL; > + goto error_endpoint_poweron; > + } > + > /* Initialize subdev */ > v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops); > > /* Will be powered off via pm_runtime_idle */ > ret = imx258_power_on(&client->dev); > if (ret) > - return ret; > + goto error_endpoint_poweron; > > /* Check module identity */ > ret = imx258_identify_module(imx258); > @@ -1255,6 +1414,7 @@ static int imx258_probe(struct i2c_client *client) > pm_runtime_set_active(&client->dev); > pm_runtime_enable(&client->dev); > pm_runtime_idle(&client->dev); > + v4l2_fwnode_endpoint_free(&endpoint); Do you need to free in _remove() too ? > > return 0; > > @@ -1267,6 +1427,9 @@ static int imx258_probe(struct i2c_client *client) > error_identify: > imx258_power_off(&client->dev); > > +error_endpoint_poweron: > + v4l2_fwnode_endpoint_free(&ep); > + > return ret; > } > > -- > 2.25.1 >
Hi Jacopo Thanks for the review On Fri, 2 Jun 2023 at 14:23, Jacopo Mondi <jacopo.mondi@ideasonboard.com> wrote: > > Hi Dave > > On Tue, May 30, 2023 at 06:29:48PM +0100, Dave Stevenson wrote: > > Extends the driver to also support 2 data lanes. > > Frame rates are obviously more restricted on 2 lanes, but some > > hardware simply hasn't wired more up. > > > > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com> > > --- > > drivers/media/i2c/imx258.c | 211 ++++++++++++++++++++++++++++++++----- > > 1 file changed, 187 insertions(+), 24 deletions(-) > > > > diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c > > index d40521f9a3c6..433dff7f1fa0 100644 > > --- a/drivers/media/i2c/imx258.c > > +++ b/drivers/media/i2c/imx258.c > > @@ -86,13 +86,17 @@ struct imx258_reg_list { > > const struct imx258_reg *regs; > > }; > > > > +#define IMX258_LANE_CONFIGS 2 > > +#define IMX258_2_LANE_MODE 0 > > +#define IMX258_4_LANE_MODE 1 > > + > > nit: This might be better expressed as an enum... Will do. It's always a toss up between the two. > > /* Link frequency config */ > > struct imx258_link_freq_config { > > u64 link_frequency; > > u32 pixels_per_line; > > > > /* PLL registers for this link frequency */ > > - struct imx258_reg_list reg_list; > > + struct imx258_reg_list reg_list[IMX258_LANE_CONFIGS]; > > }; > > > > /* Mode : resolution and related config&values */ > > @@ -112,8 +116,30 @@ struct imx258_mode { > > struct imx258_reg_list reg_list; > > }; > > > > -/* 4208x3120 needs 1267Mbps/lane, 4 lanes */ > > -static const struct imx258_reg mipi_1267mbps_19_2mhz[] = { > > +/* 4208x3120 needs 1267Mbps/lane, 4 lanes. Use that rate on 2 lanes as well */ > > I might be missing how the same link freq (and thus lane bandwidth) > gives the same frame rate on 4 and 2 data lanes setup.. > > I get a total bandwidth with default VTS and PPL for 10bpp mode at 30 > fps of > > vts * ppl * bpp * fps = > 3152 * 5352 * 10 * 30 = 5060851200 bit/sec > > The resulting lane bandwidth for 4 lanes is > 1.265.212.800 which ~= 1267 Mbps/lane you have above > and results in a link frequency of > 632606400 which matches your 634MHz/636MHz > > With 2 lanes either you double the bandwidth or you halve the frame > rate. Seeing that now link_freq_to_pixel_rate() will give you a *2 > result in 4 lanes configuration, I presume full res mode runs at 15FPS > on 2 lanes ? If that's the case, should you remove '30FPS' from the > VTS default value defines ? The comment here doesn't specify a frame rate, although admittedly it is ambiguously worded. I'll reword to: 4208x3120 @ 30fps needs 1267Mbps/lane when using 4 lanes. To avoid further computation of clock settings, adopt the same per lane data rate when using 2 lanes, thus allowing a maximum of 15fps. > > +static const struct imx258_reg mipi_1267mbps_19_2mhz_2l[] = { > > + { 0x0136, 0x13 }, > > + { 0x0137, 0x33 }, > > + { 0x0301, 0x0A }, > > + { 0x0303, 0x02 }, > > + { 0x0305, 0x03 }, > > + { 0x0306, 0x00 }, > > + { 0x0307, 0xC6 }, > > + { 0x0309, 0x0A }, > > + { 0x030B, 0x01 }, > > + { 0x030D, 0x02 }, > > + { 0x030E, 0x00 }, > > + { 0x030F, 0xD8 }, > > + { 0x0310, 0x00 }, > > + > > + { 0x0114, 0x01 }, > > + { 0x0820, 0x09 }, > > + { 0x0821, 0xa6 }, > > + { 0x0822, 0x66 }, > > + { 0x0823, 0x66 }, > > +}; > > + > > +static const struct imx258_reg mipi_1267mbps_19_2mhz_4l[] = { > > { 0x0136, 0x13 }, > > { 0x0137, 0x33 }, > > { 0x0301, 0x05 }, > > @@ -127,16 +153,18 @@ static const struct imx258_reg mipi_1267mbps_19_2mhz[] = { > > { 0x030E, 0x00 }, > > { 0x030F, 0xD8 }, > > { 0x0310, 0x00 }, > > + > > + { 0x0114, 0x03 }, > > { 0x0820, 0x13 }, > > { 0x0821, 0x4C }, > > { 0x0822, 0xCC }, > > { 0x0823, 0xCC }, > > }; > > > > -static const struct imx258_reg mipi_1272mbps_24mhz[] = { > > +static const struct imx258_reg mipi_1272mbps_24mhz_2l[] = { > > { 0x0136, 0x18 }, > > { 0x0137, 0x00 }, > > - { 0x0301, 0x05 }, > > + { 0x0301, 0x0a }, > > { 0x0303, 0x02 }, > > { 0x0305, 0x04 }, > > { 0x0306, 0x00 }, > > @@ -147,13 +175,59 @@ static const struct imx258_reg mipi_1272mbps_24mhz[] = { > > { 0x030E, 0x00 }, > > { 0x030F, 0xD8 }, > > { 0x0310, 0x00 }, > > + > > + { 0x0114, 0x01 }, > > { 0x0820, 0x13 }, > > { 0x0821, 0x4C }, > > { 0x0822, 0xCC }, > > { 0x0823, 0xCC }, > > }; > > > > -static const struct imx258_reg mipi_640mbps_19_2mhz[] = { > > +static const struct imx258_reg mipi_1272mbps_24mhz_4l[] = { > > + { 0x0136, 0x18 }, > > + { 0x0137, 0x00 }, > > + { 0x0301, 0x05 }, > > + { 0x0303, 0x02 }, > > + { 0x0305, 0x04 }, > > + { 0x0306, 0x00 }, > > + { 0x0307, 0xD4 }, > > + { 0x0309, 0x0A }, > > + { 0x030B, 0x01 }, > > + { 0x030D, 0x02 }, > > + { 0x030E, 0x00 }, > > + { 0x030F, 0xD8 }, > > + { 0x0310, 0x00 }, > > + > > + { 0x0114, 0x03 }, > > + { 0x0820, 0x13 }, > > + { 0x0821, 0xE0 }, > > + { 0x0822, 0x00 }, > > + { 0x0823, 0x00 }, > > +}; > > + > > +static const struct imx258_reg mipi_640mbps_19_2mhz_2l[] = { > > + { 0x0136, 0x13 }, > > + { 0x0137, 0x33 }, > > + { 0x0301, 0x05 }, > > + { 0x0303, 0x02 }, > > + { 0x0305, 0x03 }, > > + { 0x0306, 0x00 }, > > + { 0x0307, 0x64 }, > > + { 0x0309, 0x0A }, > > + { 0x030B, 0x01 }, > > + { 0x030D, 0x02 }, > > + { 0x030E, 0x00 }, > > + { 0x030F, 0xD8 }, > > + { 0x0310, 0x00 }, > > + > > + { 0x0114, 0x01 }, > > + { 0x0820, 0x05 }, > > + { 0x0821, 0x00 }, > > + { 0x0822, 0x00 }, > > + { 0x0823, 0x00 }, > > +}; > > + > > +static const struct imx258_reg mipi_640mbps_19_2mhz_4l[] = { > > { 0x0136, 0x13 }, > > { 0x0137, 0x33 }, > > { 0x0301, 0x05 }, > > @@ -167,13 +241,37 @@ static const struct imx258_reg mipi_640mbps_19_2mhz[] = { > > { 0x030E, 0x00 }, > > { 0x030F, 0xD8 }, > > { 0x0310, 0x00 }, > > + > > + { 0x0114, 0x03 }, > > { 0x0820, 0x0A }, > > { 0x0821, 0x00 }, > > { 0x0822, 0x00 }, > > { 0x0823, 0x00 }, > > }; > > > > -static const struct imx258_reg mipi_642mbps_24mhz[] = { > > +static const struct imx258_reg mipi_642mbps_24mhz_2l[] = { > > + { 0x0136, 0x18 }, > > + { 0x0137, 0x00 }, > > + { 0x0301, 0x0A }, > > + { 0x0303, 0x02 }, > > + { 0x0305, 0x04 }, > > + { 0x0306, 0x00 }, > > + { 0x0307, 0x6B }, > > + { 0x0309, 0x0A }, > > + { 0x030B, 0x01 }, > > + { 0x030D, 0x02 }, > > + { 0x030E, 0x00 }, > > + { 0x030F, 0xD8 }, > > + { 0x0310, 0x00 }, > > + > > + { 0x0114, 0x01 }, > > + { 0x0820, 0x0A }, > > + { 0x0821, 0x00 }, > > + { 0x0822, 0x00 }, > > + { 0x0823, 0x00 }, > > +}; > > + > > +static const struct imx258_reg mipi_642mbps_24mhz_4l[] = { > > { 0x0136, 0x18 }, > > { 0x0137, 0x00 }, > > { 0x0301, 0x05 }, > > @@ -187,6 +285,8 @@ static const struct imx258_reg mipi_642mbps_24mhz[] = { > > { 0x030E, 0x00 }, > > { 0x030F, 0xD8 }, > > { 0x0310, 0x00 }, > > + > > + { 0x0114, 0x03 }, > > { 0x0820, 0x0A }, > > { 0x0821, 0x00 }, > > { 0x0822, 0x00 }, > > @@ -241,7 +341,6 @@ static const struct imx258_reg mode_common_regs[] = { > > { 0x5F05, 0xED }, > > { 0x0112, 0x0A }, > > { 0x0113, 0x0A }, > > - { 0x0114, 0x03 }, > > { 0x0342, 0x14 }, > > { 0x0343, 0xE8 }, > > { 0x0344, 0x00 }, > > @@ -360,11 +459,13 @@ enum { > > > > /* > > * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample > > - * data rate => double data rate; number of lanes => 4; bits per pixel => 10 > > + * data rate => double data rate; > > + * number of lanes => (configurable 2 or 4); > > + * bits per pixel => 10 > > */ > > -static u64 link_freq_to_pixel_rate(u64 f) > > +static u64 link_freq_to_pixel_rate(u64 f, unsigned int nlanes) > > { > > - f *= 2 * 4; > > + f *= 2 * nlanes; > > do_div(f, 10); > > > > return f; > > @@ -394,15 +495,27 @@ static const struct imx258_link_freq_config link_freq_configs_19_2[] = { > > [IMX258_LINK_FREQ_1267MBPS] = { > > .pixels_per_line = IMX258_PPL_DEFAULT, > > .reg_list = { > > - .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz), > > - .regs = mipi_1267mbps_19_2mhz, > > + [IMX258_2_LANE_MODE] = { > > + .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_2l), > > + .regs = mipi_1267mbps_19_2mhz_2l, > > + }, > > + [IMX258_4_LANE_MODE] = { > > + .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_4l), > > + .regs = mipi_1267mbps_19_2mhz_4l, > > + }, > > } > > }, > > [IMX258_LINK_FREQ_640MBPS] = { > > .pixels_per_line = IMX258_PPL_DEFAULT, > > .reg_list = { > > - .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz), > > - .regs = mipi_640mbps_19_2mhz, > > + [IMX258_2_LANE_MODE] = { > > + .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_2l), > > + .regs = mipi_640mbps_19_2mhz_2l, > > + }, > > + [IMX258_4_LANE_MODE] = { > > + .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_4l), > > + .regs = mipi_640mbps_19_2mhz_4l, > > + }, > > } > > }, > > }; > > @@ -411,15 +524,27 @@ static const struct imx258_link_freq_config link_freq_configs_24[] = { > > [IMX258_LINK_FREQ_1267MBPS] = { > > .pixels_per_line = IMX258_PPL_DEFAULT, > > .reg_list = { > > - .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz), > > - .regs = mipi_1272mbps_24mhz, > > + [IMX258_2_LANE_MODE] = { > > + .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_2l), > > + .regs = mipi_1272mbps_24mhz_2l, > > + }, > > + [IMX258_4_LANE_MODE] = { > > + .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_4l), > > + .regs = mipi_1272mbps_24mhz_4l, > > + }, > > } > > }, > > [IMX258_LINK_FREQ_640MBPS] = { > > .pixels_per_line = IMX258_PPL_DEFAULT, > > .reg_list = { > > - .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz), > > - .regs = mipi_642mbps_24mhz, > > + [IMX258_2_LANE_MODE] = { > > + .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_2l), > > + .regs = mipi_642mbps_24mhz_2l, > > + }, > > + [IMX258_4_LANE_MODE] = { > > + .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_4l), > > + .regs = mipi_642mbps_24mhz_4l, > > + }, > > } > > }, > > }; > > @@ -478,6 +603,7 @@ struct imx258 { > > > > const struct imx258_link_freq_config *link_freq_configs; > > const s64 *link_freq_menu_items; > > + unsigned int nlanes; > > > > /* > > * Mutex for serialized access: > > @@ -787,7 +913,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, > > __v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index); > > > > link_freq = imx258->link_freq_menu_items[mode->link_freq_index]; > > - pixel_rate = link_freq_to_pixel_rate(link_freq); > > + pixel_rate = link_freq_to_pixel_rate(link_freq, imx258->nlanes); > > __v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate); > > /* Update limits and set FPS to default */ > > vblank_def = imx258->cur_mode->vts_def - > > @@ -816,11 +942,13 @@ static int imx258_start_streaming(struct imx258 *imx258) > > { > > struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); > > const struct imx258_reg_list *reg_list; > > + const struct imx258_link_freq_config *link_freq_cfg; > > int ret, link_freq_index; > > > > /* Setup PLL */ > > link_freq_index = imx258->cur_mode->link_freq_index; > > - reg_list = &imx258->link_freq_configs[link_freq_index].reg_list; > > + link_freq_cfg = &imx258->link_freq_configs[link_freq_index]; > > + reg_list = &link_freq_cfg->reg_list[imx258->nlanes == 2 ? 0 : 1]; > > ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs); > > if (ret) { > > dev_err(&client->dev, "%s failed to set plls\n", __func__); > > @@ -1074,9 +1202,11 @@ static int imx258_init_controls(struct imx258 *imx258) > > vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; > > > > pixel_rate_max = > > - link_freq_to_pixel_rate(imx258->link_freq_menu_items[0]); > > + link_freq_to_pixel_rate(imx258->link_freq_menu_items[0], > > + imx258->nlanes); > > pixel_rate_min = > > - link_freq_to_pixel_rate(imx258->link_freq_menu_items[1]); > > + link_freq_to_pixel_rate(imx258->link_freq_menu_items[1], > > + imx258->nlanes); > > /* By default, PIXEL_RATE is read only */ > > imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, > > V4L2_CID_PIXEL_RATE, > > @@ -1174,6 +1304,10 @@ static int imx258_get_regulators(struct imx258 *imx258, > > static int imx258_probe(struct i2c_client *client) > > { > > struct imx258 *imx258; > > + struct fwnode_handle *endpoint; > > + struct v4l2_fwnode_endpoint ep = { > > + .bus_type = V4L2_MBUS_CSI2_DPHY > > + }; > > int ret; > > u32 val = 0; > > > > @@ -1216,13 +1350,38 @@ static int imx258_probe(struct i2c_client *client) > > return -EINVAL; > > } > > > > + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); > > + if (!endpoint) { > > + dev_err(&client->dev, "Endpoint node not found\n"); > > + return -EINVAL; > > + } > > + > > + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); > > + fwnode_handle_put(endpoint); > > + if (ret == -ENXIO) { > > Doesn't the core warns you already ? Anywy, doesn't hurt I suppose It looks to me like it's a pr_debug, so not apparently. https://elixir.bootlin.com/linux/latest/source/drivers/media/v4l2-core/v4l2-fwnode.c#L443 There's no real need to differentiate why it failed here, so I'll combine the two error cases and include the error code. > > + dev_err(&client->dev, "Unsupported bus type, should be CSI2\n"); > > + goto error_endpoint_poweron; > > + } else if (ret) { > > + dev_err(&client->dev, "Parsing endpoint node failed\n"); > > + goto error_endpoint_poweron; > > It's a pretty peculiar name :) Why not 'error_endpoint_free' ? It's been a while since I originally wrote this. Probably because it's called if either the endpoint parsing fails, or if power_on fails. I'll rename it as you suggest. > Anyway, if parsing fails, I don't think you need to v4l2_fwnode_endpoint_free() > as the core should take care of doing so. Yes, it looks like it does, so I can just return here. I still need the error path should the number of lanes be invalid, or imx258_power_on fails, just not here. > > + } > > + > > + /* Get number of data lanes */ > > + imx258->nlanes = ep.bus.mipi_csi2.num_data_lanes; > > + if (imx258->nlanes != 2 && imx258->nlanes != 4) { > > + dev_err(&client->dev, "Invalid data lanes: %u\n", > > + imx258->nlanes); > > + ret = -EINVAL; > > + goto error_endpoint_poweron; > > + } > > + > > /* Initialize subdev */ > > v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops); > > > > /* Will be powered off via pm_runtime_idle */ > > ret = imx258_power_on(&client->dev); > > if (ret) > > - return ret; > > + goto error_endpoint_poweron; > > > > /* Check module identity */ > > ret = imx258_identify_module(imx258); > > @@ -1255,6 +1414,7 @@ static int imx258_probe(struct i2c_client *client) > > pm_runtime_set_active(&client->dev); > > pm_runtime_enable(&client->dev); > > pm_runtime_idle(&client->dev); > > + v4l2_fwnode_endpoint_free(&endpoint); > > Do you need to free in _remove() too ? This is the success path at the end of _probe. We don't need the endpoint after this, and it's a local to this function, therefore cleaning up here. As noted earlier, this should be: v4l2_fwnode_endpoint_free(&ep); Thanks Dave > > > > return 0; > > > > @@ -1267,6 +1427,9 @@ static int imx258_probe(struct i2c_client *client) > > error_identify: > > imx258_power_off(&client->dev); > > > > +error_endpoint_poweron: > > + v4l2_fwnode_endpoint_free(&ep); > > + > > return ret; > > } > > > > -- > > 2.25.1 > >
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c index d40521f9a3c6..433dff7f1fa0 100644 --- a/drivers/media/i2c/imx258.c +++ b/drivers/media/i2c/imx258.c @@ -86,13 +86,17 @@ struct imx258_reg_list { const struct imx258_reg *regs; }; +#define IMX258_LANE_CONFIGS 2 +#define IMX258_2_LANE_MODE 0 +#define IMX258_4_LANE_MODE 1 + /* Link frequency config */ struct imx258_link_freq_config { u64 link_frequency; u32 pixels_per_line; /* PLL registers for this link frequency */ - struct imx258_reg_list reg_list; + struct imx258_reg_list reg_list[IMX258_LANE_CONFIGS]; }; /* Mode : resolution and related config&values */ @@ -112,8 +116,30 @@ struct imx258_mode { struct imx258_reg_list reg_list; }; -/* 4208x3120 needs 1267Mbps/lane, 4 lanes */ -static const struct imx258_reg mipi_1267mbps_19_2mhz[] = { +/* 4208x3120 needs 1267Mbps/lane, 4 lanes. Use that rate on 2 lanes as well */ +static const struct imx258_reg mipi_1267mbps_19_2mhz_2l[] = { + { 0x0136, 0x13 }, + { 0x0137, 0x33 }, + { 0x0301, 0x0A }, + { 0x0303, 0x02 }, + { 0x0305, 0x03 }, + { 0x0306, 0x00 }, + { 0x0307, 0xC6 }, + { 0x0309, 0x0A }, + { 0x030B, 0x01 }, + { 0x030D, 0x02 }, + { 0x030E, 0x00 }, + { 0x030F, 0xD8 }, + { 0x0310, 0x00 }, + + { 0x0114, 0x01 }, + { 0x0820, 0x09 }, + { 0x0821, 0xa6 }, + { 0x0822, 0x66 }, + { 0x0823, 0x66 }, +}; + +static const struct imx258_reg mipi_1267mbps_19_2mhz_4l[] = { { 0x0136, 0x13 }, { 0x0137, 0x33 }, { 0x0301, 0x05 }, @@ -127,16 +153,18 @@ static const struct imx258_reg mipi_1267mbps_19_2mhz[] = { { 0x030E, 0x00 }, { 0x030F, 0xD8 }, { 0x0310, 0x00 }, + + { 0x0114, 0x03 }, { 0x0820, 0x13 }, { 0x0821, 0x4C }, { 0x0822, 0xCC }, { 0x0823, 0xCC }, }; -static const struct imx258_reg mipi_1272mbps_24mhz[] = { +static const struct imx258_reg mipi_1272mbps_24mhz_2l[] = { { 0x0136, 0x18 }, { 0x0137, 0x00 }, - { 0x0301, 0x05 }, + { 0x0301, 0x0a }, { 0x0303, 0x02 }, { 0x0305, 0x04 }, { 0x0306, 0x00 }, @@ -147,13 +175,59 @@ static const struct imx258_reg mipi_1272mbps_24mhz[] = { { 0x030E, 0x00 }, { 0x030F, 0xD8 }, { 0x0310, 0x00 }, + + { 0x0114, 0x01 }, { 0x0820, 0x13 }, { 0x0821, 0x4C }, { 0x0822, 0xCC }, { 0x0823, 0xCC }, }; -static const struct imx258_reg mipi_640mbps_19_2mhz[] = { +static const struct imx258_reg mipi_1272mbps_24mhz_4l[] = { + { 0x0136, 0x18 }, + { 0x0137, 0x00 }, + { 0x0301, 0x05 }, + { 0x0303, 0x02 }, + { 0x0305, 0x04 }, + { 0x0306, 0x00 }, + { 0x0307, 0xD4 }, + { 0x0309, 0x0A }, + { 0x030B, 0x01 }, + { 0x030D, 0x02 }, + { 0x030E, 0x00 }, + { 0x030F, 0xD8 }, + { 0x0310, 0x00 }, + + { 0x0114, 0x03 }, + { 0x0820, 0x13 }, + { 0x0821, 0xE0 }, + { 0x0822, 0x00 }, + { 0x0823, 0x00 }, +}; + +static const struct imx258_reg mipi_640mbps_19_2mhz_2l[] = { + { 0x0136, 0x13 }, + { 0x0137, 0x33 }, + { 0x0301, 0x05 }, + { 0x0303, 0x02 }, + { 0x0305, 0x03 }, + { 0x0306, 0x00 }, + { 0x0307, 0x64 }, + { 0x0309, 0x0A }, + { 0x030B, 0x01 }, + { 0x030D, 0x02 }, + { 0x030E, 0x00 }, + { 0x030F, 0xD8 }, + { 0x0310, 0x00 }, + + { 0x0114, 0x01 }, + { 0x0820, 0x05 }, + { 0x0821, 0x00 }, + { 0x0822, 0x00 }, + { 0x0823, 0x00 }, +}; + +static const struct imx258_reg mipi_640mbps_19_2mhz_4l[] = { { 0x0136, 0x13 }, { 0x0137, 0x33 }, { 0x0301, 0x05 }, @@ -167,13 +241,37 @@ static const struct imx258_reg mipi_640mbps_19_2mhz[] = { { 0x030E, 0x00 }, { 0x030F, 0xD8 }, { 0x0310, 0x00 }, + + { 0x0114, 0x03 }, { 0x0820, 0x0A }, { 0x0821, 0x00 }, { 0x0822, 0x00 }, { 0x0823, 0x00 }, }; -static const struct imx258_reg mipi_642mbps_24mhz[] = { +static const struct imx258_reg mipi_642mbps_24mhz_2l[] = { + { 0x0136, 0x18 }, + { 0x0137, 0x00 }, + { 0x0301, 0x0A }, + { 0x0303, 0x02 }, + { 0x0305, 0x04 }, + { 0x0306, 0x00 }, + { 0x0307, 0x6B }, + { 0x0309, 0x0A }, + { 0x030B, 0x01 }, + { 0x030D, 0x02 }, + { 0x030E, 0x00 }, + { 0x030F, 0xD8 }, + { 0x0310, 0x00 }, + + { 0x0114, 0x01 }, + { 0x0820, 0x0A }, + { 0x0821, 0x00 }, + { 0x0822, 0x00 }, + { 0x0823, 0x00 }, +}; + +static const struct imx258_reg mipi_642mbps_24mhz_4l[] = { { 0x0136, 0x18 }, { 0x0137, 0x00 }, { 0x0301, 0x05 }, @@ -187,6 +285,8 @@ static const struct imx258_reg mipi_642mbps_24mhz[] = { { 0x030E, 0x00 }, { 0x030F, 0xD8 }, { 0x0310, 0x00 }, + + { 0x0114, 0x03 }, { 0x0820, 0x0A }, { 0x0821, 0x00 }, { 0x0822, 0x00 }, @@ -241,7 +341,6 @@ static const struct imx258_reg mode_common_regs[] = { { 0x5F05, 0xED }, { 0x0112, 0x0A }, { 0x0113, 0x0A }, - { 0x0114, 0x03 }, { 0x0342, 0x14 }, { 0x0343, 0xE8 }, { 0x0344, 0x00 }, @@ -360,11 +459,13 @@ enum { /* * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample - * data rate => double data rate; number of lanes => 4; bits per pixel => 10 + * data rate => double data rate; + * number of lanes => (configurable 2 or 4); + * bits per pixel => 10 */ -static u64 link_freq_to_pixel_rate(u64 f) +static u64 link_freq_to_pixel_rate(u64 f, unsigned int nlanes) { - f *= 2 * 4; + f *= 2 * nlanes; do_div(f, 10); return f; @@ -394,15 +495,27 @@ static const struct imx258_link_freq_config link_freq_configs_19_2[] = { [IMX258_LINK_FREQ_1267MBPS] = { .pixels_per_line = IMX258_PPL_DEFAULT, .reg_list = { - .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz), - .regs = mipi_1267mbps_19_2mhz, + [IMX258_2_LANE_MODE] = { + .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_2l), + .regs = mipi_1267mbps_19_2mhz_2l, + }, + [IMX258_4_LANE_MODE] = { + .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_4l), + .regs = mipi_1267mbps_19_2mhz_4l, + }, } }, [IMX258_LINK_FREQ_640MBPS] = { .pixels_per_line = IMX258_PPL_DEFAULT, .reg_list = { - .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz), - .regs = mipi_640mbps_19_2mhz, + [IMX258_2_LANE_MODE] = { + .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_2l), + .regs = mipi_640mbps_19_2mhz_2l, + }, + [IMX258_4_LANE_MODE] = { + .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_4l), + .regs = mipi_640mbps_19_2mhz_4l, + }, } }, }; @@ -411,15 +524,27 @@ static const struct imx258_link_freq_config link_freq_configs_24[] = { [IMX258_LINK_FREQ_1267MBPS] = { .pixels_per_line = IMX258_PPL_DEFAULT, .reg_list = { - .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz), - .regs = mipi_1272mbps_24mhz, + [IMX258_2_LANE_MODE] = { + .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_2l), + .regs = mipi_1272mbps_24mhz_2l, + }, + [IMX258_4_LANE_MODE] = { + .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_4l), + .regs = mipi_1272mbps_24mhz_4l, + }, } }, [IMX258_LINK_FREQ_640MBPS] = { .pixels_per_line = IMX258_PPL_DEFAULT, .reg_list = { - .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz), - .regs = mipi_642mbps_24mhz, + [IMX258_2_LANE_MODE] = { + .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_2l), + .regs = mipi_642mbps_24mhz_2l, + }, + [IMX258_4_LANE_MODE] = { + .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_4l), + .regs = mipi_642mbps_24mhz_4l, + }, } }, }; @@ -478,6 +603,7 @@ struct imx258 { const struct imx258_link_freq_config *link_freq_configs; const s64 *link_freq_menu_items; + unsigned int nlanes; /* * Mutex for serialized access: @@ -787,7 +913,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, __v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index); link_freq = imx258->link_freq_menu_items[mode->link_freq_index]; - pixel_rate = link_freq_to_pixel_rate(link_freq); + pixel_rate = link_freq_to_pixel_rate(link_freq, imx258->nlanes); __v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate); /* Update limits and set FPS to default */ vblank_def = imx258->cur_mode->vts_def - @@ -816,11 +942,13 @@ static int imx258_start_streaming(struct imx258 *imx258) { struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); const struct imx258_reg_list *reg_list; + const struct imx258_link_freq_config *link_freq_cfg; int ret, link_freq_index; /* Setup PLL */ link_freq_index = imx258->cur_mode->link_freq_index; - reg_list = &imx258->link_freq_configs[link_freq_index].reg_list; + link_freq_cfg = &imx258->link_freq_configs[link_freq_index]; + reg_list = &link_freq_cfg->reg_list[imx258->nlanes == 2 ? 0 : 1]; ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs); if (ret) { dev_err(&client->dev, "%s failed to set plls\n", __func__); @@ -1074,9 +1202,11 @@ static int imx258_init_controls(struct imx258 *imx258) vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; pixel_rate_max = - link_freq_to_pixel_rate(imx258->link_freq_menu_items[0]); + link_freq_to_pixel_rate(imx258->link_freq_menu_items[0], + imx258->nlanes); pixel_rate_min = - link_freq_to_pixel_rate(imx258->link_freq_menu_items[1]); + link_freq_to_pixel_rate(imx258->link_freq_menu_items[1], + imx258->nlanes); /* By default, PIXEL_RATE is read only */ imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_PIXEL_RATE, @@ -1174,6 +1304,10 @@ static int imx258_get_regulators(struct imx258 *imx258, static int imx258_probe(struct i2c_client *client) { struct imx258 *imx258; + struct fwnode_handle *endpoint; + struct v4l2_fwnode_endpoint ep = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; int ret; u32 val = 0; @@ -1216,13 +1350,38 @@ static int imx258_probe(struct i2c_client *client) return -EINVAL; } + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); + if (!endpoint) { + dev_err(&client->dev, "Endpoint node not found\n"); + return -EINVAL; + } + + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); + fwnode_handle_put(endpoint); + if (ret == -ENXIO) { + dev_err(&client->dev, "Unsupported bus type, should be CSI2\n"); + goto error_endpoint_poweron; + } else if (ret) { + dev_err(&client->dev, "Parsing endpoint node failed\n"); + goto error_endpoint_poweron; + } + + /* Get number of data lanes */ + imx258->nlanes = ep.bus.mipi_csi2.num_data_lanes; + if (imx258->nlanes != 2 && imx258->nlanes != 4) { + dev_err(&client->dev, "Invalid data lanes: %u\n", + imx258->nlanes); + ret = -EINVAL; + goto error_endpoint_poweron; + } + /* Initialize subdev */ v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops); /* Will be powered off via pm_runtime_idle */ ret = imx258_power_on(&client->dev); if (ret) - return ret; + goto error_endpoint_poweron; /* Check module identity */ ret = imx258_identify_module(imx258); @@ -1255,6 +1414,7 @@ static int imx258_probe(struct i2c_client *client) pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); + v4l2_fwnode_endpoint_free(&endpoint); return 0; @@ -1267,6 +1427,9 @@ static int imx258_probe(struct i2c_client *client) error_identify: imx258_power_off(&client->dev); +error_endpoint_poweron: + v4l2_fwnode_endpoint_free(&ep); + return ret; }
Extends the driver to also support 2 data lanes. Frame rates are obviously more restricted on 2 lanes, but some hardware simply hasn't wired more up. Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com> --- drivers/media/i2c/imx258.c | 211 ++++++++++++++++++++++++++++++++----- 1 file changed, 187 insertions(+), 24 deletions(-)