Linux Media Controller development
 help / color / mirror / Atom feed
From: Hao Yao <hao.yao@intel.com>
To: Sakari Ailus <sakari.ailus@linux.intel.com>
Cc: Arec Kao <arec.kao@intel.com>,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	<linux-media@vger.kernel.org>, Bingbu Cao <bingbu.cao@intel.com>
Subject: Re: [PATCH 2/2] media: i2c: ov13b10: Support 2 lane mode
Date: Mon, 10 Mar 2025 12:06:04 +0800	[thread overview]
Message-ID: <f24a1543-9a8f-4e42-8cf7-40644f6d706d@intel.com> (raw)
In-Reply-To: <Z8q_xpTIs1UsN0l9@kekkonen.localdomain>

Hi Sakari,

Thanks for reviewing this.

On 2025/3/7 17:43, Sakari Ailus wrote:
> Hi Bingbu, Hao,
> 
> Thanks for the patchset.
> 
> On Fri, Mar 07, 2025 at 05:31:17PM +0800, Hao Yao wrote:
>> 1. Fix pixel rate calculation to consider different lane number
>> 2. Add 2104x1560 60fps 2 data lanes register setting
>> 3. Support 2 lane in check_hwcfg
>> 4. Select correct mode considering lane number used
>>
>> Signed-off-by: Bingbu Cao <bingbu.cao@intel.com>
>> Signed-off-by: Hao Yao <hao.yao@intel.com>
>> ---
>>   drivers/media/i2c/ov13b10.c | 134 ++++++++++++++++++++++++++++++------
>>   1 file changed, 112 insertions(+), 22 deletions(-)
>>
>> diff --git a/drivers/media/i2c/ov13b10.c b/drivers/media/i2c/ov13b10.c
>> index 2e83fc23f321..20481b8d4e79 100644
>> --- a/drivers/media/i2c/ov13b10.c
>> +++ b/drivers/media/i2c/ov13b10.c
>> @@ -514,6 +514,52 @@ static const struct ov13b10_reg mode_1364x768_120fps_regs[] = {
>>   	{0x5001, 0x0d},
>>   };
>>   
>> +static const struct ov13b10_reg mode_2lanes_2104x1560_60fps_regs[] = {
>> +	{0x3016, 0x32},
>> +	{0x3106, 0x29},
>> +	{0x0305, 0xaf},
>> +	{0x3501, 0x06},
>> +	{0x3662, 0x88},
>> +	{0x3714, 0x28},
>> +	{0x3739, 0x10},
>> +	{0x37c2, 0x14},
>> +	{0x37d9, 0x06},
>> +	{0x37e2, 0x0c},
>> +	{0x3800, 0x00},
>> +	{0x3801, 0x00},
>> +	{0x3802, 0x00},
>> +	{0x3803, 0x08},
>> +	{0x3804, 0x10},
>> +	{0x3805, 0x8f},
>> +	{0x3806, 0x0c},
>> +	{0x3807, 0x47},
>> +	{0x3808, 0x08},
>> +	{0x3809, 0x38},
>> +	{0x380a, 0x06},
>> +	{0x380b, 0x18},
>> +	{0x380c, 0x04},
>> +	{0x380d, 0x98},
>> +	{0x380e, 0x06},
>> +	{0x380f, 0x3e},
>> +	{0x3810, 0x00},
>> +	{0x3811, 0x07},
>> +	{0x3812, 0x00},
>> +	{0x3813, 0x05},
>> +	{0x3814, 0x03},
>> +	{0x3816, 0x03},
>> +	{0x3820, 0x8b},
>> +	{0x3c8c, 0x18},
>> +	{0x4008, 0x00},
>> +	{0x4009, 0x05},
>> +	{0x4050, 0x00},
>> +	{0x4051, 0x05},
>> +	{0x4501, 0x08},
>> +	{0x4505, 0x00},
>> +	{0x4837, 0x0e},
>> +	{0x5000, 0xfd},
>> +	{0x5001, 0x0d},
>> +};
>> +
>>   static const char * const ov13b10_test_pattern_menu[] = {
>>   	"Disabled",
>>   	"Vertical Color Bar Type 1",
>> @@ -527,15 +573,16 @@ static const char * const ov13b10_test_pattern_menu[] = {
>>   #define OV13B10_LINK_FREQ_INDEX_0	0
>>   
>>   #define OV13B10_EXT_CLK			19200000
>> -#define OV13B10_DATA_LANES		4
>> +#define OV13B10_4_DATA_LANES		4
>> +#define OV13B10_2_DATA_LANES		2
>>   
>>   /*
>> - * 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
>> + * pixel_rate = data_rate * nr_of_lanes / bits_per_pixel
>> + * data_rate => link_freq * 2; number of lanes => 4; bits per pixel => 10
>>    */
>> -static u64 link_freq_to_pixel_rate(u64 f)
>> +static u64 link_freq_to_pixel_rate(u64 f, u8 lanes)
>>   {
>> -	f *= 2 * OV13B10_DATA_LANES;
>> +	f *= 2 * lanes;
>>   	do_div(f, 10);
>>   
>>   	return f;
>> @@ -559,7 +606,8 @@ static const struct ov13b10_link_freq_config
>>   };
>>   
>>   /* Mode configs */
>> -static const struct ov13b10_mode supported_modes[] = {
>> +static const struct ov13b10_mode supported_4_lanes_modes[] = {
>> +	/* 4 data lanes */
>>   	{
>>   		.width = 4208,
>>   		.height = 3120,
>> @@ -634,6 +682,23 @@ static const struct ov13b10_mode supported_modes[] = {
>>   	},
>>   };
>>   
>> +static const struct ov13b10_mode supported_2_lanes_modes[] = {
>> +	/* 2 data lanes */
>> +	{
>> +		.width = 2104,
>> +		.height = 1560,
>> +		.vts_def = OV13B10_VTS_60FPS,
>> +		.vts_min = OV13B10_VTS_60FPS,
>> +		.link_freq_index = OV13B10_LINK_FREQ_INDEX_0,
>> +		.ppl = 2352,
>> +		.reg_list = {
>> +			.num_of_regs =
>> +				ARRAY_SIZE(mode_2lanes_2104x1560_60fps_regs),
>> +			.regs = mode_2lanes_2104x1560_60fps_regs,
>> +		},
>> +	},
>> +};
>> +
>>   struct ov13b10 {
>>   	struct v4l2_subdev sd;
>>   	struct media_pad pad;
>> @@ -651,12 +716,20 @@ struct ov13b10 {
>>   	struct v4l2_ctrl *hblank;
>>   	struct v4l2_ctrl *exposure;
>>   
>> +	/* Supported modes */
>> +	const struct ov13b10_mode *supported_modes;
>> +
>>   	/* Current mode */
>>   	const struct ov13b10_mode *cur_mode;
>>   
>>   	/* Mutex for serialized access */
>>   	struct mutex mutex;
>>   
>> +	u8 supported_modes_num;
>> +
>> +	/* Data lanes used */
>> +	u8 data_lanes;
>> +
>>   	/* True if the device has been identified */
>>   	bool identified;
>>   };
>> @@ -760,8 +833,8 @@ static int ov13b10_write_reg_list(struct ov13b10 *ov13b,
>>   /* Open sub-device */
>>   static int ov13b10_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>>   {
>> -	const struct ov13b10_mode *default_mode = &supported_modes[0];
>>   	struct ov13b10 *ov13b = to_ov13b10(sd);
>> +	const struct ov13b10_mode *default_mode = ov13b->supported_modes;
>>   	struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_state_get_format(fh->state,
>>   									  0);
>>   
>> @@ -980,7 +1053,10 @@ static int ov13b10_enum_frame_size(struct v4l2_subdev *sd,
>>   				   struct v4l2_subdev_state *sd_state,
>>   				   struct v4l2_subdev_frame_size_enum *fse)
>>   {
>> -	if (fse->index >= ARRAY_SIZE(supported_modes))
>> +	struct ov13b10 *ov13b = to_ov13b10(sd);
>> +	const struct ov13b10_mode *supported_modes = ov13b->supported_modes;
>> +
>> +	if (fse->index >= ov13b->supported_modes_num)
>>   		return -EINVAL;
>>   
>>   	if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
>> @@ -1040,6 +1116,7 @@ ov13b10_set_pad_format(struct v4l2_subdev *sd,
>>   {
>>   	struct ov13b10 *ov13b = to_ov13b10(sd);
>>   	const struct ov13b10_mode *mode;
>> +	const struct ov13b10_mode *supported_modes = ov13b->supported_modes;
>>   	struct v4l2_mbus_framefmt *framefmt;
>>   	s32 vblank_def;
>>   	s32 vblank_min;
>> @@ -1054,7 +1131,7 @@ ov13b10_set_pad_format(struct v4l2_subdev *sd,
>>   		fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
>>   
>>   	mode = v4l2_find_nearest_size(supported_modes,
>> -				      ARRAY_SIZE(supported_modes),
>> +				      ov13b->supported_modes_num,
>>   				      width, height,
>>   				      fmt->format.width, fmt->format.height);
>>   	ov13b10_update_pad_format(mode, fmt);
>> @@ -1065,7 +1142,8 @@ ov13b10_set_pad_format(struct v4l2_subdev *sd,
>>   		ov13b->cur_mode = mode;
>>   		__v4l2_ctrl_s_ctrl(ov13b->link_freq, mode->link_freq_index);
>>   		link_freq = 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,
>> +						     ov13b->data_lanes);
>>   		__v4l2_ctrl_s_ctrl_int64(ov13b->pixel_rate, pixel_rate);
>>   
>>   		/* Update limits and set FPS to default */
>> @@ -1312,7 +1390,8 @@ static int ov13b10_init_controls(struct ov13b10 *ov13b)
>>   	if (ov13b->link_freq)
>>   		ov13b->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>>   
>> -	pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
>> +	pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0],
>> +						 ov13b->data_lanes);
>>   	pixel_rate_min = 0;
>>   	/* By default, PIXEL_RATE is read only */
>>   	ov13b->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops,
>> @@ -1423,7 +1502,7 @@ static int ov13b10_get_pm_resources(struct device *dev)
>>   	return 0;
>>   }
>>   
>> -static int ov13b10_check_hwcfg(struct device *dev)
>> +static int ov13b10_check_hwcfg(struct device *dev, struct ov13b10 *ov13b)
>>   {
>>   	struct v4l2_fwnode_endpoint bus_cfg = {
>>   		.bus_type = V4L2_MBUS_CSI2_DPHY
>> @@ -1433,6 +1512,7 @@ static int ov13b10_check_hwcfg(struct device *dev)
>>   	unsigned int i, j;
>>   	int ret;
>>   	u32 ext_clk;
>> +	u8 dlane;
>>   
>>   	if (!fwnode)
>>   		return -ENXIO;
>> @@ -1459,12 +1539,25 @@ static int ov13b10_check_hwcfg(struct device *dev)
>>   	if (ret)
>>   		return ret;
>>   
>> -	if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV13B10_DATA_LANES) {
>> +	dlane = bus_cfg.bus.mipi_csi2.num_data_lanes;
>> +	if (dlane != OV13B10_4_DATA_LANES && dlane != OV13B10_2_DATA_LANES) {
>>   		dev_err(dev, "number of CSI2 data lanes %d is not supported",
>> -			bus_cfg.bus.mipi_csi2.num_data_lanes);
>> +			dlane);
>>   		ret = -EINVAL;
>>   		goto out_err;
>>   	}
>> +	ov13b->data_lanes = dlane;
>> +	ov13b->supported_modes = supported_4_lanes_modes;
>> +	ov13b->supported_modes_num = ARRAY_SIZE(supported_4_lanes_modes);
>> +	if (dlane == OV13B10_2_DATA_LANES) {
>> +		ov13b->supported_modes = supported_2_lanes_modes;
>> +		ov13b->supported_modes_num =
>> +			ARRAY_SIZE(supported_2_lanes_modes);
> 
> How about using switch() here?

How about:
	ov13b->data_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
	switch (ov13b->data_lanes) {
	case OV13B10_4_DATA_LANES:
		ov13b->supported_modes = supported_4_lanes_modes;
		ov13b->supported_modes_num =
			ARRAY_SIZE(supported_4_lanes_modes);
		break;

	case OV13B10_2_DATA_LANES:
		ov13b->supported_modes = supported_2_lanes_modes;
		ov13b->supported_modes_num =
			ARRAY_SIZE(supported_2_lanes_modes);
		break;

	default:
		dev_err(dev, "number of CSI2 data lanes %d is not supported",
			ov13b->data_lanes);
		ret = -EINVAL;
		goto out_err;
	}


Best Regards,
Hao Yao

> 
>> +	}
>> +
>> +	ov13b->cur_mode = ov13b->supported_modes;
>> +	dev_dbg(dev, "%u lanes with %u modes selected\n",
>> +		ov13b->data_lanes, ov13b->supported_modes_num);
>>   
>>   	if (!bus_cfg.nr_of_link_frequencies) {
>>   		dev_err(dev, "no link frequencies defined");
>> @@ -1499,17 +1592,17 @@ static int ov13b10_probe(struct i2c_client *client)
>>   	bool full_power;
>>   	int ret;
>>   
>> +	ov13b = devm_kzalloc(&client->dev, sizeof(*ov13b), GFP_KERNEL);
>> +	if (!ov13b)
>> +		return -ENOMEM;
>> +
>>   	/* Check HW config */
>> -	ret = ov13b10_check_hwcfg(&client->dev);
>> +	ret = ov13b10_check_hwcfg(&client->dev, ov13b);
>>   	if (ret) {
>>   		dev_err(&client->dev, "failed to check hwcfg: %d", ret);
>>   		return ret;
>>   	}
>>   
>> -	ov13b = devm_kzalloc(&client->dev, sizeof(*ov13b), GFP_KERNEL);
>> -	if (!ov13b)
>> -		return -ENOMEM;
>> -
>>   	/* Initialize subdev */
>>   	v4l2_i2c_subdev_init(&ov13b->sd, client, &ov13b10_subdev_ops);
>>   
>> @@ -1533,9 +1626,6 @@ static int ov13b10_probe(struct i2c_client *client)
>>   		}
>>   	}
>>   
>> -	/* Set default mode to max resolution */
>> -	ov13b->cur_mode = &supported_modes[0];
>> -
>>   	ret = ov13b10_init_controls(ov13b);
>>   	if (ret)
>>   		goto error_power_off;
> 


  reply	other threads:[~2025-03-10  4:06 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-07  9:31 [PATCH 1/2] media: i2c: ov13b10: Fix h_blank calculation Hao Yao
2025-03-07  9:31 ` [PATCH 2/2] media: i2c: ov13b10: Support 2 lane mode Hao Yao
2025-03-07  9:43   ` Sakari Ailus
2025-03-10  4:06     ` Hao Yao [this message]
2025-03-10  7:14       ` Sakari Ailus
2025-03-11  6:42         ` Hao Yao
2025-03-11  8:17           ` Sakari Ailus

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f24a1543-9a8f-4e42-8cf7-40644f6d706d@intel.com \
    --to=hao.yao@intel.com \
    --cc=arec.kao@intel.com \
    --cc=bingbu.cao@intel.com \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    --cc=sakari.ailus@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox